mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 11:27:29 +00:00
lx_kit: add Platform session wrapper for x86
The x86 platform driver uses a different API than the one for ARM for which the lx_kit glue code was designed. Since the x86 platform driver will eventually adopt a similar interface we implement a wrapper that encapsulates the old interface. Ref genodelabs/genode#4411
This commit is contained in:
parent
77ab7bf68b
commit
2515196b82
@ -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 <util/mmio.h>
|
||||
#include <util/string.h>
|
||||
#include <base/exception.h>
|
||||
#include <io_mem_session/client.h>
|
||||
#include <irq_session/client.h>
|
||||
|
||||
namespace Platform {
|
||||
struct Connection;
|
||||
|
||||
using namespace Genode;
|
||||
}
|
||||
|
||||
#define Platform Legacy_platform
|
||||
#include <legacy/x86/platform_session/connection.h>
|
||||
#undef Platform
|
||||
|
||||
|
||||
struct Platform::Connection
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
char _devices_node_buffer[4096u] { };
|
||||
Constructible<Xml_node> _devices_node { };
|
||||
|
||||
Constructible<Legacy_platform::Connection> _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<Device> _devices_list[MAX_DEVICES] { };
|
||||
|
||||
Legacy_platform::Device_capability device_cap(char const *name);
|
||||
|
||||
Connection(Env &);
|
||||
|
||||
/********************************
|
||||
** Platform session interface **
|
||||
********************************/
|
||||
|
||||
void update();
|
||||
|
||||
template <typename FN> 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_ */
|
@ -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 <base/attached_dataspace.h>
|
||||
#include <base/exception.h>
|
||||
#include <io_mem_session/client.h>
|
||||
#include <irq_session/client.h>
|
||||
#include <platform_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
#include <util/string.h>
|
||||
|
||||
|
||||
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_dataspace> _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 <typename T>
|
||||
T *local_addr() { return reinterpret_cast<T *>(_local_addr()); }
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Irq : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Index { unsigned value; };
|
||||
|
||||
private:
|
||||
|
||||
Device &_device;
|
||||
Index _index;
|
||||
|
||||
Constructible<Irq_session_client> _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_ */
|
413
repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc
Normal file
413
repos/dde_linux/src/lib/lx_kit/spec/x86/platform.cc
Normal file
@ -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 <base/ram_allocator.h>
|
||||
#include <util/xml_generator.h>
|
||||
|
||||
/* DDE includes */
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_kit/device.h>
|
||||
#include <platform_session/device.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
using Str = String<16>;
|
||||
|
||||
template <typename T, typename... TAIL>
|
||||
static Str to_string(T const &arg, TAIL &&... args)
|
||||
{
|
||||
return Str(arg, args...);
|
||||
}
|
||||
|
||||
|
||||
template <typename FN>
|
||||
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 <typename FN>
|
||||
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<void*>();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user