1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Architecture specific source file to hold multiprocessor functions 5 * COPYRIGHT: Copyright 2023 Justin Miller <justin.miller@reactos.org> 6 * Copyright 2023 Victor Perevertkin <victor.perevertkin@reactos.org> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 typedef struct _APINFO 16 { 17 DECLSPEC_ALIGN(PAGE_SIZE) KIDTENTRY Idt[256]; 18 DECLSPEC_ALIGN(PAGE_SIZE) KGDTENTRY Gdt[128]; 19 DECLSPEC_ALIGN(16) UINT8 NMIStackData[DOUBLE_FAULT_STACK_SIZE]; 20 KIPCR Pcr; 21 ETHREAD Thread; 22 KTSS Tss; 23 KTSS TssDoubleFault; 24 KTSS TssNMI; 25 } APINFO, *PAPINFO; 26 27 typedef struct _AP_SETUP_STACK 28 { 29 PVOID ReturnAddr; 30 PVOID KxLoaderBlock; 31 } AP_SETUP_STACK, *PAP_SETUP_STACK; // Note: expected layout only for 32-bit x86 32 33 /* FUNCTIONS *****************************************************************/ 34 35 CODE_SEG("INIT") 36 VOID 37 NTAPI 38 KeStartAllProcessors(VOID) 39 { 40 PVOID KernelStack, DPCStack; 41 ULONG ProcessorCount = 0; 42 PAPINFO APInfo; 43 44 while (TRUE) 45 { 46 ProcessorCount++; 47 KernelStack = NULL; 48 DPCStack = NULL; 49 50 // Allocate structures for a new CPU. 51 APInfo = ExAllocatePoolZero(NonPagedPool, sizeof(*APInfo), TAG_KERNEL); 52 if (!APInfo) 53 break; 54 ASSERT(ALIGN_DOWN_POINTER_BY(APInfo, PAGE_SIZE) == APInfo); 55 56 KernelStack = MmCreateKernelStack(FALSE, 0); 57 if (!KernelStack) 58 break; 59 60 DPCStack = MmCreateKernelStack(FALSE, 0); 61 if (!DPCStack) 62 break; 63 64 // Initalize a new PCR for the specific AP 65 KiInitializePcr(ProcessorCount, 66 &APInfo->Pcr, 67 &APInfo->Idt[0], 68 &APInfo->Gdt[0], 69 &APInfo->Tss, 70 (PKTHREAD)&APInfo->Thread, 71 DPCStack); 72 73 // Prepare descriptor tables 74 KDESCRIPTOR bspGdt, bspIdt; 75 __sgdt(&bspGdt.Limit); 76 __sidt(&bspIdt.Limit); 77 RtlCopyMemory(&APInfo->Gdt, (PVOID)bspGdt.Base, bspGdt.Limit + 1); 78 RtlCopyMemory(&APInfo->Idt, (PVOID)bspIdt.Base, bspIdt.Limit + 1); 79 80 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_R0_PCR), (ULONG_PTR)&APInfo->Pcr); 81 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_DF_TSS), (ULONG_PTR)&APInfo->TssDoubleFault); 82 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_NMI_TSS), (ULONG_PTR)&APInfo->TssNMI); 83 84 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_TSS), (ULONG_PTR)&APInfo->Tss); 85 // Clear TSS Busy flag (aka set the type to "TSS (Available)") 86 KiGetGdtEntry(&APInfo->Gdt, KGDT_TSS)->HighWord.Bits.Type = I386_TSS; 87 88 APInfo->TssDoubleFault.Esp0 = (ULONG_PTR)&APInfo->NMIStackData; 89 APInfo->TssDoubleFault.Esp = (ULONG_PTR)&APInfo->NMIStackData; 90 91 APInfo->TssNMI.Esp0 = (ULONG_PTR)&APInfo->NMIStackData; 92 APInfo->TssNMI.Esp = (ULONG_PTR)&APInfo->NMIStackData; 93 94 // Fill the processor state 95 PKPROCESSOR_STATE ProcessorState = &APInfo->Pcr.Prcb->ProcessorState; 96 RtlZeroMemory(ProcessorState, sizeof(*ProcessorState)); 97 98 ProcessorState->SpecialRegisters.Cr0 = __readcr0(); 99 ProcessorState->SpecialRegisters.Cr3 = __readcr3(); 100 ProcessorState->SpecialRegisters.Cr4 = __readcr4(); 101 102 ProcessorState->ContextFrame.SegCs = KGDT_R0_CODE; 103 ProcessorState->ContextFrame.SegDs = KGDT_R3_DATA; 104 ProcessorState->ContextFrame.SegEs = KGDT_R3_DATA; 105 ProcessorState->ContextFrame.SegSs = KGDT_R0_DATA; 106 ProcessorState->ContextFrame.SegFs = KGDT_R0_PCR; 107 108 ProcessorState->SpecialRegisters.Gdtr.Base = (ULONG_PTR)APInfo->Gdt; 109 ProcessorState->SpecialRegisters.Gdtr.Limit = sizeof(APInfo->Gdt) - 1; 110 ProcessorState->SpecialRegisters.Idtr.Base = (ULONG_PTR)APInfo->Idt; 111 ProcessorState->SpecialRegisters.Idtr.Limit = sizeof(APInfo->Idt) - 1; 112 113 ProcessorState->SpecialRegisters.Tr = KGDT_TSS; 114 115 ProcessorState->ContextFrame.Esp = (ULONG_PTR)KernelStack; 116 ProcessorState->ContextFrame.Eip = (ULONG_PTR)KiSystemStartup; 117 ProcessorState->ContextFrame.EFlags = __readeflags() & ~EFLAGS_INTERRUPT_MASK; 118 119 ProcessorState->ContextFrame.Esp = (ULONG)((ULONG_PTR)ProcessorState->ContextFrame.Esp - sizeof(AP_SETUP_STACK)); 120 PAP_SETUP_STACK ApStack = (PAP_SETUP_STACK)ProcessorState->ContextFrame.Esp; 121 ApStack->KxLoaderBlock = KeLoaderBlock; 122 ApStack->ReturnAddr = NULL; 123 124 // Update the LOADER_PARAMETER_BLOCK structure for the new processor 125 KeLoaderBlock->KernelStack = (ULONG_PTR)KernelStack; 126 KeLoaderBlock->Prcb = (ULONG_PTR)&APInfo->Pcr.Prcb; 127 KeLoaderBlock->Thread = (ULONG_PTR)&APInfo->Pcr.Prcb->IdleThread; 128 129 // Start the CPU 130 DPRINT("Attempting to Start a CPU with number: %lu\n", ProcessorCount); 131 if (!HalStartNextProcessor(KeLoaderBlock, ProcessorState)) 132 { 133 break; 134 } 135 136 // And wait for it to start 137 while (KeLoaderBlock->Prcb != 0) 138 { 139 //TODO: Add a time out so we don't wait forever 140 KeMemoryBarrier(); 141 YieldProcessor(); 142 } 143 } 144 145 // The last CPU didn't start - clean the data 146 ProcessorCount--; 147 148 if (APInfo) 149 ExFreePoolWithTag(APInfo, TAG_KERNEL); 150 if (KernelStack) 151 MmDeleteKernelStack(KernelStack, FALSE); 152 if (DPCStack) 153 MmDeleteKernelStack(DPCStack, FALSE); 154 155 DPRINT1("KeStartAllProcessors: Successful AP startup count is %lu\n", ProcessorCount); 156 } 157