1 1.8 cegger /* $NetBSD: installboot.c,v 1.8 2009/03/18 10:22:34 cegger Exp $ */ 2 1.1 nonaka 3 1.1 nonaka /* 4 1.6 keihan * Copyright (c) 2000 NONAKA Kimihiro (nonaka (at) NetBSD.org). 5 1.1 nonaka * All rights reserved. 6 1.1 nonaka * 7 1.1 nonaka * Redistribution and use in source and binary forms, with or without 8 1.1 nonaka * modification, are permitted provided that the following conditions 9 1.1 nonaka * are met: 10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 11 1.1 nonaka * notice, this list of conditions and the following disclaimer. 12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 14 1.1 nonaka * documentation and/or other materials provided with the distribution. 15 1.1 nonaka * 3. The name of the author may not be used to endorse or promote products 16 1.1 nonaka * derived from this software without specific prior written permission. 17 1.1 nonaka * 18 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 nonaka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 nonaka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 nonaka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 nonaka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 nonaka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 nonaka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 nonaka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 nonaka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 1.1 nonaka * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 nonaka */ 29 1.1 nonaka 30 1.1 nonaka #include <sys/param.h> 31 1.1 nonaka #include <sys/exec_elf.h> 32 1.5 lukem #include <sys/bootblock.h> 33 1.1 nonaka 34 1.1 nonaka #include <stdio.h> 35 1.1 nonaka #include <stdlib.h> 36 1.1 nonaka #include <unistd.h> 37 1.1 nonaka #include <fcntl.h> 38 1.1 nonaka #include <err.h> 39 1.4 he #include <string.h> 40 1.1 nonaka 41 1.1 nonaka int nowrite, verbose; 42 1.1 nonaka char *boot, *dev; 43 1.1 nonaka 44 1.1 nonaka void usage(void); 45 1.1 nonaka int devread(int, void *, daddr_t, size_t, char *); 46 1.1 nonaka char *load_boot(char *, size_t *); 47 1.1 nonaka int load_prep_partition(int, struct mbr_partition *); 48 1.1 nonaka int main(int, char **); 49 1.1 nonaka 50 1.1 nonaka void 51 1.8 cegger usage(void) 52 1.1 nonaka { 53 1.1 nonaka 54 1.2 cgd fprintf(stderr, "usage: %s [-n] [-v] <boot> <device>\n", 55 1.2 cgd getprogname()); 56 1.1 nonaka exit(1); 57 1.1 nonaka } 58 1.1 nonaka 59 1.1 nonaka int 60 1.1 nonaka devread(int fd, void *buf, daddr_t blk, size_t size, char *msg) 61 1.1 nonaka { 62 1.1 nonaka 63 1.1 nonaka if (lseek(fd, (off_t)dbtob(blk), SEEK_SET) != dbtob(blk)) { 64 1.1 nonaka warn("%s: devread: lseek", msg); 65 1.1 nonaka return 1; 66 1.1 nonaka } 67 1.1 nonaka if (read(fd, buf, size) != size) { 68 1.1 nonaka warn("%s: devread: read", msg); 69 1.1 nonaka return 1; 70 1.1 nonaka } 71 1.1 nonaka return 0; 72 1.1 nonaka } 73 1.1 nonaka 74 1.1 nonaka char * 75 1.1 nonaka load_boot(char *boot, size_t *bootsize) 76 1.1 nonaka { 77 1.1 nonaka Elf32_Ehdr eh; 78 1.1 nonaka Elf32_Phdr ph; 79 1.1 nonaka struct stat st; 80 1.1 nonaka int fd; 81 1.1 nonaka int i; 82 1.1 nonaka size_t imgsz = 0; 83 1.1 nonaka char *bp = NULL; 84 1.1 nonaka 85 1.1 nonaka if ((fd = open(boot, O_RDONLY)) < 0) { 86 1.1 nonaka warn("open: %s", boot); 87 1.1 nonaka return NULL; 88 1.1 nonaka } 89 1.1 nonaka 90 1.1 nonaka if (fstat(fd, &st) != 0) { 91 1.1 nonaka warn("fstat: %s", boot); 92 1.1 nonaka goto out; 93 1.1 nonaka } 94 1.1 nonaka 95 1.1 nonaka /* 96 1.1 nonaka * First, check ELF. 97 1.1 nonaka */ 98 1.1 nonaka if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) { 99 1.1 nonaka warn("read: eh: %s", boot); 100 1.1 nonaka goto out; 101 1.1 nonaka } 102 1.1 nonaka if (memcmp(eh.e_ident, ELFMAG, SELFMAG) != 0 || 103 1.1 nonaka eh.e_ident[EI_CLASS] != ELFCLASS32) { 104 1.1 nonaka lseek(fd, 0L, SEEK_SET); 105 1.1 nonaka goto notelf; 106 1.1 nonaka } 107 1.1 nonaka if (be16toh(eh.e_machine) != EM_PPC) { 108 1.1 nonaka warn("not PowerPC binary."); 109 1.1 nonaka goto out; 110 1.1 nonaka } 111 1.1 nonaka 112 1.1 nonaka for (i = 0; i < be16toh(eh.e_phnum); i++) { 113 1.1 nonaka (void)lseek(fd, be32toh(eh.e_phoff) + sizeof(ph) * i, SEEK_SET); 114 1.1 nonaka if (read(fd, &ph, sizeof(ph)) != sizeof(ph)) { 115 1.1 nonaka warn("read: ph: %s", boot); 116 1.1 nonaka goto out; 117 1.1 nonaka } 118 1.1 nonaka 119 1.1 nonaka if ((be32toh(ph.p_type) != PT_LOAD) || 120 1.1 nonaka !(be32toh(ph.p_flags) & PF_X)) 121 1.1 nonaka continue; 122 1.1 nonaka 123 1.1 nonaka imgsz = st.st_size - be32toh(ph.p_offset); 124 1.1 nonaka lseek(fd, be32toh(ph.p_offset), SEEK_SET); 125 1.1 nonaka break; 126 1.1 nonaka } 127 1.1 nonaka 128 1.1 nonaka notelf: 129 1.1 nonaka /* 130 1.1 nonaka * Second, check PReP bootable image. 131 1.1 nonaka */ 132 1.1 nonaka if (imgsz == 0) { 133 1.1 nonaka char buf[DEV_BSIZE]; 134 1.1 nonaka 135 1.1 nonaka printf("Bootable image: "); 136 1.1 nonaka if (load_prep_partition(fd, 0)) { 137 1.1 nonaka warn("no PReP bootable image."); 138 1.1 nonaka goto out; 139 1.1 nonaka } 140 1.1 nonaka 141 1.1 nonaka if (lseek(fd, (off_t)dbtob(1), SEEK_SET) != dbtob(1)) { 142 1.1 nonaka warn("bootable image lseek sector 1"); 143 1.1 nonaka goto out; 144 1.1 nonaka } 145 1.1 nonaka if (read(fd, buf, DEV_BSIZE) != DEV_BSIZE) { 146 1.1 nonaka warn("read: start/size"); 147 1.1 nonaka goto out; 148 1.1 nonaka } 149 1.1 nonaka 150 1.1 nonaka imgsz = le32toh(*(u_int32_t *)(buf + sizeof(u_int32_t))) 151 1.1 nonaka - dbtob(2); 152 1.1 nonaka lseek(fd, le32toh(*(u_int32_t *)buf), SEEK_SET); 153 1.1 nonaka } 154 1.1 nonaka 155 1.1 nonaka if ((bp = (char *)calloc(roundup(imgsz, DEV_BSIZE), 1)) == NULL) { 156 1.1 nonaka warn("calloc: no memory for boot image."); 157 1.1 nonaka goto out; 158 1.1 nonaka } 159 1.1 nonaka 160 1.1 nonaka if (read(fd, bp, imgsz) != imgsz) { 161 1.1 nonaka warn("read: boot image: %s", boot); 162 1.1 nonaka goto out; 163 1.1 nonaka } 164 1.1 nonaka 165 1.1 nonaka if (verbose) { 166 1.1 nonaka printf("image size = %d\n", imgsz); 167 1.1 nonaka } 168 1.1 nonaka 169 1.1 nonaka *bootsize = roundup(imgsz, DEV_BSIZE); 170 1.1 nonaka 171 1.1 nonaka close(fd); 172 1.1 nonaka return bp; 173 1.1 nonaka 174 1.1 nonaka out: 175 1.1 nonaka if (bp != NULL) 176 1.1 nonaka free(bp); 177 1.1 nonaka if (fd >= 0) 178 1.1 nonaka close(fd); 179 1.1 nonaka return NULL; 180 1.1 nonaka } 181 1.1 nonaka 182 1.1 nonaka int 183 1.1 nonaka load_prep_partition(int devfd, struct mbr_partition *ppp) 184 1.1 nonaka { 185 1.1 nonaka char mbr[512]; 186 1.1 nonaka struct mbr_partition *mbrp; 187 1.1 nonaka int i; 188 1.1 nonaka 189 1.1 nonaka if (devread(devfd, mbr, MBR_BBSECTOR, DEV_BSIZE, "MBR") != 0) 190 1.1 nonaka return 1; 191 1.5 lukem if (*(u_int16_t *)&mbr[MBR_MAGIC_OFFSET] != htole16(MBR_MAGIC)) { 192 1.1 nonaka warn("no MBR_MAGIC"); 193 1.1 nonaka return 1; 194 1.1 nonaka } 195 1.1 nonaka 196 1.5 lukem mbrp = (struct mbr_partition *)&mbr[MBR_PART_OFFSET]; 197 1.5 lukem for (i = 0; i < MBR_PART_COUNT; i++) { 198 1.5 lukem if (mbrp[i].mbrp_type == MBR_PTYPE_PREP) 199 1.1 nonaka break; 200 1.1 nonaka } 201 1.5 lukem if (i == MBR_PART_COUNT) { 202 1.1 nonaka warn("no PReP partition."); 203 1.1 nonaka return 1; 204 1.1 nonaka } 205 1.1 nonaka 206 1.1 nonaka if (verbose) { 207 1.1 nonaka printf("PReP partition: start = %d, size = %d\n", 208 1.1 nonaka le32toh(mbrp[i].mbrp_start), le32toh(mbrp[i].mbrp_size)); 209 1.1 nonaka } 210 1.1 nonaka 211 1.1 nonaka if (ppp) { 212 1.1 nonaka *ppp = mbrp[i]; 213 1.1 nonaka ppp->mbrp_start = le32toh(ppp->mbrp_start); 214 1.1 nonaka ppp->mbrp_size = le32toh(ppp->mbrp_size); 215 1.1 nonaka } 216 1.1 nonaka 217 1.1 nonaka return 0; 218 1.1 nonaka } 219 1.1 nonaka 220 1.1 nonaka int 221 1.1 nonaka main(int argc, char **argv) 222 1.1 nonaka { 223 1.1 nonaka struct mbr_partition ppp; 224 1.1 nonaka size_t bootsize; 225 1.1 nonaka int c; 226 1.1 nonaka int boot00[512/sizeof(int)]; 227 1.1 nonaka int devfd = -1; 228 1.1 nonaka char *bp; 229 1.1 nonaka 230 1.1 nonaka while ((c = getopt(argc, argv, "vn")) != EOF) { 231 1.1 nonaka switch (c) { 232 1.1 nonaka case 'n': 233 1.1 nonaka nowrite = 1; 234 1.1 nonaka break; 235 1.1 nonaka case 'v': 236 1.1 nonaka verbose = 1; 237 1.1 nonaka break; 238 1.1 nonaka default: 239 1.1 nonaka usage(); 240 1.1 nonaka break; 241 1.1 nonaka } 242 1.1 nonaka } 243 1.1 nonaka 244 1.1 nonaka if (argc - optind < 2) 245 1.1 nonaka usage(); 246 1.1 nonaka 247 1.1 nonaka boot = argv[optind]; 248 1.1 nonaka dev = argv[optind + 1]; 249 1.1 nonaka if (verbose) { 250 1.1 nonaka printf("boot: %s\n", boot); 251 1.1 nonaka printf("dev: %s\n", dev); 252 1.1 nonaka } 253 1.1 nonaka 254 1.1 nonaka if ((bp = load_boot(boot, &bootsize)) == NULL) 255 1.1 nonaka return 1; 256 1.1 nonaka 257 1.1 nonaka if ((devfd = open(dev, O_RDONLY, 0)) < 0) { 258 1.1 nonaka warn("open: %s", dev); 259 1.1 nonaka goto out; 260 1.1 nonaka } 261 1.1 nonaka 262 1.1 nonaka if (load_prep_partition(devfd, &ppp)) { 263 1.1 nonaka warn("load_prep_partition"); 264 1.1 nonaka goto out; 265 1.1 nonaka } 266 1.1 nonaka 267 1.1 nonaka if (bootsize + dbtob(2) > dbtob(ppp.mbrp_size)) { 268 1.1 nonaka warn("boot image is too big."); 269 1.1 nonaka goto out; 270 1.1 nonaka } 271 1.1 nonaka 272 1.1 nonaka close(devfd); 273 1.1 nonaka 274 1.1 nonaka if (nowrite) { 275 1.1 nonaka free(bp); 276 1.1 nonaka return 0; 277 1.1 nonaka } 278 1.1 nonaka 279 1.1 nonaka if ((devfd = open(dev, O_RDWR, 0)) < 0) { 280 1.1 nonaka warn("open: %s", dev); 281 1.1 nonaka goto out; 282 1.1 nonaka } 283 1.1 nonaka 284 1.1 nonaka /* 285 1.1 nonaka * Write boot image. 286 1.1 nonaka */ 287 1.1 nonaka memset(boot00, 0, sizeof(boot00)); 288 1.1 nonaka (void)lseek(devfd, (off_t)dbtob(ppp.mbrp_start), SEEK_SET); 289 1.1 nonaka if (write(devfd, boot00, sizeof(boot00)) != sizeof(boot00)) { 290 1.1 nonaka warn("write boot00(prep mbr)"); 291 1.1 nonaka goto out; 292 1.1 nonaka } 293 1.1 nonaka 294 1.1 nonaka (void)lseek(devfd, (off_t)dbtob(ppp.mbrp_start+1), SEEK_SET); 295 1.1 nonaka boot00[0] = htole32(dbtob(2)); 296 1.1 nonaka boot00[1] = htole32(bootsize); 297 1.1 nonaka if (write(devfd, boot00, sizeof(boot00)) != sizeof(boot00)) { 298 1.1 nonaka warn("write boot00(prep start/size)"); 299 1.1 nonaka goto out; 300 1.1 nonaka } 301 1.1 nonaka 302 1.1 nonaka if (devread(devfd, boot00, 1, DEV_BSIZE, "start/size") != 0) 303 1.1 nonaka goto out; 304 1.1 nonaka boot00[0] = htole32(dbtob(ppp.mbrp_start)); 305 1.1 nonaka boot00[1] = htole32(bootsize + dbtob(2)); 306 1.1 nonaka (void)lseek(devfd, (off_t)dbtob(1), SEEK_SET); 307 1.1 nonaka if (write(devfd, boot00, sizeof(boot00)) != sizeof(boot00)) { 308 1.1 nonaka warn("write boot00(master start/size)"); 309 1.1 nonaka goto out; 310 1.1 nonaka } 311 1.1 nonaka 312 1.1 nonaka (void)lseek(devfd, (off_t)dbtob(ppp.mbrp_start+2), SEEK_SET); 313 1.1 nonaka if (write(devfd, bp, bootsize) != bootsize) { 314 1.1 nonaka warn("write boot loader"); 315 1.1 nonaka goto out; 316 1.1 nonaka } 317 1.1 nonaka 318 1.1 nonaka close(devfd); 319 1.1 nonaka free(bp); 320 1.1 nonaka return 0; 321 1.1 nonaka 322 1.1 nonaka out: 323 1.1 nonaka if (devfd >= 0) 324 1.1 nonaka close(devfd); 325 1.1 nonaka if (bp != NULL) 326 1.1 nonaka free(bp); 327 1.1 nonaka return 1; 328 1.1 nonaka } 329