This patch makes OSv boot without requiring ACPI to be present which for example is the case on firecracker.
We simply treat failure to find ACPI root pointer as an indicator that ACPI is not available and mark it off as such. Also if ACPI is off we power OSv off using non-ACPI method and skip probing panic driver as it relies on ACPI as well. Lastly we skip MADT table parsing if APCI is off and for now assume there is single vCPU only. Eventually we should parse vCPU information from MP table as an alternative. Signed-off-by: Waldemar Kozaczuk <[email protected]> --- arch/x64/power.cc | 30 +++++++++++++++++++++--------- arch/x64/smp.cc | 20 +++++++++++++++++++- drivers/acpi.cc | 19 +++++++++++++++++++ drivers/acpi.hh | 1 + drivers/pvpanic.cc | 4 ++++ 5 files changed, 64 insertions(+), 10 deletions(-) diff --git a/arch/x64/power.cc b/arch/x64/power.cc index 81849335..61d56bcc 100644 --- a/arch/x64/power.cc +++ b/arch/x64/power.cc @@ -15,6 +15,8 @@ extern "C" { #include "acpi.h" } +#include <drivers/acpi.hh> + namespace osv { void halt(void) @@ -27,15 +29,25 @@ void halt(void) void poweroff(void) { - ACPI_STATUS status = AcpiEnterSleepStatePrep(ACPI_STATE_S5); - if (ACPI_FAILURE(status)) { - debug("AcpiEnterSleepStatePrep failed: %s\n", AcpiFormatException(status)); - halt(); - } - status = AcpiEnterSleepState(ACPI_STATE_S5); - if (ACPI_FAILURE(status)) { - debug("AcpiEnterSleepState failed: %s\n", AcpiFormatException(status)); - halt(); + if (acpi::is_enabled()) { + ACPI_STATUS status = AcpiEnterSleepStatePrep(ACPI_STATE_S5); + if (ACPI_FAILURE(status)) { + debug("AcpiEnterSleepStatePrep failed: %s\n", AcpiFormatException(status)); + halt(); + } + status = AcpiEnterSleepState(ACPI_STATE_S5); + if (ACPI_FAILURE(status)) { + debug("AcpiEnterSleepState failed: %s\n", AcpiFormatException(status)); + halt(); + } + } else { + // On hypervisors that do not support ACPI like firecracker we + // resort to a reset using the 8042 PS/2 Controller ("keyboard controller") + // as a way to shutdown the VM + //TODO: Figure out if there is another method we could try + // first to to power off on non-firecracker platforms + // without using ACPI + processor::outb(0xfe, 0x64); } // We shouldn't get here on x86. diff --git a/arch/x64/smp.cc b/arch/x64/smp.cc index 073ef206..2869d6e2 100644 --- a/arch/x64/smp.cc +++ b/arch/x64/smp.cc @@ -15,6 +15,7 @@ extern "C" { #include "acpi.h" } +#include <drivers/acpi.hh> #include <boost/intrusive/parent_from_member.hpp> #include <osv/debug.hh> #include <osv/sched.hh> @@ -72,9 +73,26 @@ void parse_madt() debug(fmt("%d CPUs detected\n") % nr_cpus); } +void parse_mp_table() +{ + //TODO: This a nasty hack to support single vCPU. Eventually we should + // parse out equivalent information about all vCPUs from MP table. For + // details please see https://wiki.osdev.org/Symmetric_Multiprocessing#Finding_information_using_MP_Table + auto c = new sched::cpu(0); + c->arch.apic_id = 0; + c->arch.initstack.next = smp_stack_free; + smp_stack_free = &c->arch.initstack; + sched::cpus.push_back(c); +} + void smp_init() { - parse_madt(); + if (acpi::is_enabled()) { + parse_madt(); + } else { + parse_mp_table(); + } + sched::current_cpu = sched::cpus[0]; for (auto c : sched::cpus) { c->incoming_wakeups = aligned_array_new<sched::cpu::incoming_wakeup_queue>(sched::cpus.size()); diff --git a/drivers/acpi.cc b/drivers/acpi.cc index 506ca68f..4a38a32e 100644 --- a/drivers/acpi.cc +++ b/drivers/acpi.cc @@ -539,8 +539,21 @@ namespace acpi { static ACPI_TABLE_DESC TableArray[ACPI_MAX_INIT_TABLES]; +static bool enabled = false; + +bool is_enabled() { + return enabled; +} + void early_init() { + ACPI_SIZE rsdp; + auto st = AcpiFindRootPointer(&rsdp); + if (ACPI_FAILURE(st)) { + acpi_w("Warning: Failed to find ACPI root pointer!\n"); + return; + } + ACPI_STATUS status; status = AcpiInitializeTables(TableArray, ACPI_MAX_INIT_TABLES, TRUE); @@ -569,6 +582,8 @@ void early_init() acpi_e("AcpiLoadTables failed: %s\n", AcpiFormatException(status)); return; } + + enabled = true; } UINT32 acpi_poweroff(void *unused) @@ -581,6 +596,10 @@ UINT32 acpi_poweroff(void *unused) // The following function comes from the documentation example page 262 void init() { + if (!enabled) { + return; + } + ACPI_STATUS status; diff --git a/drivers/acpi.hh b/drivers/acpi.hh index 8373745b..10f82f58 100644 --- a/drivers/acpi.hh +++ b/drivers/acpi.hh @@ -12,6 +12,7 @@ namespace acpi { void init(); +bool is_enabled(); } diff --git a/drivers/pvpanic.cc b/drivers/pvpanic.cc index 2f114fb3..e643b5a0 100644 --- a/drivers/pvpanic.cc +++ b/drivers/pvpanic.cc @@ -21,6 +21,10 @@ static u32 port; void probe_and_setup() { + if (!acpi::is_enabled()) { + return; + } + ACPI_BUFFER results; ACPI_OBJECT obj; ACPI_STATUS status; -- 2.19.1 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
