#include <acess.h>
#include <proc.h>
#include <mm_virt.h>
+#include <threads_int.h> // Needed for SSE handling
#define MAX_BACKTRACE 6
// === IMPORTS ===
- int MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
-void Error_Backtrace(Uint IP, Uint BP);
+extern int MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
+extern void Error_Backtrace(Uint IP, Uint BP);
+extern void Proc_EnableSSE(void);
+extern void Proc_RestoreSSE(Uint32 Data);
// === PROTOTYPES ===
void Error_Handler(tRegs *Regs);
void Error_Handler(tRegs *Regs)
{
Uint cr;
+
+ if( Regs->IntNum == 7 )
+ {
+ tThread *thread = Proc_GetCurThread();
+ if(!thread->SavedState.bSSEModified)
+ {
+ Proc_EnableSSE();
+ if(!thread->SavedState.SSE)
+ thread->SavedState.SSE = malloc(sizeof(tSSEState) + 0xF);
+ else
+ Proc_RestoreSSE( ((Uint)thread->SavedState.SSE + 0xF) & ~0xF );
+ thread->SavedState.bSSEModified = 1;
+// __asm__ __volatile__ ("sti");
+ return ;
+ }
+ // oops, SSE enabled but a #NM, bad news
+ }
if( Regs->IntNum == 14 ) {
__asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
}
Log("CPU Error %x, Code: 0x%x", Regs->IntNum, Regs->ErrorCode);
-// Log(" - %s", csaERROR_NAMES[Regs->IntNum]);
+ Log(" - %s", csaERROR_NAMES[Regs->IntNum]);
Log(" CS:RIP = 0x%04x:%016llx", Regs->CS, Regs->RIP);
Log(" SS:RSP = 0x%04x:%016llx", Regs->SS, Regs->RSP);
Log(" RFLAGS = 0x%016llx", Regs->RFlags);
tPAddr CR3;
} tMemoryState;
+// 512 bytes, 16 byte aligned
+typedef struct sSSEState
+{
+ char data[512];
+} tSSEState;
+
/**
* \brief Task state for thread handler
*/
{
Uint RIP, RSP;
Uint64 UserRIP, UserCS;
+ tSSEState *SSE;
+ int bSSEModified;
} tTaskState;
// === CONSTANTS ===
void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable )
{
tPAddr curpage = *Ent & PADDR_MASK;
+ int bCopied = 0;
+
if( MM_GetRefCount( curpage ) <= 0 ) {
Log_KernelPanic("MMVirt", "Page %P still marked COW, but unreferenced", curpage);
}
{
*Ent &= ~PF_COW;
*Ent |= PF_PRESENT|PF_WRITE;
-// Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
+ Log_Debug("MMVirt", "COW ent at %p (%p) only %P", Ent, NextLevel, curpage);
}
else
{
memcpy( tmp, NextLevel, 0x1000 );
MM_FreeTemp( (tVAddr)tmp );
-// Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
+ Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
MM_DerefPhys( curpage );
*Ent &= PF_USER;
*Ent |= paddr|PF_PRESENT|PF_WRITE;
+
+ bCopied = 1;
}
INVLPG( (tVAddr)NextLevel );
- // Mark COW on pages
+ // Mark COW on contents if it's a PDPT, Dir or Table
if(bTable)
{
Uint64 *dp = NextLevel;
int i;
for( i = 0; i < 512; i ++ )
{
- if( !(dp[i] & PF_PRESENT) ) continue;
- MM_RefPhys( dp[i] & PADDR_MASK );
+ if( !(dp[i] & PF_PRESENT) )
+ continue;
+
+ if( bCopied )
+ MM_RefPhys( dp[i] & PADDR_MASK );
if( dp[i] & PF_WRITE ) {
dp[i] &= ~PF_WRITE;
dp[i] |= PF_COW;
xor eax, eax ; Return zero
ret
+[global Proc_InitialiseSSE]
+Proc_InitialiseSSE:
+ mov rax, cr4
+ or ax, (1 << 9)|(1 << 10) ; Set OSFXSR and OSXMMEXCPT
+ mov cr4, rax
+ mov rax, cr0
+ and ax, ~(1 << 2) ; Clear EM
+ or rax, (1 << 1) ; Set MP
+ mov rax, cr0
+ ret
+[global Proc_DisableSSE]
+Proc_DisableSSE:
+ mov rax, cr0
+ or ax, 1 << 3 ; Set TS
+ mov cr0, rax
+ ret
+[global Proc_EnableSSE]
+Proc_EnableSSE:
+ mov rax, cr0
+ and ax, ~(1 << 3) ; Clear TS
+ mov cr0, rax
+ ret
+
+[global Proc_SaveSSE]
+Proc_SaveSSE:
+ fxsave [rdi]
+ ret
+[global Proc_RestoreSSE]
+Proc_RestoreSSE:
+ fxrstor [rdi]
+ ret
+
; vim: ft=nasm
extern Uint SaveState(Uint *RSP, Uint *Regs);
extern Uint Proc_CloneInt(Uint *RSP, Uint *CR3);
extern void NewTaskHeader(void); // Actually takes cdecl args
+extern void Proc_InitialiseSSE(void);
+extern void Proc_SaveSSE(Uint DestPtr);
+extern void Proc_DisableSSE(void);
extern Uint64 gInitialPML4[512]; // start.asm
extern int giNumCPUs;
Warning("Oh, hell, Unable to allocate PPD for Thread#0");
}
+ Proc_InitialiseSSE();
+
Log_Log("Proc", "Multithreading initialised");
}
newThread->SavedState.RSP = rsp;
newThread->SavedState.RIP = (Uint)&NewTaskHeader;
+ newThread->SavedState.SSE = NULL;
// Log("New (KThread) %p, rsp = %p\n", newThread->SavedState.RIP, newThread->SavedState.RSP);
// MAGIC_BREAK();
if(rip == 0) return 0; // Child
newThread->KernelStack = cur->KernelStack;
newThread->SavedState.RIP = rip;
+ newThread->SavedState.SSE = NULL;
// DEBUG
#if 0
new->SavedState.RSP = new->KernelStack - sizeof(stack_contents);
new->SavedState.RIP = (Uint)&NewTaskHeader;
+ new->SavedState.SSE = NULL;
// Log("New (Worker) %p, rsp = %p\n", new->SavedState.RIP, new->SavedState.RSP);
return base + USER_STACK_SZ;
}
-
void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
{
Uint *stack;
- char **envp;
int i;
- Uint delta;
+ char **envp = NULL;
Uint16 ss, cs;
Threads_Exit(0, -1);
}
stack -= (DataSize+7)/8;
- LOG("stack = 0x%x", stack);
- Log("stack = %p, DataSize = %i", stack, DataSize);
memcpy( stack, ArgV, DataSize );
free(ArgV);
// Adjust Arguments and environment
- delta = (Uint)stack - (Uint)ArgV;
- ArgV = (char**)stack;
- for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
- envp = &ArgV[i+1];
- for( i = 0; envp[i]; i++ ) envp[i] += delta;
+ if(DataSize)
+ {
+ Uint delta = (Uint)stack - (Uint)ArgV;
+ ArgV = (char**)stack;
+ for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
+ envp = &ArgV[i+1];
+ for( i = 0; envp[i]; i++ ) envp[i] += delta;
+ }
// User Mode Segments
// 0x2B = 64-bit
gTSSs[cpu].RSP0 = nextthread->KernelStack-4;
__asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread));
+ // 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,