vm_session: adjustments to work with seoul vmm

for foc, nova, sel4

Issue #3111
This commit is contained in:
Alexander Boettcher
2019-04-11 14:28:36 +02:00
committed by Christian Helmuth
parent 8950de5a89
commit cc64c43758
19 changed files with 302 additions and 187 deletions

View File

@@ -0,0 +1,19 @@
--- src/kernel/sel4/src/arch/x86/object/vcpu.c
+++ src/kernel/sel4/src/arch/x86/object/vcpu.c
@@ -760,6 +774,8 @@ decodeWriteVMCS(cap_t cap, word_t length, word_t* buffer)
case VMX_GUEST_CR3:
case VMX_CONTROL_EXCEPTION_BITMAP:
case VMX_CONTROL_ENTRY_INTERRUPTION_INFO:
+ case VMX_CONTROL_ENTRY_EXCEPTION_ERROR_CODE:
+ case VMX_CONTROL_ENTRY_INSTRUCTION_LENGTH:
break;
case VMX_CONTROL_PIN_EXECUTION_CONTROLS:
value = applyFixedBits(value, pin_control_high, pin_control_low);
@@ -909,6 +925,7 @@ decodeReadVMCS(cap_t cap, word_t length, word_t* buffer)
case VMX_GUEST_CR0:
case VMX_GUEST_CR3:
case VMX_GUEST_CR4:
+ case VMX_CONTROL_ENTRY_EXCEPTION_ERROR_CODE:
break;
default:
userError("VCPU ReadVMCS: Invalid field %lx.", (long)field);

View File

@@ -1 +1 @@
8518d37c4b819daba60648ca23a739ccf1f55460
34b8f0e01692d1d2ba2f02c98bafe321fc09de22

View File

@@ -57,14 +57,13 @@ class Genode::Vm_session_component
Rpc_entrypoint &_ep;
Constrained_ram_allocator _constrained_md_ram_alloc;
Sliced_heap _sliced_heap;
Heap _heap;
Avl_region _map { &_heap };
List<Vcpu> _vcpus { };
unsigned _id_alloc { 0 };
unsigned _pd_id { 0 };
Cap_sel _vm_page_table;
Page_table_registry _page_table_registry { _sliced_heap };
Page_table_registry _page_table_registry { _heap };
Vm_space _vm_space;
struct {
addr_t _phys;

View File

@@ -127,10 +127,15 @@ class Genode::Vm_space
Leaf_cnode _vm_cnodes[NUM_LEAF_CNODES];
public:
/**
* Allocator for the selectors within '_vm_cnodes'
*/
using Selector_allocator = Bit_allocator<1UL << NUM_VM_SEL_LOG2>;
private:
Selector_allocator _sel_alloc { };
/**
@@ -188,7 +193,7 @@ class Genode::Vm_space
* wasting of resources (idx selectors, creating kernel
* capabilities, causing kernel warning ...).
*/
return false;
return true;
}
/* allocate page-table-entry selector */
addr_t pte_idx;
@@ -277,6 +282,15 @@ class Genode::Vm_space
return Cap_sel(idx);
}
void _unmap_and_free(Cap_sel const idx, addr_t const paddr)
{
_leaf_cnode(idx.value()).remove(idx);
_sel_alloc.free(idx.value());
Untyped_memory::free_page(_phys_alloc, paddr);
}
public:
/**
@@ -348,12 +362,7 @@ class Genode::Vm_space
return true;
}, [&] (Cap_sel const &idx, addr_t const paddr) {
_leaf_cnode(idx.value()).remove(idx);
_sel_alloc.free(idx.value());
Untyped_memory::free_page(_phys_alloc, paddr);
_unmap_and_free(idx, paddr);
});
for (unsigned i = 0; i < NUM_LEAF_CNODES; i++) {

View File

@@ -77,7 +77,12 @@ void Genode::Vm_space::unsynchronized_alloc_page_tables(addr_t const start,
/* 1 MB range - page table */
Cap_sel const pt = _alloc_and_map<Page_table_kobj>(virt, map_page_table, phys);
_page_table_registry.insert_page_table(virt, pt, phys,
PAGE_TABLE_LOG2_SIZE);
try {
_page_table_registry.insert_page_table(virt, pt, phys,
PAGE_TABLE_LOG2_SIZE);
} catch (...) {
_unmap_and_free(pt, phys);
throw;
}
}
}

View File

@@ -77,7 +77,6 @@ try
Cap_quota_guard(resources.cap_quota),
_ep(ep),
_constrained_md_ram_alloc(ram, _ram_quota_guard(), _cap_quota_guard()),
_sliced_heap(_constrained_md_ram_alloc, local_rm),
_heap(_constrained_md_ram_alloc, local_rm),
_pd_id(Platform_pd::pd_id_alloc().alloc()),
_vm_page_table(platform_specific().core_sel_alloc().alloc()),
@@ -249,34 +248,53 @@ void Vm_session_component::_attach_vm_memory(Dataspace_component &dsc,
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.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);
} catch (Page_table_registry::Mapping_cache_full full) {
if (full.reason == Page_table_registry::Mapping_cache_full::MEMORY)
if (full.reason == Page_table_registry::Mapping_cache_full::MEMORY) {
if (_ram_quota_guard().limit().value > 4 * 1024 * 1024)
/* we get in trouble in core if we use too much memory */
throw Vm_space::Selector_allocator::Out_of_indices();
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");
} catch (Vm_space::Selector_allocator::Out_of_indices) {
Genode::warning("run out of indices - flush all - cap=",
_cap_quota_guard().used(), "/",
_cap_quota_guard().avail(), "/",
_cap_quota_guard().limit(), " ram=",
_ram_quota_guard().used(), "/",
_ram_quota_guard().avail(), "/",
_ram_quota_guard().limit(), " guest=",
Genode::Hex(0UL - _map.avail()));
_vm_space.map_guest(page.addr, page.hotspot,
(1 << page.log2_order) / 4096,
dsc.cacheability(),
dsc.writable() && attribute.writeable,
attribute.executable, FLUSH);
/* drop all attachment to limit ram usage of this session */
while (true) {
addr_t out_addr = 0;
if (!_map.any_block_addr(&out_addr))
break;
detach(out_addr);
}
} catch (...) {
// Alloc_page_table_failed
Genode::error("alloc_guest_page_table exception");
return;
}
page = flex.page();

View File

@@ -114,26 +114,43 @@ void Genode::Vm_space::unsynchronized_alloc_guest_page_tables(addr_t const start
addr_t constexpr PAGE_TABLE_AREA = 1UL << EPT_PAGE_TABLE_LOG2_SIZE;
addr_t virt = start & ~(PAGE_TABLE_AREA - 1);
for (; size != 0; size -= min(size, PAGE_TABLE_AREA), virt += PAGE_TABLE_AREA) {
addr_t phys = 0;
if (!_page_table_registry.page_level3_at(virt, EPT_PAGE_PDPT_LOG2_SIZE)) {
/* 512 GB range - page directory pointer table */
addr_t phys = 0;
Cap_sel const pd = _alloc_and_map<Ept_page_pointer_table_kobj>(virt, map_pdpt, phys);
_page_table_registry.insert_page_level3(virt, pd, phys, EPT_PAGE_PDPT_LOG2_SIZE);
try {
_page_table_registry.insert_page_level3(virt, pd, phys, EPT_PAGE_PDPT_LOG2_SIZE);
} catch (...) {
_unmap_and_free(pd, phys);
throw;
}
}
if (!_page_table_registry.page_directory_at(virt, EPT_PAGE_DIR_LOG2_SIZE)) {
/* 1 GB range - page directory */
addr_t phys = 0;
Cap_sel const pd = _alloc_and_map<Ept_page_directory_kobj>(virt, map_directory, phys);
_page_table_registry.insert_page_directory(virt, pd, phys,
EPT_PAGE_DIR_LOG2_SIZE);
try {
_page_table_registry.insert_page_directory(virt, pd, phys,
EPT_PAGE_DIR_LOG2_SIZE);
} catch (...) {
_unmap_and_free(pd, phys);
throw;
}
}
if (!_page_table_registry.page_table_at(virt, EPT_PAGE_TABLE_LOG2_SIZE)) {
/* 2 MB range - page table */
addr_t phys = 0;
Cap_sel const pt = _alloc_and_map<Ept_page_table_kobj>(virt, map_page_table, phys);
_page_table_registry.insert_page_table(virt, pt, phys,
EPT_PAGE_TABLE_LOG2_SIZE);
try {
_page_table_registry.insert_page_table(virt, pt, phys,
EPT_PAGE_TABLE_LOG2_SIZE);
} catch (...) {
_unmap_and_free(pt, phys);
throw;
}
}
}
}

View File

@@ -54,7 +54,7 @@ struct Vcpu : Genode::Thread
enum { EXIT_ON_HLT = 1U << 7, EXIT_ON_RDTSC = 1U << 12 };
addr_t const _vmcs_ctrl0 = EXIT_ON_HLT; // | EXIT_ON_RDTSC;
addr_t const _vmcs_ctrl0 = EXIT_ON_HLT;
enum { STACK_SIZE = 0x3000 };
@@ -132,6 +132,18 @@ struct Vcpu : Genode::Thread
local_state = _remote;
_remote = NONE;
if (local_state == PAUSE) {
_write_sel4_state(service, state);
seL4_Word badge = 0;
/* consume spurious notification - XXX better way ? */
seL4_SetMR(0, state.ip.value());
seL4_SetMR(1, _vmcs_ctrl0 | state.ctrl_primary.value());
seL4_SetMR(2, state.inj_info.value() & ~0x3000U);
if (seL4_VMEnter(&badge) == SEL4_VMENTER_RESULT_FAULT)
Genode::error("invalid state ahead ", badge);
}
}
if (local_state == NONE) {
@@ -141,16 +153,6 @@ struct Vcpu : Genode::Thread
if (local_state == PAUSE) {
_write_sel4_state(service, state);
seL4_Word badge = 0;
/* consume spurious notification - XXX better way ? */
seL4_SetMR(0, state.ip.value());
seL4_SetMR(1, _vmcs_ctrl0 | state.ctrl_primary.value());
seL4_SetMR(2, state.inj_info.value() & ~0x3000);
if (seL4_VMEnter(&badge) == SEL4_VMENTER_RESULT_FAULT)
Genode::error("invalid state ahead ", badge);
state = Vm_state {};
state.ip.value(seL4_GetMR(SEL4_VMENTER_CALL_EIP_MR));
@@ -180,7 +182,7 @@ struct Vcpu : Genode::Thread
seL4_SetMR(0, state.ip.value());
seL4_SetMR(1, _vmcs_ctrl0 | state.ctrl_primary.value());
seL4_SetMR(2, state.inj_info.value() & ~0x3000);
seL4_SetMR(2, state.inj_info.value() & ~0x3000U);
seL4_Word badge = 0;
seL4_Word res = seL4_VMEnter(&badge);
@@ -255,8 +257,6 @@ struct Vcpu : Genode::Thread
RSP = 0x681c,
RIP = 0x681e,
INST_LEN = 0x440c,
EFER = 0x2806,
CTRL_0 = 0x4002,
@@ -322,9 +322,11 @@ struct Vcpu : Genode::Thread
INTR_INFO = 0x4016,
INTR_ERROR = 0x4018,
ENTRY_INST_LEN = 0x401a,
IDT_INFO = 0x4408,
IDT_ERROR = 0x440a,
EXIT_INST_LEN = 0x440c,
TSC_OFF_LO = 0x2010,
TSC_OFF_HI = 0x2011,
@@ -438,7 +440,9 @@ struct Vcpu : Genode::Thread
}
if (state.inj_info.valid()) {
addr_t ctrl_0 = _read_vmcs(service, Vmcs::CTRL_0);
addr_t ctrl_0 = state.ctrl_primary.valid() ?
state.ctrl_primary.value() :
_read_vmcs(service, Vmcs::CTRL_0);
if (state.inj_info.value() & 0x2000)
Genode::warning("inj_info for NMI not supported");
@@ -451,10 +455,8 @@ struct Vcpu : Genode::Thread
state.ctrl_primary.value(ctrl_0);
}
if (state.inj_error.valid()) {
/* not supported by seL4 */
//_write_vmcs(service, Vmcs::INTR_ERROR, state.inj_error.value());
}
if (state.inj_error.valid())
_write_vmcs(service, Vmcs::INTR_ERROR, state.inj_error.value());
if (state.flags.valid())
_write_vmcs(service, Vmcs::RFLAGS, state.flags.value());
@@ -465,6 +467,9 @@ struct Vcpu : Genode::Thread
if (state.ip.valid())
_write_vmcs(service, Vmcs::RIP, state.ip.value());
if (state.ip_len.valid())
_write_vmcs(service, Vmcs::ENTRY_INST_LEN, state.ip_len.value());
if (state.efer.valid())
_write_vmcs(service, Vmcs::EFER, state.efer.value());
@@ -589,11 +594,12 @@ struct Vcpu : Genode::Thread
uint16_t _read_vmcs_16(seL4_X86_VCPU const service, enum Vmcs const field) {
return _read_vmcsX<uint16_t>(service, field); }
uint16_t _read_vmcs_32(seL4_X86_VCPU const service, enum Vmcs const field) {
uint32_t _read_vmcs_32(seL4_X86_VCPU const service, enum Vmcs const field) {
return _read_vmcsX<uint32_t>(service, field); }
void _read_sel4_state_async(seL4_X86_VCPU const service, Vm_state &state)
{
#if 0
state.ax.value(state.ax.value()); /* XXX ? */
state.cx.value(state.cx.value());
state.dx.value(state.dx.value());
@@ -602,11 +608,12 @@ struct Vcpu : Genode::Thread
state.di.value(state.di.value()); /* XXX ? */
state.si.value(state.si.value());
state.bp.value(state.bp.value());
#endif
state.flags.value(_read_vmcs(service, Vmcs::RFLAGS));
state.ip.value(_read_vmcs(service, Vmcs::RIP));
state.ip_len.value(_read_vmcs(service, Vmcs::INST_LEN));
state.ip_len.value(_read_vmcs(service, Vmcs::EXIT_INST_LEN));
state.cr3.value(_read_vmcs(service, Vmcs::CR3));
@@ -630,10 +637,8 @@ struct Vcpu : Genode::Thread
addr_t const cr0_shadow = _read_vmcs(service, Vmcs::CR0_SHADOW);
state.cr0.value((cr0 & ~cr0_mask) | (cr0_shadow & cr0_mask));
if (state.cr0.value() != cr0_shadow) {
Genode::error("reset cr0_shadow to cr0 ", Genode::Hex(cr0), " ", Genode::Hex(cr0_shadow), "->", Genode::Hex(state.cr0.value()));
if (state.cr0.value() != cr0_shadow)
_write_vmcs(service, Vmcs::CR0_SHADOW, state.cr0.value());
}
}
/* cr2 not supported on seL4 */
@@ -644,10 +649,8 @@ struct Vcpu : Genode::Thread
addr_t const cr4_shadow = _read_vmcs(service, Vmcs::CR4_SHADOW);
state.cr4.value((cr4 & ~cr4_mask) | (cr4_shadow & cr4_mask));
if (state.cr4.value() != cr4_shadow) {
Genode::error("reset cr4_shadow to cr4 ", Genode::Hex(cr4), " ", Genode::Hex(cr4_shadow), "->", Genode::Hex(state.cr4.value()));
if (state.cr4.value() != cr4_shadow)
_write_vmcs(service, Vmcs::CR4_SHADOW, state.cr4.value());
}
}
typedef Genode::Vm_state::Segment Segment;
@@ -711,9 +714,7 @@ struct Vcpu : Genode::Thread
state.exit_reason == VMEXIT_RECALL)
{
state.inj_info.value(_read_vmcs(service, Vmcs::INTR_INFO));
/* no support by seL4 to read this value */
state.inj_error.value(0);
//state.inj_error.value(_read_vmcs(service, Vmcs::INTR_ERROR));
state.inj_error.value(_read_vmcs(service, Vmcs::INTR_ERROR));
} else {
state.inj_info.value(_read_vmcs(service, Vmcs::IDT_INFO));
state.inj_error.value(_read_vmcs(service, Vmcs::IDT_ERROR));
@@ -768,7 +769,7 @@ struct Vcpu : Genode::Thread
{
Lock::Guard guard(_remote_lock);
if (_remote == RUN)
if (_remote == RUN || _remote == PAUSE)
return;
_remote = RUN;