/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: halkdx86.cpp - Processor-specific support routines for halkd.cpp. // #include "hal.h" #include "halkd.h" #define KDDBG if (0) kdprintf extern "C" void * __cdecl memcpy(void *, const void *, size_t); //////////////////////////////////////////////// User visible progress beacon. // static UINT16 KdpSpinBase = 0x2f00; void KdpSpin() { if (KdpSpinBase != 0) { static UINT8 state = 0; // Write the spinner to the screen. *((UINT16 *)0xb809e) = KdpSpinBase + ("+-|*" [state++ & 0x3]); } } ///////////////////////////////////////// Debugger Unique Interrupts Routines. // // NB: Without these, we share routines with the mainline code and we get // caught in a loop when the debugger inserts a break after the pushfd when // someone tries to single step through Processor:g_DisableInterrupts! // bool __declspec(naked) KdpDisableInterruptsInline() { __asm { pushfd; pop eax; test eax, Struct_Microsoft_Singularity_Isal_IX_EFlags_IF; setnz al; nop; // required so that the linker doesn't combine with g_Disable cli; ret; } } void __declspec(naked) KdpRestoreInterruptsInline(bool enabled) { __asm { nop; test cl, cl; je done; nop; // required so that the linker doesn't combine with g_Restore sti; done: ret; } } // Pause processor in deference to other hardware threads on the same core. void __declspec(naked) KdpPause() { __asm { pause; ret; } } // Flush instruction cache. void __declspec(naked) KdpFlushInstCache() { __asm { wbinvd; // privileged instruction ret; } } // Break into the debugger. void __declspec(naked) Class_Microsoft_Singularity_DebugStub::g_Break() { __asm { int 3; ret; } } // Read a machine specific register (MSR on x86 & x64). bool KdpReadMsr(UINT32 msr, UINT32 *plo, UINT32 *phi) { UINT32 lo; UINT32 hi; __asm { mov ecx, msr; rdmsr; mov hi, edx; mov lo, eax; } *phi = hi; *plo = lo; return true; } // Write a machine specific register (MSR on x86 & x64). bool KdpWriteMsr(UINT32 msr, UINT32 lo, UINT32 hi) { __asm { mov ecx, msr; mov edx, hi; mov eax, lo; wrmsr; } return true; } ////////////////////////////////////////////////////////////////////////////// // void KdpToKdContext(IN CONST Struct_Microsoft_Singularity_Isal_SpillContext *singularity, OUT CONTEXT *windbg) { windbg->ContextFlags = (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS); // CONTEXT_FULL; windbg->Eax = singularity->ax; windbg->Ebx = singularity->bx; windbg->Ecx = singularity->cx; windbg->Edx = singularity->dx; windbg->Esp = singularity->sp; windbg->Ebp = singularity->bp; windbg->Esi = singularity->si; windbg->Edi = singularity->di; windbg->Eip = singularity->ip; windbg->EFlags = singularity->fl; windbg->FloatSave.ControlWord = singularity->mmx.fcw; windbg->FloatSave.StatusWord = singularity->mmx.fsw; windbg->FloatSave.TagWord = singularity->mmx.ftw; windbg->FloatSave.ErrorOffset = singularity->mmx.ip; windbg->FloatSave.ErrorSelector = singularity->mmx.cs; windbg->FloatSave.DataOffset = singularity->mmx.dp; windbg->FloatSave.DataSelector = singularity->mmx.ds; memcpy(&windbg->FloatSave.St0, &singularity->mmx.st0, 10); memcpy(&windbg->FloatSave.St1, &singularity->mmx.st1, 10); memcpy(&windbg->FloatSave.St2, &singularity->mmx.st2, 10); memcpy(&windbg->FloatSave.St3, &singularity->mmx.st3, 10); memcpy(&windbg->FloatSave.St4, &singularity->mmx.st4, 10); memcpy(&windbg->FloatSave.St5, &singularity->mmx.st5, 10); memcpy(&windbg->FloatSave.St6, &singularity->mmx.st6, 10); memcpy(&windbg->FloatSave.St7, &singularity->mmx.st7, 10); memcpy(&windbg->ExtendedRegisters, &singularity->mmx, 512); // Segment registers other than cs don't change so they are live windbg->SegCs = singularity->cs; __asm { mov ebx, windbg; xor eax, eax; mov ax, gs; mov [ebx]CONTEXT.SegGs, eax; mov ax, fs; mov [ebx]CONTEXT.SegFs, eax; mov ax, es; mov [ebx]CONTEXT.SegEs, eax; mov ax, ds; mov [ebx]CONTEXT.SegDs, eax; mov ax, ss; mov [ebx]CONTEXT.SegSs, eax; } } void KdpFromKdContext(IN CONST CONTEXT *windbg, OUT Struct_Microsoft_Singularity_Isal_SpillContext *singularity) { singularity->ax = windbg->Eax; singularity->bx = windbg->Ebx; singularity->cx = windbg->Ecx; singularity->dx = windbg->Edx; singularity->sp = windbg->Esp; singularity->bp = windbg->Ebp; singularity->si = windbg->Esi; singularity->di = windbg->Edi; singularity->ip = windbg->Eip; singularity->fl = windbg->EFlags; // CONTEXT_FLOATING_POINT if (windbg->ContextFlags & CONTEXT_FLOATING_POINT) { singularity->mmx.fcw = windbg->FloatSave.ControlWord; singularity->mmx.fsw = windbg->FloatSave.StatusWord; singularity->mmx.ftw = windbg->FloatSave.TagWord; singularity->mmx.cs = windbg->FloatSave.ErrorSelector; singularity->mmx.ip = windbg->FloatSave.ErrorOffset; singularity->mmx.ds = windbg->FloatSave.DataSelector; singularity->mmx.dp = windbg->FloatSave.DataOffset; memcpy(&singularity->mmx.st0, &windbg->FloatSave.St0, 10); memcpy(&singularity->mmx.st1, &windbg->FloatSave.St1, 10); memcpy(&singularity->mmx.st2, &windbg->FloatSave.St2, 10); memcpy(&singularity->mmx.st3, &windbg->FloatSave.St3, 10); memcpy(&singularity->mmx.st4, &windbg->FloatSave.St4, 10); memcpy(&singularity->mmx.st5, &windbg->FloatSave.St5, 10); memcpy(&singularity->mmx.st6, &windbg->FloatSave.St6, 10); memcpy(&singularity->mmx.st7, &windbg->FloatSave.St7, 10); } // CONTEXT_EXTENDED_REGISTERS if (windbg->ContextFlags & CONTEXT_EXTENDED_REGISTERS) { memcpy(&singularity->mmx, &windbg->ExtendedRegisters, 512); } } void KdpSetControlReport(IN OUT PDBGKD_CONTROL_REPORT report, IN CONST Struct_Microsoft_Singularity_Isal_SpillContext *x86Context) // Routine Description: // Fill in the Wait_State_Change message record. // // Arguments: // WaitStateChange - Supplies pointer to record to fill in // x86Context - Supplies a pointer to a context record. { UINT32 _dr6; UINT32 _dr7; UINT16 _cs; UINT16 _ds; UINT16 _es; UINT16 _fs; __asm { mov eax, dr6; mov _dr6, eax; mov eax, dr7; mov _dr7, eax; mov ax, cs; mov _cs, ax; mov ax, ds; mov _ds, ax; mov ax, es; mov _es, ax; mov ax, fs; mov _fs, ax; } report->Dr6 = _dr6; report->Dr7 = _dr7; report->SegCs = _cs; report->SegDs = _ds; report->SegEs = _es; report->SegFs = _fs; report->EFlags = x86Context->fl; report->ReportFlags = X86_REPORT_INCLUDES_SEGS; #if !PAGING // Let the debugger know so that it doesn't have to retrieve the CS descriptor. report->ReportFlags |= X86_REPORT_STANDARD_CS; #endif } void KdpSetControlSet(IN CONST DBGKD_CONTROL_SET * control, IN OUT Struct_Microsoft_Singularity_Isal_SpillContext *x86Context) { if (control->TraceFlag) { //KDDBG("KD: Warning - trace flag set prev efl=%x\n",x86Context->efl); x86Context->fl |= Struct_Microsoft_Singularity_Isal_IX_EFlags_TF; } else { //KDDBG("KD: turning off tracing in efl\n"); x86Context->fl &= ~Struct_Microsoft_Singularity_Isal_IX_EFlags_TF; } UINT32 _dr7 = control->Dr7; __asm { mov eax, _dr7; mov dr7, eax } } ////////////////////////////////////////////////////////////////////////////// void KdpReadSpecialRegisters(KSPECIAL_REGISTERS *pksp, IN CONST Struct_Microsoft_Singularity_Isal_SpillContext *x86Context) { Struct_Microsoft_Singularity_Kd_X86Descriptor idtp; Struct_Microsoft_Singularity_Kd_X86Descriptor gdtp; __asm { mov ebx, pksp; sidt idtp.Limit; sgdt gdtp.Limit; mov eax, cr0; mov [ebx]KSPECIAL_REGISTERS.Cr0, eax; mov eax, cr2; mov [ebx]KSPECIAL_REGISTERS.Cr2, eax; mov eax, cr3; mov [ebx]KSPECIAL_REGISTERS.Cr3, eax; _emit 0x0f; // mov eax,cr4 _emit 0x20; _emit 0xe0; mov [ebx]KSPECIAL_REGISTERS.Cr4, eax; // Should we save segment regs as well? str ax; mov [ebx]KSPECIAL_REGISTERS.Tr, ax; } pksp->Idtr = idtp; pksp->Gdtr = gdtp; } void KdpWriteSpecialRegisters(CONST KSPECIAL_REGISTERS *pksp) { __asm { mov ebx, pksp; mov eax, [ebx]KSPECIAL_REGISTERS.KernelDr0; mov dr0, eax; mov eax, [ebx]KSPECIAL_REGISTERS.KernelDr1; mov dr1, eax; mov eax, [ebx]KSPECIAL_REGISTERS.KernelDr2; mov dr2, eax; mov eax, [ebx]KSPECIAL_REGISTERS.KernelDr3; mov dr3, eax; mov eax, [ebx]KSPECIAL_REGISTERS.KernelDr6; mov dr6, eax; mov eax, [ebx]KSPECIAL_REGISTERS.KernelDr7; mov dr7, eax; } } ////////////////////////////////////////////////////////////////////////////// KdDebugTrapData * KdpIsDebugTrap(IN CONST Struct_Microsoft_Singularity_Isal_SpillContext *context, int id) { if (id == Struct_Microsoft_Singularity_Isal_IX_EVectors_FirstChanceException) { return (KdDebugTrapData *)(context->ax); } return NULL; } // Convert a trap into a exception record. void KdpConvertTrapToException(IN OUT EXCEPTION_RECORD64 *per, IN OUT Struct_Microsoft_Singularity_Isal_SpillContext *context, int id) { // Breakpoints: switch (id) { case Struct_Microsoft_Singularity_Isal_IX_EVectors_SingleStep: KDDBG("SingleStep\n"); per->ExceptionCode = STATUS_SINGLE_STEP; per->ExceptionAddress = SIGN_EXTEND(context->ip); // context->efl &= ~Struct_Microsoft_Singularity_Isal_IX_EFlags_TF; break; case Struct_Microsoft_Singularity_Isal_IX_EVectors_Breakpoint: KDDBG("Breakpoint\n"); context->ip -= 1; per->ExceptionCode = STATUS_BREAKPOINT; per->NumberParameters = 1; per->ExceptionInformation0 = BREAKPOINT_BREAK; per->ExceptionAddress = SIGN_EXTEND(context->ip); break; case Struct_Microsoft_Singularity_Isal_IX_EVectors_IllegalInstruction: KDDBG("Illegal Instruction\n"); per->ExceptionCode = STATUS_ILLEGAL_INSTRUCTION; break; case Struct_Microsoft_Singularity_Isal_IX_EVectors_PageFault: KDDBG("KD: 0x0E %d\n", id); per->ExceptionCode = STATUS_ACCESS_VIOLATION; per->ExceptionAddress = SIGN_EXTEND(context->ip); per->NumberParameters = 1; { UINT32 _cr2; __asm { mov eax, cr2; mov _cr2, eax; } per->ExceptionInformation0 = SIGN_EXTEND(_cr2); } break; case Struct_Microsoft_Singularity_Isal_IX_EVectors_FirstChanceException: { KdDebugTrapData *trapData = (KdDebugTrapData *) (context->ax); switch (trapData->tag) { case KdDebugTrapData::FIRST_CHANCE_EXCEPTION: context->ax = trapData->firstChanceException.throwAddr; KDDBG("KD: First chance C# exception\n"); // per->ExceptionCode = STATUS_CPP_EH_EXCEPTION; //0xe06d7363; per->ExceptionCode = STATUS_VCPP_EXCEPTION; //0x8000ff1f; per->ExceptionAddress = SIGN_EXTEND(context->ip); per->NumberParameters = 1; per->ExceptionInformation0 = BREAKPOINT_BREAK; break; default: KDDBG("KD: Unexpected interrupt %d\n", id); per->ExceptionCode = 0x80000000 + id; per->ExceptionAddress = SIGN_EXTEND(context->ip); break; } break; } case Struct_Microsoft_Singularity_Isal_IX_EVectors_SecondChanceException: KDDBG("KD: Second chance C# exception\n"); per->ExceptionCode = STATUS_VCPP_EXCEPTION; per->ExceptionAddress = SIGN_EXTEND(context->ip); break; case Struct_Microsoft_Singularity_Isal_IX_EVectors_DebuggerBreakRequest: KDDBG("KD: Debugger ctrl-break\n"); per->ExceptionCode = STATUS_BREAKPOINT; per->ExceptionInformation0 = BREAKPOINT_BREAK; per->ExceptionAddress = SIGN_EXTEND(context->ip); break; case Struct_Microsoft_Singularity_Isal_IX_EVectors_Nmi: KDDBG("KD: NMI exception\n"); per->ExceptionCode = STATUS_UNHANDLED_EXCEPTION; per->ExceptionInformation0 = BREAKPOINT_BREAK; per->ExceptionAddress = SIGN_EXTEND(context->ip); break; default: KDDBG("KD: Unexpected interrupt %d\n", id); per->ExceptionCode = 0x80000000 + id; per->ExceptionAddress = SIGN_EXTEND(context->ip); break; } KDDBG("Trap: Context at %p\n", context); KDDBG(" CXT=%08x THR=%08x\n", context, Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext()->_thread); KDDBG(" EIP=%08x EFL=%08x\n", context->ip, context->fl); KDDBG(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", context->ax, context->bx, context->cx, context->dx); KDDBG(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n", context->sp, context->bp, context->si, context->di); } // // Read or Write I/O Space. // // Return: // // iowrite == 0: value read from port // // iowrite !=0: zero // int KdpReadWriteIoSpace( int size, // 1, 2, 4 int iowrite, // true if write, false if read unsigned short addr, unsigned int value ) { unsigned int retValue = 0; if (iowrite != 0) { // I/O Write's if (size == 1) { unsigned char byteValue = (unsigned char)value; __outbyte(addr, value); } else if (size == 2) { unsigned short wordValue = (unsigned short)value; __outword(addr, value); } else if (size == 4) { __outdword(addr, value); } } else { // I/O Read's if (size == 1) { retValue = __inbyte(addr); } else if (size == 2) { retValue = __inword(addr); } else if (size == 4) { retValue = __indword(addr); } } return retValue; }