Home | History | Annotate | Line # | Download | only in xxboot
      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