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