#include <proc.h>
#include <hal_proc.h>
+// === DEBUG OPTIONS ===
+#define TRACE_COW 0
+
// === CONSTANTS ===
#define PHYS_BITS 52 // TODO: Move out
#define VIRT_BITS 48
{
*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
{
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;
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' : '-'),
*/
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;
// 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;
}
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 )
}
if(expected != CHANGEABLE_BITS) {
+ // Merge
+
+ // Dump
MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
expected = 0;
}
*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 )
if( Flags & MM_PFLAG_COW ) {
*ent &= ~PF_WRITE;
*ent |= PF_COW;
+ INVLPG_ALL();
}
else {
*ent &= ~PF_COW;
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
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)
}
// #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;
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);
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;
// 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");
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;
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
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
* \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;
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;
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);
#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,
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 ;
}
void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
{
#if 0
- {
tThread *thread;
// If the spinlock is set, let it complete
// ACK Timer here?
Proc_Reschedule();
- }
#endif
}