md.c revision 1.2.4.1 1 /* $NetBSD: md.c,v 1.2.4.1 2015/05/14 07:58:50 snj Exp $ */
2
3 /*
4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved.
6 *
7 * Based on code written by Philip A. Nelson for Piermont Information
8 * Systems Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of Piermont Information Systems Inc. may not be used to endorse
19 * or promote products derived from this software without specific prior
20 * written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /* md.c -- ofppc machine specific routines */
36
37 #include <sys/param.h>
38 #include <sys/sysctl.h>
39 #include <sys/disklabel_rdb.h>
40 #include <stdio.h>
41 #include <util.h>
42 #include <machine/cpu.h>
43
44 #include "defs.h"
45 #include "md.h"
46 #include "msg_defs.h"
47 #include "menu_defs.h"
48 #include "endian.h"
49
50 static int check_rdb(void);
51 static uint32_t rdbchksum(void *);
52
53 /* We use MBR_PTYPE_PREP like port-prep does. */
54 static int nonewfsmsdos = 0, nobootfix = 0, noprepfix=0;
55 static int bootpart_fat12 = PART_BOOT_FAT12;
56 static int bootpart_binfo = PART_BOOT_BINFO;
57 static int bootpart_prep = PART_BOOT_PREP;
58 static int bootinfo_mbr = 1;
59 static int rdb_found = 0;
60
61 /* bootstart/bootsize are for the fat */
62 int binfostart, binfosize, bprepstart, bprepsize;
63
64 void
65 md_init(void)
66 {
67 }
68
69 void
70 md_init_set_status(int flags)
71 {
72
73 (void)flags;
74 }
75
76 int
77 md_get_info(void)
78 {
79
80 if (check_rdb())
81 return 1;
82
83 return set_bios_geom_with_mbr_guess();
84 }
85
86 /*
87 * md back-end code for menu-driven BSD disklabel editor.
88 */
89 int
90 md_make_bsd_partitions(void)
91 {
92 int i;
93 int part;
94 int maxpart = getmaxpartitions();
95 int partstart;
96 int part_raw, part_bsd;
97 int ptend;
98 int no_swap = 0;
99 partinfo *p;
100
101 if (rdb_found) {
102 /*
103 * We found RDB partitions on the disk, which cannot be
104 * modified by rewriting the disklabel.
105 * So just use what we have got.
106 */
107 for (part = 0; part < maxpart; part++) {
108 if (PI_ISBSDFS(&pm->bsdlabel[part])) {
109 pm->bsdlabel[part].pi_flags |=
110 PIF_NEWFS | PIF_MOUNT;
111
112 if (part == PART_A)
113 strcpy(pm->bsdlabel[part].pi_mount, "/");
114 }
115 }
116
117 part_bsd = part_raw = getrawpartition();
118 if (part_raw == -1)
119 part_raw = PART_C; /* for sanity... */
120 pm->bsdlabel[part_raw].pi_offset = 0;
121 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
122
123 set_sizemultname_meg();
124 rdb_edit_check:
125 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw,
126 part_bsd) == 0) {
127 msg_display(MSG_abort);
128 return 0;
129 }
130 if (md_check_partitions() == 0)
131 goto rdb_edit_check;
132
133 return 1;
134 }
135
136 /*
137 * Initialize global variables that track space used on this disk.
138 * Standard 4.4BSD 8-partition labels always cover whole disk.
139 */
140 if (pm->ptsize == 0)
141 pm->ptsize = pm->dlsize - pm->ptstart;
142 if (pm->dlsize == 0)
143 pm->dlsize = pm->ptstart + pm->ptsize;
144
145 partstart = pm->ptstart;
146 ptend = pm->ptstart + pm->ptsize;
147
148 /* Ask for layout type -- standard or special */
149 msg_display(MSG_layout,
150 pm->ptsize / (MEG / pm->sectorsize),
151 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE,
152 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE + XNEEDMB);
153
154 process_menu(MENU_layout, NULL);
155
156 /* Set so we use the 'real' geometry for rounding, input in MB */
157 pm->current_cylsize = pm->dlcylsize;
158 set_sizemultname_meg();
159
160 /* Build standard partitions */
161 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel);
162
163 /* Set initial partition types to unused */
164 for (part = 0 ; part < maxpart ; ++part)
165 pm->bsdlabel[part].pi_fstype = FS_UNUSED;
166
167 /* Whole disk partition */
168 part_raw = getrawpartition();
169 if (part_raw == -1)
170 part_raw = PART_C; /* for sanity... */
171 pm->bsdlabel[part_raw].pi_offset = 0;
172 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
173
174 if (part_raw == PART_D) {
175 /* Probably a system that expects an i386 style mbr */
176 part_bsd = PART_C;
177 pm->bsdlabel[PART_C].pi_offset = pm->ptstart;
178 pm->bsdlabel[PART_C].pi_size = pm->ptsize;
179 } else {
180 part_bsd = part_raw;
181 }
182
183 if (pm->bootsize != 0) {
184 pm->bsdlabel[PART_BOOT_FAT12].pi_fstype = FS_MSDOS;
185 pm->bsdlabel[PART_BOOT_FAT12].pi_size = pm->bootsize;
186 pm->bsdlabel[PART_BOOT_FAT12].pi_offset = pm->bootstart;
187 pm->bsdlabel[PART_BOOT_FAT12].pi_flags |= PART_BOOT_FAT12_PI_FLAGS;
188 strlcpy(pm->bsdlabel[PART_BOOT_FAT12].pi_mount,
189 PART_BOOT_FAT12_PI_MOUNT,
190 sizeof pm->bsdlabel[PART_BOOT_FAT12].pi_mount);
191 }
192 if (binfosize != 0) {
193 pm->bsdlabel[PART_BOOT_BINFO].pi_fstype = FS_OTHER;
194 pm->bsdlabel[PART_BOOT_BINFO].pi_size = binfosize;
195 pm->bsdlabel[PART_BOOT_BINFO].pi_offset = binfostart;
196 }
197 if (bprepsize != 0) {
198 pm->bsdlabel[PART_BOOT_PREP].pi_fstype = FS_BOOT;
199 pm->bsdlabel[PART_BOOT_PREP].pi_size = bprepsize;
200 pm->bsdlabel[PART_BOOT_PREP].pi_offset = bprepstart;
201 }
202
203 #ifdef PART_REST
204 pm->bsdlabel[PART_REST].pi_offset = 0;
205 pm->bsdlabel[PART_REST].pi_size = pm->ptstart;
206 #endif
207
208 /*
209 * Save any partitions that are outside the area we are
210 * going to use.
211 * In particular this saves details of the other MBR
212 * partitions on a multiboot i386 system.
213 */
214 for (i = maxpart; i--;) {
215 if (pm->bsdlabel[i].pi_size != 0)
216 /* Don't overwrite special partitions */
217 continue;
218 p = &pm->oldlabel[i];
219 if (p->pi_fstype == FS_UNUSED || p->pi_size == 0)
220 continue;
221 if (layoutkind == LY_USEEXIST) {
222 if (PI_ISBSDFS(p))
223 p->pi_flags |= PIF_MOUNT;
224 } else {
225 if (p->pi_offset < pm->ptstart + pm->ptsize &&
226 p->pi_offset + p->pi_size > pm->ptstart)
227 /* Not outside area we are allocating */
228 continue;
229 if (p->pi_fstype == FS_SWAP)
230 no_swap = 1;
231 }
232 pm->bsdlabel[i] = pm->oldlabel[i];
233 }
234
235 if (layoutkind == LY_USEEXIST) {
236 /* XXX Check we have a sensible layout */
237 ;
238 } else
239 get_ptn_sizes(partstart, ptend - partstart, no_swap);
240
241 /*
242 * OK, we have a partition table. Give the user the chance to
243 * edit it and verify it's OK, or abort altogether.
244 */
245 edit_check:
246 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw, part_bsd) == 0) {
247 msg_display(MSG_abort);
248 return 0;
249 }
250 if (md_check_partitions() == 0)
251 goto edit_check;
252
253 /* Disk name */
254 msg_prompt(MSG_packname, pm->bsddiskname, pm->bsddiskname, sizeof pm->bsddiskname);
255
256 /* save label to disk for MI code to update. */
257 (void) savenewlabel(pm->bsdlabel, maxpart);
258
259 /* Everything looks OK. */
260 return 1;
261 }
262
263 /*
264 * any additional partition validation
265 */
266 int
267 md_check_partitions(void)
268 {
269 int part, fprep=0, ffat=0;
270
271 if (rdb_found)
272 return 1;
273
274 /* we need to find a boot partition, otherwise we can't create
275 * our msdos fs boot partition. We make the assumption that
276 * the user hasn't done something stupid, like move it away
277 * from the MBR partition.
278 */
279 for (part = PART_A; part < MAXPARTITIONS; part++) {
280 if (pm->bsdlabel[part].pi_fstype == FS_MSDOS) {
281 bootpart_fat12 = part;
282 ffat++;
283 } else if (pm->bsdlabel[part].pi_fstype == FS_BOOT) {
284 bootpart_prep = part;
285 fprep++;
286 } else if (pm->bsdlabel[part].pi_fstype == FS_OTHER) {
287 bootpart_binfo = part;
288 fprep++;
289 }
290 }
291 /* oh, the confusion */
292 if (ffat >= 1 && fprep < 2)
293 return 1;
294 if (ffat < 1 && fprep >= 2)
295 return 2;
296 if (ffat >=1 && fprep >= 2)
297 return 3;
298
299 msg_display(MSG_nobootpartdisklabel);
300 process_menu(MENU_ok, NULL);
301 return 0;
302 }
303
304 /*
305 * hook called before writing new disklabel.
306 */
307 int
308 md_pre_disklabel(void)
309 {
310
311 if (rdb_found)
312 return 0;
313
314 msg_display(MSG_dofdisk);
315
316 /* write edited MBR onto disk. */
317 if (write_mbr(pm->diskdev, &mbr, 1) != 0) {
318 msg_display(MSG_wmbrfail);
319 process_menu(MENU_ok, NULL);
320 return 1;
321 }
322 return 0;
323 }
324
325 /*
326 * hook called after writing disklabel to new target disk.
327 */
328 int
329 md_post_disklabel(void)
330 {
331 char bootdev[100];
332
333 if (pm->bootstart == 0 || pm->bootsize == 0 || rdb_found)
334 return 0;
335
336 snprintf(bootdev, sizeof bootdev, "/dev/r%s%c", pm->diskdev,
337 'a'+bootpart_fat12);
338 run_program(RUN_DISPLAY, "/sbin/newfs_msdos %s", bootdev);
339
340 return 0;
341 }
342
343 /*
344 * hook called after upgrade() or install() has finished setting
345 * up the target disk but immediately before the user is given the
346 * ``disks are now set up'' message.
347 */
348 int
349 md_post_newfs(void)
350 {
351
352 /* No bootblock. We use ofwboot from a partition visiable by OFW. */
353 return 0;
354 }
355
356 int
357 md_post_extract(void)
358 {
359 char bootdev[100], bootbdev[100], version[64];
360
361 /* if we can't make it bootable, just punt */
362 if ((nobootfix && noprepfix) || rdb_found)
363 return 0;
364
365 snprintf(version, sizeof version, "NetBSD/%s %s", MACH, REL);
366 run_program(RUN_DISPLAY, "/usr/mdec/mkbootinfo '%s' %d "
367 "/tmp/bootinfo.txt", version, bootinfo_mbr);
368
369 if (!nobootfix) {
370 run_program(RUN_DISPLAY, "/bin/mkdir -p /%s/boot/ppc",
371 target_prefix());
372 run_program(RUN_DISPLAY, "/bin/mkdir -p /%s/boot/netbsd",
373 target_prefix());
374 run_program(RUN_DISPLAY, "/bin/cp /usr/mdec/ofwboot "
375 "/%s/boot/netbsd", target_prefix());
376 run_program(RUN_DISPLAY, "/bin/cp /tmp/bootinfo.txt "
377 "/%s/boot/ppc", target_prefix());
378 run_program(RUN_DISPLAY, "/bin/cp /usr/mdec/ofwboot "
379 "/%s/boot/ofwboot", target_prefix());
380 }
381
382 if (!noprepfix) {
383 snprintf(bootdev, sizeof bootdev, "/dev/r%s%c", pm->diskdev,
384 'a'+bootpart_prep);
385 snprintf(bootbdev, sizeof bootbdev, "/dev/%s%c", pm->diskdev,
386 'a'+bootpart_prep);
387 run_program(RUN_DISPLAY, "/bin/dd if=/dev/zero of=%s bs=512",
388 bootdev);
389 run_program(RUN_DISPLAY, "/bin/dd if=/usr/mdec/ofwboot "
390 "of=%s bs=512", bootbdev);
391
392 snprintf(bootdev, sizeof bootdev, "/dev/r%s%c", pm->diskdev,
393 'a'+bootpart_binfo);
394 snprintf(bootbdev, sizeof bootbdev, "/dev/%s%c", pm->diskdev,
395 'a'+bootpart_binfo);
396 run_program(RUN_DISPLAY, "/bin/dd if=/dev/zero of=%s bs=512",
397 bootdev);
398 run_program(RUN_DISPLAY, "/bin/dd if=/tmp/bootinfo.txt "
399 "of=%s bs=512", bootbdev);
400 }
401
402 return 0;
403 }
404
405 void
406 md_cleanup_install(void)
407 {
408
409 #ifndef DEBUG
410 enable_rc_conf();
411 #endif
412 }
413
414 int
415 md_pre_update(void)
416 {
417 struct mbr_partition *part;
418 mbr_info_t *ext;
419 int i;
420
421 if (check_rdb())
422 return 1;
423
424 read_mbr(pm->diskdev, &mbr);
425 /* do a sanity check of the partition table */
426 for (ext = &mbr; ext; ext = ext->extended) {
427 part = ext->mbr.mbr_parts;
428 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
429 if (part->mbrp_type == MBR_PTYPE_PREP &&
430 part->mbrp_size > 50)
431 bootinfo_mbr = i+1;
432 if (part->mbrp_type == MBR_PTYPE_RESERVED_x21 &&
433 part->mbrp_size < (MIN_FAT12_BOOT/512)) {
434 msg_display(MSG_boottoosmall);
435 msg_display_add(MSG_nobootpartdisklabel, 0);
436 if (!ask_yesno(NULL))
437 return 0;
438 nobootfix = 1;
439 }
440 }
441 }
442
443 i = md_check_partitions();
444 switch (i) {
445 case 0: nobootfix=1; noprepfix=1; break;
446 case 1: noprepfix=1; break;
447 case 2: nobootfix=1; break;
448 default: break;
449 }
450
451 return 1;
452 }
453
454 /* Upgrade support */
455 int
456 md_update(void)
457 {
458
459 nonewfsmsdos = 1;
460 md_post_newfs();
461 return 1;
462 }
463
464
465 int
466 md_check_mbr(mbr_info_t *mbri)
467 {
468 mbr_info_t *ext;
469 struct mbr_partition *part;
470 int i;
471
472 for (ext = mbri; ext; ext = ext->extended) {
473 part = ext->mbr.mbr_parts;
474 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
475 if (part->mbrp_type == MBR_PTYPE_FAT12) {
476 pm->bootstart = part->mbrp_start;
477 pm->bootsize = part->mbrp_size;
478 } else if (part->mbrp_type == MBR_PTYPE_PREP &&
479 part->mbrp_size < 50) {
480 /* this is the bootinfo partition */
481 binfostart = part->mbrp_start;
482 binfosize = part->mbrp_size;
483 bootinfo_mbr = i+1;
484 } else if (part->mbrp_type == MBR_PTYPE_PREP &&
485 part->mbrp_size > 50) {
486 bprepstart = part->mbrp_start;
487 bprepsize = part->mbrp_size;
488 }
489 break;
490 }
491 }
492
493 /* we need to either have a pair of prep partitions, or a single
494 * fat. if neither, things are broken. */
495 if (!(pm->bootsize >= (MIN_FAT12_BOOT/512) ||
496 (binfosize >= (MIN_BINFO_BOOT/512) &&
497 bprepsize >= (MIN_PREP_BOOT/512)))) {
498 msg_display(MSG_bootnotright);
499 msg_display_add(MSG_reeditpart, 0);
500 if (!ask_yesno(NULL))
501 return 0;
502 return 1;
503 }
504
505 /* check the prep partitions */
506 if ((binfosize > 0 || bprepsize > 0) &&
507 (binfosize < (MIN_BINFO_BOOT/512) ||
508 bprepsize < (MIN_PREP_BOOT/512))) {
509 msg_display(MSG_preptoosmall);
510 msg_display_add(MSG_reeditpart, 0);
511 if (!ask_yesno(NULL))
512 return 0;
513 return 1;
514 }
515
516 /* check the fat12 parititons */
517 if (pm->bootsize > 0 && pm->bootsize < (MIN_FAT12_BOOT/512)) {
518 msg_display(MSG_boottoosmall);
519 msg_display_add(MSG_reeditpart, 0);
520 if (!ask_yesno(NULL))
521 return 0;
522 return 1;
523 }
524
525 /* if both sets contain zero, thats bad */
526 if ((pm->bootstart == 0 || pm->bootsize == 0) &&
527 (binfosize == 0 || binfostart == 0 ||
528 bprepsize == 0 || bprepstart == 0)) {
529 msg_display(MSG_nobootpart);
530 msg_display_add(MSG_reeditpart, 0);
531 if (!ask_yesno(NULL))
532 return 0;
533 return 1;
534 }
535 return 2;
536 }
537
538 /*
539 * NOTE, we use a reserved partition type, because some RS/6000 machines hang
540 * hard if they find a FAT12, and if we use type prep, that indicates that
541 * it should be read raw.
542 * One partition for FAT12 booting
543 * One partition for NetBSD
544 * One partition to hold the bootinfo.txt file
545 * One partition to hold ofwboot
546 */
547
548 int
549 md_mbr_use_wholedisk(mbr_info_t *mbri)
550 {
551 struct mbr_sector *mbrs = &mbri->mbr;
552 mbr_info_t *ext;
553 struct mbr_partition *part;
554
555 part = &mbrs->mbr_parts[0];
556 /* Set the partition information for full disk usage. */
557 while ((ext = mbri->extended)) {
558 mbri->extended = ext->extended;
559 free(ext);
560 }
561 memset(part, 0, MBR_PART_COUNT * sizeof *part);
562
563 part[0].mbrp_type = MBR_PTYPE_RESERVED_x21;
564 part[0].mbrp_size = FAT12_BOOT_SIZE/512;
565 part[0].mbrp_start = bsec;
566 part[0].mbrp_flag = 0;
567
568 part[1].mbrp_type = MBR_PTYPE_NETBSD;
569 part[1].mbrp_size = pm->dlsize - (bsec + FAT12_BOOT_SIZE/512 +
570 BINFO_BOOT_SIZE/512 + PREP_BOOT_SIZE/512);
571 part[1].mbrp_start = bsec + FAT12_BOOT_SIZE/512 + BINFO_BOOT_SIZE/512 +
572 PREP_BOOT_SIZE/512;
573 part[1].mbrp_flag = MBR_PFLAG_ACTIVE;
574
575 part[2].mbrp_type = MBR_PTYPE_PREP;
576 part[2].mbrp_size = BINFO_BOOT_SIZE/512;
577 part[2].mbrp_start = bsec + FAT12_BOOT_SIZE/512;
578 part[2].mbrp_flag = 0;
579
580 part[3].mbrp_type = MBR_PTYPE_PREP;
581 part[3].mbrp_size = PREP_BOOT_SIZE/512;
582 part[3].mbrp_start = bsec + FAT12_BOOT_SIZE/512 + BINFO_BOOT_SIZE/512;
583 part[3].mbrp_flag = 0;
584
585 pm->ptstart = part[1].mbrp_start;
586 pm->ptsize = part[1].mbrp_size;
587 pm->bootstart = part[0].mbrp_start;
588 pm->bootsize = part[0].mbrp_size;
589 binfostart = part[2].mbrp_start;
590 binfosize= part[2].mbrp_size;
591 bprepstart = part[3].mbrp_start;
592 bprepsize = part[3].mbrp_size;
593 bootinfo_mbr = 4;
594
595 return 1;
596 }
597
598 const char *md_disklabel_cmd(void)
599 {
600
601 /* we cannot rewrite an RDB disklabel */
602 if (rdb_found)
603 return "sync No disklabel";
604
605 return "disklabel -w -r";
606 }
607
608 static int
609 check_rdb(void)
610 {
611 char buf[512], diskpath[MAXPATHLEN];
612 struct rdblock *rdb;
613 off_t blk;
614 int fd;
615
616 /* Find out if this disk has a valid RDB, before continuing. */
617 rdb = (struct rdblock *)buf;
618 fd = opendisk(pm->diskdev, O_RDONLY, diskpath, sizeof(diskpath), 0);
619 if (fd < 0)
620 return 0;
621 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) {
622 if (pread(fd, rdb, 512, blk * 512) != 512)
623 return 0;
624 if (rdb->id == RDBLOCK_ID && rdbchksum(rdb) == 0) {
625 rdb_found = 1; /* do not repartition! */
626 return 1;
627 }
628 }
629 return 0;
630 }
631
632 static uint32_t
633 rdbchksum(void *bdata)
634 {
635 uint32_t *blp, cnt, val;
636
637 blp = bdata;
638 cnt = blp[1];
639 val = 0;
640 while (cnt--)
641 val += *blp++;
642 return val;
643 }
644
645 int
646 md_pre_mount()
647 {
648
649 return 0;
650 }
651