1 /* $NetBSD: boot.c,v 1.20 2011/01/22 19:19:16 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jonathan Stone, Michael Hitch, Simon Burge and Wayne Knowles.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1992, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * Ralph Campbell.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)boot.c 8.1 (Berkeley) 6/10/93
64 */
65
66 #include <lib/libsa/stand.h>
67 #include <lib/libsa/loadfile.h>
68 #include <lib/libsa/dev_net.h>
69 #include <lib/libkern/libkern.h>
70
71 #include <sys/param.h>
72 #include <sys/boot_flag.h>
73 #include <sys/exec.h>
74 #include <sys/exec_elf.h>
75
76 #include <machine/cpu.h>
77
78 #include <cobalt/dev/gtreg.h>
79
80 #include "boot.h"
81 #include "cons.h"
82 #include "common.h"
83 #include "bootinfo.h"
84
85 char *kernelnames[] = {
86 "netbsd",
87 "netbsd.gz",
88 "onetbsd",
89 "onetbsd.gz",
90 "netbsd.bak",
91 "netbsd.bak.gz",
92 "netbsd.old",
93 "netbsd.old.gz",
94 "netbsd.cobalt",
95 "netbsd.cobalt.gz",
96 "netbsd.elf",
97 "netbsd.elf.gz",
98 NULL
99 };
100
101 u_int cobalt_id;
102 static const char * const cobalt_model[] =
103 {
104 [0] = "Unknown Cobalt",
105 [COBALT_ID_QUBE2700] = "Cobalt Qube 2700",
106 [COBALT_ID_RAQ] = "Cobalt RaQ",
107 [COBALT_ID_QUBE2] = "Cobalt Qube 2",
108 [COBALT_ID_RAQ2] = "Cobalt RaQ 2"
109 };
110 #define COBALT_MODELS __arraycount(cobalt_model)
111
112 extern u_long end; /* Boot loader code end address */
113 void start(void);
114
115 static char *bootstring;
116
117 static int patch_bootstring(char *bootspec);
118 static int get_bsdbootname(char **, char **, int *);
119 static int parse_bootname(char *, int, char **, char **);
120 static void prominit(unsigned int memsize);
121 static void print_banner(unsigned int memsize);
122 static u_int read_board_id(void);
123
124 void cpu_reboot(void);
125
126 int main(unsigned int memsize);
127
128 /*
129 * Perform CPU reboot.
130 */
131 void
cpu_reboot(void)132 cpu_reboot(void)
133 {
134
135 printf("rebooting...\n\n");
136
137 *(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET;
138 printf("WARNING: reboot failed!\n");
139
140 for (;;)
141 ;
142 }
143
144 /*
145 * Substitute root value with NetBSD root partition name.
146 */
147 int
patch_bootstring(char * bootspec)148 patch_bootstring(char *bootspec)
149 {
150 char *sp = bootstring;
151 uint8_t unit, part;
152 int dev;
153 char *file;
154
155 DPRINTF(("patch_bootstring: %s\n", bootspec));
156
157 /* get boot parameters */
158 if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0)
159 unit = part = 0;
160
161 DPRINTF(("patch_bootstring: unit = %d, part = %d\n", unit, part));
162
163 /* take out the 'root=xxx' parameter */
164 if ((sp = strstr(bootstring, "root=")) != NULL) {
165 const char *end;
166
167 end = strchr(sp, ' ');
168
169 /* strip off leading spaces */
170 for (--sp; (sp > bootstring) && (*sp == ' '); --sp)
171 ;
172
173 if (end != NULL)
174 strcpy(++sp, end);
175 else
176 *++sp = '\0';
177 }
178
179 DPRINTF(("patch_bootstring: [%s]\n", bootstring));
180
181 #define DEVNAMESIZE (MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a"))
182 if (strcmp(devsw[dev].dv_name, "wd") == 0 &&
183 strlen(bootstring) <= (511 - DEVNAMESIZE)) {
184 int len;
185
186 /* omit "nfsroot=" arg on wd boot */
187 if ((sp = strstr(bootstring, "nfsroot=")) != NULL) {
188 const char *end;
189
190 end = strchr(sp, ' ');
191
192 /* strip off leading spaces */
193 for (--sp; (sp > bootstring) && (*sp == ' '); --sp)
194 ;
195
196 if (end != NULL)
197 strcpy(++sp, end);
198 else
199 *++sp = '\0';
200 }
201
202 /* bsd notation -> linux notation (wd0a -> hda1) */
203 strcat(bootstring, " root=/dev/hd");
204
205 len = strlen(bootstring);
206 bootstring[len++] = unit + 'a';
207 bootstring[len++] = part + '1';
208 bootstring[len++] = '\0';
209 }
210
211 DPRINTF(("patch_bootstring: -> %s\n", bootstring));
212 return 0;
213 }
214
215 /*
216 * Extract NetBSD boot specification
217 */
218 static int
get_bsdbootname(char ** dev,char ** kname,int * howtop)219 get_bsdbootname(char **dev, char **kname, int *howtop)
220 {
221 int len;
222 int bootunit, bootpart;
223 char *bootstr_dev, *bootstr_kname;
224 char *prompt_dev, *prompt_kname;
225 char *ptr, *spec;
226 char c, namebuf[PATH_MAX];
227 static char bootdev[] = "wd0a";
228 static char nfsbootdev[] = "nfs";
229
230 bootstr_dev = prompt_dev = NULL;
231 bootstr_kname = prompt_kname = NULL;
232
233 /* first, get root device specified by the firmware */
234 spec = bootstring;
235
236 /* assume the last one is valid */
237 while ((spec = strstr(spec, "root=")) != NULL) {
238 spec += 5; /* skip 'root=' */
239 ptr = strchr(spec, ' ');
240 len = (ptr == NULL) ? strlen(spec) : ptr - spec;
241 /* decode unit and part from "/dev/hd[ab][1-4]" strings */
242 if (len == 9 && memcmp("/dev/hd", spec, 7) == 0) {
243 bootunit = spec[7] - 'a';
244 bootpart = spec[8] - '1';
245 if (bootunit >= 0 && bootunit < 2 &&
246 bootpart >= 0 && bootpart < 4) {
247 bootdev[sizeof(bootdev) - 3] = '0' + bootunit;
248 #if 0 /* bootpart is fdisk partition of Linux root */
249 bootdev[sizeof(bootdev) - 2] = 'a' + bootpart;
250 #endif
251 bootstr_dev = bootdev;
252 }
253 }
254 spec += len;
255 }
256
257 /* second, get bootname from bootstrings */
258 if ((spec = strstr(bootstring, "nbsd=")) != NULL) {
259 ptr = strchr(spec, ' ');
260 spec += 5; /* skip 'nbsd=' */
261 len = (ptr == NULL) ? strlen(spec) : ptr - spec;
262 if (len > 0) {
263 if (parse_bootname(spec, len,
264 &bootstr_dev, &bootstr_kname))
265 return 1;
266 }
267 }
268
269 /* third, check if netboot */
270 if (strstr(bootstring, "nfsroot=") != NULL) {
271 bootstr_dev = nfsbootdev;
272 }
273
274 DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n",
275 bootstr_dev ? bootstr_dev : "<NULL>",
276 bootstr_kname ? bootstr_kname : "<NULL>"));
277
278 spec = NULL;
279 len = 0;
280
281 memset(namebuf, 0, sizeof namebuf);
282 printf("Boot [%s:%s]: ",
283 bootstr_dev ? bootstr_dev : DEFBOOTDEV,
284 bootstr_kname ? bootstr_kname : DEFKERNELNAME);
285
286 if (tgets(namebuf) == -1)
287 printf("\n");
288
289 ptr = namebuf;
290 while ((c = *ptr) != '\0') {
291 while (c == ' ')
292 c = *++ptr;
293 if (c == '\0')
294 break;
295 if (c == '-') {
296 while ((c = *++ptr) && c != ' ')
297 BOOT_FLAG(c, *howtop);
298 } else {
299 spec = ptr;
300 while ((c = *++ptr) && c != ' ')
301 ;
302 if (c)
303 *ptr++ = '\0';
304 len = strlen(spec);
305 }
306 }
307
308 if (len > 0) {
309 if (parse_bootname(spec, len, &prompt_dev, &prompt_kname))
310 return 1;
311 }
312
313 DPRINTF(("prompt_dev = %s, prompt_kname = %s\n",
314 prompt_dev ? prompt_dev : "<NULL>",
315 prompt_kname ? prompt_kname : "<NULL>"));
316
317 if (prompt_dev)
318 *dev = prompt_dev;
319 else
320 *dev = bootstr_dev;
321
322 if (prompt_kname)
323 *kname = prompt_kname;
324 else
325 *kname = bootstr_kname;
326
327 DPRINTF(("dev = %s, kname = %s\n",
328 *dev ? *dev : "<NULL>",
329 *kname ? *kname : "<NULL>"));
330
331 return 0;
332 }
333
334 static int
parse_bootname(char * spec,int len,char ** dev,char ** kname)335 parse_bootname(char *spec, int len, char **dev, char **kname)
336 {
337 char *bootname, *ptr;
338
339 bootname = alloc(len + 1);
340 if (bootname == NULL)
341 return 1;
342 memcpy(bootname, spec, len);
343 bootname[len] = '\0';
344
345 if ((ptr = memchr(bootname, ':', len)) != NULL) {
346 /* "wdXX:kernel" */
347 *ptr = '\0';
348 *dev = bootname;
349 if (*++ptr)
350 *kname = ptr;
351 } else
352 /* "kernel" */
353 *kname = bootname;
354 return 0;
355 }
356
357 /*
358 * Get the bootstring from PROM.
359 */
360 void
prominit(unsigned int memsize)361 prominit(unsigned int memsize)
362 {
363
364 bootstring = (char *)(memsize - 512);
365 bootstring[511] = '\0';
366 }
367
368 /*
369 * Print boot message.
370 */
371 void
print_banner(unsigned int memsize)372 print_banner(unsigned int memsize)
373 {
374
375 lcd_banner();
376
377 printf("\n");
378 printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n",
379 bootprog_name, bootprog_rev, (void*)&start);
380 printf(">> Model:\t\t%s\n", cobalt_model[cobalt_id]);
381 printf(">> Memory:\t\t%lu k\n", (memsize - MIPS_KSEG0_START) / 1024);
382 printf(">> PROM boot string:\t%s\n", bootstring);
383 }
384
385 u_int
read_board_id(void)386 read_board_id(void)
387 {
388 uint32_t tag, reg;
389
390 #define PCIB_PCI_BUS 0
391 #define PCIB_PCI_DEV 9
392 #define PCIB_PCI_FUNC 0
393 #define PCIB_BOARD_ID_REG 0x94
394 #define COBALT_BOARD_ID(reg) ((reg & 0x000000f0) >> 4)
395
396 tag = (PCIB_PCI_BUS << 16) | (PCIB_PCI_DEV << 11) |
397 (PCIB_PCI_FUNC << 8);
398 reg = pcicfgread(tag, PCIB_BOARD_ID_REG);
399
400 return COBALT_BOARD_ID(reg);
401 }
402
403 /*
404 * Entry point.
405 * Parse PROM boot string, load the kernel and jump into it
406 */
407 int
main(unsigned int memsize)408 main(unsigned int memsize)
409 {
410 char **namep, *dev, *kernel, *bi_addr;
411 char bootpath[PATH_MAX];
412 int win;
413 u_long marks[MARK_MAX];
414 void (*entry)(unsigned int, u_int, char *);
415
416 struct btinfo_flags bi_flags;
417 struct btinfo_symtab bi_syms;
418 struct btinfo_bootpath bi_bpath;
419 struct btinfo_howto bi_howto;
420 int addr, speed, howto;
421
422 try_bootp = 1;
423
424 /* Initialize boot info early */
425 dev = NULL;
426 kernel = NULL;
427 howto = 0x0;
428 bi_flags.bi_flags = 0x0;
429 bi_addr = bi_init();
430
431 lcd_init();
432 cobalt_id = read_board_id();
433 prominit(memsize);
434 if (cninit(&addr, &speed) != NULL)
435 bi_flags.bi_flags |= BI_SERIAL_CONSOLE;
436
437 print_banner(memsize);
438
439 memset(marks, 0, sizeof marks);
440 get_bsdbootname(&dev, &kernel, &howto);
441
442 if (kernel != NULL) {
443 DPRINTF(("kernel: %s\n", kernel));
444 kernelnames[0] = kernel;
445 kernelnames[1] = NULL;
446 } else {
447 DPRINTF(("kernel: NULL\n"));
448 }
449
450 win = 0;
451 DPRINTF(("Kernel names: %p\n", kernelnames));
452 for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) {
453 kernel = *namep;
454
455 bootpath[0] = '\0';
456
457 strcpy(bootpath, dev ? dev : DEFBOOTDEV);
458 strcat(bootpath, ":");
459 strcat(bootpath, kernel);
460
461 lcd_loadfile(bootpath);
462 printf("Loading: %s", bootpath);
463 if (howto)
464 printf(" (howto 0x%x)", howto);
465 printf("\n");
466 patch_bootstring(bootpath);
467 win = (loadfile(bootpath, marks, LOAD_ALL) != -1);
468 }
469
470 if (win) {
471 strncpy(bi_bpath.bootpath, kernel, BTINFO_BOOTPATH_LEN);
472 bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
473
474 entry = (void *)marks[MARK_ENTRY];
475 bi_syms.nsym = marks[MARK_NSYM];
476 bi_syms.ssym = marks[MARK_SYM];
477 bi_syms.esym = marks[MARK_END];
478 bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
479
480 bi_add(&bi_flags, BTINFO_FLAGS, sizeof(bi_flags));
481
482 bi_howto.bi_howto = howto;
483 bi_add(&bi_howto, BTINFO_HOWTO, sizeof(bi_howto));
484
485 entry = (void *)marks[MARK_ENTRY];
486
487 DPRINTF(("Bootinfo @ 0x%lx\n", (u_long)bi_addr));
488 printf("Starting at 0x%lx\n\n", (u_long)entry);
489 (*entry)(memsize, BOOTINFO_MAGIC, bi_addr);
490 }
491
492 delay(20000);
493 lcd_failed();
494 (void)printf("Boot failed! Rebooting...\n");
495 return 0;
496 }
497