projects/linux·blob master · refs

179 lines · 3.5 KiB

1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 * Copyright (c) 2025, Google LLC.
5 * Pasha Tatashin <[email protected]>
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
23static 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
43static 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
51static 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
98static 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
123static 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
144int 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
175err_reboot:
176 reboot(RB_AUTOBOOT);
177
178 return -1;
179}