This implementation drives both client and server sides with PPC64 specific code. It basically reads instructions from both sides and compare them.
Signed-off-by: Jose Ricardo Ziviani <jos...@linux.vnet.ibm.com> --- risu_ppc64le.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 risu_ppc64le.c diff --git a/risu_ppc64le.c b/risu_ppc64le.c new file mode 100644 index 0000000..9c1fafd --- /dev/null +++ b/risu_ppc64le.c @@ -0,0 +1,158 @@ +/****************************************************************************** + * Copyright (c) IBM Corp, 2016 + * 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: + * Jose Ricardo Ziviani - initial implementation + * based on Claudio Fontana's risu_aarch64.c + * based on Peter Maydell's risu_arm.c + *****************************************************************************/ + +#include <stdio.h> +#include <ucontext.h> +#include <string.h> + +#include "risu.h" +#include "risu_reginfo_ppc64le.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.regs->nip += 4; +} + +void set_x0(void *vuc, uint64_t x0) +{ + ucontext_t *uc = vuc; + uc->uc_mcontext.gp_regs[0] = x0; +} + +static int get_risuop(uint32_t insn) +{ + uint32_t op = insn & 0xf; + uint32_t key = insn & ~0xf; + uint32_t risukey = 0x00005af0; + 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[0]; + break; + case OP_GETMEMBLOCK: + set_x0(uc, ri.gregs[0] + (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[0]; + break; + case OP_GETMEMBLOCK: + set_x0(uc, master_ri.gregs[0] + (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; +} -- 2.7.4