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 - 2025 Red Hat, Inc.