2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2015-06-08 09:05:32 +02:00
|
|
|
* \brief platform session component
|
2011-12-22 16:19:25 +01:00
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2008-01-28
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2008-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
2015-06-08 09:05:32 +02:00
|
|
|
#pragma once
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-04-17 14:12:30 +02:00
|
|
|
/* base */
|
2015-04-16 15:54:07 +02:00
|
|
|
#include <base/allocator_guard.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <base/rpc_server.h>
|
2015-04-16 15:54:07 +02:00
|
|
|
#include <base/tslab.h>
|
2015-04-17 14:12:30 +02:00
|
|
|
#include <ram_session/connection.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
#include <root/component.h>
|
|
|
|
|
2016-05-13 16:09:20 +02:00
|
|
|
#include <util/mmio.h>
|
2015-11-05 09:06:29 +01:00
|
|
|
#include <util/retry.h>
|
2016-12-01 17:37:08 +01:00
|
|
|
#include <util/reconstructible.h>
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2015-04-17 14:12:30 +02:00
|
|
|
/* os */
|
2013-02-18 10:06:34 +01:00
|
|
|
#include <io_mem_session/connection.h>
|
2016-11-23 14:21:34 +01:00
|
|
|
#include <os/ram_session_guard.h>
|
2015-04-22 17:06:10 +02:00
|
|
|
#include <os/session_policy.h>
|
2015-06-08 09:05:32 +02:00
|
|
|
#include <platform_session/platform_session.h>
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-04-17 14:12:30 +02:00
|
|
|
/* local */
|
2011-12-22 16:19:25 +01:00
|
|
|
#include "pci_device_component.h"
|
|
|
|
#include "pci_config_access.h"
|
2013-02-18 10:08:14 +01:00
|
|
|
#include "pci_device_pd_ipc.h"
|
2015-11-05 22:15:50 +01:00
|
|
|
#include "device_pd.h"
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-06-08 09:05:32 +02:00
|
|
|
namespace Platform {
|
2015-04-17 14:12:30 +02:00
|
|
|
bool bus_valid(int bus = 0);
|
2015-05-26 20:12:17 +02:00
|
|
|
unsigned short bridge_bdf(unsigned char bus);
|
2015-11-05 09:06:29 +01:00
|
|
|
|
|
|
|
class Rmrr;
|
|
|
|
class Root;
|
2016-06-01 11:08:22 +02:00
|
|
|
class Ram_dataspace;
|
2015-04-17 14:12:30 +02:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-06-01 11:08:22 +02:00
|
|
|
class Platform::Ram_dataspace : public Genode::List<Ram_dataspace>::Element {
|
|
|
|
|
|
|
|
private:
|
|
|
|
Genode::Ram_dataspace_capability _cap;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Ram_dataspace(Genode::Ram_dataspace_capability c) : _cap(c) { }
|
|
|
|
|
|
|
|
bool match(const Genode::Ram_dataspace_capability &cap) const {
|
|
|
|
return cap.local_name() == _cap.local_name(); }
|
|
|
|
};
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
class Platform::Rmrr : public Genode::List<Platform::Rmrr>::Element
|
|
|
|
{
|
2015-10-20 14:47:24 +02:00
|
|
|
public:
|
|
|
|
|
|
|
|
class Bdf : public Genode::List<Bdf>::Element {
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
Genode::uint8_t _bus, _dev, _func;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Bdf(Genode::uint8_t bus, Genode::uint8_t dev,
|
|
|
|
Genode::uint8_t func)
|
|
|
|
: _bus(bus), _dev(dev), _func(func) { }
|
|
|
|
|
|
|
|
bool match(Genode::uint8_t bus, Genode::uint8_t dev,
|
|
|
|
Genode::uint8_t func) {
|
|
|
|
return bus == _bus && dev == _dev && func == _func; }
|
|
|
|
};
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
private:
|
|
|
|
|
2016-11-06 14:19:47 +01:00
|
|
|
Genode::uint64_t const _start, _end;
|
|
|
|
Genode::Io_mem_dataspace_capability _cap;
|
|
|
|
Genode::List<Bdf> _bdf_list;
|
2015-10-20 14:47:24 +02:00
|
|
|
|
2016-12-01 17:37:08 +01:00
|
|
|
Genode::Constructible<Genode::Io_mem_connection> _io_mem;
|
2015-11-05 09:06:29 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2015-10-20 14:47:24 +02:00
|
|
|
Rmrr(Genode::uint64_t start, Genode::uint64_t end)
|
|
|
|
: _start(start), _end(end)
|
2015-11-05 09:06:29 +01:00
|
|
|
{ }
|
|
|
|
|
2016-11-06 14:19:47 +01:00
|
|
|
Genode::Io_mem_dataspace_capability match(Device_config config)
|
|
|
|
{
|
2015-11-05 09:06:29 +01:00
|
|
|
Genode::uint8_t bus = config.bus_number();
|
|
|
|
Genode::uint8_t device = config.device_number();
|
|
|
|
Genode::uint8_t function = config.function_number();
|
|
|
|
|
2015-10-20 14:47:24 +02:00
|
|
|
for (Bdf *bdf = _bdf_list.first(); bdf; bdf = bdf->next()) {
|
|
|
|
if (!bdf->match(bus, device, function))
|
|
|
|
continue;
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2015-10-20 14:47:24 +02:00
|
|
|
if (_cap.valid())
|
|
|
|
return _cap;
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2016-11-06 14:19:47 +01:00
|
|
|
_io_mem.construct(_start, _end - _start + 1);
|
|
|
|
_cap = _io_mem->dataspace();
|
2015-10-20 14:47:24 +02:00
|
|
|
return _cap;
|
|
|
|
}
|
|
|
|
return Genode::Io_mem_dataspace_capability();
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
|
|
|
|
2015-10-20 14:47:24 +02:00
|
|
|
void add(Bdf * bdf) { _bdf_list.insert(bdf); }
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
static Genode::List<Rmrr> *list()
|
|
|
|
{
|
|
|
|
static Genode::List<Rmrr> _list;
|
|
|
|
return &_list;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
namespace Platform { class Session_component; }
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
class Platform::Session_component : public Genode::Rpc_object<Session>
|
|
|
|
{
|
|
|
|
private:
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Rpc_entrypoint &_ep;
|
|
|
|
Genode::Rpc_entrypoint &_device_pd_ep;
|
2016-11-23 14:21:34 +01:00
|
|
|
Genode::Ram_session_guard _env_ram;
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Ram_session_capability _env_ram_cap;
|
|
|
|
Genode::Region_map &_local_rm;
|
2016-11-23 14:21:34 +01:00
|
|
|
Genode::Heap _md_alloc;
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Session_label const _label;
|
|
|
|
Genode::Session_policy const _policy { _label };
|
|
|
|
Genode::List<Device_component> _device_list;
|
|
|
|
bool _no_device_pd = false;
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Registry of RAM dataspaces allocated by the session
|
|
|
|
*/
|
|
|
|
Genode::List<Platform::Ram_dataspace> _ram_caps;
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-23 14:21:34 +01:00
|
|
|
void _insert(Genode::Ram_dataspace_capability cap) {
|
|
|
|
_ram_caps.insert(new (_md_alloc) Platform::Ram_dataspace(cap)); }
|
2015-11-05 22:15:50 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
bool _remove(Genode::Ram_dataspace_capability cap)
|
|
|
|
{
|
|
|
|
for (Platform::Ram_dataspace *ds = _ram_caps.first(); ds;
|
2016-11-23 14:21:34 +01:00
|
|
|
ds = ds->next()) {
|
|
|
|
|
|
|
|
if (!ds->match(cap))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
_ram_caps.remove(ds);
|
|
|
|
destroy(_md_alloc, ds);
|
|
|
|
return true;
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
return false;
|
|
|
|
}
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Session-local RAM account
|
|
|
|
*
|
2016-11-23 14:21:34 +01:00
|
|
|
* Restrict physical address to 3G on 32bit, 4G on 64bit
|
2016-11-06 14:27:26 +01:00
|
|
|
*/
|
|
|
|
Genode::Ram_connection _ram {
|
|
|
|
_label.string(), 0, (sizeof(void *) == 4) ? 0xc0000000UL : 0x100000000UL };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Associate session RAM session with platform_drv _ram session and
|
|
|
|
* equip RAM session with initial quota to account for core-internal
|
|
|
|
* allocation meta-data overhead.
|
|
|
|
*/
|
|
|
|
void _init_ram()
|
|
|
|
{
|
|
|
|
_ram.ref_account(_env_ram_cap);
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
enum { OVERHEAD = 4096 };
|
|
|
|
if (_env_ram.transfer_quota(_ram, OVERHEAD) != 0)
|
2016-11-23 14:21:34 +01:00
|
|
|
throw Genode::Root::Quota_exceeded();
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
2015-11-05 22:15:50 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
bool const _ram_initialized = (_init_ram(), true);
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Deduce specified amount of quota from an allocator guard, or throw
|
|
|
|
* an 'Out_of_metadata' exception if the guard's quota is depleted.
|
|
|
|
*/
|
|
|
|
struct Quota_reservation
|
|
|
|
{
|
2016-11-23 14:21:34 +01:00
|
|
|
Genode::Ram_session_guard &guard;
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::size_t const amount;
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-23 14:21:34 +01:00
|
|
|
Quota_reservation(Genode::Ram_session_guard &guard,
|
|
|
|
Genode::size_t amount)
|
2016-11-06 14:27:26 +01:00
|
|
|
: guard(guard), amount(amount)
|
|
|
|
{
|
|
|
|
if (!guard.withdraw(amount))
|
|
|
|
throw Out_of_metadata();
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-23 14:21:34 +01:00
|
|
|
~Quota_reservation()
|
|
|
|
{
|
|
|
|
if (!guard.revert_withdraw(amount))
|
|
|
|
throw Fatal();
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
};
|
2016-01-08 18:11:23 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
class Device_pd
|
|
|
|
{
|
base: apply routing policy to environment sessions
This patch changes the child-construction procedure to allow the routing
of environment sessions to arbitrary servers, not only to the parent.
In particular, it restores the ability to route the LOG session of the
child to a LOG service provided by a child of init. In principle, it
becomes possible to also route the immediate child's PD, CPU, and RAM
environment sessions in arbitrary ways, which simplifies scenarios that
intercept those sessions, e.g., the CPU sampler.
Note that the latter ability should be used with great caution because
init needs to interact with these sessions to create/destruct the child.
Normally, the sessions are provided by the parent. So init is safe at
all times. If they are routed to a child however, init will naturally
become dependent on this particular child. For the LOG session, this is
actually not a problem because even though the parent creates the LOG
session as part of the child's environment, it never interacts with the
session directly.
Fixes #2197
2016-12-12 17:40:55 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
class Startup_failed : Genode::Exception { };
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
private:
|
2015-04-20 11:38:55 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
enum { RAM_QUOTA = 190 * 4096 };
|
2015-04-20 11:38:55 +02:00
|
|
|
|
base: apply routing policy to environment sessions
This patch changes the child-construction procedure to allow the routing
of environment sessions to arbitrary servers, not only to the parent.
In particular, it restores the ability to route the LOG session of the
child to a LOG service provided by a child of init. In principle, it
becomes possible to also route the immediate child's PD, CPU, and RAM
environment sessions in arbitrary ways, which simplifies scenarios that
intercept those sessions, e.g., the CPU sampler.
Note that the latter ability should be used with great caution because
init needs to interact with these sessions to create/destruct the child.
Normally, the sessions are provided by the parent. So init is safe at
all times. If they are routed to a child however, init will naturally
become dependent on this particular child. For the LOG session, this is
actually not a problem because even though the parent creates the LOG
session as part of the child's environment, it never interacts with the
session directly.
Fixes #2197
2016-12-12 17:40:55 +01:00
|
|
|
Quota_reservation const _reservation;
|
|
|
|
Device_pd_policy _policy;
|
|
|
|
Genode::Child _child;
|
|
|
|
|
|
|
|
void _check_child_started_up() const {
|
|
|
|
if (!_child.active())
|
|
|
|
throw Startup_failed(); }
|
|
|
|
|
|
|
|
bool const _active = (_check_child_started_up(), true);
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Slave::Connection<Device_pd_connection> _connection;
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
public:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \throw Out_of_metadata session RAM does not suffice
|
|
|
|
* for creating device PD
|
base: apply routing policy to environment sessions
This patch changes the child-construction procedure to allow the routing
of environment sessions to arbitrary servers, not only to the parent.
In particular, it restores the ability to route the LOG session of the
child to a LOG service provided by a child of init. In principle, it
becomes possible to also route the immediate child's PD, CPU, and RAM
environment sessions in arbitrary ways, which simplifies scenarios that
intercept those sessions, e.g., the CPU sampler.
Note that the latter ability should be used with great caution because
init needs to interact with these sessions to create/destruct the child.
Normally, the sessions are provided by the parent. So init is safe at
all times. If they are routed to a child however, init will naturally
become dependent on this particular child. For the LOG session, this is
actually not a problem because even though the parent creates the LOG
session as part of the child's environment, it never interacts with the
session directly.
Fixes #2197
2016-12-12 17:40:55 +01:00
|
|
|
* \throw Startup_failed child could not be started
|
2016-11-06 14:27:26 +01:00
|
|
|
* \throw Parent::Service_denied by 'Slave::Connection'
|
|
|
|
*/
|
|
|
|
Device_pd(Genode::Region_map &local_rm,
|
|
|
|
Genode::Rpc_entrypoint &ep,
|
2016-11-23 14:21:34 +01:00
|
|
|
Genode::Ram_session_guard &guard,
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Ram_session_capability ref_ram,
|
|
|
|
Genode::Session_label const &label)
|
|
|
|
try :
|
|
|
|
_reservation(guard, RAM_QUOTA),
|
|
|
|
_policy(ep, local_rm, ref_ram, RAM_QUOTA, label),
|
|
|
|
_child(local_rm, ep, _policy),
|
|
|
|
_connection(_policy, Genode::Slave::Args())
|
|
|
|
{ }
|
|
|
|
/* thrown by 'Quota_reservation' */
|
|
|
|
catch (Out_of_metadata) { throw; }
|
|
|
|
/* thrown by 'Device_pd_policy' or 'Child' */
|
|
|
|
catch (Genode::Ram_session::Alloc_failed) { throw Out_of_metadata(); }
|
|
|
|
/* throw by 'Slave::Connection' */
|
|
|
|
catch (Genode::Parent::Quota_exceeded) { throw Out_of_metadata(); }
|
|
|
|
|
|
|
|
Device_pd_client &session() { return _connection; }
|
|
|
|
|
|
|
|
Genode::Ram_session_capability ram_session_cap() {
|
|
|
|
return _child.ram_session_cap(); }
|
|
|
|
};
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Device_pd *_device_pd = nullptr;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Free device PD at session destruction
|
|
|
|
*/
|
|
|
|
struct Device_pd_guard
|
|
|
|
{
|
|
|
|
Session_component &session;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
~Device_pd_guard() {
|
|
|
|
if (session._device_pd)
|
|
|
|
Genode::destroy(session._md_alloc, session._device_pd); }
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
} _device_pd_guard { *this };
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Attempt to initialize device PD
|
|
|
|
*
|
|
|
|
* \throw Out_of_metadata session quota does not suffice to spawn the
|
|
|
|
* device PD
|
|
|
|
*/
|
|
|
|
void _try_init_device_pd()
|
|
|
|
{
|
|
|
|
if (_device_pd || _no_device_pd)
|
|
|
|
return;
|
2014-01-24 10:11:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
|
|
|
_device_pd = new (_md_alloc)
|
2016-11-23 14:21:34 +01:00
|
|
|
Device_pd(_local_rm, _device_pd_ep, _env_ram,
|
2016-11-06 14:27:26 +01:00
|
|
|
_env_ram_cap, _label);
|
2013-02-18 10:06:34 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* thrown by '_md_alloc' */
|
|
|
|
catch (Genode::Allocator::Out_of_memory) { throw Out_of_metadata(); }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* thrown by 'Device_pd' */
|
|
|
|
catch (Out_of_metadata) { throw; }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
catch (...) {
|
|
|
|
Genode::warning("PCI device protection domain for IOMMU support "
|
|
|
|
"is not available");
|
|
|
|
_no_device_pd = true;
|
2015-04-22 17:06:10 +02:00
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES *
|
|
|
|
Device_config::MAX_DEVICES *
|
|
|
|
Device_config::MAX_FUNCTIONS };
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
static Genode::Bit_array<MAX_PCI_DEVICES> bdf_in_use;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Scan PCI buses for a device
|
|
|
|
*
|
|
|
|
* \param bus start scanning at bus number
|
|
|
|
* \param device start scanning at device number
|
|
|
|
* \param function start scanning at function number
|
|
|
|
* \param out_device_config device config information of the
|
|
|
|
* found device
|
|
|
|
* \param config_access interface for accessing the PCI
|
|
|
|
* configuration
|
|
|
|
* space
|
|
|
|
*
|
|
|
|
* \retval true device was found
|
|
|
|
* \retval false no device was found
|
|
|
|
*/
|
|
|
|
bool _find_next(int bus, int device, int function,
|
|
|
|
Device_config *out_device_config,
|
|
|
|
Config_access *config_access)
|
|
|
|
{
|
|
|
|
for (; bus < Device_config::MAX_BUSES; bus++) {
|
|
|
|
if (!bus_valid(bus))
|
|
|
|
continue;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
for (; device < Device_config::MAX_DEVICES; device++) {
|
|
|
|
for (; function < Device_config::MAX_FUNCTIONS; function++) {
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* read config space */
|
|
|
|
Device_config config(bus, device, function, config_access);
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (config.valid()) {
|
|
|
|
*out_device_config = config;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function = 0; /* init value for next device */
|
|
|
|
}
|
|
|
|
device = 0; /* init value for next bus */
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* List containing extended PCI config space information
|
|
|
|
*/
|
|
|
|
static Genode::List<Config_space> &config_space_list() {
|
|
|
|
static Genode::List<Config_space> config_space;
|
|
|
|
return config_space;
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Find for a given PCI device described by the bus:dev:func triple
|
|
|
|
* the corresponding extended 4K PCI config space address.
|
|
|
|
* A io mem dataspace is created and returned.
|
|
|
|
*/
|
|
|
|
Genode::addr_t
|
|
|
|
lookup_config_space(Genode::uint16_t const bdf)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
addr_t config_space = ~0UL; /* invalid */
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Config_space *e = config_space_list().first();
|
|
|
|
for (; e && (config_space == ~0UL); e = e->next())
|
|
|
|
config_space = e->lookup_config_space(bdf);
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
return config_space;
|
|
|
|
}
|
2015-05-26 10:40:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/*
|
|
|
|
* List of aliases for PCI Class/Subclas/Prog I/F triple used
|
|
|
|
* by xml config for this platform driver
|
|
|
|
*/
|
|
|
|
unsigned class_subclass_prog(const char * name) {
|
|
|
|
using namespace Genode;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
static struct {
|
|
|
|
const char * alias;
|
|
|
|
uint8_t pci_class, pci_subclass, pci_progif;
|
|
|
|
} const aliases [] = {
|
|
|
|
{ "AHCI" , 0x1, 0x06, 0x0},
|
|
|
|
{ "ALL" , 0x0, 0x00, 0x0},
|
|
|
|
{ "AUDIO" , 0x4, 0x01, 0x0},
|
|
|
|
{ "ETHERNET" , 0x2, 0x00, 0x0},
|
|
|
|
{ "HDAUDIO" , 0x4, 0x03, 0x0},
|
|
|
|
{ "USB" , 0xc, 0x03, 0x0},
|
|
|
|
{ "VGA" , 0x3, 0x00, 0x0},
|
|
|
|
{ "WIFI" , 0x2, 0x80, 0x0},
|
|
|
|
{ "ISABRIDGE", 0x6, 0x01, 0x0}
|
|
|
|
};
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
for (unsigned i = 0; i < sizeof(aliases) / sizeof(aliases[0]); i++) {
|
|
|
|
if (strcmp(aliases[i].alias, name))
|
|
|
|
continue;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
return 0U | aliases[i].pci_class << 16 |
|
|
|
|
aliases[i].pci_subclass << 8 |
|
|
|
|
aliases[i].pci_progif;
|
2015-04-22 17:06:10 +02:00
|
|
|
}
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
return ~0U;
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Check device usage according to session policy
|
|
|
|
*/
|
|
|
|
bool permit_device(const char * name)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
|
|
|
_policy.for_each_sub_node("device", [&] (Xml_node dev) {
|
|
|
|
try {
|
|
|
|
/* enforce restriction based on name name */
|
|
|
|
char policy_name[8];
|
|
|
|
dev.attribute("name").value(policy_name,
|
|
|
|
sizeof(policy_name));
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (!strcmp(policy_name, name))
|
|
|
|
/* found identical match - permit access */
|
|
|
|
throw true;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) { }
|
|
|
|
});
|
|
|
|
} catch (bool result) { return result; }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
return false;
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Check according session policy device usage
|
|
|
|
*/
|
|
|
|
bool permit_device(Genode::uint8_t b, Genode::uint8_t d,
|
|
|
|
Genode::uint8_t f, unsigned class_code)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
|
|
|
_policy.for_each_sub_node("pci", [&] (Xml_node node) {
|
2015-04-22 17:06:10 +02:00
|
|
|
try {
|
2016-11-06 14:27:26 +01:00
|
|
|
unsigned bus, device, function;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
node.attribute("bus").value(&bus);
|
|
|
|
node.attribute("device").value(&device);
|
|
|
|
node.attribute("function").value(&function);
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (b == bus && d == device && f == function)
|
|
|
|
throw true;
|
|
|
|
|
|
|
|
return;
|
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) { }
|
|
|
|
|
|
|
|
/* enforce restriction based upon classes */
|
|
|
|
unsigned class_sub_prog = 0;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
char alias_class[32];
|
|
|
|
node.attribute("class").value(alias_class,
|
|
|
|
sizeof(alias_class));
|
|
|
|
|
|
|
|
class_sub_prog = class_subclass_prog(alias_class);
|
2016-11-06 14:27:26 +01:00
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum { DONT_CHECK_PROGIF = 8 };
|
|
|
|
/* if class/subclass don't match - deny */
|
|
|
|
if (class_sub_prog && (class_sub_prog ^ class_code) >> DONT_CHECK_PROGIF)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* if this bdf is used by some policy - deny */
|
|
|
|
if (find_dev_in_policy(b, d, f))
|
|
|
|
return;
|
|
|
|
|
|
|
|
throw true;
|
|
|
|
});
|
|
|
|
} catch (bool result) { return result; }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lookup a given device name.
|
|
|
|
*/
|
|
|
|
bool find_dev_in_policy(const char * dev_name, bool once = true)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
try {
|
|
|
|
config()->xml_node().for_each_sub_node("policy", [&] (Xml_node policy) {
|
|
|
|
policy.for_each_sub_node("device", [&] (Xml_node device) {
|
|
|
|
try {
|
|
|
|
/* device attribute from policy node */
|
|
|
|
char policy_device[8];
|
|
|
|
device.attribute("name").value(policy_device, sizeof(policy_device));
|
|
|
|
|
|
|
|
if (!strcmp(policy_device, dev_name)) {
|
|
|
|
if (once)
|
|
|
|
throw true;
|
|
|
|
once = true;
|
|
|
|
}
|
|
|
|
} catch (Xml_node::Nonexistent_attribute) { }
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch (bool result) { return result; }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lookup a given device name.
|
|
|
|
*/
|
|
|
|
bool find_dev_in_policy(Genode::uint8_t b, Genode::uint8_t d,
|
|
|
|
Genode::uint8_t f, bool once = true)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
|
|
|
Xml_node xml(config()->xml_node());
|
|
|
|
xml.for_each_sub_node("policy", [&] (Xml_node policy) {
|
|
|
|
policy.for_each_sub_node("pci", [&] (Xml_node node) {
|
2015-04-22 17:06:10 +02:00
|
|
|
try {
|
2016-11-06 14:27:26 +01:00
|
|
|
unsigned bus, device, function;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
node.attribute("bus").value(&bus);
|
|
|
|
node.attribute("device").value(&device);
|
|
|
|
node.attribute("function").value(&function);
|
|
|
|
|
|
|
|
if (b == bus && d == device && f == function) {
|
|
|
|
if (once)
|
|
|
|
throw true;
|
|
|
|
once = true;
|
|
|
|
}
|
|
|
|
} catch (Xml_node::Nonexistent_attribute) { }
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch (bool result) { return result; }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2016-11-23 14:21:34 +01:00
|
|
|
Session_component(Genode::Env &env,
|
|
|
|
Genode::Rpc_entrypoint &ep,
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Rpc_entrypoint &device_pd_ep,
|
|
|
|
char const *args)
|
|
|
|
:
|
|
|
|
_ep(ep), _device_pd_ep(device_pd_ep),
|
2016-11-23 14:21:34 +01:00
|
|
|
_env_ram(env.ram(), env.ram_session_cap(),
|
|
|
|
Genode::Arg_string::find_arg(args, "ram_quota").long_value(0)),
|
|
|
|
_env_ram_cap(env.ram_session_cap()),
|
|
|
|
_local_rm(env.rm()),
|
|
|
|
_md_alloc(_env_ram, env.rm()),
|
2016-11-06 14:27:26 +01:00
|
|
|
_label(Genode::label_from_args(args))
|
|
|
|
{
|
|
|
|
/* non-pci devices */
|
|
|
|
_policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) {
|
|
|
|
try {
|
|
|
|
char policy_device[8];
|
|
|
|
device_node.attribute("name").value(policy_device,
|
|
|
|
sizeof(policy_device));
|
|
|
|
|
|
|
|
enum { DOUBLET = false };
|
|
|
|
if (!find_dev_in_policy(policy_device, DOUBLET))
|
2015-04-22 17:06:10 +02:00
|
|
|
return;
|
2016-11-06 14:27:26 +01:00
|
|
|
|
|
|
|
Genode::error("'", _label, "' - device "
|
|
|
|
"'", Genode::Cstring(policy_device), "' "
|
|
|
|
"is part of more than one policy");
|
|
|
|
} catch (Genode::Xml_node::Nonexistent_attribute) {
|
|
|
|
Genode::error("'", _label, "' - device node "
|
|
|
|
"misses a 'name' attribute");
|
|
|
|
}
|
|
|
|
throw Genode::Root::Unavailable();
|
|
|
|
});
|
|
|
|
|
|
|
|
/* pci devices */
|
|
|
|
_policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) {
|
|
|
|
enum { INVALID_CLASS = 0x1000000U };
|
|
|
|
unsigned class_sub_prog = INVALID_CLASS;
|
|
|
|
|
|
|
|
using Genode::Xml_attribute;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Valid input is either a triple of 'bus', 'device',
|
|
|
|
* 'function' attributes or a single 'class' attribute.
|
|
|
|
* All other attribute names are traded as wrong.
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
char alias_class[32];
|
|
|
|
node.attribute("class").value(alias_class,
|
|
|
|
sizeof(alias_class));
|
|
|
|
|
|
|
|
class_sub_prog = class_subclass_prog(alias_class);
|
|
|
|
if (class_sub_prog >= INVALID_CLASS) {
|
|
|
|
Genode::error("'", _label, "' - invalid 'class' ",
|
|
|
|
"attribute '", Genode::Cstring(alias_class), "'");
|
|
|
|
throw Genode::Root::Unavailable();
|
2015-04-22 17:06:10 +02:00
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) { }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* if we read a class attribute all is fine */
|
|
|
|
if (class_sub_prog < INVALID_CLASS) {
|
|
|
|
/* sanity check that 'class' is the only attribute */
|
2015-04-22 17:06:10 +02:00
|
|
|
try {
|
2016-11-06 14:27:26 +01:00
|
|
|
node.attribute(1);
|
|
|
|
Genode::error("'", _label, "' - attributes beside 'class' detected");
|
2015-04-22 17:06:10 +02:00
|
|
|
throw Genode::Root::Unavailable();
|
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) { }
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* we have a class and it is the only attribute */
|
|
|
|
return;
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* no 'class' attribute - now check for valid bdf triple */
|
|
|
|
try {
|
|
|
|
node.attribute(3);
|
|
|
|
Genode::error("'", _label, "' - "
|
|
|
|
"invalid number of pci node attributes");
|
|
|
|
throw Genode::Root::Unavailable();
|
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) { }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
|
|
|
unsigned bus, device, function;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
node.attribute("bus").value(&bus);
|
|
|
|
node.attribute("device").value(&device);
|
|
|
|
node.attribute("function").value(&function);
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if ((bus >= Device_config::MAX_BUSES) ||
|
|
|
|
(device >= Device_config::MAX_DEVICES) ||
|
|
|
|
(function >= Device_config::MAX_FUNCTIONS))
|
|
|
|
throw Xml_attribute::Nonexistent_attribute();
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
enum { DOUBLET = false };
|
|
|
|
if (!find_dev_in_policy(bus, device, function, DOUBLET))
|
|
|
|
return;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::error("'", _label, "' - device '",
|
|
|
|
Genode::Hex(bus), ":",
|
|
|
|
Genode::Hex(device), ".", function, "' "
|
|
|
|
"is part of more than one policy");
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) {
|
|
|
|
Genode::error("'", _label, "' - "
|
|
|
|
"invalid pci node attributes for bdf");
|
|
|
|
}
|
|
|
|
throw Genode::Root::Unavailable();
|
|
|
|
});
|
|
|
|
}
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*/
|
|
|
|
~Session_component()
|
|
|
|
{
|
|
|
|
/* release all elements of the session's device list */
|
|
|
|
while (_device_list.first())
|
|
|
|
release_device(_device_list.first()->cap());
|
|
|
|
}
|
2015-04-16 15:54:07 +02:00
|
|
|
|
|
|
|
|
2016-11-23 14:21:34 +01:00
|
|
|
void upgrade_ram_quota(long quota) { _env_ram.upgrade(quota); }
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
static void add_config_space(Genode::uint32_t bdf_start,
|
|
|
|
Genode::uint32_t func_count,
|
|
|
|
Genode::addr_t base)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
Config_space * space =
|
|
|
|
new (env()->heap()) Config_space(bdf_start, func_count,
|
|
|
|
base);
|
|
|
|
config_space_list().insert(space);
|
|
|
|
}
|
2015-10-06 15:37:59 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check whether msi usage was explicitly switched off
|
|
|
|
*/
|
|
|
|
bool msi_usage()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
char mode[8];
|
|
|
|
_policy.attribute("irq_mode").value(mode, sizeof(mode));
|
|
|
|
if (!Genode::strcmp("nomsi", mode))
|
|
|
|
return false;
|
|
|
|
} catch (Genode::Xml_node::Nonexistent_attribute) { }
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-06 15:37:59 +02:00
|
|
|
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/***************************
|
|
|
|
** PCI session interface **
|
|
|
|
***************************/
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Device_capability first_device(unsigned device_class,
|
|
|
|
unsigned class_mask) override {
|
|
|
|
return next_device(Device_capability(), device_class, class_mask); }
|
|
|
|
|
|
|
|
Device_capability next_device(Device_capability prev_device,
|
|
|
|
unsigned device_class,
|
|
|
|
unsigned class_mask) override
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Create the interface to the PCI config space.
|
|
|
|
* This involves the creation of I/O port sessions.
|
|
|
|
*/
|
|
|
|
Config_access config_access;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* lookup device component for previous device */
|
|
|
|
auto lambda = [&] (Device_component *prev)
|
2011-12-22 16:19:25 +01:00
|
|
|
{
|
2016-11-06 14:27:26 +01:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2016-11-06 14:27:26 +01:00
|
|
|
* Start bus scanning after the previous device's location.
|
|
|
|
* If no valid device was specified for 'prev_device',
|
|
|
|
* start at the beginning.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
2016-11-06 14:27:26 +01:00
|
|
|
int bus = 0, device = 0, function = -1;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (prev) {
|
|
|
|
Device_config config = prev->config();
|
|
|
|
bus = config.bus_number();
|
|
|
|
device = config.device_number();
|
|
|
|
function = config.function_number();
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/*
|
|
|
|
* Scan buses for devices.
|
|
|
|
* If no device is found, return an invalid capability.
|
|
|
|
*/
|
|
|
|
Device_config config;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
while (true) {
|
|
|
|
function += 1;
|
|
|
|
if (!_find_next(bus, device, function, &config,
|
|
|
|
&config_access))
|
|
|
|
return Device_capability();
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* get new bdf values */
|
|
|
|
bus = config.bus_number();
|
|
|
|
device = config.device_number();
|
|
|
|
function = config.function_number();
|
2013-02-18 10:08:14 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* if filter of driver don't match skip and continue */
|
|
|
|
if ((config.class_code() ^ device_class) & class_mask)
|
|
|
|
continue;
|
2015-04-20 11:38:55 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* check that policy permit access to the matched device */
|
|
|
|
if (permit_device(bus, device, function,
|
|
|
|
config.class_code()))
|
|
|
|
break;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* lookup if we have a extended pci config space */
|
|
|
|
Genode::addr_t config_space =
|
|
|
|
lookup_config_space(config.bdf());
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/*
|
|
|
|
* A device was found. Create a new device component for the
|
|
|
|
* device and return its capability.
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
Device_component * dev = new (_md_alloc)
|
|
|
|
Device_component(config, config_space, _ep, *this,
|
|
|
|
_md_alloc);
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* if more than one driver uses the device - warn about */
|
2015-10-06 16:53:56 +02:00
|
|
|
if (bdf_in_use.get(Device_config::MAX_BUSES * bus +
|
2016-11-06 14:27:26 +01:00
|
|
|
Device_config::MAX_DEVICES * device +
|
|
|
|
function, 1))
|
|
|
|
Genode::error("Device ",
|
|
|
|
Genode::Hex(bus), ":",
|
|
|
|
Genode::Hex(device), ".", function, " "
|
|
|
|
"is used by more than one driver - "
|
|
|
|
"session '", _label, "'.");
|
|
|
|
else
|
|
|
|
bdf_in_use.set(Device_config::MAX_BUSES * bus +
|
|
|
|
Device_config::MAX_DEVICES * device +
|
|
|
|
function, 1);
|
|
|
|
|
|
|
|
_device_list.insert(dev);
|
|
|
|
return _ep.manage(dev);
|
|
|
|
} catch (Genode::Allocator::Out_of_memory) {
|
|
|
|
throw Out_of_metadata();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return _ep.apply(prev_device, lambda);
|
|
|
|
}
|
2015-04-20 11:38:55 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
void release_device(Device_capability device_cap) override
|
|
|
|
{
|
|
|
|
Device_component * device;
|
|
|
|
auto lambda = [&] (Device_component *d)
|
|
|
|
{
|
|
|
|
device = d;
|
|
|
|
if (!device)
|
|
|
|
return;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
unsigned const bus = device->config().bus_number();
|
|
|
|
unsigned const dev = device->config().device_number();
|
|
|
|
unsigned const func = device->config().function_number();
|
2015-09-23 08:37:12 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (bdf_in_use.get(Device_config::MAX_BUSES * bus +
|
|
|
|
Device_config::MAX_DEVICES * dev +
|
|
|
|
func, 1))
|
|
|
|
bdf_in_use.clear(Device_config::MAX_BUSES * bus +
|
|
|
|
Device_config::MAX_DEVICES * dev + func, 1);
|
2015-09-23 08:37:12 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
_device_list.remove(device);
|
|
|
|
_ep.dissolve(device);
|
|
|
|
};
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* lookup device component for previous device */
|
|
|
|
_ep.apply(device_cap, lambda);
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (!device) return;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (device->config().valid())
|
|
|
|
destroy(_md_alloc, device);
|
|
|
|
else
|
|
|
|
destroy(_md_alloc, device);
|
|
|
|
}
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
void assign_device(Device_component * device)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (!device || !device->get_config_space().valid())
|
|
|
|
return;
|
2013-02-18 10:08:14 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Io_mem_dataspace_capability io_mem = device->get_config_space();
|
2015-05-05 18:43:58 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
_try_init_device_pd();
|
|
|
|
if (!_device_pd)
|
|
|
|
return;
|
|
|
|
|
|
|
|
try {
|
|
|
|
_device_pd->session().assign_pci(io_mem, device->config().bdf());
|
|
|
|
|
|
|
|
for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
|
|
|
|
Io_mem_dataspace_capability rmrr_cap = r->match(device->config());
|
|
|
|
if (rmrr_cap.valid())
|
|
|
|
_device_pd->session().attach_dma_mem(rmrr_cap);
|
2015-11-16 14:04:04 +01:00
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
} catch (...) {
|
|
|
|
Genode::error("assignment to device pd or of RMRR region failed");
|
2015-05-05 18:43:58 +02:00
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
2015-05-05 18:43:58 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* De-/Allocation of dma capable dataspaces
|
|
|
|
*/
|
|
|
|
typedef Genode::Ram_dataspace_capability Ram_capability;
|
2015-02-08 13:02:11 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Helper method for rollback
|
|
|
|
*/
|
|
|
|
void _rollback(Genode::size_t const size,
|
|
|
|
Genode::Ram_dataspace_capability const ram_cap = Genode::Ram_dataspace_capability(),
|
|
|
|
bool const throw_oom = true)
|
|
|
|
{
|
|
|
|
if (ram_cap.valid())
|
|
|
|
_ram.free(ram_cap);
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-23 14:21:34 +01:00
|
|
|
if (_env_ram.revert_transfer_quota(_ram, size))
|
2016-11-06 14:27:26 +01:00
|
|
|
throw Fatal();
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (throw_oom)
|
|
|
|
throw Out_of_metadata();
|
|
|
|
}
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t const size) override
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We always try to create the device PD first because
|
|
|
|
* otherwise we might consume the requested size multiple
|
|
|
|
* times which breaks our accounting.
|
|
|
|
*/
|
|
|
|
_try_init_device_pd();
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* transfer ram quota to session specific ram session */
|
2016-11-23 14:21:34 +01:00
|
|
|
if (_env_ram.transfer_quota<Out_of_metadata>(_ram, size))
|
2016-11-06 14:27:26 +01:00
|
|
|
throw Fatal();
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
enum { UPGRADE_QUOTA = 4096 };
|
|
|
|
|
|
|
|
/* allocate dataspace from session specific ram session */
|
|
|
|
Ram_capability ram_cap = Genode::retry<Genode::Ram_session::Quota_exceeded>(
|
|
|
|
[&] () {
|
|
|
|
Ram_capability ram = Genode::retry<Genode::Ram_session::Out_of_metadata>(
|
|
|
|
[&] () { return _ram.alloc(size, Genode::UNCACHED); },
|
|
|
|
[&] () { throw Genode::Ram_session::Quota_exceeded(); });
|
|
|
|
return ram;
|
|
|
|
},
|
|
|
|
[&] () {
|
2016-11-23 14:21:34 +01:00
|
|
|
if (!_env_ram.withdraw(UPGRADE_QUOTA))
|
2016-11-06 14:27:26 +01:00
|
|
|
_rollback(size);
|
|
|
|
|
|
|
|
_ram.upgrade_ram(UPGRADE_QUOTA);
|
|
|
|
});
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (!ram_cap.valid())
|
|
|
|
return ram_cap;
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (_device_pd) {
|
|
|
|
Genode::retry<Genode::Rm_session::Out_of_metadata>(
|
|
|
|
[&] () { _device_pd->session().attach_dma_mem(ram_cap); },
|
2016-06-01 11:08:22 +02:00
|
|
|
[&] () {
|
2016-11-23 14:21:34 +01:00
|
|
|
if (!_env_ram.withdraw(UPGRADE_QUOTA))
|
2016-11-06 14:27:26 +01:00
|
|
|
_rollback(size, ram_cap);
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (_env_ram.transfer_quota(_ram, UPGRADE_QUOTA))
|
|
|
|
throw Fatal();
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
if (_ram.transfer_quota(_device_pd->ram_session_cap(), UPGRADE_QUOTA))
|
|
|
|
throw Fatal();
|
|
|
|
});
|
|
|
|
}
|
2013-02-18 10:08:14 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try { _insert(ram_cap); }
|
2016-11-23 14:21:34 +01:00
|
|
|
catch (Genode::Allocator::Out_of_memory) {
|
|
|
|
_rollback(size, ram_cap); }
|
2015-11-16 14:04:04 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
return ram_cap;
|
|
|
|
}
|
2013-02-18 10:08:14 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
void free_dma_buffer(Genode::Ram_dataspace_capability ram_cap) override
|
|
|
|
{
|
|
|
|
if (!ram_cap.valid() || !_remove(ram_cap))
|
|
|
|
return;
|
2014-01-24 10:11:25 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::size_t size = Genode::Dataspace_client(ram_cap).size();
|
|
|
|
_rollback(size, ram_cap, false);
|
|
|
|
}
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
Device_capability device(String const &name) override;
|
|
|
|
};
|
2015-04-17 14:12:30 +02:00
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
class Platform::Root : public Genode::Root_component<Session_component>
|
|
|
|
{
|
|
|
|
private:
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-05-13 16:09:20 +02:00
|
|
|
struct Fadt {
|
|
|
|
Genode::uint32_t features = 0, reset_type = 0, reset_value = 0;
|
|
|
|
Genode::uint64_t reset_addr = 0;
|
|
|
|
|
|
|
|
/* Table 5-35 Fixed ACPI Description Table Fixed Feature Flags */
|
|
|
|
struct Features : Genode::Register<32> {
|
|
|
|
struct Reset : Bitfield<10, 1> { };
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ACPI spec - 5.2.3.2 Generic Address Structure */
|
|
|
|
struct Gas : Genode::Register<32>
|
|
|
|
{
|
|
|
|
struct Address_space : Bitfield <0, 8> {
|
|
|
|
enum { SYSTEM_IO = 1 };
|
|
|
|
};
|
|
|
|
struct Access_size : Bitfield<24,8> {
|
|
|
|
enum { UNDEFINED = 0, BYTE = 1, WORD = 2, DWORD = 3, QWORD = 4};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
} fadt;
|
|
|
|
|
2016-11-23 14:21:34 +01:00
|
|
|
Genode::Env &_env;
|
|
|
|
Genode::Rpc_entrypoint _device_pd_ep;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
void _parse_report_rom(const char * acpi_rom)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
Config_access config_access;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
Xml_node xml_acpi(acpi_rom);
|
|
|
|
if (!xml_acpi.has_type("acpi"))
|
|
|
|
throw 1;
|
2015-06-10 11:28:00 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
for (unsigned i = 0; i < xml_acpi.num_sub_nodes(); i++) {
|
|
|
|
Xml_node node = xml_acpi.sub_node(i);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.has_type("bdf")) {
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
uint32_t bdf_start = 0;
|
|
|
|
uint32_t func_count = 0;
|
|
|
|
addr_t base = 0;
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
node.attribute("start").value(&bdf_start);
|
|
|
|
node.attribute("count").value(&func_count);
|
|
|
|
node.attribute("base").value(&base);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
Session_component::add_config_space(bdf_start, func_count,
|
|
|
|
base);
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.has_type("irq_override")) {
|
|
|
|
unsigned irq = 0xff;
|
|
|
|
unsigned gsi = 0xff;
|
|
|
|
unsigned flags = 0xff;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
node.attribute("irq").value(&irq);
|
|
|
|
node.attribute("gsi").value(&gsi);
|
|
|
|
node.attribute("flags").value(&flags);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
using Platform::Irq_override;
|
|
|
|
Irq_override * o = new (env()->heap()) Irq_override(irq,
|
|
|
|
gsi,
|
|
|
|
flags);
|
|
|
|
Irq_override::list()->insert(o);
|
|
|
|
}
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.has_type("rmrr")) {
|
|
|
|
uint64_t mem_start, mem_end;
|
|
|
|
node.attribute("start").value(&mem_start);
|
|
|
|
node.attribute("end").value(&mem_end);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.num_sub_nodes() == 0)
|
|
|
|
throw 2;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-10-20 14:47:24 +02:00
|
|
|
Rmrr * rmrr = new (env()->heap()) Rmrr(mem_start, mem_end);
|
|
|
|
Rmrr::list()->insert(rmrr);
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
for (unsigned s = 0; s < node.num_sub_nodes(); s++) {
|
|
|
|
Xml_node scope = node.sub_node(s);
|
|
|
|
if (!scope.num_sub_nodes() || !scope.has_type("scope"))
|
|
|
|
throw 3;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
unsigned bus, dev, func;
|
|
|
|
scope.attribute("bus_start").value(&bus);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
for (unsigned p = 0; p < scope.num_sub_nodes(); p++) {
|
|
|
|
Xml_node path = scope.sub_node(p);
|
|
|
|
if (!path.has_type("path"))
|
|
|
|
throw 4;
|
2015-06-10 11:28:00 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
path.attribute("dev").value(&dev);
|
|
|
|
path.attribute("func").value(&func);
|
|
|
|
|
|
|
|
Device_config bridge(bus, dev, func,
|
|
|
|
&config_access);
|
2016-05-11 18:21:47 +02:00
|
|
|
if (bridge.pci_bridge())
|
2015-11-05 09:06:29 +01:00
|
|
|
/* PCI bridge spec 3.2.5.3, 3.2.5.4 */
|
|
|
|
bus = bridge.read(&config_access, 0x19,
|
|
|
|
Device::ACCESS_8BIT);
|
2015-05-26 20:12:17 +02:00
|
|
|
}
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2015-10-20 14:47:24 +02:00
|
|
|
rmrr->add(new (env()->heap()) Rmrr::Bdf(bus, dev,
|
|
|
|
func));
|
2013-02-18 10:06:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-13 16:09:20 +02:00
|
|
|
if (node.has_type("fadt")) {
|
|
|
|
node.attribute("features").value(&fadt.features);
|
|
|
|
node.attribute("reset_type").value(&fadt.reset_type);
|
|
|
|
node.attribute("reset_addr").value(&fadt.reset_addr);
|
|
|
|
node.attribute("reset_value").value(&fadt.reset_value);
|
|
|
|
}
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (!node.has_type("routing"))
|
|
|
|
continue;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
unsigned gsi;
|
|
|
|
unsigned bridge_bdf;
|
|
|
|
unsigned device;
|
|
|
|
unsigned device_pin;
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
node.attribute("gsi").value(&gsi);
|
|
|
|
node.attribute("bridge_bdf").value(&bridge_bdf);
|
|
|
|
node.attribute("device").value(&device);
|
|
|
|
node.attribute("device_pin").value(&device_pin);
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
/* check that bridge bdf is actually a valid device */
|
|
|
|
Device_config config((bridge_bdf >> 8 & 0xff),
|
|
|
|
(bridge_bdf >> 3) & 0x1f,
|
|
|
|
bridge_bdf & 0x7, &config_access);
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (!config.valid())
|
|
|
|
continue;
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!config.pci_bridge() && bridge_bdf != 0)
|
2015-11-05 09:06:29 +01:00
|
|
|
/**
|
|
|
|
* If the bridge bdf has not a type header of a bridge in
|
|
|
|
* the pci config space, then it should be the host bridge
|
|
|
|
* device. The host bridge device need not to be
|
|
|
|
* necessarily at 0:0.0, it may be on another location. The
|
|
|
|
* irq routing information for the host bridge however
|
|
|
|
* contain entries for the bridge bdf to be 0:0.0 -
|
|
|
|
* therefore we override it here for the irq rerouting
|
|
|
|
* information of host bridge devices.
|
|
|
|
*/
|
|
|
|
bridge_bdf = 0;
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
Irq_routing * r = new (env()->heap()) Irq_routing(gsi,
|
|
|
|
bridge_bdf,
|
|
|
|
device,
|
|
|
|
device_pin);
|
|
|
|
Irq_routing::list()->insert(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
Session_component *_create_session(const char *args)
|
|
|
|
{
|
|
|
|
try {
|
2016-11-06 14:27:26 +01:00
|
|
|
return new (md_alloc())
|
2016-11-23 14:21:34 +01:00
|
|
|
Session_component(_env, *ep(), _device_pd_ep, args);
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
|
|
|
catch (Genode::Session_policy::No_policy_defined) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::error("Invalid session request, no matching policy for ",
|
|
|
|
"'", Genode::label_from_args(args).string(), "'");
|
2015-11-05 09:06:29 +01:00
|
|
|
throw Genode::Root::Unavailable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void _upgrade_session(Session_component *s, const char *args) override
|
|
|
|
{
|
|
|
|
long ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").long_value(0);
|
|
|
|
s->upgrade_ram_quota(ram_quota);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param ep entry point to be used for serving the PCI session
|
|
|
|
* and PCI device interface
|
|
|
|
* \param md_alloc meta-data allocator for allocating PCI-session
|
|
|
|
* components and PCI-device components
|
|
|
|
*/
|
2016-11-23 14:21:34 +01:00
|
|
|
Root(Genode::Env &env, Genode::Allocator &md_alloc,
|
2016-05-13 16:38:26 +02:00
|
|
|
const char *acpi_rom)
|
2015-11-05 09:06:29 +01:00
|
|
|
:
|
2016-05-13 16:38:26 +02:00
|
|
|
Genode::Root_component<Session_component>(&env.ep().rpc_ep(),
|
2016-11-23 14:21:34 +01:00
|
|
|
&md_alloc),
|
|
|
|
_env(env),
|
2016-05-13 16:38:26 +02:00
|
|
|
_device_pd_ep(&env.pd(), STACK_SIZE, "device_pd_slave")
|
2015-11-05 09:06:29 +01:00
|
|
|
{
|
|
|
|
/* enforce initial bus scan */
|
|
|
|
bus_valid();
|
|
|
|
|
|
|
|
if (acpi_rom) {
|
|
|
|
try {
|
2015-05-26 20:12:17 +02:00
|
|
|
_parse_report_rom(acpi_rom);
|
2015-11-05 09:06:29 +01:00
|
|
|
} catch (...) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::error("PCI config space data could not be parsed.");
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
2016-05-13 16:09:20 +02:00
|
|
|
|
|
|
|
void system_reset()
|
|
|
|
{
|
|
|
|
const bool io_port_space = (Fadt::Gas::Address_space::get(fadt.reset_type) == Fadt::Gas::Address_space::SYSTEM_IO);
|
|
|
|
|
|
|
|
if (!io_port_space)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Config_access config_access;
|
|
|
|
const unsigned raw_access_size = Fadt::Gas::Access_size::get(fadt.reset_type);
|
|
|
|
const bool reset_support = config_access.reset_support(fadt.reset_addr, raw_access_size);
|
|
|
|
if (!reset_support)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const bool feature_reset = Fadt::Features::Reset::get(fadt.features);
|
|
|
|
|
|
|
|
if (!feature_reset) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::warning("system reset failed - feature not supported");
|
2016-05-13 16:09:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Device::Access_size access_size = Device::ACCESS_8BIT;
|
|
|
|
|
|
|
|
unsigned raw_size = Fadt::Gas::Access_size::get(fadt.reset_type);
|
|
|
|
switch (raw_size) {
|
|
|
|
case Fadt::Gas::Access_size::WORD:
|
|
|
|
access_size = Device::ACCESS_16BIT;
|
|
|
|
break;
|
|
|
|
case Fadt::Gas::Access_size::DWORD:
|
|
|
|
access_size = Device::ACCESS_32BIT;
|
|
|
|
break;
|
|
|
|
case Fadt::Gas::Access_size::QWORD:
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::error("system reset failed - unsupported access size");
|
2016-05-13 16:09:20 +02:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
config_access.system_reset(fadt.reset_addr, fadt.reset_value,
|
|
|
|
access_size);
|
|
|
|
/* if we are getting here - the reset failed */
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::warning("system reset failed");
|
2016-05-13 16:09:20 +02:00
|
|
|
}
|
2015-11-05 09:06:29 +01:00
|
|
|
};
|