Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 1 | /* |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 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> |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 29 | |
| 30 | /* |
| 31 | * BIOS disk device handling. |
Toomas Soome | 560b248 | 2017-02-05 18:44:23 +0200 | [diff] [blame] | 32 | * |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 33 | * Ideas and algorithms from: |
| 34 | * |
| 35 | * - NetBSD libi386/biosdisk.c |
| 36 | * - FreeBSD biosboot/disk.c |
| 37 | * |
| 38 | */ |
| 39 | |
| 40 | #include <sys/disk.h> |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 41 | #include <sys/limits.h> |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 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 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 52 | #define BIOS_NUMDRIVES 0x475 |
| 53 | #define BIOSDISK_SECSIZE 512 |
| 54 | #define BUFSIZE (1 * BIOSDISK_SECSIZE) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 55 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 56 | #define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ |
| 57 | #define WDMAJOR 0 /* major numbers for devices we frontend for */ |
| 58 | #define WFDMAJOR 1 |
| 59 | #define FDMAJOR 2 |
| 60 | #define DAMAJOR 4 |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 61 | |
| 62 | #ifdef DISK_DEBUG |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 63 | #define DEBUG(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 64 | #else |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 65 | #define DEBUG(fmt, args...) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 66 | #endif |
| 67 | |
| 68 | /* |
| 69 | * List of BIOS devices, translation from disk unit number to |
| 70 | * BIOS unit number. |
| 71 | */ |
| 72 | static struct bdinfo |
| 73 | { |
| 74 | int bd_unit; /* BIOS unit number */ |
| 75 | int bd_cyl; /* BIOS geometry */ |
| 76 | int bd_hds; |
| 77 | int bd_sec; |
| 78 | int bd_flags; |
| 79 | #define BD_MODEINT13 0x0000 |
| 80 | #define BD_MODEEDD1 0x0001 |
| 81 | #define BD_MODEEDD3 0x0002 |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 82 | #define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 83 | #define BD_MODEMASK 0x0003 |
| 84 | #define BD_FLOPPY 0x0004 |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 85 | #define BD_NO_MEDIA 0x0008 |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 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 | |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 94 | #define BD(dev) (bdinfo[(dev)->dd.d_unit]) |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 95 | #define BD_RD 0 |
| 96 | #define BD_WR 1 |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 97 | |
Toomas Soome | f8e0ecf | 2018-08-16 14:26:58 +0300 | [diff] [blame] | 98 | static void bd_io_workaround(struct disk_devdesc *dev); |
| 99 | |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 100 | static int bd_io(struct disk_devdesc *, daddr_t, int, caddr_t, int); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 101 | static int bd_int13probe(struct bdinfo *bd); |
| 102 | |
| 103 | static int bd_init(void); |
Toomas Soome | 38dea91 | 2016-11-26 00:42:58 +0200 | [diff] [blame] | 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); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 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); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 112 | |
| 113 | struct devsw biosdisk = { |
| 114 | "disk", |
| 115 | DEVT_DISK, |
| 116 | bd_init, |
| 117 | bd_strategy, |
| 118 | bd_open, |
| 119 | bd_close, |
| 120 | bd_ioctl, |
| 121 | bd_print, |
Toomas Soome | 74207d1 | 2017-02-22 20:40:10 +0200 | [diff] [blame] | 122 | NULL |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 123 | }; |
| 124 | |
| 125 | /* |
| 126 | * Translate between BIOS device numbers and our private unit numbers. |
| 127 | */ |
| 128 | int |
| 129 | bd_bios2unit(int biosdev) |
| 130 | { |
| 131 | int i; |
| 132 | |
| 133 | DEBUG("looking for bios device 0x%x", biosdev); |
| 134 | for (i = 0; i < nbdinfo; i++) { |
| 135 | DEBUG("bd unit %d is BIOS device 0x%x", i, bdinfo[i].bd_unit); |
| 136 | if (bdinfo[i].bd_unit == biosdev) |
| 137 | return (i); |
| 138 | } |
| 139 | return (-1); |
| 140 | } |
| 141 | |
| 142 | int |
| 143 | bd_unit2bios(int unit) |
| 144 | { |
| 145 | |
| 146 | if ((unit >= 0) && (unit < nbdinfo)) |
| 147 | return (bdinfo[unit].bd_unit); |
| 148 | return (-1); |
| 149 | } |
| 150 | |
| 151 | /* |
| 152 | * Quiz the BIOS for disk devices, save a little info about them. |
| 153 | */ |
| 154 | static int |
| 155 | bd_init(void) |
| 156 | { |
| 157 | int base, unit, nfd = 0; |
| 158 | |
| 159 | /* sequence 0, 0x80 */ |
| 160 | for (base = 0; base <= 0x80; base += 0x80) { |
| 161 | for (unit = base; (nbdinfo < MAXBDDEV); unit++) { |
| 162 | #ifndef VIRTUALBOX |
| 163 | /* |
| 164 | * Check the BIOS equipment list for number |
| 165 | * of fixed disks. |
| 166 | */ |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 167 | if (base == 0x80 && |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 168 | (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) |
| 169 | break; |
| 170 | #endif |
| 171 | bdinfo[nbdinfo].bd_open = 0; |
| 172 | bdinfo[nbdinfo].bd_bcache = NULL; |
| 173 | bdinfo[nbdinfo].bd_unit = unit; |
| 174 | bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0; |
| 175 | if (!bd_int13probe(&bdinfo[nbdinfo])) |
| 176 | break; |
| 177 | |
| 178 | #ifndef BOOT2 |
| 179 | /* XXX we need "disk aliases" to make this simpler */ |
| 180 | printf("BIOS drive %c: is disk%d\n", (unit < 0x80) ? |
| 181 | ('A' + unit): ('C' + unit - 0x80), nbdinfo); |
| 182 | #endif |
| 183 | nbdinfo++; |
| 184 | if (base == 0x80) |
| 185 | nfd++; |
| 186 | } |
| 187 | } |
| 188 | bcache_add_dev(nbdinfo); |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 189 | return (0); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 190 | } |
| 191 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 192 | /* |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 193 | * Return EDD version or 0 if EDD is not supported on this drive. |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 194 | */ |
| 195 | static int |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 196 | bd_check_extensions(int unit) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 197 | { |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 198 | /* Determine if we can use EDD with this device. */ |
| 199 | v86.ctl = V86_FLAGS; |
| 200 | v86.addr = 0x13; |
| 201 | v86.eax = 0x4100; |
| 202 | v86.edx = unit; |
| 203 | v86.ebx = 0x55aa; |
| 204 | v86int(); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 205 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 206 | if (V86_CY(v86.efl) || /* carry set */ |
| 207 | (v86.ebx & 0xffff) != 0xaa55) /* signature */ |
| 208 | return (0); |
| 209 | |
| 210 | /* extended disk access functions (AH=42h-44h,47h,48h) supported */ |
| 211 | if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) |
| 212 | return (0); |
| 213 | |
| 214 | return ((v86.eax >> 8) & 0xff); |
| 215 | } |
| 216 | |
| 217 | static void |
| 218 | bd_reset_disk(int unit) |
| 219 | { |
| 220 | /* reset disk */ |
| 221 | v86.ctl = V86_FLAGS; |
| 222 | v86.addr = 0x13; |
| 223 | v86.eax = 0; |
| 224 | v86.edx = unit; |
| 225 | v86int(); |
| 226 | } |
| 227 | |
| 228 | /* |
| 229 | * Read CHS info. Return 0 on success, error otherwise. |
| 230 | */ |
| 231 | static int |
| 232 | bd_get_diskinfo_std(struct bdinfo *bd) |
| 233 | { |
| 234 | bzero(&v86, sizeof (v86)); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 235 | v86.ctl = V86_FLAGS; |
| 236 | v86.addr = 0x13; |
| 237 | v86.eax = 0x800; |
| 238 | v86.edx = bd->bd_unit; |
| 239 | v86int(); |
| 240 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 241 | if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) |
| 242 | return ((v86.eax & 0xff00) >> 8); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 243 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 244 | /* return custom error on absurd sector number */ |
| 245 | if ((v86.ecx & 0x3f) == 0) |
| 246 | return (0x60); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 247 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 248 | bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; |
| 249 | /* Convert max head # -> # of heads */ |
| 250 | bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; |
| 251 | bd->bd_sec = v86.ecx & 0x3f; |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 252 | bd->bd_type = v86.ebx; |
| 253 | bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 254 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 255 | return (0); |
| 256 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 257 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 258 | /* |
| 259 | * Read EDD info. Return 0 on success, error otherwise. |
| 260 | */ |
| 261 | static int |
| 262 | bd_get_diskinfo_ext(struct bdinfo *bd) |
| 263 | { |
| 264 | struct edd_params params; |
| 265 | uint64_t total; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 266 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 267 | /* Get disk params */ |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 268 | bzero(¶ms, sizeof (params)); |
| 269 | params.len = sizeof (params); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 270 | v86.ctl = V86_FLAGS; |
| 271 | v86.addr = 0x13; |
| 272 | v86.eax = 0x4800; |
| 273 | v86.edx = bd->bd_unit; |
| 274 | v86.ds = VTOPSEG(¶ms); |
| 275 | v86.esi = VTOPOFF(¶ms); |
| 276 | v86int(); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 277 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 278 | if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) |
| 279 | return ((v86.eax & 0xff00) >> 8); |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 280 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 281 | /* |
| 282 | * Sector size must be a multiple of 512 bytes. |
| 283 | * An alternate test would be to check power of 2, |
| 284 | * powerof2(params.sector_size). |
| 285 | * 4K is largest read buffer we can use at this time. |
| 286 | */ |
| 287 | if (params.sector_size >= 512 && |
| 288 | params.sector_size <= 4096 && |
| 289 | (params.sector_size % BIOSDISK_SECSIZE) == 0) |
| 290 | bd->bd_sectorsize = params.sector_size; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 291 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 292 | bd->bd_cyl = params.cylinders; |
| 293 | bd->bd_hds = params.heads; |
| 294 | bd->bd_sec = params.sectors_per_track; |
| 295 | |
| 296 | if (params.sectors != 0) { |
| 297 | total = params.sectors; |
| 298 | } else { |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 299 | total = (uint64_t)params.cylinders * |
| 300 | params.heads * params.sectors_per_track; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 301 | } |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 302 | bd->bd_sectors = total; |
| 303 | |
| 304 | return (0); |
| 305 | } |
| 306 | |
| 307 | /* |
| 308 | * Try to detect a device supported by the legacy int13 BIOS |
| 309 | */ |
| 310 | static int |
| 311 | bd_int13probe(struct bdinfo *bd) |
| 312 | { |
| 313 | int edd; |
| 314 | int ret; |
| 315 | |
| 316 | bd->bd_flags &= ~BD_NO_MEDIA; |
| 317 | |
| 318 | edd = bd_check_extensions(bd->bd_unit); |
| 319 | if (edd == 0) |
| 320 | bd->bd_flags |= BD_MODEINT13; |
| 321 | else if (edd < 0x30) |
| 322 | bd->bd_flags |= BD_MODEEDD1; |
| 323 | else |
| 324 | bd->bd_flags |= BD_MODEEDD3; |
| 325 | |
| 326 | /* Default sector size */ |
| 327 | bd->bd_sectorsize = BIOSDISK_SECSIZE; |
| 328 | |
| 329 | /* |
| 330 | * Test if the floppy device is present, so we can avoid receiving |
| 331 | * bogus information from bd_get_diskinfo_std(). |
| 332 | */ |
| 333 | if (bd->bd_unit < 0x80) { |
| 334 | /* reset disk */ |
| 335 | bd_reset_disk(bd->bd_unit); |
| 336 | |
| 337 | /* Get disk type */ |
| 338 | v86.ctl = V86_FLAGS; |
| 339 | v86.addr = 0x13; |
| 340 | v86.eax = 0x1500; |
| 341 | v86.edx = bd->bd_unit; |
| 342 | v86int(); |
| 343 | if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0) |
| 344 | return (0); |
| 345 | } |
| 346 | |
| 347 | ret = 1; |
| 348 | if (edd != 0) |
| 349 | ret = bd_get_diskinfo_ext(bd); |
| 350 | if (ret != 0 || bd->bd_sectors == 0) |
| 351 | ret = bd_get_diskinfo_std(bd); |
| 352 | |
| 353 | if (ret != 0 && bd->bd_unit < 0x80) { |
| 354 | /* Set defaults for 1.44 floppy */ |
| 355 | bd->bd_cyl = 80; |
| 356 | bd->bd_hds = 2; |
| 357 | bd->bd_sec = 18; |
| 358 | bd->bd_type = 4; |
| 359 | bd->bd_sectors = 2880; |
| 360 | /* Since we are there, there most likely is no media */ |
| 361 | bd->bd_flags |= BD_NO_MEDIA; |
| 362 | ret = 0; |
| 363 | } |
| 364 | |
| 365 | if (ret != 0) { |
| 366 | if (bd->bd_sectors != 0 && edd != 0) { |
| 367 | bd->bd_sec = 63; |
| 368 | bd->bd_hds = 255; |
| 369 | bd->bd_cyl = |
| 370 | (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) / |
| 371 | bd->bd_sec * bd->bd_hds; |
| 372 | } else { |
| 373 | printf("Can not get information about %s unit %#x\n", |
| 374 | biosdisk.dv_name, bd->bd_unit); |
| 375 | return (0); |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | if (bd->bd_sec == 0) |
| 380 | bd->bd_sec = 63; |
| 381 | if (bd->bd_hds == 0) |
| 382 | bd->bd_hds = 255; |
| 383 | |
| 384 | if (bd->bd_sectors == 0) |
| 385 | bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; |
| 386 | |
| 387 | DEBUG("unit 0x%x geometry %d/%d/%d", bd->bd_unit, bd->bd_cyl, |
| 388 | bd->bd_hds, bd->bd_sec); |
| 389 | |
| 390 | return (1); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | /* |
| 394 | * Print information about disks |
| 395 | */ |
| 396 | static int |
| 397 | bd_print(int verbose) |
| 398 | { |
| 399 | static char line[80]; |
| 400 | struct disk_devdesc dev; |
| 401 | int i, ret = 0; |
| 402 | |
Toomas Soome | 502b33a | 2016-11-18 15:26:15 +0200 | [diff] [blame] | 403 | if (nbdinfo == 0) |
| 404 | return (0); |
| 405 | |
| 406 | printf("%s devices:", biosdisk.dv_name); |
| 407 | if ((ret = pager_output("\n")) != 0) |
| 408 | return (ret); |
| 409 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 410 | for (i = 0; i < nbdinfo; i++) { |
Dan McDonald | 9c02c7e | 2016-11-18 14:34:54 -0500 | [diff] [blame] | 411 | snprintf(line, sizeof (line), |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 412 | " disk%d: BIOS drive %c (%s%ju X %u):\n", i, |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 413 | (bdinfo[i].bd_unit < 0x80) ? ('A' + bdinfo[i].bd_unit): |
Dan McDonald | 9c02c7e | 2016-11-18 14:34:54 -0500 | [diff] [blame] | 414 | ('C' + bdinfo[i].bd_unit - 0x80), |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 415 | (bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ? |
| 416 | "no media, " : "", |
Dan McDonald | 9c02c7e | 2016-11-18 14:34:54 -0500 | [diff] [blame] | 417 | (uintmax_t)bdinfo[i].bd_sectors, |
| 418 | bdinfo[i].bd_sectorsize); |
Toomas Soome | e8fda35 | 2018-08-16 14:21:13 +0300 | [diff] [blame] | 419 | if ((ret = pager_output(line)) != 0) |
| 420 | break; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 421 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 422 | if ((bdinfo[i].bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) |
| 423 | continue; |
| 424 | |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 425 | dev.dd.d_dev = &biosdisk; |
| 426 | dev.dd.d_unit = i; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 427 | dev.d_slice = -1; |
| 428 | dev.d_partition = -1; |
| 429 | if (disk_open(&dev, |
| 430 | bdinfo[i].bd_sectorsize * bdinfo[i].bd_sectors, |
Toomas Soome | 74207d1 | 2017-02-22 20:40:10 +0200 | [diff] [blame] | 431 | bdinfo[i].bd_sectorsize) == 0) { |
Toomas Soome | e8fda35 | 2018-08-16 14:21:13 +0300 | [diff] [blame] | 432 | snprintf(line, sizeof (line), " disk%d", i); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 433 | ret = disk_print(&dev, line, verbose); |
| 434 | disk_close(&dev); |
| 435 | if (ret != 0) |
Toomas Soome | e8fda35 | 2018-08-16 14:21:13 +0300 | [diff] [blame] | 436 | break; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 437 | } |
| 438 | } |
| 439 | return (ret); |
| 440 | } |
| 441 | |
| 442 | /* |
| 443 | * Attempt to open the disk described by (dev) for use by (f). |
| 444 | * |
| 445 | * Note that the philosophy here is "give them exactly what |
| 446 | * they ask for". This is necessary because being too "smart" |
| 447 | * about what the user might want leads to complications. |
| 448 | * (eg. given no slice or partition value, with a disk that is |
| 449 | * sliced - are they after the first BSD slice, or the DOS |
| 450 | * slice before it?) |
| 451 | */ |
| 452 | static int |
| 453 | bd_open(struct open_file *f, ...) |
| 454 | { |
| 455 | struct disk_devdesc *dev; |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 456 | struct disk_devdesc disk; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 457 | va_list ap; |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 458 | uint64_t size; |
Toomas Soome | bde4412 | 2017-02-18 16:10:20 +0200 | [diff] [blame] | 459 | int rc; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 460 | |
| 461 | va_start(ap, f); |
| 462 | dev = va_arg(ap, struct disk_devdesc *); |
| 463 | va_end(ap); |
| 464 | |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 465 | if (dev->dd.d_unit < 0 || dev->dd.d_unit >= nbdinfo) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 466 | return (EIO); |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 467 | |
| 468 | if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) { |
| 469 | if (!bd_int13probe(&BD(dev))) |
| 470 | return (EIO); |
| 471 | if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) |
| 472 | return (EIO); |
| 473 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 474 | BD(dev).bd_open++; |
| 475 | if (BD(dev).bd_bcache == NULL) |
| 476 | BD(dev).bd_bcache = bcache_allocate(); |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 477 | |
| 478 | /* |
| 479 | * Read disk size from partition. |
| 480 | * This is needed to work around buggy BIOS systems returning |
| 481 | * wrong (truncated) disk media size. |
| 482 | * During bd_probe() we tested if the mulitplication of bd_sectors |
| 483 | * would overflow so it should be safe to perform here. |
| 484 | */ |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 485 | disk.dd.d_dev = dev->dd.d_dev; |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 486 | disk.dd.d_unit = dev->dd.d_unit; |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 487 | disk.d_slice = -1; |
| 488 | disk.d_partition = -1; |
| 489 | disk.d_offset = 0; |
| 490 | |
| 491 | if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize, |
Toomas Soome | 74207d1 | 2017-02-22 20:40:10 +0200 | [diff] [blame] | 492 | BD(dev).bd_sectorsize) == 0) { |
Toomas Soome | cff899e | 2016-11-20 14:51:31 +0200 | [diff] [blame] | 493 | |
| 494 | if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) { |
| 495 | size /= BD(dev).bd_sectorsize; |
| 496 | if (size > BD(dev).bd_sectors) |
| 497 | BD(dev).bd_sectors = size; |
| 498 | } |
| 499 | disk_close(&disk); |
| 500 | } |
| 501 | |
Toomas Soome | bde4412 | 2017-02-18 16:10:20 +0200 | [diff] [blame] | 502 | rc = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, |
| 503 | BD(dev).bd_sectorsize); |
| 504 | if (rc != 0) { |
| 505 | BD(dev).bd_open--; |
| 506 | if (BD(dev).bd_open == 0) { |
| 507 | bcache_free(BD(dev).bd_bcache); |
| 508 | BD(dev).bd_bcache = NULL; |
| 509 | } |
| 510 | } |
| 511 | return (rc); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 512 | } |
| 513 | |
| 514 | static int |
| 515 | bd_close(struct open_file *f) |
| 516 | { |
| 517 | struct disk_devdesc *dev; |
| 518 | |
| 519 | dev = (struct disk_devdesc *)f->f_devdata; |
| 520 | BD(dev).bd_open--; |
| 521 | if (BD(dev).bd_open == 0) { |
| 522 | bcache_free(BD(dev).bd_bcache); |
| 523 | BD(dev).bd_bcache = NULL; |
| 524 | } |
| 525 | return (disk_close(dev)); |
| 526 | } |
| 527 | |
| 528 | static int |
| 529 | bd_ioctl(struct open_file *f, u_long cmd, void *data) |
| 530 | { |
| 531 | struct disk_devdesc *dev; |
Toomas Soome | edb3504 | 2016-11-07 15:37:12 +0200 | [diff] [blame] | 532 | int rc; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 533 | |
| 534 | dev = (struct disk_devdesc *)f->f_devdata; |
Toomas Soome | edb3504 | 2016-11-07 15:37:12 +0200 | [diff] [blame] | 535 | |
| 536 | rc = disk_ioctl(dev, cmd, data); |
| 537 | if (rc != ENOTTY) |
| 538 | return (rc); |
| 539 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 540 | switch (cmd) { |
| 541 | case DIOCGSECTORSIZE: |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 542 | *(uint32_t *)data = BD(dev).bd_sectorsize; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 543 | break; |
| 544 | case DIOCGMEDIASIZE: |
Toomas Soome | 79bea51 | 2016-12-04 13:15:56 +0200 | [diff] [blame] | 545 | *(uint64_t *)data = BD(dev).bd_sectors * BD(dev).bd_sectorsize; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 546 | break; |
| 547 | default: |
| 548 | return (ENOTTY); |
| 549 | } |
| 550 | return (0); |
| 551 | } |
| 552 | |
| 553 | static int |
Toomas Soome | 38dea91 | 2016-11-26 00:42:58 +0200 | [diff] [blame] | 554 | bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 555 | char *buf, size_t *rsize) |
| 556 | { |
| 557 | struct bcache_devdata bcd; |
| 558 | struct disk_devdesc *dev; |
| 559 | |
| 560 | dev = (struct disk_devdesc *)devdata; |
| 561 | bcd.dv_strategy = bd_realstrategy; |
| 562 | bcd.dv_devdata = devdata; |
| 563 | bcd.dv_cache = BD(dev).bd_bcache; |
Toomas Soome | 38dea91 | 2016-11-26 00:42:58 +0200 | [diff] [blame] | 564 | return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, size, |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 565 | buf, rsize)); |
| 566 | } |
| 567 | |
| 568 | static int |
Toomas Soome | 38dea91 | 2016-11-26 00:42:58 +0200 | [diff] [blame] | 569 | bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 570 | char *buf, size_t *rsize) |
| 571 | { |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 572 | struct disk_devdesc *dev = (struct disk_devdesc *)devdata; |
| 573 | uint64_t disk_blocks, offset; |
| 574 | size_t blks, blkoff, bsize, rest; |
| 575 | caddr_t bbuf; |
| 576 | int rc; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 577 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 578 | if ((BD(dev).bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) |
| 579 | return (EIO); |
| 580 | |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 581 | /* |
Toomas Soome | 78916de | 2017-06-13 20:35:48 +0300 | [diff] [blame] | 582 | * First make sure the IO size is a multiple of 512 bytes. While we do |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 583 | * process partial reads below, the strategy mechanism is built |
Toomas Soome | 78916de | 2017-06-13 20:35:48 +0300 | [diff] [blame] | 584 | * assuming IO is a multiple of 512B blocks. If the request is not |
| 585 | * a multiple of 512B blocks, it has to be some sort of bug. |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 586 | */ |
| 587 | if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) { |
| 588 | printf("bd_strategy: %d bytes I/O not multiple of %d\n", |
| 589 | size, BIOSDISK_SECSIZE); |
| 590 | return (EIO); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 591 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 592 | |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 593 | DEBUG("open_disk %p", dev); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 594 | |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 595 | offset = dblk * BIOSDISK_SECSIZE; |
| 596 | dblk = offset / BD(dev).bd_sectorsize; |
| 597 | blkoff = offset % BD(dev).bd_sectorsize; |
| 598 | |
| 599 | /* |
| 600 | * Check the value of the size argument. We do have quite small |
| 601 | * heap (64MB), but we do not know good upper limit, so we check against |
| 602 | * INT_MAX here. This will also protect us against possible overflows |
| 603 | * while translating block count to bytes. |
| 604 | */ |
| 605 | if (size > INT_MAX) { |
Toomas Soome | 43f9d55 | 2018-08-16 14:23:38 +0300 | [diff] [blame] | 606 | DEBUG("too large I/O: %zu bytes", size); |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 607 | return (EIO); |
| 608 | } |
| 609 | |
| 610 | blks = size / BD(dev).bd_sectorsize; |
| 611 | if (blks == 0 || (size % BD(dev).bd_sectorsize) != 0) |
| 612 | blks++; |
| 613 | |
| 614 | if (dblk > dblk + blks) |
| 615 | return (EIO); |
| 616 | |
| 617 | if (rsize) |
| 618 | *rsize = 0; |
| 619 | |
| 620 | /* |
| 621 | * Get disk blocks, this value is either for whole disk or for |
| 622 | * partition. |
| 623 | */ |
| 624 | if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { |
| 625 | /* DIOCGMEDIASIZE does return bytes. */ |
| 626 | disk_blocks /= BD(dev).bd_sectorsize; |
| 627 | } else { |
| 628 | /* We should not get here. Just try to survive. */ |
| 629 | disk_blocks = BD(dev).bd_sectors - dev->d_offset; |
| 630 | } |
| 631 | |
| 632 | /* Validate source block address. */ |
| 633 | if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks) |
| 634 | return (EIO); |
| 635 | |
| 636 | /* |
| 637 | * Truncate if we are crossing disk or partition end. |
| 638 | */ |
| 639 | if (dblk + blks >= dev->d_offset + disk_blocks) { |
| 640 | blks = dev->d_offset + disk_blocks - dblk; |
| 641 | size = blks * BD(dev).bd_sectorsize; |
Toomas Soome | 43f9d55 | 2018-08-16 14:23:38 +0300 | [diff] [blame] | 642 | DEBUG("short I/O %d", blks); |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 643 | } |
| 644 | |
| 645 | if (V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize == 0) |
| 646 | panic("BUG: Real mode buffer is too small\n"); |
| 647 | |
| 648 | bbuf = PTOV(V86_IO_BUFFER); |
| 649 | rest = size; |
| 650 | |
| 651 | while (blks > 0) { |
| 652 | int x = min(blks, V86_IO_BUFFER_SIZE / BD(dev).bd_sectorsize); |
| 653 | |
| 654 | switch (rw & F_MASK) { |
| 655 | case F_READ: |
| 656 | DEBUG("read %d from %lld to %p", x, dblk, buf); |
| 657 | bsize = BD(dev).bd_sectorsize * x - blkoff; |
| 658 | if (rest < bsize) |
| 659 | bsize = rest; |
| 660 | |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 661 | if ((rc = bd_io(dev, dblk, x, bbuf, BD_RD)) != 0) |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 662 | return (EIO); |
| 663 | |
| 664 | bcopy(bbuf + blkoff, buf, bsize); |
| 665 | break; |
| 666 | case F_WRITE : |
| 667 | DEBUG("write %d from %lld to %p", x, dblk, buf); |
| 668 | if (blkoff != 0) { |
| 669 | /* |
| 670 | * We got offset to sector, read 1 sector to |
| 671 | * bbuf. |
| 672 | */ |
| 673 | x = 1; |
| 674 | bsize = BD(dev).bd_sectorsize - blkoff; |
| 675 | bsize = min(bsize, rest); |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 676 | rc = bd_io(dev, dblk, x, bbuf, BD_RD); |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 677 | } else if (rest < BD(dev).bd_sectorsize) { |
| 678 | /* |
| 679 | * The remaining block is not full |
| 680 | * sector. Read 1 sector to bbuf. |
| 681 | */ |
| 682 | x = 1; |
| 683 | bsize = rest; |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 684 | rc = bd_io(dev, dblk, x, bbuf, BD_RD); |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 685 | } else { |
| 686 | /* We can write full sector(s). */ |
| 687 | bsize = BD(dev).bd_sectorsize * x; |
| 688 | } |
| 689 | /* |
| 690 | * Put your Data In, Put your Data out, |
| 691 | * Put your Data In, and shake it all about |
| 692 | */ |
| 693 | bcopy(buf, bbuf + blkoff, bsize); |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 694 | if ((rc = bd_io(dev, dblk, x, bbuf, BD_WR)) != 0) |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 695 | return (EIO); |
| 696 | |
| 697 | break; |
| 698 | default: |
| 699 | /* DO NOTHING */ |
| 700 | return (EROFS); |
| 701 | } |
| 702 | |
| 703 | blkoff = 0; |
| 704 | buf += bsize; |
| 705 | rest -= bsize; |
| 706 | blks -= x; |
| 707 | dblk += x; |
| 708 | } |
| 709 | |
| 710 | if (rsize != NULL) |
| 711 | *rsize = size; |
| 712 | return (0); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 713 | } |
| 714 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 715 | static int |
| 716 | bd_edd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, |
| 717 | int dowrite) |
| 718 | { |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 719 | static struct edd_packet packet; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 720 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 721 | packet.len = sizeof (struct edd_packet); |
| 722 | packet.count = blks; |
| 723 | packet.off = VTOPOFF(dest); |
| 724 | packet.seg = VTOPSEG(dest); |
| 725 | packet.lba = dblk; |
| 726 | v86.ctl = V86_FLAGS; |
| 727 | v86.addr = 0x13; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 728 | /* Should we Write with verify ?? 0x4302 ? */ |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 729 | if (dowrite == BD_WR) |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 730 | v86.eax = 0x4300; |
| 731 | else |
| 732 | v86.eax = 0x4200; |
| 733 | v86.edx = BD(dev).bd_unit; |
| 734 | v86.ds = VTOPSEG(&packet); |
| 735 | v86.esi = VTOPOFF(&packet); |
| 736 | v86int(); |
| 737 | if (V86_CY(v86.efl)) |
| 738 | return (v86.eax >> 8); |
| 739 | return (0); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 740 | } |
| 741 | |
| 742 | static int |
| 743 | bd_chs_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, |
| 744 | int dowrite) |
| 745 | { |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 746 | uint32_t x, bpc, cyl, hd, sec; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 747 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 748 | bpc = BD(dev).bd_sec * BD(dev).bd_hds; /* blocks per cylinder */ |
| 749 | x = dblk; |
| 750 | cyl = x / bpc; /* block # / blocks per cylinder */ |
| 751 | x %= bpc; /* block offset into cylinder */ |
| 752 | hd = x / BD(dev).bd_sec; /* offset / blocks per track */ |
| 753 | sec = x % BD(dev).bd_sec; /* offset into track */ |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 754 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 755 | /* correct sector number for 1-based BIOS numbering */ |
| 756 | sec++; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 757 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 758 | if (cyl > 1023) { |
| 759 | /* CHS doesn't support cylinders > 1023. */ |
| 760 | return (1); |
| 761 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 762 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 763 | v86.ctl = V86_FLAGS; |
| 764 | v86.addr = 0x13; |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 765 | if (dowrite == BD_WR) |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 766 | v86.eax = 0x300 | blks; |
| 767 | else |
| 768 | v86.eax = 0x200 | blks; |
| 769 | v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; |
| 770 | v86.edx = (hd << 8) | BD(dev).bd_unit; |
| 771 | v86.es = VTOPSEG(dest); |
| 772 | v86.ebx = VTOPOFF(dest); |
| 773 | v86int(); |
| 774 | if (V86_CY(v86.efl)) |
| 775 | return (v86.eax >> 8); |
| 776 | return (0); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 777 | } |
| 778 | |
Toomas Soome | f8e0ecf | 2018-08-16 14:26:58 +0300 | [diff] [blame] | 779 | static void |
| 780 | bd_io_workaround(struct disk_devdesc *dev) |
| 781 | { |
| 782 | uint8_t buf[8 * 1024]; |
| 783 | |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 784 | bd_edd_io(dev, 0xffffffff, 1, (caddr_t)buf, BD_RD); |
Toomas Soome | f8e0ecf | 2018-08-16 14:26:58 +0300 | [diff] [blame] | 785 | } |
| 786 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 787 | static int |
Toomas Soome | 560b248 | 2017-02-05 18:44:23 +0200 | [diff] [blame] | 788 | bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, |
| 789 | int dowrite) |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 790 | { |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 791 | int result, retry; |
Toomas Soome | 560b248 | 2017-02-05 18:44:23 +0200 | [diff] [blame] | 792 | |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 793 | /* Just in case some idiot actually tries to read/write -1 blocks... */ |
| 794 | if (blks < 0) |
| 795 | return (-1); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 796 | |
| 797 | /* |
Toomas Soome | f8e0ecf | 2018-08-16 14:26:58 +0300 | [diff] [blame] | 798 | * Workaround for a problem with some HP ProLiant BIOS failing to work |
| 799 | * out the boot disk after installation. hrs and kuriyama discovered |
| 800 | * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and |
| 801 | * discovered that an int13h call seems to cause a buffer overrun in |
| 802 | * the bios. The problem is alleviated by doing an extra read before |
| 803 | * the buggy read. It is not immediately known whether other models |
| 804 | * are similarly affected. |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 805 | * Loop retrying the operation a couple of times. The BIOS |
| 806 | * may also retry. |
| 807 | */ |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 808 | if (dowrite == BD_RD && dblk >= 0x100000000) |
Toomas Soome | f8e0ecf | 2018-08-16 14:26:58 +0300 | [diff] [blame] | 809 | bd_io_workaround(dev); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 810 | for (retry = 0; retry < 3; retry++) { |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 811 | if (BD(dev).bd_flags & BD_MODEEDD) |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 812 | result = bd_edd_io(dev, dblk, blks, dest, dowrite); |
| 813 | else |
| 814 | result = bd_chs_io(dev, dblk, blks, dest, dowrite); |
| 815 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 816 | if (result == 0) { |
| 817 | if (BD(dev).bd_flags & BD_NO_MEDIA) |
| 818 | BD(dev).bd_flags &= ~BD_NO_MEDIA; |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 819 | break; |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 820 | } |
| 821 | |
| 822 | bd_reset_disk(BD(dev).bd_unit); |
| 823 | |
| 824 | /* |
| 825 | * Error codes: |
| 826 | * 20h controller failure |
| 827 | * 31h no media in drive (IBM/MS INT 13 extensions) |
| 828 | * 80h no media in drive, VMWare (Fusion) |
| 829 | * There is no reason to repeat the IO with errors above. |
| 830 | */ |
| 831 | if (result == 0x20 || result == 0x31 || result == 0x80) { |
| 832 | BD(dev).bd_flags |= BD_NO_MEDIA; |
| 833 | break; |
| 834 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 835 | } |
| 836 | |
Toomas Soome | b75eb7e | 2017-06-03 01:58:24 +0300 | [diff] [blame^] | 837 | if (result != 0 && (BD(dev).bd_flags & BD_NO_MEDIA) == 0) { |
Toomas Soome | c9a7c75 | 2018-08-16 12:04:31 +0300 | [diff] [blame] | 838 | if (dowrite == BD_WR) { |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 839 | printf("%s%d: Write %d sector(s) from %p (0x%x) " |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 840 | "to %lld: 0x%x\n", dev->dd.d_dev->dv_name, |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 841 | dev->dd.d_unit, blks, dest, VTOP(dest), dblk, |
| 842 | result); |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 843 | } else { |
| 844 | printf("%s%d: Read %d sector(s) from %lld to %p " |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 845 | "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name, |
Toomas Soome | 76b3594 | 2018-03-13 11:58:56 +0200 | [diff] [blame] | 846 | dev->dd.d_unit, blks, dblk, dest, VTOP(dest), |
| 847 | result); |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 848 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 849 | } |
Toomas Soome | 4c004ea | 2017-05-19 03:06:10 +0300 | [diff] [blame] | 850 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 851 | return (result); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 852 | } |
| 853 | |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 854 | /* |
| 855 | * Return the BIOS geometry of a given "fixed drive" in a format |
| 856 | * suitable for the legacy bootinfo structure. Since the kernel is |
| 857 | * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we |
| 858 | * prefer to get the information directly, rather than rely on being |
| 859 | * able to put it together from information already maintained for |
| 860 | * different purposes and for a probably different number of drives. |
| 861 | * |
| 862 | * For valid drives, the geometry is expected in the format (31..0) |
| 863 | * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are |
| 864 | * indicated by returning the geometry of a "1.2M" PC-format floppy |
| 865 | * disk. And, incidentally, what is returned is not the geometry as |
| 866 | * such but the highest valid cylinder, head, and sector numbers. |
| 867 | */ |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 868 | uint32_t |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 869 | bd_getbigeom(int bunit) |
| 870 | { |
| 871 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 872 | v86.ctl = V86_FLAGS; |
| 873 | v86.addr = 0x13; |
| 874 | v86.eax = 0x800; |
| 875 | v86.edx = 0x80 + bunit; |
| 876 | v86int(); |
| 877 | if (V86_CY(v86.efl)) |
| 878 | return (0x4f010f); |
| 879 | return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | |
| 880 | (v86.edx & 0xff00) | (v86.ecx & 0x3f)); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 881 | } |
| 882 | |
| 883 | /* |
| 884 | * Return a suitable dev_t value for (dev). |
| 885 | * |
| 886 | * In the case where it looks like (dev) is a SCSI disk, we allow the number of |
| 887 | * IDE disks to be specified in $num_ide_disks. There should be a Better Way. |
| 888 | */ |
| 889 | int |
| 890 | bd_getdev(struct i386_devdesc *d) |
| 891 | { |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 892 | struct disk_devdesc *dev; |
| 893 | int biosdev; |
| 894 | int major; |
| 895 | int rootdev; |
| 896 | char *nip, *cp; |
| 897 | int i, unit; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 898 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 899 | dev = (struct disk_devdesc *)d; |
| 900 | biosdev = bd_unit2bios(dev->dd.d_unit); |
| 901 | DEBUG("unit %d BIOS device %d", dev->dd.d_unit, biosdev); |
| 902 | if (biosdev == -1) /* not a BIOS device */ |
| 903 | return (-1); |
| 904 | if (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, |
| 905 | BD(dev).bd_sectorsize) != 0) /* oops, not a viable device */ |
| 906 | return (-1); |
| 907 | else |
| 908 | disk_close(dev); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 909 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 910 | if (biosdev < 0x80) { |
| 911 | /* floppy (or emulated floppy) or ATAPI device */ |
| 912 | if (bdinfo[dev->dd.d_unit].bd_type == DT_ATAPI) { |
| 913 | /* is an ATAPI disk */ |
| 914 | major = WFDMAJOR; |
| 915 | } else { |
| 916 | /* is a floppy disk */ |
| 917 | major = FDMAJOR; |
| 918 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 919 | } else { |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 920 | /* assume an IDE disk */ |
| 921 | major = WDMAJOR; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 922 | } |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 923 | /* default root disk unit number */ |
| 924 | unit = biosdev & 0x7f; |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 925 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 926 | /* XXX a better kludge to set the root disk unit number */ |
| 927 | if ((nip = getenv("root_disk_unit")) != NULL) { |
| 928 | i = strtol(nip, &cp, 0); |
| 929 | /* check for parse error */ |
| 930 | if ((cp != nip) && (*cp == 0)) |
| 931 | unit = i; |
| 932 | } |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 933 | |
Toomas Soome | 5855bf0 | 2018-05-19 18:50:26 +0300 | [diff] [blame] | 934 | rootdev = MAKEBOOTDEV(major, dev->d_slice + 1, unit, dev->d_partition); |
| 935 | DEBUG("dev is 0x%x\n", rootdev); |
| 936 | return (rootdev); |
Toomas Soome | 199767f | 2015-10-25 00:06:51 +0300 | [diff] [blame] | 937 | } |