1 1.31 jakllsch /* $NetBSD: biosdisk_ll.c,v 1.31 2011/02/21 02:58:02 jakllsch Exp $ */ 2 1.21 junyoung 3 1.21 junyoung /*- 4 1.21 junyoung * Copyright (c) 2005 The NetBSD Foundation, Inc. 5 1.21 junyoung * All rights reserved. 6 1.21 junyoung * 7 1.21 junyoung * This code is derived from software contributed to The NetBSD Foundation 8 1.21 junyoung * by Bang Jun-Young. 9 1.21 junyoung * 10 1.21 junyoung * Redistribution and use in source and binary forms, with or without 11 1.21 junyoung * modification, are permitted provided that the following conditions 12 1.21 junyoung * are met: 13 1.21 junyoung * 1. Redistributions of source code must retain the above copyright 14 1.21 junyoung * notice, this list of conditions and the following disclaimer. 15 1.21 junyoung * 2. Redistributions in binary form must reproduce the above copyright 16 1.21 junyoung * notice, this list of conditions and the following disclaimer in the 17 1.21 junyoung * documentation and/or other materials provided with the distribution. 18 1.21 junyoung * 19 1.21 junyoung * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.21 junyoung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.21 junyoung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.21 junyoung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.21 junyoung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.21 junyoung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.21 junyoung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.21 junyoung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.21 junyoung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.21 junyoung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.21 junyoung * POSSIBILITY OF SUCH DAMAGE. 30 1.21 junyoung */ 31 1.1 perry 32 1.1 perry /* 33 1.1 perry * Copyright (c) 1996 34 1.1 perry * Matthias Drochner. All rights reserved. 35 1.1 perry * Copyright (c) 1996 36 1.1 perry * Perry E. Metzger. All rights reserved. 37 1.1 perry * 38 1.1 perry * Redistribution and use in source and binary forms, with or without 39 1.1 perry * modification, are permitted provided that the following conditions 40 1.1 perry * are met: 41 1.1 perry * 1. Redistributions of source code must retain the above copyright 42 1.1 perry * notice, this list of conditions and the following disclaimer. 43 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright 44 1.1 perry * notice, this list of conditions and the following disclaimer in the 45 1.1 perry * documentation and/or other materials provided with the distribution. 46 1.1 perry * 3. All advertising materials mentioning features or use of this software 47 1.1 perry * must display the following acknowledgements: 48 1.1 perry * This product includes software developed for the NetBSD Project 49 1.1 perry * by Matthias Drochner. 50 1.1 perry * This product includes software developed for the NetBSD Project 51 1.1 perry * by Perry E. Metzger. 52 1.1 perry * 4. The names of the authors may not be used to endorse or promote products 53 1.1 perry * derived from this software without specific prior written permission. 54 1.1 perry * 55 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 56 1.1 perry * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 57 1.1 perry * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 58 1.1 perry * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 59 1.1 perry * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 60 1.1 perry * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 61 1.1 perry * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 62 1.1 perry * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 63 1.1 perry * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 64 1.1 perry * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 65 1.1 perry */ 66 1.1 perry 67 1.2 thorpej /* 68 1.3 drochner * shared by bootsector startup (bootsectmain) and biosdisk.c 69 1.3 drochner * needs lowlevel parts from bios_disk.S 70 1.2 thorpej */ 71 1.1 perry 72 1.29 jakllsch #include <lib/libkern/libkern.h> 73 1.1 perry #include <lib/libsa/stand.h> 74 1.1 perry 75 1.1 perry #include "biosdisk_ll.h" 76 1.1 perry #include "diskbuf.h" 77 1.19 junyoung #include "libi386.h" 78 1.1 perry 79 1.17 dsl static int do_read(struct biosdisk_ll *, daddr_t, int, char *); 80 1.1 perry 81 1.7 drochner /* 82 1.7 drochner * we get from get_diskinfo(): 83 1.22 junyoung * %ah %ch %cl %dh (registers after int13/8), ie 84 1.21 junyoung * xxxxxxxx cccccccc CCssssss hhhhhhhh 85 1.7 drochner */ 86 1.22 junyoung #define STATUS(di) ((di)>>24) 87 1.22 junyoung #define SPT(di) (((di)>>8)&0x3f) 88 1.22 junyoung #define HEADS(di) (((di)&0xff)+1) 89 1.7 drochner #define CYL(di) (((((di)>>16)&0xff)|(((di)>>6)&0x300))+1) 90 1.1 perry 91 1.4 drochner #ifndef BIOSDISK_RETRIES 92 1.4 drochner #define BIOSDISK_RETRIES 5 93 1.4 drochner #endif 94 1.4 drochner 95 1.20 junyoung int 96 1.23 junyoung set_geometry(struct biosdisk_ll *d, struct biosdisk_extinfo *ed) 97 1.1 perry { 98 1.7 drochner int diskinfo; 99 1.1 perry 100 1.23 junyoung diskinfo = biosdisk_getinfo(d->dev); 101 1.7 drochner d->sec = SPT(diskinfo); 102 1.7 drochner d->head = HEADS(diskinfo); 103 1.7 drochner d->cyl = CYL(diskinfo); 104 1.8 fvdl d->chs_sectors = d->sec * d->head * d->cyl; 105 1.1 perry 106 1.21 junyoung if (d->dev >= 0x80 + get_harddrives()) { 107 1.21 junyoung d->secsize = 2048; 108 1.21 junyoung d->type = BIOSDISK_TYPE_CD; 109 1.21 junyoung } else { 110 1.21 junyoung d->secsize = 512; 111 1.21 junyoung if (d->dev & 0x80) 112 1.21 junyoung d->type = BIOSDISK_TYPE_HD; 113 1.21 junyoung else 114 1.21 junyoung d->type = BIOSDISK_TYPE_FD; 115 1.21 junyoung } 116 1.21 junyoung 117 1.21 junyoung /* 118 1.21 junyoung * Some broken BIOSes such as one found on Soltek SL-75DRV2 report 119 1.21 junyoung * that they don't support int13 extension for CD-ROM drives while 120 1.21 junyoung * they actually do. As a workaround, if the boot device is a CD we 121 1.21 junyoung * assume that the extension is available. Note that only very old 122 1.21 junyoung * BIOSes don't support the extended mode, and they don't work with 123 1.21 junyoung * ATAPI CD-ROM drives, either. So there's no problem. 124 1.21 junyoung */ 125 1.5 ws d->flags = 0; 126 1.21 junyoung if (d->type == BIOSDISK_TYPE_CD || 127 1.23 junyoung (d->type == BIOSDISK_TYPE_HD && biosdisk_int13ext(d->dev))) { 128 1.23 junyoung d->flags |= BIOSDISK_INT13EXT; 129 1.17 dsl if (ed != NULL) { 130 1.21 junyoung ed->size = sizeof(*ed); 131 1.30 dyoung if (biosdisk_getextinfo(d->dev, ed) != 0) 132 1.31 jakllsch return -1; 133 1.17 dsl } 134 1.13 jdolecek } 135 1.13 jdolecek 136 1.13 jdolecek /* 137 1.20 junyoung * If the drive is 2.88MB floppy drive, check that we can actually 138 1.20 junyoung * read sector >= 18. If not, assume 1.44MB floppy disk. 139 1.13 jdolecek */ 140 1.21 junyoung if (d->type == BIOSDISK_TYPE_FD && SPT(diskinfo) == 36) { 141 1.21 junyoung char buf[512]; 142 1.21 junyoung 143 1.23 junyoung if (biosdisk_read(d->dev, 0, 0, 18, 1, buf)) { 144 1.13 jdolecek d->sec = 18; 145 1.13 jdolecek d->chs_sectors /= 2; 146 1.20 junyoung } 147 1.6 fvdl } 148 1.1 perry 149 1.21 junyoung return 0; 150 1.1 perry } 151 1.1 perry 152 1.2 thorpej /* 153 1.2 thorpej * Global shared "diskbuf" is used as read ahead buffer. For reading from 154 1.2 thorpej * floppies, the bootstrap has to be loaded on a 64K boundary to ensure that 155 1.2 thorpej * this buffer doesn't cross a 64K DMA boundary. 156 1.1 perry */ 157 1.2 thorpej static int ra_dev; 158 1.27 jakllsch static daddr_t ra_end; 159 1.27 jakllsch static daddr_t ra_first; 160 1.2 thorpej 161 1.18 thorpej /* 162 1.18 thorpej * Because some older BIOSes have bugs in their int13 extensions, we 163 1.18 thorpej * only try to use the extended read if the I/O request can't be addressed 164 1.18 thorpej * using CHS. 165 1.18 thorpej * 166 1.18 thorpej * Of course, some BIOSes have bugs in ths CHS read, such as failing to 167 1.18 thorpej * function properly if the MBR table has a different geometry than the 168 1.18 thorpej * BIOS would generate internally for the device in question, and so we 169 1.18 thorpej * provide a way to force the extended on hard disks via a compile-time 170 1.18 thorpej * option. 171 1.18 thorpej */ 172 1.18 thorpej #if defined(FORCE_INT13EXT) 173 1.18 thorpej #define NEED_INT13EXT(d, dblk, num) \ 174 1.18 thorpej (((d)->dev & 0x80) != 0) 175 1.18 thorpej #else 176 1.18 thorpej #define NEED_INT13EXT(d, dblk, num) \ 177 1.21 junyoung (((d)->type == BIOSDISK_TYPE_CD) || \ 178 1.21 junyoung ((d)->type == BIOSDISK_TYPE_HD && \ 179 1.21 junyoung ((dblk) + (num)) >= (d)->chs_sectors)) 180 1.18 thorpej #endif 181 1.18 thorpej 182 1.5 ws static int 183 1.17 dsl do_read(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf) 184 1.5 ws { 185 1.5 ws 186 1.18 thorpej if (NEED_INT13EXT(d, dblk, num)) { 187 1.21 junyoung struct { 188 1.21 junyoung int8_t size; 189 1.21 junyoung int8_t resvd; 190 1.21 junyoung int16_t cnt; 191 1.21 junyoung int16_t off; 192 1.21 junyoung int16_t seg; 193 1.21 junyoung int64_t sec; 194 1.21 junyoung } ext; 195 1.21 junyoung 196 1.23 junyoung if (!(d->flags & BIOSDISK_INT13EXT)) 197 1.8 fvdl return -1; 198 1.5 ws ext.size = sizeof(ext); 199 1.5 ws ext.resvd = 0; 200 1.5 ws ext.cnt = num; 201 1.14 dsl /* seg:off of physical address */ 202 1.14 dsl ext.off = (int)buf & 0xf; 203 1.14 dsl ext.seg = vtophys(buf) >> 4; 204 1.5 ws ext.sec = dblk; 205 1.5 ws 206 1.23 junyoung if (biosdisk_extread(d->dev, &ext)) { 207 1.23 junyoung (void)biosdisk_reset(d->dev); 208 1.5 ws return -1; 209 1.12 dyoung } 210 1.5 ws 211 1.5 ws return ext.cnt; 212 1.5 ws } else { 213 1.21 junyoung int cyl, head, sec, nsec, spc, dblk32; 214 1.21 junyoung 215 1.16 fvdl dblk32 = (int)dblk; 216 1.7 drochner spc = d->head * d->sec; 217 1.16 fvdl cyl = dblk32 / spc; 218 1.16 fvdl head = (dblk32 % spc) / d->sec; 219 1.16 fvdl sec = dblk32 % d->sec; 220 1.6 fvdl nsec = d->sec - sec; 221 1.5 ws 222 1.5 ws if (nsec > num) 223 1.5 ws nsec = num; 224 1.5 ws 225 1.23 junyoung if (biosdisk_read(d->dev, cyl, head, sec, nsec, buf)) { 226 1.23 junyoung (void)biosdisk_reset(d->dev); 227 1.5 ws return -1; 228 1.12 dyoung } 229 1.5 ws 230 1.5 ws return nsec; 231 1.5 ws } 232 1.5 ws } 233 1.5 ws 234 1.21 junyoung /* 235 1.21 junyoung * NB if 'cold' is set below not all of the program is loaded, so 236 1.21 junyoung * mustn't use data segment, bss, call library functions or do read-ahead. 237 1.14 dsl */ 238 1.20 junyoung int 239 1.17 dsl readsects(struct biosdisk_ll *d, daddr_t dblk, int num, char *buf, int cold) 240 1.1 perry { 241 1.17 dsl #ifdef BOOTXX 242 1.17 dsl #define cold 1 /* collapse out references to diskbufp */ 243 1.17 dsl #endif 244 1.2 thorpej while (num) { 245 1.20 junyoung int nsec; 246 1.1 perry 247 1.2 thorpej /* check for usable data in read-ahead buffer */ 248 1.2 thorpej if (cold || diskbuf_user != &ra_dev || d->dev != ra_dev 249 1.2 thorpej || dblk < ra_first || dblk >= ra_end) { 250 1.2 thorpej 251 1.2 thorpej /* no, read from disk */ 252 1.20 junyoung char *trbuf; 253 1.7 drochner int maxsecs; 254 1.4 drochner int retries = BIOSDISK_RETRIES; 255 1.2 thorpej 256 1.2 thorpej if (cold) { 257 1.2 thorpej /* transfer directly to buffer */ 258 1.2 thorpej trbuf = buf; 259 1.7 drochner maxsecs = num; 260 1.2 thorpej } else { 261 1.2 thorpej /* fill read-ahead buffer */ 262 1.14 dsl trbuf = alloc_diskbuf(0); /* no data yet */ 263 1.21 junyoung maxsecs = DISKBUFSIZE / d->secsize; 264 1.2 thorpej } 265 1.2 thorpej 266 1.7 drochner while ((nsec = do_read(d, dblk, maxsecs, trbuf)) < 0) { 267 1.4 drochner #ifdef DISK_DEBUG 268 1.4 drochner if (!cold) 269 1.29 jakllsch printf("read error dblk %"PRId64"-%"PRId64"\n", 270 1.27 jakllsch dblk, (dblk + maxsecs - 1)); 271 1.4 drochner #endif 272 1.5 ws if (--retries >= 0) 273 1.4 drochner continue; 274 1.20 junyoung return -1; /* XXX cannot output here if 275 1.2 thorpej * (cold) */ 276 1.5 ws } 277 1.5 ws if (!cold) { 278 1.5 ws ra_dev = d->dev; 279 1.5 ws ra_first = dblk; 280 1.5 ws ra_end = dblk + nsec; 281 1.5 ws diskbuf_user = &ra_dev; 282 1.2 thorpej } 283 1.2 thorpej } else /* can take blocks from end of read-ahead 284 1.2 thorpej * buffer */ 285 1.2 thorpej nsec = ra_end - dblk; 286 1.2 thorpej 287 1.2 thorpej if (!cold) { 288 1.2 thorpej /* copy data from read-ahead to user buffer */ 289 1.2 thorpej if (nsec > num) 290 1.2 thorpej nsec = num; 291 1.11 perry memcpy(buf, 292 1.21 junyoung diskbufp + (dblk - ra_first) * d->secsize, 293 1.21 junyoung nsec * d->secsize); 294 1.2 thorpej } 295 1.21 junyoung buf += nsec * d->secsize; 296 1.2 thorpej num -= nsec; 297 1.2 thorpej dblk += nsec; 298 1.1 perry } 299 1.1 perry 300 1.20 junyoung return 0; 301 1.1 perry } 302 1.21 junyoung 303 1.21 junyoung /* 304 1.21 junyoung * Return the number of hard disk drives. 305 1.21 junyoung */ 306 1.21 junyoung int 307 1.21 junyoung get_harddrives(void) 308 1.21 junyoung { 309 1.21 junyoung /* 310 1.21 junyoung * Some BIOSes are buggy so that they return incorrect number 311 1.21 junyoung * of hard drives with int13/ah=8. We read a byte at 0040:0075 312 1.21 junyoung * instead, which is known to be always correct. 313 1.21 junyoung */ 314 1.21 junyoung int n = 0; 315 1.21 junyoung 316 1.21 junyoung pvbcopy((void *)0x475, &n, 1); 317 1.21 junyoung 318 1.21 junyoung return n; 319 1.21 junyoung } 320