genode/repos/os/src/drivers/platform/spec/x86/device_pd.cc
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

104 lines
2.7 KiB
C++

/*
* \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 const io_mem_cap,
Genode::addr_t const offset,
Genode::uint16_t const rid)
{
using namespace Genode;
Dataspace_client ds_client(io_mem_cap);
addr_t page = _address_space.attach(io_mem_cap, 0x1000, offset);
/* sanity check */
if (!page)
throw Region_map::Region_conflict();
/* trigger eager mapping of memory */
_pd.map(page, 0x1000);
/* 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() + offset), " "
"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);
}