platform_drv(x86): support dynamic reconfiguration

Fixes #3989
This commit is contained in:
Alexander Boettcher
2020-12-15 13:31:07 +01:00
committed by Norman Feske
parent a981fb864c
commit 6789ce8b83
5 changed files with 147 additions and 29 deletions

View File

@@ -245,6 +245,9 @@ proc platform_drv_config {} {
append_if [have_board pc] drv_config {
<service name="ROM" label="acpi"> <child name="acpi_report_rom"/> </service>}
append_if [expr [have_spec x86]] drv_config {
<service name="Report"> <child name="acpi_report_rom"/> </service>}
append_if [expr [have_board rpi] || [have_board pc]] drv_config {
<service name="Timer"> <any-child/> </service>}

View File

@@ -42,8 +42,12 @@ struct Platform::Main
Genode::Constructible<Genode::Attached_rom_dataspace> system_state { };
Genode::Constructible<Genode::Attached_rom_dataspace> acpi_ready { };
Genode::Signal_handler<Platform::Main> _acpi_report;
Genode::Signal_handler<Platform::Main> _system_report;
Signal_handler<Main> _acpi_report { _env.ep(), *this,
&Main::acpi_update };
Signal_handler<Main> _system_report { _env.ep(), *this,
&Main::system_update };
Signal_handler<Main> _config_handler { _env.ep(), *this,
&Main::config_update };
Genode::Capability<Genode::Typed_root<Platform::Session_component> > root_cap { };
@@ -52,14 +56,22 @@ struct Platform::Main
void acpi_update()
{
acpi_rom->update();
if (!root.constructed()) {
acpi_rom->update();
if (!acpi_rom->valid() || root.constructed())
if (!acpi_rom->valid())
return;
root.construct(_env, sliced_heap, _config,
acpi_rom->local_addr<const char>(), _acpi_platform);
}
if (root_cap.valid())
return;
const char * report_addr = acpi_rom->local_addr<const char>();
root.construct(_env, sliced_heap, _config, report_addr, _acpi_platform);
/* don't announce service if no policy entry is available */
if (!root->config_with_policy())
return;
root_cap = _env.ep().manage(*root);
@@ -92,6 +104,23 @@ struct Platform::Main
}
}
void config_update()
{
_config.update();
if (!_config.valid())
return;
if (!root_cap.valid())
acpi_update();
if (root.constructed()) {
root->generate_pci_report();
root->config_update();
}
}
static bool acpi_platform(Genode::Env & env)
{
using Name = String<32>;
@@ -110,13 +139,12 @@ struct Platform::Main
Main(Genode::Env &env)
:
_env(env),
_acpi_report(_env.ep(), *this, &Main::acpi_update),
_system_report(_env.ep(), *this, &Main::system_update),
_acpi_platform(acpi_platform(env))
{
const Genode::Xml_node config = _config.xml();
_config.sigh(_config_handler);
_acpi_ready = config.attribute_value("acpi_ready", false);
if (_config.valid())
_acpi_ready = _config.xml().attribute_value("acpi_ready", false);
if (_acpi_ready) {
acpi_ready.construct(env, "acpi_ready");

View File

@@ -86,6 +86,8 @@ class Nonpci::Ps2 : public Platform::Device_component
{
return Genode::Io_mem_session_capability();
}
virtual String<5> name() const override { return "PS2"; }
};
@@ -123,6 +125,8 @@ class Nonpci::Pit : public Platform::Device_component
return Genode::Io_port_session_capability();
}
virtual String<5> name() const override { return "PIT"; }
};

View File

@@ -547,6 +547,17 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
Device_config device_config() const { return _device_config; }
Genode::addr_t config_space() const { return _config_space; }
virtual String<5> name() const { return "PCI"; }
template <typename FUNC>
void for_each_device(FUNC const &fn) const
{
fn(*this);
for (auto *dev = this; dev; dev = dev->next()) {
fn(*dev); }
}
/**************************
** PCI-device interface **
**************************/

View File

@@ -214,13 +214,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
_env.pd(), _ram_guard, _cap_guard };
Genode::Heap _md_alloc;
Genode::Session_label const _label;
Genode::Session_policy const _policy { _label, _config.xml() };
Genode::List<Device_component> _device_list { };
Platform::Pci_buses &_pci_bus;
Genode::Heap &_global_heap;
Pci::Config::Delayer &_delayer;
Device_bars_pool &_devices_bars;
bool _iommu;
bool _msi_usage { true };
/**
* Registry of RAM dataspaces allocated by the session
@@ -325,8 +325,10 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
{
using namespace Genode;
Session_policy const policy { _label, _config.xml() };
try {
_policy.for_each_sub_node("device", [&] (Xml_node dev) {
policy.for_each_sub_node("device", [&] (Xml_node dev) {
/* enforce restriction based on name name */
if (dev.attribute_value("name", Genode::String<10>()) == name)
@@ -373,7 +375,9 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
using namespace Genode;
try {
_policy.for_each_sub_node("pci", [&] (Xml_node node) {
Session_policy const policy { _label, _config.xml() };
policy.for_each_sub_node("pci", [&] (Xml_node node) {
if (_bdf_exactly_specified(node)) {
if (_bdf_matches(node, bdf))
@@ -488,8 +492,18 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
/* subtract the RPC session and session dataspace capabilities */
_cap_guard.withdraw(Genode::Cap_quota{2});
check_for_policy();
}
void check_for_policy()
{
Session_policy const policy { _label, _config.xml() };
typedef Genode::String<10> Mode;
_msi_usage = policy.attribute_value("irq_mode", Mode()) != "nomsi";
/* check policy for non-pci devices */
_policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) {
policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) {
if (!device_node.has_attribute("name")) {
Genode::error("'", _label, "' - device node "
@@ -509,7 +523,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
});
/* pci devices */
_policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) {
policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) {
enum { INVALID_CLASS = 0x1000000U };
@@ -571,6 +585,40 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
});
}
bool policy_valid()
{
try {
/* check that policy is available */
check_for_policy();
} catch (...) {
return false;
}
/* check that device entries in policy are still permitted */
if (!_device_list.first())
return true;
bool result = true;
_device_list.first()->for_each_device([&](auto const &dev) {
/* Non PCI devices */
if (!dev.device_config().valid()) {
if (!permit_device(dev.name().string()))
result = false;
return;
}
/* PCI devices */
if (!permit_device(dev.device_config().bdf(),
dev.device_config().class_code()))
result = false;
});
return result;
}
/**
* Destructor
*/
@@ -610,11 +658,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
/**
* Check whether msi usage was explicitly switched off
*/
bool msi_usage()
{
typedef Genode::String<10> Mode;
return _policy.attribute_value("irq_mode", Mode()) != "nomsi";
}
bool msi_usage() const { return _msi_usage; }
/***************************
@@ -821,7 +865,8 @@ class Platform::Root : public Genode::Root_component<Session_component>
Device_bars_pool _devices_bars { };
Genode::Constructible<Platform::Pci_buses> _buses { };
bool _iommu { false };
bool _iommu { false };
bool _pci_reported { false };
struct Timer_delayer : Pci::Config::Delayer, Timer::Connection
{
@@ -830,6 +875,8 @@ class Platform::Root : public Genode::Root_component<Session_component>
void usleep(uint64_t us) override { Timer::Connection::usleep(us); }
} _delayer { _env };
Genode::Registry<Genode::Registered<Session_component> > _sessions { };
void _parse_report_rom(Genode::Env &env, const char * acpi_rom,
bool acpi_platform)
{
@@ -1014,10 +1061,14 @@ class Platform::Root : public Genode::Root_component<Session_component>
Session_component *_create_session(const char *args) override
{
try {
return new (md_alloc())
Session_component(_env, _config, *_pci_confspace, *_buses,
_heap, _delayer, _devices_bars, args,
_iommu);
return new (md_alloc())
Genode::Registered<Session_component>(_sessions, _env,
_config,
*_pci_confspace,
*_buses, _heap,
_delayer,
_devices_bars, args,
_iommu);
}
catch (Genode::Session_policy::No_policy_defined) {
Genode::error("Invalid session request, no matching policy for ",
@@ -1065,8 +1116,16 @@ class Platform::Root : public Genode::Root_component<Session_component>
_construct_buses();
if (config.xml().has_sub_node("report")
&& config.xml().sub_node("report").attribute_value("pci", true)) {
generate_pci_report();
}
void generate_pci_report()
{
if (!_pci_reported && _config.valid() &&
_config.xml().has_sub_node("report") &&
_config.xml().sub_node("report").attribute_value("pci", false)) {
_pci_reported = true;
_pci_reporter.construct(_env, "pci", "pci");
@@ -1091,7 +1150,9 @@ class Platform::Root : public Genode::Root_component<Session_component>
using Genode::Hex;
xml.node("device", [&] () {
xml.attribute("bdf" , String<8>(Hex(bus, Hex::Prefix::OMIT_PREFIX), ":", Hex(device, Hex::Prefix::OMIT_PREFIX), ".", function));
xml.attribute("bus" , String<5>(Hex(bus)));
xml.attribute("device" , String<5>(Hex(device)));
xml.attribute("function" , String<5>(Hex(function)));
xml.attribute("vendor_id" , String<8>(Hex(config.vendor_id())));
xml.attribute("device_id" , String<8>(Hex(config.device_id())));
xml.attribute("class_code", String<12>(Hex(config.class_code())));
@@ -1118,4 +1179,15 @@ class Platform::Root : public Genode::Root_component<Session_component>
});
}
}
bool config_with_policy() const {
return _config.valid() && _config.xml().has_sub_node("policy"); }
void config_update()
{
_sessions.for_each([&](auto &session) {
if (!session.policy_valid())
destroy(session);
});
}
};