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