Re: Funny results with long double denorms on m68k

2023-08-21 Thread Keith Packard via

> When I developped the FPU emulation I compared the result of QEMU and a real 
> hardware using 
> https://github.com/vivier/m68k-testfloat and 
> https://github.com/vivier/m68k-softfloat

It looks like the second of those has similar issues with m68k denorms?

https://github.com/vivier/m68k-softfloat/blob/6ecdd5c9627d02c7502de4acaf54c5c5b0a43bdf/softfloat/bits64/softfloat.c#L640

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH] softfloat: Handle m68k extended precision denormals properly

2023-08-20 Thread Keith Packard via

> That does look like a correct change.  I'll fold it in.
> Please let us know if you encounter anything else.

Thanks so much. With these fixes, all of my long double math library
tests in picolibc are passing now (once I fixed a bunch of additional
m68k-denorm related math library bugs). That includes the fmal tests I
mentioned, which check all four rounding modes across a fairly extensive
set of inputs.

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH] softfloat: Handle m68k extended precision denormals properly

2023-08-20 Thread Keith Packard via

> Motorola treats denormals with explicit integer bit set as
> having unbiased exponent 0, unlike Intel which treats it as
> having unbiased exponent 1 (like all other IEEE formats).

Thanks for having a look at this. Your patch fixes a couple of cases,
but there are further adventures that await if you're interested.

   x:  0x1p0  0x3fff 0x8000 0x
   y:  0x1p-16383 0x 0x8000 0x
   build_mul:  0x1p-16382 0x 0x8000 0x
 runtime_mul:  0x1p-16383 0x0001 0x8000 0x

I think the enclosed additional patch fixes this. I've still got 75 fmal
failures on this target, but the obvious 'multiply is broken' problem
appears fixed.

From b722c92f8329f56f5243496eca3779f1156aff4f Mon Sep 17 00:00:00 2001
From: Keith Packard 
Date: Sun, 20 Aug 2023 18:20:13 -0700
Subject: [PATCH] softfloat: Handle m68k LDBL_MIN_EXP normal values

Unlike Intel 80-bit floats, Motorola allows for normal values with a
zero exponent. Handle that by not setting exponent to 1 when the value
is normal for this format.

Signed-off-by: Keith Packard 
---
 fpu/softfloat-parts.c.inc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index d0c43c28fb..cea854cdf1 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -288,7 +288,7 @@ static void partsN(uncanon_normal)(FloatPartsN *p, 
float_status *s,
 p->frac_lo &= ~round_mask;
 }
 
-exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0;
+exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0 && 
!fmt->m68k_denormal;
 frac_shr(p, frac_shift);
 
 if (is_tiny && (flags & float_flag_inexact)) {
-- 
2.40.1

-- 
-keith


signature.asc
Description: PGP signature


Funny results with long double denorms on m68k

2023-08-20 Thread Keith Packard via

I'm doing some testing of an fmal implementation and discovered some
"odd" results on m68k where the emulated 80-bit FPU is generating
results that don't match how GCC computes things. Assuming gcc is
correct, this means there are some subtle bugs in how qemu is handling
denorms for this platform.

From what I can discern from examining gcc output, the 68881 80-bit
format handles denorms differently than the 8087. It allows normal
numbers to have an exponent field of zero -- with an explicit 1
bit. Furthermore, denorms don't have their exponent biased by 1, the
natural 0 value is correct.

As a simple example of this issue, I've attached a sample program which
multiplies the smallest denorm (__LDBL_DENORM_MIN__, or 0x1p-16446l) by
the largest value (__LDBL_MAX__, or 0x1p+16383l). This should be
0x1p-63, but qemu computes this as 0x1p-62. In raw form:

   x:  0x1p+16383 0x7ffe 0x8000 0x
   y:  0x1p-16446 0x 0x 0x0001
   build_mul:  0x1p-630x3fc0 0x8000 0x
 runtime_mul:  0x1p-620x3fc1 0x8000 0x

Looking just at the exponents, we see that the runtime computed value
has an exponent of 0x3fc1. Subtracting the bias of 0x3fff, we get -62.

This particular fault comes from converting the denorm into canonical
form in fpu/softfloat-parts.c.inc:partsN(canonicalize):

} else {
int shift = frac_normalize(p);
p->cls = float_class_normal;
p->exp = fmt->frac_shift - fmt->exp_bias - shift + 1;
}

the extra '1' added there is the exponent bias required for standard
denorm format values.

This is only one of a number of related faults; there are similar issues
when converting back from canonical form to 68881 form. As that involves
complicated rounding semantics, it's a lot more difficult to figure out
how to fix it. For instance:

   x:  0x1.1p-82230x1fe0 0x8800 0x
   y:  0x1.1p-82240x1fdf 0x8800 0x
   build_mul:  0x1p-16446 0x 0x 0x0001
 runtime_mul:  0x0p+0 0x 0x 0x

In this case, the multiplication results in a value just larger than 1/2
of the smallest denorm. That should round up to the smallest denorm, but
qemu generates zero instead.

-

#include 
#include 

#define X   0x1p+16383l
#define Y   0x1p-16446l

static long double build_mul = X * Y;
static volatile long double x = X;
static volatile long double y = Y;

static void
dump_ld(const char *label, long double ld)
{
union {
long double d;
struct {
uint32_texp:16;
uint32_tspace:16;
uint32_th;
uint32_tl;
};
} u;

u.d = ld;
printf("%12s: % -27La 0x%04x 0x%08x 0x%08x\n", label, u.d, u.exp, u.h, u.l);
}

int main(void)
{
long double runtime_mul = x * y;

dump_ld("x", x);
dump_ld("y", y);
dump_ld("build_mul", build_mul);
dump_ld("runtime_mul", runtime_mul);
return 0;
}

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] target/m68k: Map FPU exceptions to FPSR register

2023-08-02 Thread Keith Packard via
Add helpers for reading/writing the 68881 FPSR register so that
changes in floating point exception state can be seen by the
application.

Call these helpers in pre_load/post_load hooks to synchronize
exception state.

Signed-off-by: Keith Packard 
---
 target/m68k/cpu.c| 12 +++
 target/m68k/cpu.h|  2 ++
 target/m68k/fpu_helper.c | 72 
 target/m68k/helper.c |  4 +--
 target/m68k/helper.h |  2 ++
 target/m68k/translate.c  |  4 +--
 6 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 70d58471dc..a0e9b723a5 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -404,12 +404,23 @@ static const VMStateDescription vmstate_freg = {
 }
 };
 
+static int fpu_pre_load(void *opaque)
+{
+M68kCPU *s = opaque;
+
+s->env.fpsr = cpu_m68k_get_fpsr(>env);
+
+return 0;
+}
+
 static int fpu_post_load(void *opaque, int version)
 {
 M68kCPU *s = opaque;
 
 cpu_m68k_restore_fp_status(>env);
 
+cpu_m68k_set_fpsr(>env, s->env.fpsr);
+
 return 0;
 }
 
@@ -418,6 +429,7 @@ const VMStateDescription vmmstate_fpu = {
 .version_id = 1,
 .minimum_version_id = 1,
 .needed = fpu_needed,
+.pre_load = fpu_pre_load,
 .post_load = fpu_post_load,
 .fields = (VMStateField[]) {
 VMSTATE_UINT32(env.fpcr, M68kCPU),
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index b741c50a8f..1e491fda77 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -173,6 +173,8 @@ struct ArchCPU {
 CPUM68KState env;
 };
 
+uint32_t cpu_m68k_get_fpsr(CPUM68KState *env);
+void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val);
 
 #ifndef CONFIG_USER_ONLY
 void m68k_cpu_do_interrupt(CPUState *cpu);
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index ab120b5f59..8314791f50 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -164,6 +164,78 @@ void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val)
 cpu_m68k_set_fpcr(env, val);
 }
 
+/* Convert host exception flags to cpu_m68k form.  */
+static int cpu_m68k_exceptbits_from_host(int host_bits)
+{
+int target_bits = 0;
+
+if (host_bits & float_flag_invalid) {
+target_bits |= 0x80;
+}
+if (host_bits & float_flag_overflow) {
+target_bits |= 0x40;
+}
+if (host_bits & (float_flag_underflow | float_flag_output_denormal)) {
+target_bits |= 0x20;
+}
+if (host_bits & float_flag_divbyzero) {
+target_bits |= 0x10;
+}
+if (host_bits & float_flag_inexact) {
+target_bits |= 0x08;
+}
+return target_bits;
+}
+
+/* Convert cpu_m68k exception flags to target form.  */
+static int cpu_m68k_exceptbits_to_host(int target_bits)
+{
+int host_bits = 0;
+
+if (target_bits & 0x80) {
+host_bits |= float_flag_invalid;
+}
+if (target_bits & 0x40) {
+host_bits |= float_flag_overflow;
+}
+if (target_bits & 0x20) {
+host_bits |= float_flag_underflow;
+}
+if (target_bits & 0x10) {
+host_bits |= float_flag_divbyzero;
+}
+if (target_bits & 0x08) {
+host_bits |= float_flag_inexact;
+}
+return host_bits;
+}
+
+uint32_t cpu_m68k_get_fpsr(CPUM68KState *env)
+{
+int host_flags = get_float_exception_flags(>fp_status);
+int target_flags = cpu_m68k_exceptbits_from_host(host_flags);
+int except = (env->fpsr & ~(0xf8)) | target_flags;
+return except;
+}
+
+uint32_t HELPER(get_fpsr)(CPUM68KState *env)
+{
+return cpu_m68k_get_fpsr(env);
+}
+
+void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val)
+{
+env->fpsr = val;
+
+int host_flags = cpu_m68k_exceptbits_to_host((int) env->fpsr);
+set_float_exception_flags(host_flags, >fp_status);
+}
+
+void HELPER(set_fpsr)(CPUM68KState *env, uint32_t val)
+{
+cpu_m68k_set_fpsr(env, val);
+}
+
 #define PREC_BEGIN(prec)\
 do {\
 FloatX80RoundPrec old = \
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 0a1544cd68..beab4b96bc 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -118,7 +118,7 @@ static int m68k_fpu_gdb_get_reg(CPUM68KState *env, 
GByteArray *mem_buf, int n)
 case 8: /* fpcontrol */
 return gdb_get_reg32(mem_buf, env->fpcr);
 case 9: /* fpstatus */
-return gdb_get_reg32(mem_buf, env->fpsr);
+return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env));
 case 10: /* fpiar, not implemented */
 return gdb_get_reg32(mem_buf, 0);
 }
@@ -137,7 +137,7 @@ static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t 
*mem_buf, int n)
 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
 return 4;
 case 9: /* fpstatus */
-env->fpsr = ldl_p(mem_buf);
+cpu_m68k_set_fpsr(env, ldl_p(mem_buf));
 return 4;
 case 10: /* fpiar, not implemented */
 

Re: [PATCH] target/m68k: Map FPU exceptions to FPSR register

2023-08-02 Thread Keith Packard via

> Good catch.  Mostly ok.

Thanks much for looking at this.

> No need for inline markers.

Thanks.

> In general it is bad form to call HELPER(foo) directly.  In this case
> it doesn't hurt, but better form to reverse the implementations.

Good point. I had copied this from the arm vfp code which flipped the
order. I've flipped those around.

> What's missing is an update to vmstate, to make sure all the architectural 
> bits are 
> properly saved. Add

Yup, thanks. I've sent another version of the patch along.

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] target/m68k: Map FPU exceptions to FPSR register

2023-08-02 Thread Keith Packard via
Add helpers for reading/writing the 68881 FPSR register so that
changes in floating point exception state can be seen by the
application.

Signed-off-by: Keith Packard 
---
 target/m68k/cpu.h|  2 ++
 target/m68k/fpu_helper.c | 72 
 target/m68k/helper.c |  4 +--
 target/m68k/helper.h |  2 ++
 target/m68k/translate.c  |  4 +--
 5 files changed, 80 insertions(+), 4 deletions(-)

diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index b741c50a8f..1e491fda77 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -173,6 +173,8 @@ struct ArchCPU {
 CPUM68KState env;
 };
 
+uint32_t cpu_m68k_get_fpsr(CPUM68KState *env);
+void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val);
 
 #ifndef CONFIG_USER_ONLY
 void m68k_cpu_do_interrupt(CPUState *cpu);
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index ab120b5f59..542ce1790a 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -164,6 +164,78 @@ void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val)
 cpu_m68k_set_fpcr(env, val);
 }
 
+/* Convert host exception flags to cpu_m68k form.  */
+static inline int cpu_m68k_exceptbits_from_host(int host_bits)
+{
+int target_bits = 0;
+
+if (host_bits & float_flag_invalid) {
+target_bits |= 0x80;
+}
+if (host_bits & float_flag_overflow) {
+target_bits |= 0x40;
+}
+if (host_bits & (float_flag_underflow | float_flag_output_denormal)) {
+target_bits |= 0x20;
+}
+if (host_bits & float_flag_divbyzero) {
+target_bits |= 0x10;
+}
+if (host_bits & float_flag_inexact) {
+target_bits |= 0x08;
+}
+return target_bits;
+}
+
+/* Convert cpu_m68k exception flags to target form.  */
+static inline int cpu_m68k_exceptbits_to_host(int target_bits)
+{
+int host_bits = 0;
+
+if (target_bits & 0x80) {
+host_bits |= float_flag_invalid;
+}
+if (target_bits & 0x40) {
+host_bits |= float_flag_overflow;
+}
+if (target_bits & 0x20) {
+host_bits |= float_flag_underflow;
+}
+if (target_bits & 0x10) {
+host_bits |= float_flag_divbyzero;
+}
+if (target_bits & 0x08) {
+host_bits |= float_flag_inexact;
+}
+return host_bits;
+}
+
+uint32_t HELPER(get_fpsr)(CPUM68KState *env)
+{
+int host_flags = get_float_exception_flags(>fp_status);
+int target_flags = cpu_m68k_exceptbits_from_host(host_flags);
+int except = (env->fpsr & ~(0xf8)) | target_flags;
+return except;
+}
+
+uint32_t cpu_m68k_get_fpsr(CPUM68KState *env)
+{
+return HELPER(get_fpsr)(env);
+}
+
+void HELPER(set_fpsr)(CPUM68KState *env, uint32_t val)
+{
+env->fpsr = val;
+
+int host_flags = cpu_m68k_exceptbits_to_host((int) env->fpsr);
+set_float_exception_flags(host_flags, >fp_status);
+}
+
+void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val)
+{
+return HELPER(set_fpsr)(env, val);
+}
+
 #define PREC_BEGIN(prec)\
 do {\
 FloatX80RoundPrec old = \
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 0a1544cd68..beab4b96bc 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -118,7 +118,7 @@ static int m68k_fpu_gdb_get_reg(CPUM68KState *env, 
GByteArray *mem_buf, int n)
 case 8: /* fpcontrol */
 return gdb_get_reg32(mem_buf, env->fpcr);
 case 9: /* fpstatus */
-return gdb_get_reg32(mem_buf, env->fpsr);
+return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env));
 case 10: /* fpiar, not implemented */
 return gdb_get_reg32(mem_buf, 0);
 }
@@ -137,7 +137,7 @@ static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t 
*mem_buf, int n)
 cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
 return 4;
 case 9: /* fpstatus */
-env->fpsr = ldl_p(mem_buf);
+cpu_m68k_set_fpsr(env, ldl_p(mem_buf));
 return 4;
 case 10: /* fpiar, not implemented */
 return 4;
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 2bbe0dc032..95aa5e53bb 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -54,6 +54,8 @@ DEF_HELPER_4(fsdiv, void, env, fp, fp, fp)
 DEF_HELPER_4(fddiv, void, env, fp, fp, fp)
 DEF_HELPER_4(fsgldiv, void, env, fp, fp, fp)
 DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp)
+DEF_HELPER_2(set_fpsr, void, env, i32)
+DEF_HELPER_1(get_fpsr, i32, env)
 DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32)
 DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp)
 DEF_HELPER_3(fconst, void, env, fp, i32)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index d037c57453..360d054162 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4718,7 +4718,7 @@ static void gen_load_fcr(DisasContext *s, TCGv res, int 
reg)
 tcg_gen_movi_i32(res, 0);
 break;
 case M68K_FPSR:
-  

[PATCH 0/3] target/m68k: Fix a few semihosting bugs

2023-08-02 Thread Keith Packard via
The first two patches mirror similar patches I recently sent for nios2.

 1. Use correct parameter for EXIT (d1 instead of d0)
 2. Fix use of deposit64 in LSEEK (argument order was incorrect)

The second patch has also been submitted by Peter Maydell, it's
included here because it was required to get things working.

The final patch adds semihosting support for non-ColdFire processors
(which don't support the HALT instruction) by using BKPT #0 instead
(as per the m68k semihosting docs).

All of these have been tested using picolibc (patches for m68k support
there are moving upstream as well).





[PATCH 1/3] target/m68k: Pass semihosting arg to exit

2023-08-02 Thread Keith Packard via
Instead of using d0 (the semihost function number), use d1 (the
provide exit status).

Signed-off-by: Keith Packard 
---
 target/m68k/m68k-semi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 88ad9ba814..12235759c7 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -130,8 +130,8 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
 args = env->dregs[1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->dregs[0]);
-exit(env->dregs[0]);
+gdb_exit(env->dregs[1]);
+exit(env->dregs[1]);
 
 case HOSTED_OPEN:
 GET_ARG(0);
-- 
2.40.1




[PATCH 3/3] target/m68k: Support semihosting on non-ColdFire targets

2023-08-02 Thread Keith Packard via
According to the m68k semihosting spec:

"The instruction used to trigger a semihosting request depends on the
 m68k processor variant.  On ColdFire, "halt" is used; on other processors
 (which don't implement "halt"), "bkpt #0" may be used."

Add support for non-CodeFire processors by matching BKPT #0
instructions. When semihosting is disabled, convert those
back to illegal op exceptions.

Signed-off-by: Keith Packard 
---
 target/m68k/cpu.h   |  1 +
 target/m68k/op_helper.c | 16 
 target/m68k/translate.c |  4 
 3 files changed, 21 insertions(+)

diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index cf70282717..b741c50a8f 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -67,6 +67,7 @@
 
 #define EXCP_RTE0x100
 #define EXCP_HALT_INSN  0x101
+#define EXCP_BKPT_INSN  0x102
 
 #define M68K_DTTR0   0
 #define M68K_DTTR1   1
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 1ce850bbc5..2d89db6dde 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -295,6 +295,22 @@ static void m68k_interrupt_all(CPUM68KState *env, int 
is_hw)
 /* Return from an exception.  */
 m68k_rte(env);
 return;
+case EXCP_BKPT_INSN:
+if (semihosting_enabled((env->sr & SR_S) == 0)
+&& (env->pc & 3) == 0
+&& cpu_lduw_code(env, env->pc - 4) == 0x4e71
+&& cpu_ldl_code(env, env->pc) == 0x4e7bf000) {
+env->pc += 4;
+do_m68k_semihosting(env, env->dregs[0]);
+return;
+}
+/*
+ * When semihosting is not enabled, translate this back to
+ * an illegal op exception.
+ */
+cs->exception_index = EXCP_ILLEGAL;
+env->pc += 2;
+break;
 }
 }
 
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index e07161d76f..d037c57453 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -2640,6 +2640,10 @@ DISAS_INSN(bkpt)
 #if defined(CONFIG_USER_ONLY)
 gen_exception(s, s->base.pc_next, EXCP_DEBUG);
 #else
+if ((insn & 7) == 0) {
+gen_exception(s, s->pc, EXCP_BKPT_INSN);
+return;
+}
 gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
 #endif
 }
-- 
2.40.1




[PATCH 2/3] target/m68k: Fix semihost lseek offset computation

2023-08-02 Thread Keith Packard via
The arguments for deposit64 are (value, start, length, fieldval); this
appears to have thought they were (value, fieldval, start,
length). Reorder the parameters to match the actual function.

Signed-off-by: Keith Packard 
---
 target/m68k/m68k-semi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/m68k/m68k-semi.c b/target/m68k/m68k-semi.c
index 12235759c7..12179bde38 100644
--- a/target/m68k/m68k-semi.c
+++ b/target/m68k/m68k-semi.c
@@ -166,7 +166,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
 GET_ARG64(2);
 GET_ARG64(3);
 semihost_sys_lseek(cs, m68k_semi_u64_cb, arg0,
-   deposit64(arg2, arg1, 32, 32), arg3);
+   deposit64(arg2, 32, 32, arg1), arg3);
 break;
 
 case HOSTED_RENAME:
-- 
2.40.1




Re: [PATCH] target/nios2: Pass semihosting arg to exit

2023-08-01 Thread Keith Packard via

> Yeah, the closest to a "standard" we have for nios2 is that
> I asked the Codesourcery folks to document it in the libgloss
> sources and put the URL to it in a comment at the top of
> nios2-semi.c, given that there's no official spec and the
> original and main guest-side user is libgloss.
> m68k is in a similar position only without the URL
> in our source file :-)

Yeah, we had the same ask when getting risc-v semihosting merged. For
that, I actually pushed through an "official" risc-v standard. I kinda
wish I'd used the m68k model instead of the arm model as that provides
simple POSIX semantics...

https://github.com/riscv-software-src/riscv-semihosting/blob/main/riscv-semihosting-spec.adoc

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] target/nios2: Pass semihosting arg to exit

2023-08-01 Thread Keith Packard via
Instead of using R_ARG0 (the semihost function number), use R_ARG1
(the provided exit status).

Signed-off-by: Keith Packard 
---
 target/nios2/nios2-semi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index 3738774976..f3b7aee4f1 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -133,8 +133,8 @@ void do_nios2_semihosting(CPUNios2State *env)
 args = env->regs[R_ARG1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->regs[R_ARG0]);
-exit(env->regs[R_ARG0]);
+gdb_exit(env->regs[R_ARG1]);
+exit(env->regs[R_ARG1]);
 
 case HOSTED_OPEN:
 GET_ARG(0);
-- 
2.40.1




Re: [PATCH] target/nios2: Pass semihosting arg to exit

2023-08-01 Thread Keith Packard via

> says that for HOSTED_EXIT the exit code is in r5,
> not in a parameter block pointed to by r5. That
> would imply that the correct change is to use
> R_ARG1 rather than R_ARG0 here.

Ah, thanks -- I hadn't managed to find the actual standard yet. I'll
resubmit with that fixed.

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] target/nios2: Fix semihost lseek offset computation

2023-07-31 Thread Keith Packard via
The arguments for deposit64 are (value, start, length, fieldval); this
appears to have thought they were (value, fieldval, start,
length). Reorder the parameters to match the actual function.

Signed-off-by: Keith Packard 
---
 target/nios2/nios2-semi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index ffd1f095f6..fc1df1dfeb 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -170,7 +170,7 @@ void do_nios2_semihosting(CPUNios2State *env)
 GET_ARG64(2);
 GET_ARG64(3);
 semihost_sys_lseek(cs, nios2_semi_u64_cb, arg0,
-   deposit64(arg2, arg1, 32, 32), arg3);
+   deposit64(arg2, 32, 32, arg1), arg3);
 break;
 
 case HOSTED_RENAME:
-- 
2.40.1




[PATCH] target/nios2: Pass semihosting arg to exit

2023-07-31 Thread Keith Packard via
Instead of using the function number (which is always zero), fetch the
application-provided exit code argument and pass that to the two exit
functions.

Signed-off-by: Keith Packard 
---
 target/nios2/nios2-semi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index 3738774976..ffd1f095f6 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -133,8 +133,9 @@ void do_nios2_semihosting(CPUNios2State *env)
 args = env->regs[R_ARG1];
 switch (nr) {
 case HOSTED_EXIT:
-gdb_exit(env->regs[R_ARG0]);
-exit(env->regs[R_ARG0]);
+GET_ARG(0);
+gdb_exit(arg0);
+exit(arg0);
 
 case HOSTED_OPEN:
 GET_ARG(0);
-- 
2.40.1




[PATCH] semihosting: Write back semihosting data before completion callback

2022-10-11 Thread Keith Packard via
'lock_user' allocates a host buffer to shadow a target buffer,
'unlock_user' copies that host buffer back to the target and frees the
host memory. If the completion function uses the target buffer, it
must be called after unlock_user to ensure the data are present.

This caused the arm-compatible TARGET_SYS_READC to fail as the
completion function, common_semi_readc_cb, pulled data from the target
buffer which would not have been gotten the console data.

I decided to fix all instances of this pattern instead of just the
console_read function to make things consistent and potentially fix
bugs in other cases.

Signed-off-by: Keith Packard 
---
 semihosting/syscalls.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index 508a0ad88c..78ba97d7ab 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -321,11 +321,11 @@ static void host_read(CPUState *cs, 
gdb_syscall_complete_cb complete,
 ret = read(gf->hostfd, ptr, len);
 } while (ret == -1 && errno == EINTR);
 if (ret == -1) {
-complete(cs, -1, errno);
 unlock_user(ptr, buf, 0);
+complete(cs, -1, errno);
 } else {
-complete(cs, ret, 0);
 unlock_user(ptr, buf, ret);
+complete(cs, ret, 0);
 }
 }
 
@@ -341,8 +341,8 @@ static void host_write(CPUState *cs, 
gdb_syscall_complete_cb complete,
 return;
 }
 ret = write(gf->hostfd, ptr, len);
-complete(cs, ret, ret == -1 ? errno : 0);
 unlock_user(ptr, buf, 0);
+complete(cs, ret, ret == -1 ? errno : 0);
 }
 
 static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -428,8 +428,8 @@ static void host_stat(CPUState *cs, gdb_syscall_complete_cb 
complete,
 ret = -1;
 }
 }
-complete(cs, ret, err);
 unlock_user(name, fname, 0);
+complete(cs, ret, err);
 }
 
 static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -446,8 +446,8 @@ static void host_remove(CPUState *cs, 
gdb_syscall_complete_cb complete,
 }
 
 ret = remove(p);
-complete(cs, ret, ret ? errno : 0);
 unlock_user(p, fname, 0);
+complete(cs, ret, ret ? errno : 0);
 }
 
 static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -471,9 +471,9 @@ static void host_rename(CPUState *cs, 
gdb_syscall_complete_cb complete,
 }
 
 ret = rename(ostr, nstr);
-complete(cs, ret, ret ? errno : 0);
 unlock_user(ostr, oname, 0);
 unlock_user(nstr, nname, 0);
+complete(cs, ret, ret ? errno : 0);
 }
 
 static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -490,8 +490,8 @@ static void host_system(CPUState *cs, 
gdb_syscall_complete_cb complete,
 }
 
 ret = system(p);
-complete(cs, ret, ret == -1 ? errno : 0);
 unlock_user(p, cmd, 0);
+complete(cs, ret, ret == -1 ? errno : 0);
 }
 
 static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -556,8 +556,8 @@ static void staticfile_read(CPUState *cs, 
gdb_syscall_complete_cb complete,
 }
 memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len);
 gf->staticfile.off += len;
-complete(cs, len, 0);
 unlock_user(ptr, buf, len);
+complete(cs, len, 0);
 }
 
 static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -610,8 +610,8 @@ static void console_read(CPUState *cs, 
gdb_syscall_complete_cb complete,
 return;
 }
 ret = qemu_semihosting_console_read(cs, ptr, len);
-complete(cs, ret, 0);
 unlock_user(ptr, buf, ret);
+complete(cs, ret, 0);
 }
 
 static void console_write(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -626,8 +626,8 @@ static void console_write(CPUState *cs, 
gdb_syscall_complete_cb complete,
 return;
 }
 ret = qemu_semihosting_console_write(ptr, len);
-complete(cs, ret ? ret : -1, ret ? 0 : EIO);
 unlock_user(ptr, buf, 0);
+complete(cs, ret ? ret : -1, ret ? 0 : EIO);
 }
 
 static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
-- 
2.37.2




Re: [PATCH] tcg: Remove dh_alias indirection for dh_typecode

2022-02-17 Thread Keith Packard via
Richard Henderson  writes:

> Reported-by: Keith Packard 
> Signed-off-by: Richard Henderson 

Looks good to me, and it passes my very simple test when run on s390.

Tested-by: Keith Packard 

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH] tcg: Add 'signed' bit to typecodes

2022-02-16 Thread Keith Packard via
Richard Henderson  writes:

> The signed information is still there, merged with the typecode:
>
> #define dh_typecode_void 0
> #define dh_typecode_noreturn 0
> #define dh_typecode_i32 2
> #define dh_typecode_s32 3
> #define dh_typecode_i64 4
> #define dh_typecode_s64 5
> #define dh_typecode_ptr 6
>
> Note that is_signed is bit 0.
>
> But I can see that dh_alias_s32 hides it -- definitely a bug there.

Awesome. I suspected that was the underlying cause -- missing some of
what dh_alias does to the values.

As I said in the commit message, I looked at just filling out the
dh_typecode_ set to avoid using dh_alias entirely, but that actually
turned out to be a more complicated patch as you need to handle 'tl'
types, which are machine-specific; something dh_alias handles.

Either way works; I took the path which involved creating less new code
(as dh_is_signed was already written) to try and make it a bit easier to
evaluate the result.

Thanks for taking a look at the patch; I had a fine evening chasing this
down starting with a bug report written in an embedded python dialect :-)

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] tcg: Add 'signed' bit to typecodes

2022-02-16 Thread Keith Packard via
Commit 7319d83a (tcg: Combine dh_is_64bit and dh_is_signed to
dh_typecode) converted the tcg type system to a 3-bit field from two
separate 1-bit fields. This subtly lost the 'signed' information from
the types as it uses the dh_alias macro to reduce the types down to
basic machine types. However, the dh_alias macro also discards sign
information, aliasing 's32' to 'i32'.

I considered two solutions; switching away from using dh_alias and
expressing typecode values for all types or staying with dh_alias and
re-inserting the sign information. The latter approach turns out a bit
cleaner as it doesn't require dealing with machine-dependent types
like 'tl'.

I re-inserted the dh_is_signed macro with its values and 'or' in that
bit to the unsigned typecode.

This bug was detected when running the 'arm' emulator on an s390
system. The s390 uses TCG_TARGET_EXTEND_ARGS which triggers code
in tcg_gen_callN to extend 32 bit values to 64 bits; the incorrect
sign data in the typemask for each argument caused the values to be
extended as unsigned values.

This simple program exhibits the problem:

static volatile int num = -9;
static volatile int den = -5;

int
main(void)
{
int quo = num / den;
printf("num %d den %d quo %d\n", num, den, quo);
exit(0);
}

When run on the broken qemu, this results in:

num -9 den -5 quo 0

The correct result is:

num -9 den -5 quo 1

This issue was originally discovered when running snek on s390x under
qemu 6.2:

https://github.com/keith-packard/snek/issues/58

Signed-off-by: Keith Packard 
---
 include/exec/helper-head.h | 25 ++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h
index b974eb394a..eb1066f939 100644
--- a/include/exec/helper-head.h
+++ b/include/exec/helper-head.h
@@ -85,14 +85,33 @@
 #define dh_retvar_ptr tcgv_ptr_temp(retval)
 #define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
 
+#define dh_is_signed_void 0
+#define dh_is_signed_noreturn 0
+#define dh_is_signed_i32 0
+#define dh_is_signed_s32 1
+#define dh_is_signed_i64 0
+#define dh_is_signed_s64 1
+#define dh_is_signed_f16 0
+#define dh_is_signed_f32 0
+#define dh_is_signed_f64 0
+#define dh_is_signed_tl  0
+#define dh_is_signed_int 1
+/*
+ * ??? This is highly specific to the host cpu.  There are even special
+ * extension instructions that may be required, e.g. ia64's addp4.  But
+ * for now we don't support any 64-bit targets with 32-bit pointers.
+ */
+#define dh_is_signed_ptr 0
+#define dh_is_signed_cptr dh_is_signed_ptr
+#define dh_is_signed_env dh_is_signed_ptr
+#define dh_is_signed(t) dh_is_signed_##t
+
 #define dh_typecode_void 0
 #define dh_typecode_noreturn 0
 #define dh_typecode_i32 2
-#define dh_typecode_s32 3
 #define dh_typecode_i64 4
-#define dh_typecode_s64 5
 #define dh_typecode_ptr 6
-#define dh_typecode(t) glue(dh_typecode_, dh_alias(t))
+#define dh_typecode(t) (glue(dh_typecode_, dh_alias(t)) | dh_is_signed(t))
 
 #define dh_callflag_i32  0
 #define dh_callflag_s32  0
-- 
2.34.1




Re: [PATCH v2 4/4] tests/tcg: add HeapInfo checking to semihosting test

2021-03-09 Thread Keith Packard via
Alex Bennée  writes:

> +asprintf(_info, "heap: %p -> %p\n", info.heap_base, 
> info.heap_limit);
> +__semi_call(SYS_WRITE0, (uintptr_t) heap_info);
> +if (info.heap_base != brk) {

That requires qemu to know a lot about the run-time environment, which
it rarely does in my experience of embedded systems...

All I've been able to check is whether the heap base is not below the
heap limit and the stack base is not above the stack limit. Not exactly
great validation, but at least it caught the case where I set the stack
limit to the top of the stack?

if (block.heap_base != NULL && block.heap_limit != NULL) {
/* Error if heap base is above limit */
if ((uintptr_t) block.heap_base >= (uintptr_t) 
block.heap_limit) {
printf("heap base %p >= heap_limit %p\n",
   block.heap_base, block.heap_limit);
exit(1);
}
}
if (block.stack_base != NULL && block.stack_limit != NULL) {
/* Error if stack base is below limit */
if ((uintptr_t) block.stack_base < (uintptr_t) 
block.stack_limit) {
printf("stack base %p < stack_limit %p\n",
   block.stack_base, block.stack_limit);
exit(2);
}
}
exit(0);


-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v2 2/4] semihosting/arm-compat-semi: unify GET/SET_ARG helpers

2021-03-09 Thread Keith Packard via
Alex Bennée  writes:

> Note: we aren't currently testing riscv32 due to missing toolchain for
> check-tcg tests.

That's surprising -- the usual risc-v toolchain supports both 64- and
32- bit targets.

Othewise, this patch is

Reviewed-by: Keith Packard 

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v1 3/3] semihosting/arg-compat: fix up handling of SYS_HEAPINFO

2021-03-08 Thread Keith Packard via
Alistair Francis  writes:

> I have started on the effort, but I have not finished yet. Adding
> riscv_cpu_is_32bit() was the first step there and I have some more
> patches locally but I don't have anything working yet.

That's awesome. I think waiting until we see what APIs you're developing
for detecting and operating in 32-bit mode on a 64-bit capable processor
seems like a good idea for now.

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v1 3/3] semihosting/arg-compat: fix up handling of SYS_HEAPINFO

2021-03-06 Thread Keith Packard via
Peter Maydell  writes:

> ILP32 for AArch64 is a zombie target -- it is kinda-sorta
> supported in some toolchains but has no support in eg
> the Linux syscall ABI. The semihosting ABI does not implement
> any kind of ILP32 variant -- you can have A32/T32 (AArch32)
> semihosting, where register and field sizes are 32 bit, or
> you can have A64 (AArch64) semihosting, where register and
> field sizes are 64 bit.

Yeah, I did ILP32 support for Picolibc; all of the aarch64 asm support
needed fixing as ilp32 doesn't specify that register arguments clear the
top 32 bits. Seems pretty obvious that it's little used.

For semihosting, as the ABI isn't visible to the hardware/emulator, the
only reasonable answer that I could come up with was to treat ILP32 the
same as the LP64 and pass 64 bit parameters.

As picolibc is designed for bare-metal environments, it's pretty easy to
support ilp32 otherwise.

> I meant, how does the RISCV semihosting ABI specify what
> the field size is? To answer my own question, I just looked at
> the spec doc and it says "depends on whether the caller is
> 32-bit or 64-bit", which implies that we need to look at the
> current state of the CPU in some way.

Yes. As qemu currently fixes that value based on compilation parameters,
we can use the relevant native types directly and ignore the CPU
state. Adding dynamic XLEN support to qemu would involve a bunch of work
as the same code can be run in both 64- and 32- bit modes, so you'd have
to translate it twice and select which to execute based on the CPU
state.

> Part of why I asked is that the current RISCV implementation
> is just looking at sizeof(target_ulong); but the qemu-system-riscv64
> executable AIUI now supports emulating both "this is a 64 bit
> guest CPU" and "this is a 32 bit host CPU", and so looking at
> a QEMU-compile-time value like "sizeof(target_ulong)" will
> produce the wrong answer for 32-bit CPUs emulated in
> the qemu-system-riscv64 binary. My guess is maybe
> it should be looking at the result of riscv_cpu_is_32bit() instead.

Wow. I read through the code and couldn't find anything that looked like
it supported that, sounds like I must have missed something?

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v1 3/3] semihosting/arg-compat: fix up handling of SYS_HEAPINFO

2021-03-05 Thread Keith Packard via
Peter Maydell  writes:

> For semihosting for Arm what matters is "what state is the core
> in at the point where it makes the semihosting SVC/HLT/etc insn?".

Ok, that means we *aren't* talking about -mabi=ilp32, which is good --
in my current picolibc implementation, the semihosting code uses a pure
64-bit interface for aarch64 targets, even when using ilp32 ABI.

> How does RISCV specify it?

Because the ISA is identical between 64- and 32- bit (and 128-bit)
execution modes, the only difference between the two is the Machine XLEN
value which encodes the native base integer ISA width. You switch modes
by modifying this value.

I don't know of any implementation in hardware or software that supports
modifying this value. I'm not sure we need to support this in the
semihosting code for qemu as I'm pretty sure getting qemu to support
dynamic XLEN values would be a large project (a project which I don't
personally feel would offer much value).

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v1 3/3] semihosting/arg-compat: fix up handling of SYS_HEAPINFO

2021-03-05 Thread Keith Packard via
Peter Maydell  writes:

> Also, you don't seem to have the correct "is the CPU in
> 32-bit or 64-bit mode" test here: you cannot rely on target_ulong
> being the right size, you must make a runtime check.

Do you mean whether a dual aarch64/arm core is in arm or aarch64 mode,
or whether an aarch64 is running a 32-bit ABI?

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v1 3/3] semihosting/arg-compat: fix up handling of SYS_HEAPINFO

2021-03-05 Thread Keith Packard via
Alex Bennée  writes:

> I'm not sure this every worked properly and it's certainly not
> exercised by check-tcg or Peter's semihosting tests. Hoist it into
> it's own helper function and attempt to validate the results in the
> linux-user semihosting test at the least.

The patch is mostly code motion, moving the existing heapinfo stuff into
a separate function. That makes it really hard to see how you've
changed the values being returned. I'd love to see a two patch series,
one of which moves the code as-is and a second patch which fixes
whatever bugs you've found.

-- 
-keith


signature.asc
Description: PGP signature


[PATCH] Create API for checking and clearing GDB connection status

2021-01-12 Thread Keith Packard via
When checking whether there is a live gdb connection, code shouldn't
use 'gdbserver_state.init' as that value is set when the
gdbserver_state structure is initialized in init_gdbserver_state, not
when the gdb socket has a valid connection.

I've created two new functions to manage the gdb connection status:

/* Check whether GDB is currently connected */
static int gdb_is_connected(void)

#ifdef CONFIG_USER_ONLY

/* Close GDB connection */
static void gdb_disconnect(void)

#endif

The first checks whether there is an active GDB connection, the second
closes that connection and resets the connection status indication.

The 'handle_detach' function used 'gdbserver_state.c_cpu' as an
indication of whether there is a connection, so I've used the same in
gdb_is_connected as that is independent of CONFIG_USER_ONLY.

This avoids a segfault when qemu is run with the '-s' flag (create a
gdb protocol socket), but without the '-S' flag (delay until 'c'
command is received).

Signed-off-by: Keith Packard 
---
 gdbstub.c | 51 +--
 1 file changed, 33 insertions(+), 18 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index d99bc0bf2e..8ee7e442d5 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -413,8 +413,28 @@ static void reset_gdbserver_state(void)
 
 bool gdb_has_xml;
 
+/* Check whether GDB is currently connected */
+static int gdb_is_connected(void)
+{
+/*
+ * XXX c_cpu is NULL until gdb_accept_init has been called, so use
+ * this as a proxy for whether the gdb connection is active
+ */
+return gdbserver_state.c_cpu != NULL;
+}
+
 #ifdef CONFIG_USER_ONLY
 
+/* Close GDB connection */
+static void gdb_disconnect(void)
+{
+if (gdb_is_connected()) {
+close(gdbserver_state.fd);
+gdbserver_state.fd = -1;
+gdbserver_state.c_cpu = NULL;
+}
+}
+
 static int get_char(void)
 {
 uint8_t ch;
@@ -424,12 +444,11 @@ static int get_char(void)
 ret = qemu_recv(gdbserver_state.fd, , 1, 0);
 if (ret < 0) {
 if (errno == ECONNRESET)
-gdbserver_state.fd = -1;
+gdb_disconnect();
 if (errno != EINTR)
 return -1;
 } else if (ret == 0) {
-close(gdbserver_state.fd);
-gdbserver_state.fd = -1;
+gdb_disconnect();
 return -1;
 } else {
 break;
@@ -2796,7 +2815,7 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const 
char *fmt, va_list va)
 target_ulong addr;
 uint64_t i64;
 
-if (!gdbserver_state.init) {
+if (!gdb_is_connected()) {
 return;
 }
 
@@ -3025,9 +3044,9 @@ void gdb_exit(CPUArchState *env, int code)
   if (gdbserver_state.socket_path) {
   unlink(gdbserver_state.socket_path);
   }
-  if (gdbserver_state.fd < 0) {
-  return;
-  }
+if (!gdb_is_connected()) {
+return;
+}
 #endif
 
   trace_gdbstub_op_exiting((uint8_t)code);
@@ -3072,7 +3091,7 @@ gdb_handlesig(CPUState *cpu, int sig)
 char buf[256];
 int n;
 
-if (!gdbserver_state.init || gdbserver_state.fd < 0) {
+if (!gdb_is_connected()) {
 return sig;
 }
 
@@ -3086,14 +3105,14 @@ gdb_handlesig(CPUState *cpu, int sig)
 }
 /* put_packet() might have detected that the peer terminated the
connection.  */
-if (gdbserver_state.fd < 0) {
+if (!gdb_is_connected()) {
 return sig;
 }
 
 sig = 0;
 gdbserver_state.state = RS_IDLE;
 gdbserver_state.running_state = 0;
-while (gdbserver_state.running_state == 0) {
+while (gdbserver_state.running_state == 0 && gdb_is_connected()) {
 n = read(gdbserver_state.fd, buf, 256);
 if (n > 0) {
 int i;
@@ -3104,10 +3123,7 @@ gdb_handlesig(CPUState *cpu, int sig)
 } else {
 /* XXX: Connection closed.  Should probably wait for another
connection before continuing.  */
-if (n == 0) {
-close(gdbserver_state.fd);
-}
-gdbserver_state.fd = -1;
+gdb_disconnect();
 return sig;
 }
 }
@@ -3121,7 +3137,7 @@ void gdb_signalled(CPUArchState *env, int sig)
 {
 char buf[4];
 
-if (!gdbserver_state.init || gdbserver_state.fd < 0) {
+if (!gdb_is_connected()) {
 return;
 }
 
@@ -3280,11 +3296,10 @@ int gdbserver_start(const char *port_or_path)
 /* Disable gdb stub for child processes.  */
 void gdbserver_fork(CPUState *cpu)
 {
-if (!gdbserver_state.init || gdbserver_state.fd < 0) {
+if (!gdb_is_connected()) {
 return;
 }
-close(gdbserver_state.fd);
-gdbserver_state.fd = -1;
+gdb_disconnect();
 cpu_breakpoint_remove_all(cpu, BP_GDB);
 cpu_watchpoint_remove_all(cpu, BP_GDB);
 }
-- 
2.30.0




Re: [PATCH] gdbstub.c uses incorrect check for active gdb in use_gdb_syscalls

2021-01-12 Thread Keith Packard via
Alex Bennée  writes:

> It would be better to wrap the test in a function (static bool
> is_connected()?) so the semantic meaning is clear in the code and we can
> fix things in one place if needed.

That makes good sense to me.

> How exactly did you create the segfault? Just starting with -s and
> attaching to a running tasks works fine for me although I Can see
> semihosting stuff would never get to gdb after connection.

Making a semihosting call before GDB is connected results in
dereferencing a NULL gdbserver_state.c_cpu pointer below
gdb_do_syscallv. The sequence goes like this:

 1. gdbserver_start is called during qemu startup, which calls
init_gdbserver_state which sets gdbserver_state.init = true

 2. application makes semihosting call (like putc)

 3. semihosting code calls use_gdb_syscalls(), which returns true
because gdbserver_state.init is true

 4. gdb_do_syscallv checks gdbserver_state.init, which is true

 5. gdb_do_syscallv uses gdbserver_state.c_cpu, which is still NULL and
causes a segfault in qemu_cpu_kick

> Hmm I don't see anything obviously wrong - although I note a bunch of
> tests also check for ->fd which is probably a clearer indication of an
> active connection. I'm sure this could be improved with a semantically
> clearer code though.

fd is < 0 only *after* a connection has failed, it is not set to -1 before
a connection has started. I agree that using 'fd' is a good idea instead
of c_cpu, but it would need to be combined with checking 'init' and
initializing fd to -1 when init is set to true.

In any case, hiding all of this behind a couple of functions seems like
a good idea. For now, I'll continue to use c_cpu as that is independent
of CONFIG_USER_ONLY *and* has the advantage of being initialized to NULL
by default. It's marked with XXX in the patch as it seems like a bit of
a kludge.

> Yes it's a bit of a hack. I can imagine starting with a remote GDB
> connection and then loosing it after opening a file descriptor would
> result in Bad Things (tm). I'm not sure what the cleanest approach is to
> handling the resulting mess.

Hrm. use_gdb_syscalls caches the results of the first test, so we won't
ever mix things, we'll just get some semihosting calls dropped when the
gdb server is not connected. If use_gdb_syscalls checks for a valid
connection, then gdb will never get semihosting calls if -S is not on
the command line. If use_gdb_syscalls checks for gdbserver_state.init,
then gdb will get semihosting calls whenever it is connected, otherwise
those calls will be dropped.

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH v1 16/20] riscv: Add semihosting support

2021-01-08 Thread Keith Packard via
Alistair Francis  writes:

> Whoops, I thought I had already reviewed this commit.

You had provided quite extensive review with lots of useful comments,
but never added the magic tag for this commit :-)

-- 
-keith


signature.asc
Description: PGP signature


[PATCH 6/9] riscv: Add semihosting support for user mode

2021-01-07 Thread Keith Packard via
From: Kito Cheng 

This could made testing more easier and ARM/AArch64 has supported on
their linux user mode too, so I think it should be reasonable.

Verified GCC testsuite with newlib/semihosting.

Signed-off-by: Kito Cheng 
Reviewed-by: Keith Packard 
Message-Id: <20201214200713.3886611-7-kei...@keithp.com>
---
 linux-user/riscv/cpu_loop.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index aa9e437875..9665dabb09 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -23,6 +23,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "elf.h"
+#include "hw/semihosting/common-semi.h"
 
 void cpu_loop(CPURISCVState *env)
 {
@@ -91,6 +92,10 @@ void cpu_loop(CPURISCVState *env)
 sigcode = TARGET_SEGV_MAPERR;
 sigaddr = env->badaddr;
 break;
+case RISCV_EXCP_SEMIHOST:
+env->gpr[xA0] = do_common_semihosting(cs);
+env->pc += 4;
+break;
 case EXCP_DEBUG:
 gdbstep:
 signum = TARGET_SIGTRAP;
-- 
2.29.2




[PATCH 3/9] semihosting: Change internal common-semi interfaces to use CPUState *

2021-01-07 Thread Keith Packard via
This makes all of the internal interfaces architecture-independent and
renames the internal functions to use the 'common_semi' prefix instead
of 'arm' or 'arm_semi'.

To do this, some new architecture-specific internal helper functions
were created:

static inline target_ulong
common_semi_arg(CPUState *cs, int argno)

Returns the argno'th semihosting argument, where argno can be
either 0 or 1.

static inline void
common_semi_set_ret(CPUState *cs, target_ulong ret)

Sets the semihosting return value.

static inline bool
common_semi_sys_exit_extended(CPUState *cs, int nr)

This detects whether the specified semihosting call, which
is either TARGET_SYS_EXIT or TARGET_SYS_EXIT_EXTENDED should
be executed using the TARGET_SYS_EXIT_EXTENDED semantics.

static inline target_ulong
common_semi_rambase(CPUState *cs)

Returns the base of RAM region used for heap and stack. This
is used to construct plausible values for the SYS_HEAPINFO
call.

In addition, several existing functions have been changed to flag
areas of code which are architecture specific:

static target_ulong
common_semi_flen_buf(CPUState *cs)

Returns the current stack pointer minus 64, which is
where a stat structure will be placed on the stack

#define GET_ARG(n)

This fetches arguments from the semihosting command's argument
block. The address of this is available implicitly through the
local 'args' variable. This is *mostly* architecture
independent, but does depend on the current ABI's notion of
the size of a 'long' parameter, which may need run-time checks
(as it does on AARCH64)

#define SET_ARG(n, val)

This mirrors GET_ARG and stores data back into the argument
block.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 



v2:
Add common_semi_rambase hook to get memory address for
SYS_HEAPINFO call.
Message-Id: <20201214200713.3886611-4-kei...@keithp.com>
---
 hw/semihosting/common-semi.c | 351 +++
 1 file changed, 187 insertions(+), 164 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 74f09c038c..33c82f73b1 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -32,15 +32,18 @@
 #include "cpu.h"
 #include "hw/semihosting/semihost.h"
 #include "hw/semihosting/console.h"
+#include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
-#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "exec/gdbstub.h"
 #include "qemu/cutils.h"
+#ifdef TARGET_ARM
 #include "hw/arm/boot.h"
+#endif
 #include "hw/boards.h"
 #endif
 
@@ -134,6 +137,50 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifdef TARGET_ARM
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env)) {
+return env->xregs[argno];
+} else {
+return env->regs[argno];
+}
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env)) {
+env->xregs[0] = ret;
+} else {
+env->regs[0] = ret;
+}
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
+}
+
+#ifndef CONFIG_USER_ONLY
+#include "hw/arm/boot.h"
+static inline target_ulong
+common_semi_rambase(CPUState *cs)
+{
+CPUArchState *env = cs->env_ptr;
+const struct arm_boot_info *info = env->boot_info;
+return info->loader_start;
+}
+#endif
+
+#endif /* TARGET_ARM */
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -239,11 +286,10 @@ static target_ulong syscall_err;
 #include "exec/softmmu-semi.h"
 #endif
 
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
 {
 if (code == (uint32_t)-1) {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 ts->swi_errno = errno;
@@ -254,10 +300,9 @@ static inline uint32_t set_swi_errno(CPUARMState *env, 
uint32_t code)
 return code;
 }
 
-static inline uint32_t get_swi_errno(CPUARMState *env)
+static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 return ts->swi_errno;
@@ -266,24 +311,22 @@ static inline uint32_t get_swi_errno(CPUARMState *env)
 #endif
 }
 
-static target_ulong arm_semi_syscall_len;
+static target_ulong common_semi_syscall_len;
 
-static void arm_semi_cb(CPUState *cs, target_ulong ret, 

[PATCH 4/9] semihosting: Support SYS_HEAPINFO when env->boot_info is not set

2021-01-07 Thread Keith Packard via
env->boot_info is only set in some ARM startup paths, so we cannot
rely on it to support the SYS_HEAPINFO semihosting function. When not
available, fallback to finding a RAM memory region containing the
current stack and use the base of that.

Signed-off-by: Keith Packard 

Message-Id: <20201214200713.3886611-5-kei...@keithp.com>
---
 hw/semihosting/common-semi.c | 43 +++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 33c82f73b1..f09deff4d3 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -137,6 +137,36 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifndef CONFIG_USER_ONLY
+#include "exec/address-spaces.h"
+/*
+ * Find the base of a RAM region containing the specified address
+ */
+static inline hwaddr
+common_semi_find_region_base(hwaddr addr)
+{
+MemoryRegion *subregion;
+
+/*
+ * Find the chunk of R/W memory containing the address.  This is
+ * used for the SYS_HEAPINFO semihosting call, which should
+ * probably be using information from the loaded application.
+ */
+QTAILQ_FOREACH(subregion, _system_memory()->subregions,
+   subregions_link) {
+if (subregion->ram && !subregion->readonly) {
+Int128 top128 = int128_add(int128_make64(subregion->addr),
+   subregion->size);
+Int128 addr128 = int128_make64(addr);
+if (subregion->addr <= addr && int128_lt(addr128, top128)) {
+return subregion->addr;
+}
+}
+}
+return 0;
+}
+#endif
+
 #ifdef TARGET_ARM
 static inline target_ulong
 common_semi_arg(CPUState *cs, int argno)
@@ -175,7 +205,18 @@ common_semi_rambase(CPUState *cs)
 {
 CPUArchState *env = cs->env_ptr;
 const struct arm_boot_info *info = env->boot_info;
-return info->loader_start;
+target_ulong sp;
+
+if (info) {
+return info->loader_start;
+}
+
+if (is_a64(env)) {
+sp = env->xregs[31];
+} else {
+sp = env->regs[13];
+}
+return common_semi_find_region_base(sp);
 }
 #endif
 
-- 
2.29.2




[PATCH 2/9] semihosting: Change common-semi API to be architecture-independent

2021-01-07 Thread Keith Packard via
The public API is now defined in
hw/semihosting/common-semi.h. do_common_semihosting takes CPUState *
instead of CPUARMState *. All internal functions have been renamed
common_semi_ instead of arm_semi_ or arm_. Aside from the API change,
there are no functional changes in this patch.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 
Message-Id: <20201214200713.3886611-3-kei...@keithp.com>
---
 hw/semihosting/common-semi.c  | 16 ++--
 hw/semihosting/common-semi.h  | 36 +++
 linux-user/aarch64/cpu_loop.c |  3 ++-
 linux-user/arm/cpu_loop.c |  3 ++-
 target/arm/cpu.h  |  8 
 target/arm/helper.c   |  5 +++--
 target/arm/m_helper.c |  7 ++-
 7 files changed, 59 insertions(+), 19 deletions(-)
 create mode 100644 hw/semihosting/common-semi.h

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index f7b7bff522..74f09c038c 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,10 +1,14 @@
 /*
- *  Arm "Angel" semihosting syscalls
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
  *  Written by Paul Brook.
  *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -373,12 +377,12 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, 
gdb_syscall_complete_cb cb,
  * do anything with its return value, because it is not necessarily
  * the result of the syscall, but could just be the old value of X0.
  * The only thing safe to do with this is that the callers of
- * do_arm_semihosting() will write it straight back into X0.
+ * do_common_semihosting() will write it straight back into X0.
  * (In linux-user mode, the callback will have happened before
  * gdb_do_syscallv() returns.)
  *
  * We should tidy this up so neither this function nor
- * do_arm_semihosting() return a value, so the mistake of
+ * do_common_semihosting() return a value, so the mistake of
  * doing something with the return value is not possible to make.
  */
 
@@ -675,10 +679,10 @@ static const GuestFDFunctions guestfd_fns[] = {
  * leave the register unchanged. We use 0xdeadbeef as the return value
  * when there isn't a defined return value for the call.
  */
-target_ulong do_arm_semihosting(CPUARMState *env)
+target_ulong do_common_semihosting(CPUState *cs)
 {
-ARMCPU *cpu = env_archcpu(env);
-CPUState *cs = env_cpu(env);
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
 char * s;
diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h
new file mode 100644
index 00..bc53e92c79
--- /dev/null
+++ b/hw/semihosting/common-semi.h
@@ -0,0 +1,36 @@
+/*
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
+ *
+ *  Copyright (c) 2005, 2007 CodeSourcery.
+ *  Copyright (c) 2019 Linaro
+ *  Written by Paul Brook.
+ *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ *
+ *  ARM Semihosting is documented in:
+ * Semihosting for AArch32 and AArch64 Release 2.0
+ * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ */
+
+#ifndef COMMON_SEMI_H
+#define COMMON_SEMI_H
+
+target_ulong do_common_semihosting(CPUState *cs);
+
+#endif /* COMMON_SEMI_H */
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index bbe9fefca8..42b9c15f53 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -22,6 +22,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "qemu/guest-random.h"
+#include "hw/semihosting/common-semi.h"
 
 #define get_user_code_u32(x, gaddr, env)\
 ({ abi_long __r = get_user_u32((x), (gaddr));   \
@@ -129,7 +130,7 @@ void cpu_loop(CPUARMState *env)
 

[PATCH 0/9] Add RISC-V semihosting 0.2. Finish ARM semihosting 2.0

2021-01-07 Thread Keith Packard via
This series adds support for RISC-V Semihosting, version 0.2 as
specified here:

https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

This specification references the ARM semihosting release 2.0 as
specified here:

https://static.docs.arm.com/100863/0200/semihosting.pdf

That specification includes several semihosting calls which were not
previously implemented. This series includes implementations for the
remaining calls so that both RISC-V and ARM versions are now complete.

Tests for release 2.0 can be found in picolibc on the semihost-2.0-all
branch:

https://github.com/picolibc/picolibc/tree/semihost-2.0-all

These tests uncovered a bug in the SYS_HEAPINFO implementation for
ARM, which has been fixed in this series as well.

The series is structured as follows:

 1. Move shared semihosting files
 2. Change public common semihosting APIs
 3. Change internal semihosting interfaces
 4. Fix SYS_HEAPINFO crash on ARM
 5-6. Add RISC-V semihosting implementation
 7-9. Add missing semihosting operations from release 2.0





[PATCH 8/9] semihosting: Implement SYS_TMPNAM

2021-01-07 Thread Keith Packard via
Part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
Message-Id: <20201214200713.3886611-9-kei...@keithp.com>
---
 hw/semihosting/common-semi.c | 21 +++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index b1368d945c..b0648c3812 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -835,6 +835,7 @@ target_ulong do_common_semihosting(CPUState *cs)
 CPUArchState *env = cs->env_ptr;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
+target_ulong ul_ret;
 char * s;
 int nr;
 uint32_t ret;
@@ -998,8 +999,24 @@ target_ulong do_common_semihosting(CPUState *cs)
 
 return guestfd_fns[gf->type].flenfn(cs, gf);
 case TARGET_SYS_TMPNAM:
-qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
-return -1;
+GET_ARG(0);
+GET_ARG(1);
+GET_ARG(2);
+if (asprintf(, "/tmp/qemu-%x%02x", getpid(),
+ (int) (arg1 & 0xff)) < 0) {
+return -1;
+}
+ul_ret = (target_ulong) -1;
+
+/* Make sure there's enough space in the buffer */
+if (strlen(s) < arg2) {
+char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0);
+strcpy(output, s);
+unlock_user(output, arg0, arg2);
+ul_ret = 0;
+}
+free(s);
+return ul_ret;
 case TARGET_SYS_REMOVE:
 GET_ARG(0);
 GET_ARG(1);
-- 
2.29.2




[PATCH 7/9] semihosting: Implement SYS_ELAPSED and SYS_TICKFREQ

2021-01-07 Thread Keith Packard via
These are part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
Message-Id: <20201214200713.3886611-8-kei...@keithp.com>
---
 hw/semihosting/common-semi.c | 16 
 include/qemu/timer.h |  2 ++
 util/qemu-timer-common.c |  4 
 3 files changed, 22 insertions(+)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index f0cf5f10f5..b1368d945c 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -38,6 +38,7 @@
 #include "hw/semihosting/console.h"
 #include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
+#include "qemu/timer.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
@@ -73,6 +74,8 @@
 #define TARGET_SYS_EXIT0x18
 #define TARGET_SYS_SYNCCACHE   0x19
 #define TARGET_SYS_EXIT_EXTENDED 0x20
+#define TARGET_SYS_ELAPSED 0x30
+#define TARGET_SYS_TICKFREQ0x31
 
 /* ADP_Stopped_ApplicationExit is used for exit(0),
  * anything else is implemented as exit(1) */
@@ -837,6 +840,7 @@ target_ulong do_common_semihosting(CPUState *cs)
 uint32_t ret;
 uint32_t len;
 GuestFD *gf;
+int64_t elapsed;
 
 (void) env; /* Used implicitly by arm lock_user macro */
 nr = common_semi_arg(cs, 0) & 0xU;
@@ -1246,6 +1250,18 @@ target_ulong do_common_semihosting(CPUState *cs)
 }
 gdb_exit(cs->env_ptr, ret);
 exit(ret);
+case TARGET_SYS_ELAPSED:
+elapsed = get_clock() - clock_start;
+if (sizeof(target_ulong) == 8) {
+SET_ARG(0, elapsed);
+} else {
+SET_ARG(0, (uint32_t) elapsed);
+SET_ARG(1, (uint32_t) (elapsed >> 32));
+}
+return 0;
+case TARGET_SYS_TICKFREQ:
+/* qemu always uses nsec */
+return 10;
 case TARGET_SYS_SYNCCACHE:
 /*
  * Clean the D-cache and invalidate the I-cache for the specified
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index bdecc5b41f..ca6fae51f1 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -806,6 +806,8 @@ static inline int64_t get_clock_realtime(void)
 return tv.tv_sec * 10LL + (tv.tv_usec * 1000);
 }
 
+extern int64_t clock_start;
+
 /* Warning: don't insert tracepoints into these functions, they are
also used by simpletrace backend and tracepoints would cause
an infinite recursion! */
diff --git a/util/qemu-timer-common.c b/util/qemu-timer-common.c
index baf3317f74..cc1326f726 100644
--- a/util/qemu-timer-common.c
+++ b/util/qemu-timer-common.c
@@ -27,6 +27,8 @@
 /***/
 /* real time host monotonic timer */
 
+int64_t clock_start;
+
 #ifdef _WIN32
 
 int64_t clock_freq;
@@ -41,6 +43,7 @@ static void __attribute__((constructor)) init_get_clock(void)
 exit(1);
 }
 clock_freq = freq.QuadPart;
+clock_start = get_clock();
 }
 
 #else
@@ -55,5 +58,6 @@ static void __attribute__((constructor)) init_get_clock(void)
 if (clock_gettime(CLOCK_MONOTONIC, ) == 0) {
 use_rt_clock = 1;
 }
+clock_start = get_clock();
 }
 #endif
-- 
2.29.2




[PATCH 9/9] semihosting: Implement SYS_ISERROR

2021-01-07 Thread Keith Packard via
Part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
Message-Id: <20201214200713.3886611-10-kei...@keithp.com>
---
 hw/semihosting/common-semi.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index b0648c3812..abc15bf219 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -59,6 +59,7 @@
 #define TARGET_SYS_WRITE   0x05
 #define TARGET_SYS_READ0x06
 #define TARGET_SYS_READC   0x07
+#define TARGET_SYS_ISERROR 0x08
 #define TARGET_SYS_ISTTY   0x09
 #define TARGET_SYS_SEEK0x0a
 #define TARGET_SYS_FLEN0x0c
@@ -967,6 +968,9 @@ target_ulong do_common_semihosting(CPUState *cs)
 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
 case TARGET_SYS_READC:
 return qemu_semihosting_console_inc(cs->env_ptr);
+case TARGET_SYS_ISERROR:
+GET_ARG(0);
+return (target_long) arg0 < 0 ? 1 : 0;
 case TARGET_SYS_ISTTY:
 GET_ARG(0);
 
-- 
2.29.2




[PATCH 1/9] semihosting: Move ARM semihosting code to shared directories

2021-01-07 Thread Keith Packard via
This commit renames two files which provide ARM semihosting support so
that they can be shared by other architectures:

 1. target/arm/arm-semi.c -> hw/semihosting/common-semi.c
 2. linux-user/arm/semihost.c -> linux-user/semihost.c

The build system was modified use a new config variable,
CONFIG_ARM_COMPATIBLE_SEMIHOSTING, which has been added to the ARM
softmmu and linux-user default configs. The contents of the source
files has not been changed in this patch.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 



v2
Place common-semi.c name in arm_ss, just as arm-semi.c was

v3
Create CONFIG_ARM_COMPATIBLE_SEMIHOSTING and assign in
arm config files

v4
Also update aarch64_be default config

v5
Also update armeb default config
---
 default-configs/devices/arm-softmmu.mak   | 1 +
 default-configs/targets/aarch64-linux-user.mak| 1 +
 default-configs/targets/aarch64_be-linux-user.mak | 1 +
 default-configs/targets/arm-linux-user.mak| 1 +
 default-configs/targets/armeb-linux-user.mak  | 1 +
 hw/semihosting/Kconfig| 3 +++
 target/arm/arm-semi.c => hw/semihosting/common-semi.c | 0
 hw/semihosting/meson.build| 3 +++
 linux-user/arm/meson.build| 3 ---
 linux-user/meson.build| 1 +
 linux-user/{arm => }/semihost.c   | 0
 target/arm/meson.build| 2 --
 12 files changed, 12 insertions(+), 5 deletions(-)
 rename target/arm/arm-semi.c => hw/semihosting/common-semi.c (100%)
 rename linux-user/{arm => }/semihost.c (100%)

diff --git a/default-configs/devices/arm-softmmu.mak 
b/default-configs/devices/arm-softmmu.mak
index 08a32123b4..0500156a0c 100644
--- a/default-configs/devices/arm-softmmu.mak
+++ b/default-configs/devices/arm-softmmu.mak
@@ -42,4 +42,5 @@ CONFIG_FSL_IMX25=y
 CONFIG_FSL_IMX7=y
 CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 CONFIG_ALLWINNER_H3=y
diff --git a/default-configs/targets/aarch64-linux-user.mak 
b/default-configs/targets/aarch64-linux-user.mak
index 163c9209f4..4713253709 100644
--- a/default-configs/targets/aarch64-linux-user.mak
+++ b/default-configs/targets/aarch64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=aarch64
 TARGET_BASE_ARCH=arm
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml 
gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml 
gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/aarch64_be-linux-user.mak 
b/default-configs/targets/aarch64_be-linux-user.mak
index 4c953cf8c5..fae831558d 100644
--- a/default-configs/targets/aarch64_be-linux-user.mak
+++ b/default-configs/targets/aarch64_be-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_BASE_ARCH=arm
 TARGET_WORDS_BIGENDIAN=y
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml 
gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml 
gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/arm-linux-user.mak 
b/default-configs/targets/arm-linux-user.mak
index c7cd872e86..e741ffd4d3 100644
--- a/default-configs/targets/arm-linux-user.mak
+++ b/default-configs/targets/arm-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_SYSTBL_ABI=common,oabi
 TARGET_SYSTBL=syscall.tbl
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml 
gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/armeb-linux-user.mak 
b/default-configs/targets/armeb-linux-user.mak
index 79bf10e99b..255e44e8b0 100644
--- a/default-configs/targets/armeb-linux-user.mak
+++ b/default-configs/targets/armeb-linux-user.mak
@@ -4,3 +4,4 @@ TARGET_SYSTBL=syscall.tbl
 TARGET_WORDS_BIGENDIAN=y
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml 
gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/Kconfig b/hw/semihosting/Kconfig
index efe0a30734..4c30dc6b16 100644
--- a/hw/semihosting/Kconfig
+++ b/hw/semihosting/Kconfig
@@ -1,3 +1,6 @@
 
 config SEMIHOSTING
bool
+
+config ARM_COMPATIBLE_SEMIHOSTING
+   bool
diff --git a/target/arm/arm-semi.c b/hw/semihosting/common-semi.c
similarity index 100%
rename from target/arm/arm-semi.c
rename to hw/semihosting/common-semi.c
diff --git a/hw/semihosting/meson.build b/hw/semihosting/meson.build
index f40ac574c4..5b4a170270 100644
--- a/hw/semihosting/meson.build
+++ b/hw/semihosting/meson.build
@@ -2,3 +2,6 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
   'config.c',
   'console.c',
 ))
+
+specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
+   if_true: files('common-semi.c'))

[PATCH 5/9] riscv: Add semihosting support

2021-01-07 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

Message-Id: <20201214200713.3886611-6-kei...@keithp.com>
---
 default-configs/devices/riscv32-softmmu.mak   |  2 +
 default-configs/devices/riscv64-softmmu.mak   |  2 +
 .../targets/riscv32-linux-user.mak|  1 +
 .../targets/riscv64-linux-user.mak|  1 +
 hw/semihosting/common-semi.c  | 82 ++-
 hw/semihosting/common-semi.h  |  5 +-
 linux-user/qemu.h |  4 +-
 linux-user/semihost.c |  8 +-
 qemu-options.hx   | 10 ++-
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu_helper.c | 10 +++
 .../riscv/insn_trans/trans_privileged.c.inc   | 37 -
 target/riscv/translate.c  | 11 +++
 13 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/default-configs/devices/riscv32-softmmu.mak 
b/default-configs/devices/riscv32-softmmu.mak
index 94a236c9c2..d847bd5692 100644
--- a/default-configs/devices/riscv32-softmmu.mak
+++ b/default-configs/devices/riscv32-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/devices/riscv64-softmmu.mak 
b/default-configs/devices/riscv64-softmmu.mak
index 76b6195648..d5eec75f05 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/targets/riscv32-linux-user.mak 
b/default-configs/targets/riscv32-linux-user.mak
index dfb259e8aa..6a9d1b1bc1 100644
--- a/default-configs/targets/riscv32-linux-user.mak
+++ b/default-configs/targets/riscv32-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv32
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-csr.xml 
gdb-xml/riscv-32bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/riscv64-linux-user.mak 
b/default-configs/targets/riscv64-linux-user.mak
index b13895f3b0..0a92849a1b 100644
--- a/default-configs/targets/riscv64-linux-user.mak
+++ b/default-configs/targets/riscv64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv64
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-csr.xml 
gdb-xml/riscv-64bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index f09deff4d3..f0cf5f10f5 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,6 +1,6 @@
 /*
  *  Semihosting support for systems modeled on the Arm "Angel"
- *  semihosting syscalls design.
+ *  semihosting syscalls design. This includes Arm and RISC-V processors
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
@@ -25,6 +25,10 @@
  *  ARM Semihosting is documented in:
  * Semihosting for AArch32 and AArch64 Release 2.0
  * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ *  RISC-V Semihosting is documented in:
+ * RISC-V Semihosting
+ * 
https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
  */
 
 #include "qemu/osdep.h"
@@ -222,6 +226,42 @@ common_semi_rambase(CPUState *cs)
 
 #endif /* TARGET_ARM */
 
+#ifdef TARGET_RISCV
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+RISCVCPU *cpu = RISCV_CPU(cs);
+CPURISCVState *env = >env;
+return env->gpr[xA0 + argno];
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+RISCVCPU *cpu = RISCV_CPU(cs);
+CPURISCVState *env = >env;
+env->gpr[xA0] = ret;
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
+}
+
+#ifndef CONFIG_USER_ONLY
+
+static inline target_ulong
+common_semi_rambase(CPUState *cs)
+{
+RISCVCPU *cpu = RISCV_CPU(cs);
+CPURISCVState *env = >env;
+return common_semi_find_region_base(env->gpr[xSP]);
+}
+#endif
+
+#endif
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -398,6 +438,12 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
 sp = env->regs[13];
 }
 #endif
+#ifdef TARGET_RISCV
+RISCVCPU *cpu = 

[PATCH] gdbstub.c uses incorrect check for active gdb in use_gdb_syscalls

2020-12-23 Thread Keith Packard via
When checking whether there is a live gdb connection, code shouldn't
use 'gdbserver_state.init' as that value is set when the
gdbserver_state structure is initialized in init_gdbserver_state, not
when the gdb socket has a valid connection.

The 'handle_detach' function appears to use 'gdbserver_state.c_cpu' as
an indication of whether there is a connection, so I've used the same
in use_gdb_syscalls.

This avoids a segfault when qemu is run with the '-s' flag (create a
gdb protocol socket), but without the '-S' flag (delay until 'c'
command is received).

I would like this patch to inform a discussion on whether the numerous
other places using gdbserver_state.init are also incorrect (most of
them appear to be using it in the same way use_gdb_syscalls does), and
also whether use_gdb_syscalls should cache the result of this check or
whether it should check each time it is called to see if a gdb
connection is currently acive. For the second question, I don't have a
clear idea; mixing gdb and native calls seems problematic for stateful
operations like file open/close.

Signed-off-by: Keith Packard 
---
 gdbstub.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdbstub.c b/gdbstub.c
index d99bc0bf2e..4e709d16fd 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -460,7 +460,7 @@ int use_gdb_syscalls(void)
 /* -semihosting-config target=auto */
 /* On the first call check if gdb is connected and remember. */
 if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
-gdb_syscall_mode = gdbserver_state.init ?
+gdb_syscall_mode = gdbserver_state.c_cpu != NULL ?
 GDB_SYS_ENABLED : GDB_SYS_DISABLED;
 }
 return gdb_syscall_mode == GDB_SYS_ENABLED;
-- 
2.29.2




[PATCH 9/9] semihosting: Implement SYS_ISERROR

2020-12-14 Thread Keith Packard via
Part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index b0648c3812..abc15bf219 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -59,6 +59,7 @@
 #define TARGET_SYS_WRITE   0x05
 #define TARGET_SYS_READ0x06
 #define TARGET_SYS_READC   0x07
+#define TARGET_SYS_ISERROR 0x08
 #define TARGET_SYS_ISTTY   0x09
 #define TARGET_SYS_SEEK0x0a
 #define TARGET_SYS_FLEN0x0c
@@ -967,6 +968,9 @@ target_ulong do_common_semihosting(CPUState *cs)
 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
 case TARGET_SYS_READC:
 return qemu_semihosting_console_inc(cs->env_ptr);
+case TARGET_SYS_ISERROR:
+GET_ARG(0);
+return (target_long) arg0 < 0 ? 1 : 0;
 case TARGET_SYS_ISTTY:
 GET_ARG(0);
 
-- 
2.29.2




[PATCH 1/9] semihosting: Move ARM semihosting code to shared directories

2020-12-14 Thread Keith Packard via
This commit renames two files which provide ARM semihosting support so
that they can be shared by other architectures:

 1. target/arm/arm-semi.c -> hw/semihosting/common-semi.c
 2. linux-user/arm/semihost.c -> linux-user/semihost.c

The build system was modified use a new config variable,
CONFIG_ARM_COMPATIBLE_SEMIHOSTING, which has been added to the ARM
softmmu and linux-user default configs. The contents of the source
files has not been changed in this patch.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 



v2
Place common-semi.c name in arm_ss, just as arm-semi.c was

v3
Create CONFIG_ARM_COMPATIBLE_SEMIHOSTING and assign in
arm config files

v4
Also update aarch64_be default config
---
 default-configs/devices/arm-softmmu.mak   | 1 +
 default-configs/targets/aarch64-linux-user.mak| 1 +
 default-configs/targets/aarch64_be-linux-user.mak | 1 +
 default-configs/targets/arm-linux-user.mak| 1 +
 hw/semihosting/Kconfig| 3 +++
 target/arm/arm-semi.c => hw/semihosting/common-semi.c | 0
 hw/semihosting/meson.build| 3 +++
 linux-user/arm/meson.build| 3 ---
 linux-user/meson.build| 1 +
 linux-user/{arm => }/semihost.c   | 0
 target/arm/meson.build| 2 --
 11 files changed, 11 insertions(+), 5 deletions(-)
 rename target/arm/arm-semi.c => hw/semihosting/common-semi.c (100%)
 rename linux-user/{arm => }/semihost.c (100%)

diff --git a/default-configs/devices/arm-softmmu.mak 
b/default-configs/devices/arm-softmmu.mak
index 08a32123b4..0500156a0c 100644
--- a/default-configs/devices/arm-softmmu.mak
+++ b/default-configs/devices/arm-softmmu.mak
@@ -42,4 +42,5 @@ CONFIG_FSL_IMX25=y
 CONFIG_FSL_IMX7=y
 CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 CONFIG_ALLWINNER_H3=y
diff --git a/default-configs/targets/aarch64-linux-user.mak 
b/default-configs/targets/aarch64-linux-user.mak
index 163c9209f4..4713253709 100644
--- a/default-configs/targets/aarch64-linux-user.mak
+++ b/default-configs/targets/aarch64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=aarch64
 TARGET_BASE_ARCH=arm
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml 
gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml 
gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/aarch64_be-linux-user.mak 
b/default-configs/targets/aarch64_be-linux-user.mak
index 4c953cf8c5..fae831558d 100644
--- a/default-configs/targets/aarch64_be-linux-user.mak
+++ b/default-configs/targets/aarch64_be-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_BASE_ARCH=arm
 TARGET_WORDS_BIGENDIAN=y
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml 
gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml 
gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/arm-linux-user.mak 
b/default-configs/targets/arm-linux-user.mak
index c7cd872e86..e741ffd4d3 100644
--- a/default-configs/targets/arm-linux-user.mak
+++ b/default-configs/targets/arm-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_SYSTBL_ABI=common,oabi
 TARGET_SYSTBL=syscall.tbl
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml 
gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/Kconfig b/hw/semihosting/Kconfig
index efe0a30734..4c30dc6b16 100644
--- a/hw/semihosting/Kconfig
+++ b/hw/semihosting/Kconfig
@@ -1,3 +1,6 @@
 
 config SEMIHOSTING
bool
+
+config ARM_COMPATIBLE_SEMIHOSTING
+   bool
diff --git a/target/arm/arm-semi.c b/hw/semihosting/common-semi.c
similarity index 100%
rename from target/arm/arm-semi.c
rename to hw/semihosting/common-semi.c
diff --git a/hw/semihosting/meson.build b/hw/semihosting/meson.build
index f40ac574c4..5b4a170270 100644
--- a/hw/semihosting/meson.build
+++ b/hw/semihosting/meson.build
@@ -2,3 +2,6 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
   'config.c',
   'console.c',
 ))
+
+specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
+   if_true: files('common-semi.c'))
diff --git a/linux-user/arm/meson.build b/linux-user/arm/meson.build
index 432984b58e..5a93c925cf 100644
--- a/linux-user/arm/meson.build
+++ b/linux-user/arm/meson.build
@@ -1,6 +1,3 @@
-linux_user_ss.add(when: 'TARGET_AARCH64', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'TARGET_ARM', if_true: files('semihost.c'))
-
 subdir('nwfpe')
 
 syscall_nr_generators += {
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..7fe28d659e 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -16,6 +16,7 @@ linux_user_ss.add(rt)
 
 linux_user_ss.add(when: 

[PATCH 5/9] riscv: Add semihosting support

2020-12-14 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support

v8:
Fix errors reported by checkpatch that crept in.

v9:
Changes suggested by Alistair Francis :
Don't add me to the MAINTAINERS file.
Remove duplicate #include in target/riscv/cpu.h
Reference RISC-V semihosting spec in target/riscv/riscv-semi.c

v10:
Use common semihosting implementation instead of a separate copy.

Make sure addresses of the three breakpoint-signaling
instructions all lie within the same page. Change suggested by
Richard Henderson 

v11:
Use CONFIG_ARM_COMPATIBLE_SEMIHOSTING

v12:
Fix bug in SYS_EXIT support on rv64

v13:
Add common_semi_rambase implementation. This locates the
memory region containing the stack and uses the base of that.

Fix SET_ARG and GET_ARG on rv64 targets to operate on 64-bit
values rather than 32-bit. Put_user_ual/get_user_ual are
confusingly defined by softmmu-semi.h as being equivalent to
put_user_u32/get_user_u32.
---
 default-configs/devices/riscv32-softmmu.mak   |  2 +
 default-configs/devices/riscv64-softmmu.mak   |  2 +
 .../targets/riscv32-linux-user.mak|  1 +
 .../targets/riscv64-linux-user.mak|  1 +
 hw/semihosting/common-semi.c  | 82 ++-
 hw/semihosting/common-semi.h  |  5 +-
 linux-user/qemu.h |  4 +-
 linux-user/semihost.c |  8 +-
 qemu-options.hx   | 10 ++-
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu_helper.c | 10 +++
 .../riscv/insn_trans/trans_privileged.c.inc   | 37 -
 target/riscv/translate.c  | 11 +++
 13 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/default-configs/devices/riscv32-softmmu.mak 
b/default-configs/devices/riscv32-softmmu.mak
index 94a236c9c2..d847bd5692 100644
--- a/default-configs/devices/riscv32-softmmu.mak
+++ b/default-configs/devices/riscv32-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/devices/riscv64-softmmu.mak 
b/default-configs/devices/riscv64-softmmu.mak
index 76b6195648..d5eec75f05 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/targets/riscv32-linux-user.mak 
b/default-configs/targets/riscv32-linux-user.mak
index dfb259e8aa..6a9d1b1bc1 100644
--- a/default-configs/targets/riscv32-linux-user.mak
+++ b/default-configs/targets/riscv32-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv32
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-csr.xml 
gdb-xml/riscv-32bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/riscv64-linux-user.mak 
b/default-configs/targets/riscv64-linux-user.mak
index b13895f3b0..0a92849a1b 100644
--- a/default-configs/targets/riscv64-linux-user.mak
+++ b/default-configs/targets/riscv64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv64
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-csr.xml 
gdb-xml/riscv-64bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index f09deff4d3..f0cf5f10f5 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,6 +1,6 @@
 /*
  *  Semihosting support for systems modeled on the Arm "Angel"
- *  semihosting syscalls design.
+ *  semihosting syscalls design. This includes Arm and RISC-V processors
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
@@ -25,6 +25,10 @@
  *  ARM Semihosting is documented in:
  * Semihosting for AArch32 and AArch64 Release 2.0
  *   

[PATCH 8/9] semihosting: Implement SYS_TMPNAM

2020-12-14 Thread Keith Packard via
Part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 21 +++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index b1368d945c..b0648c3812 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -835,6 +835,7 @@ target_ulong do_common_semihosting(CPUState *cs)
 CPUArchState *env = cs->env_ptr;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
+target_ulong ul_ret;
 char * s;
 int nr;
 uint32_t ret;
@@ -998,8 +999,24 @@ target_ulong do_common_semihosting(CPUState *cs)
 
 return guestfd_fns[gf->type].flenfn(cs, gf);
 case TARGET_SYS_TMPNAM:
-qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
-return -1;
+GET_ARG(0);
+GET_ARG(1);
+GET_ARG(2);
+if (asprintf(, "/tmp/qemu-%x%02x", getpid(),
+ (int) (arg1 & 0xff)) < 0) {
+return -1;
+}
+ul_ret = (target_ulong) -1;
+
+/* Make sure there's enough space in the buffer */
+if (strlen(s) < arg2) {
+char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0);
+strcpy(output, s);
+unlock_user(output, arg0, arg2);
+ul_ret = 0;
+}
+free(s);
+return ul_ret;
 case TARGET_SYS_REMOVE:
 GET_ARG(0);
 GET_ARG(1);
-- 
2.29.2




[PATCH 2/9] semihosting: Change common-semi API to be architecture-independent

2020-12-14 Thread Keith Packard via
The public API is now defined in
hw/semihosting/common-semi.h. do_common_semihosting takes CPUState *
instead of CPUARMState *. All internal functions have been renamed
common_semi_ instead of arm_semi_ or arm_. Aside from the API change,
there are no functional changes in this patch.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 
---
 hw/semihosting/common-semi.c  | 16 ++--
 hw/semihosting/common-semi.h  | 36 +++
 linux-user/aarch64/cpu_loop.c |  3 ++-
 linux-user/arm/cpu_loop.c |  3 ++-
 target/arm/cpu.h  |  8 
 target/arm/helper.c   |  5 +++--
 target/arm/m_helper.c |  7 ++-
 7 files changed, 59 insertions(+), 19 deletions(-)
 create mode 100644 hw/semihosting/common-semi.h

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index f7b7bff522..74f09c038c 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,10 +1,14 @@
 /*
- *  Arm "Angel" semihosting syscalls
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
  *  Written by Paul Brook.
  *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -373,12 +377,12 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, 
gdb_syscall_complete_cb cb,
  * do anything with its return value, because it is not necessarily
  * the result of the syscall, but could just be the old value of X0.
  * The only thing safe to do with this is that the callers of
- * do_arm_semihosting() will write it straight back into X0.
+ * do_common_semihosting() will write it straight back into X0.
  * (In linux-user mode, the callback will have happened before
  * gdb_do_syscallv() returns.)
  *
  * We should tidy this up so neither this function nor
- * do_arm_semihosting() return a value, so the mistake of
+ * do_common_semihosting() return a value, so the mistake of
  * doing something with the return value is not possible to make.
  */
 
@@ -675,10 +679,10 @@ static const GuestFDFunctions guestfd_fns[] = {
  * leave the register unchanged. We use 0xdeadbeef as the return value
  * when there isn't a defined return value for the call.
  */
-target_ulong do_arm_semihosting(CPUARMState *env)
+target_ulong do_common_semihosting(CPUState *cs)
 {
-ARMCPU *cpu = env_archcpu(env);
-CPUState *cs = env_cpu(env);
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
 char * s;
diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h
new file mode 100644
index 00..bc53e92c79
--- /dev/null
+++ b/hw/semihosting/common-semi.h
@@ -0,0 +1,36 @@
+/*
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
+ *
+ *  Copyright (c) 2005, 2007 CodeSourcery.
+ *  Copyright (c) 2019 Linaro
+ *  Written by Paul Brook.
+ *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ *
+ *  ARM Semihosting is documented in:
+ * Semihosting for AArch32 and AArch64 Release 2.0
+ * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ */
+
+#ifndef COMMON_SEMI_H
+#define COMMON_SEMI_H
+
+target_ulong do_common_semihosting(CPUState *cs);
+
+#endif /* COMMON_SEMI_H */
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index bbe9fefca8..42b9c15f53 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -22,6 +22,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "qemu/guest-random.h"
+#include "hw/semihosting/common-semi.h"
 
 #define get_user_code_u32(x, gaddr, env)\
 ({ abi_long __r = get_user_u32((x), (gaddr));   \
@@ -129,7 +130,7 @@ void cpu_loop(CPUARMState *env)
 queue_signal(env, info.si_signo, QEMU_SI_FAULT, );
 

[PATCH 6/9] riscv: Add semihosting support for user mode

2020-12-14 Thread Keith Packard via
From: Kito Cheng 

This could made testing more easier and ARM/AArch64 has supported on
their linux user mode too, so I think it should be reasonable.

Verified GCC testsuite with newlib/semihosting.

Signed-off-by: Kito Cheng 
Reviewed-by: Keith Packard 
---
 linux-user/riscv/cpu_loop.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index aa9e437875..9665dabb09 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -23,6 +23,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "elf.h"
+#include "hw/semihosting/common-semi.h"
 
 void cpu_loop(CPURISCVState *env)
 {
@@ -91,6 +92,10 @@ void cpu_loop(CPURISCVState *env)
 sigcode = TARGET_SEGV_MAPERR;
 sigaddr = env->badaddr;
 break;
+case RISCV_EXCP_SEMIHOST:
+env->gpr[xA0] = do_common_semihosting(cs);
+env->pc += 4;
+break;
 case EXCP_DEBUG:
 gdbstep:
 signum = TARGET_SIGTRAP;
-- 
2.29.2




[PATCH 7/9] semihosting: Implement SYS_ELAPSED and SYS_TICKFREQ

2020-12-14 Thread Keith Packard via
These are part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 16 
 include/qemu/timer.h |  2 ++
 util/qemu-timer-common.c |  4 
 3 files changed, 22 insertions(+)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index f0cf5f10f5..b1368d945c 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -38,6 +38,7 @@
 #include "hw/semihosting/console.h"
 #include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
+#include "qemu/timer.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
@@ -73,6 +74,8 @@
 #define TARGET_SYS_EXIT0x18
 #define TARGET_SYS_SYNCCACHE   0x19
 #define TARGET_SYS_EXIT_EXTENDED 0x20
+#define TARGET_SYS_ELAPSED 0x30
+#define TARGET_SYS_TICKFREQ0x31
 
 /* ADP_Stopped_ApplicationExit is used for exit(0),
  * anything else is implemented as exit(1) */
@@ -837,6 +840,7 @@ target_ulong do_common_semihosting(CPUState *cs)
 uint32_t ret;
 uint32_t len;
 GuestFD *gf;
+int64_t elapsed;
 
 (void) env; /* Used implicitly by arm lock_user macro */
 nr = common_semi_arg(cs, 0) & 0xU;
@@ -1246,6 +1250,18 @@ target_ulong do_common_semihosting(CPUState *cs)
 }
 gdb_exit(cs->env_ptr, ret);
 exit(ret);
+case TARGET_SYS_ELAPSED:
+elapsed = get_clock() - clock_start;
+if (sizeof(target_ulong) == 8) {
+SET_ARG(0, elapsed);
+} else {
+SET_ARG(0, (uint32_t) elapsed);
+SET_ARG(1, (uint32_t) (elapsed >> 32));
+}
+return 0;
+case TARGET_SYS_TICKFREQ:
+/* qemu always uses nsec */
+return 10;
 case TARGET_SYS_SYNCCACHE:
 /*
  * Clean the D-cache and invalidate the I-cache for the specified
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index bdecc5b41f..ca6fae51f1 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -806,6 +806,8 @@ static inline int64_t get_clock_realtime(void)
 return tv.tv_sec * 10LL + (tv.tv_usec * 1000);
 }
 
+extern int64_t clock_start;
+
 /* Warning: don't insert tracepoints into these functions, they are
also used by simpletrace backend and tracepoints would cause
an infinite recursion! */
diff --git a/util/qemu-timer-common.c b/util/qemu-timer-common.c
index baf3317f74..cc1326f726 100644
--- a/util/qemu-timer-common.c
+++ b/util/qemu-timer-common.c
@@ -27,6 +27,8 @@
 /***/
 /* real time host monotonic timer */
 
+int64_t clock_start;
+
 #ifdef _WIN32
 
 int64_t clock_freq;
@@ -41,6 +43,7 @@ static void __attribute__((constructor)) init_get_clock(void)
 exit(1);
 }
 clock_freq = freq.QuadPart;
+clock_start = get_clock();
 }
 
 #else
@@ -55,5 +58,6 @@ static void __attribute__((constructor)) init_get_clock(void)
 if (clock_gettime(CLOCK_MONOTONIC, ) == 0) {
 use_rt_clock = 1;
 }
+clock_start = get_clock();
 }
 #endif
-- 
2.29.2




[PATCH 4/9] semihosting: Support SYS_HEAPINFO when env->boot_info is not set

2020-12-14 Thread Keith Packard via
env->boot_info is only set in some ARM startup paths, so we cannot
rely on it to support the SYS_HEAPINFO semihosting function. When not
available, fallback to finding a RAM memory region containing the
current stack and use the base of that.

Signed-off-by: Keith Packard 

---

v2
Explicitly convert 64-bits to 128-bits in find_region_base
for hosts that don't have native 128-bit int type.
---
 hw/semihosting/common-semi.c | 43 +++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 33c82f73b1..f09deff4d3 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -137,6 +137,36 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifndef CONFIG_USER_ONLY
+#include "exec/address-spaces.h"
+/*
+ * Find the base of a RAM region containing the specified address
+ */
+static inline hwaddr
+common_semi_find_region_base(hwaddr addr)
+{
+MemoryRegion *subregion;
+
+/*
+ * Find the chunk of R/W memory containing the address.  This is
+ * used for the SYS_HEAPINFO semihosting call, which should
+ * probably be using information from the loaded application.
+ */
+QTAILQ_FOREACH(subregion, _system_memory()->subregions,
+   subregions_link) {
+if (subregion->ram && !subregion->readonly) {
+Int128 top128 = int128_add(int128_make64(subregion->addr),
+   subregion->size);
+Int128 addr128 = int128_make64(addr);
+if (subregion->addr <= addr && int128_lt(addr128, top128)) {
+return subregion->addr;
+}
+}
+}
+return 0;
+}
+#endif
+
 #ifdef TARGET_ARM
 static inline target_ulong
 common_semi_arg(CPUState *cs, int argno)
@@ -175,7 +205,18 @@ common_semi_rambase(CPUState *cs)
 {
 CPUArchState *env = cs->env_ptr;
 const struct arm_boot_info *info = env->boot_info;
-return info->loader_start;
+target_ulong sp;
+
+if (info) {
+return info->loader_start;
+}
+
+if (is_a64(env)) {
+sp = env->xregs[31];
+} else {
+sp = env->regs[13];
+}
+return common_semi_find_region_base(sp);
 }
 #endif
 
-- 
2.29.2




[PATCH 3/9] semihosting: Change internal common-semi interfaces to use CPUState *

2020-12-14 Thread Keith Packard via
This makes all of the internal interfaces architecture-independent and
renames the internal functions to use the 'common_semi' prefix instead
of 'arm' or 'arm_semi'.

To do this, some new architecture-specific internal helper functions
were created:

static inline target_ulong
common_semi_arg(CPUState *cs, int argno)

Returns the argno'th semihosting argument, where argno can be
either 0 or 1.

static inline void
common_semi_set_ret(CPUState *cs, target_ulong ret)

Sets the semihosting return value.

static inline bool
common_semi_sys_exit_extended(CPUState *cs, int nr)

This detects whether the specified semihosting call, which
is either TARGET_SYS_EXIT or TARGET_SYS_EXIT_EXTENDED should
be executed using the TARGET_SYS_EXIT_EXTENDED semantics.

static inline target_ulong
common_semi_rambase(CPUState *cs)

Returns the base of RAM region used for heap and stack. This
is used to construct plausible values for the SYS_HEAPINFO
call.

In addition, several existing functions have been changed to flag
areas of code which are architecture specific:

static target_ulong
common_semi_flen_buf(CPUState *cs)

Returns the current stack pointer minus 64, which is
where a stat structure will be placed on the stack

#define GET_ARG(n)

This fetches arguments from the semihosting command's argument
block. The address of this is available implicitly through the
local 'args' variable. This is *mostly* architecture
independent, but does depend on the current ABI's notion of
the size of a 'long' parameter, which may need run-time checks
(as it does on AARCH64)

#define SET_ARG(n, val)

This mirrors GET_ARG and stores data back into the argument
block.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 



v2:
Add common_semi_rambase hook to get memory address for
SYS_HEAPINFO call.
---
 hw/semihosting/common-semi.c | 351 +++
 1 file changed, 187 insertions(+), 164 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 74f09c038c..33c82f73b1 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -32,15 +32,18 @@
 #include "cpu.h"
 #include "hw/semihosting/semihost.h"
 #include "hw/semihosting/console.h"
+#include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
-#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "exec/gdbstub.h"
 #include "qemu/cutils.h"
+#ifdef TARGET_ARM
 #include "hw/arm/boot.h"
+#endif
 #include "hw/boards.h"
 #endif
 
@@ -134,6 +137,50 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifdef TARGET_ARM
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env)) {
+return env->xregs[argno];
+} else {
+return env->regs[argno];
+}
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env)) {
+env->xregs[0] = ret;
+} else {
+env->regs[0] = ret;
+}
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
+}
+
+#ifndef CONFIG_USER_ONLY
+#include "hw/arm/boot.h"
+static inline target_ulong
+common_semi_rambase(CPUState *cs)
+{
+CPUArchState *env = cs->env_ptr;
+const struct arm_boot_info *info = env->boot_info;
+return info->loader_start;
+}
+#endif
+
+#endif /* TARGET_ARM */
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -239,11 +286,10 @@ static target_ulong syscall_err;
 #include "exec/softmmu-semi.h"
 #endif
 
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
 {
 if (code == (uint32_t)-1) {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 ts->swi_errno = errno;
@@ -254,10 +300,9 @@ static inline uint32_t set_swi_errno(CPUARMState *env, 
uint32_t code)
 return code;
 }
 
-static inline uint32_t get_swi_errno(CPUARMState *env)
+static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 return ts->swi_errno;
@@ -266,24 +311,22 @@ static inline uint32_t get_swi_errno(CPUARMState *env)
 #endif
 }
 
-static target_ulong arm_semi_syscall_len;
+static target_ulong common_semi_syscall_len;
 
-static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void common_semi_cb(CPUState 

[PATCH 0/9] Add RISC-V semihosting 0.2. Finish ARM semihosting 2.0

2020-12-14 Thread Keith Packard via
This series adds support for RISC-V Semihosting, version 0.2 as
specified here:

https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

This specification references the ARM semihosting release 2.0 as specified here:

https://static.docs.arm.com/100863/0200/semihosting.pdf

That specification includes several semihosting calls which were not
previously implemented. This series includes implementations for the
remaining calls so that both RISC-V and ARM versions are now complete.

Tests for release 2.0 can be found in picolibc on the semihost-2.0-all
branch:

https://github.com/picolibc/picolibc/tree/semihost-2.0-all

These tests uncovered a bug in the SYS_HEAPINFO implementation for
ARM, which has been fixed in this series as well.

The series is structured as follows:

 1. Move shared semihosting files
 2. Change public common semihosting APIs
 3. Change internal semihosting interfaces
 4. Fix SYS_HEAPINFO crash on ARM
 5-6. Add RISC-V semihosting implementation
 7-9. Add missing semihosting operations from release 2.0

Signed-off-by: Keith Packard 





Re: [PATCH 0/8] Add RISC-V semihosting 0.2. Finish ARM semihosting 2.0

2020-12-14 Thread Keith Packard via
Alex Bennée  writes:

> Hmm scratch that... it fails in a number of linux-user only builds with:
>
>   /usr/bin/ld: 
> libqemu-aarch64_be-linux-user.fa.p/linux-user_aarch64_cpu_loop.c.o: in 
> function `cpu_loop':
>   /builds/stsquad/qemu/build/../linux-user/aarch64/cpu_loop.c:133: undefined 
> reference to `do_common_semihosting'
>   collect2: error: ld returned 1 exit status
>   [651/2871] Compiling C object 
> libqemu-alpha-linux-user.fa.p/target_alpha_translate.c.o
>   ninja: build stopped: subcommand failed.

I missed changing default-configs/targets/aarch64_be-linux-user.mak.

>   https://gitlab.com/stsquad/qemu/-/pipelines/229443833/failures

Some of these were caused by a missing explicit cast to Int128, which is
needed on hosts without compiler support for 128-bit ints. The rest
app to have been the same problem with aarch64_be-linux-user.

> On the next re-spin could you include Kito Cheng's patch for linux-user
> support and also drop the version numbering from the commit titles so I
> don't have to file them off again.

Yup, all done. Thanks much for the review and for getting these tests
run. I've rebased on current master and fixed the problems identified
above.

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH 5/8] riscv: Add semihosting support [v13]

2020-12-09 Thread Keith Packard via
Kito Cheng  writes:

> Hi Keith:
>
> Thanks for your reply, but it seems like we need some more modification in
>  linux-user/riscv/cpu_loop.c to enable that, I guess I should post that in 
> mail
> rather than attachment :)

Ah, I completely missed the attachment! So sorry. That applies cleanly
on top of the rest of my series, so I think we can just leave it like
that unless someone wants it presented differently. Not sure why I
thought this was working before; I clearly missed the most important
bit.

Reviewed-by: Keith Packard 

I've got a github repo with these bits in case anyone wants to look at
the whole tree:

https://github.com/keith-packard/qemu/tree/semihosting

-- 
-keith


signature.asc
Description: PGP signature


Re: [PATCH 5/8] riscv: Add semihosting support [v13]

2020-12-09 Thread Keith Packard via
Kito Cheng  writes:

> Hi Keith:
>
> Thanks for the patch, I've verified with newlib semihosting support
> which is contributed by Craig Blackmore from embecosm,
> and I would like to add semihosting to user mode, do you mind add this
> patch into this patch series?

I tried to add that already, but I admit that I haven't tested it in a
while. You should find that there are patches to linux-user/semihost.c
and linux-user/qemu.h to enable it.

-- 
-keith


signature.asc
Description: PGP signature


[PATCH 4/8] semihosting: Support SYS_HEAPINFO when env->boot_info is not set

2020-11-25 Thread Keith Packard via
env->boot_info is only set in some ARM startup paths, so we cannot
rely on it to support the SYS_HEAPINFO semihosting function. When not
available, fallback to finding a RAM memory region containing the
current stack and use the base of that.

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 42 +++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 27bdfd0e83..ddfa448cc2 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -133,6 +133,35 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifndef CONFIG_USER_ONLY
+#include "exec/address-spaces.h"
+/*
+ * Find the base of a RAM region containing the specified address
+ */
+static inline hwaddr
+common_semi_find_region_base(hwaddr addr)
+{
+MemoryRegion *subregion;
+
+/*
+ * Find the chunk of R/W memory containing the address.  This is
+ * used for the SYS_HEAPINFO semihosting call, which should
+ * probably be using information from the loaded application.
+ */
+QTAILQ_FOREACH(subregion, _system_memory()->subregions,
+   subregions_link) {
+if (subregion->ram && !subregion->readonly) {
+Int128 top128 = int128_add(int128_make64(subregion->addr),
+   subregion->size);
+if (subregion->addr <= addr && int128_lt(addr, top128)) {
+return subregion->addr;
+}
+}
+}
+return 0;
+}
+#endif
+
 #ifdef TARGET_ARM
 static inline target_ulong
 common_semi_arg(CPUState *cs, int argno)
@@ -171,7 +200,18 @@ common_semi_rambase(CPUState *cs)
 {
 CPUArchState *env = cs->env_ptr;
 const struct arm_boot_info *info = env->boot_info;
-return info->loader_start;
+target_ulong sp;
+
+if (info) {
+return info->loader_start;
+}
+
+if (is_a64(env)) {
+sp = env->xregs[31];
+} else {
+sp = env->regs[13];
+}
+return common_semi_find_region_base(sp);
 }
 #endif
 
-- 
2.29.2




[PATCH 6/8] semihosting: Implement SYS_ELAPSED and SYS_TICKFREQ

2020-11-25 Thread Keith Packard via
These are part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 16 
 include/qemu/timer.h |  2 ++
 util/qemu-timer-common.c |  4 
 3 files changed, 22 insertions(+)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 2b6a3fd9fd..c84b0d906b 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -38,6 +38,7 @@
 #include "hw/semihosting/console.h"
 #include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
+#include "qemu/timer.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
@@ -69,6 +70,8 @@
 #define TARGET_SYS_EXIT0x18
 #define TARGET_SYS_SYNCCACHE   0x19
 #define TARGET_SYS_EXIT_EXTENDED 0x20
+#define TARGET_SYS_ELAPSED 0x30
+#define TARGET_SYS_TICKFREQ0x31
 
 /* ADP_Stopped_ApplicationExit is used for exit(0),
  * anything else is implemented as exit(1) */
@@ -832,6 +835,7 @@ target_ulong do_common_semihosting(CPUState *cs)
 uint32_t ret;
 uint32_t len;
 GuestFD *gf;
+int64_t elapsed;
 
 (void) env; /* Used implicitly by arm lock_user macro */
 nr = common_semi_arg(cs, 0) & 0xU;
@@ -1241,6 +1245,18 @@ target_ulong do_common_semihosting(CPUState *cs)
 }
 gdb_exit(cs->env_ptr, ret);
 exit(ret);
+case TARGET_SYS_ELAPSED:
+elapsed = get_clock() - clock_start;
+if (sizeof(target_ulong) == 8) {
+SET_ARG(0, elapsed);
+} else {
+SET_ARG(0, (uint32_t) elapsed);
+SET_ARG(1, (uint32_t) (elapsed >> 32));
+}
+return 0;
+case TARGET_SYS_TICKFREQ:
+/* qemu always uses nsec */
+return 10;
 case TARGET_SYS_SYNCCACHE:
 /*
  * Clean the D-cache and invalidate the I-cache for the specified
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index bdecc5b41f..ca6fae51f1 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -806,6 +806,8 @@ static inline int64_t get_clock_realtime(void)
 return tv.tv_sec * 10LL + (tv.tv_usec * 1000);
 }
 
+extern int64_t clock_start;
+
 /* Warning: don't insert tracepoints into these functions, they are
also used by simpletrace backend and tracepoints would cause
an infinite recursion! */
diff --git a/util/qemu-timer-common.c b/util/qemu-timer-common.c
index baf3317f74..cc1326f726 100644
--- a/util/qemu-timer-common.c
+++ b/util/qemu-timer-common.c
@@ -27,6 +27,8 @@
 /***/
 /* real time host monotonic timer */
 
+int64_t clock_start;
+
 #ifdef _WIN32
 
 int64_t clock_freq;
@@ -41,6 +43,7 @@ static void __attribute__((constructor)) init_get_clock(void)
 exit(1);
 }
 clock_freq = freq.QuadPart;
+clock_start = get_clock();
 }
 
 #else
@@ -55,5 +58,6 @@ static void __attribute__((constructor)) init_get_clock(void)
 if (clock_gettime(CLOCK_MONOTONIC, ) == 0) {
 use_rt_clock = 1;
 }
+clock_start = get_clock();
 }
 #endif
-- 
2.29.2




[PATCH 8/8] semihosting: Implement SYS_ISERROR

2020-11-25 Thread Keith Packard via
Part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 9a04d98e4e..fda0e714ef 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -55,6 +55,7 @@
 #define TARGET_SYS_WRITE   0x05
 #define TARGET_SYS_READ0x06
 #define TARGET_SYS_READC   0x07
+#define TARGET_SYS_ISERROR 0x08
 #define TARGET_SYS_ISTTY   0x09
 #define TARGET_SYS_SEEK0x0a
 #define TARGET_SYS_FLEN0x0c
@@ -962,6 +963,9 @@ target_ulong do_common_semihosting(CPUState *cs)
 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len);
 case TARGET_SYS_READC:
 return qemu_semihosting_console_inc(cs->env_ptr);
+case TARGET_SYS_ISERROR:
+GET_ARG(0);
+return (target_long) arg0 < 0 ? 1 : 0;
 case TARGET_SYS_ISTTY:
 GET_ARG(0);
 
-- 
2.29.2




[PATCH 7/8] semihosting: Implement SYS_TMPNAM

2020-11-25 Thread Keith Packard via
Part of Semihosting for AArch32 and AArch64 Release 2.0

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 21 +++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index c84b0d906b..9a04d98e4e 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -830,6 +830,7 @@ target_ulong do_common_semihosting(CPUState *cs)
 CPUArchState *env = cs->env_ptr;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
+target_ulong ul_ret;
 char * s;
 int nr;
 uint32_t ret;
@@ -993,8 +994,24 @@ target_ulong do_common_semihosting(CPUState *cs)
 
 return guestfd_fns[gf->type].flenfn(cs, gf);
 case TARGET_SYS_TMPNAM:
-qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
-return -1;
+GET_ARG(0);
+GET_ARG(1);
+GET_ARG(2);
+if (asprintf(, "/tmp/qemu-%x%02x", getpid(),
+ (int) (arg1 & 0xff)) < 0) {
+return -1;
+}
+ul_ret = (target_ulong) -1;
+
+/* Make sure there's enough space in the buffer */
+if (strlen(s) < arg2) {
+char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0);
+strcpy(output, s);
+unlock_user(output, arg0, arg2);
+ul_ret = 0;
+}
+free(s);
+return ul_ret;
 case TARGET_SYS_REMOVE:
 GET_ARG(0);
 GET_ARG(1);
-- 
2.29.2




[PATCH 5/8] riscv: Add semihosting support [v13]

2020-11-25 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support

v8:
Fix errors reported by checkpatch that crept in.

v9:
Changes suggested by Alistair Francis :
Don't add me to the MAINTAINERS file.
Remove duplicate #include in target/riscv/cpu.h
Reference RISC-V semihosting spec in target/riscv/riscv-semi.c

v10:
Use common semihosting implementation instead of a separate copy.

Make sure addresses of the three breakpoint-signaling
instructions all lie within the same page. Change suggested by
Richard Henderson 

v11:
Use CONFIG_ARM_COMPATIBLE_SEMIHOSTING

v12:
Fix bug in SYS_EXIT support on rv64

v13:
Add common_semi_rambase implementation. This locates the
memory region containing the stack and uses the base of that.

Fix SET_ARG and GET_ARG on rv64 targets to operate on 64-bit
values rather than 32-bit. Put_user_ual/get_user_ual are
confusingly defined by softmmu-semi.h as being equivalent to
put_user_u32/get_user_u32.
---
 default-configs/devices/riscv32-softmmu.mak   |  2 +
 default-configs/devices/riscv64-softmmu.mak   |  2 +
 .../targets/riscv32-linux-user.mak|  1 +
 .../targets/riscv64-linux-user.mak|  1 +
 hw/semihosting/common-semi.c  | 82 ++-
 hw/semihosting/common-semi.h  |  5 +-
 linux-user/qemu.h |  4 +-
 linux-user/semihost.c |  8 +-
 qemu-options.hx   | 10 ++-
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu_helper.c | 10 +++
 .../riscv/insn_trans/trans_privileged.c.inc   | 37 -
 target/riscv/translate.c  | 11 +++
 13 files changed, 162 insertions(+), 12 deletions(-)

diff --git a/default-configs/devices/riscv32-softmmu.mak 
b/default-configs/devices/riscv32-softmmu.mak
index 94a236c9c2..d847bd5692 100644
--- a/default-configs/devices/riscv32-softmmu.mak
+++ b/default-configs/devices/riscv32-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/devices/riscv64-softmmu.mak 
b/default-configs/devices/riscv64-softmmu.mak
index 76b6195648..d5eec75f05 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/targets/riscv32-linux-user.mak 
b/default-configs/targets/riscv32-linux-user.mak
index dfb259e8aa..6a9d1b1bc1 100644
--- a/default-configs/targets/riscv32-linux-user.mak
+++ b/default-configs/targets/riscv32-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv32
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-csr.xml 
gdb-xml/riscv-32bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/riscv64-linux-user.mak 
b/default-configs/targets/riscv64-linux-user.mak
index b13895f3b0..0a92849a1b 100644
--- a/default-configs/targets/riscv64-linux-user.mak
+++ b/default-configs/targets/riscv64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv64
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-csr.xml 
gdb-xml/riscv-64bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index ddfa448cc2..2b6a3fd9fd 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,6 +1,6 @@
 /*
  *  Semihosting support for systems modeled on the Arm "Angel"
- *  semihosting syscalls design.
+ *  semihosting syscalls design. This includes Arm and RISC-V processors
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
@@ -25,6 +25,10 @@
  *  ARM Semihosting is documented in:
  * Semihosting for AArch32 and AArch64 Release 2.0
  *   

[PATCH 3/8] semihosting: Change internal common-semi interfaces to use CPUState * [v2]

2020-11-25 Thread Keith Packard via
This makes all of the internal interfaces architecture-independent and
renames the internal functions to use the 'common_semi' prefix instead
of 'arm' or 'arm_semi'.

To do this, some new architecture-specific internal helper functions
were created:

static inline target_ulong
common_semi_arg(CPUState *cs, int argno)

Returns the argno'th semihosting argument, where argno can be
either 0 or 1.

static inline void
common_semi_set_ret(CPUState *cs, target_ulong ret)

Sets the semihosting return value.

static inline bool
common_semi_sys_exit_extended(CPUState *cs, int nr)

This detects whether the specified semihosting call, which
is either TARGET_SYS_EXIT or TARGET_SYS_EXIT_EXTENDED should
be executed using the TARGET_SYS_EXIT_EXTENDED semantics.

static inline target_ulong
common_semi_rambase(CPUState *cs)

Returns the base of RAM region used for heap and stack. This
is used to construct plausible values for the SYS_HEAPINFO
call.

In addition, several existing functions have been changed to flag
areas of code which are architecture specific:

static target_ulong
common_semi_flen_buf(CPUState *cs)

Returns the current stack pointer minus 64, which is
where a stat structure will be placed on the stack

#define GET_ARG(n)

This fetches arguments from the semihosting command's argument
block. The address of this is available implicitly through the
local 'args' variable. This is *mostly* architecture
independent, but does depend on the current ABI's notion of
the size of a 'long' parameter, which may need run-time checks
(as it does on AARCH64)

#define SET_ARG(n, val)

This mirrors GET_ARG and stores data back into the argument
block.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 



v2:
Add common_semi_rambase hook to get memory address for
SYS_HEAPINFO call.
---
 hw/semihosting/common-semi.c | 350 ++-
 1 file changed, 185 insertions(+), 165 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index cafbe579c7..27bdfd0e83 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -32,15 +32,15 @@
 #include "cpu.h"
 #include "hw/semihosting/semihost.h"
 #include "hw/semihosting/console.h"
+#include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
-#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "exec/gdbstub.h"
 #include "qemu/cutils.h"
-#include "hw/arm/boot.h"
 #endif
 
 #define TARGET_SYS_OPEN0x01
@@ -133,6 +133,50 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifdef TARGET_ARM
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env)) {
+return env->xregs[argno];
+} else {
+return env->regs[argno];
+}
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env)) {
+env->xregs[0] = ret;
+} else {
+env->regs[0] = ret;
+}
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
+}
+
+#ifndef CONFIG_USER_ONLY
+#include "hw/arm/boot.h"
+static inline target_ulong
+common_semi_rambase(CPUState *cs)
+{
+CPUArchState *env = cs->env_ptr;
+const struct arm_boot_info *info = env->boot_info;
+return info->loader_start;
+}
+#endif
+
+#endif /* TARGET_ARM */
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -238,11 +282,10 @@ static target_ulong syscall_err;
 #include "exec/softmmu-semi.h"
 #endif
 
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
 {
 if (code == (uint32_t)-1) {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 ts->swi_errno = errno;
@@ -253,10 +296,9 @@ static inline uint32_t set_swi_errno(CPUARMState *env, 
uint32_t code)
 return code;
 }
 
-static inline uint32_t get_swi_errno(CPUARMState *env)
+static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 return ts->swi_errno;
@@ -265,24 +307,22 @@ static inline uint32_t get_swi_errno(CPUARMState *env)
 #endif
 }
 
-static target_ulong arm_semi_syscall_len;
+static target_ulong common_semi_syscall_len;
 
-static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void common_semi_cb(CPUState *cs, target_ulong 

[PATCH 1/8] semihosting: Move ARM semihosting code to shared directories [v3]

2020-11-25 Thread Keith Packard via
This commit renames two files which provide ARM semihosting support so
that they can be shared by other architectures:

 1. target/arm/arm-semi.c -> hw/semihosting/common-semi.c
 2. linux-user/arm/semihost.c -> linux-user/semihost.c

The build system was modified use a new config variable,
CONFIG_ARM_COMPATIBLE_SEMIHOSTING, which has been added to the ARM
softmmu and linux-user default configs. The contents of the source
files has not been changed in this patch.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 



v2
Place common-semi.c name in arm_ss, just as arm-semi.c was

v3
Create CONFIG_ARM_COMPATIBLE_SEMIHOSTING and assign in
arm config files
---
 default-configs/devices/arm-softmmu.mak   | 1 +
 default-configs/targets/aarch64-linux-user.mak| 1 +
 default-configs/targets/arm-linux-user.mak| 1 +
 hw/semihosting/Kconfig| 3 +++
 target/arm/arm-semi.c => hw/semihosting/common-semi.c | 0
 hw/semihosting/meson.build| 3 +++
 linux-user/arm/meson.build| 3 ---
 linux-user/meson.build| 1 +
 linux-user/{arm => }/semihost.c   | 0
 target/arm/meson.build| 2 --
 10 files changed, 10 insertions(+), 5 deletions(-)
 rename target/arm/arm-semi.c => hw/semihosting/common-semi.c (100%)
 rename linux-user/{arm => }/semihost.c (100%)

diff --git a/default-configs/devices/arm-softmmu.mak 
b/default-configs/devices/arm-softmmu.mak
index 08a32123b4..0500156a0c 100644
--- a/default-configs/devices/arm-softmmu.mak
+++ b/default-configs/devices/arm-softmmu.mak
@@ -42,4 +42,5 @@ CONFIG_FSL_IMX25=y
 CONFIG_FSL_IMX7=y
 CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 CONFIG_ALLWINNER_H3=y
diff --git a/default-configs/targets/aarch64-linux-user.mak 
b/default-configs/targets/aarch64-linux-user.mak
index 163c9209f4..4713253709 100644
--- a/default-configs/targets/aarch64-linux-user.mak
+++ b/default-configs/targets/aarch64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=aarch64
 TARGET_BASE_ARCH=arm
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml 
gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml 
gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/arm-linux-user.mak 
b/default-configs/targets/arm-linux-user.mak
index c7cd872e86..e741ffd4d3 100644
--- a/default-configs/targets/arm-linux-user.mak
+++ b/default-configs/targets/arm-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_SYSTBL_ABI=common,oabi
 TARGET_SYSTBL=syscall.tbl
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml 
gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/Kconfig b/hw/semihosting/Kconfig
index efe0a30734..4c30dc6b16 100644
--- a/hw/semihosting/Kconfig
+++ b/hw/semihosting/Kconfig
@@ -1,3 +1,6 @@
 
 config SEMIHOSTING
bool
+
+config ARM_COMPATIBLE_SEMIHOSTING
+   bool
diff --git a/target/arm/arm-semi.c b/hw/semihosting/common-semi.c
similarity index 100%
rename from target/arm/arm-semi.c
rename to hw/semihosting/common-semi.c
diff --git a/hw/semihosting/meson.build b/hw/semihosting/meson.build
index f40ac574c4..5b4a170270 100644
--- a/hw/semihosting/meson.build
+++ b/hw/semihosting/meson.build
@@ -2,3 +2,6 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
   'config.c',
   'console.c',
 ))
+
+specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
+   if_true: files('common-semi.c'))
diff --git a/linux-user/arm/meson.build b/linux-user/arm/meson.build
index 432984b58e..5a93c925cf 100644
--- a/linux-user/arm/meson.build
+++ b/linux-user/arm/meson.build
@@ -1,6 +1,3 @@
-linux_user_ss.add(when: 'TARGET_AARCH64', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'TARGET_ARM', if_true: files('semihost.c'))
-
 subdir('nwfpe')
 
 syscall_nr_generators += {
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..7fe28d659e 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -16,6 +16,7 @@ linux_user_ss.add(rt)
 
 linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
 linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
+linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: 
files('semihost.c'))
 
 
 syscall_nr_generators = {}
diff --git a/linux-user/arm/semihost.c b/linux-user/semihost.c
similarity index 100%
rename from linux-user/arm/semihost.c
rename to linux-user/semihost.c
diff --git a/target/arm/meson.build b/target/arm/meson.build
index f5de2a77b8..15b936c101 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -32,8 +32,6 @@ arm_ss.add(files(
 ))
 arm_ss.add(zlib)
 
-arm_ss.add(when: 'CONFIG_TCG', if_true: files('arm-semi.c'))
-
 

[PATCH 0/8] Add RISC-V semihosting 0.2. Finish ARM semihosting 2.0

2020-11-25 Thread Keith Packard via
This series adds support for RISC-V Semihosting, version 0.2 as
specified here:

https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

This specification references the ARM semihosting release 2.0 as specified here:

https://static.docs.arm.com/100863/0200/semihosting.pdf

That specification includes several semihosting calls which were not
previously implemented. This series includes implementations for the
remaining calls so that both RISC-V and ARM versions are now complete.

Tests for release 2.0 can be found in picolibc on the semihost-2.0-all
branch:

https://github.com/picolibc/picolibc/tree/semihost-2.0-all

These tests uncovered a bug in the SYS_HEAPINFO implementation for
ARM, which has been fixed in this series as well.

The series is structured as follows:

 1. Move shared semihosting files
 2. Change public common semihosting APIs
 3. Change internal semihosting interfaces
 4. Fix SYS_HEAPINFO crash on ARM
 5. Add RISC-V semihosting implementation
 6-8. Add missing semihosting operations from release 2.0

Signed-off-by: Keith Packard 





[PATCH 2/8] semihosting: Change common-semi API to be architecture-independent

2020-11-25 Thread Keith Packard via
The public API is now defined in
hw/semihosting/common-semi.h. do_common_semihosting takes CPUState *
instead of CPUARMState *. All internal functions have been renamed
common_semi_ instead of arm_semi_ or arm_. Aside from the API change,
there are no functional changes in this patch.

Signed-off-by: Keith Packard 
Reviewed-by: Alistair Francis 
---
 hw/semihosting/common-semi.c  | 16 ++--
 hw/semihosting/common-semi.h  | 36 +++
 linux-user/aarch64/cpu_loop.c |  3 ++-
 linux-user/arm/cpu_loop.c |  3 ++-
 target/arm/cpu.h  |  8 
 target/arm/helper.c   |  5 +++--
 target/arm/m_helper.c |  7 ++-
 7 files changed, 59 insertions(+), 19 deletions(-)
 create mode 100644 hw/semihosting/common-semi.h

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index c892e0e674..cafbe579c7 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,10 +1,14 @@
 /*
- *  Arm "Angel" semihosting syscalls
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
  *  Written by Paul Brook.
  *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -372,12 +376,12 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, 
gdb_syscall_complete_cb cb,
  * do anything with its return value, because it is not necessarily
  * the result of the syscall, but could just be the old value of X0.
  * The only thing safe to do with this is that the callers of
- * do_arm_semihosting() will write it straight back into X0.
+ * do_common_semihosting() will write it straight back into X0.
  * (In linux-user mode, the callback will have happened before
  * gdb_do_syscallv() returns.)
  *
  * We should tidy this up so neither this function nor
- * do_arm_semihosting() return a value, so the mistake of
+ * do_common_semihosting() return a value, so the mistake of
  * doing something with the return value is not possible to make.
  */
 
@@ -674,10 +678,10 @@ static const GuestFDFunctions guestfd_fns[] = {
  * leave the register unchanged. We use 0xdeadbeef as the return value
  * when there isn't a defined return value for the call.
  */
-target_ulong do_arm_semihosting(CPUARMState *env)
+target_ulong do_common_semihosting(CPUState *cs)
 {
-ARMCPU *cpu = env_archcpu(env);
-CPUState *cs = env_cpu(env);
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
 char * s;
diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h
new file mode 100644
index 00..bc53e92c79
--- /dev/null
+++ b/hw/semihosting/common-semi.h
@@ -0,0 +1,36 @@
+/*
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
+ *
+ *  Copyright (c) 2005, 2007 CodeSourcery.
+ *  Copyright (c) 2019 Linaro
+ *  Written by Paul Brook.
+ *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ *
+ *  ARM Semihosting is documented in:
+ * Semihosting for AArch32 and AArch64 Release 2.0
+ * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ */
+
+#ifndef COMMON_SEMI_H
+#define COMMON_SEMI_H
+
+target_ulong do_common_semihosting(CPUState *cs);
+
+#endif /* COMMON_SEMI_H */
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index bbe9fefca8..42b9c15f53 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -22,6 +22,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "qemu/guest-random.h"
+#include "hw/semihosting/common-semi.h"
 
 #define get_user_code_u32(x, gaddr, env)\
 ({ abi_long __r = get_user_u32((x), (gaddr));   \
@@ -129,7 +130,7 @@ void cpu_loop(CPUARMState *env)
 queue_signal(env, info.si_signo, QEMU_SI_FAULT, );
 

[PATCH] semihosting: Merge semihosting console init functions to fix READC

2020-10-28 Thread Keith Packard via
Commit 619985e937 (semihosting: defer connect_chardevs a little more
to use serialx) moved the call to qemu_semihosting_connect_chardevs
until after all of the serial devices were initialized to make
semihosting console configuration easier.

This change broke semihosting console input as the call to
qemu_semihosting_console_init was now made *before*
qemu_semihosting_connect_chardevs, which it requires.

To fix that, and to make sure it doesn't happen in the future, I've
merged these two functions together into
qemu_semihosting_console_init, which finds the Chardev and then wires
up console input.

These were split when semihosting READC was added to control the
priority of semihosting input compared with other users of a
multiplexed console. With connect_chardevs now occuring much later in
qemu initialization, the semihosting console input will have the same
priority as it did before the referenced commit was applied.

Signed-off-by: Keith Packard 
---
 hw/semihosting/config.c   | 21 ++-
 hw/semihosting/console.c  | 58 ++-
 include/hw/semihosting/semihost.h |  4 +--
 softmmu/vl.c  |  5 +--
 4 files changed, 40 insertions(+), 48 deletions(-)

diff --git a/hw/semihosting/config.c b/hw/semihosting/config.c
index 9807f10cb0..1bf3125f0c 100644
--- a/hw/semihosting/config.c
+++ b/hw/semihosting/config.c
@@ -51,14 +51,13 @@ QemuOptsList qemu_semihosting_config_opts = {
 typedef struct SemihostingConfig {
 bool enabled;
 SemihostingTarget target;
-Chardev *chardev;
+const char *chardev;
 const char **argv;
 int argc;
 const char *cmdline; /* concatenated argv */
 } SemihostingConfig;
 
 static SemihostingConfig semihosting;
-static const char *semihost_chardev;
 
 bool semihosting_enabled(void)
 {
@@ -122,7 +121,7 @@ void semihosting_arg_fallback(const char *file, const char 
*cmd)
 }
 }
 
-Chardev *semihosting_get_chardev(void)
+const char *semihosting_get_chardev(void)
 {
 return semihosting.chardev;
 }
@@ -145,7 +144,7 @@ int qemu_semihosting_config_options(const char *optarg)
 true);
 const char *target = qemu_opt_get(opts, "target");
 /* setup of chardev is deferred until they are initialised */
-semihost_chardev = qemu_opt_get(opts, "chardev");
+semihosting.chardev = qemu_opt_get(opts, "chardev");
 if (target != NULL) {
 if (strcmp("native", target) == 0) {
 semihosting.target = SEMIHOSTING_TARGET_NATIVE;
@@ -171,17 +170,3 @@ int qemu_semihosting_config_options(const char *optarg)
 
 return 0;
 }
-
-void qemu_semihosting_connect_chardevs(void)
-{
-/* We had to defer this until chardevs were created */
-if (semihost_chardev) {
-Chardev *chr = qemu_chr_find(semihost_chardev);
-if (chr == NULL) {
-error_report("semihosting chardev '%s' not found",
- semihost_chardev);
-exit(1);
-}
-semihosting.chardev = chr;
-}
-}
diff --git a/hw/semihosting/console.c b/hw/semihosting/console.c
index 9b4fee9260..345f21b8e5 100644
--- a/hw/semihosting/console.c
+++ b/hw/semihosting/console.c
@@ -29,11 +29,23 @@
 #include "qapi/error.h"
 #include "qemu/fifo8.h"
 
+#define FIFO_SIZE   1024
+
+/* Access to this structure is protected by the BQL */
+typedef struct SemihostingConsole {
+CharBackend backend;
+GSList  *sleeping_cpus;
+boolgot;
+Fifo8   fifo;
+Chardev *chardev;
+} SemihostingConsole;
+
+static SemihostingConsole console;
+
 int qemu_semihosting_log_out(const char *s, int len)
 {
-Chardev *chardev = semihosting_get_chardev();
-if (chardev) {
-return qemu_chr_write_all(chardev, (uint8_t *) s, len);
+if (console.chardev) {
+return qemu_chr_write_all(console.chardev, (uint8_t *) s, len);
 } else {
 return write(STDERR_FILENO, s, len);
 }
@@ -107,17 +119,6 @@ void qemu_semihosting_console_outc(CPUArchState *env, 
target_ulong addr)
 }
 }
 
-#define FIFO_SIZE   1024
-
-/* Access to this structure is protected by the BQL */
-typedef struct SemihostingConsole {
-CharBackend backend;
-GSList  *sleeping_cpus;
-boolgot;
-Fifo8   fifo;
-} SemihostingConsole;
-
-static SemihostingConsole console;
 
 static int console_can_read(void *opaque)
 {
@@ -166,15 +167,24 @@ target_ulong qemu_semihosting_console_inc(CPUArchState 
*env)
 
 void qemu_semihosting_console_init(void)
 {
-Chardev *chr = semihosting_get_chardev();
-
-if  (chr) {
-fifo8_create(, FIFO_SIZE);
-qemu_chr_fe_init(, chr, _abort);
-qemu_chr_fe_set_handlers(,
- console_can_read,
- console_read,
- NULL, NULL, ,
- 

[PATCH 4/4] riscv: Add semihosting support [v11]

2020-10-28 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support

v8:
Fix errors reported by checkpatch that crept in.

v9:
Changes suggested by Alistair Francis :
Don't add me to the MAINTAINERS file.
Remove duplicate #include in target/riscv/cpu.h
Reference RISC-V semihosting spec in target/riscv/riscv-semi.c

v10:
Use common semihosting implementation instead of a separate copy.

Make sure addresses of the three breakpoint-signaling
instructions all lie within the same page. Change suggested by
Richard Henderson 

v11:
Use CONFIG_ARM_COMPATIBLE_SEMIHOSTING
---
 default-configs/devices/riscv32-softmmu.mak   |  2 +
 default-configs/devices/riscv64-softmmu.mak   |  2 +
 .../targets/riscv32-linux-user.mak|  1 +
 .../targets/riscv64-linux-user.mak|  1 +
 hw/semihosting/common-semi.c  | 51 ++-
 hw/semihosting/common-semi.h  |  5 +-
 linux-user/qemu.h |  4 +-
 linux-user/semihost.c |  8 +--
 qemu-options.hx   | 10 ++--
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu_helper.c | 10 
 .../riscv/insn_trans/trans_privileged.c.inc   | 37 +-
 target/riscv/translate.c  | 11 
 13 files changed, 131 insertions(+), 12 deletions(-)

diff --git a/default-configs/devices/riscv32-softmmu.mak 
b/default-configs/devices/riscv32-softmmu.mak
index 94a236c9c2..d847bd5692 100644
--- a/default-configs/devices/riscv32-softmmu.mak
+++ b/default-configs/devices/riscv32-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/devices/riscv64-softmmu.mak 
b/default-configs/devices/riscv64-softmmu.mak
index 76b6195648..d5eec75f05 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -3,6 +3,8 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/targets/riscv32-linux-user.mak 
b/default-configs/targets/riscv32-linux-user.mak
index dfb259e8aa..6a9d1b1bc1 100644
--- a/default-configs/targets/riscv32-linux-user.mak
+++ b/default-configs/targets/riscv32-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv32
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-csr.xml 
gdb-xml/riscv-32bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/riscv64-linux-user.mak 
b/default-configs/targets/riscv64-linux-user.mak
index b13895f3b0..0a92849a1b 100644
--- a/default-configs/targets/riscv64-linux-user.mak
+++ b/default-configs/targets/riscv64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=riscv64
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml 
gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-csr.xml 
gdb-xml/riscv-64bit-virtual.xml
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index c77fb21bec..8675934a71 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,6 +1,6 @@
 /*
  *  Semihosting support for systems modeled on the Arm "Angel"
- *  semihosting syscalls design.
+ *  semihosting syscalls design. This includes Arm and RISC-V processors
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
@@ -25,6 +25,10 @@
  *  ARM Semihosting is documented in:
  * Semihosting for AArch32 and AArch64 Release 2.0
  * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ *  RISC-V Semihosting is documented in:
+ * RISC-V Semihosting
+ * 
https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
  */
 
 #include "qemu/osdep.h"
@@ -163,6 +167,30 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
 }
 #endif /* TARGET_ARM */
 
+#ifdef TARGET_RISCV
+static inline target_ulong

[PATCH 2/4] semihosting: Change common-semi API to be architecture-independent

2020-10-28 Thread Keith Packard via
The public API is now defined in
hw/semihosting/common-semi.h. do_common_semihosting takes CPUState *
instead of CPUARMState *. All internal functions have been renamed
common_semi_ instead of arm_semi_ or arm_. Aside from the API change,
there are no functional changes in this patch.

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c  | 16 ++--
 hw/semihosting/common-semi.h  | 36 +++
 linux-user/aarch64/cpu_loop.c |  3 ++-
 linux-user/arm/cpu_loop.c |  3 ++-
 target/arm/cpu.h  |  8 
 target/arm/helper.c   |  5 +++--
 target/arm/m_helper.c |  7 ++-
 7 files changed, 59 insertions(+), 19 deletions(-)
 create mode 100644 hw/semihosting/common-semi.h

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 8718fd0194..e0c59bc599 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,10 +1,14 @@
 /*
- *  Arm "Angel" semihosting syscalls
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
  *  Written by Paul Brook.
  *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -371,12 +375,12 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, 
gdb_syscall_complete_cb cb,
  * do anything with its return value, because it is not necessarily
  * the result of the syscall, but could just be the old value of X0.
  * The only thing safe to do with this is that the callers of
- * do_arm_semihosting() will write it straight back into X0.
+ * do_common_semihosting() will write it straight back into X0.
  * (In linux-user mode, the callback will have happened before
  * gdb_do_syscallv() returns.)
  *
  * We should tidy this up so neither this function nor
- * do_arm_semihosting() return a value, so the mistake of
+ * do_common_semihosting() return a value, so the mistake of
  * doing something with the return value is not possible to make.
  */
 
@@ -673,10 +677,10 @@ static const GuestFDFunctions guestfd_fns[] = {
  * leave the register unchanged. We use 0xdeadbeef as the return value
  * when there isn't a defined return value for the call.
  */
-target_ulong do_arm_semihosting(CPUARMState *env)
+target_ulong do_common_semihosting(CPUState *cs)
 {
-ARMCPU *cpu = env_archcpu(env);
-CPUState *cs = env_cpu(env);
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
 char * s;
diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h
new file mode 100644
index 00..bc53e92c79
--- /dev/null
+++ b/hw/semihosting/common-semi.h
@@ -0,0 +1,36 @@
+/*
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
+ *
+ *  Copyright (c) 2005, 2007 CodeSourcery.
+ *  Copyright (c) 2019 Linaro
+ *  Written by Paul Brook.
+ *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ *
+ *  ARM Semihosting is documented in:
+ * Semihosting for AArch32 and AArch64 Release 2.0
+ * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ */
+
+#ifndef COMMON_SEMI_H
+#define COMMON_SEMI_H
+
+target_ulong do_common_semihosting(CPUState *cs);
+
+#endif /* COMMON_SEMI_H */
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index bbe9fefca8..42b9c15f53 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -22,6 +22,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "qemu/guest-random.h"
+#include "hw/semihosting/common-semi.h"
 
 #define get_user_code_u32(x, gaddr, env)\
 ({ abi_long __r = get_user_u32((x), (gaddr));   \
@@ -129,7 +130,7 @@ void cpu_loop(CPUARMState *env)
 queue_signal(env, info.si_signo, QEMU_SI_FAULT, );
 break;
 case 

[PATCH 3/4] semihosting: Change internal common-semi interfaces to use CPUState *

2020-10-28 Thread Keith Packard via
This makes all of the internal interfaces architecture-independent and
renames the internal functions to use the 'common_semi' prefix instead
of 'arm' or 'arm_semi'.

To do this, some new architecture-specific internal helper functions
were created:

static inline target_ulong
common_semi_arg(CPUState *cs, int argno)

Returns the argno'th semihosting argument, where argno can be
either 0 or 1.

static inline void
common_semi_set_ret(CPUState *cs, target_ulong ret)

Sets the semihosting return value.

static inline bool
common_semi_sys_exit_extended(CPUState *cs, int nr)

This detects whether the specified semihosting call, which
is either TARGET_SYS_EXIT or TARGET_SYS_EXIT_EXTENDED should
be executed using the TARGET_SYS_EXIT_EXTENDED semantics.

In addition, several existing functions have been changed to flag
areas of code which are architecture specific:

static target_ulong
common_semi_flen_buf(CPUState *cs)

Returns the current stack pointer minus 64, which is
where a stat structure will be placed on the stack

#define GET_ARG(n)

This fetches arguments from the semihosting command's argument
block. The address of this is available implicitly through the
local 'args' variable. This is *mostly* architecture
independent, but does depend on the current ABI's notion of
the size of a 'long' parameter, which may need run-time checks
(as it does on AARCH64)

#define SET_ARG(n, val)

This mirrors GET_ARG and stores data back into the argument
block.

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 326 ++-
 1 file changed, 164 insertions(+), 162 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index e0c59bc599..c77fb21bec 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -32,11 +32,12 @@
 #include "cpu.h"
 #include "hw/semihosting/semihost.h"
 #include "hw/semihosting/console.h"
+#include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
-#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "exec/gdbstub.h"
 #include "qemu/cutils.h"
@@ -132,6 +133,36 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifdef TARGET_ARM
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env))
+return env->xregs[argno];
+else
+return env->regs[argno];
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env))
+env->xregs[0] = ret;
+else
+env->regs[0] = ret;
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
+}
+#endif /* TARGET_ARM */
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -237,11 +268,10 @@ static target_ulong syscall_err;
 #include "exec/softmmu-semi.h"
 #endif
 
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
 {
 if (code == (uint32_t)-1) {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 ts->swi_errno = errno;
@@ -252,10 +282,9 @@ static inline uint32_t set_swi_errno(CPUARMState *env, 
uint32_t code)
 return code;
 }
 
-static inline uint32_t get_swi_errno(CPUARMState *env)
+static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 return ts->swi_errno;
@@ -264,24 +293,22 @@ static inline uint32_t get_swi_errno(CPUARMState *env)
 #endif
 }
 
-static target_ulong arm_semi_syscall_len;
+static target_ulong common_semi_syscall_len;
 
-static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
-ARMCPU *cpu = ARM_CPU(cs);
-CPUARMState *env = >env;
-target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
+target_ulong reg0 = common_semi_arg(cs, 0);
 
 if (ret == (target_ulong)-1) {
 errno = err;
-set_swi_errno(env, -1);
+set_swi_errno(cs, -1);
 reg0 = ret;
 } else {
 /* Fixup syscalls that use nonstardard return conventions.  */
 switch (reg0) {
 case TARGET_SYS_WRITE:
 case TARGET_SYS_READ:
-reg0 = arm_semi_syscall_len - ret;
+reg0 = common_semi_syscall_len - ret;
 break;
 case TARGET_SYS_SEEK:
 reg0 = 0;
@@ -291,77 

[PATCH 0/4] Add RISC-V semihosting support

2020-10-28 Thread Keith Packard via
This series adapts the existing ARM semihosting code to be
target-independent, and then uses that to provide semihosting support
for RISC-V targets.





[PATCH 1/4] semihosting: Move ARM semihosting code to shared directories [v3]

2020-10-28 Thread Keith Packard via
This commit renames two files which provide ARM semihosting support so
that they can be shared by other architectures:

 1. target/arm/arm-semi.c -> hw/semihosting/common-semi.c
 2. linux-user/arm/semihost.c -> linux-user/semihost.c

The build system was modified use a new config variable,
CONFIG_ARM_COMPATIBLE_SEMIHOSTING, which has been added to the ARM
softmmu and linux-user default configs. The contents of the source
files has not been changed in this patch.

Signed-off-by: Keith Packard 



v2
Place common-semi.c name in arm_ss, just as arm-semi.c was

v3
Create CONFIG_ARM_COMPATIBLE_SEMIHOSTING and assign in
arm config files
---
 default-configs/devices/arm-softmmu.mak   | 1 +
 default-configs/targets/aarch64-linux-user.mak| 1 +
 default-configs/targets/arm-linux-user.mak| 1 +
 hw/semihosting/Kconfig| 3 +++
 target/arm/arm-semi.c => hw/semihosting/common-semi.c | 0
 hw/semihosting/meson.build| 3 +++
 linux-user/arm/meson.build| 3 ---
 linux-user/meson.build| 1 +
 linux-user/{arm => }/semihost.c   | 0
 target/arm/meson.build| 2 --
 10 files changed, 10 insertions(+), 5 deletions(-)
 rename target/arm/arm-semi.c => hw/semihosting/common-semi.c (100%)
 rename linux-user/{arm => }/semihost.c (100%)

diff --git a/default-configs/devices/arm-softmmu.mak 
b/default-configs/devices/arm-softmmu.mak
index 08a32123b4..0500156a0c 100644
--- a/default-configs/devices/arm-softmmu.mak
+++ b/default-configs/devices/arm-softmmu.mak
@@ -42,4 +42,5 @@ CONFIG_FSL_IMX25=y
 CONFIG_FSL_IMX7=y
 CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 CONFIG_ALLWINNER_H3=y
diff --git a/default-configs/targets/aarch64-linux-user.mak 
b/default-configs/targets/aarch64-linux-user.mak
index 163c9209f4..4713253709 100644
--- a/default-configs/targets/aarch64-linux-user.mak
+++ b/default-configs/targets/aarch64-linux-user.mak
@@ -2,3 +2,4 @@ TARGET_ARCH=aarch64
 TARGET_BASE_ARCH=arm
 TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml 
gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml 
gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/default-configs/targets/arm-linux-user.mak 
b/default-configs/targets/arm-linux-user.mak
index c7cd872e86..e741ffd4d3 100644
--- a/default-configs/targets/arm-linux-user.mak
+++ b/default-configs/targets/arm-linux-user.mak
@@ -3,3 +3,4 @@ TARGET_SYSTBL_ABI=common,oabi
 TARGET_SYSTBL=syscall.tbl
 TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml 
gdb-xml/arm-vfp3.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
 TARGET_HAS_BFLT=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/hw/semihosting/Kconfig b/hw/semihosting/Kconfig
index efe0a30734..4c30dc6b16 100644
--- a/hw/semihosting/Kconfig
+++ b/hw/semihosting/Kconfig
@@ -1,3 +1,6 @@
 
 config SEMIHOSTING
bool
+
+config ARM_COMPATIBLE_SEMIHOSTING
+   bool
diff --git a/target/arm/arm-semi.c b/hw/semihosting/common-semi.c
similarity index 100%
rename from target/arm/arm-semi.c
rename to hw/semihosting/common-semi.c
diff --git a/hw/semihosting/meson.build b/hw/semihosting/meson.build
index f40ac574c4..5b4a170270 100644
--- a/hw/semihosting/meson.build
+++ b/hw/semihosting/meson.build
@@ -2,3 +2,6 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
   'config.c',
   'console.c',
 ))
+
+specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
+   if_true: files('common-semi.c'))
diff --git a/linux-user/arm/meson.build b/linux-user/arm/meson.build
index 432984b58e..5a93c925cf 100644
--- a/linux-user/arm/meson.build
+++ b/linux-user/arm/meson.build
@@ -1,6 +1,3 @@
-linux_user_ss.add(when: 'TARGET_AARCH64', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'TARGET_ARM', if_true: files('semihost.c'))
-
 subdir('nwfpe')
 
 syscall_nr_generators += {
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..7fe28d659e 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -16,6 +16,7 @@ linux_user_ss.add(rt)
 
 linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
 linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
+linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: 
files('semihost.c'))
 
 
 syscall_nr_generators = {}
diff --git a/linux-user/arm/semihost.c b/linux-user/semihost.c
similarity index 100%
rename from linux-user/arm/semihost.c
rename to linux-user/semihost.c
diff --git a/target/arm/meson.build b/target/arm/meson.build
index f5de2a77b8..15b936c101 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -32,8 +32,6 @@ arm_ss.add(files(
 ))
 arm_ss.add(zlib)
 
-arm_ss.add(when: 'CONFIG_TCG', if_true: files('arm-semi.c'))
-
 arm_ss.add(when: 'CONFIG_KVM', 

[PATCH 3/4] semihosting: Change internal common-semi interfaces to use CPUState *

2020-10-26 Thread Keith Packard via
This makes all of the internal interfaces architecture-independent and
renames the internal functions to use the 'common_semi' prefix instead
of 'arm' or 'arm_semi'.

To do this, some new architecture-specific internal helper functions
were created:

static inline target_ulong
common_semi_arg(CPUState *cs, int argno)

Returns the argno'th semihosting argument, where argno can be
either 0 or 1.

static inline void
common_semi_set_ret(CPUState *cs, target_ulong ret)

Sets the semihosting return value.

static inline bool
common_semi_sys_exit_extended(CPUState *cs, int nr)

This detects whether the specified semihosting call, which
is either TARGET_SYS_EXIT or TARGET_SYS_EXIT_EXTENDED should
be executed using the TARGET_SYS_EXIT_EXTENDED semantics.

In addition, several existing functions have been changed to flag
areas of code which are architecture specific:

static target_ulong
common_semi_flen_buf(CPUState *cs)

Returns the current stack pointer minus 64, which is
where a stat structure will be placed on the stack

#define GET_ARG(n)

This fetches arguments from the semihosting command's argument
block. The address of this is available implicitly through the
local 'args' variable. This is *mostly* architecture
independent, but does depend on the current ABI's notion of
the size of a 'long' parameter, which may need run-time checks
(as it does on AARCH64)

#define SET_ARG(n, val)

This mirrors GET_ARG and stores data back into the argument
block.

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c | 326 ++-
 1 file changed, 164 insertions(+), 162 deletions(-)

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index e0c59bc599..c77fb21bec 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -32,11 +32,12 @@
 #include "cpu.h"
 #include "hw/semihosting/semihost.h"
 #include "hw/semihosting/console.h"
+#include "hw/semihosting/common-semi.h"
 #include "qemu/log.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 
-#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024)
 #else
 #include "exec/gdbstub.h"
 #include "qemu/cutils.h"
@@ -132,6 +133,36 @@ typedef struct GuestFD {
 
 static GArray *guestfd_array;
 
+#ifdef TARGET_ARM
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env))
+return env->xregs[argno];
+else
+return env->regs[argno];
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
+if (is_a64(env))
+env->xregs[0] = ret;
+else
+env->regs[0] = ret;
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr));
+}
+#endif /* TARGET_ARM */
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -237,11 +268,10 @@ static target_ulong syscall_err;
 #include "exec/softmmu-semi.h"
 #endif
 
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code)
 {
 if (code == (uint32_t)-1) {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 ts->swi_errno = errno;
@@ -252,10 +282,9 @@ static inline uint32_t set_swi_errno(CPUARMState *env, 
uint32_t code)
 return code;
 }
 
-static inline uint32_t get_swi_errno(CPUARMState *env)
+static inline uint32_t get_swi_errno(CPUState *cs)
 {
 #ifdef CONFIG_USER_ONLY
-CPUState *cs = env_cpu(env);
 TaskState *ts = cs->opaque;
 
 return ts->swi_errno;
@@ -264,24 +293,22 @@ static inline uint32_t get_swi_errno(CPUARMState *env)
 #endif
 }
 
-static target_ulong arm_semi_syscall_len;
+static target_ulong common_semi_syscall_len;
 
-static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 {
-ARMCPU *cpu = ARM_CPU(cs);
-CPUARMState *env = >env;
-target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
+target_ulong reg0 = common_semi_arg(cs, 0);
 
 if (ret == (target_ulong)-1) {
 errno = err;
-set_swi_errno(env, -1);
+set_swi_errno(cs, -1);
 reg0 = ret;
 } else {
 /* Fixup syscalls that use nonstardard return conventions.  */
 switch (reg0) {
 case TARGET_SYS_WRITE:
 case TARGET_SYS_READ:
-reg0 = arm_semi_syscall_len - ret;
+reg0 = common_semi_syscall_len - ret;
 break;
 case TARGET_SYS_SEEK:
 reg0 = 0;
@@ -291,77 

[PATCH 1/4] semihosting: Move ARM semihosting code to shared directories

2020-10-26 Thread Keith Packard via
This commit renames two files which provide ARM semihosting support so
that they can be shared by other architectures:

 1. target/arm/arm-semi.c -> hw/semihosting/common-semi.c
 2. linux-user/arm/semihost.c -> linux-user/semihost.c

The build system was modified to reflect this change, but the contents
of the two files are unchanged.

Signed-off-by: Keith Packard 
---
 target/arm/arm-semi.c => hw/semihosting/common-semi.c | 0
 hw/semihosting/meson.build| 2 ++
 linux-user/arm/meson.build| 3 ---
 linux-user/meson.build| 2 ++
 linux-user/{arm => }/semihost.c   | 0
 target/arm/meson.build| 2 --
 6 files changed, 4 insertions(+), 5 deletions(-)
 rename target/arm/arm-semi.c => hw/semihosting/common-semi.c (100%)
 rename linux-user/{arm => }/semihost.c (100%)

diff --git a/target/arm/arm-semi.c b/hw/semihosting/common-semi.c
similarity index 100%
rename from target/arm/arm-semi.c
rename to hw/semihosting/common-semi.c
diff --git a/hw/semihosting/meson.build b/hw/semihosting/meson.build
index f40ac574c4..fbd2841e59 100644
--- a/hw/semihosting/meson.build
+++ b/hw/semihosting/meson.build
@@ -2,3 +2,5 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
   'config.c',
   'console.c',
 ))
+
+specific_ss.add(when: 'CONFIG_TCG', if_true: files ('common-semi.c'))
diff --git a/linux-user/arm/meson.build b/linux-user/arm/meson.build
index 432984b58e..5a93c925cf 100644
--- a/linux-user/arm/meson.build
+++ b/linux-user/arm/meson.build
@@ -1,6 +1,3 @@
-linux_user_ss.add(when: 'TARGET_AARCH64', if_true: files('semihost.c'))
-linux_user_ss.add(when: 'TARGET_ARM', if_true: files('semihost.c'))
-
 subdir('nwfpe')
 
 syscall_nr_generators += {
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..2fdd12cee5 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -17,6 +17,8 @@ linux_user_ss.add(rt)
 linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
 linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
 
+linux_user_ss.add(when: 'TARGET_AARCH64', if_true: files('semihost.c'))
+linux_user_ss.add(when: 'TARGET_ARM', if_true: files('semihost.c'))
 
 syscall_nr_generators = {}
 
diff --git a/linux-user/arm/semihost.c b/linux-user/semihost.c
similarity index 100%
rename from linux-user/arm/semihost.c
rename to linux-user/semihost.c
diff --git a/target/arm/meson.build b/target/arm/meson.build
index f5de2a77b8..15b936c101 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -32,8 +32,6 @@ arm_ss.add(files(
 ))
 arm_ss.add(zlib)
 
-arm_ss.add(when: 'CONFIG_TCG', if_true: files('arm-semi.c'))
-
 arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c'), if_false: 
files('kvm-stub.c'))
 
 arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
-- 
2.28.0




[PATCH 2/4] semihosting: Change common-semi API to be architecture-independent

2020-10-26 Thread Keith Packard via
The public API is now defined in
hw/semihosting/common-semi.h. do_common_semihosting takes CPUState *
instead of CPUARMState *. All internal functions have been renamed
common_semi_ instead of arm_semi_ or arm_. Aside from the API change,
there are no functional changes in this patch.

Signed-off-by: Keith Packard 
---
 hw/semihosting/common-semi.c  | 16 ++--
 hw/semihosting/common-semi.h  | 36 +++
 linux-user/aarch64/cpu_loop.c |  3 ++-
 linux-user/arm/cpu_loop.c |  3 ++-
 target/arm/cpu.h  |  8 
 target/arm/helper.c   |  5 +++--
 target/arm/m_helper.c |  7 ++-
 7 files changed, 59 insertions(+), 19 deletions(-)
 create mode 100644 hw/semihosting/common-semi.h

diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index 8718fd0194..e0c59bc599 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,10 +1,14 @@
 /*
- *  Arm "Angel" semihosting syscalls
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
  *  Written by Paul Brook.
  *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
@@ -371,12 +375,12 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, 
gdb_syscall_complete_cb cb,
  * do anything with its return value, because it is not necessarily
  * the result of the syscall, but could just be the old value of X0.
  * The only thing safe to do with this is that the callers of
- * do_arm_semihosting() will write it straight back into X0.
+ * do_common_semihosting() will write it straight back into X0.
  * (In linux-user mode, the callback will have happened before
  * gdb_do_syscallv() returns.)
  *
  * We should tidy this up so neither this function nor
- * do_arm_semihosting() return a value, so the mistake of
+ * do_common_semihosting() return a value, so the mistake of
  * doing something with the return value is not possible to make.
  */
 
@@ -673,10 +677,10 @@ static const GuestFDFunctions guestfd_fns[] = {
  * leave the register unchanged. We use 0xdeadbeef as the return value
  * when there isn't a defined return value for the call.
  */
-target_ulong do_arm_semihosting(CPUARMState *env)
+target_ulong do_common_semihosting(CPUState *cs)
 {
-ARMCPU *cpu = env_archcpu(env);
-CPUState *cs = env_cpu(env);
+ARMCPU *cpu = ARM_CPU(cs);
+CPUARMState *env = >env;
 target_ulong args;
 target_ulong arg0, arg1, arg2, arg3;
 char * s;
diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h
new file mode 100644
index 00..bc53e92c79
--- /dev/null
+++ b/hw/semihosting/common-semi.h
@@ -0,0 +1,36 @@
+/*
+ *  Semihosting support for systems modeled on the Arm "Angel"
+ *  semihosting syscalls design.
+ *
+ *  Copyright (c) 2005, 2007 CodeSourcery.
+ *  Copyright (c) 2019 Linaro
+ *  Written by Paul Brook.
+ *
+ *  Copyright © 2020 by Keith Packard 
+ *  Adapted for systems other than ARM, including RISC-V, by Keith Packard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ *
+ *  ARM Semihosting is documented in:
+ * Semihosting for AArch32 and AArch64 Release 2.0
+ * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ */
+
+#ifndef COMMON_SEMI_H
+#define COMMON_SEMI_H
+
+target_ulong do_common_semihosting(CPUState *cs);
+
+#endif /* COMMON_SEMI_H */
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index bbe9fefca8..42b9c15f53 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -22,6 +22,7 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 #include "qemu/guest-random.h"
+#include "hw/semihosting/common-semi.h"
 
 #define get_user_code_u32(x, gaddr, env)\
 ({ abi_long __r = get_user_u32((x), (gaddr));   \
@@ -129,7 +130,7 @@ void cpu_loop(CPUARMState *env)
 queue_signal(env, info.si_signo, QEMU_SI_FAULT, );
 break;
 case 

[PATCH 0/4] riscv: Add semihosting support [v10]

2020-10-26 Thread Keith Packard via
This series first adapts the existing ARM semihosting code to be
architecture-neutral, then adds RISC-V semihosting support using that.

Patch 1/4 moves the ARM semihosting support code to common directories and
adapts the build system to match.

Patch 2/4 changes the public API to this code to use
architecture-independent names and types.

Patch 3/4 changes the internals of this code to use architecture
neutral types where practical, and adds helper functions to abstract
away the architecture-specific details.

Patch 4/4 adds the RISC-V support, including modifying the breakpoint
handling code to recognize a semihosting sequence and adding RISC-V
specific implementations of the helper functions.





[PATCH 4/4] riscv: Add semihosting support [v10]

2020-10-26 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support

v8:
Fix errors reported by checkpatch that crept in.

v9:
Changes suggested by Alistair Francis :
Don't add me to the MAINTAINERS file.
Remove duplicate #include in target/riscv/cpu.h
Reference RISC-V semihosting spec in target/riscv/riscv-semi.c

v10:
Use common semihosting implementation instead of a separate copy.

Make sure addresses of the three breakpoint-signaling
instructions all lie within the same page. Change suggested by
Richard Henderson 
---
 default-configs/devices/riscv32-softmmu.mak   |  1 +
 default-configs/devices/riscv64-softmmu.mak   |  1 +
 hw/semihosting/common-semi.c  | 51 ++-
 hw/semihosting/common-semi.h  |  5 +-
 hw/semihosting/meson.build|  2 +
 linux-user/meson.build|  3 ++
 linux-user/qemu.h |  4 +-
 linux-user/semihost.c |  8 +--
 qemu-options.hx   | 10 ++--
 target/riscv/cpu_bits.h   |  1 +
 target/riscv/cpu_helper.c | 10 
 .../riscv/insn_trans/trans_privileged.c.inc   | 37 +-
 target/riscv/translate.c  | 11 
 13 files changed, 132 insertions(+), 12 deletions(-)

diff --git a/default-configs/devices/riscv32-softmmu.mak 
b/default-configs/devices/riscv32-softmmu.mak
index 94a236c9c2..e8a4eeebec 100644
--- a/default-configs/devices/riscv32-softmmu.mak
+++ b/default-configs/devices/riscv32-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/devices/riscv64-softmmu.mak 
b/default-configs/devices/riscv64-softmmu.mak
index 76b6195648..d8a87b7671 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c
index c77fb21bec..8675934a71 100644
--- a/hw/semihosting/common-semi.c
+++ b/hw/semihosting/common-semi.c
@@ -1,6 +1,6 @@
 /*
  *  Semihosting support for systems modeled on the Arm "Angel"
- *  semihosting syscalls design.
+ *  semihosting syscalls design. This includes Arm and RISC-V processors
  *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Copyright (c) 2019 Linaro
@@ -25,6 +25,10 @@
  *  ARM Semihosting is documented in:
  * Semihosting for AArch32 and AArch64 Release 2.0
  * https://static.docs.arm.com/100863/0200/semihosting.pdf
+ *
+ *  RISC-V Semihosting is documented in:
+ * RISC-V Semihosting
+ * 
https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
  */
 
 #include "qemu/osdep.h"
@@ -163,6 +167,30 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
 }
 #endif /* TARGET_ARM */
 
+#ifdef TARGET_RISCV
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+RISCVCPU *cpu = RISCV_CPU(cs);
+CPURISCVState *env = >env;
+return env->gpr[xA0 + argno];
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+RISCVCPU *cpu = RISCV_CPU(cs);
+CPURISCVState *env = >env;
+env->gpr[xA0] = ret;
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 0);
+}
+#endif
+
 /*
  * Allocate a new guest file descriptor and return it; if we
  * couldn't allocate a new fd then return -1.
@@ -339,6 +367,12 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
 sp = env->regs[13];
 }
 #endif
+#ifdef TARGET_RISCV
+RISCVCPU *cpu = RISCV_CPU(cs);
+CPURISCVState *env = >env;
+
+sp = env->gpr[xSP];
+#endif
 
 return sp - 64;
 }
@@ -678,6 +712,18 @@ static const GuestFDFunctions guestfd_fns[] = {
  put_user_u32(val, args + (n) * 4))
 #endif
 
+#ifdef TARGET_RISCV
+#define GET_ARG(n) do { \
+if (get_user_ual(arg ## n, args + (n) * sizeof(target_ulong))) { \
+errno = EFAULT; 

[PATCH] riscv: Add semihosting support [v8]

2020-10-23 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support

v8:
Fix errors reported by checkpatch that crept in.
---
 MAINTAINERS   |1 +
 default-configs/devices/riscv32-softmmu.mak   |1 +
 default-configs/devices/riscv64-softmmu.mak   |1 +
 linux-user/meson.build|1 +
 linux-user/qemu.h |4 +-
 linux-user/riscv/meson.build  |2 +
 linux-user/riscv/semihost.c   |   76 ++
 qemu-options.hx   |   10 +-
 target/riscv/cpu.h|7 +
 target/riscv/cpu_bits.h   |1 +
 target/riscv/cpu_helper.c |9 +
 .../riscv/insn_trans/trans_privileged.c.inc   |   24 +-
 target/riscv/meson.build  |1 +
 target/riscv/riscv-semi.c | 1086 +
 target/riscv/translate.c  |   11 +
 15 files changed, 1229 insertions(+), 6 deletions(-)
 create mode 100644 linux-user/riscv/meson.build
 create mode 100644 linux-user/riscv/semihost.c
 create mode 100644 target/riscv/riscv-semi.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a197bd358..8cf5b1e448 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -279,6 +279,7 @@ M: Palmer Dabbelt 
 M: Alistair Francis 
 M: Sagar Karandikar 
 M: Bastian Koppelmann 
+M: Keith Packard 
 L: qemu-ri...@nongnu.org
 S: Supported
 F: target/riscv/
diff --git a/default-configs/devices/riscv32-softmmu.mak 
b/default-configs/devices/riscv32-softmmu.mak
index 94a236c9c2..e8a4eeebec 100644
--- a/default-configs/devices/riscv32-softmmu.mak
+++ b/default-configs/devices/riscv32-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/devices/riscv64-softmmu.mak 
b/default-configs/devices/riscv64-softmmu.mak
index 76b6195648..d8a87b7671 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..31b5ed99b5 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -29,6 +29,7 @@ subdir('microblaze')
 subdir('mips64')
 subdir('mips')
 subdir('ppc')
+subdir('riscv')
 subdir('s390x')
 subdir('sh4')
 subdir('sparc64')
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 941ca99722..faeaab9614 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -105,6 +105,8 @@ typedef struct TaskState {
 /* FPA state */
 FPA11 fpa;
 # endif
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_RISCV)
 int swi_errno;
 #endif
 #if defined(TARGET_I386) && !defined(TARGET_X86_64)
@@ -118,7 +120,7 @@ typedef struct TaskState {
 #ifdef TARGET_M68K
 abi_ulong tp_value;
 #endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV)
 /* Extra fields for semihosted binaries.  */
 abi_ulong heap_base;
 abi_ulong heap_limit;
diff --git a/linux-user/riscv/meson.build b/linux-user/riscv/meson.build
new file mode 100644
index 00..aee3179cdb
--- /dev/null
+++ b/linux-user/riscv/meson.build
@@ -0,0 +1,2 @@
+linux_user_ss.add(when: 'TARGET_RISCV64', if_true: files('semihost.c'))
+linux_user_ss.add(when: 'TARGET_RISCV32', if_true: files('semihost.c'))
diff --git a/linux-user/riscv/semihost.c b/linux-user/riscv/semihost.c
new file mode 100644
index 00..2d35ebab68
--- /dev/null
+++ b/linux-user/riscv/semihost.c
@@ -0,0 +1,76 @@
+/*
+ * RISC-V Semihosting Console Support
+ *
+ * Copyright (c) 2019 Linaro Ltd
+ *
+ * Currently RISC-V and ARM are unique in having support for semihosting 
support
+ * in linux-user. So for now we implement the common console API but
+ * just for risc-v and arm linux-user.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "hw/semihosting/console.h"
+#include "qemu.h"
+#include 
+
+int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
+{
+int len = target_strlen(addr);
+void *s;
+

[PATCH 2/2] riscv: Add sifive test device to sifive_u target

2020-10-23 Thread Keith Packard via
The SiFive test device provides a mechanism for terminating the qemu
instance from the emulated system. This patch adds that device to the
sifive_u target, including constructing a suitable FDT node.

Signed-off-by: Keith Packard 
---
 hw/riscv/sifive_u.c | 15 +++
 include/hw/riscv/sifive_u.h |  1 +
 2 files changed, 16 insertions(+)

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 6ad975d692..8d803fe7c0 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -15,6 +15,7 @@
  * 5) OTP (One-Time Programmable) memory with stored serial number
  * 6) GEM (Gigabit Ethernet Controller) and management block
  * 7) DMA (Direct Memory Access Controller)
+ * 8) TEST (Test device)
  *
  * This board currently generates devicetree dynamically that indicates at 
least
  * two harts and up to five harts.
@@ -44,6 +45,7 @@
 #include "hw/char/serial.h"
 #include "hw/cpu/cluster.h"
 #include "hw/misc/unimp.h"
+#include "hw/misc/sifive_test.h"
 #include "target/riscv/cpu.h"
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/sifive_u.h"
@@ -72,6 +74,7 @@ static const struct MemmapEntry {
 } sifive_u_memmap[] = {
 [SIFIVE_U_DEV_DEBUG] ={0x0,  0x100 },
 [SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 },
+[SIFIVE_U_DEV_TEST] = {   0x10, 0x1000 },
 [SIFIVE_U_DEV_CLINT] ={  0x200,0x1 },
 [SIFIVE_U_DEV_L2CC] = {  0x201, 0x1000 },
 [SIFIVE_U_DEV_PDMA] = {  0x300,   0x10 },
@@ -397,6 +400,16 @@ static void create_fdt(SiFiveUState *s, const struct 
MemmapEntry *memmap,
 qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);
 
 g_free(nodename);
+
+nodename = g_strdup_printf("/soc/test@%lx",
+   (long)memmap[SIFIVE_U_DEV_TEST].base);
+qemu_fdt_add_subnode(fdt, nodename);
+qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,test0");
+qemu_fdt_setprop_cells(fdt, nodename, "reg",
+   0x0, memmap[SIFIVE_U_DEV_TEST].base,
+   0x0, memmap[SIFIVE_U_DEV_TEST].size);
+
+g_free(nodename);
 }
 
 static void sifive_u_machine_reset(void *opaque, int n, int level)
@@ -780,6 +793,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error 
**errp)
 sysbus_connect_irq(SYS_BUS_DEVICE(>gem), 0,
qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ));
 
+sifive_test_create(memmap[SIFIVE_U_DEV_TEST].base);
+
 create_unimplemented_device("riscv.sifive.u.gem-mgmt",
 memmap[SIFIVE_U_DEV_GEM_MGMT].base, 
memmap[SIFIVE_U_DEV_GEM_MGMT].size);
 
diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h
index 22e7e6efa1..4b3ebc3fc6 100644
--- a/include/hw/riscv/sifive_u.h
+++ b/include/hw/riscv/sifive_u.h
@@ -72,6 +72,7 @@ typedef struct SiFiveUState {
 enum {
 SIFIVE_U_DEV_DEBUG,
 SIFIVE_U_DEV_MROM,
+SIFIVE_U_DEV_TEST,
 SIFIVE_U_DEV_CLINT,
 SIFIVE_U_DEV_L2CC,
 SIFIVE_U_DEV_PDMA,
-- 
2.28.0




[PATCH 1/2] riscv: Add sifive test device to sifive_e target

2020-10-23 Thread Keith Packard via
The SiFive test device provides a mechanism for terminating the qemu
instance from the emulated system. This patch adds that device to the
sifive_e target.

Signed-off-by: Keith Packard 
---
 hw/riscv/sifive_e.c | 4 
 include/hw/riscv/sifive_e.h | 1 +
 2 files changed, 5 insertions(+)

diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index fcfac16816..417e3a5409 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -11,6 +11,7 @@
  * 3) PRCI (Power, Reset, Clock, Interrupt)
  * 4) Registers emulated as RAM: AON, GPIO, QSPI, PWM
  * 5) Flash memory emulated as RAM
+ * 6) TEST (Test device)
  *
  * The Mask ROM reset vector jumps to the flash payload at 0x2040_.
  * The OTP ROM and Flash boot code will be emulated in a future version.
@@ -45,6 +46,7 @@
 #include "hw/intc/sifive_clint.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_e_prci.h"
+#include "hw/misc/sifive_test.h"
 #include "chardev/char.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/sysemu.h"
@@ -57,6 +59,7 @@ static const struct MemmapEntry {
 [SIFIVE_E_DEV_DEBUG] ={0x0, 0x1000 },
 [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 },
 [SIFIVE_E_DEV_OTP] =  {0x2, 0x2000 },
+[SIFIVE_E_DEV_TEST] = {   0x10, 0x1000 },
 [SIFIVE_E_DEV_CLINT] ={  0x200,0x1 },
 [SIFIVE_E_DEV_PLIC] = {  0xc00,  0x400 },
 [SIFIVE_E_DEV_AON] =  { 0x1000, 0x8000 },
@@ -216,6 +219,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error 
**errp)
 memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
 SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
 SIFIVE_CLINT_TIMEBASE_FREQ, false);
+sifive_test_create(memmap[SIFIVE_E_DEV_TEST].base);
 create_unimplemented_device("riscv.sifive.e.aon",
 memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
 sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h
index 83604da805..92bab6d0d4 100644
--- a/include/hw/riscv/sifive_e.h
+++ b/include/hw/riscv/sifive_e.h
@@ -56,6 +56,7 @@ enum {
 SIFIVE_E_DEV_DEBUG,
 SIFIVE_E_DEV_MROM,
 SIFIVE_E_DEV_OTP,
+SIFIVE_E_DEV_TEST,
 SIFIVE_E_DEV_CLINT,
 SIFIVE_E_DEV_PLIC,
 SIFIVE_E_DEV_AON,
-- 
2.28.0




[PATCH 0/2] riscv: Add SiFive test device to sifive targets

2020-10-23 Thread Keith Packard via
The SiFive test device, which is already available in the qemu tree,
allows the system under emulation to shut down qemu. This is currently
used by OpenSBI to terminate QEMU at powerdown time. These two patches
add this device to the two sifive models.





[PATCH] riscv: Add semihosting support [v8]

2020-09-17 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support

v8:
Fix errors reported by checkpatch that crept in.
---
 default-configs/riscv32-softmmu.mak   |1 +
 default-configs/riscv64-softmmu.mak   |1 +
 linux-user/meson.build|1 +
 linux-user/qemu.h |4 +-
 linux-user/riscv/meson.build  |2 +
 linux-user/riscv/semihost.c   |   76 ++
 qemu-options.hx   |   10 +-
 target/riscv/cpu.h|7 +
 target/riscv/cpu_bits.h   |1 +
 target/riscv/cpu_helper.c |9 +
 .../riscv/insn_trans/trans_privileged.c.inc   |   24 +-
 target/riscv/meson.build  |1 +
 target/riscv/riscv-semi.c | 1086 +
 target/riscv/translate.c  |   11 +
 14 files changed, 1228 insertions(+), 6 deletions(-)
 create mode 100644 linux-user/riscv/meson.build
 create mode 100644 linux-user/riscv/semihost.c
 create mode 100644 target/riscv/riscv-semi.c

diff --git a/default-configs/riscv32-softmmu.mak 
b/default-configs/riscv32-softmmu.mak
index 94a236c9c2..e8a4eeebec 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/riscv64-softmmu.mak 
b/default-configs/riscv64-softmmu.mak
index 76b6195648..d8a87b7671 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..31b5ed99b5 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -29,6 +29,7 @@ subdir('microblaze')
 subdir('mips64')
 subdir('mips')
 subdir('ppc')
+subdir('riscv')
 subdir('s390x')
 subdir('sh4')
 subdir('sparc64')
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index a69a0bd347..9fadb1505f 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -105,6 +105,8 @@ typedef struct TaskState {
 /* FPA state */
 FPA11 fpa;
 # endif
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_RISCV)
 int swi_errno;
 #endif
 #if defined(TARGET_I386) && !defined(TARGET_X86_64)
@@ -118,7 +120,7 @@ typedef struct TaskState {
 #ifdef TARGET_M68K
 abi_ulong tp_value;
 #endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV)
 /* Extra fields for semihosted binaries.  */
 abi_ulong heap_base;
 abi_ulong heap_limit;
diff --git a/linux-user/riscv/meson.build b/linux-user/riscv/meson.build
new file mode 100644
index 00..aee3179cdb
--- /dev/null
+++ b/linux-user/riscv/meson.build
@@ -0,0 +1,2 @@
+linux_user_ss.add(when: 'TARGET_RISCV64', if_true: files('semihost.c'))
+linux_user_ss.add(when: 'TARGET_RISCV32', if_true: files('semihost.c'))
diff --git a/linux-user/riscv/semihost.c b/linux-user/riscv/semihost.c
new file mode 100644
index 00..2d35ebab68
--- /dev/null
+++ b/linux-user/riscv/semihost.c
@@ -0,0 +1,76 @@
+/*
+ * RISC-V Semihosting Console Support
+ *
+ * Copyright (c) 2019 Linaro Ltd
+ *
+ * Currently RISC-V and ARM are unique in having support for semihosting 
support
+ * in linux-user. So for now we implement the common console API but
+ * just for risc-v and arm linux-user.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "hw/semihosting/console.h"
+#include "qemu.h"
+#include 
+
+int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
+{
+int len = target_strlen(addr);
+void *s;
+if (len < 0) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: passed inaccessible address " TARGET_FMT_lx,
+  __func__, addr);
+return 0;
+}
+s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1);
+g_assert(s);  /* target_strlen has already verified this will work */
+len = write(STDERR_FILENO, s, len);
+unlock_user(s, addr, 0);
+return len;

[PATCH] riscv: Add semihosting support [v7]

2020-09-17 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting version 0.2 as
documented in

   https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch

v5:
Reference current RISC-V semihosting specification

v6:
Add support for semihosting in riscv64-linux-user and
riscv32-linux-user

v7:
Add meson build support
---
 default-configs/riscv32-softmmu.mak   |1 +
 default-configs/riscv64-softmmu.mak   |1 +
 linux-user/meson.build|1 +
 linux-user/qemu.h |4 +-
 linux-user/riscv/meson.build  |2 +
 linux-user/riscv/semihost.c   |   76 ++
 qemu-options.hx   |   10 +-
 target/riscv/cpu.h|7 +
 target/riscv/cpu_bits.h   |1 +
 target/riscv/cpu_helper.c |9 +
 .../riscv/insn_trans/trans_privileged.c.inc   |   24 +-
 target/riscv/meson.build  |1 +
 target/riscv/riscv-semi.c | 1086 +
 target/riscv/translate.c  |   11 +
 14 files changed, 1228 insertions(+), 6 deletions(-)
 create mode 100644 linux-user/riscv/meson.build
 create mode 100644 linux-user/riscv/semihost.c
 create mode 100644 target/riscv/riscv-semi.c

diff --git a/default-configs/riscv32-softmmu.mak 
b/default-configs/riscv32-softmmu.mak
index 94a236c9c2..e8a4eeebec 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/default-configs/riscv64-softmmu.mak 
b/default-configs/riscv64-softmmu.mak
index 76b6195648..d8a87b7671 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 2b94e4ba24..31b5ed99b5 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -29,6 +29,7 @@ subdir('microblaze')
 subdir('mips64')
 subdir('mips')
 subdir('ppc')
+subdir('riscv')
 subdir('s390x')
 subdir('sh4')
 subdir('sparc64')
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index a69a0bd347..9fadb1505f 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -105,6 +105,8 @@ typedef struct TaskState {
 /* FPA state */
 FPA11 fpa;
 # endif
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_RISCV)
 int swi_errno;
 #endif
 #if defined(TARGET_I386) && !defined(TARGET_X86_64)
@@ -118,7 +120,7 @@ typedef struct TaskState {
 #ifdef TARGET_M68K
 abi_ulong tp_value;
 #endif
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV)
 /* Extra fields for semihosted binaries.  */
 abi_ulong heap_base;
 abi_ulong heap_limit;
diff --git a/linux-user/riscv/meson.build b/linux-user/riscv/meson.build
new file mode 100644
index 00..aee3179cdb
--- /dev/null
+++ b/linux-user/riscv/meson.build
@@ -0,0 +1,2 @@
+linux_user_ss.add(when: 'TARGET_RISCV64', if_true: files('semihost.c'))
+linux_user_ss.add(when: 'TARGET_RISCV32', if_true: files('semihost.c'))
diff --git a/linux-user/riscv/semihost.c b/linux-user/riscv/semihost.c
new file mode 100644
index 00..22bfa1f336
--- /dev/null
+++ b/linux-user/riscv/semihost.c
@@ -0,0 +1,76 @@
+/*
+ * RISC-V Semihosting Console Support
+ *
+ * Copyright (c) 2019 Linaro Ltd
+ *
+ * Currently RISC-V and ARM are unique in having support for semihosting 
support
+ * in linux-user. So for now we implement the common console API but
+ * just for risc-v and arm linux-user.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "hw/semihosting/console.h"
+#include "qemu.h"
+#include 
+
+int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
+{
+int len = target_strlen(addr);
+void *s;
+if (len < 0){
+   qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: passed inaccessible address " TARGET_FMT_lx,
+ __func__, addr);
+   return 0;
+}
+s = lock_user(VERIFY_READ, addr, (long)(len + 1), 1);
+g_assert(s);  /* target_strlen has already verified this will work */
+len = write(STDERR_FILENO, s, len);
+unlock_user(s, addr, 0);
+return len;
+}
+
+void qemu_semihosting_console_outc(CPUArchState *env, 

[PATCH] hw/arm: Add 'virtm' hardware

2020-06-25 Thread Keith Packard via
'virtm' is a hardware target that is designed to be used for compiler
and library testing on Cortex-M processors. It supports all cortex-m
processors and includes sufficient memory to run even large test
cases.

Signed-off-by: Keith Packard 
---
 MAINTAINERS  |   9 +++-
 hw/arm/Makefile.objs |   2 +-
 hw/arm/virtm.c   | 112 +++
 3 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 hw/arm/virtm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1b40446c73..4c7e394dd6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -850,9 +850,16 @@ Virt
 M: Peter Maydell 
 L: qemu-...@nongnu.org
 S: Maintained
-F: hw/arm/virt*
+F: hw/arm/virt.c
+F: hw/arm/virt-acpi-build.c
 F: include/hw/arm/virt.h
 
+Virt M
+M: Keith Packard 
+L: qemu-...@nongnu.org
+S: Maintained
+F: hw/arm/virtm.c
+
 Xilinx Zynq
 M: Edgar E. Iglesias 
 M: Alistair Francis 
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 534a6a119e..54be15b40a 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,6 +1,6 @@
 obj-y += boot.o
 obj-$(CONFIG_PLATFORM_BUS) += sysbus-fdt.o
-obj-$(CONFIG_ARM_VIRT) += virt.o
+obj-$(CONFIG_ARM_VIRT) += virt.o virtm.o
 obj-$(CONFIG_ACPI) += virt-acpi-build.o
 obj-$(CONFIG_DIGIC) += digic_boards.o
 obj-$(CONFIG_EXYNOS4) += exynos4_boards.o
diff --git a/hw/arm/virtm.c b/hw/arm/virtm.c
new file mode 100644
index 00..beda3644f5
--- /dev/null
+++ b/hw/arm/virtm.c
@@ -0,0 +1,112 @@
+/*
+ * Virtual ARM Cortex M
+ *
+ * Copyright © 2020, Keith Packard 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/arm/boot.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/armv7m.h"
+#include "hw/misc/unimp.h"
+#include "cpu.h"
+
+#define NUM_IRQ_LINES 32
+#define ROM_BASE  0x
+#define ROM_SIZE  0x2000
+#define RAM_BASE0x2000
+#define RAM_SIZE0x2000
+
+static const char *valid_cpus[] = {
+ARM_CPU_TYPE_NAME("cortex-m0"),
+ARM_CPU_TYPE_NAME("cortex-m3"),
+ARM_CPU_TYPE_NAME("cortex-m33"),
+ARM_CPU_TYPE_NAME("cortex-m4"),
+ARM_CPU_TYPE_NAME("cortex-m7"),
+};
+
+static bool cpu_type_valid(const char *cpu)
+{
+int i;
+
+return true;
+for (i = 0; i < ARRAY_SIZE(valid_cpus); i++) {
+if (strcmp(cpu, valid_cpus[i]) == 0) {
+return true;
+}
+}
+return false;
+}
+
+static void machvirtm_init(MachineState *ms)
+{
+DeviceState *nvic;
+
+if (!cpu_type_valid(ms->cpu_type)) {
+error_report("virtm: CPU type %s not supported", ms->cpu_type);
+exit(1);
+}
+
+MemoryRegion *ram = g_new(MemoryRegion, 1);
+MemoryRegion *rom = g_new(MemoryRegion, 1);
+MemoryRegion *system_memory = get_system_memory();
+
+/* Flash programming is done via the SCU, so pretend it is ROM.  */
+memory_region_init_rom(rom, NULL, "virtm.rom", ROM_SIZE,
+   _fatal);
+memory_region_add_subregion(system_memory, ROM_BASE, rom);
+
+memory_region_init_ram(ram, NULL, "virtm.ram", RAM_SIZE,
+   _fatal);
+memory_region_add_subregion(system_memory, RAM_BASE, ram);
+
+nvic = qdev_new(TYPE_ARMV7M);
+qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES);
+qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type);
+qdev_prop_set_bit(nvic, "enable-bitband", true);
+object_property_set_link(OBJECT(nvic), OBJECT(get_system_memory()),
+ "memory", _abort);
+/* This will exit with an error if the user passed us a bad cpu_type */
+sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), _fatal);
+
+armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, ROM_SIZE);
+}
+
+static void virtm_class_init(ObjectClass *oc, void *data)
+{
+MachineClass *mc = MACHINE_CLASS(oc);
+
+mc->desc = "Virtual Cortex-M";
+mc->init = machvirtm_init;
+mc->ignore_memory_transaction_failures = true;
+mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
+}
+
+static const TypeInfo virtm_type = {
+.name = MACHINE_TYPE_NAME("virtm"),
+.parent = TYPE_MACHINE,
+.class_init = virtm_class_init,
+};
+
+static void virtm_machine_init(void)
+{
+type_register_static(_type);
+}
+

[PATCH] riscv: Separate FPU register size from core register size in gdbstub [v2]

2020-01-28 Thread Keith Packard via
The size of the FPU registers is dictated by the 'f' and 'd' features,
not the core processor register size. Processors with the 'd' feature
have 64-bit FPU registers. Processors without the 'd' feature but with
the 'f' feature have 32-bit FPU registers.

Signed-off-by: Keith Packard 

---

v2:
Fix checkpatch formatting complaints.
---
 configure  |  4 ++--
 target/riscv/gdbstub.c | 20 +++-
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/configure b/configure
index a72a5def57..c21bff8d10 100755
--- a/configure
+++ b/configure
@@ -7709,13 +7709,13 @@ case "$target_name" in
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 mttcg=yes
-gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml 
riscv-32bit-virtual.xml"
+gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-64bit-fpu.xml 
riscv-32bit-csr.xml riscv-32bit-virtual.xml"
   ;;
   riscv64)
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 mttcg=yes
-gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml 
riscv-64bit-virtual.xml"
+gdb_xml_files="riscv-64bit-cpu.xml riscv-32bit-fpu.xml riscv-64bit-fpu.xml 
riscv-64bit-csr.xml riscv-64bit-virtual.xml"
   ;;
   sh4|sh4eb)
 TARGET_ARCH=sh4
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 1a7947e019..1a72f7be9c 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -303,7 +303,12 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t 
*mem_buf, int n)
 static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
 {
 if (n < 32) {
-return gdb_get_reg64(mem_buf, env->fpr[n]);
+if (env->misa & RVD) {
+return gdb_get_reg64(mem_buf, env->fpr[n]);
+}
+if (env->misa & RVF) {
+return gdb_get_reg32(mem_buf, env->fpr[n]);
+}
 /* there is hole between ft11 and fflags in fpu.xml */
 } else if (n < 36 && n > 32) {
 target_ulong val = 0;
@@ -403,23 +408,20 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState 
*cs)
 {
 RISCVCPU *cpu = RISCV_CPU(cs);
 CPURISCVState *env = >env;
-#if defined(TARGET_RISCV32)
-if (env->misa & RVF) {
+if (env->misa & RVD) {
+gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+ 36, "riscv-64bit-fpu.xml", 0);
+} else if (env->misa & RVF) {
 gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
  36, "riscv-32bit-fpu.xml", 0);
 }
-
+#if defined(TARGET_RISCV32)
 gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
  240, "riscv-32bit-csr.xml", 0);
 
 gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
  1, "riscv-32bit-virtual.xml", 0);
 #elif defined(TARGET_RISCV64)
-if (env->misa & RVF) {
-gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
- 36, "riscv-64bit-fpu.xml", 0);
-}
-
 gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
  240, "riscv-64bit-csr.xml", 0);
 
-- 
2.25.0




[PATCH] riscv: Add semihosting support [v4]

2020-01-28 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting as documented in

https://riscv.org/specifications/

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.

v4:
Fix errors reported by checkpatch
---
 default-configs/riscv32-softmmu.mak   |1 +
 linux-user/qemu.h |2 +
 qemu-options.hx   |4 +-
 target/riscv/Makefile.objs|2 +-
 target/riscv/cpu.h|2 +
 target/riscv/cpu_bits.h   |1 +
 target/riscv/cpu_helper.c |9 +
 .../riscv/insn_trans/trans_privileged.inc.c   |   24 +-
 target/riscv/riscv-semi.c | 1084 +
 target/riscv/translate.c  |   11 +
 10 files changed, 1136 insertions(+), 4 deletions(-)
 create mode 100644 target/riscv/riscv-semi.c

diff --git a/default-configs/riscv32-softmmu.mak 
b/default-configs/riscv32-softmmu.mak
index 1ae077ed87..21b7bedf19 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 560a68090e..122d95d6b6 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -105,6 +105,8 @@ typedef struct TaskState {
 /* FPA state */
 FPA11 fpa;
 # endif
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_RISCV)
 int swi_errno;
 #endif
 #if defined(TARGET_I386) && !defined(TARGET_X86_64)
diff --git a/qemu-options.hx b/qemu-options.hx
index 224a8e8712..4892e6b12c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4109,7 +4109,7 @@ ETEXI
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
 "-semihostingsemihosting mode\n",
 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
-QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
+QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
 STEXI
 @item -semihosting
 @findex -semihosting
@@ -4119,7 +4119,7 @@ DEF("semihosting-config", HAS_ARG, 
QEMU_OPTION_semihosting_config,
 "-semihosting-config 
[enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
 "semihosting configuration\n",
 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
-QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
+QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
 STEXI
 @item -semihosting-config 
[enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]
 @findex -semihosting-config
diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs
index ff651f69f6..6fd7f40e29 100644
--- a/target/riscv/Makefile.objs
+++ b/target/riscv/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o 
gdbstub.o
+obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o 
gdbstub.o riscv-semi.o
 obj-$(CONFIG_SOFTMMU) += pmp.o
 
 ifeq ($(CONFIG_SOFTMMU),y)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index de0a8d893a..310ec6ab40 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -338,6 +338,8 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
 typedef CPURISCVState CPUArchState;
 typedef RISCVCPU ArchCPU;
 
+target_ulong do_riscv_semihosting(CPURISCVState *env);
+
 #include "exec/cpu-all.h"
 
 #endif /* RISCV_CPU_H */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index e99834856c..c45745d73b 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -496,6 +496,7 @@
 #define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */
 #define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */
 #define RISCV_EXCP_STORE_PAGE_FAULT0xf /* since: priv-1.10.0 */
+#define RISCV_EXCP_SEMIHOST0x10
 
 #define RISCV_EXCP_INT_FLAG0x8000
 #define RISCV_EXCP_INT_MASK0x7fff
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 85403da9c8..6a04469936 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -532,6 +532,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 [PRV_M] = RISCV_EXCP_M_ECALL
 };
 
+if  (cause == RISCV_EXCP_SEMIHOST) {
+if (env->priv >= PRV_S) {
+env->gpr[xA0] = do_riscv_semihosting(env);
+env->pc += 4;
+return;
+}
+cause = RISCV_EXCP_BREAKPOINT;
+}
+
 if (!async) {
 /* set tval to badaddr for traps with address information */
 switch (cause) {
diff --git a/target/riscv/insn_trans/trans_privileged.inc.c 

[PATCH] riscv: Add semihosting support [v3]

2020-01-28 Thread Keith Packard via
Adapt the arm semihosting support code for RISCV. This implementation
is based on the standard for RISC-V semihosting as documented in

https://riscv.org/specifications/

Signed-off-by: Keith Packard 

---

v2:
Update PC after exception is handled to follow
change in the ARM version for SYS_READC

v3:
Disallow semihosting in user mode; report a regular
breakpoint in that case.
---
 default-configs/riscv32-softmmu.mak   |1 +
 linux-user/qemu.h |2 +
 qemu-options.hx   |4 +-
 target/riscv/Makefile.objs|2 +-
 target/riscv/cpu.h|2 +
 target/riscv/cpu_bits.h   |1 +
 target/riscv/cpu_helper.c |9 +
 .../riscv/insn_trans/trans_privileged.inc.c   |   23 +-
 target/riscv/riscv-semi.c | 1073 +
 target/riscv/translate.c  |   11 +
 10 files changed, 1124 insertions(+), 4 deletions(-)
 create mode 100644 target/riscv/riscv-semi.c

diff --git a/default-configs/riscv32-softmmu.mak 
b/default-configs/riscv32-softmmu.mak
index 1ae077ed87..21b7bedf19 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -3,6 +3,7 @@
 # Uncomment the following lines to disable these optional devices:
 #
 #CONFIG_PCI_DEVICES=n
+CONFIG_SEMIHOSTING=y
 
 # Boards:
 #
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 560a68090e..122d95d6b6 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -105,6 +105,8 @@ typedef struct TaskState {
 /* FPA state */
 FPA11 fpa;
 # endif
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_RISCV)
 int swi_errno;
 #endif
 #if defined(TARGET_I386) && !defined(TARGET_X86_64)
diff --git a/qemu-options.hx b/qemu-options.hx
index 224a8e8712..4892e6b12c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4109,7 +4109,7 @@ ETEXI
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
 "-semihostingsemihosting mode\n",
 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
-QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
+QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
 STEXI
 @item -semihosting
 @findex -semihosting
@@ -4119,7 +4119,7 @@ DEF("semihosting-config", HAS_ARG, 
QEMU_OPTION_semihosting_config,
 "-semihosting-config 
[enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
 "semihosting configuration\n",
 QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
-QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
+QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
 STEXI
 @item -semihosting-config 
[enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]
 @findex -semihosting-config
diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs
index ff651f69f6..6fd7f40e29 100644
--- a/target/riscv/Makefile.objs
+++ b/target/riscv/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o 
gdbstub.o
+obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o 
gdbstub.o riscv-semi.o
 obj-$(CONFIG_SOFTMMU) += pmp.o
 
 ifeq ($(CONFIG_SOFTMMU),y)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index de0a8d893a..310ec6ab40 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -338,6 +338,8 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
 typedef CPURISCVState CPUArchState;
 typedef RISCVCPU ArchCPU;
 
+target_ulong do_riscv_semihosting(CPURISCVState *env);
+
 #include "exec/cpu-all.h"
 
 #endif /* RISCV_CPU_H */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index e99834856c..c45745d73b 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -496,6 +496,7 @@
 #define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */
 #define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */
 #define RISCV_EXCP_STORE_PAGE_FAULT0xf /* since: priv-1.10.0 */
+#define RISCV_EXCP_SEMIHOST0x10
 
 #define RISCV_EXCP_INT_FLAG0x8000
 #define RISCV_EXCP_INT_MASK0x7fff
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 85403da9c8..6a04469936 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -532,6 +532,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 [PRV_M] = RISCV_EXCP_M_ECALL
 };
 
+if  (cause == RISCV_EXCP_SEMIHOST) {
+if (env->priv >= PRV_S) {
+env->gpr[xA0] = do_riscv_semihosting(env);
+env->pc += 4;
+return;
+}
+cause = RISCV_EXCP_BREAKPOINT;
+}
+
 if (!async) {
 /* set tval to badaddr for traps with address information */
 switch (cause) {
diff --git a/target/riscv/insn_trans/trans_privileged.inc.c 
b/target/riscv/insn_trans/trans_privileged.inc.c
index c5e4b3e49a..ddc26e889f 100644
--- 

[PATCH] riscv: Separate FPU register size from core register size in gdbstub

2020-01-28 Thread Keith Packard via
The size of the FPU registers is dictated by the 'f' and 'd' features,
not the core processor register size. Processors with the 'd' feature
have 64-bit FPU registers. Processors without the 'd' feature but with
the 'f' feature have 32-bit FPU registers.

Signed-off-by: Keith Packard 
---
 configure  |  4 ++--
 target/riscv/gdbstub.c | 18 +-
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/configure b/configure
index a72a5def57..c21bff8d10 100755
--- a/configure
+++ b/configure
@@ -7709,13 +7709,13 @@ case "$target_name" in
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 mttcg=yes
-gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml 
riscv-32bit-virtual.xml"
+gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-64bit-fpu.xml 
riscv-32bit-csr.xml riscv-32bit-virtual.xml"
   ;;
   riscv64)
 TARGET_BASE_ARCH=riscv
 TARGET_ABI_DIR=riscv
 mttcg=yes
-gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml 
riscv-64bit-virtual.xml"
+gdb_xml_files="riscv-64bit-cpu.xml riscv-32bit-fpu.xml riscv-64bit-fpu.xml 
riscv-64bit-csr.xml riscv-64bit-virtual.xml"
   ;;
   sh4|sh4eb)
 TARGET_ARCH=sh4
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 1a7947e019..c1803a5916 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -303,7 +303,10 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t 
*mem_buf, int n)
 static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
 {
 if (n < 32) {
-return gdb_get_reg64(mem_buf, env->fpr[n]);
+if (env->misa & RVD)
+return gdb_get_reg64(mem_buf, env->fpr[n]);
+if (env->misa & RVF)
+return gdb_get_reg32(mem_buf, env->fpr[n]);
 /* there is hole between ft11 and fflags in fpu.xml */
 } else if (n < 36 && n > 32) {
 target_ulong val = 0;
@@ -403,23 +406,20 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState 
*cs)
 {
 RISCVCPU *cpu = RISCV_CPU(cs);
 CPURISCVState *env = >env;
-#if defined(TARGET_RISCV32)
-if (env->misa & RVF) {
+if (env->misa & RVD) {
+gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+ 36, "riscv-64bit-fpu.xml", 0);
+} else if (env->misa & RVF) {
 gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
  36, "riscv-32bit-fpu.xml", 0);
 }
-
+#if defined(TARGET_RISCV32)
 gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
  240, "riscv-32bit-csr.xml", 0);
 
 gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
  1, "riscv-32bit-virtual.xml", 0);
 #elif defined(TARGET_RISCV64)
-if (env->misa & RVF) {
-gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
- 36, "riscv-64bit-fpu.xml", 0);
-}
-
 gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
  240, "riscv-64bit-csr.xml", 0);
 
-- 
2.25.0