From 2e62543fdb02a17f7fc263a4de6830a749973e10 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 29 Sep 2015 22:03:03 +0200 Subject: [PATCH] nova: use remote revoke Fixes #1733 --- repos/base-nova/src/core/core_rm_session.cc | 52 ++++++++++++++++++- .../src/core/include/core_rm_session.h | 23 +++----- repos/base-nova/src/core/include/platform.h | 33 +++++++----- .../base-nova/src/core/include/platform_pd.h | 8 +-- repos/base-nova/src/core/include/util.h | 5 +- .../src/core/io_mem_session_support.cc | 4 +- repos/base-nova/src/core/ipc_pager.cc | 2 +- repos/base-nova/src/core/platform.cc | 37 +++++++++---- repos/base-nova/src/core/platform_pd.cc | 17 ++++++ .../base-nova/src/core/ram_session_support.cc | 51 +++++++----------- .../base-nova/src/core/rm_session_support.cc | 19 +++---- repos/base/src/core/core_mem_alloc.cc | 2 +- repos/base/src/core/rm_session_component.cc | 4 +- repos/ports/include/vmm/vcpu_thread.h | 4 +- 14 files changed, 165 insertions(+), 96 deletions(-) diff --git a/repos/base-nova/src/core/core_rm_session.cc b/repos/base-nova/src/core/core_rm_session.cc index 34965ffa8..212949737 100644 --- a/repos/base-nova/src/core/core_rm_session.cc +++ b/repos/base-nova/src/core/core_rm_session.cc @@ -25,6 +25,27 @@ using namespace Genode; +/** + * Map dataspace core-locally + */ +static inline void * alloc_region(Dataspace_component *ds, const size_t size) +{ + /* + * Allocate range in core's virtual address space + * + * Start with trying to use natural alignment. If this does not work, + * successively weaken the alignment constraint until we hit the page size. + */ + void *virt_addr = 0; + size_t align_log2 = log2(ds->size()); + for (; align_log2 >= get_page_size_log2(); align_log2--) { + if (platform()->region_alloc()->alloc_aligned(size, + &virt_addr, align_log2).is_ok()) + break; + } + + return virt_addr; +} Rm_session::Local_addr Core_rm_session::attach(Dataspace_capability ds_cap, size_t size, @@ -46,8 +67,35 @@ Core_rm_session::attach(Dataspace_capability ds_cap, size_t size, return nullptr; } - /* allocate range in core's virtual address space */ - return ds->core_local_addr(); + const size_t page_rounded_size = align_addr(ds->size(), get_page_size_log2()); + + /* allocate the virtual region contiguous for the dataspace */ + void * virt_ptr = alloc_region(ds, page_rounded_size); + if (!virt_ptr) + throw Out_of_metadata(); + + /* map it */ + Nova::Utcb * const utcb = reinterpret_cast(Thread_base::myself()->utcb()); + const Nova::Rights rights(true, ds->writable(), executable); + + if (map_local(utcb, ds->phys_addr(), reinterpret_cast(virt_ptr), + page_rounded_size >> get_page_size_log2(), rights, true)) { + platform()->region_alloc()->free(virt_ptr, page_rounded_size); + throw Out_of_metadata(); + } + + return virt_ptr; }; return _ds_ep->apply(ds_cap, lambda); } + + +void Core_rm_session::detach(Local_addr core_local_addr) +{ + size_t size = platform_specific()->region_alloc_size_at(core_local_addr); + + unmap_local(reinterpret_cast(Thread_base::myself()->utcb()), + core_local_addr, size >> get_page_size_log2()); + + platform()->region_alloc()->free(core_local_addr); +} diff --git a/repos/base-nova/src/core/include/core_rm_session.h b/repos/base-nova/src/core/include/core_rm_session.h index 5c0642a3b..ed7c48466 100644 --- a/repos/base-nova/src/core/include/core_rm_session.h +++ b/repos/base-nova/src/core/include/core_rm_session.h @@ -35,28 +35,21 @@ namespace Genode { Local_addr attach(Dataspace_capability ds_cap, size_t size=0, off_t offset=0, bool use_local_addr = false, Local_addr local_addr = 0, - bool executable = false); + bool executable = false) override; - void detach(Local_addr) - { - /* - * The core-local mapping gets established in - * 'Ram_session_component::_clear_ds()' and reverted in - * 'Ram_session_component::_revoke_ram_ds(), so there's - * nothing to do here. - */ - } + void detach(Local_addr) override; - Pager_capability add_client(Thread_capability thread) { + Pager_capability add_client(Thread_capability thread) override { return Pager_capability(); } - void remove_client(Pager_capability) { } + void remove_client(Pager_capability) override { } - void fault_handler(Signal_context_capability handler) { } + void fault_handler(Signal_context_capability handler) override { } - State state() { return State(); } + State state() override { return State(); } - Dataspace_capability dataspace() { return Dataspace_capability(); } + Dataspace_capability dataspace() override { + return Dataspace_capability(); } }; } diff --git a/repos/base-nova/src/core/include/platform.h b/repos/base-nova/src/core/include/platform.h index 5c121f7e3..f804af2aa 100644 --- a/repos/base-nova/src/core/include/platform.h +++ b/repos/base-nova/src/core/include/platform.h @@ -57,20 +57,22 @@ namespace Genode { ** Generic platform interface ** ********************************/ - Range_allocator *ram_alloc() { return _core_mem_alloc.phys_alloc(); } - Range_allocator *io_mem_alloc() { return &_io_mem_alloc; } - Range_allocator *io_port_alloc() { return &_io_port_alloc; } - Range_allocator *irq_alloc() { return &_irq_alloc; } - Range_allocator *region_alloc() { return _core_mem_alloc.virt_alloc(); } - Range_allocator *core_mem_alloc() { return &_core_mem_alloc; } - addr_t vm_start() const { return _vm_base; } - size_t vm_size() const { return _vm_size; } - Rom_fs *rom_fs() { return &_rom_fs; } + Range_allocator *ram_alloc() override { return _core_mem_alloc.phys_alloc(); } + Range_allocator *io_mem_alloc() override { return &_io_mem_alloc; } + Range_allocator *io_port_alloc() override { return &_io_port_alloc; } + Range_allocator *irq_alloc() override { return &_irq_alloc; } + Range_allocator *region_alloc() override { return _core_mem_alloc.virt_alloc(); } + Range_allocator *core_mem_alloc() override { return &_core_mem_alloc; } + addr_t vm_start() const override { return _vm_base; } + size_t vm_size() const override { return _vm_size; } + Rom_fs *rom_fs() override { return &_rom_fs; } - void wait_for_exit(); - bool supports_unmap() { return true; } + void wait_for_exit() override; + bool supports_unmap() override { return true; } + bool supports_direct_unmap() const override { return true; } - Affinity::Space affinity_space() const { return _cpus; } + + Affinity::Space affinity_space() const override { return _cpus; } /******************* @@ -81,6 +83,13 @@ namespace Genode { * Return capability selector of first global system interrupt */ int gsi_base_sel() const { return _gsi_base_sel; } + + /** + * Determine size of a core local mapping required for a + * core_rm_session detach(). + */ + size_t region_alloc_size_at(void * addr) { + return (*_core_mem_alloc.virt_alloc())()->size_at(addr); } }; } diff --git a/repos/base-nova/src/core/include/platform_pd.h b/repos/base-nova/src/core/include/platform_pd.h index 918ec5739..c22424c44 100644 --- a/repos/base-nova/src/core/include/platform_pd.h +++ b/repos/base-nova/src/core/include/platform_pd.h @@ -83,7 +83,7 @@ namespace Genode { * * \return PD selector */ - addr_t pd_sel() { return _pd_sel; } + addr_t pd_sel() const { return _pd_sel; } /** * Capability selector of core protection domain @@ -97,11 +97,7 @@ namespace Genode { ** Address-space interface ** *****************************/ - /* - * On NOVA, we don't use directed unmap but rely on the - * in-kernel mapping database. See 'rm_session_support.cc'. - */ - void flush(addr_t, size_t) { PDBG("not implemented"); } + void flush(addr_t, size_t); }; } diff --git a/repos/base-nova/src/core/include/util.h b/repos/base-nova/src/core/include/util.h index 84eb0993e..3e24d0882 100644 --- a/repos/base-nova/src/core/include/util.h +++ b/repos/base-nova/src/core/include/util.h @@ -22,14 +22,13 @@ namespace Genode { constexpr size_t get_page_size_log2() { return 12; } constexpr size_t get_page_size() { return 1 << get_page_size_log2(); } - constexpr addr_t get_page_mask() { return ~(get_page_size() - 1); } constexpr size_t get_super_page_size_log2() { return 22; } constexpr size_t get_super_page_size() { return 1 << get_super_page_size_log2(); } - inline addr_t trunc_page(addr_t addr) { return addr & get_page_mask(); } + inline addr_t trunc_page(addr_t addr) { return addr & _align_mask(get_page_size_log2()); } inline addr_t round_page(addr_t addr) { return trunc_page(addr + get_page_size() - 1); } - inline addr_t map_src_addr(addr_t core_local, addr_t phys) { return core_local; } + inline addr_t map_src_addr(addr_t core_local, addr_t phys) { return phys; } inline size_t constrain_map_size_log2(size_t size_log2) { return size_log2; } diff --git a/repos/base-nova/src/core/io_mem_session_support.cc b/repos/base-nova/src/core/io_mem_session_support.cc index 02aa8401d..43b9c0d88 100644 --- a/repos/base-nova/src/core/io_mem_session_support.cc +++ b/repos/base-nova/src/core/io_mem_session_support.cc @@ -23,7 +23,7 @@ using namespace Genode; void Io_mem_session_component::_unmap_local(addr_t base, size_t size) { - size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); + size_t page_rounded_size = align_addr(size, get_page_size_log2()); Nova::Rights rwx(true, true, true); int count = page_rounded_size >> 12; @@ -35,7 +35,7 @@ void Io_mem_session_component::_unmap_local(addr_t base, size_t size) addr_t Io_mem_session_component::_map_local(addr_t base, size_t size) { - size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); + size_t page_rounded_size = align_addr(size, get_page_size_log2()); /* align large I/O dataspaces on a super-page boundary within core */ size_t alignment = (size >= get_super_page_size()) ? get_super_page_size_log2() diff --git a/repos/base-nova/src/core/ipc_pager.cc b/repos/base-nova/src/core/ipc_pager.cc index 83bdc858f..dd49d7454 100644 --- a/repos/base-nova/src/core/ipc_pager.cc +++ b/repos/base-nova/src/core/ipc_pager.cc @@ -60,7 +60,7 @@ void Ipc_pager::set_reply_mapping(Mapping m) { Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); utcb->set_msg_word(0); - bool res = utcb->append_item(m.mem_crd(), m.dst_addr(), false, false, + bool res = utcb->append_item(m.mem_crd(), m.dst_addr(), true, false, false, m.dma(), m.write_combined()); /* one item ever fits on the UTCB */ (void)res; diff --git a/repos/base-nova/src/core/platform.cc b/repos/base-nova/src/core/platform.cc index 5a7662bdb..1c8574c03 100644 --- a/repos/base-nova/src/core/platform.cc +++ b/repos/base-nova/src/core/platform.cc @@ -521,11 +521,12 @@ Platform::Platform() : addr_t const rom_mem_size = rom_mem_end - rom_mem_start; bool const aux_in_rom_area = (rom_mem_start <= mem_desc->aux) && (mem_desc->aux < rom_mem_end); + addr_t const pages_mapped = (rom_mem_size >> get_page_size_log2()) + + (aux_in_rom_area ? 1 : 0); /* map ROM + extra page for the case aux crosses page boundary */ addr_t core_local_addr = _map_pages(rom_mem_start >> get_page_size_log2(), - (rom_mem_size >> get_page_size_log2()) + - (aux_in_rom_area ? 1 : 0)); + pages_mapped); if (!core_local_addr) { PERR("could not map multi boot module"); nova_die(); @@ -535,9 +536,8 @@ Platform::Platform() : core_local_addr += mem_desc->addr - rom_mem_start; if (verbose_boot_info) - printf("map multi-boot module: physical 0x%8lx -> [0x%8lx-0x%8lx)" - " - ", (addr_t)mem_desc->addr, (addr_t)core_local_addr, - (addr_t)(core_local_addr + mem_desc->size)); + printf("map multi-boot module: physical 0x%8lx+0x%8llx" + " - ", (addr_t)mem_desc->addr, mem_desc->size); char * name; if (aux_in_rom_area) { @@ -597,20 +597,35 @@ Platform::Platform() : printf("%s\n", name); - /* revoke write permission on rom module */ + /* revoke mapping of rom module - not needed */ unmap_local(__main_thread_utcb, trunc_page(core_local_addr), - rom_mem_size >> get_page_size_log2(), true, - Nova::Rights(false, true, false)); + pages_mapped); + region_alloc()->free(reinterpret_cast(trunc_page(core_local_addr)), + pages_mapped << get_page_size_log2()); /* create rom module */ Rom_module *rom_module = new (core_mem_alloc()) - Rom_module(core_local_addr, mem_desc->size, name); + Rom_module(rom_mem_start, mem_desc->size, name); _rom_fs.insert(rom_module); } /* export hypervisor info page as ROM module */ - _rom_fs.insert(new (core_mem_alloc()) - Rom_module((addr_t)hip, get_page_size(), "hypervisor_info_page")); + { + void * phys_ptr = 0; + ram_alloc()->alloc(get_page_size(), &phys_ptr); + addr_t phys_addr = reinterpret_cast(phys_ptr); + + addr_t core_local_addr = _map_pages(phys_addr >> get_page_size_log2(), 1); + + memcpy(reinterpret_cast(core_local_addr), hip, get_page_size()); + + unmap_local(__main_thread_utcb, core_local_addr, 1); + region_alloc()->free(reinterpret_cast(core_local_addr), get_page_size()); + + _rom_fs.insert(new (core_mem_alloc()) + Rom_module(phys_addr, get_page_size(), + "hypervisor_info_page")); + } /* I/O port allocator (only meaningful for x86) */ _io_port_alloc.add_range(0, 0x10000); diff --git a/repos/base-nova/src/core/platform_pd.cc b/repos/base-nova/src/core/platform_pd.cc index c9b31ce92..6f839e88b 100644 --- a/repos/base-nova/src/core/platform_pd.cc +++ b/repos/base-nova/src/core/platform_pd.cc @@ -13,6 +13,7 @@ /* Genode includes */ #include +#include /* core includes */ #include @@ -62,3 +63,19 @@ Platform_pd::~Platform_pd() Nova::revoke(Nova::Obj_crd(_pd_sel, 0)); cap_map()->remove(_pd_sel, 0, false); } + + +void Platform_pd::flush(addr_t remote_virt, size_t size) +{ + Nova::Rights const revoke_rwx(true, true, true); + + Flexpage_iterator flex(remote_virt, size, remote_virt, size, 0); + Flexpage page = flex.page(); + + while (page.valid()) { + Nova::Mem_crd mem(page.addr >> 12, page.log2_order - 12, revoke_rwx); + Nova::revoke(mem, true, true, pd_sel()); + + page = flex.page(); + } +} diff --git a/repos/base-nova/src/core/ram_session_support.cc b/repos/base-nova/src/core/ram_session_support.cc index 4a1872933..f504bc13e 100644 --- a/repos/base-nova/src/core/ram_session_support.cc +++ b/repos/base-nova/src/core/ram_session_support.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2009-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -24,31 +24,12 @@ /* NOVA includes */ #include -enum { verbose_ram_ds = false }; - using namespace Genode; -void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) -{ - size_t page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask(); - - if (verbose_ram_ds) - printf("-- revoke - ram ds size=0x%8zx phys 0x%8lx has core-local addr 0x%8lx - thread 0x%8p\n", - page_rounded_size, ds->phys_addr(), ds->core_local_addr(), Thread_base::myself()->utcb()); - - unmap_local((Nova::Utcb *)Thread_base::myself()->utcb(), - ds->core_local_addr(), - page_rounded_size >> get_page_size_log2()); - - platform()->region_alloc()->free((void*)ds->core_local_addr(), - page_rounded_size); -} +void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds) { } -/** - * Map dataspace core-locally - */ static inline void * alloc_region(Dataspace_component *ds, const size_t size) { /* @@ -71,33 +52,41 @@ static inline void * alloc_region(Dataspace_component *ds, const size_t size) void Ram_session_component::_clear_ds(Dataspace_component *ds) { - memset((void *)ds->core_local_addr(), 0, ds->size()); + size_t page_rounded_size = align_addr(ds->size(), get_page_size_log2()); + + memset((void *)ds->core_local_addr(), 0, page_rounded_size); + + /* we don't keep any core-local mapping */ + unmap_local(reinterpret_cast(Thread_base::myself()->utcb()), + ds->core_local_addr(), + page_rounded_size >> get_page_size_log2()); + + platform()->region_alloc()->free((void*)ds->core_local_addr(), + page_rounded_size); + + ds->assign_core_local_addr(nullptr); } void Ram_session_component::_export_ram_ds(Dataspace_component *ds) { - const size_t page_rounded_size = (ds->size() + get_page_size() - 1) & get_page_mask(); + size_t page_rounded_size = align_addr(ds->size(), get_page_size_log2()); /* allocate the virtual region contiguous for the dataspace */ void * virt_ptr = alloc_region(ds, page_rounded_size); if (!virt_ptr) throw Out_of_metadata(); - /* map it */ + /* map it writeable for _clear_ds */ Nova::Utcb * const utcb = reinterpret_cast(Thread_base::myself()->utcb()); - const Nova::Rights rights(true, ds->writable(), true); + const Nova::Rights rights_rw(true, true, false); if (map_local(utcb, ds->phys_addr(), reinterpret_cast(virt_ptr), - page_rounded_size >> get_page_size_log2(), rights, true)) { + page_rounded_size >> get_page_size_log2(), rights_rw, true)) { platform()->region_alloc()->free(virt_ptr, page_rounded_size); throw Out_of_metadata(); } - /* we succeeded, so assign the virtual address to the dataspace */ + /* assign virtual address to the dataspace to be used by clear_ds */ ds->assign_core_local_addr(virt_ptr); - - if (verbose_ram_ds) - printf("-- map - ram ds size=0x%8zx phys 0x%8lx has core-local addr 0x%8lx\n", - page_rounded_size, ds->phys_addr(), ds->core_local_addr()); } diff --git a/repos/base-nova/src/core/rm_session_support.cc b/repos/base-nova/src/core/rm_session_support.cc index e5d6b0617..b422106c8 100644 --- a/repos/base-nova/src/core/rm_session_support.cc +++ b/repos/base-nova/src/core/rm_session_support.cc @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2009-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -14,17 +14,18 @@ /* core includes */ #include -#include using namespace Genode; -void Rm_client::unmap(addr_t core_local_base, addr_t, size_t size) + +/*************** + ** Rm_client ** + ***************/ + +void Rm_client::unmap(addr_t, addr_t virt_base, size_t size) { - using namespace Nova; + Locked_ptr locked_address_space(_address_space); - Utcb * utcb = reinterpret_cast(Genode::Thread_base::myself()->utcb()); - - unmap_local(utcb, trunc_page(core_local_base), - (round_page(core_local_base + size) - - trunc_page(core_local_base)) / get_page_size(), false); + if (locked_address_space.is_valid()) + locked_address_space->flush(virt_base, size); } diff --git a/repos/base/src/core/core_mem_alloc.cc b/repos/base/src/core/core_mem_alloc.cc index 8d47bf9aa..4dc82ddb1 100644 --- a/repos/base/src/core/core_mem_alloc.cc +++ b/repos/base/src/core/core_mem_alloc.cc @@ -38,7 +38,7 @@ void * Mapped_avl_allocator::map_addr(void * addr) Range_allocator::Alloc_return Mapped_mem_allocator::alloc_aligned(size_t size, void **out_addr, int align, addr_t from, addr_t to) { - size_t page_rounded_size = (size + get_page_size() - 1) & get_page_mask(); + size_t page_rounded_size = align_addr(size, get_page_size_log2()); void *phys_addr = 0; align = max((size_t)align, get_page_size_log2()); diff --git a/repos/base/src/core/rm_session_component.cc b/repos/base/src/core/rm_session_component.cc index 853a253ad..ab6bdbe59 100644 --- a/repos/base/src/core/rm_session_component.cc +++ b/repos/base/src/core/rm_session_component.cc @@ -476,7 +476,7 @@ void Rm_session_component::detach(Local_addr local_addr) /* * Deallocate region on platforms that support unmap * - * On platforms without support for unmap (in particular NOVA 0.1), the + * On platforms without support for unmap, the * same virtual address must not be reused. Hence, we never mark used * regions as free. * @@ -513,7 +513,7 @@ void Rm_session_component::detach(Local_addr local_addr) /* * XXX Unmapping managed dataspaces on kernels, which take a core- * local virtual address as unmap argument is not supported yet. - * This is the case for Fiasco, Pistachio, and NOVA. On those + * This is the case for Fiasco and Pistachio. On those * kernels, the unmap operation must be issued for each leaf * dataspace the managed dataspace is composed of. For kernels with * support for directed unmap (OKL4), unmap can be diff --git a/repos/ports/include/vmm/vcpu_thread.h b/repos/ports/include/vmm/vcpu_thread.h index 037acbdae..f43bdfb23 100644 --- a/repos/ports/include/vmm/vcpu_thread.h +++ b/repos/ports/include/vmm/vcpu_thread.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace Vmm { @@ -46,6 +47,7 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread Genode::Pd_connection _pd_session; Genode::Affinity::Location _location; Genode::Cpu_session *_cpu_session; + Genode::Rm_connection _rm; Genode::addr_t _exc_pt_sel; @@ -70,7 +72,7 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread _pd_session.bind_thread(vcpu_vm); /* create new pager object and assign it to the new thread */ - Pager_capability pager_cap = env()->rm_session()->add_client(vcpu_vm); + Pager_capability pager_cap = _rm.add_client(vcpu_vm); _cpu_session->set_pager(vcpu_vm, pager_cap);