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