redo boot around an explicit system volume and fixed kernel/HAL images, redo volumes and filesystem paths around capabilities instead of drive numbers and kernel CWD state, add a capability/security model with derived and revocable handles and security contexts, add port IPC and rssrv to manage the userspace resource namespace and publish the system volume, move process, dll and path loading to userspace and add process builder syscalls, init now supervises rssrv and the session process, redo the syscall ABI around request structs and four arguments, add a volume manager and proper partition arrival/removal handling so FAT and NTFS mount dynamically, clean up the HAL/DDK boundary so drivers don't depend on HAL internals, save fpu state properly now, the serial driver doesn't hang on a missing port, fix AHCI startup races, fix timeout accounting, fix shared mmap writeback, more smoke tests
This commit is contained in:
1 parent
4add6789ba
commit
f882d339fb
232 files changed
+20934
-8898
No files matched your search
+64
-65
@@ -1,15 +1,16 @@
|
||||
// SMP bring-up and CPU topology management. This file owns AP startup, CPU admission, and topology-derived scheduling metadata.
|
||||
// SMP bring-up and CPU topology management. This file owns secondary-processor admission and topology-derived scheduling metadata.
|
||||
|
||||
// The bootloader is intentionally not involved in AP ownership. The kernel
|
||||
// asks the HAL for MADT-discovered LAPIC IDs, copies a small low-memory x86 AP
|
||||
// startup blob, sends INIT/SIPI through the local APIC, and waits for each AP
|
||||
// to enter KiApKernelEntry() and park in kernel-owned state.
|
||||
// The bootloader is intentionally not involved in secondary-processor ownership.
|
||||
// The kernel asks the HAL for platform processor identities, prepares the x86
|
||||
// bootstrap state, asks the HAL to start each processor, and waits for it to
|
||||
// enter KiApKernelEntry() and park in kernel-owned state.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/status.h>
|
||||
#include <kernel/ke_hal.h>
|
||||
#include <kernel/ke_smp.h>
|
||||
#include <kernel/ke_cpu.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
@@ -21,7 +22,6 @@
|
||||
#include <kernel/mm_phys.h>
|
||||
#include <kernel/mm_pfn.h>
|
||||
#include <kernel/mm_virt.h>
|
||||
#include <kernel/hal/hal_apic.h>
|
||||
|
||||
#define AP_TRAMPOLINE_MAX_PHYS 0x000A0000ULL
|
||||
#define AP_TRAMPOLINE_PREFERRED_MIN 0x00070000ULL
|
||||
@@ -276,13 +276,13 @@ static KSTATUS KiBuildApTrampoline(void) {
|
||||
}
|
||||
|
||||
_Noreturn void KiApKernelEntry(KCPU* cpu) {
|
||||
(void)HalDisableInterrupts();
|
||||
(void)KeDisableInterrupts();
|
||||
|
||||
if (!cpu)
|
||||
HalStopProcessor();
|
||||
KeStopProcessor();
|
||||
|
||||
// APs start from the SIPI reset state, so do not assume the firmware/BSP
|
||||
// CR4 feature bits are present. The scheduler and context-switch paths
|
||||
// Secondary processors enter through the x86 bootstrap path, so do not assume
|
||||
// firmware CR4 feature bits are present. The scheduler and context-switch paths
|
||||
// use FXSAVE/FXRSTOR on every CPU; without OSFXSR, those instructions
|
||||
// raise #UD as soon as an AP enters its idle thread.
|
||||
uintptr_t cr4 = __readcr4();
|
||||
@@ -302,7 +302,7 @@ _Noreturn void KiApKernelEntry(KCPU* cpu) {
|
||||
KeSetUserGsBase(0);
|
||||
if (gApBootBlock) gApBootBlock->Stage = AP_STAGE_GS;
|
||||
|
||||
HalApicEnableCurrentCpu();
|
||||
KeInitializeCurrentProcessorInterruptController();
|
||||
|
||||
KeInitializeGdtForCpu(cpu);
|
||||
KeLoadGdtForCurrentCpu(cpu);
|
||||
@@ -332,41 +332,41 @@ _Noreturn void KiApKernelEntry(KCPU* cpu) {
|
||||
idle->State = ThreadRunning;
|
||||
idle->RunningCpu = cpu->CpuIndex;
|
||||
idle->Queued = 0;
|
||||
// Do not arm the AP's periodic LAPIC timer while it is still in
|
||||
// the raw park loop. Timer IRQs are scheduler-owned events;
|
||||
// the AP may take them only after it has a current idle thread.
|
||||
HalTimerConfigureCurrentCpu();
|
||||
// Do not arm this processor's periodic timer while it is still in the raw
|
||||
// park loop. Timer IRQs are scheduler-owned events and require
|
||||
// a current idle thread before they may be delivered.
|
||||
KeConfigureCurrentProcessorTimer();
|
||||
|
||||
_InterlockedExchange(&cpu->State, KeCpuSchedulerActive);
|
||||
HalEnableInterrupts();
|
||||
KeEnableInterrupts();
|
||||
KeStartInitialThread(idle);
|
||||
}
|
||||
}
|
||||
|
||||
// The BSP admits parked APs by publishing AdmissionRequested and
|
||||
// The boot processor admits parked secondary processors by publishing AdmissionRequested and
|
||||
// sending a wake IPI. Avoid the classic lost wakeup where the state
|
||||
// changes between the poll and HLT: check once with interrupts
|
||||
// disabled, then use STI;HLT as a single sleep transition.
|
||||
uintptr_t interruptFlags = HalDisableInterrupts();
|
||||
uintptr_t interruptFlags = KeDisableInterrupts();
|
||||
if (_InterlockedCompareExchange(&cpu->State, 0, 0) == KeCpuAdmissionRequested) {
|
||||
HalRestoreInterrupts(interruptFlags);
|
||||
KeRestoreInterrupts(interruptFlags);
|
||||
continue;
|
||||
}
|
||||
HalWaitForInterrupt();
|
||||
KeWaitForInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
// Prepares cpu Record.
|
||||
static void KiPrepareCpuRecord(uint32_t cpuIndex, const HAL_CPU_INFO* info) {
|
||||
static void KiPrepareCpuRecord(uint32_t cpuIndex, const HAL_PROCESSOR_INFO* info) {
|
||||
KCPU* cpu = &gCpus[cpuIndex];
|
||||
memset(cpu, 0, sizeof(*cpu));
|
||||
cpu->Self = cpu;
|
||||
cpu->CpuIndex = cpuIndex;
|
||||
cpu->LapicId = info->LapicId;
|
||||
cpu->AcpiProcessorId = info->ProcessorUid;
|
||||
cpu->HardwareId = info->HardwareId;
|
||||
cpu->FirmwareId = info->FirmwareId;
|
||||
cpu->BootProcessorIndex = cpuIndex;
|
||||
cpu->State = info->Enabled ? KeCpuPresent : KeCpuAbsent;
|
||||
cpu->IsBsp = info->IsBsp ? 1 : 0;
|
||||
cpu->IsBootProcessor = info->IsBootProcessor ? 1 : 0;
|
||||
cpu->PackageId = 0;
|
||||
cpu->CoreId = cpuIndex;
|
||||
cpu->ThreadId = 0;
|
||||
@@ -517,11 +517,11 @@ void KeBuildProcessorTopology(void) {
|
||||
if (cpu->State == KeCpuAbsent)
|
||||
continue;
|
||||
|
||||
uint32_t apic = cpu->LapicId;
|
||||
cpu->ThreadId = smtMask ? (apic & smtMask) : 0u;
|
||||
cpu->CoreId = coreBits ? ((apic >> topo.SmtShift) & coreMask) :
|
||||
(apic >> topo.SmtShift);
|
||||
cpu->PackageId = (topo.CoreShift < 32u) ? (apic >> topo.CoreShift) : 0u;
|
||||
uint32_t hardwareId = cpu->HardwareId;
|
||||
cpu->ThreadId = smtMask ? (hardwareId & smtMask) : 0u;
|
||||
cpu->CoreId = coreBits ? ((hardwareId >> topo.SmtShift) & coreMask) :
|
||||
(hardwareId >> topo.SmtShift);
|
||||
cpu->PackageId = (topo.CoreShift < 32u) ? (hardwareId >> topo.CoreShift) : 0u;
|
||||
cpu->PhysicalCoreIndex = KE_INVALID_CPU;
|
||||
cpu->CoreSiblingMask = 0;
|
||||
cpu->PackageMask = 0;
|
||||
@@ -591,9 +591,9 @@ void KeBuildProcessorTopology(void) {
|
||||
KCPU* cpu = &gCpus[i];
|
||||
if (cpu->State == KeCpuAbsent)
|
||||
continue;
|
||||
DbgPrint("SMP: cpu%u lapic=%u pkg=%u core=%u thread=%u primary=%u siblings=0x%llx package=0x%llx\n",
|
||||
DbgPrint("SMP: cpu%u hardware=%u pkg=%u core=%u thread=%u primary=%u siblings=0x%llx package=0x%llx\n",
|
||||
i,
|
||||
cpu->LapicId,
|
||||
cpu->HardwareId,
|
||||
cpu->PackageId,
|
||||
cpu->CoreId,
|
||||
cpu->ThreadId,
|
||||
@@ -656,40 +656,39 @@ static void KiFillBootBlockForCpu(KCPU* cpu, uint32_t apIndex) {
|
||||
|
||||
// Starts application Processors.
|
||||
KSTATUS KeStartApplicationProcessors(void) {
|
||||
HAL_CPU_TOPOLOGY topo;
|
||||
KSTATUS st = HalGetProcessorTopology(&topo);
|
||||
HAL_PROCESSOR_TOPOLOGY topo;
|
||||
KSTATUS st = KeQueryProcessorTopology(&topo);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
|
||||
if (topo.CpuCount == 0 || topo.CpuCount > KE_MAX_CPUS)
|
||||
if (topo.Count == 0 || topo.Count > KE_MAX_CPUS)
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
|
||||
uint32_t bspLapic = HalGetBspLapicId();
|
||||
uint32_t bootHardwareId = topo.BootProcessorHardwareId;
|
||||
KCPU* bsp = KeGetCurrentCpu();
|
||||
bsp->LapicId = bspLapic;
|
||||
bsp->IsBsp = 1;
|
||||
bsp->HardwareId = bootHardwareId;
|
||||
bsp->IsBootProcessor = 1;
|
||||
bsp->State = KeCpuStarted;
|
||||
|
||||
DbgPrint("SMP: APIC mode=%s BSP LAPIC=%u MADT CPUs=%u\n",
|
||||
HalApicUsingX2Apic() ? "x2APIC" : "xAPIC",
|
||||
bspLapic, topo.CpuCount);
|
||||
DbgPrint("SMP: platform processors boot-id=%u firmware-count=%u\n",
|
||||
bootHardwareId, topo.Count);
|
||||
|
||||
uint32_t count = 1;
|
||||
for (uint32_t i = 0; i < topo.CpuCount && count < KE_MAX_CPUS; i++) {
|
||||
HAL_CPU_INFO* info = &topo.Cpus[i];
|
||||
for (uint32_t i = 0; i < topo.Count && count < KE_MAX_CPUS; i++) {
|
||||
HAL_PROCESSOR_INFO* info = &topo.Processors[i];
|
||||
if (KiSmpDiagnosticsEnabled()) {
|
||||
DbgPrint("SMP: topology[%u] uid=%u lapic=%u flags=0x%x enabled=%u bsp=%u addressable=%u\n",
|
||||
i, info->ProcessorUid, info->LapicId, info->Flags,
|
||||
info->Enabled, info->IsBsp, HalApicCanAddressId(info->LapicId));
|
||||
DbgPrint("SMP: topology[%u] firmware=%u hardware=%u flags=0x%x enabled=%u boot=%u startable=%u\n",
|
||||
i, info->FirmwareId, info->HardwareId, info->Flags,
|
||||
info->Enabled, info->IsBootProcessor, info->Startable);
|
||||
}
|
||||
|
||||
if (!info->Enabled) continue;
|
||||
if (info->LapicId == bspLapic) {
|
||||
bsp->AcpiProcessorId = info->ProcessorUid;
|
||||
if (info->HardwareId == bootHardwareId) {
|
||||
bsp->FirmwareId = info->FirmwareId;
|
||||
continue;
|
||||
}
|
||||
if (!HalApicCanAddressId(info->LapicId)) {
|
||||
DbgPrint("SMP: skipping AP uid=%u lapic=%u; current APIC mode cannot address it\n",
|
||||
info->ProcessorUid, info->LapicId);
|
||||
if (!info->Startable) {
|
||||
DbgPrint("SMP: skipping processor firmware=%u hardware=%u; HAL cannot start it\n",
|
||||
info->FirmwareId, info->HardwareId);
|
||||
continue;
|
||||
}
|
||||
KiPrepareCpuRecord(count, info);
|
||||
@@ -697,7 +696,7 @@ KSTATUS KeStartApplicationProcessors(void) {
|
||||
}
|
||||
gCpuCount = count;
|
||||
|
||||
DbgPrint("SMP: discovered %u addressable CPU(s), BSP LAPIC=%u\n", gCpuCount, bspLapic);
|
||||
DbgPrint("SMP: discovered %u usable processor(s), boot hardware ID=%u\n", gCpuCount, bootHardwareId);
|
||||
if (gCpuCount <= 1) {
|
||||
DbgPrint("SMP: no application processors present\n");
|
||||
return NTLSTATUS_SUCCESS;
|
||||
@@ -721,7 +720,6 @@ KSTATUS KeStartApplicationProcessors(void) {
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t sipiVector = (uint8_t)(gApTrampolinePhys >> 12);
|
||||
uint32_t claimed = 0;
|
||||
|
||||
for (uint32_t i = 1; i < gCpuCount; i++) {
|
||||
@@ -730,20 +728,21 @@ KSTATUS KeStartApplicationProcessors(void) {
|
||||
|
||||
st = KiAllocateApStack(cpu);
|
||||
if (!KSUCCESS(st)) {
|
||||
DbgPrint("SMP: AP%u LAPIC=%u stack allocation failed status=0x%x; disabling AP and continuing\n",
|
||||
i, cpu->LapicId, st);
|
||||
DbgPrint("SMP: AP%u hardware=%u stack allocation failed status=0x%x; disabling AP and continuing\n",
|
||||
i, cpu->HardwareId, st);
|
||||
_InterlockedExchange(&cpu->State, KeCpuAbsent);
|
||||
continue;
|
||||
}
|
||||
|
||||
KiFillBootBlockForCpu(cpu, i);
|
||||
if (KiSmpDiagnosticsEnabled())
|
||||
DbgPrint("SMP: starting AP%u LAPIC=%u vector=0x%x\n", i, cpu->LapicId, sipiVector);
|
||||
DbgPrint("SMP: starting AP%u hardware=%u entry=0x%016llX\n",
|
||||
i, cpu->HardwareId, (uint64_t)gApTrampolinePhys);
|
||||
|
||||
st = HalStartApplicationProcessor(cpu->LapicId, sipiVector);
|
||||
st = KeStartProcessor(cpu->HardwareId, gApTrampolinePhys);
|
||||
if (!KSUCCESS(st)) {
|
||||
DbgPrint("SMP: AP%u LAPIC=%u startup IPI failed status=0x%x; disabling AP and continuing\n",
|
||||
i, cpu->LapicId, st);
|
||||
DbgPrint("SMP: AP%u hardware=%u startup IPI failed status=0x%x; disabling AP and continuing\n",
|
||||
i, cpu->HardwareId, st);
|
||||
_InterlockedExchange(&cpu->State, KeCpuAbsent);
|
||||
continue;
|
||||
}
|
||||
@@ -763,8 +762,8 @@ KSTATUS KeStartApplicationProcessors(void) {
|
||||
}
|
||||
|
||||
if (!parked) {
|
||||
DbgPrint("SMP: AP%u failed to reach kernel park state lapic=%u state=%u stage=0x%x(%s) heartbeat=%llu last=%llu; disabling AP and continuing\n",
|
||||
i, cpu->LapicId, gApBootBlock->State, gApBootBlock->Stage,
|
||||
DbgPrint("SMP: AP%u failed to reach kernel park state hardware=%u state=%u stage=0x%x(%s) heartbeat=%llu last=%llu; disabling AP and continuing\n",
|
||||
i, cpu->HardwareId, gApBootBlock->State, gApBootBlock->Stage,
|
||||
KiApStageName(gApBootBlock->Stage), gApBootBlock->Heartbeat, lastHeartbeat);
|
||||
_InterlockedExchange(&cpu->State, KeCpuAbsent);
|
||||
continue;
|
||||
@@ -781,7 +780,7 @@ KSTATUS KeStartApplicationProcessors(void) {
|
||||
}
|
||||
|
||||
if (claimed == 0 && gCpuCount > 1)
|
||||
DbgPrint("SMP: no APs reached kernel-owned state; continuing BSP-only\n");
|
||||
DbgPrint("SMP: no APs reached kernel-owned state; continuing boot-processor-only\n");
|
||||
|
||||
KeBuildProcessorTopology();
|
||||
DbgPrint("SMP: kernel claimed %u APs\n", claimed);
|
||||
@@ -816,12 +815,12 @@ KSTATUS KeAdmitApplicationProcessorsToScheduler(void) {
|
||||
_InterlockedExchange(&cpu->State, KeCpuAdmissionRequested);
|
||||
KiSmpPoolCheckpoint("smp before AP wake", i);
|
||||
|
||||
// Parked APs sleep with HLT and have no LAPIC timer armed yet. The
|
||||
// Parked secondary processors sleep with no periodic timer armed yet. The
|
||||
// state transition alone is not sufficient; send a fixed-vector IPI
|
||||
// only to wake the parked loop. ReschedulePending is intentionally left
|
||||
// clear, so the interrupt exit path will not try to schedule before
|
||||
// the AP has installed its idle thread.
|
||||
HalApicSendRescheduleIpi(cpu->LapicId);
|
||||
KeSendProcessorInterrupt(cpu->HardwareId, KE_VECTOR_RESCHEDULE_IPI);
|
||||
|
||||
int active = 0;
|
||||
for (uint32_t spin = 0; spin < AP_SCHED_TIMEOUT_SPINS; spin++) {
|
||||
@@ -834,8 +833,8 @@ KSTATUS KeAdmitApplicationProcessorsToScheduler(void) {
|
||||
|
||||
if (!active) {
|
||||
KePanic(KE_PANIC_CODE_INIT,
|
||||
"SMP: AP%u failed scheduler admission lapic=%u state=%ld ticks=%llu\n",
|
||||
i, cpu->LapicId, cpu->State, cpu->SchedulerTicks);
|
||||
"SMP: AP%u failed scheduler admission hardware=%u state=%ld ticks=%llu\n",
|
||||
i, cpu->HardwareId, cpu->State, cpu->SchedulerTicks);
|
||||
}
|
||||
|
||||
_InterlockedExchange(&cpu->State, KeCpuOnline);
|
||||
|
||||
Reference in new issue
Block a user