core: kernel-agnostic 'Mapping' type

This patch unifies the core-internal 'Mapping' type across all base
platforms.

As one minor downside on seL4, the diagnostic error messages when
observing faults other than page faults no longer print the faulting
thread and PD names.

Issue #2243
This commit is contained in:
Norman Feske 2021-04-09 18:47:28 +02:00
parent 7ae1210531
commit dc89ebf978
23 changed files with 334 additions and 544 deletions

View File

@ -17,7 +17,6 @@
/* Genode includes */
#include <base/cache.h>
#include <base/ipc.h>
#include <base/stdint.h>
#include <base/native_capability.h>
#include <util/touch.h>
@ -26,66 +25,12 @@
/* core includes */
#include <util.h>
#include <mapping.h>
/* L4/Fiasco includes */
#include <fiasco/syscall.h>
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

View File

@ -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);

View File

@ -16,7 +16,6 @@
#define _CORE__INCLUDE__IPC_PAGER_H_
/* Genode includes */
#include <base/cache.h>
#include <base/ipc.h>
#include <base/stdint.h>
#include <base/native_capability.h>
@ -28,67 +27,15 @@
/* base-internal includes */
#include <base/internal/native_thread.h>
/* core-local includes */
#include <mapping.h>
/* Fiasco.OC includes */
#include <foc/syscall.h>
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);

View File

@ -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();

View File

@ -27,6 +27,7 @@
/* core-local includes */
#include <kernel/signal_receiver.h>
#include <hw/mapping.h>
#include <mapping.h>
#include <object.h>
#include <rpc_cap_factory.h>
@ -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:

View File

@ -61,11 +61,24 @@ void Pager_entrypoint::entry()
if (!locked_ptr.valid()) continue;
Hw::Address_space * as = static_cast<Hw::Address_space*>(&*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 { }

View File

@ -19,48 +19,38 @@
#include <base/ipc.h>
#include <base/stdint.h>
/* core-local includes */
#include <mapping.h>
/* NOVA includes */
#include <nova/syscalls.h>
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

View File

@ -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));
}

View File

@ -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<addr_t>(mapping.dst_addr(), map_crd_size) , " "
Hex_range<addr_t>(mapping.dst_addr, map_size) , " "
"eagerly error=", err);
}
return mapped;
};

View File

@ -14,60 +14,16 @@
#ifndef _CORE__INCLUDE__IPC_PAGER_H_
#define _CORE__INCLUDE__IPC_PAGER_H_
#include <base/cache.h>
/* Genode includes */
#include <base/ipc.h>
#include <base/stdint.h>
/* base-internal includes */
#include <base/internal/okl4.h>
namespace Genode {
/* core-local includes */
#include <mapping.h>
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

View File

@ -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());

View File

@ -22,64 +22,12 @@
/* core-local includes */
#include <kip.h>
#include <mapping.h>
/* base-internal includes */
#include <base/internal/pistachio.h>
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

View File

@ -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);
}

View File

@ -14,73 +14,15 @@
#ifndef _CORE__INCLUDE__IPC_PAGER_H_
#define _CORE__INCLUDE__IPC_PAGER_H_
#include <base/cache.h>
/* Genode includes */
#include <base/ipc.h>
#include <base/stdint.h>
namespace Genode {
class Mapping;
class Ipc_pager;
}
/* core-local includes */
#include <mapping.h>
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

View File

@ -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;
}

View File

@ -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 <typename FN>
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);
}
}

View File

@ -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), "'");
}

View File

@ -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;
}

View File

@ -13,41 +13,45 @@
/* core includes */
#include <vm_space.h>
#include "arch_kernel_object.h"
#include <arch_kernel_object.h>
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)
{

View File

@ -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;

View File

@ -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)

View File

@ -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 <base/stdint.h>
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_ */

View File

@ -314,16 +314,16 @@ Mapping Region_map_component::create_map_item(Region_map_component *,
Rm_region &region,
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