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