aboutsummaryrefslogtreecommitdiff
path: root/risu_aarch64.c
diff options
context:
space:
mode:
authorClaudio Fontana <claudio.fontana@huawei.com>2013-09-19 16:32:03 +0200
committerPeter Maydell <peter.maydell@linaro.org>2014-04-25 13:07:15 +0100
commita2bfca0c940f0246764c0625ae0b7d66eb1c14c5 (patch)
tree9a70e764439721946a992ebe129362ad4915e3e4 /risu_aarch64.c
parent3af90c91d9b8762071e3cc7ff518cb9c6527940e (diff)
risu_aarch64: provide risu initial implementation for aarch64
Signed-off-by: Claudio Fontana <claudio.fontana@huawei.com>
Diffstat (limited to 'risu_aarch64.c')
-rw-r--r--risu_aarch64.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/risu_aarch64.c b/risu_aarch64.c
new file mode 100644
index 0000000..edf9d7f
--- /dev/null
+++ b/risu_aarch64.c
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * Copyright (c) 2013 Linaro Limited
+ * 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
+ *
+ * Contributors:
+ * Claudio Fontana (Linaro) - initial implementation
+ * based on Peter Maydell's risu_arm.c
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <string.h>
+
+#include "risu.h"
+#include "risu_reginfo_aarch64.h"
+
+struct reginfo master_ri, apprentice_ri;
+
+uint8_t apprentice_memblock[MEMBLOCKLEN];
+
+static int mem_used = 0;
+static int packet_mismatch = 0;
+
+void advance_pc(void *vuc)
+{
+ ucontext_t *uc = vuc;
+ uc->uc_mcontext.pc += 4;
+}
+
+static void set_x0(void *vuc, uint64_t x0)
+{
+ ucontext_t *uc = vuc;
+ uc->uc_mcontext.regs[0] = x0;
+}
+
+static int get_risuop(uint32_t insn)
+{
+ /* Return the risuop we have been asked to do
+ * (or -1 if this was a SIGILL for a non-risuop insn)
+ */
+ uint32_t op = insn & 0xf;
+ uint32_t key = insn & ~0xf;
+ uint32_t risukey = 0xe7fe5af0;
+ 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:
+ /* Do a simple register compare on (a) explicit request
+ * (b) end of test (c) a non-risuop UNDEF
+ */
+ return send_data_pkt(sock, &ri, sizeof(ri));
+ case OP_SETMEMBLOCK:
+ memblock = NULL + ri.regs[0];
+ break;
+ case OP_GETMEMBLOCK:
+ set_x0(uc, ri.regs[0] + (memblock - NULL));
+ 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.
+ *
+ * We don't have any kind of identifying info in the incoming data
+ * that says whether it's register or memory data, so if the two
+ * sides get out of sync then we will fail obscurely.
+ */
+int recv_and_compare_register_info(int sock, void *uc)
+{
+ int resp = 0, op;
+
+ reginfo_init(&master_ri, uc);
+ op = get_risuop(master_ri.faulting_insn);
+
+ switch (op) {
+ case OP_COMPARE:
+ case OP_TESTEND:
+ default:
+ /* Do a simple register compare on (a) explicit request
+ * (b) end of test (c) a non-risuop UNDEF
+ */
+ if (recv_data_pkt(sock, &apprentice_ri, sizeof(apprentice_ri))) {
+ packet_mismatch = 1;
+ resp = 2;
+
+ } else if (!reginfo_is_eq(&master_ri, &apprentice_ri)) {
+ /* register mismatch */
+ resp = 2;
+
+ } else if (op == OP_TESTEND) {
+ resp = 1;
+ }
+ send_response_byte(sock, resp);
+ break;
+ case OP_SETMEMBLOCK:
+ memblock = NULL + master_ri.regs[0];
+ break;
+ case OP_GETMEMBLOCK:
+ set_x0(uc, master_ri.regs[0] + (memblock - NULL));
+ 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) {
+ /* memory mismatch */
+ 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");
+ /* We don't have valid reginfo from the apprentice side
+ * so stop now rather than printing anything about it.
+ */
+ fprintf(stderr, "master reginfo:\n");
+ reginfo_dump(&master_ri, stderr);
+ return 1;
+ }
+ if (memcmp(&master_ri, &apprentice_ri, sizeof(master_ri)) != 0)
+ {
+ 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, stderr);
+ fprintf(stderr, "apprentice reginfo:\n");
+ reginfo_dump(&apprentice_ri, stderr);
+
+ reginfo_dump_mismatch(&master_ri, &apprentice_ri, stderr);
+ return resp;
+}