xref: /netbsd-src/sys/arch/x68k/stand/boot/boot.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /*	$NetBSD: boot.c,v 1.22 2014/08/05 13:49:04 isaki Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Minoura Makoto
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <machine/bootinfo.h>
31 
32 #include <lib/libsa/stand.h>
33 #include <lib/libsa/loadfile.h>
34 #include <lib/libsa/ufs.h>
35 #ifdef NETBOOT
36 #include <lib/libsa/dev_net.h>
37 #endif
38 #include <lib/libkern/libkern.h>
39 
40 #include "libx68k.h"
41 #include "iocs.h"
42 #include "switch.h"
43 
44 #include "exec_image.h"
45 
46 
47 #define HEAP_START	((void*) 0x00080000)
48 #define HEAP_END	((void*) 0x000fffff)
49 #define EXSCSI_BDID	((void*) 0x00ea0001)
50 #define SRAM_MEMSIZE	(*((long*) 0x00ed0008))
51 
52 char default_kernel[20] =
53 #ifndef NETBOOT
54     "sd0a:netbsd";
55 #else
56     "nfs:netbsd";
57 #endif
58 int mpu;
59 #ifndef NETBOOT
60 int hostadaptor;
61 #endif
62 int console_device = -1;
63 
64 #ifdef DEBUG
65 #ifdef NETBOOT
66 int debug = 1;
67 #endif
68 #endif
69 
70 static void help(void);
71 #ifndef NETBOOT
72 static int get_scsi_host_adapter(void);
73 #endif
74 static void doboot(const char *, int);
75 static void boot(char *);
76 #ifndef NETBOOT
77 static void cmd_ls(char *);
78 #endif
79 int bootmenu(void);
80 void bootmain(int);
81 extern int detectmpu(void);
82 extern int badbaddr(void *);
83 
84 #ifndef NETBOOT
85 /* from boot_ufs/bootmain.c */
86 static int
87 get_scsi_host_adapter(void)
88 {
89 	char *bootrom;
90 	int ha;
91 
92 	bootrom = (char *) (IOCS_BOOTINF() & 0x00ffffe0);
93 	/*
94 	 * bootrom+0x24	"SCSIIN" ... Internal SCSI (spc@0)
95 	 *		"SCSIEX" ... External SCSI (spc@1 or mha@0)
96 	 */
97 	if (*(u_short *)(bootrom + 0x24 + 4) == 0x494e) {	/* "IN" */
98 		ha = (X68K_BOOT_SCSIIF_SPC << 4) | 0;
99 	} else if (badbaddr(EXSCSI_BDID)) {
100 		ha = (X68K_BOOT_SCSIIF_MHA << 4) | 0;
101 	} else {
102 		ha = (X68K_BOOT_SCSIIF_SPC << 4) | 1;
103 	}
104 
105 	return ha;
106 }
107 #endif
108 
109 static void
110 help(void)
111 {
112 	printf("Usage:\n");
113 	printf("boot [dev:][file] -[flags]\n");
114 #ifndef NETBOOT
115 	printf(" dev:   sd<ID><PART>, ID=0-7, PART=a-p\n");
116 	printf("        cd<ID>a, ID=0-7\n");
117 	printf("        fd<UNIT>a, UNIT=0-3, format is detected.\n");
118 #else
119 	printf(" dev:   nfs, first probed NE2000 is used.\n");
120 #endif
121 	printf(" file:  netbsd, netbsd.gz, etc.\n");
122 	printf(" flags: abdqsv\n");
123 #ifndef NETBOOT
124 	printf("ls [dev:][directory]\n");
125 #endif
126 	printf("switch [show | key=val]\n");
127 	printf("halt\nreboot\n");
128 }
129 
130 static void
131 doboot(const char *file, int flags)
132 {
133 	u_long		marks[MARK_MAX];
134 	int fd;
135 	int dev, unit, part;
136 	char *name;
137 	short *p;
138 	int loadflag;
139 
140 	printf("Starting %s, flags 0x%x\n", file, flags);
141 
142 	loadflag = LOAD_KERNEL;
143 	if (file[0] == 'f')
144 		loadflag &= ~LOAD_BACKWARDS;
145 
146 	marks[MARK_START] = 0x100000;
147 	if ((fd = loadfile(file, marks, loadflag)) == -1) {
148 		printf("loadfile failed\n");
149 		return;
150 	}
151 	close(fd);
152 
153 	if (devparse(file, &dev, &unit, &part, &name) != 0) {
154 		printf("XXX: unknown corruption in /boot.\n");
155 	}
156 
157 #ifdef DEBUG
158 #ifndef NETBOOT
159 	printf("dev = %x, unit = %d, part = %c, name = %s\n",
160 	       dev, unit, part + 'a', name);
161 #else
162 	printf("dev = %x, unit = %d, name = %s\n",
163 	       dev, unit, name);
164 #endif
165 #endif
166 
167 #ifndef NETBOOT
168 	if (dev == 0) {		/* SCSI */
169 		dev = X68K_MAKESCSIBOOTDEV(X68K_MAJOR_SD,
170 					   hostadaptor >> 4,
171 					   hostadaptor & 15,
172 					   unit & 7, 0, 0);
173 	} else {
174 		dev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0);
175 	}
176 #else
177 	dev = X68K_MAKEBOOTDEV(X68K_MAJOR_NE, unit, 0);
178 #endif
179 #ifdef DEBUG
180 	printf("boot device = %x\n", dev);
181 #ifndef NETBOOT
182 	printf("if = %d, unit = %d, id = %d, lun = %d, part = %c\n",
183 	       B_X68K_SCSI_IF(dev),
184 	       B_X68K_SCSI_IF_UN(dev),
185 	       B_X68K_SCSI_ID(dev),
186 	       B_X68K_SCSI_LUN(dev),
187 	       B_X68K_SCSI_PART(dev) + 'a');
188 #else
189 	printf("if = %d, unit = %d\n",
190 	       B_X68K_SCSI_IF(dev),
191 	       B_X68K_SCSI_IF_UN(dev));
192 #endif
193 #endif
194 
195 	p = ((short*) marks[MARK_ENTRY]) - 1;
196 #ifdef DEBUG
197 	printf("Kernel Version: 0x%x\n", *p);
198 #endif
199 	if (*p != 0x4e73 && *p != 0) {
200 		/*
201 		 * XXX temporary solution; compatibility loader
202 		 * must be written.
203 		 */
204 		printf("This kernel is too new to be loaded by "
205 		       "this version of /boot.\n");
206 		return;
207 	}
208 
209 	exec_image(marks[MARK_START], 0, marks[MARK_ENTRY]-marks[MARK_START],
210 		   marks[MARK_END]-marks[MARK_START], dev, flags);
211 
212 	return;
213 }
214 
215 static void
216 boot(char *arg)
217 {
218 	char filename[80];
219 	char *p;
220 	int flags = 0;
221 
222 	if (*arg == 0 || *arg == '-') {
223 		strcpy(filename, default_kernel);
224 		if (*arg == '-')
225 			if (parseopts(arg, &flags) == 0) {
226 				help();
227 				return;
228 			}
229 		doboot(filename, flags);
230 		return;
231 	} else {
232 		p = gettrailer(arg);
233 		if (strchr(arg, ':')) {
234 			strcpy(filename, arg);
235 			if (arg[strlen(arg) - 1] == ':')
236 				strcat(filename, "netbsd");
237 		} else {
238 			strcpy(filename, default_kernel);
239 			strcpy(strchr(filename, ':') + 1, arg);
240 		}
241 		if (*p == '-') {
242 			if (parseopts(p, &flags) == 0)
243 				return;
244 		} else if (*p != 0) {
245 			help();
246 			return;
247 		}
248 
249 		doboot(filename, flags);
250 		return;
251 	}
252 }
253 
254 #ifndef NETBOOT
255 static void
256 cmd_ls(char *arg)
257 {
258 	char filename[80];
259 
260 	devopen_open_dir = 1;
261 	if (*arg == 0) {
262 		strcpy(filename, default_kernel);
263 		strcpy(strchr(filename, ':')+1, "/");
264 	} else if (strchr(arg, ':') == 0) {
265 		strcpy(filename, default_kernel);
266 		strcpy(strchr(filename, ':')+1, arg);
267 	} else {
268 		strcpy(filename, arg);
269 		if (*(strchr(arg, ':')+1) == 0)
270 			strcat(filename, "/");
271 	}
272 	ls(filename);
273 	devopen_open_dir = 0;
274 }
275 #endif
276 
277 int
278 bootmenu(void)
279 {
280 	char input[80];
281 	int n = 5, c;
282 
283 	printf("Press return to boot now, any other key for boot menu\n");
284 	printf("booting %s - starting in %d seconds. ",
285 		default_kernel, n);
286 	while (n-- > 0 && (c = awaitkey_1sec()) == 0) {
287 		printf("\r");
288 		printf("booting %s - starting in %d seconds. ",
289 		       default_kernel, n);
290 	}
291 	printf("\r");
292 	printf("booting %s - starting in %d seconds. ", default_kernel, 0);
293 	printf("\n");
294 
295 	if (c == 0 || c == '\r') {
296 		doboot(default_kernel, 0);
297 		printf("Could not start %s; ", default_kernel);
298 		strcat(default_kernel, ".gz");
299 		printf("trying %s.\n", default_kernel);
300 		doboot(default_kernel, 0);
301 		printf("Could not start %s; ", default_kernel);
302 	}
303 
304 	printf("Please use the absolute unit# (e.g. SCSI ID)"
305 	       " instead of the NetBSD logical #.\n");
306 	for (;;) {
307 		char *p, *options;
308 
309 		printf("> ");
310 		gets(input);
311 
312 		for (p = &input[0]; p - &input[0] < 80 && *p == ' '; p++)
313 			;
314 		options = gettrailer(p);
315 		if (strcmp("boot", p) == 0)
316 			boot(options);
317 		else if (strcmp("help", p) == 0 ||
318 			 strcmp("?", p) == 0)
319 			help();
320 		else if (strcmp("halt", p) == 0 ||
321 			 strcmp("reboot", p) == 0)
322 			exit(0);
323 		else if (strcmp("switch", p) == 0)
324 			cmd_switch(options);
325 #ifndef NETBOOT
326 		else if (strcmp("ls", p) == 0)
327 			cmd_ls(options);
328 #endif
329 		else
330 			printf("Unknown command %s\n", p);
331 	}
332 }
333 
334 static u_int
335 checkmemsize(void)
336 {
337 	u_int m;
338 
339 #define MIN_MB 4
340 #define MAX_MB 12
341 
342 	for (m = MIN_MB; m <= MAX_MB; m++) {
343 		if (badbaddr((void *)(m * 1024 * 1024 - 1))) {
344 			/* no memory */
345 			break;
346 		}
347 	}
348 
349 	return (m - 1) * 1024 * 1024;
350 }
351 
352 extern const char bootprog_rev[];
353 extern const char bootprog_name[];
354 
355 /*
356  * Arguments from the boot block:
357  *   bootdev - specifies the device from which /boot was read, in
358  *		bootdev format.
359  */
360 void
361 bootmain(int bootdev)
362 {
363 	u_int sram_memsize;
364 	u_int probed_memsize;
365 
366 #ifndef NETBOOT
367 	hostadaptor = get_scsi_host_adapter();
368 #else
369 	rtc_offset = RTC_OFFSET;
370 	try_bootp = 1;
371 #endif
372 	mpu = detectmpu();
373 
374 	if (mpu < 3) {		/* not tested on 68020 */
375 		printf("This MPU cannot run NetBSD.\n");
376 		exit(1);
377 	}
378 	sram_memsize = SRAM_MEMSIZE;
379 	if (sram_memsize < 4*1024*1024) {
380 		printf("Main memory too small.\n");
381 		exit(1);
382 	}
383 
384 	console_device = consio_init(console_device);
385 	setheap(HEAP_START, HEAP_END);
386 
387 #ifndef NETBOOT
388 	switch (B_TYPE(bootdev)) {
389 	case X68K_MAJOR_FD:
390 		default_kernel[0] = 'f';
391 		default_kernel[2] = '0' + B_UNIT(bootdev);
392 		default_kernel[3] = 'a';
393 		break;
394 	case X68K_MAJOR_SD:
395 		default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev);
396 		default_kernel[3] =
397 			'a' + sd_getbsdpartition(B_X68K_SCSI_ID(bootdev),
398 						 B_X68K_SCSI_PART(bootdev));
399 		break;
400 	case X68K_MAJOR_CD:
401 		default_kernel[0] = 'c';
402 		default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev);
403 		default_kernel[3] = 'a';
404 		break;
405 	default:
406 		printf("Warning: unknown boot device: %x\n", bootdev);
407 	}
408 #endif
409 	print_title("%s, Revision %s\n", bootprog_name, bootprog_rev);
410 
411 	/* check actual memory size for machines with a dead SRAM battery */
412 	probed_memsize = checkmemsize();
413 	if (sram_memsize != probed_memsize) {
414 		printf("\x1b[1mWarning: SRAM Memory Size (%d MB) "
415 		    "is different from probed Memory Size (%d MB)\n"
416 		    "         Check and reset SRAM values.\x1b[m\n\n",
417 		    sram_memsize / (1024 * 1024),
418 		    probed_memsize / (1024 * 1024));
419 	}
420 
421 	bootmenu();
422 }
423