1 1.12 tsutsui /* $NetBSD: zbsdmod.c,v 1.12 2019/11/13 17:59:56 tsutsui Exp $ */ 2 1.1 peter /* $OpenBSD: zbsdmod.c,v 1.7 2005/05/02 02:45:29 uwe Exp $ */ 3 1.1 peter 4 1.1 peter /* 5 1.1 peter * Copyright (c) 2005 Uwe Stuehler <uwe (at) bsdx.de> 6 1.1 peter * 7 1.1 peter * Permission to use, copy, modify, and distribute this software for any 8 1.1 peter * purpose with or without fee is hereby granted, provided that the above 9 1.1 peter * copyright notice and this permission notice appear in all copies. 10 1.1 peter * 11 1.1 peter * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 1.1 peter * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 peter * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 1.1 peter * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 peter * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 peter * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 1.1 peter * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 peter */ 19 1.1 peter 20 1.1 peter /* 21 1.1 peter * Zaurus NetBSD bootstrap loader. 22 1.1 peter */ 23 1.1 peter 24 1.7 nonaka #include <sys/cdefs.h> 25 1.7 nonaka #define ELFSIZE 32 26 1.7 nonaka #include <sys/exec_elf.h> 27 1.7 nonaka #include <sys/types.h> 28 1.7 nonaka #include <sys/errno.h> 29 1.7 nonaka 30 1.7 nonaka #include <machine/bootinfo.h> 31 1.7 nonaka 32 1.1 peter #include "compat_linux.h" 33 1.1 peter 34 1.7 nonaka /* Linux LKM support */ 35 1.7 nonaka const char __module_kernel_version[] __attribute__((section(".modinfo"))) = 36 1.7 nonaka "kernel_version=" UTS_RELEASE; 37 1.7 nonaka const char __module_using_checksums[] __attribute__((section(".modinfo"))) = 38 1.7 nonaka "using_checksums=1"; 39 1.1 peter 40 1.1 peter #define ZBOOTDEV_MAJOR 99 41 1.1 peter #define ZBOOTDEV_MODE 0222 42 1.1 peter #define ZBOOTDEV_NAME "zboot" 43 1.1 peter #define ZBOOTMOD_NAME "zbsdmod" 44 1.1 peter 45 1.1 peter /* Prototypes */ 46 1.1 peter int init_module(void); 47 1.1 peter void cleanup_module(void); 48 1.1 peter 49 1.1 peter static ssize_t zbsdmod_write(struct file *, const char *, size_t, loff_t *); 50 1.1 peter static int zbsdmod_open(struct inode *, struct file *); 51 1.1 peter static int zbsdmod_close(struct inode *, struct file *); 52 1.1 peter 53 1.1 peter static void elf32bsdboot(void); 54 1.1 peter 55 1.1 peter static struct file_operations fops = { 56 1.1 peter 0, /* struct module *owner */ 57 1.1 peter 0, /* lseek */ 58 1.1 peter 0, /* read */ 59 1.1 peter zbsdmod_write, /* write */ 60 1.1 peter 0, /* readdir */ 61 1.1 peter 0, /* poll */ 62 1.1 peter 0, /* ioctl */ 63 1.1 peter 0, /* mmap */ 64 1.1 peter zbsdmod_open, /* open */ 65 1.1 peter 0, /* flush */ 66 1.1 peter zbsdmod_close, /* release */ 67 1.1 peter 0, /* sync */ 68 1.1 peter 0, /* async */ 69 1.1 peter 0, /* check media change */ 70 1.1 peter 0, /* revalidate */ 71 1.1 peter 0, /* lock */ 72 1.7 nonaka 0, /* sendpage */ 73 1.7 nonaka 0, /* get_unmapped_area */ 74 1.7 nonaka #ifdef MAGIC_ROM_PTR 75 1.7 nonaka 0, /* romptr */ 76 1.7 nonaka #endif /* MAGIC_ROM_PTR */ 77 1.1 peter }; 78 1.1 peter 79 1.1 peter static int isopen; 80 1.1 peter static loff_t position; 81 1.1 peter 82 1.1 peter /* Outcast local variables to avoid stack usage in elf32bsdboot(). */ 83 1.1 peter static int cpsr; 84 1.1 peter static unsigned int sz; 85 1.1 peter static int i; 86 1.1 peter static vaddr_t minv, maxv, posv; 87 1.1 peter static vaddr_t elfv, shpv; 88 1.1 peter static int *addr; 89 1.1 peter static vaddr_t *esymp; 90 1.1 peter static Elf_Shdr *shp; 91 1.1 peter static Elf_Off off; 92 1.1 peter static int havesyms; 93 1.1 peter 94 1.6 nonaka /* The maximum size of a kernel image is restricted to 5MB. */ 95 1.6 nonaka static u_int bsdimage[5242880/sizeof(u_int)]; /* XXX use kmalloc() */ 96 1.1 peter static char bootargs[BOOTARGS_BUFSIZ]; 97 1.8 nonaka static u_int datacacheclean[65536/sizeof(u_int)] __attribute__((aligned(32))); 98 1.1 peter 99 1.1 peter /* 100 1.1 peter * Boot the loaded BSD kernel image, or return if an error is found. 101 1.1 peter * Part of this routine is borrowed from sys/lib/libsa/loadfile.c. 102 1.1 peter */ 103 1.1 peter static void 104 1.1 peter elf32bsdboot(void) 105 1.1 peter { 106 1.1 peter 107 1.1 peter #define elf ((Elf32_Ehdr *)bsdimage) 108 1.1 peter #define phdr ((Elf32_Phdr *)((char *)elf + elf->e_phoff)) 109 1.1 peter 110 1.1 peter if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 111 1.1 peter elf->e_ident[EI_CLASS] != ELFCLASS32) 112 1.1 peter return; 113 1.1 peter 114 1.1 peter minv = (vaddr_t)~0; 115 1.1 peter maxv = (vaddr_t)0; 116 1.1 peter posv = (vaddr_t)0; 117 1.1 peter esymp = 0; 118 1.1 peter 119 1.1 peter /* 120 1.1 peter * Get min and max addresses used by the loaded kernel. 121 1.1 peter */ 122 1.1 peter for (i = 0; i < elf->e_phnum; i++) { 123 1.1 peter 124 1.1 peter if (phdr[i].p_type != PT_LOAD || 125 1.1 peter (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0) 126 1.1 peter continue; 127 1.1 peter 128 1.1 peter #define IS_TEXT(p) (p.p_flags & PF_X) 129 1.7 nonaka #define IS_DATA(p) (p.p_flags & PF_W) 130 1.1 peter #define IS_BSS(p) (p.p_filesz < p.p_memsz) 131 1.1 peter /* 132 1.1 peter * XXX: Assume first address is lowest 133 1.1 peter */ 134 1.1 peter if (IS_TEXT(phdr[i]) || IS_DATA(phdr[i])) { 135 1.1 peter posv = phdr[i].p_vaddr; 136 1.1 peter if (minv > posv) 137 1.1 peter minv = posv; 138 1.1 peter posv += phdr[i].p_filesz; 139 1.1 peter if (maxv < posv) 140 1.1 peter maxv = posv; 141 1.1 peter } 142 1.12 tsutsui if (IS_BSS(phdr[i])) { 143 1.12 tsutsui posv += phdr[i].p_memsz - phdr[i].p_filesz; 144 1.1 peter if (maxv < posv) 145 1.1 peter maxv = posv; 146 1.1 peter } 147 1.1 peter /* 148 1.1 peter * 'esym' is the first word in the .data section, 149 1.1 peter * and marks the end of the symbol table. 150 1.1 peter */ 151 1.1 peter if (IS_DATA(phdr[i]) && !IS_BSS(phdr[i])) 152 1.1 peter esymp = (vaddr_t *)phdr[i].p_vaddr; 153 1.1 peter } 154 1.1 peter 155 1.9 joerg __asm volatile ("mrs %0, cpsr" : "=r" (cpsr)); 156 1.1 peter cpsr |= 0xc0; /* set FI */ 157 1.1 peter __asm volatile ("msr cpsr_all, %0" :: "r" (cpsr)); 158 1.1 peter 159 1.1 peter /* 160 1.1 peter * Copy the boot arguments. 161 1.1 peter */ 162 1.1 peter sz = BOOTARGS_BUFSIZ; 163 1.1 peter while (sz > 0) { 164 1.1 peter sz--; 165 1.1 peter ((char *)minv - BOOTARGS_BUFSIZ)[sz] = bootargs[sz]; 166 1.1 peter } 167 1.1 peter 168 1.1 peter /* 169 1.1 peter * Set up pointers to copied ELF and section headers. 170 1.1 peter */ 171 1.1 peter #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 172 1.1 peter elfv = maxv = roundup(maxv, sizeof(long)); 173 1.1 peter maxv += sizeof(Elf_Ehdr); 174 1.1 peter 175 1.1 peter sz = elf->e_shnum * sizeof(Elf_Shdr); 176 1.1 peter shp = (Elf_Shdr *)((vaddr_t)elf + elf->e_shoff); 177 1.1 peter shpv = maxv; 178 1.1 peter maxv += roundup(sz, sizeof(long)); 179 1.1 peter 180 1.1 peter /* 181 1.1 peter * Now load the symbol sections themselves. Make sure the 182 1.1 peter * sections are aligned, and offsets are relative to the 183 1.1 peter * copied ELF header. Don't bother with string tables if 184 1.1 peter * there are no symbol sections. 185 1.1 peter */ 186 1.1 peter off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long)); 187 1.1 peter for (havesyms = i = 0; i < elf->e_shnum; i++) 188 1.1 peter if (shp[i].sh_type == SHT_SYMTAB) 189 1.1 peter havesyms = 1; 190 1.1 peter for (i = 0; i < elf->e_shnum; i++) { 191 1.1 peter if (shp[i].sh_type == SHT_SYMTAB || 192 1.1 peter shp[i].sh_type == SHT_STRTAB) { 193 1.1 peter if (havesyms) { 194 1.1 peter sz = shp[i].sh_size; 195 1.1 peter while (sz > 0) { 196 1.1 peter sz--; 197 1.1 peter ((char *)maxv)[sz] = 198 1.1 peter ((char *)elf + 199 1.1 peter shp[i].sh_offset)[sz]; 200 1.1 peter } 201 1.1 peter } 202 1.1 peter maxv += roundup(shp[i].sh_size, sizeof(long)); 203 1.1 peter shp[i].sh_offset = off; 204 1.1 peter off += roundup(shp[i].sh_size, sizeof(long)); 205 1.1 peter } 206 1.1 peter } 207 1.1 peter 208 1.1 peter /* 209 1.1 peter * Copy the ELF and section headers. 210 1.1 peter */ 211 1.1 peter sz = sizeof(Elf_Ehdr); 212 1.1 peter while (sz > 0) { 213 1.1 peter sz--; 214 1.1 peter ((char *)elfv)[sz] = ((char *)elf)[sz]; 215 1.1 peter } 216 1.1 peter sz = elf->e_shnum * sizeof(Elf_Shdr); 217 1.1 peter while (sz > 0) { 218 1.1 peter sz--; 219 1.1 peter ((char *)shpv)[sz] = ((char *)shp)[sz]; 220 1.1 peter } 221 1.1 peter 222 1.1 peter /* 223 1.1 peter * Frob the copied ELF header to give information relative 224 1.1 peter * to elfv. 225 1.1 peter */ 226 1.1 peter ((Elf_Ehdr *)elfv)->e_phoff = 0; 227 1.1 peter ((Elf_Ehdr *)elfv)->e_shoff = sizeof(Elf_Ehdr); 228 1.1 peter ((Elf_Ehdr *)elfv)->e_phentsize = 0; 229 1.1 peter ((Elf_Ehdr *)elfv)->e_phnum = 0; 230 1.1 peter 231 1.1 peter /* 232 1.1 peter * Tell locore.S where the symbol table ends, and arrange 233 1.1 peter * to skip esym when loading the data section. 234 1.1 peter */ 235 1.1 peter if (esymp != 0) 236 1.1 peter *esymp = (vaddr_t)maxv; 237 1.1 peter for (i = 0; esymp != 0 && i < elf->e_phnum; i++) { 238 1.1 peter if (phdr[i].p_type != PT_LOAD || 239 1.1 peter (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0) 240 1.1 peter continue; 241 1.1 peter if (phdr[i].p_vaddr == (vaddr_t)esymp) { 242 1.1 peter phdr[i].p_vaddr = (vaddr_t)((char *)phdr[i].p_vaddr + sizeof(long)); 243 1.1 peter phdr[i].p_offset = (vaddr_t)((char *)phdr[i].p_offset + sizeof(long)); 244 1.1 peter phdr[i].p_filesz -= sizeof(long); 245 1.1 peter break; 246 1.1 peter } 247 1.1 peter } 248 1.1 peter 249 1.1 peter /* 250 1.1 peter * Load text and data. 251 1.1 peter */ 252 1.1 peter for (i = 0; i < elf->e_phnum; i++) { 253 1.1 peter if (phdr[i].p_type != PT_LOAD || 254 1.1 peter (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0) 255 1.1 peter continue; 256 1.1 peter 257 1.1 peter if (IS_TEXT(phdr[i]) || IS_DATA(phdr[i])) { 258 1.1 peter sz = phdr[i].p_filesz; 259 1.1 peter while (sz > 0) { 260 1.1 peter sz--; 261 1.1 peter ((char *)phdr[i].p_vaddr)[sz] = 262 1.1 peter (((char *)elf) + phdr[i].p_offset)[sz]; 263 1.1 peter } 264 1.1 peter } 265 1.11 tsutsui if (IS_BSS(phdr[i])) { 266 1.11 tsutsui memset((void *)(phdr[i].p_vaddr + phdr[i].p_filesz), 0, 267 1.11 tsutsui phdr[i].p_memsz - phdr[i].p_filesz); 268 1.11 tsutsui } 269 1.1 peter } 270 1.1 peter 271 1.1 peter addr = (int *)(elf->e_entry); 272 1.1 peter __asm volatile ( 273 1.8 nonaka /* Clean D-cache */ 274 1.8 nonaka "mov r0, %1;" 275 1.8 nonaka "mov r1, #65536;" 276 1.8 nonaka "1:" 277 1.8 nonaka "ldr r2, [r0], #32;" 278 1.8 nonaka "subs r1, r1, #32;" 279 1.8 nonaka "bne 1b;" 280 1.8 nonaka "mcr p15, 0, r1, c7, c10, 4;" /*drain write and fill buffer*/ 281 1.8 nonaka "mrc p15, 0, r1, c2, c0, 0;" /* CPWAIT */ 282 1.8 nonaka "mov r1, r1;" 283 1.8 nonaka "sub pc, pc, #4;" 284 1.8 nonaka /* Disable MMU and jump to kernel entry address */ 285 1.1 peter "mov r0, %0;" 286 1.8 nonaka "mcr p15, 0, r1, c7, c7, 0;" /* flush I+D cache */ 287 1.8 nonaka "mrc p15, 0, r1, c2, c0, 0;" /* CPWAIT */ 288 1.7 nonaka "mov r1, r1;" 289 1.1 peter "sub pc, pc, #4;" 290 1.1 peter "mov r1, #(0x00000010 | 0x00000020);" 291 1.10 tsutsui /* 292 1.10 tsutsui * Put the rest of instructions into the same cacheline 293 1.10 tsutsui * to make sure no I$ refill after invalidation. 294 1.10 tsutsui */ 295 1.10 tsutsui "b 2f;" 296 1.10 tsutsui ".align 5;" 297 1.10 tsutsui "2:" 298 1.8 nonaka "mcr p15, 0, r1, c1, c0, 0;" /* Write new control register */ 299 1.8 nonaka "mcr p15, 0, r1, c8, c7, 0;" /* invalidate I+D TLB */ 300 1.8 nonaka "mcr p15, 0, r1, c7, c5, 0;" /* invalidate I$ and BTB */ 301 1.8 nonaka "mcr p15, 0, r1, c7, c10, 4;" /*drain write and fill buffer*/ 302 1.8 nonaka "mrc p15, 0, r1, c2, c0, 0;" /* CPWAIT_AND_RETURN */ 303 1.7 nonaka "sub pc, r0, r1, lsr #32;" 304 1.8 nonaka :: "r" (addr), "r" (datacacheclean) : "r0", "r1", "r2"); 305 1.1 peter } 306 1.1 peter 307 1.1 peter /* 308 1.3 ad * Initialize the module. 309 1.1 peter */ 310 1.1 peter int 311 1.1 peter init_module(void) 312 1.1 peter { 313 1.1 peter struct proc_dir_entry *entry; 314 1.1 peter int rc; 315 1.1 peter 316 1.1 peter rc = register_chrdev(ZBOOTDEV_MAJOR, ZBOOTDEV_NAME, &fops); 317 1.1 peter if (rc != 0) { 318 1.1 peter printk("%s: register_chrdev(%d, ...): error %d\n", 319 1.5 nonaka ZBOOTMOD_NAME, ZBOOTDEV_MAJOR, -rc); 320 1.1 peter return 1; 321 1.1 peter } 322 1.1 peter 323 1.1 peter entry = proc_mknod(ZBOOTDEV_NAME, ZBOOTDEV_MODE | S_IFCHR, 324 1.1 peter &proc_root, MKDEV(ZBOOTDEV_MAJOR, 0)); 325 1.1 peter if (entry == (struct proc_dir_entry *)0) { 326 1.1 peter (void)unregister_chrdev(ZBOOTDEV_MAJOR, ZBOOTDEV_NAME); 327 1.1 peter return 1; 328 1.1 peter } 329 1.1 peter 330 1.1 peter printk("%s: NetBSD/" MACHINE " bootstrap device is %d,0\n", 331 1.1 peter ZBOOTMOD_NAME, ZBOOTDEV_MAJOR); 332 1.1 peter 333 1.1 peter return 0; 334 1.1 peter } 335 1.1 peter 336 1.1 peter /* 337 1.1 peter * Cleanup - undo whatever init_module did. 338 1.1 peter */ 339 1.1 peter void 340 1.1 peter cleanup_module(void) 341 1.1 peter { 342 1.1 peter 343 1.1 peter (void)unregister_chrdev(ZBOOTDEV_MAJOR, ZBOOTDEV_NAME); 344 1.1 peter remove_proc_entry(ZBOOTDEV_NAME, &proc_root); 345 1.1 peter 346 1.1 peter printk("%s: NetBSD/" MACHINE " bootstrap device unloaded\n", 347 1.1 peter ZBOOTMOD_NAME); 348 1.1 peter } 349 1.1 peter 350 1.1 peter static ssize_t 351 1.1 peter zbsdmod_write(struct file *f, const char *buf, size_t len, loff_t *offp) 352 1.1 peter { 353 1.1 peter 354 1.1 peter if (len < 1) 355 1.1 peter return 0; 356 1.1 peter 357 1.1 peter if (*offp + len >= sizeof(bsdimage)) 358 1.8 nonaka return -EFBIG; 359 1.1 peter 360 1.1 peter memcpy(((char *)bsdimage) + *offp, buf, len); 361 1.1 peter 362 1.1 peter *offp += len; 363 1.1 peter if (*offp > position) 364 1.1 peter position = *offp; 365 1.1 peter 366 1.1 peter return len; 367 1.1 peter } 368 1.1 peter 369 1.1 peter static int 370 1.1 peter zbsdmod_open(struct inode *ino, struct file *f) 371 1.1 peter { 372 1.1 peter 373 1.1 peter /* XXX superuser check */ 374 1.1 peter 375 1.1 peter if (isopen) 376 1.1 peter return -EBUSY; 377 1.1 peter 378 1.1 peter isopen = 1; 379 1.1 peter position = 0; 380 1.1 peter 381 1.1 peter return 0; 382 1.1 peter } 383 1.1 peter 384 1.1 peter static int 385 1.1 peter zbsdmod_close(struct inode *ino, struct file *f) 386 1.1 peter { 387 1.1 peter 388 1.1 peter if (!isopen) 389 1.1 peter return -EBUSY; 390 1.1 peter 391 1.1 peter if (position > 0) { 392 1.7 nonaka printk("%s: loaded %ld bytes\n", ZBOOTDEV_NAME, position); 393 1.7 nonaka if (position < (loff_t)BOOTINFO_MAXSIZE) { 394 1.1 peter *(u_int *)bootargs = BOOTARGS_MAGIC; 395 1.4 nonaka memcpy(bootargs + sizeof(u_int), bsdimage, position); 396 1.1 peter } else { 397 1.1 peter elf32bsdboot(); 398 1.4 nonaka printk("%s: boot failed\n", ZBOOTDEV_NAME); 399 1.1 peter } 400 1.1 peter } 401 1.1 peter isopen = 0; 402 1.1 peter 403 1.1 peter return 0; 404 1.1 peter } 405