mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
legacy_platform_drv: ACPI devices in configuration
Known ACPI device resources can be statically configured on startup like follows. <config> <policy label_prefix="driver"> <device name="ACPI0000"/> </policy> <device name="ACPI0000" typee="acpi"> <irq number="99" mode="level" polarity="low"/> <io_mem address="0xfc000000" size="0x100000"/> <io_port_range address="0x4000" size="4"/> </device> </config> Fixes #4545
This commit is contained in:
parent
c5bdc1ccbe
commit
393766a931
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief PCI-device interface
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2008-01-28
|
||||
*/
|
||||
|
||||
@ -80,10 +81,10 @@ struct Platform::Device : Platform::Abstract_device
|
||||
{
|
||||
/*
|
||||
* Mask out the resource-description bits of the base
|
||||
* address register. I/O resources use the lowest 3
|
||||
* address register. I/O resources use the lowest 2
|
||||
* bits, memory resources use the lowest 4 bits.
|
||||
*/
|
||||
return _bar & ((type() == IO) ? ~7 : ~15);
|
||||
return _bar & ((type() == IO) ? ~3 : ~15);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,3 +182,26 @@ The driver provides for the PS2 and PIT device the IO_PORT and IRQ resources.
|
||||
! </policy>
|
||||
! </config>
|
||||
!</start>
|
||||
|
||||
Also, known ACPI device resources can be statically configured on
|
||||
startup like follows.
|
||||
|
||||
!<config>
|
||||
! <policy label_prefix="driver">
|
||||
! <device name="INT34C5"/>
|
||||
! <device name="ACPI0000"/>
|
||||
! </policy>
|
||||
!
|
||||
! <device hid="INT34C5" type="acpi">
|
||||
! <irq number="14" mode="level" polarity="low"/>
|
||||
! <io_mem address="0xfd690000" size="0x1000"/>
|
||||
! <io_mem address="0xfd6a0000" size="0x1000"/>
|
||||
! <io_mem address="0xfd6d0000" size="0x1000"/>
|
||||
! <io_mem address="0xfd6e0000" size="0x1000"/>
|
||||
! </device>
|
||||
! <device name="ACPI0000" type="acpi">
|
||||
! <irq number="99"/>
|
||||
! <io_mem address="0xfc000000" size="0x100000"/>
|
||||
! <io_port_range address="0x4000" size="4"/>
|
||||
! </device>
|
||||
!</config>
|
||||
|
207
repos/os/src/drivers/platform/legacy/x86/acpi_devices.cc
Normal file
207
repos/os/src/drivers/platform/legacy/x86/acpi_devices.cc
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* \brief ACPI device information from config
|
||||
* \author Christian Helmuth
|
||||
* \date 2022-05-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include "acpi_devices.h"
|
||||
|
||||
namespace Platform { namespace Acpi {
|
||||
struct Device_impl;
|
||||
|
||||
typedef String<16> Str;
|
||||
}}
|
||||
|
||||
|
||||
void Platform::Acpi::Device::Resource::print(Output &o) const
|
||||
{
|
||||
using Genode::print;
|
||||
switch (type) {
|
||||
case Type::IRQ:
|
||||
print(o, "IRQ [", base);
|
||||
print(o, " ", irq == Irq::EDGE ? "edge" : irq == Irq::LEVEL_LOW ? "level-low" : "level-high");
|
||||
print(o, "]");
|
||||
break;
|
||||
case Type::IOMEM:
|
||||
print(o, "IOMEM ");
|
||||
print(o, "[", Hex(base, Hex::Prefix::OMIT_PREFIX, Hex::PAD));
|
||||
print(o, "-", Hex(base + (size - 1), Hex::Prefix::OMIT_PREFIX, Hex::PAD));
|
||||
print(o, "]");
|
||||
break;
|
||||
case Type::IOPORT:
|
||||
print(o, "IOPORT ");
|
||||
print(o, "[", Hex((unsigned short)base, Hex::Prefix::OMIT_PREFIX, Hex::PAD));
|
||||
print(o, "-", Hex((unsigned short)(base + (size - 1)), Hex::Prefix::OMIT_PREFIX, Hex::PAD));
|
||||
print(o, "]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Platform::Acpi::Device_impl : private Registry<Device>::Element,
|
||||
public Platform::Acpi::Device
|
||||
{
|
||||
private:
|
||||
|
||||
Hid _hid; /* ACPI Spec 6.1.5 Hardware ID */
|
||||
|
||||
struct Resource_element : Registry<Resource_element>::Element
|
||||
{
|
||||
unsigned id;
|
||||
Resource res;
|
||||
|
||||
Resource_element(Registry<Resource_element> ®istry,
|
||||
unsigned id,
|
||||
Resource res)
|
||||
:
|
||||
Registry<Resource_element>::Element(registry, *this),
|
||||
id(id), res(res)
|
||||
{ }
|
||||
};
|
||||
|
||||
Registry<Resource_element> _resource_registry { };
|
||||
|
||||
Resource_result _lookup_resource(Resource::Type type, unsigned const id) const
|
||||
{
|
||||
Resource const *res = nullptr;
|
||||
_resource_registry.for_each([&] (Resource_element const &e) {
|
||||
if (e.res.type == type && e.id == id)
|
||||
res = &e.res;
|
||||
});
|
||||
|
||||
if (res)
|
||||
return *res;
|
||||
else
|
||||
return Invalid_resource { };
|
||||
}
|
||||
|
||||
unsigned _max_irq_id { 0 };
|
||||
unsigned _max_iomem_id { 0 };
|
||||
unsigned _max_ioport_id { 0 };
|
||||
|
||||
public:
|
||||
|
||||
Device_impl(Registry<Device> ®istry,
|
||||
Allocator &heap, Xml_node config)
|
||||
:
|
||||
Registry<Device>::Element(registry, *this),
|
||||
_hid(config.attribute_value("name", Hid("ACPI0000")))
|
||||
{
|
||||
config.for_each_sub_node("irq", [&] (Xml_node node) {
|
||||
auto irq = [&] (Str const &mode, Str const &polarity) {
|
||||
if (mode == "level") {
|
||||
if (polarity == "high")
|
||||
return Resource::Irq::LEVEL_HIGH;
|
||||
else
|
||||
return Resource::Irq::LEVEL_LOW;
|
||||
} else {
|
||||
return Resource::Irq::EDGE;
|
||||
}
|
||||
};
|
||||
new (heap)
|
||||
Resource_element {
|
||||
_resource_registry,
|
||||
_max_irq_id++,
|
||||
Resource {
|
||||
.type = Resource::Type::IRQ,
|
||||
.base = node.attribute_value("number", addr_t(0)),
|
||||
.irq = irq(node.attribute_value("mode", Str("unchanged")),
|
||||
node.attribute_value("polarity", Str("unchanged"))) } };
|
||||
});
|
||||
config.for_each_sub_node("io_mem", [&] (Xml_node node) {
|
||||
new (heap)
|
||||
Resource_element {
|
||||
_resource_registry,
|
||||
_max_iomem_id++,
|
||||
Resource {
|
||||
.type = Resource::Type::IOMEM,
|
||||
.base = node.attribute_value("address", addr_t(0)),
|
||||
.size = node.attribute_value("size", size_t(0)) } };
|
||||
});
|
||||
config.for_each_sub_node("io_port_range", [&] (Xml_node node) {
|
||||
new (heap)
|
||||
Resource_element {
|
||||
_resource_registry,
|
||||
_max_ioport_id++,
|
||||
Resource {
|
||||
.type = Resource::Type::IOPORT,
|
||||
.base = node.attribute_value("address", addr_t(0)),
|
||||
.size = node.attribute_value("size", size_t(0)) } };
|
||||
});
|
||||
}
|
||||
|
||||
~Device_impl() { error("unexpected call of ", __func__); }
|
||||
|
||||
/* Platform::Acpi::Device interface */
|
||||
|
||||
Hid hid() const override { return _hid; }
|
||||
|
||||
Resource_result resource(unsigned idx) const override
|
||||
{
|
||||
/*
|
||||
* Index of all IOMEM and IOPORT resources - no IRQ!
|
||||
*
|
||||
* first _max_iomem_id IOMEM, then _max_ioport_id IOPORT
|
||||
*/
|
||||
if (idx < _max_iomem_id)
|
||||
return iomem(idx);
|
||||
else if (idx < _max_iomem_id + _max_ioport_id)
|
||||
return ioport(idx - _max_iomem_id);
|
||||
else
|
||||
return Invalid_resource { };
|
||||
}
|
||||
|
||||
Resource_result irq(unsigned id) const override
|
||||
{
|
||||
return _lookup_resource(Resource::Type::IRQ, id);
|
||||
}
|
||||
|
||||
Resource_result iomem(unsigned id) const override
|
||||
{
|
||||
return _lookup_resource(Resource::Type::IOMEM, id);
|
||||
}
|
||||
|
||||
Resource_result ioport(unsigned id) const override
|
||||
{
|
||||
return _lookup_resource(Resource::Type::IOPORT, id);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Platform::Acpi::Device_registry::Lookup_result
|
||||
Platform::Acpi::Device_registry::lookup(Platform::Acpi::Device::Hid hid) const
|
||||
{
|
||||
Device const *found = nullptr;
|
||||
|
||||
this->for_each([&] (Device const &device) {
|
||||
if (device.hid() == hid)
|
||||
found = &device;
|
||||
});
|
||||
|
||||
if (found)
|
||||
return found;
|
||||
else
|
||||
return Lookup_failed { };
|
||||
}
|
||||
|
||||
|
||||
void Platform::Acpi::Device_registry::init_devices(Allocator &heap, Xml_node config)
|
||||
{
|
||||
/* init only once */
|
||||
if (_initialized)
|
||||
return;
|
||||
|
||||
config.for_each_sub_node("device", [&] (Xml_node node) {
|
||||
if (node.attribute_value("type", Str()) == "acpi")
|
||||
new (heap) Device_impl(*this, heap, node);
|
||||
});
|
||||
|
||||
_initialized = true;
|
||||
}
|
71
repos/os/src/drivers/platform/legacy/x86/acpi_devices.h
Normal file
71
repos/os/src/drivers/platform/legacy/x86/acpi_devices.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* \brief ACPI device information from config
|
||||
* \author Christian Helmuth
|
||||
* \date 2022-05-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <base/allocator.h>
|
||||
#include <base/registry.h>
|
||||
#include <util/xml_node.h>
|
||||
#include <util/attempt.h>
|
||||
|
||||
|
||||
namespace Platform { namespace Acpi {
|
||||
using namespace Genode;
|
||||
|
||||
class Device;
|
||||
|
||||
class Device_registry;
|
||||
} }
|
||||
|
||||
|
||||
struct Platform::Acpi::Device : Interface
|
||||
{
|
||||
typedef String<10> Hid; /* ACPI Spec 6.1.5 Hardware ID */
|
||||
|
||||
struct Resource
|
||||
{
|
||||
enum class Type { IRQ, IOMEM, IOPORT };
|
||||
|
||||
enum class Irq { EDGE, LEVEL_LOW, LEVEL_HIGH };
|
||||
|
||||
Type type;
|
||||
addr_t base;
|
||||
|
||||
union {
|
||||
size_t size;
|
||||
Irq irq;
|
||||
};
|
||||
|
||||
void print(Output &o) const;
|
||||
};
|
||||
|
||||
enum struct Invalid_resource { };
|
||||
typedef Attempt<Resource, Invalid_resource> Resource_result;
|
||||
|
||||
virtual Hid hid() const = 0;
|
||||
virtual Resource_result resource(unsigned idx) const = 0;
|
||||
virtual Resource_result irq(unsigned id) const = 0;
|
||||
virtual Resource_result iomem(unsigned id) const = 0;
|
||||
virtual Resource_result ioport(unsigned id) const = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Platform::Acpi::Device_registry : Genode::Registry<Device>
|
||||
{
|
||||
bool _initialized { false };
|
||||
|
||||
void init_devices(Allocator &heap, Xml_node config);
|
||||
|
||||
enum struct Lookup_failed { };
|
||||
typedef Attempt<Device const *, Lookup_failed> Lookup_result;
|
||||
|
||||
Lookup_result lookup(Device::Hid name) const;
|
||||
};
|
@ -167,7 +167,7 @@ class Platform::Irq_component : public Platform::Irq_proxy
|
||||
void Platform::Irq_session_component::ack_irq()
|
||||
{
|
||||
if (msi()) {
|
||||
_irq_conn->ack_irq();
|
||||
_msi_conn->ack_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -186,7 +186,9 @@ void Platform::Irq_session_component::ack_irq()
|
||||
Platform::Irq_session_component::Irq_session_component(unsigned irq,
|
||||
addr_t pci_config_space,
|
||||
Env &env,
|
||||
Allocator &heap)
|
||||
Allocator &heap,
|
||||
Irq_session::Trigger trigger,
|
||||
Irq_session::Polarity polarity)
|
||||
:
|
||||
_gsi(irq)
|
||||
{
|
||||
@ -197,11 +199,11 @@ Platform::Irq_session_component::Irq_session_component(unsigned irq,
|
||||
try {
|
||||
using namespace Genode;
|
||||
|
||||
_irq_conn.construct(env, msi, Irq_session::TRIGGER_UNCHANGED,
|
||||
_msi_conn.construct(env, msi, Irq_session::TRIGGER_UNCHANGED,
|
||||
Irq_session::POLARITY_UNCHANGED,
|
||||
pci_config_space);
|
||||
|
||||
_msi_info = _irq_conn->info();
|
||||
_msi_info = _msi_conn->info();
|
||||
if (_msi_info.type == Irq_session::Info::Type::MSI) {
|
||||
_gsi = msi;
|
||||
return;
|
||||
@ -216,9 +218,6 @@ Platform::Irq_session_component::Irq_session_component(unsigned irq,
|
||||
if (_gsi >= INVALID_IRQ)
|
||||
return;
|
||||
|
||||
Irq_session::Trigger trigger;
|
||||
Irq_session::Polarity polarity;
|
||||
|
||||
_gsi = Platform::Irq_override::irq_override(_gsi, trigger, polarity);
|
||||
if (_gsi != irq || trigger != Irq_session::TRIGGER_UNCHANGED ||
|
||||
polarity != POLARITY_UNCHANGED) {
|
||||
@ -241,7 +240,7 @@ Platform::Irq_session_component::Irq_session_component(unsigned irq,
|
||||
Platform::Irq_session_component::~Irq_session_component()
|
||||
{
|
||||
if (msi()) {
|
||||
_irq_conn->sigh(Signal_context_capability());
|
||||
_msi_conn->sigh(Signal_context_capability());
|
||||
|
||||
irq_alloc.free_msi(_gsi);
|
||||
return;
|
||||
@ -258,9 +257,9 @@ Platform::Irq_session_component::~Irq_session_component()
|
||||
|
||||
void Platform::Irq_session_component::sigh(Signal_context_capability sigh)
|
||||
{
|
||||
if (_irq_conn.constructed()) {
|
||||
if (_msi_conn.constructed()) {
|
||||
/* register signal handler for msi directly at parent */
|
||||
_irq_conn->sigh(sigh);
|
||||
_msi_conn->sigh(sigh);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -42,18 +42,21 @@ class Platform::Irq_session_component : public Rpc_object<Irq_session>,
|
||||
Platform::Irq_sigh _irq_sigh { };
|
||||
Irq_session::Info _msi_info { };
|
||||
|
||||
Constructible<Irq_connection> _irq_conn { };
|
||||
Constructible<Irq_connection> _msi_conn { };
|
||||
|
||||
public:
|
||||
|
||||
enum { INVALID_IRQ = 0xffU };
|
||||
|
||||
Irq_session_component(unsigned, addr_t, Env &, Allocator &heap);
|
||||
Irq_session_component(unsigned, addr_t, Env &, Allocator &heap,
|
||||
Trigger trigger = TRIGGER_UNCHANGED,
|
||||
Polarity polarity = POLARITY_UNCHANGED);
|
||||
|
||||
~Irq_session_component();
|
||||
|
||||
bool msi()
|
||||
{
|
||||
return _irq_conn.constructed() &&
|
||||
return _msi_conn.constructed() &&
|
||||
_msi_info.type == Irq_session::Info::Type::MSI;
|
||||
}
|
||||
|
||||
@ -136,9 +139,9 @@ class Platform::Irq_override : public List<Platform::Irq_override>::Element
|
||||
Irq_session::Trigger trigger() const { return _trigger; }
|
||||
Irq_session::Polarity polarity() const { return _polarity; }
|
||||
|
||||
static unsigned irq_override (unsigned irq,
|
||||
Irq_session::Trigger &trigger,
|
||||
Irq_session::Polarity &polarity)
|
||||
static unsigned irq_override(unsigned irq,
|
||||
Irq_session::Trigger &trigger,
|
||||
Irq_session::Polarity &polarity)
|
||||
{
|
||||
for (Irq_override *i = list()->first(); i; i = i->next())
|
||||
if (i->irq() == irq) {
|
||||
@ -147,8 +150,7 @@ class Platform::Irq_override : public List<Platform::Irq_override>::Element
|
||||
return i->gsi();
|
||||
}
|
||||
|
||||
trigger = Irq_session::TRIGGER_UNCHANGED;
|
||||
polarity = Irq_session::POLARITY_UNCHANGED;
|
||||
/* trigger and polarity not touched in this case! */
|
||||
return irq;
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief Platform driver for x86
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2008-01-28
|
||||
*/
|
||||
|
||||
@ -20,17 +21,26 @@
|
||||
#include "pci_session_component.h"
|
||||
#include "pci_device_config.h"
|
||||
#include "device_pd.h"
|
||||
#include "acpi_devices.h"
|
||||
|
||||
namespace Platform { struct Main; };
|
||||
namespace Platform {
|
||||
struct Main;
|
||||
|
||||
namespace Nonpci { void acpi_device_registry(Acpi::Device_registry &); }
|
||||
};
|
||||
|
||||
struct Platform::Main
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
Acpi::Device_registry _acpi_device_registry { };
|
||||
|
||||
/*
|
||||
* Use sliced heap to allocate each session component at a separate
|
||||
* dataspace.
|
||||
*/
|
||||
Env &_env;
|
||||
Sliced_heap sliced_heap { _env.ram(), _env.rm() };
|
||||
|
||||
Attached_rom_dataspace _config { _env, "config" };
|
||||
@ -73,7 +83,7 @@ struct Platform::Main
|
||||
});
|
||||
} catch (...) { }
|
||||
|
||||
root.construct(_env, sliced_heap, _config,
|
||||
root.construct(_env, _heap, sliced_heap, _config,
|
||||
acpi_rom->local_addr<const char>(), acpi_platform,
|
||||
msi_platform);
|
||||
}
|
||||
@ -143,6 +153,8 @@ struct Platform::Main
|
||||
root->generate_pci_report();
|
||||
root->config_update();
|
||||
}
|
||||
|
||||
_acpi_device_registry.init_devices(_heap, _config.xml());
|
||||
}
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
@ -165,6 +177,8 @@ struct Platform::Main
|
||||
config_update();
|
||||
acpi_update();
|
||||
system_update();
|
||||
|
||||
Nonpci::acpi_device_registry(_acpi_device_registry);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief Non PCI devices, e.g. PS2
|
||||
* \author Alexander Boettcher
|
||||
* \author Christian Helmuth
|
||||
* \date 2015-04-17
|
||||
*/
|
||||
|
||||
@ -13,6 +14,7 @@
|
||||
|
||||
#include "pci_session_component.h"
|
||||
#include "irq.h"
|
||||
#include "acpi_devices.h"
|
||||
|
||||
namespace Platform { namespace Nonpci { class Ps2; class Pit; } }
|
||||
|
||||
@ -85,7 +87,7 @@ class Platform::Nonpci::Ps2 : public Device_component
|
||||
return Io_mem_session_capability();
|
||||
}
|
||||
|
||||
String<5> name() const override { return "PS2"; }
|
||||
Device_name_string name() const override { return "PS2"; }
|
||||
};
|
||||
|
||||
|
||||
@ -124,7 +126,166 @@ class Platform::Nonpci::Pit : public Device_component
|
||||
return Io_port_session_capability();
|
||||
}
|
||||
|
||||
String<5> name() const override { return "PIT"; }
|
||||
Device_name_string name() const override { return "PIT"; }
|
||||
};
|
||||
|
||||
|
||||
namespace Platform { namespace Nonpci {
|
||||
class Acpi;
|
||||
|
||||
void acpi_device_registry(Platform::Acpi::Device_registry &);
|
||||
} }
|
||||
|
||||
|
||||
static Platform::Acpi::Device_registry *_acpi_device_registry;
|
||||
|
||||
void Platform::Nonpci::acpi_device_registry(Platform::Acpi::Device_registry ®istry)
|
||||
{
|
||||
_acpi_device_registry = ®istry;
|
||||
}
|
||||
|
||||
|
||||
class Platform::Nonpci::Acpi : public Device_component
|
||||
{
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
|
||||
Allocator &_session_heap;
|
||||
|
||||
Platform::Acpi::Device const &_acpi_device;
|
||||
|
||||
Irq_session_component *_irq0 = nullptr;
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Acpi(Acpi const &) = delete;
|
||||
Acpi &operator = (Acpi const &) = delete;
|
||||
|
||||
public:
|
||||
|
||||
Acpi(Platform::Acpi::Device const &acpi_device,
|
||||
Env &env,
|
||||
Attached_io_mem_dataspace &pciconf,
|
||||
Session_component &session,
|
||||
Allocator &session_heap,
|
||||
Allocator &global_heap,
|
||||
Pci::Config::Delayer &delayer,
|
||||
Device_bars_pool &devices_bars)
|
||||
:
|
||||
Device_component(env, pciconf, session, 0,
|
||||
global_heap, delayer, devices_bars),
|
||||
_env(env), _session_heap(session_heap), _acpi_device(acpi_device)
|
||||
{ }
|
||||
|
||||
Device_name_string name() const override { return _acpi_device.hid(); }
|
||||
|
||||
/* Platform::Device interface */
|
||||
|
||||
void bus_address(unsigned char *bus, unsigned char *dev,
|
||||
unsigned char *fn) override
|
||||
{
|
||||
*bus = 0; *dev = 0; *fn = 0;
|
||||
}
|
||||
|
||||
unsigned short vendor_id() override { return ~0; }
|
||||
|
||||
unsigned short device_id() override { return ~0; }
|
||||
|
||||
unsigned class_code() override { return ~0; }
|
||||
|
||||
Resource resource(int resource_id) override
|
||||
{
|
||||
using Acpi_device = Platform::Acpi::Device;
|
||||
|
||||
return _acpi_device.resource(resource_id).convert<Resource>(
|
||||
[&] (Acpi_device::Resource r) {
|
||||
/* craft artificial BAR values from resource info */
|
||||
switch (r.type) {
|
||||
case Acpi_device::Resource::Type::IOMEM:
|
||||
return Resource((r.base & 0xfffffff0) | 0b0000, r.size);
|
||||
|
||||
case Acpi_device::Resource::Type::IOPORT:
|
||||
return Resource((r.base & 0xfffffffc) | 0b01, r.size);
|
||||
|
||||
case Acpi_device::Resource::Type::IRQ:
|
||||
return Resource();
|
||||
}
|
||||
return Resource();
|
||||
},
|
||||
[&] (Acpi_device::Invalid_resource) { return Resource(); });
|
||||
}
|
||||
|
||||
unsigned config_read(unsigned char, Access_size) override
|
||||
{
|
||||
warning("ignore config_read from ACPI device ", _acpi_device.hid());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_write(unsigned char, unsigned, Access_size) override
|
||||
{
|
||||
warning("ignore config_write to ACPI device ", _acpi_device.hid());
|
||||
}
|
||||
|
||||
Irq_session_capability irq(uint8_t v_id) override
|
||||
{
|
||||
using Acpi_device = Platform::Acpi::Device;
|
||||
|
||||
/* TODO more than one IRQ */
|
||||
if (v_id != 0) {
|
||||
warning("ACPI device with more than one IRQ not supported (requested id ", v_id, ")");
|
||||
return Irq_session_capability();
|
||||
}
|
||||
if (_irq0) return _irq0->cap();
|
||||
|
||||
/* TODO needs try see pci_device.cc ::iomem() */
|
||||
return _acpi_device.irq(v_id).convert<Irq_session_capability>(
|
||||
[&] (Acpi_device::Resource r) {
|
||||
Platform::Irq_session_component &irq =
|
||||
*new(_session_heap)
|
||||
Platform::Irq_session_component(r.base, ~0UL, _env, _session_heap,
|
||||
Irq_session::TRIGGER_LEVEL,
|
||||
Irq_session::POLARITY_LOW);
|
||||
_env.ep().manage(irq);
|
||||
_irq0 = &irq;
|
||||
return irq.cap();
|
||||
},
|
||||
[&] (Acpi_device::Invalid_resource) { return Irq_session_capability(); });
|
||||
}
|
||||
|
||||
Io_port_session_capability io_port(uint8_t v_id) override
|
||||
{
|
||||
using Acpi_device = Platform::Acpi::Device;
|
||||
|
||||
/* TODO needs try see pci_device.cc ::iomem() */
|
||||
|
||||
return _acpi_device.ioport(v_id).convert<Io_port_session_capability>(
|
||||
[&] (Acpi_device::Resource r) {
|
||||
Io_port_connection &ioport =
|
||||
*new (_session_heap) Io_port_connection(_env, r.base, r.size);
|
||||
return ioport.cap();
|
||||
},
|
||||
[&] (Acpi_device::Invalid_resource) { return Io_port_session_capability(); });
|
||||
}
|
||||
|
||||
Io_mem_session_capability io_mem(uint8_t v_id,
|
||||
Cache /* ignored */,
|
||||
addr_t /* ignored */,
|
||||
size_t /* ignored */) override
|
||||
{
|
||||
using Acpi_device = Platform::Acpi::Device;
|
||||
|
||||
/* TODO needs try see pci_device.cc ::iomem() */
|
||||
|
||||
return _acpi_device.iomem(v_id).convert<Io_mem_session_capability>(
|
||||
[&] (Acpi_device::Resource r) {
|
||||
Io_mem_connection &iomem =
|
||||
*new (_session_heap) Io_mem_connection(_env, r.base, r.size);
|
||||
return iomem.cap();
|
||||
},
|
||||
[&] (Acpi_device::Invalid_resource) { return Io_mem_session_capability(); });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -136,20 +297,34 @@ Platform::Device_capability Platform::Session_component::device(Device_name cons
|
||||
if (!name.valid_string())
|
||||
return Device_capability();
|
||||
|
||||
char const * device_name = name.string();
|
||||
const char * devices [] = { "PS2", "PIT" };
|
||||
unsigned devices_i = 0;
|
||||
Device_name_string const device_name { name.string() };
|
||||
|
||||
for (; devices_i < sizeof(devices) / sizeof(devices[0]); devices_i++)
|
||||
if (!strcmp(device_name, devices[devices_i]))
|
||||
break;
|
||||
enum class Type { UNKNOWN, PS2, PIT, ACPI } device_type { Type::UNKNOWN };
|
||||
|
||||
if (devices_i >= sizeof(devices) / sizeof(devices[0])) {
|
||||
error("unknown '", device_name, " device name");
|
||||
Platform::Acpi::Device const *acpi_device = nullptr;
|
||||
|
||||
if (device_name == "PS2")
|
||||
device_type = Type::PS2;
|
||||
|
||||
else if (device_name == "PIT")
|
||||
device_type = Type::PIT;
|
||||
|
||||
else if (_acpi_device_registry)
|
||||
device_type = _acpi_device_registry->lookup(device_name).convert<Type>(
|
||||
[&] (Acpi::Device const *device) {
|
||||
acpi_device = device;
|
||||
return Type::ACPI;
|
||||
},
|
||||
[&] (Acpi::Device_registry::Lookup_failed) { return Type::UNKNOWN; });
|
||||
|
||||
bool const found = device_type != Type::UNKNOWN;
|
||||
|
||||
if (!found) {
|
||||
error("unknown device name '", device_name, "'");
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
if (!permit_device(devices[devices_i])) {
|
||||
if (!permit_device(device_name.string())) {
|
||||
error("denied access to device '", device_name, "' for "
|
||||
"session '", _label, "'");
|
||||
return Device_capability();
|
||||
@ -158,17 +333,24 @@ Platform::Device_capability Platform::Session_component::device(Device_name cons
|
||||
try {
|
||||
Device_component * dev = nullptr;
|
||||
|
||||
switch(devices_i) {
|
||||
case 0:
|
||||
switch (device_type) {
|
||||
case Type::PS2:
|
||||
dev = new (_md_alloc) Nonpci::Ps2(_env, _pciconf, *this,
|
||||
_global_heap, _delayer,
|
||||
_devices_bars);
|
||||
break;
|
||||
case 1:
|
||||
case Type::PIT:
|
||||
dev = new (_md_alloc) Nonpci::Pit(_env, _pciconf, *this,
|
||||
_global_heap, _delayer,
|
||||
_devices_bars);
|
||||
break;
|
||||
case Type::ACPI:
|
||||
dev = new (_md_alloc) Nonpci::Acpi(*acpi_device,
|
||||
_env, _pciconf, *this,
|
||||
_md_alloc,
|
||||
_global_heap, _delayer,
|
||||
_devices_bars);
|
||||
break;
|
||||
default:
|
||||
return Device_capability();
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
/*
|
||||
* \brief PCI device component implementation
|
||||
* \author Alexander Boettcher
|
||||
* \author Christian Helmuth
|
||||
* \date 2022-06-24
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -102,10 +104,24 @@ Genode::Io_mem_session_capability Platform::Device_component::io_mem(uint8_t con
|
||||
return Io_mem_session_capability();
|
||||
}
|
||||
|
||||
|
||||
unsigned Platform::Device_component::config_read(unsigned char address, Access_size size)
|
||||
{
|
||||
if (pci_device())
|
||||
return _device_config.read(_config_access, address, size,
|
||||
_device_config.DONT_TRACK_ACCESS);
|
||||
|
||||
return ~0;
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device_component::config_write(unsigned char address,
|
||||
unsigned value,
|
||||
Access_size size)
|
||||
{
|
||||
if (!pci_device())
|
||||
return;
|
||||
|
||||
/* white list of ports which we permit to write */
|
||||
switch (address) {
|
||||
case 0x40 ... 0xff:
|
||||
@ -164,7 +180,7 @@ Genode::Irq_session_capability Platform::Device_component::irq(uint8_t id)
|
||||
if (_irq_session)
|
||||
return _irq_session->cap();
|
||||
|
||||
if (!_device_config.valid()) {
|
||||
if (!pci_device()) {
|
||||
/* Non PCI devices */
|
||||
_irq_session = construct_at<Irq_session_component>(_mem_irq_component,
|
||||
_irq_line, ~0UL,
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief platform device component
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2008-01-28
|
||||
*/
|
||||
|
||||
@ -33,6 +34,8 @@ namespace Platform {
|
||||
class Device_component;
|
||||
class Session_component;
|
||||
|
||||
typedef String<10> Device_name_string;
|
||||
|
||||
typedef Registry<Registered<Device_config::Device_bars> > Device_bars_pool;
|
||||
}
|
||||
|
||||
@ -536,12 +539,15 @@ class Platform::Device_component : public Rpc_object<Platform::Device>,
|
||||
}
|
||||
}
|
||||
|
||||
if (!_device_config.valid())
|
||||
if (!pci_device())
|
||||
return;
|
||||
|
||||
_power_off();
|
||||
}
|
||||
|
||||
/* distinct non-PCI and PCI devices */
|
||||
bool pci_device() const { return _device_config.valid(); }
|
||||
|
||||
/****************************************
|
||||
** Methods used solely by pci session **
|
||||
****************************************/
|
||||
@ -549,7 +555,7 @@ class Platform::Device_component : public Rpc_object<Platform::Device>,
|
||||
Device_config device_config() const { return _device_config; }
|
||||
addr_t config_space() const { return _config_space; }
|
||||
|
||||
virtual String<5> name() const { return "PCI"; }
|
||||
virtual Device_name_string name() const { return "PCI"; }
|
||||
|
||||
template <typename FUNC>
|
||||
void for_each_device(FUNC const &fn) const
|
||||
@ -580,18 +586,14 @@ class Platform::Device_component : public Rpc_object<Platform::Device>,
|
||||
|
||||
Resource resource(int resource_id) override
|
||||
{
|
||||
if (pci_device())
|
||||
return _device_config.resource(resource_id).api_resource();
|
||||
|
||||
/* return invalid resource if device is invalid */
|
||||
if (!_device_config.valid())
|
||||
return Resource(0, 0);
|
||||
|
||||
return _device_config.resource(resource_id).api_resource();
|
||||
return Resource(0, 0);
|
||||
}
|
||||
|
||||
unsigned config_read(unsigned char address, Access_size size) override
|
||||
{
|
||||
return _device_config.read(_config_access, address, size,
|
||||
_device_config.DONT_TRACK_ACCESS);
|
||||
}
|
||||
unsigned config_read(unsigned char address, Access_size size) override;
|
||||
|
||||
void config_write(unsigned char address, unsigned value,
|
||||
Access_size size) override;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief PCI device configuration
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2008-01-29
|
||||
*/
|
||||
|
||||
@ -292,12 +293,12 @@ namespace Platform {
|
||||
/**
|
||||
* Return true if device is a PCI bridge
|
||||
*/
|
||||
bool pci_bridge() { return _header_type == HEADER_PCI_TO_PCI; }
|
||||
bool pci_bridge() const { return _header_type == HEADER_PCI_TO_PCI; }
|
||||
|
||||
/**
|
||||
* Return true if device is valid
|
||||
*/
|
||||
bool valid() { return _vendor_id != INVALID_VENDOR; }
|
||||
bool valid() const { return _vendor_id != INVALID_VENDOR; }
|
||||
|
||||
/**
|
||||
* Return resource description by resource ID
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief Platform session component
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2008-01-28
|
||||
*/
|
||||
|
||||
@ -218,7 +219,7 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
Session_label const _label;
|
||||
List<Device_component> _device_list { };
|
||||
Platform::Pci_buses &_pci_bus;
|
||||
Heap &_global_heap;
|
||||
Allocator &_global_heap;
|
||||
Pci::Config::Delayer &_delayer;
|
||||
Device_bars_pool &_devices_bars;
|
||||
bool const _iommu;
|
||||
@ -349,8 +350,8 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
try {
|
||||
policy.for_each_sub_node("device", [&] (Xml_node dev) {
|
||||
|
||||
/* enforce restriction based on name name */
|
||||
if (dev.attribute_value("name", String<10>()) == name)
|
||||
/* enforce restriction based on name */
|
||||
if (dev.attribute_value("name", Device_name_string()) == name)
|
||||
/* found identical match - permit access */
|
||||
throw true;
|
||||
});
|
||||
@ -424,8 +425,7 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
_config.xml().for_each_sub_node("policy", [&] (Xml_node policy) {
|
||||
policy.for_each_sub_node("device", [&] (Xml_node device) {
|
||||
|
||||
typedef String<10> Name;
|
||||
if (device.attribute_value("name", Name()) == dev_name) {
|
||||
if (device.attribute_value("name", Device_name_string()) == dev_name) {
|
||||
|
||||
if (once)
|
||||
throw true;
|
||||
@ -474,7 +474,7 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
Attached_io_mem_dataspace &pciconf,
|
||||
addr_t pciconf_base,
|
||||
Platform::Pci_buses &buses,
|
||||
Heap &global_heap,
|
||||
Allocator &global_heap,
|
||||
Pci::Config::Delayer &delayer,
|
||||
Device_bars_pool &devices_bars,
|
||||
char const *args,
|
||||
@ -521,8 +521,8 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
throw Service_denied();
|
||||
}
|
||||
|
||||
typedef String<16> Name;
|
||||
Name const name = device_node.attribute_value("name", Name());
|
||||
Device_name_string const name =
|
||||
device_node.attribute_value("name", Device_name_string());
|
||||
|
||||
enum { DOUBLET = false };
|
||||
if (find_dev_in_policy(name.string(), DOUBLET)) {
|
||||
@ -610,7 +610,7 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
_device_list.first()->for_each_device([&](auto const &dev) {
|
||||
|
||||
/* Non PCI devices */
|
||||
if (!dev.device_config().valid()) {
|
||||
if (!dev.pci_device()) {
|
||||
if (!permit_device(dev.name().string()))
|
||||
result = false;
|
||||
|
||||
@ -777,7 +777,7 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
if (device->device_config().valid()) {
|
||||
if (device->pci_device()) {
|
||||
if (bdf_in_use.get(device->device_config().bdf().value(), 1))
|
||||
bdf_in_use.clear(device->device_config().bdf().value(), 1);
|
||||
}
|
||||
@ -877,6 +877,7 @@ class Platform::Session_component : public Rpc_object<Session>
|
||||
return _env.pd().dma_addr(ram_cap);
|
||||
}
|
||||
|
||||
/* non-PCI devices */
|
||||
Device_capability device(Device_name const &name) override;
|
||||
};
|
||||
|
||||
@ -886,14 +887,13 @@ class Platform::Root : public Root_component<Session_component>
|
||||
private:
|
||||
|
||||
Env &_env;
|
||||
Allocator &_heap;
|
||||
Attached_rom_dataspace &_config;
|
||||
|
||||
Constructible<Attached_io_mem_dataspace> _pci_confspace { };
|
||||
addr_t _pci_confspace_base = 0;
|
||||
Constructible<Expanding_reporter> _pci_reporter { };
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
Device_bars_pool _devices_bars { };
|
||||
|
||||
Constructible<Platform::Pci_buses> _buses { };
|
||||
@ -1123,11 +1123,12 @@ class Platform::Root : public Root_component<Session_component>
|
||||
* \param md_alloc meta-data allocator for allocating PCI-session
|
||||
* components and PCI-device components
|
||||
*/
|
||||
Root(Env &env, Allocator &md_alloc, Attached_rom_dataspace &config,
|
||||
Root(Env &env, Allocator &heap, Allocator &md_alloc, Attached_rom_dataspace &config,
|
||||
char const *acpi_rom, bool acpi_platform, bool msi_platform)
|
||||
:
|
||||
Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
|
||||
_env(env),
|
||||
_heap(heap),
|
||||
_config(config),
|
||||
_msi_platform(msi_platform)
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
TARGET = legacy_pc_platform_drv
|
||||
REQUIRES = x86
|
||||
SRC_CC = main.cc irq.cc pci_device.cc nonpci_devices.cc session.cc
|
||||
SRC_CC += device_pd.cc
|
||||
SRC_CC += device_pd.cc acpi_devices.cc
|
||||
LIBS = base
|
||||
|
||||
INC_DIR = $(PRG_DIR)
|
||||
|
Loading…
x
Reference in New Issue
Block a user