xref: /openbsd-src/sys/arch/octeon/stand/rdboot/rdboot.c (revision d807f41cc31248f3b16b002b1fbfbeea53bf0599)
1*d807f41cSkn /*	$OpenBSD: rdboot.c,v 1.9 2023/10/20 19:55:49 kn Exp $	*/
23a62b615Svisa 
33a62b615Svisa /*
4cf939257Svisa  * Copyright (c) 2019-2020 Visa Hankala
53a62b615Svisa  *
63a62b615Svisa  * Permission to use, copy, modify, and/or distribute this software for any
73a62b615Svisa  * purpose with or without fee is hereby granted, provided that the above
83a62b615Svisa  * copyright notice and this permission notice appear in all copies.
93a62b615Svisa  *
103a62b615Svisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113a62b615Svisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123a62b615Svisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133a62b615Svisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143a62b615Svisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153a62b615Svisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163a62b615Svisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173a62b615Svisa  */
183a62b615Svisa 
193a62b615Svisa #include <sys/types.h>
203a62b615Svisa #include <sys/param.h>
213a62b615Svisa #include <sys/ioctl.h>
223a62b615Svisa #include <sys/mount.h>
233a62b615Svisa #include <sys/reboot.h>
243a62b615Svisa #include <sys/select.h>
25cf939257Svisa #include <sys/stat.h>
263a62b615Svisa 
273a62b615Svisa #include <err.h>
283a62b615Svisa #include <errno.h>
293a62b615Svisa #include <fcntl.h>
303a62b615Svisa #include <paths.h>
313a62b615Svisa #include <stdio.h>
32cf939257Svisa #include <stdlib.h>
333a62b615Svisa #include <string.h>
343a62b615Svisa #include <termios.h>
353a62b615Svisa #include <unistd.h>
363a62b615Svisa #include <util.h>
373a62b615Svisa 
383a62b615Svisa #include <machine/octboot.h>
393a62b615Svisa #include <machine/param.h>
403a62b615Svisa 
413a62b615Svisa #include "cmd.h"
423a62b615Svisa #include "disk.h"
433a62b615Svisa 
443a62b615Svisa #define DEVRANDOM	"/dev/random"
453a62b615Svisa #define BOOTRANDOM	"/etc/random.seed"
46b4bcf630Sderaadt #define BOOTRANDOM_MAX	256	/* no point being greater than RC4STATE */
473a62b615Svisa #define KERNEL		"/bsd"
483a62b615Svisa 
49eb518625Svisa int	loadrandom(void);
50*d807f41cSkn void	kexec(int);
513a62b615Svisa 
523a62b615Svisa struct cmd_state cmd;
533a62b615Svisa int octbootfd = -1;
54*d807f41cSkn const char version[] = "1.4";
553a62b615Svisa 
563a62b615Svisa int
main(void)573a62b615Svisa main(void)
583a62b615Svisa {
593a62b615Svisa 	char rootdev[PATH_MAX];
60*d807f41cSkn 	int fd, hasboot, isupgrade = 0;
613a62b615Svisa 
623a62b615Svisa 	fd = open(_PATH_CONSOLE, O_RDWR);
633a62b615Svisa 	login_tty(fd);
643a62b615Svisa 
653a62b615Svisa 	/* Keep stdout unbuffered to mimic ordinary bootblocks. */
663a62b615Svisa 	setvbuf(stdout, NULL, _IONBF, 0);
673a62b615Svisa 
683a62b615Svisa 	printf(">> OpenBSD/" MACHINE " BOOT %s\n", version);
693a62b615Svisa 
703a62b615Svisa 	octbootfd = open("/dev/octboot", O_WRONLY);
713a62b615Svisa 	if (octbootfd == -1)
723a62b615Svisa 		err(1, "cannot open boot control device");
733a62b615Svisa 
743a62b615Svisa 	memset(&cmd, 0, sizeof(cmd));
753a62b615Svisa 	cmd.boothowto = 0;
763a62b615Svisa 	cmd.conf = "/etc/boot.conf";
773a62b615Svisa 	strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
783a62b615Svisa 	cmd.timeout = 5;
793a62b615Svisa 
803a62b615Svisa 	if (ioctl(octbootfd, OBIOC_GETROOTDEV, rootdev) == -1) {
813a62b615Svisa 		if (errno != ENOENT)
823a62b615Svisa 			fprintf(stderr, "cannot get rootdev from kernel: %s\n",
833a62b615Svisa 			    strerror(errno));
843a62b615Svisa 	} else {
853a62b615Svisa 		snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa",
863a62b615Svisa 		    rootdev, isduid(rootdev, OPENDEV_PART) ? "." : "");
873a62b615Svisa 	}
883a62b615Svisa 
893a62b615Svisa 	disk_init();
903a62b615Svisa 
913a62b615Svisa 	if (upgrade()) {
923a62b615Svisa 		strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
933a62b615Svisa 		printf("upgrade detected: switching to %s\n", cmd.image);
94*d807f41cSkn 		isupgrade = 1;
953a62b615Svisa 	}
963a62b615Svisa 
973a62b615Svisa 	hasboot = read_conf();
983a62b615Svisa 
993a62b615Svisa 	for (;;) {
1003a62b615Svisa 		if (hasboot <= 0) {
1013a62b615Svisa 			do {
1023a62b615Svisa 				printf("boot> ");
1033a62b615Svisa 			} while (!getcmd());
1043a62b615Svisa 		}
1053a62b615Svisa 
106eb518625Svisa 		if (loadrandom() == 0)
107eb518625Svisa 			cmd.boothowto |= RB_GOODRANDOM;
108eb518625Svisa 
109*d807f41cSkn 		kexec(isupgrade);
1103a62b615Svisa 
1113a62b615Svisa 		hasboot = 0;
1123a62b615Svisa 		strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
1133a62b615Svisa 		printf("will try %s\n", cmd.image);
1143a62b615Svisa 	}
1153a62b615Svisa 
1163a62b615Svisa 	return 0;
1173a62b615Svisa }
1183a62b615Svisa 
119eb518625Svisa int
loadrandom(void)1203a62b615Svisa loadrandom(void)
1213a62b615Svisa {
1223a62b615Svisa 	char buf[BOOTRANDOM_MAX];
123eb518625Svisa 	struct stat sb;
124eb518625Svisa 	int fd, ret = 0;
1253a62b615Svisa 
1263a62b615Svisa 	/* Read the file from the device specified by the kernel path. */
1273a62b615Svisa 	if (disk_open(cmd.path) == NULL)
128eb518625Svisa 		return -1;
1293a62b615Svisa 	fd = open(BOOTRANDOM, O_RDONLY);
1303a62b615Svisa 	if (fd == -1) {
1313a62b615Svisa 		fprintf(stderr, "%s: cannot open %s: %s", __func__, BOOTRANDOM,
1323a62b615Svisa 		    strerror(errno));
1333a62b615Svisa 		disk_close();
134eb518625Svisa 		return -1;
1353a62b615Svisa 	}
136eb518625Svisa 	if (fstat(fd, &sb) == 0) {
137eb518625Svisa 		if (sb.st_mode & S_ISTXT) {
138eb518625Svisa 			printf("NOTE: random seed is being reused.\n");
139eb518625Svisa 			ret = -1;
140eb518625Svisa 		}
141eb518625Svisa 		if (read(fd, buf, sizeof(buf)) != sizeof(buf))
142eb518625Svisa 			ret = -1;
143eb518625Svisa 		fchmod(fd, sb.st_mode | S_ISTXT);
144eb518625Svisa 	} else {
145eb518625Svisa 		ret = -1;
146eb518625Svisa 	}
1473a62b615Svisa 	close(fd);
1483a62b615Svisa 	disk_close();
1493a62b615Svisa 
1503a62b615Svisa 	/*
1513a62b615Svisa 	 * Push the whole buffer to the entropy pool.
1523a62b615Svisa 	 * The kernel will use the entropy on kexec().
1533a62b615Svisa 	 * It does not matter if some of the buffer content is uninitialized.
1543a62b615Svisa 	 */
1553a62b615Svisa 	fd = open(DEVRANDOM, O_WRONLY);
1563a62b615Svisa 	if (fd == -1) {
1573a62b615Svisa 		fprintf(stderr, "%s: cannot open %s: %s", __func__,
1583a62b615Svisa 		    DEVRANDOM, strerror(errno));
159eb518625Svisa 		return -1;
1603a62b615Svisa 	}
1613a62b615Svisa 	write(fd, buf, sizeof(buf));
1623a62b615Svisa 	close(fd);
163eb518625Svisa 	return ret;
1643a62b615Svisa }
1653a62b615Svisa 
1663a62b615Svisa void
kexec(int isupgrade)167*d807f41cSkn kexec(int isupgrade)
1683a62b615Svisa {
1693a62b615Svisa 	struct octboot_kexec_args kargs;
170cf939257Svisa 	struct stat sb;
171a084a2f8Svisa 	char boothowtostr[32];
1723a62b615Svisa 	char rootdev[32];
173cf939257Svisa 	char *kimg = NULL;
1743a62b615Svisa 	const char *path;
175cf939257Svisa 	ssize_t n;
176cf939257Svisa 	off_t pos;
177cf939257Svisa 	int argc, fd = -1, ret;
1783a62b615Svisa 
1793a62b615Svisa 	path = disk_open(cmd.path);
1803a62b615Svisa 	if (path == NULL)
1813a62b615Svisa 		return;
1823a62b615Svisa 
183cf939257Svisa 	fd = open(path, O_RDONLY);
184cf939257Svisa 	if (fd == -1)
185cf939257Svisa 		goto load_failed;
186cf939257Svisa 	if (fstat(fd, &sb) == -1)
187cf939257Svisa 		goto load_failed;
188cf939257Svisa 	if (!S_ISREG(sb.st_mode) || sb.st_size == 0) {
189cf939257Svisa 		errno = ENOEXEC;
190cf939257Svisa 		goto load_failed;
191cf939257Svisa 	}
192cf939257Svisa 
193*d807f41cSkn 	/* Prevent re-upgrade: chmod a-x bsd.upgrade */
194*d807f41cSkn 	if (isupgrade) {
195*d807f41cSkn 		sb.st_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
196*d807f41cSkn 		if (fchmod(fd, sb.st_mode) == -1)
197*d807f41cSkn 			printf("fchmod a-x %s: failed\n", path);
198*d807f41cSkn 	}
199*d807f41cSkn 
200cf939257Svisa 	kimg = malloc(sb.st_size);
201cf939257Svisa 	if (kimg == NULL)
202cf939257Svisa 		goto load_failed;
203cf939257Svisa 
204cf939257Svisa 	pos = 0;
205cf939257Svisa 	while (pos < sb.st_size) {
206cf939257Svisa 		n = read(fd, kimg + pos, sb.st_size - pos);
207cf939257Svisa 		if (n == -1)
208cf939257Svisa 			goto load_failed;
209cf939257Svisa 		pos += n;
210cf939257Svisa 	}
211cf939257Svisa 
212cf939257Svisa 	close(fd);
213cf939257Svisa 	disk_close();
214cf939257Svisa 
2153a62b615Svisa 	memset(&kargs, 0, sizeof(kargs));
216cf939257Svisa 	kargs.kimg = kimg;
217cf939257Svisa 	kargs.klen = sb.st_size;
2183a62b615Svisa 	argc = 0;
2193a62b615Svisa 	if (cmd.boothowto != 0) {
220a084a2f8Svisa 		snprintf(boothowtostr, sizeof(boothowtostr), "boothowto=%d",
221a084a2f8Svisa 		    cmd.boothowto);
222a084a2f8Svisa 		kargs.argv[argc++] = boothowtostr;
2233a62b615Svisa 	}
2243a62b615Svisa 	if (cmd.hasduid) {
2253a62b615Svisa 		snprintf(rootdev, sizeof(rootdev),
2263a62b615Svisa 		    "rootdev=%02x%02x%02x%02x%02x%02x%02x%02x",
2273a62b615Svisa 		    cmd.bootduid[0], cmd.bootduid[1],
2283a62b615Svisa 		    cmd.bootduid[2], cmd.bootduid[3],
2293a62b615Svisa 		    cmd.bootduid[4], cmd.bootduid[5],
2303a62b615Svisa 		    cmd.bootduid[6], cmd.bootduid[7]);
2313a62b615Svisa 		kargs.argv[argc++] = rootdev;
2323a62b615Svisa 	}
2333a62b615Svisa 
2343a62b615Svisa 	printf("booting %s\n", cmd.path);
2353a62b615Svisa 	ret = ioctl(octbootfd, OBIOC_KEXEC, &kargs);
2363a62b615Svisa 	if (ret == -1)
2373a62b615Svisa 		fprintf(stderr, "failed to execute kernel %s: %s\n",
2383a62b615Svisa 		    cmd.path, strerror(errno));
2393a62b615Svisa 	else
2403a62b615Svisa 		fprintf(stderr, "kexec() returned unexpectedly\n");
241cf939257Svisa 	free(kimg);
242cf939257Svisa 	return;
2433a62b615Svisa 
244cf939257Svisa load_failed:
245cf939257Svisa 	fprintf(stderr, "failed to load kernel %s: %s\n",
246cf939257Svisa 	    cmd.path, strerror(errno));
247cf939257Svisa 	if (fd != -1)
248cf939257Svisa 		close(fd);
2493a62b615Svisa 	disk_close();
250cf939257Svisa 	free(kimg);
2513a62b615Svisa }
252