acpi: transition to the new base API

Issue #1987
This commit is contained in:
Josef Söntgen 2016-05-28 10:52:26 +02:00 committed by Christian Helmuth
parent 833c9e01f5
commit c77f146e72
3 changed files with 111 additions and 98 deletions

View File

@ -11,7 +11,7 @@
*/
/*
* Copyright (C) 2009-2015 Genode Labs GmbH
* Copyright (C) 2009-2016 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.
@ -19,6 +19,7 @@
/* base includes */
#include <io_mem_session/connection.h>
#include <util/misc_math.h>
#include <util/mmio.h>
/* os includes */
@ -137,10 +138,10 @@ struct Dmar_struct_header : Generic
} while (addr < dmar_entry_end());
}
struct Dmar_struct_header * clone()
struct Dmar_struct_header * clone(Genode::Allocator &alloc)
{
size_t const size = dmar_entry_end() - reinterpret_cast<addr_t>(this);
char * clone = new (env()->heap()) char[size];
char * clone = new (&alloc) char[size];
memcpy(clone, this, size);
return reinterpret_cast<Dmar_struct_header *>(clone);
@ -371,7 +372,7 @@ class Table_wrapper
/**
* Parse override structures
*/
void parse_madt()
void parse_madt(Genode::Allocator &alloc)
{
Apic_struct *apic = _table->apic_struct();
for (; apic < _table->end(); apic = apic->next()) {
@ -382,12 +383,12 @@ class Table_wrapper
PINF("MADT IRQ %u -> GSI %u flags: %x", o->irq, o->gsi, o->flags);
Irq_override::list()->insert(new (env()->heap())
Irq_override::list()->insert(new (&alloc)
Irq_override(o->irq, o->gsi, o->flags));
}
}
void parse_mcfg() const
void parse_mcfg(Genode::Allocator &alloc) const
{
Mcfg_struct *mcfg = _table->mcfg_struct();
for (; mcfg < _table->mcfg_end(); mcfg = mcfg->next()) {
@ -400,11 +401,11 @@ class Table_wrapper
uint32_t bus_start = mcfg->pci_bus_start * 32 * 8;
Pci_config_space::list()->insert(
new (env()->heap()) Pci_config_space(bus_start, func_count, mcfg->base));
new (&alloc) Pci_config_space(bus_start, func_count, mcfg->base));
}
}
void parse_dmar() const
void parse_dmar(Genode::Allocator &alloc) const
{
Dmar_struct_header *head = _table->dmar_header();
PLOG("%u bit DMA physical addressable%s\n", head->width + 1,
@ -415,7 +416,7 @@ class Table_wrapper
PLOG("DMA remapping structure type=%u", dmar.read<Dmar_common::Type>());
});
Dmar_entry::list()->insert(new (env()->heap()) Dmar_entry(head->clone()));
Dmar_entry::list()->insert(new (&alloc) Dmar_entry(head->clone(alloc)));
}
Table_wrapper(addr_t base) : _base(base), _table(0)
@ -487,14 +488,14 @@ class Element : public List<Element>::Element
uint8_t _type; /* the type of this element */
uint32_t _size; /* size in bytes */
uint32_t _size_len; /* length of size in bytes */
char *_name; /* name of element */
char _name[64]; /* name of element */
uint32_t _name_len; /* length of name in bytes */
uint32_t _bdf; /* bus device function */
uint8_t const *_data; /* pointer to the data section */
uint32_t _para_len; /* parameters to be skipped */
bool _valid; /* true if this is a valid element */
bool _routed; /* has the PCI information been read */
List<Pci_routing> *_pci; /* list of PCI routing elements for this element */
List<Pci_routing> _pci; /* list of PCI routing elements for this element */
/* packages we are looking for */
enum { DEVICE = 0x5b, SUB_DEVICE = 0x82, DEVICE_NAME = 0x8, SCOPE = 0x10, METHOD = 0x14, PACKAGE_OP = 0x12 };
@ -655,8 +656,7 @@ class Element : public List<Element>::Element
/* is absolute name */
if (*name == ROOT_PREFIX || !parent) {
_name = (char *)env()->heap()->alloc(_name_len);
memcpy(_name, name + prefix_len, _name_len);
memcpy(_name, name + prefix_len, min(sizeof(_name), _name_len));
}
else {
/* skip parts */
@ -665,7 +665,11 @@ class Element : public List<Element>::Element
/* skip parent prefix */
for (uint32_t p = 0; name[p] == PARENT_PREFIX; p++, parent_len -= NAME_LEN) ;
_name = (char *)env()->heap()->alloc(_name_len + parent_len);
if (_name_len + parent_len > sizeof(_name)) {
PERR("name is not large enough");
throw -1;
}
memcpy(_name, parent->_name, parent_len);
memcpy(_name + parent_len, name + prefix_len, _name_len);
@ -747,7 +751,7 @@ class Element : public List<Element>::Element
* Try to locate _PRT table and its GSI values for device
* (data has to be located within the device data)
*/
void _direct_prt(Element *dev)
void _direct_prt(Genode::Allocator &alloc, Element *dev)
{
uint32_t len = 0;
@ -771,11 +775,11 @@ class Element : public List<Element>::Element
}
if (i == 4) {
Pci_routing * r = new (env()->heap()) Pci_routing(val[0], val[1], val[3]);
Pci_routing * r = new (&alloc) Pci_routing(val[0], val[1], val[3]);
/* set _ADR, _PIN, _GSI */
dev->pci_list()->insert(r);
dev->pci_list()->first()->dump();
dev->pci_list().insert(r);
dev->pci_list().first()->dump();
}
len = len ? (e.data() - (_data + offset)) + e.size() : 1;
@ -785,7 +789,7 @@ class Element : public List<Element>::Element
/**
* Search for _PRT outside of device
*/
void _indirect_prt(Element *dev)
void _indirect_prt(Genode::Allocator &alloc, Element *dev)
{
uint32_t name_len;
uint32_t found = 0;
@ -805,7 +809,7 @@ class Element : public List<Element>::Element
for (uint32_t skip = 0; skip <= dev->_name_len / NAME_LEN; skip++) {
Element *e = dev->_compare(name, skip * NAME_LEN);
if (e)
e->_direct_prt(dev);
e->_direct_prt(alloc, dev);
}
}
else
@ -815,9 +819,11 @@ class Element : public List<Element>::Element
Element(uint8_t const *data = 0, bool package_op4 = false)
:
_type(0), _size(0), _size_len(0), _name(0), _name_len(0), _bdf(0),
_data(data), _para_len(0), _valid(false), _routed(false), _pci(0)
_type(0), _size(0), _size_len(0), _name_len(0), _bdf(0),
_data(data), _para_len(0), _valid(false), _routed(false)
{
_name[0] = '\0';
if (!data)
return;
@ -900,18 +906,14 @@ class Element : public List<Element>::Element
_type = other._type;
_size = other._size;
_size_len = other._size_len;
memcpy(_name, other._name, sizeof(_name));
_name_len = other._name_len;
_bdf = other._bdf;
_data = other._data;
_para_len = other._para_len;
_valid = other._valid;
_routed = other._routed;
_pci = other._pci;
_para_len = other._para_len;
if (other._name) {
_name = (char *)env()->heap()->alloc(other._name_len);
memcpy(_name, other._name, _name_len);
}
}
bool is_device_name() { return _type == DEVICE_NAME; }
@ -933,11 +935,7 @@ class Element : public List<Element>::Element
public:
virtual ~Element()
{
if (_name)
env()->heap()->free(_name, _name_len);
}
virtual ~Element() { }
/**
* Accessors
@ -969,7 +967,7 @@ class Element : public List<Element>::Element
return &_list;
}
static void clean_list()
static void clean_list(Genode::Allocator &alloc)
{
unsigned long freed_up = 0;
@ -985,7 +983,7 @@ class Element : public List<Element>::Element
Element * next = element->next();
Element::list()->remove(element);
destroy(env()->heap(), element);
destroy(&alloc, element);
element = next;
}
@ -996,17 +994,12 @@ class Element : public List<Element>::Element
/**
* Return list of PCI information for this element
*/
List<Pci_routing> *pci_list()
{
if (!_pci)
_pci = new (env()->heap()) List<Pci_routing>();
return _pci;
}
List<Pci_routing> & pci_list() { return _pci; }
/**
* Parse elements of table
*/
static void parse(Generic *table)
static void parse(Genode::Allocator &alloc, Generic *table)
{
uint8_t const *data = table->data();
for (; data < table->data() + table->size; data++) {
@ -1018,7 +1011,7 @@ class Element : public List<Element>::Element
if (data + e.size() > table->data() + table->size)
break;
Element *i = new (env()->heap()) Element(e);
Element *i = new (&alloc) Element(e);
list()->insert(i);
/* skip header */
@ -1031,13 +1024,13 @@ class Element : public List<Element>::Element
data += e._para_len;
}
parse_bdf();
parse_bdf(alloc);
}
/**
* Parse BDF and GSI information
*/
static void parse_bdf()
static void parse_bdf(Genode::Allocator &alloc)
{
for (Element *e = list()->first(); e; e = e->next()) {
@ -1064,8 +1057,8 @@ class Element : public List<Element>::Element
if (verbose)
PDBG("Scanning device %x", e->_bdf);
prt->_direct_prt(e);
prt->_indirect_prt(e);
prt->_direct_prt(alloc, e);
prt->_indirect_prt(alloc, e);
}
e->_routed = true;
@ -1083,7 +1076,7 @@ class Element : public List<Element>::Element
if (!e->is_device() || e->_bdf != bridge_bdf)
continue;
Pci_routing *r = e->pci_list()->first();
Pci_routing *r = e->pci_list().first();
for (; r; r = r->next()) {
if (r->match_bdf(device_bdf) && r->pin() == pin) {
if (verbose) PDBG("Found GSI: %u device : %x pin %u",
@ -1104,6 +1097,9 @@ class Acpi_table
{
private:
Genode::Env &env;
Genode::Allocator &alloc;
/* BIOS range to scan for RSDP */
enum { BIOS_BASE = 0xe0000, BIOS_SIZE = 0x20000 };
@ -1118,7 +1114,7 @@ class Acpi_table
if (!io_ds.valid())
throw -1;
uint8_t *ret = env()->rm_session()->attach(io_ds, size);
uint8_t *ret = env.rm().attach(io_ds, size);
cap = io_mem.cap();
return ret;
}
@ -1146,25 +1142,25 @@ class Acpi_table
try {
area = _search_rsdp(_map_io(BIOS_BASE, BIOS_SIZE, cap));
return area;
} catch (...) { env()->parent()->close(cap); }
} catch (...) { env.parent().close(cap); }
/* search EBDA (BIOS addr + 0x40e) */
try {
area = _map_io(0x0, 0x1000, cap);
if (area) {
unsigned short base = (*reinterpret_cast<unsigned short *>(area + 0x40e)) << 4;
env()->parent()->close(cap);
env.parent().close(cap);
area = _map_io(base, 1024, cap);
area = _search_rsdp(area);
}
return area;
} catch (...) { env()->parent()->close(cap); }
} catch (...) { env.parent().close(cap); }
return 0;
}
template <typename T>
void _parse_tables(T * entries, uint32_t count)
void _parse_tables(Genode::Allocator &alloc, T * entries, uint32_t count)
{
/* search for SSDT and DSDT tables */
for (uint32_t i = 0; i < count; i++) {
@ -1181,23 +1177,23 @@ class Acpi_table
if (verbose)
PDBG("Found %s", table.name());
Element::parse(table.table());
Element::parse(alloc, table.table());
}
if (table.is_madt()) {
PDBG("Found MADT");
table.parse_madt();
table.parse_madt(alloc);
}
if (table.is_mcfg()) {
PDBG("Found MCFG");
table.parse_mcfg();
table.parse_mcfg(alloc);
}
if (table.is_dmar()) {
PDBG("Found DMAR");
table.parse_dmar();
table.parse_dmar(alloc);
}
}
@ -1207,7 +1203,7 @@ class Acpi_table
if (verbose)
PDBG("Found dsdt %s", table.name());
Element::parse(table.table());
Element::parse(alloc, table.table());
}
}
}
@ -1216,7 +1212,8 @@ class Acpi_table
public:
Acpi_table()
Acpi_table(Genode::Env &env, Genode::Allocator &alloc)
: env(env), alloc(alloc)
{
Io_mem_session_capability io_mem;
@ -1255,22 +1252,22 @@ class Acpi_table
addr_t const xsdt = rsdp->xsdt;
uint8_t const acpi_revision = rsdp->revision;
/* drop rsdp io_mem mapping since rsdt/xsdt may overlap */
env()->parent()->close(io_mem);
env.parent().close(io_mem);
if (acpi_revision != 0 && xsdt && sizeof(addr_t) != sizeof(uint32_t)) {
/* running 64bit and xsdt is valid */
Table_wrapper table(xsdt);
uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1);
_parse_tables(entries, table.entry_count(entries));
_parse_tables(alloc, entries, table.entry_count(entries));
} else {
/* running (32bit) or (64bit and xsdt isn't valid) */
Table_wrapper table(rsdt);
uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1);
_parse_tables(entries, table.entry_count(entries));
_parse_tables(alloc, entries, table.entry_count(entries));
}
/* free up memory of elements not of any use */
Element::clean_list();
Element::clean_list(alloc);
/* free up io memory */
acpi_memory().free_io_memory();
@ -1278,15 +1275,6 @@ class Acpi_table
};
/**
* Parse acpi table
*/
static void init_acpi_table()
{
static Acpi_table table;
}
static void attribute_hex(Xml_generator &xml, char const *name,
unsigned long long value)
{
@ -1296,9 +1284,10 @@ static void attribute_hex(Xml_generator &xml, char const *name,
}
void Acpi::generate_report()
void Acpi::generate_report(Genode::Env &env, Genode::Allocator &alloc)
{
init_acpi_table();
/* parse table */
Acpi_table acpi_table(env, alloc);
enum { REPORT_SIZE = 4 * 4096 };
static Reporter acpi("acpi", "acpi", REPORT_SIZE);
@ -1373,7 +1362,7 @@ void Acpi::generate_report()
if (!e->is_device())
continue;
Pci_routing *r = e->pci_list()->first();
Pci_routing *r = e->pci_list().first();
for (; r; r = r->next()) {
xml.node("routing", [&] () {
attribute_hex(xml, "gsi", r->gsi());

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
* Copyright (C) 2009-2016 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.
@ -14,12 +14,16 @@
#ifndef _ACPI_H_
#define _ACPI_H_
/* Genode includes */
#include <base/env.h>
namespace Acpi
{
/**
* Generate report rom
*/
void generate_report();
void generate_report(Genode::Env&, Genode::Allocator&);
}
#endif /* _ACPI_H_ */

View File

@ -5,33 +5,53 @@
*/
/*
* Copyright (C) 2009-2015 Genode Labs GmbH
* Copyright (C) 2009-2016 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 <base/printf.h>
#include <base/sleep.h>
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/log.h>
#include <util/xml_generator.h>
#include <os/reporter.h>
/* local includes */
#include <acpi.h>
#include "acpi.h"
int main(int argc, char **argv)
{
namespace Acpi {
using namespace Genode;
struct Main;
}
struct Acpi::Main
{
Genode::Env &env;
Genode::Heap heap { env.ram(), env.rm() };
Main(Env &env) : env(env)
{
try {
Acpi::generate_report();
Acpi::generate_report(env, heap);
} catch (Genode::Xml_generator::Buffer_exceeded) {
PERR("ACPI report too large - failure");
Genode::error("ACPI report too large - failure");
throw;
} catch (...) {
PERR("Unknown exception occured - failure");
Genode::error("Unknown exception occured - failure");
throw;
}
}
};
Genode::sleep_forever();
return 0;
/***************
** Component **
***************/
namespace Component {
Genode::size_t stack_size() { return 2*1024*sizeof(long); }
void construct(Genode::Env &env) { static Acpi::Main main(env); }
}