No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hp700 / stand / xxboot / main.c
blob7c599c2815a3ba0c95ae819ad58af7016b171403
1 /* $NetBSD: main.c,v 1.8 2009/03/14 21:04:09 dsl Exp $ */
3 /*
4 * Copyright (c) 2003 ITOH Yasufumi.
5 * All rights reserved.
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.
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.
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"
34 #define STACK_SIZE ((unsigned) (64*1024))
35 #define LOAD_ALIGN ((unsigned) 2048)
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 */
42 static char *hexstr(char *, unsigned);
43 void ipl_main(unsigned /*interactive*/, unsigned /*sptop*/, unsigned /*psw*/);
44 void load_file(const char *, unsigned /*loadadr*/, unsigned /*interactive*/,
45 int /*part*/);
46 void load_file_ino(ino32_t, const char *, unsigned /*loadadr*/,
47 unsigned /*interactive*/, int /*part*/);
49 struct loadinfo {
50 void *sec_image;
51 unsigned sec_size;
52 #if 0
53 unsigned sec_pad;
54 #endif
55 unsigned entry_offset;
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 *);
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*/);
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[];
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);
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))
95 unsigned offset_raw_read;
97 extern char diskbuf[2048];
98 #define BLK_PER_READ 4
99 #define MASK_BLK_PER_READ (BLK_PER_READ - 1)
101 void
102 RAW_READ(void *buf, daddr_t blkpos, size_t bytelen)
104 char *b = buf;
105 size_t off, readlen;
106 int devoff;
107 static int prvdevoff = -dbtob(BLK_PER_READ);
108 int pos;
110 for ( ; bytelen > 0; b += readlen, bytelen -= readlen) {
112 * read 2KB, avoiding unneeded read
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) {
120 * sequential media
121 * -- read sequentially or rewind
123 pos = prvdevoff + dbtob(BLK_PER_READ);
124 if (devoff < pos)
125 pos = 0; /* rewind */
127 /* "repositioning media...\r\n" */
128 if (devoff - pos > 512 * 1024)
129 print(str_seekseq);
131 for (; pos < devoff; pos += dbtob(BLK_PER_READ))
132 boot_input(diskbuf,
133 dbtob(BLK_PER_READ), pos);
135 #endif
136 prvdevoff = devoff;
137 boot_input(diskbuf, dbtob(BLK_PER_READ), devoff);
140 * copy specified size to the destination
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;
152 * convert number to hex string
153 * buf must have enough space
155 static char *
156 hexstr(char *buf, unsigned val)
158 unsigned v;
159 char rev[16];
160 char *r = rev, *b = buf;
162 /* inverse order */
163 do {
164 v = val & 0xf;
165 *r++ = (v <= 9) ? '0' + v : 'a' - 10 + v;
166 val >>= 4;
167 } while (val);
169 /* reverse string */
170 while (r > rev)
171 *b++ = *--r;
173 *b = '\0';
174 return buf;
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 */
183 char buf[32];
184 int part = 0; /* default partition "a" */
185 unsigned secsz, partoff, partsz;
186 int c, c1;
187 unsigned loadadr;
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
198 print(hexstr(buf, (psw & 0x08000000) ? (unsigned) 0x64 : 0x32));
199 print(str_bit_firmware); /* "bit firmware\r\n" */
202 * check disklabel
203 * (dklabel has disklabel on startup)
205 if (dklabel.d_magic == DISKMAGIC && (secsz = dklabel.d_secsize) != 0) {
207 * select boot partition
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;
226 break;
227 case '!': /* reset */
228 if (c1 == 0) {
229 part = -1;
230 goto echoback;
232 break;
233 default:
234 if (c1 == 0 && c >= 'a' && c <= 'p') {
235 part = c - 'a';
236 echoback:
237 putch(c);
238 c1 = 1;
240 break;
243 break_while:
244 if (part == -1)
245 return; /* reset */
249 * "\r\nbooting from partition _\r\n"
251 str_booting_part[25] = 'a' + part;
252 print(str_booting_part);
254 partoff = dklabel.d_partitions[part].p_offset;
255 partsz = dklabel.d_partitions[part].p_size;
257 if (part >= (int) dklabel.d_npartitions || partsz == 0) {
258 print(str_warn_unused); /* "unused partition\r\n" */
259 goto select_partition;
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;
270 * following device accesses are only in the partition
272 offset_raw_read = partoff * secsz;
273 } else {
275 * no disklabel --- assume the whole of the device
276 * is a filesystem
278 print(str_nolabel); /* "no disklabel\r\n" */
281 if (ufs_init()) {
282 print(str_nofs); /* "no filesystem found\r\n" */
283 return;
285 str_filesystem[12] = (ufs_info.fstype == UFSTYPE_FFS) ? 'F' : 'L';
286 print(str_filesystem); /* "filesystem: _FS\r\n" */
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" */
293 print(str_noboot); /* "no secondary boot found\r\n" */
296 void
297 load_file(const char *path, unsigned loadadr, unsigned interactive, int part)
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);
307 void
308 load_file_ino(ino32_t ino, const char *fn, unsigned loadadr, unsigned interactive, int part)
309 /* fn: for message only */
311 union ufs_dinode dinode;
312 size_t sz;
313 struct loadinfo inf;
314 char buf[32];
316 if (ino == 0 || ufs_get_inode(ino, &dinode))
317 return; /* not found */
319 print(str_loading); /* "loading " */
320 print(fn);
321 print(str_at); /* " at 0x" */
322 print(hexstr(buf, loadadr));
323 print(str_dddot); /* "..." */
325 sz = DI_SIZE(&dinode);
326 ufs_read(&dinode, (void *) loadadr, 0, sz);
328 print(str_done); /* "done\r\n" */
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" */
338 /* pass control to the secondary boot */
339 dispatch(interactive, loadadr, loadadr + inf.sec_size, part,
340 loadadr + inf.entry_offset);
344 * fill in loading information from an ELF executable
346 static inline void
347 xi_elf32(struct loadinfo *inf, Elf32_Ehdr *hdr)
349 char *top = (void *) hdr;
350 Elf32_Phdr *ph;
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;
363 static inline void
364 xi_elf64(struct loadinfo *inf, Elf64_Ehdr *hdr)
366 char *top = (void *) hdr;
367 Elf64_Phdr *ph;
370 * secondary boot is not so large, so 32bit (unsigned) arithmetic
371 * is enough
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;
385 xi_load(struct loadinfo *inf, void *buf)
387 Elf32_Ehdr *e32hdr = buf;
388 Elf64_Ehdr *e64hdr = buf;
389 u_int16_t class_data;
392 * check ELF header
393 * (optimized assuming big endian byte order)
395 /* ELF magic */
396 if (*(u_int32_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 */
401 /* file and machine type */
402 if (*(u_int32_t *)&e32hdr->e_type != (ET_EXEC << 16 | EM_PARISC))
403 return 1; /* Not an executable / Wrong architecture */
405 if ((class_data = *(u_int16_t *)&e32hdr->e_ident[EI_CLASS]) ==
406 (ELFCLASS32 << 8 | ELFDATA2MSB)) {
408 /* support one section executable (ld -N) only */
409 if (e32hdr->e_phnum != 1)
410 return 1; /* Wrong number of loading sections */
412 /* fill in loading information */
413 xi_elf32(inf, e32hdr);
415 } else if (class_data == (ELFCLASS64 << 8 | ELFDATA2MSB)) {
417 /* support one section executable (ld -N) only */
418 if (e64hdr->e_phnum != 1)
419 return 1; /* Wrong number of loading sections */
421 /* fill in loading information */
422 xi_elf64(inf, e64hdr);
424 } else
425 return 1; /* Not a 32bit or 64bit ELF */
427 /* move text + data to the top address */
428 memmove(buf, inf->sec_image, inf->sec_size);
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
434 return 0;