Re: [edk2-devel] [PATCH v4 37/40] UefiCpuPkg: Allow AP booting under SEV-ES

2020-02-07 Thread Lendacky, Thomas
On 2/6/20 3:35 AM, Laszlo Ersek wrote:
> On 02/05/20 00:01, Lendacky, Thomas wrote:
>> BZ: 
>> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2198data=02%7C01%7Cthomas.lendacky%40amd.com%7Cf4521a4f24d54b8f122108d7aae7de74%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637165785175188824sdata=l7ff9Q7OFJ5JYGHt0meU04nBuM9aP1o5RT0fl8s9PoA%3Dreserved=0
>>
>> Typically, an AP is booted using the INIT-SIPI-SIPI sequence. This
>> sequence is intercepted by the hypervisor, which sets the AP's registers
>> to the values requested by the sequence. At that point, the hypervisor can
>> start the AP, which will then begin execution at the appropriate location.
>>
>> Under SEV-ES, AP booting presents some challenges since the hypervisor is
>> not allowed to alter the AP's register state. In this situation, we have
>> to distinguish between the AP's first boot and AP's subsequent boots.
>>
>> First boot:
>>  Once the AP's register state has been defined (which is before the guest
>>  is first booted) it cannot be altered. Should the hypervisor attempt to
>>  alter the register state, the change would be detected by the hardware
>>  and the VMRUN instruction would fail. Given this, the first boot for the
>>  AP is required to begin execution with this initial register state, which
>>  is typically the reset vector. This prevents the BSP from directing the
>>  AP startup location through the INIT-SIPI-SIPI sequence.
>>
>>  To work around this, the firmware will provide a build time reserved area
>>  that can be used as the initial IP value. The hypervisor can extract this
>>  location value by checking for the SEV-ES reset block GUID that must be
>>  located 48-bytes from the end of the firmware. The format of the SEV-ES
>>  reset block area is:
>>
>>0x00 - 0x01 - SEV-ES Reset IP
>>0x02 - 0x03 - SEV-ES Reset CS Segment Base[32:16]
> 
> Slight typo here I think: in the next patch, you correctly write [31:16].

Yup, good catch, should be 31.

Thanks,
Tom

> 
> Thanks
> Laszlo
> 
>>0x04 - 0x05 - Size of the SEV-ES reset block
>>0x06 - 0x15 - SEV-ES Reset Block GUID
>>(00f771de-1a7e-4fcb-890e-68c77e2fb44e)
>>
>>The total size is 22 bytes. Any expansion to this block must be done
>>by adding new values before existing values.
>>
>>  The hypervisor will use the IP and CS values obtained from the SEV-ES
>>  reset block to set as the AP's initial values. The CS Segment Base
>>  represents the upper 16 bits of the CS segment base and must be left
>>  shifted by 16 bits to form the complete CS segment base value.
>>
>>  Before booting the AP for the first time, the BSP must initialize the
>>  SEV-ES reset area. This consists of programming a FAR JMP instruction
>>  to the contents of a memory location that is also located in the SEV-ES
>>  reset area. The BSP must program the IP and CS values for the FAR JMP
>>  based on values drived from the INIT-SIPI-SIPI sequence.
>>
>> Subsequent boots:
>>  Again, the hypervisor cannot alter the AP register state, so a method is
>>  required to take the AP out of halt state and redirect it to the desired
>>  IP location. If it is determined that the AP is running in an SEV-ES
>>  guest, then instead of calling CpuSleep(), a VMGEXIT is issued with the
>>  AP Reset Hold exit code (0x8004). The hypervisor will put the AP in
>>  a halt state, waiting for an INIT-SIPI-SIPI sequence. Once the sequence
>>  is recognized, the hypervisor will resume the AP. At this point the AP
>>  must transition from the current 64-bit long mode down to 16-bit real
>>  mode and begin executing at the derived location from the INIT-SIPI-SIPI
>>  sequence.
>>
>>  Another change is around the area of obtaining the (x2)APIC ID during AP
>>  startup. During AP startup, the AP can't take a #VC exception before the
>>  AP has established a stack. However, the AP stack is set by using the
>>  (x2)APIC ID, which is obtained through CPUID instructions. A CPUID
>>  instruction will cause a #VC, so a different method must be used. The
>>  GHCB protocol supports a method to obtain CPUID information from the
>>  hypervisor through the GHCB MSR. This method does not require a stack,
>>  so it is used to obtain the necessary CPUID information to determine the
>>  (x2)APIC ID.
>>
>> The new 16-bit protected mode GDT entry is used in order to transition
>> from 64-bit long mode down to 16-bit real mode.
>>
>> A new assembler routine is created that takes the AP from 64-bit long mode
>> to 16-bit real mode.  This is located under 1MB in memory and transitions
>> from 64-bit long mode to 32-bit compatibility mode to 16-bit protected
>> mode and finally 16-bit real mode.
>>
>> Cc: Eric Dong 
>> Cc: Ray Ni 
>> Cc: Laszlo Ersek 
>> Signed-off-by: Tom Lendacky 
>> ---
>>  UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
>>  UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
>>  UefiCpuPkg/Library/MpInitLib/MpLib.h  |  

Re: [edk2-devel] [PATCH v4 37/40] UefiCpuPkg: Allow AP booting under SEV-ES

2020-02-06 Thread Laszlo Ersek
On 02/05/20 00:01, Lendacky, Thomas wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198
> 
> Typically, an AP is booted using the INIT-SIPI-SIPI sequence. This
> sequence is intercepted by the hypervisor, which sets the AP's registers
> to the values requested by the sequence. At that point, the hypervisor can
> start the AP, which will then begin execution at the appropriate location.
> 
> Under SEV-ES, AP booting presents some challenges since the hypervisor is
> not allowed to alter the AP's register state. In this situation, we have
> to distinguish between the AP's first boot and AP's subsequent boots.
> 
> First boot:
>  Once the AP's register state has been defined (which is before the guest
>  is first booted) it cannot be altered. Should the hypervisor attempt to
>  alter the register state, the change would be detected by the hardware
>  and the VMRUN instruction would fail. Given this, the first boot for the
>  AP is required to begin execution with this initial register state, which
>  is typically the reset vector. This prevents the BSP from directing the
>  AP startup location through the INIT-SIPI-SIPI sequence.
> 
>  To work around this, the firmware will provide a build time reserved area
>  that can be used as the initial IP value. The hypervisor can extract this
>  location value by checking for the SEV-ES reset block GUID that must be
>  located 48-bytes from the end of the firmware. The format of the SEV-ES
>  reset block area is:
> 
>0x00 - 0x01 - SEV-ES Reset IP
>0x02 - 0x03 - SEV-ES Reset CS Segment Base[32:16]

Slight typo here I think: in the next patch, you correctly write [31:16].

Thanks
Laszlo

>0x04 - 0x05 - Size of the SEV-ES reset block
>0x06 - 0x15 - SEV-ES Reset Block GUID
>(00f771de-1a7e-4fcb-890e-68c77e2fb44e)
> 
>The total size is 22 bytes. Any expansion to this block must be done
>by adding new values before existing values.
> 
>  The hypervisor will use the IP and CS values obtained from the SEV-ES
>  reset block to set as the AP's initial values. The CS Segment Base
>  represents the upper 16 bits of the CS segment base and must be left
>  shifted by 16 bits to form the complete CS segment base value.
> 
>  Before booting the AP for the first time, the BSP must initialize the
>  SEV-ES reset area. This consists of programming a FAR JMP instruction
>  to the contents of a memory location that is also located in the SEV-ES
>  reset area. The BSP must program the IP and CS values for the FAR JMP
>  based on values drived from the INIT-SIPI-SIPI sequence.
> 
> Subsequent boots:
>  Again, the hypervisor cannot alter the AP register state, so a method is
>  required to take the AP out of halt state and redirect it to the desired
>  IP location. If it is determined that the AP is running in an SEV-ES
>  guest, then instead of calling CpuSleep(), a VMGEXIT is issued with the
>  AP Reset Hold exit code (0x8004). The hypervisor will put the AP in
>  a halt state, waiting for an INIT-SIPI-SIPI sequence. Once the sequence
>  is recognized, the hypervisor will resume the AP. At this point the AP
>  must transition from the current 64-bit long mode down to 16-bit real
>  mode and begin executing at the derived location from the INIT-SIPI-SIPI
>  sequence.
> 
>  Another change is around the area of obtaining the (x2)APIC ID during AP
>  startup. During AP startup, the AP can't take a #VC exception before the
>  AP has established a stack. However, the AP stack is set by using the
>  (x2)APIC ID, which is obtained through CPUID instructions. A CPUID
>  instruction will cause a #VC, so a different method must be used. The
>  GHCB protocol supports a method to obtain CPUID information from the
>  hypervisor through the GHCB MSR. This method does not require a stack,
>  so it is used to obtain the necessary CPUID information to determine the
>  (x2)APIC ID.
> 
> The new 16-bit protected mode GDT entry is used in order to transition
> from 64-bit long mode down to 16-bit real mode.
> 
> A new assembler routine is created that takes the AP from 64-bit long mode
> to 16-bit real mode.  This is located under 1MB in memory and transitions
> from 64-bit long mode to 32-bit compatibility mode to 16-bit protected
> mode and finally 16-bit real mode.
> 
> Cc: Eric Dong 
> Cc: Ray Ni 
> Cc: Laszlo Ersek 
> Signed-off-by: Tom Lendacky 
> ---
>  UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
>  UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
>  UefiCpuPkg/Library/MpInitLib/MpLib.h  |  60 
>  UefiCpuPkg/Library/MpInitLib/DxeMpLib.c   |  70 -
>  UefiCpuPkg/Library/MpInitLib/MpLib.c  | 256 +-
>  UefiCpuPkg/Library/MpInitLib/PeiMpLib.c   |  19 ++
>  UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c  |   2 +-
>  UefiCpuPkg/Library/MpInitLib/Ia32/MpEqu.inc   |   2 +-
>  .../Library/MpInitLib/Ia32/MpFuncs.nasm   |  15 +
>  UefiCpuPkg/Library/MpInitLib/X64/MpEqu.inc|   4 +-
>