1 /* $NetBSD: md.c,v 1.15 2025/04/26 03:49:33 tsutsui 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