1 /* $NetBSD: installboot.c,v 1.7 2005/12/11 12:18:51 christos Exp $ */
4 * Copyright (c) 2000 NONAKA Kimihiro (nonaka@NetBSD.org).
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 form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/param.h>
31 #include <sys/exec_elf.h>
32 #include <sys/bootblock.h>
45 int devread(int, void *, daddr_t
, size_t, char *);
46 char *load_boot(char *, size_t *);
47 int load_prep_partition(int, struct mbr_partition
*);
48 int main(int, char **);
54 fprintf(stderr
, "usage: %s [-n] [-v] <boot> <device>\n",
60 devread(int fd
, void *buf
, daddr_t blk
, size_t size
, char *msg
)
63 if (lseek(fd
, (off_t
)dbtob(blk
), SEEK_SET
) != dbtob(blk
)) {
64 warn("%s: devread: lseek", msg
);
67 if (read(fd
, buf
, size
) != size
) {
68 warn("%s: devread: read", msg
);
75 load_boot(char *boot
, size_t *bootsize
)
85 if ((fd
= open(boot
, O_RDONLY
)) < 0) {
86 warn("open: %s", boot
);
90 if (fstat(fd
, &st
) != 0) {
91 warn("fstat: %s", boot
);
98 if (read(fd
, &eh
, sizeof(eh
)) != sizeof(eh
)) {
99 warn("read: eh: %s", boot
);
102 if (memcmp(eh
.e_ident
, ELFMAG
, SELFMAG
) != 0 ||
103 eh
.e_ident
[EI_CLASS
] != ELFCLASS32
) {
104 lseek(fd
, 0L, SEEK_SET
);
107 if (be16toh(eh
.e_machine
) != EM_PPC
) {
108 warn("not PowerPC binary.");
112 for (i
= 0; i
< be16toh(eh
.e_phnum
); i
++) {
113 (void)lseek(fd
, be32toh(eh
.e_phoff
) + sizeof(ph
) * i
, SEEK_SET
);
114 if (read(fd
, &ph
, sizeof(ph
)) != sizeof(ph
)) {
115 warn("read: ph: %s", boot
);
119 if ((be32toh(ph
.p_type
) != PT_LOAD
) ||
120 !(be32toh(ph
.p_flags
) & PF_X
))
123 imgsz
= st
.st_size
- be32toh(ph
.p_offset
);
124 lseek(fd
, be32toh(ph
.p_offset
), SEEK_SET
);
130 * Second, check PReP bootable image.
135 printf("Bootable image: ");
136 if (load_prep_partition(fd
, 0)) {
137 warn("no PReP bootable image.");
141 if (lseek(fd
, (off_t
)dbtob(1), SEEK_SET
) != dbtob(1)) {
142 warn("bootable image lseek sector 1");
145 if (read(fd
, buf
, DEV_BSIZE
) != DEV_BSIZE
) {
146 warn("read: start/size");
150 imgsz
= le32toh(*(u_int32_t
*)(buf
+ sizeof(u_int32_t
)))
152 lseek(fd
, le32toh(*(u_int32_t
*)buf
), SEEK_SET
);
155 if ((bp
= (char *)calloc(roundup(imgsz
, DEV_BSIZE
), 1)) == NULL
) {
156 warn("calloc: no memory for boot image.");
160 if (read(fd
, bp
, imgsz
) != imgsz
) {
161 warn("read: boot image: %s", boot
);
166 printf("image size = %d\n", imgsz
);
169 *bootsize
= roundup(imgsz
, DEV_BSIZE
);
183 load_prep_partition(int devfd
, struct mbr_partition
*ppp
)
186 struct mbr_partition
*mbrp
;
189 if (devread(devfd
, mbr
, MBR_BBSECTOR
, DEV_BSIZE
, "MBR") != 0)
191 if (*(u_int16_t
*)&mbr
[MBR_MAGIC_OFFSET
] != htole16(MBR_MAGIC
)) {
192 warn("no MBR_MAGIC");
196 mbrp
= (struct mbr_partition
*)&mbr
[MBR_PART_OFFSET
];
197 for (i
= 0; i
< MBR_PART_COUNT
; i
++) {
198 if (mbrp
[i
].mbrp_type
== MBR_PTYPE_PREP
)
201 if (i
== MBR_PART_COUNT
) {
202 warn("no PReP partition.");
207 printf("PReP partition: start = %d, size = %d\n",
208 le32toh(mbrp
[i
].mbrp_start
), le32toh(mbrp
[i
].mbrp_size
));
213 ppp
->mbrp_start
= le32toh(ppp
->mbrp_start
);
214 ppp
->mbrp_size
= le32toh(ppp
->mbrp_size
);
221 main(int argc
, char **argv
)
223 struct mbr_partition ppp
;
226 int boot00
[512/sizeof(int)];
230 while ((c
= getopt(argc
, argv
, "vn")) != EOF
) {
244 if (argc
- optind
< 2)
248 dev
= argv
[optind
+ 1];
250 printf("boot: %s\n", boot
);
251 printf("dev: %s\n", dev
);
254 if ((bp
= load_boot(boot
, &bootsize
)) == NULL
)
257 if ((devfd
= open(dev
, O_RDONLY
, 0)) < 0) {
258 warn("open: %s", dev
);
262 if (load_prep_partition(devfd
, &ppp
)) {
263 warn("load_prep_partition");
267 if (bootsize
+ dbtob(2) > dbtob(ppp
.mbrp_size
)) {
268 warn("boot image is too big.");
279 if ((devfd
= open(dev
, O_RDWR
, 0)) < 0) {
280 warn("open: %s", dev
);
287 memset(boot00
, 0, sizeof(boot00
));
288 (void)lseek(devfd
, (off_t
)dbtob(ppp
.mbrp_start
), SEEK_SET
);
289 if (write(devfd
, boot00
, sizeof(boot00
)) != sizeof(boot00
)) {
290 warn("write boot00(prep mbr)");
294 (void)lseek(devfd
, (off_t
)dbtob(ppp
.mbrp_start
+1), SEEK_SET
);
295 boot00
[0] = htole32(dbtob(2));
296 boot00
[1] = htole32(bootsize
);
297 if (write(devfd
, boot00
, sizeof(boot00
)) != sizeof(boot00
)) {
298 warn("write boot00(prep start/size)");
302 if (devread(devfd
, boot00
, 1, DEV_BSIZE
, "start/size") != 0)
304 boot00
[0] = htole32(dbtob(ppp
.mbrp_start
));
305 boot00
[1] = htole32(bootsize
+ dbtob(2));
306 (void)lseek(devfd
, (off_t
)dbtob(1), SEEK_SET
);
307 if (write(devfd
, boot00
, sizeof(boot00
)) != sizeof(boot00
)) {
308 warn("write boot00(master start/size)");
312 (void)lseek(devfd
, (off_t
)dbtob(ppp
.mbrp_start
+2), SEEK_SET
);
313 if (write(devfd
, bp
, bootsize
) != bootsize
) {
314 warn("write boot loader");