1160 lines
30 KiB
C++
1160 lines
30 KiB
C++
//++
|
|
//
|
|
// Copyright (c) Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// blsingularity.cpp
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module initializes and boots Singularity.
|
|
//
|
|
//--
|
|
|
|
|
|
#include "bl.h"
|
|
|
|
#define SINGULARITY_DISTRO_INI_PATH "singularity/singboot.ini"
|
|
#define SINGULARITY_LOG_RECORD_SIZE 0x20000
|
|
#define SINGULARITY_LOG_TEXT_SIZE 0x20000
|
|
#define SINGULARITY_KERNEL_STACK_SIZE 0xC0000
|
|
|
|
//
|
|
// Define halclass style basic definitions and macros.
|
|
//
|
|
|
|
typedef ULONG_PTR PTR_TYPE;
|
|
|
|
typedef LONG_PTR SPTR_TYPE;
|
|
typedef ULONG_PTR UPTR_TYPE;
|
|
|
|
#define OFFSETOF FIELD_OFFSET
|
|
|
|
#define STATIC_ASSERT C_ASSERT
|
|
|
|
//
|
|
// Include halclasswin.h for Singularity definitions.
|
|
//
|
|
|
|
#define SINGULARITY_LOADER 1
|
|
|
|
#pragma pack(1)
|
|
#include <halclasswin.h>
|
|
#pragma pack()
|
|
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, rc) == RM_CODE_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, rd) == RM_DATA_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, pc) == PM_CODE_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, pd) == PM_DATA_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, lc) == LM_CODE_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, ld) == LM_DATA_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, pp) == PROCESSOR_SELECTOR);
|
|
C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, tss) == TSS_SELECTOR);
|
|
|
|
Class_Microsoft_Singularity_Hal_Platform *BlPlatform;
|
|
Class_Microsoft_Singularity_Hal_Cpu *BlCpuArray;
|
|
|
|
typedef struct _BL_DISTRO_FILE {
|
|
LIST_ENTRY Entry;
|
|
UINT32 Size;
|
|
CHAR Path[1024];
|
|
PVOID Data;
|
|
} BL_DISTRO_FILE, *PBL_DISTRO_FILE;
|
|
|
|
typedef struct _BL_DISTRO {
|
|
UINT32 NumberOfFiles;
|
|
UINT32 TotalSize;
|
|
LIST_ENTRY FileList;
|
|
PVOID Data;
|
|
} BL_DISTRO, PBL_DISTRO;
|
|
|
|
BL_DISTRO BlDistro;
|
|
PBL_DISTRO_FILE BlKernelFile;
|
|
|
|
PVOID BlKernelBase;
|
|
ULONG_PTR BlKernelSize;
|
|
|
|
UINT32
|
|
(*BlKernelEntryPoint)(
|
|
Class_Microsoft_Singularity_Hal_Platform *Platform,
|
|
Class_Microsoft_Singularity_Hal_Cpu *Cpu
|
|
);
|
|
|
|
|
|
|
|
PBL_SMAP BlSingularitySmap;
|
|
PWCHAR BlCommandLine;
|
|
Struct_Microsoft_Singularity_Io_FileImage *BlSingularityFileImageTable;
|
|
UINT32 BlSingularityFileImageTableSize;
|
|
|
|
//
|
|
// OHCI 1394 buffer for Singularity KD.
|
|
//
|
|
// AIFIX: Currently, this buffer needs to be allocated in low memory, because
|
|
// Singularity KD does not connect if it is allocated in high memory.
|
|
//
|
|
|
|
__declspec(align(PAGE_SIZE)) UINT8 BlSingularityOhci1394Buffer[3 * PAGE_SIZE];
|
|
|
|
VOID
|
|
BlSingularityLoadDistro(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function loads the distro.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT32 BytesRead;
|
|
UINT32 CharactersConsumed;
|
|
PBL_DISTRO_FILE DistroFile;
|
|
UINT32 DummySize;
|
|
PLIST_ENTRY Entry;
|
|
UINT32 FilesRead;
|
|
PLIST_ENTRY Head;
|
|
PCHAR NewLine;
|
|
PCHAR Next;
|
|
UINT32 Size;
|
|
PCHAR Temp;
|
|
PVOID BlIniFileData;
|
|
UINT32 BlIniFileSize;
|
|
|
|
BlDistro.NumberOfFiles = 0;
|
|
BlRtlInitializeListHead(&BlDistro.FileList);
|
|
|
|
//
|
|
// Read the distro INI file.
|
|
//
|
|
|
|
if (BlFsGetFileSize(SINGULARITY_DISTRO_INI_PATH, &BlIniFileSize) == FALSE) {
|
|
|
|
BlRtlPrintf("BL: Unable to get INI file!\n");
|
|
BlRtlHalt();
|
|
}
|
|
|
|
BlIniFileData = BlPoolAllocateBlock(BlIniFileSize + 1);
|
|
|
|
if (BlFsReadFile(SINGULARITY_DISTRO_INI_PATH, BlIniFileData, BlIniFileSize) == FALSE) {
|
|
|
|
BlRtlPrintf("BL: Unable to read INI file!\n");
|
|
BlRtlHalt();
|
|
}
|
|
|
|
//
|
|
// Parse INI file and build distro file list.
|
|
//
|
|
|
|
NewLine = (PCHAR) BlIniFileData;
|
|
|
|
for (;;) {
|
|
|
|
Next = NewLine;
|
|
NewLine = Next + 1;
|
|
|
|
while ((*NewLine != 0) && (*NewLine != '\r') && (*NewLine != '\n')) {
|
|
|
|
NewLine += 1;
|
|
}
|
|
|
|
if (*NewLine == 0) {
|
|
|
|
break;
|
|
}
|
|
|
|
while ((*NewLine == '\r') || (*NewLine == '\n')) {
|
|
|
|
*NewLine = 0;
|
|
NewLine += 1;
|
|
}
|
|
|
|
Next = (PCHAR)BlRtlFindSubstring(Next, "Size=");
|
|
|
|
if (Next == NULL) {
|
|
|
|
continue;
|
|
}
|
|
|
|
Next += 5;
|
|
|
|
if (BlRtlParsePositiveDecimal(Next,
|
|
&Size,
|
|
&CharactersConsumed) == FALSE) {
|
|
|
|
ParseFailure:
|
|
BlRtlPrintf("BL: Error parsing distro INI file!\n");
|
|
BlRtlHalt();
|
|
}
|
|
|
|
Next = (PCHAR)BlRtlFindSubstring(Next, "Path=");
|
|
|
|
if (Next == NULL) {
|
|
|
|
goto ParseFailure;
|
|
}
|
|
|
|
Next += 5;
|
|
|
|
if (*Next == 0) {
|
|
|
|
goto ParseFailure;
|
|
}
|
|
|
|
DistroFile = (PBL_DISTRO_FILE) BlPoolAllocateBlock(sizeof(BL_DISTRO_FILE));
|
|
|
|
BLASSERT((NewLine - Next) < sizeof(DistroFile->Path));
|
|
|
|
Temp = (PCHAR)Next;
|
|
|
|
while (Temp != NewLine) {
|
|
|
|
if (*Temp == '\\') {
|
|
|
|
*Temp = '/';
|
|
}
|
|
|
|
Temp += 1;
|
|
}
|
|
|
|
BlRtlCopyMemory(DistroFile->Path, Next, NewLine - Next);
|
|
|
|
//
|
|
// By convention with DistroBuiderl, the first file with a size of zero is
|
|
// really the INI file, so we need to set its size.
|
|
//
|
|
if (Size == 0) {
|
|
Size = BlIniFileSize;
|
|
}
|
|
|
|
DistroFile->Size = Size;
|
|
|
|
BlDistro.NumberOfFiles += 1;
|
|
BlDistro.TotalSize += Size;
|
|
|
|
BlRtlInsertTailList(&BlDistro.FileList, &DistroFile->Entry);
|
|
}
|
|
|
|
//
|
|
// Read distro files.
|
|
//
|
|
|
|
BlDistro.Data = (PVOID) BlMmAllocatePhysicalRegion(ROUND_UP_TO_PAGES(BlDistro.TotalSize), BL_MM_PHYSICAL_REGION_DISTRO);
|
|
|
|
#if DISTRO_VERBOSE
|
|
|
|
BlKdPrintf("DISTRO: Reading distro (%u files , %u bytes).\n",
|
|
BlDistro.NumberOfFiles,
|
|
BlDistro.TotalSize);
|
|
|
|
#endif
|
|
|
|
FilesRead = 0;
|
|
BytesRead = 0;
|
|
|
|
Next = (PCHAR) BlDistro.Data;
|
|
Head = &BlDistro.FileList;
|
|
|
|
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) {
|
|
|
|
DistroFile = CONTAINING_RECORD(Entry, BL_DISTRO_FILE, Entry);
|
|
|
|
DistroFile->Data = Next;
|
|
|
|
BLASSERT(DistroFile->Path[0] == '/');
|
|
|
|
#if DISTRO_VERBOSE
|
|
|
|
BlKdPrintf("DISTRO: %s [%u bytes]\n",
|
|
DistroFile->Path,
|
|
DistroFile->Size);
|
|
|
|
#endif
|
|
|
|
if (BlFsReadFile(&DistroFile->Path[1], DistroFile->Data, DistroFile->Size) == FALSE) {
|
|
|
|
BlRtlPrintf("\n"
|
|
"BL: Error reading %s!\n",
|
|
DistroFile->Path);
|
|
|
|
BlRtlHalt();
|
|
}
|
|
|
|
Next += DistroFile->Size;
|
|
|
|
FilesRead += 1;
|
|
BytesRead += DistroFile->Size;
|
|
|
|
BlVideoPrintf("\rReading distro files ... %u / %u [%u / %u]",
|
|
FilesRead,
|
|
BlDistro.NumberOfFiles,
|
|
BytesRead,
|
|
BlDistro.TotalSize);
|
|
|
|
}
|
|
|
|
BlVideoPrintf("\n");
|
|
|
|
//
|
|
// If this is a network boot, then signal the PXE server to exit.
|
|
// This is the only mechanism to notify the server that the boot succeeded.
|
|
//
|
|
|
|
if (BlGetBeb()->BootType == BL_PXE_BOOT) {
|
|
|
|
BlFsGetFileSize("end.:", &DummySize);
|
|
}
|
|
|
|
//
|
|
// Switch distro range to read-only.
|
|
//
|
|
|
|
BlMmMapVirtualRange(BlDistro.Data,
|
|
BlDistro.Data,
|
|
BlDistro.TotalSize,
|
|
FALSE,
|
|
TRUE,
|
|
FALSE);
|
|
|
|
//
|
|
// Build file image table.
|
|
//
|
|
|
|
BlSingularityFileImageTable = (Struct_Microsoft_Singularity_Io_FileImage *) BlPoolAllocateBlock(BlDistro.NumberOfFiles * sizeof(Struct_Microsoft_Singularity_Io_FileImage));
|
|
|
|
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) {
|
|
|
|
DistroFile = CONTAINING_RECORD(Entry, BL_DISTRO_FILE, Entry);
|
|
|
|
BlSingularityFileImageTable[BlSingularityFileImageTableSize].Address = (ULONG_PTR) DistroFile->Data;
|
|
BlSingularityFileImageTable[BlSingularityFileImageTableSize].Size = DistroFile->Size;
|
|
BlSingularityFileImageTableSize += 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
BlSingularityLoadKernelImage(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function loads the kernel image.
|
|
//
|
|
//--
|
|
|
|
{
|
|
BLASSERT(BlRtlIsListEmpty(&BlDistro.FileList) == FALSE);
|
|
|
|
//
|
|
// Kernel is the first entry in the distro file list.
|
|
//
|
|
|
|
BlKernelFile = CONTAINING_RECORD(BlDistro.FileList.Flink,
|
|
BL_DISTRO_FILE,
|
|
Entry);
|
|
|
|
//
|
|
// Get the virtual range for the kernel image.
|
|
//
|
|
|
|
BlPeGetVirtualRange(BlKernelFile->Data, &BlKernelBase, &BlKernelSize);
|
|
|
|
BLASSERT(((UINT64) BlKernelBase % PAGE_SIZE) == 0);
|
|
|
|
BLASSERT((BlKernelSize % PAGE_SIZE) == 0);
|
|
|
|
//
|
|
// Allocate a physical region for the kernel image, since pages are identity mapped at boot.
|
|
//
|
|
// AIFIX: This needs to be be made dynamic!
|
|
//
|
|
|
|
if (BlMmAllocateSpecificPhysicalRegion((UINT64) BlKernelBase,
|
|
BlKernelSize,
|
|
BL_MM_PHYSICAL_REGION_KERNEL_IMAGE) == FALSE) {
|
|
|
|
BlMmDumpPhysicalRegionList();
|
|
|
|
BlRtlHalt();
|
|
}
|
|
|
|
#if SINGULARITY_VERBOSE
|
|
|
|
BlRtlPrintf("BL: Loading kernel ... [%p ... %p]\n",
|
|
BlKernelBase,
|
|
(ULONG_PTR) BlKernelBase + BlKernelSize - 1);
|
|
|
|
#endif
|
|
|
|
BlPeLoadImage(BlKernelBase, BlKernelFile->Data, (PVOID *) &BlKernelEntryPoint);
|
|
|
|
}
|
|
|
|
//
|
|
// AIFIX: Fix task page definition.
|
|
//
|
|
|
|
#if defined(BOOT_X86)
|
|
|
|
typedef Struct_Microsoft_Singularity_Isal_IX_TSS BL_TASK_SEGMENT;
|
|
|
|
#elif defined(BOOT_X64)
|
|
|
|
typedef Struct_Microsoft_Singularity_Isal_IX_TSS64 BL_TASK_SEGMENT;
|
|
|
|
#endif
|
|
|
|
typedef struct _BL_PROCESSOR {
|
|
UINT32 Index;
|
|
Class_Microsoft_Singularity_Hal_Cpu *Cpu;
|
|
PVOID KernelStack;
|
|
ULONG_PTR KernelStackSize;
|
|
PVOID ContextPage;
|
|
PVOID BasePage;
|
|
BL_TASK_SEGMENT *TaskPage;
|
|
} BL_PROCESSOR, *PBL_PROCESSOR;
|
|
|
|
PBL_PROCESSOR BlProcessor;
|
|
UINT32 BlProcessorCount;
|
|
|
|
VOID
|
|
BlSingularityInitializeProcessor(
|
|
UINT32 Index
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function initializes the specified processor.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Index - Supplies the index of the processor to initialize.
|
|
//
|
|
//--
|
|
|
|
{
|
|
Class_Microsoft_Singularity_Hal_Cpu *Processor;
|
|
|
|
//
|
|
// Initialize native processor structure.
|
|
//
|
|
|
|
Processor = BlProcessor[Index].Cpu;
|
|
Processor->Size = sizeof(Class_Microsoft_Singularity_Hal_Cpu);
|
|
Processor->Id = Index;
|
|
#if 0
|
|
Processor->ApicId = Index;
|
|
#endif
|
|
Processor->KernelStackLimit = (ULONG_PTR) BlProcessor[Index].KernelStack;
|
|
// Processor->KernelStackBegin = Processor->KernelStackLimit + SINGULARITY_KERNEL_STACK_SIZE;
|
|
Processor->KernelStackBegin = Processor->KernelStackLimit + BlProcessor[Index].KernelStackSize;
|
|
Processor->CpuRecordPage = (ULONG_PTR) BlProcessor[Index].BasePage;
|
|
|
|
//
|
|
// Initialize task structure.
|
|
//
|
|
|
|
BlProcessor[Index].TaskPage->io_bitmap_offset = sizeof(BL_TASK_SEGMENT);
|
|
|
|
//
|
|
// Initialize segments.
|
|
//
|
|
|
|
BlRtlZeroMemory(&Processor->segments, sizeof(Processor->segments));
|
|
|
|
Processor->segments.gdtPtr.addr = (ULONG_PTR) &Processor->segments.gdt;
|
|
Processor->segments.gdtPtr.limit = sizeof(Processor->segments.gdt) - 1;
|
|
|
|
BlRtlCopyMemory(&Processor->segments.gdt.pc,
|
|
(PVOID) (BlMmInitialGdtr.Base + PM_CODE_SELECTOR),
|
|
sizeof(CODE_SEGMENT));
|
|
|
|
BlRtlCopyMemory(&Processor->segments.gdt.pd,
|
|
(PVOID) (BlMmInitialGdtr.Base + PM_DATA_SELECTOR),
|
|
sizeof(CODE_SEGMENT));
|
|
|
|
#if defined(BOOT_X64)
|
|
BlRtlCopyMemory(&Processor->segments.gdt.lc,
|
|
(PVOID) (BlMmInitialGdtr.Base + LM_CODE_SELECTOR),
|
|
sizeof(CODE_SEGMENT));
|
|
|
|
BlRtlCopyMemory(&Processor->segments.gdt.ld,
|
|
(PVOID) (BlMmInitialGdtr.Base + LM_DATA_SELECTOR),
|
|
sizeof(CODE_SEGMENT));
|
|
#endif
|
|
|
|
BlMmInitializeDataSegment((PDATA_SEGMENT) &Processor->segments.gdt.pp,
|
|
(UINT32) (ULONG_PTR) BlProcessor[Index].ContextPage,
|
|
PAGE_SIZE - 1);
|
|
|
|
BlMmInitializeSystemSegment((PSYSTEM_SEGMENT) &Processor->segments.gdt.tss,
|
|
SSDT_AVAILABLE_TSS,
|
|
(ULONG_PTR) BlProcessor[Index].TaskPage,
|
|
sizeof(BL_TASK_SEGMENT) - 1);
|
|
|
|
return;
|
|
}
|
|
|
|
UINT32 BlSingularityProcessorToStart;
|
|
|
|
UINT32
|
|
BlSingularityCallKernel(
|
|
UINT32 Index
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function calls the kernel.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Index - Supplies the index of the current processor.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Kernel exit code.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT32 ExitCode;
|
|
|
|
#if SINGULARITY_VERBOSE
|
|
|
|
|
|
BlRtlPrintf("\fBL: Processor[%d]: Starting Singularity ...\n",
|
|
Index
|
|
);
|
|
|
|
BlRtlPrintf("BL: Cpu = %p\n",
|
|
BlProcessor[Index].Cpu
|
|
);
|
|
|
|
|
|
BlRtlPrintf("BL: GDT =[%p...%p]\n",
|
|
BlProcessor[Index].Cpu->segments.gdtPtr.addr,
|
|
BlProcessor[Index].Cpu->segments.gdtPtr.addr + BlProcessor[Index].Cpu->segments.gdtPtr.limit
|
|
);
|
|
|
|
|
|
BlRtlPrintf("BL: stack=[%p...%p]\n",
|
|
BlProcessor[Index].Cpu->KernelStackLimit,
|
|
BlProcessor[Index].Cpu->KernelStackBegin
|
|
);
|
|
|
|
#endif
|
|
|
|
BlMmSetGdtr((PGDTR) &BlProcessor[Index].Cpu->segments.gdtPtr.limit);
|
|
|
|
#if defined(BOOT_X86)
|
|
|
|
BlMmSetFs(PROCESSOR_SELECTOR);
|
|
|
|
#elif defined(BOOT_X64)
|
|
|
|
BlMmSetGs(PROCESSOR_SELECTOR);
|
|
|
|
#endif
|
|
|
|
BlMmSetCr3(BlMmBootCr3);
|
|
|
|
BlRtlPrintf("BL: kernel=[%p ... %p]\n",
|
|
BlKernelBase, (ULONG_PTR) BlKernelBase + BlKernelSize - 1);
|
|
BlRtlPrintf("BL: entry= %p\n", BlKernelEntryPoint);
|
|
|
|
|
|
ExitCode = BlKernelEntryPoint(BlPlatform, BlProcessor[Index].Cpu);
|
|
|
|
BlMmSetGdtr(&BlMmInitialGdtr);
|
|
|
|
BlVideoInitialize();
|
|
|
|
return ExitCode;
|
|
}
|
|
|
|
VOID
|
|
BlSingularityEnterKernel(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function enters Singularity.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT32 ExitCode;
|
|
PVOID LocalVariable;
|
|
UINT32 Index;
|
|
|
|
Index = BlSingularityProcessorToStart;
|
|
|
|
BLASSERT(((ULONG_PTR) &LocalVariable) >= BlProcessor[Index].Cpu->KernelStackLimit);
|
|
|
|
BLASSERT(((ULONG_PTR) &LocalVariable) < BlProcessor[Index].Cpu->KernelStackBegin);
|
|
|
|
//
|
|
// The bootstrap processor runs in a loop calling kernel entry point and performing warm boot
|
|
// when the kernel returns. The application processors do not return from the kernel call and are
|
|
// reinitialized with SIPIs by the kernel after a warm boot.
|
|
//
|
|
|
|
if (Index == 0) {
|
|
|
|
for (;;) {
|
|
BlMmDumpPhysicalRegionList();
|
|
ExitCode = BlSingularityCallKernel(Index);
|
|
|
|
#if SINGULARITY_VERBOSE
|
|
|
|
BlRtlPrintf("BL: Processor[%02x]: Kernel exited with 0x%08x.\n",
|
|
Index,
|
|
ExitCode);
|
|
|
|
#endif
|
|
|
|
BlPlatform->BootCount += 1;
|
|
|
|
BlRtlZeroMemory(BlKernelBase, BlKernelSize);
|
|
|
|
BlPeLoadImage(BlKernelBase, BlKernelFile->Data, (PVOID *) &BlKernelEntryPoint);
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
ExitCode = BlSingularityCallKernel(Index);
|
|
|
|
BlRtlPrintf("BL: AP returned from kernel call!\n");
|
|
|
|
BlRtlHalt();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
BlSingularityExit(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function exits Singularity and performs the "kill action" requested by the kernel.
|
|
//
|
|
//--
|
|
|
|
{
|
|
BlMmSetGdtr(&BlMmInitialGdtr);
|
|
|
|
BlVideoInitialize();
|
|
|
|
switch (BlPlatform->KillAction) {
|
|
|
|
case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_SHUTDOWN: {
|
|
|
|
BlRtlPrintf("BL: Kernel requested shutdown.\n");
|
|
|
|
BlRtlShutdownSystem();
|
|
|
|
break;
|
|
}
|
|
|
|
case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_RESTART: {
|
|
|
|
BlRtlPrintf("BL: Kernel requested restart.\n");
|
|
|
|
BlRtlResetSystem();
|
|
|
|
break;
|
|
}
|
|
|
|
case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_HALT: {
|
|
|
|
BlRtlPrintf("BL: Kernel requested halt.\n");
|
|
|
|
BlRtlHalt();
|
|
|
|
break;
|
|
}
|
|
|
|
case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_WARMBOOT: {
|
|
|
|
BlRtlPrintf("BL: Kernel requested warmboot.\n");
|
|
|
|
BlPlatform->BootCount += 1;
|
|
|
|
BlRtlZeroMemory(BlKernelBase, BlKernelSize);
|
|
|
|
BlPeLoadImage(BlKernelBase, BlKernelFile->Data, (PVOID *) &BlKernelEntryPoint);
|
|
|
|
BlSingularityProcessorToStart = 0;
|
|
|
|
BlMmSwitchStack((PVOID) BlProcessor[0].Cpu->KernelStackBegin, BlSingularityEnterKernel);
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
|
|
BlRtlPrintf("BL: Unrecognized kill action 0x%08x!\n", BlPlatform->KillAction);
|
|
|
|
BlRtlHalt();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
unsigned int IsApicPresent (void)
|
|
{
|
|
unsigned int reg_edx = BlGetCpuidEdx(1);
|
|
|
|
return ((reg_edx >> 9) & 0x1);
|
|
}
|
|
|
|
#define INITIAL_APIC_ID_BITS 0xFF000000 // EBX[31:24] unique APIC ID
|
|
// Returns the 8-bit unique Initial APIC ID for the processor this
|
|
// code is actually running on. The default value returned is 0xFF if
|
|
// Hyper-Threading Technology is not supported.
|
|
// Taken from intel application note Ap-485 "Intel Processor Identification and the CPUID instruction"
|
|
unsigned char GetAPIC_ID (void)
|
|
{
|
|
unsigned int reg_ebx = BlGetCpuidEbx(1);
|
|
|
|
return (unsigned char) ((reg_ebx & INITIAL_APIC_ID_BITS) >> 24);
|
|
}
|
|
|
|
VOID
|
|
BlSingularityInitialize(
|
|
UINT32 NumberOfProcessors,
|
|
PFAR_POINTER ApEntry16,
|
|
PFAR_POINTER ApStartupLock
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function initializes Singularity.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// NumberOfProcessors - Supplies the number of processors on the system.
|
|
//
|
|
// ApEntry6 - Supplies a pointer to the 16-bit entry point for
|
|
// application processors on a multi-processor system.
|
|
//
|
|
// ApStartupLock - Supplies a pointer to the lock used for AP startup
|
|
// synchronization.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT64 Base;
|
|
UINT32 Index;
|
|
PVOID PhysicalRegionHandle;
|
|
UINT64 Size;
|
|
UINT32 Type;
|
|
UINT8 id;
|
|
UINT64 HighAddress;
|
|
UINT64 TempAddress;
|
|
UINT64 StackStart;
|
|
UINT64 PlayStart;
|
|
int i;
|
|
char* p;
|
|
|
|
//
|
|
// Allocate processor array and set processor count.
|
|
//
|
|
|
|
BlProcessor = (PBL_PROCESSOR) BlPoolAllocateBlock(sizeof(BL_PROCESSOR) * NumberOfProcessors);
|
|
BlProcessorCount = NumberOfProcessors;
|
|
|
|
//
|
|
// Load distro.
|
|
//
|
|
|
|
BlSingularityLoadDistro();
|
|
|
|
//
|
|
// Load kernel image.
|
|
//
|
|
|
|
BlSingularityLoadKernelImage();
|
|
|
|
//
|
|
// Allocate native platform structure.
|
|
//
|
|
|
|
BlPlatform = (Class_Microsoft_Singularity_Hal_Platform *) BlMmAllocatePhysicalRegion(ROUND_UP_TO_PAGES(sizeof(Class_Microsoft_Singularity_Hal_Platform)), BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM);
|
|
|
|
BlPlatform->Size = sizeof(Class_Microsoft_Singularity_Hal_Platform);
|
|
|
|
if (IsApicPresent()) {
|
|
BlPlatform->hasApic = 1;
|
|
}
|
|
else {
|
|
BlPlatform->hasApic = 0;
|
|
}
|
|
|
|
//
|
|
// Set offsets for per-cpu and per-thread pointers.
|
|
//
|
|
|
|
BlPlatform->CpuRecordPointerOffset = 0;
|
|
BlPlatform->ThreadRecordPointerOffset = sizeof(PTR_TYPE);
|
|
|
|
//
|
|
// Set boot time.
|
|
//
|
|
|
|
if (BlStartTime.Year != 0) {
|
|
BlPlatform->BootYear = 2000 + BlStartTime.Year;
|
|
BlPlatform->BootMonth = BlStartTime.Month;
|
|
BlPlatform->BootDay = BlStartTime.Day;
|
|
BlPlatform->BootHour = BlStartTime.Hour;
|
|
BlPlatform->BootMinute = BlStartTime.Minute;
|
|
BlPlatform->BootSecond = BlStartTime.Second;
|
|
}
|
|
|
|
//
|
|
// Set processor count.
|
|
//
|
|
|
|
BlPlatform->CpuRealCount = NumberOfProcessors;
|
|
BlPlatform->CpuMaxCount = NumberOfProcessors;
|
|
|
|
//
|
|
// Set MPS floating pointer structure address.
|
|
//
|
|
|
|
BlPlatform->MpFloat32 = (UINT32) (ULONG_PTR) BlMpsFps;
|
|
|
|
//
|
|
// Set kernel range.
|
|
//
|
|
|
|
BlPlatform->KernelDllBase = (ULONG_PTR) BlKernelBase;
|
|
BlPlatform->KernelDllFirstPage = (ULONG_PTR) BlKernelBase;
|
|
BlPlatform->KernelDllSize = BlKernelSize;
|
|
|
|
//
|
|
// Set command line.
|
|
//
|
|
|
|
BlPlatform->CommandLine32 = (ULONG_PTR) BlCommandLine;
|
|
BlPlatform->CommandLineCount = BlRtlStringLengthW(BlCommandLine);
|
|
|
|
//
|
|
// Set PNP node list address.
|
|
//
|
|
|
|
BlPlatform->PnpNodesAddr32 = (ULONG_PTR) BlPnpSystemDeviceNodeList;
|
|
BlPlatform->PnpNodesSize32 = BlPnpSystemDeviceNodeListSize;
|
|
|
|
//
|
|
// Set ISA information.
|
|
//
|
|
|
|
BlPlatform->IsaCsns = BlPnpIsaConfiguration.NumberOfCardSelectNumbers;
|
|
BlPlatform->IsaReadPort = BlPnpIsaConfiguration.DataReadPort;
|
|
|
|
//
|
|
// Set PCI BIOS information.
|
|
//
|
|
|
|
BlPlatform->PciBiosAX = BlPciInstallationCheck.Eax;
|
|
BlPlatform->PciBiosBX = BlPciInstallationCheck.Ebx;
|
|
BlPlatform->PciBiosCX = BlPciInstallationCheck.Ecx;
|
|
BlPlatform->PciBiosEDX = BlPciInstallationCheck.Edx;
|
|
|
|
//
|
|
// Set VESA information.
|
|
//
|
|
|
|
BlPlatform->VesaBuffer = BlVesaVideoBuffer;
|
|
|
|
//
|
|
// Set ACPI information.
|
|
//
|
|
|
|
BlPlatform->AcpiRoot32 = (ULONG_PTR) BlAcpiRsdpAddress;
|
|
|
|
//
|
|
// Set file image table.
|
|
//
|
|
|
|
BlPlatform->FileImageTableBase32 = (ULONG_PTR) BlSingularityFileImageTable;
|
|
BlPlatform->FileImageTableEntries = BlSingularityFileImageTableSize;
|
|
|
|
//
|
|
// Allocate log record and text buffers.
|
|
//
|
|
|
|
BlPlatform->LogRecordBuffer = (ULONG_PTR) BlMmAllocatePhysicalRegion(SINGULARITY_LOG_RECORD_SIZE, BL_MM_PHYSICAL_REGION_LOG_RECORD);
|
|
BlPlatform->LogRecordSize = SINGULARITY_LOG_RECORD_SIZE;
|
|
|
|
BlPlatform->LogTextBuffer = (ULONG_PTR) BlMmAllocatePhysicalRegion(SINGULARITY_LOG_TEXT_SIZE, BL_MM_PHYSICAL_REGION_LOG_TEXT);
|
|
BlPlatform->LogTextSize = SINGULARITY_LOG_TEXT_SIZE;
|
|
|
|
//
|
|
// Set debugger settings.
|
|
//
|
|
|
|
if (BlKdComPort != 0) {
|
|
|
|
BlPlatform->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_SERIAL;
|
|
BlPlatform->DebugBasePort = BlComBasePort[BlKdComPort];
|
|
|
|
}
|
|
else if (BlPciOhci1394BaseAddress != 0) {
|
|
|
|
BlRtlPrintf("Got 1394 debugger base address!\n");
|
|
BlPlatform->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_1394;
|
|
BlPlatform->Ohci1394Base = BlPciOhci1394BaseAddress;
|
|
BlPlatform->Ohci1394BufferAddr32 = (ULONG_PTR) BlSingularityOhci1394Buffer;
|
|
BlPlatform->Ohci1394BufferSize32 = sizeof(BlSingularityOhci1394Buffer);
|
|
|
|
}
|
|
else {
|
|
|
|
BlRtlPrintf("Debugger OFF\n");
|
|
BlPlatform->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_NONE;
|
|
|
|
}
|
|
|
|
BlPlatform->TwiddleSpinBase = 0xb8000;
|
|
|
|
//
|
|
// Set exit routine.
|
|
//
|
|
|
|
BlPlatform->Kill32 = (ULONG_PTR) BlSingularityExit;
|
|
|
|
//
|
|
// Set entry routine and startup lock address for application processors.
|
|
//
|
|
|
|
BlPlatform->MpEnter32 = (ULONG_PTR) BlRtlConvertFarPointerToLinearPointer(ApEntry16);
|
|
BlPlatform->MpStartupLock32 = (ULONG_PTR) BlRtlConvertFarPointerToLinearPointer(ApStartupLock);
|
|
|
|
//
|
|
// Allocate native processor structures.
|
|
//
|
|
|
|
BlCpuArray =
|
|
(Class_Microsoft_Singularity_Hal_Cpu *) BlMmAllocatePhysicalRegion(ROUND_UP_TO_PAGES(sizeof(Class_Microsoft_Singularity_Hal_Cpu) * NumberOfProcessors), BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR);
|
|
|
|
BlPlatform->Cpus = (ULONG_PTR) BlCpuArray;
|
|
|
|
//
|
|
// Allocate per-processor resources upfront.
|
|
//
|
|
|
|
for (Index = 0; Index < NumberOfProcessors; Index += 1) {
|
|
|
|
BlProcessor[Index].Index = Index;
|
|
BlProcessor[Index].Cpu = &BlCpuArray[Index];
|
|
BlProcessor[Index].ContextPage = (PVOID) BlMmAllocatePhysicalRegion(2 * PAGE_SIZE, BL_MM_PHYSICAL_REGION_CONTEXT);
|
|
BlProcessor[Index].BasePage = (PVOID) ((ULONG_PTR) BlProcessor[Index].ContextPage + PAGE_SIZE);
|
|
BlProcessor[Index].TaskPage = (BL_TASK_SEGMENT *) BlMmAllocatePhysicalRegion(PAGE_SIZE, BL_MM_PHYSICAL_REGION_TASK);
|
|
}
|
|
|
|
//
|
|
// Allocate kernel stack for the bootstrap processor.
|
|
//
|
|
|
|
StackStart = BlMmAllocatePhysicalRegion(SINGULARITY_KERNEL_STACK_SIZE,
|
|
BL_MM_PHYSICAL_REGION_KERNEL_STACK);
|
|
if (0 == StackStart) {
|
|
BlRtlPrintf("Failed to allocate kernel stack.\n", StackStart);
|
|
BlRtlHalt();
|
|
}
|
|
|
|
BlRtlPrintf("Allocated kernel stack at 0x%016I64x\n", StackStart);
|
|
|
|
BlProcessor[0].KernelStack = (PVOID) (StackStart);
|
|
BlProcessor[0].Cpu->DomainBsp = TRUE;
|
|
|
|
BlPlatform->OutgoingMessage = 0;
|
|
BlPlatform->OutgoingCount = 0;
|
|
BlPlatform->IncomingFree = 0;
|
|
BlPlatform->IncomingFreeCount = 0;
|
|
BlPlatform->IncomingMessage = 0;
|
|
BlPlatform->IncomingCount = 0;
|
|
BlPlatform->OutgoingFree = 0;
|
|
BlPlatform->OutgoingFreeCount = 0;
|
|
BlPlatform->MaxBufferLength = 0;
|
|
|
|
BlProcessor[0].KernelStackSize = SINGULARITY_KERNEL_STACK_SIZE;
|
|
|
|
//
|
|
// Initialize the first processor structure.
|
|
//
|
|
|
|
BlSingularityInitializeProcessor(0);
|
|
|
|
//
|
|
// Allocate memory map for Singularity.
|
|
//
|
|
|
|
BlSingularitySmap = (PBL_SMAP) BlMmAllocatePhysicalRegion(sizeof(BL_SMAP), BL_MM_PHYSICAL_REGION_SINGULARITY_SMAP);
|
|
|
|
//
|
|
// Claim all remaining physical memory for Singularity.
|
|
//
|
|
|
|
while (BlMmFindFreePhysicalRegion(&Base, &Size) != FALSE) {
|
|
|
|
BlMmAllocateSpecificPhysicalRegion(Base, Size, BL_MM_PHYSICAL_REGION_SINGULARITY);
|
|
}
|
|
|
|
//
|
|
// Generate memory map for Singularity.
|
|
//
|
|
|
|
BlRtlZeroMemory(BlSingularitySmap, sizeof(BL_SMAP));
|
|
|
|
BlPlatform->PhysicalBase = (ULONG_PTR) -1;
|
|
|
|
PhysicalRegionHandle = NULL;
|
|
|
|
while (BlMmGetNextPhysicalRegion(&PhysicalRegionHandle,
|
|
&Base,
|
|
&Size,
|
|
&Type) != FALSE) {
|
|
|
|
if ((Type == BL_MM_PHYSICAL_REGION_SINGULARITY) ||
|
|
(Type == BL_MM_PHYSICAL_REGION_KERNEL_IMAGE) ||
|
|
(Type == BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM) ||
|
|
(Type == BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR) ||
|
|
(Type == BL_MM_PHYSICAL_REGION_KERNEL_STACK)
|
|
) {
|
|
|
|
if (Type == BL_MM_PHYSICAL_REGION_SINGULARITY) {
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_AVAILABLE;
|
|
}
|
|
else if (Type == BL_MM_PHYSICAL_REGION_KERNEL_IMAGE ||
|
|
(Type == BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM) ||
|
|
(Type == BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR)) {
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_KERNEL_NONGC;
|
|
}
|
|
else if (Type == BL_MM_PHYSICAL_REGION_KERNEL_STACK) {
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_KERNEL_STACK;
|
|
}
|
|
else {
|
|
BlRtlPrintf("UNKNOWN TYPE MEMORY??? %d\n", Type);
|
|
}
|
|
if (Base < BlPlatform->PhysicalBase) {
|
|
BlPlatform->PhysicalBase = (ULONG_PTR) Base;
|
|
}
|
|
BlSingularitySmap->EntryCount += 1;
|
|
}
|
|
else {
|
|
#if MM_VERBOSE
|
|
BlRtlPrintf("Building SMAP marking type %s nongc\n", BlMmPhysicalRegionTypeString(Type));
|
|
#endif
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size;
|
|
BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_KERNEL_NONGC;
|
|
BlSingularitySmap->EntryCount += 1;
|
|
}
|
|
}
|
|
|
|
BlPlatform->Smap32 = (ULONG_PTR) (PVOID) BlSingularitySmap->Entry;
|
|
BlPlatform->SmapCount = BlSingularitySmap->EntryCount;
|
|
|
|
#if MM_VERBOSE
|
|
|
|
BlMmDumpPhysicalRegionList();
|
|
|
|
#endif
|
|
|
|
//
|
|
// Start processor 0.
|
|
//
|
|
|
|
BlSingularityProcessorToStart = 0;
|
|
|
|
BlMmSwitchStack((PVOID) BlProcessor[0].Cpu->KernelStackBegin, BlSingularityEnterKernel);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
BlSingularityApEntry(
|
|
VOID
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function implements the entry point for application processors.
|
|
//
|
|
//--
|
|
|
|
{
|
|
UINT32 Index;
|
|
|
|
UINT8 MyIdChar;
|
|
UINT32 MyId;
|
|
UINT32 MyStack;
|
|
Class_Microsoft_Singularity_Hal_Cpu *Processor;
|
|
// BlRtlPrintf("In Ap Entry\n");
|
|
|
|
// BlRtlPrintf("Non AP processor booting\n");
|
|
Index = BlPlatform->MpBootInfo.TargetCpu;
|
|
|
|
if (Index == 0) {
|
|
|
|
// BlRtlPrintf("BL: BSP entered AP code!\n");
|
|
BlRtlHalt();
|
|
}
|
|
|
|
#if SINGULARITY_VERBOSE
|
|
|
|
BlRtlPrintf("BL: Initializing processor %u of %u. [Max=%u]\n",
|
|
Index + 1,
|
|
BlPlatform->CpuRealCount,
|
|
BlPlatform->CpuMaxCount);
|
|
|
|
#endif
|
|
|
|
BlProcessor[Index].KernelStack = (PVOID) BlPlatform->MpBootInfo.KernelStackLimit;
|
|
BlProcessor[Index].Cpu->DomainBsp = FALSE;
|
|
BlProcessor[Index].KernelStackSize = BlPlatform->MpBootInfo.KernelStackBegin - BlPlatform->MpBootInfo.KernelStackLimit;
|
|
|
|
BlSingularityInitializeProcessor(Index);
|
|
|
|
BlSingularityProcessorToStart = Index;
|
|
|
|
BlMmSwitchStack((PVOID) BlProcessor[Index].Cpu->KernelStackBegin, BlSingularityEnterKernel);
|
|
|
|
return;
|
|
}
|