exec.c revision 1.72
1/*	$NetBSD: exec.c,v 1.72 2019/06/24 13:58:24 pgoyette 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 a NetBSD ELF kernel. The low level startup is done in startprog.S.
92 * This is a special version of exec.c to support use of XMS.
93 */
94
95#include <sys/param.h>
96#include <sys/reboot.h>
97
98#include <i386/multiboot.h>
99
100#include <lib/libsa/stand.h>
101#include <lib/libkern/libkern.h>
102
103#include "loadfile.h"
104#include "libi386.h"
105#include "bootinfo.h"
106#include "bootmod.h"
107#include "vbe.h"
108#ifdef SUPPORT_PS2
109#include "biosmca.h"
110#endif
111#ifdef EFIBOOT
112#include "efiboot.h"
113#undef DEBUG	/* XXX */
114#endif
115
116#define BOOT_NARGS	6
117
118#ifndef	PAGE_SIZE
119#define	PAGE_SIZE	4096
120#endif
121
122#define MODULE_WARNING_SEC	5
123
124#define MAXMODNAME	32	/* from <sys/module.h> */
125
126extern struct btinfo_console btinfo_console;
127
128boot_module_t *boot_modules;
129bool boot_modules_enabled = true;
130bool kernel_loaded;
131
132typedef struct userconf_command {
133	char *uc_text;
134	size_t uc_len;
135	struct userconf_command *uc_next;
136} userconf_command_t;
137userconf_command_t *userconf_commands = NULL;
138
139static struct btinfo_framebuffer btinfo_framebuffer;
140
141static struct btinfo_modulelist *btinfo_modulelist;
142static size_t btinfo_modulelist_size;
143static uint32_t image_end;
144static char module_base[64] = "/";
145static int howto;
146
147static struct btinfo_userconfcommands *btinfo_userconfcommands = NULL;
148static size_t btinfo_userconfcommands_size = 0;
149
150static void	module_init(const char *);
151static void	module_add_common(const char *, uint8_t);
152
153static void	userconf_init(void);
154
155static void	extract_device(const char *, char *, size_t);
156static void	module_base_path(char *, size_t);
157static int	module_open(boot_module_t *, int, const char *, const char *,
158		    bool);
159
160void
161framebuffer_configure(struct btinfo_framebuffer *fb)
162{
163	if (fb)
164		btinfo_framebuffer = *fb;
165	else {
166		btinfo_framebuffer.physaddr = 0;
167		btinfo_framebuffer.flags = 0;
168	}
169}
170
171void
172module_add(char *name)
173{
174	return module_add_common(name, BM_TYPE_KMOD);
175}
176
177void
178splash_add(char *name)
179{
180	return module_add_common(name, BM_TYPE_IMAGE);
181}
182
183void
184rnd_add(char *name)
185{
186	return module_add_common(name, BM_TYPE_RND);
187}
188
189void
190fs_add(char *name)
191{
192	return module_add_common(name, BM_TYPE_FS);
193}
194
195/*
196 * Add a /-separated list of module names to the boot list
197 */
198void
199module_add_split(const char *name, uint8_t type)
200{
201	char mod_name[MAXMODNAME];
202	int i;
203	const char *mp = name;
204	char *ep;
205
206	while (*mp) {				/* scan list of module names */
207		i = MAXMODNAME;
208		ep = mod_name;
209		while (--i) {			/* scan for end of first name */
210			*ep = *mp;
211			if (*ep == '/')		/* NUL-terminate the name */
212				*ep = '\0';
213
214			if (*ep == 0 ) {	/* add non-empty name */
215				if (ep != mod_name)
216					module_add_common(mod_name, type);
217				break;
218			}
219			ep++; mp++;
220		}
221		if (*ep != 0) {
222			printf("module name too long\n");
223			return;
224		}
225		if  (*mp == '/') {		/* skip separator if more */
226			mp++;
227		}
228	}
229}
230
231static void
232module_add_common(const char *name, uint8_t type)
233{
234	boot_module_t *bm, *bmp;
235	size_t len;
236	char *str;
237
238	while (*name == ' ' || *name == '\t')
239		++name;
240
241	for (bm = boot_modules; bm != NULL; bm = bm->bm_next)
242		if (bm->bm_type == type && strcmp(bm->bm_path, name) == 0)
243			return;
244
245	bm = alloc(sizeof(boot_module_t));
246	len = strlen(name) + 1;
247	str = alloc(len);
248	if (bm == NULL || str == NULL) {
249		printf("couldn't allocate module\n");
250		return;
251	}
252	memcpy(str, name, len);
253	bm->bm_path = str;
254	bm->bm_next = NULL;
255	bm->bm_type = type;
256	if (boot_modules == NULL)
257		boot_modules = bm;
258	else {
259		for (bmp = boot_modules; bmp->bm_next;
260		    bmp = bmp->bm_next)
261			;
262		bmp->bm_next = bm;
263	}
264}
265
266void
267userconf_add(char *cmd)
268{
269	userconf_command_t *uc;
270	size_t len;
271	char *text;
272
273	while (*cmd == ' ' || *cmd == '\t')
274		++cmd;
275
276	uc = alloc(sizeof(*uc));
277	if (uc == NULL) {
278		printf("couldn't allocate command\n");
279		return;
280	}
281
282	len = strlen(cmd) + 1;
283	text = alloc(len);
284	if (text == NULL) {
285		dealloc(uc, sizeof(*uc));
286		printf("couldn't allocate command\n");
287		return;
288	}
289	memcpy(text, cmd, len);
290
291	uc->uc_text = text;
292	uc->uc_len = len;
293	uc->uc_next = NULL;
294
295	if (userconf_commands == NULL)
296		userconf_commands = uc;
297	else {
298		userconf_command_t *ucp;
299		for (ucp = userconf_commands; ucp->uc_next != NULL;
300		     ucp = ucp->uc_next)
301			;
302		ucp->uc_next = uc;
303	}
304}
305
306struct btinfo_prekern bi_prekern;
307int has_prekern = 0;
308
309static int
310common_load_prekern(const char *file, u_long *basemem, u_long *extmem,
311    physaddr_t loadaddr, int floppy, u_long marks[MARK_MAX])
312{
313	paddr_t kernpa_start, kernpa_end;
314	char prekernpath[] = "/prekern";
315	u_long prekern_start;
316	int fd, flags;
317
318	*extmem = getextmem();
319	*basemem = getbasemem();
320
321	marks[MARK_START] = loadaddr;
322
323	/* Load the prekern (static) */
324	flags = LOAD_KERNEL & ~(LOAD_HDR|LOAD_SYM);
325	if ((fd = loadfile(prekernpath, marks, flags)) == -1)
326		return EIO;
327	close(fd);
328
329	prekern_start = marks[MARK_START];
330
331	/* The kernel starts at 2MB. */
332	marks[MARK_START] = loadaddr;
333	marks[MARK_END] = loadaddr + (1UL << 21);
334	kernpa_start = (1UL << 21);
335
336	/* Load the kernel (dynamic) */
337	flags = (LOAD_KERNEL | LOAD_DYN) & ~(floppy ? LOAD_BACKWARDS : 0);
338	if ((fd = loadfile(file, marks, flags)) == -1)
339		return EIO;
340	close(fd);
341
342	kernpa_end = marks[MARK_END] - loadaddr;
343
344	/* If the root fs type is unusual, load its module. */
345	if (fsmod != NULL)
346		module_add_split(fsmod, BM_TYPE_KMOD);
347
348	bi_prekern.kernpa_start = kernpa_start;
349	bi_prekern.kernpa_end = kernpa_end;
350	BI_ADD(&bi_prekern, BTINFO_PREKERN, sizeof(struct btinfo_prekern));
351
352	/*
353	 * Gather some information for the kernel. Do this after the
354	 * "point of no return" to avoid memory leaks.
355	 * (but before DOS might be trashed in the XMS case)
356	 */
357#ifdef PASS_BIOSGEOM
358	bi_getbiosgeom();
359#endif
360#ifdef PASS_MEMMAP
361	bi_getmemmap();
362#endif
363
364	marks[MARK_START] = prekern_start;
365	marks[MARK_END] = (((u_long)marks[MARK_END] + sizeof(int) - 1)) &
366	    (-sizeof(int));
367	image_end = marks[MARK_END];
368	kernel_loaded = true;
369
370	return 0;
371}
372
373static int
374common_load_kernel(const char *file, u_long *basemem, u_long *extmem,
375    physaddr_t loadaddr, int floppy, u_long marks[MARK_MAX])
376{
377	int fd;
378#ifdef XMS
379	u_long xmsmem;
380	physaddr_t origaddr = loadaddr;
381#endif
382
383	*extmem = getextmem();
384	*basemem = getbasemem();
385
386#ifdef XMS
387	if ((getextmem1() == 0) && (xmsmem = checkxms())) {
388		u_long kernsize;
389
390		/*
391		 * With "CONSERVATIVE_MEMDETECT", extmem is 0 because
392		 * getextmem() is getextmem1(). Without, the "smart"
393		 * methods could fail to report all memory as well.
394		 * xmsmem is a few kB less than the actual size, but
395		 * better than nothing.
396		 */
397		if (xmsmem > *extmem)
398			*extmem = xmsmem;
399		/*
400		 * Get the size of the kernel
401		 */
402		marks[MARK_START] = loadaddr;
403		if ((fd = loadfile(file, marks, COUNT_KERNEL)) == -1)
404			return EIO;
405		close(fd);
406
407		kernsize = marks[MARK_END];
408		kernsize = (kernsize + 1023) / 1024;
409
410		loadaddr = xmsalloc(kernsize);
411		if (!loadaddr)
412			return ENOMEM;
413	}
414#endif
415	marks[MARK_START] = loadaddr;
416	if ((fd = loadfile(file, marks,
417	    LOAD_KERNEL & ~(floppy ? LOAD_BACKWARDS : 0))) == -1)
418		return EIO;
419
420	close(fd);
421
422	/* If the root fs type is unusual, load its module. */
423	if (fsmod != NULL)
424		module_add_split(fsmod, BM_TYPE_KMOD);
425
426	/*
427	 * Gather some information for the kernel. Do this after the
428	 * "point of no return" to avoid memory leaks.
429	 * (but before DOS might be trashed in the XMS case)
430	 */
431#ifdef PASS_BIOSGEOM
432	bi_getbiosgeom();
433#endif
434#ifdef PASS_MEMMAP
435	bi_getmemmap();
436#endif
437
438#ifdef XMS
439	if (loadaddr != origaddr) {
440		/*
441		 * We now have done our last DOS IO, so we may
442		 * trash the OS. Copy the data from the temporary
443		 * buffer to its real address.
444		 */
445		marks[MARK_START] -= loadaddr;
446		marks[MARK_END] -= loadaddr;
447		marks[MARK_SYM] -= loadaddr;
448		marks[MARK_END] -= loadaddr;
449		ppbcopy(loadaddr, origaddr, marks[MARK_END]);
450	}
451#endif
452	marks[MARK_END] = (((u_long) marks[MARK_END] + sizeof(int) - 1)) &
453	    (-sizeof(int));
454	image_end = marks[MARK_END];
455	kernel_loaded = true;
456
457	return 0;
458}
459
460int
461exec_netbsd(const char *file, physaddr_t loadaddr, int boothowto, int floppy,
462    void (*callback)(void))
463{
464	uint32_t boot_argv[BOOT_NARGS];
465	u_long marks[MARK_MAX];
466	struct btinfo_symtab btinfo_symtab;
467	u_long extmem;
468	u_long basemem;
469	int error;
470#ifdef EFIBOOT
471	int i;
472#endif
473
474#ifdef	DEBUG
475	printf("exec: file=%s loadaddr=0x%lx\n", file ? file : "NULL",
476	    loadaddr);
477#endif
478
479	BI_ALLOC(BTINFO_MAX);
480
481	BI_ADD(&btinfo_console, BTINFO_CONSOLE, sizeof(struct btinfo_console));
482
483	howto = boothowto;
484
485	memset(marks, 0, sizeof(marks));
486
487	if (has_prekern) {
488		error = common_load_prekern(file, &basemem, &extmem, loadaddr,
489		    floppy, marks);
490	} else {
491		error = common_load_kernel(file, &basemem, &extmem, loadaddr,
492		    floppy, marks);
493	}
494	if (error) {
495		errno = error;
496		goto out;
497	}
498#ifdef EFIBOOT
499	/* adjust to the real load address */
500	marks[MARK_START] -= efi_loadaddr;
501	marks[MARK_ENTRY] -= efi_loadaddr;
502	marks[MARK_DATA] -= efi_loadaddr;
503	/* MARK_NSYM */
504	marks[MARK_SYM] -= efi_loadaddr;
505	marks[MARK_END] -= efi_loadaddr;
506#endif
507
508	boot_argv[0] = boothowto;
509	boot_argv[1] = 0;
510	boot_argv[2] = vtophys(bootinfo);	/* old cyl offset */
511	boot_argv[3] = marks[MARK_END];
512	boot_argv[4] = extmem;
513	boot_argv[5] = basemem;
514
515	/* pull in any modules if necessary */
516	if (boot_modules_enabled) {
517		module_init(file);
518		if (btinfo_modulelist) {
519#ifdef EFIBOOT
520			/* convert module loaded address to paddr */
521			struct bi_modulelist_entry *bim;
522			bim = (void *)(btinfo_modulelist + 1);
523			for (i = 0; i < btinfo_modulelist->num; i++, bim++)
524				bim->base -= efi_loadaddr;
525			btinfo_modulelist->endpa -= efi_loadaddr;
526#endif
527			BI_ADD(btinfo_modulelist, BTINFO_MODULELIST,
528			    btinfo_modulelist_size);
529		}
530	}
531
532	userconf_init();
533	if (btinfo_userconfcommands != NULL)
534		BI_ADD(btinfo_userconfcommands, BTINFO_USERCONFCOMMANDS,
535		    btinfo_userconfcommands_size);
536
537#ifdef DEBUG
538	printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY],
539	    marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]);
540#endif
541
542	btinfo_symtab.nsym = marks[MARK_NSYM];
543	btinfo_symtab.ssym = marks[MARK_SYM];
544	btinfo_symtab.esym = marks[MARK_END];
545	BI_ADD(&btinfo_symtab, BTINFO_SYMTAB, sizeof(struct btinfo_symtab));
546
547	/* set new video mode if necessary */
548	vbe_commit();
549	BI_ADD(&btinfo_framebuffer, BTINFO_FRAMEBUFFER,
550	    sizeof(struct btinfo_framebuffer));
551
552	if (callback != NULL)
553		(*callback)();
554#ifdef EFIBOOT
555	/* Copy bootinfo to safe arena. */
556	for (i = 0; i < bootinfo->nentries; i++) {
557		struct btinfo_common *bi = (void *)(u_long)bootinfo->entry[i];
558		char *p = alloc(bi->len);
559		memcpy(p, bi, bi->len);
560		bootinfo->entry[i] = vtophys(p);
561	}
562
563	efi_kernel_start = marks[MARK_START];
564	efi_kernel_size = image_end - (efi_loadaddr + efi_kernel_start);
565#endif
566	startprog(marks[MARK_ENTRY], BOOT_NARGS, boot_argv,
567	    x86_trunc_page(basemem * 1024));
568	panic("exec returned");
569
570out:
571	BI_FREE();
572	bootinfo = NULL;
573	return -1;
574}
575
576int
577count_netbsd(const char *file, u_long *rsz)
578{
579	u_long marks[MARK_MAX];
580	char kdev[64];
581	char base_path[64] = "/";
582	struct stat st;
583	boot_module_t *bm;
584	u_long sz;
585	int err, fd;
586
587	if (has_prekern) {
588		/*
589		 * Hardcoded for now. Need to count both the prekern and the
590		 * kernel. 128MB is enough in all cases, so use that.
591		 */
592		*rsz = (128UL << 20);
593		return 0;
594	}
595
596	howto = AB_SILENT;
597
598	memset(marks, 0, sizeof(marks));
599	if ((fd = loadfile(file, marks, COUNT_KERNEL | LOAD_NOTE)) == -1)
600		return -1;
601	close(fd);
602	marks[MARK_END] = (((u_long) marks[MARK_END] + sizeof(int) - 1)) &
603	    (-sizeof(int));
604	sz = marks[MARK_END];
605
606	/* The modules must be allocated after the kernel */
607	if (boot_modules_enabled) {
608		extract_device(file, kdev, sizeof(kdev));
609		module_base_path(base_path, sizeof(base_path));
610
611		/* If the root fs type is unusual, load its module. */
612		if (fsmod != NULL)
613			module_add_split(fsmod, BM_TYPE_KMOD);
614
615		for (bm = boot_modules; bm; bm = bm->bm_next) {
616			fd = module_open(bm, 0, kdev, base_path, false);
617			if (fd == -1)
618				continue;
619			sz = (sz + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
620			err = fstat(fd, &st);
621			if (err == -1 || st.st_size == -1) {
622				close(fd);
623				continue;
624			}
625			sz += st.st_size;
626			close(fd);
627		}
628	}
629
630	*rsz = sz;
631	return 0;
632}
633
634static void
635extract_device(const char *path, char *buf, size_t buflen)
636{
637	size_t i;
638
639	if (strchr(path, ':') != NULL) {
640		for (i = 0; i < buflen - 2 && path[i] != ':'; i++)
641			buf[i] = path[i];
642		buf[i++] = ':';
643		buf[i] = '\0';
644	} else
645		buf[0] = '\0';
646}
647
648static const char *
649module_path(boot_module_t *bm, const char *kdev, const char *base_path)
650{
651	static char buf[256];
652	char name_buf[256], dev_buf[64];
653	const char *name, *name2, *p;
654
655	name = bm->bm_path;
656	for (name2 = name; *name2; ++name2) {
657		if (*name2 == ' ' || *name2 == '\t') {
658			strlcpy(name_buf, name, sizeof(name_buf));
659			if ((uintptr_t)name2 - (uintptr_t)name < sizeof(name_buf))
660				name_buf[name2 - name] = '\0';
661			name = name_buf;
662			break;
663		}
664	}
665	if ((p = strchr(name, ':')) != NULL) {
666		/* device specified, use it */
667		if (p[1] == '/')
668			snprintf(buf, sizeof(buf), "%s", name);
669		else {
670			p++;
671			extract_device(name, dev_buf, sizeof(dev_buf));
672			snprintf(buf, sizeof(buf), "%s%s/%s/%s.kmod",
673			    dev_buf, base_path, p, p);
674		}
675	} else {
676		/* device not specified; load from kernel device if known */
677		if (name[0] == '/')
678			snprintf(buf, sizeof(buf), "%s%s", kdev, name);
679		else
680			snprintf(buf, sizeof(buf), "%s%s/%s/%s.kmod",
681			    kdev, base_path, name, name);
682	}
683
684	return buf;
685}
686
687static int
688module_open(boot_module_t *bm, int mode, const char *kdev,
689    const char *base_path, bool doload)
690{
691	int fd;
692	const char *path;
693
694	/* check the expanded path first */
695	path = module_path(bm, kdev, base_path);
696	fd = open(path, mode);
697	if (fd != -1) {
698		if ((howto & AB_SILENT) == 0 && doload)
699			printf("Loading %s ", path);
700	} else {
701		/* now attempt the raw path provided */
702		fd = open(bm->bm_path, mode);
703		if (fd != -1 && (howto & AB_SILENT) == 0 && doload)
704			printf("Loading %s ", bm->bm_path);
705	}
706	if (!doload && fd == -1) {
707		printf("WARNING: couldn't open %s", bm->bm_path);
708		if (strcmp(bm->bm_path, path) != 0)
709			printf(" (%s)", path);
710		printf("\n");
711	}
712	return fd;
713}
714
715static void
716module_base_path(char *buf, size_t bufsize)
717{
718	const char *machine;
719
720	switch (netbsd_elf_class) {
721	case ELFCLASS32:
722		machine = "i386";
723		break;
724	case ELFCLASS64:
725		machine = "amd64";
726		break;
727	default:
728		machine = "generic";
729		break;
730	}
731	if (netbsd_version / 1000000 % 100 == 99) {
732		/* -current */
733		snprintf(buf, bufsize,
734		    "/stand/%s/%d.%d.%d/modules", machine,
735		    netbsd_version / 100000000,
736		    netbsd_version / 1000000 % 100,
737		    netbsd_version / 100 % 100);
738	} else if (netbsd_version != 0) {
739		/* release */
740		snprintf(buf, bufsize,
741		    "/stand/%s/%d.%d/modules", machine,
742		    netbsd_version / 100000000,
743		    netbsd_version / 1000000 % 100);
744	}
745}
746
747static void
748module_init(const char *kernel_path)
749{
750	struct bi_modulelist_entry *bi;
751	struct stat st;
752	char kdev[64];
753	char *buf;
754	boot_module_t *bm;
755	ssize_t len;
756	off_t off;
757	int err, fd, nfail = 0;
758
759	extract_device(kernel_path, kdev, sizeof(kdev));
760	module_base_path(module_base, sizeof(module_base));
761
762	/* First, see which modules are valid and calculate btinfo size */
763	len = sizeof(struct btinfo_modulelist);
764	for (bm = boot_modules; bm; bm = bm->bm_next) {
765		fd = module_open(bm, 0, kdev, module_base, false);
766		if (fd == -1) {
767			bm->bm_len = -1;
768			++nfail;
769			continue;
770		}
771		err = fstat(fd, &st);
772		if (err == -1 || st.st_size == -1) {
773			printf("WARNING: couldn't stat %s\n", bm->bm_path);
774			close(fd);
775			bm->bm_len = -1;
776			++nfail;
777			continue;
778		}
779		bm->bm_len = st.st_size;
780		close(fd);
781		len += sizeof(struct bi_modulelist_entry);
782	}
783
784	/* Allocate the module list */
785	btinfo_modulelist = alloc(len);
786	if (btinfo_modulelist == NULL) {
787		printf("WARNING: couldn't allocate module list\n");
788		wait_sec(MODULE_WARNING_SEC);
789		return;
790	}
791	memset(btinfo_modulelist, 0, len);
792	btinfo_modulelist_size = len;
793
794	/* Fill in btinfo structure */
795	buf = (char *)btinfo_modulelist;
796	btinfo_modulelist->num = 0;
797	off = sizeof(struct btinfo_modulelist);
798
799	for (bm = boot_modules; bm; bm = bm->bm_next) {
800		if (bm->bm_len == -1)
801			continue;
802		fd = module_open(bm, 0, kdev, module_base, true);
803		if (fd == -1)
804			continue;
805		image_end = (image_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
806		len = pread(fd, (void *)(uintptr_t)image_end, SSIZE_MAX);
807		if (len < bm->bm_len) {
808			if ((howto & AB_SILENT) != 0)
809				printf("Loading %s ", bm->bm_path);
810			printf(" FAILED\n");
811		} else {
812			btinfo_modulelist->num++;
813			bi = (struct bi_modulelist_entry *)(buf + off);
814			off += sizeof(struct bi_modulelist_entry);
815			strncpy(bi->path, bm->bm_path, sizeof(bi->path) - 1);
816			bi->base = image_end;
817			bi->len = len;
818			switch (bm->bm_type) {
819			    case BM_TYPE_KMOD:
820				bi->type = BI_MODULE_ELF;
821				break;
822			    case BM_TYPE_IMAGE:
823				bi->type = BI_MODULE_IMAGE;
824				break;
825			    case BM_TYPE_FS:
826				bi->type = BI_MODULE_FS;
827				break;
828			    case BM_TYPE_RND:
829			    default:
830				/* safest -- rnd checks the sha1 */
831				bi->type = BI_MODULE_RND;
832				break;
833			}
834			if ((howto & AB_SILENT) == 0)
835				printf(" \n");
836		}
837		if (len > 0)
838			image_end += len;
839		close(fd);
840	}
841	btinfo_modulelist->endpa = image_end;
842
843	if (nfail > 0) {
844		printf("WARNING: %d module%s failed to load\n",
845		    nfail, nfail == 1 ? "" : "s");
846#if notyet
847		wait_sec(MODULE_WARNING_SEC);
848#endif
849	}
850}
851
852static void
853userconf_init(void)
854{
855	size_t count, len;
856	userconf_command_t *uc;
857	char *buf;
858	off_t off;
859
860	/* Calculate the userconf commands list size */
861	count = 0;
862	for (uc = userconf_commands; uc != NULL; uc = uc->uc_next)
863		count++;
864	len = sizeof(*btinfo_userconfcommands) +
865	      count * sizeof(struct bi_userconfcommand);
866
867	/* Allocate the userconf commands list */
868	btinfo_userconfcommands = alloc(len);
869	if (btinfo_userconfcommands == NULL) {
870		printf("WARNING: couldn't allocate userconf commands list\n");
871		return;
872	}
873	memset(btinfo_userconfcommands, 0, len);
874	btinfo_userconfcommands_size = len;
875
876	/* Fill in btinfo structure */
877	buf = (char *)btinfo_userconfcommands;
878	off = sizeof(*btinfo_userconfcommands);
879	btinfo_userconfcommands->num = 0;
880	for (uc = userconf_commands; uc != NULL; uc = uc->uc_next) {
881		struct bi_userconfcommand *bi;
882		bi = (struct bi_userconfcommand *)(buf + off);
883		strncpy(bi->text, uc->uc_text, sizeof(bi->text) - 1);
884
885		off += sizeof(*bi);
886		btinfo_userconfcommands->num++;
887	}
888}
889
890int
891exec_multiboot(const char *file, char *args)
892{
893	struct multiboot_info *mbi;
894	struct multiboot_module *mbm;
895	struct bi_modulelist_entry *bim;
896	int i, len;
897	u_long marks[MARK_MAX];
898	u_long extmem;
899	u_long basemem;
900	char *cmdline;
901
902	mbi = alloc(sizeof(struct multiboot_info));
903	mbi->mi_flags = MULTIBOOT_INFO_HAS_MEMORY;
904
905	if (common_load_kernel(file, &basemem, &extmem, 0, 0, marks))
906		goto out;
907
908	mbi->mi_mem_upper = extmem;
909	mbi->mi_mem_lower = basemem;
910
911	if (args) {
912		mbi->mi_flags |= MULTIBOOT_INFO_HAS_CMDLINE;
913		len = strlen(file) + 1 + strlen(args) + 1;
914		cmdline = alloc(len);
915		snprintf(cmdline, len, "%s %s", file, args);
916		mbi->mi_cmdline = (char *) vtophys(cmdline);
917	}
918
919	/* pull in any modules if necessary */
920	if (boot_modules_enabled) {
921		module_init(file);
922		if (btinfo_modulelist) {
923			mbm = alloc(sizeof(struct multiboot_module) *
924					   btinfo_modulelist->num);
925
926			bim = (struct bi_modulelist_entry *)
927			  (((char *) btinfo_modulelist) +
928			   sizeof(struct btinfo_modulelist));
929			for (i = 0; i < btinfo_modulelist->num; i++) {
930				mbm[i].mmo_start = bim->base;
931				mbm[i].mmo_end = bim->base + bim->len;
932				mbm[i].mmo_string = (char *)vtophys(bim->path);
933				mbm[i].mmo_reserved = 0;
934				bim++;
935			}
936			mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS;
937			mbi->mi_mods_count = btinfo_modulelist->num;
938			mbi->mi_mods_addr = vtophys(mbm);
939		}
940	}
941
942#ifdef DEBUG
943	printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY],
944	    marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]);
945#endif
946
947#if 0
948	if (btinfo_symtab.nsym) {
949		mbi->mi_flags |= MULTIBOOT_INFO_HAS_ELF_SYMS;
950		mbi->mi_elfshdr_addr = marks[MARK_SYM];
951	btinfo_symtab.nsym = marks[MARK_NSYM];
952	btinfo_symtab.ssym = marks[MARK_SYM];
953	btinfo_symtab.esym = marks[MARK_END];
954#endif
955
956	multiboot(marks[MARK_ENTRY], vtophys(mbi),
957	    x86_trunc_page(mbi->mi_mem_lower * 1024));
958	panic("exec returned");
959
960out:
961	dealloc(mbi, 0);
962	return -1;
963}
964
965void
966x86_progress(const char *fmt, ...)
967{
968	va_list ap;
969
970	if ((howto & AB_SILENT) != 0)
971		return;
972	va_start(ap, fmt);
973	vprintf(fmt, ap);
974	va_end(ap);
975}
976