X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fmm_virt.c;h=d7d1d81f948b50178e66faf479f7f8d38ccce2ff;hb=95a7eaaa4a1065334125b65130866f8d1048ddb7;hp=a022da2b9e9f92f24b414e520d1051eb2b7e11fa;hpb=df4e449c0972a703ce403332668a7bb3366d126a;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c index a022da2b..d7d1d81f 100644 --- a/Kernel/arch/x86/mm_virt.c +++ b/Kernel/arch/x86/mm_virt.c @@ -9,13 +9,18 @@ * 0xFE - Unused * 0xFF - System Calls / Kernel's User Code */ +#define DEBUG 1 #include #include #include -#define KERNEL_STACKS 0xF0000000 +#define KERNEL_STACKS 0xF0000000 #define KERNEL_STACK_SIZE 0x00002000 -#define KERNEL_STACK_END 0xFD000000 +#define KERNEL_STACKS_END 0xFD000000 +#define WORKER_STACKS 0x00100000 // Thread0 Only! +#define WORKER_STACK_SIZE KERNEL_STACK_SIZE +#define WORKER_STACKS_END 0xB0000000 +#define NUM_WORKER_STACKS ((WORKER_STACKS_END-WORKER_STACKS)/WORKER_STACK_SIZE) #define PAGE_TABLE_ADDR 0xFD000000 #define PAGE_DIR_ADDR 0xFD3F4000 #define PAGE_CR3_ADDR 0xFD3F4FD0 @@ -39,6 +44,8 @@ // === IMPORTS === extern Uint32 gaInitPageDir[1024]; extern Uint32 gaInitPageTable[1024]; +extern void Threads_SegFault(Uint Addr); +extern void Error_Backtrace(Uint eip, Uint ebp); // === PROTOTYPES === void MM_PreinitVirtual(); @@ -55,6 +62,9 @@ tPAddr *gaTmpTable = (void*)TMP_TABLE_ADDR; tPAddr *gaTmpDir = (void*)TMP_DIR_ADDR; tPAddr *gTmpCR3 = (void*)TMP_CR3_ADDR; int gilTempMappings = 0; + int gilTempFractal = 0; +Uint32 gWorkerStacks[NUM_WORKER_STACKS/32]; + int giLastUsedWorker = 0; // === CODE === /** @@ -80,7 +90,7 @@ void MM_InstallVirtual() { if( gaPageDir[ i ] ) continue; // Skip stack tables, they are process unique - if( i > KERNEL_STACKS >> 22 && i < KERNEL_STACK_END >> 22) { + if( i > KERNEL_STACKS >> 22 && i < KERNEL_STACKS_END >> 22) { gaPageDir[ i ] = 0; continue; } @@ -105,7 +115,7 @@ void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs) && gaPageTable[Addr>>12] & PF_COW ) { tPAddr paddr; - if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 0) + if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1) { gaPageTable[Addr>>12] &= ~PF_COW; gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE; @@ -117,11 +127,26 @@ void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs) gaPageTable[Addr>>12] &= PF_USER; gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE; } + INVLPG( Addr & ~0xFFF ); //LEAVE('-') return; } + // If it was a user, tell the thread handler + if(ErrorCode & 4) { + Warning("%s %s %s memory%s", + (ErrorCode&4?"User":"Kernel"), + (ErrorCode&2?"write to":"read from"), + (ErrorCode&1?"bad/locked":"non-present"), + (ErrorCode&16?" (Instruction Fetch)":"") + ); + Warning("User Pagefault: Instruction at %p accessed %p", Regs->eip, Addr); + __asm__ __volatile__ ("sti"); // Restart IRQs + Threads_SegFault(Addr); + return ; + } + // -- Check Error Code -- if(ErrorCode & 8) Warning("Reserved Bits Trashed!"); @@ -135,6 +160,10 @@ void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs) ); } + Log("Code at %p accessed %p", Regs->eip, Addr); + // Print Stack Backtrace + Error_Backtrace(Regs->eip, Regs->ebp); + Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]); if( gaPageDir[Addr>>22] & PF_PRESENT ) Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]); @@ -145,7 +174,7 @@ void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs) } /** - * \fn void MM_DumpTables(Uint Start, Uint End) + * \fn void MM_DumpTables(tVAddr Start, tVAddr End) * \brief Dumps the layout of the page tables */ void MM_DumpTables(tVAddr Start, tVAddr End) @@ -157,6 +186,24 @@ void MM_DumpTables(tVAddr Start, tVAddr End) const tPAddr MASK = ~0xF98; Start >>= 12; End >>= 12; + + #if 0 + Log("Directory Entries:"); + for(page = Start >> 10; + page < (End >> 10)+1; + page ++) + { + if(gaPageDir[page]) + { + Log(" 0x%08x-0x%08x :: 0x%08x", + page<<22, ((page+1)<<22)-1, + gaPageDir[page]&~0xFFF + ); + } + } + #endif + + Log("Table Entries:"); for(page = Start, curPos = Start<<12; page < End; curPos += 0x1000, page++) @@ -166,7 +213,7 @@ void MM_DumpTables(tVAddr Start, tVAddr End) || (gaPageTable[page] & MASK) != expected) { if(expected) { - Log("0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)", + Log(" 0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)", rangeStart, curPos - 1, gaPageTable[rangeStart>>12] & ~0xFFF, (expected & ~0xFFF) - 1, @@ -368,10 +415,12 @@ Uint MM_ClearUser() } MM_DerefPhys( gaPageDir[i] & ~0xFFF ); + gaPageDir[i] = 0; + INVLPG( &gaPageTable[i*1024] ); } + INVLPG( gaPageDir ); - - return *gTmpCR3; + return *gaPageCR3; } /** @@ -381,10 +430,12 @@ Uint MM_ClearUser() Uint MM_Clone() { Uint i, j; - Uint kStackBase = gCurrentThread->KernelStack - KERNEL_STACK_SIZE; + Uint ret; + Uint page = 0; + Uint kStackBase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE; void *tmp; - //ENTER(""); + LOCK( &gilTempFractal ); // Create Directory Table *gTmpCR3 = MM_AllocPhys() | 3; @@ -398,29 +449,31 @@ Uint MM_Clone() // 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[i*1024] ); + INVLPG( &gaTmpTable[page] ); // Fill - for( j = 0; j < 1024; j ++ ) + for( j = 0; j < 1024; j ++, page++ ) { - if( !(gaPageTable[i*1024+j] & PF_PRESENT) ) { - gaTmpTable[i*1024+j] = 0; + if( !(gaPageTable[page] & PF_PRESENT) ) { + gaTmpTable[page] = 0; continue; } // Refrence old page - MM_RefPhys( gaPageTable[i*1024+j] & ~0xFFF ); + MM_RefPhys( gaPageTable[page] & ~0xFFF ); // Add to new table - if(gaPageTable[i*1024+j] & PF_WRITE) { - gaTmpTable[i*1024+j] = (gaPageTable[i*1024+j] & ~PF_WRITE) | PF_COW; - gaPageTable[i*1024+j] = (gaPageTable[i*1024+j] & ~PF_WRITE) | PF_COW; + 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[i*1024+j] = gaPageTable[i*1024+j]; + gaTmpTable[page] = gaPageTable[page]; } } @@ -445,7 +498,7 @@ Uint MM_Clone() // Allocate kernel stack for(i = KERNEL_STACKS >> 22; - i < KERNEL_STACK_END >> 22; + i < KERNEL_STACKS_END >> 22; i ++ ) { // Check if directory is allocated @@ -489,8 +542,11 @@ Uint MM_Clone() } } - //LEAVE('x', *gTmpCR3 & ~0xFFF); - return *gTmpCR3 & ~0xFFF; + ret = *gTmpCR3 & ~0xFFF; + RELEASE( &gilTempFractal ); + + //LEAVE('x', ret); + return ret; } /** @@ -501,7 +557,7 @@ Uint MM_NewKStack() { Uint base = KERNEL_STACKS; 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)); + + // Find a free worker stack address + for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++) + { + // Used block + if( gWorkerStacks[base/32] == -1 ) { + base += 31; base &= ~31; + base --; // Counteracted by the base++ + continue; + } + // Used stack + if( gWorkerStacks[base/32] & (1 << base) ) { + continue; + } + } + if(base >= NUM_WORKER_STACKS) { + Warning("Uh-oh! Out of worker stacks"); + return 0; + } + + // It's ours now! + gWorkerStacks[base/32] |= (1 << base); + // Make life easier for later calls + giLastUsedWorker = base; + // We have one + base = WORKER_STACKS + base * WORKER_STACK_SIZE; + + // Acquire the lock for the temp fractal mappings + LOCK(&gilTempFractal); + + // Set the temp fractals to TID0's address space + *gTmpCR3 = (Uint)gaInitPageDir | 3; + INVLPG( gaTmpDir ); + + // Check if the directory is mapped (we are assuming that the stacks + // will fit neatly in a directory + if(gaTmpDir[ base >> 22 ] == 0) { + gaTmpDir[ base >> 22 ] = MM_AllocPhys() | 3; + INVLPG( &gaTmpTable[ (base>>22) & ~0x3FF ] ); + } + + // Mapping Time! + for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 ) + { + pages[ addr >> 12 ] = MM_AllocPhys(); + gaTmpTable[ (base + addr) >> 12 ] = pages[addr>>12] | 3; + } + // 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 + + 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((Uint)tmpPage); + i --; + } + + return base; +} + /** * \fn void MM_SetFlags(Uint VAddr, Uint Flags, Uint Mask) * \brief Sets the flags on a page @@ -621,7 +770,7 @@ Uint MM_MapTemp(tPAddr PAddr) return TEMP_MAP_ADDR + (i << 12); } RELEASE( &gilTempMappings ); - Proc_Yield(); + Threads_Yield(); } }