1/* $NetBSD: md.c,v 1.11 2012/01/29 16:01:36 phx 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 50static int check_rdb(void); 51static uint32_t rdbchksum(void *); 52 53/* We use MBR_PTYPE_PREP like port-prep does. */ 54static int nonewfsmsdos = 0, nobootfix = 0, noprepfix=0; 55static int bootpart_fat12 = PART_BOOT_FAT12; 56static int bootpart_binfo = PART_BOOT_BINFO; 57static int bootpart_prep = PART_BOOT_PREP; 58static int bootinfo_mbr = 1; 59static int rdb_found = 0; 60 61/* bootstart/bootsize are for the fat */ 62int binfostart, binfosize, bprepstart, bprepsize; 63 64void 65md_init(void) 66{ 67} 68 69void 70md_init_set_status(int flags) 71{ 72 73 (void)flags; 74} 75 76int 77md_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 */ 89int 90md_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(&bsdlabel[part])) { 109 bsdlabel[part].pi_flags |= 110 PIF_NEWFS | PIF_MOUNT; 111 112 if (part == PART_A) 113 strcpy(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 bsdlabel[part_raw].pi_offset = 0; 121 bsdlabel[part_raw].pi_size = dlsize; 122 123 set_sizemultname_meg(); 124rdb_edit_check: 125 if (edit_and_check_label(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 (ptsize == 0) 141 ptsize = dlsize - ptstart; 142 if (dlsize == 0) 143 dlsize = ptstart + ptsize; 144 145 partstart = ptstart; 146 ptend = ptstart + ptsize; 147 148 /* Ask for layout type -- standard or special */ 149 msg_display(MSG_layout, 150 ptsize / (MEG / 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 current_cylsize = dlcylsize; 158 set_sizemultname_meg(); 159 160 /* Build standard partitions */ 161 memset(&bsdlabel, 0, sizeof bsdlabel); 162 163 /* Set initial partition types to unused */ 164 for (part = 0 ; part < maxpart ; ++part) 165 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 bsdlabel[part_raw].pi_offset = 0; 172 bsdlabel[part_raw].pi_size = dlsize; 173 174 if (part_raw == PART_D) { 175 /* Probably a system that expects an i386 style mbr */ 176 part_bsd = PART_C; 177 bsdlabel[PART_C].pi_offset = ptstart; 178 bsdlabel[PART_C].pi_size = ptsize; 179 } else { 180 part_bsd = part_raw; 181 } 182 183 if (bootsize != 0) { 184 bsdlabel[PART_BOOT_FAT12].pi_fstype = FS_MSDOS; 185 bsdlabel[PART_BOOT_FAT12].pi_size = bootsize; 186 bsdlabel[PART_BOOT_FAT12].pi_offset = bootstart; 187 bsdlabel[PART_BOOT_FAT12].pi_flags |= PART_BOOT_FAT12_PI_FLAGS; 188 strlcpy(bsdlabel[PART_BOOT_FAT12].pi_mount, 189 PART_BOOT_FAT12_PI_MOUNT, 190 sizeof bsdlabel[PART_BOOT_FAT12].pi_mount); 191 } 192 if (binfosize != 0) { 193 bsdlabel[PART_BOOT_BINFO].pi_fstype = FS_OTHER; 194 bsdlabel[PART_BOOT_BINFO].pi_size = binfosize; 195 bsdlabel[PART_BOOT_BINFO].pi_offset = binfostart; 196 } 197 if (bprepsize != 0) { 198 bsdlabel[PART_BOOT_PREP].pi_fstype = FS_BOOT; 199 bsdlabel[PART_BOOT_PREP].pi_size = bprepsize; 200 bsdlabel[PART_BOOT_PREP].pi_offset = bprepstart; 201 } 202 203#ifdef PART_REST 204 bsdlabel[PART_REST].pi_offset = 0; 205 bsdlabel[PART_REST].pi_size = 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 (bsdlabel[i].pi_size != 0) 216 /* Don't overwrite special partitions */ 217 continue; 218 p = &oldlabel[i]; 219 if (p->pi_fstype == FS_UNUSED || p->pi_size == 0) 220 continue; 221 if (layoutkind == 4) { 222 if (PI_ISBSDFS(p)) 223 p->pi_flags |= PIF_MOUNT; 224 } else { 225 if (p->pi_offset < ptstart + ptsize && 226 p->pi_offset + p->pi_size > ptstart) 227 /* Not outside area we are allocating */ 228 continue; 229 if (p->pi_fstype == FS_SWAP) 230 no_swap = 1; 231 } 232 bsdlabel[i] = oldlabel[i]; 233 } 234 235 if (layoutkind == 4) { 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(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, bsddiskname, bsddiskname, sizeof bsddiskname); 255 256 /* save label to disk for MI code to update. */ 257 (void) savenewlabel(bsdlabel, maxpart); 258 259 /* Everything looks OK. */ 260 return 1; 261} 262 263/* 264 * any additional partition validation 265 */ 266int 267md_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 (bsdlabel[part].pi_fstype == FS_MSDOS) { 281 bootpart_fat12 = part; 282 ffat++; 283 } else if (bsdlabel[part].pi_fstype == FS_BOOT) { 284 bootpart_prep = part; 285 fprep++; 286 } else if (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 */ 307int 308md_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(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 */ 328int 329md_post_disklabel(void) 330{ 331 char bootdev[100]; 332 333 if (bootstart == 0 || bootsize == 0 || rdb_found) 334 return 0; 335 336 snprintf(bootdev, sizeof bootdev, "/dev/r%s%c", 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 */ 348int 349md_post_newfs(void) 350{ 351 352 /* No bootblock. We use ofwboot from a partition visiable by OFW. */ 353 return 0; 354} 355 356int 357md_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", diskdev, 384 'a'+bootpart_prep); 385 snprintf(bootbdev, sizeof bootbdev, "/dev/%s%c", 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", diskdev, 393 'a'+bootpart_binfo); 394 snprintf(bootbdev, sizeof bootbdev, "/dev/%s%c", 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 405void 406md_cleanup_install(void) 407{ 408 409#ifndef DEBUG 410 enable_rc_conf(); 411#endif 412} 413 414int 415md_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(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 process_menu(MENU_yesno, NULL); 437 if (!yesno) 438 return 0; 439 nobootfix = 1; 440 } 441 } 442 } 443 444 i = md_check_partitions(); 445 switch (i) { 446 case 0: nobootfix=1; noprepfix=1; break; 447 case 1: noprepfix=1; break; 448 case 2: nobootfix=1; break; 449 default: break; 450 } 451 452 return 1; 453} 454 455/* Upgrade support */ 456int 457md_update(void) 458{ 459 460 nonewfsmsdos = 1; 461 md_post_newfs(); 462 return 1; 463} 464 465 466int 467md_check_mbr(mbr_info_t *mbri) 468{ 469 mbr_info_t *ext; 470 struct mbr_partition *part; 471 int i; 472 473 for (ext = mbri; ext; ext = ext->extended) { 474 part = ext->mbr.mbr_parts; 475 for (i = 0; i < MBR_PART_COUNT; part++, i++) { 476 if (part->mbrp_type == MBR_PTYPE_FAT12) { 477 bootstart = part->mbrp_start; 478 bootsize = part->mbrp_size; 479 } else if (part->mbrp_type == MBR_PTYPE_PREP && 480 part->mbrp_size < 50) { 481 /* this is the bootinfo partition */ 482 binfostart = part->mbrp_start; 483 binfosize = part->mbrp_size; 484 bootinfo_mbr = i+1; 485 } else if (part->mbrp_type == MBR_PTYPE_PREP && 486 part->mbrp_size > 50) { 487 bprepstart = part->mbrp_start; 488 bprepsize = part->mbrp_size; 489 } 490 break; 491 } 492 } 493 494 /* we need to either have a pair of prep partitions, or a single 495 * fat. if neither, things are broken. */ 496 if (!(bootsize >= (MIN_FAT12_BOOT/512) || 497 (binfosize >= (MIN_BINFO_BOOT/512) && 498 bprepsize >= (MIN_PREP_BOOT/512)))) { 499 msg_display(MSG_bootnotright); 500 msg_display_add(MSG_reeditpart, 0); 501 process_menu(MENU_yesno, NULL); 502 if (!yesno) 503 return 0; 504 return 1; 505 } 506 507 /* check the prep partitions */ 508 if ((binfosize > 0 || bprepsize > 0) && 509 (binfosize < (MIN_BINFO_BOOT/512) || 510 bprepsize < (MIN_PREP_BOOT/512))) { 511 msg_display(MSG_preptoosmall); 512 msg_display_add(MSG_reeditpart, 0); 513 process_menu(MENU_yesno, NULL); 514 if (!yesno) 515 return 0; 516 return 1; 517 } 518 519 /* check the fat12 parititons */ 520 if (bootsize > 0 && bootsize < (MIN_FAT12_BOOT/512)) { 521 msg_display(MSG_boottoosmall); 522 msg_display_add(MSG_reeditpart, 0); 523 process_menu(MENU_yesno, NULL); 524 if (!yesno) 525 return 0; 526 return 1; 527 } 528 529 /* if both sets contain zero, thats bad */ 530 if ((bootstart == 0 || bootsize == 0) && 531 (binfosize == 0 || binfostart == 0 || 532 bprepsize == 0 || bprepstart == 0)) { 533 msg_display(MSG_nobootpart); 534 msg_display_add(MSG_reeditpart, 0); 535 process_menu(MENU_yesno, NULL); 536 if (!yesno) 537 return 0; 538 return 1; 539 } 540 return 2; 541} 542 543/* 544 * NOTE, we use a reserved partition type, because some RS/6000 machines hang 545 * hard if they find a FAT12, and if we use type prep, that indicates that 546 * it should be read raw. 547 * One partition for FAT12 booting 548 * One partition for NetBSD 549 * One partition to hold the bootinfo.txt file 550 * One partition to hold ofwboot 551 */ 552 553int 554md_mbr_use_wholedisk(mbr_info_t *mbri) 555{ 556 struct mbr_sector *mbrs = &mbri->mbr; 557 mbr_info_t *ext; 558 struct mbr_partition *part; 559 560 part = &mbrs->mbr_parts[0]; 561 /* Set the partition information for full disk usage. */ 562 while ((ext = mbri->extended)) { 563 mbri->extended = ext->extended; 564 free(ext); 565 } 566 memset(part, 0, MBR_PART_COUNT * sizeof *part); 567 568 part[0].mbrp_type = MBR_PTYPE_RESERVED_x21; 569 part[0].mbrp_size = FAT12_BOOT_SIZE/512; 570 part[0].mbrp_start = bsec; 571 part[0].mbrp_flag = 0; 572 573 part[1].mbrp_type = MBR_PTYPE_NETBSD; 574 part[1].mbrp_size = dlsize - (bsec + FAT12_BOOT_SIZE/512 + 575 BINFO_BOOT_SIZE/512 + PREP_BOOT_SIZE/512); 576 part[1].mbrp_start = bsec + FAT12_BOOT_SIZE/512 + BINFO_BOOT_SIZE/512 + 577 PREP_BOOT_SIZE/512; 578 part[1].mbrp_flag = MBR_PFLAG_ACTIVE; 579 580 part[2].mbrp_type = MBR_PTYPE_PREP; 581 part[2].mbrp_size = BINFO_BOOT_SIZE/512; 582 part[2].mbrp_start = bsec + FAT12_BOOT_SIZE/512; 583 part[2].mbrp_flag = 0; 584 585 part[3].mbrp_type = MBR_PTYPE_PREP; 586 part[3].mbrp_size = PREP_BOOT_SIZE/512; 587 part[3].mbrp_start = bsec + FAT12_BOOT_SIZE/512 + BINFO_BOOT_SIZE/512; 588 part[3].mbrp_flag = 0; 589 590 ptstart = part[1].mbrp_start; 591 ptsize = part[1].mbrp_size; 592 bootstart = part[0].mbrp_start; 593 bootsize = part[0].mbrp_size; 594 binfostart = part[2].mbrp_start; 595 binfosize= part[2].mbrp_size; 596 bprepstart = part[3].mbrp_start; 597 bprepsize = part[3].mbrp_size; 598 bootinfo_mbr = 4; 599 600 return 1; 601} 602 603const char *md_disklabel_cmd(void) 604{ 605 606 /* we cannot rewrite an RDB disklabel */ 607 if (rdb_found) 608 return "sync No disklabel"; 609 610 return "disklabel -w -r"; 611} 612 613static int 614check_rdb(void) 615{ 616 char buf[512], diskpath[MAXPATHLEN]; 617 struct rdblock *rdb; 618 off_t blk; 619 int fd; 620 621 /* Find out if this disk has a valid RDB, before continuing. */ 622 rdb = (struct rdblock *)buf; 623 fd = opendisk(diskdev, O_RDONLY, diskpath, sizeof(diskpath), 0); 624 if (fd < 0) 625 return 0; 626 for (blk = 0; blk < RDB_MAXBLOCKS; blk++) { 627 if (pread(fd, rdb, 512, blk * 512) != 512) 628 return 0; 629 if (rdb->id == RDBLOCK_ID && rdbchksum(rdb) == 0) { 630 rdb_found = 1; /* do not repartition! */ 631 return 1; 632 } 633 } 634 return 0; 635} 636 637static uint32_t 638rdbchksum(void *bdata) 639{ 640 uint32_t *blp, cnt, val; 641 642 blp = bdata; 643 cnt = blp[1]; 644 val = 0; 645 while (cnt--) 646 val += *blp++; 647 return val; 648} 649 650int 651md_pre_mount() 652{ 653 654 return 0; 655} 656