| // Copyright 2017 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #include <asm.h> |
| |
| #include <arch/x86/vmx_state.h> |
| #include <zircon/errors.h> |
| |
| .text |
| |
| /* zx_status_t vmx_enter(VmxState* vmx_state) */ |
| FUNCTION(vmx_enter) |
| // Store the return address. |
| // We do this first to adjust the RSP we store. |
| popq HS_RIP(%rdi) |
| |
| // Store the callee save registers. |
| mov %rbx, HS_RBX(%rdi) |
| mov %rsp, HS_RSP(%rdi) |
| mov %rbp, HS_RBP(%rdi) |
| mov %r12, HS_R12(%rdi) |
| mov %r13, HS_R13(%rdi) |
| mov %r14, HS_R14(%rdi) |
| mov %r15, HS_R15(%rdi) |
| |
| // Store the processor flags. |
| pushfq |
| popq HS_RFLAGS(%rdi) |
| |
| // We are going to trample RDI, so move it to RSP. This also conveniently |
| // mirrors the exit code. |
| mov %rdi, %rsp |
| |
| // Load the guest CR2. |
| mov GS_CR2(%rsp), %rax |
| mov %rax, %cr2 |
| |
| // Load the guest registers not covered by the VMCS. |
| mov GS_RAX(%rsp), %rax |
| mov GS_RCX(%rsp), %rcx |
| mov GS_RDX(%rsp), %rdx |
| mov GS_RBX(%rsp), %rbx |
| mov GS_RBP(%rsp), %rbp |
| mov GS_RSI(%rsp), %rsi |
| mov GS_RDI(%rsp), %rdi |
| mov GS_R8(%rsp), %r8 |
| mov GS_R9(%rsp), %r9 |
| mov GS_R10(%rsp), %r10 |
| mov GS_R11(%rsp), %r11 |
| mov GS_R12(%rsp), %r12 |
| mov GS_R13(%rsp), %r13 |
| mov GS_R14(%rsp), %r14 |
| mov GS_R15(%rsp), %r15 |
| |
| // If we are resuming, jump to resume. |
| testb $1, VS_RESUME(%rsp) |
| jnz resume |
| |
| // Launch the guest. |
| vmlaunch |
| jmp failure |
| |
| resume: |
| // Resume the guest. |
| vmresume |
| |
| failure: |
| // We will only be here if vmlaunch or vmresume failed. |
| // Restore host RDI and RSP. |
| mov %rsp, %rdi |
| mov HS_RSP(%rdi), %rsp |
| |
| // Set up the return address. |
| pushq HS_RIP(%rdi) |
| |
| // Return ZX_ERR_INTERNAL. |
| mov $ZX_ERR_INTERNAL, %eax |
| ret |
| END_FUNCTION(vmx_enter) |
| |
| /* This is effectively the second-half of vmx_enter. When we return from a |
| * VM exit, vmx_state argument is stored in RSP. We use this to restore the |
| * stack and registers to the state they were in when vmx_enter was called. |
| */ |
| FUNCTION(vmx_exit_entry) |
| // Store the guest registers not covered by the VMCS. At this point, |
| // vmx_state is in RSP. |
| mov %rax, GS_RAX(%rsp) |
| mov %rcx, GS_RCX(%rsp) |
| mov %rdx, GS_RDX(%rsp) |
| mov %rbx, GS_RBX(%rsp) |
| mov %rbp, GS_RBP(%rsp) |
| mov %rsi, GS_RSI(%rsp) |
| mov %rdi, GS_RDI(%rsp) |
| mov %r8, GS_R8(%rsp) |
| mov %r9, GS_R9(%rsp) |
| mov %r10, GS_R10(%rsp) |
| mov %r11, GS_R11(%rsp) |
| mov %r12, GS_R12(%rsp) |
| mov %r13, GS_R13(%rsp) |
| mov %r14, GS_R14(%rsp) |
| mov %r15, GS_R15(%rsp) |
| |
| // Store the guest CR2. |
| mov %cr2, %rax |
| mov %rax, GS_CR2(%rsp) |
| |
| // Load vmx_state from RSP into RDI. |
| mov %rsp, %rdi |
| |
| // Load the host callee save registers. |
| mov HS_RBX(%rdi), %rbx |
| mov HS_RSP(%rdi), %rsp |
| mov HS_RBP(%rdi), %rbp |
| mov HS_R12(%rdi), %r12 |
| mov HS_R13(%rdi), %r13 |
| mov HS_R14(%rdi), %r14 |
| mov HS_R15(%rdi), %r15 |
| |
| // Load the host processor flags. |
| pushq HS_RFLAGS(%rdi) |
| popfq |
| |
| // Set up the return address. |
| pushq HS_RIP(%rdi) |
| |
| // Call vmx_exit(vmx_state). |
| sub $8, %rsp |
| call vmx_exit |
| add $8, %rsp |
| |
| // Return ZX_OK, using the return address of vmx_enter pushed above. |
| mov $ZX_OK, %eax |
| ret |
| END_FUNCTION(vmx_exit_entry) |