qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] Moving BIOS tables from SeaBIOS to QEMU


From: Laszlo Ersek
Subject: Re: [Qemu-devel] Moving BIOS tables from SeaBIOS to QEMU
Date: Mon, 25 Feb 2013 14:22:25 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130216 Thunderbird/17.0.3

On 02/24/13 19:00, Kevin O'Connor wrote:
> On Sat, Feb 23, 2013 at 04:47:26PM +0000, David Woodhouse wrote:
>> On Sat, 2013-02-23 at 11:38 -0500, Kevin O'Connor wrote:
>>> IMO, we need to move the ACPI table creation (and PIR/MPTABLE/SMBIOS)
>>> to QEMU and just have QEMU pass the tables to SeaBIOS for it to copy
>>> into memory like it does on CSM, coreboot, and Xen.
>>
>> I believe it's on Laszlo's TODO list.
> 
> Laszlo, what is your plan for doing this?

Didn't have much of a plan until now, just "look into it".

It seems quite a bit of work (I expect many resubmits to qemu-devel) and
I think I'd prefer to start working on it no earlier than March 18th.
(Of course if anyone else implements it by then I'll be happy :))

> I did a review of the SeaBIOS code to see what information is
> currently used to generate the ACPI, SMBIOS, MPTABLE, and PIR bios
> tables.  Here's what I came up with:
> 
> - hardcoded information: Most of the tables are simply hardcoded with
>   various values.  This should not be a problem to move to QEMU
> 
> - information passed in from QEMU: RamSize, RamSizeOver4G, fw_cfg
>   (irq0-override, system suspend states, numa memory, additional acpi
>   tables, smbios overrides).  These should also be possible to obtain
>   directly within QEMU (though I'm unsure how qemu exposes this
>   information internally).

In the long term I believe everything should be passed as fw_cfg files,
one file per table. I'm not sure about the naming convention, but
probably something like "acpi/SSDT".

This already seems quite messy. For example, acpi-dsdt.aml is built as
part of SeaBIOS, then installed on the filesystem with qemu.

Qemu can load manually specified ACPI tables from files, with the
-acpitable switch:

do_acpitable_option() [arch_init.c]
  acpi_table_add() [hw/acpi.c]

If no such option is specified, it auto-loads acpi-dsdt.aml (I'm
ignoring q35 for now).

Then the loaded tables are all exported under one fw_cfg key:

pc_init1() [hw/pc_piix.c]
  pc_acpi_init() [hw/pc.c]
    acpi_table_add() [hw/acpi.c]
  pc_memory_init() [hw/pc.c]
    bochs_bios_init()
      fw_cfg_add_bytes(..., FW_CFG_ACPI_TABLES, acpi_tables, ...)

SeaBIOS then splits/"relabels" this single blob into sub-blobs,

qemu_cfg_legacy()
  loop
    qemu_romfile_add("acpi/table%d", QEMU_CFG_ACPI_TABLES, offset, len)

Then eg. the DSDT is installed in

qemu_platform_setup()
  acpi_setup()
    romfile_findprefix()
    qemu_cfg_read_file() via funcptr
    fill_dsdt()

So it's a seabios-qemu-seabios ping-pong.

At first I would export the ACPI table in qemu (install the fw_cfg file)
in the same spot where currently the corresponding "base info" is
prepared for SeaBIOS. If a table in SeaBIOS is currently built from
several fw_cfg sources, then I'd probably export the qemu replacement in
the latest "base info" spot, verifying if I can still collect earlier
pieces of "base info".

I think we should move forward table-wise... each could take a separate
series.

Don't know what to do with the -acpitable switch though. A mixture of
loaded and autogenerated tables promises trouble.

> - CPU information: Number of CPUs, the apic id of the CPUs, which CPUs
>   are active, and the cpuid information from the first CPU.  Again
>   this should be available in QEMU, but I'm not sure what the internal
>   interfaces look like for obtaining it.

I'd just look at what the fw_cfg info is composed from, and re-use it.

> - Various hardware probes: The ioapic version, whether or not hpet is
>   present, running on piix4 or ich9, whether or not acpi should be
>   used.  Again should be possible to obtain from QEMU with sufficient
>   interfaces.
> 
> - PCI device info: The list of PCI devices, PCI buses, pin
>   assignments, irq assignments, if hotplug supported, and memory
>   regions.  This should mostly be available in QEMU - order of
>   initializing would be important so that the tables were initialized
>   after all PCI devices.
> 
> Of these, the only thing I see that could be problematic is the PCI
> irq assignments (used in mptable) and the PCI region space (used in
> ACPI DSDT _SB.PCI.CRS).  These are slightly problematic as they
> currently rely somewhat on the current SeaBIOS pciinit.c bridge/device
> setup.  However, the mptable irqs is a simple algorithm that could be
> replicated in QEMU, and it looks to be of dubious value anyway (so
> could possibly be dropped from the mptable).  Also, the PCI region
> space does not need to be exact, so a heuristic that just ensured it
> was large enough should suffice.

Without the CRS stuff efifb wasn't working in OVMF-based guests, so I
already had to implement a similar search in OVMF (with ample guidance
from Gerd & others of course). The series is archived under

http://thread.gmane.org/gmane.comp.bios.tianocore.devel/81

The interesting commits are:
http://tianocore.git.sourceforge.net/git/gitweb.cgi?p=tianocore/edk2;a=commitdiff;h=57c0beb609a75349c067075b45cdafce1a1b77f8
http://tianocore.git.sourceforge.net/git/gitweb.cgi?p=tianocore/edk2;a=commitdiff;h=cf98e61d1a6aea646f8f4063d950c2f3f2a00596

The search iterates over the memory map (below 4GB), determines the
highest reserved/system memory address, plus the smallest common
"bounding box" for all mmio ranges. Then this "bounding box" is clamped
up by the highest RAM address, and the result (if not the empty set) is
communicated via the same BDAT method. (The struct is allocated from the
"reserved pool".)

I guess this same iteration could be done inside qemu, using the memory
region API. The "info mtree" implementation could be a good example.
(See mtree_info() in "memory.c".)


> Given this, one possible way to migrate the ACPI tables from SeaBIOS
> would be to:
> 
> 1 - replace the BDAT PCI range interface in SeaBIOS with a SSDT based
>     template system similar to the way software suspend states are
>     handled in SeaBIOS today.  This would eliminate the only runtime
>     references to SeaBIOS memory from ACPI.

I've made peace with generating AML in C source.

> 2 - relicense the SeaBIOS' acpi.c, mptable.c, pirtable.c, smbios.c
>     code to GPLv2 (from LGPLv3) and copy into QEMU.  Only I've claimed
>     a copyright since Fabrice's work (LGPLv2) and I'm willing to
>     relicense.

That's very generous of you, thank you.

>     There have been a handful of contributors to these
>     files, but they all look to be regular QEMU contributors so I
>     don't think there would be any objections.  Along with the code,
>     the IASL parsing code and associated build python scripts would
>     also need to be copied into QEMU.

This is one area where I expect many stylistic remarks...

Plus, although python is already used in the qemu build process (to
generate C source from qapi schema, at least), "iasl" is not yet a
direct dependency of qemu.

> 3 - update the code to use the internal QEMU interfaces instead of the
>     SeaBIOS interfaces to obtain the information outlined above.

I believe rather than "copy + update" it'd be "read + rewrite" (which of
course still depends on you relicensing the SeaBIOS basis).

> 
> 4 - pass the tables from QEMU to SeaBIOS via the fw_cfg interface.
>     The PIR, MPTABLE, and SMBIOS are easy to copy into memory from
>     fw_cfg.  The ACPI does have a few tables that are special (RSDP,
>     RSDT, FADT, DSDT, FACS), but it should be easy to detect these and
>     update the pointers in SeaBIOS during the copy to memory.

That's how ACPI tables are installed in OVMF / edk2 as well; linked
tables are special-cased and pointers (and checksums) are set on the fly.

Thanks
Laszlo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]