mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 02:40:08 +00:00
parent
daafe3f4e2
commit
9489bf41a5
@ -1,12 +1,13 @@
|
||||
/*
|
||||
* \brief CPU context of a virtual machine for TrustZone
|
||||
* \author Stefan Kalkowski
|
||||
* \author Martin Stein
|
||||
* \date 2013-10-30
|
||||
* \brief CPU context of a virtual machine for TrustZone
|
||||
* \author Stefan Kalkowski
|
||||
* \author Martin Stein
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2013-10-30
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2023 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.
|
||||
@ -20,6 +21,8 @@
|
||||
|
||||
namespace Genode {
|
||||
|
||||
enum { VCPU_EXCEPTION_STARTUP = 0xfe };
|
||||
|
||||
/**
|
||||
* CPU context of a virtual machine
|
||||
*/
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief CPU, PIC, and timer context of a virtual machine
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-10
|
||||
* \brief CPU, PIC, and timer context of a virtual machine
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2015-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2015-2023 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.
|
||||
@ -19,6 +20,8 @@
|
||||
|
||||
namespace Genode {
|
||||
|
||||
enum { VCPU_EXCEPTION_STARTUP = 0xfe };
|
||||
|
||||
/**
|
||||
* CPU context of a virtual machine
|
||||
*/
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief CPU, PIC, and timer context of a virtual machine
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-10
|
||||
* \brief CPU, PIC, and timer context of a virtual machine
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2015-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2015-2023 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.
|
||||
@ -19,6 +20,8 @@
|
||||
|
||||
namespace Genode {
|
||||
|
||||
enum { VCPU_EXCEPTION_STARTUP = 0xfe };
|
||||
|
||||
/**
|
||||
* CPU context of a virtual machine
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@
|
||||
#define _INCLUDE__SPEC__PC__VM_STATE_H_
|
||||
|
||||
/* x86 CPU state */
|
||||
#include <virtualization/extended_vcpu_state.h>
|
||||
#include <cpu/vcpu_state.h>
|
||||
#include <virtualization/svm.h>
|
||||
|
||||
namespace Genode {
|
||||
@ -24,8 +24,13 @@ namespace Genode {
|
||||
* CPU context of a virtual machine
|
||||
*/
|
||||
struct Vm_data;
|
||||
|
||||
struct Vm_state;
|
||||
}
|
||||
|
||||
struct Genode::Vm_state : Genode::Vcpu_state
|
||||
{
|
||||
};
|
||||
|
||||
struct Genode::Vm_data
|
||||
{
|
||||
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* \brief Extended vCPU state
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2023-05-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__SPEC__X86_64_VIRTUALIZATION__EXTENDED_VCPU_STATE_H
|
||||
#define _INCLUDE__SPEC__X86_64_VIRTUALIZATION__EXTENDED_VCPU_STATE_H
|
||||
|
||||
/* x86 CPU state */
|
||||
#include <cpu/vcpu_state.h>
|
||||
#include <cpu/atomic.h>
|
||||
|
||||
namespace Genode {
|
||||
struct Vm_state;
|
||||
struct Vcpu_run_state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run state of the Vcpu to sync between the VMM library and the
|
||||
* kernel.
|
||||
*/
|
||||
class Genode::Vcpu_run_state : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
enum Value : int {
|
||||
/*
|
||||
* vCPU isn't initialized yet. Needed for initialization in
|
||||
* Vm::exception() and to block premature pause requests.
|
||||
*/
|
||||
STARTUP = 0,
|
||||
|
||||
/*
|
||||
* The vCPU is runable but not yet running. Used in pause() to
|
||||
* make the vCPU run once (RUN_ONCE)
|
||||
*/
|
||||
RUNNABLE = 1,
|
||||
|
||||
/*
|
||||
* The vCPU hasn't run yet, but a pause has been requested.
|
||||
* Run the vCPU once, dispatch the result and then issue a pause
|
||||
* request.
|
||||
*/
|
||||
RUN_ONCE = 2,
|
||||
|
||||
/*
|
||||
* The vCPU is running. Used in pause() to force an exit only when the
|
||||
* vCPU is actually running.
|
||||
*/
|
||||
RUNNING = 3,
|
||||
|
||||
/*
|
||||
* vCPU has exited because of an external interrupt and could run
|
||||
* without state syncing. Needed to skip state syncing in Vm::proceed
|
||||
* and to request updating the state from the vCPU in case of a
|
||||
* Vcpu::pause() (SYNC_FROM_VCPU)
|
||||
*/
|
||||
INTERRUPTIBLE = 4,
|
||||
|
||||
/*
|
||||
* vCPU is running and is being forced out by a thread on a remote core
|
||||
* by signaling the vCPU's handler. Causes a state writeback and
|
||||
* Vm::pause() after an external interrupt VM exit.
|
||||
*/
|
||||
EXITING = 5,
|
||||
|
||||
/*
|
||||
* A Vcpu::pause() request was issued while the vCPU was INTERRUPTIBLE.
|
||||
* Skips the next run in Vm::proceed() and causes a full pause exit in
|
||||
* the subsequent Vm::exception().
|
||||
*/
|
||||
SYNC_FROM_VCPU = 6,
|
||||
|
||||
/*
|
||||
* The vCPU is dispatching a signal to the handler in the VMM. Needed to
|
||||
* distinguish between a dispatch from the vCPU and a dispatch from an
|
||||
* assynchronous pause request.
|
||||
*/
|
||||
DISPATCHING = 7,
|
||||
|
||||
/*
|
||||
* The vCPU needs to first dispatch an exit in the VMM, and a pause
|
||||
* request needs to be injected right after.
|
||||
*/
|
||||
DISPATCHING_PAUSED = 8,
|
||||
|
||||
/*
|
||||
* An exit has been dispatched to the VMM. Needed to let
|
||||
* an assynchrous pause request dispatch a new signal.
|
||||
*/
|
||||
DISPATCHED = 9,
|
||||
|
||||
/*
|
||||
* The vCPU was RUNNABLE, or DISPATCHED but a pause has been requested.
|
||||
* Used to create a pause exit in the wrapper.
|
||||
*/
|
||||
PAUSING = 10,
|
||||
|
||||
/*
|
||||
* The vCPU handler in the VMM is dispatching and a pause
|
||||
* signal has been issued. Needed to skip more pause requests.
|
||||
* FIXME
|
||||
*/
|
||||
PAUSED = 11
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
int _value { }; /* base type of Vcpu_run_state */
|
||||
|
||||
public:
|
||||
|
||||
Value value() const { return Value(_value); }
|
||||
|
||||
void set(Value const &value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
bool cas(Value cmp_val, Value new_val)
|
||||
{
|
||||
return cmpxchg(&_value, cmp_val, new_val);
|
||||
}
|
||||
};
|
||||
|
||||
struct Genode::Vm_state : Genode::Vcpu_state
|
||||
{
|
||||
Vcpu_run_state run_state;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__SPEC__X86_64_VIRTUALIZATION__EXTENDED_VCPU_STATE_H */
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Martin Stein
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2013-10-30
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2023 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.
|
||||
@ -62,6 +63,16 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
Scheduler_state _scheduled = INACTIVE;
|
||||
Board::Vcpu_context _vcpu_context;
|
||||
|
||||
void _sync_to_vmm();
|
||||
void _sync_from_vmm();
|
||||
void _pause_vcpu()
|
||||
{
|
||||
if (_scheduled != INACTIVE)
|
||||
Cpu_job::_deactivate_own_share();
|
||||
|
||||
_scheduled = INACTIVE;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -125,16 +136,15 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
|
||||
void run()
|
||||
{
|
||||
_sync_from_vmm();
|
||||
if (_scheduled != ACTIVE) Cpu_job::_activate_own_share();
|
||||
_scheduled = ACTIVE;
|
||||
}
|
||||
|
||||
void pause()
|
||||
{
|
||||
if (_scheduled != INACTIVE)
|
||||
Cpu_job::_deactivate_own_share();
|
||||
|
||||
_scheduled = INACTIVE;
|
||||
_pause_vcpu();
|
||||
_sync_to_vmm();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
/*
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Martin Stein
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2013-10-30
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Martin Stein
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2013-10-30
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2023 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.
|
||||
@ -35,6 +36,10 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
_vcpu_context(cpu)
|
||||
{
|
||||
affinity(cpu);
|
||||
/* once constructed, exit with a startup exception */
|
||||
pause();
|
||||
_state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP;
|
||||
_context.submit(1);
|
||||
}
|
||||
|
||||
|
||||
@ -79,3 +84,11 @@ void Vm::proceed(Cpu & cpu)
|
||||
|
||||
monitor_mode_enter_normal_world(_state, (void*) cpu.stack_start());
|
||||
}
|
||||
|
||||
|
||||
void Vm::_sync_to_vmm()
|
||||
{}
|
||||
|
||||
|
||||
void Vm::_sync_from_vmm()
|
||||
{}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-10
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2015-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2015-2023 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.
|
||||
@ -147,6 +148,10 @@ Kernel::Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
_vcpu_context(cpu)
|
||||
{
|
||||
affinity(cpu);
|
||||
/* once constructed, exit with a startup exception */
|
||||
pause();
|
||||
_state.cpu_exception = Genode::VCPU_EXCEPTION_STARTUP;
|
||||
_context.submit(1);
|
||||
}
|
||||
|
||||
|
||||
@ -201,6 +206,14 @@ void Kernel::Vm::proceed(Cpu & cpu)
|
||||
}
|
||||
|
||||
|
||||
void Vm::_sync_to_vmm()
|
||||
{}
|
||||
|
||||
|
||||
void Vm::_sync_from_vmm()
|
||||
{}
|
||||
|
||||
|
||||
void Vm::inject_irq(unsigned irq)
|
||||
{
|
||||
_state.irqs.last_irq = irq;
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-10
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Stefan Kalkowski
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2015-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2015-2023 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.
|
||||
@ -149,6 +150,11 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
_state.ccsidr_data_el1[level] = Cpu::Ccsidr_el1::read();
|
||||
}
|
||||
}
|
||||
|
||||
/* once constructed, exit with a startup exception */
|
||||
pause();
|
||||
_state.exception_type = Genode::VCPU_EXCEPTION_STARTUP;
|
||||
_context.submit(1);
|
||||
}
|
||||
|
||||
|
||||
@ -208,6 +214,14 @@ void Vm::proceed(Cpu & cpu)
|
||||
}
|
||||
|
||||
|
||||
void Vm::_sync_to_vmm()
|
||||
{}
|
||||
|
||||
|
||||
void Vm::_sync_from_vmm()
|
||||
{}
|
||||
|
||||
|
||||
void Vm::inject_irq(unsigned irq)
|
||||
{
|
||||
_state.irqs.last_irq = irq;
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
* Copyright (C) 2022-2023 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.
|
||||
@ -41,6 +41,7 @@ namespace Board {
|
||||
/* FIXME move into Vcpu_context as 'enum class' when we have C++20 */
|
||||
enum Platform_exitcodes : Genode::uint64_t {
|
||||
EXIT_NPF = 0xfc,
|
||||
EXIT_INIT = 0xfd,
|
||||
EXIT_STARTUP = 0xfe,
|
||||
EXIT_PAUSED = 0xff,
|
||||
};
|
||||
@ -64,12 +65,13 @@ struct Board::Vcpu_context
|
||||
Genode::addr_t context_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, unsigned exit_reason);
|
||||
void write_vcpu_state(Genode::Vcpu_state &state);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__PC__VIRTUALIZATION__BOARD_H_ */
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* \brief SVM specific implementations
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2022-10-14
|
||||
* \brief SVM specific implementations
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2022-10-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
* Copyright (C) 2022-2023 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.
|
||||
@ -156,12 +156,12 @@ void Board::Vcpu_context::initialize_svm(Kernel::Cpu & cpu, void * table)
|
||||
}
|
||||
|
||||
|
||||
void Board::Vcpu_context::write_vcpu_state(Genode::Vcpu_state &state, unsigned exit_reason)
|
||||
void Board::Vcpu_context::write_vcpu_state(Genode::Vcpu_state &state)
|
||||
{
|
||||
typedef Genode::Vcpu_state::Range Range;
|
||||
|
||||
state.discharge();
|
||||
state.exit_reason = exit_reason;
|
||||
state.exit_reason = (unsigned) exitcode;
|
||||
|
||||
state.fpu.charge([&] (Genode::Vcpu_state::Fpu::State &fpu) {
|
||||
memcpy(&fpu, (void *) regs->fpu_context(), sizeof(fpu));
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* \brief Kernel backend for x86 virtual machines
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2022-10-14
|
||||
* \brief Kernel backend for x86 virtual machines
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2022-10-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
* Copyright (C) 2022-2023 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.
|
||||
@ -33,7 +33,6 @@ using Genode::addr_t;
|
||||
using Kernel::Cpu;
|
||||
using Kernel::Vm;
|
||||
using Board::Vmcb;
|
||||
using Vcpu_run_state = Genode::Vcpu_run_state;
|
||||
|
||||
|
||||
Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
@ -51,7 +50,6 @@ Vm::Vm(Irq::Pool & user_irq_pool,
|
||||
_vcpu_context(id.id, &data.vmcb, data.vmcb_phys_addr)
|
||||
{
|
||||
affinity(cpu);
|
||||
_state.run_state.set(Vcpu_run_state::STARTUP);
|
||||
}
|
||||
|
||||
|
||||
@ -65,53 +63,31 @@ void Vm::proceed(Cpu & cpu)
|
||||
using namespace Board;
|
||||
cpu.switch_to(*_vcpu_context.regs);
|
||||
|
||||
bool do_world_switch = false;
|
||||
|
||||
switch (_state.run_state.value()) {
|
||||
case Vcpu_run_state::STARTUP: break;
|
||||
case Vcpu_run_state::SYNC_FROM_VCPU: break;
|
||||
case Vcpu_run_state::PAUSING: break;
|
||||
case Vcpu_run_state::INTERRUPTIBLE:
|
||||
if (_state.run_state.cas(Vcpu_run_state::INTERRUPTIBLE,
|
||||
Vcpu_run_state::RUNNING))
|
||||
do_world_switch = true;
|
||||
break;
|
||||
case Vcpu_run_state::RUNNABLE:
|
||||
_state.run_state.cas(Vcpu_run_state::RUNNABLE,
|
||||
Vcpu_run_state::RUNNING);
|
||||
[[fallthrough]];
|
||||
case Vcpu_run_state::RUN_ONCE:
|
||||
_vcpu_context.read_vcpu_state(_state);
|
||||
do_world_switch = true;
|
||||
break;
|
||||
default:
|
||||
Genode::error("proceed: illegal state ",
|
||||
Genode::Hex(_state.run_state.value()));
|
||||
}
|
||||
|
||||
if (do_world_switch) {
|
||||
Cpu::Ia32_tsc_aux::write((Cpu::Ia32_tsc_aux::access_t) _vcpu_context.tsc_aux_guest);
|
||||
|
||||
/*
|
||||
* We push the host context's physical address to trapno so that
|
||||
* we can pop it later
|
||||
* */
|
||||
_vcpu_context.regs->trapno = _vcpu_context.vmcb.root_vmcb_phys;
|
||||
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
|
||||
* */
|
||||
} else {
|
||||
if (_vcpu_context.exitcode == EXIT_INIT) {
|
||||
_vcpu_context.regs->trapno = TRAP_VMSKIP;
|
||||
Hypervisor::restore_state_for_entry((addr_t)&_vcpu_context.regs->r8,
|
||||
_vcpu_context.regs->fpu_context());
|
||||
/* jumps to _kernel_entry */
|
||||
}
|
||||
|
||||
Cpu::Ia32_tsc_aux::write(
|
||||
(Cpu::Ia32_tsc_aux::access_t)_vcpu_context.tsc_aux_guest);
|
||||
|
||||
/*
|
||||
* We push the host context's physical address to trapno so that
|
||||
* we can pop it later
|
||||
*/
|
||||
_vcpu_context.regs->trapno = _vcpu_context.vmcb.root_vmcb_phys;
|
||||
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
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
using namespace Board;
|
||||
@ -134,7 +110,7 @@ void Vm::exception(Cpu & cpu)
|
||||
" at ip=",
|
||||
(void *)_vcpu_context.regs->ip, " sp=",
|
||||
(void *)_vcpu_context.regs->sp);
|
||||
pause();
|
||||
_pause_vcpu();
|
||||
return;
|
||||
};
|
||||
|
||||
@ -144,73 +120,58 @@ void Vm::exception(Cpu & cpu)
|
||||
VMEXIT_NPF = 0x400,
|
||||
};
|
||||
|
||||
switch (_state.run_state.value()) {
|
||||
case Vcpu_run_state::STARTUP:
|
||||
if (_vcpu_context.exitcode == EXIT_INIT) {
|
||||
_vcpu_context.initialize_svm(cpu, _id.table);
|
||||
_vcpu_context.tsc_aux_host = cpu.id();
|
||||
_vcpu_context.write_vcpu_state(_state, EXIT_STARTUP);
|
||||
_state.run_state.set(Vcpu_run_state::DISPATCHING);
|
||||
pause();
|
||||
_vcpu_context.exitcode = EXIT_STARTUP;
|
||||
_pause_vcpu();
|
||||
_context.submit(1);
|
||||
return;
|
||||
case Vcpu_run_state::SYNC_FROM_VCPU:
|
||||
_vcpu_context.write_vcpu_state(_state, EXIT_PAUSED);
|
||||
_state.run_state.set(Vcpu_run_state::PAUSED);
|
||||
pause();
|
||||
_context.submit(1);
|
||||
return;
|
||||
case Vcpu_run_state::EXITING: break;
|
||||
case Vcpu_run_state::RUNNING: break;
|
||||
case Vcpu_run_state::RUN_ONCE: break;
|
||||
case Vcpu_run_state::PAUSING: return;
|
||||
default:
|
||||
Genode::error("exception: illegal state ",
|
||||
Genode::Hex(_state.run_state.value()));
|
||||
}
|
||||
|
||||
Genode::uint64_t exitcode = _vcpu_context.vmcb.read<Vmcb::Exitcode>();
|
||||
_vcpu_context.exitcode = _vcpu_context.vmcb.read<Vmcb::Exitcode>();
|
||||
|
||||
switch (exitcode) {
|
||||
switch (_vcpu_context.exitcode) {
|
||||
case VMEXIT_INVALID:
|
||||
Genode::error("Vm::exception: invalid SVM state!");
|
||||
return;
|
||||
case 0x40 ... 0x5f:
|
||||
Genode::error("Vm::exception: unhandled SVM exception ",
|
||||
Genode::Hex(exitcode));
|
||||
Genode::Hex(_vcpu_context.exitcode));
|
||||
return;
|
||||
case VMEXIT_INTR:
|
||||
if (!_state.run_state.cas(Vcpu_run_state::RUNNING,
|
||||
Vcpu_run_state::INTERRUPTIBLE))
|
||||
{
|
||||
_vcpu_context.write_vcpu_state(_state, EXIT_PAUSED);
|
||||
|
||||
/*
|
||||
* If the interruptible state couldn't be set, the state might
|
||||
* be EXITING and a pause() signal might have already been send
|
||||
* (to cause the vCPU exit in the first place).
|
||||
*/
|
||||
bool submit = false;
|
||||
/* In the RUN_ONCE case, first we will need to send a signal. */
|
||||
if (_state.run_state.value() == Vcpu_run_state::RUN_ONCE)
|
||||
submit = true;
|
||||
|
||||
_state.run_state.set(Vcpu_run_state::PAUSED);
|
||||
pause();
|
||||
|
||||
if (submit)
|
||||
_context.submit(1);
|
||||
}
|
||||
_vcpu_context.exitcode = EXIT_PAUSED;
|
||||
return;
|
||||
case VMEXIT_NPF:
|
||||
exitcode = EXIT_NPF;
|
||||
_vcpu_context.exitcode = EXIT_NPF;
|
||||
[[fallthrough]];
|
||||
default:
|
||||
_vcpu_context.write_vcpu_state(_state, (unsigned) exitcode);
|
||||
_state.run_state.set(Vcpu_run_state::DISPATCHING);
|
||||
pause();
|
||||
_pause_vcpu();
|
||||
_context.submit(1);
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Vm::_sync_to_vmm()
|
||||
{
|
||||
_vcpu_context.write_vcpu_state(_state);
|
||||
|
||||
/*
|
||||
* Set exit code so that if _run() was not called after an exit, the
|
||||
* next exit due to a signal will be interpreted as PAUSE request.
|
||||
*/
|
||||
_vcpu_context.exitcode = Board::EXIT_PAUSED;
|
||||
}
|
||||
|
||||
|
||||
void Vm::_sync_from_vmm()
|
||||
{
|
||||
/* first run() will skip through to issue startup exit */
|
||||
if (_vcpu_context.exitcode == Board::EXIT_INIT)
|
||||
return;
|
||||
|
||||
_vcpu_context.read_vcpu_state(_state);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Client-side VM session interface
|
||||
* \brief Client-side VM session interface (base-hw generic)
|
||||
* \author Alexander Boettcher
|
||||
* \date 2018-08-27
|
||||
*/
|
||||
@ -15,6 +15,7 @@
|
||||
#include <base/attached_dataspace.h>
|
||||
#include <base/env.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/internal/capability_space.h>
|
||||
#include <kernel/interface.h>
|
||||
|
||||
@ -26,6 +27,7 @@
|
||||
using namespace Genode;
|
||||
|
||||
using Exit_config = Vm_connection::Exit_config;
|
||||
using Call_with_state = Vm_connection::Call_with_state;
|
||||
|
||||
|
||||
/****************************
|
||||
@ -38,20 +40,24 @@ struct Hw_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
|
||||
Attached_dataspace _state;
|
||||
Native_capability _kernel_vcpu { };
|
||||
void *_ep_handler { nullptr };
|
||||
|
||||
Capability<Native_vcpu> _create_vcpu(Vm_connection &, Vcpu_handler_base &);
|
||||
|
||||
Vcpu_state & _local_state()
|
||||
{
|
||||
return *_state.local_addr<Vcpu_state>();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
const Hw_vcpu& operator=(const Hw_vcpu &) = delete;
|
||||
Hw_vcpu(const Hw_vcpu&) = delete;
|
||||
|
||||
Hw_vcpu(Env &, Vm_connection &, Vcpu_handler_base &);
|
||||
|
||||
void run() {
|
||||
Kernel::run_vm(Capability_space::capid(_kernel_vcpu)); }
|
||||
|
||||
void pause() {
|
||||
Kernel::pause_vm(Capability_space::capid(_kernel_vcpu)); }
|
||||
|
||||
Vcpu_state & state() { return *_state.local_addr<Vcpu_state>(); }
|
||||
void with_state(Call_with_state &);
|
||||
};
|
||||
|
||||
|
||||
@ -60,11 +66,25 @@ Hw_vcpu::Hw_vcpu(Env &env, Vm_connection &vm, Vcpu_handler_base &handler)
|
||||
Rpc_client<Native_vcpu>(_create_vcpu(vm, handler)),
|
||||
_state(env.rm(), vm.with_upgrade([&] () { return call<Rpc_state>(); }))
|
||||
{
|
||||
_ep_handler = reinterpret_cast<Thread *>(&handler.rpc_ep());
|
||||
call<Rpc_exception_handler>(handler.signal_cap());
|
||||
_kernel_vcpu = call<Rpc_native_vcpu>();
|
||||
}
|
||||
|
||||
|
||||
void Hw_vcpu::with_state(Call_with_state &cw)
|
||||
{
|
||||
if (Thread::myself() != _ep_handler) {
|
||||
error("vCPU state requested outside of vcpu_handler EP");
|
||||
sleep_forever();
|
||||
}
|
||||
Kernel::pause_vm(Capability_space::capid(_kernel_vcpu));
|
||||
|
||||
if (cw.call_with_state(_local_state()))
|
||||
Kernel::run_vm(Capability_space::capid(_kernel_vcpu));
|
||||
}
|
||||
|
||||
|
||||
Capability<Vm_session::Native_vcpu> Hw_vcpu::_create_vcpu(Vm_connection &vm,
|
||||
Vcpu_handler_base &handler)
|
||||
{
|
||||
@ -79,9 +99,7 @@ Capability<Vm_session::Native_vcpu> Hw_vcpu::_create_vcpu(Vm_connection &vm,
|
||||
** vCPU API **
|
||||
**************/
|
||||
|
||||
void Vm_connection::Vcpu::run() { static_cast<Hw_vcpu &>(_native_vcpu).run(); }
|
||||
void Vm_connection::Vcpu::pause() { static_cast<Hw_vcpu &>(_native_vcpu).pause(); }
|
||||
Vcpu_state & Vm_connection::Vcpu::state() { return static_cast<Hw_vcpu &>(_native_vcpu).state(); }
|
||||
void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast<Hw_vcpu &>(_native_vcpu).with_state(cw); }
|
||||
|
||||
|
||||
Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Client-side VM session interface
|
||||
* \brief Client-side VM session interface (x86_64 specific)
|
||||
* \author Alexander Boettcher
|
||||
* \author Benjamin Lamowski
|
||||
* \date 2018-08-27
|
||||
@ -17,8 +17,8 @@
|
||||
#include <base/env.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/signal.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/internal/capability_space.h>
|
||||
#include <virtualization/extended_vcpu_state.h>
|
||||
#include <kernel/interface.h>
|
||||
|
||||
#include <vm_session/connection.h>
|
||||
@ -29,6 +29,7 @@
|
||||
using namespace Genode;
|
||||
|
||||
using Exit_config = Vm_connection::Exit_config;
|
||||
using Call_with_state = Vm_connection::Call_with_state;
|
||||
|
||||
|
||||
/****************************
|
||||
@ -42,17 +43,13 @@ struct Hw_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
Attached_dataspace _state;
|
||||
Native_capability _kernel_vcpu { };
|
||||
Vcpu_handler_base & _vcpu_handler;
|
||||
Thread * _ep_handler { nullptr };
|
||||
unsigned _id { 0 };
|
||||
Vcpu_state _stashed_state { };
|
||||
bool _need_state_update { false };
|
||||
bool _extra_pause { false };
|
||||
Vcpu_handler<Hw_vcpu> _wrapper;
|
||||
void *_ep_handler { nullptr };
|
||||
|
||||
void _wrapper_dispatch();
|
||||
void _prepare_pause_exit();
|
||||
void _update_charged_state(Vcpu_state & old_state, Vcpu_state & new_state);
|
||||
Capability<Native_vcpu> _create_vcpu(Vm_connection &, Vcpu_handler_base &);
|
||||
void _run();
|
||||
Vcpu_state & _local_state() { return *_state.local_addr<Vcpu_state>(); }
|
||||
Capability<Native_vcpu> _create_vcpu(Vm_connection &,
|
||||
Vcpu_handler_base &);
|
||||
|
||||
public:
|
||||
|
||||
@ -61,10 +58,8 @@ struct Hw_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
|
||||
Hw_vcpu(Env &, Vm_connection &, Vcpu_handler_base &);
|
||||
|
||||
void run();
|
||||
void pause();
|
||||
void with_state(Call_with_state &);
|
||||
|
||||
Vm_state & state() { return *_state.local_addr<Vm_state>(); }
|
||||
};
|
||||
|
||||
|
||||
@ -72,383 +67,33 @@ Hw_vcpu::Hw_vcpu(Env &env, Vm_connection &vm, Vcpu_handler_base &handler)
|
||||
:
|
||||
Rpc_client<Native_vcpu>(_create_vcpu(vm, handler)),
|
||||
_state(env.rm(), vm.with_upgrade([&] () { return call<Rpc_state>(); })),
|
||||
_vcpu_handler(handler),
|
||||
_wrapper(handler.ep(), *this, &Hw_vcpu::_wrapper_dispatch)
|
||||
_vcpu_handler(handler)
|
||||
{
|
||||
static unsigned counter = 0;
|
||||
call<Rpc_exception_handler>(_wrapper.signal_cap());
|
||||
call<Rpc_exception_handler>(handler.signal_cap());
|
||||
_kernel_vcpu = call<Rpc_native_vcpu>();
|
||||
_id = counter++;
|
||||
_ep_handler = reinterpret_cast<Thread *>(&handler.rpc_ep());
|
||||
_run();
|
||||
}
|
||||
|
||||
|
||||
void Hw_vcpu::_wrapper_dispatch()
|
||||
void Hw_vcpu::_run()
|
||||
{
|
||||
/*
|
||||
* If this is running, the VM is not. Either it hasn't, or it has been
|
||||
* forced out and has written any state back.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We run from the same EP as the orignal dispatch handler that
|
||||
* will call run() from its dispatch loop, set _ep_handler.
|
||||
*/
|
||||
if (!_ep_handler)
|
||||
_ep_handler = Thread::myself();
|
||||
|
||||
int run_state = state().run_state.value();
|
||||
|
||||
/*
|
||||
* In case the VMM dispatch method waits for a pause signal,
|
||||
* we need a different state to make the pause() method
|
||||
* send another signal.
|
||||
*/
|
||||
if (run_state == Vcpu_run_state::DISPATCHING)
|
||||
state().run_state.set(Vcpu_run_state::DISPATCHED);
|
||||
|
||||
if (run_state == Vcpu_run_state::DISPATCHING_PAUSED)
|
||||
state().run_state.set(Vcpu_run_state::PAUSING);
|
||||
|
||||
/*
|
||||
* Dispatch the exit originating from the vCPU
|
||||
*/
|
||||
if (run_state == Vcpu_run_state::DISPATCHING ||
|
||||
run_state == Vcpu_run_state::DISPATCHING_PAUSED ||
|
||||
run_state == Vcpu_run_state::PAUSED) {
|
||||
/* Call the VMM's dispatch method. */
|
||||
_vcpu_handler.dispatch(1);
|
||||
/*
|
||||
* Dispatch will probably have called run(), but if the state is set
|
||||
* to PAUSING it won't.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch a possible folded in pause signal.
|
||||
* Note that we only the local run_state against pausing.
|
||||
* If the DISPATCHED state was changed to PAUSING in between, pause()
|
||||
* has sent a new signal.
|
||||
*/
|
||||
if (run_state == Vcpu_run_state::PAUSING ||
|
||||
run_state == Vcpu_run_state::DISPATCHING_PAUSED ||
|
||||
_extra_pause) {
|
||||
Kernel::pause_vm(Capability_space::capid(_kernel_vcpu));
|
||||
_update_charged_state(_stashed_state, state());
|
||||
/*
|
||||
* Tell run() to get any stashed state from the original dispatch.
|
||||
* Necessary because that state is discharged when the VMM
|
||||
* dispatches and would be lost otherwise.
|
||||
*/
|
||||
_need_state_update = true;
|
||||
_extra_pause = false;
|
||||
_prepare_pause_exit();
|
||||
state().run_state.set(Vcpu_run_state::PAUSED);
|
||||
_vcpu_handler.dispatch(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Hw_vcpu::run()
|
||||
{
|
||||
if (_need_state_update) {
|
||||
_update_charged_state(state(), _stashed_state);
|
||||
_stashed_state.discharge();
|
||||
_need_state_update = false;
|
||||
}
|
||||
|
||||
switch (state().run_state.value()) {
|
||||
case Vcpu_run_state::STARTUP:
|
||||
break;
|
||||
case Vcpu_run_state::DISPATCHED:
|
||||
if (_ep_handler != Thread::myself()) {
|
||||
Genode::error("Vcpu (", _id, ") run: setting run from remote CPU unsupported");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state().run_state.cas(Vcpu_run_state::DISPATCHED,
|
||||
Vcpu_run_state::RUNNABLE))
|
||||
return; /* state changed to PAUSING */
|
||||
break;
|
||||
case Vcpu_run_state::PAUSED:
|
||||
state().run_state.set(Vcpu_run_state::RUNNABLE);
|
||||
/*
|
||||
* It is the VMM's responsibility to be reasonable here.
|
||||
* If Vcpu::run() is called assynchronously while the vCPU handler
|
||||
* is still dispatching a request before pause this breaks.
|
||||
*/
|
||||
if (_ep_handler != Thread::myself())
|
||||
Genode::warning("Vcpu (", _id, ") run: asynchronous call of run()");
|
||||
break;
|
||||
case Vcpu_run_state::PAUSING:
|
||||
return;
|
||||
default:
|
||||
Genode::error("Vcpu (", _id, ") run: ignoring state ",
|
||||
Genode::Hex(state().run_state.value()));
|
||||
return;
|
||||
}
|
||||
|
||||
Kernel::run_vm(Capability_space::capid(_kernel_vcpu));
|
||||
}
|
||||
|
||||
|
||||
void Hw_vcpu::pause()
|
||||
void Hw_vcpu::with_state(Call_with_state &cw)
|
||||
{
|
||||
switch (state().run_state.value()) {
|
||||
/*
|
||||
* Ignore pause requests before the vCPU has started up.
|
||||
*/
|
||||
case Vcpu_run_state::STARTUP:
|
||||
return;
|
||||
if (Thread::myself() != _ep_handler) {
|
||||
error("vCPU state requested outside of vcpu_handler EP");
|
||||
sleep_forever();
|
||||
}
|
||||
Kernel::pause_vm(Capability_space::capid(_kernel_vcpu));
|
||||
|
||||
/*
|
||||
* When a pause is requested while starting or dispatching, the original
|
||||
* exit needs to be handled before a pause exit can be injected.
|
||||
* In these two cases it may happen be that the pause signal would be
|
||||
* folded in with the signal from the kernel, therefore we need to make
|
||||
* sure that the wrapper will prepare the pause exit anyway.
|
||||
*/
|
||||
case Vcpu_run_state::DISPATCHING:
|
||||
if (!state().run_state.cas(Vcpu_run_state::DISPATCHING,
|
||||
Vcpu_run_state::DISPATCHING_PAUSED))
|
||||
pause(); /* moved on to DISPATCHED, retry */
|
||||
return;
|
||||
|
||||
/*
|
||||
* The vCPU could run anytime. Switch to RUN_ONCE to make the kernel
|
||||
* exit and send a signal after running.
|
||||
* If the state has changed, it must be to running, in that case retry
|
||||
* the pause.
|
||||
*/
|
||||
case Vcpu_run_state::RUNNABLE:
|
||||
if (!state().run_state.cas(Vcpu_run_state::RUNNABLE,
|
||||
Vcpu_run_state::RUN_ONCE))
|
||||
{
|
||||
pause();
|
||||
return;
|
||||
}
|
||||
|
||||
_extra_pause = true;
|
||||
return;
|
||||
|
||||
/*
|
||||
* The vCPU may be running, signal that any interrupt exit is because it
|
||||
* is forced out.
|
||||
*
|
||||
* If the CPU is already at the beginning of the exception handling,
|
||||
* the handler will get two signals: whatever the normal exit would have
|
||||
* been and the pause exit straight after, which is ok.
|
||||
*
|
||||
* If the state is written after it was already switched to
|
||||
* INTERRUPTIBLE in the exit handler, we simply retry.
|
||||
*/
|
||||
case Vcpu_run_state::RUNNING:
|
||||
if (_ep_handler == Thread::myself()) {
|
||||
Genode::error("Vcpu (", _id, " ) pause: illegal state in line ", __LINE__ );
|
||||
return;
|
||||
};
|
||||
|
||||
if (!state().run_state.cas(Vcpu_run_state::RUNNING,
|
||||
Vcpu_run_state::EXITING)) {
|
||||
pause();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* A pause request is received when the CPU was already forced out.
|
||||
* In this case we need to write the state back first and send the
|
||||
* signal later. If this comes from another thread then it may be
|
||||
* interrupted after reading the state, while the vCPU thread starts
|
||||
* RUNNING. Therefore if the swap fails, retry the pause().
|
||||
*/
|
||||
case Vcpu_run_state::INTERRUPTIBLE:
|
||||
if (!state().run_state.cas(Vcpu_run_state::INTERRUPTIBLE,
|
||||
Vcpu_run_state::SYNC_FROM_VCPU))
|
||||
pause();
|
||||
return;
|
||||
|
||||
/*
|
||||
* A pause is requested while the VM has been dispatched.
|
||||
* Send a new signal in case the VMM waits for a pause() exit
|
||||
* before doing another run.
|
||||
*/
|
||||
case Vcpu_run_state::DISPATCHED:
|
||||
if (!state().run_state.cas(Vcpu_run_state::DISPATCHED,
|
||||
Vcpu_run_state::PAUSING)) {
|
||||
pause();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* We're already pausing or paused, ignore it.
|
||||
*/
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
_wrapper.local_submit();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare a pause exit to dispatch to the VMM.
|
||||
* Because we don't do a round trip to the kernel we charge some state to keep
|
||||
* seoul happy.
|
||||
*/
|
||||
void Hw_vcpu::_prepare_pause_exit()
|
||||
{
|
||||
state().exit_reason = 0xFF;
|
||||
state().ax.set_charged();
|
||||
state().bx.set_charged();
|
||||
state().cx.set_charged();
|
||||
state().dx.set_charged();
|
||||
|
||||
state().bp.set_charged();
|
||||
state().di.set_charged();
|
||||
state().si.set_charged();
|
||||
|
||||
state().flags.set_charged();
|
||||
|
||||
state().sp.set_charged();
|
||||
|
||||
state().ip.set_charged();
|
||||
state().ip_len.set_charged();
|
||||
|
||||
state().qual_primary.set_charged();
|
||||
state().qual_secondary.set_charged();
|
||||
|
||||
state().intr_state.set_charged();
|
||||
state().actv_state.set_charged();
|
||||
|
||||
state().inj_info.set_charged();
|
||||
state().inj_error.set_charged();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Update fields not already charged from one Vcpu_state to the other.
|
||||
*/
|
||||
void Hw_vcpu::_update_charged_state(Vcpu_state & old_state, Vcpu_state & new_state)
|
||||
{
|
||||
if (new_state.ax.charged() || new_state.cx.charged() ||
|
||||
new_state.dx.charged() || new_state.bx.charged()) {
|
||||
old_state.ax.update(new_state.ax.value());
|
||||
old_state.cx.update(new_state.cx.value());
|
||||
old_state.dx.update(new_state.dx.value());
|
||||
old_state.bx.update(new_state.bx.value());
|
||||
}
|
||||
if (new_state.bp.charged() || new_state.di.charged() ||
|
||||
new_state.si.charged()) {
|
||||
old_state.bp.update(new_state.bp.value());
|
||||
old_state.si.update(new_state.si.value());
|
||||
old_state.di.update(new_state.di.value());
|
||||
}
|
||||
if (new_state.sp.charged()) {
|
||||
old_state.sp.update(new_state.sp.value());
|
||||
}
|
||||
if (new_state.ip.charged()) {
|
||||
old_state.ip.update(new_state.ip.value());
|
||||
old_state.ip_len.update(new_state.ip_len.value());
|
||||
}
|
||||
if (new_state.flags.charged()) {
|
||||
old_state.flags.update(new_state.flags.value());
|
||||
}
|
||||
if (new_state.es.charged() || new_state.ds.charged()) {
|
||||
old_state.es.update(new_state.es.value());
|
||||
old_state.ds.update(new_state.ds.value());
|
||||
}
|
||||
if (new_state.fs.charged() || new_state.gs.charged()) {
|
||||
old_state.fs.update(new_state.fs.value());
|
||||
old_state.gs.update(new_state.gs.value());
|
||||
}
|
||||
if (new_state.cs.charged() || new_state.ss.charged()) {
|
||||
old_state.cs.update(new_state.cs.value());
|
||||
old_state.ss.update(new_state.ss.value());
|
||||
}
|
||||
if (new_state.tr.charged()) {
|
||||
old_state.tr.update(new_state.tr.value());
|
||||
}
|
||||
if (new_state.ldtr.charged()) {
|
||||
old_state.ldtr.update(new_state.ldtr.value());
|
||||
}
|
||||
if (new_state.gdtr.charged()) {
|
||||
old_state.gdtr.update(new_state.gdtr.value());
|
||||
}
|
||||
if (new_state.idtr.charged()) {
|
||||
old_state.idtr.update(new_state.idtr.value());
|
||||
}
|
||||
if (new_state.cr0.charged() || new_state.cr2.charged() ||
|
||||
new_state.cr3.charged() || new_state.cr4.charged()) {
|
||||
old_state.cr0.update(new_state.cr0.value());
|
||||
old_state.cr2.update(new_state.cr2.value());
|
||||
old_state.cr3.update(new_state.cr3.value());
|
||||
old_state.cr4.update(new_state.cr4.value());
|
||||
}
|
||||
if (new_state.dr7.charged()) {
|
||||
old_state.dr7.update(new_state.dr7.value());
|
||||
}
|
||||
if (new_state.sysenter_cs.charged() || new_state.sysenter_sp.charged() ||
|
||||
new_state.sysenter_ip.charged()) {
|
||||
old_state.sysenter_ip.update(new_state.sysenter_ip.value());
|
||||
old_state.sysenter_sp.update(new_state.sysenter_sp.value());
|
||||
old_state.sysenter_cs.update(new_state.sysenter_cs.value());
|
||||
}
|
||||
if (new_state.ctrl_primary.charged() ||
|
||||
new_state.ctrl_secondary.charged()) {
|
||||
old_state.ctrl_primary.update(new_state.ctrl_primary.value());
|
||||
old_state.ctrl_secondary.update(new_state.ctrl_secondary.value());
|
||||
}
|
||||
if (new_state.inj_info.charged() || new_state.inj_error.charged()) {
|
||||
old_state.inj_info.update(new_state.inj_info.value());
|
||||
old_state.inj_error.update(new_state.inj_error.value());
|
||||
}
|
||||
if (new_state.intr_state.charged() || new_state.actv_state.charged()) {
|
||||
old_state.intr_state.update(new_state.intr_state.value());
|
||||
old_state.actv_state.update(new_state.actv_state.value());
|
||||
}
|
||||
if (new_state.tsc_offset.charged()) {
|
||||
old_state.tsc.update(new_state.tsc.value());
|
||||
old_state.tsc_offset.update(new_state.tsc_offset.value());
|
||||
old_state.tsc_aux.update(new_state.tsc_aux.value());
|
||||
}
|
||||
if (new_state.efer.charged()) {
|
||||
old_state.efer.update(new_state.efer.value());
|
||||
}
|
||||
if (new_state.pdpte_0.charged() || new_state.pdpte_1.charged() ||
|
||||
new_state.pdpte_2.charged() || new_state.pdpte_3.charged()) {
|
||||
old_state.pdpte_0.update(new_state.pdpte_0.value());
|
||||
old_state.pdpte_1.update(new_state.pdpte_1.value());
|
||||
old_state.pdpte_2.update(new_state.pdpte_2.value());
|
||||
old_state.pdpte_3.update(new_state.pdpte_3.value());
|
||||
}
|
||||
|
||||
if (new_state.r8 .charged() || new_state.r9 .charged() ||
|
||||
new_state.r10.charged() || new_state.r11.charged() ||
|
||||
new_state.r12.charged() || new_state.r13.charged() ||
|
||||
new_state.r14.charged() || new_state.r15.charged()) {
|
||||
old_state.r8.update(new_state.r8.value());
|
||||
old_state.r9.update(new_state.r9.value());
|
||||
old_state.r10.update(new_state.r10.value());
|
||||
old_state.r11.update(new_state.r11.value());
|
||||
old_state.r12.update(new_state.r12.value());
|
||||
old_state.r13.update(new_state.r13.value());
|
||||
old_state.r14.update(new_state.r14.value());
|
||||
old_state.r15.update(new_state.r15.value());
|
||||
}
|
||||
if (new_state.star .charged() || new_state.lstar.charged() ||
|
||||
new_state.cstar.charged() || new_state.fmask.charged() ||
|
||||
new_state.kernel_gs_base.charged()) {
|
||||
old_state.star.update(new_state.star.value());
|
||||
old_state.lstar.update(new_state.lstar.value());
|
||||
old_state.cstar.update(new_state.cstar.value());
|
||||
old_state.fmask.update(new_state.fmask.value());
|
||||
old_state.kernel_gs_base.update(new_state.kernel_gs_base.value());
|
||||
}
|
||||
if (new_state.tpr.charged() || new_state.tpr_threshold.charged()) {
|
||||
old_state.tpr.update(new_state.tpr.value());
|
||||
old_state.tpr_threshold.update(new_state.tpr_threshold.value());
|
||||
}
|
||||
if(cw.call_with_state(_local_state()))
|
||||
_run();
|
||||
}
|
||||
|
||||
|
||||
@ -466,9 +111,7 @@ Capability<Vm_session::Native_vcpu> Hw_vcpu::_create_vcpu(Vm_connection &vm,
|
||||
** vCPU API **
|
||||
**************/
|
||||
|
||||
void Vm_connection::Vcpu::run() { static_cast<Hw_vcpu &>(_native_vcpu).run(); }
|
||||
void Vm_connection::Vcpu::pause() { static_cast<Hw_vcpu &>(_native_vcpu).pause(); }
|
||||
Vcpu_state & Vm_connection::Vcpu::state() { return static_cast<Hw_vcpu &>(_native_vcpu).state(); }
|
||||
void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast<Hw_vcpu &>(_native_vcpu).with_state(cw); }
|
||||
|
||||
|
||||
Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc,
|
||||
|
Loading…
Reference in New Issue
Block a user