Index: soft/giet_vm/giet_drivers/ioc_driver.c
===================================================================
--- soft/giet_vm/giet_drivers/ioc_driver.c	(revision 289)
+++ soft/giet_vm/giet_drivers/ioc_driver.c	(revision 295)
@@ -7,31 +7,45 @@
 ///////////////////////////////////////////////////////////////////////////////////
 // The ioc_driver.c and ioc_driver.h files are part ot the GIET-VM kernel.
-// This driver supports the SocLib vci_block_device component, that is
-// a single channel, block oriented, external storage contrÃŽler.
-//
-// It can exist only one block-device controler in the architecture.
-//
-// The _ioc_read() and _ioc_write() functions use the _ioc_access() function,
-// that is always blocking. The _ioc_access function will call the read or
-// write function in the driver of the choosen IOC peripheral, which can be for
-// now: BDV, HBA and SPI. This function can be called in 4 modes:
-//
-// - In BOOT_PA mode, the _ioc_access() function use the buffer virtual address
-//   as a physical address (as the page tables are not build). This mode is
-//   used by the boot code to load the map.bin file into memory.
-//
-// - In BOOT_VA mode, the _ioc_access() function makes a V2P translation to
-//   compute the buffer physical address. This mode is used by the boot code to
-//   load the various .elf files into memory.
-//
-// - In KERNEL mode, the _ioc_access() function makes a V2P translation to
-//   compute the buffer physical address. There is no checking of user access
-//   right to the memory buffer.  This mode must be used to access IOC, for an
-//   "open" system call.
-//
-// - In USER mode, the _ioc_access() function makes a V2P translation to
-//   compute the buffer physical address. The user access right to the memory
-//   buffer must be checked.  This mode must be used to access IOC, for a
-//   "read/write" system call.
+//
+// This abstact driver define a generic API, supporting various physical
+// block device controlers, including:
+// - vci_block_device : single channel)                    => bdv_driver
+// - vci_ahci         : multi channels                     => hba_driver
+// - sd_card          : single channel                     => sdc_driver
+// - ramdisk (single channel meory mapped virtual disk)    => rdk_driver
+//
+// It can exist only one block-device type in the architecture, that must be
+// defined by one of the following configuration variables in hard_config.h file:
+// USE_IOC_BDV, USE_IOC_SDC, USE_IOC_HBA, USE_IOC_RDK.
+//
+// Any physical driver xxx must provide the following API:
+// - _xxx_init()
+// - _xxx_read()
+// - _xxx_write()
+// - _xxx_get_status()
+// - _xxx_get_block_size()
+// The "channel" parameter is no transmited to single channel devices.
+//
+// The _ioc_read() and _ioc_write() functions are always blocking for
+// the calling user program.
+//
+// These functions compute the physical address of the memory buffer before 
+// calling the proper physical device. They can be called in 3 modes:
+//
+// - In BOOT mode, these functions use the buffer virtual address
+//   as a physical address if the MMU is not activated.
+//   They make a V2P translation if the MMU is activated.
+//   This mode is used to load the map.bin file (before memory activation),
+//   or to load the various .elf files (after MMU activation).
+//
+// - In KERNEL mode, these functions make a V2P translation to
+//   compute the buffer physical address.
+//   There is no checking of user access right to the memory buffer.  
+//   This mode must be used for an "open" system call.
+//
+// - In USER mode, these functions make a V2P translation to
+//   compute the buffer physical address. 
+//   The user access right to the memory buffer are checked.  
+//   This mode must be used for a "read" or "write" system call.
 //
 // The IOMMU can be activated or not:
@@ -60,10 +74,21 @@
 //   if the IOMMU is not activated.
 // An error code is returned if these conditions are not verified.
+//
+// The "seg_ioc_base" virtual base address of the segment containing the
+// memory-mapped registers of the device must be defined in the giet_vsegs.ld file.
+// If the RAMDISK is used, an extra memory segment with virtual base address
+// "seg_ramdisk_base" must be defined in the giet_vsegs.ld file.
 ///////////////////////////////////////////////////////////////////////////////////
-// The seg_ioc_base virtual base addresses must be defined in giet_vsegs.ld file.
+// Implementation note:
+// In order to share the code, the two _ioc_read() and _ioc_write() functions
+// call the same _ioc_access() function.
 ///////////////////////////////////////////////////////////////////////////////////
 
 #include <giet_config.h>
 #include <ioc_driver.h>
+#include <bdv_driver.h>
+#include <hba_driver.h>
+#include <sdc_driver.h>
+#include <rdk_driver.h>
 #include <utils.h>
 #include <tty_driver.h>
@@ -81,38 +106,39 @@
 #endif
 
-#if (USE_BDV + USE_SPI + USE_HBA) != 1
-# error: You must use only one IOC controller (BDV or SPI or HBA)
-#endif
-
-#if USE_BDV
+#if (USE_IOC_BDV + USE_IOC_SPI + USE_IOC_HBA + USE_IOC_RDK) != 1
+# error: You must use only one IOC controller type (BDV or SPI or HBA or RDK)
+#endif
+
+#if USE_IOC_BDV
 # include <bdv_driver.h>
 #endif
 
-#if USE_SPI
+#if USE_IOC_SPI
 # include <sdc_driver.h>
 #endif
 
-#if USE_HBA
+#if USE_IOC_HBA
 # include <hba_driver.h>
 #endif
 
+#if USE_IOC_RDK
+# include <rdk_driver.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// IOC global variables
+///////////////////////////////////////////////////////////////////////////////
 
 #define in_unckdata __attribute__((section (".unckdata")))
 
-///////////////////// IOC global variables
-
-in_unckdata unsigned int _ioc_lock = 0;
-in_unckdata unsigned int _ioc_status = 0;
-in_unckdata volatile unsigned int _ioc_gtid;
 in_unckdata volatile unsigned int _ioc_iommu_ix1 = 0;
 in_unckdata volatile unsigned int _ioc_iommu_npages; 
 
 ///////////////////////////////////////////////////////////////////////////////
-//      _ioc_access()
 // This function transfer data between a memory buffer and the block device.
 // The buffer lentgth is (count*block_size) bytes.
 // Arguments are:
 // - to_mem     : from external storage to memory when non 0.
-// - kernel     : kernel buffer with identity mapping when non 0. 
+// - mode       : BOOT_PA / BOOT_VA / KERNEL / USER 
 // - lba        : first block index on the external storage.
 // - buf_vaddr  : virtual base address of the memory buffer.
@@ -121,4 +147,5 @@
 ///////////////////////////////////////////////////////////////////////////////
 static unsigned int _ioc_access( unsigned int to_mem,
+                                 unsigned int channel,
                                  unsigned int mode,
                                  unsigned int lba,
@@ -128,19 +155,17 @@
 
 #if GIET_DEBUG_IOC_DRIVER
-_tty_get_lock( 0 );
-_puts("\n[IOC DEBUG] Enter _ioc_access() at cycle ");
-_putd( _get_proctime() );
-_puts(" for processor ");
-_putd( _get_procid() );
-_puts("\n - mode    = ");
-_putd( mode );
-_puts("\n - vaddr   = ");
-_putx( buf_vaddr );
-_puts("\n - sectors = ");
-_putd( count );
-_puts("\n - lba     = ");
-_putx( lba );
-_puts("\n");
-_tty_release_lock( 0 );
+unsigned int procid  = _get_procid();
+unsigned int cid     = procid / NB_PROCS_MAX;
+unsigned int lpid    = procid % NB_PROCS_MAX;
+unsigned int x       = cid >> Y_WIDTH;
+unsigned int y       = cid & ((1<<Y_WIDTH) - 1);
+
+_printf("\n[IOC DEBUG] Processor[%d,%d,%d] enters _ioc_access() at cycle %d\n"
+        " - channel  = %d\n"
+        " - mode     = %d\n"
+        " - vaddr    = %d\n"
+        " - sectors  = %d\n"
+        " - lba      = %d\n",
+        x, y, lpid, _get_proctime(), channel, mode, buf_vaddr, count, lba );
 #endif
 
@@ -160,28 +185,31 @@
     if ((unsigned int) buf_vaddr & 0x3)
     {
-        _tty_get_lock( 0 );
-        _puts("\n[GIET ERROR] in _ioc_access() : buffer not word aligned\n");
-        _tty_release_lock( 0 );
-        return 1; 
+        _printf("\n[GIET ERROR] in _ioc_access() : buffer not word aligned\n");
+        _exit(); 
+    }
+
+    // check channel 
+    if ( (USE_IOC_HBA == 0) && (channel > 0) )
+    {
+        _printf("\n[GIET ERROR] in _ioc_access() : channel must be 0 when HBA not used\n");
+        _exit(); 
     }
 
     unsigned int length = count << 9;  // count * 512 bytes
 
-    // computing target buffer physical address
-    if ( mode == IOC_BOOT_PA_MODE )                // identity mapping
+    // computing memory buffer physical address
+    if ( (mode == IOC_BOOT_MODE) && ((_get_mmu_mode() & 0x4) == 0) ) // identity mapping
     {
         buf_paddr = (paddr_t)buf_vaddr;
     }
-    else                                           // V2P translation
+    else                                                    // V2P translation required
     {
         // get page table virtual address
         pt_vbase = _get_context_slot(CTX_PTAB_ID);
-        vpn_min = buf_vaddr >> 12;
-        vpn_max = (buf_vaddr + length - 1) >> 12;
+        vpn_min  = buf_vaddr >> 12;
+        vpn_max  = (buf_vaddr + length - 1) >> 12;
 
         // loop on all virtual pages covering the user buffer
-        for (vpn = vpn_min, ix2 = 0 ; 
-             vpn <= vpn_max ; 
-             vpn++, ix2++ ) 
+        for (vpn = vpn_min, ix2 = 0 ; vpn <= vpn_max ; vpn++, ix2++ ) 
         {
             // get ppn and flags for each vpn
@@ -193,7 +221,5 @@
             if ( ko )
             {
-                _tty_get_lock( 0 );
-                _puts("\n[GIET ERROR] in _ioc_access() : buffer unmapped\n");
-                _tty_release_lock( 0 );
+                _printf("\n[GIET ERROR] in _ioc_access() : buffer unmapped\n");
                 return 1; 
             }
@@ -201,7 +227,5 @@
             if ( (mode == IOC_USER_MODE) && ((flags & PTE_U) == 0) )
             {
-                _tty_get_lock( 0 );
-                _puts("\n[GIET ERROR] in _ioc_access() : buffer not user accessible\n");
-                _tty_release_lock( 0 );
+                _printf("\n[GIET ERROR] in _ioc_access() : buffer not user accessible\n");
                 return 1; 
             }
@@ -209,7 +233,5 @@
             if ( ((flags & PTE_W) == 0 ) && to_mem )
             {
-                _tty_get_lock( 0 );
-                _puts("\n[GIET ERROR] in _ioc_access() : buffer not writable\n");
-                _tty_release_lock( 0 );
+                _printf("\n[GIET ERROR] in _ioc_access() : buffer not writable\n");
                 return 1; 
             }
@@ -223,7 +245,5 @@
             if (ix2 > 511) // check buffer length < 2 Mbytes
             {
-                _tty_get_lock( 0 );
-                _puts("\n[GIET ERROR] in _ioc_access() : user buffer > 2 Mbytes\n");
-                _tty_release_lock( 0 );
+                _printf("\n[GIET ERROR] in _ioc_access() : user buffer > 2 Mbytes\n");
                 return 1; 
             }
@@ -242,7 +262,5 @@
             if ((ppn - ppn_first) != ix2) 
             {
-                _tty_get_lock( 0 );
-                _puts("[GIET ERROR] in _ioc_access() : split physical buffer\n");
-                _tty_release_lock( 0 );
+                _printf("[GIET ERROR] in _ioc_access() : split physical buffer\n");
                 return 1; 
             }
@@ -272,5 +290,5 @@
     else         // memory read : update data caches
     {
-        // L1 cache : nothing to do if L1 write-through
+        // L1 cache : nothing to do for L1 write-through
 
         // L2 cache (only if IOB used)
@@ -280,13 +298,40 @@
     if ( GIET_USE_IOMMU ) buf_paddr = (paddr_t) buf_xaddr;
 
-#if   USE_BDV
-    if (to_mem) error = _bdv_read (mode, lba, buf_paddr, count);
-    else        error = _bdv_write(mode, lba, buf_paddr, count);
-#elif USE_SPI
-    if (to_mem) error = _sdc_read (mode, lba, buf_paddr, count);
-    else        error = _sdc_write(mode, lba, buf_paddr, count);
-#elif USE_HBA
-    if (to_mem) error = _hba_read (mode, lba, buf_paddr, count);
-    else        error = _hba_write(mode, lba, buf_paddr, count);
+    ///////////////////////////////////////////
+    // select the proper physical device 
+    ///////////////////////////////////////////
+
+#if       ( USE_IOC_BDV )
+
+#if GIET_DEBUG_IOC_DRIVER
+_printf("\n[IOC DEBUG] Calling BDV driver\n");
+#endif
+        if (to_mem) error = _bdv_read ( mode, lba, buf_paddr, count);
+        else        error = _bdv_write( mode, lba, buf_paddr, count);
+
+#elif ( USE_IOC_SPI )
+
+#if GIET_DEBUG_IOC_DRIVER
+_printf("\n[IOC DEBUG] Calling SPI driver\n");
+#endif
+        if (to_mem) error = _sdc_read (mode, lba, buf_paddr, count);
+        else        error = _sdc_write(mode, lba, buf_paddr, count);
+
+#elif ( USE_IOC_HBA )
+
+#if GIET_DEBUG_IOC_DRIVER
+_printf("\n[IOC DEBUG] Calling HBA driver\n");
+#endif
+        if (to_mem) error = _hba_read (channel, mode, lba, buf_paddr, count);
+        else        error = _hba_write(channel, mode, lba, buf_paddr, count);
+
+#elif ( USE_IOC_RDK )
+
+#if GIET_DEBUG_IOC_DRIVER
+_printf("\n[IOC DEBUG] Calling RDK driver\n");
+#endif
+        if (to_mem) error = _rdk_read (lba, buf_vaddr, count);
+        else        error = _rdk_write(lba, buf_vaddr, count);
+
 #endif
 
@@ -295,5 +340,4 @@
 
 ///////////////////////////////////////////////////////////////////////////////
-//       _ioc_init()
 // This function cheks block size, and activates the IOC interrupts.
 // Return 0 for success.
@@ -301,17 +345,28 @@
 unsigned int _ioc_init( unsigned int channel )
 {
-#if   USE_BDV
-    return _bdv_init( channel );
-#elif USE_SPI
-    return _sdc_init( channel );
-#elif USE_HBA
+
+#if   ( USE_IOC_BDV ) 
+
+    return _bdv_init();
+
+#elif ( USE_IOC_SPI ) 
+
+    return _sdc_init();
+    
+#elif ( USE_IOC_HBA ) 
+
     return _hba_init( channel );
-#endif
+    
+#elif ( USE_IOC_RDK ) 
+
+    return _rdk_init();
+    
+#endif
+    
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-//     _ioc_read()
 // Transfer data from the block device to a memory buffer. 
-// - mode     : BOOT / KERNEL / USER
+// - mode     : BOOT_PA / BOOT_VA / KERNEL / USER 
 // - lba      : first block index on the block device
 // - buffer   : base address of the memory buffer (must be word aligned)
@@ -319,5 +374,6 @@
 // Returns 0 if success, > 0 if error.
 ///////////////////////////////////////////////////////////////////////////////
-unsigned int _ioc_read( unsigned int mode,  
+unsigned int _ioc_read( unsigned int channel,
+                        unsigned int mode,  
                         unsigned int lba, 
                         void*        buffer, 
@@ -325,4 +381,5 @@
 {
     return _ioc_access( 1,        // read access
+                        channel,
                         mode,  
                         lba,
@@ -332,7 +389,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
-//     _ioc_write()
 // Transfer data from a memory buffer to the block device. 
-// - mode     : BOOT / KERNEL / USER
+// - mode     : BOOT_PA / BOOT_VA / KERNEL / USER 
 // - lba      : first block index on the block device
 // - buffer   : base address of the memory buffer (must be word aligned)
@@ -340,5 +396,6 @@
 // Returns 0 if success, > 0 if error.
 ///////////////////////////////////////////////////////////////////////////////
-unsigned int _ioc_write( unsigned int mode,  
+unsigned int _ioc_write( unsigned int channel,
+                         unsigned int mode,  
                          unsigned int lba, 
                          const void*  buffer, 
@@ -346,4 +403,5 @@
 {
     return _ioc_access( 0,        // write access
+                        channel,
                         mode,  
                         lba,
@@ -353,34 +411,59 @@
 
 ///////////////////////////////////////////////////////////////////////////////
-//     _ioc_get_status()
 // This function returns in the status variable, the transfert status, and
 // acknowledge the IRQ if the IOC controler is not busy.
 // Returns 0 if success, > 0 if error
 ///////////////////////////////////////////////////////////////////////////////
-unsigned int _ioc_get_status( unsigned int  channel,
-                              unsigned int* status )
-{
-#if   USE_BDV
-    return _bdv_get_status(channel, status);
-#elif USE_SPI
-    return _sdc_get_status(channel, status);
-#elif USE_HBA
-    return _hba_get_status(channel, status);
-#endif
+unsigned int _ioc_get_status( unsigned int  channel )
+{
+
+#if   ( USE_IOC_BDV ) 
+
+    return _bdv_get_status( );
+
+#elif ( USE_IOC_SPI ) 
+
+    return _sdc_get_status( );
+
+#elif ( USE_IOC_HBA ) 
+
+    return _hba_get_status( channel );
+
+#elif ( USE_IOC_RDK )
+
+    _printf("[GIET ERROR] _ioc_get_status() should not be called");
+    _printf(" when RAMDISK  is used...\n");
+    _exit();
+
+    return 0;
+
+#endif
+
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-//     _ioc_get_block_size()
 // This function returns the block_size with which the IOC has been configured.
 ///////////////////////////////////////////////////////////////////////////////
 unsigned int _ioc_get_block_size() 
 {
-#if   USE_BDV
+
+#if   ( USE_IOC_BDV ) 
+
     return _bdv_get_block_size();
-#elif USE_SPI
+    
+#elif ( USE_IOC_SPI ) 
+
     return _sdc_get_block_size();
-#elif USE_HBA
+    
+#elif ( USE_IOC_HBA ) 
+
     return _hba_get_block_size();
-#endif
+    
+#elif ( USE_IOC_RDK ) 
+
+    return 512;
+
+#endif
+
 }
 
