mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/CpuDxe: Add StartApsStackless routine
This routine starts the APs and directs them to run the specified code. The specified code is entered without a stack being available. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16349 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
a1e8986d97
commit
533263ee5a
|
@ -0,0 +1,304 @@
|
||||||
|
/** @file
|
||||||
|
CPU DXE AP Startup
|
||||||
|
|
||||||
|
Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
|
||||||
|
This program and the accompanying materials
|
||||||
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "CpuDxe.h"
|
||||||
|
#include "CpuGdt.h"
|
||||||
|
#include "CpuMp.h"
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT8 JmpToCli[2];
|
||||||
|
|
||||||
|
UINT16 GdtLimit;
|
||||||
|
UINT32 GdtBase;
|
||||||
|
|
||||||
|
UINT8 Cli;
|
||||||
|
|
||||||
|
UINT8 MovAxRealSegment; UINT16 RealSegment;
|
||||||
|
UINT8 MovDsAx[2];
|
||||||
|
|
||||||
|
UINT8 MovBxGdtr[3];
|
||||||
|
UINT8 LoadGdt[5];
|
||||||
|
|
||||||
|
UINT8 MovEaxCr0[2];
|
||||||
|
UINT32 MovEaxCr0Value;
|
||||||
|
UINT8 MovCr0Eax[3];
|
||||||
|
|
||||||
|
UINT8 FarJmp32Flat[2]; UINT32 FlatJmpOffset; UINT16 FlatJmpSelector;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now in IA32
|
||||||
|
//
|
||||||
|
UINT8 MovEaxCr4;
|
||||||
|
UINT32 MovEaxCr4Value;
|
||||||
|
UINT8 MovCr4Eax[3];
|
||||||
|
|
||||||
|
UINT8 MoveDataSelectorIntoAx[2]; UINT16 FlatDataSelector;
|
||||||
|
UINT8 MoveFlatDataSelectorFromAxToDs[2];
|
||||||
|
UINT8 MoveFlatDataSelectorFromAxToEs[2];
|
||||||
|
UINT8 MoveFlatDataSelectorFromAxToFs[2];
|
||||||
|
UINT8 MoveFlatDataSelectorFromAxToGs[2];
|
||||||
|
UINT8 MoveFlatDataSelectorFromAxToSs[2];
|
||||||
|
|
||||||
|
#if defined (MDE_CPU_X64)
|
||||||
|
//
|
||||||
|
// Transition to X64
|
||||||
|
//
|
||||||
|
UINT8 MovEaxCr3;
|
||||||
|
UINT32 Cr3Value;
|
||||||
|
UINT8 MovCr3Eax[3];
|
||||||
|
|
||||||
|
UINT8 MoveCr4ToEax[3];
|
||||||
|
UINT8 SetCr4Bit5[4];
|
||||||
|
UINT8 MoveEaxToCr4[3];
|
||||||
|
|
||||||
|
UINT8 MoveLongModeEnableMsrToEcx[5];
|
||||||
|
UINT8 ReadLmeMsr[2];
|
||||||
|
UINT8 SetLongModeEnableBit[4];
|
||||||
|
UINT8 WriteLmeMsr[2];
|
||||||
|
|
||||||
|
UINT8 MoveCr0ToEax[3];
|
||||||
|
UINT8 SetCr0PagingBit[4];
|
||||||
|
UINT8 MoveEaxToCr0[3];
|
||||||
|
//UINT8 DeadLoop[2];
|
||||||
|
|
||||||
|
UINT8 FarJmp32LongMode; UINT32 LongJmpOffset; UINT16 LongJmpSelector;
|
||||||
|
#endif // defined (MDE_CPU_X64)
|
||||||
|
|
||||||
|
#if defined (MDE_CPU_X64)
|
||||||
|
UINT8 MovEaxOrRaxCpuDxeEntry[2]; UINTN CpuDxeEntryValue;
|
||||||
|
#else
|
||||||
|
UINT8 MovEaxOrRaxCpuDxeEntry; UINTN CpuDxeEntryValue;
|
||||||
|
#endif
|
||||||
|
UINT8 JmpToCpuDxeEntry[2];
|
||||||
|
|
||||||
|
} STARTUP_CODE;
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
/**
|
||||||
|
This .asm code used for translating processor from 16 bit real mode into
|
||||||
|
64 bit long mode. which help to create the mStartupCodeTemplate value.
|
||||||
|
|
||||||
|
To assemble:
|
||||||
|
* nasm -o ApStartup ApStartup.asm
|
||||||
|
Then disassemble:
|
||||||
|
* ndisasm -b 16 ApStartup
|
||||||
|
* ndisasm -b 16 -e 6 ApStartup
|
||||||
|
* ndisasm -b 32 -e 32 ApStartup (This -e offset may need adjustment)
|
||||||
|
* ndisasm -b 64 -e 0x83 ApStartup (This -e offset may need adjustment)
|
||||||
|
|
||||||
|
%define DEFAULT_CR0 0x00000023
|
||||||
|
%define DEFAULT_CR4 0x640
|
||||||
|
|
||||||
|
BITS 16
|
||||||
|
|
||||||
|
jmp short TransitionFromReal16To32BitFlat
|
||||||
|
|
||||||
|
ALIGN 2
|
||||||
|
|
||||||
|
Gdtr:
|
||||||
|
dw 0x5a5a
|
||||||
|
dd 0x5a5a5a5a
|
||||||
|
|
||||||
|
;
|
||||||
|
; Modified: EAX, EBX
|
||||||
|
;
|
||||||
|
TransitionFromReal16To32BitFlat:
|
||||||
|
|
||||||
|
cli
|
||||||
|
mov ax, 0x5a5a
|
||||||
|
mov ds, ax
|
||||||
|
|
||||||
|
mov bx, Gdtr
|
||||||
|
o32 lgdt [ds:bx]
|
||||||
|
|
||||||
|
mov eax, cr4
|
||||||
|
btc eax, 5
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
mov eax, DEFAULT_CR0
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
jmp 0x5a5a:dword jumpTo32BitAndLandHere
|
||||||
|
BITS 32
|
||||||
|
jumpTo32BitAndLandHere:
|
||||||
|
|
||||||
|
mov eax, DEFAULT_CR4
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
mov ax, 0x5a5a
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
|
||||||
|
;
|
||||||
|
; Jump to CpuDxe for IA32
|
||||||
|
;
|
||||||
|
mov eax, 0x5a5a5a5a
|
||||||
|
or eax, eax
|
||||||
|
jz Transition32FlatTo64Flat
|
||||||
|
jmp eax
|
||||||
|
|
||||||
|
;
|
||||||
|
; Transition to X64
|
||||||
|
;
|
||||||
|
Transition32FlatTo64Flat:
|
||||||
|
mov eax, 0x5a5a5a5a
|
||||||
|
mov cr3, eax
|
||||||
|
|
||||||
|
mov eax, cr4
|
||||||
|
bts eax, 5 ; enable PAE
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
mov ecx, 0xc0000080
|
||||||
|
rdmsr
|
||||||
|
bts eax, 8 ; set LME
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
mov eax, cr0
|
||||||
|
bts eax, 31 ; set PG
|
||||||
|
mov cr0, eax ; enable paging
|
||||||
|
|
||||||
|
;
|
||||||
|
; Jump to CpuDxe for X64
|
||||||
|
;
|
||||||
|
jmp 0x5a5a:jumpTo64BitAndLandHere
|
||||||
|
BITS 64
|
||||||
|
jumpTo64BitAndLandHere:
|
||||||
|
mov rax, 0xcdcdcdcdcdcdcdcd
|
||||||
|
jmp rax
|
||||||
|
**/
|
||||||
|
STARTUP_CODE mStartupCodeTemplate = {
|
||||||
|
{ 0xeb, 0x06 }, // Jump to cli
|
||||||
|
0, // GDT Limit
|
||||||
|
0, // GDT Base
|
||||||
|
0xfa, // cli (Clear Interrupts)
|
||||||
|
0xb8, 0x0000, // mov ax, RealSegment
|
||||||
|
{ 0x8e, 0xd8 }, // mov ds, ax
|
||||||
|
{ 0xBB, 0x02, 0x00 }, // mov bx, Gdtr
|
||||||
|
{ 0x3e, 0x66, 0x0f, 0x01, 0x17 }, // lgdt [ds:bx]
|
||||||
|
{ 0x66, 0xB8 }, 0x00000023, // mov eax, cr0 value
|
||||||
|
{ 0x0F, 0x22, 0xC0 }, // mov cr0, eax
|
||||||
|
{ 0x66, 0xEA }, // far jmp to 32-bit flat
|
||||||
|
OFFSET_OF(STARTUP_CODE, MovEaxCr4),
|
||||||
|
LINEAR_CODE_SEL,
|
||||||
|
0xB8, 0x00000640, // mov eax, cr4 value
|
||||||
|
{ 0x0F, 0x22, 0xe0 }, // mov cr4, eax
|
||||||
|
{ 0x66, 0xb8 }, CPU_DATA_SEL, // mov ax, FlatDataSelector
|
||||||
|
{ 0x8e, 0xd8 }, // mov ds, ax
|
||||||
|
{ 0x8e, 0xc0 }, // mov es, ax
|
||||||
|
{ 0x8e, 0xe0 }, // mov fs, ax
|
||||||
|
{ 0x8e, 0xe8 }, // mov gs, ax
|
||||||
|
{ 0x8e, 0xd0 }, // mov ss, ax
|
||||||
|
|
||||||
|
#if defined (MDE_CPU_X64)
|
||||||
|
0xB8, 0x00000000, // mov eax, cr3 value
|
||||||
|
{ 0x0F, 0x22, 0xd8 }, // mov cr3, eax
|
||||||
|
|
||||||
|
{ 0x0F, 0x20, 0xE0 }, // mov eax, cr4
|
||||||
|
{ 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5
|
||||||
|
{ 0x0F, 0x22, 0xE0 }, // mov cr4, eax
|
||||||
|
|
||||||
|
{ 0xB9, 0x80, 0x00, 0x00, 0xC0 }, // mov ecx, 0xc0000080
|
||||||
|
{ 0x0F, 0x32 }, // rdmsr
|
||||||
|
{ 0x0F, 0xBA, 0xE8, 0x08 }, // bts eax, 8
|
||||||
|
{ 0x0F, 0x30 }, // wrmsr
|
||||||
|
|
||||||
|
{ 0x0F, 0x20, 0xC0 }, // mov eax, cr0
|
||||||
|
{ 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31
|
||||||
|
{ 0x0F, 0x22, 0xC0 }, // mov cr0, eax
|
||||||
|
|
||||||
|
0xEA, // FarJmp32LongMode
|
||||||
|
OFFSET_OF(STARTUP_CODE, MovEaxOrRaxCpuDxeEntry),
|
||||||
|
LINEAR_CODE64_SEL,
|
||||||
|
#endif // defined (MDE_CPU_X64)
|
||||||
|
|
||||||
|
//0xeb, 0xfe, // jmp $
|
||||||
|
#if defined (MDE_CPU_X64)
|
||||||
|
{ 0x48, 0xb8 }, 0x0, // mov rax, X64 CpuDxe MP Entry Point
|
||||||
|
#else
|
||||||
|
0xB8, 0x0, // mov eax, IA32 CpuDxe MP Entry Point
|
||||||
|
#endif
|
||||||
|
{ 0xff, 0xe0 }, // jmp to eax/rax (CpuDxe MP Entry Point)
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Starts the Application Processors and directs them to jump to the
|
||||||
|
specified routine.
|
||||||
|
|
||||||
|
The processor jumps to this code in flat mode, but the processor's
|
||||||
|
stack is not initialized.
|
||||||
|
|
||||||
|
@param ApEntryPoint Pointer to the Entry Point routine
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The APs were started
|
||||||
|
@retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
StartApsStackless (
|
||||||
|
IN STACKLESS_AP_ENTRY_POINT ApEntryPoint
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
volatile STARTUP_CODE *StartupCode;
|
||||||
|
IA32_DESCRIPTOR Gdtr;
|
||||||
|
EFI_PHYSICAL_ADDRESS StartAddress;
|
||||||
|
|
||||||
|
StartAddress = BASE_1MB;
|
||||||
|
Status = gBS->AllocatePages (
|
||||||
|
AllocateMaxAddress,
|
||||||
|
EfiACPIMemoryNVS,
|
||||||
|
EFI_SIZE_TO_PAGES (sizeof (*StartupCode)),
|
||||||
|
&StartAddress
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartupCode = (STARTUP_CODE*)(VOID*)(UINTN) StartAddress;
|
||||||
|
CopyMem ((VOID*) StartupCode, &mStartupCodeTemplate, sizeof (*StartupCode));
|
||||||
|
StartupCode->RealSegment = (UINT16) (((UINTN) StartAddress) >> 4);
|
||||||
|
|
||||||
|
AsmReadGdtr (&Gdtr);
|
||||||
|
StartupCode->GdtLimit = Gdtr.Limit;
|
||||||
|
StartupCode->GdtBase = (UINT32) Gdtr.Base;
|
||||||
|
|
||||||
|
StartupCode->CpuDxeEntryValue = (UINTN) ApEntryPoint;
|
||||||
|
|
||||||
|
StartupCode->FlatJmpOffset += (UINT32) StartAddress;
|
||||||
|
|
||||||
|
#if defined (MDE_CPU_X64)
|
||||||
|
StartupCode->Cr3Value = (UINT32) AsmReadCr3 ();
|
||||||
|
StartupCode->LongJmpOffset += (UINT32) StartAddress;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)(VOID*) StartupCode);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine
|
||||||
|
//
|
||||||
|
MicroSecondDelay (100 * 1000);
|
||||||
|
|
||||||
|
gBS->FreePages (StartAddress, EFI_SIZE_TO_PAGES (sizeof (*StartupCode)));
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <Library/UefiCpuLib.h>
|
#include <Library/UefiCpuLib.h>
|
||||||
#include <Library/UefiLib.h>
|
#include <Library/UefiLib.h>
|
||||||
#include <Library/CpuExceptionHandlerLib.h>
|
#include <Library/CpuExceptionHandlerLib.h>
|
||||||
|
#include <Library/TimerLib.h>
|
||||||
#include <Guid/IdleLoopEvent.h>
|
#include <Guid/IdleLoopEvent.h>
|
||||||
#include <Guid/VectorHandoffTable.h>
|
#include <Guid/VectorHandoffTable.h>
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,14 @@
|
||||||
UefiCpuLib
|
UefiCpuLib
|
||||||
UefiLib
|
UefiLib
|
||||||
CpuExceptionHandlerLib
|
CpuExceptionHandlerLib
|
||||||
|
TimerLib
|
||||||
|
|
||||||
[Sources]
|
[Sources]
|
||||||
|
ApStartup.c
|
||||||
CpuDxe.c
|
CpuDxe.c
|
||||||
CpuDxe.h
|
CpuDxe.h
|
||||||
CpuGdt.c
|
CpuGdt.c
|
||||||
|
CpuGdt.h
|
||||||
CpuMp.c
|
CpuMp.c
|
||||||
CpuMp.h
|
CpuMp.h
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,30 @@ InitializeMpSupport (
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
typedef
|
||||||
|
VOID
|
||||||
|
(EFIAPI *STACKLESS_AP_ENTRY_POINT)(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Starts the Application Processors and directs them to jump to the
|
||||||
|
specified routine.
|
||||||
|
|
||||||
|
The processor jumps to this code in flat mode, but the processor's
|
||||||
|
stack is not initialized.
|
||||||
|
|
||||||
|
@param ApEntryPoint Pointer to the Entry Point routine
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The APs were started
|
||||||
|
@retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
StartApsStackless (
|
||||||
|
IN STACKLESS_AP_ENTRY_POINT ApEntryPoint
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The AP entry point that the Startup-IPI target code will jump to.
|
The AP entry point that the Startup-IPI target code will jump to.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue