biosdisk.c revision 357496
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/11/stand/i386/libi386/biosdisk.c 357496 2020-02-04 07:18:49Z tsoome $"); 30 31/* 32 * BIOS disk device handling. 33 * 34 * Ideas and algorithms from: 35 * 36 * - NetBSD libi386/biosdisk.c 37 * - FreeBSD biosboot/disk.c 38 * 39 */ 40 41#include <sys/disk.h> 42#include <sys/limits.h> 43#include <sys/queue.h> 44#include <stand.h> 45#include <machine/bootinfo.h> 46#include <stdarg.h> 47#include <stdbool.h> 48 49#include <bootstrap.h> 50#include <btxv86.h> 51#include <edd.h> 52#include "disk.h" 53#include "libi386.h" 54 55#define BIOS_NUMDRIVES 0x475 56#define BIOSDISK_SECSIZE 512 57#define BUFSIZE (1 * BIOSDISK_SECSIZE) 58 59#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ 60#define WDMAJOR 0 /* major numbers for devices we frontend for */ 61#define WFDMAJOR 1 62#define FDMAJOR 2 63#define DAMAJOR 4 64#define ACDMAJOR 117 65#define CDMAJOR 15 66 67#ifdef DISK_DEBUG 68#define DEBUG(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) 69#else 70#define DEBUG(fmt, args...) 71#endif 72 73struct specification_packet { 74 uint8_t sp_size; 75 uint8_t sp_bootmedia; 76 uint8_t sp_drive; 77 uint8_t sp_controller; 78 uint32_t sp_lba; 79 uint16_t sp_devicespec; 80 uint16_t sp_buffersegment; 81 uint16_t sp_loadsegment; 82 uint16_t sp_sectorcount; 83 uint16_t sp_cylsec; 84 uint8_t sp_head; 85 uint8_t sp_dummy[16]; /* Avoid memory corruption */ 86}; 87 88/* 89 * List of BIOS devices, translation from disk unit number to 90 * BIOS unit number. 91 */ 92typedef struct bdinfo 93{ 94 STAILQ_ENTRY(bdinfo) bd_link; /* link in device list */ 95 int bd_unit; /* BIOS unit number */ 96 int bd_cyl; /* BIOS geometry */ 97 int bd_hds; 98 int bd_sec; 99 int bd_flags; 100#define BD_MODEINT13 0x0000 101#define BD_MODEEDD1 0x0001 102#define BD_MODEEDD3 0x0002 103#define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3) 104#define BD_MODEMASK 0x0003 105#define BD_FLOPPY 0x0004 106#define BD_CDROM 0x0008 107#define BD_NO_MEDIA 0x0010 108 int bd_type; /* BIOS 'drive type' (floppy only) */ 109 uint16_t bd_sectorsize; /* Sector size */ 110 uint64_t bd_sectors; /* Disk size */ 111 int bd_open; /* reference counter */ 112 void *bd_bcache; /* buffer cache data */ 113} bdinfo_t; 114 115#define BD_RD 0 116#define BD_WR 1 117 118typedef STAILQ_HEAD(bdinfo_list, bdinfo) bdinfo_list_t; 119static bdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo); 120static bdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo); 121static bdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo); 122 123static void bd_io_workaround(bdinfo_t *); 124static int bd_io(struct disk_devdesc *, bdinfo_t *, daddr_t, int, caddr_t, int); 125static bool bd_int13probe(bdinfo_t *); 126 127static int bd_init(void); 128static int cd_init(void); 129static int fd_init(void); 130static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 131 char *buf, size_t *rsize); 132static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, 133 char *buf, size_t *rsize); 134static int bd_open(struct open_file *f, ...); 135static int bd_close(struct open_file *f); 136static int bd_ioctl(struct open_file *f, u_long cmd, void *data); 137static int bd_print(int verbose); 138static int cd_print(int verbose); 139static int fd_print(int verbose); 140static void bd_reset_disk(int); 141static int bd_get_diskinfo_std(struct bdinfo *); 142 143struct devsw biosfd = { 144 .dv_name = "fd", 145 .dv_type = DEVT_FD, 146 .dv_init = fd_init, 147 .dv_strategy = bd_strategy, 148 .dv_open = bd_open, 149 .dv_close = bd_close, 150 .dv_ioctl = bd_ioctl, 151 .dv_print = fd_print, 152 .dv_cleanup = NULL 153}; 154 155struct devsw bioscd = { 156 .dv_name = "cd", 157 .dv_type = DEVT_CD, 158 .dv_init = cd_init, 159 .dv_strategy = bd_strategy, 160 .dv_open = bd_open, 161 .dv_close = bd_close, 162 .dv_ioctl = bd_ioctl, 163 .dv_print = cd_print, 164 .dv_cleanup = NULL 165}; 166 167struct devsw bioshd = { 168 .dv_name = "disk", 169 .dv_type = DEVT_DISK, 170 .dv_init = bd_init, 171 .dv_strategy = bd_strategy, 172 .dv_open = bd_open, 173 .dv_close = bd_close, 174 .dv_ioctl = bd_ioctl, 175 .dv_print = bd_print, 176 .dv_cleanup = NULL 177}; 178 179static bdinfo_list_t * 180bd_get_bdinfo_list(struct devsw *dev) 181{ 182 if (dev->dv_type == DEVT_DISK) 183 return (&hdinfo); 184 if (dev->dv_type == DEVT_CD) 185 return (&cdinfo); 186 if (dev->dv_type == DEVT_FD) 187 return (&fdinfo); 188 return (NULL); 189} 190 191/* XXX this gets called way way too often, investigate */ 192static bdinfo_t * 193bd_get_bdinfo(struct devdesc *dev) 194{ 195 bdinfo_list_t *bdi; 196 bdinfo_t *bd = NULL; 197 int unit; 198 199 bdi = bd_get_bdinfo_list(dev->d_dev); 200 if (bdi == NULL) 201 return (bd); 202 203 unit = 0; 204 STAILQ_FOREACH(bd, bdi, bd_link) { 205 if (unit == dev->d_unit) 206 return (bd); 207 unit++; 208 } 209 return (bd); 210} 211 212/* 213 * Translate between BIOS device numbers and our private unit numbers. 214 */ 215int 216bd_bios2unit(int biosdev) 217{ 218 bdinfo_list_t *bdi[] = { &fdinfo, &cdinfo, &hdinfo, NULL }; 219 bdinfo_t *bd; 220 int i, unit; 221 222 DEBUG("looking for bios device 0x%x", biosdev); 223 for (i = 0; bdi[i] != NULL; i++) { 224 unit = 0; 225 STAILQ_FOREACH(bd, bdi[i], bd_link) { 226 if (bd->bd_unit == biosdev) { 227 DEBUG("bd unit %d is BIOS device 0x%x", unit, 228 bd->bd_unit); 229 return (unit); 230 } 231 unit++; 232 } 233 } 234 return (-1); 235} 236 237int 238bd_unit2bios(struct i386_devdesc *dev) 239{ 240 bdinfo_list_t *bdi; 241 bdinfo_t *bd; 242 int unit; 243 244 bdi = bd_get_bdinfo_list(dev->dd.d_dev); 245 if (bdi == NULL) 246 return (-1); 247 248 unit = 0; 249 STAILQ_FOREACH(bd, bdi, bd_link) { 250 if (unit == dev->dd.d_unit) 251 return (bd->bd_unit); 252 unit++; 253 } 254 return (-1); 255} 256 257/* 258 * Use INT13 AH=15 - Read Drive Type. 259 */ 260static int 261fd_count(void) 262{ 263 int drive; 264 265 for (drive = 0; drive < MAXBDDEV; drive++) { 266 bd_reset_disk(drive); 267 268 v86.ctl = V86_FLAGS; 269 v86.addr = 0x13; 270 v86.eax = 0x1500; 271 v86.edx = drive; 272 v86int(); 273 274 if (V86_CY(v86.efl)) 275 break; 276 277 if ((v86.eax & 0x300) == 0) 278 break; 279 } 280 281 return (drive); 282} 283 284/* 285 * Quiz the BIOS for disk devices, save a little info about them. 286 */ 287static int 288fd_init(void) 289{ 290 int unit, numfd; 291 bdinfo_t *bd; 292 293 numfd = fd_count(); 294 for (unit = 0; unit < numfd; unit++) { 295 if ((bd = calloc(1, sizeof(*bd))) == NULL) 296 break; 297 298 bd->bd_sectorsize = BIOSDISK_SECSIZE; 299 bd->bd_flags = BD_FLOPPY; 300 bd->bd_unit = unit; 301 302 /* Use std diskinfo for floppy drive */ 303 if (bd_get_diskinfo_std(bd) != 0) { 304 free(bd); 305 break; 306 } 307 if (bd->bd_sectors == 0) 308 bd->bd_flags |= BD_NO_MEDIA; 309 310 printf("BIOS drive %c: is %s%d\n", ('A' + unit), 311 biosfd.dv_name, unit); 312 313 STAILQ_INSERT_TAIL(&fdinfo, bd, bd_link); 314 } 315 316 bcache_add_dev(unit); 317 return (0); 318} 319 320static int 321bd_init(void) 322{ 323 int base, unit; 324 bdinfo_t *bd; 325 326 base = 0x80; 327 for (unit = 0; unit < *(unsigned char *)PTOV(BIOS_NUMDRIVES); unit++) { 328 /* 329 * Check the BIOS equipment list for number of fixed disks. 330 */ 331 if ((bd = calloc(1, sizeof(*bd))) == NULL) 332 break; 333 bd->bd_unit = base + unit; 334 if (!bd_int13probe(bd)) { 335 free(bd); 336 break; 337 } 338 339 printf("BIOS drive %c: is %s%d\n", ('C' + unit), 340 bioshd.dv_name, unit); 341 342 STAILQ_INSERT_TAIL(&hdinfo, bd, bd_link); 343 } 344 bcache_add_dev(unit); 345 return (0); 346} 347 348/* 349 * We can't quiz, we have to be told what device to use, so this function 350 * doesn't do anything. Instead, the loader calls bc_add() with the BIOS 351 * device number to add. 352 */ 353static int 354cd_init(void) 355{ 356 357 return (0); 358} 359 360/* 361 * Information from bootable CD-ROM. 362 */ 363static int 364bd_get_diskinfo_cd(struct bdinfo *bd) 365{ 366 struct specification_packet bc_sp; 367 int ret = -1; 368 369 (void) memset(&bc_sp, 0, sizeof (bc_sp)); 370 /* Set sp_size as per specification. */ 371 bc_sp.sp_size = sizeof (bc_sp) - sizeof (bc_sp.sp_dummy); 372 373 v86.ctl = V86_FLAGS; 374 v86.addr = 0x13; 375 v86.eax = 0x4b01; 376 v86.edx = bd->bd_unit; 377 v86.ds = VTOPSEG(&bc_sp); 378 v86.esi = VTOPOFF(&bc_sp); 379 v86int(); 380 381 if ((v86.eax & 0xff00) == 0 && 382 bc_sp.sp_drive == bd->bd_unit) { 383 bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) + 384 ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1; 385 bd->bd_sec = bc_sp.sp_cylsec & 0x3f; 386 bd->bd_hds = bc_sp.sp_head + 1; 387 bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; 388 389 if (bc_sp.sp_bootmedia & 0x0F) { 390 /* Floppy or hard-disk emulation */ 391 bd->bd_sectorsize = BIOSDISK_SECSIZE; 392 return (-1); 393 } else { 394 bd->bd_sectorsize = 2048; 395 bd->bd_flags = BD_MODEEDD | BD_CDROM; 396 ret = 0; 397 } 398 } 399 400 /* 401 * If this is the boot_drive, default to non-emulation bootable CD-ROM. 402 */ 403 if (ret != 0 && bd->bd_unit >= 0x88) { 404 bd->bd_cyl = 0; 405 bd->bd_hds = 1; 406 bd->bd_sec = 15; 407 bd->bd_sectorsize = 2048; 408 bd->bd_flags = BD_MODEEDD | BD_CDROM; 409 bd->bd_sectors = 0; 410 ret = 0; 411 } 412 413 /* 414 * Note we can not use bd_get_diskinfo_ext() nor bd_get_diskinfo_std() 415 * here - some systems do get hung with those. 416 */ 417 /* 418 * Still no size? use 7.961GB. The size does not really matter 419 * as long as it is reasonably large to make our reads to pass 420 * the sector count check. 421 */ 422 if (bd->bd_sectors == 0) 423 bd->bd_sectors = 4173824; 424 425 return (ret); 426} 427 428int 429bc_add(int biosdev) 430{ 431 bdinfo_t *bd; 432 int nbcinfo = 0; 433 434 if (!STAILQ_EMPTY(&cdinfo)) 435 return (-1); 436 437 if ((bd = calloc(1, sizeof(*bd))) == NULL) 438 return (-1); 439 440 bd->bd_unit = biosdev; 441 if (bd_get_diskinfo_cd(bd) < 0) { 442 free(bd); 443 return (-1); 444 } 445 446 STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link); 447 printf("BIOS CD is cd%d\n", nbcinfo); 448 nbcinfo++; 449 bcache_add_dev(nbcinfo); /* register cd device in bcache */ 450 return(0); 451} 452 453/* 454 * Return EDD version or 0 if EDD is not supported on this drive. 455 */ 456static int 457bd_check_extensions(int unit) 458{ 459 /* do not use ext calls for floppy devices */ 460 if (unit < 0x80) 461 return (0); 462 463 /* Determine if we can use EDD with this device. */ 464 v86.ctl = V86_FLAGS; 465 v86.addr = 0x13; 466 v86.eax = 0x4100; 467 v86.edx = unit; 468 v86.ebx = 0x55aa; 469 v86int(); 470 471 if (V86_CY(v86.efl) || /* carry set */ 472 (v86.ebx & 0xffff) != 0xaa55) /* signature */ 473 return (0); 474 475 /* extended disk access functions (AH=42h-44h,47h,48h) supported */ 476 if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) 477 return (0); 478 479 return ((v86.eax >> 8) & 0xff); 480} 481 482static void 483bd_reset_disk(int unit) 484{ 485 /* reset disk */ 486 v86.ctl = V86_FLAGS; 487 v86.addr = 0x13; 488 v86.eax = 0; 489 v86.edx = unit; 490 v86int(); 491} 492 493/* 494 * Read CHS info. Return 0 on success, error otherwise. 495 */ 496static int 497bd_get_diskinfo_std(struct bdinfo *bd) 498{ 499 bzero(&v86, sizeof(v86)); 500 v86.ctl = V86_FLAGS; 501 v86.addr = 0x13; 502 v86.eax = 0x800; 503 v86.edx = bd->bd_unit; 504 v86int(); 505 506 if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) 507 return ((v86.eax & 0xff00) >> 8); 508 509 /* return custom error on absurd sector number */ 510 if ((v86.ecx & 0x3f) == 0) 511 return (0x60); 512 513 bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; 514 /* Convert max head # -> # of heads */ 515 bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; 516 bd->bd_sec = v86.ecx & 0x3f; 517 bd->bd_type = v86.ebx; 518 bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; 519 520 return (0); 521} 522 523/* 524 * Read EDD info. Return 0 on success, error otherwise. 525 * 526 * Avoid stack corruption on some systems by adding extra bytes to 527 * params block. 528 */ 529static int 530bd_get_diskinfo_ext(struct bdinfo *bd) 531{ 532 struct disk_params { 533 struct edd_params head; 534 struct edd_device_path_v3 device_path; 535 uint8_t dummy[16]; 536 } __packed dparams; 537 struct edd_params *params; 538 uint64_t total; 539 540 params = &dparams.head; 541 542 /* Get disk params */ 543 bzero(&dparams, sizeof(dparams)); 544 params->len = sizeof(struct edd_params_v3); 545 v86.ctl = V86_FLAGS; 546 v86.addr = 0x13; 547 v86.eax = 0x4800; 548 v86.edx = bd->bd_unit; 549 v86.ds = VTOPSEG(&dparams); 550 v86.esi = VTOPOFF(&dparams); 551 v86int(); 552 553 if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) 554 return ((v86.eax & 0xff00) >> 8); 555 556 /* 557 * Sector size must be a multiple of 512 bytes. 558 * An alternate test would be to check power of 2, 559 * powerof2(params.sector_size). 560 * 16K is largest read buffer we can use at this time. 561 */ 562 if (params->sector_size >= 512 && 563 params->sector_size <= 16384 && 564 (params->sector_size % BIOSDISK_SECSIZE) == 0) 565 bd->bd_sectorsize = params->sector_size; 566 567 bd->bd_cyl = params->cylinders; 568 bd->bd_hds = params->heads; 569 bd->bd_sec = params->sectors_per_track; 570 571 if (params->sectors != 0) { 572 total = params->sectors; 573 } else { 574 total = (uint64_t)params->cylinders * 575 params->heads * params->sectors_per_track; 576 } 577 bd->bd_sectors = total; 578 579 return (0); 580} 581 582/* 583 * Try to detect a device supported by the legacy int13 BIOS 584 */ 585static bool 586bd_int13probe(bdinfo_t *bd) 587{ 588 int edd, ret; 589 590 bd->bd_flags &= ~BD_NO_MEDIA; 591 592 if ((bd->bd_flags & BD_CDROM) != 0) { 593 return (bd_get_diskinfo_cd(bd) == 0); 594 } 595 596 edd = bd_check_extensions(bd->bd_unit); 597 if (edd == 0) 598 bd->bd_flags |= BD_MODEINT13; 599 else if (edd < 0x30) 600 bd->bd_flags |= BD_MODEEDD1; 601 else 602 bd->bd_flags |= BD_MODEEDD3; 603 604 /* Default sector size */ 605 if (bd->bd_sectorsize == 0) 606 bd->bd_sectorsize = BIOSDISK_SECSIZE; 607 608 /* 609 * Test if the floppy device is present, so we can avoid receiving 610 * bogus information from bd_get_diskinfo_std(). 611 */ 612 if (bd->bd_unit < 0x80) { 613 /* reset disk */ 614 bd_reset_disk(bd->bd_unit); 615 616 /* Get disk type */ 617 v86.ctl = V86_FLAGS; 618 v86.addr = 0x13; 619 v86.eax = 0x1500; 620 v86.edx = bd->bd_unit; 621 v86int(); 622 if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0) 623 return (false); 624 } 625 626 ret = 1; 627 if (edd != 0) 628 ret = bd_get_diskinfo_ext(bd); 629 if (ret != 0 || bd->bd_sectors == 0) 630 ret = bd_get_diskinfo_std(bd); 631 632 if (ret != 0 && bd->bd_unit < 0x80) { 633 /* Set defaults for 1.44 floppy */ 634 bd->bd_cyl = 80; 635 bd->bd_hds = 2; 636 bd->bd_sec = 18; 637 bd->bd_sectors = 2880; 638 /* Since we are there, there most likely is no media */ 639 bd->bd_flags |= BD_NO_MEDIA; 640 ret = 0; 641 } 642 643 if (ret != 0) { 644 if (bd->bd_sectors != 0 && edd != 0) { 645 bd->bd_sec = 63; 646 bd->bd_hds = 255; 647 bd->bd_cyl = 648 (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) / 649 bd->bd_sec * bd->bd_hds; 650 } else { 651 const char *dv_name; 652 653 if ((bd->bd_flags & BD_FLOPPY) != 0) 654 dv_name = biosfd.dv_name; 655 else 656 dv_name = bioshd.dv_name; 657 658 printf("Can not get information about %s unit %#x\n", 659 dv_name, bd->bd_unit); 660 return (false); 661 } 662 } 663 664 if (bd->bd_sec == 0) 665 bd->bd_sec = 63; 666 if (bd->bd_hds == 0) 667 bd->bd_hds = 255; 668 669 if (bd->bd_sectors == 0) 670 bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; 671 672 DEBUG("unit 0x%x geometry %d/%d/%d\n", bd->bd_unit, bd->bd_cyl, 673 bd->bd_hds, bd->bd_sec); 674 675 return (true); 676} 677 678static int 679bd_count(bdinfo_list_t *bdi) 680{ 681 bdinfo_t *bd; 682 int i; 683 684 i = 0; 685 STAILQ_FOREACH(bd, bdi, bd_link) 686 i++; 687 return (i); 688} 689 690/* 691 * Print information about disks 692 */ 693static int 694bd_print_common(struct devsw *dev, bdinfo_list_t *bdi, int verbose) 695{ 696 char line[80]; 697 struct disk_devdesc devd; 698 bdinfo_t *bd; 699 int i, ret = 0; 700 char drive; 701 702 if (STAILQ_EMPTY(bdi)) 703 return (0); 704 705 printf("%s devices:", dev->dv_name); 706 if ((ret = pager_output("\n")) != 0) 707 return (ret); 708 709 i = -1; 710 STAILQ_FOREACH(bd, bdi, bd_link) { 711 i++; 712 713 switch (dev->dv_type) { 714 case DEVT_FD: 715 drive = 'A'; 716 break; 717 case DEVT_CD: 718 drive = 'C' + bd_count(&hdinfo); 719 break; 720 default: 721 drive = 'C'; 722 break; 723 } 724 725 snprintf(line, sizeof(line), 726 " %s%d: BIOS drive %c (%s%ju X %u):\n", 727 dev->dv_name, i, drive + i, 728 (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ? 729 "no media, " : "", 730 (uintmax_t)bd->bd_sectors, 731 bd->bd_sectorsize); 732 if ((ret = pager_output(line)) != 0) 733 break; 734 735 if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) 736 continue; 737 738 if (dev->dv_type != DEVT_DISK) 739 continue; 740 741 devd.dd.d_dev = dev; 742 devd.dd.d_unit = i; 743 devd.d_slice = -1; 744 devd.d_partition = -1; 745 if (disk_open(&devd, 746 bd->bd_sectorsize * bd->bd_sectors, 747 bd->bd_sectorsize) == 0) { 748 snprintf(line, sizeof(line), " %s%d", 749 dev->dv_name, i); 750 ret = disk_print(&devd, line, verbose); 751 disk_close(&devd); 752 if (ret != 0) 753 break; 754 } 755 } 756 return (ret); 757} 758 759static int 760fd_print(int verbose) 761{ 762 return (bd_print_common(&biosfd, &fdinfo, verbose)); 763} 764 765static int 766bd_print(int verbose) 767{ 768 return (bd_print_common(&bioshd, &hdinfo, verbose)); 769} 770 771static int 772cd_print(int verbose) 773{ 774 return (bd_print_common(&bioscd, &cdinfo, verbose)); 775} 776 777/* 778 * Read disk size from partition. 779 * This is needed to work around buggy BIOS systems returning 780 * wrong (truncated) disk media size. 781 * During bd_probe() we tested if the multiplication of bd_sectors 782 * would overflow so it should be safe to perform here. 783 */ 784static uint64_t 785bd_disk_get_sectors(struct disk_devdesc *dev) 786{ 787 bdinfo_t *bd; 788 struct disk_devdesc disk; 789 uint64_t size; 790 791 bd = bd_get_bdinfo(&dev->dd); 792 if (bd == NULL) 793 return (0); 794 795 disk.dd.d_dev = dev->dd.d_dev; 796 disk.dd.d_unit = dev->dd.d_unit; 797 disk.d_slice = -1; 798 disk.d_partition = -1; 799 disk.d_offset = 0; 800 801 size = bd->bd_sectors * bd->bd_sectorsize; 802 if (disk_open(&disk, size, bd->bd_sectorsize) == 0) { 803 (void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size); 804 disk_close(&disk); 805 } 806 return (size / bd->bd_sectorsize); 807} 808 809/* 810 * Attempt to open the disk described by (dev) for use by (f). 811 * 812 * Note that the philosophy here is "give them exactly what 813 * they ask for". This is necessary because being too "smart" 814 * about what the user might want leads to complications. 815 * (eg. given no slice or partition value, with a disk that is 816 * sliced - are they after the first BSD slice, or the DOS 817 * slice before it?) 818 */ 819static int 820bd_open(struct open_file *f, ...) 821{ 822 bdinfo_t *bd; 823 struct disk_devdesc *dev; 824 va_list ap; 825 int rc; 826 827 va_start(ap, f); 828 dev = va_arg(ap, struct disk_devdesc *); 829 va_end(ap); 830 831 bd = bd_get_bdinfo(&dev->dd); 832 if (bd == NULL) 833 return (EIO); 834 835 if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) { 836 if (!bd_int13probe(bd)) 837 return (EIO); 838 if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) 839 return (EIO); 840 } 841 if (bd->bd_bcache == NULL) 842 bd->bd_bcache = bcache_allocate(); 843 844 if (bd->bd_open == 0) 845 bd->bd_sectors = bd_disk_get_sectors(dev); 846 bd->bd_open++; 847 848 rc = 0; 849 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 850 rc = disk_open(dev, bd->bd_sectors * bd->bd_sectorsize, 851 bd->bd_sectorsize); 852 if (rc != 0) { 853 bd->bd_open--; 854 if (bd->bd_open == 0) { 855 bcache_free(bd->bd_bcache); 856 bd->bd_bcache = NULL; 857 } 858 } 859 } 860 return (rc); 861} 862 863static int 864bd_close(struct open_file *f) 865{ 866 struct disk_devdesc *dev; 867 bdinfo_t *bd; 868 int rc = 0; 869 870 dev = (struct disk_devdesc *)f->f_devdata; 871 bd = bd_get_bdinfo(&dev->dd); 872 if (bd == NULL) 873 return (EIO); 874 875 bd->bd_open--; 876 if (bd->bd_open == 0) { 877 bcache_free(bd->bd_bcache); 878 bd->bd_bcache = NULL; 879 } 880 if (dev->dd.d_dev->dv_type == DEVT_DISK) 881 rc = disk_close(dev); 882 return (rc); 883} 884 885static int 886bd_ioctl(struct open_file *f, u_long cmd, void *data) 887{ 888 bdinfo_t *bd; 889 struct disk_devdesc *dev; 890 int rc; 891 892 dev = (struct disk_devdesc *)f->f_devdata; 893 bd = bd_get_bdinfo(&dev->dd); 894 if (bd == NULL) 895 return (EIO); 896 897 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 898 rc = disk_ioctl(dev, cmd, data); 899 if (rc != ENOTTY) 900 return (rc); 901 } 902 903 switch (cmd) { 904 case DIOCGSECTORSIZE: 905 *(uint32_t *)data = bd->bd_sectorsize; 906 break; 907 case DIOCGMEDIASIZE: 908 *(uint64_t *)data = bd->bd_sectors * bd->bd_sectorsize; 909 break; 910 default: 911 return (ENOTTY); 912 } 913 return (0); 914} 915 916static int 917bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, 918 char *buf, size_t *rsize) 919{ 920 bdinfo_t *bd; 921 struct bcache_devdata bcd; 922 struct disk_devdesc *dev; 923 daddr_t offset; 924 925 dev = (struct disk_devdesc *)devdata; 926 bd = bd_get_bdinfo(&dev->dd); 927 if (bd == NULL) 928 return (EINVAL); 929 930 bcd.dv_strategy = bd_realstrategy; 931 bcd.dv_devdata = devdata; 932 bcd.dv_cache = bd->bd_bcache; 933 934 offset = 0; 935 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 936 937 offset = dev->d_offset * bd->bd_sectorsize; 938 offset /= BIOSDISK_SECSIZE; 939 } 940 return (bcache_strategy(&bcd, rw, dblk + offset, size, 941 buf, rsize)); 942} 943 944static int 945bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, 946 char *buf, size_t *rsize) 947{ 948 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 949 bdinfo_t *bd; 950 uint64_t disk_blocks, offset, d_offset; 951 size_t blks, blkoff, bsize, bio_size, rest; 952 caddr_t bbuf = NULL; 953 int rc; 954 955 bd = bd_get_bdinfo(&dev->dd); 956 if (bd == NULL || (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) 957 return (EIO); 958 959 /* 960 * First make sure the IO size is a multiple of 512 bytes. While we do 961 * process partial reads below, the strategy mechanism is built 962 * assuming IO is a multiple of 512B blocks. If the request is not 963 * a multiple of 512B blocks, it has to be some sort of bug. 964 */ 965 if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) { 966 printf("bd_strategy: %d bytes I/O not multiple of %d\n", 967 size, BIOSDISK_SECSIZE); 968 return (EIO); 969 } 970 971 DEBUG("open_disk %p", dev); 972 973 offset = dblk * BIOSDISK_SECSIZE; 974 dblk = offset / bd->bd_sectorsize; 975 blkoff = offset % bd->bd_sectorsize; 976 977 /* 978 * Check the value of the size argument. We do have quite small 979 * heap (64MB), but we do not know good upper limit, so we check against 980 * INT_MAX here. This will also protect us against possible overflows 981 * while translating block count to bytes. 982 */ 983 if (size > INT_MAX) { 984 DEBUG("too large I/O: %zu bytes", size); 985 return (EIO); 986 } 987 988 blks = size / bd->bd_sectorsize; 989 if (blks == 0 || (size % bd->bd_sectorsize) != 0) 990 blks++; 991 992 if (dblk > dblk + blks) 993 return (EIO); 994 995 if (rsize) 996 *rsize = 0; 997 998 /* 999 * Get disk blocks, this value is either for whole disk or for 1000 * partition. 1001 */ 1002 d_offset = 0; 1003 disk_blocks = 0; 1004 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1005 if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { 1006 /* DIOCGMEDIASIZE does return bytes. */ 1007 disk_blocks /= bd->bd_sectorsize; 1008 } 1009 d_offset = dev->d_offset; 1010 } 1011 if (disk_blocks == 0) 1012 disk_blocks = bd->bd_sectors - d_offset; 1013 1014 /* Validate source block address. */ 1015 if (dblk < d_offset || dblk >= d_offset + disk_blocks) 1016 return (EIO); 1017 1018 /* 1019 * Truncate if we are crossing disk or partition end. 1020 */ 1021 if (dblk + blks >= d_offset + disk_blocks) { 1022 blks = d_offset + disk_blocks - dblk; 1023 size = blks * bd->bd_sectorsize; 1024 DEBUG("short I/O %d", blks); 1025 } 1026 1027 bio_size = min(BIO_BUFFER_SIZE, size); 1028 while (bio_size > bd->bd_sectorsize) { 1029 bbuf = bio_alloc(bio_size); 1030 if (bbuf != NULL) 1031 break; 1032 bio_size -= bd->bd_sectorsize; 1033 } 1034 if (bbuf == NULL) { 1035 bio_size = V86_IO_BUFFER_SIZE; 1036 if (bio_size / bd->bd_sectorsize == 0) 1037 panic("BUG: Real mode buffer is too small"); 1038 1039 /* Use alternate 4k buffer */ 1040 bbuf = PTOV(V86_IO_BUFFER); 1041 } 1042 rest = size; 1043 rc = 0; 1044 while (blks > 0) { 1045 int x = min(blks, bio_size / bd->bd_sectorsize); 1046 1047 switch (rw & F_MASK) { 1048 case F_READ: 1049 DEBUG("read %d from %lld to %p", x, dblk, buf); 1050 bsize = bd->bd_sectorsize * x - blkoff; 1051 if (rest < bsize) 1052 bsize = rest; 1053 1054 if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD)) != 0) { 1055 rc = EIO; 1056 goto error; 1057 } 1058 1059 bcopy(bbuf + blkoff, buf, bsize); 1060 break; 1061 case F_WRITE : 1062 DEBUG("write %d from %lld to %p", x, dblk, buf); 1063 if (blkoff != 0) { 1064 /* 1065 * We got offset to sector, read 1 sector to 1066 * bbuf. 1067 */ 1068 x = 1; 1069 bsize = bd->bd_sectorsize - blkoff; 1070 bsize = min(bsize, rest); 1071 rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD); 1072 } else if (rest < bd->bd_sectorsize) { 1073 /* 1074 * The remaining block is not full 1075 * sector. Read 1 sector to bbuf. 1076 */ 1077 x = 1; 1078 bsize = rest; 1079 rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD); 1080 } else { 1081 /* We can write full sector(s). */ 1082 bsize = bd->bd_sectorsize * x; 1083 } 1084 /* 1085 * Put your Data In, Put your Data out, 1086 * Put your Data In, and shake it all about 1087 */ 1088 bcopy(buf, bbuf + blkoff, bsize); 1089 if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_WR)) != 0) { 1090 rc = EIO; 1091 goto error; 1092 } 1093 1094 break; 1095 default: 1096 /* DO NOTHING */ 1097 rc = EROFS; 1098 goto error; 1099 } 1100 1101 blkoff = 0; 1102 buf += bsize; 1103 rest -= bsize; 1104 blks -= x; 1105 dblk += x; 1106 } 1107 1108 if (rsize != NULL) 1109 *rsize = size; 1110error: 1111 if (bbuf != PTOV(V86_IO_BUFFER)) 1112 bio_free(bbuf, bio_size); 1113 return (rc); 1114} 1115 1116static int 1117bd_edd_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest, 1118 int dowrite) 1119{ 1120 static struct edd_packet packet; 1121 1122 packet.len = sizeof(struct edd_packet); 1123 packet.count = blks; 1124 packet.off = VTOPOFF(dest); 1125 packet.seg = VTOPSEG(dest); 1126 packet.lba = dblk; 1127 v86.ctl = V86_FLAGS; 1128 v86.addr = 0x13; 1129 /* Should we Write with verify ?? 0x4302 ? */ 1130 if (dowrite == BD_WR) 1131 v86.eax = 0x4300; 1132 else 1133 v86.eax = 0x4200; 1134 v86.edx = bd->bd_unit; 1135 v86.ds = VTOPSEG(&packet); 1136 v86.esi = VTOPOFF(&packet); 1137 v86int(); 1138 if (V86_CY(v86.efl)) 1139 return (v86.eax >> 8); 1140 return (0); 1141} 1142 1143static int 1144bd_chs_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest, 1145 int dowrite) 1146{ 1147 uint32_t x, bpc, cyl, hd, sec; 1148 1149 bpc = bd->bd_sec * bd->bd_hds; /* blocks per cylinder */ 1150 x = dblk; 1151 cyl = x / bpc; /* block # / blocks per cylinder */ 1152 x %= bpc; /* block offset into cylinder */ 1153 hd = x / bd->bd_sec; /* offset / blocks per track */ 1154 sec = x % bd->bd_sec; /* offset into track */ 1155 1156 /* correct sector number for 1-based BIOS numbering */ 1157 sec++; 1158 1159 if (cyl > 1023) { 1160 /* CHS doesn't support cylinders > 1023. */ 1161 return (1); 1162 } 1163 1164 v86.ctl = V86_FLAGS; 1165 v86.addr = 0x13; 1166 if (dowrite == BD_WR) 1167 v86.eax = 0x300 | blks; 1168 else 1169 v86.eax = 0x200 | blks; 1170 v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; 1171 v86.edx = (hd << 8) | bd->bd_unit; 1172 v86.es = VTOPSEG(dest); 1173 v86.ebx = VTOPOFF(dest); 1174 v86int(); 1175 if (V86_CY(v86.efl)) 1176 return (v86.eax >> 8); 1177 return (0); 1178} 1179 1180static void 1181bd_io_workaround(bdinfo_t *bd) 1182{ 1183 uint8_t buf[8 * 1024]; 1184 1185 bd_edd_io(bd, 0xffffffff, 1, (caddr_t)buf, BD_RD); 1186} 1187 1188static int 1189bd_io(struct disk_devdesc *dev, bdinfo_t *bd, daddr_t dblk, int blks, 1190 caddr_t dest, int dowrite) 1191{ 1192 int result, retry; 1193 1194 /* Just in case some idiot actually tries to read/write -1 blocks... */ 1195 if (blks < 0) 1196 return (-1); 1197 1198 /* 1199 * Workaround for a problem with some HP ProLiant BIOS failing to work 1200 * out the boot disk after installation. hrs and kuriyama discovered 1201 * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and 1202 * discovered that an int13h call seems to cause a buffer overrun in 1203 * the bios. The problem is alleviated by doing an extra read before 1204 * the buggy read. It is not immediately known whether other models 1205 * are similarly affected. 1206 * Loop retrying the operation a couple of times. The BIOS 1207 * may also retry. 1208 */ 1209 if (dowrite == BD_RD && dblk >= 0x100000000) 1210 bd_io_workaround(bd); 1211 for (retry = 0; retry < 3; retry++) { 1212 if (bd->bd_flags & BD_MODEEDD) 1213 result = bd_edd_io(bd, dblk, blks, dest, dowrite); 1214 else 1215 result = bd_chs_io(bd, dblk, blks, dest, dowrite); 1216 1217 if (result == 0) { 1218 if (bd->bd_flags & BD_NO_MEDIA) 1219 bd->bd_flags &= ~BD_NO_MEDIA; 1220 break; 1221 } 1222 1223 bd_reset_disk(bd->bd_unit); 1224 1225 /* 1226 * Error codes: 1227 * 20h controller failure 1228 * 31h no media in drive (IBM/MS INT 13 extensions) 1229 * 80h no media in drive, VMWare (Fusion) 1230 * There is no reason to repeat the IO with errors above. 1231 */ 1232 if (result == 0x20 || result == 0x31 || result == 0x80) { 1233 bd->bd_flags |= BD_NO_MEDIA; 1234 break; 1235 } 1236 } 1237 1238 if (result != 0 && (bd->bd_flags & BD_NO_MEDIA) == 0) { 1239 if (dowrite == BD_WR) { 1240 printf("%s%d: Write %d sector(s) from %p (0x%x) " 1241 "to %lld: 0x%x\n", dev->dd.d_dev->dv_name, 1242 dev->dd.d_unit, blks, dest, VTOP(dest), dblk, 1243 result); 1244 } else { 1245 printf("%s%d: Read %d sector(s) from %lld to %p " 1246 "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name, 1247 dev->dd.d_unit, blks, dblk, dest, VTOP(dest), 1248 result); 1249 } 1250 } 1251 1252 return (result); 1253} 1254 1255/* 1256 * Return the BIOS geometry of a given "fixed drive" in a format 1257 * suitable for the legacy bootinfo structure. Since the kernel is 1258 * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we 1259 * prefer to get the information directly, rather than rely on being 1260 * able to put it together from information already maintained for 1261 * different purposes and for a probably different number of drives. 1262 * 1263 * For valid drives, the geometry is expected in the format (31..0) 1264 * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are 1265 * indicated by returning the geometry of a "1.2M" PC-format floppy 1266 * disk. And, incidentally, what is returned is not the geometry as 1267 * such but the highest valid cylinder, head, and sector numbers. 1268 */ 1269uint32_t 1270bd_getbigeom(int bunit) 1271{ 1272 1273 v86.ctl = V86_FLAGS; 1274 v86.addr = 0x13; 1275 v86.eax = 0x800; 1276 v86.edx = 0x80 + bunit; 1277 v86int(); 1278 if (V86_CY(v86.efl)) 1279 return (0x4f010f); 1280 return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | 1281 (v86.edx & 0xff00) | (v86.ecx & 0x3f)); 1282} 1283 1284/* 1285 * Return a suitable dev_t value for (dev). 1286 * 1287 * In the case where it looks like (dev) is a SCSI disk, we allow the number of 1288 * IDE disks to be specified in $num_ide_disks. There should be a Better Way. 1289 */ 1290int 1291bd_getdev(struct i386_devdesc *d) 1292{ 1293 struct disk_devdesc *dev; 1294 bdinfo_t *bd; 1295 int biosdev; 1296 int major; 1297 int rootdev; 1298 char *nip, *cp; 1299 int i, unit, slice, partition; 1300 1301 /* XXX: Assume partition 'a'. */ 1302 slice = 0; 1303 partition = 0; 1304 1305 dev = (struct disk_devdesc *)d; 1306 bd = bd_get_bdinfo(&dev->dd); 1307 if (bd == NULL) 1308 return (-1); 1309 1310 biosdev = bd_unit2bios(d); 1311 DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev); 1312 if (biosdev == -1) /* not a BIOS device */ 1313 return (-1); 1314 1315 if (dev->dd.d_dev->dv_type == DEVT_DISK) { 1316 if (disk_open(dev, bd->bd_sectors * bd->bd_sectorsize, 1317 bd->bd_sectorsize) != 0) /* oops, not a viable device */ 1318 return (-1); 1319 else 1320 disk_close(dev); 1321 slice = dev->d_slice + 1; 1322 partition = dev->d_partition; 1323 } 1324 1325 if (biosdev < 0x80) { 1326 /* floppy (or emulated floppy) or ATAPI device */ 1327 if (bd->bd_type == DT_ATAPI) { 1328 /* is an ATAPI disk */ 1329 major = WFDMAJOR; 1330 } else { 1331 /* is a floppy disk */ 1332 major = FDMAJOR; 1333 } 1334 } else { 1335 /* assume an IDE disk */ 1336 major = WDMAJOR; 1337 } 1338 /* default root disk unit number */ 1339 unit = biosdev & 0x7f; 1340 1341 if (dev->dd.d_dev->dv_type == DEVT_CD) { 1342 /* 1343 * XXX: Need to examine device spec here to figure out if 1344 * SCSI or ATAPI. No idea on how to figure out device number. 1345 * All we can really pass to the kernel is what bus and device 1346 * on which bus we were booted from, which dev_t isn't well 1347 * suited to since those number don't match to unit numbers 1348 * very well. We may just need to engage in a hack where 1349 * we pass -C to the boot args if we are the boot device. 1350 */ 1351 major = ACDMAJOR; 1352 unit = 0; /* XXX */ 1353 } 1354 1355 /* XXX a better kludge to set the root disk unit number */ 1356 if ((nip = getenv("root_disk_unit")) != NULL) { 1357 i = strtol(nip, &cp, 0); 1358 /* check for parse error */ 1359 if ((cp != nip) && (*cp == 0)) 1360 unit = i; 1361 } 1362 1363 rootdev = MAKEBOOTDEV(major, slice, unit, partition); 1364 DEBUG("dev is 0x%x\n", rootdev); 1365 return (rootdev); 1366} 1367