qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

Add Nios II semihosting support.

This patch adds support for libgloss semihosting to Nios II bare-metal
emulation. The specification for the protocol can be found in the
libgloss sources.

Signed-off-by: Sandra Loosemore <sandra@codesourcery.com>
Signed-off-by: Julian Brown <julian@codesourcery.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1554321185-2825-3-git-send-email-sandra@codesourcery.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Sandra Loosemore and committed by
Peter Maydell
413a99a9 ed960ba9

+476 -6
+4 -4
qemu-options.hx
··· 3968 3968 DEF("semihosting", 0, QEMU_OPTION_semihosting, 3969 3969 "-semihosting semihosting mode\n", 3970 3970 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | 3971 - QEMU_ARCH_MIPS) 3971 + QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2) 3972 3972 STEXI 3973 3973 @item -semihosting 3974 3974 @findex -semihosting 3975 - Enable semihosting mode (ARM, M68K, Xtensa, MIPS only). 3975 + Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only). 3976 3976 ETEXI 3977 3977 DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, 3978 3978 "-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \ 3979 3979 " semihosting configuration\n", 3980 3980 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | 3981 - QEMU_ARCH_MIPS) 3981 + QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2) 3982 3982 STEXI 3983 3983 @item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]] 3984 3984 @findex -semihosting-config 3985 - Enable and configure semihosting (ARM, M68K, Xtensa, MIPS only). 3985 + Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only). 3986 3986 @table @option 3987 3987 @item target=@code{native|gdb|auto} 3988 3988 Defines where the semihosting calls will be addressed, to QEMU (@code{native})
+1 -1
target/nios2/Makefile.objs
··· 1 - obj-y += translate.o op_helper.o helper.o cpu.o mmu.o 1 + obj-y += translate.o op_helper.o helper.o cpu.o mmu.o nios2-semi.o 2 2 obj-$(CONFIG_SOFTMMU) += monitor.o 3 3 4 4 $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+3 -1
target/nios2/cpu.h
··· 141 141 #define R_PC 64 142 142 143 143 /* Exceptions */ 144 - #define EXCP_BREAK -1 144 + #define EXCP_BREAK 0x1000 145 145 #define EXCP_RESET 0 146 146 #define EXCP_PRESET 1 147 147 #define EXCP_IRQ 2 ··· 221 221 222 222 qemu_irq *nios2_cpu_pic_init(Nios2CPU *cpu); 223 223 void nios2_check_interrupts(CPUNios2State *env); 224 + 225 + void do_nios2_semihosting(CPUNios2State *env); 224 226 225 227 #define TARGET_PHYS_ADDR_SPACE_BITS 32 226 228 #ifdef CONFIG_USER_ONLY
+13
target/nios2/helper.c
··· 23 23 #include "cpu.h" 24 24 #include "qemu/host-utils.h" 25 25 #include "exec/exec-all.h" 26 + #include "exec/cpu_ldst.h" 26 27 #include "exec/log.h" 27 28 #include "exec/helper-proto.h" 29 + #include "exec/semihost.h" 28 30 29 31 #if defined(CONFIG_USER_ONLY) 30 32 ··· 169 171 break; 170 172 171 173 case EXCP_BREAK: 174 + qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n", 175 + env->regs[R_PC]); 176 + /* The semihosting instruction is "break 1". */ 177 + if (semihosting_enabled() && 178 + cpu_ldl_code(env, env->regs[R_PC]) == 0x003da07a) { 179 + qemu_log_mask(CPU_LOG_INT, "Entering semihosting\n"); 180 + env->regs[R_PC] += 4; 181 + do_nios2_semihosting(env); 182 + break; 183 + } 184 + 172 185 if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) { 173 186 env->regs[CR_BSTATUS] = env->regs[CR_STATUS]; 174 187 env->regs[R_BA] = env->regs[R_PC] + 4;
+455
target/nios2/nios2-semi.c
··· 1 + /* 2 + * Nios II Semihosting syscall interface. 3 + * This code is derived from m68k-semi.c. 4 + * The semihosting protocol implemented here is described in the 5 + * libgloss sources: 6 + * https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/nios2/nios2-semi.txt;hb=HEAD 7 + * 8 + * Copyright (c) 2017-2019 Mentor Graphics 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License as published by 12 + * the Free Software Foundation; either version 2 of the License, or 13 + * (at your option) any later version. 14 + * 15 + * This program is distributed in the hope that it will be useful, 16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 + * GNU General Public License for more details. 19 + * 20 + * You should have received a copy of the GNU General Public License 21 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 22 + */ 23 + 24 + #include "qemu/osdep.h" 25 + 26 + #include "cpu.h" 27 + #if defined(CONFIG_USER_ONLY) 28 + #include "qemu.h" 29 + #else 30 + #include "qemu-common.h" 31 + #include "exec/gdbstub.h" 32 + #include "exec/softmmu-semi.h" 33 + #endif 34 + #include "qemu/log.h" 35 + #include "sysemu/sysemu.h" 36 + 37 + #define HOSTED_EXIT 0 38 + #define HOSTED_INIT_SIM 1 39 + #define HOSTED_OPEN 2 40 + #define HOSTED_CLOSE 3 41 + #define HOSTED_READ 4 42 + #define HOSTED_WRITE 5 43 + #define HOSTED_LSEEK 6 44 + #define HOSTED_RENAME 7 45 + #define HOSTED_UNLINK 8 46 + #define HOSTED_STAT 9 47 + #define HOSTED_FSTAT 10 48 + #define HOSTED_GETTIMEOFDAY 11 49 + #define HOSTED_ISATTY 12 50 + #define HOSTED_SYSTEM 13 51 + 52 + typedef uint32_t gdb_mode_t; 53 + typedef uint32_t gdb_time_t; 54 + 55 + struct nios2_gdb_stat { 56 + uint32_t gdb_st_dev; /* device */ 57 + uint32_t gdb_st_ino; /* inode */ 58 + gdb_mode_t gdb_st_mode; /* protection */ 59 + uint32_t gdb_st_nlink; /* number of hard links */ 60 + uint32_t gdb_st_uid; /* user ID of owner */ 61 + uint32_t gdb_st_gid; /* group ID of owner */ 62 + uint32_t gdb_st_rdev; /* device type (if inode device) */ 63 + uint64_t gdb_st_size; /* total size, in bytes */ 64 + uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */ 65 + uint64_t gdb_st_blocks; /* number of blocks allocated */ 66 + gdb_time_t gdb_st_atime; /* time of last access */ 67 + gdb_time_t gdb_st_mtime; /* time of last modification */ 68 + gdb_time_t gdb_st_ctime; /* time of last change */ 69 + } QEMU_PACKED; 70 + 71 + struct gdb_timeval { 72 + gdb_time_t tv_sec; /* second */ 73 + uint64_t tv_usec; /* microsecond */ 74 + } QEMU_PACKED; 75 + 76 + #define GDB_O_RDONLY 0x0 77 + #define GDB_O_WRONLY 0x1 78 + #define GDB_O_RDWR 0x2 79 + #define GDB_O_APPEND 0x8 80 + #define GDB_O_CREAT 0x200 81 + #define GDB_O_TRUNC 0x400 82 + #define GDB_O_EXCL 0x800 83 + 84 + static int translate_openflags(int flags) 85 + { 86 + int hf; 87 + 88 + if (flags & GDB_O_WRONLY) { 89 + hf = O_WRONLY; 90 + } else if (flags & GDB_O_RDWR) { 91 + hf = O_RDWR; 92 + } else { 93 + hf = O_RDONLY; 94 + } 95 + 96 + if (flags & GDB_O_APPEND) { 97 + hf |= O_APPEND; 98 + } 99 + if (flags & GDB_O_CREAT) { 100 + hf |= O_CREAT; 101 + } 102 + if (flags & GDB_O_TRUNC) { 103 + hf |= O_TRUNC; 104 + } 105 + if (flags & GDB_O_EXCL) { 106 + hf |= O_EXCL; 107 + } 108 + 109 + return hf; 110 + } 111 + 112 + static bool translate_stat(CPUNios2State *env, target_ulong addr, 113 + struct stat *s) 114 + { 115 + struct nios2_gdb_stat *p; 116 + 117 + p = lock_user(VERIFY_WRITE, addr, sizeof(struct nios2_gdb_stat), 0); 118 + 119 + if (!p) { 120 + return false; 121 + } 122 + p->gdb_st_dev = cpu_to_be32(s->st_dev); 123 + p->gdb_st_ino = cpu_to_be32(s->st_ino); 124 + p->gdb_st_mode = cpu_to_be32(s->st_mode); 125 + p->gdb_st_nlink = cpu_to_be32(s->st_nlink); 126 + p->gdb_st_uid = cpu_to_be32(s->st_uid); 127 + p->gdb_st_gid = cpu_to_be32(s->st_gid); 128 + p->gdb_st_rdev = cpu_to_be32(s->st_rdev); 129 + p->gdb_st_size = cpu_to_be64(s->st_size); 130 + #ifdef _WIN32 131 + /* Windows stat is missing some fields. */ 132 + p->gdb_st_blksize = 0; 133 + p->gdb_st_blocks = 0; 134 + #else 135 + p->gdb_st_blksize = cpu_to_be64(s->st_blksize); 136 + p->gdb_st_blocks = cpu_to_be64(s->st_blocks); 137 + #endif 138 + p->gdb_st_atime = cpu_to_be32(s->st_atime); 139 + p->gdb_st_mtime = cpu_to_be32(s->st_mtime); 140 + p->gdb_st_ctime = cpu_to_be32(s->st_ctime); 141 + unlock_user(p, addr, sizeof(struct nios2_gdb_stat)); 142 + return true; 143 + } 144 + 145 + static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret, 146 + uint32_t err) 147 + { 148 + target_ulong args = env->regs[R_ARG1]; 149 + if (put_user_u32(ret, args) || 150 + put_user_u32(err, args + 4)) { 151 + /* 152 + * The nios2 semihosting ABI does not provide any way to report this 153 + * error to the guest, so the best we can do is log it in qemu. 154 + * It is always a guest error not to pass us a valid argument block. 155 + */ 156 + qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value " 157 + "discarded because argument block not writable\n"); 158 + } 159 + } 160 + 161 + static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret, 162 + uint32_t err) 163 + { 164 + target_ulong args = env->regs[R_ARG1]; 165 + if (put_user_u32(ret >> 32, args) || 166 + put_user_u32(ret, args + 4) || 167 + put_user_u32(err, args + 8)) { 168 + /* No way to report this via nios2 semihosting ABI; just log it */ 169 + qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: return value " 170 + "discarded because argument block not writable\n"); 171 + } 172 + } 173 + 174 + static int nios2_semi_is_lseek; 175 + 176 + static void nios2_semi_cb(CPUState *cs, target_ulong ret, target_ulong err) 177 + { 178 + Nios2CPU *cpu = NIOS2_CPU(cs); 179 + CPUNios2State *env = &cpu->env; 180 + 181 + if (nios2_semi_is_lseek) { 182 + /* 183 + * FIXME: We've already lost the high bits of the lseek 184 + * return value. 185 + */ 186 + nios2_semi_return_u64(env, ret, err); 187 + nios2_semi_is_lseek = 0; 188 + } else { 189 + nios2_semi_return_u32(env, ret, err); 190 + } 191 + } 192 + 193 + /* 194 + * Read the input value from the argument block; fail the semihosting 195 + * call if the memory read fails. 196 + */ 197 + #define GET_ARG(n) do { \ 198 + if (get_user_ual(arg ## n, args + (n) * 4)) { \ 199 + result = -1; \ 200 + errno = EFAULT; \ 201 + goto failed; \ 202 + } \ 203 + } while (0) 204 + 205 + void do_nios2_semihosting(CPUNios2State *env) 206 + { 207 + int nr; 208 + uint32_t args; 209 + target_ulong arg0, arg1, arg2, arg3; 210 + void *p; 211 + void *q; 212 + uint32_t len; 213 + uint32_t result; 214 + 215 + nr = env->regs[R_ARG0]; 216 + args = env->regs[R_ARG1]; 217 + switch (nr) { 218 + case HOSTED_EXIT: 219 + gdb_exit(env, env->regs[R_ARG0]); 220 + exit(env->regs[R_ARG0]); 221 + case HOSTED_OPEN: 222 + GET_ARG(0); 223 + GET_ARG(1); 224 + GET_ARG(2); 225 + GET_ARG(3); 226 + if (use_gdb_syscalls()) { 227 + gdb_do_syscall(nios2_semi_cb, "open,%s,%x,%x", arg0, (int)arg1, 228 + arg2, arg3); 229 + return; 230 + } else { 231 + p = lock_user_string(arg0); 232 + if (!p) { 233 + result = -1; 234 + errno = EFAULT; 235 + } else { 236 + result = open(p, translate_openflags(arg2), arg3); 237 + unlock_user(p, arg0, 0); 238 + } 239 + } 240 + break; 241 + case HOSTED_CLOSE: 242 + { 243 + /* Ignore attempts to close stdin/out/err. */ 244 + GET_ARG(0); 245 + int fd = arg0; 246 + if (fd > 2) { 247 + if (use_gdb_syscalls()) { 248 + gdb_do_syscall(nios2_semi_cb, "close,%x", arg0); 249 + return; 250 + } else { 251 + result = close(fd); 252 + } 253 + } else { 254 + result = 0; 255 + } 256 + break; 257 + } 258 + case HOSTED_READ: 259 + GET_ARG(0); 260 + GET_ARG(1); 261 + GET_ARG(2); 262 + len = arg2; 263 + if (use_gdb_syscalls()) { 264 + gdb_do_syscall(nios2_semi_cb, "read,%x,%x,%x", 265 + arg0, arg1, len); 266 + return; 267 + } else { 268 + p = lock_user(VERIFY_WRITE, arg1, len, 0); 269 + if (!p) { 270 + result = -1; 271 + errno = EFAULT; 272 + } else { 273 + result = read(arg0, p, len); 274 + unlock_user(p, arg1, len); 275 + } 276 + } 277 + break; 278 + case HOSTED_WRITE: 279 + GET_ARG(0); 280 + GET_ARG(1); 281 + GET_ARG(2); 282 + len = arg2; 283 + if (use_gdb_syscalls()) { 284 + gdb_do_syscall(nios2_semi_cb, "write,%x,%x,%x", 285 + arg0, arg1, len); 286 + return; 287 + } else { 288 + p = lock_user(VERIFY_READ, arg1, len, 1); 289 + if (!p) { 290 + result = -1; 291 + errno = EFAULT; 292 + } else { 293 + result = write(arg0, p, len); 294 + unlock_user(p, arg0, 0); 295 + } 296 + } 297 + break; 298 + case HOSTED_LSEEK: 299 + { 300 + uint64_t off; 301 + GET_ARG(0); 302 + GET_ARG(1); 303 + GET_ARG(2); 304 + GET_ARG(3); 305 + off = (uint32_t)arg2 | ((uint64_t)arg1 << 32); 306 + if (use_gdb_syscalls()) { 307 + nios2_semi_is_lseek = 1; 308 + gdb_do_syscall(nios2_semi_cb, "lseek,%x,%lx,%x", 309 + arg0, off, arg3); 310 + } else { 311 + off = lseek(arg0, off, arg3); 312 + nios2_semi_return_u64(env, off, errno); 313 + } 314 + return; 315 + } 316 + case HOSTED_RENAME: 317 + GET_ARG(0); 318 + GET_ARG(1); 319 + GET_ARG(2); 320 + GET_ARG(3); 321 + if (use_gdb_syscalls()) { 322 + gdb_do_syscall(nios2_semi_cb, "rename,%s,%s", 323 + arg0, (int)arg1, arg2, (int)arg3); 324 + return; 325 + } else { 326 + p = lock_user_string(arg0); 327 + q = lock_user_string(arg2); 328 + if (!p || !q) { 329 + result = -1; 330 + errno = EFAULT; 331 + } else { 332 + result = rename(p, q); 333 + } 334 + unlock_user(p, arg0, 0); 335 + unlock_user(q, arg2, 0); 336 + } 337 + break; 338 + case HOSTED_UNLINK: 339 + GET_ARG(0); 340 + GET_ARG(1); 341 + if (use_gdb_syscalls()) { 342 + gdb_do_syscall(nios2_semi_cb, "unlink,%s", 343 + arg0, (int)arg1); 344 + return; 345 + } else { 346 + p = lock_user_string(arg0); 347 + if (!p) { 348 + result = -1; 349 + errno = EFAULT; 350 + } else { 351 + result = unlink(p); 352 + unlock_user(p, arg0, 0); 353 + } 354 + } 355 + break; 356 + case HOSTED_STAT: 357 + GET_ARG(0); 358 + GET_ARG(1); 359 + GET_ARG(2); 360 + if (use_gdb_syscalls()) { 361 + gdb_do_syscall(nios2_semi_cb, "stat,%s,%x", 362 + arg0, (int)arg1, arg2); 363 + return; 364 + } else { 365 + struct stat s; 366 + p = lock_user_string(arg0); 367 + if (!p) { 368 + result = -1; 369 + errno = EFAULT; 370 + } else { 371 + result = stat(p, &s); 372 + unlock_user(p, arg0, 0); 373 + } 374 + if (result == 0 && !translate_stat(env, arg2, &s)) { 375 + result = -1; 376 + errno = EFAULT; 377 + } 378 + } 379 + break; 380 + case HOSTED_FSTAT: 381 + GET_ARG(0); 382 + GET_ARG(1); 383 + if (use_gdb_syscalls()) { 384 + gdb_do_syscall(nios2_semi_cb, "fstat,%x,%x", 385 + arg0, arg1); 386 + return; 387 + } else { 388 + struct stat s; 389 + result = fstat(arg0, &s); 390 + if (result == 0 && !translate_stat(env, arg1, &s)) { 391 + result = -1; 392 + errno = EFAULT; 393 + } 394 + } 395 + break; 396 + case HOSTED_GETTIMEOFDAY: 397 + /* Only the tv parameter is used. tz is assumed NULL. */ 398 + GET_ARG(0); 399 + if (use_gdb_syscalls()) { 400 + gdb_do_syscall(nios2_semi_cb, "gettimeofday,%x,%x", 401 + arg0, 0); 402 + return; 403 + } else { 404 + qemu_timeval tv; 405 + struct gdb_timeval *p; 406 + result = qemu_gettimeofday(&tv); 407 + if (result != 0) { 408 + p = lock_user(VERIFY_WRITE, arg0, sizeof(struct gdb_timeval), 409 + 0); 410 + if (!p) { 411 + result = -1; 412 + errno = EFAULT; 413 + } else { 414 + p->tv_sec = cpu_to_be32(tv.tv_sec); 415 + p->tv_usec = cpu_to_be64(tv.tv_usec); 416 + unlock_user(p, arg0, sizeof(struct gdb_timeval)); 417 + } 418 + } 419 + } 420 + break; 421 + case HOSTED_ISATTY: 422 + GET_ARG(0); 423 + if (use_gdb_syscalls()) { 424 + gdb_do_syscall(nios2_semi_cb, "isatty,%x", arg0); 425 + return; 426 + } else { 427 + result = isatty(arg0); 428 + } 429 + break; 430 + case HOSTED_SYSTEM: 431 + GET_ARG(0); 432 + GET_ARG(1); 433 + if (use_gdb_syscalls()) { 434 + gdb_do_syscall(nios2_semi_cb, "system,%s", 435 + arg0, (int)arg1); 436 + return; 437 + } else { 438 + p = lock_user_string(arg0); 439 + if (!p) { 440 + result = -1; 441 + errno = EFAULT; 442 + } else { 443 + result = system(p); 444 + unlock_user(p, arg0, 0); 445 + } 446 + } 447 + break; 448 + default: 449 + qemu_log_mask(LOG_GUEST_ERROR, "nios2-semihosting: unsupported " 450 + "semihosting syscall %d\n", nr); 451 + result = 0; 452 + } 453 + failed: 454 + nios2_semi_return_u32(env, result, errno); 455 + }