hw: generalize virtualization memory

The initial vCPU memory was written for AMD's SVM.

Make the vCPU memory provider virtualization technology agnostic.

Issue #5113
This commit is contained in:
Benjamin Lamowski 2024-01-24 17:39:32 +01:00 committed by Christian Helmuth
parent e82859444e
commit 3a88d133ed
5 changed files with 69 additions and 42 deletions

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
* Copyright (C) 2022-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.
@ -23,15 +23,20 @@ namespace Genode {
/**
* CPU context of a virtual machine
*/
struct Vcpu_data;
}
struct Vcpu_data
{
void * virt_area;
addr_t phys_addr;
Vcpu_state *vcpu_state;
struct Genode::Vcpu_data
{
alignas(Genode::get_page_size())
uint8_t vmcb[get_page_size()];
Genode::addr_t vmcb_phys_addr;
Genode::Vcpu_state * vcpu_state;
static constexpr size_t num_pages() {
return 3;
}
static constexpr size_t size() {
return get_page_size() * num_pages();
}
};
};
#endif /* _INCLUDE__SPEC__PC__VM_STATE_H_ */

View File

@ -23,6 +23,9 @@
#include <spec/x86_64/virtualization/svm.h>
#include <cpu.h>
using Genode::addr_t;
using Genode::uint64_t;
namespace Board {
using Vm_page_table = Hw::Page_table;
@ -62,15 +65,18 @@ namespace Kernel {
struct Board::Vcpu_context
{
Vcpu_context(unsigned id, void *vcpu_data_ptr);
Vcpu_context(unsigned id, void *virt_area, addr_t vmcb_phys_addr);
void initialize_svm(Kernel::Cpu &cpu, void *table);
void read_vcpu_state(Genode::Vcpu_state &state);
void write_vcpu_state(Genode::Vcpu_state &state);
void read_vcpu_state(Vcpu_state &state);
void write_vcpu_state(Vcpu_state &state);
Vmcb &vmcb;
addr_t vmcb_phys_addr;
Vmcb &vmcb;
Genode::Align_at<Core::Cpu::Context> regs;
Genode::uint64_t tsc_aux_host = 0U;
Genode::uint64_t tsc_aux_guest = 0U;
Genode::uint64_t exitcode = EXIT_INIT;
uint64_t tsc_aux_host = 0U;
uint64_t tsc_aux_guest = 0U;
uint64_t exitcode = EXIT_INIT;
};
#endif /* _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2022-2023 Genode Labs GmbH
* Copyright (C) 2022-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.
@ -47,7 +47,7 @@ Vm::Vm(Irq::Pool & user_irq_pool,
_state(*data.vcpu_state),
_context(context),
_id(id),
_vcpu_context(id.id, data.vmcb)
_vcpu_context(id.id, data.virt_area, data.phys_addr)
{
affinity(cpu);
}
@ -78,9 +78,8 @@ void Vm::proceed(Cpu & cpu)
* we can pop it later
*/
_vcpu_context.regs->trapno = _vcpu_context.vmcb.root_vmcb_phys;
Hypervisor::switch_world(_vcpu_context.vmcb.vcpu_data()->vmcb_phys_addr,
(addr_t) &_vcpu_context.regs->r8,
_vcpu_context.regs->fpu_context());
Hypervisor::switch_world( _vcpu_context.vmcb_phys_addr,
(addr_t)&_vcpu_context.regs->r8, _vcpu_context.regs->fpu_context());
/*
* This will fall into an interrupt or otherwise jump into
* _kernel_entry
@ -175,9 +174,12 @@ void Vm::_sync_from_vmm()
}
Board::Vcpu_context::Vcpu_context(unsigned id, void *vcpu_data_ptr)
Board::Vcpu_context::Vcpu_context(unsigned id,
void *virt_area,
addr_t vmcb_phys_addr)
:
vmcb(*Genode::construct_at<Vmcb>(vcpu_data_ptr, id)),
vmcb(*Genode::construct_at<Vmcb>(virt_area, id)),
vmcb_phys_addr(vmcb_phys_addr),
regs(1)
{
regs->trapno = TRAP_VMEXIT;

View File

@ -154,11 +154,6 @@ struct alignas(Genode::get_page_size()) Board::Vmcb
sizeof(Board::Vmcb_state_save_area) -
Board::Vmcb_control_area::total_size];
Genode::Vcpu_data * vcpu_data()
{
return reinterpret_cast<Genode::Vcpu_data *>(this);
}
/*
* AMD Manual Vol. 2, Table B-1: VMCB Layout, Control Area
*/

View File

@ -6,7 +6,7 @@
*/
/*
* Copyright (C) 2015-2023 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.
@ -103,21 +103,40 @@ static Vmid_allocator &alloc()
Genode::addr_t Vm_session_component::_alloc_vcpu_data(Genode::addr_t ds_addr)
{
void * vcpu_data_ptr = cma()
.alloc_aligned(sizeof(Board::Vcpu_data), 12)
.convert<void *>(
[&](void *ptr) { return ptr; },
[&](Range_allocator::Alloc_error) -> void * {
/* XXX handle individual error conditions */
error("failed to allocate kernel object");
throw Insufficient_ram_quota();
}
);
/*
* XXX these allocations currently leak memory on VM Session
* destruction. This cannot be easily fixed because the
* Core Mem Allocator does not implement free().
*
* Normally we would use constrained_md_ram_alloc to make the allocation,
* but to get the physical address of the pages in virt_area, we need
* to use the Core Mem Allocator.
*/
Genode::Vcpu_data* vcpu_data = (Genode::Vcpu_data *) vcpu_data_ptr;
vcpu_data->vcpu_state = (Genode::Vcpu_state *) ds_addr;
vcpu_data->vmcb_phys_addr = (addr_t)cma().phys_addr(vcpu_data->vmcb);
return (Genode::addr_t) vcpu_data_ptr;
Vcpu_data * vcpu_data = (Vcpu_data *) cma()
.try_alloc(sizeof(Board::Vcpu_data))
.convert<void *>(
[&](void *ptr) { return ptr; },
[&](Range_allocator::Alloc_error) -> void * {
/* XXX handle individual error conditions */
error("failed to allocate kernel object");
throw Insufficient_ram_quota();
});
vcpu_data->virt_area = cma()
.alloc_aligned(Vcpu_data::size(), 12)
.convert<void *>(
[&](void *ptr) { return ptr; },
[&](Range_allocator::Alloc_error) -> void * {
/* XXX handle individual error conditions */
error("failed to allocate kernel object");
throw Insufficient_ram_quota();
});
vcpu_data->vcpu_state = (Vcpu_state *) ds_addr;
vcpu_data->phys_addr = (addr_t)cma().phys_addr(vcpu_data->virt_area);
return (Genode::addr_t) vcpu_data;
}