On 09/05/14 10:52, Laszlo Ersek wrote:
> On 08/26/14 02:12, Jordan Justen wrote:
>> On Mon, Aug 25, 2014 at 4:27 PM, Laszlo Ersek <ler...@redhat.com> wrote:
>>> On 08/26/14 00:24, Jordan Justen wrote:
>>>> On Fri, Aug 8, 2014 at 7:08 PM, Laszlo Ersek <ler...@redhat.com> wrote:
>>>>> Recent changes in the QEMU ACPI table generator have shown that our
>>>>> limited client for that interface is insufficient and/or brittle.
>>>>>
>>>>> Implement the full interface utilizing OrderedCollectionLib for addressing
>>>>> fw_cfg blobs by name.
>>>>>
>>>>> In addition, we stop using EFI_ACPI_TABLE_PROTOCOL in the QEMU loader
>>>>> client, because:
>>>>> - splitting the blobs for EFI_ACPI_TABLE_PROTOCOL is just untenable short
>>>>>   of a complete ACPI parser,
>>>>> - and it is fully sufficient to install the RSD PTR as an EFI
>>>>>   configuration table for the guest OS to see everything.
>>>>>
>>>>> In short, for this interface, EFI_ACPI_TABLE_PROTOCOL is an unwanted and
>>>>> restrictive convenience; let's stop using it.
>>>>
>>>> Hmm. Been through a few rounds of this for Xen. It's QEMU's turn now? :)
>>>>
>>>> Is this required?
>>>
>>> Depends on how good (how accurate) ACPI tables you want to have in your
>>> VMs. For a few qemu releases now, qemu has been the "master" of ACPI
>>> payload generation. SeaBIOS too has kept its own builtin tables, yes,
>>> but when the QEMU generated payload is available, it interprets this
>>> linker/loader script just the same.
>>>
>>> If you want PCI hotplug, pvpanic support; or, going forward, memory
>>> hotplug, then yes, those things need ACPI support, and the ACPI stuff
>>> for them is now developed in QEMU (and dynamically generated by it,
>>> dependent on the actual hardware config).
>>>
>>>> What happens if another driver uses EFI_ACPI_TABLE_PROTOCOL? We now
>>>> have two drivers that want to install the pointer.
>>>
>>> Yes, I checked that. The UEFI spec says that whenever you install a
>>> configuration table that's already present (by GUID), the reference is
>>> updated.
>>>
>>>   InstallConfigurationTable()
>>>
>>>   [...]
>>>   * If Guid is present in the System Table, and Table is not NULL, then
>>>     the (Guid, Table) pair is updated with the new Table value.
>>>   [...]
>>>
>>> For this reason, the first thing InstallAllQemuLinkedTables() does is
>>> check, with EfiGetSystemConfigurationTable(), for the presence of any of
>>> the ACPI GUIDs in the config table.
>>>
>>> There's no "absolute" cure against another driver in OVMF just grabbing
>>> EFI_ACPI_TABLE_PROTOCOL and installing its own stuff (which would then
>>> completely hide the tables installed by this patchset, because
>>> "MdeModulePkg/Universal/Acpi/AcpiTableDxe" would simply replace QEMU's
>>> RSD PTR's address in the UEFI config table with its own).
>>>
>>> But ACPI tables are not randomly installed in OVMF, we keep it
>>> centralized in AcpiTableDxe.
>>
>> I don't agree with this statement. Rather, I would say that OVMF
>> follows the EDK II method of publishing tables, which means
>> EFI_ACPI_TABLE_PROTOCOL.
>>
>> In the past we were a good little sample platform, and provided the
>> ACPI tables directly. Well, that is less and less the case. But, is it
>> a good idea to stop using EFI_ACPI_TABLE_PROTOCOL?
>>
>> What about MdeModulePkg/Universal/Network/IScsiDxe/IScsiIbft.c, which
>> uses EFI_ACPI_TABLE_PROTOCOL?
>>
>> Do we need to keep monitoring which EDK II drivers decide to use
>> EFI_ACPI_TABLE_PROTOCOL, or can we find a way to make these work
>> together? If the answer is no, then I wonder if this is something that
>> UEFI or EDK II needs to consider.
> 
> I think I might have found a solution -- at this point it's just an
> idea, but I want to run it by you guys first before I start implementing
> it. The idea is based on this patchset, in an incremental fashion.
> 
> Where the current code calls gBS->InstallConfigurationTable(), we shall
> replace that call with further processing.
> 
> Michael has proposed before to check the *targets* of all the pointer
> commands. Namely, a pointed-to "something" in the blob that hosts it is
> with a good chance an ACPI table. Not guaranteed, but likely.
> 
> Now, after all is done by the current patchset *except* linking the RSDP
> into the UEFI config table, the payload we have in AcpiNVS memory is a
> nicely cross-linked, checksummed forest of ACPI stuff. We re-scan the
> QEMU commands. We ignore everything different from AddPointer. When an
> AddPointer call is found, the following statements are true:
> 
> (a) the pointer field in the blob that the AddPointer call would
> originally patch *now* contains a valid, absolute physical address.
> 
> (b) the pointed-to byte-array may or may not be an ACPI table. It could
> be an ACPI table, or it could be some funny area that QEMU has
> preallocated, like the target of the TCPA.LASA field, or the target of
> the BGRT.ImageAddress field, or something else.
> 
> (c) *if* the pointed-to byte-array is an ACPI table, then we'll have it
> already checksummed, since we're past the first complete pass of the
> processing.
> 
> So the idea is, look at the target area,
> - determine if the remaining size in that blob (the pointed-to blob)
>   could still contain an ACPI table header,
> - if so, check the presumed "length" field in that header, and see if
>   it's self-consistent (ie. >= sizeof(header), and <= remaining size in
>   blob)
> - if so, run a checksum on the bytes that presumably constitute the
>   ACPI table
> - if it sums to zero, we attempt to install the target area with
>   EFI_ACPI_TABLE_PROTOCOL, otherwise we leave it alone.
> 
> Now, EFI_ACPI_TABLE_PROTOCOL makes deep copies of the tables it gets,
> but we'll leave the entire forest that we've build during the first
> processing in place. Why? Because this way all the stuff that *didn't*
> look like an ACPI table during the procedure above will remain in place,
> and the pointers *to* them will remain valid, in those ACPI table copies
> that EFI_ACPI_TABLE_PROTOCOL creates.
> 
> For example, consider a BGRT table, where QEMU places both the BGRT in
> the blob, and the image data right after it (and sets BGRT.ImageAddress
> to the relative address inside the blob where the image data starts).
> The above procedure will result in:
> 
> - the BGRT table itself being allocated twice, once by our first pass,
> and once by EFI_ACPI_TABLE_PROTOCOL itself (from the second pass). The
> first instance will be leaked (it won't be reachable from the system
> table that EFI_ACPI_TABLE_PROTOCOL now manages), but it's not grave.
> 
> - the BGRT image data will be allocated only once, from our first pass,
> and it will be referenced *both* from our first-pass BGRT table (which
> is irrelevant) *and* from the BGRT copy that EFI_ACPI_TABLE_PROTOCOL
> installs (which is relevant).
> 
> This approach would leak a few pages of AcpiNVS memory, and it has a
> slight chance to call EFI_ACPI_TABLE_PROTOCOL.InstallTable() with
> garbage (that has a valid-looking Length field and checksums to zero).
> But it would remain compatible with EFI_ACPI_TABLE_PROTOCOL, and it
> wouldn't miss anything from QEMU's payload that in fact *is* an ACPI table.

In addition, I could tighten the Length + checksum validation with
ACPI_BUILD_APPNAME6 and ACPI_BUILD_APPNAME4 checks, according to qemu's
build_header() function -- if Michael agrees that these are stable. IOW,
the OEMID would have to be "BOCHS ", and the first four bytes of
OEMTableID would have to be "BXPC". I think these four checks together
are pretty strong: a static check for a *10-byte* signature (in effect),
and a dynamic check for length + checksum.

I think this should be acceptable.

Thanks,
Laszlo

------------------------------------------------------------------------------
Slashdot TV.  
Video for Nerds.  Stuff that matters.
http://tv.slashdot.org/
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to