target-mips: add Unified Hosting Interface (UHI) support
Add UHI semihosting support for MIPS. QEMU run with "-semihosting" option will alter the behaviour of SDBBP 1 instruction -- UHI operation will be called instead of generating a debug exception. Also tweak Malta's pseudo-bootloader. On CPU reset the $4 register is set to -1 if semihosting arguments are passed to indicate that the UHI operations should be used to obtain input arguments. Signed-off-by: Leon Alrae <leon.alrae@imgtec.com> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
		
							parent
							
								
									ff33476772
								
							
						
					
					
						commit
						3b3c1694cf
					
				| @ -53,6 +53,7 @@ | ||||
| #include "qemu/error-report.h" | ||||
| #include "hw/empty_slot.h" | ||||
| #include "sysemu/kvm.h" | ||||
| #include "exec/semihost.h" | ||||
| 
 | ||||
| //#define DEBUG_BOARD_INIT
 | ||||
| 
 | ||||
| @ -634,7 +635,13 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, | ||||
| 
 | ||||
|     /* Second part of the bootloader */ | ||||
|     p = (uint32_t *) (base + 0x580); | ||||
|     stl_p(p++, 0x24040002);                                      /* addiu a0, zero, 2 */ | ||||
| 
 | ||||
|     if (semihosting_get_argc()) { | ||||
|         /* Preserve a0 content as arguments have been passed */ | ||||
|         stl_p(p++, 0x00000000);                         /* nop */ | ||||
|     } else { | ||||
|         stl_p(p++, 0x24040002);                         /* addiu a0, zero, 2 */ | ||||
|     } | ||||
|     stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */ | ||||
|     stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */ | ||||
|     stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */ | ||||
|  | ||||
| @ -3345,20 +3345,22 @@ Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only). | ||||
| ETEXI | ||||
| DEF("semihosting", 0, QEMU_OPTION_semihosting, | ||||
|     "-semihosting    semihosting mode\n", | ||||
|     QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) | ||||
|     QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | | ||||
|     QEMU_ARCH_MIPS) | ||||
| STEXI | ||||
| @item -semihosting | ||||
| @findex -semihosting | ||||
| Enable semihosting mode (ARM, M68K, Xtensa only). | ||||
| Enable semihosting mode (ARM, M68K, Xtensa, MIPS only). | ||||
| ETEXI | ||||
| DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, | ||||
|     "-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \ | ||||
|     "                semihosting configuration\n", | ||||
| QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32) | ||||
| QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | | ||||
| QEMU_ARCH_MIPS) | ||||
| STEXI | ||||
| @item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]] | ||||
| @findex -semihosting-config | ||||
| Enable and configure semihosting (ARM, M68K, Xtensa only). | ||||
| Enable and configure semihosting (ARM, M68K, Xtensa, MIPS only). | ||||
| @table @option | ||||
| @item target=@code{native|gdb|auto} | ||||
| Defines where the semihosting calls will be addressed, to QEMU (@code{native}) | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o | ||||
| obj-y += gdbstub.o msa_helper.o | ||||
| obj-y += gdbstub.o msa_helper.o mips-semi.o | ||||
| obj-$(CONFIG_SOFTMMU) += machine.o | ||||
| obj-$(CONFIG_KVM) += kvm.o | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) | ||||
| DEF_HELPER_2(raise_exception, noreturn, env, i32) | ||||
| 
 | ||||
| DEF_HELPER_1(do_semihosting, void, env) | ||||
| 
 | ||||
| #ifdef TARGET_MIPS64 | ||||
| DEF_HELPER_4(sdl, void, env, tl, tl, int) | ||||
| DEF_HELPER_4(sdr, void, env, tl, tl, int) | ||||
|  | ||||
							
								
								
									
										336
									
								
								target-mips/mips-semi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								target-mips/mips-semi.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,336 @@ | ||||
| /*
 | ||||
|  * Unified Hosting Interface syscalls. | ||||
|  * | ||||
|  * Copyright (c) 2015 Imagination Technologies | ||||
|  * | ||||
|  * This library is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * This library is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <sys/stat.h> | ||||
| #include "cpu.h" | ||||
| #include "exec/helper-proto.h" | ||||
| #include "exec/softmmu-semi.h" | ||||
| #include "exec/semihost.h" | ||||
| 
 | ||||
| typedef enum UHIOp { | ||||
|     UHI_exit = 1, | ||||
|     UHI_open = 2, | ||||
|     UHI_close = 3, | ||||
|     UHI_read = 4, | ||||
|     UHI_write = 5, | ||||
|     UHI_lseek = 6, | ||||
|     UHI_unlink = 7, | ||||
|     UHI_fstat = 8, | ||||
|     UHI_argc = 9, | ||||
|     UHI_argnlen = 10, | ||||
|     UHI_argn = 11, | ||||
|     UHI_plog = 13, | ||||
|     UHI_assert = 14, | ||||
|     UHI_pread = 19, | ||||
|     UHI_pwrite = 20, | ||||
|     UHI_link = 22 | ||||
| } UHIOp; | ||||
| 
 | ||||
| typedef struct UHIStat { | ||||
|     int16_t uhi_st_dev; | ||||
|     uint16_t uhi_st_ino; | ||||
|     uint32_t uhi_st_mode; | ||||
|     uint16_t uhi_st_nlink; | ||||
|     uint16_t uhi_st_uid; | ||||
|     uint16_t uhi_st_gid; | ||||
|     int16_t uhi_st_rdev; | ||||
|     uint64_t uhi_st_size; | ||||
|     uint64_t uhi_st_atime; | ||||
|     uint64_t uhi_st_spare1; | ||||
|     uint64_t uhi_st_mtime; | ||||
|     uint64_t uhi_st_spare2; | ||||
|     uint64_t uhi_st_ctime; | ||||
|     uint64_t uhi_st_spare3; | ||||
|     uint64_t uhi_st_blksize; | ||||
|     uint64_t uhi_st_blocks; | ||||
|     uint64_t uhi_st_spare4[2]; | ||||
| } UHIStat; | ||||
| 
 | ||||
| enum UHIOpenFlags { | ||||
|     UHIOpen_RDONLY = 0x0, | ||||
|     UHIOpen_WRONLY = 0x1, | ||||
|     UHIOpen_RDWR   = 0x2, | ||||
|     UHIOpen_APPEND = 0x8, | ||||
|     UHIOpen_CREAT  = 0x200, | ||||
|     UHIOpen_TRUNC  = 0x400, | ||||
|     UHIOpen_EXCL   = 0x800 | ||||
| }; | ||||
| 
 | ||||
| static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src, | ||||
|                                target_ulong vaddr) | ||||
| { | ||||
|     hwaddr len = sizeof(struct UHIStat); | ||||
|     UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); | ||||
|     if (!dst) { | ||||
|         errno = EFAULT; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     dst->uhi_st_dev = tswap16(src->st_dev); | ||||
|     dst->uhi_st_ino = tswap16(src->st_ino); | ||||
|     dst->uhi_st_mode = tswap32(src->st_mode); | ||||
|     dst->uhi_st_nlink = tswap16(src->st_nlink); | ||||
|     dst->uhi_st_uid = tswap16(src->st_uid); | ||||
|     dst->uhi_st_gid = tswap16(src->st_gid); | ||||
|     dst->uhi_st_rdev = tswap16(src->st_rdev); | ||||
|     dst->uhi_st_size = tswap64(src->st_size); | ||||
|     dst->uhi_st_atime = tswap64(src->st_atime); | ||||
|     dst->uhi_st_mtime = tswap64(src->st_mtime); | ||||
|     dst->uhi_st_ctime = tswap64(src->st_ctime); | ||||
| #ifdef _WIN32 | ||||
|     dst->uhi_st_blksize = 0; | ||||
|     dst->uhi_st_blocks = 0; | ||||
| #else | ||||
|     dst->uhi_st_blksize = tswap64(src->st_blksize); | ||||
|     dst->uhi_st_blocks = tswap64(src->st_blocks); | ||||
| #endif | ||||
|     unlock_user(dst, vaddr, len); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int get_open_flags(target_ulong target_flags) | ||||
| { | ||||
|     int open_flags = 0; | ||||
| 
 | ||||
|     if (target_flags & UHIOpen_RDWR) { | ||||
|         open_flags |= O_RDWR; | ||||
|     } else if (target_flags & UHIOpen_WRONLY) { | ||||
|         open_flags |= O_WRONLY; | ||||
|     } else { | ||||
|         open_flags |= O_RDONLY; | ||||
|     } | ||||
| 
 | ||||
|     open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0; | ||||
|     open_flags |= (target_flags & UHIOpen_CREAT)  ? O_CREAT  : 0; | ||||
|     open_flags |= (target_flags & UHIOpen_TRUNC)  ? O_TRUNC  : 0; | ||||
|     open_flags |= (target_flags & UHIOpen_EXCL)   ? O_EXCL   : 0; | ||||
| 
 | ||||
|     return open_flags; | ||||
| } | ||||
| 
 | ||||
| static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr, | ||||
|                          target_ulong len, target_ulong offset) | ||||
| { | ||||
|     int num_of_bytes; | ||||
|     void *dst = lock_user(VERIFY_READ, vaddr, len, 1); | ||||
|     if (!dst) { | ||||
|         errno = EFAULT; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (offset) { | ||||
| #ifdef _WIN32 | ||||
|         num_of_bytes = 0; | ||||
| #else | ||||
|         num_of_bytes = pwrite(fd, dst, len, offset); | ||||
| #endif | ||||
|     } else { | ||||
|         num_of_bytes = write(fd, dst, len); | ||||
|     } | ||||
| 
 | ||||
|     unlock_user(dst, vaddr, 0); | ||||
|     return num_of_bytes; | ||||
| } | ||||
| 
 | ||||
| static int read_from_file(CPUMIPSState *env, target_ulong fd, | ||||
|                           target_ulong vaddr, target_ulong len, | ||||
|                           target_ulong offset) | ||||
| { | ||||
|     int num_of_bytes; | ||||
|     void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); | ||||
|     if (!dst) { | ||||
|         errno = EFAULT; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (offset) { | ||||
| #ifdef _WIN32 | ||||
|         num_of_bytes = 0; | ||||
| #else | ||||
|         num_of_bytes = pread(fd, dst, len, offset); | ||||
| #endif | ||||
|     } else { | ||||
|         num_of_bytes = read(fd, dst, len); | ||||
|     } | ||||
| 
 | ||||
|     unlock_user(dst, vaddr, len); | ||||
|     return num_of_bytes; | ||||
| } | ||||
| 
 | ||||
| static int copy_argn_to_target(CPUMIPSState *env, int arg_num, | ||||
|                                target_ulong vaddr) | ||||
| { | ||||
|     int strsize = strlen(semihosting_get_arg(arg_num)) + 1; | ||||
|     char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0); | ||||
|     if (!dst) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     strcpy(dst, semihosting_get_arg(arg_num)); | ||||
| 
 | ||||
|     unlock_user(dst, vaddr, strsize); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #define GET_TARGET_STRING(p, addr)              \ | ||||
|     do {                                        \ | ||||
|         p = lock_user_string(addr);             \ | ||||
|         if (!p) {                               \ | ||||
|             gpr[2] = -1;                        \ | ||||
|             gpr[3] = EFAULT;                    \ | ||||
|             goto uhi_done;                      \ | ||||
|         }                                       \ | ||||
|     } while (0) | ||||
| 
 | ||||
| #define FREE_TARGET_STRING(p, gpr)              \ | ||||
|     do {                                        \ | ||||
|         unlock_user(p, gpr, 0);                 \ | ||||
|     } while (0) | ||||
| 
 | ||||
| void helper_do_semihosting(CPUMIPSState *env) | ||||
| { | ||||
|     target_ulong *gpr = env->active_tc.gpr; | ||||
|     const UHIOp op = gpr[25]; | ||||
|     char *p, *p2; | ||||
| 
 | ||||
|     switch (op) { | ||||
|     case UHI_exit: | ||||
|         qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]); | ||||
|         exit(gpr[4]); | ||||
|     case UHI_open: | ||||
|         GET_TARGET_STRING(p, gpr[4]); | ||||
|         if (!strcmp("/dev/stdin", p)) { | ||||
|             gpr[2] = 0; | ||||
|         } else if (!strcmp("/dev/stdout", p)) { | ||||
|             gpr[2] = 1; | ||||
|         } else if (!strcmp("/dev/stderr", p)) { | ||||
|             gpr[2] = 2; | ||||
|         } else { | ||||
|             gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]); | ||||
|             gpr[3] = errno; | ||||
|         } | ||||
|         FREE_TARGET_STRING(p, gpr[4]); | ||||
|         break; | ||||
|     case UHI_close: | ||||
|         if (gpr[4] < 3) { | ||||
|             /* ignore closing stdin/stdout/stderr */ | ||||
|             gpr[2] = 0; | ||||
|             goto uhi_done; | ||||
|         } | ||||
|         gpr[2] = close(gpr[4]); | ||||
|         gpr[3] = errno; | ||||
|         break; | ||||
|     case UHI_read: | ||||
|         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0); | ||||
|         gpr[3] = errno; | ||||
|         break; | ||||
|     case UHI_write: | ||||
|         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0); | ||||
|         gpr[3] = errno; | ||||
|         break; | ||||
|     case UHI_lseek: | ||||
|         gpr[2] = lseek(gpr[4], gpr[5], gpr[6]); | ||||
|         gpr[3] = errno; | ||||
|         break; | ||||
|     case UHI_unlink: | ||||
|         GET_TARGET_STRING(p, gpr[4]); | ||||
|         gpr[2] = remove(p); | ||||
|         gpr[3] = errno; | ||||
|         FREE_TARGET_STRING(p, gpr[4]); | ||||
|         break; | ||||
|     case UHI_fstat: | ||||
|         { | ||||
|             struct stat sbuf; | ||||
|             memset(&sbuf, 0, sizeof(sbuf)); | ||||
|             gpr[2] = fstat(gpr[4], &sbuf); | ||||
|             gpr[3] = errno; | ||||
|             if (gpr[2]) { | ||||
|                 goto uhi_done; | ||||
|             } | ||||
|             gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]); | ||||
|             gpr[3] = errno; | ||||
|         } | ||||
|         break; | ||||
|     case UHI_argc: | ||||
|         gpr[2] = semihosting_get_argc(); | ||||
|         break; | ||||
|     case UHI_argnlen: | ||||
|         if (gpr[4] >= semihosting_get_argc()) { | ||||
|             gpr[2] = -1; | ||||
|             goto uhi_done; | ||||
|         } | ||||
|         gpr[2] = strlen(semihosting_get_arg(gpr[4])); | ||||
|         break; | ||||
|     case UHI_argn: | ||||
|         if (gpr[4] >= semihosting_get_argc()) { | ||||
|             gpr[2] = -1; | ||||
|             goto uhi_done; | ||||
|         } | ||||
|         gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]); | ||||
|         break; | ||||
|     case UHI_plog: | ||||
|         GET_TARGET_STRING(p, gpr[4]); | ||||
|         p2 = strstr(p, "%d"); | ||||
|         if (p2) { | ||||
|             int char_num = p2 - p; | ||||
|             char *buf = g_malloc(char_num + 1); | ||||
|             strncpy(buf, p, char_num); | ||||
|             buf[char_num] = '\0'; | ||||
|             gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2); | ||||
|             g_free(buf); | ||||
|         } else { | ||||
|             gpr[2] = printf("%s", p); | ||||
|         } | ||||
|         FREE_TARGET_STRING(p, gpr[4]); | ||||
|         break; | ||||
|     case UHI_assert: | ||||
|         GET_TARGET_STRING(p, gpr[4]); | ||||
|         GET_TARGET_STRING(p2, gpr[5]); | ||||
|         printf("assertion '"); | ||||
|         printf("\"%s\"", p); | ||||
|         printf("': file \"%s\", line %d\n", p2, (int)gpr[6]); | ||||
|         FREE_TARGET_STRING(p2, gpr[5]); | ||||
|         FREE_TARGET_STRING(p, gpr[4]); | ||||
|         abort(); | ||||
|         break; | ||||
|     case UHI_pread: | ||||
|         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); | ||||
|         gpr[3] = errno; | ||||
|         break; | ||||
|     case UHI_pwrite: | ||||
|         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); | ||||
|         gpr[3] = errno; | ||||
|         break; | ||||
| #ifndef _WIN32 | ||||
|     case UHI_link: | ||||
|         GET_TARGET_STRING(p, gpr[4]); | ||||
|         GET_TARGET_STRING(p2, gpr[5]); | ||||
|         gpr[2] = link(p, p2); | ||||
|         gpr[3] = errno; | ||||
|         FREE_TARGET_STRING(p2, gpr[5]); | ||||
|         FREE_TARGET_STRING(p, gpr[4]); | ||||
|         break; | ||||
| #endif | ||||
|     default: | ||||
|         fprintf(stderr, "Unknown UHI operation %d\n", op); | ||||
|         abort(); | ||||
|     } | ||||
| uhi_done: | ||||
|     return; | ||||
| } | ||||
| @ -29,6 +29,7 @@ | ||||
| #include "exec/helper-proto.h" | ||||
| #include "exec/helper-gen.h" | ||||
| #include "sysemu/kvm.h" | ||||
| #include "exec/semihost.h" | ||||
| 
 | ||||
| #include "trace-tcg.h" | ||||
| 
 | ||||
| @ -11549,6 +11550,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) | ||||
|     return 4; | ||||
| } | ||||
| 
 | ||||
| static inline bool is_uhi(int sdbbp_code) | ||||
| { | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     return false; | ||||
| #else | ||||
|     return semihosting_enabled() && sdbbp_code == 1; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) | ||||
| { | ||||
|     int rx, ry; | ||||
| @ -11848,11 +11858,15 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) | ||||
|             } | ||||
|             break; | ||||
|         case RR_SDBBP: | ||||
|             /* XXX: not clear which exception should be raised
 | ||||
|              *      when in debug mode... | ||||
|              */ | ||||
|             check_insn(ctx, ISA_MIPS32); | ||||
|             generate_exception(ctx, EXCP_DBp); | ||||
|             if (is_uhi(extract32(ctx->opcode, 5, 6))) { | ||||
|                 gen_helper_do_semihosting(cpu_env); | ||||
|             } else { | ||||
|                 /* XXX: not clear which exception should be raised
 | ||||
|                  *      when in debug mode... | ||||
|                  */ | ||||
|                 check_insn(ctx, ISA_MIPS32); | ||||
|                 generate_exception(ctx, EXCP_DBp); | ||||
|             } | ||||
|             break; | ||||
|         case RR_SLT: | ||||
|             gen_slt(ctx, OPC_SLT, 24, rx, ry); | ||||
| @ -12699,11 +12713,15 @@ static void gen_pool16c_insn(DisasContext *ctx) | ||||
|         generate_exception(ctx, EXCP_BREAK); | ||||
|         break; | ||||
|     case SDBBP16: | ||||
|         /* XXX: not clear which exception should be raised
 | ||||
|          *      when in debug mode... | ||||
|          */ | ||||
|         check_insn(ctx, ISA_MIPS32); | ||||
|         generate_exception(ctx, EXCP_DBp); | ||||
|         if (is_uhi(extract32(ctx->opcode, 0, 4))) { | ||||
|             gen_helper_do_semihosting(cpu_env); | ||||
|         } else { | ||||
|             /* XXX: not clear which exception should be raised
 | ||||
|              *      when in debug mode... | ||||
|              */ | ||||
|             check_insn(ctx, ISA_MIPS32); | ||||
|             generate_exception(ctx, EXCP_DBp); | ||||
|         } | ||||
|         break; | ||||
|     case JRADDIUSP + 0: | ||||
|     case JRADDIUSP + 1: | ||||
| @ -13067,8 +13085,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) | ||||
|             ctx->bstate = BS_STOP; | ||||
|             break; | ||||
|         case SDBBP: | ||||
|             check_insn(ctx, ISA_MIPS32); | ||||
|             generate_exception(ctx, EXCP_DBp); | ||||
|             if (is_uhi(extract32(ctx->opcode, 16, 10))) { | ||||
|                 gen_helper_do_semihosting(cpu_env); | ||||
|             } else { | ||||
|                 check_insn(ctx, ISA_MIPS32); | ||||
|                 generate_exception(ctx, EXCP_DBp); | ||||
|             } | ||||
|             break; | ||||
|         default: | ||||
|             goto pool32axf_invalid; | ||||
| @ -16460,10 +16482,14 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx) | ||||
|         } | ||||
|         break; | ||||
|     case R6_OPC_SDBBP: | ||||
|         if (ctx->hflags & MIPS_HFLAG_SBRI) { | ||||
|             generate_exception(ctx, EXCP_RI); | ||||
|         if (is_uhi(extract32(ctx->opcode, 6, 20))) { | ||||
|             gen_helper_do_semihosting(cpu_env); | ||||
|         } else { | ||||
|             generate_exception(ctx, EXCP_DBp); | ||||
|             if (ctx->hflags & MIPS_HFLAG_SBRI) { | ||||
|                 generate_exception(ctx, EXCP_RI); | ||||
|             } else { | ||||
|                 generate_exception(ctx, EXCP_DBp); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
| #if defined(TARGET_MIPS64) | ||||
| @ -16833,11 +16859,15 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx) | ||||
|         gen_cl(ctx, op1, rd, rs); | ||||
|         break; | ||||
|     case OPC_SDBBP: | ||||
|         /* XXX: not clear which exception should be raised
 | ||||
|          *      when in debug mode... | ||||
|          */ | ||||
|         check_insn(ctx, ISA_MIPS32); | ||||
|         generate_exception(ctx, EXCP_DBp); | ||||
|         if (is_uhi(extract32(ctx->opcode, 6, 20))) { | ||||
|             gen_helper_do_semihosting(cpu_env); | ||||
|         } else { | ||||
|             /* XXX: not clear which exception should be raised
 | ||||
|              *      when in debug mode... | ||||
|              */ | ||||
|             check_insn(ctx, ISA_MIPS32); | ||||
|             generate_exception(ctx, EXCP_DBp); | ||||
|         } | ||||
|         break; | ||||
| #if defined(TARGET_MIPS64) | ||||
|     case OPC_DCLO: | ||||
| @ -19910,6 +19940,11 @@ void cpu_state_reset(CPUMIPSState *env) | ||||
|     restore_flush_mode(env); | ||||
|     restore_pamask(env); | ||||
|     cs->exception_index = EXCP_NONE; | ||||
| 
 | ||||
|     if (semihosting_get_argc()) { | ||||
|         /* UHI interface can be used to obtain argc and argv */ | ||||
|         env->active_tc.gpr[4] = -1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Leon Alrae
						Leon Alrae