mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-21 17:57:44 +00:00
parent
9489bf41a5
commit
85012d5edd
@ -3,11 +3,12 @@
|
|||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Alexander Boettcher
|
* \author Alexander Boettcher
|
||||||
|
* \author Benjamin Lamowski
|
||||||
* \date 2009-12-27
|
* \date 2009-12-27
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2022 Genode Labs
|
* Copyright (c) 2009-2023 Genode Labs
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation
|
* obtaining a copy of this software and associated documentation
|
||||||
@ -284,6 +285,8 @@ namespace Nova {
|
|||||||
EC_RESCHEDULE = 3U,
|
EC_RESCHEDULE = 3U,
|
||||||
EC_MIGRATE = 4U,
|
EC_MIGRATE = 4U,
|
||||||
EC_TIME = 5U,
|
EC_TIME = 5U,
|
||||||
|
EC_GET_VCPU_STATE = 6U,
|
||||||
|
EC_SET_VCPU_STATE = 7U,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Sc_op {
|
enum Sc_op {
|
||||||
@ -665,6 +668,7 @@ namespace Nova {
|
|||||||
#endif
|
#endif
|
||||||
} gdtr, idtr;
|
} gdtr, idtr;
|
||||||
unsigned long long tsc_val, tsc_off, tsc_aux;
|
unsigned long long tsc_val, tsc_off, tsc_aux;
|
||||||
|
unsigned long long exit_reason;
|
||||||
uint8_t fpu[512];
|
uint8_t fpu[512];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)];
|
mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)];
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Alexander Boettcher
|
* \author Alexander Boettcher
|
||||||
|
* \author Benjamin Lamowski
|
||||||
* \date 2012-06-06
|
* \date 2012-06-06
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012 Genode Labs
|
* Copyright (c) 2012-2023 Genode Labs
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation
|
* obtaining a copy of this software and associated documentation
|
||||||
@ -362,7 +363,6 @@ namespace Nova {
|
|||||||
return syscall_2(NOVA_MISC, 2, sm_auth_acpi, sleep_state_a, sleep_state_b);
|
return syscall_2(NOVA_MISC, 2, sm_auth_acpi, sleep_state_a, sleep_state_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ALWAYS_INLINE
|
ALWAYS_INLINE
|
||||||
inline uint8_t sm_ctrl(mword_t sm, Sem_op op, unsigned long long timeout = 0)
|
inline uint8_t sm_ctrl(mword_t sm, Sem_op op, unsigned long long timeout = 0)
|
||||||
{
|
{
|
||||||
|
@ -1 +1 @@
|
|||||||
a9f11fdc132f027ed1d58da86fe39679da98699c
|
3f6464b9126ffc77fdfd4b670ed7b4d3d3d0aff8
|
||||||
|
@ -4,7 +4,7 @@ DOWNLOADS := nova.git
|
|||||||
|
|
||||||
# r10 branch
|
# r10 branch
|
||||||
URL(nova) := https://github.com/alex-ab/NOVA.git
|
URL(nova) := https://github.com/alex-ab/NOVA.git
|
||||||
REV(nova) := 1dff7b1311016b111ce71365ffe7ba625fa4708c
|
REV(nova) := 89f714dcb32c7f4e97d29a8651e55862b8362df1
|
||||||
DIR(nova) := src/kernel/nova
|
DIR(nova) := src/kernel/nova
|
||||||
|
|
||||||
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))
|
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
* \brief NOVA-specific VM-connection implementation
|
* \brief NOVA-specific VM-connection implementation
|
||||||
* \author Alexander Boettcher
|
* \author Alexander Boettcher
|
||||||
* \author Christian Helmuth
|
* \author Christian Helmuth
|
||||||
|
* \author Benjamin Lamowski
|
||||||
* \date 2018-08-27
|
* \date 2018-08-27
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018-2021 Genode Labs GmbH
|
* Copyright (C) 2018-2023 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
@ -16,6 +17,7 @@
|
|||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/allocator.h>
|
#include <base/allocator.h>
|
||||||
#include <base/registry.h>
|
#include <base/registry.h>
|
||||||
|
#include <base/sleep.h>
|
||||||
#include <base/attached_dataspace.h>
|
#include <base/attached_dataspace.h>
|
||||||
#include <vm_session/connection.h>
|
#include <vm_session/connection.h>
|
||||||
#include <vm_session/handler.h>
|
#include <vm_session/handler.h>
|
||||||
@ -33,6 +35,7 @@
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
using Exit_config = Vm_connection::Exit_config;
|
using Exit_config = Vm_connection::Exit_config;
|
||||||
|
using Call_with_state = Vm_connection::Call_with_state;
|
||||||
|
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
@ -43,6 +46,8 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
enum { VM_EXIT_STARTUP = 0xfe, VM_EXIT_RECALL = 0xff };
|
||||||
|
|
||||||
typedef Id_space<Nova_vcpu> Vcpu_space;
|
typedef Id_space<Nova_vcpu> Vcpu_space;
|
||||||
|
|
||||||
static Vcpu_space &_vcpu_space()
|
static Vcpu_space &_vcpu_space()
|
||||||
@ -59,17 +64,12 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
|||||||
Allocator &_alloc;
|
Allocator &_alloc;
|
||||||
void *_ep_handler { nullptr };
|
void *_ep_handler { nullptr };
|
||||||
void *_dispatching { nullptr };
|
void *_dispatching { nullptr };
|
||||||
bool _block { true };
|
bool _resume { false };
|
||||||
|
bool _last_resume { true };
|
||||||
|
|
||||||
Vcpu_state _vcpu_state __attribute__((aligned(0x10))) { };
|
Vcpu_state _vcpu_state __attribute__((aligned(0x10))) { };
|
||||||
|
|
||||||
enum Remote_state_requested {
|
inline void _read_nova_state(Nova::Utcb &);
|
||||||
NONE = 0,
|
|
||||||
PAUSE = 1,
|
|
||||||
RUN = 2
|
|
||||||
} _remote { NONE };
|
|
||||||
|
|
||||||
inline void _read_nova_state(Nova::Utcb &, unsigned exit_reason);
|
|
||||||
|
|
||||||
inline void _write_nova_state(Nova::Utcb &);
|
inline void _write_nova_state(Nova::Utcb &);
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
|||||||
uint32_t value() const { return _value; }
|
uint32_t value() const { return _value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool _handle_exit(Nova::Utcb &, uint16_t exit_reason);
|
void _handle_exit(Nova::Utcb &);
|
||||||
|
|
||||||
__attribute__((regparm(1))) static void _exit_entry(addr_t badge);
|
__attribute__((regparm(1))) static void _exit_entry(addr_t badge);
|
||||||
|
|
||||||
@ -146,7 +146,6 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
|||||||
uint16_t vcpu_id,
|
uint16_t vcpu_id,
|
||||||
uint16_t exit_reason,
|
uint16_t exit_reason,
|
||||||
Nova::Mtd mtd);
|
Nova::Mtd mtd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Noncopyable
|
* Noncopyable
|
||||||
*/
|
*/
|
||||||
@ -158,181 +157,182 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
|||||||
Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc,
|
Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc,
|
||||||
Vcpu_handler_base &handler, Exit_config const &exit_config);
|
Vcpu_handler_base &handler, Exit_config const &exit_config);
|
||||||
|
|
||||||
void run();
|
void startup()
|
||||||
|
{
|
||||||
|
call<Rpc_startup>();
|
||||||
|
}
|
||||||
|
|
||||||
void pause();
|
void with_state(Call_with_state &cw);
|
||||||
|
|
||||||
Vcpu_state & state() { return _vcpu_state; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason)
|
void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb)
|
||||||
{
|
{
|
||||||
typedef Genode::Vcpu_state::Segment Segment;
|
typedef Genode::Vcpu_state::Segment Segment;
|
||||||
typedef Genode::Vcpu_state::Range Range;
|
typedef Genode::Vcpu_state::Range Range;
|
||||||
|
|
||||||
state().discharge();
|
_vcpu_state.discharge();
|
||||||
state().exit_reason = exit_reason;
|
_vcpu_state.exit_reason = static_cast<unsigned int>(utcb.exit_reason);
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::FPU) {
|
if (utcb.mtd & Nova::Mtd::FPU) {
|
||||||
state().fpu.charge([&] (Vcpu_state::Fpu::State &fpu) {
|
_vcpu_state.fpu.charge([&] (Vcpu_state::Fpu::State &fpu) {
|
||||||
memcpy(&fpu, utcb.fpu, sizeof(fpu));
|
memcpy(&fpu, utcb.fpu, sizeof(fpu));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::ACDB) {
|
if (utcb.mtd & Nova::Mtd::ACDB) {
|
||||||
state().ax.charge(utcb.ax);
|
_vcpu_state.ax.charge(utcb.ax);
|
||||||
state().cx.charge(utcb.cx);
|
_vcpu_state.cx.charge(utcb.cx);
|
||||||
state().dx.charge(utcb.dx);
|
_vcpu_state.dx.charge(utcb.dx);
|
||||||
state().bx.charge(utcb.bx);
|
_vcpu_state.bx.charge(utcb.bx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::EBSD) {
|
if (utcb.mtd & Nova::Mtd::EBSD) {
|
||||||
state().di.charge(utcb.di);
|
_vcpu_state.di.charge(utcb.di);
|
||||||
state().si.charge(utcb.si);
|
_vcpu_state.si.charge(utcb.si);
|
||||||
state().bp.charge(utcb.bp);
|
_vcpu_state.bp.charge(utcb.bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::EFL) state().flags.charge(utcb.flags);
|
if (utcb.mtd & Nova::Mtd::EFL) _vcpu_state.flags.charge(utcb.flags);
|
||||||
if (utcb.mtd & Nova::Mtd::ESP) state().sp.charge(utcb.sp);
|
if (utcb.mtd & Nova::Mtd::ESP) _vcpu_state.sp.charge(utcb.sp);
|
||||||
if (utcb.mtd & Nova::Mtd::DR) state().dr7.charge(utcb.dr7);
|
if (utcb.mtd & Nova::Mtd::DR) _vcpu_state.dr7.charge(utcb.dr7);
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::EIP) {
|
if (utcb.mtd & Nova::Mtd::EIP) {
|
||||||
state().ip.charge(utcb.ip);
|
_vcpu_state.ip.charge(utcb.ip);
|
||||||
state().ip_len.charge(utcb.instr_len);
|
_vcpu_state.ip_len.charge(utcb.instr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::R8_R15) {
|
if (utcb.mtd & Nova::Mtd::R8_R15) {
|
||||||
state(). r8.charge(utcb.read_r8());
|
_vcpu_state. r8.charge(utcb.read_r8());
|
||||||
state(). r9.charge(utcb.read_r9());
|
_vcpu_state. r9.charge(utcb.read_r9());
|
||||||
state().r10.charge(utcb.read_r10());
|
_vcpu_state.r10.charge(utcb.read_r10());
|
||||||
state().r11.charge(utcb.read_r11());
|
_vcpu_state.r11.charge(utcb.read_r11());
|
||||||
state().r12.charge(utcb.read_r12());
|
_vcpu_state.r12.charge(utcb.read_r12());
|
||||||
state().r13.charge(utcb.read_r13());
|
_vcpu_state.r13.charge(utcb.read_r13());
|
||||||
state().r14.charge(utcb.read_r14());
|
_vcpu_state.r14.charge(utcb.read_r14());
|
||||||
state().r15.charge(utcb.read_r15());
|
_vcpu_state.r15.charge(utcb.read_r15());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::CR) {
|
if (utcb.mtd & Nova::Mtd::CR) {
|
||||||
state().cr0.charge(utcb.cr0);
|
_vcpu_state.cr0.charge(utcb.cr0);
|
||||||
state().cr2.charge(utcb.cr2);
|
_vcpu_state.cr2.charge(utcb.cr2);
|
||||||
state().cr3.charge(utcb.cr3);
|
_vcpu_state.cr3.charge(utcb.cr3);
|
||||||
state().cr4.charge(utcb.cr4);
|
_vcpu_state.cr4.charge(utcb.cr4);
|
||||||
}
|
}
|
||||||
if (utcb.mtd & Nova::Mtd::CSSS) {
|
if (utcb.mtd & Nova::Mtd::CSSS) {
|
||||||
state().cs.charge(Segment { .sel = utcb.cs.sel,
|
_vcpu_state.cs.charge(Segment { .sel = utcb.cs.sel,
|
||||||
.ar = utcb.cs.ar,
|
.ar = utcb.cs.ar,
|
||||||
.limit = utcb.cs.limit,
|
.limit = utcb.cs.limit,
|
||||||
.base = utcb.cs.base });
|
.base = utcb.cs.base });
|
||||||
state().ss.charge(Segment { .sel = utcb.ss.sel,
|
_vcpu_state.ss.charge(Segment { .sel = utcb.ss.sel,
|
||||||
.ar = utcb.ss.ar,
|
.ar = utcb.ss.ar,
|
||||||
.limit = utcb.ss.limit,
|
.limit = utcb.ss.limit,
|
||||||
.base = utcb.ss.base });
|
.base = utcb.ss.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::ESDS) {
|
if (utcb.mtd & Nova::Mtd::ESDS) {
|
||||||
state().es.charge(Segment { .sel = utcb.es.sel,
|
_vcpu_state.es.charge(Segment { .sel = utcb.es.sel,
|
||||||
.ar = utcb.es.ar,
|
.ar = utcb.es.ar,
|
||||||
.limit = utcb.es.limit,
|
.limit = utcb.es.limit,
|
||||||
.base = utcb.es.base });
|
.base = utcb.es.base });
|
||||||
state().ds.charge(Segment { .sel = utcb.ds.sel,
|
_vcpu_state.ds.charge(Segment { .sel = utcb.ds.sel,
|
||||||
.ar = utcb.ds.ar,
|
.ar = utcb.ds.ar,
|
||||||
.limit = utcb.ds.limit,
|
.limit = utcb.ds.limit,
|
||||||
.base = utcb.ds.base });
|
.base = utcb.ds.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::FSGS) {
|
if (utcb.mtd & Nova::Mtd::FSGS) {
|
||||||
state().fs.charge(Segment { .sel = utcb.fs.sel,
|
_vcpu_state.fs.charge(Segment { .sel = utcb.fs.sel,
|
||||||
.ar = utcb.fs.ar,
|
.ar = utcb.fs.ar,
|
||||||
.limit = utcb.fs.limit,
|
.limit = utcb.fs.limit,
|
||||||
.base = utcb.fs.base });
|
.base = utcb.fs.base });
|
||||||
state().gs.charge(Segment { .sel = utcb.gs.sel,
|
_vcpu_state.gs.charge(Segment { .sel = utcb.gs.sel,
|
||||||
.ar = utcb.gs.ar,
|
.ar = utcb.gs.ar,
|
||||||
.limit = utcb.gs.limit,
|
.limit = utcb.gs.limit,
|
||||||
.base = utcb.gs.base });
|
.base = utcb.gs.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::TR) {
|
if (utcb.mtd & Nova::Mtd::TR) {
|
||||||
state().tr.charge(Segment { .sel = utcb.tr.sel,
|
_vcpu_state.tr.charge(Segment { .sel = utcb.tr.sel,
|
||||||
.ar = utcb.tr.ar,
|
.ar = utcb.tr.ar,
|
||||||
.limit = utcb.tr.limit,
|
.limit = utcb.tr.limit,
|
||||||
.base = utcb.tr.base });
|
.base = utcb.tr.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::LDTR) {
|
if (utcb.mtd & Nova::Mtd::LDTR) {
|
||||||
state().ldtr.charge(Segment { .sel = utcb.ldtr.sel,
|
_vcpu_state.ldtr.charge(Segment { .sel = utcb.ldtr.sel,
|
||||||
.ar = utcb.ldtr.ar,
|
.ar = utcb.ldtr.ar,
|
||||||
.limit = utcb.ldtr.limit,
|
.limit = utcb.ldtr.limit,
|
||||||
.base = utcb.ldtr.base });
|
.base = utcb.ldtr.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::GDTR) {
|
if (utcb.mtd & Nova::Mtd::GDTR) {
|
||||||
state().gdtr.charge(Range { .limit = utcb.gdtr.limit,
|
_vcpu_state.gdtr.charge(Range { .limit = utcb.gdtr.limit,
|
||||||
.base = utcb.gdtr.base });
|
.base = utcb.gdtr.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::IDTR) {
|
if (utcb.mtd & Nova::Mtd::IDTR) {
|
||||||
state().idtr.charge(Range { .limit = utcb.idtr.limit,
|
_vcpu_state.idtr.charge(Range { .limit = utcb.idtr.limit,
|
||||||
.base = utcb.idtr.base });
|
.base = utcb.idtr.base });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::SYS) {
|
if (utcb.mtd & Nova::Mtd::SYS) {
|
||||||
state().sysenter_cs.charge(utcb.sysenter_cs);
|
_vcpu_state.sysenter_cs.charge(utcb.sysenter_cs);
|
||||||
state().sysenter_sp.charge(utcb.sysenter_sp);
|
_vcpu_state.sysenter_sp.charge(utcb.sysenter_sp);
|
||||||
state().sysenter_ip.charge(utcb.sysenter_ip);
|
_vcpu_state.sysenter_ip.charge(utcb.sysenter_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::QUAL) {
|
if (utcb.mtd & Nova::Mtd::QUAL) {
|
||||||
state().qual_primary.charge(utcb.qual[0]);
|
_vcpu_state.qual_primary.charge(utcb.qual[0]);
|
||||||
state().qual_secondary.charge(utcb.qual[1]);
|
_vcpu_state.qual_secondary.charge(utcb.qual[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::CTRL) {
|
if (utcb.mtd & Nova::Mtd::CTRL) {
|
||||||
state().ctrl_primary.charge(utcb.ctrl[0]);
|
_vcpu_state.ctrl_primary.charge(utcb.ctrl[0]);
|
||||||
state().ctrl_secondary.charge(utcb.ctrl[1]);
|
_vcpu_state.ctrl_secondary.charge(utcb.ctrl[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::INJ) {
|
if (utcb.mtd & Nova::Mtd::INJ) {
|
||||||
state().inj_info.charge(utcb.inj_info);
|
_vcpu_state.inj_info.charge(utcb.inj_info);
|
||||||
state().inj_error.charge(utcb.inj_error);
|
_vcpu_state.inj_error.charge(utcb.inj_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::STA) {
|
if (utcb.mtd & Nova::Mtd::STA) {
|
||||||
state().intr_state.charge(utcb.intr_state);
|
_vcpu_state.intr_state.charge(utcb.intr_state);
|
||||||
state().actv_state.charge(utcb.actv_state);
|
_vcpu_state.actv_state.charge(utcb.actv_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::TSC) {
|
if (utcb.mtd & Nova::Mtd::TSC) {
|
||||||
state().tsc.charge(utcb.tsc_val);
|
_vcpu_state.tsc.charge(utcb.tsc_val);
|
||||||
state().tsc_offset.charge(utcb.tsc_off);
|
_vcpu_state.tsc_offset.charge(utcb.tsc_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::TSC_AUX) {
|
if (utcb.mtd & Nova::Mtd::TSC_AUX) {
|
||||||
state().tsc_aux.charge(utcb.tsc_aux);
|
_vcpu_state.tsc_aux.charge(utcb.tsc_aux);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::EFER) {
|
if (utcb.mtd & Nova::Mtd::EFER) {
|
||||||
state().efer.charge(utcb.read_efer());
|
_vcpu_state.efer.charge(utcb.read_efer());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::PDPTE) {
|
if (utcb.mtd & Nova::Mtd::PDPTE) {
|
||||||
state().pdpte_0.charge(utcb.pdpte[0]);
|
_vcpu_state.pdpte_0.charge(utcb.pdpte[0]);
|
||||||
state().pdpte_1.charge(utcb.pdpte[1]);
|
_vcpu_state.pdpte_1.charge(utcb.pdpte[1]);
|
||||||
state().pdpte_2.charge(utcb.pdpte[2]);
|
_vcpu_state.pdpte_2.charge(utcb.pdpte[2]);
|
||||||
state().pdpte_3.charge(utcb.pdpte[3]);
|
_vcpu_state.pdpte_3.charge(utcb.pdpte[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::SYSCALL_SWAPGS) {
|
if (utcb.mtd & Nova::Mtd::SYSCALL_SWAPGS) {
|
||||||
state().star.charge(utcb.read_star());
|
_vcpu_state.star.charge(utcb.read_star());
|
||||||
state().lstar.charge(utcb.read_lstar());
|
_vcpu_state.lstar.charge(utcb.read_lstar());
|
||||||
state().cstar.charge(utcb.read_cstar());
|
_vcpu_state.cstar.charge(utcb.read_cstar());
|
||||||
state().fmask.charge(utcb.read_fmask());
|
_vcpu_state.fmask.charge(utcb.read_fmask());
|
||||||
state().kernel_gs_base.charge(utcb.read_kernel_gs_base());
|
_vcpu_state.kernel_gs_base.charge(utcb.read_kernel_gs_base());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utcb.mtd & Nova::Mtd::TPR) {
|
if (utcb.mtd & Nova::Mtd::TPR) {
|
||||||
state().tpr.charge(utcb.read_tpr());
|
_vcpu_state.tpr.charge(utcb.read_tpr());
|
||||||
state().tpr_threshold.charge(utcb.read_tpr_threshold());
|
_vcpu_state.tpr_threshold.charge(utcb.read_tpr_threshold());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,291 +342,234 @@ void Nova_vcpu::_write_nova_state(Nova::Utcb &utcb)
|
|||||||
utcb.items = 0;
|
utcb.items = 0;
|
||||||
utcb.mtd = 0;
|
utcb.mtd = 0;
|
||||||
|
|
||||||
if (state().ax.charged() || state().cx.charged() ||
|
if (_vcpu_state.ax.charged() || _vcpu_state.cx.charged() ||
|
||||||
state().dx.charged() || state().bx.charged()) {
|
_vcpu_state.dx.charged() || _vcpu_state.bx.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::ACDB;
|
utcb.mtd |= Nova::Mtd::ACDB;
|
||||||
utcb.ax = state().ax.value();
|
utcb.ax = _vcpu_state.ax.value();
|
||||||
utcb.cx = state().cx.value();
|
utcb.cx = _vcpu_state.cx.value();
|
||||||
utcb.dx = state().dx.value();
|
utcb.dx = _vcpu_state.dx.value();
|
||||||
utcb.bx = state().bx.value();
|
utcb.bx = _vcpu_state.bx.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().bp.charged() || state().di.charged() || state().si.charged()) {
|
if (_vcpu_state.bp.charged() || _vcpu_state.di.charged() || _vcpu_state.si.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::EBSD;
|
utcb.mtd |= Nova::Mtd::EBSD;
|
||||||
utcb.di = state().di.value();
|
utcb.di = _vcpu_state.di.value();
|
||||||
utcb.si = state().si.value();
|
utcb.si = _vcpu_state.si.value();
|
||||||
utcb.bp = state().bp.value();
|
utcb.bp = _vcpu_state.bp.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().flags.charged()) {
|
if (_vcpu_state.flags.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::EFL;
|
utcb.mtd |= Nova::Mtd::EFL;
|
||||||
utcb.flags = state().flags.value();
|
utcb.flags = _vcpu_state.flags.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().sp.charged()) {
|
if (_vcpu_state.sp.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::ESP;
|
utcb.mtd |= Nova::Mtd::ESP;
|
||||||
utcb.sp = state().sp.value();
|
utcb.sp = _vcpu_state.sp.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().ip.charged()) {
|
if (_vcpu_state.ip.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::EIP;
|
utcb.mtd |= Nova::Mtd::EIP;
|
||||||
utcb.ip = state().ip.value();
|
utcb.ip = _vcpu_state.ip.value();
|
||||||
utcb.instr_len = state().ip_len.value();
|
utcb.instr_len = _vcpu_state.ip_len.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().dr7.charged()) {
|
if (_vcpu_state.dr7.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::DR;
|
utcb.mtd |= Nova::Mtd::DR;
|
||||||
utcb.dr7 = state().dr7.value();
|
utcb.dr7 = _vcpu_state.dr7.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().r8 .charged() || state().r9 .charged() ||
|
if (_vcpu_state.r8 .charged() || _vcpu_state.r9 .charged() ||
|
||||||
state().r10.charged() || state().r11.charged() ||
|
_vcpu_state.r10.charged() || _vcpu_state.r11.charged() ||
|
||||||
state().r12.charged() || state().r13.charged() ||
|
_vcpu_state.r12.charged() || _vcpu_state.r13.charged() ||
|
||||||
state().r14.charged() || state().r15.charged()) {
|
_vcpu_state.r14.charged() || _vcpu_state.r15.charged()) {
|
||||||
|
|
||||||
utcb.mtd |= Nova::Mtd::R8_R15;
|
utcb.mtd |= Nova::Mtd::R8_R15;
|
||||||
utcb.write_r8 (state().r8.value());
|
utcb.write_r8 (_vcpu_state.r8.value());
|
||||||
utcb.write_r9 (state().r9.value());
|
utcb.write_r9 (_vcpu_state.r9.value());
|
||||||
utcb.write_r10(state().r10.value());
|
utcb.write_r10(_vcpu_state.r10.value());
|
||||||
utcb.write_r11(state().r11.value());
|
utcb.write_r11(_vcpu_state.r11.value());
|
||||||
utcb.write_r12(state().r12.value());
|
utcb.write_r12(_vcpu_state.r12.value());
|
||||||
utcb.write_r13(state().r13.value());
|
utcb.write_r13(_vcpu_state.r13.value());
|
||||||
utcb.write_r14(state().r14.value());
|
utcb.write_r14(_vcpu_state.r14.value());
|
||||||
utcb.write_r15(state().r15.value());
|
utcb.write_r15(_vcpu_state.r15.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().cr0.charged() || state().cr2.charged() ||
|
if (_vcpu_state.cr0.charged() || _vcpu_state.cr2.charged() ||
|
||||||
state().cr3.charged() || state().cr4.charged()) {
|
_vcpu_state.cr3.charged() || _vcpu_state.cr4.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::CR;
|
utcb.mtd |= Nova::Mtd::CR;
|
||||||
utcb.cr0 = state().cr0.value();
|
utcb.cr0 = _vcpu_state.cr0.value();
|
||||||
utcb.cr2 = state().cr2.value();
|
utcb.cr2 = _vcpu_state.cr2.value();
|
||||||
utcb.cr3 = state().cr3.value();
|
utcb.cr3 = _vcpu_state.cr3.value();
|
||||||
utcb.cr4 = state().cr4.value();
|
utcb.cr4 = _vcpu_state.cr4.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().cs.charged() || state().ss.charged()) {
|
if (_vcpu_state.cs.charged() || _vcpu_state.ss.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::CSSS;
|
utcb.mtd |= Nova::Mtd::CSSS;
|
||||||
utcb.cs.sel = state().cs.value().sel;
|
utcb.cs.sel = _vcpu_state.cs.value().sel;
|
||||||
utcb.cs.ar = state().cs.value().ar;
|
utcb.cs.ar = _vcpu_state.cs.value().ar;
|
||||||
utcb.cs.limit = state().cs.value().limit;
|
utcb.cs.limit = _vcpu_state.cs.value().limit;
|
||||||
utcb.cs.base = state().cs.value().base;
|
utcb.cs.base = _vcpu_state.cs.value().base;
|
||||||
|
|
||||||
utcb.ss.sel = state().ss.value().sel;
|
utcb.ss.sel = _vcpu_state.ss.value().sel;
|
||||||
utcb.ss.ar = state().ss.value().ar;
|
utcb.ss.ar = _vcpu_state.ss.value().ar;
|
||||||
utcb.ss.limit = state().ss.value().limit;
|
utcb.ss.limit = _vcpu_state.ss.value().limit;
|
||||||
utcb.ss.base = state().ss.value().base;
|
utcb.ss.base = _vcpu_state.ss.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().es.charged() || state().ds.charged()) {
|
if (_vcpu_state.es.charged() || _vcpu_state.ds.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::ESDS;
|
utcb.mtd |= Nova::Mtd::ESDS;
|
||||||
utcb.es.sel = state().es.value().sel;
|
utcb.es.sel = _vcpu_state.es.value().sel;
|
||||||
utcb.es.ar = state().es.value().ar;
|
utcb.es.ar = _vcpu_state.es.value().ar;
|
||||||
utcb.es.limit = state().es.value().limit;
|
utcb.es.limit = _vcpu_state.es.value().limit;
|
||||||
utcb.es.base = state().es.value().base;
|
utcb.es.base = _vcpu_state.es.value().base;
|
||||||
|
|
||||||
utcb.ds.sel = state().ds.value().sel;
|
utcb.ds.sel = _vcpu_state.ds.value().sel;
|
||||||
utcb.ds.ar = state().ds.value().ar;
|
utcb.ds.ar = _vcpu_state.ds.value().ar;
|
||||||
utcb.ds.limit = state().ds.value().limit;
|
utcb.ds.limit = _vcpu_state.ds.value().limit;
|
||||||
utcb.ds.base = state().ds.value().base;
|
utcb.ds.base = _vcpu_state.ds.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().fs.charged() || state().gs.charged()) {
|
if (_vcpu_state.fs.charged() || _vcpu_state.gs.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::FSGS;
|
utcb.mtd |= Nova::Mtd::FSGS;
|
||||||
utcb.fs.sel = state().fs.value().sel;
|
utcb.fs.sel = _vcpu_state.fs.value().sel;
|
||||||
utcb.fs.ar = state().fs.value().ar;
|
utcb.fs.ar = _vcpu_state.fs.value().ar;
|
||||||
utcb.fs.limit = state().fs.value().limit;
|
utcb.fs.limit = _vcpu_state.fs.value().limit;
|
||||||
utcb.fs.base = state().fs.value().base;
|
utcb.fs.base = _vcpu_state.fs.value().base;
|
||||||
|
|
||||||
utcb.gs.sel = state().gs.value().sel;
|
utcb.gs.sel = _vcpu_state.gs.value().sel;
|
||||||
utcb.gs.ar = state().gs.value().ar;
|
utcb.gs.ar = _vcpu_state.gs.value().ar;
|
||||||
utcb.gs.limit = state().gs.value().limit;
|
utcb.gs.limit = _vcpu_state.gs.value().limit;
|
||||||
utcb.gs.base = state().gs.value().base;
|
utcb.gs.base = _vcpu_state.gs.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().tr.charged()) {
|
if (_vcpu_state.tr.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::TR;
|
utcb.mtd |= Nova::Mtd::TR;
|
||||||
utcb.tr.sel = state().tr.value().sel;
|
utcb.tr.sel = _vcpu_state.tr.value().sel;
|
||||||
utcb.tr.ar = state().tr.value().ar;
|
utcb.tr.ar = _vcpu_state.tr.value().ar;
|
||||||
utcb.tr.limit = state().tr.value().limit;
|
utcb.tr.limit = _vcpu_state.tr.value().limit;
|
||||||
utcb.tr.base = state().tr.value().base;
|
utcb.tr.base = _vcpu_state.tr.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().ldtr.charged()) {
|
if (_vcpu_state.ldtr.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::LDTR;
|
utcb.mtd |= Nova::Mtd::LDTR;
|
||||||
utcb.ldtr.sel = state().ldtr.value().sel;
|
utcb.ldtr.sel = _vcpu_state.ldtr.value().sel;
|
||||||
utcb.ldtr.ar = state().ldtr.value().ar;
|
utcb.ldtr.ar = _vcpu_state.ldtr.value().ar;
|
||||||
utcb.ldtr.limit = state().ldtr.value().limit;
|
utcb.ldtr.limit = _vcpu_state.ldtr.value().limit;
|
||||||
utcb.ldtr.base = state().ldtr.value().base;
|
utcb.ldtr.base = _vcpu_state.ldtr.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().gdtr.charged()) {
|
if (_vcpu_state.gdtr.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::GDTR;
|
utcb.mtd |= Nova::Mtd::GDTR;
|
||||||
utcb.gdtr.limit = state().gdtr.value().limit;
|
utcb.gdtr.limit = _vcpu_state.gdtr.value().limit;
|
||||||
utcb.gdtr.base = state().gdtr.value().base;
|
utcb.gdtr.base = _vcpu_state.gdtr.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().idtr.charged()) {
|
if (_vcpu_state.idtr.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::IDTR;
|
utcb.mtd |= Nova::Mtd::IDTR;
|
||||||
utcb.idtr.limit = state().idtr.value().limit;
|
utcb.idtr.limit = _vcpu_state.idtr.value().limit;
|
||||||
utcb.idtr.base = state().idtr.value().base;
|
utcb.idtr.base = _vcpu_state.idtr.value().base;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().sysenter_cs.charged() || state().sysenter_sp.charged() ||
|
if (_vcpu_state.sysenter_cs.charged() || _vcpu_state.sysenter_sp.charged() ||
|
||||||
state().sysenter_ip.charged()) {
|
_vcpu_state.sysenter_ip.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::SYS;
|
utcb.mtd |= Nova::Mtd::SYS;
|
||||||
utcb.sysenter_cs = state().sysenter_cs.value();
|
utcb.sysenter_cs = _vcpu_state.sysenter_cs.value();
|
||||||
utcb.sysenter_sp = state().sysenter_sp.value();
|
utcb.sysenter_sp = _vcpu_state.sysenter_sp.value();
|
||||||
utcb.sysenter_ip = state().sysenter_ip.value();
|
utcb.sysenter_ip = _vcpu_state.sysenter_ip.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().ctrl_primary.charged() || state().ctrl_secondary.charged()) {
|
if (_vcpu_state.ctrl_primary.charged() || _vcpu_state.ctrl_secondary.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::CTRL;
|
utcb.mtd |= Nova::Mtd::CTRL;
|
||||||
utcb.ctrl[0] = state().ctrl_primary.value();
|
utcb.ctrl[0] = _vcpu_state.ctrl_primary.value();
|
||||||
utcb.ctrl[1] = state().ctrl_secondary.value();
|
utcb.ctrl[1] = _vcpu_state.ctrl_secondary.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().inj_info.charged() || state().inj_error.charged()) {
|
if (_vcpu_state.inj_info.charged() || _vcpu_state.inj_error.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::INJ;
|
utcb.mtd |= Nova::Mtd::INJ;
|
||||||
utcb.inj_info = state().inj_info.value();
|
utcb.inj_info = _vcpu_state.inj_info.value();
|
||||||
utcb.inj_error = state().inj_error.value();
|
utcb.inj_error = _vcpu_state.inj_error.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().intr_state.charged() || state().actv_state.charged()) {
|
if (_vcpu_state.intr_state.charged() || _vcpu_state.actv_state.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::STA;
|
utcb.mtd |= Nova::Mtd::STA;
|
||||||
utcb.intr_state = state().intr_state.value();
|
utcb.intr_state = _vcpu_state.intr_state.value();
|
||||||
utcb.actv_state = state().actv_state.value();
|
utcb.actv_state = _vcpu_state.actv_state.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().tsc.charged() || state().tsc_offset.charged()) {
|
if (_vcpu_state.tsc.charged() || _vcpu_state.tsc_offset.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::TSC;
|
utcb.mtd |= Nova::Mtd::TSC;
|
||||||
utcb.tsc_val = state().tsc.value();
|
utcb.tsc_val = _vcpu_state.tsc.value();
|
||||||
utcb.tsc_off = state().tsc_offset.value();
|
utcb.tsc_off = _vcpu_state.tsc_offset.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().tsc_aux.charged()) {
|
if (_vcpu_state.tsc_aux.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::TSC_AUX;
|
utcb.mtd |= Nova::Mtd::TSC_AUX;
|
||||||
utcb.tsc_aux = state().tsc_aux.value();
|
utcb.tsc_aux = _vcpu_state.tsc_aux.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().efer.charged()) {
|
if (_vcpu_state.efer.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::EFER;
|
utcb.mtd |= Nova::Mtd::EFER;
|
||||||
utcb.write_efer(state().efer.value());
|
utcb.write_efer(_vcpu_state.efer.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().pdpte_0.charged() || state().pdpte_1.charged() ||
|
if (_vcpu_state.pdpte_0.charged() || _vcpu_state.pdpte_1.charged() ||
|
||||||
state().pdpte_2.charged() || state().pdpte_3.charged()) {
|
_vcpu_state.pdpte_2.charged() || _vcpu_state.pdpte_3.charged()) {
|
||||||
|
|
||||||
utcb.mtd |= Nova::Mtd::PDPTE;
|
utcb.mtd |= Nova::Mtd::PDPTE;
|
||||||
utcb.pdpte[0] = (Nova::mword_t)state().pdpte_0.value();
|
utcb.pdpte[0] = (Nova::mword_t)_vcpu_state.pdpte_0.value();
|
||||||
utcb.pdpte[1] = (Nova::mword_t)state().pdpte_1.value();
|
utcb.pdpte[1] = (Nova::mword_t)_vcpu_state.pdpte_1.value();
|
||||||
utcb.pdpte[2] = (Nova::mword_t)state().pdpte_2.value();
|
utcb.pdpte[2] = (Nova::mword_t)_vcpu_state.pdpte_2.value();
|
||||||
utcb.pdpte[3] = (Nova::mword_t)state().pdpte_3.value();
|
utcb.pdpte[3] = (Nova::mword_t)_vcpu_state.pdpte_3.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().star.charged() || state().lstar.charged() ||
|
if (_vcpu_state.star.charged() || _vcpu_state.lstar.charged() ||
|
||||||
state().cstar.charged() || state().fmask.charged() ||
|
_vcpu_state.cstar.charged() || _vcpu_state.fmask.charged() ||
|
||||||
state().kernel_gs_base.charged()) {
|
_vcpu_state.kernel_gs_base.charged()) {
|
||||||
|
|
||||||
utcb.mtd |= Nova::Mtd::SYSCALL_SWAPGS;
|
utcb.mtd |= Nova::Mtd::SYSCALL_SWAPGS;
|
||||||
utcb.write_star (state().star.value());
|
utcb.write_star (_vcpu_state.star.value());
|
||||||
utcb.write_lstar(state().lstar.value());
|
utcb.write_lstar(_vcpu_state.lstar.value());
|
||||||
utcb.write_cstar(state().cstar.value());
|
utcb.write_cstar(_vcpu_state.cstar.value());
|
||||||
utcb.write_fmask(state().fmask.value());
|
utcb.write_fmask(_vcpu_state.fmask.value());
|
||||||
utcb.write_kernel_gs_base(state().kernel_gs_base.value());
|
utcb.write_kernel_gs_base(_vcpu_state.kernel_gs_base.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().tpr.charged() || state().tpr_threshold.charged()) {
|
if (_vcpu_state.tpr.charged() || _vcpu_state.tpr_threshold.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::TPR;
|
utcb.mtd |= Nova::Mtd::TPR;
|
||||||
utcb.write_tpr(state().tpr.value());
|
utcb.write_tpr(_vcpu_state.tpr.value());
|
||||||
utcb.write_tpr_threshold(state().tpr_threshold.value());
|
utcb.write_tpr_threshold(_vcpu_state.tpr_threshold.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state().fpu.charged()) {
|
if (_vcpu_state.fpu.charged()) {
|
||||||
utcb.mtd |= Nova::Mtd::FPU;
|
utcb.mtd |= Nova::Mtd::FPU;
|
||||||
state().fpu.with_state([&] (Vcpu_state::Fpu::State const &fpu) {
|
_vcpu_state.fpu.with_state([&] (Vcpu_state::Fpu::State const &fpu) {
|
||||||
memcpy(utcb.fpu, &fpu, sizeof(fpu));
|
memcpy(utcb.fpu, &fpu, sizeof(fpu));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Nova_vcpu::run()
|
|
||||||
{
|
|
||||||
if (!_ep_handler) {
|
|
||||||
/* not started yet - trigger startup of native vCPU */
|
|
||||||
call<Rpc_startup>();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread * const current = Thread::myself();
|
|
||||||
|
|
||||||
if (_dispatching == current) {
|
|
||||||
_block = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_ep_handler == current) && !_block)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_ep_handler != current)
|
|
||||||
_remote = RUN;
|
|
||||||
|
|
||||||
Nova::ec_ctrl(Nova::EC_RECALL, _ec_sel());
|
|
||||||
Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not touch the UTCB before _read_nova_state() and after
|
* Do not touch the UTCB before _read_nova_state() and after
|
||||||
* _write_nova_state(), particularly not by logging diagnostics.
|
* _write_nova_state(), particularly not by logging diagnostics.
|
||||||
*/
|
*/
|
||||||
bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason)
|
void Nova_vcpu::_handle_exit(Nova::Utcb &utcb)
|
||||||
{
|
{
|
||||||
/* reset blocking state */
|
if (utcb.exit_reason == VM_EXIT_RECALL) {
|
||||||
bool const previous_blocked = _block;
|
/*
|
||||||
_block = true;
|
* A recall exit is only requested from an asynchronous Signal to the
|
||||||
|
* vCPU Handler. In that case, VM_EXIT_RECALL has already been processed
|
||||||
/* NOVA specific exit reasons */
|
* asynchronously by getting and setting the state via system calls and
|
||||||
enum { VM_EXIT_STARTUP = 0xfe, VM_EXIT_RECALL = 0xff };
|
* the regular exit does not need to be processed.
|
||||||
|
*/
|
||||||
if (exit_reason == VM_EXIT_STARTUP)
|
utcb.mtd = 0;
|
||||||
_ep_handler = Thread::myself();
|
utcb.items = 0;
|
||||||
|
return;
|
||||||
/* transform state from NOVA to Genode */
|
|
||||||
if (exit_reason != VM_EXIT_RECALL || !previous_blocked)
|
|
||||||
_read_nova_state(utcb, exit_reason);
|
|
||||||
|
|
||||||
if (exit_reason == VM_EXIT_RECALL) {
|
|
||||||
if (previous_blocked)
|
|
||||||
state().exit_reason = exit_reason;
|
|
||||||
|
|
||||||
/* consume potential multiple sem ups */
|
|
||||||
Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP);
|
|
||||||
Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_DOWNZERO);
|
|
||||||
|
|
||||||
if (_remote == PAUSE) {
|
|
||||||
_remote = NONE;
|
|
||||||
} else {
|
|
||||||
if (_remote == RUN) {
|
|
||||||
_remote = NONE;
|
|
||||||
if (!previous_blocked) {
|
|
||||||
/* still running - reply without state transfer */
|
|
||||||
_block = false;
|
|
||||||
utcb.items = 0;
|
|
||||||
utcb.mtd = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previous_blocked) {
|
|
||||||
/* resume vCPU - with vCPU state update */
|
|
||||||
_block = false;
|
|
||||||
_write_nova_state(utcb);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_read_nova_state(utcb);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_dispatching = Thread::myself();
|
_dispatching = Thread::myself();
|
||||||
/* call dispatch handler */
|
/* call dispatch handler */
|
||||||
@ -637,36 +580,92 @@ bool Nova_vcpu::_handle_exit(Nova::Utcb &utcb, uint16_t exit_reason)
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_block) {
|
|
||||||
/* block vCPU in kernel - no vCPU state update */
|
|
||||||
utcb.items = 0;
|
|
||||||
utcb.mtd = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reply to NOVA and transfer vCPU state */
|
/* reply to NOVA and transfer vCPU state */
|
||||||
_write_nova_state(utcb);
|
_write_nova_state(utcb);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Nova_vcpu::with_state(Call_with_state &cw)
|
||||||
|
{
|
||||||
|
Thread *myself = Thread::myself();
|
||||||
|
bool remote = (_dispatching != myself);
|
||||||
|
Nova::Utcb &utcb = *reinterpret_cast<Nova::Utcb *>(myself->utcb());
|
||||||
|
|
||||||
|
if (remote) {
|
||||||
|
if (Thread::myself() != _ep_handler) {
|
||||||
|
error("vCPU state requested outside of vcpu_handler EP");
|
||||||
|
sleep_forever();
|
||||||
|
};
|
||||||
|
|
||||||
|
Exit_config config { };
|
||||||
|
Nova::Mtd mtd = _portal_mtd(0, config);
|
||||||
|
|
||||||
|
uint8_t res = Nova::ec_ctrl(Nova::EC_GET_VCPU_STATE, _ec_sel(), mtd.value());
|
||||||
|
|
||||||
|
if (res != Nova::NOVA_OK) {
|
||||||
|
error("Getting vCPU state failed with: ", res);
|
||||||
|
sleep_forever();
|
||||||
|
};
|
||||||
|
|
||||||
|
_read_nova_state(utcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
_resume = cw.call_with_state(_vcpu_state);
|
||||||
|
|
||||||
|
if (remote) {
|
||||||
|
_write_nova_state(utcb);
|
||||||
|
/*
|
||||||
|
* A recall is needed
|
||||||
|
* a) when the vCPU should be stopped or
|
||||||
|
* b) when the vCPU should be resumed from a stopped state.
|
||||||
|
*/
|
||||||
|
bool recall = !(_resume && _last_resume);
|
||||||
|
|
||||||
|
uint8_t res = Nova::ec_ctrl(Nova::EC_SET_VCPU_STATE, _ec_sel(), recall);
|
||||||
|
|
||||||
|
if (res != Nova::NOVA_OK) {
|
||||||
|
error("Setting vCPU state failed with: ", res);
|
||||||
|
sleep_forever();
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resume the vCPU and indicate to the next exit if state
|
||||||
|
* needs to be synced or not.
|
||||||
|
*/
|
||||||
|
if (_resume)
|
||||||
|
Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename... ARGS>
|
||||||
|
static void nova_reply(Thread &myself, Nova::Utcb &utcb, ARGS &&... args)
|
||||||
|
{
|
||||||
|
Receive_window &rcv_window = myself.native_thread().server_rcv_window;
|
||||||
|
|
||||||
|
/* reset receive window to values expected by RPC server code */
|
||||||
|
rcv_window.prepare_rcv_window(utcb);
|
||||||
|
|
||||||
|
Nova::reply(myself.stack_top(), args...);
|
||||||
|
}
|
||||||
|
|
||||||
void Nova_vcpu::_exit_entry(addr_t badge)
|
void Nova_vcpu::_exit_entry(addr_t badge)
|
||||||
{
|
{
|
||||||
Thread &myself = *Thread::myself();
|
Thread &myself = *Thread::myself();
|
||||||
Nova::Utcb &utcb = *reinterpret_cast<Nova::Utcb *>(myself.utcb());
|
Nova::Utcb &utcb = *reinterpret_cast<Nova::Utcb *>(myself.utcb());
|
||||||
|
|
||||||
uint16_t const exit_reason { Badge(badge).exit_reason() };
|
|
||||||
Vcpu_space::Id const vcpu_id { Badge(badge).vcpu_id() };
|
Vcpu_space::Id const vcpu_id { Badge(badge).vcpu_id() };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_vcpu_space().apply<Nova_vcpu>(vcpu_id, [&] (Nova_vcpu &vcpu)
|
_vcpu_space().apply<Nova_vcpu>(vcpu_id, [&] (Nova_vcpu &vcpu)
|
||||||
{
|
{
|
||||||
bool const block = vcpu._handle_exit(utcb, exit_reason);
|
vcpu._handle_exit(utcb);
|
||||||
|
|
||||||
if (block) {
|
vcpu._last_resume = vcpu._resume;
|
||||||
Nova::reply(myself.stack_top(), vcpu._sm_sel());
|
if (vcpu._resume) {
|
||||||
|
nova_reply(myself, utcb);
|
||||||
} else {
|
} else {
|
||||||
Nova::reply(myself.stack_top());
|
nova_reply(myself, utcb, vcpu._sm_sel());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -675,44 +674,11 @@ void Nova_vcpu::_exit_entry(addr_t badge)
|
|||||||
/* somebody called us directly ? ... ignore/deny */
|
/* somebody called us directly ? ... ignore/deny */
|
||||||
utcb.items = 0;
|
utcb.items = 0;
|
||||||
utcb.mtd = 0;
|
utcb.mtd = 0;
|
||||||
Nova::reply(myself.stack_top());
|
nova_reply(myself, utcb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Nova_vcpu::pause()
|
|
||||||
{
|
|
||||||
Thread * const current = Thread::myself();
|
|
||||||
|
|
||||||
if (_dispatching == current) {
|
|
||||||
/* current thread is already dispatching */
|
|
||||||
if (_block)
|
|
||||||
/* issue pause exit next time - fall through */
|
|
||||||
_block = false;
|
|
||||||
else {
|
|
||||||
_block = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_ep_handler == current) && _block) {
|
|
||||||
_remote = PAUSE;
|
|
||||||
/* already blocked */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_ep_handler != current)
|
|
||||||
_remote = PAUSE;
|
|
||||||
|
|
||||||
if (!_ep_handler) {
|
|
||||||
/* not started yet - let startup handler issue the recall */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Nova::ec_ctrl(Nova::EC_RECALL, _ec_sel());
|
|
||||||
Nova::sm_ctrl(_sm_sel(), Nova::SEMAPHORE_UP);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Signal_context_capability Nova_vcpu::_create_exit_handler(Pd_session &pd,
|
Signal_context_capability Nova_vcpu::_create_exit_handler(Pd_session &pd,
|
||||||
Vcpu_handler_base &handler,
|
Vcpu_handler_base &handler,
|
||||||
uint16_t vcpu_id,
|
uint16_t vcpu_id,
|
||||||
@ -758,6 +724,8 @@ Nova_vcpu::Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc,
|
|||||||
if (_id_elem.id().value > 0xffff)
|
if (_id_elem.id().value > 0xffff)
|
||||||
throw Vcpu_id_space_exhausted();
|
throw Vcpu_id_space_exhausted();
|
||||||
|
|
||||||
|
_ep_handler = reinterpret_cast<Thread *>(&handler.rpc_ep());
|
||||||
|
|
||||||
uint16_t const vcpu_id = (uint16_t)_id_elem.id().value;
|
uint16_t const vcpu_id = (uint16_t)_id_elem.id().value;
|
||||||
|
|
||||||
Signal_context_capability dontcare_exit =
|
Signal_context_capability dontcare_exit =
|
||||||
@ -782,14 +750,13 @@ Nova_vcpu::Nova_vcpu(Env &env, Vm_connection &vm, Allocator &alloc,
|
|||||||
** vCPU API **
|
** vCPU API **
|
||||||
**************/
|
**************/
|
||||||
|
|
||||||
void Vm_connection::Vcpu::run() { static_cast<Nova_vcpu &>(_native_vcpu).run(); }
|
void Vm_connection::Vcpu::_with_state(Call_with_state &cw) { static_cast<Nova_vcpu &>(_native_vcpu).with_state(cw); }
|
||||||
void Vm_connection::Vcpu::pause() { static_cast<Nova_vcpu &>(_native_vcpu).pause(); }
|
|
||||||
Vcpu_state & Vm_connection::Vcpu::state() { return static_cast<Nova_vcpu &>(_native_vcpu).state(); }
|
|
||||||
|
|
||||||
|
|
||||||
Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc,
|
Vm_connection::Vcpu::Vcpu(Vm_connection &vm, Allocator &alloc,
|
||||||
Vcpu_handler_base &handler, Exit_config const &exit_config)
|
Vcpu_handler_base &handler, Exit_config const &exit_config)
|
||||||
:
|
:
|
||||||
_native_vcpu(*new (alloc) Nova_vcpu(vm._env, vm, alloc, handler, exit_config))
|
_native_vcpu(*new (alloc) Nova_vcpu(vm._env, vm, alloc, handler, exit_config))
|
||||||
{ }
|
{
|
||||||
|
static_cast<Nova_vcpu &>(_native_vcpu).startup();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user