diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run index 7faa58d447..1b2a4d9e1f 100644 --- a/repos/gems/run/sculpt.run +++ b/repos/gems/run/sculpt.run @@ -419,6 +419,8 @@ install_config { + + diff --git a/repos/gems/sculpt/drivers/pc b/repos/gems/sculpt/drivers/pc index 6e14399319..263c85c5a1 100644 --- a/repos/gems/sculpt/drivers/pc +++ b/repos/gems/sculpt/drivers/pc @@ -89,6 +89,7 @@ + diff --git a/repos/os/src/drivers/platform/common.h b/repos/os/src/drivers/platform/common.h index db9ff7ccd4..a01d46a4d2 100644 --- a/repos/os/src/drivers/platform/common.h +++ b/repos/os/src/drivers/platform/common.h @@ -49,6 +49,8 @@ class Driver::Common : Device_reporter, Constructible _dev_reporter { }; Constructible _iommu_reporter { }; + uint64_t _resume_counter { }; + void _handle_devices(); bool _iommu(); @@ -67,6 +69,7 @@ class Driver::Common : Device_reporter, void handle_config(Xml_node config); void acquire_io_mmu_devices(); + void report_resume(); /********************* ** Device_reporter ** @@ -174,6 +177,7 @@ void Driver::Common::update_report() { if (_dev_reporter.constructed()) _dev_reporter->generate([&] (Xml_generator & xml) { + xml.attribute("resumed", _resume_counter); _devices.generate(xml); }); if (_iommu_reporter.constructed()) _iommu_reporter->generate([&] (Xml_generator & xml) { @@ -182,6 +186,12 @@ void Driver::Common::update_report() } +void Driver::Common::report_resume() +{ + _resume_counter ++; + update_report(); +} + void Driver::Common::disable_device(Device const & device) { _io_mmu_devices.for_each([&] (Io_mmu & io_mmu) { diff --git a/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc b/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc index 5635f175ca..98c2860694 100644 --- a/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc +++ b/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc @@ -24,6 +24,7 @@ struct Driver::Main Attached_rom_dataspace _config_rom { _env, "config" }; Attached_rom_dataspace _acpi_rom { _env, "acpi" }; Attached_rom_dataspace _system_rom { _env, "system" }; + Attached_rom_dataspace _sleep_rom { _env, "sleep_states" }; Common _common { _env, _config_rom }; Signal_handler
_config_handler { _env.ep(), *this, &Main::_handle_config }; @@ -33,6 +34,7 @@ struct Driver::Main Intel::Io_mmu_factory _intel_iommu { _env, _common.io_mmu_factories() }; void _handle_config(); + void _suspend(); void _reset(); void _system_update(); @@ -40,10 +42,13 @@ struct Driver::Main : _env(e) { _config_rom.sigh(_config_handler); - _acpi_rom.sigh(_system_handler); + _acpi_rom .sigh(_system_handler); _system_rom.sigh(_system_handler); + _sleep_rom .sigh(_system_handler); + _handle_config(); _system_update(); + _common.acquire_io_mmu_devices(); _common.announce_service(); } @@ -53,13 +58,19 @@ struct Driver::Main void Driver::Main::_handle_config() { _config_rom.update(); - _common.handle_config(_config_rom.xml()); + + if (_config_rom.valid()) + _common.handle_config(_config_rom.xml()); } void Driver::Main::_reset() { _acpi_rom.update(); + + if (!_acpi_rom.valid()) + return; + _acpi_rom.xml().with_optional_sub_node("reset", [&] (Xml_node reset) { uint16_t const io_port = reset.attribute_value("io_port", 0); @@ -79,8 +90,68 @@ void Driver::Main::_reset() void Driver::Main::_system_update() { _system_rom.update(); - if (_system_rom.xml().attribute_value("state", String<16>()) == "reset") + + if (!_system_rom.valid()) + return; + + auto const state = _system_rom.xml().attribute_value("state", String<16>()); + + if (state == "reset") _reset(); + + if (state == "suspend") { + try { _suspend(); } catch (...) { error("suspend failed"); } + /* report independent of result */ + _common.report_resume(); + } +} + + +void Driver::Main::_suspend() +{ + _sleep_rom .update(); + + if (!_sleep_rom.valid()) + return; + + struct Client: Genode::Rpc_client + { + explicit Client(Genode::Capability cap) + : Rpc_client(cap) { } + + Pd_session::Managing_system_state system_control(Pd_session::Managing_system_state const &state) override { + return call(state); } + } system_control { _env.pd().system_control_cap(Affinity::Location()) }; + + _sleep_rom.xml().with_sub_node("S3", [&] (auto const &node) { + + auto const typea = "SLP_TYPa"; + auto const typeb = "SLP_TYPb"; + auto const valid = node.attribute_value("supported", false) && + node.has_attribute(typea) && + node.has_attribute(typeb); + + if (!valid) + return; + + auto s3_sleep_typea = uint8_t(node.attribute_value(typea, 0u)); + auto s3_sleep_typeb = uint8_t(node.attribute_value(typeb, 0u)); + + Pd_session::Managing_system_state in { }, out { }; + + in.trapno = Pd_session::Managing_system_state::ACPI_SUSPEND_REQUEST; + in.ip = s3_sleep_typea; + in.sp = s3_sleep_typeb; + + out = system_control.system_control(in); + + if (!out.trapno) + error("S3 suspend failed"); + else + log("resumed from S3"); + }, [&] { + warning("S3 suspend not supported"); + }); }