/////////////////////////////////////////////////////////////////////////////////// // File : vmem.c // Date : 01/07/2012 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////////// // Extern global variables (allocated in boot.c or kernel_init.c) ////////////////////////////////////////////////////////////////////////////////// extern spin_lock_t _ptabs_spin_lock[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE]; extern unsigned long long _ptabs_paddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE]; extern unsigned int _ptabs_next_pt2[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE]; extern unsigned int _ptabs_max_pt2; /////////////////////////////////////////////////////// unsigned long long _v2p_translate( unsigned int vaddr, unsigned int* flags ) { unsigned long long ptba; unsigned long long pte2_paddr; unsigned int pte2_msb; unsigned int pte2_lsb; unsigned int flags_value; unsigned int ppn_value; unsigned int save_sr; // decode the vaddr fields unsigned int offset = vaddr & 0xFFF; unsigned int ix1 = (vaddr >> 21) & 0x7FF; unsigned int ix2 = (vaddr >> 12) & 0x1FF; // get page table vbase address page_table_t* pt = (page_table_t*)_get_context_slot(CTX_PTAB_ID); // get PTE1 unsigned int pte1 = pt->pt1[ix1]; // check PTE1 mapping if ( (pte1 & PTE_V) == 0 ) { _printf("\n[VMEM ERROR] _v2p_translate() : pte1 unmapped\n" " vaddr = %x / ptab = %x / pte1_vaddr = %x / pte1_value = %x\n", vaddr , (unsigned int)pt, &(pt->pt1[ix1]) , pte1 ); _exit(); } // test big/small page if ( (pte1 & PTE_T) == 0 ) // big page { *flags = pte1 & 0xFFC00000; offset = offset | (ix2<<12); return (((unsigned long long)(pte1 & 0x7FFFF)) << 21) | offset; } else // small page { // get physical addresses of pte2 ptba = ((unsigned long long)(pte1 & 0x0FFFFFFF)) << 12; pte2_paddr = ptba + 8*ix2; // split physical address in two 32 bits words pte2_lsb = (unsigned int) pte2_paddr; pte2_msb = (unsigned int) (pte2_paddr >> 32); // disable interrupts and save status register _it_disable( &save_sr ); // get ppn_value and flags_value, using a physical read // after temporary DTLB desactivation asm volatile ( "mfc2 $2, $1 \n" /* $2 <= MMU_MODE */ "andi $3, $2, 0xb \n" "mtc2 $3, $1 \n" /* DTLB off */ "move $4, %3 \n" /* $4 <= pte_lsb */ "mtc2 %2, $24 \n" /* PADDR_EXT <= pte_msb */ "lw %0, 0($4) \n" /* read flags */ "lw %1, 4($4) \n" /* read ppn */ "mtc2 $0, $24 \n" /* PADDR_EXT <= 0 */ "mtc2 $2, $1 \n" /* restore MMU_MODE */ : "=r" (flags_value), "=r" (ppn_value) : "r" (pte2_msb) , "r" (pte2_lsb) : "$2", "$3", "$4" ); // restore saved status register _it_restore( &save_sr ); // check PTE2 mapping if ( (flags_value & PTE_V) == 0 ) { _printf("\n[VMEM ERROR] _v2p_translate() : pte2 unmapped\n" " vaddr = %x / ptab = %x / pte1_value = %x\n" " pte2_paddr = %l / ppn = %x / flags = %x\n", vaddr , pt , pte1 , pte2_paddr , ppn_value , flags_value ); _exit(); } *flags = flags_value & 0xFFC00000; return (((unsigned long long)(ppn_value & 0x0FFFFFFF)) << 12) | offset; } } // end _v2p_translate() //////////////////////////////////////////// void _v2p_add_pte1( unsigned int vspace_id, unsigned int x, unsigned int y, unsigned int vpn, // 20 bits right-justified unsigned int flags, // 10 bits left-justified unsigned int ppn, // 28 bits right-justified unsigned int ident ) // identity mapping if non zero { unsigned int pte1; // PTE1 value paddr_t paddr; // PTE1 physical address // compute index in PT1 unsigned int ix1 = vpn >> 9; // 11 bits for ix1 // get PT1 physical base address paddr_t pt1_base = _ptabs_paddr[vspace_id][x][y]; if ( pt1_base == 0 ) { _printf("\n[GIET ERROR] in _v2p_add_pte1() : no PTAB in cluster[%d,%d]" " containing processors\n", x , y ); _exit(); } // get lock protecting PTAB[vspace_id][x][y] _spin_lock_acquire( &_ptabs_spin_lock[vspace_id][x][y] ); // compute pte1 physical address paddr = pt1_base + 4*ix1; // check PTE1 not already mapped if ( ident == 0 ) { if ( _physical_read( paddr ) & PTE_V ) { _printf("\n[GIET ERROR] in _v2p_add_pte1() : vpn %x already mapped " "in PTAB[%d,%d] for vspace %d\n", vpn , x , y , vspace_id ); _spin_lock_release( &_ptabs_spin_lock[vspace_id][x][y] ); _exit(); } } // compute pte1 : 2 bits V T / 8 bits flags / 3 bits RSVD / 19 bits bppi pte1 = PTE_V | (flags & 0x3FC00000) | ((ppn>>9) & 0x0007FFFF); // write pte1 in PT1 _physical_write( paddr , pte1 ); // release lock protecting PTAB[vspace_id][x][y] _spin_lock_release( &_ptabs_spin_lock[vspace_id][x][y] ); asm volatile ("sync"); } // end _v2p_add_pte1() /////////////////////////////////////////// void _v2p_add_pte2( unsigned int vspace_id, unsigned int x, unsigned int y, unsigned int vpn, // 20 bits right-justified unsigned int flags, // 10 bits left-justified unsigned int ppn, // 28 bits right-justified unsigned int ident ) // identity mapping if non zero { unsigned int ix1; unsigned int ix2; paddr_t pt2_pbase; // PT2 physical base address paddr_t pte2_paddr; // PTE2 physical address unsigned int pt2_id; // PT2 index unsigned int ptd; // PTD : entry in PT1 ix1 = vpn >> 9; // 11 bits for ix1 ix2 = vpn & 0x1FF; // 9 bits for ix2 // get page table physical base address paddr_t pt1_pbase = _ptabs_paddr[vspace_id][x][y]; if ( pt1_pbase == 0 ) { _printf("\n[GIET ERROR] in _v2p_add_pte2() : no PTAB for vspace %d " "in cluster[%d,%d]\n", vspace_id , x , y ); _exit(); } // get lock protecting PTAB[vspace_id][x][y] _spin_lock_acquire( &_ptabs_spin_lock[vspace_id][x][y] ); // get ptd in PT1 ptd = _physical_read( pt1_pbase + 4 * ix1 ); if ((ptd & PTE_V) == 0) // undefined PTD: compute PT2 base address, // and set a new PTD in PT1 { // get a new pt2_id pt2_id = _ptabs_next_pt2[vspace_id][x][y]; _ptabs_next_pt2[vspace_id][x][y] = pt2_id + 1; // check overflow if (pt2_id == _ptabs_max_pt2) { _printf("\n[GIET ERROR] in _v2p_add_pte2() : PTAB[%d,%d,%d]" " contains not enough PT2s\n", vspace_id, x, y ); _spin_lock_release( &_ptabs_spin_lock[vspace_id][x][y] ); _exit(); } pt2_pbase = pt1_pbase + PT1_SIZE + PT2_SIZE * pt2_id; ptd = PTE_V | PTE_T | (unsigned int) (pt2_pbase >> 12); // set PTD into PT1 _physical_write( pt1_pbase + 4*ix1, ptd); } else // valid PTD: compute PT2 base address { pt2_pbase = ((paddr_t)(ptd & 0x0FFFFFFF)) << 12; } // set PTE in PT2 : flags & PPN in two 32 bits words pte2_paddr = pt2_pbase + 8 * ix2; _physical_write(pte2_paddr , (PTE_V | flags) ); _physical_write(pte2_paddr + 4 , ppn ); // release lock protecting PTAB[vspace_id][x][y] _spin_lock_release( &_ptabs_spin_lock[vspace_id][x][y] ); asm volatile ("sync"); } // end _v2p_add_pte2() //////////////////////////////////////////// void _v2p_del_pte1( unsigned int vspace_id, unsigned int x, unsigned int y, unsigned int vpn ) // 20 bits right-justified { unsigned int ix1 = vpn >> 9; // 11 bits for ix1 // get page table physical base address paddr_t pt1_pbase = _ptabs_paddr[vspace_id][x][y]; // check PTAB defined if ( pt1_pbase == 0 ) { _printf("\n[GIET ERROR] in _v2p_del_pte1() : no PTAB for vspace %d " "in cluster[%d,%d]\n", vspace_id , x , y ); _exit(); } // get pte1 in PT1 paddr_t pte1_paddr = pt1_pbase + 4 * ix1; unsigned int pte1 = _physical_read( pte1_paddr ); // check pte1 valid if ((pte1 & PTE_V) == 0) { _printf("\n[GIET ERROR] in _v2p_del_pte1() : vpn %x not mapped in PT1" "for vspace %d in cluster[%d,%d]\n", vpn , vspace_id , x , y ); _exit(); } // invalidate PTE1 in PT1 _physical_write( pte1_paddr , 0 ); } // end _v2p_del_pte1() //////////////////////////////////////////// void _v2p_del_pte2( unsigned int vspace_id, unsigned int x, unsigned int y, unsigned int vpn ) // 20 bits right-justified { unsigned int ix1 = vpn >> 9; // 11 bits for ix1 unsigned int ix2 = vpn & 0x1FF; // 9 bits for ix2 // get page table physical base address paddr_t pt1_pbase = _ptabs_paddr[vspace_id][x][y]; // check PTAB defined if ( pt1_pbase == 0 ) { _printf("\n[GIET ERROR] in _v2p_del_pte2() : no PTAB for vspace %d " "in cluster[%d,%d]\n", vspace_id , x , y ); _exit(); } // get ptd in PT1 unsigned int ptd = _physical_read( pt1_pbase + 4 * ix1 ); // check ptd valid if ((ptd & PTE_V) == 0) { _printf("\n[GIET ERROR] in _v2p_del_pte2() : vpn %x not mapped in PT1" "for vspace %d in cluster[%d,%d]\n", vpn , vspace_id , x , y ); _exit(); } // get PT2 physical base address paddr_t pt2_pbase = ((paddr_t)(ptd & 0x0FFFFFFF)) << 12; // invalidate PTE in PT2 paddr_t pte2_paddr = pt2_pbase + 8 * ix2; _physical_write( pte2_paddr , 0 ); asm volatile ("sync"); } // end _v2p_del_pte2() // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4