diff --git a/repos/base-foc/src/core/vm_session_component.cc b/repos/base-foc/src/core/vm_session_component.cc
index 3847c8edb..7e9cbe7fb 100644
--- a/repos/base-foc/src/core/vm_session_component.cc
+++ b/repos/base-foc/src/core/vm_session_component.cc
@@ -87,7 +87,7 @@ Vcpu::Vcpu(Constrained_ram_allocator &ram_alloc,
{
try {
/* create ds for vCPU state */
- _ds_cap = _ram_alloc.alloc(4096, Cache_attribute::CACHED);
+ _ds_cap = _ram_alloc.alloc(0x1000, Cache_attribute::CACHED);
} catch (...) {
throw;
}
diff --git a/repos/base-nova/src/core/vm_session_component.cc b/repos/base-nova/src/core/vm_session_component.cc
index 94aa97693..55f6c91f2 100644
--- a/repos/base-nova/src/core/vm_session_component.cc
+++ b/repos/base-nova/src/core/vm_session_component.cc
@@ -13,6 +13,7 @@
/* Base includes */
#include
+#include
#include
#include
@@ -65,7 +66,8 @@ Vm_session_component::Vcpu::Vcpu(Constrained_ram_allocator &ram_alloc,
try {
/* create ds for vCPU state */
- _ds_cap = _ram_alloc.alloc(4096, Cache_attribute::CACHED);
+ _ds_cap = _ram_alloc.alloc(align_addr(sizeof(Genode::Vm_state), 12),
+ Cache_attribute::CACHED);
} catch (...) {
_cap_alloc.replenish(Cap_quota{CAP_RANGE});
cap_map().remove(_sel_sm_ec_sc, CAP_RANGE_LOG2);
diff --git a/repos/base-nova/src/lib/base/vm_session.cc b/repos/base-nova/src/lib/base/vm_session.cc
index 0abeccdf3..fc1a4da3f 100644
--- a/repos/base-nova/src/lib/base/vm_session.cc
+++ b/repos/base-nova/src/lib/base/vm_session.cc
@@ -58,6 +58,12 @@ struct Vcpu {
state = Vm_state {};
state.exit_reason = exit_reason;
+ if (utcb.mtd & Nova::Mtd::FPU) {
+ state.fpu.value([&] (uint8_t *fpu, size_t const) {
+ asm volatile ("fxsave %0" : "=m" (*fpu));
+ });
+ }
+
if (utcb.mtd & Nova::Mtd::ACDB) {
state.ax.value(utcb.ax);
state.cx.value(utcb.cx);
@@ -190,7 +196,6 @@ struct Vcpu {
state.tpr_threshold.value(utcb.read_tpr_threshold());
}
- /* XXX FPU state missing */
}
static void _write_nova_state(Nova::Utcb &utcb, Vm_state &state)
@@ -389,6 +394,12 @@ struct Vcpu {
utcb.write_tpr(state.tpr.value());
utcb.write_tpr_threshold(state.tpr_threshold.value());
}
+
+ if (state.fpu.valid()) {
+ state.fpu.value([&] (uint8_t *fpu, size_t const) {
+ asm volatile ("fxrstor %0" : : "m" (*fpu));
+ });
+ }
}
void _dispatch()
@@ -655,7 +666,8 @@ struct Vcpu {
if (state.qual_primary.valid() || state.qual_secondary.valid())
mtd |= Nova::Mtd::QUAL;
- /* XXX FPU missing */
+ if (state.fpu.valid())
+ mtd |= Nova::Mtd::FPU;
state = Vm_state {};
diff --git a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc
index b674e827e..642fd288a 100644
--- a/repos/base-sel4/src/core/spec/x86/vm_session_component.cc
+++ b/repos/base-sel4/src/core/spec/x86/vm_session_component.cc
@@ -13,6 +13,7 @@
/* base includes */
#include
+#include
/* core includes */
#include
@@ -45,7 +46,8 @@ Vm_session_component::Vcpu::Vcpu(Constrained_ram_allocator &ram_alloc,
seL4_Untyped const service)
:
_ram_alloc(ram_alloc),
- _ds_cap (_ram_alloc.alloc(4096, Cache_attribute::CACHED)),
+ _ds_cap (_ram_alloc.alloc(align_addr(sizeof(Genode::Vm_state), 12),
+ Cache_attribute::CACHED)),
_vcpu_id(vcpu_id)
{
try {
diff --git a/repos/base/include/spec/x86/cpu/vm_state.h b/repos/base/include/spec/x86/cpu/vm_state.h
index 1018b44ae..291120ad4 100644
--- a/repos/base/include/spec/x86/cpu/vm_state.h
+++ b/repos/base/include/spec/x86/cpu/vm_state.h
@@ -141,6 +141,30 @@ struct Genode::Vm_state
Register tpr_threshold;
unsigned exit_reason;
+
+ class Fpu {
+ private :
+
+ uint8_t _value[512] { };
+ bool _valid { false };
+
+ public:
+
+ bool valid() const { return _valid; }
+ void invalid() { _valid = false; }
+
+ template
+ void value(FUNC const &fn) {
+ _valid = true;
+ fn(_value, sizeof(_value));
+ };
+
+ Fpu &operator = (Fpu const &)
+ {
+ _valid = false;
+ return *this;
+ }
+ } fpu __attribute__((aligned(16)));
};
#endif /* _INCLUDE__SPEC__X86__CPU__VM_STATE_H_ */