mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
platform_drv: replace nova specific device_pd
by using generic Pd_session::map instead for eager memory mappings of DMA memory. Issue #2209
This commit is contained in:
parent
fe4bdde687
commit
69e71147ef
@ -15,16 +15,6 @@ include/spec/%/trace/timestamp.h:
|
||||
cp $(GENODE_DIR)/repos/os/$@ $@
|
||||
|
||||
|
||||
DEVICE_PD_SRC := src/drivers/platform/spec/x86/pci_device_pd_ipc.h \
|
||||
src/drivers/platform/spec/x86/device_pd \
|
||||
include/os/static_root.h
|
||||
|
||||
content: $(DEVICE_PD_SRC)
|
||||
$(DEVICE_PD_SRC):
|
||||
mkdir -p $(dir $@)
|
||||
cp -r $(GENODE_DIR)/repos/os/$@ $@
|
||||
|
||||
|
||||
content: README
|
||||
README:
|
||||
cp $(REP_DIR)/recipes/src/base-nova/README $@
|
||||
|
@ -54,7 +54,6 @@ proc platform_drv_build_components {} {
|
||||
lappend_if [have_platform_drv] drv_build_components drivers/platform
|
||||
lappend_if [have_spec acpi] drv_build_components drivers/acpi
|
||||
lappend_if [have_spec acpi] drv_build_components server/report_rom
|
||||
lappend_if [have_spec nova] drv_build_components drivers/platform/spec/x86/device_pd
|
||||
return $drv_build_components
|
||||
}
|
||||
|
||||
@ -69,7 +68,6 @@ proc platform_drv_boot_modules {} {
|
||||
lappend_if [have_platform_drv] drv_boot_modules platform_drv
|
||||
lappend_if [have_spec acpi] drv_boot_modules acpi_drv
|
||||
lappend_if [have_spec acpi] drv_boot_modules report_rom
|
||||
lappend_if [have_spec nova] drv_boot_modules device_pd
|
||||
lappend_if [have_spec muen] drv_boot_modules acpi
|
||||
return $drv_boot_modules
|
||||
}
|
||||
|
103
repos/os/src/drivers/platform/spec/x86/device_pd.cc
Normal file
103
repos/os/src/drivers/platform/spec/x86/device_pd.cc
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* \brief Pci device protection domain service for platform driver
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <base/log.h>
|
||||
#include <dataspace/client.h>
|
||||
#include <region_map/client.h>
|
||||
#include <pd_session/client.h>
|
||||
|
||||
#include <util/retry.h>
|
||||
|
||||
#include "device_pd.h"
|
||||
|
||||
void Platform::Device_pd::attach_dma_mem(Genode::Dataspace_capability ds_cap)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Dataspace_client ds_client(ds_cap);
|
||||
|
||||
addr_t const phys = ds_client.phys_addr();
|
||||
size_t const size = ds_client.size();
|
||||
|
||||
addr_t page = ~0UL;
|
||||
|
||||
try {
|
||||
page = _address_space.attach_at(ds_cap, phys);
|
||||
/* trigger eager mapping of memory */
|
||||
_pd.map(page, size);
|
||||
}
|
||||
catch (Out_of_ram) { throw; }
|
||||
catch (Out_of_caps) { throw; }
|
||||
catch (Region_map::Region_conflict) {
|
||||
/*
|
||||
* DMA memory already attached before.
|
||||
*/
|
||||
page = phys;
|
||||
} catch (...) {
|
||||
error(_label, ": attach_at or map failed");
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if ((page == ~0UL) || (page != phys)) {
|
||||
if (page != ~0UL)
|
||||
_address_space.detach(page);
|
||||
|
||||
Genode::error(_label, ": attachment of DMA memory @ ",
|
||||
Genode::Hex(phys), "+", Genode::Hex(size), " failed page=", Genode::Hex(page));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::Device_pd::assign_pci(Genode::Io_mem_dataspace_capability io_mem_cap,
|
||||
Genode::uint16_t rid)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Dataspace_client ds_client(io_mem_cap);
|
||||
addr_t const phys = ds_client.phys_addr();
|
||||
|
||||
addr_t page = _address_space.attach_at(io_mem_cap, phys);
|
||||
|
||||
/* sanity check */
|
||||
if (!page)
|
||||
throw Region_map::Region_conflict();
|
||||
|
||||
/* trigger eager mapping of memory */
|
||||
_pd.map(page, ds_client.size());
|
||||
|
||||
/* utility to print rid value */
|
||||
struct Rid
|
||||
{
|
||||
Genode::uint16_t const v;
|
||||
explicit Rid(Genode::uint16_t rid) : v(rid) { }
|
||||
void print(Genode::Output &out) const
|
||||
{
|
||||
using Genode::print;
|
||||
using Genode::Hex;
|
||||
print(out, Hex(v >> 8, Hex::Prefix::OMIT_PREFIX), ":",
|
||||
Hex((v >> 3) & 0x1f, Hex::Prefix::OMIT_PREFIX), ".",
|
||||
Hex(v & 0x7, Hex::Prefix::OMIT_PREFIX));
|
||||
}
|
||||
};
|
||||
|
||||
/* try to assign pci device to this protection domain */
|
||||
if (!_pd.assign_pci(page, rid))
|
||||
Genode::error(_label, ": assignment of PCI device ", Rid(rid), " failed ",
|
||||
"phys=", Genode::Hex(ds_client.phys_addr()), " "
|
||||
"virt=", Genode::Hex(page));
|
||||
else
|
||||
Genode::log(_label,": assignment of PCI device ", Rid(rid), " succeeded");
|
||||
|
||||
/* we don't need the mapping anymore */
|
||||
_address_space.detach(page);
|
||||
}
|
@ -13,33 +13,87 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <os/static_parent_services.h>
|
||||
#include <os/slave.h>
|
||||
/* base */
|
||||
#include <base/env.h>
|
||||
#include <region_map/client.h>
|
||||
#include <pd_session/connection.h>
|
||||
|
||||
enum { STACK_SIZE = 4 * sizeof(void *) * 1024 };
|
||||
/* os */
|
||||
#include <io_mem_session/connection.h>
|
||||
|
||||
namespace Platform { class Device_pd_policy; }
|
||||
namespace Platform { class Device_pd; }
|
||||
|
||||
class Platform::Device_pd_policy
|
||||
:
|
||||
private Genode::Static_parent_services<Genode::Pd_session,
|
||||
Genode::Cpu_session,
|
||||
Genode::Log_session,
|
||||
Genode::Rom_session>,
|
||||
public Genode::Slave::Policy
|
||||
class Platform::Device_pd
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Pd_connection _pd;
|
||||
Genode::Session_label const &_label;
|
||||
|
||||
/**
|
||||
* Custom handling of PD-session depletion during attach operations
|
||||
*
|
||||
* The default implementation of 'env.rm()' automatically issues a resource
|
||||
* request if the PD session quota gets exhausted. For the device PD, we don't
|
||||
* want to issue resource requests but let the platform driver reflect this
|
||||
* condition to its client.
|
||||
*/
|
||||
struct Expanding_region_map_client : Genode::Region_map_client
|
||||
{
|
||||
Genode::Env &_env;
|
||||
|
||||
Expanding_region_map_client(Genode::Env &env,
|
||||
Genode::Capability<Genode::Region_map> address_space)
|
||||
:
|
||||
Region_map_client(address_space), _env(env)
|
||||
{ }
|
||||
|
||||
Local_addr attach(Genode::Dataspace_capability ds,
|
||||
Genode::size_t size = 0, Genode::off_t offset = 0,
|
||||
bool use_local_addr = false,
|
||||
Local_addr local_addr = (void *)0,
|
||||
bool executable = false) override
|
||||
{
|
||||
return Genode::retry<Genode::Out_of_ram>(
|
||||
[&] () {
|
||||
return Genode::retry<Genode::Out_of_caps>(
|
||||
[&] () {
|
||||
return Region_map_client::attach(ds, size, offset,
|
||||
use_local_addr,
|
||||
local_addr,
|
||||
executable); },
|
||||
[&] () {
|
||||
enum { UPGRADE_CAP_QUOTA = 2 };
|
||||
if (_env.pd().avail_caps().value < UPGRADE_CAP_QUOTA)
|
||||
throw;
|
||||
|
||||
Genode::String<32> arg("cap_quota=", (unsigned)UPGRADE_CAP_QUOTA);
|
||||
_env.upgrade(Genode::Parent::Env::pd(), arg.string());
|
||||
}
|
||||
);
|
||||
},
|
||||
[&] () {
|
||||
enum { UPGRADE_RAM_QUOTA = 4096 };
|
||||
if (_env.ram().avail_ram().value < UPGRADE_RAM_QUOTA)
|
||||
throw;
|
||||
|
||||
Genode::String<32> arg("ram_quota=", (unsigned)UPGRADE_RAM_QUOTA);
|
||||
_env.upgrade(Genode::Parent::Env::pd(), arg.string());
|
||||
}
|
||||
);
|
||||
}
|
||||
} _address_space;
|
||||
|
||||
public:
|
||||
|
||||
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
|
||||
Genode::Region_map &local_rm,
|
||||
Genode::Pd_session &pd_ref,
|
||||
Genode::Pd_session_capability pd_ref_cap,
|
||||
Genode::Cap_quota cap_quota,
|
||||
Genode::Ram_quota ram_quota,
|
||||
Genode::Session_label const &label)
|
||||
Device_pd(Genode::Env &env,
|
||||
Genode::Session_label const &label)
|
||||
:
|
||||
Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm,
|
||||
pd_ref, pd_ref_cap, cap_quota, ram_quota)
|
||||
_pd(env, label.string()),
|
||||
_label(label),
|
||||
_address_space(env, _pd.address_space())
|
||||
{ }
|
||||
};
|
||||
|
||||
void attach_dma_mem(Genode::Dataspace_capability);
|
||||
void assign_pci(Genode::Io_mem_dataspace_capability, Genode::uint16_t);
|
||||
};
|
||||
|
@ -1,224 +0,0 @@
|
||||
/*
|
||||
* \brief Pci device protection domain service for platform driver
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <base/component.h>
|
||||
#include <os/static_root.h>
|
||||
#include <base/log.h>
|
||||
#include <base/sleep.h>
|
||||
#include <dataspace/client.h>
|
||||
#include <region_map/client.h>
|
||||
#include <pd_session/client.h>
|
||||
|
||||
#include <util/flex_iterator.h>
|
||||
#include <util/retry.h>
|
||||
|
||||
#include <nova/native_thread.h>
|
||||
|
||||
#include "../pci_device_pd_ipc.h"
|
||||
|
||||
|
||||
/**
|
||||
* Custom handling of PD-session depletion during attach operations
|
||||
*
|
||||
* The default implementation of 'env.rm()' automatically issues a resource
|
||||
* request if the PD session quota gets exhausted. For the device PD, we don't
|
||||
* want to issue resource requests but let the platform driver reflect this
|
||||
* condition to its client.
|
||||
*/
|
||||
struct Expanding_region_map_client : Genode::Region_map_client
|
||||
{
|
||||
Genode::Env &_env;
|
||||
|
||||
Expanding_region_map_client(Genode::Env &env)
|
||||
:
|
||||
Region_map_client(env.pd().address_space()), _env(env)
|
||||
{ }
|
||||
|
||||
Local_addr attach(Genode::Dataspace_capability ds,
|
||||
Genode::size_t size, Genode::off_t offset,
|
||||
bool use_local_addr,
|
||||
Local_addr local_addr,
|
||||
bool executable) override
|
||||
{
|
||||
return Genode::retry<Genode::Out_of_ram>(
|
||||
[&] () {
|
||||
return Genode::retry<Genode::Out_of_caps>(
|
||||
[&] () {
|
||||
return Region_map_client::attach(ds, size, offset,
|
||||
use_local_addr,
|
||||
local_addr,
|
||||
executable); },
|
||||
[&] () {
|
||||
enum { UPGRADE_CAP_QUOTA = 2 };
|
||||
if (_env.pd().avail_caps().value < UPGRADE_CAP_QUOTA)
|
||||
throw;
|
||||
|
||||
Genode::String<32> arg("cap_quota=", (unsigned)UPGRADE_CAP_QUOTA);
|
||||
_env.upgrade(Genode::Parent::Env::pd(), arg.string());
|
||||
}
|
||||
);
|
||||
},
|
||||
[&] () {
|
||||
enum { UPGRADE_RAM_QUOTA = 4096 };
|
||||
if (_env.ram().avail_ram().value < UPGRADE_RAM_QUOTA)
|
||||
throw;
|
||||
|
||||
Genode::String<32> arg("ram_quota=", (unsigned)UPGRADE_RAM_QUOTA);
|
||||
_env.upgrade(Genode::Parent::Env::pd(), arg.string());
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static bool map_eager(Genode::addr_t const page, unsigned log2_order)
|
||||
{
|
||||
using Genode::addr_t;
|
||||
|
||||
Genode::Thread * myself = Genode::Thread::myself();
|
||||
Nova::Utcb * utcb = reinterpret_cast<Nova::Utcb *>(myself->utcb());
|
||||
Nova::Rights const mapping_rw(true, true, false);
|
||||
|
||||
addr_t const page_fault_portal = myself->native_thread().exc_pt_sel + 14;
|
||||
|
||||
while (true) {
|
||||
/* setup faked page fault information */
|
||||
utcb->set_msg_word(((addr_t)&utcb->qual[2] - (addr_t)utcb->msg()) /
|
||||
sizeof(addr_t));
|
||||
utcb->ip = reinterpret_cast<addr_t>(map_eager);
|
||||
utcb->qual[1] = page;
|
||||
utcb->crd_rcv = Nova::Mem_crd(page >> 12, log2_order - 12, mapping_rw);
|
||||
|
||||
/* trigger faked page fault */
|
||||
Genode::uint8_t res = Nova::call(page_fault_portal);
|
||||
|
||||
bool const retry = utcb->msg_words();
|
||||
if (res != Nova::NOVA_OK || !retry)
|
||||
return res == Nova::NOVA_OK;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device_pd_component::attach_dma_mem(Genode::Dataspace_capability ds_cap)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Dataspace_client ds_client(ds_cap);
|
||||
|
||||
addr_t const phys = ds_client.phys_addr();
|
||||
size_t const size = ds_client.size();
|
||||
|
||||
addr_t page = ~0UL;
|
||||
|
||||
try { page = _address_space.attach_at(ds_cap, phys); }
|
||||
catch (Out_of_ram) { throw; }
|
||||
catch (Out_of_caps) { throw; }
|
||||
catch (Region_map::Region_conflict) {
|
||||
/*
|
||||
* DMA memory already attached before or collision with normal
|
||||
* device_pd memory (text, data, etc).
|
||||
* Currently we can't distinguish it easily - show error
|
||||
* message as a precaution.
|
||||
*/
|
||||
Genode::error("region conflict");
|
||||
} catch (...) { }
|
||||
|
||||
/* sanity check */
|
||||
if ((page == ~0UL) || (page != phys)) {
|
||||
if (page != ~0UL)
|
||||
_address_space.detach(page);
|
||||
|
||||
Genode::error("attachment of DMA memory @ ",
|
||||
Genode::Hex(phys), "+", Genode::Hex(size), " failed");
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::Flexpage_iterator it(page, size, page, size, 0);
|
||||
for (Genode::Flexpage flex = it.page(); flex.valid(); flex = it.page()) {
|
||||
if (map_eager(flex.addr, flex.log2_order))
|
||||
continue;
|
||||
|
||||
Genode::error("attachment of DMA memory @ ",
|
||||
Genode::Hex(phys), "+", Genode::Hex(size), " failed at ",
|
||||
flex.addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::Device_pd_component::assign_pci(Genode::Io_mem_dataspace_capability io_mem_cap,
|
||||
Genode::uint16_t rid)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Dataspace_client ds_client(io_mem_cap);
|
||||
|
||||
addr_t page = _address_space.attach(io_mem_cap);
|
||||
/* sanity check */
|
||||
if (!page)
|
||||
throw Region_map::Region_conflict();
|
||||
|
||||
/* trigger mapping of whole memory area */
|
||||
if (!map_eager(page, 12))
|
||||
Genode::error("assignment of PCI device failed - ", Genode::Hex(page));
|
||||
|
||||
/* utility to print rid value */
|
||||
struct Rid
|
||||
{
|
||||
Genode::uint16_t const v;
|
||||
explicit Rid(Genode::uint16_t rid) : v(rid) { }
|
||||
void print(Genode::Output &out) const
|
||||
{
|
||||
using Genode::print;
|
||||
using Genode::Hex;
|
||||
print(out, Hex(v >> 8, Hex::Prefix::OMIT_PREFIX), ":",
|
||||
Hex((v >> 3) & 0x1f, Hex::Prefix::OMIT_PREFIX), ".",
|
||||
Hex(v & 0x7, Hex::Prefix::OMIT_PREFIX));
|
||||
}
|
||||
};
|
||||
|
||||
/* try to assign pci device to this protection domain */
|
||||
if (!_env.pd().assign_pci(page, rid))
|
||||
Genode::error("assignment of PCI device ", Rid(rid), " failed ",
|
||||
"phys=", Genode::Hex(ds_client.phys_addr()), " "
|
||||
"virt=", Genode::Hex(page));
|
||||
else
|
||||
Genode::log("assignment of PCI device ", Rid(rid), " succeeded");
|
||||
|
||||
/* we don't need the mapping anymore */
|
||||
_address_space.detach(page);
|
||||
}
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Genode::Env &env;
|
||||
|
||||
Expanding_region_map_client rm { env };
|
||||
|
||||
Platform::Device_pd_component pd_component { rm, env };
|
||||
|
||||
Genode::Static_root<Platform::Device_pd> root { env.ep().manage(pd_component) };
|
||||
|
||||
Main(Genode::Env &env) : env(env)
|
||||
{
|
||||
env.parent().announce(env.ep().manage(root));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************
|
||||
** Component **
|
||||
***************/
|
||||
|
||||
void Component::construct(Genode::Env &env) { static Main main(env); }
|
||||
|
@ -1,6 +0,0 @@
|
||||
TARGET = device_pd
|
||||
SRC_CC = main.cc
|
||||
LIBS = base-nova
|
||||
|
||||
REQUIRES = nova
|
||||
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* \brief IPC interface between pci_drv and pci_device_pd
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-02-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <base/connection.h>
|
||||
#include <base/rpc_server.h>
|
||||
|
||||
#include <io_mem_session/capability.h>
|
||||
|
||||
namespace Platform {
|
||||
|
||||
struct Device_pd;
|
||||
struct Device_pd_client;
|
||||
struct Device_pd_connection;
|
||||
struct Device_pd_component;
|
||||
}
|
||||
|
||||
struct Platform::Device_pd : Genode::Session
|
||||
{
|
||||
static const char *service_name() { return "DEVICE_PD"; }
|
||||
|
||||
enum { CAP_QUOTA = 2 };
|
||||
|
||||
typedef Device_pd_client Client;
|
||||
|
||||
GENODE_RPC_THROW(Rpc_attach_dma_mem, void, attach_dma_mem,
|
||||
GENODE_TYPE_LIST(Genode::Out_of_ram, Genode::Out_of_caps),
|
||||
Genode::Dataspace_capability);
|
||||
GENODE_RPC_THROW(Rpc_assign_pci, void, assign_pci,
|
||||
GENODE_TYPE_LIST(Genode::Out_of_ram, Genode::Out_of_caps,
|
||||
Genode::Region_map::Region_conflict),
|
||||
Genode::Io_mem_dataspace_capability, Genode::uint16_t);
|
||||
|
||||
GENODE_RPC_INTERFACE(Rpc_attach_dma_mem, Rpc_assign_pci);
|
||||
};
|
||||
|
||||
struct Platform::Device_pd_client : Genode::Rpc_client<Device_pd>
|
||||
{
|
||||
Device_pd_client(Capability<Device_pd> cap)
|
||||
: Rpc_client<Device_pd>(cap) { }
|
||||
|
||||
void attach_dma_mem(Genode::Dataspace_capability cap) {
|
||||
call<Rpc_attach_dma_mem>(cap); }
|
||||
|
||||
void assign_pci(Genode::Io_mem_dataspace_capability cap,
|
||||
Genode::uint16_t bdf)
|
||||
{
|
||||
call<Rpc_assign_pci>(cap, bdf);
|
||||
}
|
||||
};
|
||||
|
||||
struct Platform::Device_pd_connection : Genode::Connection<Device_pd>, Device_pd_client
|
||||
{
|
||||
enum { RAM_QUOTA = 0UL };
|
||||
|
||||
Device_pd_connection(Genode::Capability<Device_pd> cap)
|
||||
:
|
||||
Genode::Connection<Device_pd>(cap),
|
||||
Device_pd_client(cap)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct Platform::Device_pd_component : Genode::Rpc_object<Device_pd,
|
||||
Device_pd_component>
|
||||
{
|
||||
Genode::Env &_env;
|
||||
Genode::Region_map &_address_space;
|
||||
|
||||
Device_pd_component(Genode::Region_map &address_space, Genode::Env &env)
|
||||
: _env(env), _address_space(address_space) { }
|
||||
|
||||
void attach_dma_mem(Genode::Dataspace_capability);
|
||||
void assign_pci(Genode::Io_mem_dataspace_capability, Genode::uint16_t);
|
||||
};
|
@ -15,9 +15,10 @@
|
||||
|
||||
/* base */
|
||||
#include <base/allocator_guard.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/tslab.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <ram_session/capability.h>
|
||||
#include <root/component.h>
|
||||
|
||||
@ -35,7 +36,6 @@
|
||||
/* local */
|
||||
#include "pci_device_component.h"
|
||||
#include "pci_config_access.h"
|
||||
#include "pci_device_pd_ipc.h"
|
||||
#include "device_pd.h"
|
||||
|
||||
namespace Platform {
|
||||
@ -199,13 +199,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
private:
|
||||
|
||||
Genode::Env &_env;
|
||||
Genode::Rpc_entrypoint &_device_pd_ep;
|
||||
Genode::Attached_rom_dataspace &_config;
|
||||
Genode::Ram_session_guard _env_ram;
|
||||
Genode::Ram_session_capability _env_ram_cap;
|
||||
Genode::Pd_session &_env_pd;
|
||||
Genode::Pd_session_capability _env_pd_cap;
|
||||
Genode::Region_map &_local_rm;
|
||||
Genode::Heap _md_alloc;
|
||||
Genode::Session_label const _label;
|
||||
Genode::Session_policy const _policy { _label, _config.xml() };
|
||||
@ -237,145 +232,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deduce specified amount of quota from an allocator guard, or throw
|
||||
* an 'Out_of_ram' exception if the guard's quota is depleted.
|
||||
*/
|
||||
struct Quota_reservation
|
||||
{
|
||||
Genode::Ram_session_guard &guard;
|
||||
|
||||
Genode::size_t const amount;
|
||||
|
||||
Quota_reservation(Genode::Ram_session_guard &guard,
|
||||
Genode::size_t amount)
|
||||
: guard(guard), amount(amount)
|
||||
{
|
||||
if (!guard.withdraw(amount))
|
||||
throw Out_of_ram();
|
||||
}
|
||||
|
||||
~Quota_reservation() noexcept(false)
|
||||
{
|
||||
if (!guard.revert_withdraw(amount))
|
||||
throw Fatal();
|
||||
}
|
||||
};
|
||||
|
||||
class Device_pd
|
||||
{
|
||||
public:
|
||||
|
||||
class Startup_failed : Genode::Exception { };
|
||||
|
||||
private:
|
||||
|
||||
enum { CAP_QUOTA = 60, RAM_QUOTA = 190 * 4096 };
|
||||
|
||||
Quota_reservation const _reservation;
|
||||
Device_pd_policy _policy;
|
||||
Genode::Child _child;
|
||||
|
||||
void _check_child_started_up() const {
|
||||
if (!_child.active())
|
||||
throw Startup_failed(); }
|
||||
|
||||
bool const _active = (_check_child_started_up(), true);
|
||||
|
||||
Genode::Slave::Connection<Device_pd_connection> _connection;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \throw Out_of_ram
|
||||
* \throw Out_of_caps
|
||||
* \throw Startup_failed child could not be started
|
||||
* \throw Service_denied by 'Slave::Connection'
|
||||
*/
|
||||
Device_pd(Genode::Region_map &local_rm,
|
||||
Genode::Rpc_entrypoint &ep,
|
||||
Genode::Ram_session_guard &ref_ram,
|
||||
Genode::Ram_session_capability ref_ram_cap,
|
||||
Genode::Pd_session &ref_pd,
|
||||
Genode::Pd_session_capability ref_pd_cap,
|
||||
Genode::Session_label const &label)
|
||||
try :
|
||||
_reservation(ref_ram, RAM_QUOTA),
|
||||
_policy(ep, local_rm, ref_pd, ref_pd_cap,
|
||||
Genode::Cap_quota{CAP_QUOTA},
|
||||
Genode::Ram_quota{RAM_QUOTA},
|
||||
label),
|
||||
_child(local_rm, ep, _policy),
|
||||
_connection(_policy, Genode::Slave::Args())
|
||||
{ }
|
||||
/* thrown by 'Quota_reservation', 'Device_pd_policy' or 'Child' */
|
||||
catch (Genode::Out_of_ram) {
|
||||
throw; }
|
||||
|
||||
catch (Genode::Out_of_caps) {
|
||||
Genode::warning("Out_of_caps during device-pd creation");
|
||||
throw; }
|
||||
|
||||
/* thrown by 'Slave::Connection' */
|
||||
catch (Genode::Insufficient_ram_quota) {
|
||||
throw Genode::Out_of_ram(); }
|
||||
|
||||
/* thrown by 'Slave::Connection' */
|
||||
catch (Genode::Insufficient_cap_quota) {
|
||||
Genode::warning("Insufficient_cap_quota during device-pd creation");
|
||||
throw Genode::Out_of_caps(); }
|
||||
|
||||
Device_pd_client &session() { return _connection; }
|
||||
|
||||
Genode::Ram_session_capability ram_session_cap() {
|
||||
return _child.ram_session_cap(); }
|
||||
};
|
||||
|
||||
Device_pd *_device_pd = nullptr;
|
||||
|
||||
/**
|
||||
* Free device PD at session destruction
|
||||
*/
|
||||
struct Device_pd_guard
|
||||
{
|
||||
Session_component &session;
|
||||
|
||||
~Device_pd_guard() {
|
||||
if (session._device_pd)
|
||||
Genode::destroy(session._md_alloc, session._device_pd); }
|
||||
|
||||
} _device_pd_guard { *this };
|
||||
|
||||
/**
|
||||
* Attempt to initialize device PD
|
||||
*
|
||||
* \throw Out_of_ram session quota does not suffice to spawn the
|
||||
* device PD
|
||||
* \throw Out_of_caps
|
||||
*/
|
||||
void _try_init_device_pd()
|
||||
{
|
||||
if (_device_pd || _no_device_pd)
|
||||
return;
|
||||
|
||||
try {
|
||||
_device_pd = new (_md_alloc)
|
||||
Device_pd(_local_rm, _device_pd_ep, _env_ram, _env_ram_cap,
|
||||
_env_pd, _env_pd_cap, _label);
|
||||
}
|
||||
catch (Genode::Out_of_ram) { /* thrown by '_md_alloc', 'Device_pd' */
|
||||
throw; }
|
||||
catch (Genode::Out_of_caps) {
|
||||
Genode::warning("Out_of_caps during Device_pd construction");
|
||||
throw; }
|
||||
catch (...) {
|
||||
Genode::warning("PCI device protection domain for IOMMU support "
|
||||
"is not available");
|
||||
_no_device_pd = true;
|
||||
}
|
||||
}
|
||||
Platform::Device_pd _device_pd { _env, _label };
|
||||
|
||||
enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES *
|
||||
Device_config::MAX_DEVICES *
|
||||
@ -383,12 +240,11 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
|
||||
static Genode::Bit_array<MAX_PCI_DEVICES> bdf_in_use;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List containing extended PCI config space information
|
||||
*/
|
||||
static Genode::List<Config_space> &config_space_list() {
|
||||
static Genode::List<Config_space> &config_space_list()
|
||||
{
|
||||
static Genode::List<Config_space> config_space;
|
||||
return config_space;
|
||||
}
|
||||
@ -398,8 +254,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
* the corresponding extended 4K PCI config space address.
|
||||
* A io mem dataspace is created and returned.
|
||||
*/
|
||||
Genode::addr_t
|
||||
lookup_config_space(Genode::uint16_t const bdf)
|
||||
Genode::addr_t lookup_config_space(Genode::uint16_t const bdf)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
@ -416,7 +271,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
* 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) {
|
||||
unsigned class_subclass_prog(const char * name)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
static struct {
|
||||
@ -591,18 +447,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
*/
|
||||
Session_component(Genode::Env &env,
|
||||
Genode::Attached_rom_dataspace &config,
|
||||
Genode::Rpc_entrypoint &device_pd_ep,
|
||||
Platform::Pci_buses &buses,
|
||||
Genode::Heap &global_heap,
|
||||
char const *args)
|
||||
:
|
||||
_env(env), _device_pd_ep(device_pd_ep),
|
||||
_env(env),
|
||||
_config(config),
|
||||
_env_ram(env.ram(), Genode::ram_quota_from_args(args).value),
|
||||
_env_ram_cap(env.ram_session_cap()),
|
||||
_env_pd(env.pd()),
|
||||
_env_pd_cap(env.pd_session_cap()),
|
||||
_local_rm(env.rm()),
|
||||
_md_alloc(_env_ram, env.rm()),
|
||||
_label(Genode::label_from_args(args)),
|
||||
_pci_bus(buses), _global_heap(global_heap)
|
||||
@ -900,17 +751,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
|
||||
Io_mem_dataspace_capability io_mem = device->get_config_space();
|
||||
|
||||
_try_init_device_pd();
|
||||
if (!_device_pd)
|
||||
return;
|
||||
|
||||
try {
|
||||
_device_pd->session().assign_pci(io_mem, device->config().bdf());
|
||||
_device_pd.assign_pci(io_mem, device->config().bdf());
|
||||
|
||||
for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
|
||||
Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config());
|
||||
if (rmrr_cap.valid())
|
||||
_device_pd->session().attach_dma_mem(rmrr_cap);
|
||||
_device_pd.attach_dma_mem(rmrr_cap);
|
||||
}
|
||||
} catch (...) {
|
||||
Genode::error("assignment to device pd or of RMRR region failed");
|
||||
@ -938,13 +785,6 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
|
||||
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t const size) override
|
||||
{
|
||||
/*
|
||||
* We always try to create the device PD first because
|
||||
* otherwise we might consume the requested size multiple
|
||||
* times which breaks our accounting.
|
||||
*/
|
||||
_try_init_device_pd();
|
||||
|
||||
Ram_capability ram_cap;
|
||||
|
||||
try { ram_cap = _env_ram.alloc(size, Genode::UNCACHED); }
|
||||
@ -953,13 +793,11 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
||||
if (!ram_cap.valid())
|
||||
return ram_cap;
|
||||
|
||||
if (_device_pd) {
|
||||
try { _device_pd->session().attach_dma_mem(ram_cap); }
|
||||
catch (Out_of_ram) { _rollback(size, ram_cap);; }
|
||||
catch (Out_of_caps) {
|
||||
Genode::warning("Out_of_caps while attaching DMA memory");
|
||||
_rollback(size, ram_cap);;
|
||||
}
|
||||
try { _device_pd.attach_dma_mem(ram_cap); }
|
||||
catch (Out_of_ram) { _rollback(size, ram_cap);; }
|
||||
catch (Out_of_caps) {
|
||||
Genode::warning("Out_of_caps while attaching DMA memory");
|
||||
_rollback(size, ram_cap);;
|
||||
}
|
||||
|
||||
try { _insert(ram_cap); }
|
||||
@ -1014,7 +852,6 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
|
||||
Genode::Reporter _pci_reporter { _env, "pci" };
|
||||
|
||||
Genode::Rpc_entrypoint _device_pd_ep;
|
||||
Genode::Heap _heap { _env.ram(), _env.rm() };
|
||||
Platform::Pci_buses _buses { _env, _heap };
|
||||
|
||||
@ -1061,7 +898,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
}
|
||||
|
||||
if (node.has_type("rmrr")) {
|
||||
uint64_t mem_start, mem_end;
|
||||
uint64_t mem_start = 0, mem_end = 0;
|
||||
node.attribute("start").value(&mem_start);
|
||||
node.attribute("end").value(&mem_end);
|
||||
|
||||
@ -1076,7 +913,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
if (!scope.num_sub_nodes() || !scope.has_type("scope"))
|
||||
throw 3;
|
||||
|
||||
unsigned bus, dev, func;
|
||||
unsigned bus = 0, dev = 0, func = 0;
|
||||
scope.attribute("bus_start").value(&bus);
|
||||
|
||||
for (unsigned p = 0; p < scope.num_sub_nodes(); p++) {
|
||||
@ -1152,7 +989,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
{
|
||||
try {
|
||||
return new (md_alloc())
|
||||
Session_component(_env, _config, _device_pd_ep, _buses, _heap, args);
|
||||
Session_component(_env, _config, _buses, _heap, args);
|
||||
}
|
||||
catch (Genode::Session_policy::No_policy_defined) {
|
||||
Genode::error("Invalid session request, no matching policy for ",
|
||||
@ -1184,8 +1021,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
:
|
||||
Genode::Root_component<Session_component>(&env.ep().rpc_ep(),
|
||||
&md_alloc),
|
||||
_env(env), _config(config),
|
||||
_device_pd_ep(&env.pd(), STACK_SIZE, "device_pd_slave")
|
||||
_env(env), _config(config)
|
||||
{
|
||||
if (acpi_rom) {
|
||||
try {
|
||||
|
@ -1,6 +1,7 @@
|
||||
TARGET = platform_drv
|
||||
REQUIRES = x86
|
||||
SRC_CC = main.cc irq.cc pci_device.cc nonpci_devices.cc session.cc
|
||||
SRC_CC += device_pd.cc
|
||||
LIBS = base
|
||||
|
||||
INC_DIR = $(PRG_DIR)
|
||||
|
Loading…
Reference in New Issue
Block a user