1 1.1 skrll /* $NetBSD: main.c,v 1.1 2014/02/24 07:23:43 skrll Exp $ */ 2 1.1 skrll 3 1.1 skrll /* 4 1.1 skrll * Copyright (c) 2003 ITOH Yasufumi. 5 1.1 skrll * All rights reserved. 6 1.1 skrll * 7 1.1 skrll * Redistribution and use in source and binary forms, with or without 8 1.1 skrll * modification, are permitted provided that the following conditions 9 1.1 skrll * are met: 10 1.1 skrll * 1. Redistributions of source code must retain the above copyright 11 1.1 skrll * notice, this list of conditions and the following disclaimer. 12 1.1 skrll * 2. Redistributions in binary forms are unlimited. 13 1.1 skrll * 14 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' 15 1.1 skrll * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 1.1 skrll * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS 18 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 1.1 skrll * THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 skrll */ 26 1.1 skrll 27 1.1 skrll #include <sys/types.h> 28 1.1 skrll #include <sys/param.h> 29 1.1 skrll #include <ufs/ufs/dinode.h> 30 1.1 skrll #include <sys/disklabel.h> 31 1.1 skrll #include <sys/exec_elf.h> 32 1.1 skrll #include "readufs.h" 33 1.1 skrll 34 1.1 skrll #define STACK_SIZE ((unsigned) (64*1024)) 35 1.1 skrll #define LOAD_ALIGN ((unsigned) 2048) 36 1.1 skrll 37 1.1 skrll #define PZ_MEM_BOOT 0x3d0 38 1.1 skrll #define DEV_CLASS 0x2c 39 1.1 skrll #define DEV_CL_MASK 0xf 40 1.1 skrll #define DEV_CL_SEQU 0x2 /* sequential record access media */ 41 1.1 skrll 42 1.1 skrll static char *hexstr(char *, unsigned); 43 1.1 skrll void ipl_main(unsigned /*interactive*/, unsigned /*sptop*/, unsigned /*psw*/); 44 1.1 skrll void load_file(const char *, uintptr_t /*loadadr*/, unsigned /*interactive*/, 45 1.1 skrll int /*part*/); 46 1.1 skrll void load_file_ino(ino32_t, const char *, uintptr_t /*loadadr*/, 47 1.1 skrll unsigned /*interactive*/, int /*part*/); 48 1.1 skrll 49 1.1 skrll struct loadinfo { 50 1.1 skrll void *sec_image; 51 1.1 skrll unsigned sec_size; 52 1.1 skrll #if 0 53 1.1 skrll unsigned sec_pad; 54 1.1 skrll #endif 55 1.1 skrll unsigned entry_offset; 56 1.1 skrll }; 57 1.1 skrll static inline void xi_elf32(struct loadinfo *, Elf32_Ehdr *); 58 1.1 skrll static inline void xi_elf64(struct loadinfo *, Elf64_Ehdr *); 59 1.1 skrll int xi_load(struct loadinfo *, void *); 60 1.1 skrll 61 1.1 skrll void reboot(void); 62 1.1 skrll void halt(void); 63 1.1 skrll void dispatch(unsigned /*interactive*/, unsigned /*top*/, 64 1.1 skrll unsigned /*end*/, int /*part*/, unsigned /*entry*/); 65 1.1 skrll void print(const char *); 66 1.1 skrll void putch(int); 67 1.1 skrll int getch(void); 68 1.1 skrll int boot_input(void *, int /*len*/, int /*pos*/); 69 1.1 skrll 70 1.1 skrll /* to make generated code relocatable, do NOT mark them as const */ 71 1.1 skrll extern char str_seekseq[], str_bit_firmware[]; 72 1.1 skrll extern char str_crlf[], str_space[], str_rubout[]; 73 1.1 skrll extern char str_bootpart[], str_booting_part[]; 74 1.1 skrll extern char str_warn_2GB[], str_warn_unused[], str_nolabel[]; 75 1.1 skrll extern char str_filesystem[], str_nofs[]; 76 1.1 skrll extern char str_lookup[], str_loading[], str_at[], str_dddot[], str_done[]; 77 1.1 skrll extern char str_boot1[], str_boot2[], str_boot3[]; 78 1.1 skrll extern char str_noboot[]; 79 1.1 skrll extern char str_ukfmt[]; 80 1.1 skrll 81 1.1 skrll #ifdef __GNUC__ 82 1.1 skrll #define memcpy(d, s, n) __builtin_memcpy(d, s, n) 83 1.1 skrll #else 84 1.1 skrll void *memcpy(void *, const void *, size_t); 85 1.1 skrll #endif 86 1.1 skrll void *memmove(void *, const void *, size_t); 87 1.1 skrll 88 1.1 skrll /* disklabel */ 89 1.1 skrll union { 90 1.1 skrll char dklsec[512]; 91 1.1 skrll struct disklabel dkl; /* to ensure alignment */ 92 1.1 skrll } labelsector; 93 1.1 skrll #define dklabel (*(struct disklabel *)(labelsector.dklsec + LABELOFFSET)) 94 1.1 skrll 95 1.1 skrll unsigned offset_raw_read; 96 1.1 skrll 97 1.1 skrll extern char diskbuf[2048]; 98 1.1 skrll #define BLK_PER_READ 4 99 1.1 skrll #define MASK_BLK_PER_READ (BLK_PER_READ - 1) 100 1.1 skrll 101 1.1 skrll void 102 1.1 skrll RAW_READ(void *buf, daddr_t blkpos, size_t bytelen) 103 1.1 skrll { 104 1.1 skrll char *b = buf; 105 1.1 skrll size_t off, readlen; 106 1.1 skrll int devoff; 107 1.1 skrll static int prvdevoff = -dbtob(BLK_PER_READ); 108 1.1 skrll int pos; 109 1.1 skrll 110 1.1 skrll for ( ; bytelen > 0; b += readlen, bytelen -= readlen) { 111 1.1 skrll /* 112 1.1 skrll * read 2KB, avoiding unneeded read 113 1.1 skrll */ 114 1.1 skrll devoff = dbtob(blkpos & ~MASK_BLK_PER_READ) + offset_raw_read; 115 1.1 skrll if (prvdevoff != devoff) { 116 1.1 skrll #if 1 /* supports sequential media */ 117 1.1 skrll if ((*(unsigned *)(PZ_MEM_BOOT+DEV_CLASS) & DEV_CL_MASK) 118 1.1 skrll == DEV_CL_SEQU) { 119 1.1 skrll /* 120 1.1 skrll * sequential media 121 1.1 skrll * -- read sequentially or rewind 122 1.1 skrll */ 123 1.1 skrll pos = prvdevoff + dbtob(BLK_PER_READ); 124 1.1 skrll if (devoff < pos) 125 1.1 skrll pos = 0; /* rewind */ 126 1.1 skrll 127 1.1 skrll /* "repositioning media...\r\n" */ 128 1.1 skrll if (devoff - pos > 512 * 1024) 129 1.1 skrll print(str_seekseq); 130 1.1 skrll 131 1.1 skrll for (; pos < devoff; pos += dbtob(BLK_PER_READ)) 132 1.1 skrll boot_input(diskbuf, 133 1.1 skrll dbtob(BLK_PER_READ), pos); 134 1.1 skrll } 135 1.1 skrll #endif 136 1.1 skrll prvdevoff = devoff; 137 1.1 skrll boot_input(diskbuf, dbtob(BLK_PER_READ), devoff); 138 1.1 skrll } 139 1.1 skrll /* 140 1.1 skrll * copy specified size to the destination 141 1.1 skrll */ 142 1.1 skrll off = dbtob(blkpos & MASK_BLK_PER_READ), 143 1.1 skrll readlen = dbtob(BLK_PER_READ) - off; 144 1.1 skrll if (readlen > bytelen) 145 1.1 skrll readlen = bytelen; 146 1.1 skrll memcpy(b, diskbuf + off, readlen); 147 1.1 skrll blkpos = (blkpos & ~MASK_BLK_PER_READ) + BLK_PER_READ; 148 1.1 skrll } 149 1.1 skrll } 150 1.1 skrll 151 1.1 skrll /* 152 1.1 skrll * convert number to hex string 153 1.1 skrll * buf must have enough space 154 1.1 skrll */ 155 1.1 skrll static char * 156 1.1 skrll hexstr(char *buf, unsigned val) 157 1.1 skrll { 158 1.1 skrll unsigned v; 159 1.1 skrll char rev[16]; 160 1.1 skrll char *r = rev, *b = buf; 161 1.1 skrll 162 1.1 skrll /* inverse order */ 163 1.1 skrll do { 164 1.1 skrll v = val & 0xf; 165 1.1 skrll *r++ = (v <= 9) ? '0' + v : 'a' - 10 + v; 166 1.1 skrll val >>= 4; 167 1.1 skrll } while (val); 168 1.1 skrll 169 1.1 skrll /* reverse string */ 170 1.1 skrll while (r > rev) 171 1.1 skrll *b++ = *--r; 172 1.1 skrll 173 1.1 skrll *b = '\0'; 174 1.1 skrll return buf; 175 1.1 skrll } 176 1.1 skrll 177 1.1 skrll void 178 1.1 skrll ipl_main(unsigned interactive, unsigned sptop, unsigned psw) 179 1.1 skrll /* interactive: parameters from PDC */ 180 1.1 skrll /* sptop: value of sp on function entry */ 181 1.1 skrll /* psw: PSW on startup */ 182 1.1 skrll { 183 1.1 skrll char buf[32]; 184 1.1 skrll int part = 0; /* default partition "a" */ 185 1.1 skrll unsigned secsz, partoff, partsz; 186 1.1 skrll int c, c1; 187 1.1 skrll uintptr_t loadadr; 188 1.1 skrll 189 1.1 skrll #if 0 190 1.1 skrll print(hexstr(buf, interactive)); 191 1.1 skrll print(str_crlf); 192 1.1 skrll print(hexstr(buf, sptop)); 193 1.1 skrll print(str_crlf); 194 1.1 skrll print(hexstr(buf, psw)); 195 1.1 skrll print(str_crlf); 196 1.1 skrll #endif 197 1.1 skrll 198 1.1 skrll print(hexstr(buf, (psw & 0x08000000) ? (unsigned) 0x64 : 0x32)); 199 1.1 skrll print(str_bit_firmware); /* "bit firmware\r\n" */ 200 1.1 skrll 201 1.1 skrll /* 202 1.1 skrll * check disklabel 203 1.1 skrll * (dklabel has disklabel on startup) 204 1.1 skrll */ 205 1.1 skrll if (dklabel.d_magic == DISKMAGIC && (secsz = dklabel.d_secsize) != 0) { 206 1.1 skrll /* 207 1.1 skrll * select boot partition 208 1.1 skrll */ 209 1.1 skrll if (interactive) { 210 1.1 skrll select_partition: 211 1.1 skrll /* "boot partition (a-p, ! to reboot) [a]:" */ 212 1.1 skrll print(str_bootpart); 213 1.1 skrll part = 0; /* default partition "a" */ 214 1.1 skrll c1 = 0; 215 1.1 skrll while ((c = getch()) >= 0) { 216 1.1 skrll switch (c) { 217 1.1 skrll case '\n': 218 1.1 skrll case '\r': 219 1.1 skrll goto break_while; 220 1.1 skrll case '\b': 221 1.1 skrll case '\177': 222 1.1 skrll if (c1) { 223 1.1 skrll print(str_rubout); 224 1.1 skrll part = c1 = 0; 225 1.1 skrll } 226 1.1 skrll break; 227 1.1 skrll case '!': /* reset */ 228 1.1 skrll if (c1 == 0) { 229 1.1 skrll part = -1; 230 1.1 skrll goto echoback; 231 1.1 skrll } 232 1.1 skrll break; 233 1.1 skrll default: 234 1.1 skrll if (c1 == 0 && c >= 'a' && c <= 'p') { 235 1.1 skrll part = c - 'a'; 236 1.1 skrll echoback: 237 1.1 skrll putch(c); 238 1.1 skrll c1 = 1; 239 1.1 skrll } 240 1.1 skrll break; 241 1.1 skrll } 242 1.1 skrll } 243 1.1 skrll break_while: 244 1.1 skrll if (part == -1) 245 1.1 skrll return; /* reset */ 246 1.1 skrll } 247 1.1 skrll 248 1.1 skrll /* 249 1.1 skrll * "\r\nbooting from partition _\r\n" 250 1.1 skrll */ 251 1.1 skrll str_booting_part[25] = 'a' + part; 252 1.1 skrll print(str_booting_part); 253 1.1 skrll 254 1.1 skrll partoff = dklabel.d_partitions[part].p_offset; 255 1.1 skrll partsz = dklabel.d_partitions[part].p_size; 256 1.1 skrll 257 1.1 skrll if (part >= (int) dklabel.d_npartitions || partsz == 0) { 258 1.1 skrll print(str_warn_unused); /* "unused partition\r\n" */ 259 1.1 skrll goto select_partition; 260 1.1 skrll } 261 1.1 skrll 262 1.1 skrll /* boot partition must be below 2GB */ 263 1.1 skrll if (partoff + partsz > ((unsigned)2*1024*1024*1024) / secsz) { 264 1.1 skrll /* "boot partition exceeds 2GB boundary\r\n" */ 265 1.1 skrll print(str_warn_2GB); 266 1.1 skrll goto select_partition; 267 1.1 skrll } 268 1.1 skrll 269 1.1 skrll /* 270 1.1 skrll * following device accesses are only in the partition 271 1.1 skrll */ 272 1.1 skrll offset_raw_read = partoff * secsz; 273 1.1 skrll } else { 274 1.1 skrll /* 275 1.1 skrll * no disklabel --- assume the whole of the device 276 1.1 skrll * is a filesystem 277 1.1 skrll */ 278 1.1 skrll print(str_nolabel); /* "no disklabel\r\n" */ 279 1.1 skrll } 280 1.1 skrll 281 1.1 skrll if (ufs_init()) { 282 1.1 skrll print(str_nofs); /* "no filesystem found\r\n" */ 283 1.1 skrll return; 284 1.1 skrll } 285 1.1 skrll str_filesystem[12] = (ufs_info.fstype == UFSTYPE_FFS) ? 'F' : 'L'; 286 1.1 skrll print(str_filesystem); /* "filesystem: _FS\r\n" */ 287 1.1 skrll 288 1.1 skrll loadadr = (sptop + STACK_SIZE + LOAD_ALIGN - 1) & (-LOAD_ALIGN); 289 1.1 skrll load_file(str_boot1, loadadr, interactive, part); /* "boot.hp700" */ 290 1.1 skrll load_file(str_boot2, loadadr, interactive, part); /* "boot" */ 291 1.1 skrll load_file(str_boot3, loadadr, interactive, part); /* "usr/mdec/boot" */ 292 1.1 skrll 293 1.1 skrll print(str_noboot); /* "no secondary boot found\r\n" */ 294 1.1 skrll } 295 1.1 skrll 296 1.1 skrll void 297 1.1 skrll load_file(const char *path, uintptr_t loadadr, unsigned interactive, int part) 298 1.1 skrll { 299 1.1 skrll 300 1.1 skrll /* look-up the file */ 301 1.1 skrll print(str_lookup); /* "looking up " */ 302 1.1 skrll print(path); 303 1.1 skrll print(str_crlf); 304 1.1 skrll load_file_ino(ufs_lookup_path(path), path, loadadr, interactive, part); 305 1.1 skrll } 306 1.1 skrll 307 1.1 skrll void 308 1.1 skrll load_file_ino(ino32_t ino, const char *fn, uintptr_t loadadr, unsigned interactive, int part) 309 1.1 skrll /* fn: for message only */ 310 1.1 skrll { 311 1.1 skrll union ufs_dinode dinode; 312 1.1 skrll size_t sz; 313 1.1 skrll struct loadinfo inf; 314 1.1 skrll char buf[32]; 315 1.1 skrll 316 1.1 skrll if (ino == 0 || ufs_get_inode(ino, &dinode)) 317 1.1 skrll return; /* not found */ 318 1.1 skrll 319 1.1 skrll print(str_loading); /* "loading " */ 320 1.1 skrll print(fn); 321 1.1 skrll print(str_at); /* " at 0x" */ 322 1.1 skrll print(hexstr(buf, loadadr)); 323 1.1 skrll print(str_dddot); /* "..." */ 324 1.1 skrll 325 1.1 skrll sz = DI_SIZE(&dinode); 326 1.1 skrll ufs_read(&dinode, (void *) loadadr, 0, sz); 327 1.1 skrll 328 1.1 skrll print(str_done); /* "done\r\n" */ 329 1.1 skrll 330 1.1 skrll /* digest executable format */ 331 1.1 skrll inf.sec_size = sz; 332 1.1 skrll inf.entry_offset = 0; 333 1.1 skrll if (xi_load(&inf, (void *) loadadr)) { 334 1.1 skrll print(fn); 335 1.1 skrll print(str_ukfmt); /* ": unknown format -- exec from top\r\n" */ 336 1.1 skrll } 337 1.1 skrll 338 1.1 skrll /* pass control to the secondary boot */ 339 1.1 skrll dispatch(interactive, loadadr, loadadr + inf.sec_size, part, 340 1.1 skrll loadadr + inf.entry_offset); 341 1.1 skrll } 342 1.1 skrll 343 1.1 skrll /* 344 1.1 skrll * fill in loading information from an ELF executable 345 1.1 skrll */ 346 1.1 skrll static inline void 347 1.1 skrll xi_elf32(struct loadinfo *inf, Elf32_Ehdr *hdr) 348 1.1 skrll { 349 1.1 skrll char *top = (void *) hdr; 350 1.1 skrll Elf32_Phdr *ph; 351 1.1 skrll 352 1.1 skrll /* text + data, bss */ 353 1.1 skrll ph = (void *) (top + hdr->e_phoff); 354 1.1 skrll inf->sec_image = top + ph->p_offset; 355 1.1 skrll inf->sec_size = ph->p_filesz; 356 1.1 skrll #if 0 357 1.1 skrll inf->sec_pad = ph->p_memsz - ph->p_filesz; 358 1.1 skrll #endif 359 1.1 skrll /* entry */ 360 1.1 skrll inf->entry_offset = hdr->e_entry - ph->p_vaddr; 361 1.1 skrll } 362 1.1 skrll 363 1.1 skrll static inline void 364 1.1 skrll xi_elf64(struct loadinfo *inf, Elf64_Ehdr *hdr) 365 1.1 skrll { 366 1.1 skrll char *top = (void *) hdr; 367 1.1 skrll Elf64_Phdr *ph; 368 1.1 skrll 369 1.1 skrll /* 370 1.1 skrll * secondary boot is not so large, so 32bit (unsigned) arithmetic 371 1.1 skrll * is enough 372 1.1 skrll */ 373 1.1 skrll /* text + data, bss */ 374 1.1 skrll ph = (void *) (top + (unsigned) hdr->e_phoff); 375 1.1 skrll inf->sec_image = top + (unsigned) ph->p_offset; 376 1.1 skrll inf->sec_size = (unsigned) ph->p_filesz; 377 1.1 skrll #if 0 378 1.1 skrll inf->sec_pad = (unsigned) ph->p_memsz - (unsigned) ph->p_filesz; 379 1.1 skrll #endif 380 1.1 skrll /* entry */ 381 1.1 skrll inf->entry_offset = (unsigned) hdr->e_entry - (unsigned) ph->p_vaddr; 382 1.1 skrll } 383 1.1 skrll 384 1.1 skrll int 385 1.1 skrll xi_load(struct loadinfo *inf, void *buf) 386 1.1 skrll { 387 1.1 skrll Elf32_Ehdr *e32hdr = buf; 388 1.1 skrll Elf64_Ehdr *e64hdr = buf; 389 1.1 skrll uint16_t class_data; 390 1.1 skrll 391 1.1 skrll /* 392 1.1 skrll * check ELF header 393 1.1 skrll * (optimized assuming big endian byte order) 394 1.1 skrll */ 395 1.1 skrll /* ELF magic */ 396 1.1 skrll if (*(uint32_t *)&e32hdr->e_ident[EI_MAG0] != 397 1.1 skrll (ELFMAG0 << 24 | ELFMAG1 << 16 | ELFMAG2 << 8 | ELFMAG3) || 398 1.1 skrll e32hdr->e_ident[EI_VERSION] != EV_CURRENT) 399 1.1 skrll return 1; /* Not an ELF */ 400 1.1 skrll 401 1.1 skrll /* file and machine type */ 402 1.1 skrll if (*(uint32_t *)&e32hdr->e_type != (ET_EXEC << 16 | EM_PARISC)) 403 1.1 skrll return 1; /* Not an executable / Wrong architecture */ 404 1.1 skrll 405 1.1 skrll if ((class_data = *(uint16_t *)&e32hdr->e_ident[EI_CLASS]) == 406 1.1 skrll (ELFCLASS32 << 8 | ELFDATA2MSB)) { 407 1.1 skrll 408 1.1 skrll /* support one section executable (ld -N) only */ 409 1.1 skrll if (e32hdr->e_phnum != 1) 410 1.1 skrll return 1; /* Wrong number of loading sections */ 411 1.1 skrll 412 1.1 skrll /* fill in loading information */ 413 1.1 skrll xi_elf32(inf, e32hdr); 414 1.1 skrll 415 1.1 skrll } else if (class_data == (ELFCLASS64 << 8 | ELFDATA2MSB)) { 416 1.1 skrll 417 1.1 skrll /* support one section executable (ld -N) only */ 418 1.1 skrll if (e64hdr->e_phnum != 1) 419 1.1 skrll return 1; /* Wrong number of loading sections */ 420 1.1 skrll 421 1.1 skrll /* fill in loading information */ 422 1.1 skrll xi_elf64(inf, e64hdr); 423 1.1 skrll 424 1.1 skrll } else 425 1.1 skrll return 1; /* Not a 32bit or 64bit ELF */ 426 1.1 skrll 427 1.1 skrll /* move text + data to the top address */ 428 1.1 skrll memmove(buf, inf->sec_image, inf->sec_size); 429 1.1 skrll 430 1.1 skrll #if 0 /* XXX bss clear is done by the secondary boot itself */ 431 1.1 skrll memset((char *) buf + inf->sec_size, 0, inf->sec_pad); 432 1.1 skrll #endif 433 1.1 skrll 434 1.1 skrll return 0; 435 1.1 skrll } 436