Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
108 lines
3.2 KiB
C
108 lines
3.2 KiB
C
/* SPDX-License-Identifier: MPL-2.0
|
|
* Stage-zero diagnostic init. No disks, network or Android framework.
|
|
* Keep this executable independent of libc to use it on both test targets.
|
|
*/
|
|
#if defined(__x86_64__)
|
|
#define NR_write 1
|
|
#define NR_read 0
|
|
#define NR_close 3
|
|
#define NR_openat 257
|
|
#define NR_mount 165
|
|
#define NR_getpid 39
|
|
#define NR_exit 60
|
|
#define NR_reboot 169
|
|
#define NR_nanosleep 35
|
|
static long call(long n, long a, long b, long c, long d, long e) {
|
|
register long r10 __asm__("r10") = d;
|
|
register long r8 __asm__("r8") = e;
|
|
long result;
|
|
__asm__ volatile("syscall" : "=a"(result)
|
|
: "a"(n), "D"(a), "S"(b), "d"(c), "r"(r10), "r"(r8)
|
|
: "rcx", "r11", "memory");
|
|
return result;
|
|
}
|
|
#elif defined(__aarch64__)
|
|
#define NR_write 64
|
|
#define NR_read 63
|
|
#define NR_close 57
|
|
#define NR_openat 56
|
|
#define NR_mount 40
|
|
#define NR_getpid 172
|
|
#define NR_exit 93
|
|
#define NR_reboot 142
|
|
#define NR_nanosleep 101
|
|
static long call(long n, long a, long b, long c, long d, long e) {
|
|
register long x8 __asm__("x8") = n;
|
|
register long x0 __asm__("x0") = a;
|
|
register long x1 __asm__("x1") = b;
|
|
register long x2 __asm__("x2") = c;
|
|
register long x3 __asm__("x3") = d;
|
|
register long x4 __asm__("x4") = e;
|
|
__asm__ volatile("svc 0" : "+r"(x0)
|
|
: "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4)
|
|
: "memory");
|
|
return x0;
|
|
}
|
|
#else
|
|
#error Unsupported architecture
|
|
#endif
|
|
|
|
static void say(const char *s) {
|
|
long n = 0;
|
|
while (s[n]) ++n;
|
|
while (n > 0) {
|
|
long written = call(NR_write, 1, (long)s, n, 0, 0);
|
|
if (written <= 0) break;
|
|
s += written;
|
|
n -= written;
|
|
}
|
|
}
|
|
|
|
static int contains(const char *s, const char *needle) {
|
|
for (; *s; ++s) {
|
|
long i = 0;
|
|
while (needle[i] && s[i] == needle[i]) ++i;
|
|
if (!needle[i]) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void file(const char *path, char *buffer, long capacity) {
|
|
long fd = call(NR_openat, -100, (long)path, 0, 0, 0);
|
|
buffer[0] = 0;
|
|
if (fd < 0) return;
|
|
long n = call(NR_read, fd, (long)buffer, capacity - 1, 0, 0);
|
|
if (n > 0) buffer[n] = 0;
|
|
call(NR_close, fd, 0, 0, 0, 0);
|
|
}
|
|
|
|
__attribute__((noreturn)) void _start(void) {
|
|
if (call(NR_getpid, 0, 0, 0, 0, 0) != 1) {
|
|
say("Tundra init must only run as PID 1 in the diagnostic ramdisk.\n");
|
|
call(NR_exit, 2, 0, 0, 0, 0);
|
|
for (;;) {}
|
|
}
|
|
say("TUNDRA_STAGE0_START\n");
|
|
long proc = call(NR_mount, (long)"proc", (long)"/proc", (long)"proc", 14, 0);
|
|
long sys = call(NR_mount, (long)"sysfs", (long)"/sys", (long)"sysfs", 14, 0);
|
|
char buffer[4096];
|
|
file("/proc/version", buffer, sizeof(buffer));
|
|
say(buffer);
|
|
file("/proc/cmdline", buffer, sizeof(buffer));
|
|
int selftest = contains(buffer, "tundra.selftest=1");
|
|
if (proc == 0 && sys == 0 && buffer[0]) {
|
|
say("TUNDRA_STAGE0_OK pid1 proc sysfs cmdline\n");
|
|
} else {
|
|
say("TUNDRA_STAGE0_FAILED pseudo-filesystems\n");
|
|
}
|
|
say("Diagnostic only: no Gecko, Gaia, HAL, USB service or persistent mounts.\n");
|
|
if (selftest) {
|
|
say("TUNDRA_STAGE0_POWEROFF\n");
|
|
call(NR_reboot, 0xfee1dead, 672274793, 0x4321fedc, 0, 0);
|
|
}
|
|
for (;;) {
|
|
long delay[2] = {15, 0};
|
|
call(NR_nanosleep, (long)delay, 0, 0, 0, 0);
|
|
say("TUNDRA_STAGE0_ALIVE\n");
|
|
}
|
|
}
|