mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 10:01:57 +00:00
parent
8743575dcf
commit
7770a0fbbe
@ -178,7 +178,7 @@ class Pci_policy : public Genode::Slave_policy, public Pci::Provider
|
|||||||
void _acpi_session()
|
void _acpi_session()
|
||||||
{
|
{
|
||||||
Pci::Session_capability session;
|
Pci::Session_capability session;
|
||||||
const char *args = "ram_quota=4K";
|
const char *args = "label=\"acpi_drv\", ram_quota=4K";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
@ -31,7 +31,7 @@ class Nonpci::Ps2 : public Pci::Device_component
|
|||||||
|
|
||||||
Ps2(Genode::Rpc_entrypoint * ep, Pci::Session_component * session)
|
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)
|
_irq_mouse(IRQ_MOUSE)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -72,6 +72,12 @@ Pci::Device_capability Pci::Session_component::device(String const &name) {
|
|||||||
return Device_capability();
|
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 {
|
try {
|
||||||
Device_component * dev = nullptr;
|
Device_component * dev = nullptr;
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <base/printf.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 "pci_device_config.h"
|
||||||
|
|
||||||
#include "irq.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>,
|
class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
||||||
public Genode::List<Device_component>::Element
|
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;
|
Genode::Io_mem_connection *_io_mem;
|
||||||
Config_access _config_access;
|
Config_access _config_access;
|
||||||
Genode::Rpc_entrypoint *_ep;
|
Genode::Rpc_entrypoint *_ep;
|
||||||
|
Pci::Session_component *_session;
|
||||||
Irq_session_component _irq_session;
|
Irq_session_component _irq_session;
|
||||||
|
|
||||||
enum { PCI_IRQ = 0x3c };
|
enum { PCI_IRQ = 0x3c };
|
||||||
@ -47,10 +48,11 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Device_component(Device_config device_config, Genode::addr_t addr,
|
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),
|
_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,
|
_irq_session(_device_config.read(&_config_access, PCI_IRQ,
|
||||||
Pci::Device::ACCESS_8BIT))
|
Pci::Device::ACCESS_8BIT))
|
||||||
{
|
{
|
||||||
@ -60,9 +62,11 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
|
|||||||
/**
|
/**
|
||||||
* Constructor for non PCI devices
|
* 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);
|
_ep->manage(&_irq_session);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
/* os */
|
/* os */
|
||||||
#include <io_mem_session/connection.h>
|
#include <io_mem_session/connection.h>
|
||||||
#include <os/config.h>
|
#include <os/config.h>
|
||||||
|
#include <os/session_policy.h>
|
||||||
#include <pci_session/pci_session.h>
|
#include <pci_session/pci_session.h>
|
||||||
|
|
||||||
/* local */
|
/* local */
|
||||||
@ -44,6 +45,8 @@ namespace Pci {
|
|||||||
Genode::List<Device_component> _device_list;
|
Genode::List<Device_component> _device_list;
|
||||||
Device_pd_client *_child;
|
Device_pd_client *_child;
|
||||||
Genode::Ram_connection *_ram;
|
Genode::Ram_connection *_ram;
|
||||||
|
Genode::Session_label _label;
|
||||||
|
Genode::Session_policy _policy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan PCI buses for a device
|
* Scan PCI buses for a device
|
||||||
@ -115,6 +118,173 @@ namespace Pci {
|
|||||||
return config_space;
|
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:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,9 +293,105 @@ namespace Pci {
|
|||||||
Session_component(Genode::Rpc_entrypoint *ep,
|
Session_component(Genode::Rpc_entrypoint *ep,
|
||||||
Genode::Allocator *md_alloc,
|
Genode::Allocator *md_alloc,
|
||||||
Device_pd_client *child,
|
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
|
* Destructor
|
||||||
@ -191,8 +457,7 @@ namespace Pci {
|
|||||||
*/
|
*/
|
||||||
Device_config config;
|
Device_config config;
|
||||||
|
|
||||||
do
|
while (true) {
|
||||||
{
|
|
||||||
function += 1;
|
function += 1;
|
||||||
if (!_find_next(bus, device, function, &config, &config_access))
|
if (!_find_next(bus, device, function, &config, &config_access))
|
||||||
return Device_capability();
|
return Device_capability();
|
||||||
@ -201,7 +466,16 @@ namespace Pci {
|
|||||||
bus = config.bus_number();
|
bus = config.bus_number();
|
||||||
device = config.device_number();
|
device = config.device_number();
|
||||||
function = config.function_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 */
|
/* lookup if we have a extended pci config space */
|
||||||
Genode::addr_t config_space = lookup_config_space(bus, device,
|
Genode::addr_t config_space = lookup_config_space(bus, device,
|
||||||
@ -214,7 +488,7 @@ namespace Pci {
|
|||||||
* FIXME: check and adjust session quota
|
* FIXME: check and adjust session quota
|
||||||
*/
|
*/
|
||||||
Device_component *device_component =
|
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)
|
if (!device_component)
|
||||||
return Device_capability();
|
return Device_capability();
|
||||||
@ -323,6 +597,10 @@ namespace Pci {
|
|||||||
for (i = 0; i < config()->xml_node().num_sub_nodes(); i++)
|
for (i = 0; i < config()->xml_node().num_sub_nodes(); i++)
|
||||||
{
|
{
|
||||||
Xml_node node = config()->xml_node().sub_node(i);
|
Xml_node node = config()->xml_node().sub_node(i);
|
||||||
|
|
||||||
|
if (!node.has_type("bdf"))
|
||||||
|
continue;
|
||||||
|
|
||||||
uint32_t bdf_start = 0;
|
uint32_t bdf_start = 0;
|
||||||
uint32_t func_count = 0;
|
uint32_t func_count = 0;
|
||||||
addr_t base = 0;
|
addr_t base = 0;
|
||||||
@ -348,9 +626,15 @@ namespace Pci {
|
|||||||
/* FIXME: extract quota from args */
|
/* FIXME: extract quota from args */
|
||||||
/* FIXME: pass quota to session-component constructor */
|
/* FIXME: pass quota to session-component constructor */
|
||||||
|
|
||||||
return new (md_alloc()) Session_component(ep(), md_alloc(),
|
try {
|
||||||
_pd_device_client,
|
return new (md_alloc()) Session_component(ep(), md_alloc(),
|
||||||
&_ram);
|
_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:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user