//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Hal.cpp // // Note: // #include "hal.h" #if SINGULARITY_KERNEL #include "halkd.h" #include "printf.cpp" #endif // SINGULARITY_KERNEL ////////////////////////////////////////////////////////////////////////////// extern "C" int _fltused = 0x9875; ////////////////////////////////////////////////////////////////////////////// // debugging code. Put it here for now. #if SINGULARITY_KERNEL void Halt() { uintptr _ebp; __asm mov _ebp, ebp; for (int i = 0; i < 30 && _ebp >= 0x4000; i++) { uintptr next = ((uintptr *)_ebp)[0]; uintptr code = ((uintptr *)_ebp)[1]; printf(" %p: %p %p\n", _ebp, next, code); _ebp = next; } printf("---- Halting. --------------------------------------------------------"); __asm int 3; } void Cls() { KdPutChar('\n'); for (uint16 n = 0; n < 79; n++) { KdPutChar('-'); } KdPutChar('\n'); } void __cdecl PutChar(char cOut) { KdPutChar(cOut); } void fail_assert(const char *expr) { printf("%s\n", expr); printf("----- Frame --- EBP ---- Code ----------------------------- Assert Failure\n"); Halt(); __asm int 3; } #elif SINGULARITY_PROCESS void fail_assert(Class_System_String *message) { Struct_Microsoft_Singularity_V1_Services_DebugService::g_Print((bartok_char*)&message->m_firstChar, message->m_stringLength); //Struct_Microsoft_Singularity_V1_Services_DebugService::g_Break(); Class_Microsoft_Singularity_DebugStub::g_Break(); } #endif // SINGULARITY_KERNEL ////////////////////////////////////////////////////////////////////////////// // extern "C" int __cdecl _cinit(void); extern "C" int __cdecl _cfini(void); #if SINGULARITY_KERNEL void Class_Microsoft_Singularity_Kernel::g_Kill(int32 action) { ((Struct_Microsoft_Singularity_BootInfo *)g_pBootInfo)->KillAction = action; void (__cdecl *pfKill)(void) = (void (__cdecl *)(void))g_pBootInfo->Kill32; printf("About to call pfKill(%p) with %08x [g_pBootInfo=%p]\n", pfKill, g_pBootInfo->KillAction, g_pBootInfo); pfKill(); Halt(); } extern wchar_t _LinkDate[]; bartok_char * Class_Microsoft_Singularity_Kernel::g_HalGetLinkDate() { return (bartok_char *)_LinkDate; } // Hoisted this out of checkHinges because VC appears to have changed its name // mangling strategy for structs in functions. struct CheckedHingeEntry { uint32 i; char *a; char *b; }; void checkHinges() { // Check for a broken image produce when Bartok compiles through an assembler. int busted = false; extern CheckedHingeEntry checkedHingeTable[]; for (CheckedHingeEntry *che = checkedHingeTable; che->a; che++) { if (che->a+1 != che->b) { printf("%06d: 0x%08x 0x%08x\n", che->i, che->a+1, che->b); busted = true; } } if (busted) { printf("----- Frame --- EBP ---- Code ------------------------------ Busted Hinges\n"); Halt(); } } extern "C" static void __cdecl HalBspEnter(Struct_Microsoft_Singularity_BootInfo *bi) { g_pBootInfo = bi; kdprintf("Singularity HAL [%ls]\n", _LinkDate); _cinit(); kdprintf("DebugPort: %04x\n", bi->DebugBasePort); KdInitialize(bi); Cls(); printf("Singularity Hardware Abstraction Layer [%ls]\n", _LinkDate); printf("\n"); IdtInitialize(); IdtLoad(); ProcessorInitialize(&bi->Cpu0, 0); checkHinges(); Class_Microsoft_Singularity_Tracing::g_Initialize(); Class_Microsoft_Singularity_Tracing::g_Log(0); Class_Microsoft_Singularity_Tracing::g_Log(1); Class_Microsoft_Singularity_Tracing::g_Log(2); Class_Microsoft_Singularity_Tracing::g_Log(3); printf("----------------------------------------------------------------------\n"); printf("Calling Kernel.Main:\n"); Class_Microsoft_Singularity_Kernel::g_Main(); // We should not rely on or use any C++ finalizers. // _cfini(); } extern "C" static void __cdecl HalApEnter(const Struct_Microsoft_Singularity_BootInfo *bi, int cpu) { IdtLoad(); const Struct_Microsoft_Singularity_CpuInfo *cpuInfo = &bi->Cpu0 + cpu; ProcessorInitialize(cpuInfo, cpu); Class_Microsoft_Singularity_Kernel::g_MpMain(cpu); Class_Microsoft_Singularity_Processor::g_DisableInterrupts(); for (int i = 0; i != i + 1; i++) { uint16* p = (uint16*)(0xb8000 + (cpu - 1) * 2 * 8); for (int r = 0; r < 8; r++) { uint16 t = (uint16)(i >> (28 - r * 4)); t &= 0xf; if (t > 9) { t += 0x1f00 + 'a' - 10; } else { t += 0x1f00 + '0'; } *p++ = t; if (Class_Microsoft_Singularity_DebugStub::g_PollForBreak() == true) { __asm int 3; } for (int i = 0; i < 50000; i++) { __asm nop; } } } } extern "C" void __cdecl Hal(Struct_Microsoft_Singularity_BootInfo *bi, int cpu) { if (cpu == 0) { HalBspEnter(bi); } else { HalApEnter(bi, cpu); } } #elif SINGULARITY_PROCESS BOOL KdDebuggerNotPresent; extern Class_System_RuntimeType * brtmainClass; extern int (*brtmain)(ClassVector_Class_System_String *args); extern int brtmainReturnsInt; // Note: CallMain's return value is only meaningful if brtmainReturnsInt is true. // Example: // int ret = CallMain(args); // if (!MainReturnsInt()) ret = 0; __declspec(naked) int Class_Microsoft_Singularity_AppRuntime:: g_CallMain(ClassVector_Class_System_String *args) { // To avoid creating an unmanaged stack frame, jmp directly to the main function: __asm { mov eax, brtmain; jmp eax; } } bool Class_Microsoft_Singularity_AppRuntime:: g_MainReturnsInt() { return (brtmainReturnsInt != 0); } void Class_Microsoft_Singularity_AppRuntime:: g_SetDebuggerPresence(bool debuggerPresent) { KdDebuggerNotPresent = !debuggerPresent; } extern "C" int32 __fastcall RuntimeEntryPoint(int threadIndex) { int32 ret = 0; Struct_Microsoft_Singularity_X86_ThreadContext * context = Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext(); if (!Struct_Microsoft_Singularity_X86_ThreadContext::m_IsInKernelMode( context)) { // fail assertion in uninitialized process mode: __asm int 3 } Struct_Microsoft_Singularity_X86_ThreadContext::m_SetProcessMode(context); if (threadIndex == -1) { _cinit(); Class_Microsoft_Singularity_Tracing::g_Initialize(); Class_Microsoft_Singularity_Tracing::g_Log(0, "RuntimeEntryPoint:Main"); Class_Microsoft_Singularity_Monitoring::g_Initialize(); ret = Class_Microsoft_Singularity_AppRuntime::g_AppStart(brtmainClass); } else { Class_Microsoft_Singularity_Tracing::g_Log(0, "RuntimeEntryPoint:Thread"); Class_System_Threading_Thread::g_ThreadStub(threadIndex); } Struct_Microsoft_Singularity_X86_ThreadContext::m_SetKernelMode(context); return ret; } #endif // SINGULARITY_PROCESS ////////////////////////////////////////////////////////////////////////////// // Need to put the following marker variables into the .CRT section. // The .CRT section contains arrays of function pointers. // The compiler creates functions and adds pointers to this section // for things like C++ global constructors. // // The XIA, XCA etc are group names with in the section. // The compiler sorts the contributions by the group name. // For example, .CRT$XCA followed by .CRT$XCB, ... .CRT$XCZ. // The marker variables below let us get pointers // to the beginning/end of the arrays of function pointers. // // For example, standard groups are // XCA used here, for begin marker // XCC "compiler" inits // XCL "library" inits // XCU "user" inits // XCZ used here, for end marker // typedef void (__cdecl *_PVFV)(void); // typedef int (__cdecl *_PIFV)(void); typedef _PVFV _PIFV; #pragma comment(linker, "/merge:.CRT=.DATA") #pragma data_seg(".CRT$XIA", "DATA") extern "C" _PIFV __xi_a[] = { NULL }; // C initializers. #pragma data_seg(".CRT$XIZ", "DATA") extern "C" _PIFV __xi_z[] = { NULL }; #pragma data_seg(".CRT$XCA", "DATA") extern "C" _PVFV __xc_a[] = { NULL }; // C++ initializers. #pragma data_seg(".CRT$XCZ", "DATA") extern "C" _PVFV __xc_z[] = { NULL }; #pragma data_seg(".CRT$XPA", "DATA") extern "C" _PVFV __xp_a[] = { NULL }; // C pre-terminators. #pragma data_seg(".CRT$XPZ", "DATA") extern "C" _PVFV __xp_z[] = { NULL }; #pragma data_seg(".CRT$XTA", "DATA") extern "C" _PVFV __xt_a[] = { NULL }; // C terminators. #pragma data_seg(".CRT$XTZ", "DATA") extern "C" _PVFV __xt_z[] = { NULL }; #pragma data_seg() // Walk an array of function pointers, call non-NULL ones. void __cdecl _initterm(_PVFV *pfbegin, _PVFV *pfend) { for (; pfbegin < pfend; pfbegin++) { if (*pfbegin != NULL) { (**pfbegin)(); } } } // Call all of the C++ static constructors. // int __cdecl _cinit(void) { // do C initializations _initterm( __xi_a, __xi_z ); // do C++ initializations _initterm( __xc_a, __xc_z ); return 0; } int __cdecl _cfini(void) { // do C initializations _initterm( __xp_a, __xp_z ); // do C++ terminations _initterm( __xt_a, __xt_z ); return 0; }