1/*
2 * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7/*vm exits related with ept violations*/
8
9#include <stdio.h>
10#include <stdlib.h>
11
12#include <sel4/sel4.h>
13
14#include <sel4vm/guest_memory.h>
15#include <sel4vm/arch/vmcs_fields.h>
16
17#include "vm.h"
18#include "guest_state.h"
19#include "vmcs.h"
20#include "debug.h"
21#include "processor/decode.h"
22#include "guest_memory.h"
23
24#define EPT_VIOL_READ(qual) ((qual) & BIT(0))
25#define EPT_VIOL_WRITE(qual) ((qual) & BIT(1))
26#define EPT_VIOL_FETCH(qual) ((qual) & BIT(2))
27
28void print_ept_violation(vm_vcpu_t *vcpu)
29{
30    /* Read linear address that guest is trying to access. */
31    unsigned int linear_address;
32    vm_vmcs_read(vcpu->vcpu.cptr, VMX_DATA_GUEST_LINEAR_ADDRESS, &linear_address);
33    printf(COLOUR_R "!!!!!!!! ALERT :: GUEST OS PAGE FAULT !!!!!!!!\n");
34    printf("    Guest OS VMExit due to EPT Violation:\n");
35    printf("        Linear address 0x%x.\n", linear_address);
36    printf("        Guest-Physical address 0x%x.\n", vm_guest_exit_get_physical(vcpu->vcpu_arch.guest_state));
37    printf("        Instruction pointer 0x%x.\n", vm_guest_state_get_eip(vcpu->vcpu_arch.guest_state));
38    printf("    This is most likely due to a bug or misconfiguration.\n" COLOUR_RESET);
39}
40
41static int unhandled_memory_fault(vm_t *vm, vm_vcpu_t *vcpu, uint32_t guest_phys, size_t size)
42{
43    memory_fault_result_t fault_result = vm->mem.unhandled_mem_fault_handler(vm, vcpu, guest_phys, size,
44                                                                             vm->mem.unhandled_mem_fault_cookie);
45    switch (fault_result) {
46    case FAULT_ERROR:
47        print_ept_violation(vcpu);
48        return -1;
49    case FAULT_HANDLED:
50    case FAULT_IGNORE:
51        vm_guest_exit_next_instruction(vcpu->vcpu_arch.guest_state, vcpu->vcpu.cptr);
52        return 0;
53    }
54    return -1;
55}
56
57/* Handling EPT violation VMExit Events. */
58int vm_ept_violation_handler(vm_vcpu_t *vcpu)
59{
60    int err;
61    uintptr_t guest_phys = vm_guest_exit_get_physical(vcpu->vcpu_arch.guest_state);
62    unsigned int qualification = vm_guest_exit_get_qualification(vcpu->vcpu_arch.guest_state);
63
64    int read = EPT_VIOL_READ(qualification);
65    int write = EPT_VIOL_WRITE(qualification);
66    int fetch = EPT_VIOL_FETCH(qualification);
67    if (read && write) {
68        /* Indicates a fault while walking EPT */
69        return VM_EXIT_HANDLE_ERROR;
70    }
71    if (fetch) {
72        /* This is not MMIO */
73        return VM_EXIT_HANDLE_ERROR;
74    }
75
76    int reg;
77    uint32_t imm;
78    int size;
79    vm_decode_ept_violation(vcpu, &reg, &imm, &size);
80    memory_fault_result_t fault_result = vm_memory_handle_fault(vcpu->vm, vcpu, guest_phys, size);
81    switch (fault_result) {
82    case FAULT_ERROR:
83        print_ept_violation(vcpu);
84        return -1;
85    case FAULT_HANDLED:
86        return VM_EXIT_HANDLED;
87    case FAULT_IGNORE:
88        vm_guest_exit_next_instruction(vcpu->vcpu_arch.guest_state, vcpu->vcpu.cptr);
89        return VM_EXIT_HANDLED;
90    case FAULT_UNHANDLED:
91        if (vcpu->vm->mem.unhandled_mem_fault_handler) {
92            err = unhandled_memory_fault(vcpu->vm, vcpu, guest_phys, size);
93            if (err) {
94                return -1;
95            }
96            return 0;
97        }
98    }
99    ZF_LOGE("Failed to handle ept fault");
100    print_ept_violation(vcpu);
101    return -1;
102}
103