From 4573849f48a9b08173fcb30aee4f07efc30ab890 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 29 Jan 2012 22:46:06 +0800 Subject: [PATCH] Kernel/x86_64 - Updated to new threading changes, fixed some bugs --- Kernel/arch/x86_64/mm_virt.c | 92 +++++++++++++++++++++++++--------- Kernel/arch/x86_64/proc.asm | 28 +++-------- Kernel/arch/x86_64/proc.c | 73 +++++++++++++++------------ Kernel/arch/x86_64/start64.asm | 5 +- 4 files changed, 116 insertions(+), 82 deletions(-) diff --git a/Kernel/arch/x86_64/mm_virt.c b/Kernel/arch/x86_64/mm_virt.c index 511803cc..79513b94 100644 --- a/Kernel/arch/x86_64/mm_virt.c +++ b/Kernel/arch/x86_64/mm_virt.c @@ -10,6 +10,9 @@ #include #include +// === DEBUG OPTIONS === +#define TRACE_COW 0 + // === CONSTANTS === #define PHYS_BITS 52 // TODO: Move out #define VIRT_BITS 48 @@ -109,7 +112,9 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable { *Ent &= ~PF_COW; *Ent |= PF_PRESENT|PF_WRITE; + #if TRACE_COW Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage); + #endif } else { @@ -127,7 +132,9 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable memcpy( tmp, NextLevel, 0x1000 ); MM_FreeTemp( (tVAddr)tmp ); + #if TRACE_COW Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr); + #endif MM_DerefPhys( curpage ); *Ent &= PF_USER; @@ -271,8 +278,10 @@ void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected) LogF("%13s", "zero" ); else LogF("%13llx", PAGETABLE(RangeStart>>12) & PADDR_MASK ); - LogF(" : 0x%6llx (%c%c%c%c)\r\n", + LogF(" : 0x%6llx (%c%c%c%c%c%c)\r\n", Length, + (Expected & PF_GLOBAL ? 'G' : '-'), + (Expected & PF_NX ? '-' : 'x'), (Expected & PF_PAGED ? 'p' : '-'), (Expected & PF_COW ? 'C' : '-'), (Expected & PF_USER ? 'U' : '-'), @@ -286,13 +295,17 @@ void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected) */ void MM_DumpTables(tVAddr Start, tVAddr End) { - const tPAddr CHANGEABLE_BITS = ~(PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED) & 0xFFF; + const tPAddr FIXED_BITS = PF_PRESENT|PF_WRITE|PF_USER|PF_COW|PF_PAGED|PF_NX|PF_GLOBAL; + const tPAddr CHANGEABLE_BITS = ~FIXED_BITS & 0xFFF; const tPAddr MASK = ~CHANGEABLE_BITS; // Physical address and access bits tVAddr rangeStart = 0; tPAddr expected = CHANGEABLE_BITS; // CHANGEABLE_BITS is used because it's not a vaild value tVAddr curPos; Uint page; - + tPAddr expected_pml4 = PF_WRITE|PF_USER; + tPAddr expected_pdp = PF_WRITE|PF_USER; + tPAddr expected_pd = PF_WRITE|PF_USER; + Log("Table Entries: (%p to %p)", Start, End); End &= (1L << 48) - 1; @@ -310,13 +323,26 @@ void MM_DumpTables(tVAddr Start, tVAddr End) // End of a range if(!(PAGEMAPLVL4(page>>27) & PF_PRESENT) + || (PAGEMAPLVL4(page>>27) & FIXED_BITS) != expected_pml4 || !(PAGEDIRPTR(page>>18) & PF_PRESENT) + || (PAGEDIRPTR(page>>18) & FIXED_BITS) != expected_pdp || !(PAGEDIR(page>>9) & PF_PRESENT) + || (PAGEDIR(page>>9) & FIXED_BITS) != expected_pd || !(PAGETABLE(page) & PF_PRESENT) - || (PAGETABLE(page) & MASK) != expected) + || (PAGETABLE(page) & MASK) != expected) { if(expected != CHANGEABLE_BITS) { + // Merge + expected &= expected_pml4 | ~(PF_WRITE|PF_USER); + expected &= expected_pdp | ~(PF_WRITE|PF_USER); + expected &= expected_pd | ~(PF_WRITE|PF_USER); + expected |= expected_pml4 & PF_NX; + expected |= expected_pdp & PF_NX; + expected |= expected_pd & PF_NX; + Log("expected (pml4 = %x, pdp = %x, pd = %x)", + expected_pml4, expected_pdp, expected_pd); + // Dump MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected ); expected = CHANGEABLE_BITS; } @@ -342,6 +368,9 @@ void MM_DumpTables(tVAddr Start, tVAddr End) if( !(PAGETABLE(page) & PF_PRESENT) ) continue; expected = (PAGETABLE(page) & MASK); + expected_pml4 = (PAGEMAPLVL4(page>>27) & FIXED_BITS); + expected_pdp = (PAGEDIRPTR (page>>18) & FIXED_BITS); + expected_pd = (PAGEDIR (page>> 9) & FIXED_BITS); rangeStart = curPos; } if(gMM_ZeroPage && (expected & PADDR_MASK) == gMM_ZeroPage ) @@ -351,6 +380,9 @@ void MM_DumpTables(tVAddr Start, tVAddr End) } if(expected != CHANGEABLE_BITS) { + // Merge + + // Dump MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected ); expected = 0; } @@ -413,8 +445,8 @@ int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, *ent |= PF_USER; INVLPG( &pmlevels[i+1][ (Addr>>size)*512 ] ); memset( &pmlevels[i+1][ (Addr>>size)*512 ], 0, 0x1000 ); - LOG("Init PML%i ent 0x%x %p with %P", 4 - i, - Addr>>size, (Addr>>size) << size, tmp); + LOG("Init PML%i ent 0x%x %p with %P (*ent = %P)", 4 - i, + Addr>>size, (Addr>>size) << size, tmp, *ent); } // Catch large pages else if( *ent & PF_LARGE ) @@ -633,6 +665,7 @@ void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask) if( Flags & MM_PFLAG_COW ) { *ent &= ~PF_WRITE; *ent |= PF_COW; + INVLPG_ALL(); } else { *ent &= ~PF_COW; @@ -875,18 +908,21 @@ tPAddr MM_Clone(void) INVLPG_ALL(); // #3 Set Copy-On-Write to all user pages - for( i = 0; i < 256; i ++) + if( Threads_GetPID() != 0 ) { - if( PAGEMAPLVL4(i) & PF_WRITE ) { - PAGEMAPLVL4(i) |= PF_COW; - PAGEMAPLVL4(i) &= ~PF_WRITE; + for( i = 0; i < 256; i ++) + { + if( PAGEMAPLVL4(i) & PF_WRITE ) { + PAGEMAPLVL4(i) |= PF_COW; + PAGEMAPLVL4(i) &= ~PF_WRITE; + } + + TMPMAPLVL4(i) = PAGEMAPLVL4(i); +// Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i)); + if( !(TMPMAPLVL4(i) & PF_PRESENT) ) continue ; + + MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK ); } - - TMPMAPLVL4(i) = PAGEMAPLVL4(i); -// Log_Debug("MM", "TMPMAPLVL4(%i) = 0x%016llx", i, TMPMAPLVL4(i)); - if( !(TMPMAPLVL4(i) & PF_PRESENT) ) continue ; - - MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK ); } // #4 Map in kernel pages @@ -981,11 +1017,13 @@ void MM_ClearUser(void) tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize) { tVAddr ret; + tPAddr phys; int i; // #1 Set temp fractal to PID0 Mutex_Acquire(&glMM_TempFractalLock); TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3; + INVLPG_ALL(); // #2 Scan for a free stack addresss < 2^47 for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE) @@ -1000,31 +1038,35 @@ tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize) } // #3 Map all save the last page in the range - // - This acts as as guard page, and doesn't cost us anything. + // - This acts as as guard page + MM_GetPageEntryPtr(ret, 1, 1, 0, NULL); // Make sure tree is allocated for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ ) { - tPAddr phys = MM_AllocPhys(); + phys = MM_AllocPhys(); if(!phys) { // TODO: Clean up Log_Error("MM", "MM_NewWorkerStack - Unable to allocate page"); return 0; } MM_MapEx(ret + i*0x1000, phys, 1, 0); + MM_SetFlags(ret + i*0x1000, MM_PFLAG_KERNEL|MM_PFLAG_RO, MM_PFLAG_KERNEL); } + // Copy data if( StackSize > 0x1000 ) { Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize); } else { - tPAddr *ptr, paddr; - tVAddr tmp_addr; - MM_GetPageEntryPtr(ret + i*0x1000, 1, 0, 0, &ptr); - paddr = *ptr & ~0xFFF; - tmp_addr = MM_MapTemp(paddr); - memcpy( (void*)(tmp_addr + (0x1000 - StackSize)), StackData, StackSize ); + tVAddr tmp_addr, dest; + tmp_addr = MM_MapTemp(phys); + dest = tmp_addr + (0x1000 - StackSize); + memcpy( (void*)dest, StackData, StackSize ); + Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i); + Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret); MM_FreeTemp(tmp_addr); } - + + TMPCR3() = 0; Mutex_Release(&glMM_TempFractalLock); return ret + i*0x1000; diff --git a/Kernel/arch/x86_64/proc.asm b/Kernel/arch/x86_64/proc.asm index db22a162..f540b3b6 100644 --- a/Kernel/arch/x86_64/proc.asm +++ b/Kernel/arch/x86_64/proc.asm @@ -14,29 +14,14 @@ GetRIP: [global NewTaskHeader] NewTaskHeader: - mov rax, [rsp] - mov dr0, rax - - sti - mov al, 0x20 - mov dx, 0x20 - out dx, al + ; [rsp+0x00]: Thread + ; [rsp+0x08]: Function + ; [rsp+0x10]: Argument - mov rdi, [rsp+0x18] - dec QWORD [rsp+0x10] - jz .call - mov rsi, [rsp+0x20] - dec QWORD [rsp+0x10] - jz .call - mov rdx, [rsp+0x28] - dec QWORD [rsp+0x10] - jz .call - mov rcx, [rsp+0x30] - dec QWORD [rsp+0x10] - jz .call -.call: + mov rdi, [rsp+0x10] mov rax, [rsp+0x8] -; xchg bx, bx + add rsp, 0x10 ; Reclaim stack space (thread/fcn) + xchg bx, bx call rax ; Quit thread with RAX as the return code @@ -113,6 +98,7 @@ SwitchTasks: mov cr3, r8 ; Make sure the stack is valid before jumping + invlpg [rdi-0x1000] invlpg [rdi] invlpg [rdi+0x1000] diff --git a/Kernel/arch/x86_64/proc.c b/Kernel/arch/x86_64/proc.c index 3594552b..a8928cac 100644 --- a/Kernel/arch/x86_64/proc.c +++ b/Kernel/arch/x86_64/proc.c @@ -49,6 +49,7 @@ extern int giNextTID; extern int giTotalTickets; extern int giNumActiveThreads; extern tThread gThreadZero; +extern tProcess gProcessZero; extern void Threads_Dump(void); extern void Proc_ReturnToUser(tVAddr Handler, tVAddr KStackTop, int Argument); extern void Time_UpdateTimestamp(void); @@ -310,7 +311,7 @@ void ArchThreads_Init(void) gaCPUs[0].Current = &gThreadZero; - gThreadZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE; + gProcessZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE; gThreadZero.CurCPU = 0; gThreadZero.KernelStack = 0xFFFFA00000000000 + KERNEL_STACK_SIZE; @@ -405,6 +406,7 @@ void Proc_Start(void) // BSP still should run the current task gaCPUs[0].Current = &gThreadZero; + __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero)); // Start interrupts and wait for APs to come up Log("Waiting for APs to come up\n"); @@ -427,24 +429,30 @@ void Proc_Start(void) tThread *Proc_GetCurThread(void) { #if USE_MP - return gaCPUs[ GetCPUNum() ].Current; + tThread *ret; + __asm__ __volatile__ ("mov %%db0, %0" : "=r"(thread)); + return ret; // gaCPUs[ GetCPUNum() ].Current; #else return gaCPUs[ 0 ].Current; #endif } +void Proc_ClearProcess(tProcess *Process) +{ + Log_Warning("Proc", "TODO: Nuke address space etc"); +} + /* * */ void Proc_ClearThread(tThread *Thread) { - Log_Warning("Proc", "TODO: Nuke address space etc"); } /** * \brief Create a new kernel thread */ -int Proc_NewKThread(void (*Fcn)(void*), void *Data) +tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) { Uint rsp; tThread *newThread, *cur; @@ -453,9 +461,6 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data) newThread = Threads_CloneTCB(0); if(!newThread) return -1; - // Set CR3 - newThread->MemState.CR3 = cur->MemState.CR3; - // Create new KStack newThread->KernelStack = MM_NewKStack(); // Check for errors @@ -466,7 +471,6 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data) rsp = newThread->KernelStack; *(Uint*)(rsp-=8) = (Uint)Data; // Data (shadowed) - *(Uint*)(rsp-=8) = 1; // Number of params *(Uint*)(rsp-=8) = (Uint)Fcn; // Function to call *(Uint*)(rsp-=8) = (Uint)newThread; // Thread ID @@ -485,7 +489,7 @@ int Proc_NewKThread(void (*Fcn)(void*), void *Data) * \fn int Proc_Clone(Uint Flags) * \brief Clone the current process */ -int Proc_Clone(Uint Flags) +tTID Proc_Clone(Uint Flags) { tThread *newThread, *cur = Proc_GetCurThread(); Uint rip; @@ -501,7 +505,7 @@ int Proc_Clone(Uint Flags) if(!newThread) return -1; // Save core machine state - rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->MemState.CR3); + rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->Process->MemState.CR3); if(rip == 0) return 0; // Child newThread->KernelStack = cur->KernelStack; newThread->SavedState.RIP = rip; @@ -531,28 +535,24 @@ int Proc_Clone(Uint Flags) int Proc_SpawnWorker(void (*Fcn)(void*), void *Data) { tThread *new, *cur; - Uint stack_contents[4]; + Uint stack_contents[3]; cur = Proc_GetCurThread(); // Create new thread - new = malloc( sizeof(tThread) ); + new = Threads_CloneThreadZero(); if(!new) { Warning("Proc_SpawnWorker - Out of heap space!\n"); return -1; } - memcpy(new, &gThreadZero, sizeof(tThread)); - // Set Thread ID - new->TID = giNextTID++; // Create the stack contents - stack_contents[3] = (Uint)Data; - stack_contents[2] = 1; + stack_contents[2] = (Uint)Data; stack_contents[1] = (Uint)Fcn; stack_contents[0] = (Uint)new; // Create a new worker stack (in PID0's address space) - // The stack is relocated by this code + // - The stack is built by this code using stack_contents new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents)); new->SavedState.RSP = new->KernelStack - sizeof(stack_contents); @@ -744,7 +744,7 @@ void Proc_Reschedule(void) #if DEBUG_TRACE_SWITCH LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n", - nextthread->MemState.CR3, + nextthread->Process->MemState.CR3, nextthread->SavedState.RIP, nextthread->SavedState.RSP, nextthread->TID, @@ -757,19 +757,30 @@ void Proc_Reschedule(void) gTSSs[cpu].RSP0 = nextthread->KernelStack-4; __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread)); - // Save FPU/MMX/XMM/SSE state - if( curthread->SavedState.SSE ) + if( curthread ) + { + // Save FPU/MMX/XMM/SSE state + if( curthread->SavedState.SSE ) + { + Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); + curthread->SavedState.bSSEModified = 0; + Proc_DisableSSE(); + } + SwitchTasks( + nextthread->SavedState.RSP, &curthread->SavedState.RSP, + nextthread->SavedState.RIP, &curthread->SavedState.RIP, + nextthread->Process->MemState.CR3 + ); + } + else { - Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); - curthread->SavedState.bSSEModified = 0; - Proc_DisableSSE(); + Uint tmp; + SwitchTasks( + nextthread->SavedState.RSP, &tmp, + nextthread->SavedState.RIP, &tmp, + nextthread->Process->MemState.CR3 + ); } - - SwitchTasks( - nextthread->SavedState.RSP, &curthread->SavedState.RSP, - nextthread->SavedState.RIP, &curthread->SavedState.RIP, - nextthread->MemState.CR3 - ); return ; } @@ -780,7 +791,6 @@ void Proc_Reschedule(void) void Proc_Scheduler(int CPU, Uint RSP, Uint RIP) { #if 0 - { tThread *thread; // If the spinlock is set, let it complete @@ -808,7 +818,6 @@ void Proc_Scheduler(int CPU, Uint RSP, Uint RIP) // ACK Timer here? Proc_Reschedule(); - } #endif } diff --git a/Kernel/arch/x86_64/start64.asm b/Kernel/arch/x86_64/start64.asm index b63b63ac..c8e7f9a8 100644 --- a/Kernel/arch/x86_64/start64.asm +++ b/Kernel/arch/x86_64/start64.asm @@ -50,10 +50,7 @@ start64: [global GetCPUNum] GetCPUNum: - xor rax, rax - str ax - sub ax, 0x38 ; TSS Base - shr ax, 4 ; One 16-byte TSS per CPU + mov rax, dr1 ret KSTACK_USERSTATE_SIZE equ (5+2+16+2)*8 ; IRET, ErrorNum, ErrorCode, GPRs, FS&GS -- 2.20.1