MIPS patches queue

- Cavium Octeon MIPS extension and CPU model (Pavel Dovgalyuk)
 - Semihosting cleanup (Richard Henderson)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmLN3yQACgkQ4+MsLN6t
 wN4RcBAAglgmqoFSHerA/oyK6AfsiMar8doL+hzr0YLdZcGpSYXOAhOHoTkNXg4u
 +DeXBOZUE5E36XonTEhBPY1bNHs07HfESqOYPqp/z1q1Z6sXV1FvJmhqbfmkYCJp
 rM18n7tK2vtB8XO/HwcUPQMN3HwKQsaikoA254bKVLPAMseBrTD+TBOTlA6dWIOg
 Vwk5EdhqSTmJn/MhetI7xBwTt5H1gs6ZDXAi+URs4bbw55+Z4tAmLaAX/pw+HSls
 aDT17RR1QcMlBx6kA48r2CsGMA0MZtPiVT92Sl7KynZQ3Q6pQcrqs5GV+IYXe9QV
 RUkBLYHww5znwY8KwLX8hEGyS4LkHihzHlHTtCQS6X2iRsnBEWwTi+ODBDwAsOTf
 xU39Wtno/Tq+UEnIerGGrzFidCLxbw68Dwq+60+JqAmk58soAP+vE4FTeN5ddjpB
 kQY6W85lhwshI00WQ/dk7Xw1w2BDBEXPJ6YHiQjcTLep2Gvp8FvudVW6metvrf4r
 uIOtouYwy3JGNWD0lmssUBSB7nb1VrLviufU26bDCnME1NRRID25ryiu//x1p9en
 u6Jp8zfMU4d4VpYv9jTbeMRYUM1gl/tPOMcR+sLFbEJ3R9xi1ngIO5Zu6OMgWn5T
 fuHUp6z4O++n4Xb5MhVi10+wye++eQJhM/n4OiQAFM8aJtz3KZw=
 =O4Yo
 -----END PGP SIGNATURE-----

Merge tag 'mips-20220712' of https://github.com/philmd/qemu into staging

MIPS patches queue

- Cavium Octeon MIPS extension and CPU model (Pavel Dovgalyuk)
- Semihosting cleanup (Richard Henderson)

# gpg: Signature made Tue 12 Jul 2022 21:52:52 BST
# gpg:                using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD  6BB2 E3E3 2C2C DEAD C0DE

* tag 'mips-20220712' of https://github.com/philmd/qemu:
  target/mips: Remove GET_TARGET_STRING and FREE_TARGET_STRING
  target/mips: Simplify UHI_argnlen and UHI_argn
  semihosting: Remove qemu_semihosting_log_out
  target/mips: Use error_report for UHI_assert
  target/mips: Avoid qemu_semihosting_log_out for UHI_plog
  target/mips: Use semihosting/syscalls.h
  target/mips: Drop link syscall from semihosting
  target/mips: Create report_fault for semihosting
  target/mips: introduce Cavium Octeon CPU model
  target/mips: implement Octeon-specific arithmetic instructions
  target/mips: implement Octeon-specific BBIT instructions
  target/mips: introduce decodetree structure for Cavium Octeon extension

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-07-13 21:48:16 +01:00
commit 455c62d85f
10 changed files with 465 additions and 233 deletions

View File

@ -40,19 +40,6 @@ int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
*/
int qemu_semihosting_console_write(void *buf, int len);
/**
* qemu_semihosting_log_out:
* @s: pointer to string
* @len: length of string
*
* Send a string to the debug output. Unlike console_out these strings
* can't be sent to a remote gdb instance as they don't exist in guest
* memory.
*
* Returns: number of bytes written
*/
int qemu_semihosting_log_out(const char *s, int len);
/*
* qemu_semihosting_console_block_until_ready:
* @cs: CPUState

View File

@ -38,15 +38,6 @@ typedef struct SemihostingConsole {
static SemihostingConsole console;
int qemu_semihosting_log_out(const char *s, int len)
{
if (console.chr) {
return qemu_chr_write_all(console.chr, (uint8_t *) s, len);
} else {
return write(STDERR_FILENO, s, len);
}
}
#define FIFO_SIZE 1024
static int console_can_read(void *opaque)

View File

@ -921,6 +921,34 @@ const mips_def_t mips_defs[] =
.insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSP_R2,
.mmu_type = MMU_TYPE_R4000,
},
{
/*
* Octeon 68xx with MIPS64 Cavium Octeon features.
*/
.name = "Octeon68XX",
.CP0_PRid = 0x000D9100,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (0x3F << CP0C1_MMU) |
(1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
(1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA) | (1 << CP0C3_DSPP) ,
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) |
(0x3c << CP0C4_KScrExist) | (1U << CP0C4_MMUExtDef) |
(3U << CP0C4_MMUSizeExt),
.CP0_LLAddr_rw_bitmask = 0,
.CP0_LLAddr_shift = 4,
.CP0_PageGrain = (1 << CP0PG_ELPA),
.SYNCI_Step = 32,
.CCRes = 2,
.CP0_Status_rw_bitmask = 0x12F8FFFF,
.SEGBITS = 42,
.PABITS = 49,
.insn_flags = CPU_MIPS64R2 | INSN_OCTEON | ASE_DSP,
.mmu_type = MMU_TYPE_R4000,
},
#endif
};

View File

@ -42,6 +42,7 @@
#define INSN_LOONGSON2E 0x0000040000000000ULL
#define INSN_LOONGSON2F 0x0000080000000000ULL
#define INSN_LOONGSON3A 0x0000100000000000ULL
#define INSN_OCTEON 0x0000200000000000ULL
/*
* bits 52-63: vendor-specific ASEs
*/

View File

@ -3,6 +3,7 @@ gen = [
decodetree.process('msa.decode', extra_args: '--decode=decode_ase_msa'),
decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'),
decodetree.process('vr54xx.decode', extra_args: '--decode=decode_ext_vr54xx'),
decodetree.process('octeon.decode', extra_args: '--decode=decode_ext_octeon'),
]
mips_ss.add(gen)
@ -24,6 +25,7 @@ mips_ss.add(files(
))
mips_ss.add(when: 'TARGET_MIPS64', if_true: files(
'tx79_translate.c',
'octeon_translate.c',
), if_false: files(
'mxu_translate.c',
))

View File

@ -0,0 +1,41 @@
# Octeon Architecture Module instruction set
#
# Copyright (C) 2022 Pavel Dovgalyuk
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Branch on bit set or clear
# BBIT0 110010 ..... ..... ................
# BBIT032 110110 ..... ..... ................
# BBIT1 111010 ..... ..... ................
# BBIT132 111110 ..... ..... ................
%bbit_p 28:1 16:5
BBIT 11 set:1 . 10 rs:5 ..... offset:16 p=%bbit_p
# Arithmetic
# BADDU rd, rs, rt
# DMUL rd, rs, rt
# EXTS rt, rs, p, lenm1
# EXTS32 rt, rs, p, lenm1
# CINS rt, rs, p, lenm1
# CINS32 rt, rs, p, lenm1
# DPOP rd, rs
# POP rd, rs
# SEQ rd, rs, rt
# SEQI rt, rs, immediate
# SNE rd, rs, rt
# SNEI rt, rs, immediate
@r3 ...... rs:5 rt:5 rd:5 ..... ......
%bitfield_p 0:1 6:5
@bitfield ...... rs:5 rt:5 lenm1:5 ..... ..... . p=%bitfield_p
BADDU 011100 ..... ..... ..... 00000 101000 @r3
DMUL 011100 ..... ..... ..... 00000 000011 @r3
EXTS 011100 ..... ..... ..... ..... 11101 . @bitfield
CINS 011100 ..... ..... ..... ..... 11001 . @bitfield
POP 011100 rs:5 00000 rd:5 00000 10110 dw:1
SEQNE 011100 rs:5 rt:5 rd:5 00000 10101 ne:1
SEQNEI 011100 rs:5 rt:5 imm:s10 10111 ne:1

View File

@ -0,0 +1,201 @@
/*
* Octeon-specific instructions translation routines
*
* Copyright (c) 2022 Pavel Dovgalyuk
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "exec/helper-gen.h"
#include "translate.h"
/* Include the auto-generated decoder. */
#include "decode-octeon.c.inc"
static bool trans_BBIT(DisasContext *ctx, arg_BBIT *a)
{
TCGv p;
if (ctx->hflags & MIPS_HFLAG_BMASK) {
LOG_DISAS("Branch in delay / forbidden slot at PC 0x"
TARGET_FMT_lx "\n", ctx->base.pc_next);
generate_exception_end(ctx, EXCP_RI);
return true;
}
/* Load needed operands */
TCGv t0 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
p = tcg_constant_tl(1ULL << a->p);
if (a->set) {
tcg_gen_and_tl(bcond, p, t0);
} else {
tcg_gen_andc_tl(bcond, p, t0);
}
ctx->hflags |= MIPS_HFLAG_BC;
ctx->btarget = ctx->base.pc_next + 4 + a->offset * 4;
ctx->hflags |= MIPS_HFLAG_BDS32;
tcg_temp_free(t0);
return true;
}
static bool trans_BADDU(DisasContext *ctx, arg_BADDU *a)
{
TCGv t0, t1;
if (a->rt == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
t1 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
gen_load_gpr(t1, a->rt);
tcg_gen_add_tl(t0, t0, t1);
tcg_gen_andi_i64(cpu_gpr[a->rd], t0, 0xff);
tcg_temp_free(t0);
tcg_temp_free(t1);
return true;
}
static bool trans_DMUL(DisasContext *ctx, arg_DMUL *a)
{
TCGv t0, t1;
if (a->rt == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
t1 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
gen_load_gpr(t1, a->rt);
tcg_gen_mul_i64(cpu_gpr[a->rd], t0, t1);
tcg_temp_free(t0);
tcg_temp_free(t1);
return true;
}
static bool trans_EXTS(DisasContext *ctx, arg_EXTS *a)
{
TCGv t0;
if (a->rt == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
tcg_gen_sextract_tl(t0, t0, a->p, a->lenm1 + 1);
gen_store_gpr(t0, a->rt);
tcg_temp_free(t0);
return true;
}
static bool trans_CINS(DisasContext *ctx, arg_CINS *a)
{
TCGv t0;
if (a->rt == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
tcg_gen_deposit_z_tl(t0, t0, a->p, a->lenm1 + 1);
gen_store_gpr(t0, a->rt);
tcg_temp_free(t0);
return true;
}
static bool trans_POP(DisasContext *ctx, arg_POP *a)
{
TCGv t0;
if (a->rd == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
if (!a->dw) {
tcg_gen_andi_i64(t0, t0, 0xffffffff);
}
tcg_gen_ctpop_tl(t0, t0);
gen_store_gpr(t0, a->rd);
tcg_temp_free(t0);
return true;
}
static bool trans_SEQNE(DisasContext *ctx, arg_SEQNE *a)
{
TCGv t0, t1;
if (a->rd == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
t1 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
gen_load_gpr(t1, a->rt);
if (a->ne) {
tcg_gen_setcond_tl(TCG_COND_NE, cpu_gpr[a->rd], t1, t0);
} else {
tcg_gen_setcond_tl(TCG_COND_EQ, cpu_gpr[a->rd], t1, t0);
}
tcg_temp_free(t0);
tcg_temp_free(t1);
return true;
}
static bool trans_SEQNEI(DisasContext *ctx, arg_SEQNEI *a)
{
TCGv t0;
if (a->rt == 0) {
/* nop */
return true;
}
t0 = tcg_temp_new();
gen_load_gpr(t0, a->rs);
/* Sign-extend to 64 bit value */
target_ulong imm = a->imm;
if (a->ne) {
tcg_gen_setcondi_tl(TCG_COND_NE, cpu_gpr[a->rt], t0, imm);
} else {
tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], t0, imm);
}
tcg_temp_free(t0);
return true;
}

View File

@ -20,9 +20,11 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/log.h"
#include "exec/gdbstub.h"
#include "semihosting/softmmu-uaccess.h"
#include "semihosting/semihost.h"
#include "semihosting/console.h"
#include "semihosting/syscalls.h"
#include "internal.h"
typedef enum UHIOp {
@ -114,268 +116,241 @@ enum UHIErrno {
UHI_EXDEV = 18,
};
static int errno_mips(int host_errno)
static void report_fault(CPUMIPSState *env)
{
/* Errno values taken from asm-mips/errno.h */
switch (host_errno) {
case 0: return 0;
case ENAMETOOLONG: return 78;
#ifdef EOVERFLOW
case EOVERFLOW: return 79;
#endif
#ifdef ELOOP
case ELOOP: return 90;
#endif
default: return EINVAL;
}
int op = env->active_tc.gpr[25];
error_report("Fault during UHI operation %d", op);
abort();
}
static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
target_ulong vaddr)
static void uhi_cb(CPUState *cs, uint64_t ret, int err)
{
hwaddr len = sizeof(struct UHIStat);
UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
if (!dst) {
errno = EFAULT;
return -1;
CPUMIPSState *env = cs->env_ptr;
#define E(N) case E##N: err = UHI_E##N; break
switch (err) {
case 0:
break;
E(PERM);
E(NOENT);
E(INTR);
E(BADF);
E(BUSY);
E(EXIST);
E(NOTDIR);
E(ISDIR);
E(INVAL);
E(NFILE);
E(MFILE);
E(FBIG);
E(NOSPC);
E(SPIPE);
E(ROFS);
E(NAMETOOLONG);
default:
err = UHI_EINVAL;
break;
case EFAULT:
report_fault(env);
}
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;
#undef E
env->active_tc.gpr[2] = ret;
env->active_tc.gpr[3] = err;
}
static int get_open_flags(target_ulong target_flags)
static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err)
{
int open_flags = 0;
QEMU_BUILD_BUG_ON(sizeof(UHIStat) < sizeof(struct gdb_stat));
if (target_flags & UHIOpen_RDWR) {
open_flags |= O_RDWR;
} else if (target_flags & UHIOpen_WRONLY) {
open_flags |= O_WRONLY;
} else {
open_flags |= O_RDONLY;
if (!err) {
CPUMIPSState *env = cs->env_ptr;
target_ulong addr = env->active_tc.gpr[5];
UHIStat *dst = lock_user(VERIFY_WRITE, addr, sizeof(UHIStat), 1);
struct gdb_stat s;
if (!dst) {
report_fault(env);
}
memcpy(&s, dst, sizeof(struct gdb_stat));
memset(dst, 0, sizeof(UHIStat));
dst->uhi_st_dev = tswap16(be32_to_cpu(s.gdb_st_dev));
dst->uhi_st_ino = tswap16(be32_to_cpu(s.gdb_st_ino));
dst->uhi_st_mode = tswap32(be32_to_cpu(s.gdb_st_mode));
dst->uhi_st_nlink = tswap16(be32_to_cpu(s.gdb_st_nlink));
dst->uhi_st_uid = tswap16(be32_to_cpu(s.gdb_st_uid));
dst->uhi_st_gid = tswap16(be32_to_cpu(s.gdb_st_gid));
dst->uhi_st_rdev = tswap16(be32_to_cpu(s.gdb_st_rdev));
dst->uhi_st_size = tswap64(be64_to_cpu(s.gdb_st_size));
dst->uhi_st_atime = tswap64(be32_to_cpu(s.gdb_st_atime));
dst->uhi_st_mtime = tswap64(be32_to_cpu(s.gdb_st_mtime));
dst->uhi_st_ctime = tswap64(be32_to_cpu(s.gdb_st_ctime));
dst->uhi_st_blksize = tswap64(be64_to_cpu(s.gdb_st_blksize));
dst->uhi_st_blocks = tswap64(be64_to_cpu(s.gdb_st_blocks));
unlock_user(dst, addr, sizeof(UHIStat));
}
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;
uhi_cb(cs, ret, err);
}
static int write_to_file(CPUMIPSState *env, target_ulong fd,
target_ulong vaddr, target_ulong len)
{
int num_of_bytes;
void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
if (!dst) {
errno = EFAULT;
return -1;
}
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)
{
int num_of_bytes;
void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
if (!dst) {
errno = EFAULT;
return -1;
}
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; \
return; \
} \
} while (0)
#define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \
do { \
p = lock_user_string(addr); \
if (!p) { \
gpr[2] = -1; \
gpr[3] = EFAULT; \
return; \
} \
p2 = lock_user_string(addr2); \
if (!p2) { \
unlock_user(p, addr, 0); \
gpr[2] = -1; \
gpr[3] = EFAULT; \
return; \
} \
} while (0)
#define FREE_TARGET_STRING(p, gpr) \
do { \
unlock_user(p, gpr, 0); \
} while (0)
void mips_semihosting(CPUMIPSState *env)
{
CPUState *cs = env_cpu(env);
target_ulong *gpr = env->active_tc.gpr;
const UHIOp op = gpr[25];
char *p, *p2;
char *p;
switch (op) {
case UHI_exit:
qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
gdb_exit(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_mips(errno);
{
target_ulong fname = gpr[4];
int ret = -1;
p = lock_user_string(fname);
if (!p) {
report_fault(env);
}
if (!strcmp("/dev/stdin", p)) {
ret = 0;
} else if (!strcmp("/dev/stdout", p)) {
ret = 1;
} else if (!strcmp("/dev/stderr", p)) {
ret = 2;
}
unlock_user(p, fname, 0);
/* FIXME: reusing a guest fd doesn't seem correct. */
if (ret >= 0) {
gpr[2] = ret;
break;
}
semihost_sys_open(cs, uhi_cb, fname, 0, gpr[5], gpr[6]);
}
FREE_TARGET_STRING(p, gpr[4]);
break;
case UHI_close:
if (gpr[4] < 3) {
/* ignore closing stdin/stdout/stderr */
gpr[2] = 0;
return;
}
gpr[2] = close(gpr[4]);
gpr[3] = errno_mips(errno);
semihost_sys_close(cs, uhi_cb, gpr[4]);
break;
case UHI_read:
gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6]);
gpr[3] = errno_mips(errno);
semihost_sys_read(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
break;
case UHI_write:
gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6]);
gpr[3] = errno_mips(errno);
semihost_sys_write(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
break;
case UHI_lseek:
gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
gpr[3] = errno_mips(errno);
semihost_sys_lseek(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
break;
case UHI_unlink:
GET_TARGET_STRING(p, gpr[4]);
gpr[2] = remove(p);
gpr[3] = errno_mips(errno);
FREE_TARGET_STRING(p, gpr[4]);
semihost_sys_remove(cs, uhi_cb, gpr[4], 0);
break;
case UHI_fstat:
{
struct stat sbuf;
memset(&sbuf, 0, sizeof(sbuf));
gpr[2] = fstat(gpr[4], &sbuf);
gpr[3] = errno_mips(errno);
if (gpr[2]) {
return;
}
gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
gpr[3] = errno_mips(errno);
}
semihost_sys_fstat(cs, uhi_fstat_cb, gpr[4], gpr[5]);
break;
case UHI_argc:
gpr[2] = semihosting_get_argc();
break;
case UHI_argnlen:
if (gpr[4] >= semihosting_get_argc()) {
gpr[2] = -1;
return;
{
const char *s = semihosting_get_arg(gpr[4]);
gpr[2] = s ? strlen(s) : -1;
}
gpr[2] = strlen(semihosting_get_arg(gpr[4]));
break;
case UHI_argn:
if (gpr[4] >= semihosting_get_argc()) {
gpr[2] = -1;
return;
{
const char *s = semihosting_get_arg(gpr[4]);
target_ulong addr;
size_t len;
if (!s) {
gpr[2] = -1;
break;
}
len = strlen(s) + 1;
addr = gpr[5];
p = lock_user(VERIFY_WRITE, addr, len, 0);
if (!p) {
report_fault(env);
}
memcpy(p, s, len);
unlock_user(p, addr, len);
gpr[2] = 0;
}
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;
GString *s = g_string_new_len(p, char_num);
g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
gpr[2] = qemu_semihosting_log_out(s->str, s->len);
g_string_free(s, true);
} else {
gpr[2] = qemu_semihosting_log_out(p, strlen(p));
{
target_ulong addr = gpr[4];
ssize_t len = target_strlen(addr);
GString *str;
char *pct_d;
if (len < 0) {
report_fault(env);
}
p = lock_user(VERIFY_READ, addr, len, 1);
if (!p) {
report_fault(env);
}
pct_d = strstr(p, "%d");
if (!pct_d) {
unlock_user(p, addr, 0);
semihost_sys_write(cs, uhi_cb, 2, addr, len);
break;
}
str = g_string_new_len(p, pct_d - p);
g_string_append_printf(str, "%d%s", (int)gpr[5], pct_d + 2);
unlock_user(p, addr, 0);
/*
* When we're using gdb, we need a guest address, so
* drop the string onto the stack below the stack pointer.
*/
if (use_gdb_syscalls()) {
addr = gpr[29] - str->len;
p = lock_user(VERIFY_WRITE, addr, str->len, 0);
memcpy(p, str->str, str->len);
unlock_user(p, addr, str->len);
semihost_sys_write(cs, uhi_cb, 2, addr, str->len);
} else {
gpr[2] = qemu_semihosting_console_write(str->str, str->len);
}
g_string_free(str, true);
}
FREE_TARGET_STRING(p, gpr[4]);
break;
case UHI_assert:
GET_TARGET_STRINGS_2(p, gpr[4], 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;
#ifndef _WIN32
case UHI_link:
GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
gpr[2] = link(p, p2);
gpr[3] = errno_mips(errno);
FREE_TARGET_STRING(p2, gpr[5]);
FREE_TARGET_STRING(p, gpr[4]);
break;
#endif
{
const char *msg, *file;
msg = lock_user_string(gpr[4]);
if (!msg) {
msg = "<EFAULT>";
}
file = lock_user_string(gpr[5]);
if (!file) {
file = "<EFAULT>";
}
error_report("UHI assertion \"%s\": file \"%s\", line %d",
msg, file, (int)gpr[6]);
abort();
}
default:
fprintf(stderr, "Unknown UHI operation %d\n", op);
error_report("Unknown UHI operation %d", op);
abort();
}
return;

View File

@ -15955,6 +15955,11 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
if (cpu_supports_isa(env, INSN_VR54XX) && decode_ext_vr54xx(ctx, ctx->opcode)) {
return;
}
#if defined(TARGET_MIPS64)
if (cpu_supports_isa(env, INSN_OCTEON) && decode_ext_octeon(ctx, ctx->opcode)) {
return;
}
#endif
/* ISA extensions */
if (ase_msa_available(env) && decode_ase_msa(ctx, ctx->opcode)) {

View File

@ -215,6 +215,7 @@ bool decode_ase_msa(DisasContext *ctx, uint32_t insn);
bool decode_ext_txx9(DisasContext *ctx, uint32_t insn);
#if defined(TARGET_MIPS64)
bool decode_ext_tx79(DisasContext *ctx, uint32_t insn);
bool decode_ext_octeon(DisasContext *ctx, uint32_t insn);
#endif
bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn);