nova: implement Pd_session::map

- factor out Rm_client::pager lambda code into utility
  Region_map_component::create_map_item
- use utility to find/lookup physical addresses to be mapped eagerly

Issue #2209
This commit is contained in:
Alexander Boettcher
2017-08-02 14:41:51 +02:00
committed by Christian Helmuth
parent 58e4f6cf9d
commit fe4bdde687
3 changed files with 108 additions and 26 deletions

View File

@@ -32,4 +32,64 @@ bool Pd_session_component::assign_pci(addr_t pci_config_memory, uint16_t bdf)
}
void Pd_session_component::map(addr_t, addr_t) { }
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 ds_offset,
addr_t region_offset) -> addr_t
{
Dataspace_component * dsc = region ? region->dataspace() : nullptr;
if (!dsc)
return ~0UL;
Mapping mapping = Region_map_component::create_map_item(region_map,
region,
ds_offset,
region_offset,
dsc, virt);
/* 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;
/* receive window in destination pd */
Nova::Mem_crd crd_mem(mapping.dst_addr() >> 12,
mapping.mem_crd().order(),
Nova::Rights(true, dsc->writable(), true));
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;
};
while (size) {
addr_t mapped = _address_space.apply_to_dataspace(virt, lambda);
virt += mapped;
size = size < mapped ? size - mapped : 0;
}
}

View File

@@ -399,6 +399,15 @@ class Genode::Region_map_component : public Genode::Weak_object<Genode::Region_m
void add_client(Rm_client &);
void remove_client(Rm_client &);
/**
* Create mapping item to be placed into the page table
*/
static Mapping create_map_item(Region_map_component *region_map,
Rm_region *region,
addr_t ds_offset,
addr_t region_offset,
Dataspace_component *dsc,
addr_t);
/**************************
** Region map interface **

View File

@@ -171,8 +171,6 @@ static void print_page_fault(char const *msg,
int Rm_client::pager(Ipc_pager &pager)
{
using Fault_area = Region_map_component::Fault_area;
Region_map::State::Fault_type pf_type = pager.write_fault() ? Region_map::State::WRITE_FAULT
: Region_map::State::READ_FAULT;
addr_t pf_addr = pager.fault_addr();
@@ -208,25 +206,6 @@ int Rm_client::pager(Ipc_pager &pager)
return 1;
}
addr_t ds_base = dsc->map_src_addr();
Fault_area src_fault_area(ds_base + ds_offset);
Fault_area dst_fault_area(pf_addr);
src_fault_area.constrain(ds_base, dsc->size());
dst_fault_area.constrain(region_offset + region->base(), region->size());
/*
* Determine mapping size compatible with source and destination,
* and apply platform-specific constraint of mapping sizes.
*/
size_t map_size_log2 = dst_fault_area.common_size_log2(dst_fault_area,
src_fault_area);
map_size_log2 = constrain_map_size_log2(map_size_log2);
src_fault_area.constrain(map_size_log2);
dst_fault_area.constrain(map_size_log2);
if (!src_fault_area.valid() || !dst_fault_area.valid())
error("invalid mapping");
/*
* Check if dataspace is compatible with page-fault type
*/
@@ -237,13 +216,15 @@ int Rm_client::pager(Ipc_pager &pager)
pf_addr, pf_ip, pf_type, *this);
/* register fault at responsible region map */
region_map->fault(this, src_fault_area.fault_addr(), pf_type);
region_map->fault(this, dsc->map_src_addr() + ds_offset, pf_type);
return 2;
}
Mapping mapping(dst_fault_area.base(), src_fault_area.base(),
dsc->cacheability(), dsc->io_mem(),
map_size_log2, dsc->writable());
Mapping mapping = Region_map_component::create_map_item(region_map,
region,
ds_offset,
region_offset,
dsc, pf_addr);
/*
* On kernels with a mapping database, the 'dsc' dataspace is a leaf
@@ -313,6 +294,38 @@ void Rm_faulter::continue_after_resolved_fault()
** Region-map component **
**************************/
Mapping Region_map_component::create_map_item(Region_map_component *region_map,
Rm_region *region,
addr_t ds_offset,
addr_t region_offset,
Dataspace_component *dsc,
addr_t page_addr)
{
addr_t ds_base = dsc->map_src_addr();
Fault_area src_fault_area(ds_base + ds_offset);
Fault_area dst_fault_area(page_addr);
src_fault_area.constrain(ds_base, dsc->size());
dst_fault_area.constrain(region_offset + region->base(), region->size());
/*
* Determine mapping size compatible with source and destination,
* and apply platform-specific constraint of mapping sizes.
*/
size_t map_size_log2 = dst_fault_area.common_size_log2(dst_fault_area,
src_fault_area);
map_size_log2 = constrain_map_size_log2(map_size_log2);
src_fault_area.constrain(map_size_log2);
dst_fault_area.constrain(map_size_log2);
if (!src_fault_area.valid() || !dst_fault_area.valid())
error("invalid mapping");
return Mapping(dst_fault_area.base(), src_fault_area.base(),
dsc->cacheability(), dsc->io_mem(),
map_size_log2, dsc->writable());
};
Region_map::Local_addr
Region_map_component::attach(Dataspace_capability ds_cap, size_t size,
off_t offset, bool use_local_addr,