md.c revision 1.11 1 /* $NetBSD: md.c,v 1.11 2020/10/12 16:14:35 martin 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 part_id bootpart_fat12 = NO_PART, bootpart_binfo = NO_PART,
56 bootpart_prep = NO_PART;
57 static int bootinfo_mbr = 1;
58 static int rdb_found = 0;
59
60 /* bootstart/bootsize are for the fat */
61 int binfostart, binfosize, bprepstart, bprepsize;
62
63 void
64 md_init(void)
65 {
66 }
67
68 void
69 md_init_set_status(int flags)
70 {
71
72 (void)flags;
73 }
74
75 bool
76 md_get_info(struct install_partition_desc *install)
77 {
78 int res;
79
80 if (check_rdb())
81 return true;
82
83
84 if (pm->no_mbr || pm->no_part)
85 return true;
86
87 if (pm->parts == NULL) {
88
89 const struct disk_partitioning_scheme *ps =
90 select_part_scheme(pm, NULL, true, NULL);
91
92 if (!ps)
93 return false;
94
95 struct disk_partitions *parts =
96 (*ps->create_new_for_disk)(pm->diskdev,
97 0, pm->dlsize, true, NULL);
98 if (!parts)
99 return false;
100
101 pm->parts = parts;
102 if (ps->size_limit > 0 && pm->dlsize > ps->size_limit)
103 pm->dlsize = ps->size_limit;
104 }
105
106 res = set_bios_geom_with_mbr_guess(pm->parts);
107 if (res == 0)
108 return false;
109 else if (res == 1)
110 return true;
111
112 pm->parts->pscheme->destroy_part_scheme(pm->parts);
113 pm->parts = NULL;
114 goto again;
115 }
116
117 /*
118 * md back-end code for menu-driven BSD disklabel editor.
119 */
120 int
121 md_make_bsd_partitions(struct install_partition_desc *install)
122 {
123 #if 0
124 int i;
125 int part;
126 int maxpart = getmaxpartitions();
127 int partstart;
128 int part_raw, part_bsd;
129 int ptend;
130 int no_swap = 0;
131 #endif
132
133 if (rdb_found) {
134 #if 0
135 /*
136 * XXX - need to test on real machine if the disklabel code
137 * deals with RDB partitions properly, otherwise write
138 * a read-only RDB backend
139 */
140 /*
141 * We found RDB partitions on the disk, which cannot be
142 * modified by rewriting the disklabel.
143 * So just use what we have got.
144 */
145 for (part = 0; part < maxpart; part++) {
146 if (PI_ISBSDFS(&pm->bsdlabel[part])) {
147 pm->bsdlabel[part].pi_flags |=
148 PIF_NEWFS | PIF_MOUNT;
149
150 if (part == PART_A)
151 strcpy(pm->bsdlabel[part].pi_mount, "/");
152 }
153 }
154
155 part_bsd = part_raw = getrawpartition();
156 if (part_raw == -1)
157 part_raw = PART_C; /* for sanity... */
158 pm->bsdlabel[part_raw].pi_offset = 0;
159 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
160
161 set_sizemultname_meg();
162 rdb_edit_check:
163 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw,
164 part_bsd) == 0) {
165 msg_display(MSG_abort);
166 return 0;
167 }
168 if (md_check_partitions() == 0)
169 goto rdb_edit_check;
170 #endif
171 return 1;
172 }
173
174 /*
175 * Initialize global variables that track space used on this disk.
176 * Standard 4.4BSD 8-partition labels always cover whole disk.
177 */
178 if (pm->ptsize == 0)
179 pm->ptsize = pm->dlsize - pm->ptstart;
180 if (pm->dlsize == 0)
181 pm->dlsize = pm->ptstart + pm->ptsize;
182
183 #if 0
184 partstart = pm->ptstart;
185 ptend = pm->ptstart + pm->ptsize;
186
187 /* Ask for layout type -- standard or special */
188 msg_fmt_display(MSG_layout, "%d%d%d",
189 pm->ptsize / (MEG / pm->sectorsize),
190 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE,
191 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE + XNEEDMB);
192
193 process_menu(MENU_layout, NULL);
194
195 /* Set so we use the 'real' geometry for rounding, input in MB */
196 pm->current_cylsize = pm->dlcylsize;
197 set_sizemultname_meg();
198
199 /* Build standard partitions */
200 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel);
201
202 /* Set initial partition types to unused */
203 for (part = 0 ; part < maxpart ; ++part)
204 pm->bsdlabel[part].pi_fstype = FS_UNUSED;
205
206 /* Whole disk partition */
207 part_raw = getrawpartition();
208 if (part_raw == -1)
209 part_raw = PART_C; /* for sanity... */
210 pm->bsdlabel[part_raw].pi_offset = 0;
211 pm->bsdlabel[part_raw].pi_size = pm->dlsize;
212
213 if (part_raw == PART_D) {
214 /* Probably a system that expects an i386 style mbr */
215 part_bsd = PART_C;
216 pm->bsdlabel[PART_C].pi_offset = pm->ptstart;
217 pm->bsdlabel[PART_C].pi_size = pm->ptsize;
218 } else {
219 part_bsd = part_raw;
220 }
221
222 if (pm->bootsize != 0) {
223 pm->bsdlabel[PART_BOOT_FAT12].pi_fstype = FS_MSDOS;
224 pm->bsdlabel[PART_BOOT_FAT12].pi_size = pm->bootsize;
225 pm->bsdlabel[PART_BOOT_FAT12].pi_offset = pm->bootstart;
226 pm->bsdlabel[PART_BOOT_FAT12].pi_flags |= PART_BOOT_FAT12_PI_FLAGS;
227 strlcpy(pm->bsdlabel[PART_BOOT_FAT12].pi_mount,
228 PART_BOOT_FAT12_PI_MOUNT,
229 sizeof pm->bsdlabel[PART_BOOT_FAT12].pi_mount);
230 }
231 if (binfosize != 0) {
232 pm->bsdlabel[PART_BOOT_BINFO].pi_fstype = FS_OTHER;
233 pm->bsdlabel[PART_BOOT_BINFO].pi_size = binfosize;
234 pm->bsdlabel[PART_BOOT_BINFO].pi_offset = binfostart;
235 }
236 if (bprepsize != 0) {
237 pm->bsdlabel[PART_BOOT_PREP].pi_fstype = FS_BOOT;
238 pm->bsdlabel[PART_BOOT_PREP].pi_size = bprepsize;
239 pm->bsdlabel[PART_BOOT_PREP].pi_offset = bprepstart;
240 }
241
242 #ifdef PART_REST
243 pm->bsdlabel[PART_REST].pi_offset = 0;
244 pm->bsdlabel[PART_REST].pi_size = pm->ptstart;
245 #endif
246
247 /*
248 * Save any partitions that are outside the area we are
249 * going to use.
250 * In particular this saves details of the other MBR
251 * partitions on a multiboot i386 system.
252 */
253 for (i = maxpart; i--;) {
254 if (pm->bsdlabel[i].pi_size != 0)
255 /* Don't overwrite special partitions */
256 continue;
257 p = &pm->oldlabel[i];
258 if (p->pi_fstype == FS_UNUSED || p->pi_size == 0)
259 continue;
260 if (layoutkind == LY_USEEXIST) {
261 if (PI_ISBSDFS(p))
262 p->pi_flags |= PIF_MOUNT;
263 } else {
264 if (p->pi_offset < pm->ptstart + pm->ptsize &&
265 p->pi_offset + p->pi_size > pm->ptstart)
266 /* Not outside area we are allocating */
267 continue;
268 if (p->pi_fstype == FS_SWAP)
269 no_swap = 1;
270 }
271 pm->bsdlabel[i] = pm->oldlabel[i];
272 }
273
274 if (layoutkind == LY_USEEXIST) {
275 /* XXX Check we have a sensible layout */
276 ;
277 } else
278 get_ptn_sizes(partstart, ptend - partstart, no_swap);
279
280 /*
281 * OK, we have a partition table. Give the user the chance to
282 * edit it and verify it's OK, or abort altogether.
283 */
284 edit_check:
285 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw, part_bsd) == 0) {
286 msg_display(MSG_abort);
287 return 0;
288 }
289 if (md_check_partitions() == 0)
290 goto edit_check;
291
292 /* Disk name */
293 msg_prompt(MSG_packname, pm->bsddiskname, pm->bsddiskname, sizeof pm->bsddiskname);
294
295 /* save label to disk for MI code to update. */
296 (void) savenewlabel(pm->bsdlabel, maxpart);
297
298 /* Everything looks OK. */
299 return 1;
300 #endif
301
302 return make_bsd_partitions(install);
303 }
304
305 /*
306 * any additional partition validation
307 */
308 bool
309 md_check_partitions(struct install_partition_desc *install)
310 {
311 struct disk_partitions *parts;
312 struct disk_part_info info;
313 int fprep=0, ffat=0;
314 part_id part;
315
316 if (rdb_found)
317 return 1;
318
319 if (install->num < 1)
320 return false;
321 parts = install->infos[0].parts; /* disklabel parts */
322 if (parts->parent)
323 parts = parts->parent; /* MBR parts */
324
325 /* we need to find a boot partition, otherwise we can't create
326 * our msdos fs boot partition. We make the assumption that
327 * the user hasn't done something stupid, like move it away
328 * from the MBR partition.
329 */
330 for (part = 0; part < parts->num_part; part++) {
331 if (!parts->pscheme->get_part_info(parts, part, &info))
332 continue;
333
334 if (info.fs_type == FS_MSDOS) {
335 bootpart_fat12 = part;
336 ffat++;
337 } else if (info.fs_type == FS_BOOT) {
338 bootpart_prep = part;
339 fprep++;
340 } else if (info.fs_type == FS_OTHER) {
341 bootpart_binfo = part;
342 fprep++;
343 }
344 }
345 /* oh, the confusion */
346 if (ffat >= 1 && fprep < 2) {
347 noprepfix = 1;
348 return true;
349 }
350 if (ffat < 1 && fprep >= 2) {
351 nobootfix = 1;
352 return true;
353 }
354 if (ffat >=1 && fprep >= 2) {
355 return true;
356 }
357
358 msg_display(MSG_nobootpartdisklabel);
359 process_menu(MENU_ok, NULL);
360 nobootfix = 1;
361 return false;
362 }
363
364 /*
365 * hook called before writing new disklabel.
366 */
367 bool
368 md_pre_disklabel(struct install_partition_desc *install,
369 struct disk_partitions *parts)
370 {
371
372 if (rdb_found)
373 return true;
374
375
376 if (parts->parent == NULL)
377 return true; /* no outer partitions */
378
379 parts = parts->parent;
380
381 msg_display_subst(MSG_dofdisk, 3, parts->disk,
382 msg_string(parts->pscheme->name),
383 msg_string(parts->pscheme->short_name));
384
385 /* write edited "MBR" onto disk. */
386 if (!parts->pscheme->write_to_disk(parts)) {
387 msg_display(MSG_wmbrfail);
388 process_menu(MENU_ok, NULL);
389 return false;
390 }
391 return true;
392 }
393
394 /*
395 * hook called after writing disklabel to new target disk.
396 */
397 bool
398 md_post_disklabel(struct install_partition_desc *install,
399 struct disk_partitions *parts)
400 {
401 char bootdev[100];
402
403 if (pm->bootstart == 0 || pm->bootsize == 0 || rdb_found)
404 return 0;
405
406 snprintf(bootdev, sizeof bootdev, "/dev/r%s%c", pm->diskdev,
407 (char)('a'+bootpart_fat12));
408 run_program(RUN_DISPLAY, "/sbin/newfs_msdos %s", bootdev);
409
410 return 0;
411 }
412
413 /*
414 * hook called after upgrade() or install() has finished setting
415 * up the target disk but immediately before the user is given the
416 * ``disks are now set up'' message.
417 */
418 int
419 md_post_newfs(struct install_partition_desc *install)
420 {
421
422 /* No bootblock. We use ofwboot from a partition visiable by OFW. */
423 return 0;
424 }
425
426 int
427 md_post_extract(struct install_partition_desc *install)
428 {
429 char bootdev[100], bootbdev[100], version[64];
430 struct disk_partitions *parts;
431
432 /* if we can't make it bootable, just punt */
433 if ((nobootfix && noprepfix) || rdb_found)
434 return 0;
435
436 snprintf(version, sizeof version, "NetBSD/%s %s", MACH, REL);
437 run_program(RUN_DISPLAY, "/usr/mdec/mkbootinfo '%s' %d "
438 "/tmp/bootinfo.txt", version, bootinfo_mbr);
439
440 if (!nobootfix) {
441 run_program(RUN_DISPLAY, "/bin/mkdir -p /%s/boot/ppc",
442 target_prefix());
443 run_program(RUN_DISPLAY, "/bin/mkdir -p /%s/boot/netbsd",
444 target_prefix());
445 run_program(RUN_DISPLAY, "/bin/cp /usr/mdec/ofwboot "
446 "/%s/boot/netbsd", target_prefix());
447 run_program(RUN_DISPLAY, "/bin/cp /tmp/bootinfo.txt "
448 "/%s/boot/ppc", target_prefix());
449 run_program(RUN_DISPLAY, "/bin/cp /usr/mdec/ofwboot "
450 "/%s/boot/ofwboot", target_prefix());
451 }
452
453 if (!noprepfix && install != NULL && install->num > 0) {
454 parts = install->infos[0].parts; /* disklabel */
455 if (parts->parent != NULL)
456 parts = parts->parent; /* MBR */
457
458 parts->pscheme->get_part_device(parts, bootpart_prep,
459 bootdev, sizeof bootdev, NULL, raw_dev_name, true, true);
460 parts->pscheme->get_part_device(parts, bootpart_prep,
461 bootbdev, sizeof bootbdev, NULL, plain_name, true, true);
462 run_program(RUN_DISPLAY, "/bin/dd if=/dev/zero of=%s bs=512",
463 bootdev);
464 run_program(RUN_DISPLAY, "/bin/dd if=/usr/mdec/ofwboot "
465 "of=%s bs=512", bootbdev);
466
467 parts->pscheme->get_part_device(parts, bootpart_binfo,
468 bootdev, sizeof bootdev, NULL, raw_dev_name, true, true);
469 parts->pscheme->get_part_device(parts, bootpart_binfo,
470 bootbdev, sizeof bootbdev, NULL, plain_name, true, true);
471 run_program(RUN_DISPLAY, "/bin/dd if=/dev/zero of=%s bs=512",
472 bootdev);
473 run_program(RUN_DISPLAY, "/bin/dd if=/tmp/bootinfo.txt "
474 "of=%s bs=512", bootbdev);
475 }
476
477 return 0;
478 }
479
480 void
481 md_cleanup_install(struct install_partition_desc *install)
482 {
483
484 #ifndef DEBUG
485 enable_rc_conf();
486 #endif
487 }
488
489 int
490 md_pre_update(struct install_partition_desc *install)
491 {
492 #if 0
493 struct mbr_partition *part;
494 mbr_info_t *ext;
495 int i;
496 #endif
497
498 if (check_rdb())
499 return 1;
500
501 #if 0
502 read_mbr(pm->diskdev, &mbr);
503 /* do a sanity check of the partition table */
504 for (ext = &mbr; ext; ext = ext->extended) {
505 part = ext->mbr.mbr_parts;
506 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
507 if (part->mbrp_type == MBR_PTYPE_PREP &&
508 part->mbrp_size > 50)
509 bootinfo_mbr = i+1;
510 if (part->mbrp_type == MBR_PTYPE_RESERVED_x21 &&
511 part->mbrp_size < (MIN_FAT12_BOOT/512)) {
512 msg_display(MSG_boottoosmall);
513 msg_fmt_display_add(MSG_nobootpartdisklabel,
514 "%d", 0);
515 if (!ask_yesno(NULL))
516 return 0;
517 nobootfix = 1;
518 }
519 }
520 }
521 #endif
522
523 if (!md_check_partitions(install))
524 return 0;
525
526 return 1;
527 }
528
529 /* Upgrade support */
530 int
531 md_update(struct install_partition_desc *install)
532 {
533
534 nonewfsmsdos = 1;
535 md_post_newfs(install);
536 return 1;
537 }
538
539
540 int
541 md_check_mbr(struct disk_partitions *parts, mbr_info_t *mbri, bool quiet)
542 {
543 mbr_info_t *ext;
544 struct mbr_partition *part;
545 int i;
546
547 for (ext = mbri; ext; ext = ext->extended) {
548 part = ext->mbr.mbr_parts;
549 for (i = 0; i < MBR_PART_COUNT; part++, i++) {
550 if (part->mbrp_type == MBR_PTYPE_FAT12) {
551 pm->bootstart = part->mbrp_start;
552 pm->bootsize = part->mbrp_size;
553 } else if (part->mbrp_type == MBR_PTYPE_PREP &&
554 part->mbrp_size < 50) {
555 /* this is the bootinfo partition */
556 binfostart = part->mbrp_start;
557 binfosize = part->mbrp_size;
558 bootinfo_mbr = i+1;
559 } else if (part->mbrp_type == MBR_PTYPE_PREP &&
560 part->mbrp_size > 50) {
561 bprepstart = part->mbrp_start;
562 bprepsize = part->mbrp_size;
563 }
564 break;
565 }
566 }
567
568 /* we need to either have a pair of prep partitions, or a single
569 * fat. if neither, things are broken. */
570 if (!(pm->bootsize >= (MIN_FAT12_BOOT/512) ||
571 (binfosize >= (MIN_BINFO_BOOT/512) &&
572 bprepsize >= (MIN_PREP_BOOT/512)))) {
573 if (quiet)
574 return 0;
575 msg_display(MSG_bootnotright);
576 return ask_reedit(parts);
577 }
578
579 /* check the prep partitions */
580 if ((binfosize > 0 || bprepsize > 0) &&
581 (binfosize < (MIN_BINFO_BOOT/512) ||
582 bprepsize < (MIN_PREP_BOOT/512))) {
583 if (quiet)
584 return 0;
585 msg_display(MSG_preptoosmall);
586 return ask_reedit(parts);
587 }
588
589 /* check the fat12 parititons */
590 if (pm->bootsize > 0 && pm->bootsize < (MIN_FAT12_BOOT/512)) {
591 if (quiet)
592 return 0;
593 msg_display(MSG_boottoosmall);
594 return ask_reedit(parts);
595 }
596
597 /* if both sets contain zero, thats bad */
598 if ((pm->bootstart == 0 || pm->bootsize == 0) &&
599 (binfosize == 0 || binfostart == 0 ||
600 bprepsize == 0 || bprepstart == 0)) {
601 if (quiet)
602 return 0;
603 msg_display(MSG_nobootpart);
604 return ask_reedit(parts);
605 }
606 return 2;
607 }
608
609 /*
610 * NOTE, we use a reserved partition type, because some RS/6000 machines hang
611 * hard if they find a FAT12, and if we use type prep, that indicates that
612 * it should be read raw.
613 * One partition for FAT12 booting
614 * One partition for NetBSD
615 * One partition to hold the bootinfo.txt file
616 * One partition to hold ofwboot
617 */
618
619 bool
620 md_parts_use_wholedisk(struct disk_partitions *parts)
621 {
622 struct disk_part_info boot_parts[] =
623 {
624 { .fs_type = FS_MSDOS, .size = FAT12_BOOT_SIZE/512 },
625 { .fs_type = FS_OTHER, .size = BINFO_BOOT_SIZE/512 },
626 { .fs_type = FS_BOOT, .size = PREP_BOOT_SIZE/512 }
627 };
628
629 return parts_use_wholedisk(parts, __arraycount(boot_parts),
630 boot_parts);
631 }
632
633 const char *md_disklabel_cmd(void)
634 {
635
636 /* we cannot rewrite an RDB disklabel */
637 if (rdb_found)
638 return "sync No disklabel";
639
640 return "disklabel -w -r";
641 }
642
643 static int
644 check_rdb(void)
645 {
646 char buf[512], diskpath[MAXPATHLEN];
647 struct rdblock *rdb;
648 off_t blk;
649 int fd;
650
651 /* Find out if this disk has a valid RDB, before continuing. */
652 rdb = (struct rdblock *)buf;
653 fd = opendisk(pm->diskdev, O_RDONLY, diskpath, sizeof(diskpath), 0);
654 if (fd < 0)
655 return 0;
656 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) {
657 if (pread(fd, rdb, 512, blk * 512) != 512)
658 return 0;
659 if (rdb->id == RDBLOCK_ID && rdbchksum(rdb) == 0) {
660 rdb_found = 1; /* do not repartition! */
661 return 1;
662 }
663 }
664 return 0;
665 }
666
667 static uint32_t
668 rdbchksum(void *bdata)
669 {
670 uint32_t *blp, cnt, val;
671
672 blp = bdata;
673 cnt = blp[1];
674 val = 0;
675 while (cnt--)
676 val += *blp++;
677 return val;
678 }
679
680 int
681 md_pre_mount(struct install_partition_desc *install, size_t ndx)
682 {
683
684 return 0;
685 }
686
687 bool
688 md_mbr_update_check(struct disk_partitions *parts, mbr_info_t *mbri)
689 {
690 return false; /* no change, no need to write back */
691 }
692
693 #ifdef HAVE_GPT
694 bool
695 md_gpt_post_write(struct disk_partitions *parts, part_id root_id,
696 bool root_is_new, part_id efi_id, bool efi_is_new)
697 {
698 /* no GPT boot support, nothing needs to be done here */
699 return true;
700 }
701 #endif
702
703