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
mount_filesystems(void)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
kho_enable(void)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
kexec_file_load(int kernel_fd,int initrd_fd,unsigned long cmdline_len,const char * cmdline,unsigned long flags)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
kexec_load(void)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
main(int argc,char * argv[])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