boot.c revision 1.28 1 /* $NetBSD: boot.c,v 1.28 2016/06/25 16:05:43 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 #include <lib/libsa/dev_net.h>
36 #include <lib/libkern/libkern.h>
37
38 #include "libx68k.h"
39 #include "iocs.h"
40 #include "switch.h"
41
42 #include "exec_image.h"
43
44
45 #define HEAP_START ((void*) 0x00080000)
46 #define HEAP_END ((void*) 0x000fffff)
47 #define EXSCSI_BDID ((void*) 0x00ea0001)
48 #define SRAM_MEMSIZE (*((long*) 0x00ed0008))
49
50 char default_kernel[20] =
51 #if defined(NETBOOT)
52 "nfs:netbsd";
53 #else
54 "sd0a:netbsd";
55 #endif
56 int mpu;
57 int hostadaptor;
58 int console_device = -1;
59
60 #ifdef DEBUG
61 int debug = 1;
62 #endif
63
64 static void help(void);
65 static int get_scsi_host_adapter(void);
66 static void doboot(const char *, int);
67 static void boot(char *);
68 static void cmd_ls(char *);
69 int bootmenu(void);
70 void bootmain(int);
71 extern int detectmpu(void);
72 extern int badbaddr(void *);
73
74 extern struct fs_ops file_system_ustarfs[];
75 extern struct fs_ops file_system_nfs[];
76
77 /* from boot_ufs/bootmain.c */
78 static int
79 get_scsi_host_adapter(void)
80 {
81 char *bootrom;
82 int ha;
83
84 bootrom = (char *) (IOCS_BOOTINF() & 0x00ffffe0);
85 /*
86 * bootrom+0x24 "SCSIIN" ... Internal SCSI (spc@0)
87 * "SCSIEX" ... External SCSI (spc@1 or mha@0)
88 */
89 if (*(u_short *)(bootrom + 0x24 + 4) == 0x494e) { /* "IN" */
90 ha = (X68K_BOOT_SCSIIF_SPC << 4) | 0;
91 } else if (badbaddr(EXSCSI_BDID)) {
92 ha = (X68K_BOOT_SCSIIF_MHA << 4) | 0;
93 } else {
94 ha = (X68K_BOOT_SCSIIF_SPC << 4) | 1;
95 }
96
97 return ha;
98 }
99
100 static void
101 help(void)
102 {
103 printf("Usage:\n");
104 printf("boot [dev:][file] -[flags]\n");
105 printf(" dev: sd<ID><PART>, ID=0-7, PART=a-p\n");
106 printf(" cd<ID>a, ID=0-7\n");
107 printf(" fd<UNIT>a, UNIT=0-3, format is detected.\n");
108 printf(" nfs, first probed NE2000 is used.\n");
109 printf(" file: netbsd, netbsd.gz, etc.\n");
110 printf(" flags: abdqsv\n");
111 printf("ls [dev:][directory]\n");
112 printf("switch [show | key=val]\n");
113 printf("halt\nreboot\n");
114 }
115
116 static void
117 doboot(const char *file, int flags)
118 {
119 u_long marks[MARK_MAX];
120 int fd;
121 int dev; /* device number in devspec[] */
122 int unit;
123 int part;
124 int bootdev;
125 char *name;
126 short *p;
127 int loadflag;
128 struct fs_ops *fs;
129
130 printf("Starting %s, flags 0x%x\n", file, flags);
131
132 if (devparse(file, &dev, &unit, &part, &name) != 0) {
133 printf("XXX: unknown corruption in /boot.\n");
134 }
135
136 #ifdef DEBUG
137 if (file[0] == 'n') {
138 printf("dev = %x, unit = %d, name = %s\n",
139 dev, unit, name);
140 } else {
141 printf("dev = %x, unit = %d, part = %c, name = %s\n",
142 dev, unit, part + 'a', name);
143 }
144 #endif
145
146 if (dev == 3) { /* netboot */
147 bootdev = X68K_MAKEBOOTDEV(X68K_MAJOR_NE, unit, 0);
148 } else if (dev == 0) { /* SCSI */
149 bootdev = X68K_MAKESCSIBOOTDEV(X68K_MAJOR_SD,
150 hostadaptor >> 4,
151 hostadaptor & 15,
152 unit & 7, 0, 0);
153 } else {
154 bootdev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0);
155 }
156 #ifdef DEBUG
157 printf("boot device = %x\n", bootdev);
158 if (file[0] == 'n') {
159 printf("if = %d, unit = %d\n",
160 B_X68K_SCSI_IF(bootdev),
161 B_X68K_SCSI_IF_UN(bootdev));
162 } else {
163 printf("if = %d, unit = %d, id = %d, lun = %d, part = %c\n",
164 B_X68K_SCSI_IF(bootdev),
165 B_X68K_SCSI_IF_UN(bootdev),
166 B_X68K_SCSI_ID(bootdev),
167 B_X68K_SCSI_LUN(bootdev),
168 B_X68K_SCSI_PART(bootdev) + 'a');
169 }
170 #endif
171
172 /*
173 * Choose the last entry of file_system[] at runtime.
174 *
175 * file_system[] is checked in turn from the beginning at all cases.
176 * Trying FS_OPS(ustarfs) for non-ustarfs displays "@" (as the
177 * mark which read a cylinder?). OTOH, trying FS_OPS(nfs) for
178 * non-nfs displays "must mount first" error message.
179 * It is better that neither is displayed and in other words you
180 * should not put these two into file_system[] at the same time.
181 * Therefore I choose one of these here.
182 */
183 if (file[0] == 'n') {
184 fs = &file_system_nfs[0];
185 } else {
186 fs = &file_system_ustarfs[0];
187 }
188 memcpy(&file_system[nfsys - 1], fs, sizeof(*fs));
189
190 loadflag = LOAD_KERNEL;
191 if (file[0] == 'f')
192 loadflag &= ~LOAD_BACKWARDS;
193
194 marks[MARK_START] = 0x100000;
195 if ((fd = loadfile(file, marks, loadflag)) == -1) {
196 printf("loadfile failed\n");
197 return;
198 }
199 close(fd);
200
201 p = ((short*) marks[MARK_ENTRY]) - 1;
202 #ifdef DEBUG
203 printf("Kernel Version: 0x%x\n", *p);
204 #endif
205 if (*p != 0x4e73 && *p != 0) {
206 /*
207 * XXX temporary solution; compatibility loader
208 * must be written.
209 */
210 printf("This kernel is too new to be loaded by "
211 "this version of /boot.\n");
212 return;
213 }
214
215 exec_image(marks[MARK_START], 0, marks[MARK_ENTRY]-marks[MARK_START],
216 marks[MARK_END]-marks[MARK_START], bootdev, flags);
217
218 return;
219 }
220
221 static void
222 boot(char *arg)
223 {
224 char filename[80];
225 char *p;
226 int flags = 0;
227
228 if (*arg == 0 || *arg == '-') {
229 strcpy(filename, default_kernel);
230 if (*arg == '-')
231 if (parseopts(arg, &flags) == 0) {
232 help();
233 return;
234 }
235 doboot(filename, flags);
236 return;
237 } else {
238 p = gettrailer(arg);
239 if (strchr(arg, ':')) {
240 strcpy(filename, arg);
241 if (arg[strlen(arg) - 1] == ':')
242 strcat(filename, "netbsd");
243 } else {
244 strcpy(filename, default_kernel);
245 strcpy(strchr(filename, ':') + 1, arg);
246 }
247 if (*p == '-') {
248 if (parseopts(p, &flags) == 0)
249 return;
250 } else if (*p != 0) {
251 help();
252 return;
253 }
254
255 doboot(filename, flags);
256 return;
257 }
258 }
259
260 static void
261 cmd_ls(char *arg)
262 {
263 char filename[80];
264
265 devopen_open_dir = 1;
266 if (*arg == 0) {
267 strcpy(filename, default_kernel);
268 strcpy(strchr(filename, ':')+1, "/");
269 } else if (strchr(arg, ':') == 0) {
270 strcpy(filename, default_kernel);
271 strcpy(strchr(filename, ':')+1, arg);
272 } else {
273 strcpy(filename, arg);
274 if (*(strchr(arg, ':')+1) == 0)
275 strcat(filename, "/");
276 }
277 ls(filename);
278 devopen_open_dir = 0;
279 }
280
281 int
282 bootmenu(void)
283 {
284 char input[80];
285 int n = 5, c;
286
287 printf("Press return to boot now, any other key for boot menu\n");
288 printf("booting %s - starting in %d seconds. ",
289 default_kernel, n);
290 while (n-- > 0 && (c = awaitkey_1sec()) == 0) {
291 printf("\r");
292 printf("booting %s - starting in %d seconds. ",
293 default_kernel, n);
294 }
295 printf("\r");
296 printf("booting %s - starting in %d seconds. ", default_kernel, 0);
297 printf("\n");
298
299 if (c == 0 || c == '\r') {
300 doboot(default_kernel, 0);
301 printf("Could not start %s; ", default_kernel);
302 strcat(default_kernel, ".gz");
303 printf("trying %s.\n", default_kernel);
304 doboot(default_kernel, 0);
305 printf("Could not start %s; ", default_kernel);
306 }
307
308 printf("Please use the absolute unit# (e.g. SCSI ID)"
309 " instead of the NetBSD logical #.\n");
310 for (;;) {
311 char *p, *options;
312
313 printf("> ");
314 gets(input);
315
316 for (p = &input[0]; p - &input[0] < 80 && *p == ' '; p++)
317 ;
318 options = gettrailer(p);
319 if (strcmp("boot", p) == 0)
320 boot(options);
321 else if (strcmp("help", p) == 0 ||
322 strcmp("?", p) == 0)
323 help();
324 else if (strcmp("halt", p) == 0 ||
325 strcmp("reboot", p) == 0)
326 exit(0);
327 else if (strcmp("switch", p) == 0)
328 cmd_switch(options);
329 else if (strcmp("ls", p) == 0)
330 cmd_ls(options);
331 else
332 printf("Unknown command %s\n", p);
333 }
334 }
335
336 static u_int
337 checkmemsize(void)
338 {
339 u_int m;
340
341 #define MIN_MB 4
342 #define MAX_MB 12
343
344 for (m = MIN_MB; m <= MAX_MB; m++) {
345 if (badbaddr((void *)(m * 1024 * 1024 - 1))) {
346 /* no memory */
347 break;
348 }
349 }
350
351 return (m - 1) * 1024 * 1024;
352 }
353
354 extern const char bootprog_rev[];
355 extern const char bootprog_name[];
356
357 /*
358 * Arguments from the boot block:
359 * bootdev - specifies the device from which /boot was read, in
360 * bootdev format.
361 */
362 void
363 bootmain(int bootdev)
364 {
365 u_int sram_memsize;
366 u_int probed_memsize;
367
368 hostadaptor = get_scsi_host_adapter();
369 rtc_offset = RTC_OFFSET;
370 try_bootp = 1;
371 mpu = detectmpu();
372
373 if (mpu < 3) { /* not tested on 68020 */
374 printf("This MPU cannot run NetBSD.\n");
375 exit(1);
376 }
377 sram_memsize = SRAM_MEMSIZE;
378 if (sram_memsize < 4*1024*1024) {
379 printf("Main memory too small.\n");
380 exit(1);
381 }
382
383 console_device = consio_init(console_device);
384 setheap(HEAP_START, HEAP_END);
385
386 #if !defined(NETBOOT)
387 switch (B_TYPE(bootdev)) {
388 case X68K_MAJOR_FD:
389 default_kernel[0] = 'f';
390 default_kernel[2] = '0' + B_UNIT(bootdev);
391 default_kernel[3] = 'a';
392 break;
393 case X68K_MAJOR_SD:
394 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev);
395 default_kernel[3] =
396 'a' + sd_getbsdpartition(B_X68K_SCSI_ID(bootdev),
397 B_X68K_SCSI_PART(bootdev));
398 break;
399 case X68K_MAJOR_CD:
400 default_kernel[0] = 'c';
401 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev);
402 default_kernel[3] = 'a';
403 break;
404 default:
405 printf("Warning: unknown boot device: %x\n", bootdev);
406 }
407 #endif
408 print_title("%s, Revision %s\n", bootprog_name, bootprog_rev);
409
410 /* check actual memory size for machines with a dead SRAM battery */
411 probed_memsize = checkmemsize();
412 if (sram_memsize != probed_memsize) {
413 printf("\x1b[1mWarning: SRAM Memory Size (%d MB) "
414 "is different from probed Memory Size (%d MB)\n"
415 " Check and reset SRAM values.\x1b[m\n\n",
416 sram_memsize / (1024 * 1024),
417 probed_memsize / (1024 * 1024));
418 }
419
420 bootmenu();
421 }
422