Re: [edk2-devel] [PATCH v4 37/40] UefiCpuPkg: Allow AP booting under SEV-ES
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
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 +- >