1*89dd1421SPasha Tatashin // SPDX-License-Identifier: GPL-2.0 2*89dd1421SPasha Tatashin 3*89dd1421SPasha Tatashin /* 4*89dd1421SPasha Tatashin * Copyright (c) 2025, Google LLC. 5*89dd1421SPasha Tatashin * Pasha Tatashin <pasha.tatashin@soleen.com> 6*89dd1421SPasha Tatashin */ 7*89dd1421SPasha Tatashin #include <fcntl.h> 8*89dd1421SPasha Tatashin #include <linux/kexec.h> 9*89dd1421SPasha Tatashin #include <stdio.h> 10*89dd1421SPasha Tatashin #include <stdlib.h> 11*89dd1421SPasha Tatashin #include <string.h> 12*89dd1421SPasha Tatashin #include <sys/mount.h> 13*89dd1421SPasha Tatashin #include <sys/reboot.h> 14*89dd1421SPasha Tatashin #include <sys/syscall.h> 15*89dd1421SPasha Tatashin #include <sys/wait.h> 16*89dd1421SPasha Tatashin #include <unistd.h> 17*89dd1421SPasha Tatashin 18*89dd1421SPasha Tatashin #define COMMAND_LINE_SIZE 2048 19*89dd1421SPasha Tatashin #define KERNEL_IMAGE "/kernel" 20*89dd1421SPasha Tatashin #define INITRD_IMAGE "/initrd.img" 21*89dd1421SPasha Tatashin #define TEST_BINARY "/test_binary" 22*89dd1421SPasha Tatashin 23*89dd1421SPasha Tatashin static int mount_filesystems(void) 24*89dd1421SPasha Tatashin { 25*89dd1421SPasha Tatashin if (mount("devtmpfs", "/dev", "devtmpfs", 0, NULL) < 0) { 26*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Warning: Failed to mount devtmpfs\n"); 27*89dd1421SPasha Tatashin return -1; 28*89dd1421SPasha Tatashin } 29*89dd1421SPasha Tatashin 30*89dd1421SPasha Tatashin if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0) { 31*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to mount debugfs\n"); 32*89dd1421SPasha Tatashin return -1; 33*89dd1421SPasha Tatashin } 34*89dd1421SPasha Tatashin 35*89dd1421SPasha Tatashin if (mount("proc", "/proc", "proc", 0, NULL) < 0) { 36*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to mount proc\n"); 37*89dd1421SPasha Tatashin return -1; 38*89dd1421SPasha Tatashin } 39*89dd1421SPasha Tatashin 40*89dd1421SPasha Tatashin return 0; 41*89dd1421SPasha Tatashin } 42*89dd1421SPasha Tatashin 43*89dd1421SPasha Tatashin static long kexec_file_load(int kernel_fd, int initrd_fd, 44*89dd1421SPasha Tatashin unsigned long cmdline_len, const char *cmdline, 45*89dd1421SPasha Tatashin unsigned long flags) 46*89dd1421SPasha Tatashin { 47*89dd1421SPasha Tatashin return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len, 48*89dd1421SPasha Tatashin cmdline, flags); 49*89dd1421SPasha Tatashin } 50*89dd1421SPasha Tatashin 51*89dd1421SPasha Tatashin static int kexec_load(void) 52*89dd1421SPasha Tatashin { 53*89dd1421SPasha Tatashin char cmdline[COMMAND_LINE_SIZE]; 54*89dd1421SPasha Tatashin int kernel_fd, initrd_fd, err; 55*89dd1421SPasha Tatashin ssize_t len; 56*89dd1421SPasha Tatashin int fd; 57*89dd1421SPasha Tatashin 58*89dd1421SPasha Tatashin fd = open("/proc/cmdline", O_RDONLY); 59*89dd1421SPasha Tatashin if (fd < 0) { 60*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to read /proc/cmdline\n"); 61*89dd1421SPasha Tatashin 62*89dd1421SPasha Tatashin return -1; 63*89dd1421SPasha Tatashin } 64*89dd1421SPasha Tatashin 65*89dd1421SPasha Tatashin len = read(fd, cmdline, sizeof(cmdline) - 1); 66*89dd1421SPasha Tatashin close(fd); 67*89dd1421SPasha Tatashin if (len < 0) 68*89dd1421SPasha Tatashin return -1; 69*89dd1421SPasha Tatashin 70*89dd1421SPasha Tatashin cmdline[len] = 0; 71*89dd1421SPasha Tatashin if (len > 0 && cmdline[len - 1] == '\n') 72*89dd1421SPasha Tatashin cmdline[len - 1] = 0; 73*89dd1421SPasha Tatashin 74*89dd1421SPasha Tatashin strncat(cmdline, " luo_stage=2", sizeof(cmdline) - strlen(cmdline) - 1); 75*89dd1421SPasha Tatashin 76*89dd1421SPasha Tatashin kernel_fd = open(KERNEL_IMAGE, O_RDONLY); 77*89dd1421SPasha Tatashin if (kernel_fd < 0) { 78*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to open kernel image\n"); 79*89dd1421SPasha Tatashin return -1; 80*89dd1421SPasha Tatashin } 81*89dd1421SPasha Tatashin 82*89dd1421SPasha Tatashin initrd_fd = open(INITRD_IMAGE, O_RDONLY); 83*89dd1421SPasha Tatashin if (initrd_fd < 0) { 84*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to open initrd image\n"); 85*89dd1421SPasha Tatashin close(kernel_fd); 86*89dd1421SPasha Tatashin return -1; 87*89dd1421SPasha Tatashin } 88*89dd1421SPasha Tatashin 89*89dd1421SPasha Tatashin err = kexec_file_load(kernel_fd, initrd_fd, strlen(cmdline) + 1, 90*89dd1421SPasha Tatashin cmdline, 0); 91*89dd1421SPasha Tatashin 92*89dd1421SPasha Tatashin close(initrd_fd); 93*89dd1421SPasha Tatashin close(kernel_fd); 94*89dd1421SPasha Tatashin 95*89dd1421SPasha Tatashin return err; 96*89dd1421SPasha Tatashin } 97*89dd1421SPasha Tatashin 98*89dd1421SPasha Tatashin static int run_test(int stage) 99*89dd1421SPasha Tatashin { 100*89dd1421SPasha Tatashin char stage_arg[32]; 101*89dd1421SPasha Tatashin int status; 102*89dd1421SPasha Tatashin pid_t pid; 103*89dd1421SPasha Tatashin 104*89dd1421SPasha Tatashin snprintf(stage_arg, sizeof(stage_arg), "%d", stage); 105*89dd1421SPasha Tatashin 106*89dd1421SPasha Tatashin pid = fork(); 107*89dd1421SPasha Tatashin if (pid < 0) 108*89dd1421SPasha Tatashin return -1; 109*89dd1421SPasha Tatashin 110*89dd1421SPasha Tatashin if (!pid) { 111*89dd1421SPasha Tatashin char *const argv[] = {TEST_BINARY, "-s", stage_arg, NULL}; 112*89dd1421SPasha Tatashin 113*89dd1421SPasha Tatashin execve(TEST_BINARY, argv, NULL); 114*89dd1421SPasha Tatashin fprintf(stderr, "INIT: execve failed\n"); 115*89dd1421SPasha Tatashin _exit(1); 116*89dd1421SPasha Tatashin } 117*89dd1421SPasha Tatashin 118*89dd1421SPasha Tatashin waitpid(pid, &status, 0); 119*89dd1421SPasha Tatashin 120*89dd1421SPasha Tatashin return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : -1; 121*89dd1421SPasha Tatashin } 122*89dd1421SPasha Tatashin 123*89dd1421SPasha Tatashin static int get_current_stage(void) 124*89dd1421SPasha Tatashin { 125*89dd1421SPasha Tatashin char cmdline[COMMAND_LINE_SIZE]; 126*89dd1421SPasha Tatashin ssize_t len; 127*89dd1421SPasha Tatashin int fd; 128*89dd1421SPasha Tatashin 129*89dd1421SPasha Tatashin fd = open("/proc/cmdline", O_RDONLY); 130*89dd1421SPasha Tatashin if (fd < 0) 131*89dd1421SPasha Tatashin return -1; 132*89dd1421SPasha Tatashin 133*89dd1421SPasha Tatashin len = read(fd, cmdline, sizeof(cmdline) - 1); 134*89dd1421SPasha Tatashin close(fd); 135*89dd1421SPasha Tatashin 136*89dd1421SPasha Tatashin if (len < 0) 137*89dd1421SPasha Tatashin return -1; 138*89dd1421SPasha Tatashin 139*89dd1421SPasha Tatashin cmdline[len] = 0; 140*89dd1421SPasha Tatashin 141*89dd1421SPasha Tatashin return strstr(cmdline, "luo_stage=2") ? 2 : 1; 142*89dd1421SPasha Tatashin } 143*89dd1421SPasha Tatashin 144*89dd1421SPasha Tatashin int main(int argc, char *argv[]) 145*89dd1421SPasha Tatashin { 146*89dd1421SPasha Tatashin int current_stage; 147*89dd1421SPasha Tatashin int err; 148*89dd1421SPasha Tatashin 149*89dd1421SPasha Tatashin if (mount_filesystems()) 150*89dd1421SPasha Tatashin goto err_reboot; 151*89dd1421SPasha Tatashin 152*89dd1421SPasha Tatashin current_stage = get_current_stage(); 153*89dd1421SPasha Tatashin if (current_stage < 0) { 154*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to read cmdline"); 155*89dd1421SPasha Tatashin goto err_reboot; 156*89dd1421SPasha Tatashin } 157*89dd1421SPasha Tatashin 158*89dd1421SPasha Tatashin printf("INIT: Starting Stage %d\n", current_stage); 159*89dd1421SPasha Tatashin 160*89dd1421SPasha Tatashin if (current_stage == 1 && kexec_load()) { 161*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Failed to load kexec kernel\n"); 162*89dd1421SPasha Tatashin goto err_reboot; 163*89dd1421SPasha Tatashin } 164*89dd1421SPasha Tatashin 165*89dd1421SPasha Tatashin if (run_test(current_stage)) { 166*89dd1421SPasha Tatashin fprintf(stderr, "INIT: Test binary returned failure\n"); 167*89dd1421SPasha Tatashin goto err_reboot; 168*89dd1421SPasha Tatashin } 169*89dd1421SPasha Tatashin 170*89dd1421SPasha Tatashin printf("INIT: Stage %d completed successfully.\n", current_stage); 171*89dd1421SPasha Tatashin reboot(current_stage == 1 ? RB_KEXEC : RB_AUTOBOOT); 172*89dd1421SPasha Tatashin 173*89dd1421SPasha Tatashin return 0; 174*89dd1421SPasha Tatashin 175*89dd1421SPasha Tatashin err_reboot: 176*89dd1421SPasha Tatashin reboot(RB_AUTOBOOT); 177*89dd1421SPasha Tatashin 178*89dd1421SPasha Tatashin return -1; 179*89dd1421SPasha Tatashin } 180