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