X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86_64%2Fmm_virt.c;h=90c3721dc6d65690c32ddba1fcd61c321836e138;hb=3764c294f21229bdf700f436fa4884f5e76e0d3a;hp=8e5ef9c8c890c64648e754288bc3cfba56b8b6ad;hpb=be1e298482fe9343cdeebaee9f088e081970e2e3;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86_64/mm_virt.c b/Kernel/arch/x86_64/mm_virt.c index 8e5ef9c8..90c3721d 100644 --- a/Kernel/arch/x86_64/mm_virt.c +++ b/Kernel/arch/x86_64/mm_virt.c @@ -3,6 +3,7 @@ * * Virtual Memory Manager */ +#define DEBUG 0 #include #include #include @@ -22,6 +23,7 @@ #define PF_PRESENT 0x1 #define PF_WRITE 0x2 #define PF_USER 0x4 +#define PF_LARGE 0x0 #define PF_COW 0x200 #define PF_PAGED 0x400 #define PF_NX 0x80000000##00000000 @@ -36,16 +38,20 @@ // === PROTOTYPES === void MM_InitVirt(void); -void MM_FinishVirtualInit(void); +//void MM_FinishVirtualInit(void); void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs); void MM_DumpTables(tVAddr Start, tVAddr End); - int MM_Map(tVAddr VAddr, tPAddr PAddr); +// int MM_Map(tVAddr VAddr, tPAddr PAddr); +void MM_Unmap(tVAddr VAddr); +void MM_ClearUser(void); + int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags); // === GLOBALS === // === CODE === void MM_InitVirt(void) { + MM_DumpTables(0, -1L); } void MM_FinishVirtualInit(void) @@ -118,6 +124,10 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) // Error_Backtrace(Regs->RIP, Regs->RBP); MM_DumpTables(0, -1); + + __asm__ __volatile__ ("cli"); + for( ;; ) + HALT(); } /** @@ -132,11 +142,12 @@ void MM_DumpTables(tVAddr Start, tVAddr End) tVAddr curPos; Uint page; + Log("Table Entries: (%p to %p)", Start, End); + End &= (1L << 48) - 1; Start >>= 12; End >>= 12; - Log("Table Entries:"); for(page = Start, curPos = Start<<12; page < End; curPos += 0x1000, page++) @@ -144,6 +155,11 @@ void MM_DumpTables(tVAddr Start, tVAddr End) if( curPos == 0x800000000000L ) curPos = 0xFFFF800000000000L; + //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27)); + //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18)); + //Debug("&PAGEDIR(%i page>>9) = %p", page>>9, &PAGEDIR(page>>9)); + //Debug("&PAGETABLE(%i page) = %p", page, &PAGETABLE(page)); + // End of a range if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) @@ -167,16 +183,19 @@ void MM_DumpTables(tVAddr Start, tVAddr End) if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) ) { page += (1 << 27) - 1; curPos += (1L << 39) - 0x1000; + //Debug("pml4 ent unset (page = 0x%x now)", page); continue; } if( !(PAGEDIRPTR(page>>18) & PF_PRESENT) ) { page += (1 << 18) - 1; curPos += (1L << 30) - 0x1000; + //Debug("pdp ent unset (page = 0x%x now)", page); continue; } if( !(PAGEDIR(page>>9) & PF_PRESENT) ) { page += (1 << 9) - 1; curPos += (1L << 21) - 0x1000; + //Debug("pd ent unset (page = 0x%x now)", page); continue; } if( !(PAGETABLE(page) & PF_PRESENT) ) continue; @@ -209,18 +228,27 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr) { tPAddr tmp; - Log("MM_Map: (VAddr=0x%x, PAddr=0x%x)", VAddr, PAddr); + ENTER("xVAddr xPAddr", VAddr, PAddr); + + // Check that the page hasn't been mapped already + { + Uint flags; + int ret; + ret = MM_GetPageEntry(VAddr, &tmp, &flags); + if( flags & PF_PRESENT ) { + LEAVE('i', 0); + return 0; + } + } // Check PML4 - //Log(" MM_Map: &PAGEMAPLVL4(%x) = %x", VAddr >> 39, &PAGEMAPLVL4(VAddr >> 39)); - //Log(" MM_Map: &PAGEDIRPTR(%x) = %x", VAddr >> 30, &PAGEDIRPTR(VAddr >> 30)); - //Log(" MM_Map: &PAGEDIR(%x) = %x", VAddr >> 21, &PAGEDIR(VAddr >> 21)); - //Log(" MM_Map: &PAGETABLE(%x) = %x", VAddr >> 12, &PAGETABLE(VAddr >> 12)); - //Log(" MM_Map: &PAGETABLE(0) = %x", &PAGETABLE(0)); if( !(PAGEMAPLVL4(VAddr >> 39) & 1) ) { tmp = MM_AllocPhys(); - if(!tmp) return 0; + if(!tmp) { + LEAVE('i', 0); + return 0; + } PAGEMAPLVL4(VAddr >> 39) = tmp | 3; INVLPG( &PAGEDIRPTR( (VAddr>>39)<<9 ) ); memset( &PAGEDIRPTR( (VAddr>>39)<<9 ), 0, 4096 ); @@ -230,7 +258,10 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr) if( !(PAGEDIRPTR(VAddr >> 30) & 1) ) { tmp = MM_AllocPhys(); - if(!tmp) return 0; + if(!tmp) { + LEAVE('i', 0); + return 0; + } PAGEDIRPTR(VAddr >> 30) = tmp | 3; INVLPG( &PAGEDIR( (VAddr>>30)<<9 ) ); memset( &PAGEDIR( (VAddr>>30)<<9 ), 0, 0x1000 ); @@ -240,21 +271,26 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr) if( !(PAGEDIR(VAddr >> 21) & 1) ) { tmp = MM_AllocPhys(); - if(!tmp) return 0; + if(!tmp) { + LEAVE('i', 0); + return 0; + } PAGEDIR(VAddr >> 21) = tmp | 3; INVLPG( &PAGETABLE( (VAddr>>21)<<9 ) ); memset( &PAGETABLE( (VAddr>>21)<<9 ), 0, 4096 ); } // Check if this virtual address is already mapped - if( PAGETABLE(VAddr >> PTAB_SHIFT) & 1 ) + if( PAGETABLE(VAddr >> PTAB_SHIFT) & 1 ) { + LEAVE('i', 0); return 0; + } PAGETABLE(VAddr >> PTAB_SHIFT) = PAddr | 3; INVLPG( VAddr ); - Log("MM_Map: RETURN 1"); - + + LEAVE('i', 1); return 1; } @@ -281,19 +317,35 @@ tPAddr MM_Allocate(tVAddr VAddr) { tPAddr ret; - Log("MM_Allocate: (VAddr=%x)", VAddr); - Log("MM_Allocate: MM_AllocPhys()"); + ENTER("xVAddr", VAddr); + + // NOTE: This is hack, but I like my dumps to be neat + #if 1 + if( !MM_Map(VAddr, 0) ) // Make sure things are allocated + { + Warning("MM_Allocate: Unable to map, tables did not initialise"); + LEAVE('i', 0); + return 0; + } + MM_Unmap(VAddr); + #endif + ret = MM_AllocPhys(); - Log("MM_Allocate: ret = %x", ret); - if(!ret) return 0; + LOG("ret = %x", ret); + if(!ret) { + LEAVE('i', 0); + return 0; + } if( !MM_Map(VAddr, ret) ) { - Warning("MM_Allocate: Unable to map", ret); + Warning("MM_Allocate: Unable to map. Strange, we should have errored earlier"); MM_DerefPhys(ret); + LEAVE('i'); return 0; } + LEAVE('x', ret); return ret; } @@ -309,26 +361,79 @@ void MM_Deallocate(tVAddr VAddr) MM_DerefPhys(phys); } +/** + * \brief Get the page table entry of a virtual address + * \param Addr Virtual Address + * \param Phys Location to put the physical address + * \param Flags Flags on the entry (set to zero if unmapped) + * \return Size of the entry (in address bits) - 12 = 4KiB page + */ +int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags) +{ + if(!Phys || !Flags) return 0; + + // Check if the PML4 entry is present + if( !(PAGEMAPLVL4(Addr >> 39) & 1) ) { + *Phys = 0; + *Flags = 0; + return 39; + } + // - Check for large page + if( PAGEMAPLVL4(Addr >> 39) & PF_LARGE ) { + *Phys = PAGEMAPLVL4(Addr >> 39) & ~0xFFF; + *Flags = PAGEMAPLVL4(Addr >> 39) & 0xFFF; + return 39; + } + + // Check the PDP entry + if( !(PAGEDIRPTR(Addr >> 30) & 1) ) { + *Phys = 0; + *Flags = 0; + return 30; + } + // - Check for large page + if( PAGEDIRPTR(Addr >> 30) & PF_LARGE ) { + *Phys = PAGEDIRPTR(Addr >> 30) & ~0xFFF; + *Flags = PAGEDIRPTR(Addr >> 30) & 0xFFF; + return 30; + } + + // Check PDIR Entry + if( !(PAGEDIR(Addr >> 21) & 1) ) { + *Phys = 0; + *Flags = 0; + return 21; + } + // - Check for large page + if( PAGEDIR(Addr >> 21) & PF_LARGE ) { + *Phys = PAGEDIR(Addr >> 21) & ~0xFFF; + *Flags = PAGEDIR(Addr >> 21) & 0xFFF; + return 21; + } + + // And, check the page table entry + if( !(PAGETABLE(Addr >> PTAB_SHIFT) & 1) ) { + *Phys = 0; + *Flags = 0; + } + else { + *Phys = PAGETABLE(Addr >> PTAB_SHIFT) & ~0xFFF; + *Flags = PAGETABLE(Addr >> PTAB_SHIFT) & 0xFFF; + } + return 12; +} + /** * \brief Get the physical address of a virtual location */ tPAddr MM_GetPhysAddr(tVAddr Addr) { - Log("MM_GetPhysAddr: (Addr=0x%x)", Addr); - if( !(PAGEMAPLVL4(Addr >> 39) & 1) ) - return 0; - Log(" MM_GetPhysAddr: PDP Valid"); - if( !(PAGEDIRPTR(Addr >> 30) & 1) ) - return 0; - Log(" MM_GetPhysAddr: PD Valid"); - if( !(PAGEDIR(Addr >> 21) & 1) ) - return 0; - Log(" MM_GetPhysAddr: PT Valid"); - if( !(PAGETABLE(Addr >> PTAB_SHIFT) & 1) ) - return 0; - Log(" MM_GetPhysAddr: Page Valid"); + tPAddr ret; + Uint flags; + + MM_GetPageEntry(Addr, &ret, &flags); - return (PAGETABLE(Addr >> PTAB_SHIFT) & ~0xFFF) | (Addr & 0xFFF); + return ret | (Addr & 0xFFF); } /** @@ -472,6 +577,8 @@ tPAddr MM_Clone(void) ret = MM_AllocPhys(); if(!ret) return 0; + Log_KernelPanic("MM", "TODO: Implement MM_Clone"); + // #2 Alter the fractal pointer // #3 Set Copy-On-Write to all user pages // #4 Return @@ -533,10 +640,36 @@ void MM_ClearUser(void) tVAddr MM_NewWorkerStack(void) { + Log_KernelPanic("MM", "TODO: Implement MM_NewWorkerStack"); return 0; } +/** + * \brief Allocate a new kernel stack + */ tVAddr MM_NewKStack(void) { + tVAddr base = MM_KSTACK_BASE; + Uint i; + for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE ) + { + if(MM_GetPhysAddr(base) != 0) + continue; + + //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE); + for( i = 0; i < KERNEL_STACK_SIZE; i += 0x1000) + { + if( !MM_Allocate(base+i) ) + { + Log_Warning("MM", "MM_NewKStack - Allocation failed"); + for( i -= 0x1000; i; i -= 0x1000) + MM_Deallocate(base+i); + return 0; + } + } + + return base + KERNEL_STACK_SIZE; + } + Log_Warning("MM", "MM_NewKStack - No address space left\n"); return 0; }