On 07/17/20 15:13, Igor Mammedov wrote:
> On Tue, 14 Jul 2020 14:28:29 +0200
> Laszlo Ersek <ler...@redhat.com> wrote:
> 
>> (CC'ing Peter Krempa due to virsh setvcpu (singular) / setvcpus (plural)
>> references)
>>
>> On 07/10/20 18:17, Igor Mammedov wrote:
> [...]
> 
>> (3) Just a thought: I wonder if we should reserve both ports (0xB2 and
>> 0xB3 too). For now we don't have any use for the "data" port, but
>> arguably it's part of the same register block.
> 
> we probably should, might be used for unplug part.
> 
> BTW any ideas how we'd like to procceed with unplug?
> 
> current flow looks like:
> 
> QEMU                       OSPM
> unplug_req()
> 1)   =>SCI     --->
>   -------------------------
> 2)                   handle_sci()
>                          scan for events and send
>                              Notify per removed CPU
>                              clear rm_evt
>   -------------------------
> 3)                   offline cpu
>   -------------------------
> 4)                    call _EJ0 to unplug CPU
>                          write into ej_evt
>               <-------------
>   -------------------------
> 5)  unplug cb
>  
> 
> We probably should modify _EJ0 to send SMI instead of direct access
> to cpuhp block, the question is how OSPM would tell FW which CPU it
> ejects.

The optimal solution would be DataTableRegion, but of course Windows
doesn't support that. So the usual replacement is something like below
(we used a variant of it in "docs/specs/vmgenid.txt"):

- Create a new ACPI data table. See "Appendix O - UEFI ACPI Data Table",
table 94, in the UEFI 2.8 spec <https://uefi.org/specifications>. In
this table, set

  Identifier = B055E4C3-B5B5-4948-9D02-A46FCA3B0A3B

(I just generated this with "uuidgen"). Set DataOffset to 54 decimal.
Place 4 zeroes at offset 54, for Data.

- Create a SystemMemory Operation Region, 58 bytes in size (for covering
the entire table), with a single 4-byte Field at offset 54. Use the
add_pointer command for pointing the OperationRegion opcode to offset 0
(that is, the very beginning) of the above-created ACPI table.

(Normally I would suggest creating an Integer object, using add_pointer
on the Integer object, and then dynamically creating an OperationRegion
at that Integer address -- but I don't know if Windows can deal with
dynamically determined OperationRegion addresses.)

- In the CPU hot-unplug ACPI code, write the APIC ID (or the selector I
guess?) of the CPU being un-plugged to the field at offset 54, before
raising the SMI

- Raise the SMI with a new command (value 5, I guess)

- in OVMF, the CpuHotplugSmm driver can register an EndOfDxe callback,
and use EFI_ACPI_SDT_PROTOCOL.GetAcpiTable(), in a loop, for locating
the data table. Save a pointer (in SMRAM) to offset 54 of that table. At
runtime, when handling the SMI (command 5) read the APIC ID (or
selector) from the data field at offset 54.

(The AddTableToList() function in edk2's
"MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableProtocol.c" file
makes sure that "UEFI ACPI Data Tables" are allocated in AcpiNVS memory,
which is permitted for use as an "SMM communication buffer".)

(The difference with VMGENID is that QEMU need not learn of the
guest-side address of the data table, hence no "write_pointer" command.
Instead, CpuHotplugSmm needs to learn of the address. That can be done
with in an EndOfDxe callback, using EFI_ACPI_SDT_PROTOCOL.GetAcpiTable()
in a loop, but that does require QEMU to produce a real ACPI data table,
not just a header-less blob placed in AcpiNVS memory.)

Thanks,
Laszlo


Reply via email to