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 "qemu/error-report.h"
 | 
				
			||||||
#include "hw/empty_slot.h"
 | 
					#include "hw/empty_slot.h"
 | 
				
			||||||
#include "sysemu/kvm.h"
 | 
					#include "sysemu/kvm.h"
 | 
				
			||||||
 | 
					#include "exec/semihost.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define DEBUG_BOARD_INIT
 | 
					//#define DEBUG_BOARD_INIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -634,7 +635,13 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Second part of the bootloader */
 | 
					    /* Second part of the bootloader */
 | 
				
			||||||
    p = (uint32_t *) (base + 0x580);
 | 
					    p = (uint32_t *) (base + 0x580);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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++, 0x24040002);                         /* addiu a0, zero, 2 */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
 | 
					    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++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
 | 
				
			||||||
    stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(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
 | 
					ETEXI
 | 
				
			||||||
DEF("semihosting", 0, QEMU_OPTION_semihosting,
 | 
					DEF("semihosting", 0, QEMU_OPTION_semihosting,
 | 
				
			||||||
    "-semihosting    semihosting mode\n",
 | 
					    "-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
 | 
					STEXI
 | 
				
			||||||
@item -semihosting
 | 
					@item -semihosting
 | 
				
			||||||
@findex -semihosting
 | 
					@findex -semihosting
 | 
				
			||||||
Enable semihosting mode (ARM, M68K, Xtensa only).
 | 
					Enable semihosting mode (ARM, M68K, Xtensa, MIPS only).
 | 
				
			||||||
ETEXI
 | 
					ETEXI
 | 
				
			||||||
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
 | 
					DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
 | 
				
			||||||
    "-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \
 | 
					    "-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \
 | 
				
			||||||
    "                semihosting configuration\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
 | 
					STEXI
 | 
				
			||||||
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]
 | 
					@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]
 | 
				
			||||||
@findex -semihosting-config
 | 
					@findex -semihosting-config
 | 
				
			||||||
Enable and configure semihosting (ARM, M68K, Xtensa only).
 | 
					Enable and configure semihosting (ARM, M68K, Xtensa, MIPS only).
 | 
				
			||||||
@table @option
 | 
					@table @option
 | 
				
			||||||
@item target=@code{native|gdb|auto}
 | 
					@item target=@code{native|gdb|auto}
 | 
				
			||||||
Defines where the semihosting calls will be addressed, to QEMU (@code{native})
 | 
					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 += 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_SOFTMMU) += machine.o
 | 
				
			||||||
obj-$(CONFIG_KVM) += kvm.o
 | 
					obj-$(CONFIG_KVM) += kvm.o
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
 | 
					DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
 | 
				
			||||||
DEF_HELPER_2(raise_exception, noreturn, env, i32)
 | 
					DEF_HELPER_2(raise_exception, noreturn, env, i32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEF_HELPER_1(do_semihosting, void, env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef TARGET_MIPS64
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
DEF_HELPER_4(sdl, void, env, tl, tl, int)
 | 
					DEF_HELPER_4(sdl, void, env, tl, tl, int)
 | 
				
			||||||
DEF_HELPER_4(sdr, 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-proto.h"
 | 
				
			||||||
#include "exec/helper-gen.h"
 | 
					#include "exec/helper-gen.h"
 | 
				
			||||||
#include "sysemu/kvm.h"
 | 
					#include "sysemu/kvm.h"
 | 
				
			||||||
 | 
					#include "exec/semihost.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "trace-tcg.h"
 | 
					#include "trace-tcg.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -11549,6 +11550,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
 | 
				
			|||||||
    return 4;
 | 
					    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)
 | 
					static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int rx, ry;
 | 
					    int rx, ry;
 | 
				
			||||||
@ -11848,11 +11858,15 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case RR_SDBBP:
 | 
					        case RR_SDBBP:
 | 
				
			||||||
 | 
					            if (is_uhi(extract32(ctx->opcode, 5, 6))) {
 | 
				
			||||||
 | 
					                gen_helper_do_semihosting(cpu_env);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
                /* XXX: not clear which exception should be raised
 | 
					                /* XXX: not clear which exception should be raised
 | 
				
			||||||
                 *      when in debug mode...
 | 
					                 *      when in debug mode...
 | 
				
			||||||
                 */
 | 
					                 */
 | 
				
			||||||
                check_insn(ctx, ISA_MIPS32);
 | 
					                check_insn(ctx, ISA_MIPS32);
 | 
				
			||||||
                generate_exception(ctx, EXCP_DBp);
 | 
					                generate_exception(ctx, EXCP_DBp);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case RR_SLT:
 | 
					        case RR_SLT:
 | 
				
			||||||
            gen_slt(ctx, OPC_SLT, 24, rx, ry);
 | 
					            gen_slt(ctx, OPC_SLT, 24, rx, ry);
 | 
				
			||||||
@ -12699,11 +12713,15 @@ static void gen_pool16c_insn(DisasContext *ctx)
 | 
				
			|||||||
        generate_exception(ctx, EXCP_BREAK);
 | 
					        generate_exception(ctx, EXCP_BREAK);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case SDBBP16:
 | 
					    case SDBBP16:
 | 
				
			||||||
 | 
					        if (is_uhi(extract32(ctx->opcode, 0, 4))) {
 | 
				
			||||||
 | 
					            gen_helper_do_semihosting(cpu_env);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            /* XXX: not clear which exception should be raised
 | 
					            /* XXX: not clear which exception should be raised
 | 
				
			||||||
             *      when in debug mode...
 | 
					             *      when in debug mode...
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
            check_insn(ctx, ISA_MIPS32);
 | 
					            check_insn(ctx, ISA_MIPS32);
 | 
				
			||||||
            generate_exception(ctx, EXCP_DBp);
 | 
					            generate_exception(ctx, EXCP_DBp);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case JRADDIUSP + 0:
 | 
					    case JRADDIUSP + 0:
 | 
				
			||||||
    case JRADDIUSP + 1:
 | 
					    case JRADDIUSP + 1:
 | 
				
			||||||
@ -13067,8 +13085,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
 | 
				
			|||||||
            ctx->bstate = BS_STOP;
 | 
					            ctx->bstate = BS_STOP;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case SDBBP:
 | 
					        case SDBBP:
 | 
				
			||||||
 | 
					            if (is_uhi(extract32(ctx->opcode, 16, 10))) {
 | 
				
			||||||
 | 
					                gen_helper_do_semihosting(cpu_env);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
                check_insn(ctx, ISA_MIPS32);
 | 
					                check_insn(ctx, ISA_MIPS32);
 | 
				
			||||||
                generate_exception(ctx, EXCP_DBp);
 | 
					                generate_exception(ctx, EXCP_DBp);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            goto pool32axf_invalid;
 | 
					            goto pool32axf_invalid;
 | 
				
			||||||
@ -16460,11 +16482,15 @@ static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case R6_OPC_SDBBP:
 | 
					    case R6_OPC_SDBBP:
 | 
				
			||||||
 | 
					        if (is_uhi(extract32(ctx->opcode, 6, 20))) {
 | 
				
			||||||
 | 
					            gen_helper_do_semihosting(cpu_env);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            if (ctx->hflags & MIPS_HFLAG_SBRI) {
 | 
					            if (ctx->hflags & MIPS_HFLAG_SBRI) {
 | 
				
			||||||
                generate_exception(ctx, EXCP_RI);
 | 
					                generate_exception(ctx, EXCP_RI);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                generate_exception(ctx, EXCP_DBp);
 | 
					                generate_exception(ctx, EXCP_DBp);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
#if defined(TARGET_MIPS64)
 | 
					#if defined(TARGET_MIPS64)
 | 
				
			||||||
    case OPC_DLSA:
 | 
					    case OPC_DLSA:
 | 
				
			||||||
@ -16833,11 +16859,15 @@ static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
 | 
				
			|||||||
        gen_cl(ctx, op1, rd, rs);
 | 
					        gen_cl(ctx, op1, rd, rs);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case OPC_SDBBP:
 | 
					    case OPC_SDBBP:
 | 
				
			||||||
 | 
					        if (is_uhi(extract32(ctx->opcode, 6, 20))) {
 | 
				
			||||||
 | 
					            gen_helper_do_semihosting(cpu_env);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            /* XXX: not clear which exception should be raised
 | 
					            /* XXX: not clear which exception should be raised
 | 
				
			||||||
             *      when in debug mode...
 | 
					             *      when in debug mode...
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
            check_insn(ctx, ISA_MIPS32);
 | 
					            check_insn(ctx, ISA_MIPS32);
 | 
				
			||||||
            generate_exception(ctx, EXCP_DBp);
 | 
					            generate_exception(ctx, EXCP_DBp);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
#if defined(TARGET_MIPS64)
 | 
					#if defined(TARGET_MIPS64)
 | 
				
			||||||
    case OPC_DCLO:
 | 
					    case OPC_DCLO:
 | 
				
			||||||
@ -19910,6 +19940,11 @@ void cpu_state_reset(CPUMIPSState *env)
 | 
				
			|||||||
    restore_flush_mode(env);
 | 
					    restore_flush_mode(env);
 | 
				
			||||||
    restore_pamask(env);
 | 
					    restore_pamask(env);
 | 
				
			||||||
    cs->exception_index = EXCP_NONE;
 | 
					    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)
 | 
					void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user