179 lines · 3.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2025, Google LLC. * Pasha Tatashin <pasha.tatashin@soleen.com> */#include <fcntl.h>#include <linux/kexec.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/mount.h>#include <sys/reboot.h>#include <sys/syscall.h>#include <sys/wait.h>#include <unistd.h> #define COMMAND_LINE_SIZE 2048#define KERNEL_IMAGE "/kernel"#define INITRD_IMAGE "/initrd.img"#define TEST_BINARY "/test_binary" static int mount_filesystems(void){	if (mount("devtmpfs", "/dev", "devtmpfs", 0, NULL) < 0) {		fprintf(stderr, "INIT: Warning: Failed to mount devtmpfs\n");		return -1;	} 	if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0) {		fprintf(stderr, "INIT: Failed to mount debugfs\n");		return -1;	} 	if (mount("proc", "/proc", "proc", 0, NULL) < 0) {		fprintf(stderr, "INIT: Failed to mount proc\n");		return -1;	} 	return 0;} static long kexec_file_load(int kernel_fd, int initrd_fd,			    unsigned long cmdline_len, const char *cmdline,			    unsigned long flags){	return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len,		       cmdline, flags);} static int kexec_load(void){	char cmdline[COMMAND_LINE_SIZE];	int kernel_fd, initrd_fd, err;	ssize_t len;	int fd; 	fd = open("/proc/cmdline", O_RDONLY);	if (fd < 0) {		fprintf(stderr, "INIT: Failed to read /proc/cmdline\n"); 		return -1;	} 	len = read(fd, cmdline, sizeof(cmdline) - 1);	close(fd);	if (len < 0)		return -1; 	cmdline[len] = 0;	if (len > 0 && cmdline[len - 1] == '\n')		cmdline[len - 1] = 0; 	strncat(cmdline, " luo_stage=2", sizeof(cmdline) - strlen(cmdline) - 1); 	kernel_fd = open(KERNEL_IMAGE, O_RDONLY);	if (kernel_fd < 0) {		fprintf(stderr, "INIT: Failed to open kernel image\n");		return -1;	} 	initrd_fd = open(INITRD_IMAGE, O_RDONLY);	if (initrd_fd < 0) {		fprintf(stderr, "INIT: Failed to open initrd image\n");		close(kernel_fd);		return -1;	} 	err = kexec_file_load(kernel_fd, initrd_fd, strlen(cmdline) + 1,			      cmdline, 0); 	close(initrd_fd);	close(kernel_fd); 	return err;} static int run_test(int stage){	char stage_arg[32];	int status;	pid_t pid; 	snprintf(stage_arg, sizeof(stage_arg), "%d", stage); 	pid = fork();	if (pid < 0)		return -1; 	if (!pid) {		char *const argv[] = {TEST_BINARY, "-s", stage_arg, NULL}; 		execve(TEST_BINARY, argv, NULL);		fprintf(stderr, "INIT: execve failed\n");		_exit(1);	} 	waitpid(pid, &status, 0); 	return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : -1;} static int get_current_stage(void){	char cmdline[COMMAND_LINE_SIZE];	ssize_t len;	int fd; 	fd = open("/proc/cmdline", O_RDONLY);	if (fd < 0)		return -1; 	len = read(fd, cmdline, sizeof(cmdline) - 1);	close(fd); 	if (len < 0)		return -1; 	cmdline[len] = 0; 	return strstr(cmdline, "luo_stage=2") ? 2 : 1;} int main(int argc, char *argv[]){	int current_stage;	int err; 	if (mount_filesystems())		goto err_reboot; 	current_stage = get_current_stage();	if (current_stage < 0) {		fprintf(stderr, "INIT: Failed to read cmdline");		goto err_reboot;	} 	printf("INIT: Starting Stage %d\n", current_stage); 	if (current_stage == 1 && kexec_load()) {		fprintf(stderr, "INIT: Failed to load kexec kernel\n");		goto err_reboot;	} 	if (run_test(current_stage)) {		fprintf(stderr, "INIT: Test binary returned failure\n");		goto err_reboot;	} 	printf("INIT: Stage %d completed successfully.\n", current_stage);	reboot(current_stage == 1 ? RB_KEXEC : RB_AUTOBOOT); 	return 0; err_reboot:	reboot(RB_AUTOBOOT); 	return -1;}