Home | History | Annotate | Line # | Download | only in dev
kloader.c revision 1.16
      1 /*	$NetBSD: kloader.c,v 1.16 2008/03/21 21:54:59 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001, 2002, 2004 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  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *        This product includes software developed by the NetBSD
     18  *        Foundation, Inc. and its contributors.
     19  * 4. Neither the name of The NetBSD Foundation nor the names of its
     20  *    contributors may be used to endorse or promote products derived
     21  *    from this software without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33  * POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: kloader.c,v 1.16 2008/03/21 21:54:59 ad Exp $");
     38 
     39 #include "debug_kloader.h"
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/malloc.h>
     44 #include <sys/proc.h>
     45 #include <sys/vnode.h>
     46 #include <sys/namei.h>
     47 #include <sys/fcntl.h>
     48 #define	ELFSIZE	32
     49 #include <sys/exec_elf.h>
     50 
     51 #include <uvm/uvm_extern.h>
     52 
     53 #include <machine/kloader.h>
     54 
     55 #define	PRINTF(fmt, args...)	printf("kloader: " fmt, ##args)
     56 
     57 #ifdef KLOADER_DEBUG
     58 int	kloader_debug = 1;
     59 #define	DPRINTF(fmt, args...)						\
     60 	if (kloader_debug)						\
     61 		printf("%s: " fmt, __func__ , ##args)
     62 #define	_DPRINTF(fmt, args...)						\
     63 	if (kloader_debug)						\
     64 		printf(fmt, ##args)
     65 #define	DPRINTFN(n, fmt, args...)					\
     66 	if (kloader_debug > (n))					\
     67 		printf("%s: " fmt, __func__ , ##args)
     68 #define	_DPRINTFN(n, fmt, args...)					\
     69 	if (kloader_debug > (n))					\
     70 		printf(fmt, ##args)
     71 #define	STATIC
     72 #else
     73 #define	DPRINTF(fmt, args...)		((void)0)
     74 #define	_DPRINTF(fmt, args...)		((void)0)
     75 #define	DPRINTFN(n, fmt, args...)	((void)0)
     76 #define	_DPRINTFN(n, fmt, args...)	((void)0)
     77 #define	STATIC	static
     78 #endif
     79 
     80 struct kloader {
     81 	struct pglist pg_head;
     82 	struct vm_page *cur_pg;
     83 	struct kloader_page_tag *cur_tag;
     84 	struct vnode *vp;
     85 	struct kloader_page_tag *tagstart;
     86 	struct kloader_bootinfo *bootinfo;
     87 	struct kloader_bootinfo *rebootinfo;
     88 	vaddr_t loader_sp;
     89 	kloader_bootfunc_t *loader;
     90 	int setuped;
     91 	int called;
     92 	struct kloader_ops *ops;
     93 };
     94 
     95 #define	BUCKET_SIZE	(PAGE_SIZE - sizeof(struct kloader_page_tag))
     96 #define	KLOADER_LWP	(&lwp0)
     97 STATIC struct kloader kloader;
     98 
     99 #define	ROUND4(x)	(((x) + 3) & ~3)
    100 
    101 STATIC int kloader_load(void);
    102 
    103 STATIC int kloader_alloc_memory(size_t);
    104 STATIC struct kloader_page_tag *kloader_get_tag(vaddr_t);
    105 STATIC void kloader_from_file(vaddr_t, off_t, size_t);
    106 STATIC void kloader_copy(vaddr_t, const void *, size_t);
    107 STATIC void kloader_zero(vaddr_t, size_t);
    108 
    109 STATIC void kloader_load_segment(Elf_Phdr *);
    110 
    111 STATIC struct vnode *kloader_open(const char *);
    112 STATIC void kloader_close(void);
    113 STATIC int kloader_read(size_t, size_t, void *);
    114 
    115 #ifdef KLOADER_DEBUG
    116 STATIC void kloader_pagetag_dump(void);
    117 #endif
    118 
    119 void
    120 __kloader_reboot_setup(struct kloader_ops *ops, const char *filename)
    121 {
    122 
    123 	if (kloader.bootinfo == NULL) {
    124 		PRINTF("No bootinfo.\n");
    125 		return;
    126 	}
    127 
    128 	if (ops == NULL || ops->jump == NULL || ops->boot == NULL) {
    129 		PRINTF("No boot operations.\n");
    130 		return;
    131 	}
    132 	kloader.ops = ops;
    133 
    134 	if (kloader.called++ == 0) {
    135 		PRINTF("kernel file name: %s\n", filename);
    136 		kloader.vp = kloader_open(filename);
    137 		if (kloader.vp == NULL)
    138 			return;
    139 
    140 		if (kloader_load() == 0) {
    141 			kloader.setuped = TRUE;
    142 #ifdef KLOADER_DEBUG
    143 			kloader_pagetag_dump();
    144 #endif
    145 		}
    146 		kloader_close();
    147 	} else {
    148 		/* Fatal case. reboot from DDB etc. */
    149 		kloader_reboot();
    150 	}
    151 }
    152 
    153 
    154 void
    155 kloader_reboot()
    156 {
    157 
    158 	if (kloader.setuped) {
    159 		PRINTF("Rebooting...\n");
    160 		(*kloader.ops->jump)(kloader.loader, kloader.loader_sp,
    161 		    kloader.rebootinfo, kloader.tagstart);
    162 	}
    163 
    164 	if (kloader.ops->reset != NULL) {
    165 		PRINTF("Resetting...\n");
    166 		(*kloader.ops->reset)();
    167 	}
    168 	while (/*CONSTCOND*/1)
    169 		;
    170 	/* NOTREACHED */
    171 }
    172 
    173 
    174 int
    175 kloader_load()
    176 {
    177 	Elf_Ehdr eh;
    178 	Elf_Phdr *ph, *p;
    179 	Elf_Shdr *sh;
    180 	Elf_Addr entry;
    181 	vaddr_t kv;
    182 	size_t sz;
    183 	size_t shstrsz;
    184 	char *shstrtab;
    185 	int symndx, strndx;
    186 	size_t ksymsz;
    187 	struct kloader_bootinfo nbi; /* new boot info */
    188 	char *oldbuf, *newbuf;
    189 	char **ap;
    190 	int i;
    191 
    192 	ph = NULL;
    193 	sh = NULL;
    194 	shstrtab = NULL;
    195 
    196 	/* read kernel's ELF header */
    197 	kloader_read(0, sizeof(Elf_Ehdr), &eh);
    198 
    199 	if (eh.e_ident[EI_MAG0] != ELFMAG0 ||
    200 	    eh.e_ident[EI_MAG1] != ELFMAG1 ||
    201 	    eh.e_ident[EI_MAG2] != ELFMAG2 ||
    202 	    eh.e_ident[EI_MAG3] != ELFMAG3) {
    203 		PRINTF("not an ELF file\n");
    204 		goto err;
    205 	}
    206 
    207 	/* read program headers */
    208 	sz = eh.e_phentsize * eh.e_phnum;
    209 	if ((ph = malloc(sz, M_TEMP, M_NOWAIT)) == NULL) {
    210 		PRINTF("can't allocate program header table.\n");
    211 		goto err;
    212 	}
    213 	if (kloader_read(eh.e_phoff, sz, ph) != 0) {
    214 		PRINTF("program header read error.\n");
    215 		goto err;
    216 	}
    217 
    218 	/* read section headers */
    219 	sz = eh.e_shentsize * eh.e_shnum;
    220 	if ((sh = malloc(sz, M_TEMP, M_NOWAIT)) == NULL) {
    221 		PRINTF("can't allocate section header table.\n");
    222 		goto err;
    223 	}
    224 	if (kloader_read(eh.e_shoff, eh.e_shentsize * eh.e_shnum, sh) != 0) {
    225 		PRINTF("section header read error.\n");
    226 		goto err;
    227 	}
    228 
    229 	/* read section names */
    230 	shstrsz = ROUND4(sh[eh.e_shstrndx].sh_size);
    231 	shstrtab = malloc(shstrsz, M_TEMP, M_NOWAIT);
    232 	if (shstrtab == NULL) {
    233 		PRINTF("unable to allocate memory for .shstrtab\n");
    234 		goto err;
    235 	}
    236 	DPRINTF("reading 0x%x bytes of .shstrtab at 0x%x\n",
    237 		sh[eh.e_shstrndx].sh_size, sh[eh.e_shstrndx].sh_offset);
    238 	kloader_read(sh[eh.e_shstrndx].sh_offset, sh[eh.e_shstrndx].sh_size,
    239 		     shstrtab);
    240 
    241 	/* save entry point, code to construct symbol table overwrites it */
    242 	entry = eh.e_entry;
    243 
    244 
    245 	/*
    246 	 * Calculate memory size
    247 	 */
    248 	sz = 0;
    249 
    250 	/* loadable segments */
    251 	for (i = 0; i < eh.e_phnum; i++) {
    252 		if (ph[i].p_type == PT_LOAD) {
    253 			DPRINTF("segment %d size = file 0x%x memory 0x%x\n",
    254 				i, ph[i].p_filesz, ph[i].p_memsz);
    255 #ifdef KLOADER_ZERO_BSS
    256 			sz += round_page(ph[i].p_memsz);
    257 #else
    258 			sz += round_page(ph[i].p_filesz);
    259 #endif
    260 			sz += PAGE_SIZE; /* compensate for partial last tag */
    261 		}
    262 	}
    263 
    264 	if (sz == 0)		/* nothing to load? */
    265 		goto err;
    266 
    267 	/* symbols/strings sections */
    268 	symndx = strndx = -1;
    269 	for (i = 0; i < eh.e_shnum; i++) {
    270 	    if (strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0)
    271 		    symndx = i;
    272 	    else if (strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0)
    273 		    strndx = i;
    274 	    else if (i != eh.e_shstrndx)
    275 		    /* while here, mark all other sections as unused */
    276 		    sh[i].sh_type = SHT_NULL;
    277 	}
    278 
    279 	if (symndx < 0 || strndx < 0) {
    280 		if (symndx < 0)
    281 			PRINTF("no .symtab section\n");
    282 		if (strndx < 0)
    283 			PRINTF("no .strtab section\n");
    284 		ksymsz = SELFMAG; /* just a bad magic */
    285 	} else {
    286 		ksymsz = sizeof(Elf_Ehdr)
    287 			+ eh.e_shentsize * eh.e_shnum
    288 			+ shstrsz		/* rounded to 4 bytes */
    289 			+ sh[symndx].sh_size
    290 			+ sh[strndx].sh_size;
    291 		DPRINTF("ksyms size = 0x%zx\n", ksymsz);
    292 	}
    293 	sz += ROUND4(ksymsz);
    294 
    295 	/* boot info for the new kernel */
    296 	sz += sizeof(struct kloader_bootinfo);
    297 
    298 	/* get memory for new kernel */
    299 	if (kloader_alloc_memory(sz) != 0)
    300 		goto err;
    301 
    302 
    303 	/*
    304 	 * Copy new kernel in.
    305 	 */
    306 	kv = 0;			/* XXX: -Wuninitialized */
    307 	for (i = 0, p = ph; i < eh.e_phnum; i++, p++) {
    308 		if (p->p_type == PT_LOAD) {
    309 			kloader_load_segment(p);
    310 			kv = p->p_vaddr + ROUND4(p->p_memsz);
    311 		}
    312 	}
    313 
    314 
    315 	/*
    316 	 * Construct symbol table for ksyms.
    317 	 */
    318 	if (symndx < 0 || strndx < 0) {
    319 		kloader_zero(kv, SELFMAG);
    320 		kv += SELFMAG;
    321 	} else {
    322 		Elf_Off eoff;
    323 		off_t symoff, stroff;
    324 
    325 		/* save offsets of .symtab and .strtab before we change them */
    326 		symoff = sh[symndx].sh_offset;
    327 		stroff = sh[strndx].sh_offset;
    328 
    329 		/* no loadable segments */
    330 		eh.e_entry = 0;
    331 		eh.e_phnum = 0;
    332 		eh.e_phoff = 0;
    333 
    334 		/* change offsets to reflect new layout */
    335 		eoff = sizeof(Elf_Ehdr);
    336 		eh.e_shoff = eoff;
    337 
    338 		eoff += eh.e_shentsize * eh.e_shnum;
    339 		sh[eh.e_shstrndx].sh_offset = eoff;
    340 
    341 		eoff += shstrsz;
    342 		sh[symndx].sh_offset = eoff;
    343 
    344 		eoff += sh[symndx].sh_size;
    345 		sh[strndx].sh_offset = eoff;
    346 
    347 		/* local copies massaged, can serve them now */
    348 		DPRINTF("ksyms ELF header\n");
    349 		kloader_copy(kv, &eh, sizeof(Elf_Ehdr));
    350 		kv += sizeof(Elf_Ehdr);
    351 
    352 		DPRINTF("ksyms section headers\n");
    353 		kloader_copy(kv, sh, eh.e_shentsize * eh.e_shnum);
    354 		kv += eh.e_shentsize * eh.e_shnum;
    355 
    356 		DPRINTF("ksyms .shstrtab\n");
    357 		kloader_copy(kv, shstrtab, shstrsz);
    358 		kv += shstrsz;
    359 
    360 		DPRINTF("ksyms .symtab\n");
    361 		kloader_from_file(kv, symoff, sh[symndx].sh_size);
    362 		kv += sh[symndx].sh_size;
    363 
    364 		DPRINTF("ksyms .strtab\n");
    365 		kloader_from_file(kv, stroff, ROUND4(sh[strndx].sh_size));
    366 		kv += ROUND4(sh[strndx].sh_size);
    367 	}
    368 
    369 	/*
    370 	 * Create boot info to pass to the new kernel.
    371 	 * All pointers in it are *not* valid until the new kernel runs!
    372 	 */
    373 
    374 	/* get a private copy of current bootinfo to vivisect */
    375 	memcpy(&nbi, kloader.bootinfo,
    376 	       sizeof(struct kloader_bootinfo));
    377 
    378 	/* new kernel entry point */
    379 	nbi.entry = entry;
    380 
    381 	/* where args currently are, see kloader_bootinfo_set() */
    382 	oldbuf = &kloader.bootinfo->_argbuf[0];
    383 
    384 	/* where args *will* be after boot code copied them */
    385 	newbuf = (char *)(void *)kv
    386 		+ offsetof(struct kloader_bootinfo, _argbuf);
    387 
    388 	DPRINTF("argv: old %p -> new %p\n", oldbuf, newbuf);
    389 
    390 	/* not a valid pointer in this kernel! */
    391 	nbi.argv = (void *)newbuf;
    392 
    393 	/* local copy that we populate with new (not yet valid) pointers */
    394 	ap = (char **)(void *)nbi._argbuf;
    395 
    396 	for (i = 0; i < kloader.bootinfo->argc; ++i) {
    397 		DPRINTFN(1, " [%d]: %p -> ", i, kloader.bootinfo->argv[i]);
    398 		ap[i] = newbuf +
    399 			(kloader.bootinfo->argv[i] - oldbuf);
    400 		_DPRINTFN(1, "%p\n", ap[i]);
    401 	}
    402 
    403 	/* arrange for the new bootinfo to get copied */
    404 	DPRINTF("bootinfo\n");
    405 	kloader_copy(kv, &nbi, sizeof(struct kloader_bootinfo));
    406 
    407 	/* will be valid by the time the new kernel starts */
    408 	kloader.rebootinfo = (void *)kv;
    409 	/* kv += sizeof(struct kloader_bootinfo); */
    410 
    411 	/*
    412 	 * Copy loader code
    413 	 */
    414 	KDASSERT(kloader.cur_pg);
    415 	kloader.loader = (void *)PG_VADDR(kloader.cur_pg);
    416 	memcpy(kloader.loader, kloader.ops->boot, PAGE_SIZE);
    417 
    418 	/* loader stack starts at the bottom of that page */
    419 	kloader.loader_sp = (vaddr_t)kloader.loader + PAGE_SIZE;
    420 
    421 	DPRINTF("[loader] addr=%p sp=%p [kernel] entry=%p\n",
    422 		kloader.loader, (void *)kloader.loader_sp, (void *)nbi.entry);
    423 
    424 	return (0);
    425  err:
    426 	if (ph != NULL)
    427 		free(ph, M_TEMP);
    428 	if (sh != NULL)
    429 		free(sh, M_TEMP);
    430 	if (shstrtab != NULL)
    431 		free(shstrtab, M_TEMP);
    432 
    433 	return 1;
    434 }
    435 
    436 
    437 int
    438 kloader_alloc_memory(size_t sz)
    439 {
    440 	extern paddr_t avail_start, avail_end;
    441 	int n, error;
    442 
    443 	n = (sz + BUCKET_SIZE - 1) / BUCKET_SIZE	/* kernel &co */
    444 	    + 1;					/* 2nd loader */
    445 
    446 	error = uvm_pglistalloc(n * PAGE_SIZE, avail_start, avail_end,
    447 				PAGE_SIZE, 0, &kloader.pg_head, n, 0);
    448 	if (error) {
    449 		PRINTF("can't allocate memory.\n");
    450 		return (1);
    451 	}
    452 	DPRINTF("allocated %d pages.\n", n);
    453 
    454 	kloader.cur_pg = TAILQ_FIRST(&kloader.pg_head);
    455 	kloader.tagstart = (void *)PG_VADDR(kloader.cur_pg);
    456 	kloader.cur_tag = NULL;
    457 
    458 	return (0);
    459 }
    460 
    461 
    462 struct kloader_page_tag *
    463 kloader_get_tag(vaddr_t dst)
    464 {
    465 	struct vm_page *pg;
    466 	vaddr_t addr;
    467 	struct kloader_page_tag *tag;
    468 
    469 	tag = kloader.cur_tag;
    470 	if (tag != NULL		/* has tag */
    471 	    && tag->sz < BUCKET_SIZE /* that has free space */
    472 	    && tag->dst + tag->sz == dst) /* and new data are contiguous */
    473 	{
    474 		DPRINTFN(1, "current tag %x/%x ok\n", tag->dst, tag->sz);
    475 		return (tag);
    476 	}
    477 
    478 	pg = kloader.cur_pg;
    479 	KDASSERT(pg != NULL);
    480 	kloader.cur_pg = TAILQ_NEXT(pg, pageq);
    481 
    482 	addr = PG_VADDR(pg);
    483 	tag = (void *)addr;
    484 
    485 	/*
    486 	 * 2nd loader uses simple word-by-word copy, so destination
    487 	 * address of a tag must be properly aligned.
    488 	 */
    489 	KASSERT(ALIGNED_POINTER(dst, register_t));
    490 
    491 	tag->src = addr + sizeof(struct kloader_page_tag);
    492 	tag->dst = dst;
    493 	tag->sz = 0;
    494 	tag->next = 0;	/* Terminate. this member may overwrite after. */
    495 	if (kloader.cur_tag)
    496 		kloader.cur_tag->next = addr;
    497 	kloader.cur_tag = tag;
    498 
    499 	return (tag);
    500 }
    501 
    502 
    503 /*
    504  * Operations to populate kloader_page_tag's with data.
    505  */
    506 
    507 void
    508 kloader_from_file(vaddr_t dst, off_t ofs, size_t sz)
    509 {
    510 	struct kloader_page_tag *tag;
    511 	size_t freesz;
    512 
    513 	while (sz > 0) {
    514 		tag = kloader_get_tag(dst);
    515 		KDASSERT(tag != NULL);
    516 		freesz = BUCKET_SIZE - tag->sz;
    517 		if (freesz > sz)
    518 			freesz = sz;
    519 
    520 		DPRINTFN(1, "0x%08lx + 0x%zx <- 0x%lx\n", dst, freesz,
    521 		    (unsigned long)ofs);
    522 		kloader_read(ofs, freesz, (void *)(tag->src + tag->sz));
    523 
    524 		tag->sz += freesz;
    525 		sz -= freesz;
    526 		ofs += freesz;
    527 		dst += freesz;
    528 	}
    529 }
    530 
    531 
    532 void
    533 kloader_copy(vaddr_t dst, const void *src, size_t sz)
    534 {
    535 	struct kloader_page_tag *tag;
    536 	size_t freesz;
    537 
    538 	while (sz > 0) {
    539 		tag = kloader_get_tag(dst);
    540 		KDASSERT(tag != NULL);
    541 		freesz = BUCKET_SIZE - tag->sz;
    542 		if (freesz > sz)
    543 			freesz = sz;
    544 
    545 		DPRINTFN(1, "0x%08lx + 0x%zx <- %p\n", dst, freesz, src);
    546 		memcpy((void *)(tag->src + tag->sz), src, freesz);
    547 
    548 		tag->sz += freesz;
    549 		sz -= freesz;
    550 		src = (const char *)src + freesz;
    551 		dst += freesz;
    552 	}
    553 }
    554 
    555 
    556 void
    557 kloader_zero(vaddr_t dst, size_t sz)
    558 {
    559 	struct kloader_page_tag *tag;
    560 	size_t freesz;
    561 
    562 	while (sz > 0) {
    563 		tag = kloader_get_tag(dst);
    564 		KDASSERT(tag != NULL);
    565 		freesz = BUCKET_SIZE - tag->sz;
    566 		if (freesz > sz)
    567 			freesz = sz;
    568 
    569 		DPRINTFN(1, "0x%08lx + 0x%zx\n", dst, freesz);
    570 		memset((void *)(tag->src + tag->sz), 0, freesz);
    571 
    572 		tag->sz += freesz;
    573 		sz -= freesz;
    574 		dst += freesz;
    575 	}
    576 }
    577 
    578 
    579 void
    580 kloader_load_segment(Elf_Phdr *p)
    581 {
    582 
    583 	DPRINTF("memory 0x%08x 0x%x <- file 0x%x 0x%x\n",
    584 		p->p_vaddr, p->p_memsz, p->p_offset, p->p_filesz);
    585 
    586 	kloader_from_file(p->p_vaddr, p->p_offset, p->p_filesz);
    587 #ifdef KLOADER_ZERO_BSS
    588 	kloader_zero(p->p_vaddr + p->p_filesz, p->p_memsz - p->p_filesz);
    589 #endif
    590 }
    591 
    592 
    593 /*
    594  * file access
    595  */
    596 struct vnode *
    597 kloader_open(const char *filename)
    598 {
    599 	struct nameidata nid;
    600 	int error;
    601 
    602 	NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, filename);
    603 
    604 	error = namei(&nid);
    605 	if (error != 0) {
    606 		PRINTF("%s: namei failed, errno=%d\n", filename, error);
    607 		return (NULL);
    608 	}
    609 
    610 	error = vn_open(&nid, FREAD, 0);
    611 	if (error != 0) {
    612 		PRINTF("%s: open failed, errno=%d\n", filename, error);
    613 		return (NULL);
    614 	}
    615 
    616 	return (nid.ni_vp);
    617 }
    618 
    619 void
    620 kloader_close()
    621 {
    622 	struct lwp *l = KLOADER_LWP;
    623 	struct vnode *vp = kloader.vp;
    624 
    625 	VOP_UNLOCK(vp, 0);
    626 	vn_close(vp, FREAD, l->l_cred);
    627 }
    628 
    629 int
    630 kloader_read(size_t ofs, size_t size, void *buf)
    631 {
    632 	struct lwp *l = KLOADER_LWP;
    633 	struct vnode *vp = kloader.vp;
    634 	size_t resid;
    635 	int error;
    636 
    637 	error = vn_rdwr(UIO_READ, vp, buf, size, ofs, UIO_SYSSPACE,
    638 	    IO_NODELOCKED | IO_SYNC, l->l_cred, &resid, NULL);
    639 
    640 	if (error)
    641 		PRINTF("read error.\n");
    642 
    643 	return (error);
    644 }
    645 
    646 
    647 /*
    648  * bootinfo
    649  */
    650 void
    651 kloader_bootinfo_set(struct kloader_bootinfo *kbi, int argc, char *argv[],
    652     struct bootinfo *bi, int printok)
    653 {
    654 	char *p, *pend, *buf;
    655 	int i;
    656 
    657 	kloader.bootinfo = kbi;
    658 	buf = kbi->_argbuf;
    659 	if (bi != NULL)
    660 		memcpy(&kbi->bootinfo, bi, sizeof(struct bootinfo));
    661 	kbi->argc = argc;
    662 	kbi->argv = (char **)buf;
    663 
    664 	p = &buf[argc * sizeof(char **)];
    665 	pend = &buf[KLOADER_KERNELARGS_MAX - 1];
    666 
    667 	for (i = 0; i < argc; i++) {
    668 		char *q = argv[i];
    669 		int len = strlen(q) + 1;
    670 		if ((p + len) > pend) {
    671 			kloader.bootinfo = NULL;
    672 			if (printok)
    673 				PRINTF("buffer insufficient.\n");
    674 			return;
    675 		}
    676 		kbi->argv[i] = p;
    677 		memcpy(p, q, len);
    678 		p += len;
    679 	}
    680 }
    681 
    682 
    683 #ifdef KLOADER_DEBUG
    684 void
    685 kloader_pagetag_dump()
    686 {
    687 	struct kloader_page_tag *tag = kloader.tagstart;
    688 	struct kloader_page_tag *p, *op;
    689 	bool print;
    690 	int i, n;
    691 
    692 	p = tag;
    693 	op = NULL;
    694 	i = 0, n = 15;
    695 
    696 	PRINTF("[page tag chain]\n");
    697 	do  {
    698 		print = FALSE;
    699 		if (i < n)
    700 			print = TRUE;
    701 		if ((uint32_t)p & 3) {
    702 			printf("tag alignment error\n");
    703 			break;
    704 		}
    705 		if ((p->src & 3) || (p->dst & 3)) {
    706 			printf("data alignement error.\n");
    707 			print = TRUE;
    708 		}
    709 
    710 		if (print) {
    711 			printf("[%2d] next 0x%08x src 0x%08x dst 0x%08x"
    712 			    " sz 0x%x\n", i, p->next, p->src, p->dst, p->sz);
    713 		} else if (i == n) {
    714 			printf("[...]\n");
    715 		}
    716 		op = p;
    717 		i++;
    718 	} while ((p = (struct kloader_page_tag *)(p->next)) != 0);
    719 
    720 	if (op != NULL)
    721 		printf("[%d(last)] next 0x%08x src 0x%08x dst 0x%08x sz 0x%x\n",
    722 		    i - 1, op->next, op->src, op->dst, op->sz);
    723 }
    724 
    725 #endif /* KLOADER_DEBUG */
    726