Re: Question on UEFI ACPI tables setup and probing on arm64

2020-11-09 Thread Ying Fang




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

2020-11-06 Thread Laszlo Ersek
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

2020-11-04 Thread Ying Fang




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

2020-11-04 Thread Ard Biesheuvel

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

2020-11-04 Thread Laszlo Ersek
+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

2020-11-03 Thread Igor Mammedov
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

2020-10-29 Thread Ying Fang

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