diff --git a/repos/dde_linux/src/include/spec/x86/lx_kit/platform_session/connection.h b/repos/dde_linux/src/include/spec/x86/lx_kit/platform_session/connection.h new file mode 100644 index 0000000000..2929a19fda --- /dev/null +++ b/repos/dde_linux/src/include/spec/x86/lx_kit/platform_session/connection.h @@ -0,0 +1,80 @@ +/* + * \brief Dummy - platform session device interface + * \author Stefan Kalkowski + * \date 2022-01-07 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _PLATFORM_SESSION__CONNECTION_H_ +#define _PLATFORM_SESSION__CONNECTION_H_ + +#include +#include +#include +#include +#include + +namespace Platform { + struct Connection; + + using namespace Genode; +} + +#define Platform Legacy_platform +#include +#undef Platform + + +struct Platform::Connection +{ + Env &_env; + + char _devices_node_buffer[4096u] { }; + Constructible _devices_node { }; + + Constructible _legacy_platform { }; + struct Device + { + using Name = String<16>; + + Name name { }; + Legacy_platform::Device_capability cap { }; + + Device(Name const &name, Legacy_platform::Device_capability cap) + : name { name }, cap { cap } { } + }; + + enum : unsigned char { MAX_DEVICES = 4 }; + Constructible _devices_list[MAX_DEVICES] { }; + + Legacy_platform::Device_capability device_cap(char const *name); + + Connection(Env &); + + /******************************** + ** Platform session interface ** + ********************************/ + + void update(); + + template void with_xml(FN const & fn) + { + if (_devices_node.constructed()) + fn(*_devices_node); + } + + Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache); + + void free_dma_buffer(Ram_dataspace_capability); + + addr_t dma_addr(Ram_dataspace_capability); +}; + + +#endif /* _PLATFORM_SESSION__CONNECTION_H_ */ diff --git a/repos/dde_linux/src/include/spec/x86/lx_kit/platform_session/device.h b/repos/dde_linux/src/include/spec/x86/lx_kit/platform_session/device.h new file mode 100644 index 0000000000..9fcf7301a4 --- /dev/null +++ b/repos/dde_linux/src/include/spec/x86/lx_kit/platform_session/device.h @@ -0,0 +1,148 @@ +/* + * \brief Dummy - platform session device interface + * \author Stefan Kalkowski + * \date 2022-01-07 + */ + +/* + * Copyright (C) 2021 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _PLATFORM_SESSION__DEVICE_H_ +#define _PLATFORM_SESSION__DEVICE_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + + +namespace Platform { + struct Connection; + class Device; + + using namespace Genode; +} + + +class Platform::Device : Interface, Noncopyable +{ + public: + + struct Range { addr_t start; size_t size; }; + + struct Mmio; + struct Irq; + struct Config_space; + + using Name = String<64>; + + private: + + Connection &_platform; + Legacy_platform::Device_capability _device_cap { }; + Name _name { }; + + public: + + int _bar_checked_for_size[6] { }; + + struct Index { unsigned value; }; + + explicit Device(Connection &platform) + : _platform { platform } { } + + struct Type { String<64> name; }; + + Device(Connection &platform, Type type); + + Device(Connection &platform, Name name); + + ~Device() { } + + Name const &name() const + { + return _name; + } +}; + + +class Platform::Device::Mmio : Range +{ + public: + + struct Index { unsigned value; }; + + private: + + Constructible _attached_ds { }; + + void *_local_addr(); + + Device &_device; + Index _index; + + public: + + Mmio(Device &device, Index index) + : _device { device }, _index { index } { } + + explicit Mmio(Device &device) + : _device { device }, _index { ~0u } { } + + size_t size() const; + + template + T *local_addr() { return reinterpret_cast(_local_addr()); } +}; + + +class Platform::Device::Irq : Noncopyable +{ + public: + + struct Index { unsigned value; }; + + private: + + Device &_device; + Index _index; + + Constructible _irq { }; + + public: + + Irq(Device &device, Index index); + + explicit Irq(Device &device) + : _device { device }, _index { ~0u } { } + + void ack(); + void sigh(Signal_context_capability); + void sigh_omit_initial_signal(Signal_context_capability); +}; + + +class Platform::Device::Config_space : Noncopyable +{ + public: + + Device &_device; + + enum class Access_size : unsigned { ACCESS_8BIT, ACCESS_16BIT, ACCESS_32BIT }; + + Config_space(Device &device) : _device { device } { } + + unsigned read(unsigned char address, Access_size size); + void write(unsigned char address, unsigned value, Access_size size); +}; + + +#endif /* _PLATFORM_SESSION__DEVICE_H_ */ diff --git a/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc b/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc new file mode 100644 index 0000000000..662ef05981 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc @@ -0,0 +1,413 @@ +/* + * \brief Legacy platform session wrapper + * \author Josef Soentgen + * \date 2022-01-14 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* Genode includes */ +#include +#include + +/* DDE includes */ +#include +#include +#include + + +using namespace Genode; + + +using Str = String<16>; + +template +static Str to_string(T const &arg, TAIL &&... args) +{ + return Str(arg, args...); +} + + +template +static void scan_resources(Legacy_platform::Device &device, + FN const &fn) +{ + using R = Legacy_platform::Device::Resource; + for (unsigned resource_id = 0; resource_id < 6; resource_id++) { + + R const resource = device.resource(resource_id); + if (resource.type() != R::INVALID) + fn(resource_id, resource); + } +} + + +static Str create_device_node(Xml_generator &xml, + Legacy_platform::Device &device) +{ + struct { + char const *key; + unsigned char value; + } bdf[3] = { + { .key = "bus", .value = 0u }, + { .key = "dev", .value = 0u }, + { .key = "func", .value = 0u }, + }; + device.bus_address(&bdf[0].value, &bdf[1].value, &bdf[2].value); + + /* start arbitrarily and count up */ + static unsigned char irq = 8; + + using namespace Genode; + + Str name = to_string("pci-", + Hex(bdf[0].value, Hex::OMIT_PREFIX), ":", + Hex(bdf[1].value, Hex::OMIT_PREFIX), ".", + Hex(bdf[2].value, Hex::OMIT_PREFIX)); + + xml.node("device", [&] () { + xml.attribute("name", name); + xml.attribute("type", "pci"); + + for (auto i : bdf) { + xml.node("property", [&] () { + xml.attribute("name", i.key); + xml.attribute("value", to_string(i.value)); + }); + } + + xml.node("irq", [&] () { + xml.attribute("number", irq++); + }); + + using R = Legacy_platform::Device::Resource; + + scan_resources(device, [&] (unsigned id, R const &r) { + + xml.node(r.type() == R::MEMORY ? "io_mem" : "io_port", [&] () { + xml.attribute("phys_addr", to_string(Hex(r.base()))); + xml.attribute("size", to_string(Hex(r.size()))); + xml.attribute("bar", id); + }); + }); + }); + + return name; +} + + +Platform::Connection::Connection(Env &env) +: + _env { env } +{ + try { + _legacy_platform.construct(env); + } catch (...) { + error("could not construct legacy platform connection"); + throw; + } + + /* empirically determined */ + _legacy_platform->upgrade_ram(32768); + _legacy_platform->upgrade_caps(8); + + Xml_generator xml { _devices_node_buffer, + sizeof (_devices_node_buffer), + "devices", [&] () { + _legacy_platform->with_upgrade([&] () { + + /* scan the virtual bus but limit to MAX_DEVICES */ + Legacy_platform::Device_capability cap { }; + for (auto &dev : _devices_list) { + + cap = _legacy_platform->next_device(cap, 0x0u, 0x0u); + if (!cap.valid()) break; + + Legacy_platform::Device_client device { cap }; + Str name = create_device_node(xml, device); + dev.construct(name, cap); + } + }); + } }; + + _devices_node.construct(_devices_node_buffer, + sizeof (_devices_node_buffer)); +} + + +Legacy_platform::Device_capability +Platform::Connection::device_cap(char const *name) +{ + for (auto const &dev : _devices_list) { + if (!dev.constructed()) + continue; + + if (dev->name == name) + return dev->cap; + } + + return Legacy_platform::Device_capability(); +} + + +void Platform::Connection::update() { } + + +Ram_dataspace_capability +Platform::Connection::alloc_dma_buffer(size_t size, Cache) +{ + return _legacy_platform->with_upgrade([&] () { + return _legacy_platform->alloc_dma_buffer(size, Cache::UNCACHED); + }); +} + + +void Platform::Connection::free_dma_buffer(Ram_dataspace_capability ds_cap) +{ + _legacy_platform->free_dma_buffer(ds_cap); +} + + +addr_t Platform::Connection::dma_addr(Ram_dataspace_capability ds_cap) +{ + return _legacy_platform->dma_addr(ds_cap); +} + + +static Legacy_platform::Device::Access_size convert(Platform::Device::Config_space::Access_size size) +{ + using PAS = Platform::Device::Config_space::Access_size; + using LAS = Legacy_platform::Device::Access_size; + switch (size) { + case PAS::ACCESS_8BIT: + return LAS::ACCESS_8BIT; + case PAS::ACCESS_16BIT: + return LAS::ACCESS_16BIT; + case PAS::ACCESS_32BIT: + return LAS::ACCESS_32BIT; + } + + return LAS::ACCESS_8BIT; +} + + +template +static void apply(Platform::Device const &device, + Xml_node const &devices, + FN const &fn) +{ + using namespace Genode; + using N = Platform::Device::Name; + + auto lookup_device = [&] (Xml_node const &node) { + if (node.attribute_value("name", N()) == device.name()) + fn(node); + }; + + devices.for_each_sub_node("device", lookup_device); +} + + +static unsigned bar_size(Platform::Device const &dev, + Xml_node const &devices, unsigned bar) +{ + if (bar > 6) + return 0; + + using namespace Genode; + + unsigned val = 0; + apply(dev, devices, [&] (Xml_node device) { + device.for_each_sub_node("io_mem", [&] (Xml_node node) { + if (node.attribute_value("bar", 6u) != bar) + return; + + val = node.attribute_value("size", 0u); + }); + }); + + return val; +} + + +static unsigned char irq_line(Platform::Device const &dev, + Xml_node const &devices) +{ + enum : unsigned char { INVALID_IRQ_LINE = 0xffu }; + unsigned char irq = INVALID_IRQ_LINE; + + apply(dev, devices, [&] (Xml_node device) { + device.for_each_sub_node("irq", [&] (Xml_node node) { + irq = node.attribute_value("number", (unsigned char)INVALID_IRQ_LINE); + }); + }); + + return irq; +} + + +Platform::Device::Device(Connection &platform, Type) +: _platform { platform } { } + + +Platform::Device::Device(Connection &platform, Name name) +: + _platform { platform }, + _device_cap { _platform.device_cap(name.string()) }, + _name { name } +{ + if (!_device_cap.valid()) { + error(__func__, ": could not get device capability"); + throw -1; + } +} + + +unsigned Platform::Device::Config_space::read(unsigned char address, + Access_size size) +{ + // 32bit BARs only for now + if (address >= 0x10 && address <= 0x24) { + unsigned const bar = (address - 0x10) / 4; + if (_device._bar_checked_for_size[bar]) { + _device._bar_checked_for_size[bar] = 0; + return bar_size(_device, *_device._platform._devices_node, bar); + } + } + + if (address == 0x3c) + return irq_line(_device, *_device._platform._devices_node); + + if (address == 0x34) + return 0u; + + if (address > 0x3f) + return 0u; + + Legacy_platform::Device::Access_size const as = convert(size); + Legacy_platform::Device_client device { _device._device_cap }; + return device.config_read(address, as); +} + + +void Platform::Device::Config_space::write(unsigned char address, + unsigned value, + Access_size size) +{ + // 32bit BARs only for now + if (address >= 0x10 && address <= 0x24) { + unsigned const bar = (address - 0x10) / 4; + if (value == 0xffffffffu) + _device._bar_checked_for_size[bar] = 1; + return; + } + + if (address != 0x04) + return; + + Legacy_platform::Device::Access_size const as = convert(size); + Legacy_platform::Device_client device { _device._device_cap }; + device.config_write(address, value, as); +} + + +size_t Platform::Device::Mmio::size() const +{ + return _attached_ds.constructed() ? _attached_ds->size() : 0; +} + + +void *Platform::Device::Mmio::_local_addr() +{ + if (!_attached_ds.constructed()) { + Legacy_platform::Device_client device { _device._device_cap }; + + uint8_t const id = + device.phys_bar_to_virt((uint8_t)_index.value); + + Io_mem_session_capability io_mem_cap = + device.io_mem(id); + + Io_mem_session_client io_mem_client(io_mem_cap); + + _attached_ds.construct(Lx_kit::env().env.rm(), + io_mem_client.dataspace()); + } + + return _attached_ds->local_addr(); +} + + +Platform::Device::Irq::Irq(Platform::Device &device, Index index) +: + _device { device }, + _index { index } +{ + Legacy_platform::Device_client client { _device._device_cap }; + + _irq.construct(client.irq((uint8_t)index.value)); +} + +void Platform::Device::Irq::ack() +{ + _irq->ack_irq(); +} + + +void Platform::Device::Irq::sigh(Signal_context_capability sigh) +{ + _irq->sigh(sigh); + _irq->ack_irq(); +} + + +void Platform::Device::Irq::sigh_omit_initial_signal(Signal_context_capability sigh) +{ + _irq->sigh(sigh); +} + + +static Platform::Device::Config_space::Access_size access_size(unsigned len) +{ + using AS = Platform::Device::Config_space::Access_size; + AS as = AS::ACCESS_8BIT; + if (len == 4) as = AS::ACCESS_32BIT; + else if (len == 2) as = AS::ACCESS_16BIT; + else as = AS::ACCESS_8BIT; + + return as; +} + + +bool Lx_kit::Device::read_config(unsigned reg, unsigned len, unsigned *val) +{ + if (!_pdev.constructed()) + enable(); + + if (!val) + return false; + + using AS = Platform::Device::Config_space::Access_size; + AS const as = access_size(len); + + *val = Platform::Device::Config_space(*_pdev).read((unsigned char)reg, as); + return true; +} + + +bool Lx_kit::Device::write_config(unsigned reg, unsigned len, unsigned val) +{ + if (!_pdev.constructed()) + return false; + + using AS = Platform::Device::Config_space::Access_size; + AS const as = access_size(len); + + Platform::Device::Config_space(*_pdev).write((unsigned char)reg, val, as); + return true; +}