xref: /netbsd-src/sys/arch/i386/stand/lib/exec.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*	$NetBSD: exec.c,v 1.47 2011/05/26 04:25:27 uebayasi Exp $	 */
2 
3 /*-
4  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Copyright (c) 1982, 1986, 1990, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. Neither the name of the University nor the names of its contributors
42  *    may be used to endorse or promote products derived from this software
43  *    without specific prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  * 	@(#)boot.c	8.1 (Berkeley) 6/10/93
58  */
59 
60 /*
61  * Copyright (c) 1996
62  *	Matthias Drochner.  All rights reserved.
63  * Copyright (c) 1996
64  * 	Perry E. Metzger.  All rights reserved.
65  *
66  * Redistribution and use in source and binary forms, with or without
67  * modification, are permitted provided that the following conditions
68  * are met:
69  * 1. Redistributions of source code must retain the above copyright
70  *    notice, this list of conditions and the following disclaimer.
71  * 2. Redistributions in binary form must reproduce the above copyright
72  *    notice, this list of conditions and the following disclaimer in the
73  *    documentation and/or other materials provided with the distribution.
74  *
75  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
76  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
79  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
80  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
81  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
82  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
83  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
84  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
85  * SUCH DAMAGE.
86  *
87  * 	@(#)boot.c	8.1 (Berkeley) 6/10/93
88  */
89 
90 /*
91  * starts NetBSD a.out kernel
92  * needs lowlevel startup from startprog.S
93  * This is a special version of exec.c to support use of XMS.
94  */
95 
96 #include <sys/param.h>
97 #include <sys/reboot.h>
98 #include <sys/reboot.h>
99 
100 #include <machine/multiboot.h>
101 #include <machine/stdarg.h>
102 
103 #include <lib/libsa/stand.h>
104 #include <lib/libkern/libkern.h>
105 
106 #include "loadfile.h"
107 #include "libi386.h"
108 #include "bootinfo.h"
109 #include "bootmod.h"
110 #include "vbe.h"
111 #ifdef SUPPORT_PS2
112 #include "biosmca.h"
113 #endif
114 
115 #define BOOT_NARGS	6
116 
117 #ifndef	PAGE_SIZE
118 #define	PAGE_SIZE	4096
119 #endif
120 
121 #define MODULE_WARNING_SEC	5
122 
123 extern struct btinfo_console btinfo_console;
124 
125 boot_module_t *boot_modules;
126 bool boot_modules_enabled = true;
127 bool kernel_loaded;
128 
129 typedef struct userconf_command {
130 	char *uc_text;
131 	size_t uc_len;
132 	struct userconf_command *uc_next;
133 } userconf_command_t;
134 userconf_command_t *userconf_commands = NULL;
135 
136 static struct btinfo_framebuffer btinfo_framebuffer;
137 
138 static struct btinfo_modulelist *btinfo_modulelist;
139 static size_t btinfo_modulelist_size;
140 static uint32_t image_end;
141 static char module_base[64] = "/";
142 static int howto;
143 
144 static struct btinfo_userconfcommands *btinfo_userconfcommands = NULL;
145 static size_t btinfo_userconfcommands_size = 0;
146 
147 static void	module_init(const char *);
148 static void	module_add_common(char *, uint8_t);
149 
150 static void	userconf_init(void);
151 
152 void
153 framebuffer_configure(struct btinfo_framebuffer *fb)
154 {
155 	if (fb)
156 		btinfo_framebuffer = *fb;
157 	else {
158 		btinfo_framebuffer.physaddr = 0;
159 		btinfo_framebuffer.flags = 0;
160 	}
161 }
162 
163 void
164 module_add(char *name)
165 {
166 	return module_add_common(name, BM_TYPE_KMOD);
167 }
168 
169 void
170 splash_add(char *name)
171 {
172 	return module_add_common(name, BM_TYPE_IMAGE);
173 }
174 
175 static void
176 module_add_common(char *name, uint8_t type)
177 {
178 	boot_module_t *bm, *bmp;
179 	size_t len;
180 	char *str;
181 
182 	while (*name == ' ' || *name == '\t')
183 		++name;
184 
185 	bm = alloc(sizeof(boot_module_t));
186 	len = strlen(name) + 1;
187 	str = alloc(len);
188 	if (bm == NULL || str == NULL) {
189 		printf("couldn't allocate module\n");
190 		return;
191 	}
192 	memcpy(str, name, len);
193 	bm->bm_path = str;
194 	bm->bm_next = NULL;
195 	bm->bm_type = type;
196 	if (boot_modules == NULL)
197 		boot_modules = bm;
198 	else {
199 		for (bmp = boot_modules; bmp->bm_next;
200 		    bmp = bmp->bm_next)
201 			;
202 		bmp->bm_next = bm;
203 	}
204 }
205 
206 void
207 userconf_add(char *cmd)
208 {
209 	userconf_command_t *uc;
210 	size_t len;
211 	char *text;
212 
213 	while (*cmd == ' ' || *cmd == '\t')
214 		++cmd;
215 
216 	uc = alloc(sizeof(*uc));
217 	if (uc == NULL) {
218 		printf("couldn't allocate command\n");
219 		return;
220 	}
221 
222 	len = strlen(cmd) + 1;
223 	text = alloc(len);
224 	if (text == NULL) {
225 		dealloc(uc, sizeof(*uc));
226 		printf("couldn't allocate command\n");
227 		return;
228 	}
229 	memcpy(text, cmd, len);
230 
231 	uc->uc_text = text;
232 	uc->uc_len = len;
233 	uc->uc_next = NULL;
234 
235 	if (userconf_commands == NULL)
236 		userconf_commands = uc;
237 	else {
238 		userconf_command_t *ucp;
239 		for (ucp = userconf_commands; ucp->uc_next != NULL;
240 		     ucp = ucp->uc_next)
241 			;
242 		ucp->uc_next = uc;
243 	}
244 }
245 
246 static int
247 common_load_kernel(const char *file, u_long *basemem, u_long *extmem,
248     physaddr_t loadaddr, int floppy, u_long marks[MARK_MAX])
249 {
250 	int fd;
251 #ifdef XMS
252 	u_long		xmsmem;
253 	physaddr_t	origaddr = loadaddr;
254 #endif
255 
256 	*extmem = getextmem();
257 	*basemem = getbasemem();
258 
259 #ifdef XMS
260 	if ((getextmem1() == 0) && (xmsmem = checkxms())) {
261 	        u_long kernsize;
262 
263 		/*
264 		 * With "CONSERVATIVE_MEMDETECT", extmem is 0 because
265 		 *  getextmem() is getextmem1(). Without, the "smart"
266 		 *  methods could fail to report all memory as well.
267 		 * xmsmem is a few kB less than the actual size, but
268 		 *  better than nothing.
269 		 */
270 		if (xmsmem > *extmem)
271 			*extmem = xmsmem;
272 		/*
273 		 * Get the size of the kernel
274 		 */
275 		marks[MARK_START] = loadaddr;
276 		if ((fd = loadfile(file, marks, COUNT_KERNEL)) == -1)
277 			return EIO;
278 		close(fd);
279 
280 		kernsize = marks[MARK_END];
281 		kernsize = (kernsize + 1023) / 1024;
282 
283 		loadaddr = xmsalloc(kernsize);
284 		if (!loadaddr)
285 			return ENOMEM;
286 	}
287 #endif
288 	marks[MARK_START] = loadaddr;
289 	if ((fd = loadfile(file, marks,
290 	    LOAD_KERNEL & ~(floppy ? LOAD_BACKWARDS : 0))) == -1)
291 		return EIO;
292 
293 	close(fd);
294 
295 	/* Now we know the root fs type, load modules for it. */
296 	module_add(fsmod);
297 	if (fsmod2 != NULL && strcmp(fsmod, fsmod2) != 0)
298 		module_add(fsmod2);
299 
300 	/*
301 	 * Gather some information for the kernel. Do this after the
302 	 * "point of no return" to avoid memory leaks.
303 	 * (but before DOS might be trashed in the XMS case)
304 	 */
305 #ifdef PASS_BIOSGEOM
306 	bi_getbiosgeom();
307 #endif
308 #ifdef PASS_MEMMAP
309 	bi_getmemmap();
310 #endif
311 
312 #ifdef XMS
313 	if (loadaddr != origaddr) {
314 		/*
315 		 * We now have done our last DOS IO, so we may
316 		 * trash the OS. Copy the data from the temporary
317 		 * buffer to its real address.
318 		 */
319 		marks[MARK_START] -= loadaddr;
320 		marks[MARK_END] -= loadaddr;
321 		marks[MARK_SYM] -= loadaddr;
322 		marks[MARK_END] -= loadaddr;
323 		ppbcopy(loadaddr, origaddr, marks[MARK_END]);
324 	}
325 #endif
326 	marks[MARK_END] = (((u_long) marks[MARK_END] + sizeof(int) - 1)) &
327 	    (-sizeof(int));
328 	image_end = marks[MARK_END];
329 	kernel_loaded = true;
330 
331 	return 0;
332 }
333 
334 int
335 exec_netbsd(const char *file, physaddr_t loadaddr, int boothowto, int floppy,
336 	    void (*callback)(void))
337 {
338 	u_long          boot_argv[BOOT_NARGS];
339 	u_long		marks[MARK_MAX];
340 	struct btinfo_symtab btinfo_symtab;
341 	u_long		extmem;
342 	u_long		basemem;
343 
344 #ifdef	DEBUG
345 	printf("exec: file=%s loadaddr=0x%lx\n",
346 	       file ? file : "NULL", loadaddr);
347 #endif
348 
349 	BI_ALLOC(32); /* ??? */
350 
351 	BI_ADD(&btinfo_console, BTINFO_CONSOLE, sizeof(struct btinfo_console));
352 
353 	howto = boothowto;
354 
355 	if (common_load_kernel(file, &basemem, &extmem, loadaddr, floppy, marks))
356 		goto out;
357 
358 	boot_argv[0] = boothowto;
359 	boot_argv[1] = 0;
360 	boot_argv[2] = vtophys(bootinfo);	/* old cyl offset */
361 	boot_argv[3] = marks[MARK_END];
362 	boot_argv[4] = extmem;
363 	boot_argv[5] = basemem;
364 
365 	/* pull in any modules if necessary */
366 	if (boot_modules_enabled) {
367 		module_init(file);
368 		if (btinfo_modulelist) {
369 			BI_ADD(btinfo_modulelist, BTINFO_MODULELIST,
370 			    btinfo_modulelist_size);
371 		}
372 	}
373 
374 	userconf_init();
375 	if (btinfo_userconfcommands != NULL)
376 		BI_ADD(btinfo_userconfcommands, BTINFO_USERCONFCOMMANDS,
377 	btinfo_userconfcommands_size);
378 
379 #ifdef DEBUG
380 	printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY],
381 	    marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]);
382 #endif
383 
384 	btinfo_symtab.nsym = marks[MARK_NSYM];
385 	btinfo_symtab.ssym = marks[MARK_SYM];
386 	btinfo_symtab.esym = marks[MARK_END];
387 	BI_ADD(&btinfo_symtab, BTINFO_SYMTAB, sizeof(struct btinfo_symtab));
388 
389 	/* set new video mode if necessary */
390 	vbe_commit();
391 	BI_ADD(&btinfo_framebuffer, BTINFO_FRAMEBUFFER,
392 	    sizeof(struct btinfo_framebuffer));
393 
394 	if (callback != NULL)
395 		(*callback)();
396 	startprog(marks[MARK_ENTRY], BOOT_NARGS, boot_argv,
397 		  x86_trunc_page(basemem*1024));
398 	panic("exec returned");
399 
400 out:
401 	BI_FREE();
402 	bootinfo = 0;
403 	return -1;
404 }
405 
406 static void
407 extract_device(const char *path, char *buf, size_t buflen)
408 {
409 	int i;
410 
411 	if (strchr(path, ':') != NULL) {
412 		for (i = 0; i < buflen - 2 && path[i] != ':'; i++)
413 			buf[i] = path[i];
414 		buf[i++] = ':';
415 		buf[i] = '\0';
416 	} else
417 		buf[0] = '\0';
418 }
419 
420 static const char *
421 module_path(boot_module_t *bm, const char *kdev)
422 {
423 	static char buf[256];
424 	char name_buf[256], dev_buf[64];
425 	const char *name, *name2, *p;
426 
427 	name = bm->bm_path;
428 	for (name2 = name; *name2; ++name2) {
429 		if (*name2 == ' ' || *name2 == '\t') {
430 			strlcpy(name_buf, name, sizeof(name_buf));
431 			if (name2 - name < sizeof(name_buf))
432 				name_buf[name2 - name] = '\0';
433 			name = name_buf;
434 			break;
435 		}
436 	}
437 	if ((p = strchr(name, ':')) != NULL) {
438 		/* device specified, use it */
439 		if (p[1] == '/')
440 			snprintf(buf, sizeof(buf), "%s", name);
441 		else {
442 			p++;
443 			extract_device(name, dev_buf, sizeof(dev_buf));
444 			snprintf(buf, sizeof(buf), "%s%s/%s/%s.kmod",
445 			    dev_buf, module_base, p, p);
446 		}
447 	} else {
448 		/* device not specified; load from kernel device if known */
449  		if (name[0] == '/')
450 			snprintf(buf, sizeof(buf), "%s%s", kdev, name);
451 		else
452 			snprintf(buf, sizeof(buf), "%s%s/%s/%s.kmod",
453 			    kdev, module_base, name, name);
454 	}
455 
456 	return buf;
457 }
458 
459 static int
460 module_open(boot_module_t *bm, int mode, const char *kdev, bool doload)
461 {
462 	int fd;
463 	const char *path;
464 
465 	/* check the expanded path first */
466 	path = module_path(bm, kdev);
467 	fd = open(path, mode);
468 	if (fd != -1) {
469 		if ((howto & AB_SILENT) == 0 && doload)
470 			printf("Loading %s ", path);
471 	} else {
472 		/* now attempt the raw path provided */
473 		fd = open(bm->bm_path, mode);
474 		if (fd != -1 && (howto & AB_SILENT) == 0 && doload)
475 			printf("Loading %s ", bm->bm_path);
476 	}
477 	if (!doload && fd == -1) {
478 		printf("WARNING: couldn't open %s", bm->bm_path);
479 		if (strcmp(bm->bm_path, path) != 0)
480 			printf(" (%s)", path);
481 		printf("\n");
482 	}
483 	return fd;
484 }
485 
486 static void
487 module_init(const char *kernel_path)
488 {
489 	struct bi_modulelist_entry *bi;
490 	struct stat st;
491 	const char *machine;
492 	char kdev[64];
493 	char *buf;
494 	boot_module_t *bm;
495 	size_t len;
496 	off_t off;
497 	int err, fd, nfail = 0;
498 
499 	extract_device(kernel_path, kdev, sizeof(kdev));
500 
501 	switch (netbsd_elf_class) {
502 	case ELFCLASS32:
503 		machine = "i386";
504 		break;
505 	case ELFCLASS64:
506 		machine = "amd64";
507 		break;
508 	default:
509 		machine = "generic";
510 		break;
511 	}
512 	if (netbsd_version / 1000000 % 100 == 99) {
513 		/* -current */
514 		snprintf(module_base, sizeof(module_base),
515 		    "/stand/%s/%d.%d.%d/modules", machine,
516 		    netbsd_version / 100000000,
517 		    netbsd_version / 1000000 % 100,
518 		    netbsd_version / 100 % 100);
519 	} else if (netbsd_version != 0) {
520 		/* release */
521 		snprintf(module_base, sizeof(module_base),
522 		    "/stand/%s/%d.%d/modules", machine,
523 		    netbsd_version / 100000000,
524 		    netbsd_version / 1000000 % 100);
525 	}
526 
527 	/* First, see which modules are valid and calculate btinfo size */
528 	len = sizeof(struct btinfo_modulelist);
529 	for (bm = boot_modules; bm; bm = bm->bm_next) {
530 		fd = module_open(bm, 0, kdev, false);
531 		if (fd == -1) {
532 			bm->bm_len = -1;
533 			++nfail;
534 			continue;
535 		}
536 		err = fstat(fd, &st);
537 		if (err == -1 || st.st_size == -1) {
538 			printf("WARNING: couldn't stat %s\n", bm->bm_path);
539 			close(fd);
540 			bm->bm_len = -1;
541 			++nfail;
542 			continue;
543 		}
544 		bm->bm_len = st.st_size;
545 		close(fd);
546 		len += sizeof(struct bi_modulelist_entry);
547 	}
548 
549 	/* Allocate the module list */
550 	btinfo_modulelist = alloc(len);
551 	if (btinfo_modulelist == NULL) {
552 		printf("WARNING: couldn't allocate module list\n");
553 		wait_sec(MODULE_WARNING_SEC);
554 		return;
555 	}
556 	memset(btinfo_modulelist, 0, len);
557 	btinfo_modulelist_size = len;
558 
559 	/* Fill in btinfo structure */
560 	buf = (char *)btinfo_modulelist;
561 	btinfo_modulelist->num = 0;
562 	off = sizeof(struct btinfo_modulelist);
563 
564 	for (bm = boot_modules; bm; bm = bm->bm_next) {
565 		if (bm->bm_len == -1)
566 			continue;
567 		fd = module_open(bm, 0, kdev, true);
568 		if (fd == -1)
569 			continue;
570 		image_end = (image_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
571 		len = pread(fd, (void *)image_end, SSIZE_MAX);
572 		if (len < bm->bm_len) {
573 			if ((howto & AB_SILENT) != 0)
574 				printf("Loading %s ", bm->bm_path);
575 			printf(" FAILED\n");
576 		} else {
577 			btinfo_modulelist->num++;
578 			bi = (struct bi_modulelist_entry *)(buf + off);
579 			off += sizeof(struct bi_modulelist_entry);
580 			strncpy(bi->path, bm->bm_path, sizeof(bi->path) - 1);
581 			bi->base = image_end;
582 			bi->len = len;
583 			bi->type = bm->bm_type == BM_TYPE_KMOD ?
584 			    BI_MODULE_ELF : BI_MODULE_IMAGE;
585 			if ((howto & AB_SILENT) == 0)
586 				printf(" \n");
587 		}
588 		if (len > 0)
589 			image_end += len;
590 		close(fd);
591 	}
592 	btinfo_modulelist->endpa = image_end;
593 
594 	if (nfail > 0) {
595 		printf("WARNING: %d module%s failed to load\n",
596 		    nfail, nfail == 1 ? "" : "s");
597 #if notyet
598 		wait_sec(MODULE_WARNING_SEC);
599 #endif
600 	}
601 }
602 
603 static void
604 userconf_init(void)
605 {
606 	size_t count, len;
607 	userconf_command_t *uc;
608 	char *buf;
609 	off_t off;
610 
611 	/* Calculate the userconf commands list size */
612 	count = 0;
613 	for (uc = userconf_commands; uc != NULL; uc = uc->uc_next)
614 		count++;
615 	len = sizeof(btinfo_userconfcommands) +
616 	      count * sizeof(struct bi_userconfcommand);
617 
618 	/* Allocate the userconf commands list */
619 	btinfo_userconfcommands = alloc(len);
620 	if (btinfo_userconfcommands == NULL) {
621 		printf("WARNING: couldn't allocate userconf commands list\n");
622 		return;
623 	}
624 	memset(btinfo_userconfcommands, 0, len);
625 	btinfo_userconfcommands_size = len;
626 
627 	/* Fill in btinfo structure */
628 	buf = (char *)btinfo_userconfcommands;
629 	off = sizeof(*btinfo_userconfcommands);
630 	btinfo_userconfcommands->num = 0;
631 	for (uc = userconf_commands; uc != NULL; uc = uc->uc_next) {
632 		struct bi_userconfcommand *bi;
633 		bi = (struct bi_userconfcommand *)(buf + off);
634 		strncpy(bi->text, uc->uc_text, sizeof(bi->text) - 1);
635 
636 		off += sizeof(*bi);
637 		btinfo_userconfcommands->num++;
638 	}
639 }
640 
641 int
642 exec_multiboot(const char *file, char *args)
643 {
644 	struct multiboot_info *mbi;
645 	struct multiboot_module *mbm;
646 	struct bi_modulelist_entry *bim;
647 	int		i, len;
648 	u_long		marks[MARK_MAX];
649 	u_long		extmem;
650 	u_long		basemem;
651 	char		*cmdline;
652 
653 	mbi = alloc(sizeof(struct multiboot_info));
654 	mbi->mi_flags = MULTIBOOT_INFO_HAS_MEMORY;
655 
656 	if (common_load_kernel(file, &basemem, &extmem, 0, 0, marks))
657 		goto out;
658 
659 	mbi->mi_mem_upper = extmem;
660 	mbi->mi_mem_lower = basemem;
661 
662 	if (args) {
663 		mbi->mi_flags |= MULTIBOOT_INFO_HAS_CMDLINE;
664 		len = strlen(file) + 1 + strlen(args) + 1;
665 		cmdline = alloc(len);
666 		snprintf(cmdline, len, "%s %s", file, args);
667 		mbi->mi_cmdline = (char *) vtophys(cmdline);
668 	}
669 
670 	/* pull in any modules if necessary */
671 	if (boot_modules_enabled) {
672 		module_init(file);
673 		if (btinfo_modulelist) {
674 			mbm = alloc(sizeof(struct multiboot_module) *
675 					   btinfo_modulelist->num);
676 
677 			bim = (struct bi_modulelist_entry *)
678 			  (((char *) btinfo_modulelist) +
679 			   sizeof(struct btinfo_modulelist));
680 			for (i = 0; i < btinfo_modulelist->num; i++) {
681 				mbm[i].mmo_start = bim->base;
682 				mbm[i].mmo_end = bim->base + bim->len;
683 				mbm[i].mmo_string = (char *)vtophys(bim->path);
684 				mbm[i].mmo_reserved = 0;
685 				bim++;
686 			}
687 			mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS;
688 			mbi->mi_mods_count = btinfo_modulelist->num;
689 			mbi->mi_mods_addr = vtophys(mbm);
690 		}
691 	}
692 
693 #ifdef DEBUG
694 	printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY],
695 	    marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]);
696 #endif
697 
698 
699 #if 0
700 	if (btinfo_symtab.nsym) {
701 		mbi->mi_flags |= MULTIBOOT_INFO_HAS_ELF_SYMS;
702 		mbi->mi_elfshdr_addr = marks[MARK_SYM];
703 	btinfo_symtab.nsym = marks[MARK_NSYM];
704 	btinfo_symtab.ssym = marks[MARK_SYM];
705 	btinfo_symtab.esym = marks[MARK_END];
706 #endif
707 
708 	multiboot(marks[MARK_ENTRY], vtophys(mbi),
709 		  x86_trunc_page(mbi->mi_mem_lower*1024));
710 	panic("exec returned");
711 
712 out:
713         dealloc(mbi, 0);
714 	return -1;
715 }
716 
717 void
718 x86_progress(const char *fmt, ...)
719 {
720 	va_list ap;
721 
722 	if ((howto & AB_SILENT) != 0)
723 		return;
724 	va_start(ap, fmt);
725 	vprintf(fmt, ap);
726 	va_end(ap);
727 }
728