aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rw-r--r--risu.c96
-rw-r--r--risu.h39
-rw-r--r--risu_arm.c28
-rw-r--r--risu_i386.c36
5 files changed, 193 insertions, 17 deletions
diff --git a/Makefile b/Makefile
index aec5703..e99404a 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/risu.c b/risu.c
index dfadf4e..e3cbf67 100644
--- a/risu.c
+++ b/risu.c
@@ -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);
}
diff --git a/risu.h b/risu.h
new file mode 100644
index 0000000..8964e30
--- /dev/null
+++ b/risu.h
@@ -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;
+}