111 lines
3.8 KiB
C++
111 lines
3.8 KiB
C++
/*
|
|
* \brief Extension of core implementation of the PD session interface
|
|
* \author Alexander Boettcher
|
|
* \date 2013-01-11
|
|
*/
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
/* core */
|
|
#include <pd_session_component.h>
|
|
#include <assertion.h>
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
bool Pd_session_component::assign_pci(addr_t pci_config_memory, uint16_t bdf)
|
|
{
|
|
uint8_t res = Nova::NOVA_PD_OOM;
|
|
do {
|
|
res = Nova::assign_pci(_pd->pd_sel(), pci_config_memory, bdf);
|
|
} while (res == Nova::NOVA_PD_OOM &&
|
|
Nova::NOVA_OK == Pager_object::handle_oom(Pager_object::SRC_CORE_PD,
|
|
_pd->pd_sel(),
|
|
"core", "ep",
|
|
Pager_object::Policy::UPGRADE_CORE_TO_DST));
|
|
|
|
return res == Nova::NOVA_OK;
|
|
}
|
|
|
|
|
|
void Pd_session_component::map(addr_t virt, addr_t size)
|
|
{
|
|
Genode::addr_t const pd_core = platform_specific().core_pd_sel();
|
|
Platform_pd &target_pd = *_pd;
|
|
Genode::addr_t const pd_dst = target_pd.pd_sel();
|
|
Nova::Utcb &utcb = *reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb());
|
|
|
|
auto lambda = [&] (Region_map_component *region_map,
|
|
Rm_region *region,
|
|
addr_t const ds_offset,
|
|
addr_t const region_offset,
|
|
addr_t const dst_region_size) -> addr_t
|
|
{
|
|
Dataspace_component * dsc = region ? ®ion->dataspace() : nullptr;
|
|
if (!dsc) {
|
|
struct No_dataspace{};
|
|
throw No_dataspace();
|
|
}
|
|
if (!region_map) {
|
|
ASSERT_NEVER_CALLED;
|
|
}
|
|
|
|
Mapping mapping = Region_map_component::create_map_item(region_map,
|
|
*region,
|
|
ds_offset,
|
|
region_offset,
|
|
*dsc, virt,
|
|
dst_region_size);
|
|
|
|
/* asynchronously map memory */
|
|
uint8_t err = Nova::NOVA_PD_OOM;
|
|
do {
|
|
utcb.set_msg_word(0);
|
|
bool res = utcb.append_item(mapping.mem_crd(), 0, true, false,
|
|
false, mapping.dma(),
|
|
mapping.write_combined());
|
|
/* one item ever fits on the UTCB */
|
|
(void)res;
|
|
|
|
Nova::Rights const map_rights (true,
|
|
region->write() && dsc->writable(),
|
|
region->executable());
|
|
|
|
/* receive window in destination pd */
|
|
Nova::Mem_crd crd_mem(mapping.dst_addr() >> 12,
|
|
mapping.mem_crd().order(), map_rights);
|
|
|
|
err = Nova::delegate(pd_core, pd_dst, crd_mem);
|
|
} while (err == Nova::NOVA_PD_OOM &&
|
|
Nova::NOVA_OK == Pager_object::handle_oom(Pager_object::SRC_CORE_PD,
|
|
_pd->pd_sel(),
|
|
"core", "ep",
|
|
Pager_object::Policy::UPGRADE_CORE_TO_DST));
|
|
|
|
addr_t const map_crd_size = 1UL << (mapping.mem_crd().order() + 12);
|
|
addr_t const mapped = mapping.dst_addr() + map_crd_size - virt;
|
|
|
|
if (err != Nova::NOVA_OK)
|
|
error("could not map memory ",
|
|
Hex_range<addr_t>(mapping.dst_addr(), map_crd_size) , " "
|
|
"eagerly error=", err);
|
|
|
|
return mapped;
|
|
};
|
|
|
|
try {
|
|
while (size) {
|
|
addr_t mapped = _address_space.apply_to_dataspace(virt, lambda);
|
|
virt += mapped;
|
|
size = size < mapped ? size : size - mapped;
|
|
}
|
|
} catch (...) {
|
|
error(__func__, " failed ", Hex(virt), "+", Hex(size));
|
|
}
|
|
}
|