diff --git a/repos/base-fiasco/src/core/include/ipc_pager.h b/repos/base-fiasco/src/core/include/ipc_pager.h index c8ce0ab198..fd97211a29 100644 --- a/repos/base-fiasco/src/core/include/ipc_pager.h +++ b/repos/base-fiasco/src/core/include/ipc_pager.h @@ -17,7 +17,6 @@ /* Genode includes */ #include #include -#include #include #include @@ -26,66 +25,12 @@ /* core includes */ #include +#include /* L4/Fiasco includes */ #include -namespace Genode { - - class Mapping; - class Ipc_pager; -} - - -class Genode::Mapping -{ - private: - - addr_t _dst_addr; - Fiasco::l4_fpage_t _fpage; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t src_addr, Cache cacheability, bool, - unsigned l2size, bool rw, bool) - : - _dst_addr(dst_addr), - _fpage(Fiasco::l4_fpage(src_addr, l2size, rw, false)) - { - if (cacheability == WRITE_COMBINED) - _fpage.fp.cache = Fiasco::L4_FPAGE_BUFFERABLE; - } - - /** - * Construct invalid flexpage - */ - Mapping() : _dst_addr(0), _fpage(Fiasco::l4_fpage(0, 0, 0, 0)) { } - - Fiasco::l4_umword_t dst_addr() const { return _dst_addr; } - Fiasco::l4_fpage_t fpage() const { return _fpage; } - - /** - * Prepare map operation - * - * On Fiasco, we need to map a page locally to be able to map it to - * another address space. - */ - void prepare_map_operation() - { - addr_t core_local_addr = _fpage.fp.page << 12; - size_t mapping_size = 1 << _fpage.fp.size; - - for (addr_t i = 0; i < mapping_size; i += L4_PAGESIZE) { - if (_fpage.fp.write) - touch_read_write((unsigned char volatile *)(core_local_addr + i)); - else - touch_read((unsigned char const volatile *)(core_local_addr + i)); - } - } -}; +namespace Genode { class Ipc_pager; } class Genode::Ipc_pager diff --git a/repos/base-fiasco/src/core/pager.cc b/repos/base-fiasco/src/core/pager.cc index 83242e557b..544ee6f83c 100644 --- a/repos/base-fiasco/src/core/pager.cc +++ b/repos/base-fiasco/src/core/pager.cc @@ -29,6 +29,26 @@ using namespace Genode; using namespace Fiasco; +/** + * Prepare map operation + * + * On Fiasco, we need to map a page locally to be able to map it to another + * address space. + */ +void Mapping::prepare_map_operation() const +{ + addr_t const core_local_addr = src_addr; + size_t const mapping_size = 1UL << size_log2; + + for (addr_t i = 0; i < mapping_size; i += L4_PAGESIZE) { + if (writeable) + touch_read_write((unsigned char volatile *)(core_local_addr + i)); + else + touch_read((unsigned char const volatile *)(core_local_addr + i)); + } +} + + /*************** ** Ipc_pager ** ***************/ @@ -51,11 +71,13 @@ void Ipc_pager::wait_for_fault() void Ipc_pager::reply_and_wait_for_fault() { - l4_msgdope_t result; + l4_fpage_t const fpage { l4_fpage(_reply_mapping.src_addr, + _reply_mapping.size_log2, + _reply_mapping.writeable, false) }; - l4_ipc_reply_and_wait(_last, - L4_IPC_SHORT_FPAGE, _reply_mapping.dst_addr(), - _reply_mapping.fpage().fpage, &_last, + l4_msgdope_t result; + l4_ipc_reply_and_wait(_last, L4_IPC_SHORT_FPAGE, + _reply_mapping.dst_addr, fpage.fpage, &_last, L4_IPC_SHORT_MSG, &_pf_addr, &_pf_ip, L4_IPC_SEND_TIMEOUT_0, &result); diff --git a/repos/base-foc/src/core/include/ipc_pager.h b/repos/base-foc/src/core/include/ipc_pager.h index 44c0e69c2a..b9ba858afd 100644 --- a/repos/base-foc/src/core/include/ipc_pager.h +++ b/repos/base-foc/src/core/include/ipc_pager.h @@ -16,7 +16,6 @@ #define _CORE__INCLUDE__IPC_PAGER_H_ /* Genode includes */ -#include #include #include #include @@ -28,67 +27,15 @@ /* base-internal includes */ #include +/* core-local includes */ +#include + /* Fiasco.OC includes */ #include -namespace Genode { - - class Mapping; - class Ipc_pager; -} +namespace Genode { class Ipc_pager; } -class Genode::Mapping -{ - private: - - addr_t _dst_addr; - Foc::l4_fpage_t _fpage { }; - Cache _cacheability; - bool _iomem; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t src_addr, Cache cache, bool io_mem, - unsigned log2size, bool write, bool executable) - : - _dst_addr(dst_addr), _cacheability(cache), _iomem(io_mem) - { - typedef Foc::L4_fpage_rights Rights; - Rights rights = ( write && executable) ? Foc::L4_FPAGE_RWX : - ( write && !executable) ? Foc::L4_FPAGE_RW : - (!write && !executable) ? Foc::L4_FPAGE_RO : - Foc::L4_FPAGE_RX; - - _fpage = Foc::l4_fpage(src_addr, log2size, rights); - } - - /** - * Construct invalid flexpage - */ - Mapping() : _dst_addr(0), _fpage(Foc::l4_fpage_invalid()), - _cacheability(UNCACHED), _iomem(false) { } - - Foc::l4_umword_t dst_addr() const { return _dst_addr; } - bool grant() const { return false; } - Foc::l4_fpage_t fpage() const { return _fpage; } - Cache cacheability() const { return _cacheability; } - bool iomem() const { return _iomem; } - - /** - * Prepare map operation is not needed on Fiasco.OC, since we clear the - * dataspace before this function is called. - */ - void prepare_map_operation() { } -}; - - -/** - * Special paging server class - */ class Genode::Ipc_pager : public Native_capability { public: @@ -97,14 +44,14 @@ class Genode::Ipc_pager : public Native_capability private: - Native_thread _last { }; /* origin of last fault */ - addr_t _pf_addr { 0 }; /* page-fault address */ - addr_t _pf_ip { 0 }; /* ip of faulter */ - Mapping _reply_mapping { }; /* page-fault answer */ - unsigned long _badge; /* badge of faulting thread */ + Native_thread _last { }; /* origin of last fault */ + addr_t _pf_addr { 0 }; /* page-fault address */ + addr_t _pf_ip { 0 }; /* ip of faulter */ + Mapping _reply_mapping { }; /* page-fault answer */ + unsigned long _badge; /* badge of faulting thread */ Foc::l4_msgtag_t _tag { }; /* receive message tag */ Foc::l4_exc_regs_t _regs { }; /* exception registers */ - Msg_type _type { PAGEFAULT }; + Msg_type _type { PAGEFAULT }; void _parse_msg_type(void); void _parse_exception(void); diff --git a/repos/base-foc/src/core/ipc_pager.cc b/repos/base-foc/src/core/ipc_pager.cc index 361c60af7b..4e96396bf6 100644 --- a/repos/base-foc/src/core/ipc_pager.cc +++ b/repos/base-foc/src/core/ipc_pager.cc @@ -29,6 +29,13 @@ using namespace Genode; using namespace Foc; +/* + * There is no preparation needed because the entire physical memory is known + * to be mapped within core. + */ +void Mapping::prepare_map_operation() const { } + + void Ipc_pager::_parse(unsigned long label) { _badge = label & ~0x3; @@ -94,31 +101,35 @@ void Ipc_pager::reply_and_wait_for_fault() l4_umword_t label; l4_msgtag_t snd_tag = l4_msgtag(0, 0, 1, 0); - l4_umword_t grant = _reply_mapping.grant() ? L4_MAP_ITEM_GRANT : 0; - l4_utcb_mr()->mr[0] = _reply_mapping.dst_addr() | L4_ITEM_MAP | grant; + l4_utcb_mr()->mr[0] = _reply_mapping.dst_addr | L4_ITEM_MAP; - switch (_reply_mapping.cacheability()) { + l4_fpage_cacheability_opt_t + cacheability = _reply_mapping.cached ? L4_FPAGE_CACHEABLE + : L4_FPAGE_UNCACHEABLE; - case WRITE_COMBINED: - l4_utcb_mr()->mr[0] |= L4_FPAGE_BUFFERABLE << 4; - break; + if (_reply_mapping.write_combined) + cacheability= L4_FPAGE_BUFFERABLE; - case CACHED: - l4_utcb_mr()->mr[0] |= L4_FPAGE_CACHEABLE << 4; - break; + l4_utcb_mr()->mr[0] |= cacheability << 4; - case UNCACHED: - if (!_reply_mapping.iomem()) - l4_utcb_mr()->mr[0] |= L4_FPAGE_BUFFERABLE << 4; - else - l4_utcb_mr()->mr[0] |= L4_FPAGE_UNCACHEABLE << 4; - break; - } - l4_utcb_mr()->mr[1] = _reply_mapping.fpage().raw; + auto rights = [] (bool writeable, bool executable) + { + if ( writeable && executable) return L4_FPAGE_RWX; + if ( writeable && !executable) return L4_FPAGE_RW; + if (!writeable && !executable) return L4_FPAGE_RO; + return L4_FPAGE_RX; + }; + + l4_fpage_t const fpage = l4_fpage(_reply_mapping.src_addr, + _reply_mapping.size_log2, + rights(_reply_mapping.writeable, + _reply_mapping.executable)); + + l4_utcb_mr()->mr[1] = fpage.raw; _tag = l4_ipc_send_and_wait(_last.kcap, l4_utcb(), snd_tag, &label, L4_IPC_SEND_TIMEOUT_0); - int err = l4_ipc_error(_tag, l4_utcb()); + int const err = l4_ipc_error(_tag, l4_utcb()); if (err) { error("Ipc error ", err, " in pagefault from ", Hex(label & ~0x3)); wait_for_fault(); diff --git a/repos/base-hw/src/core/pager.h b/repos/base-hw/src/core/pager.h index 4adfd8c368..ed51123820 100644 --- a/repos/base-hw/src/core/pager.h +++ b/repos/base-hw/src/core/pager.h @@ -27,6 +27,7 @@ /* core-local includes */ #include #include +#include #include #include @@ -56,28 +57,6 @@ namespace Genode { } -struct Genode::Mapping : Hw::Mapping -{ - Mapping() {} - - Mapping(addr_t virt, - addr_t phys, - Cache cacheable, - bool io, - unsigned size_log2, - bool writeable, - bool executable) - : - Hw::Mapping(phys, virt, 1 << size_log2, - { writeable ? Hw::RW : Hw::RO, - executable ? Hw::EXEC : Hw::NO_EXEC, Hw::USER, - Hw::NO_GLOBAL, io ? Hw::DEVICE : Hw::RAM, cacheable }) - { } - - void prepare_map_operation() const {} -}; - - class Genode::Ipc_pager { protected: diff --git a/repos/base-hw/src/core/region_map_support.cc b/repos/base-hw/src/core/region_map_support.cc index 7dcd7d8a45..e8e6d00e6a 100644 --- a/repos/base-hw/src/core/region_map_support.cc +++ b/repos/base-hw/src/core/region_map_support.cc @@ -61,11 +61,24 @@ void Pager_entrypoint::entry() if (!locked_ptr.valid()) continue; Hw::Address_space * as = static_cast(&*locked_ptr); - as->insert_translation(_mapping.virt(), _mapping.phys(), - _mapping.size(), _mapping.flags()); + + Hw::Page_flags const flags { + .writeable = _mapping.writeable ? Hw::RW : Hw::RO, + .executable = _mapping.executable ? Hw::EXEC : Hw::NO_EXEC, + .privileged = Hw::USER, + .global = Hw::NO_GLOBAL, + .type = _mapping.io_mem ? Hw::DEVICE : Hw::RAM, + .cacheable = _mapping.cached ? Genode::CACHED : Genode::UNCACHED + }; + + as->insert_translation(_mapping.dst_addr, _mapping.src_addr, + 1UL << _mapping.size_log2, flags); } /* let pager object go back to no-fault state */ po->wake_up(); } } + + +void Mapping::prepare_map_operation() const { } diff --git a/repos/base-nova/src/core/include/ipc_pager.h b/repos/base-nova/src/core/include/ipc_pager.h index f8ce96d210..98d9d5307d 100644 --- a/repos/base-nova/src/core/include/ipc_pager.h +++ b/repos/base-nova/src/core/include/ipc_pager.h @@ -19,48 +19,38 @@ #include #include +/* core-local includes */ +#include + /* NOVA includes */ #include -namespace Genode { - class Mapping; - class Ipc_pager; +namespace Genode { class Ipc_pager; } + + +namespace Genode { enum { PAGE_SIZE_LOG2 = 12 }; } + + +static inline Nova::Rights nova_map_rights(Genode::Mapping const &mapping) +{ + return Nova::Rights(true, mapping.writeable, mapping.executable); } -class Genode::Mapping + +static inline Nova::Mem_crd nova_src_crd(Genode::Mapping const &mapping) { - private: + return Nova::Mem_crd(mapping.src_addr >> Genode::PAGE_SIZE_LOG2, + mapping.size_log2 - Genode::PAGE_SIZE_LOG2, + nova_map_rights(mapping)); +} - addr_t const _dst_addr; - Cache const _cache; - Nova::Mem_crd const _mem_crd; - enum { PAGE_SIZE_LOG2 = 12 }; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t source_addr, - Cache cache, bool /* io_mem */, - unsigned size_log2, - bool writeable, bool executable) - : - _dst_addr(dst_addr), - _cache(cache), - _mem_crd(source_addr >> PAGE_SIZE_LOG2, - size_log2 - PAGE_SIZE_LOG2, - Nova::Rights(true, writeable, executable)) - { } - - void prepare_map_operation() { } - - Nova::Mem_crd mem_crd() const { return _mem_crd; } - bool dma() const { return _cache != CACHED; }; - bool write_combined() const { return _cache == WRITE_COMBINED; }; - addr_t dst_addr() const { return _dst_addr; } -}; +static inline Nova::Mem_crd nova_dst_crd(Genode::Mapping const &mapping) +{ + return Nova::Mem_crd(mapping.dst_addr >> Genode::PAGE_SIZE_LOG2, + mapping.size_log2 - Genode::PAGE_SIZE_LOG2, + nova_map_rights(mapping)); +} class Genode::Ipc_pager diff --git a/repos/base-nova/src/core/ipc_pager.cc b/repos/base-nova/src/core/ipc_pager.cc index 1574d2ace5..3c4dbb5019 100644 --- a/repos/base-nova/src/core/ipc_pager.cc +++ b/repos/base-nova/src/core/ipc_pager.cc @@ -23,6 +23,10 @@ using namespace Genode; + +void Mapping::prepare_map_operation() const { } + + Ipc_pager::Ipc_pager(Nova::Utcb &utcb, addr_t pd_dst, addr_t pd_core) : _pd_dst(pd_dst), @@ -44,23 +48,20 @@ Ipc_pager::Ipc_pager(Nova::Utcb &utcb, addr_t pd_dst, addr_t pd_core) } -void Ipc_pager::set_reply_mapping(Mapping m) +void Ipc_pager::set_reply_mapping(Mapping const mapping) { Nova::Utcb &utcb = *(Nova::Utcb *)Thread::myself()->utcb(); utcb.set_msg_word(0); - bool res = utcb.append_item(m.mem_crd(), 0, true, false, - false, m.dma(), m.write_combined()); - /* one item ever fits on the UTCB */ + + bool res = utcb.append_item(nova_src_crd(mapping), 0, true, false, false, + mapping.dma_buffer, mapping.write_combined); + + /* one item always fits in the UTCB */ (void)res; - /* receive window in destination pd */ - Nova::Mem_crd crd_mem(m.dst_addr() >> 12, m.mem_crd().order(), - Nova::Rights(m.mem_crd().rights().readable(), - m.mem_crd().rights().writeable(), - m.mem_crd().rights().executable())); /* asynchronously map memory */ - _syscall_res = Nova::delegate(_pd_core, _pd_dst, crd_mem); + _syscall_res = Nova::delegate(_pd_core, _pd_dst, nova_dst_crd(mapping)); } diff --git a/repos/base-nova/src/core/pd_session_support.cc b/repos/base-nova/src/core/pd_session_support.cc index 97f89d7872..99b0726c4f 100644 --- a/repos/base-nova/src/core/pd_session_support.cc +++ b/repos/base-nova/src/core/pd_session_support.cc @@ -66,34 +66,31 @@ void Pd_session_component::map(addr_t virt, addr_t size) 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()); + + bool res = utcb.append_item(nova_src_crd(mapping), 0, true, false, + false, + mapping.dma_buffer, + mapping.write_combined); + /* one item ever fits on the UTCB */ (void)res; - Nova::Rights const map_rights (true, - region->write() && dsc->writable(), - region->executable()); + err = Nova::delegate(pd_core, pd_dst, nova_dst_crd(mapping)); - /* 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; + addr_t const map_size = 1UL << mapping.size_log2; + addr_t const mapped = mapping.dst_addr + map_size - virt; - if (err != Nova::NOVA_OK) + if (err != Nova::NOVA_OK) { error("could not map memory ", - Hex_range(mapping.dst_addr(), map_crd_size) , " " + Hex_range(mapping.dst_addr, map_size) , " " "eagerly error=", err); + } return mapped; }; diff --git a/repos/base-okl4/src/core/include/ipc_pager.h b/repos/base-okl4/src/core/include/ipc_pager.h index 0558e62cfd..608522be02 100644 --- a/repos/base-okl4/src/core/include/ipc_pager.h +++ b/repos/base-okl4/src/core/include/ipc_pager.h @@ -14,60 +14,16 @@ #ifndef _CORE__INCLUDE__IPC_PAGER_H_ #define _CORE__INCLUDE__IPC_PAGER_H_ -#include +/* Genode includes */ #include -#include /* base-internal includes */ #include -namespace Genode { +/* core-local includes */ +#include - class Mapping; - class Ipc_pager; -} - - -class Genode::Mapping -{ - private: - - addr_t _phys_addr { 0 }; - Okl4::L4_Fpage_t _fpage { }; - Okl4::L4_PhysDesc_t _phys_desc { }; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t src_addr, Cache, bool io_mem, - unsigned l2size, bool rw, bool executable); - - /** - * Construct invalid mapping - */ - Mapping(); - - /** - * Return flexpage describing the virtual destination address - */ - Okl4::L4_Fpage_t fpage() const { return _fpage; } - - /** - * Return physical-memory descriptor describing the source location - */ - Okl4::L4_PhysDesc_t phys_desc() const { return _phys_desc; } - - /** - * Prepare map operation - * - * On OKL4, we do not need to map a page core-locally to be able to - * map it into another address space. Therefore, we can leave this - * function blank. - */ - void prepare_map_operation() { } -}; +namespace Genode { class Ipc_pager; } class Genode::Ipc_pager diff --git a/repos/base-okl4/src/core/pager.cc b/repos/base-okl4/src/core/pager.cc index fdcbd44429..17abffe3dd 100644 --- a/repos/base-okl4/src/core/pager.cc +++ b/repos/base-okl4/src/core/pager.cc @@ -61,24 +61,11 @@ static inline L4_ThreadId_t thread_get_my_global_id() } -/************* - ** Mapping ** - *************/ - -Mapping::Mapping(addr_t dst_addr, addr_t src_addr, Cache, bool, - unsigned l2size, bool rw, bool) -: - _fpage(L4_FpageLog2(dst_addr, l2size)), - /* - * OKL4 does not support write-combining as mapping attribute. - */ - _phys_desc(L4_PhysDesc(src_addr, 0)) -{ - L4_Set_Rights(&_fpage, rw ? L4_ReadWriteOnly : L4_ReadeXecOnly); -} - - -Mapping::Mapping() { } +/* + * On OKL4, we do not need to map a page core-locally to be able to map it into + * another address space. Therefore, we can leave this method blank. + */ +void Mapping::prepare_map_operation() const { } /*************** @@ -121,10 +108,21 @@ void Ipc_pager::reply_and_wait_for_fault() L4_SpaceId_t to_space; to_space.raw = L4_ThreadNo(_last) >> Thread_id_bits::THREAD; - /* map page to faulting space */ - int ret = L4_MapFpage(to_space, _reply_mapping.fpage(), - _reply_mapping.phys_desc()); + /* flexpage describing the virtual destination address */ + Okl4::L4_Fpage_t fpage { L4_FpageLog2(_reply_mapping.dst_addr, + _reply_mapping.size_log2) }; + L4_Set_Rights(&fpage, _reply_mapping.writeable ? L4_ReadWriteOnly + : L4_ReadeXecOnly); + /* + * Note that OKL4 does not support write-combining as mapping attribute. + */ + + /* physical-memory descriptor describing the source location */ + Okl4::L4_PhysDesc_t phys_desc { L4_PhysDesc(_reply_mapping.src_addr, 0) }; + + /* map page to faulting space */ + int ret = L4_MapFpage(to_space, fpage, phys_desc); if (ret != 1) error("L4_MapFpage returned ", ret, ", error=", L4_ErrorCode()); diff --git a/repos/base-pistachio/src/core/include/ipc_pager.h b/repos/base-pistachio/src/core/include/ipc_pager.h index cfa47b85d8..9d3589ffd8 100644 --- a/repos/base-pistachio/src/core/include/ipc_pager.h +++ b/repos/base-pistachio/src/core/include/ipc_pager.h @@ -22,64 +22,12 @@ /* core-local includes */ #include +#include /* base-internal includes */ #include -namespace Genode { - - class Mapping; - class Ipc_pager; -} - - -class Genode::Mapping -{ - private: - - union { - Pistachio::L4_MapItem_t _map_item; - Pistachio::L4_GrantItem_t _grant_item; - }; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t src_addr, Cache, bool io_mem, - unsigned l2size, bool rw, bool executable); - - /** - * Construct invalid mapping - */ - Mapping(); - - addr_t _dst_addr() const { return Pistachio::L4_SndBase(_map_item); } - - Pistachio::L4_Fpage_t fpage() const { - return Pistachio::L4_MapItemSndFpage(_map_item); } - - Pistachio::L4_MapItem_t map_item() const { return _map_item; }; - - /** - * Prepare map operation - * - * On Pistachio, we need to map a page locally to be able to map it - * to another address space. - */ - void prepare_map_operation() - { - using namespace Pistachio; - unsigned char volatile *core_local_addr = - (unsigned char volatile *)L4_Address(_map_item.X.snd_fpage); - - if (L4_Rights(_map_item.X.snd_fpage) & L4_Writable) - touch_read_write(core_local_addr); - else - touch_read(core_local_addr); - } -}; +namespace Genode { class Ipc_pager; } class Genode::Ipc_pager @@ -133,7 +81,16 @@ class Genode::Ipc_pager /** * Set parameters for next reply */ - void set_reply_mapping(Mapping m) { _map_item = m.map_item(); } + void set_reply_mapping(Mapping const &mapping) + { + using namespace Pistachio; + + L4_Fpage_t fpage = L4_FpageLog2(mapping.src_addr, mapping.size_log2); + + fpage += mapping.writeable ? L4_FullyAccessible : L4_Readable; + + _map_item = L4_MapItem(fpage, mapping.dst_addr); + } /** * Set destination for next reply diff --git a/repos/base-pistachio/src/core/pager.cc b/repos/base-pistachio/src/core/pager.cc index 4d2a150ca6..7942fbd0f9 100644 --- a/repos/base-pistachio/src/core/pager.cc +++ b/repos/base-pistachio/src/core/pager.cc @@ -32,25 +32,20 @@ using namespace Pistachio; ** Mapping ** *************/ -Mapping::Mapping(addr_t dst_addr, addr_t src_addr, Cache, bool, - unsigned l2size, bool rw, bool) +/** + * Prepare map operation + * + * On Pistachio, we need to map a page locally to be able to map it to another + * address space. + */ +void Mapping::prepare_map_operation() const { - bool const grant = false; + uint8_t * const core_local_addr = (uint8_t *)src_addr; - L4_Fpage_t fpage = L4_FpageLog2(src_addr, l2size); - - fpage += rw ? L4_FullyAccessible : L4_Readable; - - if (grant) - _grant_item = L4_GrantItem(fpage, dst_addr); + if (writeable) + touch_read_write(core_local_addr); else - _map_item = L4_MapItem(fpage, dst_addr); -} - - -Mapping::Mapping() -{ - _map_item = L4_MapItem(L4_Nilpage, 0); + touch_read(core_local_addr); } diff --git a/repos/base-sel4/src/core/include/ipc_pager.h b/repos/base-sel4/src/core/include/ipc_pager.h index dafd608208..0f3838a974 100644 --- a/repos/base-sel4/src/core/include/ipc_pager.h +++ b/repos/base-sel4/src/core/include/ipc_pager.h @@ -14,73 +14,15 @@ #ifndef _CORE__INCLUDE__IPC_PAGER_H_ #define _CORE__INCLUDE__IPC_PAGER_H_ -#include +/* Genode includes */ #include -#include -namespace Genode { - class Mapping; - class Ipc_pager; -} +/* core-local includes */ +#include + +namespace Genode { class Ipc_pager; } -class Genode::Mapping -{ - friend class Ipc_pager; - - private: - - addr_t _from_phys_addr { 0 }; - addr_t _to_virt_addr { 0 }; - Cache _cache { CACHED }; - size_t _num_pages { 0 }; - addr_t _fault_type { 0 }; - bool _writeable { false }; - bool _executable { false }; - - enum { PAGE_SIZE_LOG2 = 12 }; - - public: - - /** - * Constructor - */ - Mapping(addr_t dst_addr, addr_t src_addr, Cache const cache, bool, - unsigned l2size, bool rw, bool executable) - : - _from_phys_addr(src_addr), - _to_virt_addr(dst_addr), - _cache(cache), - _num_pages(1 << (l2size - PAGE_SIZE_LOG2)), - _writeable(rw), _executable(executable) - { } - - /** - * Construct invalid mapping - */ - Mapping() { } - - /** - * Prepare map operation - * - * No preparations are needed on seL4 because all mapping - * originate from the physical address space. - */ - void prepare_map_operation() { } - - addr_t from_phys() const { return _from_phys_addr; } - addr_t to_virt() const { return _to_virt_addr; } - size_t num_pages() const { return _num_pages; } - bool writeable() const { return _writeable; } - bool executable() const { return _executable; } - Cache cacheability() const { return _cache; } - addr_t fault_type() const { return _fault_type; } -}; - - -/** - * Special paging server class - */ class Genode::Ipc_pager : public Native_capability { private: @@ -126,11 +68,7 @@ class Genode::Ipc_pager : public Native_capability /** * Set parameters for next reply */ - void set_reply_mapping(Mapping m) - { - _reply_mapping = m; - _reply_mapping._fault_type = _fault_type; - } + void set_reply_mapping(Mapping m) { _reply_mapping = m; } /** * Set destination for next reply diff --git a/repos/base-sel4/src/core/include/map_local.h b/repos/base-sel4/src/core/include/map_local.h index a7f993a9d3..bc56afba76 100644 --- a/repos/base-sel4/src/core/include/map_local.h +++ b/repos/base-sel4/src/core/include/map_local.h @@ -36,13 +36,14 @@ namespace Genode { inline bool map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, Platform * platform = nullptr) { - enum { DONT_FLUSH = false, WRITEABLE = true, NON_EXECUTABLE = false }; + Vm_space::Map_attr const attr { .cached = true, + .write_combined = false, + .writeable = true, + .executable = false, + .flush_support = false }; try { platform = platform ? platform : &platform_specific(); - platform->core_vm_space().map(from_phys, to_virt, num_pages, - Cache::CACHED, - WRITEABLE, NON_EXECUTABLE, - DONT_FLUSH); + platform->core_vm_space().map(from_phys, to_virt, num_pages, attr); } catch (Page_table_registry::Mapping_cache_full) { return false; } diff --git a/repos/base-sel4/src/core/include/vm_space.h b/repos/base-sel4/src/core/include/vm_space.h index 08f59796bf..666eb9ecbe 100644 --- a/repos/base-sel4/src/core/include/vm_space.h +++ b/repos/base-sel4/src/core/include/vm_space.h @@ -136,6 +136,11 @@ class Genode::Vm_space class Alloc_page_table_failed : Exception { }; + struct Map_attr + { + bool cached, write_combined, writeable, executable, flush_support; + }; + private: Selector_allocator _sel_alloc { }; @@ -182,9 +187,7 @@ class Genode::Vm_space template bool _map_frame(addr_t const from_phys, addr_t const to_dest, - Cache const cacheability, - bool const writable, bool const executable, - bool const flush_support, bool guest, FN const &fn) + Map_attr const attr, bool guest, FN const &fn) { if (_page_table_registry.page_frame_at(to_dest)) { /* @@ -203,7 +206,7 @@ class Genode::Vm_space catch (Selector_allocator::Out_of_indices) { /* free all page-table-entry selectors and retry once */ - _flush(flush_support, fn); + _flush(attr.flush_support, fn); pte_idx = _sel_alloc.alloc(); } @@ -222,15 +225,14 @@ class Genode::Vm_space catch (Page_table_registry::Mapping_cache_full) { /* free all entries of mapping cache and re-try once */ - _flush(flush_support, fn); + _flush(attr.flush_support, fn); _page_table_registry.insert_page_frame(to_dest, Cap_sel(pte_idx)); } /* * Insert copy of page-frame selector into page table */ - long ret = _map_page(Cap_sel(pte_idx), to_dest, cacheability, - writable, executable, guest); + long ret = _map_page(Cap_sel(pte_idx), to_dest, attr, guest); if (ret != seL4_NoError) { error("seL4_*_Page_Map ", Hex(from_phys), "->", Hex(to_dest), " returned ", ret); @@ -242,12 +244,10 @@ class Genode::Vm_space /** * Platform specific map/unmap of a page frame */ - long _map_page(Genode::Cap_sel const &idx, addr_t virt, - Cache cacheability, bool const write, - bool writable, bool guest); - long _unmap_page(Genode::Cap_sel const &idx); - long _invalidate_page(Genode::Cap_sel const &, seL4_Word const, - seL4_Word const); + long _map_page(Cap_sel const &idx, addr_t virt, + Map_attr attr, bool guest); + long _unmap_page(Cap_sel const &idx); + long _invalidate_page(Cap_sel const &, seL4_Word, seL4_Word); /** * Allocate and install page structures for the protection domain. @@ -380,8 +380,7 @@ class Genode::Vm_space } bool map(addr_t const from_phys, addr_t const to_virt, - size_t const num_pages, Cache const cacheability, - bool const writable, bool const executable, bool flush_support) + size_t const num_pages, Map_attr const attr) { auto fn_unmap = [&] (Cap_sel const &idx, addr_t const v_addr) { @@ -413,25 +412,22 @@ class Genode::Vm_space for (size_t i = 0; i < num_pages; i++) { off_t const offset = i << get_page_size_log2(); - if (_map_frame(from_phys + offset, to_virt + offset, - cacheability, writable, executable, - flush_support, false /* host page table */, - fn_unmap)) + if (_map_frame(from_phys + offset, to_virt + offset, attr, + false /* host page table */, fn_unmap)) continue; ok = false; warning("mapping failed ", Hex(from_phys + offset), " -> ", Hex(to_virt + offset), " ", - !flush_support ? "core" : ""); + !attr.flush_support ? "core" : ""); } return ok; } void map_guest(addr_t const from_phys, addr_t const guest_phys, - size_t const num_pages, Cache const cacheability, - bool const writable, bool const executable, bool flush_support) + size_t const num_pages, Map_attr const attr) { auto fn_unmap = [&] (Cap_sel const &idx, addr_t const) { long err = _unmap_page(idx); @@ -450,10 +446,8 @@ class Genode::Vm_space for (size_t i = 0; i < num_pages; i++) { off_t const offset = i << get_page_size_log2(); - _map_frame(from_phys + offset, guest_phys + offset, - cacheability, writable, executable, - flush_support, true /* guest page table */, - fn_unmap); + _map_frame(from_phys + offset, guest_phys + offset, attr, + true /* guest page table */, fn_unmap); } } diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index 9106e03fd4..ee1f0d6dca 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -27,11 +27,14 @@ using namespace Genode; + +void Mapping::prepare_map_operation() const { } + + /*************** ** IPC pager ** ***************/ - void Ipc_pager::wait_for_fault() { if (_badge && _reply_sel) { @@ -47,12 +50,14 @@ void Ipc_pager::wait_for_fault() reply_and_wait_for_fault(); } + bool Ipc_pager::install_mapping() { _badge = Genode::install_mapping(_reply_mapping, _badge); return _badge; } + void Ipc_pager::reply_and_wait_for_fault() { seL4_Word badge = Rpc_obj_key::INVALID; @@ -77,10 +82,25 @@ void Ipc_pager::reply_and_wait_for_fault() _pf_addr = fault_info.pf; _pf_write = fault_info.write; _pf_exec = fault_info.exec_fault(); - _fault_type = seL4_MessageInfo_get_label(page_fault_msg_info); _pf_align = fault_info.align_fault(); + _badge = badge; - _badge = badge; + addr_t const fault_type = seL4_MessageInfo_get_label(page_fault_msg_info); + + auto fault_name = [] (addr_t type) + { + switch (type) { + case seL4_Fault_NullFault: return "seL4_Fault_NullFault"; + case seL4_Fault_CapFault: return "seL4_Fault_CapFault"; + case seL4_Fault_UnknownSyscall: return "seL4_Fault_UnknownSyscall"; + case seL4_Fault_UserException: return "seL4_Fault_UserException"; + case seL4_Fault_VMFault: return "seL4_Fault_VMFault"; + } + return "unknown"; + }; + + if (fault_type != seL4_Fault_VMFault) + error("unexpected exception during fault '", fault_name(fault_type), "'"); } diff --git a/repos/base-sel4/src/core/platform_pd.cc b/repos/base-sel4/src/core/platform_pd.cc index a0e39ab36a..5d1a2a3b8f 100644 --- a/repos/base-sel4/src/core/platform_pd.cc +++ b/repos/base-sel4/src/core/platform_pd.cc @@ -98,10 +98,14 @@ bool Platform_pd::bind_thread(Platform_thread &thread) addr_t const utcb = (thread._utcb) ? thread._utcb : (addr_t)thread.INITIAL_IPC_BUFFER_VIRT; - enum { WRITABLE = true, ONE_PAGE = 1, FLUSHABLE = true, NON_EXECUTABLE = false }; + Vm_space::Map_attr const attr { .cached = true, + .write_combined = false, + .writeable = true, + .executable = false, + .flush_support = true }; + enum { ONE_PAGE = 1 }; _vm_space.alloc_page_tables(utcb, get_page_size()); - _vm_space.map(thread._info.ipc_buffer_phys, utcb, ONE_PAGE, - Cache::CACHED, WRITABLE, NON_EXECUTABLE, FLUSHABLE); + _vm_space.map(thread._info.ipc_buffer_phys, utcb, ONE_PAGE, attr); return true; } @@ -159,51 +163,23 @@ void Platform_pd::free_sel(Cap_sel sel) bool Platform_pd::install_mapping(Mapping const &mapping, const char *thread_name) { - enum { FLUSHABLE = true }; + size_t const num_bytes = 1UL << mapping.size_log2; + size_t const num_pages = num_bytes >> get_page_size_log2(); - try { - if (mapping.fault_type() != seL4_Fault_VMFault) - throw 1; + _vm_space.alloc_page_tables(mapping.dst_addr, num_bytes); - _vm_space.alloc_page_tables(mapping.to_virt(), - mapping.num_pages() * get_page_size()); + Vm_space::Map_attr const attr { .cached = mapping.cached, + .write_combined = mapping.write_combined, + .writeable = mapping.writeable, + .executable = mapping.executable, + .flush_support = true }; - if (_vm_space.map(mapping.from_phys(), mapping.to_virt(), - mapping.num_pages(), mapping.cacheability(), - mapping.writeable(), mapping.executable(), FLUSHABLE)) - return true; + if (_vm_space.map(mapping.src_addr, mapping.dst_addr, num_pages, attr)) + return true; - Genode::warning("mapping failure for thread '", thread_name, - "' in pd '", _vm_space.pd_label(), "'"); - return false; - } catch (...) { - char const * fault_name = "unknown"; - - switch (mapping.fault_type()) { - case seL4_Fault_NullFault: - fault_name = "seL4_Fault_NullFault"; - break; - case seL4_Fault_CapFault: - fault_name = "seL4_Fault_CapFault"; - break; - case seL4_Fault_UnknownSyscall: - fault_name = "seL4_Fault_UnknownSyscall"; - break; - case seL4_Fault_UserException: - fault_name = "seL4_Fault_UserException"; - break; - case seL4_Fault_VMFault: - fault_name = "seL4_Fault_VMFault"; - break; - } - - Genode::error("unexpected exception during fault '", fault_name, "'", - " - thread '", thread_name, "' in pd '", - _vm_space.pd_label(),"' stopped"); - - /* catched by Pager_entrypoint::entry() in base-sel4/pager.cc */ - throw; - } + warning("mapping failure for thread '", thread_name, + "' in pd '", _vm_space.pd_label(), "'"); + return false; } diff --git a/repos/base-sel4/src/core/spec/arm/vm_space.cc b/repos/base-sel4/src/core/spec/arm/vm_space.cc index 3cf9835fa0..088a41e9e2 100644 --- a/repos/base-sel4/src/core/spec/arm/vm_space.cc +++ b/repos/base-sel4/src/core/spec/arm/vm_space.cc @@ -13,41 +13,45 @@ /* core includes */ #include - -#include "arch_kernel_object.h" +#include static long map_page_table(Genode::Cap_sel const pagetable, Genode::Cap_sel const vroot, - Genode::addr_t const virt) + Genode::addr_t const virt) { return seL4_ARM_PageTable_Map(pagetable.value(), vroot.value(), virt, seL4_ARM_Default_VMAttributes); } + long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, Genode::addr_t const virt, - Cache const cacheability, - bool const writable, - bool const executable, + Map_attr const map_attr, bool) { seL4_ARM_Page const service = _idx_to_sel(idx.value()); seL4_ARM_PageDirectory const pd = _pd_sel.value(); - seL4_CapRights_t const rights = writable ? seL4_ReadWrite : seL4_CanRead; - seL4_ARM_VMAttributes attr = executable ? seL4_ARM_Default_VMAttributes : seL4_ARM_Default_VMAttributes_NoExecute; + seL4_CapRights_t const rights = map_attr.writeable + ? seL4_ReadWrite : seL4_CanRead; - if (cacheability == UNCACHED) + seL4_ARM_VMAttributes attr = map_attr.executable + ? seL4_ARM_Default_VMAttributes + : seL4_ARM_Default_VMAttributes_NoExecute; + + if (!map_attr.cached) attr = seL4_ARM_Uncacheable; return seL4_ARM_Page_Map(service, pd, virt, rights, attr); } + long Genode::Vm_space::_unmap_page(Genode::Cap_sel const &idx) { seL4_ARM_Page const service = _idx_to_sel(idx.value()); return seL4_ARM_Page_Unmap(service); } + long Genode::Vm_space::_invalidate_page(Genode::Cap_sel const &idx, seL4_Word const start, seL4_Word const end) @@ -63,6 +67,7 @@ long Genode::Vm_space::_invalidate_page(Genode::Cap_sel const &idx, return error; } + void Genode::Vm_space::unsynchronized_alloc_page_tables(addr_t const start, addr_t const size) { diff --git a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc index 82e67af55b..80df4afcfa 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc @@ -248,6 +248,13 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, addr_t const guest_phys, Attach_attr const attribute) { + Vm_space::Map_attr const attr { + .cached = (dsc.cacheability() == CACHED), + .write_combined = (dsc.cacheability() == WRITE_COMBINED), + .writeable = dsc.writable() && attribute.writeable, + .executable = attribute.executable, + .flush_support = false }; + Flexpage_iterator flex(dsc.phys_addr() + attribute.offset, attribute.size, guest_phys, attribute.size, guest_phys); @@ -257,11 +264,9 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, try { try { _vm_space.alloc_guest_page_tables(page.hotspot, 1 << page.log2_order); + _vm_space.map_guest(page.addr, page.hotspot, - (1 << page.log2_order) / 4096, - dsc.cacheability(), - dsc.writable() && attribute.writeable, - attribute.executable, NO_FLUSH); + (1 << page.log2_order) / 4096, attr); } catch (Page_table_registry::Mapping_cache_full full) { if (full.reason == Page_table_registry::Mapping_cache_full::MEMORY) { if (_ram_quota_guard().limit().value > 4 * 1024 * 1024) @@ -294,10 +299,7 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc, } _vm_space.map_guest(page.addr, page.hotspot, - (1 << page.log2_order) / 4096, - dsc.cacheability(), - dsc.writable() && attribute.writeable, - attribute.executable, FLUSH); + (1 << page.log2_order) / 4096, attr); } catch (Vm_space::Alloc_page_table_failed) { Genode::error("alloc page table failed"); return; diff --git a/repos/base-sel4/src/core/spec/x86/vm_space.cc b/repos/base-sel4/src/core/spec/x86/vm_space.cc index 0527e72a5a..7a2a5673ce 100644 --- a/repos/base-sel4/src/core/spec/x86/vm_space.cc +++ b/repos/base-sel4/src/core/spec/x86/vm_space.cc @@ -16,19 +16,20 @@ long Genode::Vm_space::_map_page(Genode::Cap_sel const &idx, Genode::addr_t const virt, - Cache const cacheability, - bool const writable, - bool const, bool ept) + Map_attr const map_attr, + bool const ept) { seL4_X86_Page const service = _idx_to_sel(idx.value()); seL4_X86_PageDirectory const pd = _pd_sel.value(); - seL4_CapRights_t const rights = writable ? seL4_ReadWrite : seL4_CanRead; - seL4_X86_VMAttributes attr = seL4_X86_Default_VMAttributes; + seL4_CapRights_t const rights = map_attr.writeable ? seL4_ReadWrite + : seL4_CanRead; - if (cacheability == UNCACHED) + seL4_X86_VMAttributes attr = seL4_X86_Default_VMAttributes; + + if (!map_attr.cached) attr = seL4_X86_Uncacheable; - else - if (cacheability == WRITE_COMBINED) + + if (map_attr.write_combined) attr = seL4_X86_WriteCombining; if (ept) diff --git a/repos/base/src/core/include/mapping.h b/repos/base/src/core/include/mapping.h new file mode 100644 index 0000000000..2de2dae558 --- /dev/null +++ b/repos/base/src/core/include/mapping.h @@ -0,0 +1,37 @@ +/* + * \brief Kernel-agnostic memory-mapping arguments + * \author Norman Feske + * \date 2021-04-12 + */ + +/* + * Copyright (C) 2021 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. + */ + +#ifndef _CORE__INCLUDE__MAPPING_H_ +#define _CORE__INCLUDE__MAPPING_H_ + +#include + +namespace Genode { struct Mapping; } + + +struct Genode::Mapping +{ + addr_t dst_addr; + addr_t src_addr; + size_t size_log2; + bool cached; /* RAM caching policy */ + bool io_mem; /* IO_MEM dataspace */ + bool dma_buffer; /* must be mapped in IOMMU page tables */ + bool write_combined; /* write-combined IO_MEM dataspace */ + bool writeable; + bool executable; + + void prepare_map_operation() const; +}; + +#endif /* _CORE__INCLUDE__MAPPING_H_ */ diff --git a/repos/base/src/core/region_map_component.cc b/repos/base/src/core/region_map_component.cc index 55b335b0c6..05873170c4 100644 --- a/repos/base/src/core/region_map_component.cc +++ b/repos/base/src/core/region_map_component.cc @@ -314,16 +314,16 @@ Mapping Region_map_component::create_map_item(Region_map_component *, Rm_region ®ion, addr_t const ds_offset, addr_t const region_offset, - Dataspace_component &dsc, + Dataspace_component &dataspace, addr_t const page_addr, addr_t const dst_region_size) { - addr_t const ds_base = dsc.map_src_addr(); + addr_t const ds_base = dataspace.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()); + src_fault_area.constrain(ds_base, dataspace.size()); dst_fault_area.constrain(region_offset + region.base(), dst_region_size); /* @@ -339,11 +339,16 @@ Mapping Region_map_component::create_map_item(Region_map_component *, 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, region.write() && dsc.writable(), - region.executable()); -}; + return Mapping { .dst_addr = dst_fault_area.base(), + .src_addr = src_fault_area.base(), + .size_log2 = map_size_log2, + .cached = dataspace.cacheability() == CACHED, + .io_mem = dataspace.io_mem(), + .dma_buffer = dataspace.cacheability() != CACHED, + .write_combined = dataspace.cacheability() == WRITE_COMBINED, + .writeable = region.write() && dataspace.writable(), + .executable = region.executable() }; +} Region_map::Local_addr