DF-2813 / ochang_drv.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /* * ochang_drv.c - userspace driver for the ochang KLD (DF-2813 PoC). * * Pins itself to cpu2 (neither the strand cpu0 nor the sleeper cpu5) and * orchestrates the ARM/SLEEPER/STRAND/PROBE/RESCUE sequence, printing the * sleeper state with timestamps. * * Exit code 0 = bug reproduced (sleeper stuck >= 8 s with objects available * on the strand cpu, then woken by RESCUE in < 2 s). */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/sysctl.h> #include <sys/usched.h> static void cmd(int c) { if (sysctlbyname("kern.ochang.cmd", NULL, NULL, &c, sizeof(c)) < 0) { perror("sysctl cmd"); exit(1); } } static void status(const char *tag) { char buf[1024]; size_t len = sizeof(buf) - 1; buf[0] = 0; if (sysctlbyname("kern.ochang.status", buf, &len, NULL, 0) < 0) { perror("sysctl status"); exit(1); } buf[len] = 0; printf("[%s] %s", tag, buf); fflush(stdout); } static double now_s(void) { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec + tv.tv_usec / 1e6); } static int sleeper_got(void) { char buf[1024]; size_t len = sizeof(buf) - 1; char *p; buf[0] = 0; if (sysctlbyname("kern.ochang.status", buf, &len, NULL, 0) < 0) exit(1); buf[len] = 0; p = strstr(buf, "got="); if (!p) return (-1); return (atoi(p + 4)); } int main(void) { double t_strand, t_reacq; int cpu = 2; int i; if (usched_set(0, USCHED_SET_CPU, &cpu, sizeof(cpu)) < 0) { perror("usched_set"); exit(1); } printf("driver pinned to cpu%d\n", cpu); cmd(1); /* ARM */ status("after ARM"); usleep(200000); cmd(2); /* SLEEPER on cpu5 */ usleep(1000000); status("sleeper +1s"); cmd(3); /* STRAND: magcap objects onto cpu0 */ t_strand = now_s(); printf("=== STRAND done, watching sleeper for up to 10 s ===\n"); for (i = 0; i < 10 * 4; i++) { usleep(250000); if (sleeper_got() == 1) { printf("!!! sleeper woke unexpectedly after %.2f s\n", now_s() - t_strand); break; } } status("post-strand"); cmd(7); /* PROBE strand cpu: expect OBJECT */ cmd(8); /* PROBE sleeper cpu: expect NULL */ status("post-probe"); if (sleeper_got() != 1) { printf("=== RESCUE (cycle both cpu0 magazines to depot) ===\n"); cmd(4); t_reacq = now_s(); while (now_s() - t_reacq < 5.0) { if (sleeper_got() == 1) break; usleep(20000); } if (sleeper_got() == 1) printf("sleeper acquired %.3f s after RESCUE\n", now_s() - t_reacq); else printf("sleeper STILL stuck after RESCUE (bug in PoC)\n"); } status("final"); cmd(5); /* DRAIN */ cmd(6); /* DESTROY */ printf("=== summary: stuck_with_available_objects=%s rescue_wake=%s ===\n", "see log above", sleeper_got() == 1 ? "yes" : "no"); return (0); } |