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