mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
ACPI: Parse MADT
Implemented IRQ service and MATD parsing. Please have a look at the 'README' file. Fixes issue #151
This commit is contained in:
parent
db8058c16f
commit
ed8eb91107
@ -39,20 +39,31 @@ set config {
|
||||
<start name="acpi">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<binary name="acpi_drv"/>
|
||||
<provides><service name="PCI"/></provides>
|
||||
<provides>
|
||||
<service name="PCI"/>
|
||||
<service name="IRQ" />
|
||||
</provides>
|
||||
<route>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
<any-service> <any-child/> <parent/> </any-service>
|
||||
<service name="PCI"> <any-child /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
<route>
|
||||
<service name="IRQ"><child name="acpi" /></service>
|
||||
<any-service> <parent /> <any-child /></any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="ahci">
|
||||
<binary name="ahci_drv" />
|
||||
<resource name="RAM" quantum="10M" />
|
||||
<provides><service name="Block" /></provides>
|
||||
<route>
|
||||
<service name="IRQ"><child name="acpi" /></service>
|
||||
<any-service> <parent /> <any-child /></any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="test-ahci">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
|
@ -6,7 +6,9 @@ Behavior
|
||||
This server should be used when using a kernel (like Fiasco.OC or Nova) that
|
||||
takes advantage of x86's APIC. The server traverses the ACPI tables and sets the
|
||||
interrupt line of devices within the PCI config space to the GSIs found in the
|
||||
ACPI tables.
|
||||
ACPI tables. The 'MADT' table is parsed by the server as well, enabling clients
|
||||
to use the correct IRQ when 'Interrupt Override' structures are found wihtin the
|
||||
table.
|
||||
|
||||
Usage
|
||||
-----
|
||||
@ -15,17 +17,30 @@ Start the 'acpi_drv' in your Genode environment. Do not start the 'pci_drv'
|
||||
since this will be used as a slave of the 'acpi_drv'. You still must load the
|
||||
'pci_drv' in your boot loader.
|
||||
|
||||
Configuration snipped:
|
||||
Configuration snipped (please not that IRQ service requests of the 'timer' are
|
||||
routed to the ACPI-driver):
|
||||
|
||||
!<start name="acpi">
|
||||
! <resource name="RAM" quantum="2M"/>
|
||||
! <binary name="acpi_drv"/>
|
||||
! <provides><service name="PCI"/></provides>
|
||||
! <provides>
|
||||
! <service name="PCI"/>
|
||||
! <service name="IRQ" />
|
||||
! </provides>
|
||||
! <route>
|
||||
! <service name="ROM"> <parent/> </service>
|
||||
! <any-service> <any-child/> <parent/> </any-service>
|
||||
! <service name="PCI"> <any-child /> </service>
|
||||
! <any-service> <parent/> <any-child /> </any-service>
|
||||
! </route>
|
||||
!</start>
|
||||
!
|
||||
!<start name="timer">
|
||||
! <resource name="RAM" quantum="1M"/>
|
||||
! <provides><service name="Timer"/></provides>
|
||||
! <route>
|
||||
! <service name="IRQ"><child name="acpi" /></service>
|
||||
! <any-service> <parent /> <any-child /></any-service>
|
||||
! </route>
|
||||
!</start>
|
||||
|
||||
Limitations and known issues
|
||||
----------------------------
|
||||
|
@ -26,6 +26,30 @@ using namespace Genode;
|
||||
/* Enable debugging output */
|
||||
static const bool verbose = false;
|
||||
|
||||
/* Generic Apic structure */
|
||||
struct Apic_struct
|
||||
{
|
||||
enum Types { SRC_OVERRIDE = 2 };
|
||||
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
|
||||
bool is_override() { return type == SRC_OVERRIDE; }
|
||||
|
||||
Apic_struct *next() { return reinterpret_cast<Apic_struct *>((uint8_t *)this + length); }
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* ACPI spec 5.2.12.5 */
|
||||
struct Apic_override : Apic_struct
|
||||
{
|
||||
uint8_t bus;
|
||||
uint8_t irq;
|
||||
uint32_t gsi;
|
||||
uint16_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* ACPI spec 5.2.6 */
|
||||
struct Generic
|
||||
{
|
||||
@ -40,6 +64,37 @@ struct Generic
|
||||
uint32_t creator_rev;
|
||||
|
||||
uint8_t const *data() { return reinterpret_cast<uint8_t *>(this); }
|
||||
|
||||
/* MADT acpi structures */
|
||||
Apic_struct *apic_struct() { return reinterpret_cast<Apic_struct *>(&creator_rev + 8); }
|
||||
Apic_struct *end() { return reinterpret_cast<Apic_struct *>(signature + size); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* List that holds interrupt override information
|
||||
*/
|
||||
class Irq_override : public List<Irq_override>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
uint32_t _irq; /* source IRQ */
|
||||
uint32_t _gsi; /* target GSI */
|
||||
uint32_t _flags; /* interrupt flags */
|
||||
|
||||
public:
|
||||
|
||||
Irq_override(uint32_t irq, uint32_t gsi, uint32_t flags)
|
||||
: _irq(irq), _gsi(gsi), _flags(flags) { }
|
||||
|
||||
static List<Irq_override> *list()
|
||||
{
|
||||
static List<Irq_override> _list;
|
||||
return &_list;
|
||||
}
|
||||
|
||||
bool match(uint32_t irq) const { return irq == _irq; }
|
||||
uint32_t gsi() const { return _gsi; }
|
||||
};
|
||||
|
||||
|
||||
@ -119,11 +174,35 @@ class Table_wrapper
|
||||
*/
|
||||
bool is_facp() const { return _cmp("FACP");}
|
||||
|
||||
/**
|
||||
* Is this a MADT table
|
||||
*/
|
||||
bool is_madt() { return _cmp("APIC"); }
|
||||
|
||||
/**
|
||||
* Look for DSDT and SSDT tables
|
||||
*/
|
||||
bool is_searched() const { return _cmp("DSDT") || _cmp("SSDT"); }
|
||||
|
||||
/**
|
||||
* Parse override structures
|
||||
*/
|
||||
void parse_madt()
|
||||
{
|
||||
Apic_struct *apic = _table->apic_struct();
|
||||
for (; apic < _table->end(); apic = apic->next()) {
|
||||
if (!apic->is_override())
|
||||
continue;
|
||||
|
||||
Apic_override *o = static_cast<Apic_override *>(apic);
|
||||
|
||||
if (verbose)
|
||||
PDBG("Found IRQ %u -> GSI %u", o->irq, o->gsi);
|
||||
|
||||
Irq_override::list()->insert(new (env()->heap()) Irq_override(o->irq, o->gsi, o->flags));
|
||||
}
|
||||
}
|
||||
|
||||
Table_wrapper(addr_t base)
|
||||
: _base(base), _io_mem(0), _table(0)
|
||||
{
|
||||
@ -859,6 +938,13 @@ class Acpi_table
|
||||
|
||||
Element::parse(table.table());
|
||||
}
|
||||
|
||||
if (table.is_madt()) {
|
||||
if (verbose)
|
||||
PDBG("Found MADT");
|
||||
|
||||
table.parse_madt();
|
||||
}
|
||||
}
|
||||
|
||||
if (dsdt) {
|
||||
@ -1067,3 +1153,15 @@ void Acpi::rewrite_irq(Pci::Session_capability &session)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search override structures
|
||||
*/
|
||||
unsigned Acpi::override(unsigned irq)
|
||||
{
|
||||
for (Irq_override *i = Irq_override::list()->first(); i; i = i->next())
|
||||
if (i->match(irq))
|
||||
return i->gsi();
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
@ -25,6 +25,11 @@ class Acpi
|
||||
* Rewrite PCI-config space with GSIs found in ACPI tables
|
||||
*/
|
||||
static void rewrite_irq(Pci::Session_capability &session);
|
||||
|
||||
/**
|
||||
* Return override GSI for IRQ
|
||||
*/
|
||||
static unsigned override(unsigned irq);
|
||||
};
|
||||
|
||||
#endif /* _ACPI_H_ */
|
||||
|
@ -21,9 +21,73 @@
|
||||
#include <base/sleep.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <pci_session/client.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <root/component.h>
|
||||
|
||||
#include "acpi.h"
|
||||
|
||||
/**
|
||||
* IRQ service
|
||||
*/
|
||||
namespace Irq {
|
||||
|
||||
typedef Genode::Rpc_object<Genode::Typed_root<Genode::Irq_session> > Irq_session;
|
||||
|
||||
/**
|
||||
* Root interface of IRQ service
|
||||
*/
|
||||
class Root : public Irq_session
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Remap IRQ number and create IRQ session at parent
|
||||
*/
|
||||
Genode::Session_capability session(Root::Session_args const &args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!args.is_valid_string()) throw Root::Invalid_args();
|
||||
|
||||
long irq_number = Arg_string::find_arg(args.string(), "irq_number").long_value(-1);
|
||||
|
||||
/* check for 'MADT' overrides */
|
||||
irq_number = Acpi::override(irq_number);
|
||||
|
||||
/* qouta handling */
|
||||
size_t ram_quota = Arg_string::find_arg(args.string(), "ram_quota").long_value(0);
|
||||
size_t old_quota = 0, new_quota = 0;
|
||||
Session_capability cap;
|
||||
|
||||
/* allocate IRQ at parent*/
|
||||
try {
|
||||
old_quota = env()->ram_session()->quota();
|
||||
Irq_connection irq(irq_number);
|
||||
new_quota = env()->ram_session()->quota();
|
||||
irq.on_destruction(Irq_connection::KEEP_OPEN);
|
||||
cap = irq.cap();
|
||||
} catch (...) { throw Root::Unavailable(); }
|
||||
|
||||
/* check used quota against quota provided */
|
||||
if (old_quota > new_quota && (old_quota - new_quota) > ram_quota) {
|
||||
close(cap);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close session at parent
|
||||
*/
|
||||
void close(Genode::Session_capability session) {
|
||||
Genode::env()->parent()->close(session); }
|
||||
|
||||
void upgrade(Genode::Session_capability session, Upgrade_args const &args) { }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace Pci {
|
||||
|
||||
struct Provider
|
||||
@ -44,6 +108,8 @@ namespace Pci {
|
||||
|
||||
public:
|
||||
|
||||
Root(Provider &pci_provider) : _pci_provider(pci_provider) { }
|
||||
|
||||
Genode::Session_capability session(Session_args const &args)
|
||||
{
|
||||
if (!args.is_valid_string()) throw Invalid_args();
|
||||
@ -58,33 +124,27 @@ namespace Pci {
|
||||
}
|
||||
}
|
||||
|
||||
void close(Genode::Session_capability session) {
|
||||
Genode::Root_client(_pci_provider.root()).close(session); }
|
||||
|
||||
void upgrade(Genode::Session_capability, Upgrade_args const &) { }
|
||||
|
||||
void close(Genode::Session_capability session)
|
||||
{
|
||||
Genode::Root_client(_pci_provider.root()).close(session);
|
||||
}
|
||||
|
||||
Root(Provider &pci_provider) : _pci_provider(pci_provider) { }
|
||||
};
|
||||
}
|
||||
|
||||
typedef Genode::Capability<Genode::Typed_root<Pci::Session> > Service_capability;
|
||||
|
||||
class Pci_policy : public Genode::Slave_policy, public Pci::Provider
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Root_capability _cap;
|
||||
Genode::Rpc_entrypoint &_ep;
|
||||
Genode::Rpc_entrypoint &_pci_ep;
|
||||
Genode::Rpc_entrypoint &_irq_ep;
|
||||
|
||||
protected:
|
||||
|
||||
char const **_permitted_services() const
|
||||
{
|
||||
static char const *permitted_services[] = {
|
||||
"CAP", "RM", "LOG", "IO_PORT", 0 };
|
||||
|
||||
{
|
||||
static char const *permitted_services[] = { "CAP", "RM", "LOG", "IO_PORT", 0 };
|
||||
return permitted_services;
|
||||
};
|
||||
|
||||
@ -103,17 +163,22 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
|
||||
|
||||
Acpi::rewrite_irq(session);
|
||||
|
||||
/* announce service PCI to parent */
|
||||
/* announce PCI/IRQ services to parent */
|
||||
static Pci::Root pci_root(*this);
|
||||
Genode::env()->parent()->announce(_ep.manage(&pci_root));
|
||||
static Irq::Root irq_root;
|
||||
|
||||
Genode::env()->parent()->announce(_pci_ep.manage(&pci_root));
|
||||
Genode::env()->parent()->announce(_irq_ep.manage(&irq_root));
|
||||
|
||||
Genode::Root_client(_cap).close(session);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Pci_policy(Genode::Rpc_entrypoint &slave_ep, Genode::Rpc_entrypoint &ep)
|
||||
: Slave_policy("pci_drv", slave_ep), _ep(ep)
|
||||
Pci_policy(Genode::Rpc_entrypoint &slave_ep,
|
||||
Genode::Rpc_entrypoint &pci_ep,
|
||||
Genode::Rpc_entrypoint &irq_ep)
|
||||
: Slave_policy("pci_drv", slave_ep), _pci_ep(pci_ep), _irq_ep(irq_ep)
|
||||
{ }
|
||||
|
||||
bool announce_service(const char *service_name,
|
||||
@ -144,9 +209,13 @@ int main(int argc, char **argv)
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "acpi_ep");
|
||||
|
||||
/* IRQ service */
|
||||
static Cap_connection irq_cap;
|
||||
static Rpc_entrypoint irq_ep(&irq_cap, STACK_SIZE, "acpi_irq_ep");
|
||||
|
||||
/* use 'pci_drv' as slave service */
|
||||
static Rpc_entrypoint pci_ep(&cap, STACK_SIZE, "pci_slave");
|
||||
static Pci_policy pci_policy(pci_ep, ep);
|
||||
static Pci_policy pci_policy(pci_ep, ep, irq_ep);
|
||||
static Genode::Slave pci_slave(pci_ep, pci_policy, 512 * 1024);
|
||||
|
||||
Genode::sleep_forever();
|
||||
|
Loading…
x
Reference in New Issue
Block a user