1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6#pragma once 7 8#include <stdint.h> 9#include <stdbool.h> 10#include <vka/cspacepath_t.h> 11 12#include <sel4vm/sel4_arch/processor.h> 13 14typedef struct vm_vcpu vm_vcpu_t; 15typedef struct fault fault_t; 16 17enum fault_width { 18 WIDTH_DOUBLEWORD, 19 WIDTH_WORD, 20 WIDTH_HALFWORD, 21 WIDTH_BYTE 22}; 23 24typedef enum { 25 DATA, 26 PREFETCH, 27 VCPU 28} fault_type_t; 29 30#define CPSR_THUMB BIT(5) 31#define CPSR_IS_THUMB(x) ((x) & CPSR_THUMB) 32 33/** 34 * Data structure representating a fault 35 */ 36struct fault { 37/// The vcpu associated with the fault 38 vm_vcpu_t *vcpu; 39/// Reply capability to the faulting TCB 40 cspacepath_t reply_cap; 41/// VM registers at the time of the fault 42 seL4_UserContext regs; 43 44/// The IPA address of the fault 45 seL4_Word base_addr; 46/// The IPA address of the fault at the current stage 47 seL4_Word addr; 48/// The IPA of the instruction which caused the fault 49 seL4_Word ip; 50/// The data which was to be written, or the data to return to the VM 51 seL4_Word data; 52/// Fault status register (IL and ISS fields of HSR cp15 register) 53 seL4_Word fsr; 54/// type of fault 55 fault_type_t type; 56/// For multiple str/ldr and 32 bit access, the fault is handled in stages 57 int stage; 58/// If the instruction requires fetching, cache it here 59 seL4_Word instruction; 60/// The width of the fault 61 enum fault_width width; 62/// The mode of the processor 63 processor_mode_t pmode; 64/// The active content within the fault structure to allow lazy loading 65 int content; 66}; 67typedef struct fault fault_t; 68 69/** 70 * Initialise a fault structure. 71 * The structure will be bound to a VM and a reply cap slot 72 * will be reserved. 73 * @param[in] vm The VM that the fault structure should be bound to 74 * @return An initialised fault structure handle or NULL on failure 75 */ 76fault_t *fault_init(vm_vcpu_t *vcpu); 77 78/** 79 * Populate an initialised fault structure with fault data obtained from 80 * a pending VCPU fault message. The reply cap to the faulting TCB will 81 * also be saved 82 * @param[in] fault A handle to a fault structure 83 * @return 0 on success; 84 */ 85int new_vcpu_fault(fault_t *fault, uint32_t hsr); 86 87/** 88 * Populate an initialised fault structure with fault data obtained from 89 * a pending virtual memory fault IPC message. The reply cap to the faulting 90 * TCB will also be saved. 91 * @param[in] fault A handle to a fault structure 92 * @return 0 on success; 93 */ 94int new_memory_fault(fault_t *fault); 95 96/** 97 * Abandon the fault. 98 * Performs any necessary clean up of the fault structure once a fault 99 * has been serviced. The VM will not be restarted by a call to this function. 100 * @param[in] fault A handle to a fault structure 101 * @return 0 on success; 102 */ 103int abandon_fault(fault_t *fault); 104 105/** 106 * Restart the fault 107 * Return execution to the VM without modifying registers or advancing the 108 * program counter. This is useful when the suitable response to the fault 109 * is to map a frame. 110 * @param[in] fault A handle to a fault structure 111 * @return 0 on success; 112 */ 113int restart_fault(fault_t *fault); 114 115 116/** 117 * Ignore the fault. 118 * Advances the PC without modifying registers. Useful when VM reads and 119 * writes to invalid memory can be ignored. 120 * @param[in] fault A handle to a fault structure 121 * @return 0 on success; 122 */ 123int ignore_fault(fault_t *fault); 124 125 126/** 127 * Update register contents and return from a fault. 128 * Updates user registers based on the data field of the fault struction 129 * and replies to the faulting TCB to resume execution. 130 * @param[in] fault A handle to a fault structure 131 * @param[in] data The data word that the VM was attempting to access 132 * @return 0 on success; 133 */ 134int advance_fault(fault_t *fault); 135 136 137/** 138 * Emulates the faulting instruction of the VM on the provided data. 139 * This function does not modify the state of the fault, it only returns 140 * an updated representation of the given data based on the write operation 141 * that the VM was attempting to perform. 142 * @param[in] fault A handle to a fault structure 143 * @param[in] data The data word that the VM was attempting to access 144 * @return The updated data based on the operation that the VM 145 * was attempting to perform. 146 */ 147seL4_Word fault_emulate(fault_t *fault, seL4_Word data); 148 149/** 150 * Determine if a fault has been handled. This is useful for multi-stage faults 151 * @param[in] fault A handle to the fault 152 * @return 0 if the fault has not yet been handled, otherwise, further 153 * action is required 154 */ 155int fault_handled(fault_t *fault); 156 157/** 158 * Retrieve the data that the faulting thread is trying to write or the data 159 * that will be returned to the thread in case of a read fault. 160 * The fault must be a data fault. 161 * @param[in] fault A handle to the fault 162 * @return If it is a read fault, returns the data that will be returned 163 * to the thread when the fault is advanced. Otherwise, returns 164 * the data that the thread was attempting to write. 165 */ 166seL4_Word fault_get_data(fault_t *fault); 167 168/** 169 * Set the data that will be returned to the thread when the fault is advanced. 170 * The fault must be a data fault. 171 * @param[in] fault A handle to the fault 172 * @param[in] data The data to return to the thread. 173 */ 174void fault_set_data(fault_t *fault, seL4_Word data); 175 176/** 177 * Retrieve a mask for the data within the aligned word that the fault is 178 * attempting to access 179 * @param[in] fault A handle to the fault 180 * @return A mask for the data within the aligned word that the fault is 181 * attempting to access 182 */ 183seL4_Word fault_get_data_mask(fault_t *fault); 184 185/** 186 * Get the faulting address 187 * @param[in] fault A handle to the fault 188 * @return The address that the faulting thread was attempting to access 189 */ 190seL4_Word fault_get_address(fault_t *fault); 191 192/** 193 * Get the access width of the fault 194 * The fault must be a data fault. 195 * @param[in] fault A handle to the fault 196 * @return The access width of the fault 197 */ 198enum fault_width fault_get_width(fault_t *f); 199 200/** 201 * Get the access width size of the fault 202 * The fault must be a data fault. 203 * @param[in] fault A handle to the fault 204 * @return The access width size of the fault 205 */ 206size_t fault_get_width_size(fault_t *f); 207 208/** 209 * Get the context of a fault 210 * @param[in] fault A handle to the fault 211 * @return A handle to the fault context 212 */ 213seL4_UserContext *fault_get_ctx(fault_t *fault); 214 215/** 216 * Set the context of a fault 217 * @param[in] fault A handle to the fault 218 * @param[in] ctx A handle to the fault context 219 */ 220void fault_set_ctx(fault_t *f, seL4_UserContext *ctx); 221 222/** 223 * Get the fault status register of a fault 224 * @param[in] fault A handle to the fault 225 * @return the ARM HSR register associated with this fault. The EC 226 * field will be masked out. 227 */ 228seL4_Word fault_get_fsr(fault_t *fault); 229 230/** 231 * Determine if a fault is a prefetch fault 232 * @param[in] fault A handle to the fault 233 * @return 1 if the fault is a prefetch fault, otherwise 0 234 */ 235int fault_is_prefetch(fault_t *fault); 236 237/** 238 * Determine if we should wait for an interrupt before 239 * resuming from the fault 240 * @param[in] fault A handle to the fault 241 */ 242int fault_is_wfi(fault_t *fault); 243 244/** 245 * Determine if a fault is a vcpu fault 246 * @param[in] fault A handle to the fault 247 * @return 1 if the fault is a vcpu fault, otherwise 0 248 */ 249int fault_is_vcpu(fault_t *f); 250 251/** 252 * Determine if a fault was caused by a 32 bit instruction 253 * @param[in] fault A handle to the fault 254 * @return 0 if it is a 16 bit instruction, otherwise, it is 32bit 255 */ 256int fault_is_32bit_instruction(fault_t *f); 257 258/**************** 259 *** Helpers *** 260 ****************/ 261 262static inline int fault_is_16bit_instruction(fault_t *f) 263{ 264 return !fault_is_32bit_instruction(f); 265} 266 267static inline int fault_is_data(fault_t *f) 268{ 269 return f->type == DATA; 270} 271 272static inline int fault_is_write(fault_t *f) 273{ 274 return (fault_get_fsr(f) & (1U << 6)); 275} 276 277static inline int fault_is_read(fault_t *f) 278{ 279 return !fault_is_write(f); 280} 281 282static inline seL4_Word fault_get_addr_word(fault_t *f) 283{ 284 return fault_get_address(f) & ~(0x3U); 285} 286 287seL4_Word *decode_rt(int reg, seL4_UserContext *c); 288int decode_vcpu_reg(int rt, fault_t *f); 289void fault_print_data(fault_t *fault); 290bool fault_is_thumb(fault_t *f); 291 292/*************** 293 *** Debug *** 294 ***************/ 295 296/** 297 * Prints a fault to the console 298 * @param[in] fault A handle to a fault structure 299 */ 300void print_fault(fault_t *fault); 301 302/** 303 * Prints contents of context registers to the console 304 * @param[in] regs A handle to the VM registers to print 305 */ 306void print_ctx_regs(seL4_UserContext *regs); 307