//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Processor.cpp // // Note: // #include "hal.h" #if SINGULARITY_KERNEL #include "halkd.h" #endif // SINGULARITY_KERNEL /////////////////////////////////////////////////////////// Segment Selectors. // #define SEGMENT_SELECTOR(s) \ (uint16)(offsetof(Struct_Microsoft_Singularity_CpuInfo,s) \ - offsetof(Struct_Microsoft_Singularity_CpuInfo,GdtNull)) /////////////////////////////////////////////////////////// Processor Context. // Class_Microsoft_Singularity_Processor * Struct_Microsoft_Singularity_X86_ProcessorContext:: m_GetProcessor(Struct_Microsoft_Singularity_X86_ProcessorContext *self) { return self->_processor; } #if SINGULARITY_KERNEL void Struct_Microsoft_Singularity_X86_ProcessorContext:: m_UpdateAfterGC(Struct_Microsoft_Singularity_X86_ProcessorContext * self, Class_Microsoft_Singularity_Processor *processor) { self->_processor = processor; } #endif // SINGULARITY_KERNEL /////////////////////////////////////////////////////////// Processor Methods. // #if SINGULARITY_KERNEL static int g_nIgnoredHardwareInterrupts = 0; static __declspec(align(8)) Struct_Microsoft_Singularity_X86_IDTP g_idt; static __declspec(align(8)) Struct_Microsoft_Singularity_X86_IDTE g_idtEntries[256]; void (__fastcall *c_exceptionHandler)(int exception, Struct_Microsoft_Singularity_X86_ThreadContext *context); void (__fastcall *c_interruptHandler)(int exception, Struct_Microsoft_Singularity_X86_ThreadContext *context); __declspec(naked) void Class_Microsoft_Singularity_Processor::g_HaltUntilInterruptNative() { __asm { hlt; ret; } } __declspec(naked) void Class_Microsoft_Singularity_Processor::g_InitFpu(void) { __asm { finit; mov eax, 0x37e; push eax; fldcw [esp]; pop eax; ret; } } __declspec(naked) uint32 Class_Microsoft_Singularity_Processor::g_ReadFpuStatus(void) { __asm { xor eax,eax; push eax; fnstsw [esp]; pop eax; ret; } } __declspec(naked) void Class_Microsoft_Singularity_Processor::g_ClearFpuStatus(void) { __asm { fnclex; ret; } } __declspec(naked) Class_Microsoft_Singularity_Processor * Class_Microsoft_Singularity_Processor::g_GetCurrentProcessor() { __asm { mov eax, fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext._processor; ret; } } #endif // SINGULARITY_KERNEL __declspec(naked) uint64 Class_Microsoft_Singularity_Processor::g_ReadMsr(uint32 counter) { __asm { // ECX = msr rdmsr; ret; } } void Class_Microsoft_Singularity_Processor::g_WriteMsr(uint32 msr, uint64 value) { uint32 lo = *(((uint32*)&value) + 0); uint32 hi = *(((uint32*)&value) + 1); __asm { mov ecx, msr; mov eax, lo; mov edx, hi; wrmsr; } } void Class_Microsoft_Singularity_Processor::g_ReadCpuid(uint32 feature, uint32 *p0, uint32 *p1, uint32 *p2, uint32 *p3) { uint32 v0; uint32 v1; uint32 v2; uint32 v3; __asm { mov eax, feature; cpuid; mov v0, eax; mov v1, ebx; mov v2, ecx; mov v3, edx; } *p0 = v0; *p1 = v1; *p2 = v2; *p3 = v3; } __declspec(naked) uint64 Class_Microsoft_Singularity_Processor::g_ReadPmc(uint32 counter) { __asm { // ECX = counter rdpmc; ret; } } __declspec(naked) uint64 Class_Microsoft_Singularity_Processor::g_GetCycleCount() { __asm { rdtsc; ret; } } #ifndef ZERO_RUNTIME UIntPtr Class_Microsoft_Singularity_Processor::g_GetFrameEip(UIntPtr ebp) { if (ebp < (UIntPtr)0x10000) { return 0; } return ((UIntPtr*)ebp)[1]; } UIntPtr Class_Microsoft_Singularity_Processor::g_GetFrameEbp(UIntPtr ebp) { if (ebp < (UIntPtr)0x10000) { return 0; } return ((UIntPtr*)ebp)[0]; } __declspec(naked) UIntPtr Class_Microsoft_Singularity_Processor::g_GetStackPointer() { __asm { mov eax, esp; ret; } } __declspec(naked) UIntPtr Class_Microsoft_Singularity_Processor::g_GetFramePointer() { __asm { mov eax, ebp; ret; } } __declspec(naked) Struct_Microsoft_Singularity_X86_ProcessorContext * Class_Microsoft_Singularity_Processor::g_GetCurrentProcessorContext() { __asm { mov eax, fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext.processorContext; ret; } } #endif // !ZERO_RUNTIME __declspec(naked) Struct_Microsoft_Singularity_X86_ThreadContext * Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext() { __asm { mov eax, fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext.threadContext; ret; } } __declspec(naked) Class_System_Threading_Thread * Class_Microsoft_Singularity_Processor::g_GetCurrentThread() { __asm { mov edx, fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext.threadContext; mov eax, [edx]Struct_Microsoft_Singularity_X86_ThreadContext._thread; ret; } #if 0 Struct_Microsoft_Singularity_X86_ProcessorContext * proc; __asm { mov eax, fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext.processorContext; mov proc, eax; } return proc->threadContext->_thread; #endif } #if SINGULARITY_KERNEL __declspec(naked) void Class_Microsoft_Singularity_Processor:: g_SetCurrentThreadContext(Struct_Microsoft_Singularity_X86_ThreadContext * context) { __asm { mov fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext.threadContext, ecx; ret; } } #endif // SINGULARITY_KERNEL #if SINGULARITY_KERNEL #if DO_FXSAVE_TEST #pragma warning(disable:4733) // We'll touch fs:[0] if we want to. int Class_Microsoft_Singularity_Processor::g_TestFxsave() { uint64 beg; uint64 end; int loops = 1000000; Struct_Microsoft_Singularity_X86_ThreadContext * context = g_GetCurrentThreadContext(); Struct_Microsoft_Singularity_X86_MmxContext *fxregs = &context->mmx; int fs0; bool fEnabled = g_DisableInterrupts(); beg = RDTSC(); while (loops-- > 0) { __asm { mov eax, fxregs; fxsave [eax]; fxrstor [eax]; } } end = RDTSC(); g_RestoreInterrupts(fEnabled); printf("value of fs:[0]: %08x\n", fs0); printf("elapsed: %d\n", (int)(end - beg)); return ((int)((end - beg) / 1000000)); } #endif DO_FS0_TEST #if DO_FS0_TEST #pragma warning(disable:4733) // We'll touch fs:[0] if we want to. int Class_Microsoft_Singularity_Processor::g_TestFs0() { uint64 beg; uint64 end; int loops = 1000000; void * stackLimit = (void *)0x800000; void * threadContext = &stackLimit; void * processorContextThread = &threadContext; int fs0; bool fEnabled = g_DisableInterrupts(); __asm { mov eax, processorContextThread; mov fs:[0], eax; } beg = RDTSC(); while (loops-- > 0) { __asm { mov eax, fs:[0]; mov eax, [eax]; add eax, 0x100; cmp eax, esp; mov fs0, eax; } } end = RDTSC(); g_RestoreInterrupts(fEnabled); printf("value of fs:[0]: %08x\n", fs0); printf("elapsed: %d\n", (int)(end - beg)); return ((int)((end - beg) / 1000000)); } #endif DO_FS0_TEST #if DO_CLI_STI_TEST int Class_Microsoft_Singularity_Processor::g_TestCliSti() { uint64 beg; uint64 end; int loops = 1000000; bool fEnabled = g_DisableInterrupts(); g_nIgnoredHardwareInterrupts = 0; __asm sti; beg = RDTSC(); while (loops-- > 0) { __asm { cli; // 1 sti; cli; // 2 sti; cli; // 3 sti; cli; // 4 sti; cli; // 5 sti; cli; // 6 sti; cli; // 7 sti; cli; // 8 sti; cli; // 9 sti; cli; // 10 sti; } } end = RDTSC(); __asm cli; printf("Ignored %d hardware interrupts.\n", g_nIgnoredHardwareInterrupts); g_RestoreInterrupts(fEnabled); return ((int)((end - beg) / 1000000)) / 10; } #endif // DO_CLI_STI_TEST #endif // SINGULARITY_KERNEL #if SLOW_INTERRUPT_SAVE_RESTORE static uint32 dstack[8]; static uint64 disabled = 0; static uint64 restored = 0; bool Class_Microsoft_Singularity_Processor::g_DisableInterrupts() { uint32 eflags; __asm { pushfd; pop eax; mov eflags, eax; cli; } #if 0 if ((eflags & Struct_Microsoft_Singularity_X86_EFlags_IF) != 0) { uint32 _ebp; __asm { mov _ebp, ebp; } for (int i = 0; i < arrayof(dstack); i++) { if (_ebp != 0) { dstack[i] = ((uint32*)_ebp)[1]; _ebp = ((uint32*)_ebp)[0]; } else { dstack[i] = 0; } } disabled = g_GetCycleCount(); } #endif // 0 return (eflags & Struct_Microsoft_Singularity_X86_EFlags_IF) != 0; } void Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(bool enabled) { if (enabled) { #if 0 restored = g_GetCycleCount(); if (restored - disabled > 10000000000 && disabled != 0) { __asm int 3; } #endif // 0 __asm sti; } } #else // SLOW_INTERRUPT_SAVE_RESTORE __declspec(naked) bool Class_Microsoft_Singularity_Processor::g_DisableInterrupts() { __asm { pushfd; pop eax; test eax, Struct_Microsoft_Singularity_X86_EFlags_IF; setnz al; cli; ret; } } __declspec(naked) void Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(bool enabled) { __asm { test cl, cl; je done; sti; done: ret; } } #endif // SLOW_INTERRUPT_SAVE_RESTORE __declspec(naked) bool Class_Microsoft_Singularity_Processor::g_InterruptsDisabled() { __asm { pushfd; pop eax; test eax, Struct_Microsoft_Singularity_X86_EFlags_IF; setz al; ret; } } __declspec(naked) void Class_Microsoft_Singularity_Processor::g_EnterRing3() { // int uc3 = SEGMENT_SELECTOR(GdtUC) + 3; // int ud3 = SEGMENT_SELECTOR(GdtUD) + 3; // int uf3 = SEGMENT_SELECTOR(GdtPF) + 3; // for the moment, share UF and PF // TODO: get rid of hexadecimal constants below // warning: preserve return values eax, edx (for returning from ABI) __asm { push edx mov ecx, esp mov edx, ring3 _emit 0x0f; _emit 0x35; //sysexit ring3: pop edx mov cx, ss mov ds, cx mov es, cx mov ecx, 0x38 + 3 // SEGMENT_SELECTOR(GdtPF) + 3 mov fs, cx ret } } #if DONT_TRY_THIS_YET __declspec(naked) bool Class_Microsoft_Singularity_Processor::g_AtKernelPrivilege() { // The bottom two bits of the CS selector are the RPL // (requested privilege level) of the selector. If // this is zero, we're running at ring0. Otherwise, // we're less privileged. __asm { mov ax, cs; test ax, 3; setnz al; // or setz al; ret; } } #else bool Class_Microsoft_Singularity_Processor::g_AtKernelPrivilege() { uint16 _cs; __asm{ mov _cs, cs } // The bottom two bits of the CS selector are the RPL // (requested privilege level) of the selector. If // this is zero, we're running at ring0. Otherwise, // we're less privileged. return (_cs & 0x3) == 0; } #endif ////////////////////////////////////////////////////////////////////////////// // #if SINGULARITY_KERNEL void DumpContext(Struct_Microsoft_Singularity_X86_ThreadContext *context) { printf(" thr=%8x, prv=%8x, nxt=%8x, ctx=%08x\n", context->_thread, context->prev, context->next, context); printf(" num=%8x, err=%8x, cr2=%8x\n", context->num, context->err, context->cr2); printf(" eax=%8x, ebx=%8x, ecx=%8x, edx=%8x\n", context->eax, context->ebx, context->ecx, context->edx); printf(" esp=%8x, ebp=%8x, esi=%8x, edi=%8x\n", context->esp, context->ebp, context->esi, context->edi); printf(" efl=%8x, eip=%8x, beg=%8x, lim=%8x\n", context->efl, context->eip, context->stackBegin, context->stackLimit); printf(" cs0=%8x\n", context->cs0); #if 0 uint32 _cs; uint32 _ss; uint32 _ds; uint32 _es; uint32 _fs; uint32 _gs; uint32 _esp; __asm { push cs; pop _cs; push ss; pop _ss; push ds; pop _ds; push es; pop _es; push fs; pop _fs; push gs; pop _gs; push esp; pop _esp; } printf(" cs=%04x, ss=%04x, ds=%04x, es=%04x, fs=%04x, gs=%04x, esp=%08x\n", _cs, _ss, _ds, _es, _fs, _gs, _esp); #endif } void LimitedDispatchException(int interrupt, Struct_Microsoft_Singularity_X86_ThreadContext *context) { #if 0 Struct_Microsoft_Singularity_X86_ProcessorContext * proc; __asm { mov eax, fs:[0]Struct_Microsoft_Singularity_X86_ProcessorContext.processorContext; mov proc, eax; } #endif if (context->num == 0x2E) { printf("SYSCALL!!\n"); DumpContext(context); return; } if (context->num == 0x2F) { printf("SYSENTER!!\n"); DumpContext(context); return; } if (context->num > 0x20) { g_nIgnoredHardwareInterrupts++; return; } #if 1 printf("-- Exception 0x%02x -------------------------------------------\n", interrupt); DumpContext(context); #endif // 1 printf("Entering debugger stub...\n"); printf("[= Exception: %02x eip=%08x efl=%08x ==\n", interrupt, context->eip, context->efl); Class_Microsoft_Singularity_DebugStub::g_Trap(context, false); } void Class_Microsoft_Singularity_Processor::g_ClearIdtTable() { printf("Clearing C# IDT Table.\n"); c_exceptionHandler = LimitedDispatchException; c_interruptHandler = LimitedDispatchException; } void Class_Microsoft_Singularity_Processor::g_SetIdtTable() { printf("Setting C# IDT Table.\n"); c_exceptionHandler = Class_Microsoft_Singularity_Processor::g_DispatchException; c_interruptHandler = Class_Microsoft_Singularity_Processor::g_DispatchInterrupt; } extern "C" void __cdecl EdtEnter0(void); extern "C" void __cdecl EdtEnter1(void); extern "C" void __cdecl IdtEnter20(void); extern "C" void __cdecl IdtEnter21(void); extern "C" void __cdecl SysEnter(void); extern void FakeSyscall(); void IdtInitialize() { // Configure the simplest IDT Handler. Class_Microsoft_Singularity_Processor::g_ClearIdtTable(); // Create the IDT Entry Table, first set the exception entries. uint32 entry = (uint32)EdtEnter0; uint32 offset = ((uint32)EdtEnter1) - ((uint32)EdtEnter0); for (int i = 0; i < 0x20; i++) { #if DOUBLE_FAULT_HANDLER if (i == Struct_Microsoft_Singularity_X86_EVectors_DoubleFault) { // The double fault handler uses a task gate to set up stack. g_idtEntries[i].offset_0_15 = 0; g_idtEntries[i].offset_16_31 = 0; g_idtEntries[i].selector = SEGMENT_SELECTOR(GdtDF); g_idtEntries[i].access = (Struct_Microsoft_Singularity_X86_IDTE_PRESENT | Struct_Microsoft_Singularity_X86_IDTE_DPL_RING0 | // RING0 for hardware ints. Struct_Microsoft_Singularity_X86_IDTE_TASK_GATE); uint32 * pi = (uint32 *)&g_idtEntries[i]; printf("idt[0x%02x] = %08x %08x\n", i, pi[0], pi[1]); } else { #endif g_idtEntries[i].offset_0_15 = (uint16)entry; g_idtEntries[i].selector = SEGMENT_SELECTOR(GdtPC); g_idtEntries[i].access = (Struct_Microsoft_Singularity_X86_IDTE_PRESENT | Struct_Microsoft_Singularity_X86_IDTE_DPL_RING3 | // RING0 for hardware ints. Struct_Microsoft_Singularity_X86_IDTE_INT_GATE); g_idtEntries[i].offset_16_31 = (uint16)(entry >> 16); #if DOUBLE_FAULT_HANDLER } #endif entry += offset; } // Now set the interrupt entries. entry = (uint32)IdtEnter20; offset = ((uint32)IdtEnter21) - ((uint32)IdtEnter20); for (int i = 0x20; i < arrayof(g_idtEntries); i++) { g_idtEntries[i].offset_0_15 = (uint16)entry; g_idtEntries[i].selector = SEGMENT_SELECTOR(GdtPC); g_idtEntries[i].access = (Struct_Microsoft_Singularity_X86_IDTE_PRESENT | Struct_Microsoft_Singularity_X86_IDTE_DPL_RING3 | Struct_Microsoft_Singularity_X86_IDTE_INT_GATE); g_idtEntries[i].offset_16_31 = (uint16)(entry >> 16); entry += offset; } g_idt.limit = sizeof(g_idtEntries); g_idt.addr = (uintptr)g_idtEntries; } void IdtLoad() { __asm { lidt g_idt.limit; } } void ProcessorInitialize(const Struct_Microsoft_Singularity_CpuInfo *pCpuInfo, int cpuId) { Struct_Microsoft_Singularity_X86_ProcessorContext *proc = (Struct_Microsoft_Singularity_X86_ProcessorContext *)pCpuInfo->Fs32; proc->cpuId = cpuId; // Set up a default environment. proc->processorContext = proc; proc->threadContext = &proc->thirdContext; // Insure valid context early in boot. proc->threadContext->_thread = (Class_System_Threading_Thread *)pCpuInfo->Gs32; proc->threadContext->stackLimit = 0; proc->threadContext->stackBegin = 0; // Make sure we have a viable exception stack for early debugging. // Note that this stack is only used for early debugging (i.e before Kernel.cs runs). proc->exceptionStackBegin = Struct_Microsoft_Singularity_BootInfo_KERNEL_STACK_BEGIN + 0x2000; proc->exceptionStackLimit = Struct_Microsoft_Singularity_BootInfo_KERNEL_STACK_BEGIN; #if PAGING // XXX Set up MSRs for SYSENTER/SYSEXIT Class_Microsoft_Singularity_Processor::g_WriteMsr(0x174, SEGMENT_SELECTOR(GdtPC)); Class_Microsoft_Singularity_Processor::g_WriteMsr(0x175, proc->exceptionStackBegin + 0x2000); #if !PAGING Class_Microsoft_Singularity_Processor::g_WriteMsr(0x176, (UINT64)SysEnter); #else Class_Microsoft_Singularity_Processor::g_WriteMsr(0x176, (UINT64)FakeSyscall); #endif #endif } void Class_Microsoft_Singularity_Processor::g_PrivateEnablePaging(uint32 pdpt) { __asm { // use the pdpt argument directly as the cr3 value. This leaves // top-level write-through and cache-disable turned off. mov eax, pdpt; mov cr3, eax; // Turn on paging and write protection mov eax, cr0; or eax, Struct_Microsoft_Singularity_X86_CR0_PG + Struct_Microsoft_Singularity_X86_CR0_WP; mov cr0, eax; jmp reload_tlb; ALIGN 0x010; reload_tlb: } } void Class_Microsoft_Singularity_Processor::g_PrivateChangeAddressSpace(uint32 pdpt) { __asm { // use the pdpt argument directly as the cr3 value. This leaves // top-level write-through and cache-disable turned off. mov eax, pdpt; mov cr3, eax; jmp reload_tlb; ALIGN 0x010; reload_tlb: } } __declspec(naked) void Class_Microsoft_Singularity_Processor::g_DisablePaging() { __asm { // Turn off paging. mov eax, cr0; and eax, NOT (Struct_Microsoft_Singularity_X86_CR0_PG + Struct_Microsoft_Singularity_X86_CR0_WP); mov cr0, eax; // Flush and reset the TLB. mov eax,0; mov cr3,eax; jmp reload_tlb; ALIGN 0x010; reload_tlb: } } void Class_Microsoft_Singularity_Processor::g_PrivateInvalidateTLBEntry(UIntPtr pageAddr) { __asm { mov eax, pageAddr; invlpg [eax]; } } __declspec(naked) uint32 Class_Microsoft_Singularity_Processor::g_GetCr3() { __asm { mov eax, cr3; ret; } } // haryadi void Class_Microsoft_Singularity_Processor::g_MpCallEntryPoint(UIntPtr entry) { __asm { mov eax, entry; call eax; } } #endif // SINGULARITY_KERNEL // ///////////////////////////////////////////////////////////////// End of File.