1 /* $NetBSD: md.c,v 1.122 2009/05/14 16:23:38 sborrill Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Piermont Information Systems Inc. 21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 */ 38 39 /* md.c -- Machine specific code for i386 */ 40 41 #include <sys/param.h> 42 #include <sys/sysctl.h> 43 #include <sys/exec.h> 44 #include <sys/utsname.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <machine/cpu.h> 48 #include <stdio.h> 49 #include <stddef.h> 50 #include <util.h> 51 #include <dirent.h> 52 #include "defs.h" 53 #include "md.h" 54 #include "endian.h" 55 #include "msg_defs.h" 56 #include "menu_defs.h" 57 58 #ifdef NO_LBA_READS /* for testing */ 59 #undef BIFLAG_EXTINT13 60 #define BIFLAG_EXTINT13 0 61 #endif 62 63 static struct biosdisk_info *biosdisk = NULL; 64 65 /* prototypes */ 66 67 static int mbr_root_above_chs(void); 68 static void md_upgrade_mbrtype(void); 69 static int md_read_bootcode(const char *, struct mbr_sector *); 70 static unsigned int get_bootmodel(void); 71 72 73 int 74 md_get_info(void) 75 { 76 mbr_info_t *ext; 77 struct mbr_partition *p; 78 const char *bootcode; 79 int i; 80 int names, fl, ofl; 81 #define ACTIVE_FOUND 0x0100 82 #define NETBSD_ACTIVE 0x0200 83 #define NETBSD_NAMED 0x0400 84 #define ACTIVE_NAMED 0x0800 85 86 if (no_mbr) 87 return 1; 88 89 if (read_mbr(diskdev, &mbr) < 0) 90 memset(&mbr.mbr, 0, sizeof mbr.mbr - 2); 91 md_bios_info(diskdev); 92 93 edit: 94 if (edit_mbr(&mbr) == 0) 95 return 0; 96 97 root_limit = 0; 98 if (biosdisk != NULL && (biosdisk->bi_flags & BIFLAG_EXTINT13) == 0) { 99 if (mbr_root_above_chs()) { 100 msg_display(MSG_partabovechs); 101 process_menu(MENU_noyes, NULL); 102 if (!yesno) 103 goto edit; 104 /* The user is shooting themselves in the foot here...*/ 105 } else 106 root_limit = bcyl * bhead * bsec; 107 } 108 109 /* 110 * Ensure the install partition (at sector ptstart) and the active 111 * partition are bootable. 112 * Determine whether the bootselect code is needed. 113 * Note that MBR_BS_NEWMBR is always set, so we ignore it! 114 */ 115 fl = 0; 116 names = 0; 117 for (ext = &mbr; ext != NULL; ext = ext->extended) { 118 p = ext->mbr.mbr_parts; 119 for (i = 0; i < MBR_PART_COUNT; p++, i++) { 120 if (p->mbrp_flag == MBR_PFLAG_ACTIVE) { 121 fl |= ACTIVE_FOUND; 122 if (ext->sector + p->mbrp_start == ptstart) 123 fl |= NETBSD_ACTIVE; 124 } 125 if (ext->mbrb.mbrbs_nametab[i][0] == 0) { 126 /* No bootmenu label... */ 127 if (ext->sector == 0) 128 continue; 129 if (ext->sector + p->mbrp_start == ptstart) 130 /* 131 * Have installed into an extended ptn 132 * force name & bootsel... 133 */ 134 names++; 135 continue; 136 } 137 /* Partition has a bootmenu label... */ 138 if (ext->sector != 0) 139 fl |= MBR_BS_EXTLBA; 140 if (ext->sector + p->mbrp_start == ptstart) 141 fl |= NETBSD_NAMED; 142 else if (p->mbrp_flag == MBR_PFLAG_ACTIVE) 143 fl |= ACTIVE_NAMED; 144 else 145 names++; 146 } 147 } 148 if (!(fl & ACTIVE_FOUND)) 149 fl |= NETBSD_ACTIVE; 150 if (fl & NETBSD_NAMED && fl & NETBSD_ACTIVE) 151 fl |= ACTIVE_NAMED; 152 153 if ((names > 0 || !(fl & NETBSD_ACTIVE)) && 154 (!(fl & NETBSD_NAMED) || !(fl & ACTIVE_NAMED))) { 155 /* 156 * There appear to be multiple bootable partitions, but they 157 * don't all have bootmenu texts. 158 */ 159 msg_display(MSG_missing_bootmenu_text); 160 process_menu(MENU_yesno, NULL); 161 if (yesno) 162 goto edit; 163 } 164 165 if ((fl & MBR_BS_EXTLBA) && 166 (biosdisk == NULL || !(biosdisk->bi_flags & BIFLAG_EXTINT13))) { 167 /* Need unsupported LBA reads to read boot sectors */ 168 msg_display(MSG_no_extended_bootmenu); 169 process_menu(MENU_noyes, NULL); 170 if (!yesno) 171 goto edit; 172 } 173 174 /* Sort out the name of the mbr code we need */ 175 if (names > 0 || fl & (NETBSD_NAMED | ACTIVE_NAMED)) { 176 /* Need bootselect code */ 177 fl |= MBR_BS_ACTIVE; 178 bootcode = fl & MBR_BS_EXTLBA ? _PATH_BOOTEXT : _PATH_BOOTSEL; 179 } else 180 bootcode = _PATH_MBR; 181 182 fl &= MBR_BS_ACTIVE | MBR_BS_EXTLBA; 183 184 /* Look at what is installed */ 185 ofl = mbr.mbrb.mbrbs_flags; 186 if (ofl == 0) { 187 /* Check there is some bootcode at all... */ 188 if (mbr.mbr.mbr_magic != htole16(MBR_MAGIC) || 189 mbr.mbr.mbr_jmpboot[0] == 0 || 190 mbr_root_above_chs()) 191 /* Existing won't do, force update */ 192 fl |= MBR_BS_NEWMBR; 193 } 194 ofl = mbr.oflags & (MBR_BS_ACTIVE | MBR_BS_EXTLBA); 195 196 if (fl & ~ofl || (fl == 0 && ofl & MBR_BS_ACTIVE)) { 197 /* Existing boot code isn't the right one... */ 198 if (fl & MBR_BS_ACTIVE) 199 msg_display(MSG_installbootsel); 200 else 201 msg_display(MSG_installmbr); 202 } else 203 /* Existing code would (probably) be ok */ 204 msg_display(MSG_updatembr); 205 206 process_menu(MENU_yesno, NULL); 207 if (!yesno) 208 /* User doesn't want to update mbr code */ 209 return 1; 210 211 if (md_read_bootcode(bootcode, &mbr.mbr) == 0) 212 /* update suceeded - to memory copy */ 213 return 1; 214 215 /* This shouldn't happen since the files are in the floppy fs... */ 216 msg_display("Can't find %s", bootcode); 217 process_menu(MENU_yesno, NULL); 218 219 return 1; 220 } 221 222 /* 223 * Read MBR code from a file. 224 * The existing partition table and bootselect configuration is kept. 225 */ 226 static int 227 md_read_bootcode(const char *path, struct mbr_sector *mbrs) 228 { 229 int fd; 230 struct stat st; 231 size_t len; 232 struct mbr_sector new_mbr; 233 uint32_t dsn; 234 235 fd = open(path, O_RDONLY); 236 if (fd < 0) 237 return -1; 238 239 if (fstat(fd, &st) < 0 || st.st_size != sizeof *mbrs) { 240 close(fd); 241 return -1; 242 } 243 244 if (read(fd, &new_mbr, sizeof new_mbr) != sizeof new_mbr) { 245 close(fd); 246 return -1; 247 } 248 close(fd); 249 250 if (new_mbr.mbr_bootsel_magic != htole16(MBR_BS_MAGIC)) 251 return -1; 252 253 if (mbrs->mbr_bootsel_magic == htole16(MBR_BS_MAGIC)) { 254 len = offsetof(struct mbr_sector, mbr_bootsel); 255 } else 256 len = offsetof(struct mbr_sector, mbr_parts); 257 258 /* Preserve the 'drive serial number' - especially for Vista */ 259 dsn = mbrs->mbr_dsn; 260 memcpy(mbrs, &new_mbr, len); 261 mbrs->mbr_dsn = dsn; 262 263 /* Keep flags from object file - indicate the properties */ 264 mbrs->mbr_bootsel.mbrbs_flags = new_mbr.mbr_bootsel.mbrbs_flags; 265 mbrs->mbr_magic = htole16(MBR_MAGIC); 266 267 return 0; 268 } 269 270 int 271 md_pre_disklabel(void) 272 { 273 if (no_mbr) 274 return 0; 275 276 msg_display(MSG_dofdisk); 277 278 /* write edited MBR onto disk. */ 279 if (write_mbr(diskdev, &mbr, 1) != 0) { 280 msg_display(MSG_wmbrfail); 281 process_menu(MENU_ok, NULL); 282 return 1; 283 } 284 return 0; 285 } 286 287 int 288 md_post_disklabel(void) 289 { 290 if (get_ramsize() <= 32) 291 set_swap(diskdev, bsdlabel); 292 293 return 0; 294 } 295 296 int 297 md_post_newfs(void) 298 { 299 int ret; 300 size_t len; 301 int td, sd; 302 char bootxx[8192 + 4]; 303 char *bootxx_filename; 304 /* 305 * XXX - should either find some way to pull this automatically 306 * from sys/arch/i386/stand/lib/boot_params.S, or just bite the 307 * bullet and include /sbin/installboot on the ramdisk 308 */ 309 static struct x86_boot_params boottype = 310 {sizeof boottype, 0, 5, 0, 9600, { '\0' }, "", 0}; 311 static int conmib[] = {CTL_MACHDEP, CPU_CONSDEV}; 312 struct termios t; 313 dev_t condev; 314 #define bp (*(struct x86_boot_params *)(bootxx + 512 * 2 + 8)) 315 316 /* 317 * Get console device, should either be ttyE0 or tty0n. 318 * Too hard to double check, so just 'know' the device numbers. 319 */ 320 len = sizeof condev; 321 if (sysctl(conmib, nelem(conmib), &condev, &len, NULL, 0) != -1 322 && (condev & ~3) == 0x800) { 323 /* Motherboard serial port */ 324 boottype.bp_consdev = (condev & 3) + 1; 325 /* Defaulting the baud rate to that of stdin should suffice */ 326 if (tcgetattr(0, &t) != -1) 327 boottype.bp_conspeed = t.c_ispeed; 328 } 329 330 process_menu(MENU_getboottype, &boottype); 331 msg_display(MSG_dobootblks, diskdev); 332 if (bp.bp_consdev == ~0) 333 return 0; 334 335 ret = cp_to_target("/usr/mdec/boot", "/boot"); 336 if (ret) 337 return ret; 338 339 /* Copy bootstrap in by hand - /sbin/installboot explodes ramdisks */ 340 ret = 1; 341 342 snprintf(bootxx, sizeof bootxx, "/dev/r%s%c", diskdev, 'a' + rootpart); 343 td = open(bootxx, O_RDWR, 0); 344 bootxx_filename = bootxx_name(); 345 if (bootxx_filename != NULL) { 346 sd = open(bootxx_filename, O_RDONLY); 347 free(bootxx_filename); 348 } else 349 sd = -1; 350 if (td == -1 || sd == -1) 351 goto bad_bootxx; 352 len = read(sd, bootxx, sizeof bootxx); 353 if (len < 2048 || len > 8192) 354 goto bad_bootxx; 355 356 if (*(uint32_t *)(bootxx + 512 * 2 + 4) != X86_BOOT_MAGIC_1) 357 goto bad_bootxx; 358 359 boottype.bp_length = bp.bp_length; 360 memcpy(&bp, &boottype, min(boottype.bp_length, sizeof boottype)); 361 362 if (pwrite(td, bootxx, 512, 0) != 512) 363 goto bad_bootxx; 364 len -= 512 * 2; 365 if (pwrite(td, bootxx + 512 * 2, len, 2 * (off_t)512) != len) 366 goto bad_bootxx; 367 ret = 0; 368 369 bad_bootxx: 370 close(td); 371 close(sd); 372 373 return ret; 374 } 375 376 int 377 md_copy_filesystem(void) 378 { 379 return 0; 380 } 381 382 383 int 384 md_make_bsd_partitions(void) 385 { 386 387 return make_bsd_partitions(); 388 } 389 390 int 391 md_pre_update(void) 392 { 393 if (get_ramsize() <= 8) 394 set_swap(diskdev, NULL); 395 return 1; 396 } 397 398 /* 399 * any additional partition validation 400 */ 401 int 402 md_check_partitions(void) 403 { 404 int rval; 405 char *bootxx; 406 407 /* check we have boot code for the root partition type */ 408 bootxx = bootxx_name(); 409 rval = access(bootxx, R_OK); 410 free(bootxx); 411 if (rval == 0) 412 return 1; 413 process_menu(MENU_ok, deconst(MSG_No_Bootcode)); 414 return 0; 415 } 416 417 418 /* Upgrade support */ 419 int 420 md_update(void) 421 { 422 move_aout_libs(); 423 /* endwin(); */ 424 md_copy_filesystem(); 425 md_post_newfs(); 426 md_upgrade_mbrtype(); 427 wrefresh(curscr); 428 wmove(stdscr, 0, 0); 429 wclear(stdscr); 430 wrefresh(stdscr); 431 return 1; 432 } 433 434 void 435 md_upgrade_mbrtype(void) 436 { 437 struct mbr_partition *mbrp; 438 int i, netbsdpart = -1, oldbsdpart = -1, oldbsdcount = 0; 439 440 if (no_mbr) 441 return; 442 443 if (read_mbr(diskdev, &mbr) < 0) 444 return; 445 446 mbrp = &mbr.mbr.mbr_parts[0]; 447 448 for (i = 0; i < MBR_PART_COUNT; i++) { 449 if (mbrp[i].mbrp_type == MBR_PTYPE_386BSD) { 450 oldbsdpart = i; 451 oldbsdcount++; 452 } else if (mbrp[i].mbrp_type == MBR_PTYPE_NETBSD) 453 netbsdpart = i; 454 } 455 456 if (netbsdpart == -1 && oldbsdcount == 1) { 457 mbrp[oldbsdpart].mbrp_type = MBR_PTYPE_NETBSD; 458 write_mbr(diskdev, &mbr, 0); 459 } 460 } 461 462 463 464 void 465 md_cleanup_install(void) 466 { 467 468 enable_rc_conf(); 469 470 add_rc_conf("wscons=YES\n"); 471 472 #if defined(__i386__) && defined(SET_KERNEL_TINY) 473 /* 474 * For GENERIC_TINY, do not enable any extra screens or wsmux. 475 * Otherwise, run getty on 4 VTs. 476 */ 477 if (get_kernel_set() == SET_KERNEL_TINY) 478 run_program(RUN_CHROOT, 479 "sed -an -e '/^screen/s/^/#/;/^mux/s/^/#/;" 480 "H;$!d;g;w /etc/wscons.conf' /etc/wscons.conf"); 481 else 482 #endif 483 run_program(RUN_CHROOT, 484 "sed -an -e '/^ttyE[1-9]/s/off/on/;" 485 "H;$!d;g;w /etc/ttys' /etc/ttys"); 486 487 } 488 489 int 490 md_bios_info(dev) 491 char *dev; 492 { 493 static struct disklist *disklist = NULL; 494 static int mib[2] = {CTL_MACHDEP, CPU_DISKINFO}; 495 int i; 496 size_t len; 497 struct biosdisk_info *bip; 498 struct nativedisk_info *nip = NULL, *nat; 499 int cyl, head; 500 daddr_t sec; 501 502 if (disklist == NULL) { 503 if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) 504 goto nogeom; 505 disklist = malloc(len); 506 if (disklist == NULL) { 507 fprintf(stderr, "Out of memory\n"); 508 return -1; 509 } 510 sysctl(mib, 2, disklist, &len, NULL, 0); 511 } 512 513 for (i = 0; i < disklist->dl_nnativedisks; i++) { 514 nat = &disklist->dl_nativedisks[i]; 515 if (!strcmp(dev, nat->ni_devname)) { 516 nip = nat; 517 break; 518 } 519 } 520 if (nip == NULL || nip->ni_nmatches == 0) { 521 nogeom: 522 msg_display(MSG_nobiosgeom, dlcyl, dlhead, dlsec); 523 if (guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec) >= 0) 524 msg_display_add(MSG_biosguess, cyl, head, sec); 525 biosdisk = NULL; 526 } else { 527 guess_biosgeom_from_mbr(&mbr, &cyl, &head, &sec); 528 if (nip->ni_nmatches == 1) { 529 bip = &disklist->dl_biosdisks[nip->ni_biosmatches[0]]; 530 msg_display(MSG_onebiosmatch); 531 msg_table_add(MSG_onebiosmatch_header); 532 msg_table_add(MSG_onebiosmatch_row, bip->bi_dev, 533 bip->bi_cyl, bip->bi_head, bip->bi_sec, 534 (unsigned)bip->bi_lbasecs, 535 (unsigned)(bip->bi_lbasecs / (1000000000 / 512))); 536 msg_display_add(MSG_biosgeom_advise); 537 biosdisk = bip; 538 process_menu(MENU_biosonematch, &biosdisk); 539 } else { 540 msg_display(MSG_biosmultmatch); 541 msg_table_add(MSG_biosmultmatch_header); 542 for (i = 0; i < nip->ni_nmatches; i++) { 543 bip = &disklist->dl_biosdisks[ 544 nip->ni_biosmatches[i]]; 545 msg_table_add(MSG_biosmultmatch_row, i, 546 bip->bi_dev, bip->bi_cyl, bip->bi_head, 547 bip->bi_sec, (unsigned)bip->bi_lbasecs, 548 (unsigned)bip->bi_lbasecs/(1000000000/512)); 549 } 550 process_menu(MENU_biosmultmatch, &i); 551 if (i == -1) 552 biosdisk = NULL; 553 else 554 biosdisk = &disklist->dl_biosdisks[ 555 nip->ni_biosmatches[i]]; 556 } 557 } 558 if (biosdisk == NULL) 559 set_bios_geom(cyl, head, sec); 560 else { 561 bcyl = biosdisk->bi_cyl; 562 bhead = biosdisk->bi_head; 563 bsec = biosdisk->bi_sec; 564 } 565 return 0; 566 } 567 568 static int 569 mbr_root_above_chs(void) 570 { 571 572 return ptstart + DEFROOTSIZE * (MEG / 512) >= bcyl * bhead * bsec; 573 } 574 575 unsigned int 576 get_bootmodel(void) 577 { 578 #if defined(__i386__) 579 struct utsname ut; 580 #ifdef DEBUG 581 char *envstr; 582 583 envstr = getenv("BOOTMODEL"); 584 if (envstr != NULL) 585 return atoi(envstr); 586 #endif 587 588 if (uname(&ut) < 0) 589 ut.version[0] = 0; 590 591 #if defined(SET_KERNEL_TINY) 592 if (strstr(ut.version, "TINY") != NULL) 593 return SET_KERNEL_TINY; 594 #endif 595 #if defined(SET_KERNEL_PS2) 596 if (strstr(ut.version, "PS2") != NULL) 597 return SET_KERNEL_PS2; 598 #endif 599 #endif 600 return SET_KERNEL_GENERIC; 601 } 602 603 void 604 md_init(void) 605 { 606 } 607 608 void 609 md_init_set_status(int minimal) 610 { 611 (void)minimal; 612 613 /* Default to install same type of kernel as we are running */ 614 set_kernel_set(get_bootmodel()); 615 } 616 617 int 618 md_post_extract(void) 619 { 620 return 0; 621 } 622 623 int 624 md_check_mbr(mbr_info_t *mbri) 625 { 626 return 2; 627 } 628 629 int 630 md_mbr_use_wholedisk(mbr_info_t *mbri) 631 { 632 return mbr_use_wholedisk(mbri); 633 } 634