1 /* $NetBSD: md.c,v 1.3 2015/05/10 10:14:03 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 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