base: extend attach of vm_session

by offset, size, writeable and executable parameter

Issue #3111
This commit is contained in:
Alexander Boettcher 2018-11-14 14:57:45 +01:00 committed by Christian Helmuth
parent 17fda73ca1
commit 393643515c
14 changed files with 111 additions and 50 deletions

View File

@ -72,7 +72,7 @@ class Genode::Vm_session_component
Cap_mapping _task_vcpu { true };
unsigned _id_alloc { 0 };
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr);
void _detach_vm_memory(addr_t, size_t);
protected:
@ -105,7 +105,7 @@ class Genode::Vm_session_component
void _exception_handler(Signal_context_capability, Vcpu_id) { }
void _run(Vcpu_id) { }
void _pause(Vcpu_id) { }
void attach(Dataspace_capability, addr_t) override;
void attach(Dataspace_capability, addr_t, Attach_attr) override;
void attach_pic(addr_t) override { }
void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability);

View File

@ -165,22 +165,21 @@ Dataspace_capability Vm_session_component::_cpu_state(Vcpu_id const vcpu_id)
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
bool const executable,
bool const writeable)
Attach_attr const attribute)
{
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
guest_phys, dsc.size(), guest_phys);
Flexpage_iterator flex(dsc.phys_addr() + attribute.offset, attribute.size,
guest_phys, attribute.size, guest_phys);
using namespace Fiasco;
uint8_t flags = L4_FPAGE_RO;
if (dsc.writable() && writeable)
if (executable)
if (dsc.writable() && attribute.writeable)
if (attribute.executable)
flags = L4_FPAGE_RWX;
else
flags = L4_FPAGE_RW;
else
if (executable)
if (attribute.executable)
flags = L4_FPAGE_RX;
Flexpage page = flex.page();

View File

@ -80,7 +80,7 @@ class Genode::Vm_session_component
void _run(Vcpu_id);
void _pause(Vcpu_id);
void attach(Dataspace_capability, addr_t /* vm_addr */) override {
void attach(Dataspace_capability, addr_t, Attach_attr) override {
warning("Not implemented for TrustZone case"); }
void attach_pic(addr_t /* vm_addr */) override {

View File

@ -55,10 +55,9 @@ void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const vm_addr,
bool const /* executable */,
bool const /* writeable */)
Attach_attr const attribute)
{
_attach(dsc.phys_addr(), vm_addr, dsc.size());
_attach(dsc.phys_addr() + attribute.offset, vm_addr, attribute.size);
}

View File

@ -71,7 +71,7 @@ class Genode::Vm_session_component
void * _alloc_table();
void _attach(addr_t phys_addr, addr_t vm_addr, size_t size);
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr);
void _detach_vm_memory(addr_t, size_t);
protected:
@ -104,7 +104,7 @@ class Genode::Vm_session_component
void _exception_handler(Signal_context_capability, Vcpu_id);
void _run(Vcpu_id);
void _pause(Vcpu_id);
void attach(Dataspace_capability, addr_t) override;
void attach(Dataspace_capability, addr_t, Attach_attr) override;
void attach_pic(addr_t) override;
void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability) {}

View File

@ -83,7 +83,7 @@ class Genode::Vm_session_component
Kernel::pause_vm(kernel_object());
}
void attach(Dataspace_capability, addr_t) override { }
void attach(Dataspace_capability, addr_t, Attach_attr) override { }
void attach_pic(addr_t) override { }
void detach(addr_t, size_t) override { }
void _create_vcpu(Thread_capability) { }

View File

@ -93,7 +93,7 @@ class Genode::Vm_session_component
return nullptr;
}
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr);
void _detach_vm_memory(addr_t, size_t);
protected:
@ -126,7 +126,7 @@ class Genode::Vm_session_component
void _exception_handler(Signal_context_capability, Vcpu_id);
void _run(Vcpu_id);
void _pause(Vcpu_id) { }
void attach(Dataspace_capability, addr_t) override;
void attach(Dataspace_capability, addr_t, Attach_attr) override;
void attach_pic(addr_t) override {}
void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability);

View File

@ -331,20 +331,20 @@ Vm_session_component::~Vm_session_component()
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
bool const executable,
bool const writeable)
Attach_attr const attribute)
{
using Nova::Utcb;
Utcb & utcb = *reinterpret_cast<Utcb *>(Thread::myself()->utcb());
addr_t const src_pd = platform_specific().core_pd_sel();
Flexpage_iterator flex(dsc.phys_addr(), dsc.size(),
guest_phys, dsc.size(), guest_phys);
Flexpage_iterator flex(dsc.phys_addr() + attribute.offset, attribute.size,
guest_phys, attribute.size, guest_phys);
Flexpage page = flex.page();
while (page.valid()) {
Nova::Rights const map_rights (true, dsc.writable() && writeable,
executable);
Nova::Rights const map_rights (true,
dsc.writable() && attribute.writeable,
attribute.executable);
Nova::Mem_crd const mem(page.addr >> 12, page.log2_order - 12,
map_rights);

View File

@ -31,7 +31,12 @@ class Genode::Page_table_registry
{
public:
class Mapping_cache_full : Exception { };
struct Mapping_cache_full : Exception
{
enum Type { MEMORY, CAPS } reason;
Mapping_cache_full(enum Type reason) : reason(reason) { };
};
private:
@ -175,9 +180,9 @@ class Genode::Page_table_registry
break;
}
} catch (Genode::Allocator::Out_of_memory) {
throw Mapping_cache_full();
throw Mapping_cache_full(Mapping_cache_full::Type::MEMORY);
} catch (Genode::Out_of_caps) {
throw Mapping_cache_full();
throw Mapping_cache_full(Mapping_cache_full::Type::CAPS);
}
}

View File

@ -83,7 +83,7 @@ class Genode::Vm_session_component
return nullptr;
}
void _attach_vm_memory(Dataspace_component &, addr_t, bool, bool);
void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr);
void _detach_vm_memory(addr_t, size_t);
protected:
@ -116,7 +116,7 @@ class Genode::Vm_session_component
void _exception_handler(Signal_context_capability, Vcpu_id) {}
void _run(Vcpu_id) {}
void _pause(Vcpu_id);
void attach(Dataspace_capability, addr_t) override;
void attach(Dataspace_capability, addr_t, Attach_attr) override;
void attach_pic(addr_t) override {}
void detach(addr_t, size_t) override;
void _create_vcpu(Thread_capability);

View File

@ -242,16 +242,45 @@ void Vm_session_component::_pause(Vcpu_id const vcpu_id)
void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
addr_t const guest_phys,
bool const executable,
bool const writeable)
Attach_attr const attribute)
{
_vm_space.alloc_guest_page_tables(guest_phys, dsc.size());
Flexpage_iterator flex(dsc.phys_addr() + attribute.offset, attribute.size,
guest_phys, attribute.size, guest_phys);
enum { FLUSHABLE = true };
_vm_space.map_guest(dsc.phys_addr(), guest_phys, dsc.size() >> 12,
dsc.cacheability(),
dsc.writable() && writeable,
executable, FLUSHABLE);
Flexpage page = flex.page();
while (page.valid()) {
try {
_vm_space.alloc_guest_page_tables(page.hotspot, 1 << page.log2_order);
} catch (...) {
// Alloc_page_table_failed
Genode::error("alloc_guest_page_table exception");
return;
}
enum { NO_FLUSH = false, FLUSH = true };
try {
_vm_space.map_guest(page.addr, page.hotspot,
(1 << page.log2_order) / 4096,
dsc.cacheability(),
dsc.writable() && attribute.writeable,
attribute.executable, NO_FLUSH);
} catch (Page_table_registry::Mapping_cache_full full) {
if (full.reason == Page_table_registry::Mapping_cache_full::MEMORY)
throw Out_of_ram();
if (full.reason == Page_table_registry::Mapping_cache_full::CAPS)
throw Out_of_caps();
return;
} catch (Genode::Bit_allocator<4096u>::Out_of_indices) {
Genode::warning("run out of indices - flush all");
_vm_space.map_guest(page.addr, page.hotspot,
(1 << page.log2_order) / 4096,
dsc.cacheability(),
dsc.writable() && attribute.writeable,
attribute.executable, FLUSH);
}
page = flex.page();
}
}
void Vm_session_component::_detach_vm_memory(addr_t guest_phys, size_t size)

View File

@ -42,8 +42,14 @@ struct Genode::Vm_session_client : Rpc_client<Vm_session>
void run(Vcpu_id);
void pause(Vcpu_id);
void attach(Dataspace_capability ds,addr_t vm_addr) override {
call<Rpc_attach>(ds, vm_addr); }
void attach(Dataspace_capability ds, addr_t vm_addr,
Attach_attr attr = { .offset = 0,
.size = 0,
.executable = true,
.writeable = true } ) override
{
call<Rpc_attach>(ds, vm_addr, attr);
}
void detach(addr_t vm_addr, size_t size) override {
call<Rpc_detach>(vm_addr, size); }

View File

@ -28,6 +28,13 @@ struct Genode::Vm_session : Session
static const char *service_name() { return "VM"; }
struct Vcpu_id { unsigned id; };
struct Attach_attr
{
addr_t offset;
addr_t size;
bool executable;
bool writeable;
};
enum { CAP_QUOTA = 3 };
@ -45,7 +52,7 @@ struct Genode::Vm_session : Session
* \param ds dataspace to be attached
* \param vm_addr address in guest-physical memory address space
*/
virtual void attach(Dataspace_capability ds, addr_t vm_addr) = 0;
virtual void attach(Dataspace_capability ds, addr_t, Attach_attr) = 0;
/**
* Invalidate region of the guest-physical memory address space
@ -78,7 +85,7 @@ struct Genode::Vm_session : Session
GENODE_RPC_THROW(Rpc_attach, void, attach,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Region_conflict,
Invalid_dataspace),
Dataspace_capability, addr_t);
Dataspace_capability, addr_t, Attach_attr);
GENODE_RPC(Rpc_detach, void, detach, addr_t, size_t);
GENODE_RPC(Rpc_attach_pic, void, attach_pic, addr_t);
GENODE_RPC_THROW(Rpc_create_vcpu, void, _create_vcpu,

View File

@ -23,7 +23,8 @@ using Genode::addr_t;
using Genode::Vm_session_component;
void Vm_session_component::attach(Dataspace_capability const cap,
addr_t const guest_phys)
addr_t const guest_phys,
Attach_attr attribute)
{
if (!cap.valid())
throw Invalid_dataspace();
@ -39,11 +40,25 @@ void Vm_session_component::attach(Dataspace_capability const cap,
if (dsc.managed())
throw Invalid_dataspace();
bool const writeable = true;
bool const executable = true;
unsigned const offset = 0;
if (guest_phys & 0xffful || attribute.offset & 0xffful ||
attribute.size & 0xffful)
throw Invalid_dataspace();
switch (_map.alloc_addr(dsc.size(), guest_phys).value) {
if (!attribute.size) {
attribute.size = dsc.size();
if (attribute.offset < attribute.size)
attribute.size -= attribute.offset;
}
if (attribute.size > dsc.size())
attribute.size = dsc.size();
if (attribute.offset >= dsc.size() ||
attribute.offset > dsc.size() - attribute.size)
throw Invalid_dataspace();
switch (_map.alloc_addr(attribute.size, guest_phys).value) {
case Range_allocator::Alloc_return::OUT_OF_METADATA:
throw Out_of_ram();
case Range_allocator::Alloc_return::RANGE_CONFLICT:
@ -68,9 +83,10 @@ void Vm_session_component::attach(Dataspace_capability const cap,
/* store attachment info in meta data */
try {
_map.construct_metadata((void *)guest_phys,
guest_phys, dsc.size(),
dsc.writable() && writeable,
dsc, offset, *this, executable);
guest_phys, attribute.size,
dsc.writable() && attribute.writeable,
dsc, attribute.offset, *this,
attribute.executable);
} catch (Allocator_avl_tpl<Rm_region>::Assign_metadata_failed) {
error("failed to store attachment info");
throw Invalid_dataspace();
@ -86,7 +102,7 @@ void Vm_session_component::attach(Dataspace_capability const cap,
};
/* kernel specific code to attach memory to guest */
_attach_vm_memory(dsc, guest_phys, executable, writeable);
_attach_vm_memory(dsc, guest_phys, attribute);
});
}