The cached "CPU_INFO_IN_HOB.ApTopOfStack" field currently has type UINT32.
This is not ideal because the AP stacks are located within
"CpuMpData->Buffer", which is allocated with a plain AllocatePages() call
in MpInitLibInitialize():
platform CpuMpPei included PEI RAM > 4GB result
-------- ----------------- ------------- ------
Ia32 * n/a good
Ia32X64 no n/a BAD
Ia32X64 yes n/a good
X64 no * BAD
X64 yes no good
X64 yes yes BAD
- If we are on an Ia32X64 or X64 platform that does not include CpuMpPei,
then CpuDxe cannot reuse the CPU_INFO_IN_HOB structures preallocated by
CpuMpPei (through the CpuInitMpLib GUID HOB), and then AllocatePages()
-- invoked first in 64-bit DXE -- could return an address outside of
32-bit address space.
- If we are on an X64 platform where the permanent PEI RAM extends above
the 32-bit address space, then the same issue can surface even if
CpuMpPei is included: even the original allocation of the
CPU_INFO_IN_HOB structures, by CpuMpPei, could be satisfied from above
4GB.
The original "AP init" branch in "X64/MpFuncs.nasm" correctly considers a
64-bit stack start: the "MP_CPU_EXCHANGE_INFO.StackStart" field has type
UINTN, and the code uses QWORD addition and movement to set RSP from it.
Adapt the "GetApicId" branch of "X64/MpFuncs.nasm":
- change the type of "CPU_INFO_IN_HOB.ApTopOfStack" to UINT64,
- remove the explicit truncation to UINT32 in InitializeApData(),
- update the "GetNextProcNumber" iteration size to the new size of
"CPU_INFO_IN_HOB",
- set RSP with a QWORD movement from "CPU_INFO_IN_HOB.ApTopOfStack".
Because the same CPU_INFO_IN_HOB structure is used by "Ia32/MpFuncs.nasm",
we have to update the "GetNextProcNumber" iteration size there as well.
The ESP setting can be preserved as a DWORD movement from the original
offset (decimal 12), since our integers are little endian.
Cc: Jeff Fan <jeff.fan@intel.com>
Fixes: 845c5be1fd9bf7edfac4a103dfab70829686978f
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jeff Fan <jeff.fan@intel.com>
GetNextProcNumber:\r
cmp [edi], edx ; APIC ID match?\r
jz ProgramStack\r
GetNextProcNumber:\r
cmp [edi], edx ; APIC ID match?\r
jz ProgramStack\r
inc ebx\r
jmp GetNextProcNumber \r
\r
inc ebx\r
jmp GetNextProcNumber \r
\r
IN OUT CPU_MP_DATA *CpuMpData,\r
IN UINTN ProcessorNumber,\r
IN UINT32 BistData,\r
IN OUT CPU_MP_DATA *CpuMpData,\r
IN UINTN ProcessorNumber,\r
IN UINT32 BistData,\r
- IN UINTN ApTopOfStack\r
+ IN UINT64 ApTopOfStack\r
)\r
{\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
)\r
{\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();\r
CpuInfoInHob[ProcessorNumber].Health = BistData;\r
CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();\r
CpuInfoInHob[ProcessorNumber].Health = BistData;\r
- CpuInfoInHob[ProcessorNumber].ApTopOfStack = (UINT32) ApTopOfStack;\r
+ CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;\r
\r
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
\r
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
UINT32 BistData;\r
volatile UINT32 *ApStartupSignalBuffer;\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
UINT32 BistData;\r
volatile UINT32 *ApStartupSignalBuffer;\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
\r
//\r
// AP finished assembly code and begin to execute C code\r
\r
//\r
// AP finished assembly code and begin to execute C code\r
// This is first time AP wakeup, get BIST information from AP stack\r
//\r
ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
// This is first time AP wakeup, get BIST information from AP stack\r
//\r
ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
- BistData = *(UINT32 *) (ApTopOfStack - sizeof (UINTN));\r
+ BistData = *(UINT32 *) ((UINTN) ApTopOfStack - sizeof (UINTN));\r
//\r
// Do some AP initialize sync\r
//\r
//\r
// Do some AP initialize sync\r
//\r
// we need to make sure the each fields offset same in different\r
// architecture.\r
//\r
// we need to make sure the each fields offset same in different\r
// architecture.\r
//\r
typedef struct {\r
UINT32 InitialApicId;\r
UINT32 ApicId;\r
UINT32 Health;\r
typedef struct {\r
UINT32 InitialApicId;\r
UINT32 ApicId;\r
UINT32 Health;\r
\r
//\r
// AP reset code information including code address and size,\r
\r
//\r
// AP reset code information including code address and size,\r
GetNextProcNumber:\r
cmp dword [edi], edx ; APIC ID match?\r
jz ProgramStack\r
GetNextProcNumber:\r
cmp dword [edi], edx ; APIC ID match?\r
jz ProgramStack\r
inc ebx\r
jmp GetNextProcNumber \r
\r
ProgramStack:\r
inc ebx\r
jmp GetNextProcNumber \r
\r
ProgramStack:\r
- xor rsp, rsp\r
- mov esp, dword [edi + 12]\r
+ mov rsp, qword [edi + 12]\r
\r
CProcedureInvoke:\r
push rbp ; Push BIST data at top of AP stack\r
\r
CProcedureInvoke:\r
push rbp ; Push BIST data at top of AP stack\r