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