This also adds the basic test file and the configuration update.
This implementation can only test instructions with values in register and
no memory access.
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
configure | 6 ++-
risu_m68k.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++
risu_reginfo_m68k.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++
risu_reginfo_m68k.h | 32 +++++++++++
test_m68k.s | 28 ++++++++++
5 files changed, 368 insertions(+), 2 deletions(-)
create mode 100644 risu_m68k.c
create mode 100644 risu_reginfo_m68k.c
create mode 100644 risu_reginfo_m68k.h
create mode 100644 test_m68k.s
diff --git a/configure b/configure
index f81bdb5..f5921ee 100755
--- a/configure
+++ b/configure
@@ -18,7 +18,9 @@ EOF
}
guess_arch() {
- if check_define __arm__ ; then
+ if check_define __m68k__ ; then
+ ARCH="m68k"
+ elif check_define __arm__ ; then
ARCH="arm"
elif check_define __aarch64__ ; then
ARCH="aarch64"
@@ -63,7 +65,7 @@ Some influential environment variables:
prefixed with the given string.
ARCH force target architecture instead of trying to detect it.
- Valid values=[arm|aarch64|ppc64|ppc64le]
+ Valid values=[arm|aarch64|ppc64|ppc64le|m68k]
CC C compiler command
CFLAGS C compiler flags
diff --git a/risu_m68k.c b/risu_m68k.c
new file mode 100644
index 0000000..15e30b1
--- /dev/null
+++ b/risu_m68k.c
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Laurent Vivier
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <string.h>
+
+#include "risu.h"
+#include "risu_reginfo_m68k.h"
+
+struct reginfo master_ri, apprentice_ri;
+static int mem_used = 0;
+static int packet_mismatch = 0;
+
+uint8_t apprentice_memblock[MEMBLOCKLEN];
+
+void advance_pc(void *vuc)
+{
+ ucontext_t *uc = (ucontext_t*)vuc;
+ uc->uc_mcontext.gregs[R_PC] += 4;
+}
+
+void set_a0(void *vuc, uint32_t a0)
+{
+ ucontext_t *uc = vuc;
+ uc->uc_mcontext.gregs[R_A0] = a0;
+}
+
+static int get_risuop(uint32_t insn)
+{
+ uint32_t op = insn & 0xf;
+ uint32_t key = insn & ~0xf;
+ uint32_t risukey = 0x4afc7000;
+ return (key != risukey) ? -1 : op;
+}
+
+int send_register_info(int sock, void *uc)
+{
+ struct reginfo ri;
+ int op;
+
+ reginfo_init(&ri, uc);
+ op = get_risuop(ri.faulting_insn);
+
+ switch (op) {
+ case OP_COMPARE:
+ case OP_TESTEND:
+ default:
+ return send_data_pkt(sock, &ri, sizeof(ri));
+ case OP_SETMEMBLOCK:
+ memblock = (void*)ri.gregs[R_A0];
+ break;
+ case OP_GETMEMBLOCK:
+ set_a0(uc, ri.gregs[R_A0] + (uintptr_t)memblock);
+ break;
+ case OP_COMPAREMEM:
+ return send_data_pkt(sock, memblock, MEMBLOCKLEN);
+ break;
+ }
+ return 0;
+}
+
+/* Read register info from the socket and compare it with that from the
+ * ucontext. Return 0 for match, 1 for end-of-test, 2 for mismatch.
+ * NB: called from a signal handler.
+ */
+int recv_and_compare_register_info(int sock, void *uc)
+{
+ int resp = 0;
+ int op;
+
+ reginfo_init(&master_ri, uc);
+ op = get_risuop(master_ri.faulting_insn);
+
+ switch (op) {
+ case OP_COMPARE:
+ case OP_TESTEND:
+ default:
+ if (recv_data_pkt(sock, &apprentice_ri, sizeof(apprentice_ri))) {
+ packet_mismatch = 1;
+ resp = 2;
+ } else if (!reginfo_is_eq(&master_ri, &apprentice_ri, uc)) {
+ resp = 2;
+ }
+ else if (op == OP_TESTEND) {
+ resp = 1;
+ }
+ send_response_byte(sock, resp);
+ break;
+ case OP_SETMEMBLOCK:
+ memblock = (void*)master_ri.gregs[R_A0];
+ break;
+ case OP_GETMEMBLOCK:
+ set_a0(uc, master_ri.gregs[R_A0] + (uintptr_t)memblock);
+ break;
+ case OP_COMPAREMEM:
+ mem_used = 1;
+ if (recv_data_pkt(sock, apprentice_memblock, MEMBLOCKLEN)) {
+ packet_mismatch = 1;
+ resp = 2;
+ } else if (memcmp(memblock, apprentice_memblock, MEMBLOCKLEN) != 0) {
+ resp = 2;
+ }
+ send_response_byte(sock, resp);
+ break;
+ }
+ return resp;
+}
+
+/* Print a useful report on the status of the last comparison
+ * done in recv_and_compare_register_info(). This is called on
+ * exit, so need not restrict itself to signal-safe functions.
+ * Should return 0 if it was a good match (ie end of test)
+ * and 1 for a mismatch.
+ */
+int report_match_status(void)
+{
+ int resp = 0;
+ fprintf(stderr, "match status...\n");
+
+ if (packet_mismatch) {
+ fprintf(stderr, "packet mismatch (probably disagreement "
+ "about UNDEF on load/store)\n");
+ fprintf(stderr, "master reginfo:\n");
+ reginfo_dump(&master_ri, 0);
+ }
+ if (!reginfo_is_eq(&master_ri, &apprentice_ri, NULL)) {
+ fprintf(stderr, "mismatch on regs!\n");
+ resp = 1;
+ }
+ if (mem_used && memcmp(memblock, &apprentice_memblock, MEMBLOCKLEN) != 0) {
+ fprintf(stderr, "mismatch on memory!\n");
+ resp = 1;
+ }
+ if (!resp) {
+ fprintf(stderr, "match!\n");
+ return 0;
+ }
+
+ fprintf(stderr, "master reginfo:\n");
+ reginfo_dump(&master_ri, 1);
+
+ fprintf(stderr, "apprentice reginfo:\n");
+ reginfo_dump(&apprentice_ri, 0);
+
+ reginfo_dump_mismatch(&master_ri, &apprentice_ri, stderr);
+ return resp;
+}
diff --git a/risu_reginfo_m68k.c b/risu_reginfo_m68k.c
new file mode 100644
index 0000000..c9d21cc
--- /dev/null
+++ b/risu_reginfo_m68k.c
@@ -0,0 +1,151 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Laurent Vivier
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <string.h>
+#include <math.h>
+
+#include "risu.h"
+#include "risu_reginfo_m68k.h"
+
+/* reginfo_init: initialize with a ucontext */
+void reginfo_init(struct reginfo *ri, ucontext_t *uc)
+{
+ int i;
+ memset(ri, 0, sizeof(*ri));
+
+ ri->faulting_insn = *((uint32_t *)uc->uc_mcontext.gregs[R_PC]);
+ ri->pc = uc->uc_mcontext.gregs[R_PC] - image_start_address;
+
+ for (i = 0; i < NGREG; i++) {
+ ri->gregs[i] = uc->uc_mcontext.gregs[i];
+ }
+
+ ri->fpregs.f_pcr = uc->uc_mcontext.fpregs.f_pcr;
+ ri->fpregs.f_psr = uc->uc_mcontext.fpregs.f_psr;
+ ri->fpregs.f_fpiaddr = uc->uc_mcontext.fpregs.f_fpiaddr;
+ for (i = 0; i < 8; i++) {
+ memcpy(&ri->fpregs.f_fpregs[i * 3],
+ &uc->uc_mcontext.fpregs.f_fpregs[i * 3],
+ 3 * sizeof(int));
+ }
+}
+
+/* reginfo_is_eq: compare the reginfo structs, returns nonzero if equal */
+int reginfo_is_eq(struct reginfo *m, struct reginfo *a, ucontext_t *uc)
+{
+ int i;
+
+ if (m->gregs[R_PS] != a->gregs[R_PS]) {
+ return 0;
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (i == R_SP || i == R_A6) {
+ continue;
+ }
+ if (m->gregs[i] != a->gregs[i]) {
+ return 0;
+ }
+ }
+
+ if (m->fpregs.f_pcr != a->fpregs.f_pcr) {
+ return 0;
+ }
+
+ if (m->fpregs.f_psr != a->fpregs.f_psr) {
+ return 0;
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (m->fpregs.f_fpregs[i * 3] != a->fpregs.f_fpregs[i * 3] ||
+ m->fpregs.f_fpregs[i * 3 + 1] != a->fpregs.f_fpregs[i * 3 + 1] ||
+ m->fpregs.f_fpregs[i * 3 + 2] != a->fpregs.f_fpregs[i * 3 + 2]) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* reginfo_dump: print state to a stream, returns nonzero on success */
+void reginfo_dump(struct reginfo *ri, int is_master)
+{
+ int i;
+ if (is_master) {
+ fprintf(stderr, " pc \e[1;101;37m0x%08x\e[0m\n",
+ ri->pc);
+ }
+ fprintf(stderr, "\tPC: %08x\n", ri->gregs[R_PC]);
+ fprintf(stderr, "\tPS: %04x\n", ri->gregs[R_PS]);
+
+ for (i = 0; i < 8; i++) {
+ fprintf(stderr, "\tD%d: %8x\tA%d: %8x\n", i, ri->gregs[i],
+ i, ri->gregs[i + 8]);
+ }
+
+
+ for (i = 0; i < 8; i++) {
+ fprintf(stderr, "\tFP%d: %08x %08x %08x\n", i,
+ ri->fpregs.f_fpregs[i * 3], ri->fpregs.f_fpregs[i * 3 + 1],
+ ri->fpregs.f_fpregs[i * 3 + 2]);
+ }
+
+ fprintf(stderr, "\n");
+}
+
+int reginfo_dump_mismatch(struct reginfo *m, struct reginfo *a, FILE *f)
+{
+ int i;
+
+ if (m->gregs[R_PS] != a->gregs[R_PS]) {
+ fprintf(f, "Mismatch: Register PS\n");
+ fprintf(f, "master: [%x] - apprentice: [%x]\n",
+ m->gregs[R_PS], a->gregs[R_PS]);
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (i == R_SP || i == R_A6) {
+ continue;
+ }
+ if (m->gregs[i] != a->gregs[i]) {
+ fprintf(f, "Mismatch: Register %c%d\n", i < 8 ? 'D' : 'A', i % 8);
+ fprintf(f, "master: [%x] - apprentice: [%x]\n",
+ m->gregs[i], a->gregs[i]);
+ }
+ }
+
+ if (m->fpregs.f_pcr != a->fpregs.f_pcr) {
+ fprintf(f, "Mismatch: Register FPCR\n");
+ fprintf(f, "m: [%04x] != a: [%04x]\n",
+ m->fpregs.f_pcr, a->fpregs.f_pcr);
+ }
+
+ if (m->fpregs.f_psr != a->fpregs.f_psr) {
+ fprintf(f, "Mismatch: Register FPSR\n");
+ fprintf(f, "m: [%08x] != a: [%08x]\n",
+ m->fpregs.f_psr, a->fpregs.f_psr);
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (m->fpregs.f_fpregs[i * 3] != a->fpregs.f_fpregs[i * 3] ||
+ m->fpregs.f_fpregs[i * 3 + 1] != a->fpregs.f_fpregs[i * 3 + 1] ||
+ m->fpregs.f_fpregs[i * 3 + 2] != a->fpregs.f_fpregs[i * 3 + 2]) {
+ fprintf(f, "Mismatch: Register FP%d\n", i);
+ fprintf(f, "m: [%08x %08x %08x] != a: [%08x %08x %08x]\n",
+ m->fpregs.f_fpregs[i * 3], m->fpregs.f_fpregs[i * 3 + 1],
+ m->fpregs.f_fpregs[i * 3 + 2], a->fpregs.f_fpregs[i * 3],
+ a->fpregs.f_fpregs[i * 3 + 1],
+ a->fpregs.f_fpregs[i * 3 + 2]);
+ }
+ }
+
+
+ return !ferror(f);
+}
diff --git a/risu_reginfo_m68k.h b/risu_reginfo_m68k.h
new file mode 100644
index 0000000..9dd8f32
--- /dev/null
+++ b/risu_reginfo_m68k.h
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Laurent Vivier
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *****************************************************************************/
+
+#ifndef RISU_REGINFO_M68K_H
+#define RISU_REGINFO_M68K_H
+
+struct reginfo
+{
+ uint32_t faulting_insn;
+ uint32_t pc;
+ gregset_t gregs;
+ fpregset_t fpregs;
+};
+
+/* initialize structure from a ucontext */
+void reginfo_init(struct reginfo *ri, ucontext_t *uc);
+
+/* return 1 if structs are equal, 0 otherwise. */
+int reginfo_is_eq(struct reginfo *r1, struct reginfo *r2, ucontext_t *uc);
+
+/* print reginfo state to a stream */
+void reginfo_dump(struct reginfo *ri, int is_master);
+
+/* reginfo_dump_mismatch: print mismatch details to a stream, ret nonzero=ok */
+int reginfo_dump_mismatch(struct reginfo *m, struct reginfo *a, FILE *f);
+
+#endif /* RISU_REGINFO_M68K_H */
diff --git a/test_m68k.s b/test_m68k.s
new file mode 100644
index 0000000..6ca8a92
--- /dev/null
+++ b/test_m68k.s
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Laurent Vivier
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************
+
+/* Initialise the gp regs */
+moveq.l #0, %d0
+move.l %d0, %d1
+move.l %d0, %d2
+move.l %d0, %d3
+move.l %d0, %d4
+move.l %d0, %d5
+move.l %d0, %d6
+move.l %d0, %d7
+move.l %d0, %a0
+move.l %d0, %a1
+move.l %d0, %a2
+move.l %d0, %a3
+move.l %d0, %a4
+move.l %d0, %a5
+
+/* do compare */
+.int 0x4afc7000
+/* exit test */
+.int 0x4afc7001
--
2.9.3
On 7 February 2017 at 18:33, Laurent Vivier <laurent@vivier.eu> wrote:
> This also adds the basic test file and the configuration update.
>
> This implementation can only test instructions with values in register and
> no memory access.
>
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Hi; I got round to setting up my machine with an m68k cross
compiler so I can at least compile-test the other target
architectures, and I noticed this code generates compiler
warnings:
> +/* reginfo_dump: print state to a stream, returns nonzero on success */
> +void reginfo_dump(struct reginfo *ri, int is_master)
> +{
> + int i;
> + if (is_master) {
> + fprintf(stderr, " pc \e[1;101;37m0x%08x\e[0m\n",
> + ri->pc);
> + }
> + fprintf(stderr, "\tPC: %08x\n", ri->gregs[R_PC]);
> + fprintf(stderr, "\tPS: %04x\n", ri->gregs[R_PS]);
> +
> + for (i = 0; i < 8; i++) {
> + fprintf(stderr, "\tD%d: %8x\tA%d: %8x\n", i, ri->gregs[i],
> + i, ri->gregs[i + 8]);
> + }
> +
> +
> + for (i = 0; i < 8; i++) {
> + fprintf(stderr, "\tFP%d: %08x %08x %08x\n", i,
> + ri->fpregs.f_fpregs[i * 3], ri->fpregs.f_fpregs[i * 3 + 1],
> + ri->fpregs.f_fpregs[i * 3 + 2]);
/home/pm215/risu/risu_reginfo_m68k.c:95:37: warning: format ‘%x’
expects argument of type ‘unsigned int’, but argument 4 has type ‘int
*’ [-Wformat=]
fprintf(stderr, "\tFP%d: %08x %08x %08x\n", i,
^
and similarly for the other 3 f_fpregs[] arguments here
and in the fprintf calls in reginfo_dump_mismatch().
Looking at the m68k sys/ucontext.h its definition of
struct fpregset is
#ifdef __mcoldfire__
int f_fpregs[8][2];
#else
int f_fpregs[8][3];
#endif
so it's a 2d array, not a 1d array.
Any suggestions for how to fix the code? The whole file
seems to treat f_fpregs as a 1d array...
thanks
-- PMM
Le 18/02/2017 à 23:37, Peter Maydell a écrit :
> On 7 February 2017 at 18:33, Laurent Vivier <laurent@vivier.eu> wrote:
>> This also adds the basic test file and the configuration update.
>>
>> This implementation can only test instructions with values in register and
>> no memory access.
>>
>> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
>
> Hi; I got round to setting up my machine with an m68k cross
> compiler so I can at least compile-test the other target
> architectures, and I noticed this code generates compiler
> warnings:
>
>> +/* reginfo_dump: print state to a stream, returns nonzero on success */
>> +void reginfo_dump(struct reginfo *ri, int is_master)
>> +{
>> + int i;
>> + if (is_master) {
>> + fprintf(stderr, " pc \e[1;101;37m0x%08x\e[0m\n",
>> + ri->pc);
>> + }
>> + fprintf(stderr, "\tPC: %08x\n", ri->gregs[R_PC]);
>> + fprintf(stderr, "\tPS: %04x\n", ri->gregs[R_PS]);
>> +
>> + for (i = 0; i < 8; i++) {
>> + fprintf(stderr, "\tD%d: %8x\tA%d: %8x\n", i, ri->gregs[i],
>> + i, ri->gregs[i + 8]);
>> + }
>> +
>> +
>> + for (i = 0; i < 8; i++) {
>> + fprintf(stderr, "\tFP%d: %08x %08x %08x\n", i,
>> + ri->fpregs.f_fpregs[i * 3], ri->fpregs.f_fpregs[i * 3 + 1],
>> + ri->fpregs.f_fpregs[i * 3 + 2]);
>
> /home/pm215/risu/risu_reginfo_m68k.c:95:37: warning: format ‘%x’
> expects argument of type ‘unsigned int’, but argument 4 has type ‘int
> *’ [-Wformat=]
> fprintf(stderr, "\tFP%d: %08x %08x %08x\n", i,
> ^
>
> and similarly for the other 3 f_fpregs[] arguments here
> and in the fprintf calls in reginfo_dump_mismatch().
>
> Looking at the m68k sys/ucontext.h its definition of
> struct fpregset is
> #ifdef __mcoldfire__
> int f_fpregs[8][2];
> #else
> int f_fpregs[8][3];
> #endif
>
> so it's a 2d array, not a 1d array.
In fact, in etch-m68k, there are two definitions of fpregset:
/usr/include/sys/ucontext.h
typedef struct fpregset
{
int f_fpregs[8][3];
int f_pcr;
int f_psr;
int f_fpiaddr;
} fpregset_t;
/usr/include/asm/ucontext.h
typedef struct fpregset {
int f_fpcntl[3];
int f_fpregs[8*3];
} fpregset_t;
This is the one used by the kernel:
arch/m68k/include/asm/ucontext.h
typedef struct fpregset {
int f_fpcntl[3];
int f_fpregs[8*3];
} fpregset_t;
In the past, as the one from sys/ucontext.h was not compatible with the
one from the kernel, I have updated my system to use the one from the
kernel.
But in debian unstable, we have now:
typedef struct fpregset
{
int f_pcr;
int f_psr;
int f_fpiaddr;
#ifdef __mcoldfire__
int f_fpregs[8][2];
#else
int f_fpregs[8][3];
#endif
} fpregset_t;
And this is compatible with the kernel one.
So I'm going to update the RISU code to use the 2d array.
Thanks,
Laurent
© 2016 - 2026 Red Hat, Inc.