main.c revision 1.11 1 /* $NetBSD: main.c,v 1.11 2011/03/13 01:56:21 phx Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
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 #include <sys/param.h>
33 #include <sys/reboot.h>
34
35 #include <lib/libsa/stand.h>
36 #include <lib/libsa/loadfile.h>
37 #include <lib/libkern/libkern.h>
38
39 #include <machine/bootinfo.h>
40
41 #include "globals.h"
42
43 static const struct bootarg {
44 const char *name;
45 int value;
46 } bootargs[] = {
47 { "multi", RB_AUTOBOOT },
48 { "auto", RB_AUTOBOOT },
49 { "ask", RB_ASKNAME },
50 { "single", RB_SINGLE },
51 { "ddb", RB_KDB },
52 { "userconf", RB_USERCONF },
53 { "norm", AB_NORMAL },
54 { "quiet", AB_QUIET },
55 { "verb", AB_VERBOSE },
56 { "silent", AB_SILENT },
57 { "debug", AB_DEBUG }
58 };
59
60 void *bootinfo; /* low memory reserved to pass bootinfo structures */
61 int bi_size; /* BOOTINFO_MAXSIZE */
62 char *bi_next;
63
64 void bi_init(void *);
65 void bi_add(void *, int, int);
66
67 struct btinfo_memory bi_mem;
68 struct btinfo_console bi_cons;
69 struct btinfo_clock bi_clk;
70 struct btinfo_prodfamily bi_fam;
71 struct btinfo_bootpath bi_path;
72 struct btinfo_rootdevice bi_rdev;
73 struct btinfo_net bi_net;
74 struct btinfo_modulelist *btinfo_modulelist;
75 size_t btinfo_modulelist_size;
76
77 struct boot_module {
78 char *bm_kmod;
79 ssize_t bm_len;
80 struct boot_module *bm_next;
81 };
82 struct boot_module *boot_modules;
83 char module_base[80];
84 uint32_t kmodloadp;
85 int modules_enabled = 0;
86
87 void module_add(char *);
88 void module_load(char *);
89 int module_open(struct boot_module *);
90
91 void main(int, char **, char *, char *);
92 extern char bootprog_name[], bootprog_rev[];
93
94 struct pcidev lata[2];
95 struct pcidev lnif[1];
96 struct pcidev lusb[3];
97 int nata, nnif, nusb;
98
99 int brdtype;
100 uint32_t busclock, cpuclock;
101
102 static int check_bootname(char *);
103 static int input_cmdline(char **, int);
104 static int parse_cmdline(char **, int, char *, char *);
105 static int is_space(char);
106
107 #define BNAME_DEFAULT "nfs:"
108 #define MAX_ARGS 10
109
110 void
111 main(int argc, char *argv[], char *bootargs_start, char *bootargs_end)
112 {
113 struct brdprop *brdprop;
114 unsigned long marks[MARK_MAX];
115 char *new_argv[MAX_ARGS];
116 int n, i, fd, howto;
117 char *bname;
118
119 printf("\n");
120 printf(">> %s altboot, revision %s\n", bootprog_name, bootprog_rev);
121
122 brdprop = brd_lookup(brdtype);
123 printf(">> %s, cpu %u MHz, bus %u MHz, %dMB SDRAM\n", brdprop->verbose,
124 cpuclock / 1000000, busclock / 1000000, bi_mem.memsize >> 20);
125
126 nata = pcilookup(PCI_CLASS_IDE, lata, 2);
127 if (nata == 0)
128 nata = pcilookup(PCI_CLASS_MISCSTORAGE, lata, 2);
129 if (nata == 0)
130 nata = pcilookup(PCI_CLASS_SCSI, lata, 2);
131 nnif = pcilookup(PCI_CLASS_ETH, lnif, 1);
132 nusb = pcilookup(PCI_CLASS_USB, lusb, 3);
133
134 #ifdef DEBUG
135 if (nata == 0)
136 printf("No IDE/SATA found\n");
137 else for (n = 0; n < nata; n++) {
138 int b, d, f, bdf, pvd;
139 bdf = lata[n].bdf;
140 pvd = lata[n].pvd;
141 pcidecomposetag(bdf, &b, &d, &f);
142 printf("%04x.%04x DSK %02d:%02d:%02d\n",
143 PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
144 }
145 if (nnif == 0)
146 printf("no NET found\n");
147 else {
148 int b, d, f, bdf, pvd;
149 bdf = lnif[0].bdf;
150 pvd = lnif[0].pvd;
151 pcidecomposetag(bdf, &b, &d, &f);
152 printf("%04x.%04x NET %02d:%02d:%02d\n",
153 PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
154 }
155 if (nusb == 0)
156 printf("no USB found\n");
157 else for (n = 0; n < nusb; n++) {
158 int b, d, f, bdf, pvd;
159 bdf = lusb[0].bdf;
160 pvd = lusb[0].pvd;
161 pcidecomposetag(bdf, &b, &d, &f);
162 printf("%04x.%04x USB %02d:%02d:%02d\n",
163 PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
164 }
165 #endif
166
167 pcisetup();
168 pcifixup();
169
170 if (dskdv_init(&lata[0]) == 0
171 || (nata == 2 && dskdv_init(&lata[1]) == 0))
172 printf("IDE/SATA device driver was not found\n");
173
174 if (netif_init(&lnif[0]) == 0)
175 printf("no NET device driver was found\n");
176
177 /*
178 * When argc is too big then it is probably a pointer, which could
179 * indicate that we were launched as a Linux kernel module using
180 * "bootm".
181 */
182 if (argc > MAX_ARGS) {
183 /* parse Linux bootargs */
184 argv = new_argv;
185 argc = parse_cmdline(argv, MAX_ARGS, bootargs_start,
186 bootargs_end);
187 }
188
189 /* wait 2s for user to enter interactive mode */
190 for (n = 200; n >= 0; n--) {
191 if (n % 100 == 0)
192 printf("Hit any key to enter interactive mode: %d\r",
193 n / 100);
194 if (tstchar()) {
195 (void)getchar();
196 argv = new_argv;
197 argc = input_cmdline(argv, MAX_ARGS);
198 break;
199 }
200 delay(10000);
201 }
202 putchar('\n');
203
204 howto = RB_AUTOBOOT; /* default is autoboot = 0 */
205
206 /* get boot options and determine bootname */
207 for (n = 1; n < argc; n++) {
208 for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) {
209 if (strncasecmp(argv[n], bootargs[i].name,
210 strlen(bootargs[i].name)) == 0) {
211 howto |= bootargs[i].value;
212 break;
213 }
214 }
215 if (i >= sizeof(bootargs) / sizeof(bootargs[0]))
216 break; /* break on first unknown string */
217 }
218 if (n >= argc)
219 bname = BNAME_DEFAULT;
220 else {
221 bname = argv[n];
222 if (check_bootname(bname) == 0) {
223 printf("%s not a valid bootname\n", bname);
224 goto loadfail;
225 }
226 }
227
228 if ((fd = open(bname, 0)) < 0) {
229 if (errno == ENOENT)
230 printf("\"%s\" not found\n", bi_path.bootpath);
231 goto loadfail;
232 }
233 printf("loading \"%s\" ", bi_path.bootpath);
234 marks[MARK_START] = 0;
235 if (fdloadfile(fd, marks, LOAD_KERNEL) < 0)
236 goto loadfail;
237 close(fd);
238
239 printf("entry=%p, ssym=%p, esym=%p\n",
240 (void *)marks[MARK_ENTRY],
241 (void *)marks[MARK_SYM],
242 (void *)marks[MARK_END]);
243
244 bootinfo = (void *)0x4000;
245 bi_init(bootinfo);
246 bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons));
247 bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem));
248 bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk));
249 bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
250 bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
251 bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
252 if (brdtype == BRD_SYNOLOGY || brdtype == BRD_DLINKDSM) {
253 /* need to set this MAC address in kernel driver later */
254 bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
255 }
256
257 if (modules_enabled) {
258 module_add(fsmod);
259 if (fsmod2 != NULL && strcmp(fsmod, fsmod2) != 0)
260 module_add(fsmod2);
261 kmodloadp = marks[MARK_END];
262 btinfo_modulelist = NULL;
263 module_load(bname);
264 if (btinfo_modulelist != NULL && btinfo_modulelist->num > 0)
265 bi_add(btinfo_modulelist, BTINFO_MODULELIST,
266 btinfo_modulelist_size);
267 }
268
269 netif_shutdown_all();
270
271 __syncicache((void *)marks[MARK_ENTRY],
272 (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]);
273
274 run((void *)marks[MARK_SYM], (void *)marks[MARK_END],
275 (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]);
276
277 /* should never come here */
278 printf("exec returned. Restarting...\n");
279 _rtt();
280
281 loadfail:
282 printf("load failed. Restarting...\n");
283 _rtt();
284 }
285
286 void
287 bi_init(void *addr)
288 {
289 struct btinfo_magic bi_magic;
290
291 memset(addr, 0, BOOTINFO_MAXSIZE);
292 bi_next = (char *)addr;
293 bi_size = 0;
294
295 bi_magic.magic = BOOTINFO_MAGIC;
296 bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
297 }
298
299 void
300 bi_add(void *new, int type, int size)
301 {
302 struct btinfo_common *bi;
303
304 if (bi_size + size > BOOTINFO_MAXSIZE)
305 return; /* XXX error? */
306
307 bi = new;
308 bi->next = size;
309 bi->type = type;
310 memcpy(bi_next, new, size);
311 bi_next += size;
312 }
313
314 void
315 module_add(char *name)
316 {
317 struct boot_module *bm, *bmp;
318
319 while (*name == ' ' || *name == '\t')
320 ++name;
321
322 bm = alloc(sizeof(struct boot_module) + strlen(name) + 1);
323 if (bm == NULL) {
324 printf("couldn't allocate module %s\n", name);
325 return;
326 }
327
328 bm->bm_kmod = (char *)(bm + 1);
329 bm->bm_len = -1;
330 bm->bm_next = NULL;
331 strcpy(bm->bm_kmod, name);
332 if ((bmp = boot_modules) == NULL)
333 boot_modules = bm;
334 else {
335 while (bmp->bm_next != NULL)
336 bmp = bmp->bm_next;
337 bmp->bm_next = bm;
338 }
339 }
340
341 #define PAGE_SIZE 4096
342 #define alignpg(x) (((x)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
343
344 void
345 module_load(char *kernel_path)
346 {
347 struct boot_module *bm;
348 struct bi_modulelist_entry *bi;
349 struct stat st;
350 char *p;
351 int size, fd;
352
353 strcpy(module_base, kernel_path);
354 if ((p = strchr(module_base, ':')) == NULL)
355 return; /* eeh?! */
356 p += 1;
357 size = sizeof(module_base) - (p - module_base);
358
359 if (netbsd_version / 1000000 % 100 == 99) {
360 /* -current */
361 snprintf(p, size,
362 "/stand/sandpoint/%d.%d.%d/modules",
363 netbsd_version / 100000000,
364 netbsd_version / 1000000 % 100,
365 netbsd_version / 100 % 100);
366 }
367 else if (netbsd_version != 0) {
368 /* release */
369 snprintf(p, size,
370 "/stand/sandpoint/%d.%d/modules",
371 netbsd_version / 100000000,
372 netbsd_version / 1000000 % 100);
373 }
374
375 /*
376 * 1st pass; determine module existence
377 */
378 size = 0;
379 for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
380 fd = module_open(bm);
381 if (fd == -1)
382 continue;
383 if (fstat(fd, &st) == -1 || st.st_size == -1) {
384 printf("WARNING: couldn't stat %s\n", bm->bm_kmod);
385 close(fd);
386 continue;
387 }
388 bm->bm_len = (int)st.st_size;
389 close(fd);
390 size += sizeof(struct bi_modulelist_entry);
391 }
392 if (size == 0)
393 return;
394
395 size += sizeof(struct btinfo_modulelist);
396 btinfo_modulelist = alloc(size);
397 if (btinfo_modulelist == NULL) {
398 printf("WARNING: couldn't allocate module list\n");
399 return;
400 }
401 btinfo_modulelist_size = size;
402 btinfo_modulelist->num = 0;
403
404 /*
405 * 2nd pass; load modules into memory
406 */
407 kmodloadp = alignpg(kmodloadp);
408 bi = (struct bi_modulelist_entry *)(btinfo_modulelist + 1);
409 for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
410 if (bm->bm_len == -1)
411 continue; /* already found unavailable */
412 fd = module_open(bm);
413 printf("module \"%s\" ", bm->bm_kmod);
414 size = read(fd, (char *)kmodloadp, SSIZE_MAX);
415 if (size < bm->bm_len)
416 printf("WARNING: couldn't load");
417 else {
418 snprintf(bi->kmod, sizeof(bi->kmod), bm->bm_kmod);
419 bi->type = BI_MODULE_ELF;
420 bi->len = size;
421 bi->base = kmodloadp;
422 btinfo_modulelist->num += 1;
423 printf("loaded at 0x%08x size 0x%x", kmodloadp, size);
424 kmodloadp += alignpg(size);
425 bi += 1;
426 }
427 printf("\n");
428 close(fd);
429 }
430 btinfo_modulelist->endpa = kmodloadp;
431 }
432
433 int
434 module_open(struct boot_module *bm)
435 {
436 char path[80];
437 int fd;
438
439 snprintf(path, sizeof(path),
440 "%s/%s/%s.kmod", module_base, bm->bm_kmod, bm->bm_kmod);
441 fd = open(path, 0);
442 return fd;
443 }
444
445 #if 0
446 static const char *cmdln[] = {
447 "console=ttyS0,115200 root=/dev/sda1 rw initrd=0x200000,2M",
448 "console=ttyS0,115200 root=/dev/nfs ip=dhcp"
449 };
450
451 void
452 mkatagparams(unsigned addr, char *kcmd)
453 {
454 struct tag {
455 unsigned siz;
456 unsigned tag;
457 unsigned val[1];
458 };
459 struct tag *p;
460 #define ATAG_CORE 0x54410001
461 #define ATAG_MEM 0x54410002
462 #define ATAG_INITRD 0x54410005
463 #define ATAG_CMDLINE 0x54410009
464 #define ATAG_NONE 0x00000000
465 #define tagnext(p) (struct tag *)((unsigned *)(p) + (p)->siz)
466 #define tagsize(n) (2 + (n))
467
468 p = (struct tag *)addr;
469 p->tag = ATAG_CORE;
470 p->siz = tagsize(3);
471 p->val[0] = 0; /* flags */
472 p->val[1] = 0; /* pagesize */
473 p->val[2] = 0; /* rootdev */
474 p = tagnext(p);
475 p->tag = ATAG_MEM;
476 p->siz = tagsize(2);
477 p->val[0] = 64 * 1024 * 1024;
478 p->val[1] = 0; /* start */
479 p = tagnext(p);
480 if (kcmd != NULL) {
481 p = tagnext(p);
482 p->tag = ATAG_CMDLINE;
483 p->siz = tagsize((strlen(kcmd) + 1 + 3) >> 2);
484 strcpy((void *)p->val, kcmd);
485 }
486 p = tagnext(p);
487 p->tag = ATAG_NONE;
488 p->siz = 0;
489 }
490 #endif
491
492 void *
493 allocaligned(size_t size, size_t align)
494 {
495 uint32_t p;
496
497 if (align-- < 2)
498 return alloc(size);
499 p = (uint32_t)alloc(size + align);
500 return (void *)((p + align) & ~align);
501 }
502
503 static int hex2nibble(char c)
504 {
505
506 if (c >= 'a')
507 c &= ~0x20;
508 if (c >= 'A' && c <= 'F')
509 c -= 'A' - ('9' + 1);
510 else if (c < '0' || c > '9')
511 return -1;
512
513 return c - '0';
514 }
515
516 uint32_t
517 read_hex(const char *s)
518 {
519 int n;
520 uint32_t val;
521
522 val = 0;
523 while ((n = hex2nibble(*s++)) >= 0)
524 val = (val << 4) | n;
525 return val;
526 }
527
528 static int
529 check_bootname(char *s)
530 {
531 /*
532 * nfs:
533 * nfs:<bootfile>
534 * tftp:
535 * tftp:<bootfile>
536 * wd[N[P]]:<bootfile>
537 * mem:<address>
538 *
539 * net is a synonym of nfs.
540 */
541 if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0 ||
542 strncmp(s, "tftp:", 5) == 0 || strncmp(s, "mem:", 4) == 0)
543 return 1;
544 if (s[0] == 'w' && s[1] == 'd') {
545 s += 2;
546 if (*s != ':' && *s >= '0' && *s <= '3') {
547 ++s;
548 if (*s != ':' && *s >= 'a' && *s <= 'p')
549 ++s;
550 }
551 return *s == ':';
552 }
553 return 0;
554 }
555
556 static int input_cmdline(char **argv, int maxargc)
557 {
558 char *cmdline;
559
560 printf("\nbootargs> ");
561 cmdline = alloc(256);
562 gets(cmdline);
563
564 return parse_cmdline(argv, maxargc, cmdline,
565 cmdline + strlen(cmdline));
566 }
567
568 static int
569 parse_cmdline(char **argv, int maxargc, char *p, char *end)
570 {
571 int argc;
572
573 argv[0] = "";
574 for (argc = 1; argc < maxargc && p < end; argc++) {
575 while (is_space(*p))
576 p++;
577 if (p >= end)
578 break;
579 argv[argc] = p;
580 while (!is_space(*p) && p < end)
581 p++;
582 *p++ = '\0';
583 }
584
585 return argc;
586 }
587
588 static int
589 is_space(char c)
590 {
591 return c > '\0' && c <= ' ';
592 }
593