X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fmm_virt.c;h=e2442ae10be60667897bb74ab726bbe527539712;hb=c5de7b08d4a82908a5acf6454fd7836bdab68715;hp=8902837c2f2fc6b8f4299f426d8d22d18be88c94;hpb=2d83a99f3202f0e4688b58405f67604a24420861;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c index 8902837c..e2442ae1 100644 --- a/Kernel/arch/x86/mm_virt.c +++ b/Kernel/arch/x86/mm_virt.c @@ -15,13 +15,9 @@ #include #include #include +#include -#if USE_PAE -# define TAB 21 -# define DIR 30 -#else -# define TAB 22 -#endif +#define TAB 22 #define KERNEL_STACKS 0xF0000000 #define KERNEL_STACK_SIZE 0x00008000 @@ -55,19 +51,16 @@ #define PF_PRESENT 0x1 #define PF_WRITE 0x2 #define PF_USER 0x4 +#define PF_GLOBAL 0x80 #define PF_COW 0x200 -#define PF_PAGED 0x400 +#define PF_NOPAGE 0x400 #define INVLPG(addr) __asm__ __volatile__ ("invlpg (%0)"::"r"(addr)) -#if USE_PAE -typedef Uint64 tTabEnt; -#else typedef Uint32 tTabEnt; -#endif // === IMPORTS === -extern void _UsertextEnd, _UsertextBase; +extern char _UsertextEnd[], _UsertextBase[]; extern Uint32 gaInitPageDir[1024]; extern Uint32 gaInitPageTable[1024]; extern void Threads_SegFault(tVAddr Addr); @@ -77,7 +70,8 @@ extern void Error_Backtrace(Uint eip, Uint ebp); void MM_PreinitVirtual(void); void MM_InstallVirtual(void); void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs); -void MM_DumpTables(tVAddr Start, tVAddr End); +//void MM_DumpTables(tVAddr Start, tVAddr End); +//void MM_ClearUser(void); tPAddr MM_DuplicatePage(tVAddr VAddr); // === GLOBALS === @@ -95,10 +89,17 @@ tPAddr MM_DuplicatePage(tVAddr VAddr); #define gaPAE_TmpDir ((tTabEnt*)PAE_TMP_DIR_ADDR) #define gaPAE_TmpPDPT ((tTabEnt*)PAE_TMP_PDPT_ADDR) int gbUsePAE = 0; - int gilTempMappings = 0; - int gilTempFractal = 0; +tMutex glTempMappings; +tMutex glTempFractal; Uint32 gWorkerStacks[(NUM_WORKER_STACKS+31)/32]; int giLastUsedWorker = 0; +struct sPageInfo { + void *Node; + tVAddr Base; + Uint64 Offset; + int Length; + int Flags; +} *gaMappedRegions; // sizeof = 24 bytes // === CODE === /** @@ -107,11 +108,7 @@ Uint32 gWorkerStacks[(NUM_WORKER_STACKS+31)/32]; */ void MM_PreinitVirtual(void) { - #if USE_PAE - gaInitPageDir[ ((PAGE_TABLE_ADDR >> TAB)-3*512+3)*2 ] = ((tTabEnt)&gaInitPageDir - KERNEL_BASE) | 3; - #else gaInitPageDir[ PAGE_TABLE_ADDR >> 22 ] = ((tTabEnt)&gaInitPageDir - KERNEL_BASE) | 3; - #endif INVLPG( PAGE_TABLE_ADDR ); } @@ -123,23 +120,6 @@ void MM_InstallVirtual(void) { int i; - #if USE_PAE - // --- Pre-Allocate kernel tables - for( i = KERNEL_BASE >> TAB; i < 1024*4; i ++ ) - { - if( gaPAE_PageDir[ i ] ) continue; - - // Skip stack tables, they are process unique - if( i > KERNEL_STACKS >> TAB && i < KERNEL_STACKS_END >> TAB) { - gaPAE_PageDir[ i ] = 0; - continue; - } - // Preallocate table - gaPAE_PageDir[ i ] = MM_AllocPhys() | 3; - INVLPG( &gaPAE_PageTable[i*512] ); - memset( &gaPAE_PageTable[i*512], 0, 0x1000 ); - } - #else // --- Pre-Allocate kernel tables for( i = KERNEL_BASE>>22; i < 1024; i ++ ) { @@ -154,7 +134,6 @@ void MM_InstallVirtual(void) INVLPG( &gaPageTable[i*1024] ); memset( &gaPageTable[i*1024], 0, 0x1000 ); } - #endif // Unset kernel on the User Text pages for( i = ((tVAddr)&_UsertextEnd-(tVAddr)&_UsertextBase+0xFFF)/4096; i--; ) { @@ -167,11 +146,7 @@ void MM_InstallVirtual(void) */ void MM_FinishVirtualInit(void) { - #if USE_PAE - gaInitPDPT[ 0 ] = 0; - #else gaInitPageDir[ 0 ] = 0; - #endif } /** @@ -183,8 +158,7 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) //ENTER("xAddr bErrorCode", Addr, ErrorCode); // -- Check for COW -- - if( gaPageDir [Addr>>22] & PF_PRESENT - && gaPageTable[Addr>>12] & PF_PRESENT + if( gaPageDir [Addr>>22] & PF_PRESENT && gaPageTable[Addr>>12] & PF_PRESENT && gaPageTable[Addr>>12] & PF_COW ) { tPAddr paddr; @@ -202,21 +176,27 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE; } +// Log_Debug("MMVirt", "COW for %p (%P)", Addr, gaPageTable[Addr>>12]); + INVLPG( Addr & ~0xFFF ); - //LEAVE('-') return; } + __asm__ __volatile__ ("pushf; andw $0xFEFF, 0(%esp); popf"); + Proc_GetCurThread()->bInstrTrace = 0; + // If it was a user, tell the thread handler if(ErrorCode & 4) { - Warning("%s %s %s memory%s", - (ErrorCode&4?"User":"Kernel"), + Log_Warning("MMVirt", "User %s %s memory%s", (ErrorCode&2?"write to":"read from"), (ErrorCode&1?"bad/locked":"non-present"), (ErrorCode&16?" (Instruction Fetch)":"") ); - Warning("User Pagefault: Instruction at %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr); + Log_Warning("MMVirt", "Instruction %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr); __asm__ __volatile__ ("sti"); // Restart IRQs + #if 1 + Error_Backtrace(Regs->eip, Regs->ebp); + #endif Threads_SegFault(Addr); return ; } @@ -228,8 +208,7 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) Warning("Reserved Bits Trashed!"); else { - Warning("%s %s %s memory%s", - (ErrorCode&4?"User":"Kernel"), + Warning("Kernel %s %s memory%s", (ErrorCode&2?"write to":"read from"), (ErrorCode&1?"bad/locked":"non-present"), (ErrorCode&16?" (Instruction Fetch)":"") @@ -270,9 +249,10 @@ void MM_DumpTables(tVAddr Start, tVAddr End) { tVAddr rangeStart = 0; tPAddr expected = 0; + void *expected_node = NULL, *tmpnode = NULL; tVAddr curPos; Uint page; - const tPAddr MASK = ~0xF98; + const tPAddr MASK = ~0xF78; Start >>= 12; End >>= 12; @@ -299,17 +279,21 @@ void MM_DumpTables(tVAddr Start, tVAddr End) { if( !(gaPageDir[curPos>>22] & PF_PRESENT) || !(gaPageTable[page] & PF_PRESENT) - || (gaPageTable[page] & MASK) != expected) + || (gaPageTable[page] & MASK) != expected + || (tmpnode=NULL,MM_GetPageNode(expected, &tmpnode), tmpnode != expected_node)) { if(expected) { - Log(" 0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)", - rangeStart, curPos - 1, - gaPageTable[rangeStart>>12] & ~0xFFF, - (expected & ~0xFFF) - 1, - (expected & PF_PAGED ? "p" : "-"), - (expected & PF_COW ? "C" : "-"), - (expected & PF_USER ? "U" : "-"), - (expected & PF_WRITE ? "W" : "-") + tPAddr orig = gaPageTable[rangeStart>>12]; + Log(" 0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s) %p", + rangeStart, + orig & ~0xFFF, + curPos - rangeStart, + (orig & PF_NOPAGE ? "P" : "-"), + (orig & PF_COW ? "C" : "-"), + (orig & PF_GLOBAL ? "G" : "-"), + (orig & PF_USER ? "U" : "-"), + (orig & PF_WRITE ? "W" : "-"), + expected_node ); expected = 0; } @@ -317,20 +301,24 @@ void MM_DumpTables(tVAddr Start, tVAddr End) if( !(gaPageTable[curPos>>12] & PF_PRESENT) ) continue; expected = (gaPageTable[page] & MASK); + MM_GetPageNode(expected, &expected_node); rangeStart = curPos; } if(expected) expected += 0x1000; } if(expected) { - Log("0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)", - rangeStart, curPos - 1, - gaPageTable[rangeStart>>12] & ~0xFFF, - (expected & ~0xFFF) - 1, - (expected & PF_PAGED ? "p" : "-"), - (expected & PF_COW ? "C" : "-"), - (expected & PF_USER ? "U" : "-"), - (expected & PF_WRITE ? "W" : "-") + tPAddr orig = gaPageTable[rangeStart>>12]; + Log("0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s) %p", + rangeStart, + orig & ~0xFFF, + curPos - rangeStart, + (orig & PF_NOPAGE ? "p" : "-"), + (orig & PF_COW ? "C" : "-"), + (orig & PF_GLOBAL ? "G" : "-"), + (orig & PF_USER ? "U" : "-"), + (orig & PF_WRITE ? "W" : "-"), + expected_node ); expected = 0; } @@ -349,19 +337,16 @@ tPAddr MM_Allocate(tVAddr VAddr) { // Allocate directory paddr = MM_AllocPhys(); - //LOG("paddr = 0x%llx (new table)", paddr); if( paddr == 0 ) { Warning("MM_Allocate - Out of Memory (Called by %p)", __builtin_return_address(0)); //LEAVE('i',0); return 0; } - // Map + // Map and mark as user (if needed) gaPageDir[ VAddr >> 22 ] = paddr | 3; - // Mark as user if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER; INVLPG( &gaPageDir[ VAddr >> 22 ] ); - //LOG("Clearing new table"); memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 ); } // Check if the page is already allocated @@ -454,7 +439,10 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr) // Check if the directory is mapped if( gaPageDir[ VAddr >> 22 ] == 0 ) { - gaPageDir[ VAddr >> 22 ] = MM_AllocPhys() | 3; + tPAddr tmp = MM_AllocPhys(); + if( tmp == 0 ) + return 0; + gaPageDir[ VAddr >> 22 ] = tmp | 3; // Mark as user if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER; @@ -488,14 +476,12 @@ int MM_Map(tVAddr VAddr, tPAddr PAddr) } /** - * \fn tVAddr MM_ClearUser() * \brief Clear user's address space */ -tVAddr MM_ClearUser(void) +void MM_ClearUser(void) { Uint i, j; - // Copy Directories for( i = 0; i < (MM_USER_MAX>>22); i ++ ) { // Check if directory is not allocated @@ -504,7 +490,7 @@ tVAddr MM_ClearUser(void) continue; } - + // Deallocate tables for( j = 0; j < 1024; j ++ ) { if( gaPageTable[i*1024+j] & 1 ) @@ -512,13 +498,12 @@ tVAddr MM_ClearUser(void) gaPageTable[i*1024+j] = 0; } + // Deallocate directory MM_DerefPhys( gaPageDir[i] & ~0xFFF ); gaPageDir[i] = 0; INVLPG( &gaPageTable[i*1024] ); } INVLPG( gaPageDir ); - - return *gpPageCR3; } /** @@ -533,45 +518,52 @@ tPAddr MM_Clone(void) tVAddr kStackBase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE; void *tmp; - LOCK( &gilTempFractal ); + Mutex_Acquire( &glTempFractal ); // Create Directory Table *gpTmpCR3 = MM_AllocPhys() | 3; + if( *gpTmpCR3 == 3 ) { + *gpTmpCR3 = 0; + return 0; + } INVLPG( gaTmpDir ); //LOG("Allocated Directory (%x)", *gpTmpCR3); memsetd( gaTmpDir, 0, 1024 ); - // Copy Tables - for( i = 0; i < 768; i ++) - { - // Check if table is allocated - if( !(gaPageDir[i] & PF_PRESENT) ) { - gaTmpDir[i] = 0; - page += 1024; - continue; - } - - // Allocate new table - gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7); - INVLPG( &gaTmpTable[page] ); - // Fill - for( j = 0; j < 1024; j ++, page++ ) + if( Threads_GetPID() != 0 ) + { + // Copy Tables + for( i = 0; i < 768; i ++) { - if( !(gaPageTable[page] & PF_PRESENT) ) { - gaTmpTable[page] = 0; + // Check if table is allocated + if( !(gaPageDir[i] & PF_PRESENT) ) { + gaTmpDir[i] = 0; + page += 1024; continue; } - // Refrence old page - MM_RefPhys( gaPageTable[page] & ~0xFFF ); - // Add to new table - if(gaPageTable[page] & PF_WRITE) { - gaTmpTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW; - gaPageTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW; - INVLPG( page << 12 ); + // Allocate new table + gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7); + INVLPG( &gaTmpTable[page] ); + // Fill + for( j = 0; j < 1024; j ++, page++ ) + { + if( !(gaPageTable[page] & PF_PRESENT) ) { + gaTmpTable[page] = 0; + continue; + } + + // Refrence old page + MM_RefPhys( gaPageTable[page] & ~0xFFF ); + // Add to new table + if(gaPageTable[page] & PF_WRITE) { + gaTmpTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW; + gaPageTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW; + INVLPG( page << 12 ); + } + else + gaTmpTable[page] = gaPageTable[page]; } - else - gaTmpTable[page] = gaPageTable[page]; } } @@ -641,7 +633,7 @@ tPAddr MM_Clone(void) } ret = *gpTmpCR3 & ~0xFFF; - RELEASE( &gilTempFractal ); + Mutex_Release( &glTempFractal ); //LEAVE('x', ret); return ret; @@ -653,17 +645,32 @@ tPAddr MM_Clone(void) */ tVAddr MM_NewKStack(void) { - tVAddr base = KERNEL_STACKS; + tVAddr base; Uint i; - for(;base>12]; - - // Get the old ESP and EBP - __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp)); - __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp)); + tVAddr tmpPage; + tPAddr page; + // TODO: Thread safety // Find a free worker stack address for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++) { @@ -713,7 +714,7 @@ tVAddr MM_NewWorkerStack() //Log(" MM_NewWorkerStack: base = 0x%x", base); // Acquire the lock for the temp fractal mappings - LOCK(&gilTempFractal); + Mutex_Acquire(&glTempFractal); // Set the temp fractals to TID0's address space *gpTmpCR3 = ((Uint)gaInitPageDir - KERNEL_BASE) | 3; @@ -732,42 +733,21 @@ tVAddr MM_NewWorkerStack() // Mapping Time! for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 ) { - pages[ addr >> 12 ] = MM_AllocPhys(); - gaTmpTable[ (base + addr) >> 12 ] = pages[addr>>12] | 3; + page = MM_AllocPhys(); + gaTmpTable[ (base + addr) >> 12 ] = page | 3; } *gpTmpCR3 = 0; // Release the temp mapping lock - RELEASE(&gilTempFractal); - - // Copy the old stack - oldstack = (esp + KERNEL_STACK_SIZE-1) & ~(KERNEL_STACK_SIZE-1); - esp = oldstack - esp; // ESP as an offset in the stack - - // Make `base` be the top of the stack - base += WORKER_STACK_SIZE; - - i = (WORKER_STACK_SIZE>>12) - 1; - // Copy the contents of the old stack to the new one, altering the addresses - // `addr` is refering to bytes from the stack base (mem downwards) - for(addr = 0; addr < esp; addr += 0x1000) - { - Uint *stack = (Uint*)( oldstack-(addr+0x1000) ); - tmpPage = (void*)MM_MapTemp( pages[i] ); - // Copy old stack - for(j = 0; j < 1024; j++) - { - // Possible Stack address? - if(oldstack-esp < stack[j] && stack[j] < oldstack) - tmpPage[j] = base - (oldstack - stack[j]); - else // Seems not, best leave it alone - tmpPage[j] = stack[j]; - } - MM_FreeTemp((tVAddr)tmpPage); - i --; - } + Mutex_Release(&glTempFractal); + + // NOTE: Max of 1 page + // `page` is the last allocated page from the previious for loop + tmpPage = MM_MapTemp( page ); + memcpy( (void*)( tmpPage + (0x1000 - ContentsSize) ), StackContents, ContentsSize); + MM_FreeTemp(tmpPage); //Log("MM_NewWorkerStack: RETURN 0x%x", base); - return base; + return base + WORKER_STACK_SIZE; } /** @@ -847,6 +827,45 @@ Uint MM_GetFlags(tVAddr VAddr) return ret; } +/** + * \brief Check if the provided buffer is valid + * \return Boolean valid + */ +int MM_IsValidBuffer(tVAddr Addr, size_t Size) +{ + int bIsUser; + int dir, tab; + + Size += Addr & (PAGE_SIZE-1); + Addr &= ~(PAGE_SIZE-1); + + dir = Addr >> 22; + tab = Addr >> 12; + +// Debug("Addr = %p, Size = 0x%x, dir = %i, tab = %i", Addr, Size, dir, tab); + + if( !(gaPageDir[dir] & 1) ) return 0; + if( !(gaPageTable[tab] & 1) ) return 0; + + bIsUser = !!(gaPageTable[tab] & PF_USER); + + while( Size >= PAGE_SIZE ) + { + if( (tab & 1023) == 0 ) + { + dir ++; + if( !(gaPageDir[dir] & 1) ) return 0; + } + + if( !(gaPageTable[tab] & 1) ) return 0; + if( bIsUser && !(gaPageTable[tab] & PF_USER) ) return 0; + + tab ++; + Size -= PAGE_SIZE; + } + return 1; +} + /** * \fn tPAddr MM_DuplicatePage(tVAddr VAddr) * \brief Duplicates a virtual page to a physical one @@ -868,6 +887,9 @@ tPAddr MM_DuplicatePage(tVAddr VAddr) // Allocate new page ret = MM_AllocPhys(); + if( !ret ) { + return 0; + } // Write-lock the page (to keep data constistent), saving its R/W state wasRO = (gaPageTable[VAddr >> 12] & PF_WRITE ? 0 : 1); @@ -900,11 +922,11 @@ tVAddr MM_MapTemp(tPAddr PAddr) PAddr &= ~0xFFF; - //LOG("gilTempMappings = %i", gilTempMappings); + //LOG("glTempMappings = %i", glTempMappings); for(;;) { - LOCK( &gilTempMappings ); + Mutex_Acquire( &glTempMappings ); for( i = 0; i < NUM_TEMP_PAGES; i ++ ) { @@ -914,11 +936,11 @@ tVAddr MM_MapTemp(tPAddr PAddr) gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] = PAddr | 3; INVLPG( TEMP_MAP_ADDR + (i << 12) ); //LEAVE('p', TEMP_MAP_ADDR + (i << 12)); - RELEASE( &gilTempMappings ); + Mutex_Release( &glTempMappings ); return TEMP_MAP_ADDR + (i << 12); } - RELEASE( &gilTempMappings ); - Threads_Yield(); + Mutex_Release( &glTempMappings ); + Threads_Yield(); // TODO: Use a sleep queue here instead } } @@ -1004,6 +1026,10 @@ tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr) if(Pages == 1 && MaxBits >= PHYS_BITS) { phys = MM_AllocPhys(); + if( !phys ) { + *PhysAddr = 0; + LEAVE_RET('i', 0); + } *PhysAddr = phys; ret = MM_MapHWPages(phys, 1); if(ret == 0) { @@ -1053,8 +1079,7 @@ void MM_UnmapHWPages(tVAddr VAddr, Uint Number) i = VAddr >> 12; - LOCK( &gilTempMappings ); // Temp and HW share a directory, so they share a lock - + Mutex_Acquire( &glTempMappings ); // Temp and HW share a directory, so they share a lock for( j = 0; j < Number; j++ ) { @@ -1062,13 +1087,6 @@ void MM_UnmapHWPages(tVAddr VAddr, Uint Number) gaPageTable[ i + j ] = 0; } - RELEASE( &gilTempMappings ); + Mutex_Release( &glTempMappings ); } -// --- EXPORTS --- -EXPORT(MM_GetPhysAddr); -EXPORT(MM_Map); -//EXPORT(MM_Unmap); -EXPORT(MM_MapHWPages); -EXPORT(MM_AllocDMA); -EXPORT(MM_UnmapHWPages);