From e6d20aba935d688dc8e71b677b8e6830fb38271a Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 8 May 2018 11:21:10 +0200 Subject: [PATCH] base: support to attach RAM dataspaces readonly Fixes #1633 --- repos/base-hw/src/core/core_region_map.cc | 7 +-- repos/base-hw/src/core/spec/x86_64/cpu.cc | 2 +- .../src/core/include/region_map_component.h | 3 +- repos/base-linux/src/core/stack_area.cc | 11 +++-- .../include/base/internal/region_map_mmap.h | 21 +++++---- .../src/lib/base/region_map_client.cc | 4 +- .../src/lib/base/region_map_mmap.cc | 13 +++--- repos/base-nova/src/core/core_region_map.cc | 4 +- .../base-nova/src/core/pd_session_support.cc | 7 ++- .../src/lib/base/region_map_client.cc | 4 +- repos/base-okl4/src/core/core_region_map.cc | 2 +- repos/base-sel4/src/core/core_region_map.cc | 2 +- repos/base-sel4/src/core/stack_area.cc | 2 +- repos/base/include/region_map/client.h | 3 +- repos/base/include/region_map/region_map.h | 7 ++- repos/base/lib/symbols/ld | 2 +- repos/base/src/core/core_region_map.cc | 2 +- repos/base/src/core/include/core_region_map.h | 3 +- .../src/core/include/region_map_component.h | 3 +- repos/base/src/core/region_map_component.cc | 11 +++-- repos/base/src/core/stack_area.cc | 2 +- .../internal/expanding_region_map_client.h | 5 +- repos/base/src/lib/base/region_map_client.cc | 4 +- repos/base/src/test/rm_fault/main.cc | 46 +++++++++++++------ .../src/drivers/platform/spec/x86/device_pd.h | 6 ++- .../app/gdb_monitor/region_map_component.cc | 4 +- .../app/gdb_monitor/region_map_component.h | 3 +- repos/ports/src/noux/region_map_component.h | 11 +++-- repos/ports/src/virtualbox/mm.h | 6 ++- 29 files changed, 122 insertions(+), 78 deletions(-) diff --git a/repos/base-hw/src/core/core_region_map.cc b/repos/base-hw/src/core/core_region_map.cc index 04757feca..dd0f9663d 100644 --- a/repos/base-hw/src/core/core_region_map.cc +++ b/repos/base-hw/src/core/core_region_map.cc @@ -26,7 +26,7 @@ using namespace Genode; Region_map::Local_addr Core_region_map::attach(Dataspace_capability ds_cap, size_t size, off_t offset, bool use_local_addr, - Region_map::Local_addr, bool) + Region_map::Local_addr, bool, bool writeable) { auto lambda = [&] (Dataspace_component *ds) -> Local_addr { if (!ds) @@ -61,8 +61,9 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t size, /* map the dataspace's physical pages to corresponding virtual addresses */ unsigned num_pages = page_rounded_size >> get_page_size_log2(); - Page_flags const flags { ds->writable() ? RW : RO, NO_EXEC, KERN, - GLOBAL, ds->io_mem() ? DEVICE : RAM, + Page_flags const flags { (writeable && ds->writable()) ? RW : RO, + NO_EXEC, KERN, GLOBAL, + ds->io_mem() ? DEVICE : RAM, ds->cacheability() }; if (!map_local(ds->phys_addr(), (addr_t)virt_addr, num_pages, flags)) return nullptr; diff --git a/repos/base-hw/src/core/spec/x86_64/cpu.cc b/repos/base-hw/src/core/spec/x86_64/cpu.cc index 2be8b498b..9828f9c9e 100644 --- a/repos/base-hw/src/core/spec/x86_64/cpu.cc +++ b/repos/base-hw/src/core/spec/x86_64/cpu.cc @@ -94,8 +94,8 @@ void Genode::Cpu::mmu_fault(Context & regs, Kernel::Thread_fault & fault) }; auto fault_lambda = [] (addr_t err) { - if (!(err & ERR_P)) return Fault::PAGE_MISSING; if (err & ERR_W) return Fault::WRITE; + if (!(err & ERR_P)) return Fault::PAGE_MISSING; if (err & ERR_I) return Fault::EXEC; else return Fault::UNKNOWN; }; diff --git a/repos/base-linux/src/core/include/region_map_component.h b/repos/base-linux/src/core/include/region_map_component.h index b4b58ef94..65e105bd8 100644 --- a/repos/base-linux/src/core/include/region_map_component.h +++ b/repos/base-linux/src/core/include/region_map_component.h @@ -53,7 +53,8 @@ class Genode::Region_map_component : public Rpc_object, void add_client(Rm_client &) { } void remove_client(Rm_client &) { } - Local_addr attach(Dataspace_capability, size_t, off_t, bool, Local_addr, bool) { + Local_addr attach(Dataspace_capability, size_t, off_t, bool, + Local_addr, bool, bool) { return (addr_t)0; } void detach(Local_addr) { } diff --git a/repos/base-linux/src/core/stack_area.cc b/repos/base-linux/src/core/stack_area.cc index a19f688c6..4f24436bb 100644 --- a/repos/base-linux/src/core/stack_area.cc +++ b/repos/base-linux/src/core/stack_area.cc @@ -43,7 +43,8 @@ class Stack_area_region_map : public Genode::Region_map * Attach backing store to stack area */ Local_addr attach(Genode::Dataspace_capability, Genode::size_t size, - Genode::off_t, bool, Local_addr local_addr, bool) + Genode::off_t, bool, Local_addr local_addr, bool, + bool) override { using namespace Genode; @@ -61,17 +62,17 @@ class Stack_area_region_map : public Genode::Region_map return local_addr; } - void detach(Local_addr local_addr) + void detach(Local_addr local_addr) override { Genode::warning("stack area detach from ", (void*)local_addr, " - not implemented"); } - void fault_handler(Genode::Signal_context_capability) { } + void fault_handler(Genode::Signal_context_capability) override { } - State state() { return State(); } + State state() override { return State(); } - Genode::Dataspace_capability dataspace() { + Genode::Dataspace_capability dataspace() override { return Genode::Dataspace_capability(); } }; diff --git a/repos/base-linux/src/include/base/internal/region_map_mmap.h b/repos/base-linux/src/include/base/internal/region_map_mmap.h index b4181caf6..fa5b9d7e7 100644 --- a/repos/base-linux/src/include/base/internal/region_map_mmap.h +++ b/repos/base-linux/src/include/base/internal/region_map_mmap.h @@ -77,7 +77,8 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace bool use_local_addr, addr_t local_addr, bool executable, - bool overmap = false); + bool overmap, + bool writeable); /** * Determine size of dataspace @@ -115,25 +116,25 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace ** Region map interface ** **************************/ - Local_addr attach(Dataspace_capability ds, size_t size, - off_t, bool, Local_addr, bool executable); + Local_addr attach(Dataspace_capability, size_t size, off_t, bool, + Local_addr, bool, bool) override; - void detach(Local_addr local_addr); + void detach(Local_addr) override; - void fault_handler(Signal_context_capability) { } + void fault_handler(Signal_context_capability) override { } - State state() { return State(); } + State state() override { return State(); } /************************* ** Dataspace interface ** *************************/ - size_t size() { return _size; } + size_t size() override { return _size; } - addr_t phys_addr() { return 0; } + addr_t phys_addr() override { return 0; } - bool writable() { return true; } + bool writable() override { return true; } /** * Return pseudo dataspace capability of the RM session @@ -142,7 +143,7 @@ class Genode::Region_map_mmap : public Region_map, public Dataspace * as argument to 'Region_map_mmap::attach'. It is not a * real capability. */ - Dataspace_capability dataspace() { + Dataspace_capability dataspace() override { return Local_capability::local_cap(this); } }; diff --git a/repos/base-linux/src/lib/base/region_map_client.cc b/repos/base-linux/src/lib/base/region_map_client.cc index 5de6be48c..463c15707 100644 --- a/repos/base-linux/src/lib/base/region_map_client.cc +++ b/repos/base-linux/src/lib/base/region_map_client.cc @@ -39,10 +39,10 @@ Region_map::Local_addr Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset, bool use_local_addr, Region_map::Local_addr local_addr, - bool executable) + bool executable, bool writeable) { return _local(*this)->attach(ds, size, offset, use_local_addr, - local_addr, executable); + local_addr, executable, writeable); } diff --git a/repos/base-linux/src/lib/base/region_map_mmap.cc b/repos/base-linux/src/lib/base/region_map_mmap.cc index 01e811b1c..675ea95d1 100644 --- a/repos/base-linux/src/lib/base/region_map_mmap.cc +++ b/repos/base-linux/src/lib/base/region_map_mmap.cc @@ -123,10 +123,11 @@ void *Region_map_mmap::_map_local(Dataspace_capability ds, bool use_local_addr, addr_t local_addr, bool executable, - bool overmap) + bool overmap, + bool writeable) { int const fd = _dataspace_fd(ds); - bool const writable = _dataspace_writable(ds); + bool const writable = _dataspace_writable(ds) && writeable; int const flags = MAP_SHARED | (overmap ? MAP_FIXED : 0); int const prot = PROT_READ @@ -172,7 +173,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, size_t size, off_t offset, bool use_local_addr, Region_map::Local_addr local_addr, - bool executable) + bool executable, bool writeable) { Lock::Guard lock_guard(lock()); @@ -239,7 +240,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, * argument as the region was reserved by a PROT_NONE mapping. */ if (_is_attached()) - _map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true); + _map_local(ds, region_size, offset, true, _base + (addr_t)local_addr, executable, true, writeable); return (void *)local_addr; @@ -290,7 +291,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, */ _map_local(region.dataspace(), region.size(), region.offset(), true, rm->_base + region.start() + region.offset(), - executable, true); + executable, true, writeable); } return rm->_base; @@ -304,7 +305,7 @@ Region_map::Local_addr Region_map_mmap::attach(Dataspace_capability ds, * Note, we do not overmap. */ void *addr = _map_local(ds, region_size, offset, use_local_addr, - local_addr, executable); + local_addr, executable, false, writeable); _add_to_rmap(Region((addr_t)addr, offset, ds, region_size)); diff --git a/repos/base-nova/src/core/core_region_map.cc b/repos/base-nova/src/core/core_region_map.cc index 849b0694b..b7615e7bf 100644 --- a/repos/base-nova/src/core/core_region_map.cc +++ b/repos/base-nova/src/core/core_region_map.cc @@ -51,7 +51,7 @@ Region_map::Local_addr Core_region_map::attach(Dataspace_capability ds_cap, size_t, off_t offset, bool use_local_addr, Region_map::Local_addr, - bool executable) + bool executable, bool writeable) { auto lambda = [&] (Dataspace_component *ds) -> Local_addr { if (!ds) @@ -76,7 +76,7 @@ Core_region_map::attach(Dataspace_capability ds_cap, size_t, /* map it */ Nova::Utcb * const utcb = reinterpret_cast(Thread::myself()->utcb()); - const Nova::Rights rights(true, ds->writable(), executable); + const Nova::Rights rights(true, writeable && ds->writable(), executable); if (map_local(utcb, ds->phys_addr(), reinterpret_cast(virt_ptr), page_rounded_size >> get_page_size_log2(), rights, true)) { diff --git a/repos/base-nova/src/core/pd_session_support.cc b/repos/base-nova/src/core/pd_session_support.cc index ab340f276..a7299195a 100644 --- a/repos/base-nova/src/core/pd_session_support.cc +++ b/repos/base-nova/src/core/pd_session_support.cc @@ -66,10 +66,13 @@ void Pd_session_component::map(addr_t virt, addr_t size) /* 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(), - Nova::Rights(true, dsc->writable(), region->executable())); + mapping.mem_crd().order(), map_rights); err = Nova::delegate(pd_core, pd_dst, crd_mem); } while (err == Nova::NOVA_PD_OOM && diff --git a/repos/base-nova/src/lib/base/region_map_client.cc b/repos/base-nova/src/lib/base/region_map_client.cc index 5349d6c56..36ffeb0a3 100644 --- a/repos/base-nova/src/lib/base/region_map_client.cc +++ b/repos/base-nova/src/lib/base/region_map_client.cc @@ -24,10 +24,10 @@ Region_map_client::Region_map_client(Capability session) Region_map::Local_addr Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset, bool use_local_addr, Local_addr local_addr, - bool executable) + bool executable, bool writeable) { return call(ds, size, offset, use_local_addr, local_addr, - executable); + executable, writeable); } diff --git a/repos/base-okl4/src/core/core_region_map.cc b/repos/base-okl4/src/core/core_region_map.cc index 4b97f7224..14f322b35 100644 --- a/repos/base-okl4/src/core/core_region_map.cc +++ b/repos/base-okl4/src/core/core_region_map.cc @@ -22,7 +22,7 @@ using namespace Genode; Region_map::Local_addr Core_region_map::attach(Dataspace_capability ds_cap, size_t size, off_t offset, bool use_local_addr, - Region_map::Local_addr, bool) + Region_map::Local_addr, bool, bool) { using namespace Okl4; diff --git a/repos/base-sel4/src/core/core_region_map.cc b/repos/base-sel4/src/core/core_region_map.cc index 987e85ebb..03e12d8c9 100644 --- a/repos/base-sel4/src/core/core_region_map.cc +++ b/repos/base-sel4/src/core/core_region_map.cc @@ -24,7 +24,7 @@ using namespace Genode; Region_map::Local_addr Core_region_map::attach(Dataspace_capability ds_cap, size_t size, off_t offset, - bool use_local_addr, Region_map::Local_addr, bool) + bool use_local_addr, Region_map::Local_addr, bool, bool) { auto lambda = [&] (Dataspace_component *ds) -> Local_addr { if (!ds) diff --git a/repos/base-sel4/src/core/stack_area.cc b/repos/base-sel4/src/core/stack_area.cc index e491d78e0..373876465 100644 --- a/repos/base-sel4/src/core/stack_area.cc +++ b/repos/base-sel4/src/core/stack_area.cc @@ -58,7 +58,7 @@ class Stack_area_region_map : public Region_map * Allocate and attach on-the-fly backing store to the stack area */ Local_addr attach(Dataspace_capability, size_t size, off_t, - bool, Local_addr local_addr, bool) override + bool, Local_addr local_addr, bool, bool) override { size = round_page(size); diff --git a/repos/base/include/region_map/client.h b/repos/base/include/region_map/client.h index 911723e9b..46fda0983 100644 --- a/repos/base/include/region_map/client.h +++ b/repos/base/include/region_map/client.h @@ -44,7 +44,8 @@ class Genode::Region_map_client : public Rpc_client Local_addr attach(Dataspace_capability ds, size_t size = 0, off_t offset = 0, bool use_local_addr = false, Local_addr local_addr = (void *)0, - bool executable = false) override; + bool executable = false, + bool writeable = true) override; void detach(Local_addr) override; void fault_handler(Signal_context_capability) override; diff --git a/repos/base/include/region_map/region_map.h b/repos/base/include/region_map/region_map.h index 5afa9d7d6..66798e270 100644 --- a/repos/base/include/region_map/region_map.h +++ b/repos/base/include/region_map/region_map.h @@ -103,6 +103,7 @@ struct Genode::Region_map : Interface * the specified 'local_addr' * \param local_addr local destination address * \param executable if the mapping should be executable + * \param writeable if the mapping should be writeable * * \throw Invalid_dataspace * \throw Region_conflict @@ -116,7 +117,8 @@ struct Genode::Region_map : Interface size_t size = 0, off_t offset = 0, bool use_local_addr = false, Local_addr local_addr = (void *)0, - bool executable = false) = 0; + bool executable = false, + bool writeable = true) = 0; /** * Shortcut for attaching a dataspace at a predefined local address @@ -165,7 +167,8 @@ struct Genode::Region_map : Interface GENODE_RPC_THROW(Rpc_attach, Local_addr, attach, GENODE_TYPE_LIST(Invalid_dataspace, Region_conflict, Out_of_ram, Out_of_caps), - Dataspace_capability, size_t, off_t, bool, Local_addr, bool); + Dataspace_capability, size_t, off_t, bool, Local_addr, + bool, bool); GENODE_RPC(Rpc_detach, void, detach, Local_addr); GENODE_RPC(Rpc_fault_handler, void, fault_handler, Signal_context_capability); GENODE_RPC(Rpc_state, State, state); diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 95d72e439..5109b66a5 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -162,7 +162,7 @@ _ZN6Genode17Native_capabilityC1Ev T _ZN6Genode17Native_capabilityC2Ev T _ZN6Genode17Region_map_client13fault_handlerENS_10CapabilityINS_14Signal_contextEEE T _ZN6Genode17Region_map_client5stateEv T -_ZN6Genode17Region_map_client6attachENS_10CapabilityINS_9DataspaceEEEmlbNS_10Region_map10Local_addrEb T +_ZN6Genode17Region_map_client6attachENS_10CapabilityINS_9DataspaceEEEmlbNS_10Region_map10Local_addrEbb T _ZN6Genode17Region_map_client6detachENS_10Region_map10Local_addrE T _ZN6Genode17Region_map_client9dataspaceEv T _ZN6Genode17Region_map_clientC1ENS_10CapabilityINS_10Region_mapEEE T diff --git a/repos/base/src/core/core_region_map.cc b/repos/base/src/core/core_region_map.cc index 1c541a8a5..8fff99e35 100644 --- a/repos/base/src/core/core_region_map.cc +++ b/repos/base/src/core/core_region_map.cc @@ -23,7 +23,7 @@ using namespace Genode; Region_map::Local_addr Core_region_map::attach(Dataspace_capability ds_cap, size_t, off_t, bool, - Region_map::Local_addr, bool) + Region_map::Local_addr, bool, bool) { auto lambda = [] (Dataspace_component *ds) { if (!ds) diff --git a/repos/base/src/core/include/core_region_map.h b/repos/base/src/core/include/core_region_map.h index c51151bdc..ffbb8bb71 100644 --- a/repos/base/src/core/include/core_region_map.h +++ b/repos/base/src/core/include/core_region_map.h @@ -37,7 +37,8 @@ class Genode::Core_region_map : public Region_map Local_addr attach(Dataspace_capability, size_t size = 0, off_t offset=0, bool use_local_addr = false, Local_addr local_addr = 0, - bool executable = false) override; + bool executable = false, + bool writeable = true) override; void detach(Local_addr); diff --git a/repos/base/src/core/include/region_map_component.h b/repos/base/src/core/include/region_map_component.h index 6f3f60f70..6d9e04b4c 100644 --- a/repos/base/src/core/include/region_map_component.h +++ b/repos/base/src/core/include/region_map_component.h @@ -444,7 +444,8 @@ class Genode::Region_map_component : private Weak_object, ** Region map interface ** **************************/ - Local_addr attach (Dataspace_capability, size_t, off_t, bool, Local_addr, bool) override; + Local_addr attach (Dataspace_capability, size_t, off_t, + bool, Local_addr, bool, bool) override; void detach (Local_addr) override; void fault_handler (Signal_context_capability handler) override; State state () override; diff --git a/repos/base/src/core/region_map_component.cc b/repos/base/src/core/region_map_component.cc index 8a6e59577..0d187edf8 100644 --- a/repos/base/src/core/region_map_component.cc +++ b/repos/base/src/core/region_map_component.cc @@ -213,7 +213,8 @@ int Rm_client::pager(Ipc_pager &pager) /* * Check if dataspace is compatible with page-fault type */ - if (pf_type == Region_map::State::WRITE_FAULT && !dsc->writable()) { + if (pf_type == Region_map::State::WRITE_FAULT && + (!region->write() || !dsc->writable())) { print_page_fault("attempted write at read-only memory", pf_addr, pf_ip, pf_type, *this); @@ -337,7 +338,8 @@ Mapping Region_map_component::create_map_item(Region_map_component *, return Mapping(dst_fault_area.base(), src_fault_area.base(), dsc->cacheability(), dsc->io_mem(), - map_size_log2, dsc->writable(), region->executable()); + map_size_log2, region->write() && dsc->writable(), + region->executable()); }; @@ -345,7 +347,7 @@ Region_map::Local_addr Region_map_component::attach(Dataspace_capability ds_cap, size_t size, off_t offset, bool use_local_addr, Region_map::Local_addr local_addr, - bool executable) + bool executable, bool writeable) { /* serialize access */ Lock::Guard lock_guard(_lock); @@ -427,7 +429,8 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size, /* store attachment info in meta data */ try { - _map.metadata(attach_at, Rm_region((addr_t)attach_at, size, true, + _map.metadata(attach_at, Rm_region((addr_t)attach_at, size, + dsc->writable() && writeable, dsc, offset, this, executable)); } catch (Allocator_avl_tpl::Assign_metadata_failed) { diff --git a/repos/base/src/core/stack_area.cc b/repos/base/src/core/stack_area.cc index e85995423..0050cb2bb 100644 --- a/repos/base/src/core/stack_area.cc +++ b/repos/base/src/core/stack_area.cc @@ -67,7 +67,7 @@ class Stack_area_region_map : public Region_map * Allocate and attach on-the-fly backing store to stack area */ Local_addr attach(Dataspace_capability, size_t size, off_t, - bool, Local_addr local_addr, bool) override + bool, Local_addr local_addr, bool, bool) override { /* allocate physical memory */ size = round_page(size); diff --git a/repos/base/src/include/base/internal/expanding_region_map_client.h b/repos/base/src/include/base/internal/expanding_region_map_client.h index f2ed87ad4..4ff386876 100644 --- a/repos/base/src/include/base/internal/expanding_region_map_client.h +++ b/repos/base/src/include/base/internal/expanding_region_map_client.h @@ -35,7 +35,7 @@ struct Genode::Expanding_region_map_client : Region_map_client Local_addr attach(Dataspace_capability ds, size_t size, off_t offset, bool use_local_addr, Local_addr local_addr, - bool executable) override + bool executable, bool writeable) override { return retry( [&] () { @@ -44,7 +44,8 @@ struct Genode::Expanding_region_map_client : Region_map_client return Region_map_client::attach(ds, size, offset, use_local_addr, local_addr, - executable); }, + executable, + writeable); }, [&] { _pd_client.upgrade_caps(2); }); }, [&] () { _pd_client.upgrade_ram(8*1024); }); diff --git a/repos/base/src/lib/base/region_map_client.cc b/repos/base/src/lib/base/region_map_client.cc index 5870b65b5..25a675600 100644 --- a/repos/base/src/lib/base/region_map_client.cc +++ b/repos/base/src/lib/base/region_map_client.cc @@ -23,10 +23,10 @@ Region_map_client::Region_map_client(Capability cap) Region_map::Local_addr Region_map_client::attach(Dataspace_capability ds, size_t size, off_t offset, bool use_local_addr, Local_addr local_addr, - bool executable) + bool executable, bool writeable) { return call(ds, size, offset, use_local_addr, local_addr, - executable); + executable, writeable); } diff --git a/repos/base/src/test/rm_fault/main.cc b/repos/base/src/test/rm_fault/main.cc index 45822264b..1f97d6b9c 100644 --- a/repos/base/src/test/rm_fault/main.cc +++ b/repos/base/src/test/rm_fault/main.cc @@ -301,25 +301,45 @@ struct Main_parent _address_space.detach((void *)child_virt_addr); } - void _test_write_fault(addr_t const child_virt_addr) + void _test_write_fault(addr_t const child_virt_addr, unsigned round) { - if (_child_value() == WRITE_TEST) { - _child_stop() = STOP_TEST; + if (_child_value() != WRITE_TEST) { + Genode::log("test WRITE faults on read-only binary and " + "read-only attached RAM"); - Genode::log("got write fault on ROM ", Hex(child_virt_addr)); - - /* let client continue by providing a dataspace it may write to */ - _address_space.detach((void *)child_virt_addr); - _address_space.attach_at(_ds.cap(), child_virt_addr); + _child_value() = WRITE_TEST; + _address_space.attach_at(_binary.dataspace(), child_virt_addr); return; } - Genode::log("test WRITE fault on read-only binary"); + enum { ROUND_FAULT_ON_ROM_BINARY = 1, ROUND_FAULT_ON_RO_RAM = 2 }; - _child_value() = WRITE_TEST; + if (round == ROUND_FAULT_ON_RO_RAM) + _child_stop() = STOP_TEST; - _address_space.attach_at(_binary.dataspace(), child_virt_addr); + Genode::log("got write fault on ", Hex(child_virt_addr), + (round == ROUND_FAULT_ON_ROM_BINARY) ? " ROM (binary)" : + (round == ROUND_FAULT_ON_RO_RAM) ? " read-only attached RAM" + : " unknown"); + + /* detach region where fault happened */ + _address_space.detach((void *)child_virt_addr); + + if (round == ROUND_FAULT_ON_ROM_BINARY) { + /* attach a RAM dataspace read-only */ + enum { + SIZE = 4096, OFFSET = 0, ATTACH_AT = true, NON_EXEC = false, + READONLY = false + }; + + _address_space.attach(_ds.cap(), SIZE, OFFSET, ATTACH_AT, + child_virt_addr, NON_EXEC, READONLY); + } else + if (round == ROUND_FAULT_ON_RO_RAM) { + /* let client continue by attaching RAM dataspace writeable */ + _address_space.attach_at(_ds.cap(), child_virt_addr); + } } void _test_exec_fault(Region_map::State &state) @@ -344,7 +364,7 @@ struct Main_parent void _handle_fault() { - enum { FAULT_CNT_READ = 4, FAULT_CNT_WRITE = 5 }; + enum { FAULT_CNT_READ = 4, FAULT_CNT_WRITE = 6 }; log("received region-map fault signal, request fault state"); @@ -364,7 +384,7 @@ struct Main_parent _test_read_fault(child_virt_addr); if (_fault_cnt <= FAULT_CNT_WRITE && _fault_cnt >= FAULT_CNT_READ) - _test_write_fault(child_virt_addr); + _test_write_fault(child_virt_addr, _fault_cnt - FAULT_CNT_READ); if (!_config.xml().attribute_value("executable_fault_test", true) && _fault_cnt >=FAULT_CNT_WRITE) diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd.h b/repos/os/src/drivers/platform/spec/x86/device_pd.h index a52cecf48..89a17bf1e 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd.h +++ b/repos/os/src/drivers/platform/spec/x86/device_pd.h @@ -59,7 +59,8 @@ class Platform::Device_pd Genode::size_t size = 0, Genode::off_t offset = 0, bool use_local_addr = false, Local_addr local_addr = (void *)0, - bool executable = false) override + bool executable = false, + bool writeable = true) override { return Genode::retry( [&] () { @@ -68,7 +69,8 @@ class Platform::Device_pd return Region_map_client::attach(ds, size, offset, use_local_addr, local_addr, - executable); }, + executable, + writeable); }, [&] () { enum { UPGRADE_CAP_QUOTA = 2 }; Genode::Cap_quota const caps { UPGRADE_CAP_QUOTA }; diff --git a/repos/ports/src/app/gdb_monitor/region_map_component.cc b/repos/ports/src/app/gdb_monitor/region_map_component.cc index d956746dd..f47106327 100644 --- a/repos/ports/src/app/gdb_monitor/region_map_component.cc +++ b/repos/ports/src/app/gdb_monitor/region_map_component.cc @@ -54,7 +54,7 @@ Region_map::Local_addr Region_map_component::attach(Dataspace_capability ds_cap, size_t size, off_t offset, bool use_local_addr, Region_map::Local_addr local_addr, - bool executable) + bool executable, bool const writeable) { size_t ds_size = Dataspace_client(ds_cap).size(); @@ -72,7 +72,7 @@ Region_map_component::attach(Dataspace_capability ds_cap, size_t size, void *addr = _parent_region_map.attach(ds_cap, size, offset, use_local_addr, local_addr, - executable); + executable, writeable); Lock::Guard lock_guard(_region_map_lock); _region_map.insert(new (_alloc) Region(addr, (void*)((addr_t)addr + size - 1), ds_cap, offset)); diff --git a/repos/ports/src/app/gdb_monitor/region_map_component.h b/repos/ports/src/app/gdb_monitor/region_map_component.h index dd7f600c6..61511fd98 100644 --- a/repos/ports/src/app/gdb_monitor/region_map_component.h +++ b/repos/ports/src/app/gdb_monitor/region_map_component.h @@ -102,7 +102,8 @@ namespace Gdb_monitor { **************************************/ Local_addr attach (Dataspace_capability, size_t, - off_t, bool, Local_addr, bool) override; + off_t, bool, Local_addr, bool, + bool) override; void detach (Local_addr) override; void fault_handler (Signal_context_capability) override; State state () override; diff --git a/repos/ports/src/noux/region_map_component.h b/repos/ports/src/noux/region_map_component.h index f234a8a32..af0b61748 100644 --- a/repos/ports/src/noux/region_map_component.h +++ b/repos/ports/src/noux/region_map_component.h @@ -232,10 +232,11 @@ class Noux::Region_map_component : public Rpc_object, **************************/ Local_addr attach(Dataspace_capability ds, - size_t size = 0, off_t offset = 0, - bool use_local_addr = false, - Local_addr local_addr = (addr_t)0, - bool executable = false) override + size_t size, off_t offset, + bool use_local_addr, + Local_addr local_addr, + bool executable, + bool writeable) override { /* * Region map subtracts offset from size if size is 0 @@ -245,7 +246,7 @@ class Noux::Region_map_component : public Rpc_object, for (;;) { try { local_addr = _rm.attach(ds, size, offset, use_local_addr, - local_addr, executable); + local_addr, executable, writeable); break; } catch (Out_of_ram) { _pd.upgrade_ram(8*1024); } diff --git a/repos/ports/src/virtualbox/mm.h b/repos/ports/src/virtualbox/mm.h index 508d5e04a..24b28ee24 100644 --- a/repos/ports/src/virtualbox/mm.h +++ b/repos/ports/src/virtualbox/mm.h @@ -47,7 +47,8 @@ class Sub_rm_connection : private Genode::Rm_connection, Genode::size_t size = 0, Genode::off_t offset = 0, bool use_local_addr = false, Local_addr local_addr = (void *)0, - bool executable = false) override + bool executable = false, + bool writeable = true) override { Local_addr addr = Genode::retry( [&] () { @@ -56,7 +57,8 @@ class Sub_rm_connection : private Genode::Rm_connection, return Region_map_client::attach(ds, size, offset, use_local_addr, local_addr, - executable); }, + executable, + writeable); }, [&] () { upgrade_caps(2); }); }, [&] () { upgrade_ram(8192); });