/* $NetBSD: main.c,v 1.1 2014/02/24 07:23:43 skrll Exp $ */ /* * Copyright (c) 2003 ITOH Yasufumi. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary forms are unlimited. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "readufs.h" #define STACK_SIZE ((unsigned) (64*1024)) #define LOAD_ALIGN ((unsigned) 2048) #define PZ_MEM_BOOT 0x3d0 #define DEV_CLASS 0x2c #define DEV_CL_MASK 0xf #define DEV_CL_SEQU 0x2 /* sequential record access media */ static char *hexstr(char *, unsigned); void ipl_main(unsigned /*interactive*/, unsigned /*sptop*/, unsigned /*psw*/); void load_file(const char *, uintptr_t /*loadadr*/, unsigned /*interactive*/, int /*part*/); void load_file_ino(ino32_t, const char *, uintptr_t /*loadadr*/, unsigned /*interactive*/, int /*part*/); struct loadinfo { void *sec_image; unsigned sec_size; #if 0 unsigned sec_pad; #endif unsigned entry_offset; }; static inline void xi_elf32(struct loadinfo *, Elf32_Ehdr *); static inline void xi_elf64(struct loadinfo *, Elf64_Ehdr *); int xi_load(struct loadinfo *, void *); void reboot(void); void halt(void); void dispatch(unsigned /*interactive*/, unsigned /*top*/, unsigned /*end*/, int /*part*/, unsigned /*entry*/); void print(const char *); void putch(int); int getch(void); int boot_input(void *, int /*len*/, int /*pos*/); /* to make generated code relocatable, do NOT mark them as const */ extern char str_seekseq[], str_bit_firmware[]; extern char str_crlf[], str_space[], str_rubout[]; extern char str_bootpart[], str_booting_part[]; extern char str_warn_2GB[], str_warn_unused[], str_nolabel[]; extern char str_filesystem[], str_nofs[]; extern char str_lookup[], str_loading[], str_at[], str_dddot[], str_done[]; extern char str_boot1[], str_boot2[], str_boot3[]; extern char str_noboot[]; extern char str_ukfmt[]; #ifdef __GNUC__ #define memcpy(d, s, n) __builtin_memcpy(d, s, n) #else void *memcpy(void *, const void *, size_t); #endif void *memmove(void *, const void *, size_t); /* disklabel */ union { char dklsec[512]; struct disklabel dkl; /* to ensure alignment */ } labelsector; #define dklabel (*(struct disklabel *)(labelsector.dklsec + LABELOFFSET)) unsigned offset_raw_read; extern char diskbuf[2048]; #define BLK_PER_READ 4 #define MASK_BLK_PER_READ (BLK_PER_READ - 1) void RAW_READ(void *buf, daddr_t blkpos, size_t bytelen) { char *b = buf; size_t off, readlen; int devoff; static int prvdevoff = -dbtob(BLK_PER_READ); int pos; for ( ; bytelen > 0; b += readlen, bytelen -= readlen) { /* * read 2KB, avoiding unneeded read */ devoff = dbtob(blkpos & ~MASK_BLK_PER_READ) + offset_raw_read; if (prvdevoff != devoff) { #if 1 /* supports sequential media */ if ((*(unsigned *)(PZ_MEM_BOOT+DEV_CLASS) & DEV_CL_MASK) == DEV_CL_SEQU) { /* * sequential media * -- read sequentially or rewind */ pos = prvdevoff + dbtob(BLK_PER_READ); if (devoff < pos) pos = 0; /* rewind */ /* "repositioning media...\r\n" */ if (devoff - pos > 512 * 1024) print(str_seekseq); for (; pos < devoff; pos += dbtob(BLK_PER_READ)) boot_input(diskbuf, dbtob(BLK_PER_READ), pos); } #endif prvdevoff = devoff; boot_input(diskbuf, dbtob(BLK_PER_READ), devoff); } /* * copy specified size to the destination */ off = dbtob(blkpos & MASK_BLK_PER_READ), readlen = dbtob(BLK_PER_READ) - off; if (readlen > bytelen) readlen = bytelen; memcpy(b, diskbuf + off, readlen); blkpos = (blkpos & ~MASK_BLK_PER_READ) + BLK_PER_READ; } } /* * convert number to hex string * buf must have enough space */ static char * hexstr(char *buf, unsigned val) { unsigned v; char rev[16]; char *r = rev, *b = buf; /* inverse order */ do { v = val & 0xf; *r++ = (v <= 9) ? '0' + v : 'a' - 10 + v; val >>= 4; } while (val); /* reverse string */ while (r > rev) *b++ = *--r; *b = '\0'; return buf; } void ipl_main(unsigned interactive, unsigned sptop, unsigned psw) /* interactive: parameters from PDC */ /* sptop: value of sp on function entry */ /* psw: PSW on startup */ { char buf[32]; int part = 0; /* default partition "a" */ unsigned secsz, partoff, partsz; int c, c1; uintptr_t loadadr; #if 0 print(hexstr(buf, interactive)); print(str_crlf); print(hexstr(buf, sptop)); print(str_crlf); print(hexstr(buf, psw)); print(str_crlf); #endif print(hexstr(buf, (psw & 0x08000000) ? (unsigned) 0x64 : 0x32)); print(str_bit_firmware); /* "bit firmware\r\n" */ /* * check disklabel * (dklabel has disklabel on startup) */ if (dklabel.d_magic == DISKMAGIC && (secsz = dklabel.d_secsize) != 0) { /* * select boot partition */ if (interactive) { select_partition: /* "boot partition (a-p, ! to reboot) [a]:" */ print(str_bootpart); part = 0; /* default partition "a" */ c1 = 0; while ((c = getch()) >= 0) { switch (c) { case '\n': case '\r': goto break_while; case '\b': case '\177': if (c1) { print(str_rubout); part = c1 = 0; } break; case '!': /* reset */ if (c1 == 0) { part = -1; goto echoback; } break; default: if (c1 == 0 && c >= 'a' && c <= 'p') { part = c - 'a'; echoback: putch(c); c1 = 1; } break; } } break_while: if (part == -1) return; /* reset */ } /* * "\r\nbooting from partition _\r\n" */ str_booting_part[25] = 'a' + part; print(str_booting_part); partoff = dklabel.d_partitions[part].p_offset; partsz = dklabel.d_partitions[part].p_size; if (part >= (int) dklabel.d_npartitions || partsz == 0) { print(str_warn_unused); /* "unused partition\r\n" */ goto select_partition; } /* boot partition must be below 2GB */ if (partoff + partsz > ((unsigned)2*1024*1024*1024) / secsz) { /* "boot partition exceeds 2GB boundary\r\n" */ print(str_warn_2GB); goto select_partition; } /* * following device accesses are only in the partition */ offset_raw_read = partoff * secsz; } else { /* * no disklabel --- assume the whole of the device * is a filesystem */ print(str_nolabel); /* "no disklabel\r\n" */ } if (ufs_init()) { print(str_nofs); /* "no filesystem found\r\n" */ return; } str_filesystem[12] = (ufs_info.fstype == UFSTYPE_FFS) ? 'F' : 'L'; print(str_filesystem); /* "filesystem: _FS\r\n" */ loadadr = (sptop + STACK_SIZE + LOAD_ALIGN - 1) & (-LOAD_ALIGN); load_file(str_boot1, loadadr, interactive, part); /* "boot.hp700" */ load_file(str_boot2, loadadr, interactive, part); /* "boot" */ load_file(str_boot3, loadadr, interactive, part); /* "usr/mdec/boot" */ print(str_noboot); /* "no secondary boot found\r\n" */ } void load_file(const char *path, uintptr_t loadadr, unsigned interactive, int part) { /* look-up the file */ print(str_lookup); /* "looking up " */ print(path); print(str_crlf); load_file_ino(ufs_lookup_path(path), path, loadadr, interactive, part); } void load_file_ino(ino32_t ino, const char *fn, uintptr_t loadadr, unsigned interactive, int part) /* fn: for message only */ { union ufs_dinode dinode; size_t sz; struct loadinfo inf; char buf[32]; if (ino == 0 || ufs_get_inode(ino, &dinode)) return; /* not found */ print(str_loading); /* "loading " */ print(fn); print(str_at); /* " at 0x" */ print(hexstr(buf, loadadr)); print(str_dddot); /* "..." */ sz = DI_SIZE(&dinode); ufs_read(&dinode, (void *) loadadr, 0, sz); print(str_done); /* "done\r\n" */ /* digest executable format */ inf.sec_size = sz; inf.entry_offset = 0; if (xi_load(&inf, (void *) loadadr)) { print(fn); print(str_ukfmt); /* ": unknown format -- exec from top\r\n" */ } /* pass control to the secondary boot */ dispatch(interactive, loadadr, loadadr + inf.sec_size, part, loadadr + inf.entry_offset); } /* * fill in loading information from an ELF executable */ static inline void xi_elf32(struct loadinfo *inf, Elf32_Ehdr *hdr) { char *top = (void *) hdr; Elf32_Phdr *ph; /* text + data, bss */ ph = (void *) (top + hdr->e_phoff); inf->sec_image = top + ph->p_offset; inf->sec_size = ph->p_filesz; #if 0 inf->sec_pad = ph->p_memsz - ph->p_filesz; #endif /* entry */ inf->entry_offset = hdr->e_entry - ph->p_vaddr; } static inline void xi_elf64(struct loadinfo *inf, Elf64_Ehdr *hdr) { char *top = (void *) hdr; Elf64_Phdr *ph; /* * secondary boot is not so large, so 32bit (unsigned) arithmetic * is enough */ /* text + data, bss */ ph = (void *) (top + (unsigned) hdr->e_phoff); inf->sec_image = top + (unsigned) ph->p_offset; inf->sec_size = (unsigned) ph->p_filesz; #if 0 inf->sec_pad = (unsigned) ph->p_memsz - (unsigned) ph->p_filesz; #endif /* entry */ inf->entry_offset = (unsigned) hdr->e_entry - (unsigned) ph->p_vaddr; } int xi_load(struct loadinfo *inf, void *buf) { Elf32_Ehdr *e32hdr = buf; Elf64_Ehdr *e64hdr = buf; uint16_t class_data; /* * check ELF header * (optimized assuming big endian byte order) */ /* ELF magic */ if (*(uint32_t *)&e32hdr->e_ident[EI_MAG0] != (ELFMAG0 << 24 | ELFMAG1 << 16 | ELFMAG2 << 8 | ELFMAG3) || e32hdr->e_ident[EI_VERSION] != EV_CURRENT) return 1; /* Not an ELF */ /* file and machine type */ if (*(uint32_t *)&e32hdr->e_type != (ET_EXEC << 16 | EM_PARISC)) return 1; /* Not an executable / Wrong architecture */ if ((class_data = *(uint16_t *)&e32hdr->e_ident[EI_CLASS]) == (ELFCLASS32 << 8 | ELFDATA2MSB)) { /* support one section executable (ld -N) only */ if (e32hdr->e_phnum != 1) return 1; /* Wrong number of loading sections */ /* fill in loading information */ xi_elf32(inf, e32hdr); } else if (class_data == (ELFCLASS64 << 8 | ELFDATA2MSB)) { /* support one section executable (ld -N) only */ if (e64hdr->e_phnum != 1) return 1; /* Wrong number of loading sections */ /* fill in loading information */ xi_elf64(inf, e64hdr); } else return 1; /* Not a 32bit or 64bit ELF */ /* move text + data to the top address */ memmove(buf, inf->sec_image, inf->sec_size); #if 0 /* XXX bss clear is done by the secondary boot itself */ memset((char *) buf + inf->sec_size, 0, inf->sec_pad); #endif return 0; }