mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
parent
8743575dcf
commit
7770a0fbbe
@ -178,7 +178,7 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
|
||||
void _acpi_session()
|
||||
{
|
||||
Pci::Session_capability session;
|
||||
const char *args = "ram_quota=4K";
|
||||
const char *args = "label=\"acpi_drv\", ram_quota=4K";
|
||||
|
||||
try {
|
||||
using namespace Genode;
|
||||
|
@ -31,7 +31,7 @@ class Nonpci::Ps2 : public Pci::Device_component
|
||||
|
||||
Ps2(Genode::Rpc_entrypoint * ep, Pci::Session_component * session)
|
||||
:
|
||||
Pci::Device_component(ep, IRQ_KEYBOARD),
|
||||
Pci::Device_component(ep, session, IRQ_KEYBOARD),
|
||||
_irq_mouse(IRQ_MOUSE)
|
||||
{ }
|
||||
|
||||
@ -72,6 +72,12 @@ Pci::Device_capability Pci::Session_component::device(String const &name) {
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
if (!permit_device(devices[devices_i])) {
|
||||
PERR("Denied access to device '%s' for session '%s'", device_name,
|
||||
_label.string());
|
||||
return Device_capability();
|
||||
}
|
||||
|
||||
try {
|
||||
Device_component * dev = nullptr;
|
||||
|
||||
|
@ -19,13 +19,13 @@
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
#include <io_mem_session/io_mem_session.h>
|
||||
#include <io_mem_session/connection.h>
|
||||
|
||||
#include "pci_device_config.h"
|
||||
|
||||
#include "irq.h"
|
||||
|
||||
namespace Pci { class Device_component; }
|
||||
namespace Pci { class Device_component; class Session_component; }
|
||||
|
||||
class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
public Genode::List<Device_component>::Element
|
||||
@ -37,6 +37,7 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
Genode::Io_mem_connection *_io_mem;
|
||||
Config_access _config_access;
|
||||
Genode::Rpc_entrypoint *_ep;
|
||||
Pci::Session_component *_session;
|
||||
Irq_session_component _irq_session;
|
||||
|
||||
enum { PCI_IRQ = 0x3c };
|
||||
@ -47,10 +48,11 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
* Constructor
|
||||
*/
|
||||
Device_component(Device_config device_config, Genode::addr_t addr,
|
||||
Genode::Rpc_entrypoint *ep)
|
||||
Genode::Rpc_entrypoint *ep,
|
||||
Pci::Session_component * session)
|
||||
:
|
||||
_device_config(device_config), _config_space(addr),
|
||||
_io_mem(0), _ep(ep),
|
||||
_io_mem(0), _ep(ep), _session(session),
|
||||
_irq_session(_device_config.read(&_config_access, PCI_IRQ,
|
||||
Pci::Device::ACCESS_8BIT))
|
||||
{
|
||||
@ -60,9 +62,11 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||
/**
|
||||
* Constructor for non PCI devices
|
||||
*/
|
||||
Device_component(Genode::Rpc_entrypoint *ep, unsigned irq)
|
||||
Device_component(Genode::Rpc_entrypoint * ep,
|
||||
Pci::Session_component * session, unsigned irq)
|
||||
:
|
||||
_config_space(~0UL), _io_mem(0), _ep(ep), _irq_session(irq)
|
||||
_config_space(~0UL), _io_mem(0), _ep(ep), _session(session),
|
||||
_irq_session(irq)
|
||||
{
|
||||
_ep->manage(&_irq_session);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
/* os */
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <pci_session/pci_session.h>
|
||||
|
||||
/* local */
|
||||
@ -44,6 +45,8 @@ namespace Pci {
|
||||
Genode::List<Device_component> _device_list;
|
||||
Device_pd_client *_child;
|
||||
Genode::Ram_connection *_ram;
|
||||
Genode::Session_label _label;
|
||||
Genode::Session_policy _policy;
|
||||
|
||||
/**
|
||||
* Scan PCI buses for a device
|
||||
@ -115,6 +118,173 @@ namespace Pci {
|
||||
return config_space;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
static struct {
|
||||
const char * alias;
|
||||
uint8_t pci_class, pci_subclass, pci_progif;
|
||||
} const aliases [] = {
|
||||
{ "AHCI" , 0x1, 0x06, 0x0},
|
||||
{ "ALL" , 0x0, 0x00, 0x0},
|
||||
{ "ETHERNET", 0x2, 0x00, 0x0},
|
||||
{ "USB" , 0xc, 0x03, 0x0},
|
||||
{ "VGA" , 0x3, 0x00, 0x0},
|
||||
{ "WIFI" , 0x2, 0x80, 0x0}
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < sizeof(aliases) / sizeof(aliases[0]); i++) {
|
||||
if (strcmp(aliases[i].alias, name))
|
||||
continue;
|
||||
|
||||
return 0U | aliases[i].pci_class << 16 |
|
||||
aliases[i].pci_subclass << 8 |
|
||||
aliases[i].pci_progif;
|
||||
}
|
||||
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check device usage according to session policy
|
||||
*/
|
||||
bool permit_device(const char * name)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
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));
|
||||
|
||||
if (!strcmp(policy_name, name))
|
||||
/* found identical match - permit access */
|
||||
throw true;
|
||||
|
||||
} catch (Xml_attribute::Nonexistent_attribute) { }
|
||||
});
|
||||
} catch (bool result) { return result; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
try {
|
||||
_policy.for_each_sub_node("pci", [&] (Xml_node node) {
|
||||
try {
|
||||
unsigned bus, device, function;
|
||||
|
||||
node.attribute("bus").value(&bus);
|
||||
node.attribute("device").value(&device);
|
||||
node.attribute("function").value(&function);
|
||||
|
||||
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;
|
||||
|
||||
try {
|
||||
char alias_class[32];
|
||||
node.attribute("class").value(alias_class,
|
||||
sizeof(alias_class));
|
||||
|
||||
class_sub_prog = class_subclass_prog(alias_class);
|
||||
} catch (Xml_attribute::Nonexistent_attribute) {
|
||||
return;
|
||||
}
|
||||
/* if this does not identical matches - deny access */
|
||||
if ((class_sub_prog & class_code) != class_sub_prog)
|
||||
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;
|
||||
|
||||
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) {
|
||||
try {
|
||||
unsigned bus, device, function;
|
||||
|
||||
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:
|
||||
|
||||
/**
|
||||
@ -123,9 +293,105 @@ namespace Pci {
|
||||
Session_component(Genode::Rpc_entrypoint *ep,
|
||||
Genode::Allocator *md_alloc,
|
||||
Device_pd_client *child,
|
||||
Genode::Ram_connection *ram)
|
||||
Genode::Ram_connection *ram,
|
||||
const char *args)
|
||||
:
|
||||
_ep(ep), _md_alloc(md_alloc), _child(child), _ram(ram) { }
|
||||
_ep(ep), _md_alloc(md_alloc),
|
||||
_child(child), _ram(ram), _label(args), _policy(_label)
|
||||
{
|
||||
/* 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))
|
||||
return;
|
||||
|
||||
PERR("'%s' - device '%s' is part of more than one policy",
|
||||
_label.string(), policy_device);
|
||||
} catch (Genode::Xml_node::Nonexistent_attribute) {
|
||||
PERR("'%s' - device node misses a 'name' attribute",
|
||||
_label.string());
|
||||
}
|
||||
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) {
|
||||
PERR("'%s' - invalid 'class' attribute '%s'",
|
||||
_label.string(), alias_class);
|
||||
throw Genode::Root::Unavailable();
|
||||
}
|
||||
} catch (Xml_attribute::Nonexistent_attribute) { }
|
||||
|
||||
/* if we read a class attribute all is fine */
|
||||
if (class_sub_prog < INVALID_CLASS) {
|
||||
/* sanity check that 'class' is the only attribute */
|
||||
try {
|
||||
node.attribute(1);
|
||||
PERR("'%s' - attributes beside 'class' detected",
|
||||
_label.string());
|
||||
throw Genode::Root::Unavailable();
|
||||
} catch (Xml_attribute::Nonexistent_attribute) { }
|
||||
|
||||
/* we have a class and it is the only attribute */
|
||||
return;
|
||||
}
|
||||
|
||||
/* no 'class' attribute - now check for valid bdf triple */
|
||||
try {
|
||||
node.attribute(3);
|
||||
PERR("'%s' - invalid number of pci node attributes",
|
||||
_label.string());
|
||||
throw Genode::Root::Unavailable();
|
||||
} catch (Xml_attribute::Nonexistent_attribute) { }
|
||||
|
||||
try {
|
||||
unsigned bus, device, function;
|
||||
|
||||
node.attribute("bus").value(&bus);
|
||||
node.attribute("device").value(&device);
|
||||
node.attribute("function").value(&function);
|
||||
|
||||
if ((bus >= Device_config::MAX_BUSES) ||
|
||||
(device >= Device_config::MAX_DEVICES) ||
|
||||
(function >= Device_config::MAX_FUNCTIONS))
|
||||
throw Xml_attribute::Nonexistent_attribute();
|
||||
|
||||
enum { DOUBLET = false };
|
||||
if (!find_dev_in_policy(bus, device, function, DOUBLET))
|
||||
return;
|
||||
|
||||
PERR("'%s' - device '%2x:%2x.%x' is part of more than "
|
||||
"one policy", _label.string(), bus, device,
|
||||
function);
|
||||
} catch (Xml_attribute::Nonexistent_attribute) {
|
||||
PERR("'%s' - invalid pci node attributes for bdf",
|
||||
_label.string());
|
||||
}
|
||||
throw Genode::Root::Unavailable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
@ -191,8 +457,7 @@ namespace Pci {
|
||||
*/
|
||||
Device_config config;
|
||||
|
||||
do
|
||||
{
|
||||
while (true) {
|
||||
function += 1;
|
||||
if (!_find_next(bus, device, function, &config, &config_access))
|
||||
return Device_capability();
|
||||
@ -201,7 +466,16 @@ namespace Pci {
|
||||
bus = config.bus_number();
|
||||
device = config.device_number();
|
||||
function = config.function_number();
|
||||
} while ((config.class_code() ^ device_class) & class_mask);
|
||||
|
||||
/* if filter of driver don't match skip and continue */
|
||||
if ((config.class_code() ^ device_class) & class_mask)
|
||||
continue;
|
||||
|
||||
/* check that policy permit access to the matched device */
|
||||
if (permit_device(bus, device, function,
|
||||
config.class_code()))
|
||||
break;
|
||||
}
|
||||
|
||||
/* lookup if we have a extended pci config space */
|
||||
Genode::addr_t config_space = lookup_config_space(bus, device,
|
||||
@ -214,7 +488,7 @@ namespace Pci {
|
||||
* FIXME: check and adjust session quota
|
||||
*/
|
||||
Device_component *device_component =
|
||||
new (_md_alloc) Device_component(config, config_space, _ep);
|
||||
new (_md_alloc) Device_component(config, config_space, _ep, this);
|
||||
|
||||
if (!device_component)
|
||||
return Device_capability();
|
||||
@ -323,6 +597,10 @@ namespace Pci {
|
||||
for (i = 0; i < config()->xml_node().num_sub_nodes(); i++)
|
||||
{
|
||||
Xml_node node = config()->xml_node().sub_node(i);
|
||||
|
||||
if (!node.has_type("bdf"))
|
||||
continue;
|
||||
|
||||
uint32_t bdf_start = 0;
|
||||
uint32_t func_count = 0;
|
||||
addr_t base = 0;
|
||||
@ -348,9 +626,15 @@ namespace Pci {
|
||||
/* FIXME: extract quota from args */
|
||||
/* FIXME: pass quota to session-component constructor */
|
||||
|
||||
return new (md_alloc()) Session_component(ep(), md_alloc(),
|
||||
_pd_device_client,
|
||||
&_ram);
|
||||
try {
|
||||
return new (md_alloc()) Session_component(ep(), md_alloc(),
|
||||
_pd_device_client,
|
||||
&_ram, args);
|
||||
} catch (Genode::Session_policy::No_policy_defined) {
|
||||
PERR("Invalid session request, no matching policy for '%s'",
|
||||
Genode::Session_label(args).string());
|
||||
throw Genode::Root::Unavailable();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user