From fe4bdde68730731bb13a0fcf9aa08443aef881d2 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 2 Aug 2017 14:41:51 +0200 Subject: [PATCH] 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 --- .../base-nova/src/core/pd_session_support.cc | 62 +++++++++++++++++- .../src/core/include/region_map_component.h | 9 +++ repos/base/src/core/region_map_component.cc | 63 +++++++++++-------- 3 files changed, 108 insertions(+), 26 deletions(-) diff --git a/repos/base-nova/src/core/pd_session_support.cc b/repos/base-nova/src/core/pd_session_support.cc index fe253c4beb..3cc6e12f1d 100644 --- a/repos/base-nova/src/core/pd_session_support.cc +++ b/repos/base-nova/src/core/pd_session_support.cc @@ -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(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(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; + } +} diff --git a/repos/base/src/core/include/region_map_component.h b/repos/base/src/core/include/region_map_component.h index d28420ee70..2140a692d7 100644 --- a/repos/base/src/core/include/region_map_component.h +++ b/repos/base/src/core/include/region_map_component.h @@ -399,6 +399,15 @@ class Genode::Region_map_component : public Genode::Weak_objectmap_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,