From: "Ni, Ruiyu" <ruiyu.ni@Intel.com>
To: Laszlo Ersek <lersek@redhat.com>,
"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: Jeff Fan <vanjeff_919@hotmail.com>,
"Dong, Eric" <eric.dong@intel.com>,
"Yao, Jiewen" <jiewen.yao@intel.com>,
Fish Andrew <afish@apple.com>
Subject: Re: [PATCH v3] UefiCpuPkg/MpInitLib: Avoid calling PEI services from AP
Date: Mon, 2 Jul 2018 13:56:21 +0800 [thread overview]
Message-ID: <eeb783c7-cadb-f2dc-220d-88b4947a2a3c@Intel.com> (raw)
In-Reply-To: <0fe484e0-2c7c-8050-1375-58099b0ef06f@redhat.com>
On 6/30/2018 3:25 AM, Laszlo Ersek wrote:
> (1) I think that, right after the above line, you are missing:
>
> BufferSize = ALIGN_VALUE (BufferSize, 8);
Yes. That's a bug in the patch. I will fix it in V4.
>
> It is not noticed in practice because
>
> AllocatePages (EFI_SIZE_TO_PAGES (BufferSize))
>
> rounds up the allocation anyway. However, the above ALIGN_VALUE() would
> be necessary to remain consistent with the ALIGN_VALUE() that is used
> below, in the assignment to "ApIdtBase".
>
>> + BufferSize += VolatileRegisters.Idtr.Limit + 1;
>> + BufferSize += sizeof (CPU_MP_DATA);
>> BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
>> MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
>> ASSERT (MpBuffer != NULL);
>> ZeroMem (MpBuffer, BufferSize);
>> Buffer = (UINTN) MpBuffer;
>>
>> + /*
>> + The layout of the Buffer is as below:
>> +
>> + +--------------------+ <-- Buffer
>> + AP Stacks (N)
>> + +--------------------+ <-- MonitorBuffer
>> + AP Monitor Filters (N)
>> + +--------------------+ <-- BackupBuffer
>> + Backup Buffer
>> + +--------------------+ <-- ApIdtBase (8-byte boundary)
>> + AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.
>> + +--------------------+ <-- CpuMpData
>> + CPU_MP_DATA
>> + +--------------------+ <-- CpuMpData->CpuData
>> + CPU_AP_DATA (N)
>> + +--------------------+ <-- CpuMpData->CpuInfoHob
>> + CPU_INFO_IN_HOB (N)
>> + +--------------------+
>> +
>> + */
> Some remarks for this comment block:
>
> (2) We should likely use the "//" comment style.
OK.
>
> (3) The "BackupBuffer" comment should be "CpuMpData->BackupBuffer". We
> don't have a "BackupBuffer" local variable, only "BackupBufferAddr".
OK.
>
> (4) "CpuMpData->CpuInfoHob" is a typo; it should be
> "CpuMpData->CpuInfoInHob".
OK.
>
>> MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
>> BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
>> - CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
>> + ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);
>> + CpuMpData = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1);
>> CpuMpData->Buffer = Buffer;
>> CpuMpData->CpuApStackSize = ApStackSize;
>> CpuMpData->BackupBuffer = BackupBufferAddr;
>> @@ -1557,10 +1586,14 @@ MpInitLibInitialize (
>> CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
>> CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
>> InitializeSpinLock(&CpuMpData->MpLock);
>> +
> (5) At this point, I suggest a self-check, something like:
>
> ASSERT ((CpuMpData->CpuInfoInHob +
> sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==
> Buffer + BufferSize);
>
OK.
>> //
>> - // Save BSP's Control registers to APs
>> + // Duplicate BSP's IDT to APs.
>> + // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1
>> //
>> - SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
>> + CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);
>> + VolatileRegisters.Idtr.Base = ApIdtBase;
>> + CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));
>> //
>> // Set BSP basic information
>> //
> This is my main concern.
>
> The first CopyMem() correctly populates the IDT that is supposed to be
> shared by all the APs, from the BSP's IDT.
>
> Then, we modify "VolatileRegisters" (which is never used in the function
> beyond the second CopyMem()), so that the IDTR base points to the APs'
> shared IDT. OK.
>
> Then, with the second CopyMem(), we put the*modified* VolatileRegisters
> into CpuData[0]. This replaces the original SaveVolatileRegisters()
> call, and as a result, the CpuData[0] IDTR base will now point to the
> APs' shared IDT, and not the BSPs own IDT.
>
> (6) Is this not a problem for the BSP itself?
>
> I see three explicit uses of CpuData[0] in the code, namely:
>
> (6a) The one added above by the patch.
>
> (6b) Lower down in the same MpInitLibInitialize() function:
>
> CopyMem (
> &CpuMpData->CpuData[Index].VolatileRegisters,
> &CpuMpData->CpuData[0].VolatileRegisters,
> sizeof (CPU_VOLATILE_REGISTERS)
> );
>
> I think this is fine, for all (Index > 0) values. We could as well use
> the local "VolatileRegisters" here, as source argument.
OK.
>
> (6c) And in ApWakeupFunction():
>
> //
> // Sync BSP's Control registers to APs
> //
> RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
>
> Minimally, we should update the comment to:
>
> //
> // Sync BSP's Control registers to APs. Note that IDTR.BASE is different.
> //
>
> Which means that, from now on, we generally consider CpuData[0] to stand
> for the BSP,*except* IDTR.BASE. (I guess we could redefine CpuData[0],
> not as "BSP", but as "initializer for APs
>
> Thus, are we sure that the BSP never uses CpuData[0].IDTR.BASE for its
> own purposes?
>
> Should we perhaps:
> - keep CpuData[0] unchanged,
> - introduce a new, dedicated field, "CpuMpData->ApIdtBase", and use that
> *explicitly* wherever necessary?
Then we will make the RestoreVolatileRegisters() a bit complex. It needs
to explicitly restores the IDT.
I will add more comments for CpuData[0].VolatileRegisters.
>
>
> (7) My next question is a corollary of the above -- what about
> SwitchBSP()?
>
> - Is SwitchBSP() compatible with this design?
Yes.
> - Will the new BSP start using the old BSP's IDT?
Yes.
> - More importantly, will the old BSP start using the IDT that is shared
> by the APs?
Yes.
1). AsmExchangeRole () exchanges the IDT of BSP and AP.
2). After returning from AsmExchangeRole(), old BSP runs in
ApWakeupFunction(). It saves IDTR value using below call:
SaveVolatileRegisters(&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
It guarantees next time when it's waken up, IDTR is restored using
below call:
RestoreVolatileRegisters(&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters,
TRUE);
ProcessorNumber is 0 after first SwitchBSP() call.
Please don't worry about your (6c) restore operation. That only
happens in InitConfig path.
>
> Without these, I think GetCpuMpData() would break. The new BSP would go
> to the HOB, which is OK. However, the old BSP (= new AP) would go to the
> *original* IDTR, and that's not usable for getting CpuMpData.
>
> (I don't know how CpuData[0] relates to the*current* -- possibly
> switched -- BSP.)
>
> Thank you!
> Laszlo
>
--
Thanks,
Ray
prev parent reply other threads:[~2018-07-02 5:56 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-29 10:42 [PATCH v3] UefiCpuPkg/MpInitLib: Avoid calling PEI services from AP Ruiyu Ni
2018-06-29 19:25 ` Laszlo Ersek
2018-07-02 5:56 ` Ni, Ruiyu [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=eeb783c7-cadb-f2dc-220d-88b4947a2a3c@Intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox