/** This function initialize host common context. **/ VOID InitHostContextCommon ( VOID ) { UINT32 Index; INTERRUPT_GATE_DESCRIPTOR *IdtGate; // // PageTable // mHostContextCommon.PageTable = CreatePageTable (); mHostContextCommon.Gdtr.Limit = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr.Limit; mHostContextCommon.Gdtr.Base = (UINTN)AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.Gdtr.Limit + 1)); CopyMem ((VOID *)mHostContextCommon.Gdtr.Base, (VOID *)mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr.Base, mHostContextCommon.Gdtr.Limit + 1); AsmWriteGdtr (&mHostContextCommon.Gdtr); mHostContextCommon.Idtr.Limit = 0x100 * sizeof (INTERRUPT_GATE_DESCRIPTOR) - 1; mHostContextCommon.Idtr.Base = (UINTN)AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.Idtr.Limit + 1)); CopyMem ((VOID *)mHostContextCommon.Idtr.Base, (VOID *)mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr.Base, mHostContextCommon.Idtr.Limit + 1); IdtGate = (INTERRUPT_GATE_DESCRIPTOR *)mHostContextCommon.Idtr.Base; for (Index = 0; Index < 0x100; Index++) { IdtGate[Index].Offset15To0 = (UINT16)((UINTN)AsmExceptionHandlers + Index * mExceptionHandlerLength); IdtGate[Index].Offset31To16 = (UINT16)(((UINTN)AsmExceptionHandlers + Index * mExceptionHandlerLength) >> 16); #ifdef MDE_CPU_X64 IdtGate[Index].Offset63To32 = (UINT32)(((UINTN)AsmExceptionHandlers + Index * mExceptionHandlerLength) >> 32); #endif } // // Special for NMI // IdtGate[2].Offset15To0 = (UINT16)((UINTN)AsmNmiExceptionHandler); IdtGate[2].Offset31To16 = (UINT16)(((UINTN)AsmNmiExceptionHandler) >> 16); #ifdef MDE_CPU_X64 IdtGate[2].Offset63To32 = (UINT32)(((UINTN)AsmNmiExceptionHandler) >> 32); #endif // // VmExitHandler // InitFrmHandler (); mTeardownFinished = AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.CpuNum)); // // Init HostContextPerCpu // mApicIdList = (UINTN)AllocatePages (FRM_SIZE_TO_PAGES (sizeof(UINT32) * mHostContextCommon.CpuNum)); GetApicIdListFromAcpi ((UINT32 *)mApicIdList); for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) { mHostContextCommon.HostContextPerCpu[Index].Index = Index; mHostContextCommon.HostContextPerCpu[Index].ApicId = *((UINT32 *)mApicIdList + Index); mHostContextCommon.HostContextPerCpu[Index].Stack = (UINTN)AllocatePages (32); mHostContextCommon.HostContextPerCpu[Index].Stack += FRM_PAGES_TO_SIZE (32); InitHostVmcs (Index); } }
/** Initialize Global Descriptor Table. **/ VOID InitGlobalDescriptorTable ( VOID ) { GDT_ENTRIES *gdt; IA32_DESCRIPTOR gdtPtr; // // Allocate Runtime Data for the GDT // gdt = AllocateRuntimePool (sizeof (GdtTemplate) + 8); ASSERT (gdt != NULL); gdt = ALIGN_POINTER (gdt, 8); // // Initialize all GDT entries // CopyMem (gdt, &GdtTemplate, sizeof (GdtTemplate)); // // Write GDT register // gdtPtr.Base = (UINT32)(UINTN)(VOID*) gdt; gdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1); AsmWriteGdtr (&gdtPtr); // // Update selector (segment) registers base on new GDT // SetCodeSelector ((UINT16)CPU_CODE_SEL); SetDataSelectors ((UINT16)CPU_DATA_SEL); }
VOID __lgdt ( _In_ IA32_DESCRIPTOR* Gdtr ) { // // Use the UEFI framework function // AsmWriteGdtr(Gdtr); }
/** Platform specific mechanism to transfer control to 16bit OS waking vector @param[in] AcpiWakingVector The 16bit OS waking vector @param[in] AcpiLowMemoryBase A buffer under 1M which could be used during the transfer **/ VOID PlatformTransferControl16 ( IN UINT32 AcpiWakingVector, IN UINT32 AcpiLowMemoryBase ) { UINT32 NewValue; UINT64 BaseAddress; UINT64 SmramLength; UINTN Index; DEBUG (( EFI_D_INFO, "PlatformTransferControl - Entry\r\n")); // // Need to make sure the GDT is loaded with values that support long mode and real mode. // AsmWriteGdtr (&mGdt); // // Disable eSram block (this will also clear/zero eSRAM) // We only use eSRAM in the PEI phase. Disable now that we are resuming the OS // NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK); NewValue |= BLOCK_DISABLE_PG; QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK, NewValue); // // Update HMBOUND to top of DDR3 memory and LOCK // We disabled eSRAM so now we move HMBOUND down to top of DDR3 // QNCGetTSEGMemoryRange (&BaseAddress, &SmramLength); NewValue = (UINT32)(BaseAddress + SmramLength); DEBUG ((EFI_D_INFO,"Locking HMBOUND at: = 0x%8x\n",NewValue)); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG, (NewValue | HMBOUND_LOCK)); // // Lock all IMR regions now that HMBOUND is locked // for (Index = (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL); Index <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL); Index += 4) { NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index); NewValue |= IMR_LOCK; QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index, NewValue); } // // Call ASM routine to switch to real mode and jump to 16bit OS waking vector // AsmTransferControl(AcpiWakingVector, 0); // // Never run to here // CpuDeadLoop(); }
/** Initialize Global Descriptor Table. **/ VOID SetLinuxDescriptorTables ( VOID ) { IA32_DESCRIPTOR GdtPtr; IA32_DESCRIPTOR IdtPtr; // // Write GDT register // GdtPtr.Base = (UINT32)(UINTN)(VOID*) mGdt; GdtPtr.Limit = (UINT16) (sizeof (GdtTemplate) - 1); AsmWriteGdtr (&GdtPtr); IdtPtr.Base = (UINT32) 0; IdtPtr.Limit = (UINT16) 0; AsmWriteIdtr (&IdtPtr); }
/** 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 ); } } }