This source file includes following definitions.
- usage
- main
- loadproto
- devread
- getbootparams
- sym_set_value
- pbr_set_symbols
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 #include <sys/param.h>
37 #include <sys/mount.h>
38 #include <sys/time.h>
39 #include <sys/stat.h>
40 #include <sys/disklabel.h>
41 #include <sys/dkio.h>
42 #include <sys/ioctl.h>
43 #include <ufs/ufs/dinode.h>
44 #include <ufs/ufs/dir.h>
45 #include <ufs/ffs/fs.h>
46 #include <sys/reboot.h>
47
48 #include <uvm/uvm_extern.h>
49 #include <sys/sysctl.h>
50
51 #include <machine/cpu.h>
52 #include <machine/biosvar.h>
53
54 #include <err.h>
55 #include <a.out.h>
56 #include <sys/exec_elf.h>
57 #include <fcntl.h>
58 #include <nlist.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <util.h>
64
65 struct sym_data {
66 char *sym_name;
67 int sym_size;
68 int sym_set;
69 u_int32_t sym_value;
70 };
71
72 extern char *__progname;
73 int verbose, nowrite = 0;
74 char *boot, *proto, *dev, *realdev;
75 struct sym_data pbr_symbols[] = {
76 {"_fs_bsize_p", 2},
77 {"_fs_bsize_s", 2},
78 {"_fsbtodb", 1},
79 {"_p_offset", 4},
80 {"_inodeblk", 4},
81 {"_inodedbl", 4},
82 {"_nblocks", 2},
83 {NULL}
84 };
85
86 #define INODESEG 0x07e0
87 #define BOOTSEG 0x07c0
88
89 #define INODEOFF ((INODESEG-BOOTSEG) << 4)
90
91 static char *loadproto(char *, long *);
92 static int getbootparams(char *, int, struct disklabel *);
93 static void devread(int, void *, daddr_t, size_t, char *);
94 static void sym_set_value(struct sym_data *, char *, u_int32_t);
95 static void pbr_set_symbols(char *, char *, struct sym_data *);
96 static void usage(void);
97
98 static void
99 usage(void)
100 {
101 fprintf(stderr, "usage: %s [-nv] boot biosboot device\n", __progname);
102 exit(1);
103 }
104
105
106
107
108
109
110 int
111 main(int argc, char *argv[])
112 {
113 int c;
114 int devfd;
115 char *protostore;
116 long protosize;
117 struct stat sb;
118 struct disklabel dl;
119 struct dos_mbr mbr;
120 struct dos_partition *dp;
121 off_t startoff = 0;
122
123 while ((c = getopt(argc, argv, "vn")) != -1) {
124 switch (c) {
125 case 'n':
126
127 nowrite = 1;
128 break;
129 case 'v':
130
131 verbose = 1;
132 break;
133 default:
134 usage();
135 }
136 }
137
138 if (argc - optind < 3)
139 usage();
140
141 boot = argv[optind];
142 proto = argv[optind + 1];
143 realdev = dev = argv[optind + 2];
144
145
146 if ((devfd = opendev(dev, (nowrite? O_RDONLY:O_RDWR),
147 OPENDEV_PART, &realdev)) < 0)
148 err(1, "open: %s", realdev);
149
150 if (verbose) {
151 fprintf(stderr, "boot: %s\n", boot);
152 fprintf(stderr, "proto: %s\n", proto);
153 fprintf(stderr, "device: %s\n", realdev);
154 }
155
156 if (ioctl(devfd, DIOCGDINFO, &dl) != 0)
157 err(1, "disklabel: %s", realdev);
158
159
160 if (dl.d_magic != DISKMAGIC)
161 err(1, "bad disklabel magic=0x%08x", dl.d_magic);
162
163
164 if (dl.d_type == 0)
165 warnx("disklabel type unknown");
166
167
168 if ((protostore = loadproto(proto, &protosize)) == NULL)
169 exit(1);
170
171
172 if (protosize & (DEV_BSIZE - 1))
173 errx(1, "proto %s bad size=%ld", proto, protosize);
174
175
176 if (protosize > SBSIZE - DEV_BSIZE)
177 errx(1, "proto bootblocks too big");
178
179 if (fstat(devfd, &sb) < 0)
180 err(1, "stat: %s", realdev);
181
182 if (!S_ISCHR(sb.st_mode))
183 errx(1, "%s: not a character device", realdev);
184
185
186 if (getbootparams(boot, devfd, &dl) != 0)
187 exit(1);
188
189
190 pbr_set_symbols(proto, protostore, pbr_symbols);
191
192 if (!nowrite) {
193
194 sync(); sleep(1);
195 }
196
197 if (dl.d_type != 0 && dl.d_type != DTYPE_FLOPPY &&
198 dl.d_type != DTYPE_VND) {
199 if (lseek(devfd, (off_t)DOSBBSECTOR, SEEK_SET) < 0 ||
200 read(devfd, &mbr, sizeof(mbr)) < sizeof(mbr))
201 err(4, "can't read master boot record");
202
203 if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
204 errx(1, "broken MBR");
205
206
207 for (dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART];
208 dp++) {
209 if (dp->dp_size && dp->dp_typ == DOSPTYP_OPENBSD) {
210 startoff = (off_t)dp->dp_start * dl.d_secsize;
211 fprintf(stderr, "using MBR partition %ld: "
212 "type %d (0x%02x) offset %d (0x%x)\n",
213 (long)(dp - mbr.dmbr_parts),
214 dp->dp_typ, dp->dp_typ,
215 dp->dp_start, dp->dp_start);
216 break;
217 }
218 }
219
220 if (dp >= &mbr.dmbr_parts[NDOSPART])
221 errx(1, "no OpenBSD partition");
222 }
223
224 if (!nowrite) {
225 if (lseek(devfd, startoff, SEEK_SET) < 0 ||
226 write(devfd, protostore, protosize) != protosize)
227 err(1, "write bootstrap");
228 }
229
230 (void)close(devfd);
231
232 return 0;
233 }
234
235
236
237
238 static char *
239 loadproto(char *fname, long *size)
240 {
241 int fd;
242 size_t tdsize;
243 char *bp;
244 Elf_Ehdr eh;
245 Elf_Word phsize;
246 Elf_Phdr *ph;
247
248 if ((fd = open(fname, O_RDONLY)) < 0)
249 err(1, "%s", fname);
250
251 if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
252 errx(1, "%s: read failed", fname);
253
254 if (!IS_ELF(eh))
255 errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
256 boot,
257 eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
258 eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
259
260
261
262
263
264
265
266
267 if (eh.e_phnum != 1)
268 errx(1, "%s: %u ELF load sections (only support 1)",
269 boot, eh.e_phnum);
270
271 phsize = eh.e_phnum * sizeof(Elf_Phdr);
272 ph = malloc(phsize);
273 if (ph == NULL)
274 err(1, NULL);
275
276 lseek(fd, eh.e_phoff, SEEK_SET);
277
278 if (read(fd, ph, phsize) != phsize)
279 errx(1, "%s: can't read header", boot);
280
281 tdsize = ph->p_filesz;
282
283
284
285
286
287
288 if ((bp = calloc(tdsize, 1)) == NULL) {
289 err(1, NULL);
290 }
291
292
293 lseek(fd, ph->p_offset, SEEK_SET);
294 if (read(fd, bp, tdsize) != tdsize) {
295 errx(1, "%s: read failed", fname);
296 }
297
298 *size = tdsize;
299
300 if (verbose) {
301 fprintf(stderr, "%s: entry point %#x\n", fname, eh.e_entry);
302 fprintf(stderr, "proto bootblock size %ld\n", *size);
303 }
304
305 close(fd);
306 return bp;
307 }
308
309 static void
310 devread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
311 {
312 if (lseek(fd, dbtob((off_t)blk), SEEK_SET) != dbtob((off_t)blk))
313 err(1, "%s: devread: lseek", msg);
314
315 if (read(fd, buf, size) != size)
316 err(1, "%s: devread: read", msg);
317 }
318
319 static char sblock[SBSIZE];
320
321
322
323
324
325 static int
326 getbootparams(char *boot, int devfd, struct disklabel *dl)
327 {
328 int fd;
329 struct stat statbuf, sb;
330 struct statfs statfsbuf;
331 struct partition *pl;
332 struct fs *fs;
333 char *buf;
334 daddr_t blk, *ap;
335 struct ufs1_dinode *ip;
336 int ndb;
337 int mib[3];
338 size_t size;
339 dev_t dev;
340
341
342
343
344
345
346
347
348
349
350 sync(); sleep(1);
351
352 if ((fd = open(boot, O_RDONLY)) < 0)
353 err(1, "open: %s", boot);
354
355 if (fstatfs(fd, &statfsbuf) != 0)
356 err(1, "statfs: %s", boot);
357
358 if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
359 strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) )
360 errx(1, "%s: not on an FFS filesystem", boot);
361
362 #if 0
363 if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
364 errx(1, "read: %s", boot);
365
366 if (!IS_ELF(eh)) {
367 errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
368 boot,
369 eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
370 eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
371 }
372 #endif
373
374 if (fsync(fd) != 0)
375 err(1, "fsync: %s", boot);
376
377 if (fstat(fd, &statbuf) != 0)
378 err(1, "fstat: %s", boot);
379
380 if (fstat(devfd, &sb) != 0)
381 err(1, "fstat: %s", realdev);
382
383
384 mib[0] = CTL_MACHDEP;
385 mib[1] = CPU_CHR2BLK;
386 mib[2] = sb.st_rdev;
387 size = sizeof(dev);
388 if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) {
389 if (statbuf.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS)
390 errx(1, "cross-device install");
391 }
392
393 pl = &dl->d_partitions[DISKPART(statbuf.st_dev)];
394 close(fd);
395
396
397 devread(devfd, sblock, pl->p_offset + SBLOCK, SBSIZE, "superblock");
398 fs = (struct fs *)sblock;
399
400
401 if (fs->fs_magic != FS_MAGIC)
402 errx(1, "Bad magic number in superblock");
403 if (fs->fs_inopb <= 0)
404 err(1, "Bad inopb=%d in superblock", fs->fs_inopb);
405
406
407 if ((buf = malloc(fs->fs_bsize)) == NULL)
408 err(1, NULL);
409
410 blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
411
412 devread(devfd, buf, pl->p_offset + blk, fs->fs_bsize, "inode");
413 ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
414
415
416
417
418
419 ndb = howmany(ip->di_size, fs->fs_bsize);
420 if (ndb <= 0)
421 errx(1, "No blocks to load");
422
423
424
425
426
427 sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
428 sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 512));
429 sym_set_value(pbr_symbols, "_fsbtodb", fs->fs_fsbtodb);
430 sym_set_value(pbr_symbols, "_p_offset", pl->p_offset);
431 sym_set_value(pbr_symbols, "_inodeblk",
432 ino_to_fsba(fs, statbuf.st_ino));
433 ap = ip->di_db;
434 sym_set_value(pbr_symbols, "_inodedbl",
435 ((((char *)ap) - buf) + INODEOFF));
436 sym_set_value(pbr_symbols, "_nblocks", ndb);
437
438 if (verbose) {
439 fprintf(stderr, "%s is %d blocks x %d bytes\n",
440 boot, ndb, fs->fs_bsize);
441 fprintf(stderr, "fs block shift %u; part offset %u; "
442 "inode block %u, offset %ld\n",
443 fs->fs_fsbtodb, pl->p_offset,
444 ino_to_fsba(fs, statbuf.st_ino),
445 ((((char *)ap) - buf) + INODEOFF));
446 }
447
448 return 0;
449 }
450
451 static void
452 sym_set_value(struct sym_data *sym_list, char *sym, u_int32_t value)
453 {
454 struct sym_data *p;
455
456 for (p = sym_list; p->sym_name != NULL; p++) {
457 if (strcmp(p->sym_name, sym) == 0)
458 break;
459 }
460
461 if (p->sym_name == NULL)
462 errx(1, "%s: no such symbol", sym);
463
464 if (p->sym_set)
465 errx(1, "%s already set", p->sym_name);
466
467 p->sym_value = value;
468 p->sym_set = 1;
469 }
470
471
472
473
474
475 static void
476 pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list)
477 {
478 struct sym_data *sym;
479 struct nlist *nl;
480 char *vp;
481 u_int32_t *lp;
482 u_int16_t *wp;
483 u_int8_t *bp;
484
485 for (sym = sym_list; sym->sym_name != NULL; sym++) {
486 if (!sym->sym_set)
487 errx(1, "%s not set", sym->sym_name);
488
489
490 nl = calloc(2, sizeof(struct nlist));
491 if (nl == NULL)
492 err(1, NULL);
493
494 nl->n_un.n_name = sym->sym_name;
495
496 if (nlist(fname, nl) != 0)
497 errx(1, "%s: symbol %s not found",
498 fname, sym->sym_name);
499
500 if (nl->n_type != (N_TEXT))
501 errx(1, "%s: %s: wrong type (%x)",
502 fname, sym->sym_name, nl->n_type);
503
504
505 vp = proto + nl->n_value;
506
507 switch (sym->sym_size) {
508 case 4:
509 lp = (u_int32_t *) vp;
510 *lp = sym->sym_value;
511 break;
512 case 2:
513 if (sym->sym_value >= 0x10000)
514 errx(1, "%s: symbol out of range (%u)",
515 sym->sym_name, sym->sym_value);
516 wp = (u_int16_t *) vp;
517 *wp = (u_int16_t) sym->sym_value;
518 break;
519 case 1:
520 if (sym->sym_value >= 0x100)
521 errx(1, "%s: symbol out of range (%u)",
522 sym->sym_name, sym->sym_value);
523 bp = (u_int8_t *) vp;
524 *bp = (u_int8_t) sym->sym_value;
525 break;
526 default:
527 errx(1, "%s: bad symbol size %d",
528 sym->sym_name, sym->sym_size);
529
530 }
531
532 free(nl);
533 }
534 }