diff --git a/repos/base/run/platform_drv.inc b/repos/base/run/platform_drv.inc index c7209143b8..b964293bdc 100644 --- a/repos/base/run/platform_drv.inc +++ b/repos/base/run/platform_drv.inc @@ -51,6 +51,24 @@ proc platform_drv_policy {} { } proc platform_drv_priority {} { return "" } +proc platform_drv_add_routing {} { + if {[have_spec acpi]} { + return { + } + } + + return "" +} + +proc platform_drv_config_config {} { + if {[have_spec acpi] || [have_spec arm] || [have_spec hw_x86_64_muen]} { + return { + } + } + + return { + } +} proc append_platform_drv_config {} { global config @@ -108,6 +126,8 @@ proc append_platform_drv_config {} { } + append config "[platform_drv_add_routing]" + append_if [have_spec acpi] config { } @@ -118,18 +138,7 @@ proc append_platform_drv_config {} { } - if {[have_spec acpi] || [have_spec arm] || [have_spec hw_x86_64_muen]} { - - append config { - } - - } else { - - append config { - } - - } - + append config [platform_drv_config_config] append config [platform_drv_policy] append config { diff --git a/repos/libports/run/acpica.run b/repos/libports/run/acpica.run index 88b8b9e75f..30ddd80d79 100644 --- a/repos/libports/run/acpica.run +++ b/repos/libports/run/acpica.run @@ -27,6 +27,18 @@ proc platform_drv_policy {} { } } +# add routing information to dynamically generate change of 'system' ROM +proc platform_drv_add_routing {} { + return { + } +} + +# override default config to react on 'system' ROM changes for reset +proc platform_drv_config_config {} { + return { + } +} + append_platform_drv_build_components build $build_components diff --git a/repos/os/src/drivers/platform/spec/x86/main.cc b/repos/os/src/drivers/platform/spec/x86/main.cc index 64ff7a93ef..f977ef75fe 100644 --- a/repos/os/src/drivers/platform/spec/x86/main.cc +++ b/repos/os/src/drivers/platform/spec/x86/main.cc @@ -39,7 +39,10 @@ struct Platform::Main Genode::Lazy_volatile_object acpi_rom; Genode::Lazy_volatile_object root; + Genode::Lazy_volatile_object system_state; + Genode::Signal_handler _acpi_report; + Genode::Signal_handler _system_report; void acpi_update() { @@ -54,19 +57,48 @@ struct Platform::Main _env.parent().announce(_env.ep().manage(*root)); } + void system_update() + { + system_state->update(); + + if (!system_state->is_valid() || !root.is_constructed()) + return; + + Genode::Xml_node system(system_state->local_addr(), + system_state->size()); + + typedef Genode::String<16> Value; + const Value state = system.attribute_value("state", Value("unknown")); + + if (state == "reset") + root->system_reset(); + } + Main(Genode::Env &env) : sliced_heap(env.ram(), env.rm()), _env(env), - _acpi_report(_env.ep(), *this, &Main::acpi_update) + _acpi_report(_env.ep(), *this, &Main::acpi_update), + _system_report(_env.ep(), *this, &Main::system_update) { + const Genode::Xml_node &config = Genode::config()->xml_node(); + typedef Genode::String<8> Value; - Value const wait_for_acpi = Genode::config()->xml_node().attribute_value("acpi", Value("yes")); + Value const wait_for_acpi = config.attribute_value("acpi", Value("yes")); if (wait_for_acpi == "yes") { + bool system_reset = config.attribute_value("system", false); + if (system_reset) { + /* wait for system state changes and react upon, e.g. reset */ + system_state.construct("system"); + system_state->sigh(_system_report); + } + /* for ACPI support, wait for the first valid acpi report */ acpi_rom.construct("acpi"); acpi_rom->sigh(_acpi_report); + /* check if already valid */ + acpi_update(); return; } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_config_access.h b/repos/os/src/drivers/platform/spec/x86/pci_config_access.h index f90be5a8eb..dd1b427464 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_config_access.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_config_access.h @@ -24,7 +24,7 @@ namespace Platform { { private: - enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc }; + enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc, REG_SIZE = 4 }; /** * Request interface to access an I/O port @@ -47,7 +47,7 @@ namespace Platform { * Once created, each I/O-port session persists until * the PCI driver gets killed by its parent. */ - static Genode::Io_port_connection io_port(port, 4); + static Genode::Io_port_connection io_port(port, REG_SIZE); return &io_port; } @@ -177,6 +177,32 @@ namespace Platform { return true; } } + + bool reset_support(unsigned reg, unsigned reg_size) const + { + return (REG_ADDR <= reg) && + reg + reg_size <= REG_ADDR + REG_SIZE; + } + + bool system_reset(unsigned reg, unsigned long long value, + const Device::Access_size &access_size) + { + switch (access_size) { + case Device::ACCESS_8BIT: + _io_port()->outb(reg, value); + break; + case Device::ACCESS_16BIT: + _io_port()->outw(reg, value); + break; + case Device::ACCESS_32BIT: + _io_port()->outl(reg, value); + break; + default: + return false; + } + + return true; + } }; } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h index bbf5d74028..78212e0baf 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -853,6 +854,27 @@ class Platform::Root : public Genode::Root_component { private: + struct Fadt { + Genode::uint32_t features = 0, reset_type = 0, reset_value = 0; + Genode::uint64_t reset_addr = 0; + + /* Table 5-35 Fixed ACPI Description Table Fixed Feature Flags */ + struct Features : Genode::Register<32> { + struct Reset : Bitfield<10, 1> { }; + }; + + /* ACPI spec - 5.2.3.2 Generic Address Structure */ + struct Gas : Genode::Register<32> + { + struct Address_space : Bitfield <0, 8> { + enum { SYSTEM_IO = 1 }; + }; + struct Access_size : Bitfield<24,8> { + enum { UNDEFINED = 0, BYTE = 1, WORD = 2, DWORD = 3, QWORD = 4}; + }; + }; + } fadt; + Genode::Rpc_entrypoint _device_pd_ep; void _parse_report_rom(const char * acpi_rom) @@ -938,6 +960,13 @@ class Platform::Root : public Genode::Root_component } } + if (node.has_type("fadt")) { + node.attribute("features").value(&fadt.features); + node.attribute("reset_type").value(&fadt.reset_type); + node.attribute("reset_addr").value(&fadt.reset_addr); + node.attribute("reset_value").value(&fadt.reset_value); + } + if (!node.has_type("routing")) continue; @@ -1029,4 +1058,47 @@ class Platform::Root : public Genode::Root_component } } } + + void system_reset() + { + const bool io_port_space = (Fadt::Gas::Address_space::get(fadt.reset_type) == Fadt::Gas::Address_space::SYSTEM_IO); + + if (!io_port_space) + return; + + Config_access config_access; + const unsigned raw_access_size = Fadt::Gas::Access_size::get(fadt.reset_type); + const bool reset_support = config_access.reset_support(fadt.reset_addr, raw_access_size); + if (!reset_support) + return; + + const bool feature_reset = Fadt::Features::Reset::get(fadt.features); + + if (!feature_reset) { + PWRN("system reset failed - feature not supported"); + return; + } + + Device::Access_size access_size = Device::ACCESS_8BIT; + + unsigned raw_size = Fadt::Gas::Access_size::get(fadt.reset_type); + switch (raw_size) { + case Fadt::Gas::Access_size::WORD: + access_size = Device::ACCESS_16BIT; + break; + case Fadt::Gas::Access_size::DWORD: + access_size = Device::ACCESS_32BIT; + break; + case Fadt::Gas::Access_size::QWORD: + PERR("system reset failed - unsupported access size"); + return; + default: + break; + } + + config_access.system_reset(fadt.reset_addr, fadt.reset_value, + access_size); + /* if we are getting here - the reset failed */ + PINF("system reset failed"); + } };