ACPI: GSI parser, fix #34

Read GSIs from ACPI tables and rewrite PCI-config space IRQs
This commit is contained in:
Sebastian Sumpf 2012-02-25 21:40:23 +01:00 committed by Norman Feske
parent c2c87c8833
commit 7e00ef96ee
5 changed files with 1303 additions and 0 deletions

View File

@ -0,0 +1,35 @@
This directory contains an implementation of a simple ACPI parser
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.
Usage
-----
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:
!<start name="acpi">
! <resource name="RAM" quantum="2M"/>
! <binary name="acpi_drv"/>
! <provides><service name="PCI"/></provides>
! <route>
! <service name="ROM"> <parent/> </service>
! <any-service> <any-child/> <parent/> </any-service>
! </route>
!</start>
Limitations and known issues
----------------------------
Currently there is no interface to set the interrupt mode for Irq_sessions
(e.g., level or edge triggered). This is required by Fiasco.OCs kernel
interface. We regard this as future work.

1073
os/src/drivers/acpi/acpi.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
/*
* \brief Interface to ACPI
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2012-02-25
*/
/*
* Copyright (C) 2009-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ACPI_H_
#define _ACPI_H_
#include <base/thread.h>
#include <pci_session/capability.h>
class Acpi
{
public:
/**
* Rewrite PCI-config space with GSIs found in ACPI tables
*/
static void rewrite_irq(Pci::Session_capability &session);
};
#endif /* _ACPI_H_ */

155
os/src/drivers/acpi/main.cc Normal file
View File

@ -0,0 +1,155 @@
/*
* \brief Service and session interface
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2012-02-25
*
* The 'acpi_drv' provides the 'PCI' after rewriting the IRQ information of PCI
* devices. For this it uses the 'pci_drv' as a client and forwards the session
* capability of the 'pci_drv' afterwards
*/
/*
* Copyright (C) 2009-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <os/slave.h>
#include <base/printf.h>
#include <base/env.h>
#include <base/sleep.h>
#include <cap_session/connection.h>
#include <pci_session/client.h>
#include "acpi.h"
namespace Pci {
struct Provider
{
bool ready_to_use() { return root().valid(); }
virtual Genode::Root_capability root() = 0;
};
/**
* Root interface of PCI service
*/
class Root : public Genode::Rpc_object<Genode::Typed_root<Pci::Session> >
{
private:
Provider &_pci_provider;
public:
Genode::Session_capability session(Session_args const &args)
{
if (!args.is_valid_string()) throw Invalid_args();
if (!_pci_provider.ready_to_use())
throw Unavailable();
try {
return Genode::Root_client(_pci_provider.root()).session(args.string());
} catch (...) {
throw Unavailable();
}
}
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;
protected:
char const **_permitted_services() const
{
static char const *permitted_services[] = {
"CAP", "RM", "LOG", "IO_PORT", 0 };
return permitted_services;
};
/**
* Parse ACPI tables and announce slave PCI service
*/
void _acpi_session()
{
Pci::Session_capability session;
const char *args = "ram_quota=4K";
try {
using namespace Genode;
session = static_cap_cast<Pci::Session>(Root_client(_cap).session(args));
} catch (...) { return; }
Acpi::rewrite_irq(session);
/* announce service PCI to parent */
static Pci::Root pci_root(*this);
Genode::env()->parent()->announce(_ep.manage(&pci_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)
{ }
bool announce_service(const char *service_name,
Genode::Root_capability root,
Genode::Allocator *alloc)
{
/* wait for 'pci_drv' to announce the PCI service */
if (Genode::strcmp(service_name, "PCI"))
return false;
_cap = root;
/* connect session and start ACPI parsing */
_acpi_session();
return true;
}
Genode::Root_capability root() { return _cap; }
};
int main(int argc, char **argv)
{
using namespace Genode;
enum { STACK_SIZE = 2*4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "acpi_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 Genode::Slave pci_slave(pci_ep, pci_policy, 512 * 1024);
Genode::sleep_forever();
return 0;
}

View File

@ -0,0 +1,9 @@
TARGET = acpi_drv
REQUIRES = x86
SRC_CC = main.cc acpi.cc
LIBS = cxx env server process
INC_DIR = $(PRG_DIR)/..
vpath main.cc $(PRG_DIR)/..
vpath acpi.cc $(PRG_DIR)/..