/////////////////////////////////////////////////////////////////////////////////// // File : vmem.c // Date : 01/07/2012 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// // The vmem.c and vmem.h files are part ot the GIET-VM nano kernel. // They contain the kernel data structures and functions used to dynamically // handle the paged virtual memory. /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////// // Global variable : IOMMU page table ///////////////////////////////////////////////////////////////////////////// __attribute__((section (".iommu"))) page_table_t _iommu_ptab; ////////////////////////////////////////////////////////////////////////////// // _iommu_add_pte2() ////////////////////////////////////////////////////////////////////////////// void _iommu_add_pte2( unsigned int ix1, unsigned int ix2, unsigned int ppn, unsigned int flags ) { unsigned int ptba; unsigned int * pt_ppn; unsigned int * pt_flags; // get pointer on iommu page table page_table_t * pt = &_iommu_ptab; // get ptba and update PT2 if ((pt->pt1[ix1] & PTE_V) == 0) { _printf("\n[GIET ERROR] in iommu_add_pte2() : " "IOMMU PT1 entry not mapped / ix1 = %d\n", ix1 ); _exit(); } else { ptba = pt->pt1[ix1] << 12; pt_flags = (unsigned int *) (ptba + 8 * ix2); pt_ppn = (unsigned int *) (ptba + 8 * ix2 + 4); *pt_flags = flags; *pt_ppn = ppn; } } // end _iommu_add_pte2() ////////////////////////////////////////////////////////////////////////////// // _iommu_inval_pte2() ////////////////////////////////////////////////////////////////////////////// void _iommu_inval_pte2( unsigned int ix1, unsigned int ix2 ) { unsigned int ptba; unsigned int * pt_flags; // get pointer on iommu page table page_table_t * pt = &_iommu_ptab; // get ptba and inval PTE2 if ((pt->pt1[ix1] & PTE_V) == 0) { _printf("\n[GIET ERROR] in iommu_inval_pte2() " "IOMMU PT1 entry not mapped / ix1 = %d\n", ix1 ); _exit(); } else { ptba = pt->pt1[ix1] << 12; pt_flags = (unsigned int *) (ptba + 8 * ix2); *pt_flags = 0; } } // end _iommu_inval_pte2() ////////////////////////////////////////////////////////////////////////////// // This function makes a "vpn" to "ppn" translation, from the page table // defined by the virtual address "pt". The MMU is supposed to be activated. // It uses the address extension mechanism for physical addressing. // Return 0 if success. Return 1 if PTE1 or PTE2 unmapped. ////////////////////////////////////////////////////////////////////////////// unsigned int _v2p_translate( page_table_t* pt, unsigned int vpn, unsigned int* ppn, unsigned int* flags ) { unsigned long long ptba; unsigned long long pte2_paddr; register unsigned int pte2_msb; register unsigned int pte2_lsb; register unsigned int flags_value; register unsigned int ppn_value; unsigned int ix1 = vpn >> 9; unsigned int ix2 = vpn & 0x1FF; // get PTE1 unsigned int pte1 = pt->pt1[ix1]; // check PTE1 mapping if ( (pte1 & PTE_V) == 0 ) return 1; // get physical addresses of pte2 (two 32 bits words) ptba = (unsigned long long) (pt->pt1[ix1] & 0x0FFFFFFF) << 12; pte2_paddr = ptba + 8*ix2; pte2_lsb = (unsigned int) pte2_paddr; pte2_msb = (unsigned int) (pte2_paddr >> 32); // gets ppn_value and flags_value, after temporary DTLB desactivation asm volatile ( "li $2, 0xFFFFFFFE \n" /* Mask for IE bits */ "mfc0 $4, $12 \n" /* $4 <= SR */ "and $2, $2, $4 \n" "mtc0 $2, $12 \n" /* disable Interrupts */ "li $3, 0xB \n" "mtc2 $3, $1 \n" /* DTLB unactivated */ "mtc2 %2, $24 \n" /* PADDR_EXT <= msb */ "lw %0, 0(%3) \n" /* read flags */ "lw %1, 4(%3) \n" /* read ppn */ "mtc2 $0, $24 \n" /* PADDR_EXT <= 0 */ "li $3, 0xF \n" "mtc2 $3, $1 \n" /* DTLB activated */ "mtc0 $4, $12 \n" /* restore SR */ : "=r" (flags_value), "=r" (ppn_value) : "r" (pte2_msb), "r" (pte2_lsb) : "$2","$3","$4"); // check PTE2 mapping if ( (flags_value & PTE_V) == 0 ) return 1; // set return values *ppn = ppn_value; *flags = flags_value; return 0; } // end _v2p_translate() // 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