diff --git a/repos/base-hw/include/spec/x86_64/cpu/vcpu_state_virtualization.h b/repos/base-hw/include/spec/x86_64/cpu/vcpu_state_virtualization.h index ba3ad7f5d9..64cb7f0bf6 100644 --- a/repos/base-hw/include/spec/x86_64/cpu/vcpu_state_virtualization.h +++ b/repos/base-hw/include/spec/x86_64/cpu/vcpu_state_virtualization.h @@ -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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h index 67792284a3..9ee66acbfc 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/board.h +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/board.h @@ -23,6 +23,9 @@ #include #include +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 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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc index ff1eac5b18..02f58894cb 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/kernel/vm.cc @@ -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(vcpu_data_ptr, id)), + vmcb(*Genode::construct_at(virt_area, id)), + vmcb_phys_addr(vmcb_phys_addr), regs(1) { regs->trapno = TRAP_VMEXIT; diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h b/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h index 7c6f970724..6dce4cea24 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/svm.h @@ -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(this); - } - /* * AMD Manual Vol. 2, Table B-1: VMCB Layout, Control Area */ diff --git a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc index 515ecc65dd..c454a190aa 100644 --- a/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/x86_64/virtualization/vm_session_component.cc @@ -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 *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 *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 *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; }