From: David Woodhouse Date: Sat, 23 Feb 2013 00:24:49 +0000 (+0000) Subject: Add acpi_reboot() reset method using RESET_REG X-Git-Tag: rel-1.7.3~60 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=d338eb94f65c765d43fd9cc9c31e9ec914ca64e3;p=seabios.git Add acpi_reboot() reset method using RESET_REG Signed-off-by: David Woodhouse --- diff --git a/src/acpi.c b/src/acpi.c index 36bd39a..195dc88 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -150,17 +150,6 @@ struct madt_local_nmi { } PACKED; -/* - * 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 */ @@ -934,4 +923,51 @@ find_acpi_features(void) dprintf(4, "pm_tmr_blk=%x\n", pm_tmr); if (pm_tmr) pmtimer_setup(pm_tmr, 3579); + + // 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. + if (fadt->length >= 129) { + void *p = fadt; + acpi_set_reset_reg(p + 116, *(u8 *)(p + 128)); + } +} + +static struct acpi_20_generic_address acpi_reset_reg; +static u8 acpi_reset_val; + +void +acpi_reboot(void) +{ + // Check it passed the sanity checks in acpi_set_reset_reg() and was set + if (acpi_reset_reg.register_bit_width != 8) + return; + + u64 addr = le64_to_cpu(acpi_reset_reg.address); + + dprintf(1, "ACPI hard reset %d:%llx (%x)\n", + acpi_reset_reg.address_space_id, addr, acpi_reset_val); + + switch (acpi_reset_reg.address_space_id) { + case 0: // System Memory + writeb((void *)(u32)addr, acpi_reset_val); + break; + case 1: // System I/O + outb(acpi_reset_val, addr); + break; + case 2: // PCI config space + pci_config_writeb(acpi_ga_to_bdf(addr), addr & 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 b23717a..6289953 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_acpi_features(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 b30d62e..784abac 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();