Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
    loader: pxe receive cleanup
    9475 libefi: Do not return only if ReceiveFilter
    installboot: should support efi system partition
    8931 boot1.efi: scan all display modes rather than
    loader: spinconsole updates
    loader: gfx experiment to try GOP Blt() function.
    sha1 build test
    loader: add sha1 hash calculation
    common/sha1: update for loader build
    loader: biosdisk rework
    uts: 32-bit kernel FB needs mapping in low memory
    uts: add diag-device
    uts: boot console mirror with diag-device
    uts: enable very early console on ttya
    kmdb: add diag-device as input/output device
    uts: test VGA memory exclusion from mapping
    uts: clear boot mapping and protect boot pages test
    uts: add dboot map debug printf
    uts: need to release FB pages in release_bootstrap()
    uts: add screenmap ioctl
    uts: update sys/queue.h
    loader: add illumos uts/common to include path
    loader: tem/gfx font cleanup
    loader: vbe checks
    uts: gfx_private set KD_TEXT when KD_RESETTEXT is
    uts: gfx 8-bit update
    loader: gfx 8-bit fix
    loader: always set media size from partition.
    uts: MB2 support for 32-bit kernel
    loader: x86 should have tem 80x25
    uts: x86 should have tem 80x25
    uts: font update
    loader: font update
    uts: tem attributes
    loader: tem.c comment added
    uts: use font module
    loader: add font module
    loader: build rules for new font setup
    uts: gfx_private update for new font structure
    uts: early boot update for new font structure
    uts: font update
    uts: font build rules update for new fonts
    uts: tem update to new font structure
    loader: module.c needs to include tem_impl.h
    uts: gfx_private 8x16 font rework
    uts: make font_lookup public
    loader: font rework
    uts: font rework
    9259 libefi: efi_alloc_and_read should check for PMBR
    uts: tem utf-8 support
    loader: implement tem utf-8 support
    loader: tem should be able to display UTF-8
    7784 uts: console input should support utf-8
    7796 uts: ldterm default to utf-8
    uts: do not reset serial console
    uts: set up colors even if tem is not console
    uts: add type for early boot properties
    uts: gfx_private experiment with drm and vga
    uts: gfx_private should use setmode drm callback.
    uts: identify FB types and set up gfx_private based
    loader: replace gop and vesa with framebuffer
    uts: boot needs simple tem to support mdb
    uts: boot_keyboard should emit esc sequences for
    uts: gfx_private FB showuld be written by line
    kmdb: set terminal window size
    uts: gfx_private needs to keep track of early boot FB
    pnglite: move pnglite to usr/src/common
    loader: gfx_fb
    ficl-sys: add gfx primitives
    loader: add illumos.png logo
    ficl: add fb-putimage
    loader: add png support
    loader: add alpha blending for gfx_fb
    loader: use term-drawrect for menu frame
    ficl: add simple gfx words
    uts: provide fb_info via fbgattr dev_specific array.
    uts: gfx_private add alpha blending
    uts: update sys/ascii.h
    uts: tem OSC support (incomplete)
    uts: implement env module support and use data from
    uts: tem get colors from early boot data
    loader: use crc32 from libstand (libz)
    loader: optimize for size
    loader: pass tem info to the environment
    loader: import tem for loader console
    loader: UEFI loader needs to set ISADIR based on
    loader: need UEFI32 support
    8918 loader.efi: add vesa edid support
    uts: tem_safe_pix_clear_prom_output() should only
    uts: tem_safe_pix_clear_entire_screen() should use
    uts: tem_safe_check_first_time() should query cursor
    uts: tem implement cls callback & visual_io v4
    uts: gfx_vgatext use block cursor for vgatext
    uts: gfx_private implement cls callback & visual_io
    uts: gfx_private bitmap framebuffer implementation
    uts: early start frame buffer console support
    uts: font functions should check the input char
    uts: font rendering should support 16/24/32bit depths
    uts: use smallest font as fallback default.
    uts: update terminal dimensions based on selected
    7834 uts: vgatext should use gfx_private
    uts: add spacing property to 8859-1.bdf
    terminfo: add underline for sun-color
    terminfo: sun-color has 16 colors
    uts: add font load callback type
    loader: do not repeat int13 calls with error 0x20 and
    8905 loader: add skein/edonr support
    8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
    loader: pxe receive cleanup
    9475 libefi: Do not return only if ReceiveFilter
    installboot: should support efi system partition
    8931 boot1.efi: scan all display modes rather than
    loader: spinconsole updates
    loader: gfx experiment to try GOP Blt() function.
    sha1 build test
    loader: add sha1 hash calculation
    common/sha1: update for loader build
    loader: biosdisk rework
    uts: 32-bit kernel FB needs mapping in low memory
    uts: add diag-device
    uts: boot console mirror with diag-device
    uts: enable very early console on ttya
    kmdb: add diag-device as input/output device
    uts: test VGA memory exclusion from mapping
    uts: clear boot mapping and protect boot pages test
    uts: add dboot map debug printf
    uts: need to release FB pages in release_bootstrap()
    uts: add screenmap ioctl
    uts: update sys/queue.h
    loader: add illumos uts/common to include path
    loader: tem/gfx font cleanup
    loader: vbe checks
    uts: gfx_private set KD_TEXT when KD_RESETTEXT is
    uts: gfx 8-bit update
    loader: gfx 8-bit fix
    loader: always set media size from partition.
    uts: MB2 support for 32-bit kernel
    loader: x86 should have tem 80x25
    uts: x86 should have tem 80x25
    uts: font update
    loader: font update
    uts: tem attributes
    loader: tem.c comment added
    uts: use font module
    loader: add font module
    loader: build rules for new font setup
    uts: gfx_private update for new font structure
    uts: early boot update for new font structure
    uts: font update
    uts: font build rules update for new fonts
    uts: tem update to new font structure
    loader: module.c needs to include tem_impl.h
    uts: gfx_private 8x16 font rework
    uts: make font_lookup public
    loader: font rework
    uts: font rework
    libefi: efi_alloc_and_read should check for PMBR
    uts: tem utf-8 support
    loader: implement tem utf-8 support
    loader: tem should be able to display UTF-8
    7784 uts: console input should support utf-8
    7796 uts: ldterm default to utf-8
    uts: do not reset serial console
    uts: set up colors even if tem is not console
    uts: add type for early boot properties
    uts: gfx_private experiment with drm and vga
    uts: gfx_private should use setmode drm callback.
    uts: identify FB types and set up gfx_private based
    loader: replace gop and vesa with framebuffer
    uts: boot needs simple tem to support mdb
    uts: boot_keyboard should emit esc sequences for
    uts: gfx_private FB showuld be written by line
    kmdb: set terminal window size
    uts: gfx_private needs to keep track of early boot FB
    pnglite: move pnglite to usr/src/common
    loader: gfx_fb
    ficl-sys: add gfx primitives
    loader: add illumos.png logo
    ficl: add fb-putimage
    loader: add png support
    loader: add alpha blending for gfx_fb
    loader: use term-drawrect for menu frame
    ficl: add simple gfx words
    uts: provide fb_info via fbgattr dev_specific array.
    uts: gfx_private add alpha blending
    uts: update sys/ascii.h
    uts: tem OSC support (incomplete)
    uts: implement env module support and use data from
    uts: tem get colors from early boot data
    loader: use crc32 from libstand (libz)
    loader: optimize for size
    loader: pass tem info to the environment
    loader: import tem for loader console
    loader: UEFI loader needs to set ISADIR based on
    loader: need UEFI32 support
    8918 loader.efi: add vesa edid support
    uts: tem_safe_pix_clear_prom_output() should only
    uts: tem_safe_pix_clear_entire_screen() should use
    uts: tem_safe_check_first_time() should query cursor
    uts: tem implement cls callback & visual_io v4
    uts: gfx_vgatext use block cursor for vgatext
    uts: gfx_private implement cls callback & visual_io
    uts: gfx_private bitmap framebuffer implementation
    uts: early start frame buffer console support
    uts: font functions should check the input char
    uts: font rendering should support 16/24/32bit depths
    uts: use smallest font as fallback default.
    uts: update terminal dimensions based on selected
    7834 uts: vgatext should use gfx_private
    uts: add spacing property to 8859-1.bdf
    terminfo: add underline for sun-color
    terminfo: sun-color has 16 colors
    uts: add font load callback type
    loader: do not repeat int13 calls with error 0x20 and
    8905 loader: add skein/edonr support
    8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>


  39 
  40 #include <sys/disk.h>
  41 #include <sys/limits.h>
  42 #include <stand.h>
  43 #include <machine/bootinfo.h>
  44 #include <stdarg.h>
  45 
  46 #include <bootstrap.h>
  47 #include <btxv86.h>
  48 #include <edd.h>
  49 #include "disk.h"
  50 #include "libi386.h"
  51 
  52 CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
  53 
  54 #define BIOS_NUMDRIVES          0x475
  55 #define BIOSDISK_SECSIZE        512
  56 #define BUFSIZE                 (1 * BIOSDISK_SECSIZE)
  57 
  58 #define DT_ATAPI                0x10            /* disk type for ATAPI floppies */
  59 #define WDMAJOR                 0               /* major numbers for devices we frontend for */


  60 #define WFDMAJOR                1
  61 #define FDMAJOR                 2
  62 #define DAMAJOR                 4
  63 
  64 #ifdef DISK_DEBUG
  65 # define DEBUG(fmt, args...)    printf("%s: " fmt "\n" , __func__ , ## args)
  66 #else
  67 # define DEBUG(fmt, args...)
  68 #endif
  69 
  70 /*
  71  * List of BIOS devices, translation from disk unit number to
  72  * BIOS unit number.
  73  */
  74 static struct bdinfo
  75 {
  76         int             bd_unit;        /* BIOS unit number */
  77         int             bd_cyl;         /* BIOS geometry */
  78         int             bd_hds;
  79         int             bd_sec;
  80         int             bd_flags;
  81 #define BD_MODEINT13    0x0000
  82 #define BD_MODEEDD1     0x0001
  83 #define BD_MODEEDD3     0x0002

  84 #define BD_MODEMASK     0x0003
  85 #define BD_FLOPPY       0x0004

  86         int             bd_type;        /* BIOS 'drive type' (floppy only) */
  87         uint16_t        bd_sectorsize;  /* Sector size */
  88         uint64_t        bd_sectors;     /* Disk size */
  89         int             bd_open;        /* reference counter */
  90         void            *bd_bcache;     /* buffer cache data */
  91 } bdinfo [MAXBDDEV];
  92 static int nbdinfo = 0;
  93 
  94 #define BD(dev)         (bdinfo[(dev)->d_unit])
  95 
  96 static int bd_io(struct disk_devdesc *, daddr_t, int, caddr_t, int);
  97 static int bd_int13probe(struct bdinfo *bd);
  98 
  99 static int bd_init(void);
 100 static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
 101     char *buf, size_t *rsize);
 102 static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
 103     char *buf, size_t *rsize);
 104 static int bd_open(struct open_file *f, ...);
 105 static int bd_close(struct open_file *f);
 106 static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
 107 static int bd_print(int verbose);
 108 


























 109 struct devsw biosdisk = {
 110         "disk",
 111         DEVT_DISK,
 112         bd_init,
 113         bd_strategy,
 114         bd_open,
 115         bd_close,
 116         bd_ioctl,
 117         bd_print,
 118         NULL
 119 };
 120 
 121 /*
 122  * Translate between BIOS device numbers and our private unit numbers.
 123  */
 124 int
 125 bd_bios2unit(int biosdev)
 126 {
 127         int i;
 128 
 129         DEBUG("looking for bios device 0x%x", biosdev);
 130         for (i = 0; i < nbdinfo; i++) {
 131                 DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
 132                 if (bdinfo[i].bd_unit == biosdev)
 133                         return (i);
 134         }
 135         return (-1);
 136 }
 137 
 138 int


 169                         bdinfo[nbdinfo].bd_unit = unit;
 170                         bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0;
 171                         if (!bd_int13probe(&bdinfo[nbdinfo]))
 172                                 break;
 173 
 174 #ifndef BOOT2
 175                         /* XXX we need "disk aliases" to make this simpler */
 176                         printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ?
 177                             ('A' + unit): ('C' + unit - 0x80), nbdinfo);
 178 #endif
 179                         nbdinfo++;
 180                         if (base == 0x80)
 181                                 nfd++;
 182                 }
 183         }
 184         bcache_add_dev(nbdinfo);
 185         return(0);
 186 }
 187 
 188 /*
 189  * Try to detect a device supported by the legacy int13 BIOS
 190  */
 191 static int
 192 bd_int13probe(struct bdinfo *bd)
 193 {
 194         struct edd_params params;
 195         int ret = 1;    /* assume success */





 196 















 197         v86.ctl = V86_FLAGS;
 198         v86.addr = 0x13;














 199         v86.eax = 0x800;
 200         v86.edx = bd->bd_unit;
 201         v86int();
 202 
 203         /* Don't error out if we get bad sector number, try EDD as well */
 204         if (V86_CY(v86.efl) ||  /* carry set */
 205             (v86.edx & 0xff) <= (unsigned)(bd->bd_unit & 0x7f))   /* unit # bad */
 206                 return (0);     /* skip device */
 207 
 208         if ((v86.ecx & 0x3f) == 0)  /* absurd sector number */
 209                 ret = 0;        /* set error */

 210 
 211         /* Convert max cyl # -> # of cylinders */
 212         bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
 213         /* Convert max head # -> # of heads */
 214         bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
 215         bd->bd_sec = v86.ecx & 0x3f;
 216         bd->bd_type = v86.ebx & 0xff;
 217         bd->bd_flags |= BD_MODEINT13;
 218 
 219         /* Calculate sectors count from the geometry */
 220         bd->bd_sectors = bd->bd_cyl * bd->bd_hds * bd->bd_sec;
 221         bd->bd_sectorsize = BIOSDISK_SECSIZE;
 222         DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
 223             bd->bd_hds, bd->bd_sec);
 224 
 225         /* Determine if we can use EDD with this device. */
 226         v86.ctl = V86_FLAGS;
 227         v86.addr = 0x13;
 228         v86.eax = 0x4100;
 229         v86.edx = bd->bd_unit;
 230         v86.ebx = 0x55aa;
 231         v86int();
 232         if (V86_CY(v86.efl) ||  /* carry set */
 233             (v86.ebx & 0xffff) != 0xaa55 || /* signature */
 234             (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
 235                 return (ret);   /* return code from int13 AH=08 */
 236 
 237         /* EDD supported */
 238         bd->bd_flags |= BD_MODEEDD1;
 239         if ((v86.eax & 0xff00) >= 0x3000)
 240                 bd->bd_flags |= BD_MODEEDD3;
 241         /* Get disk params */
 242         params.len = sizeof(struct edd_params);

 243         v86.ctl = V86_FLAGS;
 244         v86.addr = 0x13;
 245         v86.eax = 0x4800;
 246         v86.edx = bd->bd_unit;
 247         v86.ds = VTOPSEG(&params);
 248         v86.esi = VTOPOFF(&params);
 249         v86int();
 250         if (!V86_CY(v86.efl)) {
 251                 uint64_t total;
 252 



 253                 /*
 254                  * Sector size must be a multiple of 512 bytes.
 255                  * An alternate test would be to check power of 2,
 256                  * powerof2(params.sector_size).
 257                  */
 258                 if (params.sector_size % BIOSDISK_SECSIZE)
 259                         bd->bd_sectorsize = BIOSDISK_SECSIZE;
 260                 else
 261                         bd->bd_sectorsize = params.sector_size;
 262 
 263                 total = bd->bd_sectorsize * params.sectors;
 264                 if (params.sectors != 0) {
 265                         /* Only update if we did not overflow. */
 266                         if (total > params.sectors)
 267                                 bd->bd_sectors = params.sectors;
 268                 }
 269 



 270                 total = (uint64_t)params.cylinders *
 271                     params.heads * params.sectors_per_track;
 272                 if (bd->bd_sectors < total)
 273                         bd->bd_sectors = total;
 274 
 275                 ret = 1;











































 276         }
 277         DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u",
 278             bd->bd_unit, bd->bd_flags, bd->bd_sectors, bd->bd_sectorsize);
 279         return (ret);








 280 }
 281 
 282 /*
 283  * Print information about disks
 284  */
 285 static int
 286 bd_print(int verbose)
 287 {
 288         static char line[80];
 289         struct disk_devdesc dev;
 290         int i, ret = 0;
 291 
 292         if (nbdinfo == 0)
 293                 return (0);
 294 
 295         printf("%s devices:", biosdisk.dv_name);
 296         if ((ret = pager_output("\n")) != 0)
 297                 return (ret);
 298 
 299         for (i = 0; i < nbdinfo; i++) {
 300                 snprintf(line, sizeof (line),
 301                     "    disk%d:   BIOS drive %c (%ju X %u):\n", i,
 302                     (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
 303                     ('C' + bdinfo[i].bd_unit - 0x80),


 304                     (uintmax_t)bdinfo[i].bd_sectors,
 305                     bdinfo[i].bd_sectorsize);
 306                 ret = pager_output(line);
 307                 if (ret != 0)
 308                         return (ret);
 309 
 310                 dev.d_dev = &biosdisk;
 311                 dev.d_unit = i;
 312                 dev.d_slice = -1;
 313                 dev.d_partition = -1;
 314                 if (disk_open(&dev,
 315                     bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors,
 316                     bdinfo[i].bd_sectorsize) == 0) {
 317                         sprintf(line, "    disk%d", i);
 318                         ret = disk_print(&dev, line, verbose);
 319                         disk_close(&dev);
 320                         if (ret != 0)
 321                                 return (ret);
 322                 }
 323         }


 332  * about what the user might want leads to complications.
 333  * (eg. given no slice or partition value, with a disk that is
 334  *  sliced - are they after the first BSD slice, or the DOS
 335  *  slice before it?)
 336  */
 337 static int
 338 bd_open(struct open_file *f, ...)
 339 {
 340         struct disk_devdesc *dev;
 341         struct disk_devdesc disk;
 342         va_list ap;
 343         uint64_t size;
 344         int rc;
 345 
 346         va_start(ap, f);
 347         dev = va_arg(ap, struct disk_devdesc *);
 348         va_end(ap);
 349 
 350         if (dev->d_unit < 0 || dev->d_unit >= nbdinfo)
 351                 return (EIO);





 352         BD(dev).bd_open++;
 353         if (BD(dev).bd_bcache == NULL)
 354             BD(dev).bd_bcache = bcache_allocate();
 355 
 356         /*
 357          * Read disk size from partition.
 358          * This is needed to work around buggy BIOS systems returning
 359          * wrong (truncated) disk media size.
 360          * During bd_probe() we tested if the mulitplication of bd_sectors
 361          * would overflow so it should be safe to perform here.
 362          */
 363         disk.d_dev = dev->d_dev;
 364         disk.d_type = dev->d_type;
 365         disk.d_unit = dev->d_unit;
 366         disk.d_opendata = NULL;
 367         disk.d_slice = -1;
 368         disk.d_partition = -1;
 369         disk.d_offset = 0;
 370 
 371         if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize,


 651     if (V86_CY(v86.efl))
 652         return (v86.eax >> 8);
 653     return (0);
 654 }
 655 
 656 static int
 657 bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
 658     int dowrite)
 659 {
 660         u_int result, retry;
 661 
 662         /* Just in case some idiot actually tries to read/write -1 blocks... */
 663         if (blks < 0)
 664                 return (-1);
 665 
 666         /*
 667          * Loop retrying the operation a couple of times.  The BIOS
 668          * may also retry.
 669          */
 670         for (retry = 0; retry < 3; retry++) {
 671                 /* if retrying, reset the drive */
 672                 if (retry > 0) {
 673                         v86.ctl = V86_FLAGS;
 674                         v86.addr = 0x13;
 675                         v86.eax = 0;
 676                         v86.edx = BD(dev).bd_unit;
 677                         v86int();
 678                 }
 679 
 680                 if (BD(dev).bd_flags & BD_MODEEDD1)
 681                         result = bd_edd_io(dev, dblk, blks, dest, dowrite);
 682                 else
 683                         result = bd_chs_io(dev, dblk, blks, dest, dowrite);
 684 
 685                 if (result == 0)


 686                         break;
 687         }
 688 


 689         /*
 690          * 0x20 - Controller failure. This is common error when the
 691          * media is not present.


 692          */
 693         if (result != 0 && result != 0x20) {






 694                 if (dowrite != 0) {
 695                         printf("%s%d: Write %d sector(s) from %p (0x%x) "
 696                             "to %lld: 0x%x", dev->d_dev->dv_name, dev->d_unit,
 697                             blks, dest, VTOP(dest), dblk, result);
 698                 } else {
 699                         printf("%s%d: Read %d sector(s) from %lld to %p "
 700                             "(0x%x): 0x%x", dev->d_dev->dv_name, dev->d_unit,
 701                             blks, dblk, dest, VTOP(dest), result);
 702         }
 703 
 704         if (result != 0)
 705             return (result);
 706     }
 707 
 708     return(0);
 709 }
 710 
 711 /*
 712  * Return the BIOS geometry of a given "fixed drive" in a format
 713  * suitable for the legacy bootinfo structure.  Since the kernel is
 714  * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
 715  * prefer to get the information directly, rather than rely on being
 716  * able to put it together from information already maintained for
 717  * different purposes and for a probably different number of drives.
 718  *
 719  * For valid drives, the geometry is expected in the format (31..0)
 720  * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
 721  * indicated by returning the geometry of a "1.2M" PC-format floppy
 722  * disk.  And, incidentally, what is returned is not the geometry as
 723  * such but the highest valid cylinder, head, and sector numbers.
 724  */
 725 u_int32_t
 726 bd_getbigeom(int bunit)
 727 {
 728 




  39 
  40 #include <sys/disk.h>
  41 #include <sys/limits.h>
  42 #include <stand.h>
  43 #include <machine/bootinfo.h>
  44 #include <stdarg.h>
  45 
  46 #include <bootstrap.h>
  47 #include <btxv86.h>
  48 #include <edd.h>
  49 #include "disk.h"
  50 #include "libi386.h"
  51 
  52 CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
  53 
  54 #define BIOS_NUMDRIVES          0x475
  55 #define BIOSDISK_SECSIZE        512
  56 #define BUFSIZE                 (1 * BIOSDISK_SECSIZE)
  57 
  58 #define DT_ATAPI                0x10    /* disk type for ATAPI floppies */
  59 
  60 /* major numbers for devices we frontend for */
  61 #define WDMAJOR                 0
  62 #define WFDMAJOR                1
  63 #define FDMAJOR                 2
  64 #define DAMAJOR                 4
  65 
  66 #ifdef DISK_DEBUG
  67 # define DEBUG(fmt, args...)    printf("%s: " fmt "\n" , __func__ , ## args)
  68 #else
  69 # define DEBUG(fmt, args...)
  70 #endif
  71 
  72 /*
  73  * List of BIOS devices, translation from disk unit number to
  74  * BIOS unit number.
  75  */
  76 static struct bdinfo
  77 {
  78         int             bd_unit;        /* BIOS unit number */
  79         int             bd_cyl;         /* BIOS geometry */
  80         int             bd_hds;
  81         int             bd_sec;
  82         int             bd_flags;
  83 #define BD_MODEINT13    0x0000
  84 #define BD_MODEEDD1     0x0001
  85 #define BD_MODEEDD3     0x0002
  86 #define BD_MODEEDD      (BD_MODEEDD1 | BD_MODEEDD3)
  87 #define BD_MODEMASK     0x0003
  88 #define BD_FLOPPY       0x0004
  89 #define BD_NO_MEDIA     0x0008
  90         int             bd_type;        /* BIOS 'drive type' (floppy only) */
  91         uint16_t        bd_sectorsize;  /* Sector size */
  92         uint64_t        bd_sectors;     /* Disk size */
  93         int             bd_open;        /* reference counter */
  94         void            *bd_bcache;     /* buffer cache data */
  95 } bdinfo [MAXBDDEV];
  96 static int nbdinfo = 0;
  97 
  98 #define BD(dev)         (bdinfo[(dev)->d_unit])
  99 
 100 static int bd_io(struct disk_devdesc *, daddr_t, int, caddr_t, int);
 101 static int bd_int13probe(struct bdinfo *bd);
 102 
 103 static int bd_init(void);
 104 static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
 105     char *buf, size_t *rsize);
 106 static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size,
 107     char *buf, size_t *rsize);
 108 static int bd_open(struct open_file *f, ...);
 109 static int bd_close(struct open_file *f);
 110 static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
 111 static int bd_print(int verbose);
 112 
 113 struct devsw biosfd = {
 114         .dv_name = "fd",
 115         .dv_type = DEVT_FD,
 116         .dv_init = bd_init,
 117         .dv_strategy = bd_strategy,
 118         .dv_open = bd_open,
 119         .dv_close = bd_close,
 120         .dv_ioctl = bd_ioctl,
 121         .dv_print = bd_print,
 122         .dv_cleanup = NULL
 123 };
 124 
 125 #if 0
 126 struct devsw bioscd = {
 127         .dv_name = "cd",
 128         .dv_type = DEVT_CD,
 129         .dv_init = bd_init,
 130         .dv_strategy = bd_strategy,
 131         .dv_open = bd_open,
 132         .dv_close = bd_close,
 133         .dv_ioctl = bd_ioctl,
 134         .dv_print = bd_print,
 135         .dv_cleanup = NULL
 136 };
 137 #endif
 138 
 139 struct devsw biosdisk = {
 140         .dv_name = "disk",
 141         .dv_type = DEVT_DISK,
 142         .dv_init = bd_init,
 143         .dv_strategy = bd_strategy,
 144         .dv_open = bd_open,
 145         .dv_close = bd_close,
 146         .dv_ioctl = bd_ioctl,
 147         .dv_print = bd_print,
 148         .dv_cleanup = NULL
 149 };
 150 
 151 /*
 152  * Translate between BIOS device numbers and our private unit numbers.
 153  */
 154 int
 155 bd_bios2unit(int biosdev)
 156 {
 157         int i;
 158 
 159         DEBUG("looking for bios device 0x%x", biosdev);
 160         for (i = 0; i < nbdinfo; i++) {
 161                 DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit);
 162                 if (bdinfo[i].bd_unit == biosdev)
 163                         return (i);
 164         }
 165         return (-1);
 166 }
 167 
 168 int


 199                         bdinfo[nbdinfo].bd_unit = unit;
 200                         bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0;
 201                         if (!bd_int13probe(&bdinfo[nbdinfo]))
 202                                 break;
 203 
 204 #ifndef BOOT2
 205                         /* XXX we need "disk aliases" to make this simpler */
 206                         printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ?
 207                             ('A' + unit): ('C' + unit - 0x80), nbdinfo);
 208 #endif
 209                         nbdinfo++;
 210                         if (base == 0x80)
 211                                 nfd++;
 212                 }
 213         }
 214         bcache_add_dev(nbdinfo);
 215         return(0);
 216 }
 217 
 218 /*
 219  * Return EDD version or 0 if EDD is not supported on this drive.
 220  */
 221 static int
 222 bd_check_extensions(int unit)
 223 {
 224         /* Determine if we can use EDD with this device. */
 225         v86.ctl = V86_FLAGS;
 226         v86.addr = 0x13;
 227         v86.eax = 0x4100;
 228         v86.edx = unit;
 229         v86.ebx = 0x55aa;
 230         v86int();
 231 
 232         if (V86_CY(v86.efl) ||                  /* carry set */
 233             (v86.ebx & 0xffff) != 0xaa55)   /* signature */
 234                 return (0);
 235 
 236         /* extended disk access functions (AH=42h-44h,47h,48h) supported */
 237         if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
 238                 return (0);
 239 
 240         return ((v86.eax >> 8) & 0xff);
 241 }
 242 
 243 static void
 244 bd_reset_disk(int unit)
 245 {
 246         /* reset disk */
 247         v86.ctl = V86_FLAGS;
 248         v86.addr = 0x13;
 249         v86.eax = 0;
 250         v86.edx = unit;
 251         v86int();
 252 }
 253 
 254 /*
 255  * Read CHS info. Return 0 on success, error otherwise.
 256  */
 257 static int
 258 bd_get_diskinfo_std(struct bdinfo *bd)
 259 {
 260         bzero(&v86, sizeof (v86));
 261         v86.ctl = V86_FLAGS;
 262         v86.addr = 0x13;
 263         v86.eax = 0x800;
 264         v86.edx = bd->bd_unit;
 265         v86int();
 266 
 267         if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
 268                 return ((v86.eax & 0xff00) >> 8);


 269 
 270         /* return custom error on absurd sector number */
 271         if ((v86.ecx & 0x3f) == 0)
 272                 return (0x60);
 273 

 274         bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
 275         /* Convert max head # -> # of heads */
 276         bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1;
 277         bd->bd_sec = v86.ecx & 0x3f;
 278         bd->bd_type = v86.ebx;
 279         bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec;
 280 
 281         return (0);
 282 }



 283 
 284 /*
 285  * Read EDD info. Return 0 on success, error otherwise.
 286  */
 287 static int
 288 bd_get_diskinfo_ext(struct bdinfo *bd)
 289 {
 290         struct edd_params params;
 291         uint64_t total;



 292 




 293         /* Get disk params */
 294         bzero(&params, sizeof (params));
 295         params.len = sizeof (params);
 296         v86.ctl = V86_FLAGS;
 297         v86.addr = 0x13;
 298         v86.eax = 0x4800;
 299         v86.edx = bd->bd_unit;
 300         v86.ds = VTOPSEG(&params);
 301         v86.esi = VTOPOFF(&params);
 302         v86int();


 303 
 304         if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0))
 305                 return ((v86.eax & 0xff00) >> 8);
 306 
 307         /*
 308          * Sector size must be a multiple of 512 bytes.
 309          * An alternate test would be to check power of 2,
 310          * powerof2(params.sector_size).
 311          */
 312         if (params.sector_size % BIOSDISK_SECSIZE)
 313                 bd->bd_sectorsize = BIOSDISK_SECSIZE;
 314         else
 315                 bd->bd_sectorsize = params.sector_size;
 316 
 317         bd->bd_cyl = params.cylinders;
 318         bd->bd_hds = params.heads;
 319         bd->bd_sec = params.sectors_per_track;



 320 
 321         if (params.sectors != 0) {
 322                 total = params.sectors;
 323         } else {
 324                 total = (uint64_t)params.cylinders *
 325                     params.heads * params.sectors_per_track;
 326         }
 327         bd->bd_sectors = total;
 328 
 329         return (0);
 330 }
 331 
 332 /*
 333  * Try to detect a device supported by the legacy int13 BIOS
 334  */
 335 static int
 336 bd_int13probe(struct bdinfo *bd)
 337 {
 338         int edd;
 339         int ret;
 340 
 341         bd->bd_flags &= ~BD_NO_MEDIA;
 342 
 343         edd = bd_check_extensions(bd->bd_unit);
 344         if (edd == 0)
 345                 bd->bd_flags |= BD_MODEINT13;
 346         else if (edd < 0x30)
 347                 bd->bd_flags |= BD_MODEEDD1;
 348         else
 349                 bd->bd_flags |= BD_MODEEDD3;
 350 
 351         /* Default sector size */
 352         bd->bd_sectorsize = BIOSDISK_SECSIZE;
 353 
 354         if (bd->bd_unit < 0x80) {
 355                 /* reset disk */
 356                 bd_reset_disk(bd->bd_unit);
 357 
 358                 /* Get disk type */
 359                 v86.ctl = V86_FLAGS;
 360                 v86.addr = 0x13;
 361                 v86.eax = 0x1500;
 362                 v86.edx = bd->bd_unit;
 363                 v86int();
 364                 if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0)
 365                         return (0);
 366 
 367                 /* Set defaults for 1.44 floppy */
 368                 bd->bd_cyl = 80;
 369                 bd->bd_hds = 2;
 370                 bd->bd_sec = 18;
 371                 bd->bd_type = 4;
 372                 bd->bd_sectors = 2880;
 373         }
 374 
 375         ret = 1;
 376         if (edd != 0)
 377                 ret = bd_get_diskinfo_ext(bd);
 378         if (ret != 0)
 379                 ret = bd_get_diskinfo_std(bd);
 380 
 381         DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl,
 382             bd->bd_hds, bd->bd_sec);
 383 
 384         return (1);
 385 }
 386 
 387 /*
 388  * Print information about disks
 389  */
 390 static int
 391 bd_print(int verbose)
 392 {
 393         static char line[80];
 394         struct disk_devdesc dev;
 395         int i, ret = 0;
 396 
 397         if (nbdinfo == 0)
 398                 return (0);
 399 
 400         printf("%s devices:", biosdisk.dv_name);
 401         if ((ret = pager_output("\n")) != 0)
 402                 return (ret);
 403 
 404         for (i = 0; i < nbdinfo; i++) {
 405                 snprintf(line, sizeof (line),
 406                     "    disk%d:   BIOS drive %c (%s%ju X %u):\n", i,
 407                     (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit):
 408                     ('C' + bdinfo[i].bd_unit - 0x80),
 409                     (bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ?
 410                     "no media, " : "",
 411                     (uintmax_t)bdinfo[i].bd_sectors,
 412                     bdinfo[i].bd_sectorsize);
 413                 ret = pager_output(line);
 414                 if (ret != 0)
 415                         return (ret);
 416 
 417                 dev.d_dev = &biosdisk;
 418                 dev.d_unit = i;
 419                 dev.d_slice = -1;
 420                 dev.d_partition = -1;
 421                 if (disk_open(&dev,
 422                     bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors,
 423                     bdinfo[i].bd_sectorsize) == 0) {
 424                         sprintf(line, "    disk%d", i);
 425                         ret = disk_print(&dev, line, verbose);
 426                         disk_close(&dev);
 427                         if (ret != 0)
 428                                 return (ret);
 429                 }
 430         }


 439  * about what the user might want leads to complications.
 440  * (eg. given no slice or partition value, with a disk that is
 441  *  sliced - are they after the first BSD slice, or the DOS
 442  *  slice before it?)
 443  */
 444 static int
 445 bd_open(struct open_file *f, ...)
 446 {
 447         struct disk_devdesc *dev;
 448         struct disk_devdesc disk;
 449         va_list ap;
 450         uint64_t size;
 451         int rc;
 452 
 453         va_start(ap, f);
 454         dev = va_arg(ap, struct disk_devdesc *);
 455         va_end(ap);
 456 
 457         if (dev->d_unit < 0 || dev->d_unit >= nbdinfo)
 458                 return (EIO);
 459 
 460         if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) {
 461                 if (!bd_int13probe(&BD(dev)))
 462                         return (EIO);
 463         }
 464         BD(dev).bd_open++;
 465         if (BD(dev).bd_bcache == NULL)
 466             BD(dev).bd_bcache = bcache_allocate();
 467 
 468         /*
 469          * Read disk size from partition.
 470          * This is needed to work around buggy BIOS systems returning
 471          * wrong (truncated) disk media size.
 472          * During bd_probe() we tested if the mulitplication of bd_sectors
 473          * would overflow so it should be safe to perform here.
 474          */
 475         disk.d_dev = dev->d_dev;
 476         disk.d_type = dev->d_type;
 477         disk.d_unit = dev->d_unit;
 478         disk.d_opendata = NULL;
 479         disk.d_slice = -1;
 480         disk.d_partition = -1;
 481         disk.d_offset = 0;
 482 
 483         if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize,


 763     if (V86_CY(v86.efl))
 764         return (v86.eax >> 8);
 765     return (0);
 766 }
 767 
 768 static int
 769 bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest,
 770     int dowrite)
 771 {
 772         u_int result, retry;
 773 
 774         /* Just in case some idiot actually tries to read/write -1 blocks... */
 775         if (blks < 0)
 776                 return (-1);
 777 
 778         /*
 779          * Loop retrying the operation a couple of times.  The BIOS
 780          * may also retry.
 781          */
 782         for (retry = 0; retry < 3; retry++) {
 783                 if (BD(dev).bd_flags & BD_MODEEDD)









 784                         result = bd_edd_io(dev, dblk, blks, dest, dowrite);
 785                 else
 786                         result = bd_chs_io(dev, dblk, blks, dest, dowrite);
 787 
 788                 if (result == 0) {
 789                         if (BD(dev).bd_flags & BD_NO_MEDIA)
 790                                 BD(dev).bd_flags &= ~BD_NO_MEDIA;
 791                         break;
 792                 }
 793 
 794                 bd_reset_disk(BD(dev).bd_unit);
 795 
 796                 /*
 797                  * Error codes:
 798                  * 20h  controller failure
 799                  * 31h  no media in drive (IBM/MS INT 13 extensions)
 800                  * There is no reason to repeat the IO with errors above.
 801                  */
 802                 if (result == 0x20 || result == 0x31 || result == 0x80) {
 803                         BD(dev).bd_flags |= BD_NO_MEDIA;
 804                         break;
 805                 }
 806         }
 807 
 808         if (result != 0 && (BD(dev).bd_flags & BD_NO_MEDIA) == 0) {
 809                 if (dowrite != 0) {
 810                         printf("%s%d: Write %d sector(s) from %p (0x%x) "
 811                             "to %lld: 0x%x\n", dev->d_dev->dv_name, dev->d_unit,
 812                             blks, dest, VTOP(dest), dblk, result);
 813                 } else {
 814                         printf("%s%d: Read %d sector(s) from %lld to %p "
 815                             "(0x%x): 0x%x\n", dev->d_dev->dv_name, dev->d_unit,
 816                             blks, dblk, dest, VTOP(dest), result);
 817                 }



 818         }
 819 
 820         return (result);
 821 }
 822 
 823 /*
 824  * Return the BIOS geometry of a given "fixed drive" in a format
 825  * suitable for the legacy bootinfo structure.  Since the kernel is
 826  * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we
 827  * prefer to get the information directly, rather than rely on being
 828  * able to put it together from information already maintained for
 829  * different purposes and for a probably different number of drives.
 830  *
 831  * For valid drives, the geometry is expected in the format (31..0)
 832  * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are
 833  * indicated by returning the geometry of a "1.2M" PC-format floppy
 834  * disk.  And, incidentally, what is returned is not the geometry as
 835  * such but the highest valid cylinder, head, and sector numbers.
 836  */
 837 u_int32_t
 838 bd_getbigeom(int bunit)
 839 {
 840