|
| 1 | +/** |
| 2 | + * SPDX-License-Identifier: Apache-2.0 |
| 3 | + * Copyright (c) Bao Project and Contributors. All rights reserved. |
| 4 | + */ |
| 5 | + |
| 6 | +#include <emul.h> |
| 7 | +#include <hypercall.h> |
| 8 | +#include <fences.h> |
| 9 | +#include <vmm.h> |
| 10 | +#include <arch/aborts.h> |
| 11 | +#include <arch/emul.h> |
| 12 | +#include <arch/srs.h> |
| 13 | + |
| 14 | +#define F8_OPCODE (0x3EUL) |
| 15 | +#define F9_OPCODE (0x3FUL) |
| 16 | +#define F9_SUBOPCODE (0x1CUL) |
| 17 | + |
| 18 | +#define OPCODE_SHIFT (5) |
| 19 | +#define OPCODE_MASK (0x3FUL << OPCODE_SHIFT) |
| 20 | + |
| 21 | +#define SUBOPCODE_SHIFT (19) |
| 22 | +#define SUBOPCODE_MASK (0x1FFFUL << SUBOPCODE_SHIFT) |
| 23 | + |
| 24 | +#define SUB8_SHIFT (14) |
| 25 | +#define SUB8_MASK (0x3UL << SUB8_SHIFT) |
| 26 | + |
| 27 | +#define SUB9_SHIFT (17) |
| 28 | +#define SUB9_MASK (0x3UL << SUB9_SHIFT) |
| 29 | + |
| 30 | +#define BITIDX_SHIFT (11) |
| 31 | +#define BITIDX_MASK (0x7UL << BITIDX_SHIFT) |
| 32 | + |
| 33 | +#define REGIDX_SHIFT (11) |
| 34 | +#define REGIDX_MASK (0x1FUL << REGIDX_SHIFT) |
| 35 | + |
| 36 | +// LEN (Bits 31-28) |
| 37 | +#define MEI_LEN_MASK (0xFUL << 28) |
| 38 | +#define MEI_LEN_SHIFT 28 |
| 39 | +#define MEI_GET_LEN(val) (((val) & MEI_LEN_MASK) >> MEI_LEN_SHIFT) |
| 40 | + |
| 41 | +// REG (Bits 20-16) |
| 42 | +#define MEI_REG_MASK (0x1F << 16) |
| 43 | +#define MEI_REG_SHIFT 16 |
| 44 | +#define MEI_GET_REG(val) (((val) & MEI_REG_MASK) >> MEI_REG_SHIFT) |
| 45 | + |
| 46 | +// DS (Bits 11-9) |
| 47 | +#define MEI_DS_MASK (0x7 << 9) |
| 48 | +#define MEI_DS_SHIFT 9 |
| 49 | +#define MEI_GET_DS(val) (((val) & MEI_DS_MASK) >> MEI_DS_SHIFT) |
| 50 | + |
| 51 | +// U (Bit 8) |
| 52 | +#define MEI_U_MASK (1 << 8) |
| 53 | +#define MEI_GET_U(val) (((val) & MEI_U_MASK) >> 8) |
| 54 | + |
| 55 | +// RW (Bit 0) |
| 56 | +#define MEI_RW_MASK (1 << 0) |
| 57 | +#define MEI_GET_RW(val) ((val) & MEI_RW_MASK) |
| 58 | + |
| 59 | +static unsigned long read_instruction(unsigned long pc) |
| 60 | +{ |
| 61 | + unsigned long inst = 0; |
| 62 | + unsigned short* pc_ptr = (unsigned short*)(pc); |
| 63 | + |
| 64 | + if (pc & 0x1) { |
| 65 | + ERROR("Trying to read guest unaligned instruction"); |
| 66 | + } |
| 67 | + |
| 68 | + /* Enable Hyp access to VM space */ |
| 69 | + set_mpid7(HYP_SPID); |
| 70 | + fence_sync(); |
| 71 | + |
| 72 | + inst = (unsigned long)(*pc_ptr | (*(pc_ptr+1) << 16)); |
| 73 | + |
| 74 | + /* Disable Hyp access to VM space */ |
| 75 | + set_mpid7(HYP_AUX_SPID); |
| 76 | + fence_sync(); |
| 77 | + |
| 78 | + return inst; |
| 79 | +} |
| 80 | + |
| 81 | +static void data_abort(void) |
| 82 | +{ |
| 83 | + unsigned long mea = get_mea(); |
| 84 | + unsigned long mei = get_mei(); |
| 85 | + |
| 86 | + unsigned int len = MEI_GET_LEN(mei); |
| 87 | + unsigned int reg = MEI_GET_REG(mei); |
| 88 | + unsigned int ds = MEI_GET_DS(mei); |
| 89 | + unsigned int u = MEI_GET_U(mei); |
| 90 | + /* unsigned int itype = MEI_GET_ITYPE(mei); */ |
| 91 | + unsigned int rw = MEI_GET_RW(mei); |
| 92 | + vaddr_t addr = mea; |
| 93 | + |
| 94 | + /* Decode possible bitwise instruction */ |
| 95 | + unsigned long inst = read_instruction(vcpu_readpc(cpu()->vcpu)); |
| 96 | + unsigned long opcode = ((inst & OPCODE_MASK) >> OPCODE_SHIFT); |
| 97 | + unsigned long subopcode = ((inst & SUBOPCODE_MASK) >> SUBOPCODE_SHIFT); |
| 98 | + unsigned long bit_op = 0; |
| 99 | + unsigned long mask = 0; |
| 100 | + |
| 101 | + if (opcode == F8_OPCODE) { |
| 102 | + mask = 1UL << ((inst & BITIDX_MASK) >> BITIDX_SHIFT); |
| 103 | + bit_op = ((inst & SUB8_MASK) >> SUB8_SHIFT) + 1; |
| 104 | + } |
| 105 | + else if (opcode == F9_OPCODE && subopcode == F9_SUBOPCODE) { |
| 106 | + unsigned long reg_idx = (inst & REGIDX_MASK) >> REGIDX_SHIFT; |
| 107 | + unsigned long bit_idx = vcpu_readreg(cpu()->vcpu, reg_idx); |
| 108 | + mask = 1UL << (bit_idx & 0x7UL); |
| 109 | + bit_op = ((inst & SUB9_MASK) >> SUB9_SHIFT) + 1; |
| 110 | + } |
| 111 | + |
| 112 | + emul_handler_t handler = vm_emul_get_mem(cpu()->vcpu->vm, addr); |
| 113 | + if (handler != NULL) { |
| 114 | + struct emul_access emul; |
| 115 | + emul.addr = addr; |
| 116 | + emul.width = len; |
| 117 | + emul.write = rw ? true : false; |
| 118 | + emul.reg = reg; |
| 119 | + emul.reg_width = ds; |
| 120 | + emul.sign_ext = ~u; |
| 121 | + |
| 122 | + emul.arch.op = (enum bitwise_op)bit_op; |
| 123 | + emul.arch.byte_mask = mask; |
| 124 | + |
| 125 | + if (handler(&emul)) { |
| 126 | + unsigned long pc_step = len; |
| 127 | + vcpu_writepc(cpu()->vcpu, vcpu_readpc(cpu()->vcpu) + pc_step); |
| 128 | + } else { |
| 129 | + ERROR("Data abort emulation failed (0x%x)", addr); |
| 130 | + } |
| 131 | + } else { |
| 132 | + ERROR("No emulation handler for access to 0x%x, at 0x%x", addr, vcpu_readpc(cpu()->vcpu)); |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +static void hvtrap(void) { |
| 137 | + unsigned long r6 = vcpu_readreg(cpu()->vcpu , 6); |
| 138 | + unsigned long res = (unsigned long)hypercall(r6); |
| 139 | + vcpu_writereg(cpu()->vcpu, 6, res); |
| 140 | +} |
| 141 | + |
| 142 | +void abort(void) |
| 143 | +{ |
| 144 | + unsigned long psw = get_psw(); |
| 145 | + unsigned long cause = (psw & (0x1UL << 7)) ? |
| 146 | + (get_feic() & 0xFFFFUL) : |
| 147 | + (get_eiic() & 0xFFFFUL); |
| 148 | + |
| 149 | + switch (cause) { |
| 150 | + case 0x01: |
| 151 | + WARNING("Exception: RESET - Reset input\n"); |
| 152 | + break; |
| 153 | + |
| 154 | + case 0x1C: |
| 155 | + WARNING("Exception: SYSERR - System error (context saving error)\n"); |
| 156 | + break; |
| 157 | + |
| 158 | + case 0x1D: |
| 159 | + WARNING("Exception: SYSERR - System error (error prior to register bank " |
| 160 | + "restoration)\n"); |
| 161 | + break; |
| 162 | + |
| 163 | + case 0x60: |
| 164 | + WARNING("Exception: RIE - Reserved instruction exception\n"); |
| 165 | + break; |
| 166 | + |
| 167 | + case 0x71: |
| 168 | + WARNING("Exception: FPE - FPU exception (precise)\n"); |
| 169 | + break; |
| 170 | + |
| 171 | + case 0x75: |
| 172 | + WARNING("Exception: FXE - FXU exception (precise)\n"); |
| 173 | + break; |
| 174 | + |
| 175 | + case 0x80: |
| 176 | + case 0x81: |
| 177 | + case 0x82: |
| 178 | + WARNING("Exception: UCPOP - Coprocessor unusable exception\n"); |
| 179 | + break; |
| 180 | + |
| 181 | + case 0x90: |
| 182 | + WARNING("Exception: MIP - Memory protection exception due to instruction fetching\n"); |
| 183 | + break; |
| 184 | + case 0x91: |
| 185 | + data_abort(); |
| 186 | + break; |
| 187 | + case 0x95: |
| 188 | + WARNING("Exception: MDP - Memory protection exception (interrupt table reference " |
| 189 | + "method)\n"); |
| 190 | + break; |
| 191 | + case 0x98: |
| 192 | + WARNING("Exception: MIP - Guest memory protection exception due to instruction " |
| 193 | + "fetching\n"); |
| 194 | + break; |
| 195 | + case 0x99: |
| 196 | + data_abort(); |
| 197 | + break; |
| 198 | + case 0x9D: |
| 199 | + WARNING("Exception: MDP - Guest memory protection exception (interrupt table " |
| 200 | + "reference method)\n"); |
| 201 | + break; |
| 202 | + |
| 203 | + case 0xA0: |
| 204 | + WARNING("Exception: PIE - Privilege instruction exception\n"); |
| 205 | + break; |
| 206 | + |
| 207 | + case 0xC0: |
| 208 | + WARNING("Exception: MAE - Misalignment exception\n"); |
| 209 | + break; |
| 210 | + |
| 211 | + case 0xE0: |
| 212 | + WARNING("Exception: FENMI - FENMI interrupt\n"); |
| 213 | + break; |
| 214 | + |
| 215 | + default: |
| 216 | + |
| 217 | + if (cause >= 0xF0 && cause <= 0xFF) { |
| 218 | + WARNING("FEINT - FEINT interrupt"); |
| 219 | + } else if (cause >= 0x1000 && cause <= 0x17FF) { |
| 220 | + WARNING("EIINT - User interrupt"); |
| 221 | + } else if (cause >= 0x10 && cause <= 0x1F) { |
| 222 | + WARNING("SYSERR - System error (instruction fetch error)"); |
| 223 | + } else if (cause >= 0xf000 && cause <= 0xf01f) { |
| 224 | + hvtrap(); |
| 225 | + }else if (cause >= 0x8000 && cause <= 0x80FF) { |
| 226 | + WARNING("SYSCALL - System call"); |
| 227 | + } else if (cause >= 0x31 && cause <= 0x3F) { |
| 228 | + WARNING("FETRAP - FE level trap"); |
| 229 | + } else if (cause >= 0x40 && cause <= 0x4F) { |
| 230 | + WARNING("TRAP0 - EI level trap 0"); |
| 231 | + } else if (cause >= 0x50 && cause <= 0x5F) { |
| 232 | + WARNING("TRAP1 - EI level trap 1"); |
| 233 | + } else { |
| 234 | + WARNING("Exception: Unknown exception code: 0x%X\n", cause); |
| 235 | + } |
| 236 | + break; |
| 237 | + } |
| 238 | +} |
0 commit comments