kernel: Use hashdestroy() to free hash tables allocated with hashinit().
[dragonfly.git] / usr.bin / doscmd / int13.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
16 * Design, Inc.
17 *
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * BSDI int13.c,v 2.3 1996/04/08 19:32:43 bostic Exp
1de703da
MD
31 *
32 * $FreeBSD: src/usr.bin/doscmd/int13.c,v 1.4.2.2 2002/04/25 11:04:51 tg Exp $
984263bc
MD
33 */
34
984263bc
MD
35#include <sys/ioctl.h>
36#include <sys/types.h>
37#include <sys/uio.h>
38#include <unistd.h>
39
40#include "doscmd.h"
41
42#define FDCHANGED _IOR('F', 64, int)
43
44#define INT13_ERR_NONE 0x00
45#define INT13_ERR_BAD_COMMAND 0x01
46#define INT13_ERR_BAD_ADDRESS_MARK 0x02
47#define INT13_ERR_WRITE_PROTECT 0x03
48#define INT13_ERR_SECTOR_ID_BAD 0x04
49#define INT13_ERR_RESET_FAILURE 0x05
50#define INT13_ERR_CLL_ACTIVE 0x06
51#define INT13_ERR_ACT_FAILED 0x07
52#define INT13_ERR_DMA_OVERRUN 0x08
53#define INT13_ERR_DMA_BOUNDARY 0x09
54#define INT13_ERR_BAD_TRACK_FLAG 0x0B
55#define INT13_ERR_MEDIA_TYP_UNKNOWN 0x0C
56#define INT13_ERR_CRC 0x10
57#define INT13_ERR_CORRECTED 0x11
58#define INT13_ERR_CTRLR_FAILURE 0x20
59#define INT13_ERR_SEEK 0x40
60#define INT13_ERR_TIME_OUT 0x80
61#define INT13_ERR_NOT_READY 0xAA
62#define INT13_ERR_UNDEFINED 0xBB
63#define INT13_ERR_SENSE_OPERATION 0xFF
64
65typedef struct {
66 u_char bootIndicator;
67 u_char beginHead;
68 u_char beginSector;
69 u_char beginCyl;
70 u_char systemID;
71 u_char endHead;
72 u_char endSector;
73 u_char endCyl;
74 u_long relSector;
75 u_long numSectors;
76} PTAB;
77
78struct diskinfo {
79 int type;
80 int sectors;
81 int cylinders;
82 int sides;
83 int secsize;
84 int fd;
85 char *path;
86 u_long location;
87 u_char *sector0;
88 u_long offset;
89 char *list[4]; /* Up to 4 devices allowed */
90 unsigned multi:2;
91 int read_only:1;
92 int removeable:1;
93 int changed:1; /* Set if we change format */
94};
95
96#define hd_status (*(u_char *)0x474)
97#define fd_status (*(u_char *)0x441)
98
99static inline int
100disize(struct diskinfo *di)
101{
102 return(di->sectors * di->cylinders * di->sides);
103}
104
105static inline int
106cylsize(struct diskinfo *di)
107{
108 return(di->sectors * di->sides);
109}
110
111static u_long ftable = 0xF1000; /* Floppy table */
112static u_long htable = 0xF1020; /* Hard disk table */
113
114static struct diskinfo diskinfo[26];
115
116static struct diskinfo floppyinfo[] = {
117 {0, 9, 40, 1, 512, -1, NULL, 0, NULL, 0,
118 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0}, /* Probably not correct */
119 {1, 9, 40, 2, 512, -1, NULL, 0, NULL, 0,
120 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
121 {2, 9, 80, 2, 512, -1, NULL, 0, NULL, 0,
122 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
123 {3, 15, 80, 2, 512, -1, NULL, 0, NULL, 0,
124 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
125 {4, 18, 80, 2, 512, -1, NULL, 0, NULL, 0,
126 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
127 {6, 36, 80, 2, 512, -1, NULL, 0, NULL, 0,
128 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
129 {-1, 0, 0, 0, 0, 0, NULL, 0, NULL, 0,
130 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0}
131};
132
133static struct diskinfo *
134getdisk(int drive)
135{
136 struct diskinfo *di;
137
138 if (drive >= 2 && drive < 0x80) {
139 return(0);
140 }
141 if (drive >= 0x80) {
142 drive -= 0x80;
143 drive += 2;
144 }
145
678e8cc6 146 if (drive > 25 || diskinfo[drive].path == NULL) {
984263bc
MD
147 return(0);
148 }
149 di = &diskinfo[drive];
150 if (di->fd < 0) {
151 if (di->removeable) {
152 di->read_only = 0;
153 if (!(di->path = di->list[di->multi]))
154 di->path = di->list[di->multi = 0];
155 }
156 if ((di->fd = open(di->path, di->read_only ? O_RDONLY
157 : O_RDWR|O_FSYNC)) < 0 &&
158 (di->read_only = 1) &&
159 (di->fd = open(di->path, O_RDONLY)) < 0) {
160 return(0);
161 }
162 di->fd = squirrel_fd(di->fd);
163 }
164 return(di);
165}
166
167int
168disk_fd(int drive)
169{
170 struct diskinfo *di;
171
172 if (drive > 1)
173 drive += 0x80 - 2;
174 di = getdisk(drive);
175 if (!di)
176 return(-1);
177 return(di->fd);
178}
179
180void
181make_readonly(int drive)
182{
183 if (drive < 0 || drive >= 26)
184 return;
185 diskinfo[drive].read_only = 1;
186}
187
188int
189init_hdisk(int drive, int cyl, int head, int tracksize, char *file, char *fake_ptab)
190{
191 struct diskinfo *di;
a62ce081 192 u_long table = 0;
984263bc
MD
193
194 if (drive < 0) {
195 for (drive = 2; drive < 26; ++drive) {
678e8cc6 196 if (diskinfo[drive].path == NULL)
984263bc
MD
197 break;
198 }
199 }
200 if (drive < 2) {
201 fprintf(stderr, "Only floppies may be assigned to A: or B:\n");
202 return(-1);
203 }
204
205 if (drive >= 26) {
206 fprintf(stderr, "Too many disk drives (only 24 allowed)\n");
207 return(-1);
208 }
209
210 di = &diskinfo[drive];
211
212 if (di->path) {
213 fprintf(stderr, "Drive %c: already assigned to %s\n", drntol(drive),
214 di->path);
215 return(-1);
216 }
217 di->fd = -1;
218 di->sectors = tracksize;
219 di->cylinders = cyl;
220 di->sides = head;
678e8cc6 221 di->sector0 = NULL;
984263bc
MD
222 di->offset = 0;
223
224 if (fake_ptab) {
225 u_char buf[512];
226 int fd;
227 PTAB *ptab;
228 int clusters;
229
230 if ((fd = open(fake_ptab, 0)) < 0) {
231 perror(fake_ptab);
232 return(-1);
233 }
234 di->sector0 = malloc(512);
235 if (!di->sector0) {
236 perror("malloc in init_hdisk");
237 quit(1);
238 }
239
240 read(fd, di->sector0, 512);
241 close(fd);
242
243 ptab = (PTAB *)(di->sector0 + 0x01BE);
244
245 for (fd = 0; fd < 4; ++fd) {
246 if (*(u_short *)(di->sector0 + 0x1FE) == 0xAA55 &&
247 ptab[fd].numSectors == (u_long)(head * tracksize * cyl) &&
248 (ptab[fd].systemID == 1 || ptab[fd].systemID == 4 ||
249 ptab[fd].systemID == 6))
250 break;
251 }
252 if (fd < 4) {
253 if (fd)
254 memcpy(ptab, ptab + fd, sizeof(PTAB));
255 memset(ptab + 1, 0, sizeof(PTAB) * 3);
256 di->offset = ptab[0].relSector;
257 di->cylinders += di->offset / cylsize(di);
258 } else {
259 memset(ptab, 0, sizeof(PTAB) * 4);
260
261 ptab->beginHead = 0;
262 ptab->beginSector = 1; /* this is 1 based */
263 ptab->beginCyl = 1;
264
265 ptab->endHead = head - 1;
266 ptab->endSector = tracksize; /* this is 1 based */
267 ptab->endCyl = cyl & 0xff;
268 ptab->endSector |= (cyl & 0x300) >> 2;
269
270 ptab->relSector = head * tracksize;
271 ptab->numSectors = head * tracksize * cyl;
272
273 *(u_short *)(di->sector0 + 0x1FE) = 0xAA55;
274
275 fd = open(file, 0);
276 if (fd < 0) {
277 perror(file);
278 return(-1);
279 }
280 memset(buf, 0, 512);
281 read(fd, buf, 512);
282 close(fd);
283 if ((clusters = buf[0x0D]) == 0) {
284 if (disize(di) <= 128 * 2048)
285 clusters = 4;
286 else if (disize(di) <= 256 * 2048)
287 clusters = 8;
288 else if (disize(di) <= 8 * 1024 * 2048)
289 clusters = 16;
290 else if (disize(di) <= 16 * 1024 * 2048)
291 clusters = 32;
292 else
293 clusters = 64;
294 }
295 if ((disize(di) / clusters) <= 4096) {
296 ptab->systemID = 0x01;
297 } else {
298 ptab->systemID = 0x04;
299 }
300
301 di->cylinders += 1; /* Extra cylinder for partition table, etc. */
302 }
303 ptab->bootIndicator = 0x80;
304 }
305 di->type = 0xf8;
306 di->path = file;
307 di->secsize = 512;
308 di->path = strdup(file);
309
310 di->location = ((table & 0xf0000) << 12) | (table & 0xffff);
311
312 if (drive == 0) {
313 ivec[0x41] = di->location;
314 } else if (drive == 1) {
315 ivec[0x46] = di->location;
316 }
317
318 table = htable + (drive - 2) * 0x10;
319 *(u_short *)(table+0x00) = di->cylinders-1; /* Cylinders */
320 *(u_char *)(table+0x02) = di->sides; /* Heads */
321 *(u_short *)(table+0x03) = 0; /* 0 */
322 *(u_short *)(table+0x05) = 0xffff; /* write pre-comp */
323 *(u_char *)(table+0x07) = 0; /* ECC Burst length */
324 *(u_char *)(table+0x08) = 0; /* Control Byte */
325 *(u_char *)(table+0x09) = 0; /* standard timeout */
326 *(u_char *)(table+0x0a) = 0; /* formatting timeout */
327 *(u_char *)(table+0x0b) = 0; /* timeout for checking drive */
328 *(u_short *)(table+0x0c) = di->cylinders-1; /* landing zone */
329 *(u_char *)(table+0x0e) = di->sectors; /* sectors/track */
330 *(u_char *)(table+0x0f) = 0;
331
332 if ((drive - 1) >= ndisks)
333 ndisks = drive - 1;
334 return(drive);
335}
336
337static inline int
338bps(int size)
339{
340 switch (size) {
341 case 128: return(0);
342 case 256: return(1);
343 case 512: return(2);
344 case 1024: return(3);
345 default:
346 fprintf(stderr, "Invalid sector size: %d\n", size);
347 quit(1);
348 }
349 /* keep `gcc -Wall' happy */
350 return(0);
351}
352
353int
354init_floppy(int drive, int type, char *file)
355{
356 struct diskinfo *di = floppyinfo;
a62ce081 357 u_long table = 0;
984263bc
MD
358 struct stat sb;
359
360 while (di->type >= 0 && di->type != type && disize(di)/2 != type)
361 ++di;
362
363 if (!di->type) {
364 fprintf(stderr, "Invalid floppy type: %d\n", type);
365 return(-1);
366 }
367
368 if (drive < 0) {
678e8cc6 369 if (diskinfo[0].path == NULL) {
984263bc 370 drive = 0;
678e8cc6 371 } else if (diskinfo[1].path == NULL) {
984263bc
MD
372 drive = 1;
373 } else {
374 fprintf(stderr, "Too many floppy drives (only 2 allowed)\n");
375 return(-1);
376 }
377 }
378 if (drive > 1) {
379 fprintf(stderr, "Floppies must be either drive A: or B:\n");
380 return(-1);
381 }
382
383 if (drive >= nfloppies)
384 nfloppies = drive + 1;
385
678e8cc6 386 if (diskinfo[drive].path == NULL) {
984263bc
MD
387 diskinfo[drive] = *di;
388 }
389
390 di = &diskinfo[drive];
391
392 if (stat(file, &sb) < 0) {
393 fprintf(stderr, "Drive %c: Could not stat %s\n", drntol(drive), file);
394 return(-1);
395 }
396
397 if (drive < 2 && (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode))) {
398 if (di->path && !di->removeable) {
399 fprintf(stderr, "Drive %c: is not removeable and hence can only have one assignment\n", drntol(drive));
400 return(-1);
401 }
402 di->removeable = 1;
403 } else if (di->removeable) {
404 fprintf(stderr, "Drive %c: already assigned to %s\n", drntol(drive),
405 di->path);
406 return(-1);
407 }
408
409 if (di->removeable) {
410#if 0 /*XXXXX*/
411 if (di->multi == 4) {
412 fprintf(stderr, "Drive %c: already assigned 4 devices\n",
413 drntol(drive));
414 return(-1);
415 }
416#endif
417 di->path = di->list[di->multi++] = strdup(file);
418 } else {
419 if (di->path) {
420 fprintf(stderr, "Drive %c: already assigned to %s\n",
421 drntol(drive), di->path);
422 return(-1);
423 }
424
425 di->path = strdup(file);
426 }
427 di->fd = -1;
428 di->location = ((table & 0xf0000) << 12) | (table & 0xffff);
678e8cc6 429 di->sector0 = NULL;
984263bc
MD
430 di->offset = 0;
431
432 ivec[0x1e] = ((ftable & 0xf0000) << 12) | (ftable & 0xffff);
433
434 table = ftable + drive * 0x0a;
435
436 *(u_char *)(table+0x00) = 0xdf; /* First Specify Byte */
437 *(u_char *)(table+0x01) = 0x02; /* Second Specify Byte */
438 *(u_char *)(table+0x02) = 0x25; /* Timer ticks to wait 'til motor OFF */
439 *(u_char *)(table+0x03) = bps(di->secsize); /* Number of bytes/sector */
440 *(u_char *)(table+0x04) = di->sectors; /* Number of sectors/track */
441 *(u_char *)(table+0x05) = 0x1b; /* Gap length, in bytes */
442 *(u_char *)(table+0x06) = 0xff; /* Data length, in bytes */
443 *(u_char *)(table+0x07) = 0x6c; /* Gap length for format */
444 *(u_char *)(table+0x09) = 0xf6; /* Fill byte for formatting */
445 *(u_char *)(table+0x09) = 0x0f; /* Head settle time, in milliseconds */
446 *(u_char *)(table+0x0a) = 0x08; /* Motor startup time, in 1/8 seconds */
447 return(drive);
448}
449
450int
451search_floppy(int i)
452{
453 return(i < nfloppies ? diskinfo[i].type : 0);
454}
455
456#define seterror(err) { \
457 if (drive & 0x80) \
458 hd_status = err; \
459 else \
460 fd_status = err; \
461 R_AH = err; \
462 R_FLAGS |= PSL_C; \
463}
464
465static int
466trynext(struct diskinfo *di)
467{
468 close(di->fd);
469 di->fd = -1;
470 di->changed = 1;
471#if 0 /*XXXXX*/
472 if (di->multi++ >= 4)
473 return(0);
474#endif
475 if (di->list[di->multi] && (di = getdisk(di - diskinfo))) {
476 di->multi = 0;
477 return(1);
478 }
479 return(0);
480}
481
482static int
483diread(struct diskinfo *di, regcontext_t *REGS,
484 off_t start, char *addr, int sectors)
485{
486 off_t res;
487
488 int drive = di - diskinfo;
489 di->multi = -1;
490
491 if (drive > 1) {
492 drive -= 2;
493 drive |= 0x80;
494 }
495
496again:
497 res = lseek(di->fd, start * di->secsize, 0);
498
499 if (res < 0 && di->removeable && trynext(di))
500 goto again;
501
502 if (res < 0) {
503 seterror(INT13_ERR_SEEK);
504 return(-1);
505 }
506
507 res = read(di->fd, addr, sectors * di->secsize);
508
509 if (res < 0 && di->removeable && trynext(di))
510 goto again;
511
512 if (di->removeable) {
513 if (res < 0) {
514 seterror(INT13_ERR_NOT_READY);
515 return(-1);
516 }
517 return(res / di->secsize);
518 }
519
520 /*
521 * reads always work, if if they don't.
522 * Just pretend any byte not read was actually a 0
523 */
524 if (res < 0)
525 memset(addr, 0, sectors * di->secsize);
526 else if (res < sectors * di->secsize)
527 memset(addr + res, 0, sectors * di->secsize - res);
528
529 return(sectors);
530}
531
532static int
533diwrite(struct diskinfo *di, regcontext_t *REGS,
534 off_t start, char *addr, int sectors)
535{
536 off_t res;
537 int drive = di - diskinfo;
538 di->multi = -1;
539
540 if (drive > 1) {
541 drive -= 2;
542 drive |= 0x80;
543 }
544
545again:
546 res = lseek(di->fd, start * di->secsize, 0);
547
548 if (res < 0 && di->removeable && trynext(di))
549 goto again;
550
551 if (res < 0) {
552 seterror(INT13_ERR_SEEK);
553 return(-1);
554 }
555
556 res = write(di->fd, addr, sectors * di->secsize);
557
558 if (res < 0 && di->removeable && trynext(di))
559 goto again;
560
561 if (di->removeable) {
562 if (res < 0) {
563 seterror(INT13_ERR_NOT_READY);
564 return(-1);
565 }
566 } else if (res < 0) {
567 seterror(INT13_ERR_WRITE_PROTECT);
568 return(-1);
569 }
570 return(res / di->secsize);
571}
572
573static void
574int13(regcontext_t *REGS)
575{
576 char *addr;
577 int sectors;
578 struct diskinfo *di;
579 off_t start;
580 int did;
581
582 int cyl;
583 int sector;
584 int side;
585 int drive;
586
587 reset_poll();
588
589 R_FLAGS &= ~PSL_C;
590
591 drive = R_DL;
592
593 if (R_AX != 0x01) {
594 if (drive & 0x80)
595 hd_status = 0;
596 else
597 fd_status = 0;
598 }
599
600 switch (R_AH) {
601 case 0x00: /* Reset */
602 break;
603 case 0x01: /* Read disk status */
604 if (drive & 0x80)
605 R_AH = hd_status;
606 else
607 R_AH = fd_status;
608 if (R_AH)
609 R_FLAGS |= PSL_C;
610 break;
611 case 0x02: /* Read */
612 R_AH = 0;
613 addr = (char *)MAKEPTR(R_ES, R_BX);
614 sectors = R_AL;
615 side = R_DH;
616 R_AL = 0; /* Start out with nothing read */
617
618 if (drive & 0x80) {
619 cyl = R_CH | ((R_CL & 0xc0) << 2);
620 sector = (R_CL & 0x3f) - 1;
621 } else {
622 sector = R_CL - 1;
623 cyl = R_CH;
624 }
625
678e8cc6 626 if ((di = getdisk(drive)) == NULL) {
984263bc
MD
627 debug(D_DISK, "Bad drive: %02x (%d : %d : %d)\n",
628 drive, cyl, side, sector);
629 seterror(INT13_ERR_BAD_COMMAND);
630 break;
631 }
632 start = cyl * di->sectors * di->sides +
633 side * di->sectors +
634 sector;
635
636 if (start >= disize(di)) {
637 debug(D_DISK, "Read past end of disk\n");
638 seterror(INT13_ERR_SEEK);
639 break;
640 }
641 if (sectors + start >= disize(di)) {
642 sectors = disize(di) - start;
643 }
644
645 if (di->sector0) {
646 if (start < di->offset) {
647 R_AL = sectors;
648 if (start == 0) {
649 memcpy(addr, di->sector0, di->secsize);
650 addr += di->secsize;
651 --sectors;
652 }
653 memset(addr, 0, sectors * di->secsize);
654 break;
655 } else {
656 start -= di->offset;
657 }
658 }
659 debug(D_DISK, "%02x: Read %2d sectors from %qd to %04x:%04x\n",
660 drive, sectors, start, R_ES, R_BX);
661
662 if ((did = diread(di, REGS, start, addr, sectors)) >= 0)
663 R_AL = did;
664#if 0
665 callint(0x0d);
666 callint(0x76);
667#endif
668 break;
669
670 case 0x03: /* Write */
671 R_AH = 0;
672 addr = (char *)MAKEPTR(R_ES, R_BX);
673 sectors = R_AL;
674 side = R_DH;
675 R_AL = 0; /* Start out with nothing written */
676
677 if (drive & 0x80) {
678 cyl = R_CH | ((R_CL & 0xc0) << 2);
679 sector = (R_CL & 0x3f) - 1;
680 } else {
681 sector = R_CL - 1;
682 cyl = R_CH;
683 }
684
678e8cc6 685 if ((di = getdisk(drive)) == NULL) {
984263bc
MD
686 debug(D_DISK, "Bad drive: %d (%d : %d : %d)\n",
687 drive, cyl, side, sector);
688 seterror(INT13_ERR_BAD_COMMAND);
689 break;
690 }
691 if (di->read_only) {
692 debug(D_DISK, "%02x: Attempt to write readonly disk\n", drive);
693 seterror(INT13_ERR_WRITE_PROTECT);
694 break;
695 }
696 start = cyl * di->sectors * di->sides +
697 side * di->sectors +
698 sector;
699
700 if (start >= disize(di)) {
701 debug(D_DISK, "Write past end of disk\n");
702 seterror(INT13_ERR_SEEK);
703 break;
704 }
705
706 if (sectors + start >= disize(di))
707 sectors = disize(di) - start;
708
709 if (di->sector0) {
710 if (start < di->offset) {
711 R_AL = sectors;
712 break;
713 } else {
714 start -= di->offset;
715 }
716 }
717
718 debug(D_DISK, "%02x: Write %2d sectors from %qd to %04x:%04x\n",
719 drive, sectors, start, R_ES, R_BX);
720
721 if ((did = diwrite(di, REGS, start, addr, sectors)) >= 0)
722 R_AL = did;
723#if 0
724 callint(0x0d);
725 callint(0x76);
726#endif
727 break;
728
729 case 0x04: /* Verify */
730 R_AH = 0;
731 sectors = R_AL;
732 side = R_DH;
733
734 if (drive & 0x80) {
735 cyl = R_CH | ((R_CL & 0xc0) << 2);
736 sector = (R_CL & 0x3f) - 1;
737 } else {
738 sector = R_CL - 1;
739 cyl = R_CH;
740 }
741
678e8cc6 742 if ((di = getdisk(drive)) == NULL) {
984263bc
MD
743 debug(D_DISK, "Bad drive: %d (%d : %d : %d)\n",
744 drive, cyl, side, sector);
745 seterror(INT13_ERR_BAD_COMMAND);
746 break;
747 }
748 start = cyl * di->sectors * di->sides +
749 side * di->sectors +
750 sector;
751
752 if (start >= disize(di)) {
753 debug(D_DISK, "Verify past end of disk\n");
754 seterror(INT13_ERR_SEEK);
755 break;
756 }
757
758 if (sectors + start >= disize(di))
759 sectors = disize(di) - start;
760
761 if (di->sector0) {
762 if (start < di->offset)
763 break;
764 else
765 start -= di->offset;
766 }
767
768 debug(D_DISK, "Verify %2d sectors from %qd\n", sectors, start);
769 if (lseek(di->fd, start * di->secsize, 0) < 0) {
770 debug(D_DISK, "Seek error\n");
771 seterror(INT13_ERR_SEEK);
772 break;
773 }
774 while (sectors > 0) {
775 char buf[512];
776 if (read(di->fd, buf, di->secsize) != di->secsize) {
777 debug(D_DISK, "Verify error\n");
778 seterror(0x04);
779 break;
780 }
781 --sectors;
782 }
783#if 0
784 callint(0x0d);
785 callint(0x76);
786#endif
787 break;
788
789 case 0x05: /* Format track */
790 seterror(INT13_ERR_BAD_COMMAND);
791 break;
792
793 case 0x08: /* Status */
794 R_AH = 0;
795
678e8cc6 796 if ((di = getdisk(drive)) == NULL) {
984263bc
MD
797 debug(D_DISK, "Bad drive: %d\n", drive);
798 seterror(INT13_ERR_BAD_COMMAND);
799 break;
800 }
801 R_AX = 0;
802
803 R_BX = di->type;
804 if ((drive & 0x80) == 0)
805 PUTVEC(R_ES, R_DI, di->location);
806
807 R_CL = di->sectors | ((di->cylinders >> 2) & 0xc0);
808 R_CH = di->cylinders & 0xff;
809 R_DL = (drive & 0x80) ? ndisks : nfloppies;
810 R_DH = di->sides - 1;
811 debug(D_DISK, "%02x: Status requested: sec %d cyl %d side %d drive %d\n",
812 drive, R_CL, R_CH, R_DH, R_DL);
813#if 0
814 callint(0x0d);
815 callint(0x76);
816#endif
817 break;
818
819 case 0x0c: /* Move read/write head */
820 case 0x0d: /* Reset */
821 break;
822
823 case 0x10: /* check for disk ready */
824 R_AH = 0; /* always open for business */
825 break;
826
827 case 0x15:
678e8cc6 828 if ((di = getdisk(drive)) == NULL) {
984263bc
MD
829 R_AH = 0;
830 R_FLAGS |= PSL_C;
831 break;
832 }
833
834 if (drive & 0x80) {
835 start = di->sectors * di->cylinders * di->sides;
836 R_CX = start >> 16;
837 R_DX = start;
838 R_AH = 3;
839 } else {
840 R_AH = 1; /* Non-changeable disk */
841 }
842 break;
843
844 case 0x16: /* Media change */
845 R_AH = 0;
846 if ((di = getdisk(drive)) && di->changed) {
847 di->changed = 0;
848 R_AH = 6;
849 }
850 break;
851
852 case 0x17: /* Determine floppy disk format */
853 seterror(INT13_ERR_BAD_COMMAND);
854 break;
855
856 case 0x18: /* Determine disk format */
678e8cc6 857 if ((di = getdisk(drive)) == NULL) {
984263bc
MD
858 R_AH = 0;
859 R_FLAGS |= PSL_C;
860 break;
861 }
862 /* XXX incomplete? */
863 break;
864
865 default:
866 unknown_int2(0x13, R_AH, REGS);
867 break;
868 }
869}
870
871void
872disk_bios_init(void)
873{
874 u_long vec;
875
876 vec = insert_softint_trampoline();
877 ivec[0x13] = vec;
878 register_callback(vec, int13, "int 13");
879
880 vec = insert_null_trampoline();
881 ivec[0x76] = vec;
882}