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