1 /* $NetBSD: main.c,v 1.8 2009/03/14 21:04:09 dsl Exp $ */
4 * Copyright (c) 2003 ITOH Yasufumi.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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>
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*/,
46 void load_file_ino(ino32_t
, const char *, unsigned /*loadadr*/,
47 unsigned /*interactive*/, int /*part*/);
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 *);
63 void dispatch(unsigned /*interactive*/, unsigned /*top*/,
64 unsigned /*end*/, int /*part*/, unsigned /*entry*/);
65 void print(const char *);
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
[];
82 #define memcpy(d, s, n) __builtin_memcpy(d, s, n)
84 void *memcpy(void *, const void *, size_t);
86 void *memmove(void *, const void *, size_t);
91 struct disklabel dkl
; /* to ensure alignment */
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)
102 RAW_READ(void *buf
, daddr_t blkpos
, size_t bytelen
)
107 static int prvdevoff
= -dbtob(BLK_PER_READ
);
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
)
121 * -- read sequentially or rewind
123 pos
= prvdevoff
+ dbtob(BLK_PER_READ
);
125 pos
= 0; /* rewind */
127 /* "repositioning media...\r\n" */
128 if (devoff
- pos
> 512 * 1024)
131 for (; pos
< devoff
; pos
+= dbtob(BLK_PER_READ
))
133 dbtob(BLK_PER_READ
), pos
);
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
)
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
156 hexstr(char *buf
, unsigned val
)
160 char *r
= rev
, *b
= buf
;
165 *r
++ = (v
<= 9) ? '0' + v
: 'a' - 10 + v
;
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 */
184 int part
= 0; /* default partition "a" */
185 unsigned secsz
, partoff
, partsz
;
190 print(hexstr(buf
, interactive
));
192 print(hexstr(buf
, sptop
));
194 print(hexstr(buf
, psw
));
198 print(hexstr(buf
, (psw
& 0x08000000) ? (unsigned) 0x64 : 0x32));
199 print(str_bit_firmware
); /* "bit firmware\r\n" */
203 * (dklabel has disklabel on startup)
205 if (dklabel
.d_magic
== DISKMAGIC
&& (secsz
= dklabel
.d_secsize
) != 0) {
207 * select boot partition
211 /* "boot partition (a-p, ! to reboot) [a]:" */
213 part
= 0; /* default partition "a" */
215 while ((c
= getch()) >= 0) {
227 case '!': /* reset */
234 if (c1
== 0 && c
>= 'a' && c
<= 'p') {
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" */
266 goto select_partition
;
270 * following device accesses are only in the partition
272 offset_raw_read
= partoff
* secsz
;
275 * no disklabel --- assume the whole of the device
278 print(str_nolabel
); /* "no disklabel\r\n" */
282 print(str_nofs
); /* "no filesystem found\r\n" */
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" */
297 load_file(const char *path
, unsigned loadadr
, unsigned interactive
, int part
)
300 /* look-up the file */
301 print(str_lookup
); /* "looking up " */
304 load_file_ino(ufs_lookup_path(path
), path
, loadadr
, interactive
, part
);
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
;
316 if (ino
== 0 || ufs_get_inode(ino
, &dinode
))
317 return; /* not found */
319 print(str_loading
); /* "loading " */
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 */
332 inf
.entry_offset
= 0;
333 if (xi_load(&inf
, (void *) loadadr
)) {
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
347 xi_elf32(struct loadinfo
*inf
, Elf32_Ehdr
*hdr
)
349 char *top
= (void *) hdr
;
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
;
357 inf
->sec_pad
= ph
->p_memsz
- ph
->p_filesz
;
360 inf
->entry_offset
= hdr
->e_entry
- ph
->p_vaddr
;
364 xi_elf64(struct loadinfo
*inf
, Elf64_Ehdr
*hdr
)
366 char *top
= (void *) hdr
;
370 * secondary boot is not so large, so 32bit (unsigned) arithmetic
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
;
378 inf
->sec_pad
= (unsigned) ph
->p_memsz
- (unsigned) ph
->p_filesz
;
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
;
393 * (optimized assuming big endian byte order)
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
);
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
);