qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 287 lines 8.4 kB view raw
1/* 2 * qemu user cpu loop 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include "qemu/osdep.h" 21#include "qemu-common.h" 22#include "qemu.h" 23#include "cpu_loop-common.h" 24 25static void gen_sigill_reg(CPUTLGState *env) 26{ 27 target_siginfo_t info; 28 29 info.si_signo = TARGET_SIGILL; 30 info.si_errno = 0; 31 info.si_code = TARGET_ILL_PRVREG; 32 info._sifields._sigfault._addr = env->pc; 33 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 34} 35 36static void do_signal(CPUTLGState *env, int signo, int sigcode) 37{ 38 target_siginfo_t info; 39 40 info.si_signo = signo; 41 info.si_errno = 0; 42 info._sifields._sigfault._addr = env->pc; 43 44 if (signo == TARGET_SIGSEGV) { 45 /* The passed in sigcode is a dummy; check for a page mapping 46 and pass either MAPERR or ACCERR. */ 47 target_ulong addr = env->excaddr; 48 info._sifields._sigfault._addr = addr; 49 if (page_check_range(addr, 1, PAGE_VALID) < 0) { 50 sigcode = TARGET_SEGV_MAPERR; 51 } else { 52 sigcode = TARGET_SEGV_ACCERR; 53 } 54 } 55 info.si_code = sigcode; 56 57 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 58} 59 60static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr) 61{ 62 env->excaddr = addr; 63 do_signal(env, TARGET_SIGSEGV, 0); 64} 65 66static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val) 67{ 68 if (unlikely(reg >= TILEGX_R_COUNT)) { 69 switch (reg) { 70 case TILEGX_R_SN: 71 case TILEGX_R_ZERO: 72 return; 73 case TILEGX_R_IDN0: 74 case TILEGX_R_IDN1: 75 case TILEGX_R_UDN0: 76 case TILEGX_R_UDN1: 77 case TILEGX_R_UDN2: 78 case TILEGX_R_UDN3: 79 gen_sigill_reg(env); 80 return; 81 default: 82 g_assert_not_reached(); 83 } 84 } 85 env->regs[reg] = val; 86} 87 88/* 89 * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in 90 * memory at the address held in the first source register. If the values are 91 * not equal, then no memory operation is performed. If the values are equal, 92 * the 8-byte quantity from the second source register is written into memory 93 * at the address held in the first source register. In either case, the result 94 * of the instruction is the value read from memory. The compare and write to 95 * memory are atomic and thus can be used for synchronization purposes. This 96 * instruction only operates for addresses aligned to a 8-byte boundary. 97 * Unaligned memory access causes an Unaligned Data Reference interrupt. 98 * 99 * Functional Description (64-bit) 100 * uint64_t memVal = memoryReadDoubleWord (rf[SrcA]); 101 * rf[Dest] = memVal; 102 * if (memVal == SPR[CmpValueSPR]) 103 * memoryWriteDoubleWord (rf[SrcA], rf[SrcB]); 104 * 105 * Functional Description (32-bit) 106 * uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA])); 107 * rf[Dest] = memVal; 108 * if (memVal == signExtend32 (SPR[CmpValueSPR])) 109 * memoryWriteWord (rf[SrcA], rf[SrcB]); 110 * 111 * 112 * This function also processes exch and exch4 which need not process SPR. 113 */ 114static void do_exch(CPUTLGState *env, bool quad, bool cmp) 115{ 116 target_ulong addr; 117 target_long val, sprval; 118 119 start_exclusive(); 120 121 addr = env->atomic_srca; 122 if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { 123 goto sigsegv_maperr; 124 } 125 126 if (cmp) { 127 if (quad) { 128 sprval = env->spregs[TILEGX_SPR_CMPEXCH]; 129 } else { 130 sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32); 131 } 132 } 133 134 if (!cmp || val == sprval) { 135 target_long valb = env->atomic_srcb; 136 if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) { 137 goto sigsegv_maperr; 138 } 139 } 140 141 set_regval(env, env->atomic_dstr, val); 142 end_exclusive(); 143 return; 144 145 sigsegv_maperr: 146 end_exclusive(); 147 gen_sigsegv_maperr(env, addr); 148} 149 150static void do_fetch(CPUTLGState *env, int trapnr, bool quad) 151{ 152 int8_t write = 1; 153 target_ulong addr; 154 target_long val, valb; 155 156 start_exclusive(); 157 158 addr = env->atomic_srca; 159 valb = env->atomic_srcb; 160 if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { 161 goto sigsegv_maperr; 162 } 163 164 switch (trapnr) { 165 case TILEGX_EXCP_OPCODE_FETCHADD: 166 case TILEGX_EXCP_OPCODE_FETCHADD4: 167 valb += val; 168 break; 169 case TILEGX_EXCP_OPCODE_FETCHADDGEZ: 170 valb += val; 171 if (valb < 0) { 172 write = 0; 173 } 174 break; 175 case TILEGX_EXCP_OPCODE_FETCHADDGEZ4: 176 valb += val; 177 if ((int32_t)valb < 0) { 178 write = 0; 179 } 180 break; 181 case TILEGX_EXCP_OPCODE_FETCHAND: 182 case TILEGX_EXCP_OPCODE_FETCHAND4: 183 valb &= val; 184 break; 185 case TILEGX_EXCP_OPCODE_FETCHOR: 186 case TILEGX_EXCP_OPCODE_FETCHOR4: 187 valb |= val; 188 break; 189 default: 190 g_assert_not_reached(); 191 } 192 193 if (write) { 194 if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) { 195 goto sigsegv_maperr; 196 } 197 } 198 199 set_regval(env, env->atomic_dstr, val); 200 end_exclusive(); 201 return; 202 203 sigsegv_maperr: 204 end_exclusive(); 205 gen_sigsegv_maperr(env, addr); 206} 207 208void cpu_loop(CPUTLGState *env) 209{ 210 CPUState *cs = env_cpu(env); 211 int trapnr; 212 213 while (1) { 214 cpu_exec_start(cs); 215 trapnr = cpu_exec(cs); 216 cpu_exec_end(cs); 217 process_queued_cpu_work(cs); 218 219 switch (trapnr) { 220 case TILEGX_EXCP_SYSCALL: 221 { 222 abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR], 223 env->regs[0], env->regs[1], 224 env->regs[2], env->regs[3], 225 env->regs[4], env->regs[5], 226 env->regs[6], env->regs[7]); 227 if (ret == -TARGET_ERESTARTSYS) { 228 env->pc -= 8; 229 } else if (ret != -TARGET_QEMU_ESIGRETURN) { 230 env->regs[TILEGX_R_RE] = ret; 231 env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0; 232 } 233 break; 234 } 235 case TILEGX_EXCP_OPCODE_EXCH: 236 do_exch(env, true, false); 237 break; 238 case TILEGX_EXCP_OPCODE_EXCH4: 239 do_exch(env, false, false); 240 break; 241 case TILEGX_EXCP_OPCODE_CMPEXCH: 242 do_exch(env, true, true); 243 break; 244 case TILEGX_EXCP_OPCODE_CMPEXCH4: 245 do_exch(env, false, true); 246 break; 247 case TILEGX_EXCP_OPCODE_FETCHADD: 248 case TILEGX_EXCP_OPCODE_FETCHADDGEZ: 249 case TILEGX_EXCP_OPCODE_FETCHAND: 250 case TILEGX_EXCP_OPCODE_FETCHOR: 251 do_fetch(env, trapnr, true); 252 break; 253 case TILEGX_EXCP_OPCODE_FETCHADD4: 254 case TILEGX_EXCP_OPCODE_FETCHADDGEZ4: 255 case TILEGX_EXCP_OPCODE_FETCHAND4: 256 case TILEGX_EXCP_OPCODE_FETCHOR4: 257 do_fetch(env, trapnr, false); 258 break; 259 case TILEGX_EXCP_SIGNAL: 260 do_signal(env, env->signo, env->sigcode); 261 break; 262 case TILEGX_EXCP_REG_IDN_ACCESS: 263 case TILEGX_EXCP_REG_UDN_ACCESS: 264 gen_sigill_reg(env); 265 break; 266 case EXCP_ATOMIC: 267 cpu_exec_step_atomic(cs); 268 break; 269 default: 270 fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr); 271 g_assert_not_reached(); 272 } 273 process_pending_signals(env); 274 } 275} 276 277void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 278{ 279 int i; 280 for (i = 0; i < TILEGX_R_COUNT; i++) { 281 env->regs[i] = regs->regs[i]; 282 } 283 for (i = 0; i < TILEGX_SPR_COUNT; i++) { 284 env->spregs[i] = 0; 285 } 286 env->pc = regs->pc; 287}