xref: /netbsd-src/sys/arch/hppa/stand/xxboot/main.c (revision 6d3ceb1d619615401b17c9aa3e4bc674a1cb048b)
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
RAW_READ(void * buf,daddr_t blkpos,size_t bytelen)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 *
hexstr(char * buf,unsigned val)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
ipl_main(unsigned interactive,unsigned sptop,unsigned psw)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
load_file(const char * path,uintptr_t loadadr,unsigned interactive,int part)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
load_file_ino(ino32_t ino,const char * fn,uintptr_t loadadr,unsigned interactive,int part)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
xi_elf32(struct loadinfo * inf,Elf32_Ehdr * hdr)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
xi_elf64(struct loadinfo * inf,Elf64_Ehdr * hdr)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
xi_load(struct loadinfo * inf,void * buf)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