genode/repos/os/src/drivers/platform/spec/x86/device_pd.h
Reto Buerki 47724c68c2 platform_drv/x86: Switch to ECAM/MMCONF
Switch port I/O based PCI config space access to memory-mapped IO.  The
base address of the PCI configuration space is acquired by mapping the
ACPI ROM and reading the first <bdf> node. An exception is thrown if the
first <bdf> node is not for PCI domain zero or if multiple <bdf> nodes
exist. This is to reduce complexity and also because multiple PCI
domains are rare.

The PCI configuration space is accessed via I/O mem dataspace which is
created in the platform_drv root and then passed on to the PCI session,
device components and finally to the actual PCI config access instances.

The memory access code is implemented in a way to make it work with Muen
subject monitor (SM) device emulation and also general x86 targets. On
Muen, the simplified device emulation code (which works also for Linux)
always returns 0xffff in EAX to indicate a non-existing device.
Therefore, EAX is enforced in the assembly templates.

Fixes #2547
2018-03-29 14:59:04 +02:00

115 lines
3.4 KiB
C++

/*
* \brief Device PD handling for the platform driver
* \author Alexander Boettcher
*/
/*
* Copyright (C) 2014-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
/* base */
#include <base/env.h>
#include <base/quota_guard.h>
#include <region_map/client.h>
#include <pd_session/connection.h>
/* os */
#include <io_mem_session/connection.h>
namespace Platform { class Device_pd; }
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;
Genode::Pd_connection &_pd;
Genode::Ram_quota_guard &_ram_guard;
Genode::Cap_quota_guard &_cap_guard;
Expanding_region_map_client(Genode::Env &env,
Genode::Pd_connection &pd,
Genode::Ram_quota_guard &ram_guard,
Genode::Cap_quota_guard &cap_guard)
:
Region_map_client(pd.address_space()), _env(env), _pd(pd),
_ram_guard(ram_guard), _cap_guard(cap_guard)
{ }
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 };
Genode::Cap_quota const caps { UPGRADE_CAP_QUOTA };
_cap_guard.withdraw(caps);
_env.pd().transfer_quota(_pd, caps);
}
);
},
[&] () {
enum { UPGRADE_RAM_QUOTA = 4096 };
Genode::Ram_quota const ram { UPGRADE_RAM_QUOTA };
_ram_guard.withdraw(ram);
_env.pd().transfer_quota(_pd, ram);
}
);
}
Local_addr attach_at(Genode::Dataspace_capability ds,
Genode::addr_t local_addr,
Genode::size_t size = 0,
Genode::off_t offset = 0) {
return attach(ds, size, offset, true, local_addr); };
} _address_space;
public:
Device_pd(Genode::Env &env,
Genode::Session_label const &label,
Genode::Ram_quota_guard &ram_guard,
Genode::Cap_quota_guard &cap_guard)
:
_pd(env, label.string(), Genode::Pd_connection::Virt_space::UNCONSTRAIN),
_label(label),
_address_space(env, _pd, ram_guard, cap_guard)
{
_pd.ref_account(env.pd_session_cap());
}
void attach_dma_mem(Genode::Dataspace_capability);
void assign_pci(Genode::Io_mem_dataspace_capability const,
Genode::addr_t const, Genode::uint16_t const);
};