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