1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <autoconf.h>
8#include <stdio.h>
9#include <stdlib.h>
10
11#include <sel4vm/guest_vm.h>
12#include <sel4vm/boot.h>
13#include "sel4vm/guest_memory.h"
14
15#include "vm.h"
16#include "mem_abort.h"
17#include "fault.h"
18#include "guest_memory.h"
19
20static int unhandled_memory_fault(vm_t *vm, vm_vcpu_t *vcpu, fault_t *fault)
21{
22    uintptr_t addr = fault_get_address(fault);
23    size_t fault_size = fault_get_width_size(fault);
24    memory_fault_result_t fault_result = vm->mem.unhandled_mem_fault_handler(vm, vcpu, addr, fault_size,
25                                                                             vm->mem.unhandled_mem_fault_cookie);
26    switch (fault_result) {
27    case FAULT_HANDLED:
28        return 0;
29    case FAULT_RESTART:
30        restart_fault(fault);
31        return 0;
32    case FAULT_IGNORE:
33        return ignore_fault(fault);
34    case FAULT_ERROR:
35        print_fault(fault);
36        abandon_fault(fault);
37        return -1;
38    default:
39        break;
40    }
41    return -1;
42}
43
44int handle_page_fault(vm_t *vm, vm_vcpu_t *vcpu, fault_t *fault)
45{
46    int err;
47    uintptr_t addr = fault_get_address(fault);
48    size_t fault_size = fault_get_width_size(fault);
49
50    memory_fault_result_t fault_result = vm_memory_handle_fault(vm, vcpu, addr, fault_size);
51    switch (fault_result) {
52    case FAULT_HANDLED:
53        return 0;
54    case FAULT_RESTART:
55        restart_fault(fault);
56        return 0;
57    case FAULT_IGNORE:
58        return ignore_fault(fault);
59    case FAULT_ERROR:
60        print_fault(fault);
61        abandon_fault(fault);
62        return -1;
63    case FAULT_UNHANDLED:
64        if (vm->mem.unhandled_mem_fault_handler) {
65            err = unhandled_memory_fault(vm, vcpu, fault);
66            if (err) {
67                return -1;
68            }
69            return 0;
70        }
71    default:
72        break;
73        /* We don't have a memory reservation for the faulting address
74         * We move onto the rest of the page fault handler */
75    }
76
77    print_fault(fault);
78    abandon_fault(fault);
79    return -1;
80}
81
82int vm_guest_mem_abort_handler(vm_vcpu_t *vcpu)
83{
84    int err;
85    fault_t *fault;
86    fault = vcpu->vcpu_arch.fault;
87    err = new_memory_fault(fault);
88    if (err) {
89        ZF_LOGE("Failed to initialise new fault");
90        return -1;
91    }
92    err = handle_page_fault(vcpu->vm, vcpu, fault);
93    if (err) {
94        return VM_EXIT_HANDLE_ERROR;
95    }
96    return VM_EXIT_HANDLED;
97}
98