Signed-off-by: David Woodhouse David.Woodhouse@intel.com ---
Nothing actually sets it yet. We'll do that from the ACPI table parser for CSM and Xen, and we can put it in our own tables for the native case.
diff --git a/src/acpi.c b/src/acpi.c index f7a2e55..97ade3f 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -150,17 +150,6 @@ struct madt_local_nmi {
/* - * ACPI 2.0 Generic Address Space definition. - */ -struct acpi_20_generic_address { - u8 address_space_id; - u8 register_bit_width; - u8 register_bit_offset; - u8 reserved; - u64 address; -} PACKED; - -/* * HPET Description Table */ struct acpi_20_hpet { @@ -936,3 +925,38 @@ find_pmtimer(void)
pmtimer_setup(pm_tmr, 3579); } + +static struct acpi_20_generic_address acpi_reset_reg; +static u8 acpi_reset_val; + +void +acpi_reboot(void) +{ + // Must be a single byte; + if (acpi_reset_reg.register_bit_width != 8) + return; + + switch (acpi_reset_reg.address_space_id) { + case 0: // System Memory + writeb((void *)(u32)acpi_reset_reg.address, acpi_reset_val); + break; + case 1: // System I/O + outb(acpi_reset_val, acpi_reset_reg.address); + break; + case 2: // PCI config space + pci_config_writeb(acpi_ga_to_bdf(acpi_reset_reg.address), + acpi_reset_reg.address & 0xffff, + acpi_reset_val); + break; + } +} + +void acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val) +{ + if (!reg || reg->address_space_id > 2 || + reg->register_bit_width != 8 || reg->register_bit_offset) + return; + + acpi_reset_reg = *reg; + acpi_reset_val = val; +} diff --git a/src/acpi.h b/src/acpi.h index e52470e..3f85814 100644 --- a/src/acpi.h +++ b/src/acpi.h @@ -3,9 +3,23 @@
#include "types.h" // u32
+/* + * ACPI 2.0 Generic Address Space definition. + */ +struct acpi_20_generic_address { + u8 address_space_id; + u8 register_bit_width; + u8 register_bit_offset; + u8 reserved; + u64 address; +} PACKED; +#define acpi_ga_to_bdf(addr) pci_to_bdf(0, (addr >> 32) & 0xffff, (addr >> 16) & 0xffff) + void acpi_setup(void); u32 find_resume_vector(void); void find_pmtimer(void); +void acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val); +void acpi_reboot(void);
#define RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR "
diff --git a/src/resume.c b/src/resume.c index adc3594..6b9ad9a 100644 --- a/src/resume.c +++ b/src/resume.c @@ -132,6 +132,9 @@ tryReboot(void) // Setup for reset on qemu. qemu_prep_reset();
+ // Reboot using ACPI RESET_REG + acpi_reboot(); + // Try keyboard controller reboot. i8042_reboot();
On Tue, Feb 19, 2013 at 06:08:31PM +0000, David Woodhouse wrote:
Signed-off-by: David Woodhouse David.Woodhouse@intel.com
Nothing actually sets it yet. We'll do that from the ACPI table parser for CSM and Xen, and we can put it in our own tables for the native case.
Looks okay to me. I'd like to see the follow up patches that make use of it before committing though.
-Kevin
On Tue, 2013-02-19 at 20:09 -0500, Kevin O'Connor wrote:
On Tue, Feb 19, 2013 at 06:08:31PM +0000, David Woodhouse wrote:
Signed-off-by: David Woodhouse David.Woodhouse@intel.com
Nothing actually sets it yet. We'll do that from the ACPI table parser for CSM and Xen, and we can put it in our own tables for the native case.
Looks okay to me. I'd like to see the follow up patches that make use of it before committing though.
Looks something like this. Not properly tested though, because first I have to make OVMF (or Xen or Coreboot) actually pass in an ACPI 2.0 table with the RESET_REG present...
We probably want a structure for the 2.0 FADT rather than screwing around with magic pointer arithmetic, and we probably want to combine find_pmtimer() and find_reset_reg() into one function too.
diff --git a/src/acpi.c b/src/acpi.c index 97ade3f..8c53dd3 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -930,6 +930,21 @@ static struct acpi_20_generic_address acpi_reset_reg; static u8 acpi_reset_val;
void +find_reset_reg(void) +{ + struct fadt_descriptor_rev1 *fadt = find_fadt(); + if (!fadt || fadt->length < 129) + return; + + // Theoretically we should check the 'reset_reg_sup' flag, but Windows + // doesn't and thus nobody seems to *set* it. If the table is large enough + // to include it, let the sanity checks in acpi_set_reset_reg() suffice. + + void *p = fadt; + acpi_set_reset_reg(p + 116, *(u8 *)(p + 128)); +} + +void acpi_reboot(void) { // Must be a single byte; diff --git a/src/acpi.h b/src/acpi.h index 3f85814..2d4cc86 100644 --- a/src/acpi.h +++ b/src/acpi.h @@ -18,6 +18,7 @@ struct acpi_20_generic_address { void acpi_setup(void); u32 find_resume_vector(void); void find_pmtimer(void); +void find_reset_reg(void); void acpi_set_reset_reg(struct acpi_20_generic_address *reg, u8 val); void acpi_reboot(void);
diff --git a/src/coreboot.c b/src/coreboot.c index 0d44834..522b686 100644 --- a/src/coreboot.c +++ b/src/coreboot.c @@ -230,6 +230,7 @@ coreboot_platform_setup(void) }
find_pmtimer(); + find_reset_reg(); }
diff --git a/src/csm.c b/src/csm.c index ab66042..bd0ffd1 100644 --- a/src/csm.c +++ b/src/csm.c @@ -157,6 +157,7 @@ handle_csm_0002(struct bregs *regs) dprintf(3, "CSM ACPI RSDP at %p\n", RsdpAddr);
find_pmtimer(); + find_reset_reg(); }
// SMBIOS table needs to be copied into the f-seg diff --git a/src/xen.c b/src/xen.c index 2dbd9df..f18c5c3 100644 --- a/src/xen.c +++ b/src/xen.c @@ -126,6 +126,7 @@ void xen_biostable_setup(void) copy_table(tables[i]);
find_pmtimer(); + find_reset_reg(); }
void xen_preinit(void)
On Tue, 2013-02-19 at 20:09 -0500, Kevin O'Connor wrote:
Looks okay to me. I'd like to see the follow up patches that make use of it before committing though.
Sent. With Qemu fixed to actually *do* a hard reset, and OVMF fixed to pass in ACPI 2.0 tables with a RESET_REG filled in (thanks, Laszlo), this fixes the endless loop of soft resets.