Skip to content

Commit

Permalink
hw: add support for VMX
Browse files Browse the repository at this point in the history
Add support for Intel's Virtual Machine Extensions with nested paging.

Fixes genodelabs#5128
  • Loading branch information
atopia committed Feb 28, 2024
1 parent 140be67 commit eb2602e
Show file tree
Hide file tree
Showing 10 changed files with 1,851 additions and 35 deletions.
1 change: 1 addition & 0 deletions repos/base-hw/lib/mk/spec/x86_64/core-hw-pc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ SRC_CC += kernel/cpu_mp.cc
SRC_CC += kernel/vm_thread_on.cc
SRC_CC += spec/x86_64/virtualization/kernel/vm.cc
SRC_CC += spec/x86_64/virtualization/kernel/svm.cc
SRC_CC += spec/x86_64/virtualization/kernel/vmx.cc
SRC_CC += spec/x86_64/virtualization/vm_session_component.cc
SRC_CC += vm_session_common.cc
SRC_CC += vm_session_component.cc
Expand Down
5 changes: 3 additions & 2 deletions repos/base-hw/src/core/spec/x86_64/platform_support.cc
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
* \brief Platform implementations specific for x86_64
* \author Reto Buerki
* \author Benjamin Lamowski
* \date 2015-05-04
*/

/*
* Copyright (C) 2015-2017 Genode Labs GmbH
* Copyright (C) 2015-2024 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.
Expand Down Expand Up @@ -55,7 +56,7 @@ void Platform::_init_additional_platform_info(Xml_generator &xml)
xml.node("hardware", [&]() {
xml.node("features", [&] () {
xml.attribute("svm", Hw::Virtualization_support::has_svm());
xml.attribute("vmx", false);
xml.attribute("vmx", Hw::Virtualization_support::has_vmx());
});
xml.node("tsc", [&]() {
xml.attribute("invariant", Hw::Lapic::invariant_tsc());
Expand Down
22 changes: 18 additions & 4 deletions repos/base-hw/src/core/spec/x86_64/virtualization/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
#include <kernel/configuration.h>
#include <kernel/irq.h>

#include <cpu.h>
#include <cpu/vcpu_state_virtualization.h>
#include <hw/spec/x86_64/page_table.h>
#include <hw/spec/x86_64/x86_64.h>
#include <spec/x86_64/virtualization/svm.h>
#include <cpu.h>
#include <spec/x86_64/virtualization/vmx.h>


using Genode::addr_t;;
Expand Down Expand Up @@ -52,6 +54,7 @@ namespace Board {
enum Custom_trapnos {
TRAP_VMEXIT = 256,
TRAP_VMSKIP = 257,
TRAP_VMERROR = 258,
};
};

Expand All @@ -68,6 +71,7 @@ struct Board::Vcpu_context
void initialize(Kernel::Cpu &cpu, addr_t table_phys_addr);
void read_vcpu_state(Vcpu_state &state);
void write_vcpu_state(Vcpu_state &state);
bool handle_vm_exit(unsigned &irq);

Genode::Align_at<Core::Cpu::Context> regs;

Expand All @@ -80,9 +84,19 @@ struct Board::Vcpu_context
static Virt_interface &detect_virtualization(Vcpu_data &vcpu_data,
unsigned id)
{
return *Genode::construct_at<Vmcb>(
vcpu_data.virt_interface_ptr(),
vcpu_data, id);
if (Hw::Virtualization_support::has_svm())
return *Genode::construct_at<Vmcb>(
vcpu_data.virt_interface_ptr(),
vcpu_data,
id);
else if (Hw::Virtualization_support::has_vmx()) {
return *Genode::construct_at<Vmcs>(
vcpu_data.virt_interface_ptr(),
vcpu_data);
} else {
Genode::error( "No virtualization support detected.");
throw Core::Service_denied();
}
}
};

Expand Down
63 changes: 41 additions & 22 deletions repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
#include <kernel/vm.h>
#include <kernel/main.h>

#include <hw/spec/x86_64/x86_64.h>
#include <virtualization/hypervisor.h>
#include <virtualization/svm.h>
#include <hw/spec/x86_64/x86_64.h>
#include <virtualization/vmx.h>

using namespace Genode;

Expand Down Expand Up @@ -86,15 +87,26 @@ void Vm::exception(Cpu & cpu)
{
using namespace Board;

bool pause = false;
addr_t table_phys_addr { 0 };
unsigned irq_id { TRAP_VMSKIP };

switch (_vcpu_context.regs->trapno) {
case Cpu_state::INTERRUPTS_START ... Cpu_state::INTERRUPTS_END:
_interrupt(_user_irq_pool, cpu.id());
break;
case TRAP_VMEXIT:
/* exception method was entered because of a VMEXIT */
break;
return;
case TRAP_VMSKIP:
/* exception method was entered without exception */
/* vCPU is running for the first time */
table_phys_addr =
reinterpret_cast<addr_t>(_id.table);
_vcpu_context.initialize(cpu, table_phys_addr);
_vcpu_context.tsc_aux_host = cpu.id();
_vcpu_context.exitcode = EXIT_STARTUP;
pause = true;
break;
case TRAP_VMEXIT: [[fallthrough]];
case TRAP_VMERROR:
pause = _vcpu_context.handle_vm_exit(irq_id);
break;
default:
error("VM: triggered unknown exception ",
Expand All @@ -107,24 +119,20 @@ void Vm::exception(Cpu & cpu)
return;
};

if (_vcpu_context.exitcode == EXIT_INIT) {
addr_t table_phys_addr =
reinterpret_cast<addr_t>(_id.table);
_vcpu_context.initialize(cpu, table_phys_addr);
_vcpu_context.tsc_aux_host = cpu.id();
_vcpu_context.exitcode = EXIT_STARTUP;
_pause_vcpu();
_context.submit(1);
return;
if ((pause == false) && (irq_id != TRAP_VMSKIP)) {
/* XXX consolidate with Cpu_job::_interrupt */
if (!_cpu->handle_if_cpu_local_interrupt(irq_id)) {
/* it isn't a CPU-local IRQ, so, it must be a user IRQ */
User_irq * irq = User_irq::object(_user_irq_pool, irq_id);
if (irq) irq->occurred();
else Genode::raw("Unknown interrupt ", irq_id);
}
_cpu->pic().finish_request();
}

unsigned irq { };
bool error { false };
_vcpu_context.exitcode = _vcpu_context.virt.handle_vm_exit(irq, error);

if (_vcpu_context.exitcode != EXIT_PAUSED) {
_pause_vcpu();
_context.submit(1);
if (pause) {
_pause_vcpu();
_context.submit(1);
}
}

Expand Down Expand Up @@ -240,3 +248,14 @@ void Board::Vcpu_context::initialize(Kernel::Cpu &cpu, addr_t table_phys_addr)
{
virt.initialize(cpu, table_phys_addr, *regs);
}


bool Board::Vcpu_context::handle_vm_exit(unsigned &irq)
{
exitcode = virt.handle_vm_exit(irq, (regs->trapno == TRAP_VMERROR));

if (exitcode == EXIT_PAUSED)
return false;
else
return true;
}

0 comments on commit eb2602e

Please sign in to comment.