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