xref: /openbsd-src/sys/arch/octeon/stand/rdboot/rdboot.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: rdboot.c,v 1.3 2019/11/01 20:54:52 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2019 Visa Hankala
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/ioctl.h>
22 #include <sys/mount.h>
23 #include <sys/reboot.h>
24 #include <sys/select.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <paths.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <termios.h>
33 #include <unistd.h>
34 #include <util.h>
35 
36 #include <machine/octboot.h>
37 #include <machine/param.h>
38 
39 #include "cmd.h"
40 #include "disk.h"
41 
42 #define DEVRANDOM	"/dev/random"
43 #define BOOTRANDOM	"/etc/random.seed"
44 #define BOOTRANDOM_MAX	256	/* no point being greater than RC4STATE */
45 #define KERNEL		"/bsd"
46 
47 void	loadrandom(void);
48 void	kexec(void);
49 
50 struct cmd_state cmd;
51 int octbootfd = -1;
52 const char version[] = "1.1";
53 
54 int
55 main(void)
56 {
57 	char rootdev[PATH_MAX];
58 	int fd, hasboot;
59 
60 	fd = open(_PATH_CONSOLE, O_RDWR);
61 	login_tty(fd);
62 
63 	/* Keep stdout unbuffered to mimic ordinary bootblocks. */
64 	setvbuf(stdout, NULL, _IONBF, 0);
65 
66 	printf(">> OpenBSD/" MACHINE " BOOT %s\n", version);
67 
68 	octbootfd = open("/dev/octboot", O_WRONLY);
69 	if (octbootfd == -1)
70 		err(1, "cannot open boot control device");
71 
72 	memset(&cmd, 0, sizeof(cmd));
73 	cmd.boothowto = 0;
74 	cmd.conf = "/etc/boot.conf";
75 	strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
76 	cmd.timeout = 5;
77 
78 	if (ioctl(octbootfd, OBIOC_GETROOTDEV, rootdev) == -1) {
79 		if (errno != ENOENT)
80 			fprintf(stderr, "cannot get rootdev from kernel: %s\n",
81 			    strerror(errno));
82 	} else {
83 		snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa",
84 		    rootdev, isduid(rootdev, OPENDEV_PART) ? "." : "");
85 	}
86 
87 	disk_init();
88 
89 	if (upgrade()) {
90 		strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
91 		printf("upgrade detected: switching to %s\n", cmd.image);
92 	}
93 
94 	hasboot = read_conf();
95 
96 	for (;;) {
97 		if (hasboot <= 0) {
98 			do {
99 				printf("boot> ");
100 			} while (!getcmd());
101 		}
102 
103 		loadrandom();
104 		kexec();
105 
106 		hasboot = 0;
107 		strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
108 		printf("will try %s\n", cmd.image);
109 	}
110 
111 	return 0;
112 }
113 
114 void
115 loadrandom(void)
116 {
117 	char buf[BOOTRANDOM_MAX];
118 	int fd;
119 
120 	/* Read the file from the device specified by the kernel path. */
121 	if (disk_open(cmd.path) == NULL)
122 		return;
123 	fd = open(BOOTRANDOM, O_RDONLY);
124 	if (fd == -1) {
125 		fprintf(stderr, "%s: cannot open %s: %s", __func__, BOOTRANDOM,
126 		    strerror(errno));
127 		disk_close();
128 		return;
129 	}
130 	read(fd, buf, sizeof(buf));
131 	close(fd);
132 	disk_close();
133 
134 	/*
135 	 * Push the whole buffer to the entropy pool.
136 	 * The kernel will use the entropy on kexec().
137 	 * It does not matter if some of the buffer content is uninitialized.
138 	 */
139 	fd = open(DEVRANDOM, O_WRONLY);
140 	if (fd == -1) {
141 		fprintf(stderr, "%s: cannot open %s: %s", __func__,
142 		    DEVRANDOM, strerror(errno));
143 		return;
144 	}
145 	write(fd, buf, sizeof(buf));
146 	close(fd);
147 }
148 
149 void
150 kexec(void)
151 {
152 	struct octboot_kexec_args kargs;
153 	char kernelflags[8];
154 	char rootdev[32];
155 	const char *path;
156 	int argc, ret;
157 
158 	path = disk_open(cmd.path);
159 	if (path == NULL)
160 		return;
161 
162 	memset(&kargs, 0, sizeof(kargs));
163 	kargs.path = path;
164 	argc = 0;
165 	if (cmd.boothowto != 0) {
166 		snprintf(kernelflags, sizeof(kernelflags), "-%s%s%s%s",
167 		    (cmd.boothowto & RB_ASKNAME) ? "a" : "",
168 		    (cmd.boothowto & RB_CONFIG) ? "c" : "",
169 		    (cmd.boothowto & RB_KDB) ? "d" : "",
170 		    (cmd.boothowto & RB_SINGLE) ? "s" : "");
171 		kargs.argv[argc++] = kernelflags;
172 	}
173 	if (cmd.hasduid) {
174 		snprintf(rootdev, sizeof(rootdev),
175 		    "rootdev=%02x%02x%02x%02x%02x%02x%02x%02x",
176 		    cmd.bootduid[0], cmd.bootduid[1],
177 		    cmd.bootduid[2], cmd.bootduid[3],
178 		    cmd.bootduid[4], cmd.bootduid[5],
179 		    cmd.bootduid[6], cmd.bootduid[7]);
180 		kargs.argv[argc++] = rootdev;
181 	}
182 
183 	printf("booting %s\n", cmd.path);
184 	ret = ioctl(octbootfd, OBIOC_KEXEC, &kargs);
185 	if (ret == -1)
186 		fprintf(stderr, "failed to execute kernel %s: %s\n",
187 		    cmd.path, strerror(errno));
188 	else
189 		fprintf(stderr, "kexec() returned unexpectedly\n");
190 
191 	disk_close();
192 }
193