Skip to content

Commit 288246d

Browse files
committed
Add new Machine::vmresume() that handles resets properly
1 parent b1c3223 commit 288246d

File tree

6 files changed

+82
-19
lines changed

6 files changed

+82
-19
lines changed

lib/tinykvm/amd64/builtin/usercode.asm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
dw .vm64_entry
44
dw .vm64_rexit
5+
dw .vm64_preserving_entry
6+
dw 0
57
dd .vm64_cpuid
68

79
ALIGN 0x10
@@ -23,6 +25,22 @@ ALIGN 0x10
2325
mov eax, 0xFFFF
2426
out 0, eax
2527
jmp .vm64_rexit_retry
28+
.vm64_preserving_entry:
29+
;; This is the entry point for a paused VM where
30+
;; its in the middle of a user program, so every
31+
;; register must be preserved. We need to flush
32+
;; the pagetables to ensure the guest can see the
33+
;; correct memory. Since the guest is potentially
34+
;; blind here, the host has pushed the registers
35+
;; necessary to perform the syscall safely.
36+
mov rax, 0x1F777
37+
syscall
38+
pop r11 ;; used by syscall for rflags
39+
pop rcx ;; used by syscall for rip
40+
pop rax
41+
;; With the registers restored, we can now
42+
;; return to the guest program.
43+
ret
2644

2745

2846
%macro vcputable 1

lib/tinykvm/amd64/usercode.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,34 @@
44
namespace tinykvm {
55

66
static const unsigned char usercode[] = {
7-
0x10, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90,
7+
0x10, 0x00, 0x20, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
88
0x90, 0x90, 0x90, 0x90, 0x49, 0x89, 0xcd, 0xb8, 0x77, 0xf7, 0x01, 0x00,
99
0x0f, 0x05, 0x4c, 0x89, 0xe9, 0x41, 0xff, 0xe7, 0x48, 0x89, 0xc7, 0xb8,
10-
0xff, 0xff, 0x00, 0x00, 0xe7, 0x00, 0xeb, 0xf7, 0x90, 0x90, 0x90, 0x90,
10+
0xff, 0xff, 0x00, 0x00, 0xe7, 0x00, 0xeb, 0xf7, 0xb8, 0x77, 0xf7, 0x01,
11+
0x00, 0x0f, 0x05, 0x41, 0x5b, 0x59, 0x58, 0xc3, 0x00, 0x00, 0x00, 0x00,
1112
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12-
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
13+
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14+
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
1416
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15-
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16-
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
17+
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18+
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
19+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
1820
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
19-
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20-
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
21+
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22+
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
2224
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23-
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24-
0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
25+
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26+
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
2628
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27-
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28-
0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
29+
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30+
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
3032
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31-
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32-
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
33+
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34+
0x00, 0x00, 0x00, 0x00
3435
};
3536

3637
const user_asm_header &usercode_header()

lib/tinykvm/amd64/usercode.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace tinykvm {
77
struct user_asm_header {
88
uint16_t vm64_entry;
99
uint16_t vm64_rexit;
10+
uint16_t vm64_preserving_entry;
11+
uint16_t vm64_unused;
1012
uint32_t vm64_cpuid;
1113

1214
uint64_t translated_vm_entry(const vMemory& memory) const noexcept {
@@ -15,6 +17,9 @@ struct user_asm_header {
1517
uint64_t translated_vm_rexit(const vMemory& memory) const noexcept {
1618
return memory.physbase + USER_ASM_ADDR + vm64_rexit;
1719
}
20+
uint64_t translated_vm_preserving_entry(const vMemory& memory) const noexcept {
21+
return memory.physbase + USER_ASM_ADDR + vm64_preserving_entry;
22+
}
1823
uint64_t translated_vm_cpuid(const vMemory& memory) const noexcept {
1924
return memory.physbase + USER_ASM_ADDR + vm64_cpuid;
2025
}

lib/tinykvm/machine.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ struct Machine
4242
void timed_vmcall_stack(address_t, address_t stk, float timeout, Args&&...);
4343
/* Retrieve optional return value from a vmcall */
4444
long return_value() const;
45+
/* Resume the VM from a paused state */
46+
void vmresume(float timeout_secs = 0.f);
4547

4648
auto& cpu() noexcept { return this->vcpu; }
4749
const auto& cpu() const noexcept { return this->vcpu; }
@@ -138,6 +140,7 @@ struct Machine
138140
address_t stack_address() const noexcept { return this->m_stack_address; }
139141
address_t heap_address() const noexcept { return this->m_heap_address; }
140142
address_t entry_address() const noexcept;
143+
address_t preserving_entry_address() const noexcept;
141144
address_t exit_address() const noexcept;
142145
void set_stack_address(address_t addr) { this->m_stack_address = addr; }
143146
address_t kernel_end_address() const noexcept { return m_kernel_end; }

lib/tinykvm/machine_inline.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,39 @@ void Machine::setup_call(tinykvm_x86regs& regs,
105105
this->enter_usermode();
106106
}
107107

108+
inline void Machine::vmresume(float timeout)
109+
{
110+
auto& regs = vcpu.registers();
111+
if (this->m_just_reset) {
112+
this->m_just_reset = false;
113+
// We have to go the long way around using the preserving entry
114+
// point, because the guest cannot see the correct memory now.
115+
// Carefully push RAX, RCX and R11 (used by SYSCALL instruction)
116+
// which will be popped by the preserving entry point. And finally,
117+
// push the old RIP which will be used by the RET instruction.
118+
struct PreservedRegisters {
119+
uint64_t r11;
120+
uint64_t rcx;
121+
uint64_t rax;
122+
uint64_t rip; // for the RET instruction
123+
} pvs;
124+
regs.rsp -= sizeof(pvs);
125+
pvs.rip = regs.rip;
126+
pvs.rax = regs.rax;
127+
pvs.rcx = regs.rcx;
128+
pvs.r11 = regs.r11;
129+
// Push the registers
130+
this->copy_to_guest(regs.rsp, &pvs, sizeof(pvs));
131+
// Set the new registers
132+
regs.rip = this->preserving_entry_address();
133+
vcpu.set_registers(regs);
134+
} else {
135+
// Nothing to do as the registers are already set
136+
// and the guest can see the memory.
137+
}
138+
this->run_in_usermode(timeout);
139+
}
140+
108141
inline void Machine::setup_clone(tinykvm_x86regs& regs, address_t stack)
109142
{
110143
/* Set IOPL=3 to allow I/O instructions */

lib/tinykvm/vcpu.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,9 @@ void Machine::enter_usermode()
495495
Machine::address_t Machine::entry_address() const noexcept {
496496
return usercode_header().translated_vm_entry(memory);
497497
}
498+
Machine::address_t Machine::preserving_entry_address() const noexcept {
499+
return usercode_header().translated_vm_preserving_entry(memory);
500+
}
498501
Machine::address_t Machine::exit_address() const noexcept {
499502
return usercode_header().translated_vm_rexit(memory);
500503
}

0 commit comments

Comments
 (0)