Re: riscv disassembler error with pmpcfg0
Thank you! Eric On Tuesday, May 14, 2024 at 12:19:55 AM CDT, Alistair Francis wrote: On Thu, Apr 4, 2024 at 5:02 AM Eric DeVolder wrote: > > I've been using QEMU8 to collect instruction information on U-Boot + OpenSBI. > > I'm running QEMU in this fashion to collect the information: > > # qemu-system-riscv64 -plugin file=qemu/build/contrib/plugins/libexeclog.so > -singlestep -d plugin,nochain -D execlog.txt ... > > When examining the instruction trace in execlog, I've noticed that the > disassembly for pmpcfg0 is erroneous, for example: > > 0, 0x5456, 0x3a002573, "csrrs a0,pmpcfg3,zero" > > the CSR encoded in the instruction above is 0x3a0, which is pmpcfg0 (which > also matches the code I'm examining). > > For the Uboot+OpenSBI code I'm examining, pmpcfg0/3 is the only one that > appears to have a problem. > > I also checked QEMU9 and it behaves as described above as well. > > I'm willing to provide a fix if I can get some advice/pointers on how this > disassembly statement is generated...I did take a quick look but it didn't > appear obvious how... Thanks for pointing this out. This should fix the issue for you: https://patchew.org/QEMU/20240514051615.330979-1-alistair.fran...@wdc.com/ Alistair > > Thanks, > eric >
riscv disassembler error with pmpcfg0
I've been using QEMU8 to collect instruction information on U-Boot + OpenSBI. I'm running QEMU in this fashion to collect the information: # qemu-system-riscv64 -plugin file=qemu/build/contrib/plugins/libexeclog.so -singlestep -d plugin,nochain -D execlog.txt ... When examining the instruction trace in execlog, I've noticed that the disassembly for pmpcfg0 is erroneous, for example: 0, 0x5456, 0x3a002573, "csrrs a0,pmpcfg3,zero" the CSR encoded in the instruction above is 0x3a0, which is pmpcfg0 (which also matches the code I'm examining). For the Uboot+OpenSBI code I'm examining, pmpcfg0/3 is the only one that appears to have a problem. I also checked QEMU9 and it behaves as described above as well. I'm willing to provide a fix if I can get some advice/pointers on how this disassembly statement is generated...I did take a quick look but it didn't appear obvious how... Thanks, eric
[PATCH v2 1/3] ACPI: bios-tables-test.c step 2 (allowed-diff entries)
Following the guidelines in tests/qtest/bios-tables-test.c, set up bios-tables-test-allowed-diff.h to ignore the imminent changes to the APIC tables, per step 2. Signed-off-by: Eric DeVolder --- tests/qtest/bios-tables-test-allowed-diff.h | 14 ++ 1 file changed, 14 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..66ae44e6b9 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,15 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/microvm/APIC", +"tests/data/acpi/microvm/APIC.ioapic2", +"tests/data/acpi/microvm/APIC.pcie", +"tests/data/acpi/pc/APIC", +"tests/data/acpi/pc/APIC.acpihmat", +"tests/data/acpi/pc/APIC.cphp", +"tests/data/acpi/pc/APIC.dimmpxm", +"tests/data/acpi/q35/APIC", +"tests/data/acpi/q35/APIC.acpihmat", +"tests/data/acpi/q35/APIC.acpihmat-noinitiator", +"tests/data/acpi/q35/APIC.core-count2", +"tests/data/acpi/q35/APIC.cphp", +"tests/data/acpi/q35/APIC.dimmpxm", +"tests/data/acpi/q35/APIC.xapic", -- 2.31.1
[PATCH v2 2/3] ACPI: i386: bump to MADT to revision 3
Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. Set .revision to 3 to match reality. Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devolder@ora cle.com/T/#t Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/i386/acpi-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..8a0932fe84 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -102,7 +102,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
[PATCH v2 3/3] ACPI: bios-tables-test.c step 5 (update expected table binaries)
Following the guidelines in tests/qtest/bios-tables-test.c, this is step 5 and 6. An examination of all the files impacted (as listed in bios-tables-test-allowe-diff.h) shows only the MADT/APIC tables bumping revision from 1 to 3, and a corresponding change to the checksum. The below diff is typical: --- /tmp/asl-1F9641.dsl2023-05-16 15:18:31.292579156 -0400 +++ /tmp/asl-GVD741.dsl2023-05-16 15:18:31.291579149 -0400 @@ -1,32 +1,32 @@ /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20230331 (64-bit version) * Copyright (c) 2000 - 2023 Intel Corporation * - * Disassembly of tests/data/acpi/pc/APIC, Tue May 16 15:18:31 2023 + * Disassembly of /tmp/aml-R4D741, Tue May 16 15:18:31 2023 * * ACPI Data Table [APIC] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex) */ [000h 004h] Signature : "APIC"[Multiple APIC Description Table (MADT)] [004h 0004 004h]Table Length : 0078 -[008h 0008 001h]Revision : 01 -[009h 0009 001h]Checksum : 8A +[008h 0008 001h]Revision : 03 +[009h 0009 001h]Checksum : 88 [00Ah 0010 006h] Oem ID : "BOCHS " [010h 0016 008h]Oem Table ID : "BXPC" [018h 0024 004h]Oem Revision : 0001 [01Ch 0028 004h] Asl Compiler ID : "BXPC" [020h 0032 004h] Asl Compiler Revision : 0001 [024h 0036 004h] Local Apic Address : FEE0 [028h 0040 004h] Flags (decoded below) : 0001 PC-AT Compatibility : 1 [02Ch 0044 001h] Subtable Type : 00 [Processor Local APIC] [02Dh 0045 001h] Length : 08 [02Eh 0046 001h]Processor ID : 00 [02Fh 0047 001h] Local Apic ID : 00 [030h 0048 004h] Flags (decoded below) : 0001 Processor Enabled : 1 @@ -81,24 +81,24 @@ [06Bh 0107 001h] Source : 0B [06Ch 0108 004h] Interrupt : 000B [070h 0112 002h] Flags (decoded below) : 000D Polarity : 1 Trigger Mode : 3 [072h 0114 001h] Subtable Type : 04 [Local APIC NMI] [073h 0115 001h] Length : 06 [074h 0116 001h]Processor ID : FF [075h 0117 002h] Flags (decoded below) : Polarity : 0 Trigger Mode : 0 [077h 0119 001h]Interrupt Input LINT : 01 Raw Table Data: Length 120 (0x78) -: 41 50 49 43 78 00 00 00 01 8A 42 4F 43 48 53 20 // APICx.BOCHS +: 41 50 49 43 78 00 00 00 03 88 42 4F 43 48 53 20 // APICx.BOCHS 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPCBXPC 0020: 01 00 00 00 00 00 E0 FE 01 00 00 00 00 08 00 00 // 0030: 01 00 00 00 01 0C 00 00 00 00 C0 FE 00 00 00 00 // 0040: 02 0A 00 00 02 00 00 00 00 00 02 0A 00 05 05 00 // 0050: 00 00 0D 00 02 0A 00 09 09 00 00 00 0D 00 02 0A // 0060: 00 0A 0A 00 00 00 0D 00 02 0A 00 0B 0B 00 00 00 // 0070: 0D 00 04 06 FF 00 00 01 // Signed-off-by: Eric DeVolder --- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes tests/qtest/bios-tables-test-allowed-diff.h | 14 -- 15 files changed, 14 deletions(-) diff --git a/tests/data/acpi/microvm/APIC b/tests/data/acpi/microvm/APIC index 68dbd44a7e35a356083f086df60f70e424c4249f..672764e711d80402890902ba9ded10915770e84c 100644 GIT binary patch delta 16 XcmZ>B<8ln}barE4U|=qq$Ylcn95e$) delta 16 XcmZ>B<8ln}barE4U|=kn$Ylcn95Mq&
[PATCH v2 0/3] ACPI: i386: bump MADT to revision 3
The following Linux kernel change broke CPU hotplug for MADT revision less than 5. e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Discussion on this topic can be located here: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t which resulted in the following fixes in Linux 6.3-rc5: a74fabfbd1b7: ("x86/ACPI/boot: Use FADT version to check support for online capable") fed8d8773b8e: ("x86/acpi/boot: Correct acpi_is_processor_usable() check") However, as part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it generates revision 3. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- version 45, is indeed accurate! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. So the QEMU i386 MADT revision can safely be moved to 3. So, set the MADT revision to 3. Regards, Eric --- v2: 17may2023 - Fix problems with the binary tables for the bios-tables-test.c and make check. v1: 15may2023 - initial --- Eric DeVolder (3): ACPI: bios-tables-test.c step 2 (allowed-diff entries) ACPI: i386: bump to MADT to revision 3 ACPI: bios-tables-test.c step 5 (update expected table binaries) hw/i386/acpi-common.c | 2 +- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes 15 files changed, 1 insertion(+), 1 deletion(-) -- 2.31.1
Re: [PATCH 2/3] ACPI: i386: bump to MADT to revision 3
On 5/16/23 07:51, Ani Sinha wrote: On Tue, May 16, 2023 at 6:01 PM Igor Mammedov wrote: On Mon, 15 May 2023 16:33:10 -0400 Eric DeVolder wrote: Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. Set .revision to 3 to match reality. Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devolder@ora cle.com/T/#t Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..8a0932fe84 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -102,7 +102,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); make check fails for me at this point (my guess is that not all APIC tables are whitelisted) I think the patchset needs to be rebased and the blobs regenerated. So I've been trying to overcome this today and not having much luck. When I run "make check V=2", I see at the end: Summary of Failures: 45/786 qemu:qtest+qtest-i386 / qtest-i386/bios-tables-test 68/786 qemu:qtest+qtest-x86_64 / qtest-x86_64/bios-tables-test If I go look at 45/786, for example, I see: Looking for expected file 'tests/data/acpi/pc/FACP' Using expected file 'tests/data/acpi/pc/FACP' Looking for expected file 'tests/data/acpi/pc/APIC' Using expected file 'tests/data/acpi/pc/APIC' Looking for expected file 'tests/data/acpi/pc/HPET' Using expected file 'tests/data/acpi/pc/HPET' Looking for expected file 'tests/data/acpi/pc/WAET' Using expected file 'tests/data/acpi/pc/WAET' Looking for expected file 'tests/data/acpi/pc/FACS' Using expected file 'tests/data/acpi/pc/FACS' Looking for expected file 'tests/data/acpi/pc/DSDT' Using expected file 'tests/data/acpi/pc/DSDT' acpi-test: Warning! APIC binary file mismatch. Actual [aml:/tmp/aml-R4D741], Expected [aml:tests/data/acpi/pc/APIC]. See source file tests/qtest/bios-tables-test.c for instructions on how to update expected files. acpi-test: Warning! APIC mismatch. Actual [asl:/tmp/asl-GVD741.dsl, aml:/tmp/aml-R4D741], Expected [asl:/tmp/asl-1F9641.dsl, aml:tests/data/acpi/pc/APIC]. --- /tmp/asl-1F9641.dsl 2023-05-16 15:18:31.292579156 -0400 +++ /tmp/asl-GVD741.dsl 2023-05-16 15:18:31.291579149 -0400 @@ -1,32 +1,32 @@ /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20230331 (64-bit version) * Copyright (c) 2000 - 2023 Intel Corporation * - * Disassembly of tests/data/acpi/pc/APIC, Tue May 16 15:18:31 2023 + * Disassembly of /tmp/aml-R4D741, Tue May 16 15:18:31 2023 * * ACPI Data Table [APIC] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex) */ [000h 004h] Signature : "APIC"[Multiple APIC Description Table (MADT)] [004h 0004 004h]Table Length : 0078 -[008h 0008 001h]Revision : 01 -[009h 0009 001h]Checksum : 8A +[008h 0008 001h]Revision : 03 +[009h 0009 001h]Checksum : 88 [00Ah 0010 006h] Oem ID : "BOCHS " [010h 0016 008h]Oem Table ID : "BXPC" [018h 0024 004h]Oem Revision : 0001 [01Ch 0028 004h] Asl Compiler ID : "BXPC" [020h 0032 004h] Asl Compiler Revision : 0001 [...] And the q35 looks very very similar. It suggests that I need to list tests/data/acpi/pc/APIC, which I have done in bios-tables-test-allowed-diff.h: /* List of comma-separated changed AML files to ignore */ "tests/data/acpi/pc/APIC", "tests/data/acpi/q35/APIC", "tests/data/acpi/microvm/APIC", "tests/data/acpi/virt/APIC", But as I looked closer at the files that changed in the last step of the previous post, there are a bunch of them: tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/a
[PATCH 3/3] ACPI: bios-tables-test.c step 5 (update expected table binaries)
Following the guidelines in tests/qtest/bios-tables-test.c, this is step 5 and 6. The MADT/APIC table diffs show (for pc, q35 and microvm) bumping revision from 1 to 3 (and checksum changing accordingly): Using expected file 'tests/data/acpi/pc/DSDT' acpi-test: Warning! APIC binary file mismatch. Actual [aml:/tmp/aml-9UKC51], Expected [aml:tests/data/acpi/pc/APIC]. See source file tests/qtest/bios-tables-test.c for instructions on how to update expected files. acpi-test: Warning! APIC mismatch. Actual [asl:/tmp/asl-CFKC51.dsl, aml:/tmp/aml-9UKC51], Expected [asl:/tmp/asl-TMFC51.dsl, aml:tests/data/acpi/pc/APIC]. --- /tmp/asl-TMFC51.dsl2023-05-15 14:15:26.599183824 -0400 +++ /tmp/asl-CFKC51.dsl2023-05-15 14:15:26.598183818 -0400 @@ -1,32 +1,32 @@ /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20230331 (64-bit version) * Copyright (c) 2000 - 2023 Intel Corporation * - * Disassembly of tests/data/acpi/pc/APIC, Mon May 15 14:15:26 2023 + * Disassembly of /tmp/aml-9UKC51, Mon May 15 14:15:26 2023 * * ACPI Data Table [APIC] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex) */ [000h 004h] Signature : "APIC"[Multiple APIC Description Table (MADT)] [004h 0004 004h]Table Length : 0078 -[008h 0008 001h]Revision : 01 -[009h 0009 001h]Checksum : 8A +[008h 0008 001h]Revision : 03 +[009h 0009 001h]Checksum : 88 [00Ah 0010 006h] Oem ID : "BOCHS " [010h 0016 008h]Oem Table ID : "BXPC" [018h 0024 004h]Oem Revision : 0001 [01Ch 0028 004h] Asl Compiler ID : "BXPC" [020h 0032 004h] Asl Compiler Revision : 0001 [024h 0036 004h] Local Apic Address : FEE0 [028h 0040 004h] Flags (decoded below) : 0001 PC-AT Compatibility : 1 [02Ch 0044 001h] Subtable Type : 00 [Processor Local APIC] [02Dh 0045 001h] Length : 08 [02Eh 0046 001h]Processor ID : 00 [02Fh 0047 001h] Local Apic ID : 00 [030h 0048 004h] Flags (decoded below) : 0001 Processor Enabled : 1 @@ -81,24 +81,24 @@ [06Bh 0107 001h] Source : 0B [06Ch 0108 004h] Interrupt : 000B [070h 0112 002h] Flags (decoded below) : 000D Polarity : 1 Trigger Mode : 3 [072h 0114 001h] Subtable Type : 04 [Local APIC NMI] [073h 0115 001h] Length : 06 [074h 0116 001h]Processor ID : FF [075h 0117 002h] Flags (decoded below) : Polarity : 0 Trigger Mode : 0 [077h 0119 001h]Interrupt Input LINT : 01 Raw Table Data: Length 120 (0x78) -: 41 50 49 43 78 00 00 00 01 8A 42 4F 43 48 53 20 // APICx.BOCHS +: 41 50 49 43 78 00 00 00 03 88 42 4F 43 48 53 20 // APICx.BOCHS 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPCBXPC 0020: 01 00 00 00 00 00 E0 FE 01 00 00 00 00 08 00 00 // 0030: 01 00 00 00 01 0C 00 00 00 00 C0 FE 00 00 00 00 // 0040: 02 0A 00 00 02 00 00 00 00 00 02 0A 00 05 05 00 // 0050: 00 00 0D 00 02 0A 00 09 09 00 00 00 0D 00 02 0A // 0060: 00 0A 0A 00 00 00 0D 00 02 0A 00 0B 0B 00 00 00 // 0070: 0D 00 04 06 FF 00 00 01 // Signed-off-by: Eric DeVolder --- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes tests/qtest/bios-tables-test-allowed-diff.h | 4 15 files changed, 4 deletions(
[PATCH 0/3] ACPI: i386: bump MADT to revision 3
The following Linux kernel change broke CPU hotplug for MADT revision less than 5. e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Discussion on this topic can be located here: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t which resulted in the following fixes in Linux 6.3-rc5: a74fabfbd1b7: ("x86/ACPI/boot: Use FADT version to check support for online capable") fed8d8773b8e: ("x86/acpi/boot: Correct acpi_is_processor_usable() check") However, as part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it generates revision 3. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- version 45, is indeed accurate! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. So the QEMU i386 MADT revision can safely be moved to 3. So, set the MADT revision to 3. Regards, Eric --- Eric DeVolder (3): ACPI: bios-tables-test.c step 2 (allowed-diff entries) ACPI: i386: bump to MADT to revision 3 ACPI: bios-tables-test.c step 5 (update expected table binaries) hw/i386/acpi-common.c | 2 +- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes 15 files changed, 1 insertion(+), 1 deletion(-) -- 2.31.1
[PATCH 1/3] ACPI: bios-tables-test.c step 2 (allowed-diff entries)
Following the guidelines in tests/qtest/bios-tables-test.c, set up bios-tables-test-allowed-diff.h to exclude the imminent changes to the APIC tables, per step 2. Signed-off-by: Eric DeVolder --- tests/qtest/bios-tables-test-allowed-diff.h | 4 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..1e5e354ecf 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,5 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/APIC", +"tests/data/acpi/q35/APIC", +"tests/data/acpi/microvm/APIC", +"tests/data/acpi/virt/APIC", -- 2.31.1
[PATCH 2/3] ACPI: i386: bump to MADT to revision 3
Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. Set .revision to 3 to match reality. Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devolder@ora cle.com/T/#t Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..8a0932fe84 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -102,7 +102,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
Re: [PATCH v3 0/3] ACPI: i386: bump MADT to revision 5
On 5/10/23 10:45, Igor Mammedov wrote: On Wed, 10 May 2023 10:08:50 -0500 Eric DeVolder wrote: On 5/10/23 03:14, Igor Mammedov wrote: On Fri, 5 May 2023 16:53:22 -0500 Eric DeVolder wrote: Thoughts? I still don't think we need to bump x86 to rev 5 in QEMU. Linux v6.3 has the fix merged (so crisis averted 8). The investigation allowed me to opportunistically provide this patch. I think this should receive serious consideration for merging, more so because generating MADT .revision 3 and reporting .revision 1 seems wrong to me. It's a way much simpler to bump revision to 3 without introducing OnlineCapable handling. So if you post rev3 patch, I'll gladly ack it. (+include kernel commit ids of kernel side fix, so if someone stumbles upon it, one can easily find what to backport) OK, I'll do that. It'll be next week as I'm on a short week this week. This patch seems really straight forward, and low risk, now. eric On 4/21/23 16:48, Eric DeVolder wrote: The following Linux kernel change broke CPU hotplug for MADT revision less than 5. e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Discussion on this topic can be located here: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t have your kernel fix landed up upstream? Yes, merged and available in v6.3. which resulted in the following fixes Linux in 6.3-rc5: a74fabfbd1b7: ("x86/ACPI/boot: Use FADT version to check support for online capable") fed8d8773b8e: ("x86/acpi/boot: Correct acpi_is_processor_usable() check") However, as part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it generates revision 3. Aarch64 generates and reports revision 4. ACPI 6.3 bumps MADT revision to 5 as it introduces an Online Capable flag that the above Linux patch utilizes to denote hot pluggable CPUs. So in order to bump MADT to the current revision of 5, need to validate that all MADT table changes between 1 and 5 are present in QEMU. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- version 45, is indeed accurate! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. A simple search of x2apic within QEMU source and hw/i386/acpi-common.c specifically reveals this. So the QEMU i386 MADT revision can safely be moved to 3. For the MADT revision change 3 -> 4, the spec adds support for the ARM GIC structures. QEMU ARM does in fact generate and report revision 4. As these will not be used by i386 QEMU, so then the QEMU i386 MADT revision can safely be moved to 4 as well. Now for the MADT revision change 4 -> 5, the spec adds the Online Capable flag to the Local APIC structure, and the ARM GICC SPE Overflow Interrupt field. All ARM stuff is irrelevant in x86 patch sure For i386, the ARM SPE is not applicable. For the i386 Local APIC flag Online Capable, the spec has certain rules about this value. And in particuar setting this value now explicitly indicates a hotpluggable CPU. So this patch makes the needed chan
Re: [PATCH v3 0/3] ACPI: i386: bump MADT to revision 5
On 5/10/23 03:14, Igor Mammedov wrote: On Fri, 5 May 2023 16:53:22 -0500 Eric DeVolder wrote: Thoughts? I still don't think we need to bump x86 to rev 5 in QEMU. Linux v6.3 has the fix merged (so crisis averted 8). The investigation allowed me to opportunistically provide this patch. I think this should receive serious consideration for merging, more so because generating MADT .revision 3 and reporting .revision 1 seems wrong to me. This patch seems really straight forward, and low risk, now. eric On 4/21/23 16:48, Eric DeVolder wrote: The following Linux kernel change broke CPU hotplug for MADT revision less than 5. e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Discussion on this topic can be located here: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t have your kernel fix landed up upstream? Yes, merged and available in v6.3. which resulted in the following fixes Linux in 6.3-rc5: a74fabfbd1b7: ("x86/ACPI/boot: Use FADT version to check support for online capable") fed8d8773b8e: ("x86/acpi/boot: Correct acpi_is_processor_usable() check") However, as part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it generates revision 3. Aarch64 generates and reports revision 4. ACPI 6.3 bumps MADT revision to 5 as it introduces an Online Capable flag that the above Linux patch utilizes to denote hot pluggable CPUs. So in order to bump MADT to the current revision of 5, need to validate that all MADT table changes between 1 and 5 are present in QEMU. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- version 45, is indeed accurate! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. A simple search of x2apic within QEMU source and hw/i386/acpi-common.c specifically reveals this. So the QEMU i386 MADT revision can safely be moved to 3. For the MADT revision change 3 -> 4, the spec adds support for the ARM GIC structures. QEMU ARM does in fact generate and report revision 4. As these will not be used by i386 QEMU, so then the QEMU i386 MADT revision can safely be moved to 4 as well. Now for the MADT revision change 4 -> 5, the spec adds the Online Capable flag to the Local APIC structure, and the ARM GICC SPE Overflow Interrupt field. All ARM stuff is irrelevant in x86 patch sure For i386, the ARM SPE is not applicable. For the i386 Local APIC flag Online Capable, the spec has certain rules about this value. And in particuar setting this value now explicitly indicates a hotpluggable CPU. So this patch makes the needed changes to move i386 MADT to revision 5. Without these changes, the information below shows "how" CPU hotplug breaks with the current upstream Linux kernel 6.3. For example, a Linux guest started with: what's the status wrt current upstream kernel? qemu cpu hotplug works with upstream kernel ( >= v6.3) but only because the kernel fix allows the legacy fallback assumption that the non Enabled cpus specified in MADT are online capable. with this patch
Re: [PATCH v3 0/3] ACPI: i386: bump MADT to revision 5
Thoughts? eric On 4/21/23 16:48, Eric DeVolder wrote: The following Linux kernel change broke CPU hotplug for MADT revision less than 5. e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Discussion on this topic can be located here: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t which resulted in the following fixes Linux in 6.3-rc5: a74fabfbd1b7: ("x86/ACPI/boot: Use FADT version to check support for online capable") fed8d8773b8e: ("x86/acpi/boot: Correct acpi_is_processor_usable() check") However, as part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it generates revision 3. Aarch64 generates and reports revision 4. ACPI 6.3 bumps MADT revision to 5 as it introduces an Online Capable flag that the above Linux patch utilizes to denote hot pluggable CPUs. So in order to bump MADT to the current revision of 5, need to validate that all MADT table changes between 1 and 5 are present in QEMU. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- version 45, is indeed accurate! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. A simple search of x2apic within QEMU source and hw/i386/acpi-common.c specifically reveals this. So the QEMU i386 MADT revision can safely be moved to 3. For the MADT revision change 3 -> 4, the spec adds support for the ARM GIC structures. QEMU ARM does in fact generate and report revision 4. As these will not be used by i386 QEMU, so then the QEMU i386 MADT revision can safely be moved to 4 as well. Now for the MADT revision change 4 -> 5, the spec adds the Online Capable flag to the Local APIC structure, and the ARM GICC SPE Overflow Interrupt field. For i386, the ARM SPE is not applicable. For the i386 Local APIC flag Online Capable, the spec has certain rules about this value. And in particuar setting this value now explicitly indicates a hotpluggable CPU. So this patch makes the needed changes to move i386 MADT to revision 5. Without these changes, the information below shows "how" CPU hotplug breaks with the current upstream Linux kernel 6.3. For example, a Linux guest started with: qemu-system-x86_64 -smp 30,maxcpus=32 ... and then attempting to hotplug a CPU: (QEMU) device_add id=cpu30 driver=host-x86_64-cpu socket-id=0 core-id=30 thread-id=0 fails with the following: APIC: NR_CPUS/possible_cpus limit of 30 reached. Processor 30/0x. ACPI: Unable to map lapic to logical cpu number acpi LNXCPU:1e: Enumeration failure # dmesg | grep smpboot smpboot: Allowing 30 CPUs, 0 hotplug CPUs smpboot: CPU0: Intel(R) Xeon(R) CPU D-1533 @ 2.10GHz (family: 0x) smpboot: Max logical packages: 1 smpboot: Total of 30 processors activated (125708.76 BogoMIPS) # iasl -d /sys/firmware/tables/acpi/APIC [000h 4]Signature : "APIC"[Multiple APIC Descript [004h 0004 4] Table Length : 0170 [008h 0008 1] Revision : 01 <= [009h 0009 1] Ch
[PATCH v3 0/3] ACPI: i386: bump MADT to revision 5
form microcode: firmware: requesting intel-ucode/06-56-03 # cat /sys/devices/system/cpu/online 0-8 (QEMU) device_del id=cpu8 Broke affinity for irq 24 CPU 8 is now offline # cat /sys/devices/system/cpu/online 0-7 RHEL 6.9 kernel 2.6.32-696.el6.x86_64 build Feb 21 2017 Both of the above 'legacy' operating systems behaved as expected. Regards, Eric --- v3: 21apr2023 - Dropped ARM patch as there is no compelling need to move to MADT revision 5, per Michael Tsirkin. - Recoded the flags to be simpler, per Michael, Ani Sinha and Miguel Luis. - Regenerated the binary tables, as per bios-tables-test.c instructions. v2: 18apr2023 https://lists.gnu.org/archive/html/qemu-devel/2023-04/msg02576.html - Code formatting changes per Igor Mammedov - Included the steps in bios-tables-test. v1: 28mar2023 https://lists.gnu.org/archive/html/qemu-devel/2023-03/msg06705.html - Initial series for ARM and i386 MADT revision bump to 5. Eric DeVolder (3): ACPI: bios-tables-test.c step 2 (allowed-diff entries) hw/acpi: i386: bump MADT to revision 5 ACPI: bios-tables-test.c step 5 (updated expected table binaries) hw/i386/acpi-common.c | 4 ++-- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes 15 files changed, 2 insertions(+), 2 deletions(-) -- 2.31.1
[PATCH v3 1/3] ACPI: bios-tables-test.c step 2 (allowed-diff entries)
Following the guidelines in tests/qtest/bios-tables-test.c, this change sets-up bios-tables-test-allowed-diff.h to exclude the imminent changes to the APIC tables, per step 2. Signed-off-by: Eric DeVolder --- tests/qtest/bios-tables-test-allowed-diff.h | 4 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..1e5e354ecf 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,5 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/APIC", +"tests/data/acpi/q35/APIC", +"tests/data/acpi/microvm/APIC", +"tests/data/acpi/virt/APIC", -- 2.31.1
[PATCH v3 2/3] ACPI: i386: bump MADT to revision 5
Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devolder@ora cle.com/T/#t Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..5a5e73c399 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -39,7 +39,7 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; + 1 /* Enabled */ : 2 /* Online Capable */; /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +102,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
[PATCH v3 3/3] ACPI: bios-tables-test.c step 5 (updated expected table binaries)
Subtable Type : 02 [Interrupt Source Override] [069h 0105 001h] Length : 0A [06Ah 0106 001h] Bus : 00 [06Bh 0107 001h] Source : 00 [06Ch 0108 004h] Interrupt : 0002 [070h 0112 002h] Flags (decoded below) : Polarity : 0 Trigger Mode : 0 @@ -121,26 +121,26 @@ [093h 0147 001h] Source : 0B [094h 0148 004h] Interrupt : 000B [098h 0152 002h] Flags (decoded below) : 000D Polarity : 1 Trigger Mode : 3 [09Ah 0154 001h] Subtable Type : 04 [Local APIC NMI] [09Bh 0155 001h] Length : 06 [09Ch 0156 001h]Processor ID : FF [09Dh 0157 002h] Flags (decoded below) : Polarity : 0 Trigger Mode : 0 [09Fh 0159 001h]Interrupt Input LINT : 01 Raw Table Data: Length 160 (0xA0) -: 41 50 49 43 A0 00 00 00 01 18 42 4F 43 48 53 20 // APIC..BOCHS +: 41 50 49 43 A0 00 00 00 05 0C 42 4F 43 48 53 20 // APIC..BOCHS 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPCBXPC 0020: 01 00 00 00 00 00 E0 FE 01 00 00 00 00 08 00 00 // 0030: 01 00 00 00 00 08 01 01 01 00 00 00 00 08 02 02 // -0040: 00 00 00 00 00 08 03 04 00 00 00 00 00 08 04 05 // -0050: 00 00 00 00 00 08 05 06 00 00 00 00 01 0C 00 00 // +0040: 02 00 00 00 00 08 03 04 02 00 00 00 00 08 04 05 // +0050: 02 00 00 00 00 08 05 06 02 00 00 00 01 0C 00 00 // 0060: 00 00 C0 FE 00 00 00 00 02 0A 00 00 02 00 00 00 // 0070: 00 00 02 0A 00 05 05 00 00 00 0D 00 02 0A 00 09 // 0080: 09 00 00 00 0D 00 02 0A 00 0A 0A 00 00 00 0D 00 // 0090: 02 0A 00 0B 0B 00 00 00 0D 00 04 06 FF 00 00 01 // .... ** Signed-off-by: Eric DeVolder --- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes tests/data/acpi/virt/APIC | Bin 172 -> 172 bytes tests/data/acpi/virt/APIC.acpihmatvirt| Bin 412 -> 412 bytes tests/data/acpi/virt/APIC.topology| Bin 732 -> 732 bytes tests/qtest/bios-tables-test-allowed-diff.h | 4 18 files changed, 4 deletions(-) diff --git a/tests/data/acpi/microvm/APIC b/tests/data/acpi/microvm/APIC index 68dbd44a7e35a356083f086df60f70e424c4249f..e1c72bd3e60e46acc2c8b3de14f5992946cd55a3 100644 GIT binary patch delta 16 XcmZ>B<8ln}barE4U|=nn$Ylcn95w?+ delta 16 XcmZ>B<8ln}barE4U|=kn$Ylcn95Mq& diff --git a/tests/data/acpi/microvm/APIC.ioapic2 b/tests/data/acpi/microvm/APIC.ioapic2 index 3063c52cd3e9bbed29c06031b375900f4a49b9e0..7c4f1b61d6c37f893d0d46be44a00e3f54a27a75 100644 GIT binary patch delta 16 XcmWFv;|bPi%*U|_AE$mIb59$o{5 delta 16 XcmWFv;|bPi%*U|?*X$mIb59$Ev1 diff --git a/tests/data/acpi/microvm/APIC.pcie b/tests/data/acpi/microvm/APIC.pcie index 4e8f6ed8d6a866429fc17aecdeafc3fb5ef65fa3..23956151765cae221853d92448a619d5576119b5 100644 GIT binary patch delta 16 Xcmd1H<8ln}bk1X7U|_A7$dv*BBEAFe delta 16 Xcmd1H<8ln}bk1X7U|_77$dv*BBDw?a diff --git a/tests/data/acpi/pc/APIC b/tests/data/acpi/pc/APIC index 208331db53b7dd5c6205cce0e95427636b86dd64..48bdab41959d7895b01491c6136d7403df284f98 100644 GIT binary patch delta 16 Xcmb=Z;BpM`bgp1vU|?;V$dv~GB#;Co delta 16 Xcmb=Z;BpM`bgp1vU|{T;$dv~GB#Z delta 18 ZcmbQhIDwJNF~HM#0s{jBqxVFvHUKF)1V;b> diff --git a/tests/data/acpi/q35/APIC b/tests/data/acpi/q35/APIC index 208331db53b7dd5c6205cce0e95427636b86dd64..48bdab41959d7895b01491c6136d7403df284f98 100644 GIT binary patch delta 16 Xcmb=Z;BpM`bgp1vU|?;V$dv~GB#;Co delta 16 Xcmb=Z;BpM`bgp1vU|{T;$dv~GB#Z del
Re: [PATCH v2 3/4] hw/acpi: i386: bump MADT to revision 5
On 4/20/23 03:05, Ani Sinha wrote: On Tue, Apr 18, 2023 at 10:22 PM Eric DeVolder wrote: Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..286c1c5c32 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ -uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; +bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true : false; how about "processor_enabled" instead of just "enabled" as the variable name. +/* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ +bool onlinecapable = enabled ? false : true; ugh, how about uint32 onlinecapable = enabled? 0x0 : 0x2 ? +uint32_t flags = onlinecapable ? 0x2 : 0x0 | /* Online Capable */ + enabled ? 0x1 : 0x0; /* Enabled */ then here, flags = onlinecapable | processor_enabled? 0x1 : 0x0; Colleague Miguel Luis pointed out that this is simpler and equivalent: uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? 1 /* Enabled */ : 2 /* Online Capable */; Is that acceptable? eric /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
Re: [PATCH v2 3/4] hw/acpi: i386: bump MADT to revision 5
On 4/19/23 09:56, Michael S. Tsirkin wrote: On Tue, Apr 18, 2023 at 12:52:18PM -0400, Eric DeVolder wrote: Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..286c1c5c32 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ -uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; +bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true : false; +/* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ +bool onlinecapable = enabled ? false : true; Pls write this as onlinecapable = !enabled or just open-code on the next line - does not look like this variable adds a lot of value. Will do! +uint32_t flags = onlinecapable ? 0x2 : 0x0 | /* Online Capable */ + enabled ? 0x1 : 0x0; /* Enabled */ /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
Re: [PATCH v2 2/4] hw/acpi: arm: bump MADT to revision 5
On 4/19/23 00:30, Michael S. Tsirkin wrote: On Tue, Apr 18, 2023 at 12:52:17PM -0400, Eric DeVolder wrote: Currently ARM QEMU generates, and reports, MADT revision 4. ACPI 6.3 introduces MADT revision 5. For MADT revision 5, the GICC structure adds an SPE Overflow Interrupt field. This new 2-byte field is created from the existing 3-byte Reserved field. The spec indicates if the SPE overflow interrupt is not supported, to zero the field. Signed-off-by: Eric DeVolder So why do we bother changing this? I'd rather defer until we actually intend to fill this field. Perfectly reasonable to me. I'll drop the ARM change going forward. eric --- hw/arm/virt-acpi-build.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 4156111d49..23268dd981 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -705,7 +705,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) int i; VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); const MemMapEntry *memmap = vms->memmap; -AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; acpi_table_begin(, table_data); @@ -763,7 +763,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) /* Processor Power Efficiency Class */ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ -build_append_int_noprefix(table_data, 0, 3); +build_append_int_noprefix(table_data, 0, 1); +/* SPE overflow Interrupt */ +build_append_int_noprefix(table_data, 0, 2); } if (vms->gic_version != VIRT_GIC_VERSION_2) { -- 2.31.1
Re: [PATCH 2/2] hw/acpi: i386: bump MADT to revision 5
On 4/12/23 02:58, Igor Mammedov wrote: On Tue, 11 Apr 2023 18:00:49 +0200 Igor Mammedov wrote: On Tue, 28 Mar 2023 11:59:26 -0400 Eric DeVolder wrote: Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). So spec mandates 3 possible states 00t - not present and not can't be added later ever 01t - present 10t - not present but might be added later and outlawed 11t combination 00t - doesn't make much sense (i.e. why put such entry in MADT in the 1st place) but looking at kernel commit aa06e20f1be, it looks like ACPI_MADT_ONLINE_CAPABLE was introduced to accommodate firmware/hw folks who would stuff MADT with LAPIC entries for all possible CPU models, and then patch it depending on actually used CPU model instead of dynamically creating LAPIC entries. (insane) on second thought, QEMU doesn't need rev 5 MADT with this flag complications. Also I see that kernel side fix ended up in checking ACPI spec version instead of dealing with MADT revisions mess. So for x86 lets bump revision to 3 or 4 to be in sync with what QEMU actually uses. If bumping to only 3 or 4, then there is no need for this patch series. Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..1e3a13a36c 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ -uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; +bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true /* Enabled */ : false; +/* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ +bool onlinecapable = enabled ? false : true; /* Online Capable */ +uint32_t flags = onlinecapable ? 0x2 : 0x0 | +enabled ? 0x1 : 0x0; align the last line with onlinecapable ' move /* Enabled */ and /* Online Capable */ comments right to magic values i.e. onlinecapable ? 0x2 : 0x0 | /* Online Capable */ ... Done. I've gone ahead and posted a v2 with these changes; keeping MADT.revision at 5. eric /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data);
[PATCH v2 1/4] ACPI: bios-tables-test.c step 2 (allowed-diff entries)
Following the guidelines in tests/qtest/bios-tables-test.c, this change sets-up bios-tables-test-allowed-diff.h to exclude the imminent changes to the APIC tables, per step 2. Signed-off-by: Eric DeVolder --- tests/qtest/bios-tables-test-allowed-diff.h | 4 1 file changed, 4 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..1e5e354ecf 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,5 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/APIC", +"tests/data/acpi/q35/APIC", +"tests/data/acpi/microvm/APIC", +"tests/data/acpi/virt/APIC", -- 2.31.1
[PATCH v2 0/4] hw/acpi: bump MADT to revision 5
r 8 APIC 0x8 kvm-clock: cpu 8, msr 2830ed00 Will online and init hotplugged CPU: 8 microcode: CPU8 sig=0x50663, pf=0x1, revision=0x71c platform microcode: firmware: requesting intel-ucode/06-56-03 # cat /sys/devices/system/cpu/online 0-8 (QEMU) device_del id=cpu8 Broke affinity for irq 24 CPU 8 is now offline # cat /sys/devices/system/cpu/online 0-7 RHEL 6.9 kernel 2.6.32-696.el6.x86_64 build Feb 21 2017 Both of the above 'legacy' operating systems behaved as expected. Regards, Eric --- v2: 18apr2023 - Code formatting changes per Igor Mammedov - Included the steps in bios-tables-test. v1: 28mar2023 https://lists.gnu.org/archive/html/qemu-devel/2023-03/msg06705.html - Initial series for ARM and i386 MADT revision bump to 5. Eric DeVolder (4): ACPI: bios-tables-test.c step 2 (allowed-diff entries) hw/acpi: arm: bump MADT to revision 5 hw/acpi: i386: bump MADT to revision 5 ACPI: bios-tables-test.c step 5 (updated expected table binaries) hw/arm/virt-acpi-build.c | 6 -- hw/i386/acpi-common.c | 13 ++--- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.xapic| Bin 2686 -> 2686 bytes tests/data/acpi/virt/APIC | Bin 172 -> 172 bytes tests/data/acpi/virt/APIC.acpihmatvirt| Bin 412 -> 412 bytes tests/data/acpi/virt/APIC.topology| Bin 732 -> 732 bytes 19 files changed, 14 insertions(+), 5 deletions(-) -- 2.31.1
[PATCH v2 3/4] hw/acpi: i386: bump MADT to revision 5
Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Link: https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..286c1c5c32 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ -uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; +bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true : false; +/* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ +bool onlinecapable = enabled ? false : true; +uint32_t flags = onlinecapable ? 0x2 : 0x0 | /* Online Capable */ + enabled ? 0x1 : 0x0; /* Enabled */ /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
[PATCH v2 4/4] ACPI: bios-tables-test.c step 5 (updated expected table binaries)
FE 01 00 00 00 00 08 00 00 // 0030: 01 00 00 00 01 0C 00 00 00 00 C0 FE 00 00 00 00 // 0040: 02 0A 00 00 02 00 00 00 00 00 02 0A 00 05 05 00 // 0050: 00 00 0D 00 02 0A 00 09 09 00 00 00 0D 00 02 0A // 0060: 00 0A 0A 00 00 00 0D 00 02 0A 00 0B 0B 00 00 00 // 0070: 0D 00 04 06 FF 00 00 01 // The diff below show ARM MADT revision change to 5. --- /tmp/asl-O2P921.dsl2023-04-18 10:41:56.560930849 -0400 +++ /tmp/asl-XJR921.dsl2023-04-18 10:41:56.558930836 -0400 @@ -1,32 +1,32 @@ /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20230331 (64-bit version) * Copyright (c) 2000 - 2023 Intel Corporation * - * Disassembly of tests/data/acpi/virt/APIC, Tue Apr 18 10:41:56 2023 + * Disassembly of /tmp/aml-ACR921, Tue Apr 18 10:41:56 2023 * * ACPI Data Table [APIC] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex) */ [000h 004h] Signature : "APIC"[Multiple APIC Description Table (MADT)] [004h 0004 004h]Table Length : 00AC -[008h 0008 001h]Revision : 04 -[009h 0009 001h]Checksum : 47 +[008h 0008 001h]Revision : 05 +[009h 0009 001h]Checksum : 46 [00Ah 0010 006h] Oem ID : "BOCHS " [010h 0016 008h]Oem Table ID : "BXPC" [018h 0024 004h]Oem Revision : 0001 [01Ch 0028 004h] Asl Compiler ID : "BXPC" [020h 0032 004h] Asl Compiler Revision : 0001 [024h 0036 004h] Local Apic Address : [028h 0040 004h] Flags (decoded below) : PC-AT Compatibility : 0 [02Ch 0044 001h] Subtable Type : 0C [Generic Interrupt Distributor] [02Dh 0045 001h] Length : 18 [02Eh 0046 002h]Reserved : [030h 0048 004h] Local GIC Hardware ID : [034h 0052 008h]Base Address : 0800 [03Ch 0060 004h] Interrupt Base : @@ -55,27 +55,27 @@ [091h 0145 001h]Reserved : 00 [092h 0146 002h] SPE Overflow Interrupt : [094h 0148 002h] TRBE Interrupt : 180D [094h 0148 001h] Subtable Type : 0D [Generic MSI Frame] [095h 0149 001h] Length : 18 [096h 0150 002h]Reserved : [098h 0152 004h]MSI Frame ID : [09Ch 0156 008h]Base Address : 0802 [0A4h 0164 004h] Flags (decoded below) : 0001 Select SPI : 1 [0A8h 0168 002h] SPI Count : 0040 [0AAh 0170 002h]SPI Base : 0050 Raw Table Data: Length 172 (0xAC) -: 41 50 49 43 AC 00 00 00 04 47 42 4F 43 48 53 20 // APIC.GBOCHS +: 41 50 49 43 AC 00 00 00 05 46 42 4F 43 48 53 20 // APIC.FBOCHS 0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPCBXPC 0020: 01 00 00 00 00 00 00 00 00 00 00 00 0C 18 00 00 // 0030: 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 // 0040: 02 00 00 00 0B 50 00 00 00 00 00 00 00 00 00 00 // .P.. 0050: 01 00 00 00 00 00 00 00 17 00 00 00 00 00 00 00 // 0060: 00 00 00 00 00 00 01 08 00 00 00 00 00 00 04 08 // 0070: 00 00 00 00 00 00 03 08 00 00 00 00 00 00 00 00 // 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // 0090: 00 00 00 00 0D 18 00 00 00 00 00 00 00 00 02 08 // .... 00A0: 00 00 00 00 01 00 00 00 40 00 50 00 // @.P. Signed-off-by: Eric DeVolder --- tests/data/acpi/microvm/APIC | Bin 70 -> 70 bytes tests/data/acpi/microvm/APIC.ioapic2 | Bin 82 -> 82 bytes tests/data/acpi/microvm/APIC.pcie | Bin 110 -> 110 bytes tests/data/acpi/pc/APIC | Bin 120 -> 120 bytes tests/data/acpi/pc/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/pc/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/pc/APIC.dimmpxm | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC | Bin 120 -> 120 bytes tests/data/acpi/q35/APIC.acpihmat | Bin 128 -> 128 bytes tests/data/acpi/q35/APIC.acpihmat-noinitiator | Bin 144 -> 144 bytes tests/data/acpi/q35/APIC.core-count2 | Bin 2478 -> 2478 bytes tests/data/acpi/q35/APIC.cphp | Bin 160 -> 160 bytes tests/data/acpi/q35/APIC.dimmpxm | Bin 144 -> 144 bytes
[PATCH v2 2/4] hw/acpi: arm: bump MADT to revision 5
Currently ARM QEMU generates, and reports, MADT revision 4. ACPI 6.3 introduces MADT revision 5. For MADT revision 5, the GICC structure adds an SPE Overflow Interrupt field. This new 2-byte field is created from the existing 3-byte Reserved field. The spec indicates if the SPE overflow interrupt is not supported, to zero the field. Signed-off-by: Eric DeVolder --- hw/arm/virt-acpi-build.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 4156111d49..23268dd981 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -705,7 +705,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) int i; VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); const MemMapEntry *memmap = vms->memmap; -AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; acpi_table_begin(, table_data); @@ -763,7 +763,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) /* Processor Power Efficiency Class */ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ -build_append_int_noprefix(table_data, 0, 3); +build_append_int_noprefix(table_data, 0, 1); +/* SPE overflow Interrupt */ +build_append_int_noprefix(table_data, 0, 2); } if (vms->gic_version != VIRT_GIC_VERSION_2) { -- 2.31.1
Re: [PATCH 0/2] hw/acpi: bump MADT to revision 5
I'm back from travel and catching up. More info below. eric On 3/31/23 11:25, Igor Mammedov wrote: On Wed, 29 Mar 2023 12:47:05 -0400 "Michael S. Tsirkin" wrote: On Wed, Mar 29, 2023 at 08:14:37AM -0500, Eric DeVolder wrote: On 3/29/23 00:19, Michael S. Tsirkin wrote: Hmm I don't think we can reasonably make such a change for 8.0. Seems too risky. Also, I feel we want to have an internal (with "x-" prefix") flag to revert to old behaviour, in case of breakage on some guests. and maybe we want to keep old revision for old machine types. Ok, what option name, for keeping old behavior, would you like? Don't much care. x-madt-rev? if it works fine (cold & hot-plug) with older linux/windows guests I'd rather avoid adding compat knob (we typically do that in ACPI tables only when change breaks something). (as old guest I'd define WinXP sp3 (/me wonders if we still care about dead EOLed OS) perhaps WS2008 would be a better minimum target these days and RHEL6 (or some older ACPI enabled kernel with hotplug support)) Thus far I've tested this patch series with the following guests. In both cases below, the guest started with -smp 8,maxcpus=16, and I simply attempted to hot plug and unplug cpu8, with: device_add id=cpu8 driver=host-x86_64-cpu socket-id=0 core-id=8 thread-id=0. 1) Windows Server 2008. In Windows, after logging-in, I close the first full-screen window and then "Server Manager" window pops up. I navigate to left hand pane and choose Diagnostics -> Device Manager -> Processors. I count them before and after. When hotplugging a cpu, you can see the new processor show up in the processor list. That is, it goes from 8 to 9. When hot unplugging the CPU, Windows refuses: The 'Intel(R) Xeon(R) CPU D-1533 @ 2.10GHz' device is not removable and cannot be ejected or unplugged. 2) RHEL 6.9 From dmesg: ACPI: APIC 7ffe32f0 000F0 (v05 BOCHS BXPC0001 BXPC 0001) SMP: Allowing 16 CPUs, 8 hotplug CPUs # cat /sys/devices/system/cpu/online 0-7 (QEMU) device_add ... CPU 8 got hotplugged Booting Node 0 Processor 8 APIC 0x8 kvm-clock: cpu 8, msr 2830ed00 Will online and init hotplugged CPU: 8 microcode: CPU8 sig=0x50663, pf=0x1, revision=0x71c platform microcode: firmware: requesting intel-ucode/06-56-03 # cat /sys/devices/system/cpu/online 0-8 (QEMU) device_del ... Broke affinity for irq 24 CPU 8 is now offline # cat /sys/devices/system/cpu/online 0-7 RHEL 6.9 kernel 2.6.32-696.el6.x86_64 build Feb 21 2017 So with these two older guest OS, it appears to still work. If there are others to be tested, let me know. On Tue, Mar 28, 2023 at 11:59:24AM -0400, Eric DeVolder wrote: The following Linux kernel change broke CPU hotplug for MADT revision less than 5. commit e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Presumably it's being fixed? Link to discussion? Patch fixing that in Linux? https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t Great! Maybe stick a Link: tag in the commit log. Sure, will include that with v2. So it's guest bug which is in process of being fixed. (i.e. QEMU technically correct as long as MADT revision < 5) Iiuc, if QEMU generates x2apic tables with .revision = 1, that is not correct (as x2APIC shows up in .revision=3). But if QEMU generates, apic, sapic, or x2apic tables with .revision = 5, that is correct (as all are valid options thru .revision 5). In this case I'd not touch x86 MADT at all (It should be upto downstream distros to fix guest kernel). Fwiw, this has been fixed and should show up in 6.3-rc6 this weekend. Probably the same applies to ARM variant i.e. we should bump rev only when current one gets in the way (aka we are pulling in new fields/definitions from new version) As part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it is at revision 3. (Arm QEMU reports revision 4, and that is valid/correct.) ACPI 6.3 bumps MADT revision to 5 as it introduces an Online Capable flag that the above Linux patch utilizes to denote hot pluggable CPUs. So in order to bump MADT to the current revision of 5, need to validate that all MADT table changes between 1 and 5 are present in QEMU. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Sect
Re: [PATCH 2/2] hw/acpi: i386: bump MADT to revision 5
On 3/29/23 08:16, Eric DeVolder wrote: On 3/29/23 00:03, Michael S. Tsirkin wrote: On Tue, Mar 28, 2023 at 11:59:26AM -0400, Eric DeVolder wrote: Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Signed-off-by: Eric DeVolder I am looking for ways to reduce risk of breakage with this. We don't currently have a reason to change it if cpu hotplug is off, do we? Maybe make it conditional on that. By "cpu hotplug off", do you mean, for example, no maxcpus= option? In other words, how should I detect "cpu hotplug off"? eric Actually, if, for example, one had -smp 30,maxcpus=32, then there would be two hotpluggable cpus reported, the last two with the Enabled=0 and Online Capable=1. If one had -smp 32 (ie "cpu hotplug off"), then all cpus would be reported as Enabled and no cpu would have its Online Capable flag set. Granted in both cases, MADT.revision would report 5, but it would still be accurate. eric --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..1e3a13a36c 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ - uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; + bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true /* Enabled */ : false; + /* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ + bool onlinecapable = enabled ? false : true; /* Online Capable */ + uint32_t flags = onlinecapable ? 0x2 : 0x0 | + enabled ? 0x1 : 0x0; /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); - AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, + AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
Re: [PATCH 2/2] hw/acpi: i386: bump MADT to revision 5
On 3/29/23 00:03, Michael S. Tsirkin wrote: On Tue, Mar 28, 2023 at 11:59:26AM -0400, Eric DeVolder wrote: Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Signed-off-by: Eric DeVolder I am looking for ways to reduce risk of breakage with this. We don't currently have a reason to change it if cpu hotplug is off, do we? Maybe make it conditional on that. By "cpu hotplug off", do you mean, for example, no maxcpus= option? In other words, how should I detect "cpu hotplug off"? eric --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..1e3a13a36c 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ -uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; +bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true /* Enabled */ : false; +/* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ +bool onlinecapable = enabled ? false : true; /* Online Capable */ +uint32_t flags = onlinecapable ? 0x2 : 0x0 | +enabled ? 0x1 : 0x0; /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
Re: [PATCH 0/2] hw/acpi: bump MADT to revision 5
On 3/29/23 00:19, Michael S. Tsirkin wrote: Hmm I don't think we can reasonably make such a change for 8.0. Seems too risky. Also, I feel we want to have an internal (with "x-" prefix") flag to revert to old behaviour, in case of breakage on some guests. and maybe we want to keep old revision for old machine types. Ok, what option name, for keeping old behavior, would you like? On Tue, Mar 28, 2023 at 11:59:24AM -0400, Eric DeVolder wrote: The following Linux kernel change broke CPU hotplug for MADT revision less than 5. commit e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") Presumably it's being fixed? Link to discussion? Patch fixing that in Linux? https://lore.kernel.org/linux-acpi/20230327191026.3454-1-eric.devol...@oracle.com/T/#t As part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it is at revision 3. (Arm QEMU reports revision 4, and that is valid/correct.) ACPI 6.3 bumps MADT revision to 5 as it introduces an Online Capable flag that the above Linux patch utilizes to denote hot pluggable CPUs. So in order to bump MADT to the current revision of 5, need to validate that all MADT table changes between 1 and 5 are present in QEMU. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- yep it says version 45! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. A simple search of x2apic within QEMU source and hw/i386/acpi-common.c specifically reveals this. But not unconditionally. I don't think that reporting revision 3 requires that generation of x2apic; one could still see apic, x2apic, or sapic in theory. I realize qemu doesn't do sapic... So the QEMU i386 MADT revision can safely be moved to 3. For the MADT revision change 3 -> 4, the spec adds support for the ARM GIC structures. QEMU ARM does in fact generate and report revision 4. As these will not be used by i386 QEMU, so then the QEMU i386 MADT revision can safely be moved to 4 as well. Now for the MADT revision change 4 -> 5, the spec adds the Online Capable flag to the Local APIC structure, and the ARM GICC SPE Overflow Interrupt field. For the ARM SPE, an existing 3-byte Reserved field is broken into a 1- byte Reserved field and a 2-byte SPE field. The spec says that is SPE Overflow is not supported, it should be zero. For the i386 Local APIC flag Online Capable, the spec has certain rules about this value. And in particuar setting this value now explicitly indicates a hotpluggable CPU. So this patch makes the needed changes to move both ARM and i386 MADT to revision 5. These are not complicated, thankfully. Without these changes, the information below shows "how" CPU hotplug breaks with the current upstream Linux kernel 6.3. For example, a Linux guest started with: qemu-system-x86_64 -smp 30,maxcpus=32 ... and then attempting to hotplug a CPU: (QEMU) device_add id=cpu30 driver=host-x86_64-cpu socket-id=0 core-id=30 thread-id=0 fails with the following: APIC: NR_CPUS/possible_cpus limit of 30 reached. Processor 30/0x. ACPI: Unable to map lapic to logical
Re: [PATCH 0/2] hw/acpi: bump MADT to revision 5
I forgot to include the updated ACPI tables. I will do that as part of v2. In the meantime, I appreciate any feedback... eric On 3/28/23 10:59, Eric DeVolder wrote: The following Linux kernel change broke CPU hotplug for MADT revision less than 5. commit e2869bd7af60 ("x86/acpi/boot: Do not register processors that cannot be onlined for x2APIC") As part of the investigation into resolving this breakage, I learned that i386 QEMU reports revision 1, while technically it is at revision 3. (Arm QEMU reports revision 4, and that is valid/correct.) ACPI 6.3 bumps MADT revision to 5 as it introduces an Online Capable flag that the above Linux patch utilizes to denote hot pluggable CPUs. So in order to bump MADT to the current revision of 5, need to validate that all MADT table changes between 1 and 5 are present in QEMU. Below is a table summarizing the changes to the MADT. This information gleamed from the ACPI specs on uefi.org. ACPIMADTWhat Version Version 1.0 MADT not present 2.0 1 Section 5.2.10.4 3.0 2 Section 5.2.11.4 5.2.11.13 Local SAPIC Structure added two new fields: ACPI Processor UID Value ACPI Processor UID String 5.2.10.14 Platform Interrupt Sources Structure: Reserved changed to Platform Interrupt Sources Flags 3.0b2 Section 5.2.11.4 Added a section describing guidelines for the ordering of processors in the MADT to support proper boot processor and multi-threaded logical processor operation. 4.0 3 Section 5.2.12 Adds Processor Local x2APIC structure type 9 Adds Local x2APIC NMI structure type 0xA 5.0 3 Section 5.2.12 6.0 3 Section 5.2.12 6.0a4 Section 5.2.12 Adds ARM GIC structure types 0xB-0xF 6.2a45 Section 5.2.12 <--- yep it says version 45! 6.2b5 Section 5.2.12 GIC ITS last Reserved offset changed to 16 from 20 (typo) 6.3 5 Section 5.2.12 Adds Local APIC Flags Online Capable! Adds GICC SPE Overflow Interrupt field 6.4 5 Section 5.2.12 Adds Multiprocessor Wakeup Structure type 0x10 (change notes says structure previously misplaced?) 6.5 5 Section 5.2.12 For the MADT revision change 1 -> 2, the spec has a change to the SAPIC structure. In general, QEMU does not generate/support SAPIC. So the QEMU i386 MADT revision can safely be moved to 2. For the MADT revision change 2 -> 3, the spec adds Local x2APIC structures. QEMU has long supported x2apic ACPI structures. A simple search of x2apic within QEMU source and hw/i386/acpi-common.c specifically reveals this. So the QEMU i386 MADT revision can safely be moved to 3. For the MADT revision change 3 -> 4, the spec adds support for the ARM GIC structures. QEMU ARM does in fact generate and report revision 4. As these will not be used by i386 QEMU, so then the QEMU i386 MADT revision can safely be moved to 4 as well. Now for the MADT revision change 4 -> 5, the spec adds the Online Capable flag to the Local APIC structure, and the ARM GICC SPE Overflow Interrupt field. For the ARM SPE, an existing 3-byte Reserved field is broken into a 1- byte Reserved field and a 2-byte SPE field. The spec says that is SPE Overflow is not supported, it should be zero. For the i386 Local APIC flag Online Capable, the spec has certain rules about this value. And in particuar setting this value now explicitly indicates a hotpluggable CPU. So this patch makes the needed changes to move both ARM and i386 MADT to revision 5. These are not complicated, thankfully. Without these changes, the information below shows "how" CPU hotplug breaks with the current upstream Linux kernel 6.3. For example, a Linux guest started with: qemu-system-x86_64 -smp 30,maxcpus=32 ... and then attempting to hotplug a CPU: (QEMU) device_add id=cpu30 driver=host-x86_64-cpu socket-id=0 core-id=30 thread-id=0 fails with the following: APIC: NR_CPUS/possible_cpus limit of 30 reached. Processor 30/0x. ACPI: Unable to map lapic to logical cpu number acpi LNXCPU:1e: Enumeration failure # dmesg | grep smpboot smpboot: Allowing 30 CPUs, 0 hotplug CPUs smpboot: CPU0: Intel(R) Xeon(R) CPU D-1533 @ 2.10GHz (family: 0x) smpboot: Max logical packages: 1 smpboot: Total of 30 processors activated (125708.76 BogoMIPS) # iasl -d /sys/firmware/tables/acpi/APIC [000h 4]Signature : "APIC"[Multiple APIC Descript [004h 0004 4] Table Length : 0170 [008h 0008 1] Revision : 01 <= [009h 0009 1] Checksum : 9C [00Ah 0010 6] Oem ID : "BO
[PATCH 1/2] hw/acpi: arm: bump MADT to revision 5
Currently ARM QEMU generates, and reports, MADT revision 4. ACPI 6.3 introduces MADT revision 5. For MADT revision 5, the GICC structure adds an SPE Overflow Interrupt field. This new 2-byte field is created from the existing 3-byte Reserved field. The spec indicates if the SPE overflow interrupt is not supported, to zero the field. Signed-off-by: Eric DeVolder --- hw/arm/virt-acpi-build.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 4156111d49..23268dd981 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -705,7 +705,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) int i; VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); const MemMapEntry *memmap = vms->memmap; -AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = vms->oem_id, .oem_table_id = vms->oem_table_id }; acpi_table_begin(, table_data); @@ -763,7 +763,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) /* Processor Power Efficiency Class */ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ -build_append_int_noprefix(table_data, 0, 3); +build_append_int_noprefix(table_data, 0, 1); +/* SPE overflow Interrupt */ +build_append_int_noprefix(table_data, 0, 2); } if (vms->gic_version != VIRT_GIC_VERSION_2) { -- 2.31.1
[PATCH 0/2] hw/acpi: bump MADT to revision 5
[020h 0032 4]Asl Compiler Revision : 0001 ... [114h 0276 1]Subtable Type : 00 [Processor Local APIC] [115h 0277 1] Length : 08 [116h 0278 1] Processor ID : 1D [117h 0279 1]Local Apic ID : 1D [118h 0280 4]Flags (decoded below) : 0001 Processor Enabled : 1 <= [11Ch 0284 1]Subtable Type : 00 [Processor Local APIC] [11Dh 0285 1] Length : 08 [11Eh 0286 1] Processor ID : 1E [11Fh 0287 1]Local Apic ID : 1E [120h 0288 4]Flags (decoded below) : Processor Enabled : 0 <= [124h 0292 1]Subtable Type : 00 [Processor Local APIC] [125h 0293 1] Length : 08 [126h 0294 1] Processor ID : 1F [127h 0295 1]Local Apic ID : 1F [128h 0296 4]Flags (decoded below) : Processor Enabled : 0 <= The (latest upstream) Linux kernel sees 30 Enabled processors, and does not consider processors 31 and 32 to be hotpluggable. With this patch series applied, by bumping MADT to revision 5, the latest upstream Linux kernel correctly identifies 30 CPUs plus 2 hotpluggable CPUS. CPU30 has been hot-added smpboot: Booting Node 0 Processor 30 APIC 0x1e Will online and init hotplugged CPU: 30 # dmesg | grep smpboot smpboot: Allowing 32 CPUs, 2 hotplug CPUs smpboot: CPU0: Intel(R) Xeon(R) CPU D-1533 @ 2.10GHz (family: 0x6, model: 0x56, stepping: 0x3) smpboot: Max logical packages: 2 smpboot: Total of 30 processors activated (125708.76 BogoMIPS) # iasl -d /sys/firmware/tables/acpi/APIC [000h 004h] Signature : "APIC"[Multiple APIC Descript [004h 0004 004h]Table Length : 0170 [008h 0008 001h]Revision : 05 <= [009h 0009 001h]Checksum : 94 [00Ah 0010 006h] Oem ID : "BOCHS " [010h 0016 008h]Oem Table ID : "BXPC" [018h 0024 004h]Oem Revision : 0001 [01Ch 0028 004h] Asl Compiler ID : "BXPC" [020h 0032 004h] Asl Compiler Revision : 0001 ... [114h 0276 001h] Subtable Type : 00 [Processor Local APIC] [115h 0277 001h] Length : 08 [116h 0278 001h]Processor ID : 1D [117h 0279 001h] Local Apic ID : 1D [118h 0280 004h] Flags (decoded below) : 0001 Processor Enabled : 1 <= Runtime Online Capable : 0 <= [11Ch 0284 001h] Subtable Type : 00 [Processor Local APIC] [11Dh 0285 001h] Length : 08 [11Eh 0286 001h]Processor ID : 1E [11Fh 0287 001h] Local Apic ID : 1E [120h 0288 004h] Flags (decoded below) : 0002 Processor Enabled : 0 <= Runtime Online Capable : 1 <= [124h 0292 001h] Subtable Type : 00 [Processor Local APIC] [125h 0293 001h] Length : 08 [126h 0294 001h]Processor ID : 1F [127h 0295 001h] Local Apic ID : 1F [128h 0296 004h] Flags (decoded below) : 0002 Processor Enabled : 0 <= Runtime Online Capable : 1 <= Regards, Eric Eric DeVolder (2): hw/acpi: arm: bump MADT to revision 5 hw/acpi: i386: bump MADT to revision 5 hw/arm/virt-acpi-build.c | 6 -- hw/i386/acpi-common.c| 13 ++--- 2 files changed, 14 insertions(+), 5 deletions(-) -- 2.31.1
[PATCH 2/2] hw/acpi: i386: bump MADT to revision 5
Currently i386 QEMU generates MADT revision 3, and reports MADT revision 1. ACPI 6.3 introduces MADT revision 5. For MADT revision 4, that introduces ARM GIC structures, which do not apply to i386. For MADT revision 5, the Local APIC flags introduces the Online Capable bitfield. Making MADT generate and report revision 5 will solve problems with CPU hotplug (the Online Capable flag indicates hotpluggable CPUs). Signed-off-by: Eric DeVolder --- hw/i386/acpi-common.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 52e5c1439a..1e3a13a36c 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -38,8 +38,15 @@ void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ -uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? - 1 /* Enabled */ : 0; +bool enabled = apic_ids->cpus[uid].cpu != NULL || force_enabled ? + true /* Enabled */ : false; +/* + * ACPI 6.3 5.2.12.2 Local APIC Flags: OnlineCapable must be 0 + * if Enabled is set. + */ +bool onlinecapable = enabled ? false : true; /* Online Capable */ +uint32_t flags = onlinecapable ? 0x2 : 0x0 | +enabled ? 0x1 : 0x0; /* ACPI spec says that LAPIC entry for non present * CPU may be omitted from MADT or it must be marked @@ -102,7 +109,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(x86ms); const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(adev); -AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = oem_id, +AcpiTable table = { .sig = "APIC", .rev = 5, .oem_id = oem_id, .oem_table_id = oem_table_id }; acpi_table_begin(, table_data); -- 2.31.1
Re: [PATCH v2] hw/acpi/erst.c: Fix memory handling issues
On 10/24/22 10:42, Christian A. Ehrhardt wrote: - Fix memset argument order: The second argument is the value, the length goes last. - Fix an integer overflow reported by Alexander Bulekov. Both issues allow the guest to overrun the host buffer allocated for the ERST memory device. Cc: Eric DeVolder Cc: qemu-sta...@nongnu.org Fixes: f7e26ffa590 ("ACPI ERST: support for ACPI ERST feature") Tested-by: Alexander Bulekov Signed-off-by: Christian A. Ehrhardt Reviewed-by: Eric DeVolder Thanks Christian! eric --- hw/acpi/erst.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index df856b2669..aefcc03ad6 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -635,7 +635,7 @@ static unsigned read_erst_record(ERSTDeviceState *s) if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { rc = STATUS_FAILED; } -if ((s->record_offset + record_length) > exchange_length) { +if (record_length > exchange_length - s->record_offset) { rc = STATUS_FAILED; } /* If all is ok, copy the record to the exchange buffer */ @@ -684,7 +684,7 @@ static unsigned write_erst_record(ERSTDeviceState *s) if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { return STATUS_FAILED; } -if ((s->record_offset + record_length) > exchange_length) { +if (record_length > exchange_length - s->record_offset) { return STATUS_FAILED; } @@ -716,7 +716,7 @@ static unsigned write_erst_record(ERSTDeviceState *s) if (nvram) { /* Write the record into the slot */ memcpy(nvram, exchange, record_length); -memset(nvram + record_length, exchange_length - record_length, 0xFF); +memset(nvram + record_length, 0xFF, exchange_length - record_length); /* If a new record, increment the record_count */ if (!record_found) { uint32_t record_count;
Re: [PATCH] hw/acpi/erst.c: Fix memset argument order
On 10/20/22 01:14, Markus Armbruster wrote: "Christian A. Ehrhardt" writes: Fix memset argument order: The second argument is the value, the length goes last. Impact of the bug? Cc: Eric DeVolder Cc: qemu-sta...@nongnu.org Fixes: f7e26ffa590 ("ACPI ERST: support for ACPI ERST feature") Signed-off-by: Christian A. Ehrhardt --- hw/acpi/erst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index df856b2669..26391f93ca 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -716,7 +716,7 @@ static unsigned write_erst_record(ERSTDeviceState *s) exchange_length = memory_region_size(>exchange_mr); This is the size of the exchange buffer. Aside: it's unsigned int, but memory_region_size() returns uint64_t. Unclean if it fits, bug if it doesn't. /* Validate record_offset */ if (s->record_offset > (exchange_length - UEFI_CPER_RECORD_MIN_SIZE)) { return STATUS_FAILED; } /* Obtain pointer to record in the exchange buffer */ exchange = memory_region_get_ram_ptr(>exchange_mr); exchange += s->record_offset; /* Validate CPER record_length */ memcpy((uint8_t *)_length, [UEFI_CPER_RECORD_LENGTH_OFFSET], sizeof(uint32_t)); Aside: record_length = *(uint32_t *)exchange[UEFI_CPER_RECORD_LENGTH_OFFSET] would do, since UEFI_CPER_RECORD_LENGTH_OFFSET is a multiple of 4. Igor requested I use memcpy() so that this would work on EB and EL hosts. record_length = le32_to_cpu(record_length); if (record_length < UEFI_CPER_RECORD_MIN_SIZE) { return STATUS_FAILED; } if ((s->record_offset + record_length) > exchange_length) { return STATUS_FAILED; } This ensures there are at least @record_length bytes of space left in the exchange buffer. Good. [...] if (nvram) { /* Write the record into the slot */ memcpy(nvram, exchange, record_length); This first copies @record_length bytes into the exchange buffer. -memset(nvram + record_length, exchange_length - record_length, 0xFF); +memset(nvram + record_length, 0xFF, exchange_length - record_length); The new code pads it to the full exchange buffer size. The old code writes 0xFF bytes. If 0xFF < exchange_length - record_length, the padding doesn't extend to the end of the buffer. Impact? The purpose of the memset() is to ensure the slot does not contain any remnants of a previous record. There is no functional requirement for this; other than it was intended to prevent the possibility of leaking data. If there were a previously deleted/overwritten record in that slot, then the tail of that record would remain. However, it still isn't visible upon the record read; it would only be visible by directly accessing the backing file/memory. If 0xFF > exchange_length - record_length, we write beyond the end of the buffer. Impact? There are two cases here, if the record is stored in any slot but the last, then it has the opportunity to corrupt the next adjacent slot/record. Given that the CPER format places the magic 'CPER' as the first 4 bytes, then I believe that upon next read of this corrupted record, it will be rejected as it does not have a valid CPER header. If the record is the last in the backing storage, then it would attempt to write beyond the end. The backing store is memory mapped into the guest, so I believe that an attempt to write beyond the end will result in a segfault. Previously stated: "Well, this is a memory error, i.e. the potential impact is anything from silent data corruption to arbitrary code execution. Phillipe described this accurately as "Ouch". Yes, ouch. I had it correct until patch series v7 (of v15); not that that is helpful. However, I do not see a path to arbitrary code execution. The erroneous memset() will write out a constant value (exchange_length - record_length) for 0xFF bytes. In terms of current Linux real world impact, ERST is used as pstore backend and writes to pstore typically only happen on kernel panic, if configured. Furthermore, the systemd-pstore service attempts to keep the pstore empty, so that reduces the chances of pstore/ERST filling up and reaching that last slot that could cause a segfault. ERST can be written by MCE, I think; not sure how relevant that is to guests. eric /* If a new record, increment the record_count */ if (!record_found) { uint32_t record_count;
Re: [PATCH] hw/acpi/erst.c: Fix memset argument order
On 10/19/22 14:37, Philippe Mathieu-Daudé wrote: On 19/10/22 21:15, Christian A. Ehrhardt wrote: Fix memset argument order: The second argument is the value, the length goes last. Cc: Eric DeVolder Cc: qemu-sta...@nongnu.org Fixes: f7e26ffa590 ("ACPI ERST: support for ACPI ERST feature") Signed-off-by: Christian A. Ehrhardt --- hw/acpi/erst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index df856b2669..26391f93ca 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -716,7 +716,7 @@ static unsigned write_erst_record(ERSTDeviceState *s) if (nvram) { /* Write the record into the slot */ memcpy(nvram, exchange, record_length); - memset(nvram + record_length, exchange_length - record_length, 0xFF); + memset(nvram + record_length, 0xFF, exchange_length - record_length); Ouch Sheesh, I'd hate to be that guy... Reviewed-by: Eric DeVolder Reviewed-by: Philippe Mathieu-Daudé
Re: [PATCH] acpi/erst: fix fallthrough code upon validation failure
On 5/13/22 09:10, Ani Sinha wrote: At any step when any validation fail in check_erst_backend_storage(), there is no need to continue further through other validation checks. Further, by continuing even when record_size is 0, we run the risk of triggering a divide by zero error if we continued with other validation checks. Hence, we should simply return from this function upon validation failure. CC: Peter Maydell CC: Eric DeVolder Signed-off-by: Ani Sinha Reviewed-by: Eric DeVolder My apologies, I've been away for the past week. Thank you for taking the time to correct this issue! eric --- hw/acpi/erst.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index de509c2b48..df856b2669 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -440,6 +440,7 @@ static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) (record_size >= 4096) /* PAGE_SIZE */ )) { error_setg(errp, "ERST record_size %u is invalid", record_size); +return; } /* Validity check header */ @@ -450,6 +451,7 @@ static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) (le16_to_cpu(header->reserved) == 0) )) { error_setg(errp, "ERST backend storage header is invalid"); +return; } /* Check storage_size against record_size */ @@ -457,6 +459,7 @@ static void check_erst_backend_storage(ERSTDeviceState *s, Error **errp) (record_size > s->storage_size)) { error_setg(errp, "ACPI ERST requires storage size be multiple of " "record size (%uKiB)", record_size); +return; } /* Compute offset of first and last record storage slot */
Re: [PATCH v16] ACPI ERST: specification for ERST support
Hi, just wondering when this is targeted for merge? Thanks, eric On 2/7/22 01:02, Ani Sinha wrote: From: Eric DeVolder Information on the implementation of the ACPI ERST support. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- docs/specs/acpi_erst.rst | 200 +++ docs/specs/index.rst | 1 + 2 files changed, 201 insertions(+) create mode 100644 docs/specs/acpi_erst.rst diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 00..a8a9d22d25 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE + + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +--- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x1,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +-- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that ident
Re: [PATCH] hw/acpi/erst: clean up unused IS_UEFI_CPER_RECORD macro
On 2/15/22 09:31, Ani Sinha wrote: This change is cosmetic. IS_UEFI_CPER_RECORD macro definition that was added as a part of the ERST implementation seems to be unused. Remove it. CC: Eric DeVolder Signed-off-by: Ani Sinha Thanks! Reviewed-by: Eric DeVolder --- hw/acpi/erst.c | 5 - 1 file changed, 5 deletions(-) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index c0a23cf467..de509c2b48 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -80,11 +80,6 @@ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U #define UEFI_CPER_RECORD_ID_OFFSET 96U -#define IS_UEFI_CPER_RECORD(ptr) \ -(((ptr)[0] == 'C') && \ - ((ptr)[1] == 'P') && \ - ((ptr)[2] == 'E') && \ - ((ptr)[3] == 'R')) /* * NOTE that when accessing CPER fields within a record, memcpy()
Re: [PATCH] docs/acpi/erst: add device id for ACPI ERST device in pci-ids.txt
On 2/15/22 09:23, Ani Sinha wrote: Adding device ID for ERST device in pci-ids.txt. It was missed when ERST related patches were reviewed. CC: Eric DeVolder Signed-off-by: Ani Sinha Thanks! Reviewed-by: Eric DeVolder --- docs/specs/pci-ids.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index 5e407a6f32..dd6859d039 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -65,6 +65,7 @@ PCI devices (other than virtio): 1b36:000f mdpy (mdev sample device), linux/samples/vfio-mdev/mdpy.c 1b36:0010 PCIe NVMe device (-device nvme) 1b36:0011 PCI PVPanic device (-device pvpanic-pci) +1b36:0012 PCI ACPI ERST device (-device acpi-erst) All these devices are documented in docs/specs.
[PATCH v15 00/10] acpi: Error Record Serialization Table, ERST, support for QEMU
This patchset introduces support for the ACPI Error Record Serialization Table, ERST. For background and implementation information, please see docs/specs/acpi_erst.rst, which is patch 2/10. Suggested-by: Konrad Wilk Signed-off-by: Eric DeVolder --- v15: 28jan2022 - Changes to build_erst() and ACTION/VALUE context struct setup, per Michael. v14: 26jan2022 - Changed build_erst() to utilize a context structure for generating accesses to ACTION and VALUE, per Michael Tsirkin. - Other simplification per Ani Sinha. v13: 24jan2022 - v12 erroneously omitted step 6 of bios-tables-test.c, this has step 6 included. - No other changes to v12. v12: 10jan2022 - Converted macros in build_erst() to uppert to follow coding style, as pointed out by Michael Tsirkin. - And few items to help further simplify build_erst(). v11: 15dec2021 - Simplified build_erst() via feedback from Michael Tsirkin - Addressed additional feedback from Ani Sinha v10: 9dec2021 - Addressed additional feedback from Ani Sinha v9: 2dec2021 - Addressed feedback from Ani Sinha v8: 15oct2021 - Added Kconfig option for ERST, per Ani Sinha - Fixed patch ordering, per Ani v7: 7oct2021 - style improvements, per Igor - use of endian accessors for storage header, per Igor - a number of optimizations and improvements, per Igor - updated spec for header, per Igor - updated spec for rst format, per Michael Tsirkin - updated spec for new record_size parameter Due to changes in the spec, I am not carrying the Acked-by from Ani Sinha. - changes for and testing of migration to systems with differing ERST_RECORD_SIZE v6: 5aug2021 - Fixed compile warning/error, per Michael Tsirkin - Fixed mingw32 build error, per Michael - Converted exchange buffer to MemoryBackend, per Igor - Migrated test to PCI, per Igor - Significantly reduced amount of copying, per Igor - Corrections/enhancements to acpi_erst.txt, per Igor - Many misc/other small items, per Igor v5: 30jun2021 - Create docs/specs/acpi_erst.txt, per Igor - Separate PCI BARs for registers and memory, per Igor - Convert debugging to use trace infrastructure, per Igor - Various other fixups, per Igor v4: 11jun2021 - Converted to a PCI device, per Igor. - Updated qtest. - Rearranged patches, per Igor. v3: 28may2021 - Converted to using a TYPE_MEMORY_BACKEND_FILE object rather than internal array with explicit file operations, per Igor. - Changed the way the qdev and base address are handled, allowing ERST to be disabled at run-time. Also aligns better with other existing code. v2: 8feb2021 - Added qtest/smoke test per Paolo Bonzini - Split patch into smaller chunks, per Igor Mammedov - Did away with use of ACPI packed structures, per Igor Mammedov v1: 26oct2020 - initial post --- Eric DeVolder (10): ACPI ERST: bios-tables-test.c steps 1 and 2 ACPI ERST: specification for ERST support ACPI ERST: PCI device_id for ERST ACPI ERST: header file for ERST ACPI ERST: support for ACPI ERST feature ACPI ERST: build the ACPI ERST table ACPI ERST: create ACPI ERST table for pc/x86 machines ACPI ERST: qtest for ERST ACPI ERST: bios-tables-test testcase ACPI ERST: step 6 of bios-tables-test.c docs/specs/acpi_erst.rst | 200 +++ hw/acpi/Kconfig |6 + hw/acpi/erst.c| 1055 + hw/acpi/meson.build |1 + hw/acpi/trace-events | 15 + hw/i386/acpi-build.c | 15 + hw/i386/acpi-microvm.c| 15 + include/hw/acpi/erst.h| 24 + include/hw/pci/pci.h |1 + tests/data/acpi/microvm/ERST.pcie | Bin 0 -> 912 bytes tests/data/acpi/pc/DSDT.acpierst | Bin 0 -> 5969 bytes tests/data/acpi/pc/ERST.acpierst | Bin 0 -> 912 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 0 -> 8306 bytes tests/data/acpi/q35/ERST.acpierst | Bin 0 -> 912 bytes tests/qtest/bios-tables-test.c| 54 ++ tests/qtest/erst-test.c | 172 ++ tests/qtest/meson.build |2 + 17 files changed, 1560 insertions(+) create mode 100644 docs/specs/acpi_erst.rst create mode 100644 hw/acpi/erst.c create mode 100644 include/hw/acpi/erst.h create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst create mode 100644 tests/qtest/erst-test.c -- 1.8.3.1
[PATCH v15 08/10] ACPI ERST: qtest for ERST
This change provides a qtest that locates and then does a simple interrogation of the ERST feature within the guest. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/erst-test.c | 172 tests/qtest/meson.build | 2 + 2 files changed, 174 insertions(+) create mode 100644 tests/qtest/erst-test.c diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c new file mode 100644 index 000..f9ad3c9 --- /dev/null +++ b/tests/qtest/erst-test.c @@ -0,0 +1,172 @@ +/* + * QTest testcase for acpi-erst + * + * Copyright (c) 2021 Oracle + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include +#include "libqos/libqos-pc.h" +#include "libqos/libqtest.h" +#include "qemu-common.h" + +#include "hw/pci/pci.h" + +static void save_fn(QPCIDevice *dev, int devfn, void *data) +{ +QPCIDevice **pdev = (QPCIDevice **) data; + +*pdev = dev; +} + +static QPCIDevice *get_erst_device(QPCIBus *pcibus) +{ +QPCIDevice *dev; + +dev = NULL; +qpci_device_foreach(pcibus, +PCI_VENDOR_ID_REDHAT, +PCI_DEVICE_ID_REDHAT_ACPI_ERST, +save_fn, ); +g_assert(dev != NULL); + +return dev; +} + +typedef struct _ERSTState { +QOSState *qs; +QPCIBar reg_bar, mem_bar; +uint64_t reg_barsize, mem_barsize; +QPCIDevice *dev; +} ERSTState; + +#define ACTION 0 +#define VALUE 8 + +static const char *reg2str(unsigned reg) +{ +switch (reg) { +case 0: +return "ACTION"; +case 8: +return "VALUE"; +default: +return NULL; +} +} + +static inline uint32_t in_reg32(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint32_t res; + +res = qpci_io_readl(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %08x", name, res); + +return res; +} + +static inline uint64_t in_reg64(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint64_t res; + +res = qpci_io_readq(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %016llx", name, (unsigned long long)res); + +return res; +} + +static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%08x -> *%s", v, name); +qpci_io_writel(s->dev, s->reg_bar, reg, v); +} + +static inline void out_reg64(ERSTState *s, unsigned reg, uint64_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%016llx -> *%s", (unsigned long long)v, name); +qpci_io_writeq(s->dev, s->reg_bar, reg, v); +} + +static void cleanup_vm(ERSTState *s) +{ +g_free(s->dev); +qtest_shutdown(s->qs); +} + +static void setup_vm_cmd(ERSTState *s, const char *cmd) +{ +const char *arch = qtest_get_arch(); + +if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { +s->qs = qtest_pc_boot(cmd); +} else { +g_printerr("erst-test tests are only available on x86\n"); +exit(EXIT_FAILURE); +} +s->dev = get_erst_device(s->qs->pcibus); + +s->reg_bar = qpci_iomap(s->dev, 0, >reg_barsize); +g_assert_cmpuint(s->reg_barsize, ==, 16); + +s->mem_bar = qpci_iomap(s->dev, 1, >mem_barsize); +g_assert_cmpuint(s->mem_barsize, ==, 0x2000); + +qpci_device_enable(s->dev); +} + +static void test_acpi_erst_basic(void) +{ +ERSTState state; +uint64_t log_address_range; +uint64_t log_address_length; +uint32_t log_address_attr; + +setup_vm_cmd(, +"-object memory-backend-file," +"mem-path=acpi-erst.XX," +"size=64K," +"share=on," +"id=nvram " +"-device acpi-erst," +"memdev=nvram"); + +out_reg32(, ACTION, 0xD); +log_address_range = in_reg64(, VALUE); +out_reg32(, ACTION, 0xE); +log_address_length = in_reg64(, VALUE); +out_reg32(, ACTION, 0xF); +log_address_attr = in_reg32(, VALUE); + +/* Check log_address_range is not 0, ~0 or base */ +g_assert_cmpuint(log_address_range, !=, 0ULL); +g_assert_cmpuint(log_address_range, !=, ~0ULL); +g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr); +g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr); + +/* Check log_address_length is bar1_size */ +g_assert_cmpuint(log_address_length, ==, state.mem_barsize); + +/* Check log_address_attr is 0 */ +g_assert_cmpuint(log_address_attr, ==, 0); + +cleanup_vm(); +} + +int main(int argc, char **argv) +{ +int ret; + +g_test_init(, , NULL); +qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
[PATCH v15 09/10] ACPI ERST: bios-tables-test testcase
This change implements the test suite checks for the ERST table. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/bios-tables-test.c | 54 ++ 1 file changed, 54 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index e6b72d9..266b215 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1446,6 +1446,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +static void test_acpi_erst(const char *machine) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +memset(, 0, sizeof(data)); +data.machine = machine; +data.variant = ".acpierst"; +params = g_strdup_printf( +" -object memory-backend-file,id=erstnvram," +"mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +free_test_data(); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +} + +static void test_acpi_piix4_acpi_erst(void) +{ +test_acpi_erst(MACHINE_PC); +} + +static void test_acpi_q35_acpi_erst(void) +{ +test_acpi_erst(MACHINE_Q35); +} + +static void test_acpi_microvm_acpi_erst(void) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +test_acpi_microvm_prepare(); +data.variant = ".pcie"; +data.tcg_only = true; /* need constant host-phys-bits */ +params = g_strdup_printf(" -machine microvm," +"acpi=on,ioapic2=off,rtc=off,pcie=on" +" -object memory-backend-file,id=erstnvram," + "mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +free_test_data(); +} + static void test_acpi_virt_tcg(void) { test_data data = { @@ -1675,6 +1726,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); +qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); +qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); @@ -1684,6 +1737,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); if (strcmp(arch, "x86_64") == 0) { qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg); +qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst); } } if (has_kvm) { -- 1.8.3.1
[PATCH v15 07/10] ACPI ERST: create ACPI ERST table for pc/x86 machines
This change exposes ACPI ERST support for x86 guests. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/i386/acpi-build.c | 15 +++ hw/i386/acpi-microvm.c | 15 +++ include/hw/acpi/erst.h | 5 + 3 files changed, 35 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ce823e8..ebd47aa 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -43,6 +43,7 @@ #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "hw/acpi/vmgenid.h" +#include "hw/acpi/erst.h" #include "sysemu/tpm_backend.h" #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" @@ -74,6 +75,8 @@ #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" +#include CONFIG_DEVICES + /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows * a little bit, there should be plenty of free space since the DSDT @@ -2575,6 +2578,18 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { acpi_add_table(table_offsets, tables_blob); diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 196d318..68ca7e7 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -30,6 +30,7 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" #include "hw/acpi/utils.h" +#include "hw/acpi/erst.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/microvm.h" #include "hw/pci/pci.h" @@ -40,6 +41,8 @@ #include "acpi-common.h" #include "acpi-microvm.h" +#include CONFIG_DEVICES + static void acpi_dsdt_add_virtio(Aml *scope, MicrovmMachineState *mms) { @@ -207,6 +210,18 @@ static void acpi_build_microvm(AcpiBuildTables *tables, ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id, x86ms->oem_table_id); diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h index 9d63717..b747fe7 100644 --- a/include/hw/acpi/erst.h +++ b/include/hw/acpi/erst.h @@ -16,4 +16,9 @@ void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, #define TYPE_ACPI_ERST "acpi-erst" +/* returns NULL unless there is exactly one device */ +static inline Object *find_erst_dev(void) +{ +return object_resolve_path_type("", TYPE_ACPI_ERST, NULL); +} #endif -- 1.8.3.1
[PATCH v15 06/10] ACPI ERST: build the ACPI ERST table
This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/acpi/erst.c | 211 + 1 file changed, 211 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..cd32aa7 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,196 @@ typedef struct { /***/ /***/ +typedef struct { +GArray *table_data; +pcibus_t bar; +uint8_t instruction; +uint8_t flags; +uint8_t register_bit_width; +pcibus_t register_offset; +} BuildSerializationInstructionEntry; + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction( +BuildSerializationInstructionEntry *e, +uint8_t serialization_action, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(e->table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(e->table_data, e->instruction, 1); +/* Flags */ +build_append_int_noprefix(e->table_data, e->flags, 1); +/* Reserved */ +build_append_int_noprefix(e->table_data, 0, 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = e->register_bit_width; +gas.bit_offset = 0; +gas.access_width = (uint8_t)ctz32(e->register_bit_width) - 2; +gas.address = (uint64_t)(e->bar + e->register_offset); +build_append_gas_from_struct(e->table_data, ); +/* Value */ +build_append_int_noprefix(e->table_data, value, 8); +/* Mask */ +mask = (1ULL << (e->register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(e->table_data, mask, 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +unsigned action; +GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; +/* Contexts for the different ways ACTION and VALUE are accessed */ +BuildSerializationInstructionEntry rd_value_32_val = { +.table_data = table_instruction_data, .bar = bar0, .flags = 0, +.instruction = INST_READ_REGISTER_VALUE, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry rd_value_32 = { +.table_data = table_instruction_data, .bar = bar0, .flags = 0, +.instruction = INST_READ_REGISTER, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry rd_value_64 = { +.table_data = table_instruction_data, .bar = bar0, .flags = 0, +.instruction = INST_READ_REGISTER, +.register_bit_width = 64, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry wr_value_32_val = { +.table_data = table_instruction_data, .bar = bar0, .flags = 0, +.instructio
[PATCH v15 04/10] ACPI ERST: header file for ERST
This change introduces the public defintions for ACPI ERST. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- include/hw/acpi/erst.h | 19 +++ 1 file changed, 19 insertions(+) create mode 100644 include/hw/acpi/erst.h diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h new file mode 100644 index 000..9d63717 --- /dev/null +++ b/include/hw/acpi/erst.h @@ -0,0 +1,19 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_ACPI_ERST_H +#define HW_ACPI_ERST_H + +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id); + +#define TYPE_ACPI_ERST "acpi-erst" + +#endif -- 1.8.3.1
[PATCH v15 05/10] ACPI ERST: support for ACPI ERST feature
This implements a PCI device for ACPI ERST. This implements the non-NVRAM "mode" of operation for ERST as it is supported by Linux and Windows. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/acpi/Kconfig | 6 + hw/acpi/erst.c | 844 +++ hw/acpi/meson.build | 1 + hw/acpi/trace-events | 15 + 4 files changed, 866 insertions(+) create mode 100644 hw/acpi/erst.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 622b0b5..19caebd 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -10,6 +10,7 @@ config ACPI_X86 select ACPI_HMAT select ACPI_PIIX4 select ACPI_PCIHP +select ACPI_ERST config ACPI_X86_ICH bool @@ -60,3 +61,8 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_ERST +bool +default y +depends on ACPI && PCI diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c new file mode 100644 index 000..fe9ba51 --- /dev/null +++ b/hw/acpi/erst.c @@ -0,0 +1,844 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-core.h" +#include "exec/memory.h" +#include "qom/object.h" +#include "hw/pci/pci.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "exec/address-spaces.h" +#include "sysemu/hostmem.h" +#include "hw/acpi/erst.h" +#include "trace.h" + +/* ACPI 4.0: Table 17-16 Serialization Actions */ +#define ACTION_BEGIN_WRITE_OPERATION 0x0 +#define ACTION_BEGIN_READ_OPERATION 0x1 +#define ACTION_BEGIN_CLEAR_OPERATION 0x2 +#define ACTION_END_OPERATION 0x3 +#define ACTION_SET_RECORD_OFFSET 0x4 +#define ACTION_EXECUTE_OPERATION 0x5 +#define ACTION_CHECK_BUSY_STATUS 0x6 +#define ACTION_GET_COMMAND_STATUS0x7 +#define ACTION_GET_RECORD_IDENTIFIER 0x8 +#define ACTION_SET_RECORD_IDENTIFIER 0x9 +#define ACTION_GET_RECORD_COUNT 0xA +#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB +#define ACTION_RESERVED 0xC +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD +#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF +#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */ + +/* ACPI 4.0: Table 17-17 Command Status Definitions */ +#define STATUS_SUCCESS0x00 +#define STATUS_NOT_ENOUGH_SPACE 0x01 +#define STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define STATUS_FAILED 0x03 +#define STATUS_RECORD_STORE_EMPTY 0x04 +#define STATUS_RECORD_NOT_FOUND 0x05 + +/* UEFI 2.1: Appendix N Common Platform Error Record */ +#define UEFI_CPER_RECORD_MIN_SIZE 128U +#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U +#define UEFI_CPER_RECORD_ID_OFFSET 96U +#define IS_UEFI_CPER_RECORD(ptr) \ +(((ptr)[0] == 'C') && \ + ((ptr)[1] == 'P') && \ + ((ptr)[2] == 'E') && \ + ((ptr)[3] == 'R')) + +/* + * NOTE that when accessing CPER fields within a record, memcpy() + * is utilized to avoid a possible misaligned access on the host. + */ + +/* + * This implementation is an ACTION (cmd) and VALUE (data) + * interface consisting of just two 64-bit registers. + */ +#define ERST_REG_SIZE (16UL) +#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ +#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ + +/* + * ERST_RECORD_SIZE is the buffer size for exchanging ERST + * record contents. Thus, it defines the maximum record size. + * As this is mapped through a PCI BAR, it must be a power of + * two and larger than UEFI_CPER_RECORD_MIN_SIZE. + * The backing storage is divided into fixed size "slots", + * each ERST_RECORD_SIZE in length, and each "slot" + * storing a single record. No attempt at optimizing storage + * through compression, compaction, etc is attempted. + * NOTE that slot 0 is reserved for the backing storage header. + * Depending upon the size of the backing storage, additional + * slots will be part of the slot 0 header in order to account + * for a record_id for each available remaining slot. + */ +/* 8KiB records, not too small, not too big */ +#define ERST_RECORD_SIZE (8192UL) + +#define ACPI_ERST_MEMDEV_PROP "
[PATCH v15 10/10] ACPI ERST: step 6 of bios-tables-test.c
} @@ -1399,11 +1394,6 @@ DefinitionBlock ("", "DSDT", 1, "BOCHS " Method (DVNT, 2, NotSerialized) { -If ((Arg0 & 0x08)) -{ -Notify (S18, Arg1) -} - If ((Arg0 & 0x10)) { Notify (S20, Arg1) diff q35/DSDT and q35/DSDT.acpierst: @@ -5,13 +5,13 @@ * * Disassembling to symbolic ASL+ operators * - * Disassembly of tests/data/acpi/q35/DSDT, Thu Dec 2 10:10:13 2021 + * Disassembly of tests/data/acpi/q35/DSDT.acpierst, Thu Dec 2 12:59:36 2021 * * Original Table Header: * Signature"DSDT" - * Length 0x2061 (8289) + * Length 0x2072 (8306) * Revision 0x01 32-bit table (V1), no 64-bit math support - * Checksum 0xFA + * Checksum 0x9A * OEM ID "BOCHS " * OEM Table ID "BXPC" * OEM Revision 0x0001 (1) @@ -3278,6 +3278,11 @@ DefinitionBlock ("", "DSDT", 1, "BOCHS " } } +Device (S10) +{ +Name (_ADR, 0x0002) // _ADR: Address +} + Method (PCNT, 0, NotSerialized) { } For both pc and q35, there is but a small difference between this DSDT.acpierst and the corresponding DSDT. In both cases, the changes occur under the hiearchy: Scope (\_SB) { Scope (PCI0) { which leads me to believe that the change to the DSDT was needed due to the introduction of the ERST PCI device. And is explained in detail by Ani Sinha: I have convinced myself of the changes we see in the DSDT tables. On i440fx side, we are adding a non-hotpluggable pci device on slot 3. So the changes we see are basically replacing an empty hotpluggable slot on the pci root port with a non-hotplugggable device. On q35, bsel on pcie root bus is not set (its not hotpluggable bus), so the change basically adds the address enumeration for the device. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- tests/data/acpi/microvm/ERST.pcie | Bin 0 -> 912 bytes tests/data/acpi/pc/DSDT.acpierst| Bin 0 -> 5969 bytes tests/data/acpi/pc/ERST.acpierst| Bin 0 -> 912 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 0 -> 8306 bytes tests/data/acpi/q35/ERST.acpierst | Bin 0 -> 912 bytes tests/qtest/bios-tables-test-allowed-diff.h | 5 - 6 files changed, 5 deletions(-) diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a6d0cb783831ebc18972ec57bb6c624438ff150d 100644 GIT binary patch literal 912 zcmaKoTMmLS5Jd;doACJehb6cK12OSWBYwCn7ocm^-rA|;CUz1YmosPDa=fm$hY?9$ z^LaU~(|o@yldVKV@Q+UZ@>zwpS)GZ(sO?Lc}v64j-jFC7yn9;D$INO8pFiUB7f+ zf49KN+;jDxe>nP4Iq`z#7tC?s!tc6i7Z+t!@(t>{e2`4% zZhiFB_p5lnFb*Ui&1$pT3_)pk?J?$-jLiezjJ$6`=r)uYry0Rn7KuJIp)|! zckaizM=~sYzU*-I~PkUtAn>Dr`~u=;o(_O$t$PK8~R}U#`{0u*{ zz`m8fl|Wu#ucTKJu-TjNQ`rN~%rBccG0yWwF_}_zQl+X71|-_g)Pr`x1*Xgb!>QealcAR5Lj8F@vR~_hFrfVBOumUtb3< zL8GI#8|W0leXv|!GGL=~vE5*uM7z%Af!czNXYqlQL#IT$!9xR0zORu68XY#=M-SGy z3b+$tZv(*Hu4BBt4F>MUo>Padde^ZZU%V_4TiQ&6ruaomTLcp<9-2bBZ=qyp40+ ziEQ&$6L)c>%cI)0;%@F~Or>jX}g)!VlmH>3A6L#ZGj;i8(jvxl3w$XL%gc z#4Y0Q*ces>sy7Obm6bTnr@oqih!n=P&+!w*9R95=2i+)QqA9kLa1VJk2ES zOh6C4;>puBt75SyO`ippr%I9Z{pk6j=(st4aP-WP=ov412KgP0p3z1}&)7R9%3U9d z!>df~G};j<@%&-TL`!{M=J{^0EAj)b4{!p{wbpF1J^oV~LmWA@f?c-apx zmJl5aIOP$4%5j~Id6TV0{V^u0sG`|bSAOB2V2gb1@Ki7>g+T~D<}I$cZmy;lKl#kP zxAm*k{f|HWWb1z8<4?h6y1Bg6FLiOw7Z@DC0gGYf$3^AUwgVosAOD1e9Hex!P-c3u zY%#r3y2G$SrRg@$K+^S+fmJX`o|0}AmQ(0%hN|GcJ*{Ry{RpZVR_9(>4G!#sMm9K*-Kb2oqvI?7dL24<1WVww+F6k zrAwi@3blP`ov2|RQA!4yn|HMt+|rp;ky|p}*s4Bhi{tS7b7IwWYtO z($_%y0DUt+12O0t{g!qm$i(>FX+UGsM;osE9mca!r!@5Ld6Jt2$-nabyyC?4*zT@l2 z4LgzF3U^-%E&8T*RhMxH{B|{Nmd$hyhrlm@q(4{QfcO=jBztZw|gWU^0Q+lFdc4 z;t%ATAUG5ws_1bncmXfi8SEC{UBmF!TrD{!GvtiVS87Q`#ts;JTa>Png~+QvKOAg( z=l%H)^?9Gb?Lui47fY7Bv8_MKSPiRTs@3YkU)Q{@YvnKAT;;J8U>fgQ>9qeF0+gJ! zS_V9pumOy9sSU)%^lS1X17`o1`MA>W^ePI^H@E*S%`|HOx^c$lLHVkhwcpCba771jDZ#SdZmhM`3K=q{% zNdudV5*`|Tn?lmSM!~R<_iYsI+Q3HPu(0YhlR~GImZVAKI~h z+O@D02|KpVC?DEYlCeYxd&-j!?Kerrtt;#;Pd>DJ8RM1`cI=OKE{vc{!8uv6Z~ u5j$m$OK@OMk$l8{6J=Z)1AB{Pv}@<7F~|QN>AydkHSF$IS^vS{(*FTuhT2R3 literal 0 HcmV?d1 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7965ac2562e7b23bf1dc2caaf00ef66453c4f47a 100644 GIT binary patch literal 912 zcmaKoOAdlC6h$9Upg{N}4xO+BmS7+z{Ww`+N;?C6GO0l^KeF>#Er>E`f@jBlg ziAb~?&(mq{$NOdKO+_MtIsSwBP(BS` zh6Ua)#A*M6_AiN-%#j24ugI^+uZh>pkpuT{$ZyEEIpDYCx8#=`Con^ B
[PATCH v15 01/10] ACPI ERST: bios-tables-test.c steps 1 and 2
Following the guidelines in tests/qtest/bios-tables-test.c, this change adds empty placeholder files per step 1 for the new ERST table, and excludes resulting changed files in bios-tables-test-allowed-diff.h per step 2. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov --- tests/data/acpi/microvm/ERST.pcie | 0 tests/data/acpi/pc/DSDT.acpierst| 0 tests/data/acpi/pc/ERST.acpierst| 0 tests/data/acpi/q35/DSDT.acpierst | 0 tests/data/acpi/q35/ERST.acpierst | 0 tests/qtest/bios-tables-test-allowed-diff.h | 5 + 6 files changed, 5 insertions(+) create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/ERST.acpierst b/tests/data/acpi/q35/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523..603db07 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/ERST.acpierst", +"tests/data/acpi/q35/DSDT.acpierst", +"tests/data/acpi/q35/ERST.acpierst", +"tests/data/acpi/microvm/ERST.pcie", -- 1.8.3.1
[PATCH v15 02/10] ACPI ERST: specification for ERST support
Information on the implementation of the ACPI ERST support. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- docs/specs/acpi_erst.rst | 200 +++ 1 file changed, 200 insertions(+) create mode 100644 docs/specs/acpi_erst.rst diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 000..a8a9d22 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE + + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +--- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x1,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +-- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that identifies the contents +as ERST and also facilitates efficient access to the records. +Depending upon the size of the backend storage, additional slots will +be designated
[PATCH v15 03/10] ACPI ERST: PCI device_id for ERST
This change reserves the PCI device_id for the new ACPI ERST device. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov Acked-by: Ani Sinha --- include/hw/pci/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 023abc0..c3f3c90 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -108,6 +108,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_REDHAT_MDPY0x000f #define PCI_DEVICE_ID_REDHAT_NVME0x0010 #define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 +#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012 #define PCI_DEVICE_ID_REDHAT_QXL 0x0100 #define FMT_PCIBUS PRIx64 -- 1.8.3.1
Re: [PATCH v14 06/10] ACPI ERST: build the ACPI ERST table
On 1/28/22 11:25, Ani Sinha wrote: [snip] On Fri, Jan 28, 2022 at 9:44 PM Michael S. Tsirkin mailto:m...@redhat.com>> wrote: > > > OK, here is the equivalent using struct assignment, is this what you were after? > > > > > > BuildSerializationInstructionEntry base = { > > > .table_data = table_instruction_data, > > > .bar = bar0, > > > .instruction = INST_WRITE_REGISTER, > > > .flags = 0, > > > .register_bit_width = 32, > > > .register_offset = ERST_VALUE_OFFSET, > > > }; > > > BuildSerializationInstructionEntry rd_value_32_val = base; > > > rd_value_32_val.instruction = INST_READ_REGISTER_VALUE; > > > BuildSerializationInstructionEntry rd_value_32 = base; > > > rd_value_32.instruction = INST_READ_REGISTER; > > > BuildSerializationInstructionEntry rd_value_64 = base; > > > rd_value_64.instruction = INST_READ_REGISTER; > > > rd_value_64.register_bit_width = 64; > > > BuildSerializationInstructionEntry wr_value_32_val = base; > > > wr_value_32_val.instruction = INST_WRITE_REGISTER_VALUE; > > > BuildSerializationInstructionEntry wr_value_32 = base; > > > BuildSerializationInstructionEntry wr_value_64 = base; > > > wr_value_64.register_bit_width = 64; > > > BuildSerializationInstructionEntry wr_action = base; > > > wr_action.instruction = INST_WRITE_REGISTER_VALUE; > > > wr_action.register_offset = ERST_ACTION_OFFSET; > > > > > > > That's what I described, yes. We should have some empty lines here I > > guess. I'm ok with the original one too, there's not too much > > duplication. > > Are the blank lines referring to spacing out the setup of each of the 7 accesors? > If so, I could put a one line comment between each setup? Or is a blank line also > needed? A blank line between declarations and code is usually a good idea. > Is it OK to post v15 with the struct assignment approach? Or would you prefer the > explicit structs (which is what I think you mean by 'the original one')? I prefer the explicit structs as you had posted before. Ok, as Michael does not have a preference, so let's go with your preference of the explicit structs! Thank you! eric > > Thanks! > eric I don't care either way. > > > > > > > > > > > > > > > > > > > > #define SERIALIZATIONINSTRUCTIONCTX(name, \ > > > > > inst, bit_width, offset) \ > > > > > BuildSerializationInstructionEntry name = { \ > > > > > .table_data = table_instruction_data, \ > > > > > .bar = bar0, \ > > > > > .instruction = inst, \ > > > > > .flags = 0, \ > > > > > .register_bit_width = bit_width, \ > > > > > .register_offset = offset, \ > > > > > } > > > > > SERIALIZATIONINSTRUCTIONCTX(rd_value_32_val, > > > > > INST_READ_REGISTER_VALUE, 32, ERST_VALUE_OFFSET); > > > > > SERIALIZATIONINSTRUCTIONCTX(rd_value_32, > > > > > INST_READ_REGISTER, 32, ERST_VALUE_OFFSET); > > > > > SERIALIZATIONINSTRUCTIONCTX(rd_value_64, > > > > > INST_READ_REGISTER, 64, ERST_VALUE_OFFSET); > > > > > SERIALIZATIONINSTRUCTIONCTX(wr_value_32_val, > > > > > INST_WRITE_REGISTER_VALUE, 32, ERST_VALUE_OFFSET); > > > > > SERIALIZATIONINSTRUCTIONCTX(wr_value_32, > > > > > INST_WRITE_REGISTER, 32, ERST_VALUE_OFFSET); > > > > > SERIALIZATIONINSTRUCTIONCTX(wr_value_64, > > > > > INST_WRITE_REGISTER, 64, ERST_VALUE_OFFSET); > > > > > SERIALIZATIONINSTRUCTIONCTX(wr_action, > > > > > INST_WRITE_REGISTER_VALUE, 32, ERST_ACTION_OFFSET); > > > > > > > > > > These are the 7 accessors needed. > > > > > > > > not at all sure this one is worth the macro mess. > > > > > > I'm hoping to produce a v15 with the style you want. > > > eric > > > > > > > > > > > > > > > > > > > > + unsigned action; > > > > > > > + > > > > > > > + trace_acpi_erst_pci_bar_0(bar0); > > > > > > > + > > > > > > > + /* Serialization Instruction Entries */ > > > > > > > + action = ACTION_BEGIN_WRITE_OPERATION; > > > > > > > + build_serialization_instruction(_action, action, action); > > > > > > > + > > > > > > > + action = ACTION_BEGIN_READ_OPERATION; > > > > > > > + build_serialization_instruction(_action, action, action); > > > > > > > + > > > > > > > + action = ACTION_BEGIN_CLEAR_OPERATION; > > > > > > > + build_serialization_instruction(_action, action, action); > > > > > > > + > > > > > > > +
Re: [PATCH v14 06/10] ACPI ERST: build the ACPI ERST table
Michael, thanks! See inline response below, please. eric On 1/28/22 09:54, Michael S. Tsirkin wrote: On Fri, Jan 28, 2022 at 09:11:41AM -0600, Eric DeVolder wrote: Michael, Thanks for examining this. Inline response below. eric On 1/27/22 18:37, Michael S. Tsirkin wrote: On Thu, Jan 27, 2022 at 04:02:07PM -0600, Eric DeVolder wrote: Ani, Thanks for the RB! Inline responses below. eric On 1/27/22 02:36, Ani Sinha wrote: On Wed, 26 Jan 2022, Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. There might be more optimizations possible but I think we have messaged this code enough. We can further rework the code if needed in subsequent patches once this is pushed. Signed-off-by: Eric DeVolder with some minor comments, Reviewed-by: Ani Sinha hw/acpi/erst.c | 225 + 1 file changed, 225 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..5d5a639 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,210 @@ typedef struct { /***/ /***/ +typedef struct { +GArray *table_data; +pcibus_t bar; +uint8_t instruction; +uint8_t flags; +uint8_t register_bit_width; +pcibus_t register_offset; +} BuildSerializationInstructionEntry; + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction( +BuildSerializationInstructionEntry *e, +uint8_t serialization_action, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(e->table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(e->table_data, e->instruction, 1); +/* Flags */ +build_append_int_noprefix(e->table_data, e->flags, 1); +/* Reserved */ +build_append_int_noprefix(e->table_data, 0, 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = e->register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(e->register_bit_width) - 2; Should this be casted as unit8_t? OK, done. +gas.address = (uint64_t)(e->bar + e->register_offset); +build_append_gas_from_struct(e->table_data, ); +/* Value */ +build_append_int_noprefix(e->table_data, value, 8); +/* Mask */ +mask = (1ULL << (e->register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(e->table_data, mask, 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; +/* Contexts for the different ways ACTION and VALUE are accessed */ +BuildSerializationInstructionEntry rd_value_32_val = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER_VALUE, +.flags = 0, +.regist
Re: [PATCH v14 06/10] ACPI ERST: build the ACPI ERST table
Michael, Thanks for examining this. Inline response below. eric On 1/27/22 18:37, Michael S. Tsirkin wrote: On Thu, Jan 27, 2022 at 04:02:07PM -0600, Eric DeVolder wrote: Ani, Thanks for the RB! Inline responses below. eric On 1/27/22 02:36, Ani Sinha wrote: On Wed, 26 Jan 2022, Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. There might be more optimizations possible but I think we have messaged this code enough. We can further rework the code if needed in subsequent patches once this is pushed. Signed-off-by: Eric DeVolder with some minor comments, Reviewed-by: Ani Sinha hw/acpi/erst.c | 225 + 1 file changed, 225 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..5d5a639 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,210 @@ typedef struct { /***/ /***/ +typedef struct { +GArray *table_data; +pcibus_t bar; +uint8_t instruction; +uint8_t flags; +uint8_t register_bit_width; +pcibus_t register_offset; +} BuildSerializationInstructionEntry; + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction( +BuildSerializationInstructionEntry *e, +uint8_t serialization_action, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(e->table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(e->table_data, e->instruction, 1); +/* Flags */ +build_append_int_noprefix(e->table_data, e->flags, 1); +/* Reserved */ +build_append_int_noprefix(e->table_data, 0, 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = e->register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(e->register_bit_width) - 2; Should this be casted as unit8_t? OK, done. +gas.address = (uint64_t)(e->bar + e->register_offset); +build_append_gas_from_struct(e->table_data, ); +/* Value */ +build_append_int_noprefix(e->table_data, value, 8); +/* Mask */ +mask = (1ULL << (e->register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(e->table_data, mask, 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; +/* Contexts for the different ways ACTION and VALUE are accessed */ +BuildSerializationInstructionEntry rd_value_32_val = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER_VALUE, +.flags = 0, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry rd_value_32 = { +.table_data = table_instruction_data,
Re: [PATCH v14 06/10] ACPI ERST: build the ACPI ERST table
Ani, Thanks for the RB! Inline responses below. eric On 1/27/22 02:36, Ani Sinha wrote: On Wed, 26 Jan 2022, Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. There might be more optimizations possible but I think we have messaged this code enough. We can further rework the code if needed in subsequent patches once this is pushed. Signed-off-by: Eric DeVolder with some minor comments, Reviewed-by: Ani Sinha hw/acpi/erst.c | 225 + 1 file changed, 225 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..5d5a639 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,210 @@ typedef struct { /***/ /***/ +typedef struct { +GArray *table_data; +pcibus_t bar; +uint8_t instruction; +uint8_t flags; +uint8_t register_bit_width; +pcibus_t register_offset; +} BuildSerializationInstructionEntry; + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction( +BuildSerializationInstructionEntry *e, +uint8_t serialization_action, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(e->table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(e->table_data, e->instruction, 1); +/* Flags */ +build_append_int_noprefix(e->table_data, e->flags, 1); +/* Reserved */ +build_append_int_noprefix(e->table_data, 0, 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = e->register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(e->register_bit_width) - 2; Should this be casted as unit8_t? OK, done. +gas.address = (uint64_t)(e->bar + e->register_offset); +build_append_gas_from_struct(e->table_data, ); +/* Value */ +build_append_int_noprefix(e->table_data, value, 8); +/* Mask */ +mask = (1ULL << (e->register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(e->table_data, mask, 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; +/* Contexts for the different ways ACTION and VALUE are accessed */ +BuildSerializationInstructionEntry rd_value_32_val = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER_VALUE, +.flags = 0, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry rd_value_32 = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER, +.flags = 0, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSe
[PATCH v14 10/10] ACPI ERST: step 6 of bios-tables-test.c
} @@ -1399,11 +1394,6 @@ DefinitionBlock ("", "DSDT", 1, "BOCHS " Method (DVNT, 2, NotSerialized) { -If ((Arg0 & 0x08)) -{ -Notify (S18, Arg1) -} - If ((Arg0 & 0x10)) { Notify (S20, Arg1) diff q35/DSDT and q35/DSDT.acpierst: @@ -5,13 +5,13 @@ * * Disassembling to symbolic ASL+ operators * - * Disassembly of tests/data/acpi/q35/DSDT, Thu Dec 2 10:10:13 2021 + * Disassembly of tests/data/acpi/q35/DSDT.acpierst, Thu Dec 2 12:59:36 2021 * * Original Table Header: * Signature"DSDT" - * Length 0x2061 (8289) + * Length 0x2072 (8306) * Revision 0x01 32-bit table (V1), no 64-bit math support - * Checksum 0xFA + * Checksum 0x9A * OEM ID "BOCHS " * OEM Table ID "BXPC" * OEM Revision 0x0001 (1) @@ -3278,6 +3278,11 @@ DefinitionBlock ("", "DSDT", 1, "BOCHS " } } +Device (S10) +{ +Name (_ADR, 0x0002) // _ADR: Address +} + Method (PCNT, 0, NotSerialized) { } For both pc and q35, there is but a small difference between this DSDT.acpierst and the corresponding DSDT. In both cases, the changes occur under the hiearchy: Scope (\_SB) { Scope (PCI0) { which leads me to believe that the change to the DSDT was needed due to the introduction of the ERST PCI device. And is explained in detail by Ani Sinha: I have convinced myself of the changes we see in the DSDT tables. On i440fx side, we are adding a non-hotpluggable pci device on slot 3. So the changes we see are basically replacing an empty hotpluggable slot on the pci root port with a non-hotplugggable device. On q35, bsel on pcie root bus is not set (its not hotpluggable bus), so the change basically adds the address enumeration for the device. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- tests/data/acpi/microvm/ERST.pcie | Bin 0 -> 912 bytes tests/data/acpi/pc/DSDT.acpierst| Bin 0 -> 5969 bytes tests/data/acpi/pc/ERST.acpierst| Bin 0 -> 912 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 0 -> 8306 bytes tests/data/acpi/q35/ERST.acpierst | Bin 0 -> 912 bytes tests/qtest/bios-tables-test-allowed-diff.h | 5 - 6 files changed, 5 deletions(-) diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a6d0cb783831ebc18972ec57bb6c624438ff150d 100644 GIT binary patch literal 912 zcmaKoTMmLS5Jd;doACJehb6cK12OSWBYwCn7ocm^-rA|;CUz1YmosPDa=fm$hY?9$ z^LaU~(|o@yldVKV@Q+UZ@>zwpS)GZ(sO?Lc}v64j-jFC7yn9;D$INO8pFiUB7f+ zf49KN+;jDxe>nP4Iq`z#7tC?s!tc6i7Z+t!@(t>{e2`4% zZhiFB_p5lnFb*Ui&1$pT3_)pk?J?$-jLiezjJ$6`=r)uYry0Rn7KuJIp)|! zckaizM=~sYzU*-I~PkUtAn>Dr`~u=;o(_O$t$PK8~R}U#`{0u*{ zz`m8fl|Wu#ucTKJu-TjNQ`rN~%rBccG0yWwF_}_zQl+X71|-_g)Pr`x1*Xgb!>QealcAR5Lj8F@vR~_hFrfVBOumUtb3< zL8GI#8|W0leXv|!GGL=~vE5*uM7z%Af!czNXYqlQL#IT$!9xR0zORu68XY#=M-SGy z3b+$tZv(*Hu4BBt4F>MUo>Padde^ZZU%V_4TiQ&6ruaomTLcp<9-2bBZ=qyp40+ ziEQ&$6L)c>%cI)0;%@F~Or>jX}g)!VlmH>3A6L#ZGj;i8(jvxl3w$XL%gc z#4Y0Q*ces>sy7Obm6bTnr@oqih!n=P&+!w*9R95=2i+)QqA9kLa1VJk2ES zOh6C4;>puBt75SyO`ippr%I9Z{pk6j=(st4aP-WP=ov412KgP0p3z1}&)7R9%3U9d z!>df~G};j<@%&-TL`!{M=J{^0EAj)b4{!p{wbpF1J^oV~LmWA@f?c-apx zmJl5aIOP$4%5j~Id6TV0{V^u0sG`|bSAOB2V2gb1@Ki7>g+T~D<}I$cZmy;lKl#kP zxAm*k{f|HWWb1z8<4?h6y1Bg6FLiOw7Z@DC0gGYf$3^AUwgVosAOD1e9Hex!P-c3u zY%#r3y2G$SrRg@$K+^S+fmJX`o|0}AmQ(0%hN|GcJ*{Ry{RpZVR_9(>4G!#sMm9K*-Kb2oqvI?7dL24<1WVww+F6k zrAwi@3blP`ov2|RQA!4yn|HMt+|rp;ky|p}*s4Bhi{tS7b7IwWYtO z($_%y0DUt+12O0t{g!qm$i(>FX+UGsM;osE9mca!r!@5Ld6Jt2$-nabyyC?4*zT@l2 z4LgzF3U^-%E&8T*RhMxH{B|{Nmd$hyhrlm@q(4{QfcO=jBztZw|gWU^0Q+lFdc4 z;t%ATAUG5ws_1bncmXfi8SEC{UBmF!TrD{!GvtiVS87Q`#ts;JTa>Png~+QvKOAg( z=l%H)^?9Gb?Lui47fY7Bv8_MKSPiRTs@3YkU)Q{@YvnKAT;;J8U>fgQ>9qeF0+gJ! zS_V9pumOy9sSU)%^lS1X17`o1`MA>W^ePI^H@E*S%`|HOx^c$lLHVkhwcpCba771jDZ#SdZmhM`3K=q{% zNdudV5*`|Tn?lmSM!~R<_iYsI+Q3HPu(0YhlR~GImZVAKI~h z+O@D02|KpVC?DEYlCeYxd&-j!?Kerrtt;#;Pd>DJ8RM1`cI=OKE{vc{!8uv6Z~ u5j$m$OK@OMk$l8{6J=Z)1AB{Pv}@<7F~|QN>AydkHSF$IS^vS{(*FTuhT2R3 literal 0 HcmV?d1 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7965ac2562e7b23bf1dc2caaf00ef66453c4f47a 100644 GIT binary patch literal 912 zcmaKoOAdlC6h$9Upg{N}4xO+BmS7+z{Ww`+N;?C6GO0l^KeF>#Er>E`f@jBlg ziAb~?&(mq{$NOdKO+_MtIsSwBP(BS` zh6Ua)#A*M6_AiN-%#j24ugI^+uZh>pkpuT{$ZyEEIpDYCx8#=`Con^ B
[PATCH v14 08/10] ACPI ERST: qtest for ERST
This change provides a qtest that locates and then does a simple interrogation of the ERST feature within the guest. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/erst-test.c | 172 tests/qtest/meson.build | 2 + 2 files changed, 174 insertions(+) create mode 100644 tests/qtest/erst-test.c diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c new file mode 100644 index 000..f9ad3c9 --- /dev/null +++ b/tests/qtest/erst-test.c @@ -0,0 +1,172 @@ +/* + * QTest testcase for acpi-erst + * + * Copyright (c) 2021 Oracle + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include +#include "libqos/libqos-pc.h" +#include "libqos/libqtest.h" +#include "qemu-common.h" + +#include "hw/pci/pci.h" + +static void save_fn(QPCIDevice *dev, int devfn, void *data) +{ +QPCIDevice **pdev = (QPCIDevice **) data; + +*pdev = dev; +} + +static QPCIDevice *get_erst_device(QPCIBus *pcibus) +{ +QPCIDevice *dev; + +dev = NULL; +qpci_device_foreach(pcibus, +PCI_VENDOR_ID_REDHAT, +PCI_DEVICE_ID_REDHAT_ACPI_ERST, +save_fn, ); +g_assert(dev != NULL); + +return dev; +} + +typedef struct _ERSTState { +QOSState *qs; +QPCIBar reg_bar, mem_bar; +uint64_t reg_barsize, mem_barsize; +QPCIDevice *dev; +} ERSTState; + +#define ACTION 0 +#define VALUE 8 + +static const char *reg2str(unsigned reg) +{ +switch (reg) { +case 0: +return "ACTION"; +case 8: +return "VALUE"; +default: +return NULL; +} +} + +static inline uint32_t in_reg32(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint32_t res; + +res = qpci_io_readl(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %08x", name, res); + +return res; +} + +static inline uint64_t in_reg64(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint64_t res; + +res = qpci_io_readq(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %016llx", name, (unsigned long long)res); + +return res; +} + +static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%08x -> *%s", v, name); +qpci_io_writel(s->dev, s->reg_bar, reg, v); +} + +static inline void out_reg64(ERSTState *s, unsigned reg, uint64_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%016llx -> *%s", (unsigned long long)v, name); +qpci_io_writeq(s->dev, s->reg_bar, reg, v); +} + +static void cleanup_vm(ERSTState *s) +{ +g_free(s->dev); +qtest_shutdown(s->qs); +} + +static void setup_vm_cmd(ERSTState *s, const char *cmd) +{ +const char *arch = qtest_get_arch(); + +if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { +s->qs = qtest_pc_boot(cmd); +} else { +g_printerr("erst-test tests are only available on x86\n"); +exit(EXIT_FAILURE); +} +s->dev = get_erst_device(s->qs->pcibus); + +s->reg_bar = qpci_iomap(s->dev, 0, >reg_barsize); +g_assert_cmpuint(s->reg_barsize, ==, 16); + +s->mem_bar = qpci_iomap(s->dev, 1, >mem_barsize); +g_assert_cmpuint(s->mem_barsize, ==, 0x2000); + +qpci_device_enable(s->dev); +} + +static void test_acpi_erst_basic(void) +{ +ERSTState state; +uint64_t log_address_range; +uint64_t log_address_length; +uint32_t log_address_attr; + +setup_vm_cmd(, +"-object memory-backend-file," +"mem-path=acpi-erst.XX," +"size=64K," +"share=on," +"id=nvram " +"-device acpi-erst," +"memdev=nvram"); + +out_reg32(, ACTION, 0xD); +log_address_range = in_reg64(, VALUE); +out_reg32(, ACTION, 0xE); +log_address_length = in_reg64(, VALUE); +out_reg32(, ACTION, 0xF); +log_address_attr = in_reg32(, VALUE); + +/* Check log_address_range is not 0, ~0 or base */ +g_assert_cmpuint(log_address_range, !=, 0ULL); +g_assert_cmpuint(log_address_range, !=, ~0ULL); +g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr); +g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr); + +/* Check log_address_length is bar1_size */ +g_assert_cmpuint(log_address_length, ==, state.mem_barsize); + +/* Check log_address_attr is 0 */ +g_assert_cmpuint(log_address_attr, ==, 0); + +cleanup_vm(); +} + +int main(int argc, char **argv) +{ +int ret; + +g_test_init(, , NULL); +qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
[PATCH v14 05/10] ACPI ERST: support for ACPI ERST feature
This implements a PCI device for ACPI ERST. This implements the non-NVRAM "mode" of operation for ERST as it is supported by Linux and Windows. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/acpi/Kconfig | 6 + hw/acpi/erst.c | 844 +++ hw/acpi/meson.build | 1 + hw/acpi/trace-events | 15 + 4 files changed, 866 insertions(+) create mode 100644 hw/acpi/erst.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 622b0b5..19caebd 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -10,6 +10,7 @@ config ACPI_X86 select ACPI_HMAT select ACPI_PIIX4 select ACPI_PCIHP +select ACPI_ERST config ACPI_X86_ICH bool @@ -60,3 +61,8 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_ERST +bool +default y +depends on ACPI && PCI diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c new file mode 100644 index 000..fe9ba51 --- /dev/null +++ b/hw/acpi/erst.c @@ -0,0 +1,844 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-core.h" +#include "exec/memory.h" +#include "qom/object.h" +#include "hw/pci/pci.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "exec/address-spaces.h" +#include "sysemu/hostmem.h" +#include "hw/acpi/erst.h" +#include "trace.h" + +/* ACPI 4.0: Table 17-16 Serialization Actions */ +#define ACTION_BEGIN_WRITE_OPERATION 0x0 +#define ACTION_BEGIN_READ_OPERATION 0x1 +#define ACTION_BEGIN_CLEAR_OPERATION 0x2 +#define ACTION_END_OPERATION 0x3 +#define ACTION_SET_RECORD_OFFSET 0x4 +#define ACTION_EXECUTE_OPERATION 0x5 +#define ACTION_CHECK_BUSY_STATUS 0x6 +#define ACTION_GET_COMMAND_STATUS0x7 +#define ACTION_GET_RECORD_IDENTIFIER 0x8 +#define ACTION_SET_RECORD_IDENTIFIER 0x9 +#define ACTION_GET_RECORD_COUNT 0xA +#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB +#define ACTION_RESERVED 0xC +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD +#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF +#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */ + +/* ACPI 4.0: Table 17-17 Command Status Definitions */ +#define STATUS_SUCCESS0x00 +#define STATUS_NOT_ENOUGH_SPACE 0x01 +#define STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define STATUS_FAILED 0x03 +#define STATUS_RECORD_STORE_EMPTY 0x04 +#define STATUS_RECORD_NOT_FOUND 0x05 + +/* UEFI 2.1: Appendix N Common Platform Error Record */ +#define UEFI_CPER_RECORD_MIN_SIZE 128U +#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U +#define UEFI_CPER_RECORD_ID_OFFSET 96U +#define IS_UEFI_CPER_RECORD(ptr) \ +(((ptr)[0] == 'C') && \ + ((ptr)[1] == 'P') && \ + ((ptr)[2] == 'E') && \ + ((ptr)[3] == 'R')) + +/* + * NOTE that when accessing CPER fields within a record, memcpy() + * is utilized to avoid a possible misaligned access on the host. + */ + +/* + * This implementation is an ACTION (cmd) and VALUE (data) + * interface consisting of just two 64-bit registers. + */ +#define ERST_REG_SIZE (16UL) +#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ +#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ + +/* + * ERST_RECORD_SIZE is the buffer size for exchanging ERST + * record contents. Thus, it defines the maximum record size. + * As this is mapped through a PCI BAR, it must be a power of + * two and larger than UEFI_CPER_RECORD_MIN_SIZE. + * The backing storage is divided into fixed size "slots", + * each ERST_RECORD_SIZE in length, and each "slot" + * storing a single record. No attempt at optimizing storage + * through compression, compaction, etc is attempted. + * NOTE that slot 0 is reserved for the backing storage header. + * Depending upon the size of the backing storage, additional + * slots will be part of the slot 0 header in order to account + * for a record_id for each available remaining slot. + */ +/* 8KiB records, not too small, not too big */ +#define ERST_RECORD_SIZE (8192UL) + +#define ACPI_ERST_MEMDEV_PROP "
[PATCH v14 06/10] ACPI ERST: build the ACPI ERST table
This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 225 + 1 file changed, 225 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..5d5a639 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,210 @@ typedef struct { /***/ /***/ +typedef struct { +GArray *table_data; +pcibus_t bar; +uint8_t instruction; +uint8_t flags; +uint8_t register_bit_width; +pcibus_t register_offset; +} BuildSerializationInstructionEntry; + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction( +BuildSerializationInstructionEntry *e, +uint8_t serialization_action, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(e->table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(e->table_data, e->instruction, 1); +/* Flags */ +build_append_int_noprefix(e->table_data, e->flags, 1); +/* Reserved */ +build_append_int_noprefix(e->table_data, 0, 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = e->register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(e->register_bit_width) - 2; +gas.address = (uint64_t)(e->bar + e->register_offset); +build_append_gas_from_struct(e->table_data, ); +/* Value */ +build_append_int_noprefix(e->table_data, value, 8); +/* Mask */ +mask = (1ULL << (e->register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(e->table_data, mask, 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +GArray *table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; +/* Contexts for the different ways ACTION and VALUE are accessed */ +BuildSerializationInstructionEntry rd_value_32_val = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER_VALUE, +.flags = 0, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry rd_value_32 = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER, +.flags = 0, +.register_bit_width = 32, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry rd_value_64 = { +.table_data = table_instruction_data, +.bar = bar0, +.instruction = INST_READ_REGISTER, +.flags = 0, +.register_bit_width = 64, +.register_offset = ERST_VALUE_OFFSET, +}; +BuildSerializationInstructionEntry wr_value_32_val = { +.table_data = table_instruction_data, +.bar = bar0, +
[PATCH v14 09/10] ACPI ERST: bios-tables-test testcase
This change implements the test suite checks for the ERST table. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/bios-tables-test.c | 54 ++ 1 file changed, 54 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index e6b72d9..266b215 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1446,6 +1446,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +static void test_acpi_erst(const char *machine) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +memset(, 0, sizeof(data)); +data.machine = machine; +data.variant = ".acpierst"; +params = g_strdup_printf( +" -object memory-backend-file,id=erstnvram," +"mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +free_test_data(); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +} + +static void test_acpi_piix4_acpi_erst(void) +{ +test_acpi_erst(MACHINE_PC); +} + +static void test_acpi_q35_acpi_erst(void) +{ +test_acpi_erst(MACHINE_Q35); +} + +static void test_acpi_microvm_acpi_erst(void) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +test_acpi_microvm_prepare(); +data.variant = ".pcie"; +data.tcg_only = true; /* need constant host-phys-bits */ +params = g_strdup_printf(" -machine microvm," +"acpi=on,ioapic2=off,rtc=off,pcie=on" +" -object memory-backend-file,id=erstnvram," + "mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +free_test_data(); +} + static void test_acpi_virt_tcg(void) { test_data data = { @@ -1675,6 +1726,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); +qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); +qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); @@ -1684,6 +1737,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); if (strcmp(arch, "x86_64") == 0) { qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg); +qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst); } } if (has_kvm) { -- 1.8.3.1
[PATCH v14 04/10] ACPI ERST: header file for ERST
This change introduces the public defintions for ACPI ERST. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- include/hw/acpi/erst.h | 19 +++ 1 file changed, 19 insertions(+) create mode 100644 include/hw/acpi/erst.h diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h new file mode 100644 index 000..9d63717 --- /dev/null +++ b/include/hw/acpi/erst.h @@ -0,0 +1,19 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_ACPI_ERST_H +#define HW_ACPI_ERST_H + +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id); + +#define TYPE_ACPI_ERST "acpi-erst" + +#endif -- 1.8.3.1
[PATCH v14 07/10] ACPI ERST: create ACPI ERST table for pc/x86 machines
This change exposes ACPI ERST support for x86 guests. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/i386/acpi-build.c | 15 +++ hw/i386/acpi-microvm.c | 15 +++ include/hw/acpi/erst.h | 5 + 3 files changed, 35 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ce823e8..ebd47aa 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -43,6 +43,7 @@ #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "hw/acpi/vmgenid.h" +#include "hw/acpi/erst.h" #include "sysemu/tpm_backend.h" #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" @@ -74,6 +75,8 @@ #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" +#include CONFIG_DEVICES + /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows * a little bit, there should be plenty of free space since the DSDT @@ -2575,6 +2578,18 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { acpi_add_table(table_offsets, tables_blob); diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 196d318..68ca7e7 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -30,6 +30,7 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" #include "hw/acpi/utils.h" +#include "hw/acpi/erst.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/microvm.h" #include "hw/pci/pci.h" @@ -40,6 +41,8 @@ #include "acpi-common.h" #include "acpi-microvm.h" +#include CONFIG_DEVICES + static void acpi_dsdt_add_virtio(Aml *scope, MicrovmMachineState *mms) { @@ -207,6 +210,18 @@ static void acpi_build_microvm(AcpiBuildTables *tables, ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id, x86ms->oem_table_id); diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h index 9d63717..b747fe7 100644 --- a/include/hw/acpi/erst.h +++ b/include/hw/acpi/erst.h @@ -16,4 +16,9 @@ void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, #define TYPE_ACPI_ERST "acpi-erst" +/* returns NULL unless there is exactly one device */ +static inline Object *find_erst_dev(void) +{ +return object_resolve_path_type("", TYPE_ACPI_ERST, NULL); +} #endif -- 1.8.3.1
[PATCH v14 02/10] ACPI ERST: specification for ERST support
Information on the implementation of the ACPI ERST support. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- docs/specs/acpi_erst.rst | 200 +++ 1 file changed, 200 insertions(+) create mode 100644 docs/specs/acpi_erst.rst diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 000..a8a9d22 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE + + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +--- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x1,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +-- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that identifies the contents +as ERST and also facilitates efficient access to the records. +Depending upon the size of the backend storage, additional slots will +be designated
[PATCH v14 01/10] ACPI ERST: bios-tables-test.c steps 1 and 2
Following the guidelines in tests/qtest/bios-tables-test.c, this change adds empty placeholder files per step 1 for the new ERST table, and excludes resulting changed files in bios-tables-test-allowed-diff.h per step 2. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov --- tests/data/acpi/microvm/ERST.pcie | 0 tests/data/acpi/pc/DSDT.acpierst| 0 tests/data/acpi/pc/ERST.acpierst| 0 tests/data/acpi/q35/DSDT.acpierst | 0 tests/data/acpi/q35/ERST.acpierst | 0 tests/qtest/bios-tables-test-allowed-diff.h | 5 + 6 files changed, 5 insertions(+) create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/ERST.acpierst b/tests/data/acpi/q35/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523..603db07 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/ERST.acpierst", +"tests/data/acpi/q35/DSDT.acpierst", +"tests/data/acpi/q35/ERST.acpierst", +"tests/data/acpi/microvm/ERST.pcie", -- 1.8.3.1
[PATCH v14 03/10] ACPI ERST: PCI device_id for ERST
This change reserves the PCI device_id for the new ACPI ERST device. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov Acked-by: Ani Sinha --- include/hw/pci/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 023abc0..c3f3c90 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -108,6 +108,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_REDHAT_MDPY0x000f #define PCI_DEVICE_ID_REDHAT_NVME0x0010 #define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 +#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012 #define PCI_DEVICE_ID_REDHAT_QXL 0x0100 #define FMT_PCIBUS PRIx64 -- 1.8.3.1
[PATCH v14 00/10] acpi: Error Record Serialization Table, ERST, support for QEMU
This patchset introduces support for the ACPI Error Record Serialization Table, ERST. For background and implementation information, please see docs/specs/acpi_erst.rst, which is patch 2/10. Suggested-by: Konrad Wilk Signed-off-by: Eric DeVolder --- v14: 26jan2022 - Changed build_erst() to utilize a context structure for generating accesses to ACTION and VALUE, per Michael Tsirkin. - Other simplification per Ani Sinha. v13: 24jan2022 - v12 erroneously omitted step 6 of bios-tables-test.c, this has step 6 included. - No other changes to v12. v12: 10jan2022 - Converted macros in build_erst() to uppert to follow coding style, as pointed out by Michael Tsirkin. - And few items to help further simplify build_erst(). v11: 15dec2021 - Simplified build_erst() via feedback from Michael Tsirkin - Addressed additional feedback from Ani Sinha v10: 9dec2021 - Addressed additional feedback from Ani Sinha v9: 2dec2021 - Addressed feedback from Ani Sinha v8: 15oct2021 - Added Kconfig option for ERST, per Ani Sinha - Fixed patch ordering, per Ani v7: 7oct2021 - style improvements, per Igor - use of endian accessors for storage header, per Igor - a number of optimizations and improvements, per Igor - updated spec for header, per Igor - updated spec for rst format, per Michael Tsirkin - updated spec for new record_size parameter Due to changes in the spec, I am not carrying the Acked-by from Ani Sinha. - changes for and testing of migration to systems with differing ERST_RECORD_SIZE v6: 5aug2021 - Fixed compile warning/error, per Michael Tsirkin - Fixed mingw32 build error, per Michael - Converted exchange buffer to MemoryBackend, per Igor - Migrated test to PCI, per Igor - Significantly reduced amount of copying, per Igor - Corrections/enhancements to acpi_erst.txt, per Igor - Many misc/other small items, per Igor v5: 30jun2021 - Create docs/specs/acpi_erst.txt, per Igor - Separate PCI BARs for registers and memory, per Igor - Convert debugging to use trace infrastructure, per Igor - Various other fixups, per Igor v4: 11jun2021 - Converted to a PCI device, per Igor. - Updated qtest. - Rearranged patches, per Igor. v3: 28may2021 - Converted to using a TYPE_MEMORY_BACKEND_FILE object rather than internal array with explicit file operations, per Igor. - Changed the way the qdev and base address are handled, allowing ERST to be disabled at run-time. Also aligns better with other existing code. v2: 8feb2021 - Added qtest/smoke test per Paolo Bonzini - Split patch into smaller chunks, per Igor Mammedov - Did away with use of ACPI packed structures, per Igor Mammedov v1: 26oct2020 - initial post --- Eric DeVolder (10): ACPI ERST: bios-tables-test.c steps 1 and 2 ACPI ERST: specification for ERST support ACPI ERST: PCI device_id for ERST ACPI ERST: header file for ERST ACPI ERST: support for ACPI ERST feature ACPI ERST: build the ACPI ERST table ACPI ERST: create ACPI ERST table for pc/x86 machines ACPI ERST: qtest for ERST ACPI ERST: bios-tables-test testcase ACPI ERST: step 6 of bios-tables-test.c docs/specs/acpi_erst.rst | 200 +++ hw/acpi/Kconfig |6 + hw/acpi/erst.c| 1069 + hw/acpi/meson.build |1 + hw/acpi/trace-events | 15 + hw/i386/acpi-build.c | 15 + hw/i386/acpi-microvm.c| 15 + include/hw/acpi/erst.h| 24 + include/hw/pci/pci.h |1 + tests/data/acpi/microvm/ERST.pcie | Bin 0 -> 912 bytes tests/data/acpi/pc/DSDT.acpierst | Bin 0 -> 5969 bytes tests/data/acpi/pc/ERST.acpierst | Bin 0 -> 912 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 0 -> 8306 bytes tests/data/acpi/q35/ERST.acpierst | Bin 0 -> 912 bytes tests/qtest/bios-tables-test.c| 54 ++ tests/qtest/erst-test.c | 172 ++ tests/qtest/meson.build |2 + 17 files changed, 1574 insertions(+) create mode 100644 docs/specs/acpi_erst.rst create mode 100644 hw/acpi/erst.c create mode 100644 include/hw/acpi/erst.h create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst create mode 100644 tests/qtest/erst-test.c -- 1.8.3.1
Re: [PATCH v13 06/10] ACPI ERST: build the ACPI ERST table
Ani, Michael, An inline response at the bottom. Thanks! eric On 1/26/22 01:05, Ani Sinha wrote: On Tue, 25 Jan 2022, Eric DeVolder wrote: Ani, Thanks for the feedback! Inline responses below. eric On 1/25/22 04:53, Ani Sinha wrote: + +action = ACTION_BEGIN_CLEAR_OPERATION; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTION_END_OPERATION; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTION_SET_RECORD_OFFSET; +BUILD_WRITE_REGISTER(32, ERST_VALUE_OFFSET, 0); +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTION_EXECUTE_OPERATION; +BUILD_WRITE_REGISTER_VALUE(32, ERST_VALUE_OFFSET, +ERST_EXECUTE_OPERATION_MAGIC); except here, on all cases we have BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); We should treat the above as special case and simplify the rest of the calls (eliminate repeated common arguments). OK, I created BUILD_WRITE_ACTION() to replace this occurrence. I've provided what this section of code looks like with this and the other below change at the end. I have seen the comment from Michael and you about using inline functions, I will respond to that in the other message. +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTION_CHECK_BUSY_STATUS; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER_VALUE(32, ERST_VALUE_OFFSET, 0x01); + +action = ACTION_GET_COMMAND_STATUS; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(32, ERST_VALUE_OFFSET); + +action = ACTION_GET_RECORD_IDENTIFIER; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(64, ERST_VALUE_OFFSET); + +action = ACTION_SET_RECORD_IDENTIFIER; +BUILD_WRITE_REGISTER(64, ERST_VALUE_OFFSET, 0); +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); This one seems reverted. Should this be BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); BUILD_WRITE_REGISTER(64, ERST_VALUE_OFFSET, 0); like others? This is a SET operation, so the data is provided in VALUE register, then the ACTION is written to perform the command, ie record the value. Ok I see. makes sense. + +action = ACTION_GET_RECORD_COUNT; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(32, ERST_VALUE_OFFSET); + +action = ACTION_BEGIN_DUMMY_WRITE_OPERATION; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(64, ERST_VALUE_OFFSET); + +action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(64, ERST_VALUE_OFFSET); + +action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(32, ERST_VALUE_OFFSET); + +action = ACTION_GET_EXECUTE_OPERATION_TIMINGS; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); +BUILD_READ_REGISTER(64, ERST_VALUE_OFFSET); + BUILD_READ_REGISTER() is always called with ERST_VALUE_OFFSET as second argument. WE should eliminate this repeated passing of same argument. The BUILD_READ_REGISTER is always against the VALUE register, as you point out, so I've s/BUILD_READ_REGISTER/BUILD_READ_VALUE/ and embedded the offset in the macro now. You can see this below. And here is what the main snippet looks like with the above changes (a diff is quite messy): /* * Macros for use with construction of the action instructions */ #define BUILD_READ_VALUE(width_in_bits) \ build_serialization_instruction_entry(table_instruction_data, \ action, INST_READ_REGISTER, 0, width_in_bits, \ bar0 + ERST_VALUE_OFFSET, 0) #define BUILD_READ_VALUE_VALUE(width_in_bits, value) \ build_serialization_instruction_entry(table_instruction_data, \ action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ bar0 + ERST_VALUE_OFFSET, value) #define BUILD_WRITE_REGISTER(width_in_bits, reg, value) \ build_serialization_instruction_entry(table_instruction_data, \ action, INST_WRITE_REGISTER, 0, width_in_bits, \ bar0 + reg, value) #define BUILD_WRITE_REGISTER_VALUE(width_in_bits, reg, value) \ build_serialization_instruction_entry(table_instruction_data, \ action, INST_WRITE_REGISTER_VALUE, 0, width_in_bits, \ bar0 + reg, value) #define BUILD_WRITE_ACTION() \ BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action) /* Serialization Instruction Entries */ action = ACTION_BEGIN_WRITE_OPERATION; BUILD_WRITE_ACTION(); action = ACTION_BEGIN_READ_OPERATION; BUILD_WRITE_ACTION(); action = ACTION_BEGIN_CLEAR_OPERATION
Re: [PATCH v13 06/10] ACPI ERST: build the ACPI ERST table
Hi Michael, Thanks for examining this! Inline response below. eric On 1/25/22 06:05, Michael S. Tsirkin wrote: On Tue, Jan 25, 2022 at 04:23:49PM +0530, Ani Sinha wrote: On Mon, 24 Jan 2022, Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 188 + 1 file changed, 188 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..b0c7539 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,173 @@ typedef struct { /***/ /***/ + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction_entry(GArray *table_data, +uint8_t serialization_action, +uint8_t instruction, +uint8_t flags, +uint8_t register_bit_width, +uint64_t register_address, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(table_data, instruction , 1); +/* Flags */ +build_append_int_noprefix(table_data, flags , 1); +/* Reserved */ +build_append_int_noprefix(table_data, 0 , 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(register_bit_width) - 2; +gas.address = register_address; +build_append_gas_from_struct(table_data, ); +/* Value */ +build_append_int_noprefix(table_data, value , 8); +/* Mask */ +mask = (1ULL << (register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(table_data, mask , 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +GArray *table_instruction_data; +unsigned action; +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; + +trace_acpi_erst_pci_bar_0(bar0); + +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); + +/* + * Macros for use with construction of the action instructions + */ +#define BUILD_READ_REGISTER(width_in_bits, reg) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER, 0, width_in_bits, \ +bar0 + reg, 0) + +#define BUILD_READ_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER_VALUE, 0, width_in_bits, \ +
Re: [PATCH v13 06/10] ACPI ERST: build the ACPI ERST table
Ani, Thanks for the feedback! Inline responses below. eric On 1/25/22 04:53, Ani Sinha wrote: On Mon, 24 Jan 2022, Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 188 + 1 file changed, 188 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..b0c7539 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,173 @@ typedef struct { /***/ /***/ + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction_entry(GArray *table_data, +uint8_t serialization_action, +uint8_t instruction, +uint8_t flags, +uint8_t register_bit_width, +uint64_t register_address, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(table_data, instruction , 1); +/* Flags */ +build_append_int_noprefix(table_data, flags , 1); +/* Reserved */ +build_append_int_noprefix(table_data, 0 , 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(register_bit_width) - 2; +gas.address = register_address; +build_append_gas_from_struct(table_data, ); +/* Value */ +build_append_int_noprefix(table_data, value , 8); +/* Mask */ +mask = (1ULL << (register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(table_data, mask , 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +GArray *table_instruction_data; +unsigned action; +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; + +trace_acpi_erst_pci_bar_0(bar0); + +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); + +/* + * Macros for use with construction of the action instructions + */ +#define BUILD_READ_REGISTER(width_in_bits, reg) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER, 0, width_in_bits, \ +bar0 + reg, 0) + +#define BUILD_READ_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +/* Serialization Instruction
[PATCH v13 05/10] ACPI ERST: support for ACPI ERST feature
This implements a PCI device for ACPI ERST. This implements the non-NVRAM "mode" of operation for ERST as it is supported by Linux and Windows. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/acpi/Kconfig | 6 + hw/acpi/erst.c | 844 +++ hw/acpi/meson.build | 1 + hw/acpi/trace-events | 15 + 4 files changed, 866 insertions(+) create mode 100644 hw/acpi/erst.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 622b0b5..19caebd 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -10,6 +10,7 @@ config ACPI_X86 select ACPI_HMAT select ACPI_PIIX4 select ACPI_PCIHP +select ACPI_ERST config ACPI_X86_ICH bool @@ -60,3 +61,8 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_ERST +bool +default y +depends on ACPI && PCI diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c new file mode 100644 index 000..fe9ba51 --- /dev/null +++ b/hw/acpi/erst.c @@ -0,0 +1,844 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-core.h" +#include "exec/memory.h" +#include "qom/object.h" +#include "hw/pci/pci.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "exec/address-spaces.h" +#include "sysemu/hostmem.h" +#include "hw/acpi/erst.h" +#include "trace.h" + +/* ACPI 4.0: Table 17-16 Serialization Actions */ +#define ACTION_BEGIN_WRITE_OPERATION 0x0 +#define ACTION_BEGIN_READ_OPERATION 0x1 +#define ACTION_BEGIN_CLEAR_OPERATION 0x2 +#define ACTION_END_OPERATION 0x3 +#define ACTION_SET_RECORD_OFFSET 0x4 +#define ACTION_EXECUTE_OPERATION 0x5 +#define ACTION_CHECK_BUSY_STATUS 0x6 +#define ACTION_GET_COMMAND_STATUS0x7 +#define ACTION_GET_RECORD_IDENTIFIER 0x8 +#define ACTION_SET_RECORD_IDENTIFIER 0x9 +#define ACTION_GET_RECORD_COUNT 0xA +#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB +#define ACTION_RESERVED 0xC +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD +#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF +#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */ + +/* ACPI 4.0: Table 17-17 Command Status Definitions */ +#define STATUS_SUCCESS0x00 +#define STATUS_NOT_ENOUGH_SPACE 0x01 +#define STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define STATUS_FAILED 0x03 +#define STATUS_RECORD_STORE_EMPTY 0x04 +#define STATUS_RECORD_NOT_FOUND 0x05 + +/* UEFI 2.1: Appendix N Common Platform Error Record */ +#define UEFI_CPER_RECORD_MIN_SIZE 128U +#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U +#define UEFI_CPER_RECORD_ID_OFFSET 96U +#define IS_UEFI_CPER_RECORD(ptr) \ +(((ptr)[0] == 'C') && \ + ((ptr)[1] == 'P') && \ + ((ptr)[2] == 'E') && \ + ((ptr)[3] == 'R')) + +/* + * NOTE that when accessing CPER fields within a record, memcpy() + * is utilized to avoid a possible misaligned access on the host. + */ + +/* + * This implementation is an ACTION (cmd) and VALUE (data) + * interface consisting of just two 64-bit registers. + */ +#define ERST_REG_SIZE (16UL) +#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ +#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ + +/* + * ERST_RECORD_SIZE is the buffer size for exchanging ERST + * record contents. Thus, it defines the maximum record size. + * As this is mapped through a PCI BAR, it must be a power of + * two and larger than UEFI_CPER_RECORD_MIN_SIZE. + * The backing storage is divided into fixed size "slots", + * each ERST_RECORD_SIZE in length, and each "slot" + * storing a single record. No attempt at optimizing storage + * through compression, compaction, etc is attempted. + * NOTE that slot 0 is reserved for the backing storage header. + * Depending upon the size of the backing storage, additional + * slots will be part of the slot 0 header in order to account + * for a record_id for each available remaining slot. + */ +/* 8KiB records, not too small, not too big */ +#define ERST_RECORD_SIZE (8192UL) + +#define ACPI_ERST_MEMDEV_PROP "
[PATCH v13 09/10] ACPI ERST: bios-tables-test testcase
This change implements the test suite checks for the ERST table. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/bios-tables-test.c | 54 ++ 1 file changed, 54 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index e6b72d9..266b215 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1446,6 +1446,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +static void test_acpi_erst(const char *machine) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +memset(, 0, sizeof(data)); +data.machine = machine; +data.variant = ".acpierst"; +params = g_strdup_printf( +" -object memory-backend-file,id=erstnvram," +"mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +free_test_data(); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +} + +static void test_acpi_piix4_acpi_erst(void) +{ +test_acpi_erst(MACHINE_PC); +} + +static void test_acpi_q35_acpi_erst(void) +{ +test_acpi_erst(MACHINE_Q35); +} + +static void test_acpi_microvm_acpi_erst(void) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +test_acpi_microvm_prepare(); +data.variant = ".pcie"; +data.tcg_only = true; /* need constant host-phys-bits */ +params = g_strdup_printf(" -machine microvm," +"acpi=on,ioapic2=off,rtc=off,pcie=on" +" -object memory-backend-file,id=erstnvram," + "mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +free_test_data(); +} + static void test_acpi_virt_tcg(void) { test_data data = { @@ -1675,6 +1726,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); +qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); +qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); @@ -1684,6 +1737,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); if (strcmp(arch, "x86_64") == 0) { qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg); +qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst); } } if (has_kvm) { -- 1.8.3.1
[PATCH v13 08/10] ACPI ERST: qtest for ERST
This change provides a qtest that locates and then does a simple interrogation of the ERST feature within the guest. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/erst-test.c | 172 tests/qtest/meson.build | 2 + 2 files changed, 174 insertions(+) create mode 100644 tests/qtest/erst-test.c diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c new file mode 100644 index 000..f9ad3c9 --- /dev/null +++ b/tests/qtest/erst-test.c @@ -0,0 +1,172 @@ +/* + * QTest testcase for acpi-erst + * + * Copyright (c) 2021 Oracle + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include +#include "libqos/libqos-pc.h" +#include "libqos/libqtest.h" +#include "qemu-common.h" + +#include "hw/pci/pci.h" + +static void save_fn(QPCIDevice *dev, int devfn, void *data) +{ +QPCIDevice **pdev = (QPCIDevice **) data; + +*pdev = dev; +} + +static QPCIDevice *get_erst_device(QPCIBus *pcibus) +{ +QPCIDevice *dev; + +dev = NULL; +qpci_device_foreach(pcibus, +PCI_VENDOR_ID_REDHAT, +PCI_DEVICE_ID_REDHAT_ACPI_ERST, +save_fn, ); +g_assert(dev != NULL); + +return dev; +} + +typedef struct _ERSTState { +QOSState *qs; +QPCIBar reg_bar, mem_bar; +uint64_t reg_barsize, mem_barsize; +QPCIDevice *dev; +} ERSTState; + +#define ACTION 0 +#define VALUE 8 + +static const char *reg2str(unsigned reg) +{ +switch (reg) { +case 0: +return "ACTION"; +case 8: +return "VALUE"; +default: +return NULL; +} +} + +static inline uint32_t in_reg32(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint32_t res; + +res = qpci_io_readl(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %08x", name, res); + +return res; +} + +static inline uint64_t in_reg64(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint64_t res; + +res = qpci_io_readq(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %016llx", name, (unsigned long long)res); + +return res; +} + +static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%08x -> *%s", v, name); +qpci_io_writel(s->dev, s->reg_bar, reg, v); +} + +static inline void out_reg64(ERSTState *s, unsigned reg, uint64_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%016llx -> *%s", (unsigned long long)v, name); +qpci_io_writeq(s->dev, s->reg_bar, reg, v); +} + +static void cleanup_vm(ERSTState *s) +{ +g_free(s->dev); +qtest_shutdown(s->qs); +} + +static void setup_vm_cmd(ERSTState *s, const char *cmd) +{ +const char *arch = qtest_get_arch(); + +if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { +s->qs = qtest_pc_boot(cmd); +} else { +g_printerr("erst-test tests are only available on x86\n"); +exit(EXIT_FAILURE); +} +s->dev = get_erst_device(s->qs->pcibus); + +s->reg_bar = qpci_iomap(s->dev, 0, >reg_barsize); +g_assert_cmpuint(s->reg_barsize, ==, 16); + +s->mem_bar = qpci_iomap(s->dev, 1, >mem_barsize); +g_assert_cmpuint(s->mem_barsize, ==, 0x2000); + +qpci_device_enable(s->dev); +} + +static void test_acpi_erst_basic(void) +{ +ERSTState state; +uint64_t log_address_range; +uint64_t log_address_length; +uint32_t log_address_attr; + +setup_vm_cmd(, +"-object memory-backend-file," +"mem-path=acpi-erst.XX," +"size=64K," +"share=on," +"id=nvram " +"-device acpi-erst," +"memdev=nvram"); + +out_reg32(, ACTION, 0xD); +log_address_range = in_reg64(, VALUE); +out_reg32(, ACTION, 0xE); +log_address_length = in_reg64(, VALUE); +out_reg32(, ACTION, 0xF); +log_address_attr = in_reg32(, VALUE); + +/* Check log_address_range is not 0, ~0 or base */ +g_assert_cmpuint(log_address_range, !=, 0ULL); +g_assert_cmpuint(log_address_range, !=, ~0ULL); +g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr); +g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr); + +/* Check log_address_length is bar1_size */ +g_assert_cmpuint(log_address_length, ==, state.mem_barsize); + +/* Check log_address_attr is 0 */ +g_assert_cmpuint(log_address_attr, ==, 0); + +cleanup_vm(); +} + +int main(int argc, char **argv) +{ +int ret; + +g_test_init(, , NULL); +qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
[PATCH v13 07/10] ACPI ERST: create ACPI ERST table for pc/x86 machines
This change exposes ACPI ERST support for x86 guests. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/i386/acpi-build.c | 15 +++ hw/i386/acpi-microvm.c | 15 +++ include/hw/acpi/erst.h | 5 + 3 files changed, 35 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ce823e8..ebd47aa 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -43,6 +43,7 @@ #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "hw/acpi/vmgenid.h" +#include "hw/acpi/erst.h" #include "sysemu/tpm_backend.h" #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" @@ -74,6 +75,8 @@ #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" +#include CONFIG_DEVICES + /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows * a little bit, there should be plenty of free space since the DSDT @@ -2575,6 +2578,18 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { acpi_add_table(table_offsets, tables_blob); diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 196d318..68ca7e7 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -30,6 +30,7 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" #include "hw/acpi/utils.h" +#include "hw/acpi/erst.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/microvm.h" #include "hw/pci/pci.h" @@ -40,6 +41,8 @@ #include "acpi-common.h" #include "acpi-microvm.h" +#include CONFIG_DEVICES + static void acpi_dsdt_add_virtio(Aml *scope, MicrovmMachineState *mms) { @@ -207,6 +210,18 @@ static void acpi_build_microvm(AcpiBuildTables *tables, ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id, x86ms->oem_table_id); diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h index 9d63717..b747fe7 100644 --- a/include/hw/acpi/erst.h +++ b/include/hw/acpi/erst.h @@ -16,4 +16,9 @@ void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, #define TYPE_ACPI_ERST "acpi-erst" +/* returns NULL unless there is exactly one device */ +static inline Object *find_erst_dev(void) +{ +return object_resolve_path_type("", TYPE_ACPI_ERST, NULL); +} #endif -- 1.8.3.1
[PATCH v13 01/10] ACPI ERST: bios-tables-test.c steps 1 and 2
Following the guidelines in tests/qtest/bios-tables-test.c, this change adds empty placeholder files per step 1 for the new ERST table, and excludes resulting changed files in bios-tables-test-allowed-diff.h per step 2. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov --- tests/data/acpi/microvm/ERST.pcie | 0 tests/data/acpi/pc/DSDT.acpierst| 0 tests/data/acpi/pc/ERST.acpierst| 0 tests/data/acpi/q35/DSDT.acpierst | 0 tests/data/acpi/q35/ERST.acpierst | 0 tests/qtest/bios-tables-test-allowed-diff.h | 5 + 6 files changed, 5 insertions(+) create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/ERST.acpierst b/tests/data/acpi/q35/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523..603db07 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/ERST.acpierst", +"tests/data/acpi/q35/DSDT.acpierst", +"tests/data/acpi/q35/ERST.acpierst", +"tests/data/acpi/microvm/ERST.pcie", -- 1.8.3.1
[PATCH v13 04/10] ACPI ERST: header file for ERST
This change introduces the public defintions for ACPI ERST. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- include/hw/acpi/erst.h | 19 +++ 1 file changed, 19 insertions(+) create mode 100644 include/hw/acpi/erst.h diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h new file mode 100644 index 000..9d63717 --- /dev/null +++ b/include/hw/acpi/erst.h @@ -0,0 +1,19 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_ACPI_ERST_H +#define HW_ACPI_ERST_H + +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id); + +#define TYPE_ACPI_ERST "acpi-erst" + +#endif -- 1.8.3.1
[PATCH v13 02/10] ACPI ERST: specification for ERST support
Information on the implementation of the ACPI ERST support. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- docs/specs/acpi_erst.rst | 200 +++ 1 file changed, 200 insertions(+) create mode 100644 docs/specs/acpi_erst.rst diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 000..a8a9d22 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE + + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +--- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x1,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +-- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that identifies the contents +as ERST and also facilitates efficient access to the records. +Depending upon the size of the backend storage, additional slots will +be designated
[PATCH v13 10/10] ACPI ERST: step 6 of bios-tables-test.c
} @@ -1399,11 +1394,6 @@ DefinitionBlock ("", "DSDT", 1, "BOCHS " Method (DVNT, 2, NotSerialized) { -If ((Arg0 & 0x08)) -{ -Notify (S18, Arg1) -} - If ((Arg0 & 0x10)) { Notify (S20, Arg1) diff q35/DSDT and q35/DSDT.acpierst: @@ -5,13 +5,13 @@ * * Disassembling to symbolic ASL+ operators * - * Disassembly of tests/data/acpi/q35/DSDT, Thu Dec 2 10:10:13 2021 + * Disassembly of tests/data/acpi/q35/DSDT.acpierst, Thu Dec 2 12:59:36 2021 * * Original Table Header: * Signature"DSDT" - * Length 0x2061 (8289) + * Length 0x2072 (8306) * Revision 0x01 32-bit table (V1), no 64-bit math support - * Checksum 0xFA + * Checksum 0x9A * OEM ID "BOCHS " * OEM Table ID "BXPC" * OEM Revision 0x0001 (1) @@ -3278,6 +3278,11 @@ DefinitionBlock ("", "DSDT", 1, "BOCHS " } } +Device (S10) +{ +Name (_ADR, 0x0002) // _ADR: Address +} + Method (PCNT, 0, NotSerialized) { } For both pc and q35, there is but a small difference between this DSDT.acpierst and the corresponding DSDT. In both cases, the changes occur under the hiearchy: Scope (\_SB) { Scope (PCI0) { which leads me to believe that the change to the DSDT was needed due to the introduction of the ERST PCI device. And is explained in detail by Ani Sinha: I have convinced myself of the changes we see in the DSDT tables. On i440fx side, we are adding a non-hotpluggable pci device on slot 3. So the changes we see are basically replacing an empty hotpluggable slot on the pci root port with a non-hotplugggable device. On q35, bsel on pcie root bus is not set (its not hotpluggable bus), so the change basically adds the address enumeration for the device. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- tests/data/acpi/microvm/ERST.pcie | Bin 0 -> 912 bytes tests/data/acpi/pc/DSDT.acpierst| Bin 0 -> 5969 bytes tests/data/acpi/pc/ERST.acpierst| Bin 0 -> 912 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 0 -> 8306 bytes tests/data/acpi/q35/ERST.acpierst | Bin 0 -> 912 bytes tests/qtest/bios-tables-test-allowed-diff.h | 5 - 6 files changed, 5 deletions(-) diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a6d0cb783831ebc18972ec57bb6c624438ff150d 100644 GIT binary patch literal 912 zcmaKoTMmLS5Jd;doACJehb6cK12OSWBYwCn7ocm^-rA|;CUz1YmosPDa=fm$hY?9$ z^LaU~(|o@yldVKV@Q+UZ@>zwpS)GZ(sO?Lc}v64j-jFC7yn9;D$INO8pFiUB7f+ zf49KN+;jDxe>nP4Iq`z#7tC?s!tc6i7Z+t!@(t>{e2`4% zZhiFB_p5lnFb*Ui&1$pT3_)pk?J?$-jLiezjJ$6`=r)uYry0Rn7KuJIp)|! zckaizM=~sYzU*-I~PkUtAn>Dr`~u=;o(_O$t$PK8~R}U#`{0u*{ zz`m8fl|Wu#ucTKJu-TjNQ`rN~%rBccG0yWwF_}_zQl+X71|-_g)Pr`x1*Xgb!>QealcAR5Lj8F@vR~_hFrfVBOumUtb3< zL8GI#8|W0leXv|!GGL=~vE5*uM7z%Af!czNXYqlQL#IT$!9xR0zORu68XY#=M-SGy z3b+$tZv(*Hu4BBt4F>MUo>Padde^ZZU%V_4TiQ&6ruaomTLcp<9-2bBZ=qyp40+ ziEQ&$6L)c>%cI)0;%@F~Or>jX}g)!VlmH>3A6L#ZGj;i8(jvxl3w$XL%gc z#4Y0Q*ces>sy7Obm6bTnr@oqih!n=P&+!w*9R95=2i+)QqA9kLa1VJk2ES zOh6C4;>puBt75SyO`ippr%I9Z{pk6j=(st4aP-WP=ov412KgP0p3z1}&)7R9%3U9d z!>df~G};j<@%&-TL`!{M=J{^0EAj)b4{!p{wbpF1J^oV~LmWA@f?c-apx zmJl5aIOP$4%5j~Id6TV0{V^u0sG`|bSAOB2V2gb1@Ki7>g+T~D<}I$cZmy;lKl#kP zxAm*k{f|HWWb1z8<4?h6y1Bg6FLiOw7Z@DC0gGYf$3^AUwgVosAOD1e9Hex!P-c3u zY%#r3y2G$SrRg@$K+^S+fmJX`o|0}AmQ(0%hN|GcJ*{Ry{RpZVR_9(>4G!#sMm9K*-Kb2oqvI?7dL24<1WVww+F6k zrAwi@3blP`ov2|RQA!4yn|HMt+|rp;ky|p}*s4Bhi{tS7b7IwWYtO z($_%y0DUt+12O0t{g!qm$i(>FX+UGsM;osE9mca!r!@5Ld6Jt2$-nabyyC?4*zT@l2 z4LgzF3U^-%E&8T*RhMxH{B|{Nmd$hyhrlm@q(4{QfcO=jBztZw|gWU^0Q+lFdc4 z;t%ATAUG5ws_1bncmXfi8SEC{UBmF!TrD{!GvtiVS87Q`#ts;JTa>Png~+QvKOAg( z=l%H)^?9Gb?Lui47fY7Bv8_MKSPiRTs@3YkU)Q{@YvnKAT;;J8U>fgQ>9qeF0+gJ! zS_V9pumOy9sSU)%^lS1X17`o1`MA>W^ePI^H@E*S%`|HOx^c$lLHVkhwcpCba771jDZ#SdZmhM`3K=q{% zNdudV5*`|Tn?lmSM!~R<_iYsI+Q3HPu(0YhlR~GImZVAKI~h z+O@D02|KpVC?DEYlCeYxd&-j!?Kerrtt;#;Pd>DJ8RM1`cI=OKE{vc{!8uv6Z~ u5j$m$OK@OMk$l8{6J=Z)1AB{Pv}@<7F~|QN>AydkHSF$IS^vS{(*FTuhT2R3 literal 0 HcmV?d1 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7965ac2562e7b23bf1dc2caaf00ef66453c4f47a 100644 GIT binary patch literal 912 zcmaKoOAdlC6h$9Upg{N}4xO+BmS7+z{Ww`+N;?C6GO0l^KeF>#Er>E`f@jBlg ziAb~?&(mq{$NOdKO+_MtIsSwBP(BS` zh6Ua)#A*M6_AiN-%#j24ugI^+uZh>pkpuT{$ZyEEIpDYCx8#=`Con^ B
[PATCH v13 03/10] ACPI ERST: PCI device_id for ERST
This change reserves the PCI device_id for the new ACPI ERST device. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov Acked-by: Ani Sinha --- include/hw/pci/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 023abc0..c3f3c90 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -108,6 +108,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_REDHAT_MDPY0x000f #define PCI_DEVICE_ID_REDHAT_NVME0x0010 #define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 +#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012 #define PCI_DEVICE_ID_REDHAT_QXL 0x0100 #define FMT_PCIBUS PRIx64 -- 1.8.3.1
[PATCH v13 00/10] acpi: Error Record Serialization Table, ERST, support for QEMU
This patchset introduces support for the ACPI Error Record Serialization Table, ERST. For background and implementation information, please see docs/specs/acpi_erst.rst, which is patch 2/10. Suggested-by: Konrad Wilk Signed-off-by: Eric DeVolder --- v13: 24jan2022 - v12 erroneously omitted step 6 of bios-tables-test.c, this has step 6 included. - No other changes to v12. v12: 10jan2022 - Converted macros in build_erst() to uppert to follow coding style, as pointed out by Michael Tsirkin. - And few items to help further simplify build_erst(). v11: 15dec2021 - Simplified build_erst() via feedback from Michael Tsirkin - Addressed additional feedback from Ani Sinha v10: 9dec2021 - Addressed additional feedback from Ani Sinha v9: 2dec2021 - Addressed feedback from Ani Sinha v8: 15oct2021 - Added Kconfig option for ERST, per Ani Sinha - Fixed patch ordering, per Ani v7: 7oct2021 - style improvements, per Igor - use of endian accessors for storage header, per Igor - a number of optimizations and improvements, per Igor - updated spec for header, per Igor - updated spec for rst format, per Michael Tsirkin - updated spec for new record_size parameter Due to changes in the spec, I am not carrying the Acked-by from Ani Sinha. - changes for and testing of migration to systems with differing ERST_RECORD_SIZE v6: 5aug2021 - Fixed compile warning/error, per Michael Tsirkin - Fixed mingw32 build error, per Michael - Converted exchange buffer to MemoryBackend, per Igor - Migrated test to PCI, per Igor - Significantly reduced amount of copying, per Igor - Corrections/enhancements to acpi_erst.txt, per Igor - Many misc/other small items, per Igor v5: 30jun2021 - Create docs/specs/acpi_erst.txt, per Igor - Separate PCI BARs for registers and memory, per Igor - Convert debugging to use trace infrastructure, per Igor - Various other fixups, per Igor v4: 11jun2021 - Converted to a PCI device, per Igor. - Updated qtest. - Rearranged patches, per Igor. v3: 28may2021 - Converted to using a TYPE_MEMORY_BACKEND_FILE object rather than internal array with explicit file operations, per Igor. - Changed the way the qdev and base address are handled, allowing ERST to be disabled at run-time. Also aligns better with other existing code. v2: 8feb2021 - Added qtest/smoke test per Paolo Bonzini - Split patch into smaller chunks, per Igor Mammedov - Did away with use of ACPI packed structures, per Igor Mammedov v1: 26oct2020 - initial post --- Eric DeVolder (10): ACPI ERST: bios-tables-test.c steps 1 and 2 ACPI ERST: specification for ERST support ACPI ERST: PCI device_id for ERST ACPI ERST: header file for ERST ACPI ERST: support for ACPI ERST feature ACPI ERST: build the ACPI ERST table ACPI ERST: create ACPI ERST table for pc/x86 machines ACPI ERST: qtest for ERST ACPI ERST: bios-tables-test testcase ACPI ERST: step 6 of bios-tables-test.c docs/specs/acpi_erst.rst | 200 +++ hw/acpi/Kconfig |6 + hw/acpi/erst.c| 1032 + hw/acpi/meson.build |1 + hw/acpi/trace-events | 15 + hw/i386/acpi-build.c | 15 + hw/i386/acpi-microvm.c| 15 + include/hw/acpi/erst.h| 24 + include/hw/pci/pci.h |1 + tests/data/acpi/microvm/ERST.pcie | Bin 0 -> 912 bytes tests/data/acpi/pc/DSDT.acpierst | Bin 0 -> 5969 bytes tests/data/acpi/pc/ERST.acpierst | Bin 0 -> 912 bytes tests/data/acpi/q35/DSDT.acpierst | Bin 0 -> 8306 bytes tests/data/acpi/q35/ERST.acpierst | Bin 0 -> 912 bytes tests/qtest/bios-tables-test.c| 54 ++ tests/qtest/erst-test.c | 172 +++ tests/qtest/meson.build |2 + 17 files changed, 1537 insertions(+) create mode 100644 docs/specs/acpi_erst.rst create mode 100644 hw/acpi/erst.c create mode 100644 include/hw/acpi/erst.h create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst create mode 100644 tests/qtest/erst-test.c -- 1.8.3.1
[PATCH v13 06/10] ACPI ERST: build the ACPI ERST table
This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 188 + 1 file changed, 188 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index fe9ba51..b0c7539 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,173 @@ typedef struct { /***/ /***/ + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction_entry(GArray *table_data, +uint8_t serialization_action, +uint8_t instruction, +uint8_t flags, +uint8_t register_bit_width, +uint64_t register_address, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(table_data, instruction , 1); +/* Flags */ +build_append_int_noprefix(table_data, flags , 1); +/* Reserved */ +build_append_int_noprefix(table_data, 0 , 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(register_bit_width) - 2; +gas.address = register_address; +build_append_gas_from_struct(table_data, ); +/* Value */ +build_append_int_noprefix(table_data, value , 8); +/* Mask */ +mask = (1ULL << (register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(table_data, mask , 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +GArray *table_instruction_data; +unsigned action; +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; + +trace_acpi_erst_pci_bar_0(bar0); + +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); + +/* + * Macros for use with construction of the action instructions + */ +#define BUILD_READ_REGISTER(width_in_bits, reg) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER, 0, width_in_bits, \ +bar0 + reg, 0) + +#define BUILD_READ_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +/* Serialization Instruction Entries */ +action = ACTION_BEGIN_WRITE_OPERATION; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTIO
Re: [PATCH v9 05/10] ACPI ERST: support for ACPI ERST feature
Ani, I'll change this from the g_assert_not_reached() back to STATUS_FAILED. Alas I realized I didn't do the last step in producing the new ACPI tables in the patchset, so even though I just put out v12, I'll need to do a followup v13 with the missing tables. Thanks! eric On 1/11/22 02:35, Ani Sinha wrote: On Tue, Dec 14, 2021 at 2:33 AM Eric DeVolder wrote: Ani, an inline response below. Thanks! eric On 12/10/21 08:09, Ani Sinha wrote: On Thu, Dec 9, 2021 at 11:24 PM Eric DeVolder wrote: Ani, inline responses below. eric On 12/9/21 00:29, Ani Sinha wrote: On Fri, Dec 3, 2021 at 12:39 AM Eric DeVolder wrote: This implements a PCI device for ACPI ERST. This implements the non-NVRAM "mode" of operation for ERST as it is supported by Linux and Windows. Few more comments on this patch ... Signed-off-by: Eric DeVolder --- hw/acpi/Kconfig | 6 + hw/acpi/erst.c | 836 +++ hw/acpi/meson.build | 1 + hw/acpi/trace-events | 15 + 4 files changed, 858 insertions(+) create mode 100644 hw/acpi/erst.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 622b0b5..19caebd 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -10,6 +10,7 @@ config ACPI_X86 select ACPI_HMAT select ACPI_PIIX4 select ACPI_PCIHP +select ACPI_ERST config ACPI_X86_ICH bool @@ -60,3 +61,8 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_ERST +bool +default y +depends on ACPI && PCI diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c new file mode 100644 index 000..4304f55 --- /dev/null +++ b/hw/acpi/erst.c @@ -0,0 +1,836 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-core.h" +#include "exec/memory.h" +#include "qom/object.h" +#include "hw/pci/pci.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "exec/address-spaces.h" +#include "sysemu/hostmem.h" +#include "hw/acpi/erst.h" +#include "trace.h" + +/* ACPI 4.0: Table 17-16 Serialization Actions */ +#define ACTION_BEGIN_WRITE_OPERATION 0x0 +#define ACTION_BEGIN_READ_OPERATION 0x1 +#define ACTION_BEGIN_CLEAR_OPERATION 0x2 +#define ACTION_END_OPERATION 0x3 +#define ACTION_SET_RECORD_OFFSET 0x4 +#define ACTION_EXECUTE_OPERATION 0x5 +#define ACTION_CHECK_BUSY_STATUS 0x6 +#define ACTION_GET_COMMAND_STATUS0x7 +#define ACTION_GET_RECORD_IDENTIFIER 0x8 +#define ACTION_SET_RECORD_IDENTIFIER 0x9 +#define ACTION_GET_RECORD_COUNT 0xA +#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB +#define ACTION_RESERVED 0xC +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD +#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF +#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 + +/* ACPI 4.0: Table 17-17 Command Status Definitions */ +#define STATUS_SUCCESS0x00 +#define STATUS_NOT_ENOUGH_SPACE 0x01 +#define STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define STATUS_FAILED 0x03 +#define STATUS_RECORD_STORE_EMPTY 0x04 +#define STATUS_RECORD_NOT_FOUND 0x05 + + +/* UEFI 2.1: Appendix N Common Platform Error Record */ +#define UEFI_CPER_RECORD_MIN_SIZE 128U +#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U +#define UEFI_CPER_RECORD_ID_OFFSET 96U +#define IS_UEFI_CPER_RECORD(ptr) \ +(((ptr)[0] == 'C') && \ + ((ptr)[1] == 'P') && \ + ((ptr)[2] == 'E') && \ + ((ptr)[3] == 'R')) + +/* + * NOTE that when accessing CPER fields within a record, memcpy() + * is utilized to avoid a possible misaligned access on the host. + */ + +/* + * This implementation is an ACTION (cmd) and VALUE (data) + * interface consisting of just two 64-bit registers. + */ +#define ERST_REG_SIZE (16UL) +#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ +#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ + +/* + * ERST_RECORD_SIZE is the buffer size for exchanging ERST + * record contents. Thus, it defines the maximum record size. + * As this is mapped through a PCI BAR, it must be a powe
Re: [PATCH v11 06/10] ACPI ERST: build the ACPI ERST table
Thanks for looking at this Michael, I've an inline response below. eric On 1/6/22 04:45, Michael S. Tsirkin wrote: On Wed, Dec 15, 2021 at 10:38:11AM -0500, Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 188 + 1 file changed, 188 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index bb6cad4..05177b3 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,173 @@ typedef struct { /***/ /***/ + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction_entry(GArray *table_data, +uint8_t serialization_action, +uint8_t instruction, +uint8_t flags, +uint8_t register_bit_width, +uint64_t register_address, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(table_data, instruction , 1); +/* Flags */ +build_append_int_noprefix(table_data, flags , 1); +/* Reserved */ +build_append_int_noprefix(table_data, 0 , 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(register_bit_width) - 2; +gas.address = register_address; +build_append_gas_from_struct(table_data, ); +/* Value */ +build_append_int_noprefix(table_data, value , 8); +/* Mask */ +mask = (1ULL << (register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(table_data, mask , 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +GArray *table_instruction_data; +unsigned action; +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; + +trace_acpi_erst_pci_bar_0(bar0); + +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); + +/* + * Macros for use with construction of the action instructions + */ +#define build_read_register(action, width_in_bits, reg) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER, 0, width_in_bits, \ +bar0 + reg, 0) + +#define build_read_register_value(action, width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +#define build_write_register(action, width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER, 0, width_in_bits, \ +bar0 + reg, value) + +#define build_write_register_value(action, width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER_VALUE, 0, width_in_bits, \ +
[PATCH v12 6/9] ACPI ERST: build the ACPI ERST table
This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 188 + 1 file changed, 188 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index bb6cad4..00dbd8be 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,173 @@ typedef struct { /***/ /***/ + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction_entry(GArray *table_data, +uint8_t serialization_action, +uint8_t instruction, +uint8_t flags, +uint8_t register_bit_width, +uint64_t register_address, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(table_data, instruction , 1); +/* Flags */ +build_append_int_noprefix(table_data, flags , 1); +/* Reserved */ +build_append_int_noprefix(table_data, 0 , 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(register_bit_width) - 2; +gas.address = register_address; +build_append_gas_from_struct(table_data, ); +/* Value */ +build_append_int_noprefix(table_data, value , 8); +/* Mask */ +mask = (1ULL << (register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(table_data, mask , 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +GArray *table_instruction_data; +unsigned action; +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; + +trace_acpi_erst_pci_bar_0(bar0); + +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); + +/* + * Macros for use with construction of the action instructions + */ +#define BUILD_READ_REGISTER(width_in_bits, reg) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER, 0, width_in_bits, \ +bar0 + reg, 0) + +#define BUILD_READ_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER, 0, width_in_bits, \ +bar0 + reg, value) + +#define BUILD_WRITE_REGISTER_VALUE(width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +/* Serialization Instruction Entries */ +action = ACTION_BEGIN_WRITE_OPERATION; +BUILD_WRITE_REGISTER_VALUE(32, ERST_ACTION_OFFSET, action); + +action = ACTIO
[PATCH v12 5/9] ACPI ERST: support for ACPI ERST feature
This implements a PCI device for ACPI ERST. This implements the non-NVRAM "mode" of operation for ERST as it is supported by Linux and Windows. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/acpi/Kconfig | 6 + hw/acpi/erst.c | 845 +++ hw/acpi/meson.build | 1 + hw/acpi/trace-events | 15 + 4 files changed, 867 insertions(+) create mode 100644 hw/acpi/erst.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 622b0b5..19caebd 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -10,6 +10,7 @@ config ACPI_X86 select ACPI_HMAT select ACPI_PIIX4 select ACPI_PCIHP +select ACPI_ERST config ACPI_X86_ICH bool @@ -60,3 +61,8 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_ERST +bool +default y +depends on ACPI && PCI diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c new file mode 100644 index 000..bb6cad4 --- /dev/null +++ b/hw/acpi/erst.c @@ -0,0 +1,845 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-core.h" +#include "exec/memory.h" +#include "qom/object.h" +#include "hw/pci/pci.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "exec/address-spaces.h" +#include "sysemu/hostmem.h" +#include "hw/acpi/erst.h" +#include "trace.h" + +/* ACPI 4.0: Table 17-16 Serialization Actions */ +#define ACTION_BEGIN_WRITE_OPERATION 0x0 +#define ACTION_BEGIN_READ_OPERATION 0x1 +#define ACTION_BEGIN_CLEAR_OPERATION 0x2 +#define ACTION_END_OPERATION 0x3 +#define ACTION_SET_RECORD_OFFSET 0x4 +#define ACTION_EXECUTE_OPERATION 0x5 +#define ACTION_CHECK_BUSY_STATUS 0x6 +#define ACTION_GET_COMMAND_STATUS0x7 +#define ACTION_GET_RECORD_IDENTIFIER 0x8 +#define ACTION_SET_RECORD_IDENTIFIER 0x9 +#define ACTION_GET_RECORD_COUNT 0xA +#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB +#define ACTION_RESERVED 0xC +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD +#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF +#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */ + +/* ACPI 4.0: Table 17-17 Command Status Definitions */ +#define STATUS_SUCCESS0x00 +#define STATUS_NOT_ENOUGH_SPACE 0x01 +#define STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define STATUS_FAILED 0x03 +#define STATUS_RECORD_STORE_EMPTY 0x04 +#define STATUS_RECORD_NOT_FOUND 0x05 + +/* UEFI 2.1: Appendix N Common Platform Error Record */ +#define UEFI_CPER_RECORD_MIN_SIZE 128U +#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U +#define UEFI_CPER_RECORD_ID_OFFSET 96U +#define IS_UEFI_CPER_RECORD(ptr) \ +(((ptr)[0] == 'C') && \ + ((ptr)[1] == 'P') && \ + ((ptr)[2] == 'E') && \ + ((ptr)[3] == 'R')) + +/* + * NOTE that when accessing CPER fields within a record, memcpy() + * is utilized to avoid a possible misaligned access on the host. + */ + +/* + * This implementation is an ACTION (cmd) and VALUE (data) + * interface consisting of just two 64-bit registers. + */ +#define ERST_REG_SIZE (16UL) +#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ +#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ + +/* + * ERST_RECORD_SIZE is the buffer size for exchanging ERST + * record contents. Thus, it defines the maximum record size. + * As this is mapped through a PCI BAR, it must be a power of + * two and larger than UEFI_CPER_RECORD_MIN_SIZE. + * The backing storage is divided into fixed size "slots", + * each ERST_RECORD_SIZE in length, and each "slot" + * storing a single record. No attempt at optimizing storage + * through compression, compaction, etc is attempted. + * NOTE that slot 0 is reserved for the backing storage header. + * Depending upon the size of the backing storage, additional + * slots will be part of the slot 0 header in order to account + * for a record_id for each available remaining slot. + */ +/* 8KiB records, not too small, not too big */ +#define ERST_RECORD_SIZE (8192UL) + +#define ACPI_ERST_MEMDEV_PROP "
[PATCH v12 4/9] ACPI ERST: header file for ERST
This change introduces the public defintions for ACPI ERST. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- include/hw/acpi/erst.h | 19 +++ 1 file changed, 19 insertions(+) create mode 100644 include/hw/acpi/erst.h diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h new file mode 100644 index 000..9d63717 --- /dev/null +++ b/include/hw/acpi/erst.h @@ -0,0 +1,19 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_ACPI_ERST_H +#define HW_ACPI_ERST_H + +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id); + +#define TYPE_ACPI_ERST "acpi-erst" + +#endif -- 1.8.3.1
[PATCH v12 9/9] ACPI ERST: bios-tables-test testcase
This change implements the test suite checks for the ERST table. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/bios-tables-test.c | 54 ++ 1 file changed, 54 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index e6b72d9..266b215 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1446,6 +1446,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +static void test_acpi_erst(const char *machine) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +memset(, 0, sizeof(data)); +data.machine = machine; +data.variant = ".acpierst"; +params = g_strdup_printf( +" -object memory-backend-file,id=erstnvram," +"mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +free_test_data(); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +} + +static void test_acpi_piix4_acpi_erst(void) +{ +test_acpi_erst(MACHINE_PC); +} + +static void test_acpi_q35_acpi_erst(void) +{ +test_acpi_erst(MACHINE_Q35); +} + +static void test_acpi_microvm_acpi_erst(void) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +test_acpi_microvm_prepare(); +data.variant = ".pcie"; +data.tcg_only = true; /* need constant host-phys-bits */ +params = g_strdup_printf(" -machine microvm," +"acpi=on,ioapic2=off,rtc=off,pcie=on" +" -object memory-backend-file,id=erstnvram," + "mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +free_test_data(); +} + static void test_acpi_virt_tcg(void) { test_data data = { @@ -1675,6 +1726,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); +qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); +qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); @@ -1684,6 +1737,7 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); if (strcmp(arch, "x86_64") == 0) { qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg); +qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst); } } if (has_kvm) { -- 1.8.3.1
[PATCH v12 1/9] ACPI ERST: bios-tables-test.c steps 1 and 2
Following the guidelines in tests/qtest/bios-tables-test.c, this change adds empty placeholder files per step 1 for the new ERST table, and excludes resulting changed files in bios-tables-test-allowed-diff.h per step 2. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov --- tests/data/acpi/microvm/ERST.pcie | 0 tests/data/acpi/pc/DSDT.acpierst| 0 tests/data/acpi/pc/ERST.acpierst| 0 tests/data/acpi/q35/DSDT.acpierst | 0 tests/data/acpi/q35/ERST.acpierst | 0 tests/qtest/bios-tables-test-allowed-diff.h | 5 + 6 files changed, 5 insertions(+) create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/ERST.acpierst b/tests/data/acpi/q35/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523..603db07 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/ERST.acpierst", +"tests/data/acpi/q35/DSDT.acpierst", +"tests/data/acpi/q35/ERST.acpierst", +"tests/data/acpi/microvm/ERST.pcie", -- 1.8.3.1
[PATCH v12 7/9] ACPI ERST: create ACPI ERST table for pc/x86 machines
This change exposes ACPI ERST support for x86 guests. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/i386/acpi-build.c | 15 +++ hw/i386/acpi-microvm.c | 15 +++ include/hw/acpi/erst.h | 5 + 3 files changed, 35 insertions(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index ce823e8..ebd47aa 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -43,6 +43,7 @@ #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "hw/acpi/vmgenid.h" +#include "hw/acpi/erst.h" #include "sysemu/tpm_backend.h" #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" @@ -74,6 +75,8 @@ #include "hw/acpi/hmat.h" #include "hw/acpi/viot.h" +#include CONFIG_DEVICES + /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows * a little bit, there should be plenty of free space since the DSDT @@ -2575,6 +2578,18 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + vmgenid_dev = find_vmgenid_dev(); if (vmgenid_dev) { acpi_add_table(table_offsets, tables_blob); diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 196d318..68ca7e7 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -30,6 +30,7 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" #include "hw/acpi/utils.h" +#include "hw/acpi/erst.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/microvm.h" #include "hw/pci/pci.h" @@ -40,6 +41,8 @@ #include "acpi-common.h" #include "acpi-microvm.h" +#include CONFIG_DEVICES + static void acpi_dsdt_add_virtio(Aml *scope, MicrovmMachineState *mms) { @@ -207,6 +210,18 @@ static void acpi_build_microvm(AcpiBuildTables *tables, ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, x86ms->oem_table_id); +#ifdef CONFIG_ACPI_ERST +{ +Object *erst_dev; +erst_dev = find_erst_dev(); +if (erst_dev) { +acpi_add_table(table_offsets, tables_blob); +build_erst(tables_blob, tables->linker, erst_dev, + x86ms->oem_id, x86ms->oem_table_id); +} +} +#endif + xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id, x86ms->oem_table_id); diff --git a/include/hw/acpi/erst.h b/include/hw/acpi/erst.h index 9d63717..b747fe7 100644 --- a/include/hw/acpi/erst.h +++ b/include/hw/acpi/erst.h @@ -16,4 +16,9 @@ void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, #define TYPE_ACPI_ERST "acpi-erst" +/* returns NULL unless there is exactly one device */ +static inline Object *find_erst_dev(void) +{ +return object_resolve_path_type("", TYPE_ACPI_ERST, NULL); +} #endif -- 1.8.3.1
[PATCH v12 8/9] ACPI ERST: qtest for ERST
This change provides a qtest that locates and then does a simple interrogation of the ERST feature within the guest. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/erst-test.c | 172 tests/qtest/meson.build | 2 + 2 files changed, 174 insertions(+) create mode 100644 tests/qtest/erst-test.c diff --git a/tests/qtest/erst-test.c b/tests/qtest/erst-test.c new file mode 100644 index 000..f9ad3c9 --- /dev/null +++ b/tests/qtest/erst-test.c @@ -0,0 +1,172 @@ +/* + * QTest testcase for acpi-erst + * + * Copyright (c) 2021 Oracle + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include +#include "libqos/libqos-pc.h" +#include "libqos/libqtest.h" +#include "qemu-common.h" + +#include "hw/pci/pci.h" + +static void save_fn(QPCIDevice *dev, int devfn, void *data) +{ +QPCIDevice **pdev = (QPCIDevice **) data; + +*pdev = dev; +} + +static QPCIDevice *get_erst_device(QPCIBus *pcibus) +{ +QPCIDevice *dev; + +dev = NULL; +qpci_device_foreach(pcibus, +PCI_VENDOR_ID_REDHAT, +PCI_DEVICE_ID_REDHAT_ACPI_ERST, +save_fn, ); +g_assert(dev != NULL); + +return dev; +} + +typedef struct _ERSTState { +QOSState *qs; +QPCIBar reg_bar, mem_bar; +uint64_t reg_barsize, mem_barsize; +QPCIDevice *dev; +} ERSTState; + +#define ACTION 0 +#define VALUE 8 + +static const char *reg2str(unsigned reg) +{ +switch (reg) { +case 0: +return "ACTION"; +case 8: +return "VALUE"; +default: +return NULL; +} +} + +static inline uint32_t in_reg32(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint32_t res; + +res = qpci_io_readl(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %08x", name, res); + +return res; +} + +static inline uint64_t in_reg64(ERSTState *s, unsigned reg) +{ +const char *name = reg2str(reg); +uint64_t res; + +res = qpci_io_readq(s->dev, s->reg_bar, reg); +g_test_message("*%s -> %016llx", name, (unsigned long long)res); + +return res; +} + +static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%08x -> *%s", v, name); +qpci_io_writel(s->dev, s->reg_bar, reg, v); +} + +static inline void out_reg64(ERSTState *s, unsigned reg, uint64_t v) +{ +const char *name = reg2str(reg); + +g_test_message("%016llx -> *%s", (unsigned long long)v, name); +qpci_io_writeq(s->dev, s->reg_bar, reg, v); +} + +static void cleanup_vm(ERSTState *s) +{ +g_free(s->dev); +qtest_shutdown(s->qs); +} + +static void setup_vm_cmd(ERSTState *s, const char *cmd) +{ +const char *arch = qtest_get_arch(); + +if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { +s->qs = qtest_pc_boot(cmd); +} else { +g_printerr("erst-test tests are only available on x86\n"); +exit(EXIT_FAILURE); +} +s->dev = get_erst_device(s->qs->pcibus); + +s->reg_bar = qpci_iomap(s->dev, 0, >reg_barsize); +g_assert_cmpuint(s->reg_barsize, ==, 16); + +s->mem_bar = qpci_iomap(s->dev, 1, >mem_barsize); +g_assert_cmpuint(s->mem_barsize, ==, 0x2000); + +qpci_device_enable(s->dev); +} + +static void test_acpi_erst_basic(void) +{ +ERSTState state; +uint64_t log_address_range; +uint64_t log_address_length; +uint32_t log_address_attr; + +setup_vm_cmd(, +"-object memory-backend-file," +"mem-path=acpi-erst.XX," +"size=64K," +"share=on," +"id=nvram " +"-device acpi-erst," +"memdev=nvram"); + +out_reg32(, ACTION, 0xD); +log_address_range = in_reg64(, VALUE); +out_reg32(, ACTION, 0xE); +log_address_length = in_reg64(, VALUE); +out_reg32(, ACTION, 0xF); +log_address_attr = in_reg32(, VALUE); + +/* Check log_address_range is not 0, ~0 or base */ +g_assert_cmpuint(log_address_range, !=, 0ULL); +g_assert_cmpuint(log_address_range, !=, ~0ULL); +g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr); +g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr); + +/* Check log_address_length is bar1_size */ +g_assert_cmpuint(log_address_length, ==, state.mem_barsize); + +/* Check log_address_attr is 0 */ +g_assert_cmpuint(log_address_attr, ==, 0); + +cleanup_vm(); +} + +int main(int argc, char **argv) +{ +int ret; + +g_test_init(, , NULL); +qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
[PATCH v12 3/9] ACPI ERST: PCI device_id for ERST
This change reserves the PCI device_id for the new ACPI ERST device. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov Acked-by: Ani Sinha --- include/hw/pci/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 483d5c7..19db80e 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -108,6 +108,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_REDHAT_MDPY0x000f #define PCI_DEVICE_ID_REDHAT_NVME0x0010 #define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 +#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012 #define PCI_DEVICE_ID_REDHAT_QXL 0x0100 #define FMT_PCIBUS PRIx64 -- 1.8.3.1
[PATCH v12 0/9] acpi: Error Record Serialization Table, ERST, support for QEMU
This patchset introduces support for the ACPI Error Record Serialization Table, ERST. For background and implementation information, please see docs/specs/acpi_erst.rst, which is patch 2/10. Suggested-by: Konrad Wilk Signed-off-by: Eric DeVolder --- v12: 10jan2022 - Converted macros in build_erst() to uppert to follow coding style, as pointed out by Michael Tsirkin. - And few items to help further simplify build_erst(). v11: 15dec2021 - Simplified build_erst() via feedback from Michael Tsirkin - Addressed additional feedback from Ani Sinha v10: 9dec2021 - Addressed additional feedback from Ani Sinha v9: 2dec2021 - Addressed feedback from Ani Sinha v8: 15oct2021 - Added Kconfig option for ERST, per Ani Sinha - Fixed patch ordering, per Ani v7: 7oct2021 - style improvements, per Igor - use of endian accessors for storage header, per Igor - a number of optimizations and improvements, per Igor - updated spec for header, per Igor - updated spec for rst format, per Michael Tsirkin - updated spec for new record_size parameter Due to changes in the spec, I am not carrying the Acked-by from Ani Sinha. - changes for and testing of migration to systems with differing ERST_RECORD_SIZE v6: 5aug2021 - Fixed compile warning/error, per Michael Tsirkin - Fixed mingw32 build error, per Michael - Converted exchange buffer to MemoryBackend, per Igor - Migrated test to PCI, per Igor - Significantly reduced amount of copying, per Igor - Corrections/enhancements to acpi_erst.txt, per Igor - Many misc/other small items, per Igor v5: 30jun2021 - Create docs/specs/acpi_erst.txt, per Igor - Separate PCI BARs for registers and memory, per Igor - Convert debugging to use trace infrastructure, per Igor - Various other fixups, per Igor v4: 11jun2021 - Converted to a PCI device, per Igor. - Updated qtest. - Rearranged patches, per Igor. v3: 28may2021 - Converted to using a TYPE_MEMORY_BACKEND_FILE object rather than internal array with explicit file operations, per Igor. - Changed the way the qdev and base address are handled, allowing ERST to be disabled at run-time. Also aligns better with other existing code. v2: 8feb2021 - Added qtest/smoke test per Paolo Bonzini - Split patch into smaller chunks, per Igor Mammedov - Did away with use of ACPI packed structures, per Igor Mammedov v1: 26oct2020 - initial post --- Eric DeVolder (9): ACPI ERST: bios-tables-test.c steps 1 and 2 ACPI ERST: specification for ERST support ACPI ERST: PCI device_id for ERST ACPI ERST: header file for ERST ACPI ERST: support for ACPI ERST feature ACPI ERST: build the ACPI ERST table ACPI ERST: create ACPI ERST table for pc/x86 machines ACPI ERST: qtest for ERST ACPI ERST: bios-tables-test testcase docs/specs/acpi_erst.rst| 200 ++ hw/acpi/Kconfig |6 + hw/acpi/erst.c | 1033 +++ hw/acpi/meson.build |1 + hw/acpi/trace-events| 15 + hw/i386/acpi-build.c| 15 + hw/i386/acpi-microvm.c | 15 + include/hw/acpi/erst.h | 24 + include/hw/pci/pci.h|1 + tests/data/acpi/microvm/ERST.pcie |0 tests/data/acpi/pc/DSDT.acpierst|0 tests/data/acpi/pc/ERST.acpierst|0 tests/data/acpi/q35/DSDT.acpierst |0 tests/data/acpi/q35/ERST.acpierst |0 tests/qtest/bios-tables-test-allowed-diff.h |5 + tests/qtest/bios-tables-test.c | 54 ++ tests/qtest/erst-test.c | 172 + tests/qtest/meson.build |2 + 18 files changed, 1543 insertions(+) create mode 100644 docs/specs/acpi_erst.rst create mode 100644 hw/acpi/erst.c create mode 100644 include/hw/acpi/erst.h create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst create mode 100644 tests/qtest/erst-test.c -- 1.8.3.1
[PATCH v12 2/9] ACPI ERST: specification for ERST support
Information on the implementation of the ACPI ERST support. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- docs/specs/acpi_erst.rst | 200 +++ 1 file changed, 200 insertions(+) create mode 100644 docs/specs/acpi_erst.rst diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 000..a8a9d22 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE + + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +--- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x1,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +-- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that identifies the contents +as ERST and also facilitates efficient access to the records. +Depending upon the size of the backend storage, additional slots will +be designated
Re: [PATCH v11 06/10] ACPI ERST: build the ACPI ERST table
Hi Ani, Thanks for such quick feedback! One inline response below. eric On 12/15/21 10:33, Ani Sinha wrote: On Wed, Dec 15, 2021 at 9:08 PM Eric DeVolder wrote: This builds the ACPI ERST table to inform OSPM how to communicate with the acpi-erst device. Signed-off-by: Eric DeVolder --- hw/acpi/erst.c | 188 + 1 file changed, 188 insertions(+) diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index bb6cad4..05177b3 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -59,6 +59,27 @@ #define STATUS_RECORD_STORE_EMPTY 0x04 #define STATUS_RECORD_NOT_FOUND 0x05 +/* ACPI 4.0: Table 17-19 Serialization Instructions */ +#define INST_READ_REGISTER 0x00 +#define INST_READ_REGISTER_VALUE 0x01 +#define INST_WRITE_REGISTER0x02 +#define INST_WRITE_REGISTER_VALUE 0x03 +#define INST_NOOP 0x04 +#define INST_LOAD_VAR1 0x05 +#define INST_LOAD_VAR2 0x06 +#define INST_STORE_VAR10x07 +#define INST_ADD 0x08 +#define INST_SUBTRACT 0x09 +#define INST_ADD_VALUE 0x0A +#define INST_SUBTRACT_VALUE0x0B +#define INST_STALL 0x0C +#define INST_STALL_WHILE_TRUE 0x0D +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E +#define INST_GOTO 0x0F +#define INST_SET_SRC_ADDRESS_BASE 0x10 +#define INST_SET_DST_ADDRESS_BASE 0x11 +#define INST_MOVE_DATA 0x12 + /* UEFI 2.1: Appendix N Common Platform Error Record */ #define UEFI_CPER_RECORD_MIN_SIZE 128U #define UEFI_CPER_RECORD_LENGTH_OFFSET 20U @@ -172,6 +193,173 @@ typedef struct { /***/ /***/ + +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */ +static void build_serialization_instruction_entry(GArray *table_data, +uint8_t serialization_action, +uint8_t instruction, +uint8_t flags, +uint8_t register_bit_width, +uint64_t register_address, +uint64_t value) +{ +/* ACPI 4.0: Table 17-18 Serialization Instruction Entry */ +struct AcpiGenericAddress gas; +uint64_t mask; + +/* Serialization Action */ +build_append_int_noprefix(table_data, serialization_action, 1); +/* Instruction */ +build_append_int_noprefix(table_data, instruction , 1); +/* Flags */ +build_append_int_noprefix(table_data, flags , 1); +/* Reserved */ +build_append_int_noprefix(table_data, 0 , 1); +/* Register Region */ +gas.space_id = AML_SYSTEM_MEMORY; +gas.bit_width = register_bit_width; +gas.bit_offset = 0; +gas.access_width = ctz32(register_bit_width) - 2; +gas.address = register_address; +build_append_gas_from_struct(table_data, ); +/* Value */ +build_append_int_noprefix(table_data, value , 8); +/* Mask */ +mask = (1ULL << (register_bit_width - 1) << 1) - 1; +build_append_int_noprefix(table_data, mask , 8); +} + +/* ACPI 4.0: 17.4.1 Serialization Action Table */ +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev, +const char *oem_id, const char *oem_table_id) +{ +GArray *table_instruction_data; +unsigned action; This variable can be eliminated (see below). +pcibus_t bar0 = pci_get_bar_addr(PCI_DEVICE(erst_dev), 0); +AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id, +.oem_table_id = oem_table_id }; + +trace_acpi_erst_pci_bar_0(bar0); + +/* + * Serialization Action Table + * The serialization action table must be generated first + * so that its size can be known in order to populate the + * Instruction Entry Count field. + */ +table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char)); + +/* + * Macros for use with construction of the action instructions + */ +#define build_read_register(action, width_in_bits, reg) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER, 0, width_in_bits, \ +bar0 + reg, 0) + +#define build_read_register_value(action, width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_READ_REGISTER_VALUE, 0, width_in_bits, \ +bar0 + reg, value) + +#define build_write_register(action, width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER, 0, width_in_bits, \ +bar0 + reg, value) + +#define build_write_register_value(action, width_in_bits, reg, value) \ +build_serialization_instruction_entry(table_instruction_data, \ +action, INST_WRITE_REGISTER_V
[PATCH v11 02/10] ACPI ERST: specification for ERST support
Information on the implementation of the ACPI ERST support. Signed-off-by: Eric DeVolder Acked-by: Ani Sinha --- docs/specs/acpi_erst.rst | 200 +++ 1 file changed, 200 insertions(+) create mode 100644 docs/specs/acpi_erst.rst diff --git a/docs/specs/acpi_erst.rst b/docs/specs/acpi_erst.rst new file mode 100644 index 000..a8a9d22 --- /dev/null +++ b/docs/specs/acpi_erst.rst @@ -0,0 +1,200 @@ +ACPI ERST DEVICE + + +The ACPI ERST device is utilized to support the ACPI Error Record +Serialization Table, ERST, functionality. This feature is designed for +storing error records in persistent storage for future reference +and/or debugging. + +The ACPI specification[1], in Chapter "ACPI Platform Error Interfaces +(APEI)", and specifically subsection "Error Serialization", outlines a +method for storing error records into persistent storage. + +The format of error records is described in the UEFI specification[2], +in Appendix N "Common Platform Error Record". + +While the ACPI specification allows for an NVRAM "mode" (see +GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES) where non-volatile RAM is +directly exposed for direct access by the OS/guest, this device +implements the non-NVRAM "mode". This non-NVRAM "mode" is what is +implemented by most BIOS (since flash memory requires programming +operations in order to update its contents). Furthermore, as of the +time of this writing, Linux only supports the non-NVRAM "mode". + + +Background/Motivation +- + +Linux uses the persistent storage filesystem, pstore, to record +information (eg. dmesg tail) upon panics and shutdowns. Pstore is +independent of, and runs before, kdump. In certain scenarios (ie. +hosts/guests with root filesystems on NFS/iSCSI where networking +software and/or hardware fails, and thus kdump fails), pstore may +contain information available for post-mortem debugging. + +Two common storage backends for the pstore filesystem are ACPI ERST +and UEFI. Most BIOS implement ACPI ERST. UEFI is not utilized in all +guests. With QEMU supporting ACPI ERST, it becomes a viable pstore +storage backend for virtual machines (as it is now for bare metal +machines). + +Enabling support for ACPI ERST facilitates a consistent method to +capture kernel panic information in a wide range of guests: from +resource-constrained microvms to very large guests, and in particular, +in direct-boot environments (which would lack UEFI run-time services). + +Note that Microsoft Windows also utilizes the ACPI ERST for certain +crash information, if available[3]. + + +Configuration|Usage +--- + +To use ACPI ERST, a memory-backend-file object and acpi-erst device +can be created, for example: + + qemu ... + -object memory-backend-file,id=erstnvram,mem-path=acpi-erst.backing,size=0x1,share=on \ + -device acpi-erst,memdev=erstnvram + +For proper operation, the ACPI ERST device needs a memory-backend-file +object with the following parameters: + + - id: The id of the memory-backend-file object is used to associate + this memory with the acpi-erst device. + - size: The size of the ACPI ERST backing storage. This parameter is + required. + - mem-path: The location of the ACPI ERST backing storage file. This + parameter is also required. + - share: The share=on parameter is required so that updates to the + ERST backing store are written to the file. + +and ERST device: + + - memdev: Is the object id of the memory-backend-file. + - record_size: Specifies the size of the records (or slots) in the + backend storage. Must be a power of two value greater than or + equal to 4096 (PAGE_SIZE). + + +PCI Interface +- + +The ERST device is a PCI device with two BARs, one for accessing the +programming registers, and the other for accessing the record exchange +buffer. + +BAR0 contains the programming interface consisting of ACTION and VALUE +64-bit registers. All ERST actions/operations/side effects happen on +the write to the ACTION, by design. Any data needed by the action must +be placed into VALUE prior to writing ACTION. Reading the VALUE +simply returns the register contents, which can be updated by a +previous ACTION. + +BAR1 contains the 8KiB record exchange buffer, which is the +implemented maximum record size. + + +Backend Storage Format +-- + +The backend storage is divided into fixed size "slots", 8KiB in +length, with each slot storing a single record. Not all slots need to +be occupied, and they need not be occupied in a contiguous fashion. +The ability to clear/erase specific records allows for the formation +of unoccupied slots. + +Slot 0 contains a backend storage header that identifies the contents +as ERST and also facilitates efficient access to the records. +Depending upon the size of the backend storage, additional slots will +be designated
[PATCH v11 09/10] ACPI ERST: bios-tables-test testcase
This change implements the test suite checks for the ERST table. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- tests/qtest/bios-tables-test.c | 56 ++ 1 file changed, 56 insertions(+) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 2588741..2f073e6 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1446,6 +1446,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void) test_acpi_tcg_acpi_hmat(MACHINE_PC); } +static void test_acpi_erst(const char *machine) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +memset(, 0, sizeof(data)); +data.machine = machine; +data.variant = ".acpierst"; +params = g_strdup_printf( +" -object memory-backend-file,id=erstnvram," +"mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +free_test_data(); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +} + +static void test_acpi_piix4_acpi_erst(void) +{ +test_acpi_erst(MACHINE_PC); +} + +static void test_acpi_q35_acpi_erst(void) +{ +test_acpi_erst(MACHINE_Q35); +} + +static void test_acpi_microvm_acpi_erst(void) +{ +gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XX", NULL); +gchar *params; +test_data data; + +test_acpi_microvm_prepare(); +data.variant = ".pcie"; +data.tcg_only = true; /* need constant host-phys-bits */ +params = g_strdup_printf(" -machine microvm," +"acpi=on,ioapic2=off,rtc=off,pcie=on" +" -object memory-backend-file,id=erstnvram," + "mem-path=%s,size=0x1,share=on" +" -device acpi-erst,memdev=erstnvram", tmp_path); +test_acpi_one(params, ); +g_free(params); +g_assert(g_rmdir(tmp_path) == 0); +g_free(tmp_path); +free_test_data(); +} + static void test_acpi_virt_tcg(void) { test_data data = { @@ -1624,6 +1675,8 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); +qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst); +qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst); qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); @@ -1639,6 +1692,9 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/kvm/xapic", test_acpi_q35_kvm_xapic); qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); } +if (strcmp(arch, "x86_64") == 0) { +qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst); +} } else if (strcmp(arch, "aarch64") == 0) { if (has_tcg) { qtest_add_func("acpi/virt", test_acpi_virt_tcg); -- 1.8.3.1
[PATCH v11 03/10] ACPI ERST: PCI device_id for ERST
This change reserves the PCI device_id for the new ACPI ERST device. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov Acked-by: Ani Sinha --- include/hw/pci/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index e7cdf2d..d3734b9 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -108,6 +108,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_REDHAT_MDPY0x000f #define PCI_DEVICE_ID_REDHAT_NVME0x0010 #define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 +#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012 #define PCI_DEVICE_ID_REDHAT_QXL 0x0100 #define FMT_PCIBUS PRIx64 -- 1.8.3.1
[PATCH v11 01/10] ACPI ERST: bios-tables-test.c steps 1 and 2
Following the guidelines in tests/qtest/bios-tables-test.c, this change adds empty placeholder files per step 1 for the new ERST table, and excludes resulting changed files in bios-tables-test-allowed-diff.h per step 2. Signed-off-by: Eric DeVolder Acked-by: Igor Mammedov --- tests/data/acpi/microvm/ERST.pcie | 0 tests/data/acpi/pc/DSDT.acpierst| 0 tests/data/acpi/pc/ERST.acpierst| 0 tests/data/acpi/q35/DSDT.acpierst | 0 tests/data/acpi/q35/ERST.acpierst | 0 tests/qtest/bios-tables-test-allowed-diff.h | 5 + 6 files changed, 5 insertions(+) create mode 100644 tests/data/acpi/microvm/ERST.pcie create mode 100644 tests/data/acpi/pc/DSDT.acpierst create mode 100644 tests/data/acpi/pc/ERST.acpierst create mode 100644 tests/data/acpi/q35/DSDT.acpierst create mode 100644 tests/data/acpi/q35/ERST.acpierst diff --git a/tests/data/acpi/microvm/ERST.pcie b/tests/data/acpi/microvm/ERST.pcie new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/pc/ERST.acpierst b/tests/data/acpi/pc/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/data/acpi/q35/ERST.acpierst b/tests/data/acpi/q35/ERST.acpierst new file mode 100644 index 000..e69de29 diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523..603db07 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,6 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/pc/DSDT.acpierst", +"tests/data/acpi/pc/ERST.acpierst", +"tests/data/acpi/q35/DSDT.acpierst", +"tests/data/acpi/q35/ERST.acpierst", +"tests/data/acpi/microvm/ERST.pcie", -- 1.8.3.1
[PATCH v11 05/10] ACPI ERST: support for ACPI ERST feature
This implements a PCI device for ACPI ERST. This implements the non-NVRAM "mode" of operation for ERST as it is supported by Linux and Windows. Signed-off-by: Eric DeVolder Reviewed-by: Ani Sinha --- hw/acpi/Kconfig | 6 + hw/acpi/erst.c | 845 +++ hw/acpi/meson.build | 1 + hw/acpi/trace-events | 15 + 4 files changed, 867 insertions(+) create mode 100644 hw/acpi/erst.c diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 622b0b5..19caebd 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -10,6 +10,7 @@ config ACPI_X86 select ACPI_HMAT select ACPI_PIIX4 select ACPI_PCIHP +select ACPI_ERST config ACPI_X86_ICH bool @@ -60,3 +61,8 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_ERST +bool +default y +depends on ACPI && PCI diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c new file mode 100644 index 000..bb6cad4 --- /dev/null +++ b/hw/acpi/erst.c @@ -0,0 +1,845 @@ +/* + * ACPI Error Record Serialization Table, ERST, Implementation + * + * ACPI ERST introduced in ACPI 4.0, June 16, 2009. + * ACPI Platform Error Interfaces : Error Serialization + * + * Copyright (c) 2021 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-core.h" +#include "exec/memory.h" +#include "qom/object.h" +#include "hw/pci/pci.h" +#include "qom/object_interfaces.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/acpi/acpi.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/bios-linker-loader.h" +#include "exec/address-spaces.h" +#include "sysemu/hostmem.h" +#include "hw/acpi/erst.h" +#include "trace.h" + +/* ACPI 4.0: Table 17-16 Serialization Actions */ +#define ACTION_BEGIN_WRITE_OPERATION 0x0 +#define ACTION_BEGIN_READ_OPERATION 0x1 +#define ACTION_BEGIN_CLEAR_OPERATION 0x2 +#define ACTION_END_OPERATION 0x3 +#define ACTION_SET_RECORD_OFFSET 0x4 +#define ACTION_EXECUTE_OPERATION 0x5 +#define ACTION_CHECK_BUSY_STATUS 0x6 +#define ACTION_GET_COMMAND_STATUS0x7 +#define ACTION_GET_RECORD_IDENTIFIER 0x8 +#define ACTION_SET_RECORD_IDENTIFIER 0x9 +#define ACTION_GET_RECORD_COUNT 0xA +#define ACTION_BEGIN_DUMMY_WRITE_OPERATION 0xB +#define ACTION_RESERVED 0xC +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE 0xD +#define ACTION_GET_ERROR_LOG_ADDRESS_LENGTH 0xE +#define ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES 0xF +#define ACTION_GET_EXECUTE_OPERATION_TIMINGS 0x10 /* ACPI 6.3 */ + +/* ACPI 4.0: Table 17-17 Command Status Definitions */ +#define STATUS_SUCCESS0x00 +#define STATUS_NOT_ENOUGH_SPACE 0x01 +#define STATUS_HARDWARE_NOT_AVAILABLE 0x02 +#define STATUS_FAILED 0x03 +#define STATUS_RECORD_STORE_EMPTY 0x04 +#define STATUS_RECORD_NOT_FOUND 0x05 + +/* UEFI 2.1: Appendix N Common Platform Error Record */ +#define UEFI_CPER_RECORD_MIN_SIZE 128U +#define UEFI_CPER_RECORD_LENGTH_OFFSET 20U +#define UEFI_CPER_RECORD_ID_OFFSET 96U +#define IS_UEFI_CPER_RECORD(ptr) \ +(((ptr)[0] == 'C') && \ + ((ptr)[1] == 'P') && \ + ((ptr)[2] == 'E') && \ + ((ptr)[3] == 'R')) + +/* + * NOTE that when accessing CPER fields within a record, memcpy() + * is utilized to avoid a possible misaligned access on the host. + */ + +/* + * This implementation is an ACTION (cmd) and VALUE (data) + * interface consisting of just two 64-bit registers. + */ +#define ERST_REG_SIZE (16UL) +#define ERST_ACTION_OFFSET (0UL) /* action (cmd) */ +#define ERST_VALUE_OFFSET (8UL) /* argument/value (data) */ + +/* + * ERST_RECORD_SIZE is the buffer size for exchanging ERST + * record contents. Thus, it defines the maximum record size. + * As this is mapped through a PCI BAR, it must be a power of + * two and larger than UEFI_CPER_RECORD_MIN_SIZE. + * The backing storage is divided into fixed size "slots", + * each ERST_RECORD_SIZE in length, and each "slot" + * storing a single record. No attempt at optimizing storage + * through compression, compaction, etc is attempted. + * NOTE that slot 0 is reserved for the backing storage header. + * Depending upon the size of the backing storage, additional + * slots will be part of the slot 0 header in order to account + * for a record_id for each available remaining slot. + */ +/* 8KiB records, not too small, not too big */ +#define ERST_RECORD_SIZE (8192UL) + +#define ACPI_ERST_MEMDEV_PROP "