1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <fcntl.h> 6 #include <sys/syscall.h> 7 #include <sys/mount.h> 8 #include <sys/reboot.h> 9 #include <linux/kexec.h> 10 11 /* from arch/x86/include/asm/setup.h */ 12 #define COMMAND_LINE_SIZE 2048 13 14 #define KHO_FINALIZE "/debugfs/kho/out/finalize" 15 #define KERNEL_IMAGE "/kernel" 16 17 static int mount_filesystems(void) 18 { 19 if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0) 20 return -1; 21 22 return mount("proc", "/proc", "proc", 0, NULL); 23 } 24 25 static int kho_enable(void) 26 { 27 const char enable[] = "1"; 28 int fd; 29 30 fd = open(KHO_FINALIZE, O_RDWR); 31 if (fd < 0) 32 return -1; 33 34 if (write(fd, enable, sizeof(enable)) != sizeof(enable)) 35 return 1; 36 37 close(fd); 38 return 0; 39 } 40 41 static long kexec_file_load(int kernel_fd, int initrd_fd, 42 unsigned long cmdline_len, const char *cmdline, 43 unsigned long flags) 44 { 45 return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len, 46 cmdline, flags); 47 } 48 49 static int kexec_load(void) 50 { 51 char cmdline[COMMAND_LINE_SIZE]; 52 ssize_t len; 53 int fd, err; 54 55 fd = open("/proc/cmdline", O_RDONLY); 56 if (fd < 0) 57 return -1; 58 59 len = read(fd, cmdline, sizeof(cmdline)); 60 close(fd); 61 if (len < 0) 62 return -1; 63 64 /* replace \n with \0 */ 65 cmdline[len - 1] = 0; 66 fd = open(KERNEL_IMAGE, O_RDONLY); 67 if (fd < 0) 68 return -1; 69 70 err = kexec_file_load(fd, -1, len, cmdline, KEXEC_FILE_NO_INITRAMFS); 71 close(fd); 72 73 return err ? : 0; 74 } 75 76 int main(int argc, char *argv[]) 77 { 78 if (mount_filesystems()) 79 goto err_reboot; 80 81 if (kho_enable()) 82 goto err_reboot; 83 84 if (kexec_load()) 85 goto err_reboot; 86 87 if (reboot(RB_KEXEC)) 88 goto err_reboot; 89 90 return 0; 91 92 err_reboot: 93 reboot(RB_AUTOBOOT); 94 return -1; 95 } 96