Changeset 166 for soft/giet_vm/sys


Ignore:
Timestamp:
Jul 6, 2012, 10:13:16 AM (12 years ago)
Author:
alain
Message:

Introducing support for IOMMU

Location:
soft/giet_vm/sys
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • soft/giet_vm/sys/common.c

    r165 r166  
    112112    unsigned int line_size;
    113113
    114     /*
    115      * compute data cache line size based on config register (bits 12:10)
    116      */
     114    // compute data cache line size based on config register (bits 12:10)
    117115    asm volatile("mfc0 %0, $16, 1" : "=r"(tmp));
    118116    tmp = ((tmp>>10) & 0x7);
    119117    line_size = 2 << tmp;
    120118
    121     /* iterate on cache lines to invalidate each one of them */
     119    // iterate on cache lines
    122120    for (i = 0; i < size; i += line_size)
    123121    {
     
    160158        val /= 16;
    161159    }
     160}
     161///////////////////////////////////////////////////////////////////////////////////
     162//      _get_ptpr()
     163// Access CP2 and returns PTPR register.
     164///////////////////////////////////////////////////////////////////////////////////
     165inline unsigned int _get_ptpr()
     166{
     167    unsigned int ret;
     168    asm volatile("mfc2 %0, $0" : "=r"(ret));
     169    return ret;
    162170}
    163171///////////////////////////////////////////////////////////////////////////////////
  • soft/giet_vm/sys/common.h

    r165 r166  
    1717typedef struct _ld_symbol_s _ld_symbol_t;
    1818
     19extern _ld_symbol_t seg_iob_base;
    1920extern _ld_symbol_t seg_icu_base;
    2021extern _ld_symbol_t seg_timer_base;
     
    4243
    4344unsigned int _get_epc();
     45unsigned int _get_ptpr();
    4446unsigned int _get_bar();
    4547unsigned int _get_cr();
  • soft/giet_vm/sys/drivers.c

    r165 r166  
    3434///////////////////////////////////////////////////////////////////////////////////
    3535
     36#include <vm_handler.h>
    3637#include <sys_handler.h>
    3738#include <giet_config.h>
     
    8788in_unckdata volatile unsigned char _dma_busy[NB_DMAS] = { [0 ... NB_DMAS-1] = 0 };
    8889
    89 in_unckdata volatile unsigned char _ioc_status;
    90 in_unckdata volatile unsigned char _ioc_done = 0;
    91 in_unckdata volatile unsigned int  _ioc_lock = 0;
     90in_unckdata volatile unsigned char _ioc_status       = 0;
     91in_unckdata volatile unsigned char _ioc_done         = 0;
     92in_unckdata unsigned int                   _ioc_lock         = 0;
     93in_unckdata unsigned int                   _ioc_iommu_ix1    = 0;
     94in_unckdata unsigned int                   _ioc_iommu_npages = 0;
    9295
    9396in_unckdata volatile unsigned char _tty_get_buf[NB_TTYS];
     
    394397////////////////////////////////////////////////////////////////////////////////
    395398// The VciBlockDevice is a single channel external storage contrÃŽler.
    396 // The three functions below use the three variables _ioc_lock _ioc_done,  and
    397 // _ioc_status for synchronisation.
     399//
     400// The IOMMU can be activated or not:
     401//
     402// 1) When the IOMMU is used, a fixed size 2Mbytes vseg is allocated to
     403// the IOC peripheral, in the I/O virtual space, and the user buffer is
     404// dynamically remapped in the IOMMU page table. The corresponding entry
     405// in the IOMMU PT1 is defined by the kernel _ioc_iommu_ix1 variable.
     406// The number of pages to be unmapped is stored in the _ioc_npages variable.
     407// The number of PT2 entries is dynamically computed and stored in the
     408// kernel _ioc_iommu_npages variable. It cannot be larger than 512.
     409// The user buffer is unmapped by the _ioc_completed() function when
     410// the transfer is completed.
     411//
     412// 2/ If the IOMMU is not used, we check that  the user buffer is mapped to a
     413// contiguous physical buffer (this is generally true because the user space
     414// page tables are statically constructed to use contiguous physical memory).
     415//
     416// Finally, the memory buffer must fulfill the following conditions:
     417// - The user buffer must be word aligned,
     418// - The user buffer must be mapped in user address space,
     419// - The user buffer must be writable in case of (to_mem) access,
     420// - The total number of physical pages occupied by the user buffer cannot
     421//   be larger than 512 pages if the IOMMU is activated,
     422// - All physical pages occupied by the user buffer must be contiguous
     423//   if the IOMMU is not activated.
     424// An error code is returned if these conditions are not verified.
     425//
    398426// As the IOC component can be used by several programs running in parallel,
    399427// the _ioc_lock variable guaranties exclusive access to the device.  The
     
    407435// variable.
    408436// The _ioc_completed() function is polling the _ioc_done variable, waiting for
    409 // tranfer conpletion. When the completion is signaled, the _ioc_completed()
     437// transfer completion. When the completion is signaled, the _ioc_completed()
    410438// function reset the _ioc_done variable to zero, and releases the _ioc_lock
    411439// variable.
     
    447475
    448476///////////////////////////////////////////////////////////////////////////////
    449 //  _ioc_write()
    450 //
    451 // Transfer data from a memory buffer to a file on the block_device.
    452 // The source memory buffer must be in user address space.
    453 // - lba    : first block index on the disk.
    454 // - buffer : base address of the memory buffer.
     477//  _ioc_access()
     478// This function transfer data between a memory buffer and the block device.
     479// The buffer lentgth is (count*block_size) bytes.
     480//
     481// Arguments are:
     482// - to_mem     : from external storage to memory when non 0
     483// - lba        : first block index on the external storage.
     484// - user_vaddr : virtual base address of the memory buffer.
     485// - count      : number of blocks to be transfered.
     486// Returns 0 if success, > 0 if error.
     487///////////////////////////////////////////////////////////////////////////////
     488unsigned int _ioc_access( unsigned int  to_mem,
     489                          unsigned int  lba,
     490                          unsigned int  user_vaddr,
     491                          unsigned int  count )
     492{
     493    unsigned int        user_vpn_min;
     494    unsigned int        user_vpn_max;
     495    unsigned int        vpn;                    // virtual page number in user space
     496    unsigned int        ppn;                    // physical page number
     497    unsigned int        flags;                  // page protection flags
     498    unsigned int        ix2;                    // Page index (for IOMMU page table)
     499    unsigned int        addr;                   // buffer address for IOC
     500    page_table_t*       user_ptp;               // user page table pointer
     501    unsigned int        ko;                             // bool returned by _v2p_translate()
     502    unsigned int        ppn_first;              // first physical page number for user buffer
     503       
     504    // check buffer alignment
     505    if ( (unsigned int)user_vaddr & 0x3 ) return 1;
     506
     507    unsigned int*       ioc_address = (unsigned int*)&seg_ioc_base;
     508    unsigned int        block_size   = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
     509    unsigned int        length       = count*block_size;
     510
     511    // get user space page table base address
     512    user_ptp     = (page_table_t*)(_get_ptpr() << 13);
     513   
     514    user_vpn_min = user_vaddr >> 12;
     515    user_vpn_max = (user_vaddr + length - 1) >> 12;
     516    ix2          = 0;
     517
     518    // loop on all virtual pages covering the user buffer
     519    for ( vpn = user_vpn_min ; vpn <= user_vpn_max ; vpn++ )
     520    {
     521        // get ppn and flags for each vpn
     522        ko = _v2p_translate( user_ptp,  // user page table pointer
     523                             vpn,               // virtual page number
     524                             &ppn,              // physical page number
     525                             &flags );  // protection flags
     526
     527        // check access rights
     528        if ( ko )                                                                 return 2;             // unmapped
     529        if ( (flags & PTE_U) == 0 )                               return 3;             // not in user space
     530        if ( ( (flags & PTE_W) == 0 ) && to_mem ) return 4;             // not writable
     531
     532        // save first ppn value
     533        if ( ix2 == 0 ) ppn_first = ppn;
     534
     535        if ( GIET_IOMMU_ACTIVE )    // the user buffer must be remapped in the I/0 space
     536        {
     537            // check buffer length < 2 Mbytes
     538            if ( ix2 > 511 ) return 2;
     539
     540            // map the physical page in IOMMU page table
     541            _iommu_add_pte2( _ioc_iommu_ix1,    // PT1 index
     542                             ix2,                               // PT2 index
     543                                                 ppn,                           // Physical page number
     544                             flags );                   // Protection flags
     545
     546            // buffer base address for IOC with IOMMU
     547        }
     548        else                    // no IOMMU : check that physical pages are contiguous
     549        {
     550            if ( (ppn - ppn_first) != ix2 )           return 5;         // split physical buffer 
     551        }
     552       
     553        // increment page index
     554        ix2++;
     555    } // end for vpn
     556
     557    // register the number of pages to be unmapped
     558    _ioc_iommu_npages = (user_vpn_max - user_vpn_min) + 1;
     559
     560    // invalidate data cache in case of memory write
     561    if ( to_mem ) _dcache_buf_invalidate( (void*)user_vaddr, length );
     562
     563    // compute buffer base address for IOC depending on IOMMU activation
     564    if ( GIET_IOMMU_ACTIVE ) addr = (_ioc_iommu_ix1) << 21 | (user_vaddr & 0xFFF);
     565    else                     addr = ppn_first | (user_vaddr & 0xFFF);
     566
     567    // get the lock on ioc device
     568    _ioc_get_lock();
     569
     570    // peripheral configuration 
     571    ioc_address[BLOCK_DEVICE_BUFFER]     = addr;
     572    ioc_address[BLOCK_DEVICE_COUNT]      = count;
     573    ioc_address[BLOCK_DEVICE_LBA]        = lba;
     574    if ( to_mem == 0 ) ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
     575    else               ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
     576
     577    return 0;
     578}
     579
     580/////////////////////////////////////////////////////////////////////////////////
     581// _ioc_completed()
     582//
     583// This function checks completion of an I/O transfer and reports errors.
     584// As it is a blocking call, the processor is stalled.
     585// If the virtual memory is activated, the pages mapped in the I/O virtual
     586// space are unmapped, and the IOB TLB is cleared.
     587// Returns 0 if success, > 0 if error.
     588/////////////////////////////////////////////////////////////////////////////////
     589unsigned int _ioc_completed()
     590{
     591    unsigned int        ret;
     592    unsigned int        ix2;
     593
     594    // busy waiting
     595    while (_ioc_done == 0)
     596        asm volatile("nop");
     597
     598    // unmap the buffer from IOMMU page table if IOMMU is activated
     599    if ( GIET_IOMMU_ACTIVE )
     600    {
     601        unsigned int* iob_address = (unsigned int*)&seg_iob_base;
     602
     603        for ( ix2 = 0 ; ix2 < _ioc_iommu_npages ; ix2++ )
     604        {
     605            // unmap the page in IOMMU page table
     606            _iommu_inval_pte2( _ioc_iommu_ix1,  // PT1 index
     607                              ix2 );                    // PT2 index
     608
     609            // clear IOMMU TLB
     610            iob_address[IOB_INVAL_PTE] = (_ioc_iommu_ix1 << 21) | (ix2) << 12;
     611        }
     612    }
     613
     614    // test IOC status
     615    if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
     616            && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    // error
     617    else                                                    ret = 0;    // success
     618
     619    // reset synchronization variables
     620    _ioc_lock =0;
     621    _ioc_done =0;
     622
     623    return ret;
     624}
     625
     626///////////////////////////////////////////////////////////////////////////////
     627// _ioc_read()
     628// Transfer data from the block device to a memory buffer in user space.
     629// - lba    : first block index on the block device
     630// - buffer : base address of the memory buffer (must be word aligned)
     631// - count  : number of blocks to be transfered.
     632// Returns 0 if success, > 0 if error.
     633///////////////////////////////////////////////////////////////////////////////
     634unsigned int _ioc_read( unsigned int    lba,
     635                        void*               buffer,
     636                        unsigned int    count )
     637{
     638    return _ioc_access( 1,              // read
     639                        lba,
     640                        (unsigned int)buffer,
     641                        count );
     642}
     643
     644///////////////////////////////////////////////////////////////////////////////
     645// _ioc_write()
     646// Transfer data from a memory buffer in user space to the block device.
     647// - lba    : first block index on the block device
     648// - buffer : base address of the memory buffer (must be word aligned)
    455649// - count  : number of blocks to be transfered.
    456650// Returns 0 if success, > 0 if error.
     
    458652unsigned int _ioc_write( unsigned int   lba,
    459653                         const void*    buffer,
    460                          unsigned int   count)
    461 {
    462     volatile unsigned int *ioc_address;
    463 
    464     ioc_address = (unsigned int*)&seg_ioc_base;
    465 
    466     /* buffer must be in user space */
    467     unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
    468 
    469     if (((unsigned int)buffer >= 0x80000000)
    470             || (((unsigned int)buffer + block_size*count) >= 0x80000000))
    471         return 1;
    472 
    473     /* get the lock on ioc device */
    474     _ioc_get_lock();
    475 
    476     /* block_device configuration for the write transfer */
    477     ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer;
    478     ioc_address[BLOCK_DEVICE_COUNT] = count;
    479     ioc_address[BLOCK_DEVICE_LBA] = lba;
    480     ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
    481     ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE;
    482 
    483     return 0;
    484 }
    485 
    486 ///////////////////////////////////////////////////////////////////////////////
    487 // _ioc_read()
    488 //
    489 // Transfer data from a file on the block device to a memory buffer.
    490 // The destination memory buffer must be in user address space.
    491 // - lba    : first block index on the disk.
    492 // - buffer : base address of the memory buffer.
    493 // - count  : number of blocks to be transfered.
    494 // All cache lines corresponding to the the target buffer are invalidated
    495 // for cache coherence.
    496 // Returns 0 if success, > 0 if error.
    497 ///////////////////////////////////////////////////////////////////////////////
    498 unsigned int _ioc_read( unsigned int    lba,
    499                         void*           buffer,
    500                         unsigned int    count )
    501 {
    502     volatile unsigned int *ioc_address;
    503 
    504     ioc_address = (unsigned int*)&seg_ioc_base;
    505 
    506     /* buffer must be in user space */
    507     unsigned int block_size = ioc_address[BLOCK_DEVICE_BLOCK_SIZE];
    508 
    509     if (((unsigned int)buffer >= 0x80000000)
    510             || (((unsigned int)buffer + block_size*count) >= 0x80000000))
    511         return 1;
    512 
    513     /* get the lock on ioc device */
    514     _ioc_get_lock();
    515 
    516     /* block_device configuration for the read transfer */
    517     ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer;
    518     ioc_address[BLOCK_DEVICE_COUNT] = count;
    519     ioc_address[BLOCK_DEVICE_LBA] = lba;
    520     ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
    521     ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ;
    522 
    523     /* invalidation of data cache */
    524     _dcache_buf_invalidate(buffer, block_size*count);
    525 
    526     return 0;
    527 }
    528 
    529 /////////////////////////////////////////////////////////////////////////////////
    530 // _ioc_completed()
    531 //
    532 // This function checks completion of an I/O transfer and reports errors.
    533 // As it is a blocking call, the processor is stalled until the next interrupt.
    534 // Returns 0 if success, > 0 if error.
    535 /////////////////////////////////////////////////////////////////////////////////
    536 unsigned int _ioc_completed()
    537 {
    538     unsigned int ret;
    539 
    540     /* busy waiting */
    541     while (_ioc_done == 0)
    542         asm volatile("nop");
    543 
    544     /* test IOC status */
    545     if ((_ioc_status != BLOCK_DEVICE_READ_SUCCESS)
    546             && (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS)) ret = 1;    /* error */
    547     else                                                    ret = 0;    /* success */
    548 
    549     /* reset synchronization variables */
    550     _ioc_lock =0;
    551     _ioc_done =0;
    552 
    553     return ret;
     654                         unsigned int   count )
     655{
     656    return _ioc_access( 0,              // write
     657                        lba,
     658                        (unsigned int)buffer,
     659                        count );
    554660}
    555661
  • soft/giet_vm/sys/drivers.h

    r165 r166  
    1818extern volatile unsigned char _ioc_status;
    1919extern volatile unsigned char _ioc_done;
    20 extern volatile unsigned int _ioc_lock;
     20extern unsigned int          _ioc_lock;
    2121
    2222extern volatile unsigned char _tty_get_buf[];
  • soft/giet_vm/sys/hwr_mapping.h

    r158 r166  
    8686};
    8787
     88/* IOB */
     89enum IOB_registers {
     90    IOB_IOMMU_PTPR       = 0,   /* R/W : Page Table Pointer Register */
     91    IOB_IOMMU_ACTIVE     = 1,   /* R/W : IOMMU activated if not 0 */
     92    IOB_IOMMU_BVAR       = 2,   /* R   : Bad Virtual Address (unmapped) */
     93    IOB_IOMMU_ETR        = 3,   /* R   : Error Type */
     94    IOB_IOMMU_BAD_ID     = 4,   /* R   : Faulty Peripheral Index */
     95    IOB_INVAL_PTE        = 5,   /* W   : Invalidate a PTE (virtual address) */
     96    IOB_IT_ADDR_IOMMU_LO = 6,   /* W/R : 32 LSB bits for IOMMU IT*/
     97    IOB_IT_ADDR_IOMMU_HI = 7,   /* W/R : 32 MSB bits for IOMMU IT */
     98    IOB_IT_ADDRESS_BEGIN = 8,   /* R/W : Peripheral IT address (2 32 bits registers) */
     99};
     100
    88101#endif
    89102
  • soft/giet_vm/sys/kernel_init.c

    r165 r166  
    2222#include <mips32_registers.h>
    2323#include <irq_handler.h>
     24#include <vm_handler.h>
    2425#include <hwr_mapping.h>
    2526#include <mwmr_channel.h>
     
    523524
    524525////////////////////////////////////////////////////////////////////////////////
    525 // This function intializes the external periherals such as the TTY controller,
    526 // the IOC (external disk controller), the NIC (external network controller),
    527 // the FBDMA (frame buffer controller), etc.
     526// This function intializes the external periherals such as the IOB component
     527// (I/O bridge, containing the IOMMU, the IOC (external disk controller),
     528// the NIC (external network controller), the FBDMA (frame buffer controller),
    528529////////////////////////////////////////////////////////////////////////////////
    529530in_kinit void _kernel_peripherals_init()
    530531{
     532    // IOC peripheral initialisation
     533    // we simply activate the IOC interrupts...
     534    unsigned int*       ioc_address = (unsigned int*)&seg_ioc_base;
     535
     536    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
     537   
     538    // IOB peripheral
     539    if ( GIET_IOMMU_ACTIVE )
     540    {
     541        unsigned int*   iob_address = (unsigned int*)&seg_iob_base;
     542        unsigned int    icu_address = (unsigned int)&seg_icu_base;
     543
     544        // define IPI address mapping the IOC interrupt ...TODO...
     545
     546        // set IOMMU page table address
     547        iob_address[IOB_IOMMU_PTPR] = (unsigned int)(&_iommu_ptab);   
     548
     549        // activate IOMMU
     550        iob_address[IOB_IOMMU_ACTIVE] = 1;   
     551    }
     552
    531553    _puts("\n[INIT] Peripherals initialisation completed at cycle ");
    532554    _putw( _proctime() );
     
    536558
    537559////////////////////////////////////////////////////////////////////////////////
    538 // This function intialises the centralised interrupt vector,
    539 // and the ICUs mask registers for all processors in all clusters.
     560// This function intialises the interrupt vector, and initialises
     561// the ICU mask registers for all processors in all clusters.
    540562// It strongly depends on the actual peripheral hardware wiring.
    541563// In this peculiar version, all clusters are identical,
  • soft/giet_vm/sys/sys.ld

    r165 r166  
    2222seg_gcd_base            = 0x95000000;   /* GCD device */
    2323seg_fb_base             = 0x96000000;   /* FrameBuffer device */
    24 seg_icu_base            = 0x9F000000;   /* ICU device */
     24seg_icu_base            = 0x9F000000;   /* ICU or XICU device */
     25seg_iob_base            = 0x9E000000;   /* IOB device */
    2526
    2627/*
Note: See TracChangeset for help on using the changeset viewer.