diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | risu.c | 96 | ||||
-rw-r--r-- | risu.h | 39 | ||||
-rw-r--r-- | risu_arm.c | 28 | ||||
-rw-r--r-- | risu_i386.c | 36 |
5 files changed, 193 insertions, 17 deletions
@@ -1,10 +1,17 @@ # trivial makefile for now +ARCH=$(shell dpkg-architecture -qDEB_HOST_ARCH_CPU) + PROG=risu -SRCS=risu.c +SRCS=risu.c risu_$(ARCH).c +HDRS=risu.h OBJS=$(SRCS:.c=.o) -$(PROG): $(SRCS) + +$(PROG): $(OBJS) $(CC) -g -Wall -Werror -o $@ $^ +%.o: %.c $(HDRS) + $(CC) -g -Wall -Werror -o $@ -c $< + clean: rm -f $(PROG) $(OBJS) @@ -1,4 +1,7 @@ -/* Random Instruction Sequences for Userspace */ +/* Random Instruction Sequences for Userspace + * Copyright 2010 Linaro Limited + * TODO: license + */ #include <unistd.h> #include <stdio.h> @@ -8,8 +11,13 @@ #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> +#include <signal.h> +#include <ucontext.h> #include <getopt.h> +#include <setjmp.h> +#include <assert.h> +#include "risu.h" int apprentice_connect(const char *hostname, uint16_t port) { @@ -93,6 +101,11 @@ int master_connect(uint16_t port) * 0: ok, continue [registers matched] * 1: exit with status 0 [end of test] * 2: exit with status 1 [mismatch, fail] + * + * We can handle the variable-length packet at setup + * (where the apprentice sends command line options, + * random seed etc) by first sending the length alone + * as a 4-byte packet, and then a packet of that length. */ int send_data_pkt(int sock, void *pkt, int pktlen) @@ -145,26 +158,78 @@ void send_response_byte(int sock, int resp) } } +typedef void sighandler_fn_t(int sig, siginfo_t *si, void *vuc); + +sighandler_fn_t master_sigill, apprentice_sigill; + +int apprentice_socket, master_socket; + +sigjmp_buf jmpbuf; + +void master_sigill(int sig, siginfo_t *si, void *uc) +{ + switch (recv_and_compare_register_info(master_socket, uc)) + { + case 0: + /* match OK */ + return; + default: + /* mismatch, or end of test */ + siglongjmp(jmpbuf, 1); + } +} + +void apprentice_sigill(int sig, siginfo_t *si, void *uc) +{ + switch (send_register_info(apprentice_socket, uc)) + { + case 0: + /* match OK */ + return; + case 1: + /* end of test */ + exit(0); + default: + /* mismatch */ + exit(1); + } +} + +static void set_sigill_handler(sighandler_fn_t *fn) +{ + struct sigaction sa; + sa.sa_sigaction = fn; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGILL, &sa, 0) != 0) + { + perror("sigaction"); + exit(1); + } +} + int master(int sock) { - printf("master waiting for data\n"); - unsigned char cmd; - recv_data_pkt(sock, &cmd, 1); - printf("Got cmd %c, sending resp 0\n", cmd); - send_response_byte(sock, 0); - printf("Exiting.\n"); - return 0; + if (sigsetjmp(jmpbuf, 1)) + { + return report_match_status(); + } + master_socket = sock; + set_sigill_handler(master_sigill); + fprintf(stderr, "raising SIGILL\n"); + raise(SIGILL); + assert(!"should never get here"); } int apprentice(int sock) { - printf("requesting stop\n"); - int resp = send_data_pkt(sock, "S", 1); - printf("got response %d\n", resp); - return resp; + apprentice_socket = sock; + set_sigill_handler(apprentice_sigill); + fprintf(stderr, "raising SIGILL\n"); + raise(SIGILL); + assert(!"should never get here"); } - int ismaster; int main(int argc, char **argv) @@ -220,15 +285,16 @@ int main(int argc, char **argv) abort(); } } + if (ismaster) { - printf("master port %d\n", port); + fprintf(stderr, "master port %d\n", port); sock = master_connect(port); return master(sock); } else { - printf("apprentice host %s port %d\n", hostname, port); + fprintf(stderr, "apprentice host %s port %d\n", hostname, port); sock = apprentice_connect(hostname, port); return apprentice(sock); } @@ -0,0 +1,39 @@ +/* Copyright 2010 Linaro Limited */ + +#ifndef RISU_H +#define RISU_H + +#include <stdint.h> + +/* Socket related routines */ +int master_connect(uint16_t port); +int apprentice_connect(const char *hostname, uint16_t port); +int send_data_pkt(int sock, void *pkt, int pktlen); +void recv_data_pkt(int sock, void *pkt, int pktlen); +void send_response_byte(int sock, int resp); + + + +/* Interface provided by CPU-specific code: */ + +/* Send the register information from the struct ucontext down the socket. + * Return the response code from the master. + * NB: called from a signal handler. + */ +int send_register_info(int sock, void *uc); + +/* 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); + +/* 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); + +#endif /* RISU_H */ diff --git a/risu_arm.c b/risu_arm.c new file mode 100644 index 0000000..7cb546a --- /dev/null +++ b/risu_arm.c @@ -0,0 +1,28 @@ +/* Copyright 2010 Linaro Limited */ + +int send_register_info(int sock, void *uc) +{ + return 1; +} + +/* 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) +{ + return 1; +} + +/* 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) +{ + return 0; +} + + diff --git a/risu_i386.c b/risu_i386.c new file mode 100644 index 0000000..673a711 --- /dev/null +++ b/risu_i386.c @@ -0,0 +1,36 @@ +/* Copyright 2010 Linaro Limited */ + +#include <stdio.h> + +#include "risu.h" + +int send_register_info(int sock, void *uc) +{ + return send_data_pkt(sock, "S", 1); +} + +static unsigned char cmd; + +/* 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) +{ + recv_data_pkt(sock, &cmd, 1); + int resp = (cmd == 'S') ? 1 : 2; + send_response_byte(sock, resp); + 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) +{ + fprintf(stderr, "match status: command %c\n", cmd); + return (cmd == 'S') ? 0 : 1; +} |