singrdk/base/Kernel/Native/Processor.cpp

827 lines
21 KiB
C++
Raw Normal View History

2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// 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.