2011-12-22 16:19:25 +01:00
|
|
|
/*
|
2017-10-19 10:13:35 +02:00
|
|
|
* \brief Platform session component
|
2011-12-22 16:19:25 +01:00
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2008-01-28
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 13:23:52 +01:00
|
|
|
* Copyright (C) 2008-2017 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 16:19:25 +01:00
|
|
|
*/
|
|
|
|
|
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>
|
2017-08-01 19:05:56 +02:00
|
|
|
#include <base/attached_rom_dataspace.h>
|
|
|
|
#include <base/heap.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>
|
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>
|
2017-06-13 13:07:58 +02:00
|
|
|
#include <os/reporter.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>
|
2017-11-13 02:40:13 +01:00
|
|
|
#include <base/allocator_guard.h>
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2015-04-17 14:12:30 +02:00
|
|
|
/* local */
|
2015-11-05 22:15:50 +01:00
|
|
|
#include "device_pd.h"
|
2018-05-03 13:51:13 +02:00
|
|
|
#include "pci_bridge.h"
|
|
|
|
#include "pci_config_access.h"
|
|
|
|
#include "pci_device_component.h"
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
typedef Genode::Ram_dataspace_capability Ram_capability;
|
|
|
|
|
2015-06-08 09:05:32 +02:00
|
|
|
namespace Platform {
|
2015-05-26 20:12:17 +02:00
|
|
|
unsigned short bridge_bdf(unsigned char bus);
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
class Pci_buses;
|
|
|
|
class Ram_dataspace;
|
2015-11-05 09:06:29 +01:00
|
|
|
class Rmrr;
|
|
|
|
class Root;
|
2017-01-02 14:23:03 +01:00
|
|
|
class Session_component;
|
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:
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
Ram_capability const _cap;
|
2016-06-01 11:08:22 +02:00
|
|
|
|
|
|
|
public:
|
2017-11-03 23:51:36 +01:00
|
|
|
Ram_dataspace(Ram_capability c) : _cap(c) { }
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
bool match(const Ram_capability &cap) const {
|
2016-06-01 11:08:22 +02:00
|
|
|
return cap.local_name() == _cap.local_name(); }
|
2017-11-03 23:51:36 +01:00
|
|
|
|
|
|
|
Ram_capability cap() const { return _cap; }
|
2016-06-01 11:08:22 +02:00
|
|
|
};
|
|
|
|
|
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:
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +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
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +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
|
|
|
{ }
|
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
Genode::Io_mem_dataspace_capability match(Genode::Env &env,
|
|
|
|
Device_config config)
|
2016-11-06 14:19:47 +01:00
|
|
|
{
|
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
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
_io_mem.construct(env, _start, _end - _start + 1);
|
2016-11-06 14:19:47 +01:00
|
|
|
_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
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
class Platform::Pci_buses
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Genode::Bit_array<Device_config::MAX_BUSES> _valid { };
|
2017-01-02 14:23:03 +01:00
|
|
|
|
|
|
|
void scan_bus(Config_access &config_access, Genode::Allocator &heap,
|
|
|
|
unsigned char bus = 0);
|
|
|
|
|
|
|
|
bool _bus_valid(int bus)
|
|
|
|
{
|
|
|
|
if (bus >= Device_config::MAX_BUSES)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return _valid.get(bus, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
Pci_buses(Genode::Allocator &heap, Genode::Attached_io_mem_dataspace &pciconf)
|
2017-01-02 14:23:03 +01:00
|
|
|
{
|
2017-10-19 10:13:35 +02:00
|
|
|
Config_access c(pciconf);
|
2017-01-02 14:23:03 +01:00
|
|
|
scan_bus(c, heap);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
for (; device < Device_config::MAX_DEVICES; device++) {
|
|
|
|
for (; function < Device_config::MAX_FUNCTIONS; function++) {
|
|
|
|
|
|
|
|
/* read config space */
|
|
|
|
Device_config config(bus, device, function, config_access);
|
|
|
|
|
|
|
|
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-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
|
|
|
|
2017-11-13 02:40:13 +01:00
|
|
|
Genode::Env &_env;
|
|
|
|
Genode::Attached_rom_dataspace &_config;
|
2017-10-19 10:13:35 +02:00
|
|
|
Genode::Attached_io_mem_dataspace &_pciconf;
|
2017-11-13 02:40:13 +01:00
|
|
|
Genode::Ram_quota_guard _ram_guard;
|
|
|
|
Genode::Cap_quota_guard _cap_guard;
|
|
|
|
Genode::Constrained_ram_allocator _env_ram {
|
|
|
|
_env.pd(), _ram_guard, _cap_guard };
|
|
|
|
Genode::Heap _md_alloc;
|
|
|
|
Genode::Session_label const _label;
|
|
|
|
Genode::Session_policy const _policy { _label, _config.xml() };
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Genode::List<Device_component> _device_list { };
|
2017-11-13 02:40:13 +01:00
|
|
|
Platform::Pci_buses &_pci_bus;
|
|
|
|
Genode::Heap &_global_heap;
|
2018-05-08 16:00:11 +02:00
|
|
|
bool _iommu;
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Registry of RAM dataspaces allocated by the session
|
|
|
|
*/
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Genode::List<Platform::Ram_dataspace> _ram_caps { };
|
2016-06-01 11:08:22 +02:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
void _insert(Ram_capability cap) {
|
2016-11-23 14:21:34 +01:00
|
|
|
_ram_caps.insert(new (_md_alloc) Platform::Ram_dataspace(cap)); }
|
2015-11-05 22:15:50 +01:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
bool _remove(Ram_capability cap)
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2017-11-13 02:40:13 +01:00
|
|
|
Platform::Device_pd _device_pd { _env, _label, _ram_guard, _cap_guard };
|
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
|
|
|
/**
|
|
|
|
* List containing extended PCI config space information
|
|
|
|
*/
|
2017-08-01 19:05:56 +02:00
|
|
|
static Genode::List<Config_space> &config_space_list()
|
|
|
|
{
|
2016-11-06 14:27:26 +01:00
|
|
|
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.
|
|
|
|
*/
|
2017-08-01 19:05:56 +02:00
|
|
|
Genode::addr_t lookup_config_space(Genode::uint16_t const bdf)
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
typedef Genode::String<32> Alias_name;
|
|
|
|
|
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
|
|
|
|
*/
|
2019-01-21 10:48:39 +01:00
|
|
|
unsigned class_subclass_prog(Alias_name const &name)
|
2017-08-01 19:05:56 +02:00
|
|
|
{
|
2016-11-06 14:27:26 +01:00
|
|
|
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},
|
2018-03-05 23:23:05 +01:00
|
|
|
{ "NVME" , 0x1, 0x08, 0x2},
|
2016-11-06 14:27:26 +01:00
|
|
|
{ "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++) {
|
2019-01-21 10:48:39 +01:00
|
|
|
if (name != aliases[i].alias)
|
2016-11-06 14:27:26 +01:00
|
|
|
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) {
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
/* enforce restriction based on name name */
|
|
|
|
if (dev.attribute_value("name", Genode::String<10>()) == name)
|
|
|
|
/* found identical match - permit access */
|
|
|
|
throw true;
|
2016-11-06 14:27:26 +01:00
|
|
|
});
|
|
|
|
} 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
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
static bool _bdf_exactly_specified(Xml_node node)
|
|
|
|
{
|
|
|
|
return node.has_attribute("bus")
|
|
|
|
&& node.has_attribute("device")
|
|
|
|
&& node.has_attribute("function");
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Bdf
|
|
|
|
{
|
|
|
|
unsigned b, d, f;
|
|
|
|
|
|
|
|
bool equals(Bdf const &other) const
|
|
|
|
{
|
|
|
|
return other.b == b && other.d == d && other.f == f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void print(Genode::Output &out) const
|
|
|
|
{
|
|
|
|
Genode::print(out, Genode::Hex(b), ":", Genode::Hex(d), ".", f);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Bdf _bdf_from_xml(Xml_node node)
|
|
|
|
{
|
|
|
|
return Bdf { .b = node.attribute_value("bus", 0U),
|
|
|
|
.d = node.attribute_value("device", 0U),
|
|
|
|
.f = node.attribute_value("function", 0U) };
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool _bdf_attributes_in_valid_range(Xml_node node)
|
|
|
|
{
|
|
|
|
return _bdf_exactly_specified(node)
|
|
|
|
&& (node.attribute_value("bus", 0U) < Device_config::MAX_BUSES)
|
|
|
|
&& (node.attribute_value("device", 0U) < Device_config::MAX_DEVICES)
|
|
|
|
&& (node.attribute_value("function", 0U) < Device_config::MAX_FUNCTIONS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool _bdf_matches(Xml_node node, Bdf bdf)
|
|
|
|
{
|
|
|
|
return _bdf_from_xml(node).equals(bdf);
|
|
|
|
}
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/**
|
|
|
|
* Check according session policy device usage
|
|
|
|
*/
|
2019-01-21 10:48:39 +01:00
|
|
|
bool permit_device(Bdf const bdf, unsigned class_code)
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
if (_bdf_exactly_specified(node)) {
|
|
|
|
if (_bdf_matches(node, bdf))
|
2016-11-06 14:27:26 +01:00
|
|
|
throw true;
|
2019-01-21 10:48:39 +01:00
|
|
|
/* check also for class entry */
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
if (!node.has_attribute("class"))
|
2016-11-06 14:27:26 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* enforce restriction based upon classes */
|
2019-01-21 10:48:39 +01:00
|
|
|
auto alias = node.attribute_value("class", Alias_name());
|
|
|
|
unsigned const class_sub_prog = class_subclass_prog(alias);
|
2016-11-06 14:27:26 +01:00
|
|
|
|
|
|
|
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 */
|
2019-01-21 10:48:39 +01:00
|
|
|
if (find_dev_in_policy(bdf))
|
2016-11-06 14:27:26 +01:00
|
|
|
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 {
|
2017-01-03 11:24:16 +01:00
|
|
|
_config.xml().for_each_sub_node("policy", [&] (Xml_node policy) {
|
2016-11-06 14:27:26 +01:00
|
|
|
policy.for_each_sub_node("device", [&] (Xml_node device) {
|
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
typedef Genode::String<10> Name;
|
|
|
|
if (device.attribute_value("name", Name()) == dev_name) {
|
|
|
|
|
|
|
|
if (once)
|
|
|
|
throw true;
|
|
|
|
once = true;
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch (bool result) { return result; }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lookup a given device name.
|
|
|
|
*/
|
2019-01-21 10:48:39 +01:00
|
|
|
bool find_dev_in_policy(Bdf const bdf, bool once = true)
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
2017-01-03 11:24:16 +01:00
|
|
|
Xml_node xml = _config.xml();
|
2016-11-06 14:27:26 +01:00
|
|
|
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
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
if (_bdf_exactly_specified(node)) {
|
|
|
|
|
|
|
|
if (_bdf_matches(node, bdf)) {
|
2016-11-06 14:27:26 +01:00
|
|
|
|
|
|
|
if (once)
|
|
|
|
throw true;
|
|
|
|
once = true;
|
|
|
|
}
|
2019-01-21 10:48:39 +01:00
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch (bool result) { return result; }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2017-10-19 10:13:35 +02:00
|
|
|
Session_component(Genode::Env &env,
|
|
|
|
Genode::Attached_rom_dataspace &config,
|
|
|
|
Genode::Attached_io_mem_dataspace &pciconf,
|
|
|
|
Platform::Pci_buses &buses,
|
|
|
|
Genode::Heap &global_heap,
|
2018-05-08 16:00:11 +02:00
|
|
|
char const *args,
|
|
|
|
bool const iommu)
|
2016-11-06 14:27:26 +01:00
|
|
|
:
|
2017-08-01 19:05:56 +02:00
|
|
|
_env(env),
|
2017-01-03 11:24:16 +01:00
|
|
|
_config(config),
|
2017-10-19 10:13:35 +02:00
|
|
|
_pciconf(pciconf),
|
2017-11-13 02:40:13 +01:00
|
|
|
_ram_guard(Genode::ram_quota_from_args(args)),
|
|
|
|
_cap_guard(Genode::cap_quota_from_args(args)),
|
2016-11-23 14:21:34 +01:00
|
|
|
_md_alloc(_env_ram, env.rm()),
|
2017-01-02 14:23:03 +01:00
|
|
|
_label(Genode::label_from_args(args)),
|
2018-05-08 16:00:11 +02:00
|
|
|
_pci_bus(buses), _global_heap(global_heap), _iommu(iommu)
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
2017-11-13 02:40:13 +01:00
|
|
|
/* subtract the RPC session and session dataspace capabilities */
|
|
|
|
_cap_guard.withdraw(Genode::Cap_quota{2});
|
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
/* check policy for non-pci devices */
|
2016-11-06 14:27:26 +01:00
|
|
|
_policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) {
|
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
if (!device_node.has_attribute("name")) {
|
|
|
|
Genode::error("'", _label, "' - device node "
|
|
|
|
"misses 'name' attribute");
|
|
|
|
throw Genode::Service_denied();
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
typedef Genode::String<16> Name;
|
|
|
|
Name const name = device_node.attribute_value("name", Name());
|
|
|
|
|
|
|
|
enum { DOUBLET = false };
|
|
|
|
if (find_dev_in_policy(name.string(), DOUBLET)) {
|
|
|
|
Genode::error("'", _label, "' - device '", name, "' "
|
2017-04-20 20:06:08 +02:00
|
|
|
"is part of more than one policy");
|
2019-01-21 10:48:39 +01:00
|
|
|
throw Genode::Service_denied();
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
/* pci devices */
|
|
|
|
_policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) {
|
2019-01-21 10:48:39 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
enum { INVALID_CLASS = 0x1000000U };
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2019-01-21 10:48:39 +01:00
|
|
|
if (node.has_attribute("class")) {
|
2016-11-06 14:27:26 +01:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
Alias_name const alias = node.attribute_value("class", Alias_name());
|
|
|
|
|
|
|
|
if (class_subclass_prog(alias) >= INVALID_CLASS) {
|
2016-11-06 14:27:26 +01:00
|
|
|
Genode::error("'", _label, "' - invalid 'class' ",
|
2019-01-21 10:48:39 +01:00
|
|
|
"attribute '", alias, "'");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Service_denied();
|
2015-04-22 17:06:10 +02:00
|
|
|
}
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* 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");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Service_denied();
|
|
|
|
}
|
|
|
|
catch (Xml_attribute::Nonexistent_attribute) { }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
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");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Service_denied();
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
} catch (Xml_attribute::Nonexistent_attribute) { }
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
if (_bdf_exactly_specified(node)) {
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
if (!_bdf_attributes_in_valid_range(node)) {
|
|
|
|
Genode::error("'", _label, "' - "
|
|
|
|
"invalid pci node attributes for bdf");
|
|
|
|
throw Genode::Service_denied();
|
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
Bdf const bdf = _bdf_from_xml(node);
|
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 };
|
2019-01-21 10:48:39 +01:00
|
|
|
if (find_dev_in_policy(bdf, DOUBLET)) {
|
|
|
|
Genode::error("'", _label, "' - device '", bdf, "' "
|
|
|
|
"is part of more than one policy");
|
|
|
|
throw Genode::Service_denied();
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
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());
|
2017-05-03 10:51:46 +02:00
|
|
|
|
|
|
|
while (Platform::Ram_dataspace *ds = _ram_caps.first()) {
|
|
|
|
_ram_caps.remove(ds);
|
2017-11-03 23:51:36 +01:00
|
|
|
_env_ram.free(ds->cap());
|
2017-05-03 10:51:46 +02:00
|
|
|
destroy(_md_alloc, ds);
|
|
|
|
}
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
2015-04-16 15:54:07 +02:00
|
|
|
|
|
|
|
|
2017-11-13 02:40:13 +01:00
|
|
|
void upgrade_resources(Genode::Session::Resources resources)
|
|
|
|
{
|
|
|
|
_ram_guard.upgrade(resources.ram_quota);
|
|
|
|
_cap_guard.upgrade(resources.cap_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,
|
2017-01-02 14:23:03 +01:00
|
|
|
Genode::addr_t base,
|
|
|
|
Genode::Allocator &heap)
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
|
|
|
Config_space * space =
|
2017-01-02 14:23:03 +01:00
|
|
|
new (heap) Config_space(bdf_start, func_count, base);
|
2016-11-06 14:27:26 +01:00
|
|
|
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()
|
|
|
|
{
|
2019-01-21 10:48:39 +01:00
|
|
|
typedef Genode::String<10> Mode;
|
|
|
|
return _policy.attribute_value("irq_mode", Mode()) != "nomsi";
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
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.
|
|
|
|
*/
|
2017-10-19 10:13:35 +02:00
|
|
|
Config_access config_access(_pciconf);
|
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;
|
2017-01-02 14:23:03 +01:00
|
|
|
if (!_pci_bus.find_next(bus, device, function, &config,
|
|
|
|
&config_access))
|
2016-11-06 14:27:26 +01:00
|
|
|
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 */
|
2019-01-21 10:48:39 +01:00
|
|
|
if (permit_device(Bdf { (unsigned)bus,
|
|
|
|
(unsigned)device,
|
|
|
|
(unsigned)function },
|
|
|
|
config.class_code()))
|
2016-11-06 14:27:26 +01:00
|
|
|
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)
|
2017-10-19 10:13:35 +02:00
|
|
|
Device_component(_env, config, config_space, config_access, *this,
|
2017-01-02 14:23:03 +01:00
|
|
|
_md_alloc, _global_heap);
|
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))
|
2017-09-15 12:59:57 +02:00
|
|
|
Genode::error("Device ", config,
|
|
|
|
" is used by more than one driver - "
|
2016-11-06 14:27:26 +01:00
|
|
|
"session '", _label, "'.");
|
|
|
|
else
|
|
|
|
bdf_in_use.set(Device_config::MAX_BUSES * bus +
|
|
|
|
Device_config::MAX_DEVICES * device +
|
|
|
|
function, 1);
|
|
|
|
|
|
|
|
_device_list.insert(dev);
|
2017-01-02 14:23:03 +01:00
|
|
|
return _env.ep().rpc_ep().manage(dev);
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
}
|
|
|
|
catch (Genode::Out_of_ram) {
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
catch (Genode::Out_of_caps) {
|
|
|
|
Genode::warning("Out_of_caps during Device_component construction");
|
|
|
|
throw;
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
|
|
|
};
|
2017-01-02 14:23:03 +01:00
|
|
|
return _env.ep().rpc_ep().apply(prev_device, lambda);
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
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);
|
2017-01-02 14:23:03 +01:00
|
|
|
_env.ep().rpc_ep().dissolve(device);
|
2016-11-06 14:27:26 +01:00
|
|
|
};
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
/* lookup device component for previous device */
|
2017-01-02 14:23:03 +01:00
|
|
|
_env.ep().rpc_ep().apply(device_cap, lambda);
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
if (device && device->config().valid())
|
2016-11-06 14:27:26 +01:00
|
|
|
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
|
|
|
|
2018-05-08 16:00:11 +02:00
|
|
|
if (!device || device->config_space() == ~0UL || !_iommu)
|
2016-11-06 14:27:26 +01:00
|
|
|
return;
|
2013-02-18 10:08:14 +01:00
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
try {
|
2017-10-19 10:13:35 +02:00
|
|
|
addr_t const function = device->config().bus_number() * 32 * 8 +
|
|
|
|
device->config().device_number() * 8 +
|
|
|
|
device->config().function_number();
|
|
|
|
addr_t const base_ecam = Dataspace_client(_pciconf.cap()).phys_addr();
|
|
|
|
addr_t const base_offset = 0x1000UL * function;
|
|
|
|
|
|
|
|
if (base_ecam + base_offset != device->config_space())
|
|
|
|
throw 1;
|
|
|
|
|
2016-11-06 14:27:26 +01:00
|
|
|
for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
|
2017-01-02 14:23:03 +01:00
|
|
|
Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config());
|
2016-11-06 14:27:26 +01:00
|
|
|
if (rmrr_cap.valid())
|
2017-08-01 19:05:56 +02:00
|
|
|
_device_pd.attach_dma_mem(rmrr_cap);
|
2015-11-16 14:04:04 +01:00
|
|
|
}
|
2018-06-28 13:47:30 +02:00
|
|
|
|
|
|
|
_device_pd.assign_pci(_pciconf.cap(), base_offset, device->config().bdf());
|
|
|
|
|
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
|
|
|
|
*/
|
2015-02-08 13:02:11 +01:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
Ram_capability alloc_dma_buffer(Genode::size_t const size) override
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
2017-11-03 23:51:36 +01:00
|
|
|
Ram_capability ram_cap = _env_ram.alloc(size, Genode::UNCACHED);
|
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
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
try {
|
|
|
|
_device_pd.attach_dma_mem(ram_cap);
|
|
|
|
_insert(ram_cap);
|
|
|
|
} catch (Out_of_ram) {
|
|
|
|
_env_ram.free(ram_cap);
|
|
|
|
throw Genode::Out_of_ram();
|
|
|
|
} catch (Out_of_caps) {
|
|
|
|
_env_ram.free(ram_cap);
|
|
|
|
throw Genode::Out_of_caps();
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
}
|
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
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
void free_dma_buffer(Ram_capability ram_cap) override
|
2016-11-06 14:27:26 +01:00
|
|
|
{
|
|
|
|
if (!ram_cap.valid() || !_remove(ram_cap))
|
|
|
|
return;
|
2014-01-24 10:11:25 +01:00
|
|
|
|
2017-11-03 23:51:36 +01:00
|
|
|
_env_ram.free(ram_cap);
|
2016-11-06 14:27:26 +01:00
|
|
|
}
|
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
|
|
|
|
2017-01-03 11:24:16 +01:00
|
|
|
Genode::Env &_env;
|
|
|
|
Genode::Attached_rom_dataspace &_config;
|
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
Genode::Constructible<Genode::Attached_io_mem_dataspace> _pci_confspace { };
|
|
|
|
|
2018-06-14 16:35:44 +02:00
|
|
|
Genode::Constructible<Genode::Expanding_reporter> _pci_reporter { };
|
2017-06-13 13:07:58 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
Genode::Heap _heap { _env.ram(), _env.rm() };
|
|
|
|
|
|
|
|
Genode::Constructible<Platform::Pci_buses> _buses { };
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2018-05-08 16:00:11 +02:00
|
|
|
bool _iommu { false };
|
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
void _parse_report_rom(Genode::Env &env, const char * acpi_rom,
|
|
|
|
bool acpi_platform)
|
2015-11-05 09:06:29 +01:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
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
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
xml_acpi.for_each_sub_node("bdf", [&] (Xml_node &node) {
|
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
uint32_t const bdf_start = node.attribute_value("start", 0U);
|
|
|
|
uint32_t const func_count = node.attribute_value("count", 0U);
|
|
|
|
addr_t const base = node.attribute_value("base", 0UL);
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
Session_component::add_config_space(bdf_start, func_count,
|
|
|
|
base, _heap);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
Device_config const bdf_first(bdf_start);
|
|
|
|
Device_config const bdf_last(bdf_start + func_count - 1);
|
|
|
|
addr_t const memory_size = 0x1000UL * func_count;
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
/* Simplification: Only consider first config space and
|
|
|
|
* check if it is for domain 0 */
|
|
|
|
if (bdf_start || _pci_confspace.constructed()) {
|
|
|
|
warning("ECAM/MMCONF range ",
|
|
|
|
bdf_first, "-", bdf_last, " - addr ",
|
|
|
|
Hex_range<addr_t>(base, memory_size), " ignored");
|
|
|
|
return;
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
2015-04-22 17:06:10 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
log("ECAM/MMCONF range ", bdf_first, "-", bdf_last, " - addr ",
|
|
|
|
Hex_range<addr_t>(base, memory_size));
|
|
|
|
|
|
|
|
_pci_confspace.construct(env, base, memory_size);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!_pci_confspace.constructed())
|
|
|
|
throw 2;
|
|
|
|
|
|
|
|
Config_access config_access(*_pci_confspace);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < xml_acpi.num_sub_nodes(); i++) {
|
|
|
|
Xml_node node = xml_acpi.sub_node(i);
|
|
|
|
|
|
|
|
if (node.has_type("bdf"))
|
|
|
|
continue;
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.has_type("irq_override")) {
|
2019-01-21 10:48:39 +01:00
|
|
|
unsigned const irq = node.attribute_value("irq", 0xffU);
|
|
|
|
unsigned const gsi = node.attribute_value("gsi", 0xffU);
|
|
|
|
unsigned const flags = node.attribute_value("flags", 0xffU);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
if (!acpi_platform) {
|
|
|
|
warning("MADT IRQ ", irq, "-> GSI ", gsi, " flags ",
|
|
|
|
flags, " ignored");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
using Platform::Irq_override;
|
2017-01-02 14:23:03 +01:00
|
|
|
Irq_override * o = new (_heap) Irq_override(irq, gsi,
|
|
|
|
flags);
|
2015-11-05 09:06:29 +01:00
|
|
|
Irq_override::list()->insert(o);
|
2017-10-19 10:13:35 +02:00
|
|
|
continue;
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2018-05-08 16:00:11 +02:00
|
|
|
if (node.has_type("drhd")) {
|
|
|
|
_iommu = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.has_type("rmrr")) {
|
2019-01-21 10:48:39 +01:00
|
|
|
uint64_t const
|
|
|
|
mem_start = node.attribute_value("start", (uint64_t)0),
|
|
|
|
mem_end = node.attribute_value("end", (uint64_t)0);
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
if (node.num_sub_nodes() == 0)
|
2017-10-19 10:13:35 +02:00
|
|
|
throw 3;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
Rmrr * rmrr = new (_heap) Rmrr(mem_start, mem_end);
|
2015-10-20 14:47:24 +02:00
|
|
|
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"))
|
2017-10-19 10:13:35 +02:00
|
|
|
throw 4;
|
2013-02-18 10:06:34 +01:00
|
|
|
|
2017-08-01 19:05:56 +02:00
|
|
|
unsigned bus = 0, dev = 0, func = 0;
|
2019-01-21 10:48:39 +01:00
|
|
|
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"))
|
2017-10-19 10:13:35 +02:00
|
|
|
throw 5;
|
2015-06-10 11:28:00 +02:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
path.attribute("dev") .value(dev);
|
|
|
|
path.attribute("func").value(func);
|
2015-11-05 09:06:29 +01:00
|
|
|
|
|
|
|
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 */
|
2017-10-19 10:13:35 +02:00
|
|
|
bus = bridge.read(config_access, 0x19,
|
2015-11-05 09:06:29 +01:00
|
|
|
Device::ACCESS_8BIT);
|
2015-05-26 20:12:17 +02:00
|
|
|
}
|
2015-11-05 09:06:29 +01:00
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
rmrr->add(new (_heap) Rmrr::Bdf(bus, dev, func));
|
2013-02-18 10:06:34 +01:00
|
|
|
}
|
2017-10-19 10:13:35 +02:00
|
|
|
continue;
|
2013-02-18 10:06:34 +01:00
|
|
|
}
|
|
|
|
|
2018-05-03 13:51:13 +02:00
|
|
|
if (node.has_type("root_bridge")) {
|
2019-01-21 10:48:39 +01:00
|
|
|
node.attribute("bdf").value(Platform::Bridge::root_bridge_bdf);
|
2017-10-19 10:13:35 +02:00
|
|
|
continue;
|
2016-05-13 16:09:20 +02:00
|
|
|
}
|
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
if (!node.has_type("routing")) {
|
|
|
|
error ("unsupported node '", node.type(), "'");
|
|
|
|
throw __LINE__;
|
|
|
|
}
|
2011-12-22 16:19:25 +01:00
|
|
|
|
2019-01-21 10:48:39 +01:00
|
|
|
unsigned const gsi = node.attribute_value("gsi", 0U),
|
|
|
|
bridge_bdf = node.attribute_value("bridge_bdf", 0U),
|
|
|
|
device = node.attribute_value("device", 0U),
|
|
|
|
device_pin = node.attribute_value("device_pin", 0U);
|
2015-04-16 15:54:07 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
/* drop routing information on non ACPI platform */
|
2018-05-03 13:51:13 +02:00
|
|
|
if (!acpi_platform)
|
2017-10-19 10:13:35 +02:00
|
|
|
continue;
|
2015-05-26 20:12:17 +02:00
|
|
|
|
2017-01-02 14:23:03 +01:00
|
|
|
Irq_routing * r = new (_heap) Irq_routing(gsi, bridge_bdf,
|
|
|
|
device, device_pin);
|
2015-11-05 09:06:29 +01:00
|
|
|
Irq_routing::list()->insert(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
void _construct_buses()
|
|
|
|
{
|
|
|
|
Genode::Dataspace_client ds_pci_mmio(_pci_confspace->cap());
|
|
|
|
uint64_t const phys_addr = ds_pci_mmio.phys_addr();
|
|
|
|
uint64_t const phys_size = ds_pci_mmio.size();
|
|
|
|
uint64_t mmio_size = 0x10000000UL; /* max MMCONF memory */
|
|
|
|
|
|
|
|
/* try surviving wrong ACPI ECAM/MMCONF table information */
|
|
|
|
while (true) {
|
|
|
|
try {
|
|
|
|
_buses.construct(_heap, *_pci_confspace);
|
|
|
|
/* construction and scan succeeded */
|
|
|
|
break;
|
|
|
|
} catch (Platform::Config_access::Invalid_mmio_access) {
|
|
|
|
|
|
|
|
error("ECAM/MMCONF MMIO access out of bounds - "
|
|
|
|
"ACPI table information is wrong!");
|
|
|
|
|
|
|
|
_pci_confspace.destruct();
|
|
|
|
|
|
|
|
while (mmio_size > phys_size) {
|
|
|
|
try {
|
|
|
|
error(" adjust size from ", Hex(phys_size),
|
|
|
|
"->", Hex(mmio_size));
|
|
|
|
_pci_confspace.construct(_env, phys_addr, mmio_size);
|
|
|
|
/* got memory - try again */
|
|
|
|
break;
|
|
|
|
} catch (Genode::Service_denied) {
|
|
|
|
/* decrease by one bus memory size */
|
|
|
|
mmio_size -= 0x1000UL * 32 * 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mmio_size <= phys_size)
|
|
|
|
/* broken machine - you're lost */
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-05 09:06:29 +01:00
|
|
|
protected:
|
|
|
|
|
|
|
|
Session_component *_create_session(const char *args)
|
|
|
|
{
|
|
|
|
try {
|
2017-05-11 20:03:28 +02:00
|
|
|
return new (md_alloc())
|
2018-05-08 16:00:11 +02:00
|
|
|
Session_component(_env, _config, *_pci_confspace, *_buses,
|
|
|
|
_heap, args, _iommu);
|
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(), "'");
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
throw Genode::Service_denied();
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-13 02:40:13 +01:00
|
|
|
void _upgrade_session(Session_component *s, const char *args) override {
|
|
|
|
s->upgrade_resources(Genode::session_resources_from_args(args)); }
|
2015-11-05 09:06:29 +01:00
|
|
|
|
|
|
|
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,
|
2017-01-03 11:24:16 +01:00
|
|
|
Genode::Attached_rom_dataspace &config,
|
2017-10-19 10:13:35 +02:00
|
|
|
const char *acpi_rom,
|
|
|
|
bool acpi_platform)
|
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),
|
2017-08-01 19:05:56 +02:00
|
|
|
_env(env), _config(config)
|
2015-11-05 09:06:29 +01:00
|
|
|
{
|
2017-10-19 10:13:35 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
_parse_report_rom(env, acpi_rom, acpi_platform);
|
|
|
|
} catch (...) {
|
|
|
|
Genode::error("ACPI report parsing error.");
|
|
|
|
throw;
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2017-06-13 13:07:58 +02:00
|
|
|
|
2018-05-03 13:51:13 +02:00
|
|
|
if (Platform::Bridge::root_bridge_bdf < Platform::Bridge::INVALID_ROOT_BRIDGE) {
|
|
|
|
Device_config config(Platform::Bridge::root_bridge_bdf);
|
|
|
|
Genode::log("Root bridge: ", config);
|
|
|
|
} else
|
|
|
|
Genode::warning("Root bridge: unknown");
|
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
_construct_buses();
|
|
|
|
|
2018-06-14 16:35:44 +02:00
|
|
|
if (config.xml().has_sub_node("report")
|
|
|
|
&& config.xml().sub_node("report").attribute_value("pci", true)) {
|
2017-06-13 13:07:58 +02:00
|
|
|
|
2018-06-14 16:35:44 +02:00
|
|
|
_pci_reporter.construct(_env, "pci", "pci");
|
2017-06-13 13:07:58 +02:00
|
|
|
|
2017-10-19 10:13:35 +02:00
|
|
|
Config_access config_access(*_pci_confspace);
|
2017-06-13 13:07:58 +02:00
|
|
|
Device_config config;
|
|
|
|
int bus = 0, device = 0, function = -1;
|
|
|
|
|
2018-06-14 16:35:44 +02:00
|
|
|
_pci_reporter->generate([&] (Genode::Reporter::Xml_generator &xml) {
|
2017-06-13 13:07:58 +02:00
|
|
|
/* iterate over pci devices */
|
|
|
|
while (true) {
|
|
|
|
function += 1;
|
2017-10-19 10:13:35 +02:00
|
|
|
if (!(*_buses).find_next(bus, device, function, &config,
|
|
|
|
&config_access))
|
2017-06-13 13:07:58 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
bus = config.bus_number();
|
|
|
|
device = config.device_number();
|
|
|
|
function = config.function_number();
|
|
|
|
|
|
|
|
using Genode::String;
|
|
|
|
using Genode::Hex;
|
|
|
|
|
|
|
|
xml.node("device", [&] () {
|
|
|
|
xml.attribute("bdf" , String<8>(Hex(bus, Hex::Prefix::OMIT_PREFIX), ":", Hex(device, Hex::Prefix::OMIT_PREFIX), ".", function));
|
|
|
|
xml.attribute("vendor_id" , String<8>(Hex(config.vendor_id())));
|
|
|
|
xml.attribute("device_id" , String<8>(Hex(config.device_id())));
|
|
|
|
xml.attribute("class_code", String<12>(Hex(config.class_code())));
|
|
|
|
xml.attribute("bridge" , config.pci_bridge() ? "yes" : "no");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2015-11-05 09:06:29 +01:00
|
|
|
}
|
|
|
|
};
|