Re: Question on UEFI ACPI tables setup and probing on arm64
On 11/7/2020 1:09 AM, Laszlo Ersek wrote: On 11/05/20 05:30, Ying Fang wrote: I see it in Qemu the *loader_start* is fixed at 1 GiB on the physical address space which points to the DRAM base. In ArmVirtQemu.dsc PcdDeviceTreeInitialBaseAddress is set 0x4000 with correspondence. Here I also see the discussion about DRAM base for ArmVirtQemu. https://lists.gnu.org/archive/html/qemu-devel/2017-10/msg03127.html I am still not sure how UEFI knows that it is running on a ArmVirtQemu machine type. It doesn't know. It remains a convention. This part is not auto-detected; the constants in QEMU and edk2 are independently open-coded, their values were synchronized by human effort initially. The user or the management layer have to make sure they boot a UEFI firmware binary on the machine type that is compatible with the machine type. There is some meta-data to help with that: Thanks so much for the reply, I now have the basic understanding how QEMU and EDK2 works together after reading the docs and code there. Does UEFI derive it from the fdt *compatible* property ? Please see the schema "docs/interop/firmware.json" in the QEMU tree; in particular the @FirmwareTarget element. For an actual example: QEMU bundles some edk2 firmware binaries (purely as a convenience, not for production), and those are accompanied by matching descriptor files. See "pc-bios/descriptors/60-edk2-aarch64.json". (It is a template that's fixed up during QEMU installation, but that's tangential here.) "targets": [ { "architecture": "aarch64", "machines": [ "virt-*" ] } ], Thanks, I'll look closer into it. Thanks Laszlo .
Re: Question on UEFI ACPI tables setup and probing on arm64
On 11/05/20 05:30, Ying Fang wrote: > I see it in Qemu the *loader_start* is fixed at 1 GiB on the > physical address space which points to the DRAM base. In ArmVirtQemu.dsc > PcdDeviceTreeInitialBaseAddress is set 0x4000 with correspondence. > > Here I also see the discussion about DRAM base for ArmVirtQemu. > https://lists.gnu.org/archive/html/qemu-devel/2017-10/msg03127.html > > I am still not sure how UEFI knows that it is running on a ArmVirtQemu > machine type. It doesn't know. It remains a convention. This part is not auto-detected; the constants in QEMU and edk2 are independently open-coded, their values were synchronized by human effort initially. The user or the management layer have to make sure they boot a UEFI firmware binary on the machine type that is compatible with the machine type. There is some meta-data to help with that: > Does UEFI derive it from the fdt *compatible* property ? Please see the schema "docs/interop/firmware.json" in the QEMU tree; in particular the @FirmwareTarget element. For an actual example: QEMU bundles some edk2 firmware binaries (purely as a convenience, not for production), and those are accompanied by matching descriptor files. See "pc-bios/descriptors/60-edk2-aarch64.json". (It is a template that's fixed up during QEMU installation, but that's tangential here.) "targets": [ { "architecture": "aarch64", "machines": [ "virt-*" ] } ], Thanks Laszlo
Re: Question on UEFI ACPI tables setup and probing on arm64
On 11/5/2020 5:46 AM, Laszlo Ersek wrote: +Ard, +Drew On 11/03/20 13:39, Igor Mammedov wrote: On Fri, 30 Oct 2020 10:50:01 +0800 Ying Fang wrote: Hi, I have a question on UEFI/ACPI tables setup and probing on arm64 platform. CCing Laszlo, who might know how it's implemented. Currently on arm64 platform guest can be booted with both fdt and ACPI supported. If ACPI is enabled, [1] says the only defined method for passing ACPI tables to the kernel is via the UEFI system configuration table. So AFAIK, ACPI Should be dependent on UEFI. That's correct. The ACPI entry point (RSD PTR) on AARCH64 is defined in terms of UEFI. What's more [2] says UEFI kernel support on the ARM architectures is only available through a *stub*. The stub populates the FDT /chosen node with some UEFI parameters describing the UEFI location info. Yes. So i dump /sys/firmware/fdt from the guest, it does have something like: /dts-v1/; / { #size-cells = <0x02>; #address-cells = <0x02>; chosen { linux,uefi-mmap-desc-ver = <0x01>; linux,uefi-mmap-desc-size = <0x30>; linux,uefi-mmap-size = <0x810>; linux,uefi-mmap-start = <0x04 0x3c0ce018>; linux,uefi-system-table = <0x04 0x3f8b0018>; bootargs = "BOOT_IMAGE=/vmlinuz-4.19.90-2003.4.0.0036.oe1.aarch64 root=/dev/mapper/openeuler-root ro rd.lvm.lv=openeuler/root rd.lvm.lv=openeuler/swap video=VGA-1:640x480-32@60me smmu.bypassdev=0x1000:0x17 smmu.bypassdev=0x1000:0x15 crashkernel=1024M,high video=efifb:off video=VGA-1:640x480-32@60me"; linux,initrd-end = <0x04 0x3a85a5da>; linux,initrd-start = <0x04 0x392f2000>; }; }; But the question is that I did not see any code adding the uefi in fdt chosen node in *arm_load_dtb* or anywhere else. That's because the "UEFI stub" is a part of the guest kernel. It wraps the guest kernel image into a UEFI application binary. For a while, the guest kernel runs as a UEFI application, stashing some UEFI artifacts in *a* device tree, and then (after some other heavy lifting) jumping into the kernel proper. Qemu only maps the OVMF binary file into a pflash device. So I'm really confused on how UEFI information is provided to guest by qemu. Does anybody know of the details about it ? It's complex, unfortunately. (1) QEMU always generates a DTB for the guest firmware. This DTB is placed at the base of the guest RAM. See the arm_load_dtb() call in virt_machine_done() [hw/arm/virt.c] in QEMU. I think. Hi Laszlo. Thanks so much for sharing the details with us. The reply nearly covers the boot sequence of aarch64 on the whole. I see it in Qemu the *loader_start* is fixed at 1 GiB on the physical address space which points to the DRAM base. In ArmVirtQemu.dsc PcdDeviceTreeInitialBaseAddress is set 0x4000 with correspondence. Here I also see the discussion about DRAM base for ArmVirtQemu. https://lists.gnu.org/archive/html/qemu-devel/2017-10/msg03127.html I am still not sure how UEFI knows that it is running on a ArmVirtQemu machine type. Does UEFI derive it from the fdt *compatible* property ? (2) QEMU generates ACPI content, and exposes it via fw_cfg. See the virt_acpi_setup() call in the same virt_machine_done() function [hw/arm/virt.c] in QEMU. (3) The fw_cfg device itself is apparent to the guest firmware via the DTB from point (1). See the following steps in edk2: (3a) "ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c" This saves the initial DTB (from the base of guest RAM, where it could be overwritten by whatever) to a dynamically allocated area. This "stashing" occurs early. (3b) "ArmVirtPkg/FdtClientDxe/FdtClientDxe.c" This driver exposes the (dynamically reallocated / copied) DTB via a custom UEFI protocol to the rest of the firmware. (This happens much later.) This protocol / driver can be considered the "owner" of the stashed DTB from (3a). (3c) "ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c" This is the fw_cfg device access library, discovering the fw_cfg registers via the above UEFI protocol. The library is linked into each firmware module that needs fw_cfg access. (4) The firmware interprets QEMU's DTB for actual content (parsing values, configuring hardware, accessing devices). This occurs in a whole bunch of locations, mostly via consuming the custom protocol from (3b). Some info that's needed very early is parsed out of the DTB right in step (3a). (5) The guest firmware has a dedicated driver that checks whether QEMU was configured with ACPI enabled or disabled, and publishes that choice to the rest of the firmware. This is necessary because some firmware actions / infrastructure parts cannot (must not) proceed until this decision has been interpreted. See in edk2:
Re: Question on UEFI ACPI tables setup and probing on arm64
On 11/4/20 10:46 PM, Laszlo Ersek wrote: ... (9) (Ard, please correct the below if necessary; thanks.) The UEFI stub of the guest kernel (which is a UEFI application) uses a device tree as its main communication channel to the (later-started) kernel entry point, AIUI. The UEFI stub basically inverts the importance of the UEFI system table versus the device tree -- the UEFI stub *converts* the UEFI system table (the multitude of UEFI config tables) into a device tree. This is my understanding anyway. Not entirely. The UEFI stub uses DT to communicate with the kernel proper, just like a non-EFI bootloader does. There are two pieces of information regarding EFI that the stub passes via the device tree: - the EFI system table address - the EFI memory map (address, size, descriptor size etc) (Aside: unfortunately, we cannot pass the latter information via a EFI configuration table, given that we call SetVirtualAddressMap() in the stub, which causes the config_tables member of the system table to be converted into a virtual address. That virtual address can only be converted into a physical address if we have access to the EFI memory map.) All other information passed between the EFI stub and the kernel proper is passed via Linux-specific EFI configuration tables. (9a) If ACPI was disabled on the QEMU command line, then the guest kernel *adopts* the device tree that was forwarded to it in (6), via the UEFI config table marked with DEVICE_TREE_GUID. Yes, although the EFI stub updates/augments it with the two data items mentioned above, as well as the kernel command line, initrd base and size and a KASLR seed [if enabled]. (9b) If ACPI was enabled on the QEMU command line, then the UEFI stub creates a brand new (empty) device tree (AIUI). ... unless GRUB executed first and loaded a initrd, and passed this information via the device tree. In this case, GRUB creates an empty DT (Note that I posted the GRUB patches to implement LoadFile2 based initrd loading just a week or so ago) Either way, the UEFI system table is linked *under* the -- adopted or new -- device tree, through the "chosen" node. And so, if ACPI was enabled, the ACPI RSD PTR (coming from step (7)) becomes visible to the kernel proper as well, through the UEFI config table with ACPI_20_TABLE_GUID. I believe this is implemented under "drivers/firmware/efi/libstub" in the kernel tree. Thanks, Laszlo
Re: Question on UEFI ACPI tables setup and probing on arm64
+Ard, +Drew On 11/03/20 13:39, Igor Mammedov wrote: > On Fri, 30 Oct 2020 10:50:01 +0800 > Ying Fang wrote: > >> Hi, >> >> I have a question on UEFI/ACPI tables setup and probing on arm64 platform. > > CCing Laszlo, > who might know how it's implemented. > >> Currently on arm64 platform guest can be booted with both fdt and ACPI >> supported. If ACPI is enabled, [1] says the only defined method for >> passing ACPI tables to the kernel is via the UEFI system configuration >> table. So AFAIK, ACPI Should be dependent on UEFI. That's correct. The ACPI entry point (RSD PTR) on AARCH64 is defined in terms of UEFI. >> >> What's more [2] says UEFI kernel support on the ARM architectures >> is only available through a *stub*. The stub populates the FDT /chosen >> node with some UEFI parameters describing the UEFI location info. Yes. >> >> So i dump /sys/firmware/fdt from the guest, it does have something like: >> >> /dts-v1/; >> >> / { >> #size-cells = <0x02>; >> #address-cells = <0x02>; >> >> chosen { >> linux,uefi-mmap-desc-ver = <0x01>; >> linux,uefi-mmap-desc-size = <0x30>; >> linux,uefi-mmap-size = <0x810>; >> linux,uefi-mmap-start = <0x04 0x3c0ce018>; >> linux,uefi-system-table = <0x04 0x3f8b0018>; >> bootargs = >> "BOOT_IMAGE=/vmlinuz-4.19.90-2003.4.0.0036.oe1.aarch64 >> root=/dev/mapper/openeuler-root ro rd.lvm.lv=openeuler/root >> rd.lvm.lv=openeuler/swap video=VGA-1:640x480-32@60me >> smmu.bypassdev=0x1000:0x17 smmu.bypassdev=0x1000:0x15 >> crashkernel=1024M,high video=efifb:off video=VGA-1:640x480-32@60me"; >> linux,initrd-end = <0x04 0x3a85a5da>; >> linux,initrd-start = <0x04 0x392f2000>; >> }; >> }; >> >> But the question is that I did not see any code adding the uefi >> in fdt chosen node in *arm_load_dtb* or anywhere else. That's because the "UEFI stub" is a part of the guest kernel. It wraps the guest kernel image into a UEFI application binary. For a while, the guest kernel runs as a UEFI application, stashing some UEFI artifacts in *a* device tree, and then (after some other heavy lifting) jumping into the kernel proper. >> Qemu only maps the OVMF binary file into a pflash device. >> So I'm really confused on how UEFI information is provided to >> guest by qemu. Does anybody know of the details about it ? It's complex, unfortunately. (1) QEMU always generates a DTB for the guest firmware. This DTB is placed at the base of the guest RAM. See the arm_load_dtb() call in virt_machine_done() [hw/arm/virt.c] in QEMU. I think. (2) QEMU generates ACPI content, and exposes it via fw_cfg. See the virt_acpi_setup() call in the same virt_machine_done() function [hw/arm/virt.c] in QEMU. (3) The fw_cfg device itself is apparent to the guest firmware via the DTB from point (1). See the following steps in edk2: (3a) "ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c" This saves the initial DTB (from the base of guest RAM, where it could be overwritten by whatever) to a dynamically allocated area. This "stashing" occurs early. (3b) "ArmVirtPkg/FdtClientDxe/FdtClientDxe.c" This driver exposes the (dynamically reallocated / copied) DTB via a custom UEFI protocol to the rest of the firmware. (This happens much later.) This protocol / driver can be considered the "owner" of the stashed DTB from (3a). (3c) "ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c" This is the fw_cfg device access library, discovering the fw_cfg registers via the above UEFI protocol. The library is linked into each firmware module that needs fw_cfg access. (4) The firmware interprets QEMU's DTB for actual content (parsing values, configuring hardware, accessing devices). This occurs in a whole bunch of locations, mostly via consuming the custom protocol from (3b). Some info that's needed very early is parsed out of the DTB right in step (3a). (5) The guest firmware has a dedicated driver that checks whether QEMU was configured with ACPI enabled or disabled, and publishes that choice to the rest of the firmware. This is necessary because some firmware actions / infrastructure parts cannot (must not) proceed until this decision has been interpreted. See in edk2: - ArmVirtPkg/PlatformHasAcpiDtDxe This driver keys off of the presence of the "etc/table-loader" fw_cfg file, coming from step (2), using the fw_cfg access library from step (3c). If ACPI was enabled on the QEMU cmdline, then the rest of the firmware is "level-triggered" to proc
Re: Question on UEFI ACPI tables setup and probing on arm64
On Fri, 30 Oct 2020 10:50:01 +0800 Ying Fang wrote: > Hi, > > I have a question on UEFI/ACPI tables setup and probing on arm64 platform. CCing Laszlo, who might know how it's implemented. > Currently on arm64 platform guest can be booted with both fdt and ACPI > supported. If ACPI is enabled, [1] says the only defined method for > passing ACPI tables to the kernel is via the UEFI system configuration > table. So AFAIK, ACPI Should be dependent on UEFI. > > What's more [2] says UEFI kernel support on the ARM architectures > is only available through a *stub*. The stub populates the FDT /chosen > node with some UEFI parameters describing the UEFI location info. > > So i dump /sys/firmware/fdt from the guest, it does have something like: > > /dts-v1/; > > / { > #size-cells = <0x02>; > #address-cells = <0x02>; > > chosen { > linux,uefi-mmap-desc-ver = <0x01>; > linux,uefi-mmap-desc-size = <0x30>; > linux,uefi-mmap-size = <0x810>; > linux,uefi-mmap-start = <0x04 0x3c0ce018>; > linux,uefi-system-table = <0x04 0x3f8b0018>; > bootargs = > "BOOT_IMAGE=/vmlinuz-4.19.90-2003.4.0.0036.oe1.aarch64 > root=/dev/mapper/openeuler-root ro rd.lvm.lv=openeuler/root > rd.lvm.lv=openeuler/swap video=VGA-1:640x480-32@60me > smmu.bypassdev=0x1000:0x17 smmu.bypassdev=0x1000:0x15 > crashkernel=1024M,high video=efifb:off video=VGA-1:640x480-32@60me"; > linux,initrd-end = <0x04 0x3a85a5da>; > linux,initrd-start = <0x04 0x392f2000>; > }; > }; > > But the question is that I did not see any code adding the uefi > in fdt chosen node in *arm_load_dtb* or anywhere else. > Qemu only maps the OVMF binary file into a pflash device. > So I'm really confused on how UEFI information is provided to > guest by qemu. Does anybody know of the details about it ? > > [1] https://www.kernel.org/doc/html/latest/arm64/arm-acpi.html > [2] https://www.kernel.org/doc/Documentation/arm/uefi.rst > > Thanks. > Ying >
Question on UEFI ACPI tables setup and probing on arm64
Hi, I have a question on UEFI/ACPI tables setup and probing on arm64 platform. Currently on arm64 platform guest can be booted with both fdt and ACPI supported. If ACPI is enabled, [1] says the only defined method for passing ACPI tables to the kernel is via the UEFI system configuration table. So AFAIK, ACPI Should be dependent on UEFI. What's more [2] says UEFI kernel support on the ARM architectures is only available through a *stub*. The stub populates the FDT /chosen node with some UEFI parameters describing the UEFI location info. So i dump /sys/firmware/fdt from the guest, it does have something like: /dts-v1/; / { #size-cells = <0x02>; #address-cells = <0x02>; chosen { linux,uefi-mmap-desc-ver = <0x01>; linux,uefi-mmap-desc-size = <0x30>; linux,uefi-mmap-size = <0x810>; linux,uefi-mmap-start = <0x04 0x3c0ce018>; linux,uefi-system-table = <0x04 0x3f8b0018>; bootargs = "BOOT_IMAGE=/vmlinuz-4.19.90-2003.4.0.0036.oe1.aarch64 root=/dev/mapper/openeuler-root ro rd.lvm.lv=openeuler/root rd.lvm.lv=openeuler/swap video=VGA-1:640x480-32@60me smmu.bypassdev=0x1000:0x17 smmu.bypassdev=0x1000:0x15 crashkernel=1024M,high video=efifb:off video=VGA-1:640x480-32@60me"; linux,initrd-end = <0x04 0x3a85a5da>; linux,initrd-start = <0x04 0x392f2000>; }; }; But the question is that I did not see any code adding the uefi in fdt chosen node in *arm_load_dtb* or anywhere else. Qemu only maps the OVMF binary file into a pflash device. So I'm really confused on how UEFI information is provided to guest by qemu. Does anybody know of the details about it ? [1] https://www.kernel.org/doc/html/latest/arm64/arm-acpi.html [2] https://www.kernel.org/doc/Documentation/arm/uefi.rst Thanks. Ying