return (UINTN) StartAddress;\r
}\r
\r
+/**\r
+ Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+ This buffer is required to safely transfer AP from real address mode to\r
+ protected mode or long mode, due to the fact that the buffer returned by\r
+ GetWakeupBuffer() may be marked as non-executable.\r
+\r
+ @param[in] BufferSize Wakeup transition buffer size.\r
+\r
+ @retval other Return wakeup transition buffer address below 4GB.\r
+ @retval 0 Cannot find free memory below 4GB.\r
+**/\r
+UINTN\r
+GetModeTransitionBuffer (\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS StartAddress;\r
+\r
+ StartAddress = BASE_4GB - 1;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiBootServicesCode,\r
+ EFI_SIZE_TO_PAGES (BufferSize),\r
+ &StartAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ StartAddress = 0;\r
+ }\r
+\r
+ return (UINTN)StartAddress;\r
+}\r
+\r
/**\r
Checks APs status and updates APs status if needed.\r
\r
InitFlagLocation equ LockLocation + 38h\r
CpuInfoLocation equ LockLocation + 3Ch\r
NumApsExecutingLocation equ LockLocation + 40h\r
+InitializeFloatingPointUnitsAddress equ LockLocation + 48h\r
+ModeTransitionMemoryLocation equ LockLocation + 4Ch\r
+ModeTransitionSegmentLocation equ LockLocation + 50h\r
+ModeHighMemoryLocation equ LockLocation + 52h\r
+ModeHighSegmentLocation equ LockLocation + 56h\r
\r
mov si, BufferStartLocation\r
mov ebx, [si]\r
\r
- mov si, ModeOffsetLocation\r
- mov eax, [si]\r
- mov si, CodeSegmentLocation\r
- mov edx, [si]\r
- mov di, ax\r
- sub di, 02h\r
- mov [di], dx\r
- sub di, 04h\r
- add eax, ebx\r
- mov [di],eax\r
-\r
mov si, DataSegmentLocation\r
mov edx, [si]\r
\r
+ ;\r
+ ; Get start address of 32-bit code in low memory (<1MB)\r
+ ;\r
+ mov edi, ModeTransitionMemoryLocation\r
+\r
mov si, GdtrLocation\r
o32 lgdt [cs:si]\r
\r
mov si, IdtrLocation\r
o32 lidt [cs:si]\r
\r
- xor ax, ax\r
- mov ds, ax\r
-\r
+ ;\r
+ ; Switch to protected mode\r
+ ;\r
mov eax, cr0 ; Get control register 0\r
or eax, 000000003h ; Set PE bit (bit #0) & MP\r
mov cr0, eax\r
\r
- jmp 0:strict dword 0 ; far jump to protected mode\r
+ ; Switch to 32-bit code in executable memory (>1MB)\r
+o32 jmp far [cs:di]\r
+\r
+;\r
+; Following code may be copied to memory with type of EfiBootServicesCode.\r
+; This is required at DXE phase if NX is enabled for EfiBootServicesCode of\r
+; memory.\r
+;\r
BITS 32\r
Flat32Start: ; protected mode entry point\r
mov ds, dx\r
mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
mov dword [ebx + 0Ch], AsmRelocateApLoopStart\r
mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
+ mov dword [ebx + 14h], Flat32Start - RendezvousFunnelProcStart\r
\r
popad\r
ret\r
)\r
{\r
volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
+ UINTN Size;\r
+ IA32_SEGMENT_DESCRIPTOR *Selector;\r
\r
ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
ExchangeInfo->Lock = 0;\r
//\r
AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
+\r
+ //\r
+ // Find a 32-bit code segment\r
+ //\r
+ Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;\r
+ Size = ExchangeInfo->GdtrProfile.Limit + 1;\r
+ while (Size > 0) {\r
+ if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {\r
+ ExchangeInfo->ModeTransitionSegment =\r
+ (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);\r
+ break;\r
+ }\r
+ Selector += 1;\r
+ Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+ }\r
+\r
+ //\r
+ // Copy all 32-bit code and 64-bit code into memory with type of\r
+ // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.\r
+ //\r
+ if (ExchangeInfo->ModeTransitionMemory != 0) {\r
+ Size = CpuMpData->AddressMap.RendezvousFunnelSize -\r
+ CpuMpData->AddressMap.ModeTransitionOffset;\r
+ CopyMem (\r
+ (VOID *)(UINTN)ExchangeInfo->ModeTransitionMemory,\r
+ CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+ CpuMpData->AddressMap.ModeTransitionOffset,\r
+ Size\r
+ );\r
+\r
+ ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory;\r
+ ExchangeInfo->ModeHighMemory += (UINT32)ExchangeInfo->ModeOffset -\r
+ (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
+ ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\r
+ } else {\r
+ ExchangeInfo->ModeTransitionMemory = (UINT32)\r
+ (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);\r
+ }\r
}\r
\r
/**\r
CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);\r
CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
(CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
+ CpuMpData->MpCpuExchangeInfo->ModeTransitionMemory = (UINT32)\r
+ GetModeTransitionBuffer (\r
+ CpuMpData->AddressMap.RendezvousFunnelSize -\r
+ CpuMpData->AddressMap.ModeTransitionOffset\r
+ );\r
}\r
BackupAndPrepareWakeupBuffer (CpuMpData);\r
}\r
UINTN RendezvousFunnelSize;\r
UINT8 *RelocateApLoopFuncAddress;\r
UINTN RelocateApLoopFuncSize;\r
+ UINTN ModeTransitionOffset;\r
} MP_ASSEMBLY_ADDRESS_MAP;\r
\r
typedef struct _CPU_MP_DATA CPU_MP_DATA;\r
UINTN NumApsExecuting;\r
CPU_MP_DATA *CpuMpData;\r
UINTN InitializeFloatingPointUnitsAddress;\r
+ UINT32 ModeTransitionMemory;\r
+ UINT16 ModeTransitionSegment;\r
+ UINT32 ModeHighMemory;\r
+ UINT16 ModeHighSegment;\r
} MP_CPU_EXCHANGE_INFO;\r
\r
#pragma pack()\r
IN UINTN WakeupBufferSize\r
);\r
\r
+/**\r
+ Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+ This buffer is required to safely transfer AP from real address mode to\r
+ protected mode or long mode, due to the fact that the buffer returned by\r
+ GetWakeupBuffer() may be marked as non-executable.\r
+\r
+ @param[in] BufferSize Wakeup transition buffer size.\r
+\r
+ @retval other Return wakeup transition buffer address below 4GB.\r
+ @retval 0 Cannot find free memory below 4GB.\r
+**/\r
+UINTN\r
+GetModeTransitionBuffer (\r
+ IN UINTN BufferSize\r
+ );\r
+\r
/**\r
This function will be called by BSP to wakeup AP.\r
\r
return (UINTN) -1;\r
}\r
\r
+/**\r
+ Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+ This buffer is required to safely transfer AP from real address mode to\r
+ protected mode or long mode, due to the fact that the buffer returned by\r
+ GetWakeupBuffer() may be marked as non-executable.\r
+\r
+ @param[in] BufferSize Wakeup transition buffer size.\r
+\r
+ @retval other Return wakeup transition buffer address below 4GB.\r
+ @retval 0 Cannot find free memory below 4GB.\r
+**/\r
+UINTN\r
+GetModeTransitionBuffer (\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ //\r
+ // PEI phase doesn't need to do such transition. So simply return 0.\r
+ //\r
+ return 0;\r
+}\r
+\r
/**\r
Checks APs status and updates APs status if needed.\r
\r
CpuInfoLocation equ LockLocation + 74h\r
NumApsExecutingLocation equ LockLocation + 7Ch\r
InitializeFloatingPointUnitsAddress equ LockLocation + 8Ch\r
-\r
+ModeTransitionMemoryLocation equ LockLocation + 94h\r
+ModeTransitionSegmentLocation equ LockLocation + 98h\r
+ModeHighMemoryLocation equ LockLocation + 9Ah\r
+ModeHighSegmentLocation equ LockLocation + 9Eh\r
mov si, BufferStartLocation\r
mov ebx, [si]\r
\r
- mov di, ModeOffsetLocation\r
- mov eax, [di]\r
- mov di, CodeSegmentLocation\r
- mov edx, [di]\r
- mov di, ax\r
- sub di, 02h\r
- mov [di],dx ; Patch long mode CS\r
- sub di, 04h\r
- add eax, ebx\r
- mov [di],eax ; Patch address\r
+ mov si, DataSegmentLocation\r
+ mov edx, [si]\r
+\r
+ ;\r
+ ; Get start address of 32-bit code in low memory (<1MB)\r
+ ;\r
+ mov edi, ModeTransitionMemoryLocation\r
\r
mov si, GdtrLocation\r
o32 lgdt [cs:si]\r
mov si, IdtrLocation\r
o32 lidt [cs:si]\r
\r
- mov si, EnableExecuteDisableLocation\r
- cmp byte [si], 0\r
- jz SkipEnableExecuteDisableBit\r
+ ;\r
+ ; Switch to protected mode\r
+ ;\r
+ mov eax, cr0 ; Get control register 0\r
+ or eax, 000000003h ; Set PE bit (bit #0) & MP\r
+ mov cr0, eax\r
+\r
+ ; Switch to 32-bit code (>1MB)\r
+o32 jmp far [cs:di]\r
+\r
+;\r
+; Following code must be copied to memory with type of EfiBootServicesCode.\r
+; This is required if NX is enabled for EfiBootServicesCode of memory.\r
+;\r
+BITS 32\r
+Flat32Start: ; protected mode entry point\r
+ mov ds, dx\r
+ mov es, dx\r
+ mov fs, dx\r
+ mov gs, dx\r
+ mov ss, dx\r
\r
;\r
; Enable execute disable bit\r
;\r
+ mov esi, EnableExecuteDisableLocation\r
+ cmp byte [ebx + esi], 0\r
+ jz SkipEnableExecuteDisableBit\r
+\r
mov ecx, 0c0000080h ; EFER MSR number\r
rdmsr ; Read EFER\r
bts eax, 11 ; Enable Execute Disable Bit\r
wrmsr ; Write EFER\r
\r
SkipEnableExecuteDisableBit:\r
-\r
- mov di, DataSegmentLocation\r
- mov edi, [di] ; Save long mode DS in edi\r
-\r
- mov si, Cr3Location ; Save CR3 in ecx\r
- mov ecx, [si]\r
-\r
- xor ax, ax\r
- mov ds, ax ; Clear data segment\r
-\r
- mov eax, cr0 ; Get control register 0\r
- or eax, 000000003h ; Set PE bit (bit #0) & MP\r
- mov cr0, eax\r
-\r
+ ;\r
+ ; Enable PAE\r
+ ;\r
mov eax, cr4\r
bts eax, 5\r
mov cr4, eax\r
\r
+ ;\r
+ ; Load page table\r
+ ;\r
+ mov esi, Cr3Location ; Save CR3 in ecx\r
+ mov ecx, [ebx + esi]\r
mov cr3, ecx ; Load CR3\r
\r
+ ;\r
+ ; Enable long mode\r
+ ;\r
mov ecx, 0c0000080h ; EFER MSR number\r
rdmsr ; Read EFER\r
bts eax, 8 ; Set LME=1\r
wrmsr ; Write EFER\r
\r
+ ;\r
+ ; Enable paging\r
+ ;\r
mov eax, cr0 ; Read CR0\r
bts eax, 31 ; Set PG=1\r
mov cr0, eax ; Write CR0\r
\r
- jmp 0:strict dword 0 ; far jump to long mode\r
+ ;\r
+ ; Far jump to 64-bit code\r
+ ;\r
+ mov edi, ModeHighMemoryLocation\r
+ add edi, ebx\r
+ jmp far [edi]\r
+\r
BITS 64\r
LongModeStart:\r
- mov eax, edi\r
- mov ds, ax\r
- mov es, ax\r
- mov ss, ax\r
-\r
mov esi, ebx\r
lea edi, [esi + InitFlagLocation]\r
cmp qword [edi], 1 ; ApInitConfig\r
lea rax, [ASM_PFX(AsmRelocateApLoop)]\r
mov qword [rcx + 18h], rax\r
mov qword [rcx + 20h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart\r
+ mov qword [rcx + 28h], Flat32Start - RendezvousFunnelProcStart\r
ret\r
\r
;-------------------------------------------------------------------------------------\r