/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { VOID *BaseOfStack; VOID *TopOfStack; EFI_STATUS Status; UINTN PageTables; // // Allocate 128KB for the Stack // BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE)); ASSERT (BaseOfStack != NULL); // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); PageTables = 0; if (FeaturePcdGet (PcdDxeIplBuildPageTables)) { // // Create page table and save PageMapLevel4 to CR3 // PageTables = CreateIdentityMappingPageTables (); } // // End of PEI phase signal // Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); ASSERT_EFI_ERROR (Status); if (FeaturePcdGet (PcdDxeIplBuildPageTables)) { AsmWriteCr3 (PageTables); } // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE); // // Transfer the control to the entry point of DxeCore. // SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, TopOfStack ); }
int main ( int argc, char **argv ) { VOID *BaseMemory; INTN result; CHAR8 *OutputFile = NULL; CHAR8 *InputFile = NULL; EFI_STATUS Status; UINT64 TempValue; SetUtilityName("GenPage"); if (argc == 1) { Usage(); return STATUS_ERROR; } argc --; argv ++; if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) { Usage(); return 0; } if (stricmp (argv[0], "--version") == 0) { Version(); return 0; } while (argc > 0) { if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) { if (argv[1] == NULL || argv[1][0] == '-') { Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option"); return STATUS_ERROR; } OutputFile = argv[1]; argc -= 2; argv += 2; continue; } if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--baseaddr") == 0)) { if (argv[1] == NULL || argv[1][0] == '-') { Error (NULL, 0, 1003, "Invalid option value", "Base address is missing for -b option"); return STATUS_ERROR; } Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue); if (EFI_ERROR (Status)) { Error (NULL, 0, 1003, "Invalid option value", "Base address is not valid intergrator"); return STATUS_ERROR; } gPageTableBaseAddress = (UINT32) TempValue; argc -= 2; argv += 2; continue; } if ((stricmp (argv[0], "-f") == 0) || (stricmp (argv[0], "--offset") == 0)) { if (argv[1] == NULL || argv[1][0] == '-') { Error (NULL, 0, 1003, "Invalid option value", "Offset is missing for -f option"); return STATUS_ERROR; } Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue); if (EFI_ERROR (Status)) { Error (NULL, 0, 1003, "Invalid option value", "Offset is not valid intergrator"); return STATUS_ERROR; } gPageTableOffsetInFile = (UINT32) TempValue; argc -= 2; argv += 2; continue; } if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) { argc --; argv ++; continue; } if ((stricmp (argv[0], "-v") ==0) || (stricmp (argv[0], "--verbose") == 0)) { argc --; argv ++; continue; } if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) { if (argv[1] == NULL || argv[1][0] == '-') { Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not specified."); return STATUS_ERROR; } Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue); if (EFI_ERROR (Status)) { Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not valid intergrator."); return STATUS_ERROR; } if (TempValue > 9) { Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue); return STATUS_ERROR; } argc -= 2; argv += 2; continue; } if (argv[0][0] == '-') { Error (NULL, 0, 1000, "Unknown option", argv[0]); return STATUS_ERROR; } // // Don't recognize the parameter. // InputFile = argv[0]; argc--; argv++; } if (InputFile == NULL) { Error (NULL, 0, 1003, "Invalid option value", "Input file is not specified"); return STATUS_ERROR; } // // Create X64 page table // BaseMemory = CreateIdentityMappingPageTables (); // // Add page table to binary file // result = GenBinPage (BaseMemory, InputFile, OutputFile); if (result < 0) { return STATUS_ERROR; } return 0; }
/*---------------------------------------------------------------------------------------*/ EFI_STATUS InitSmmFoundationCode ( IN EFI_SMM_ACCESS2_PROTOCOL *SmmAccess, IN UINTN TsegBase, IN UINTN TsegSize, IN UINTN SmmFoundationBase ) { EFI_STATUS Status; UINTN ImageSize; EFI_IMAGE_ENTRY_POINT Smm64Entry; UINTN i; EFI_PHYSICAL_ADDRESS Smm16Entry; EFI_PHYSICAL_ADDRESS Smm16Size; EFI_PHYSICAL_ADDRESS Smm16Start; UINT8 CoreCount; SMM_FOUNDATION_TABLE SmmInfo; EFI_PHYSICAL_ADDRESS PageTableEnd; UINTN SmmStackSize; //PageTable+Smm64Entry+Smm16Entry are placed towards the end of Tseg. Carve the reserve space at the end // find the total no. of AP's in the system CoreCount = (UINT8)GetTotalCpuCores (); if (!CoreCount) { return (EFI_NOT_FOUND); } DEBUG ((DEBUG_INFO, "InitSmmFoundationCode:: TsegBase %08x TsegSize %08x SmmFoundationBase %08x\n", TsegBase, TsegSize, SmmFoundationBase)); // First create PageTable at SmmFoundationBase. Needed for 16->64 bit CPU mode PageTableEnd = CreateIdentityMappingPageTables (SmmFoundationBase); DEBUG ((DEBUG_INFO, "Loaded PageTable at %016x\n", SmmFoundationBase)); DEBUG ((DEBUG_INFO, "PageTable ends at %016x\n", PageTableEnd)); // Make sure Page Table doesn't overrun size allotted for it. Leave 1MB for // rest of SmmFoundation code. if (PageTableEnd > (EFI_PHYSICAL_ADDRESS) (TsegBase + TsegSize - 0x100000)) { DEBUG ((DEBUG_ERROR, "Page Table overflowed allotted space\n")); ASSERT (FALSE); } // Next load Smm64 entry point after PageTable ends Status = LoadExeFileInMemory (&SMM64EntryFileGuid , EFI_SECTION_PE32, (EFI_PHYSICAL_ADDRESS)PageTableEnd, &ImageSize, &Smm64Entry); if (EFI_ERROR (Status)) { return Status; } DEBUG ((DEBUG_INFO, "Loaded Smm64Foundation at %08x\n", Smm64Entry)); // PageTable and Smm64 foundation code is in Tseg. This is shared by all core. Next build Smm16Entry // for each core Smm16Size = AsmGetSmm16CodeSize (); SmmStackSize = GetSmmStackSize (); // Smm16Start after PageTable, Smm64 code. Align to 0x200 Smm16Start = ((PageTableEnd + ImageSize + 0x1ff) / 0x200) * 0x200, ZeroMem (&SmmInfo, sizeof (SmmInfo)); // Indicate no SMM Entry has been identified yet, and need to initialize everything. Smm16Entry = NULL; // Relocate all the CPU cores for (i = 0; i < CoreCount; i++) { // Open the SMM area to build SMM PageTable and copy Smm Foundation code // After CPU rsm the SMM area may be closed so make sure to enable again Status = SmmAccess->Open (mSmmAccess); // Find the next available SMM base for Smm16Entry code for each core and update Smm16Entry variable // Smm16 code for each core is after Smm64 foundation code Status = FindNextAvailableSmm16EntryBase ( Smm16Start, (EFI_PHYSICAL_ADDRESS) TsegBase + TsegSize, Smm16Size, &Smm16Entry ); if (EFI_ERROR (Status)) { return Status; } // Update SmmInfo foundation table SmmInfo.StackBase = TsegBase + TsegSize - (i * SmmStackSize); SmmInfo.StackSize = SmmStackSize; SmmInfo.UefiSmmCoreBase = 0; SmmInfo.TotalCores = CoreCount; SmmInfo.CoreSmmBase = Smm16Entry; SmmInfo.Smm64Entry = Smm64Entry; SmmInfo.CpuNumber = (UINT8) i; SmmInfo.ApicId = GetCoreApicId (SmmInfo.CpuNumber); // Check Smm code and Stack are not overlapping if (SmmInfo.CoreSmmBase + Smm16Size > SmmInfo.StackBase - SmmStackSize) { return EFI_OUT_OF_RESOURCES; } DEBUG ((DEBUG_INFO, "Core %x Smm16Foundation at %08x Stack at %08x \n", i, SmmInfo.CoreSmmBase, SmmInfo.StackBase)); // Prepare Smm16 Startup code at Tseg ie. update the SmmInfo structure in Smm16Entry location of each core Status = PrepareSmmStartupVector ( Smm16Entry, SmmFoundationBase, &SmmInfo ); if (EFI_ERROR (Status)) { return Status; } // Send SIPI to each core to set new SmmBase at Tseg (default 0x38000) Status = RelocateSmmBase ( i, Smm16Entry - 0x8000, // newSmmBase TsegBase, // TsegBase (UINT32)TsegSize // TsegSize ); if (EFI_ERROR (Status)) { return Status; } SmmAccess->Close (mSmmAccess); } // Finally send Sipi to all core to test if responding. Add correction if necessary - FMO SendSmiIpl (0xff); DEBUG ((DEBUG_INFO, "Unused SmmFoundation space %08x \n", (SmmInfo.StackBase - SmmStackSize) - (SmmInfo.CoreSmmBase + Smm16Size))); return EFI_SUCCESS; }
/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS BaseOfStack; EFI_PHYSICAL_ADDRESS TopOfStack; UINTN PageTables; X64_IDT_GATE_DESCRIPTOR *IdtTable; UINTN SizeOfTemplate; VOID *TemplateBase; EFI_PHYSICAL_ADDRESS VectorAddress; UINT32 Index; X64_IDT_TABLE *IdtTableForX64; EFI_VECTOR_HANDOFF_INFO *VectorInfo; EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; BOOLEAN BuildPageTablesIa32Pae; if (IsNullDetectionEnabled ()) { ClearFirst4KPage (HobList.Raw); } Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack); ASSERT_EFI_ERROR (Status); if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) { // // Compute the top of the stack we were allocated, which is used to load X64 dxe core. // Pre-allocate a 32 bytes which confroms to x64 calling convention. // // The first four parameters to a function are passed in rcx, rdx, r8 and r9. // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the // register parameters is reserved on the stack, in case the called function // wants to spill them; this is important if the function is variadic. // TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32; // // x64 Calling Conventions requires that the stack must be aligned to 16 bytes // TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16); // // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA // memory, it may be corrupted when copying FV to high-end memory // AsmWriteGdtr (&gGdt); // // Create page table and save PageMapLevel4 to CR3 // PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE); // // End of PEI phase signal // PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); // // Paging might be already enabled. To avoid conflict configuration, // disable paging first anyway. // AsmWriteCr0 (AsmReadCr0 () & (~BIT31)); AsmWriteCr3 (PageTables); // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase); Status = PeiServicesAllocatePages ( EfiBootServicesData, EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT), &VectorAddress ); ASSERT_EFI_ERROR (Status); // // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that // it may not be gotten correctly after IDT register is re-written. // IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress; IdtTableForX64->PeiService = GetPeiServicesTablePointer (); VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1); IdtTable = IdtTableForX64->IdtTable; for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) { IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e; IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0; IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL; IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress; IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16)); IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32)); IdtTable[Index].Reserved = 0; CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate); AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index); VectorAddress += SizeOfTemplate; } gLidtDescriptor.Base = (UINTN) IdtTable; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmWriteIdtr (&gLidtDescriptor); DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", __FUNCTION__, BaseOfStack, STACK_SIZE )); // // Go to Long Mode and transfer control to DxeCore. // Interrupts will not get turned on until the CPU AP is loaded. // Call x64 drivers passing in single argument, a pointer to the HOBs. // AsmEnablePaging64 ( SYS_CODE64_SEL, DxeCoreEntryPoint, (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), 0, TopOfStack ); } else { // // Get Vector Hand-off Info PPI and build Guided HOB // Status = PeiServicesLocatePpi ( &gEfiVectorHandoffInfoPpiGuid, 0, NULL, (VOID **)&VectorHandoffInfoPpi ); if (Status == EFI_SUCCESS) { DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n")); VectorInfo = VectorHandoffInfoPpi->Info; Index = 1; while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) { VectorInfo ++; Index ++; } BuildGuidDataHob ( &gEfiVectorHandoffInfoPpiGuid, VectorHandoffInfoPpi->Info, sizeof (EFI_VECTOR_HANDOFF_INFO) * Index ); } // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT; TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); PageTables = 0; BuildPageTablesIa32Pae = ToBuildPageTable (); if (BuildPageTablesIa32Pae) { PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE); if (IsEnableNonExecNeeded ()) { EnableExecuteDisableBit(); } } // // End of PEI phase signal // PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); if (BuildPageTablesIa32Pae) { // // Paging might be already enabled. To avoid conflict configuration, // disable paging first anyway. // AsmWriteCr0 (AsmReadCr0 () & (~BIT31)); AsmWriteCr3 (PageTables); // // Set Physical Address Extension (bit 5 of CR4). // AsmWriteCr4 (AsmReadCr4 () | BIT5); } // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", __FUNCTION__, BaseOfStack, STACK_SIZE )); // // Transfer the control to the entry point of DxeCore. // if (BuildPageTablesIa32Pae) { AsmEnablePaging32 ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, (VOID *) (UINTN) TopOfStack ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, (VOID *) (UINTN) TopOfStack ); } } }