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