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