diff --git a/repos/os/include/platform_session/device.h b/repos/os/include/platform_session/device.h index 47f24d684e..1d8950b9ee 100644 --- a/repos/os/include/platform_session/device.h +++ b/repos/os/include/platform_session/device.h @@ -21,6 +21,7 @@ #include #include #include +#include #include class Platform::Device : Interface, Noncopyable @@ -29,6 +30,7 @@ class Platform::Device : Interface, Noncopyable struct Mmio; struct Irq; + struct Io_port_range; typedef Platform::Session::Device_name Name; @@ -52,6 +54,11 @@ class Platform::Device : Interface, Noncopyable return _cap.call(index, range, cache); } + Io_port_session_capability _io_port_range(unsigned index) + { + return _cap.call(index); + } + Region_map &_rm() { return _platform._rm; } public: @@ -167,4 +174,33 @@ class Platform::Device::Irq : Noncopyable } }; + +class Platform::Device::Io_port_range : Noncopyable +{ + private: + + Io_port_session_client _io_port_range; + + public: + + struct Index { unsigned value; }; + + Io_port_range(Device &device, Index index) + : _io_port_range(device._io_port_range(index.value)) { } + + explicit Io_port_range(Device &device) + : Io_port_range(device, Index { 0 }) { } + + uint8_t inb(uint16_t addr) { return _io_port_range.inb(addr); }; + uint16_t inw(uint16_t addr) { return _io_port_range.inw(addr); }; + uint32_t inl(uint16_t addr) { return _io_port_range.inl(addr); }; + + void outb(uint16_t addr, uint8_t value) { + _io_port_range.outb(addr, value); }; + void outw(uint16_t addr, uint16_t value) { + _io_port_range.outw(addr, value); }; + void outl(uint16_t addr, uint32_t value) { + _io_port_range.outl(addr, value); }; +}; + #endif /* _INCLUDE__PLATFORM_SESSION__DEVICE_H_ */ diff --git a/repos/os/include/platform_session/platform_session.h b/repos/os/include/platform_session/platform_session.h index a826aafd1b..6818276188 100644 --- a/repos/os/include/platform_session/platform_session.h +++ b/repos/os/include/platform_session/platform_session.h @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace Platform { @@ -42,8 +43,10 @@ struct Platform::Device_interface : Interface GENODE_RPC(Rpc_irq, Irq_session_capability, irq, unsigned); GENODE_RPC(Rpc_io_mem, Io_mem_session_capability, io_mem, unsigned, Range &, Cache); + GENODE_RPC(Rpc_io_port_range, Io_port_session_capability, io_port_range, + unsigned); - GENODE_RPC_INTERFACE(Rpc_irq, Rpc_io_mem); + GENODE_RPC_INTERFACE(Rpc_irq, Rpc_io_mem, Rpc_io_port_range); }; diff --git a/repos/os/src/drivers/platform/device.cc b/repos/os/src/drivers/platform/device.cc index 83d47a40e6..c0adf9a25d 100644 --- a/repos/os/src/drivers/platform/device.cc +++ b/repos/os/src/drivers/platform/device.cc @@ -122,6 +122,12 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc) xml.attribute("number", irq.number); }); }); + _io_port_range_list.for_each([&] (Io_port_range & io_port_range) { + xml.node("io_port_range", [&] () { + xml.attribute("phys_addr", String<16>(Hex(io_port_range.addr))); + xml.attribute("size", String<16>(Hex(io_port_range.size))); + }); + }); _property_list.for_each([&] (Property & p) { xml.node("property", [&] () { xml.attribute("name", p.name); diff --git a/repos/os/src/drivers/platform/device.h b/repos/os/src/drivers/platform/device.h index 17772775e0..ff0a3fa249 100644 --- a/repos/os/src/drivers/platform/device.h +++ b/repos/os/src/drivers/platform/device.h @@ -35,6 +35,7 @@ namespace Driver { class Session_component; struct Irq_update_policy; struct Io_mem_update_policy; + struct Io_port_update_policy; struct Property_update_policy; struct Clock_update_policy; struct Reset_domain_update_policy; @@ -78,6 +79,15 @@ class Driver::Device : private List_model::Element Irq(unsigned number) : number(number) {} }; + struct Io_port_range : List_model::Element + { + uint16_t addr; + uint16_t size; + + Io_port_range(uint16_t addr, uint16_t size) + : addr(addr), size(size) {} + }; + struct Property : List_model::Element { using Name = Genode::String<64>; @@ -149,6 +159,13 @@ class Driver::Device : private List_model::Element fn(idx++, iomem.range); }); } + template void for_each_io_port_range(FN const & fn) + { + unsigned idx = 0; + _io_port_range_list.for_each([&] (Io_port_range const & ipr) { + fn(idx++, ipr.addr, ipr.size); }); + } + void report(Xml_generator &, Session_component &); protected: @@ -160,15 +177,16 @@ class Driver::Device : private List_model::Element friend class List_model; friend class List; - Name _name; - Type _type; - Owner _owner {}; - List_model _io_mem_list {}; - List_model _irq_list {}; - List_model _property_list {}; - List_model _clock_list {}; - List_model _power_domain_list {}; - List_model _reset_domain_list {}; + Name _name; + Type _type; + Owner _owner {}; + List_model _io_mem_list {}; + List_model _irq_list {}; + List_model _io_port_range_list {}; + List_model _property_list {}; + List_model _clock_list {}; + List_model _power_domain_list {}; + List_model _reset_domain_list {}; /* * Noncopyable @@ -290,6 +308,39 @@ struct Driver::Io_mem_update_policy : Genode::List_model::Update }; +struct Driver::Io_port_update_policy +: Genode::List_model::Update_policy +{ + Genode::Allocator & alloc; + + Io_port_update_policy(Genode::Allocator & alloc) : alloc(alloc) {} + + void destroy_element(Element & ipr) { + Genode::destroy(alloc, &ipr); } + + Element & create_element(Genode::Xml_node node) + { + uint16_t addr = node.attribute_value("address", 0); + uint16_t size = node.attribute_value("size", 0); + return *(new (alloc) Element(addr, size)); + } + + void update_element(Element &, Genode::Xml_node) {} + + static bool element_matches_xml_node(Element const & ipr, Genode::Xml_node node) + { + uint16_t addr = node.attribute_value("address", 0); + uint16_t size = node.attribute_value("size", 0); + return addr == ipr.addr && size == ipr.size; + } + + static bool node_is_element(Genode::Xml_node node) + { + return node.has_type("io_port_range"); + } +}; + + struct Driver::Property_update_policy : Genode::List_model::Update_policy { Genode::Allocator & alloc; diff --git a/repos/os/src/drivers/platform/device_component.cc b/repos/os/src/drivers/platform/device_component.cc index c8e3cb5fa1..5ec400f0de 100644 --- a/repos/os/src/drivers/platform/device_component.cc +++ b/repos/os/src/drivers/platform/device_component.cc @@ -81,6 +81,25 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx) } +Genode::Io_port_session_capability Device_component::io_port_range(unsigned idx) +{ + Io_port_session_capability cap; + + _io_port_range_registry.for_each([&] (Io_port_range & ipr) + { + if (ipr.idx != idx) + return; + + if (!ipr.io_port_range.constructed()) + ipr.io_port_range.construct(_session.env(), ipr.addr, ipr.size); + + cap = ipr.io_port_range->cap(); + }); + + return cap; +} + + Device_component::Device_component(Registry & registry, Driver::Session_component & session, Driver::Device & device) @@ -109,7 +128,7 @@ Device_component::Device_component(Registry & registry, _cap_quota += Irq_session::CAP_QUOTA; new (session.heap()) Irq(_irq_registry, idx, nr); }); - + device.for_each_io_mem([&] (unsigned idx, Range range) { session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA}); @@ -118,6 +137,17 @@ Device_component::Device_component(Registry & registry, _cap_quota += Io_mem_session::CAP_QUOTA; new (session.heap()) Io_mem(_io_mem_registry, idx, range); }); + + device.for_each_io_port_range([&] (unsigned idx, uint16_t addr, + uint16_t size) + { + session.ram_quota_guard().withdraw(Ram_quota{Io_port_session::RAM_QUOTA}); + _ram_quota += Io_port_session::RAM_QUOTA; + session.cap_quota_guard().withdraw(Cap_quota{Io_port_session::CAP_QUOTA}); + _cap_quota += Io_port_session::CAP_QUOTA; + new (session.heap()) Io_port_range(_io_port_range_registry, + idx, addr, size); + }); } catch(...) { _release_resources(); throw; diff --git a/repos/os/src/drivers/platform/device_component.h b/repos/os/src/drivers/platform/device_component.h index 6998cd8ed8..babefbef91 100644 --- a/repos/os/src/drivers/platform/device_component.h +++ b/repos/os/src/drivers/platform/device_component.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,22 @@ class Driver::Device_component : public Rpc_object::Element + { + unsigned idx; + uint16_t addr; + uint16_t size; + Constructible io_port_range {}; + + Io_port_range(Registry & registry, + unsigned idx, + uint16_t addr, + uint16_t size) + : + Registry::Element(registry, *this), + idx(idx), addr(addr), size(size) {} + }; + Device_component(Registry & registry, Session_component & session, Driver::Device & device); @@ -76,8 +93,9 @@ class Driver::Device_component : public Rpc_object::Element _reg_elem; Registry _irq_registry {}; Registry _io_mem_registry {}; + Registry _io_port_range_registry {}; void _release_resources(); diff --git a/repos/os/src/drivers/platform/device_model_policy.cc b/repos/os/src/drivers/platform/device_model_policy.cc index bb72ab98b2..a3e7dfac3c 100644 --- a/repos/os/src/drivers/platform/device_model_policy.cc +++ b/repos/os/src/drivers/platform/device_model_policy.cc @@ -28,6 +28,11 @@ void Device_model::destroy_element(Device & device) device._io_mem_list.destroy_all_elements(policy); } + { + Io_port_update_policy policy(_heap); + device._io_port_range_list.destroy_all_elements(policy); + } + { Property_update_policy policy(_heap); device._property_list.destroy_all_elements(policy); @@ -73,6 +78,11 @@ void Device_model::update_element(Device & device, device._io_mem_list.update_from_xml(policy, node); } + { + Io_port_update_policy policy(_heap); + device._io_port_range_list.update_from_xml(policy, node); + } + { Property_update_policy policy(_heap); device._property_list.update_from_xml(policy, node);