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/$@ $@
|
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
|
content: README
|
||||||
README:
|
README:
|
||||||
cp $(REP_DIR)/recipes/src/base-nova/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_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 drivers/acpi
|
||||||
lappend_if [have_spec acpi] drv_build_components server/report_rom
|
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
|
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_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 acpi_drv
|
||||||
lappend_if [have_spec acpi] drv_boot_modules report_rom
|
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
|
lappend_if [have_spec muen] drv_boot_modules acpi
|
||||||
return $drv_boot_modules
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <os/static_parent_services.h>
|
/* base */
|
||||||
#include <os/slave.h>
|
#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
|
class Platform::Device_pd
|
||||||
:
|
|
||||||
private Genode::Static_parent_services<Genode::Pd_session,
|
|
||||||
Genode::Cpu_session,
|
|
||||||
Genode::Log_session,
|
|
||||||
Genode::Rom_session>,
|
|
||||||
public Genode::Slave::Policy
|
|
||||||
{
|
{
|
||||||
|
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:
|
public:
|
||||||
|
|
||||||
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
|
Device_pd(Genode::Env &env,
|
||||||
Genode::Region_map &local_rm,
|
Genode::Session_label const &label)
|
||||||
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)
|
|
||||||
:
|
:
|
||||||
Genode::Slave::Policy(label, "device_pd", *this, slave_ep, local_rm,
|
_pd(env, label.string()),
|
||||||
pd_ref, pd_ref_cap, cap_quota, ram_quota)
|
_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 */
|
/* base */
|
||||||
#include <base/allocator_guard.h>
|
#include <base/allocator_guard.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <base/heap.h>
|
||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <base/tslab.h>
|
#include <base/tslab.h>
|
||||||
#include <base/attached_rom_dataspace.h>
|
|
||||||
#include <ram_session/capability.h>
|
#include <ram_session/capability.h>
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
|
|
||||||
@ -35,7 +36,6 @@
|
|||||||
/* local */
|
/* local */
|
||||||
#include "pci_device_component.h"
|
#include "pci_device_component.h"
|
||||||
#include "pci_config_access.h"
|
#include "pci_config_access.h"
|
||||||
#include "pci_device_pd_ipc.h"
|
|
||||||
#include "device_pd.h"
|
#include "device_pd.h"
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
@ -199,13 +199,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
Genode::Env &_env;
|
Genode::Env &_env;
|
||||||
Genode::Rpc_entrypoint &_device_pd_ep;
|
|
||||||
Genode::Attached_rom_dataspace &_config;
|
Genode::Attached_rom_dataspace &_config;
|
||||||
Genode::Ram_session_guard _env_ram;
|
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::Heap _md_alloc;
|
||||||
Genode::Session_label const _label;
|
Genode::Session_label const _label;
|
||||||
Genode::Session_policy const _policy { _label, _config.xml() };
|
Genode::Session_policy const _policy { _label, _config.xml() };
|
||||||
@ -237,145 +232,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
Platform::Device_pd _device_pd { _env, _label };
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES *
|
enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES *
|
||||||
Device_config::MAX_DEVICES *
|
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;
|
static Genode::Bit_array<MAX_PCI_DEVICES> bdf_in_use;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List containing extended PCI config space information
|
* 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;
|
static Genode::List<Config_space> config_space;
|
||||||
return 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.
|
* the corresponding extended 4K PCI config space address.
|
||||||
* A io mem dataspace is created and returned.
|
* A io mem dataspace is created and returned.
|
||||||
*/
|
*/
|
||||||
Genode::addr_t
|
Genode::addr_t lookup_config_space(Genode::uint16_t const bdf)
|
||||||
lookup_config_space(Genode::uint16_t const bdf)
|
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
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
|
* List of aliases for PCI Class/Subclas/Prog I/F triple used
|
||||||
* by xml config for this platform driver
|
* by xml config for this platform driver
|
||||||
*/
|
*/
|
||||||
unsigned class_subclass_prog(const char * name) {
|
unsigned class_subclass_prog(const char * name)
|
||||||
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
@ -591,18 +447,13 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
|
|||||||
*/
|
*/
|
||||||
Session_component(Genode::Env &env,
|
Session_component(Genode::Env &env,
|
||||||
Genode::Attached_rom_dataspace &config,
|
Genode::Attached_rom_dataspace &config,
|
||||||
Genode::Rpc_entrypoint &device_pd_ep,
|
|
||||||
Platform::Pci_buses &buses,
|
Platform::Pci_buses &buses,
|
||||||
Genode::Heap &global_heap,
|
Genode::Heap &global_heap,
|
||||||
char const *args)
|
char const *args)
|
||||||
:
|
:
|
||||||
_env(env), _device_pd_ep(device_pd_ep),
|
_env(env),
|
||||||
_config(config),
|
_config(config),
|
||||||
_env_ram(env.ram(), Genode::ram_quota_from_args(args).value),
|
_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()),
|
_md_alloc(_env_ram, env.rm()),
|
||||||
_label(Genode::label_from_args(args)),
|
_label(Genode::label_from_args(args)),
|
||||||
_pci_bus(buses), _global_heap(global_heap)
|
_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();
|
Io_mem_dataspace_capability io_mem = device->get_config_space();
|
||||||
|
|
||||||
_try_init_device_pd();
|
|
||||||
if (!_device_pd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
try {
|
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()) {
|
for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
|
||||||
Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config());
|
Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config());
|
||||||
if (rmrr_cap.valid())
|
if (rmrr_cap.valid())
|
||||||
_device_pd->session().attach_dma_mem(rmrr_cap);
|
_device_pd.attach_dma_mem(rmrr_cap);
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
Genode::error("assignment to device pd or of RMRR region failed");
|
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
|
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;
|
Ram_capability ram_cap;
|
||||||
|
|
||||||
try { ram_cap = _env_ram.alloc(size, Genode::UNCACHED); }
|
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())
|
if (!ram_cap.valid())
|
||||||
return ram_cap;
|
return ram_cap;
|
||||||
|
|
||||||
if (_device_pd) {
|
try { _device_pd.attach_dma_mem(ram_cap); }
|
||||||
try { _device_pd->session().attach_dma_mem(ram_cap); }
|
catch (Out_of_ram) { _rollback(size, ram_cap);; }
|
||||||
catch (Out_of_ram) { _rollback(size, ram_cap);; }
|
catch (Out_of_caps) {
|
||||||
catch (Out_of_caps) {
|
Genode::warning("Out_of_caps while attaching DMA memory");
|
||||||
Genode::warning("Out_of_caps while attaching DMA memory");
|
_rollback(size, ram_cap);;
|
||||||
_rollback(size, ram_cap);;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try { _insert(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::Reporter _pci_reporter { _env, "pci" };
|
||||||
|
|
||||||
Genode::Rpc_entrypoint _device_pd_ep;
|
|
||||||
Genode::Heap _heap { _env.ram(), _env.rm() };
|
Genode::Heap _heap { _env.ram(), _env.rm() };
|
||||||
Platform::Pci_buses _buses { _env, _heap };
|
Platform::Pci_buses _buses { _env, _heap };
|
||||||
|
|
||||||
@ -1061,7 +898,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (node.has_type("rmrr")) {
|
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("start").value(&mem_start);
|
||||||
node.attribute("end").value(&mem_end);
|
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"))
|
if (!scope.num_sub_nodes() || !scope.has_type("scope"))
|
||||||
throw 3;
|
throw 3;
|
||||||
|
|
||||||
unsigned bus, dev, func;
|
unsigned bus = 0, dev = 0, func = 0;
|
||||||
scope.attribute("bus_start").value(&bus);
|
scope.attribute("bus_start").value(&bus);
|
||||||
|
|
||||||
for (unsigned p = 0; p < scope.num_sub_nodes(); p++) {
|
for (unsigned p = 0; p < scope.num_sub_nodes(); p++) {
|
||||||
@ -1152,7 +989,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return new (md_alloc())
|
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) {
|
catch (Genode::Session_policy::No_policy_defined) {
|
||||||
Genode::error("Invalid session request, no matching policy for ",
|
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(),
|
Genode::Root_component<Session_component>(&env.ep().rpc_ep(),
|
||||||
&md_alloc),
|
&md_alloc),
|
||||||
_env(env), _config(config),
|
_env(env), _config(config)
|
||||||
_device_pd_ep(&env.pd(), STACK_SIZE, "device_pd_slave")
|
|
||||||
{
|
{
|
||||||
if (acpi_rom) {
|
if (acpi_rom) {
|
||||||
try {
|
try {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
TARGET = platform_drv
|
TARGET = platform_drv
|
||||||
REQUIRES = x86
|
REQUIRES = x86
|
||||||
SRC_CC = main.cc irq.cc pci_device.cc nonpci_devices.cc session.cc
|
SRC_CC = main.cc irq.cc pci_device.cc nonpci_devices.cc session.cc
|
||||||
|
SRC_CC += device_pd.cc
|
||||||
LIBS = base
|
LIBS = base
|
||||||
|
|
||||||
INC_DIR = $(PRG_DIR)
|
INC_DIR = $(PRG_DIR)
|
||||||
|
Loading…
Reference in New Issue
Block a user