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");
+ }
};