Add full support for drives with more that 2<<32 sectors.
[seabios.git] / src / disk.c
1 // 16bit code to access hard drives.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
8 #include "disk.h" // floppy_13
9 #include "biosvar.h" // struct bregs
10 #include "config.h" // CONFIG_*
11 #include "cmos.h" // inb_cmos
12 #include "util.h" // debug_enter
13 #include "ata.h" // ATA_*
14
15 #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
16 #define DEBUGF(fmt, args...)
17
18
19 /****************************************************************
20  * Helper functions
21  ****************************************************************/
22
23 void
24 __disk_ret(const char *fname, struct bregs *regs, u8 code)
25 {
26     SET_BDA(disk_last_status, code);
27     if (code)
28         __set_code_fail(fname, regs, code);
29     else
30         set_code_success(regs);
31 }
32
33 static void
34 __disk_stub(const char *fname, struct bregs *regs)
35 {
36     __debug_stub(fname, regs);
37     __disk_ret(fname, regs, DISK_RET_SUCCESS);
38 }
39
40 #define DISK_STUB(regs) \
41     __disk_stub(__func__, (regs))
42
43 static void
44 basic_access(struct bregs *regs, u8 device, u16 command)
45 {
46     u8 type = GET_EBDA(ata.devices[device].type);
47     u16 nlc, nlh, nlspt;
48     if (type == ATA_TYPE_ATA) {
49         nlc   = GET_EBDA(ata.devices[device].lchs.cylinders);
50         nlh   = GET_EBDA(ata.devices[device].lchs.heads);
51         nlspt = GET_EBDA(ata.devices[device].lchs.spt);
52     } else {
53         // Must be cd emulation.
54         nlc   = GET_EBDA(cdemu.vdevice.cylinders);
55         nlh   = GET_EBDA(cdemu.vdevice.heads);
56         nlspt = GET_EBDA(cdemu.vdevice.spt);
57     }
58
59     u16 count       = regs->al;
60     u16 cylinder    = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
61     u16 sector      = regs->cl & 0x3f;
62     u16 head        = regs->dh;
63
64     if (count > 128 || count == 0 || sector == 0) {
65         BX_INFO("int13_harddisk: function %02x, parameter out of range!\n"
66                 , regs->ah);
67         disk_ret(regs, DISK_RET_EPARAM);
68         return;
69     }
70
71     // sanity check on cyl heads, sec
72     if (cylinder >= nlc || head >= nlh || sector > nlspt) {
73         BX_INFO("int13_harddisk: function %02x, parameters out of"
74                 " range %04x/%04x/%04x!\n"
75                 , regs->ah, cylinder, head, sector);
76         disk_ret(regs, DISK_RET_EPARAM);
77         return;
78     }
79
80     if (!command) {
81         // If verify or seek
82         disk_ret(regs, DISK_RET_SUCCESS);
83         return;
84     }
85
86     // translate lchs to lba
87     u32 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
88                + (u32)sector - 1);
89
90     u16 segment = regs->es;
91     u16 offset  = regs->bx;
92     void *far_buffer = MAKE_FARPTR(segment, offset);
93
94     irq_enable();
95
96     int status;
97     if (type == ATA_TYPE_ATA)
98         status = ata_cmd_data(device, command, lba, count, far_buffer);
99     else
100         status = cdrom_read_emu(device, lba, count, far_buffer);
101
102     irq_disable();
103
104     // Set nb of sector transferred
105     regs->al = GET_EBDA(ata.trsfsectors);
106
107     if (status != 0) {
108         BX_INFO("int13_harddisk: function %02x, error %02x !\n"
109                 , regs->ah, status);
110         disk_ret(regs, DISK_RET_EBADTRACK);
111     }
112     disk_ret(regs, DISK_RET_SUCCESS);
113 }
114
115 static void
116 extended_access(struct bregs *regs, u8 device, u16 command)
117 {
118     // Get lba and check.
119     u64 lba = GET_INT13EXT(regs, lba);
120     u8 type = GET_EBDA(ata.devices[device].type);
121     if (type == ATA_TYPE_ATA
122         && lba >= GET_EBDA(ata.devices[device].sectors)) {
123         BX_INFO("int13_harddisk: function %02x. LBA out of range\n", regs->ah);
124         disk_ret(regs, DISK_RET_EPARAM);
125         return;
126     }
127
128     if (!command) {
129         // If verify or seek
130         disk_ret(regs, DISK_RET_SUCCESS);
131         return;
132     }
133
134     u16 segment = GET_INT13EXT(regs, segment);
135     u16 offset = GET_INT13EXT(regs, offset);
136     void *far_buffer = MAKE_FARPTR(segment, offset);
137     u16 count = GET_INT13EXT(regs, count);
138
139     irq_enable();
140
141     u8 status;
142     if (type == ATA_TYPE_ATA)
143         status = ata_cmd_data(device, command, lba, count, far_buffer);
144     else
145         status = cdrom_read(device, lba, count, far_buffer);
146
147     irq_disable();
148
149     SET_INT13EXT(regs, count, GET_EBDA(ata.trsfsectors));
150
151     if (status != 0) {
152         BX_INFO("int13_harddisk: function %02x, error %02x !\n"
153                 , regs->ah, status);
154         disk_ret(regs, DISK_RET_EBADTRACK);
155         return;
156     }
157     disk_ret(regs, DISK_RET_SUCCESS);
158 }
159
160
161 /****************************************************************
162  * Hard Drive functions
163  ****************************************************************/
164
165 // disk controller reset
166 static void
167 disk_1300(struct bregs *regs, u8 device)
168 {
169     ata_reset(device);
170 }
171
172 // read disk status
173 static void
174 disk_1301(struct bregs *regs, u8 device)
175 {
176     u8 v = GET_BDA(disk_last_status);
177     regs->ah = v;
178     set_cf(regs, v);
179     // XXX - clear disk_last_status?
180 }
181
182 // read disk sectors
183 static void
184 disk_1302(struct bregs *regs, u8 device)
185 {
186     basic_access(regs, device, ATA_CMD_READ_SECTORS);
187 }
188
189 // write disk sectors
190 static void
191 disk_1303(struct bregs *regs, u8 device)
192 {
193     basic_access(regs, device, ATA_CMD_WRITE_SECTORS);
194 }
195
196 // verify disk sectors
197 static void
198 disk_1304(struct bregs *regs, u8 device)
199 {
200     basic_access(regs, device, 0);
201     // FIXME verify
202 }
203
204 // format disk track
205 static void
206 disk_1305(struct bregs *regs, u8 device)
207 {
208     DISK_STUB(regs);
209 }
210
211 // read disk drive parameters
212 static void
213 disk_1308(struct bregs *regs, u8 device)
214 {
215     // Get logical geometry from table
216     u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
217     u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
218     u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
219     u16 count = GET_EBDA(ata.hdcount);
220
221     nlc = nlc - 2; /* 0 based , last sector not used */
222     regs->al = 0;
223     regs->ch = nlc & 0xff;
224     regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
225     regs->dh = nlh - 1;
226     regs->dl = count; /* FIXME returns 0, 1, or n hard drives */
227
228     // FIXME should set ES & DI
229     disk_ret(regs, DISK_RET_SUCCESS);
230 }
231
232 // initialize drive parameters
233 static void
234 disk_1309(struct bregs *regs, u8 device)
235 {
236     DISK_STUB(regs);
237 }
238
239 // seek to specified cylinder
240 static void
241 disk_130c(struct bregs *regs, u8 device)
242 {
243     DISK_STUB(regs);
244 }
245
246 // alternate disk reset
247 static void
248 disk_130d(struct bregs *regs, u8 device)
249 {
250     DISK_STUB(regs);
251 }
252
253 // check drive ready
254 static void
255 disk_1310(struct bregs *regs, u8 device)
256 {
257     // should look at 40:8E also???
258
259     // Read the status from controller
260     u8 status = inb(GET_EBDA(ata.channels[device/2].iobase1) + ATA_CB_STAT);
261     if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY )
262         disk_ret(regs, DISK_RET_SUCCESS);
263     else
264         disk_ret(regs, DISK_RET_ENOTREADY);
265 }
266
267 // recalibrate
268 static void
269 disk_1311(struct bregs *regs, u8 device)
270 {
271     DISK_STUB(regs);
272 }
273
274 // controller internal diagnostic
275 static void
276 disk_1314(struct bregs *regs, u8 device)
277 {
278     DISK_STUB(regs);
279 }
280
281 // read disk drive size
282 static void
283 disk_1315(struct bregs *regs, u8 device)
284 {
285     // Get logical geometry from table
286     u16 nlc   = GET_EBDA(ata.devices[device].lchs.cylinders);
287     u16 nlh   = GET_EBDA(ata.devices[device].lchs.heads);
288     u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
289
290     // Compute sector count seen by int13
291     u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
292     regs->cx = lba >> 16;
293     regs->dx = lba & 0xffff;
294
295     disk_ret(regs, DISK_RET_SUCCESS);
296     regs->ah = 3; // hard disk accessible
297 }
298
299 // IBM/MS installation check
300 static void
301 disk_1341(struct bregs *regs, u8 device)
302 {
303     regs->bx = 0xaa55;  // install check
304     regs->cx = 0x0007;  // ext disk access and edd, removable supported
305     disk_ret(regs, DISK_RET_SUCCESS);
306     regs->ah = 0x30;    // EDD 3.0
307 }
308
309 // IBM/MS extended read
310 static void
311 disk_1342(struct bregs *regs, u8 device)
312 {
313     extended_access(regs, device, ATA_CMD_READ_SECTORS);
314 }
315
316 // IBM/MS extended write
317 static void
318 disk_1343(struct bregs *regs, u8 device)
319 {
320     extended_access(regs, device, ATA_CMD_WRITE_SECTORS);
321 }
322
323 // IBM/MS verify
324 static void
325 disk_1344(struct bregs *regs, u8 device)
326 {
327     extended_access(regs, device, 0);
328 }
329
330 // IBM/MS lock/unlock drive
331 static void
332 disk_1345(struct bregs *regs, u8 device)
333 {
334     // Always success for HD
335     disk_ret(regs, DISK_RET_SUCCESS);
336 }
337
338 // IBM/MS eject media
339 static void
340 disk_1346(struct bregs *regs, u8 device)
341 {
342     // Volume Not Removable
343     disk_ret(regs, DISK_RET_ENOTREMOVABLE);
344 }
345
346 // IBM/MS extended seek
347 static void
348 disk_1347(struct bregs *regs, u8 device)
349 {
350     extended_access(regs, device, 0);
351 }
352
353 // IBM/MS get drive parameters
354 static void
355 disk_1348(struct bregs *regs, u8 device)
356 {
357     u16 size = GET_INT13DPT(regs, size);
358
359     // Buffer is too small
360     if (size < 0x1a) {
361         disk_ret(regs, DISK_RET_EPARAM);
362         return;
363     }
364
365     // EDD 1.x
366
367     u8  type    = GET_EBDA(ata.devices[device].type);
368     u16 npc     = GET_EBDA(ata.devices[device].pchs.cylinders);
369     u16 nph     = GET_EBDA(ata.devices[device].pchs.heads);
370     u16 npspt   = GET_EBDA(ata.devices[device].pchs.spt);
371     u64 lba     = GET_EBDA(ata.devices[device].sectors);
372     u16 blksize = GET_EBDA(ata.devices[device].blksize);
373
374     SET_INT13DPT(regs, size, 0x1a);
375     if (type == ATA_TYPE_ATA) {
376         if (lba > (u64)npspt*nph*0x3fff) {
377             SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
378             SET_INT13DPT(regs, cylinders, 0x3fff);
379         } else {
380             SET_INT13DPT(regs, infos, 0x02); // geometry is valid
381             SET_INT13DPT(regs, cylinders, (u32)npc);
382         }
383         SET_INT13DPT(regs, heads, (u32)nph);
384         SET_INT13DPT(regs, spt, (u32)npspt);
385         SET_INT13DPT(regs, sector_count, lba);
386     } else {
387         // ATAPI
388         // 0x74 = removable, media change, lockable, max values
389         SET_INT13DPT(regs, infos, 0x74);
390         SET_INT13DPT(regs, cylinders, 0xffffffff);
391         SET_INT13DPT(regs, heads, 0xffffffff);
392         SET_INT13DPT(regs, spt, 0xffffffff);
393         SET_INT13DPT(regs, sector_count, (u64)-1);
394     }
395     SET_INT13DPT(regs, blksize, blksize);
396
397     if (size < 0x1e) {
398         disk_ret(regs, DISK_RET_SUCCESS);
399         return;
400     }
401
402     // EDD 2.x
403
404     SET_INT13DPT(regs, size, 0x1e);
405
406     SET_INT13DPT(regs, dpte_segment, SEG_EBDA);
407     SET_INT13DPT(regs, dpte_offset
408                  , offsetof(struct extended_bios_data_area_s, ata.dpte));
409
410     // Fill in dpte
411     u8 channel = device / 2;
412     u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1);
413     u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2);
414     u8 irq = GET_EBDA(ata.channels[channel].irq);
415     u8 mode = GET_EBDA(ata.devices[device].mode);
416
417     u16 options;
418     if (type == ATA_TYPE_ATA) {
419         u8 translation = GET_EBDA(ata.devices[device].translation);
420         options  = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
421         options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
422         options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
423     } else {
424         // ATAPI
425         options  = (1<<5); // removable device
426         options |= (1<<6); // atapi device
427     }
428     options |= (1<<4); // lba translation
429     options |= (mode==ATA_MODE_PIO32?1:0)<<7;
430
431     SET_EBDA(ata.dpte.iobase1, iobase1);
432     SET_EBDA(ata.dpte.iobase2, iobase2 + ATA_CB_DC);
433     SET_EBDA(ata.dpte.prefix, (0xe | (device % 2))<<4 );
434     SET_EBDA(ata.dpte.unused, 0xcb );
435     SET_EBDA(ata.dpte.irq, irq );
436     SET_EBDA(ata.dpte.blkcount, 1 );
437     SET_EBDA(ata.dpte.dma, 0 );
438     SET_EBDA(ata.dpte.pio, 0 );
439     SET_EBDA(ata.dpte.options, options);
440     SET_EBDA(ata.dpte.reserved, 0);
441     if (size >= 0x42)
442         SET_EBDA(ata.dpte.revision, 0x11);
443     else
444         SET_EBDA(ata.dpte.revision, 0x10);
445
446     u8 *p = MAKE_FARPTR(SEG_EBDA
447                         , offsetof(struct extended_bios_data_area_s, ata.dpte));
448     u8 sum = checksum(p, 15);
449     SET_EBDA(ata.dpte.checksum, ~sum);
450
451     if (size < 0x42) {
452         disk_ret(regs, DISK_RET_SUCCESS);
453         return;
454     }
455
456     // EDD 3.x
457     channel = device / 2;
458     u8 iface = GET_EBDA(ata.channels[channel].iface);
459     iobase1 = GET_EBDA(ata.channels[channel].iobase1);
460
461     SET_INT13DPT(regs, size, 0x42);
462     SET_INT13DPT(regs, key, 0xbedd);
463     SET_INT13DPT(regs, dpi_length, 0x24);
464     SET_INT13DPT(regs, reserved1, 0);
465     SET_INT13DPT(regs, reserved2, 0);
466
467     if (iface==ATA_IFACE_ISA) {
468         SET_INT13DPT(regs, host_bus[0], 'I');
469         SET_INT13DPT(regs, host_bus[1], 'S');
470         SET_INT13DPT(regs, host_bus[2], 'A');
471         SET_INT13DPT(regs, host_bus[3], 0);
472     } else {
473         // FIXME PCI
474     }
475     SET_INT13DPT(regs, iface_type[0], 'A');
476     SET_INT13DPT(regs, iface_type[1], 'T');
477     SET_INT13DPT(regs, iface_type[2], 'A');
478     SET_INT13DPT(regs, iface_type[3], 0);
479
480     if (iface==ATA_IFACE_ISA) {
481         SET_INT13DPT(regs, iface_path[0], iobase1);
482         SET_INT13DPT(regs, iface_path[2], 0);
483         SET_INT13DPT(regs, iface_path[4], 0L);
484     } else {
485         // FIXME PCI
486     }
487     SET_INT13DPT(regs, device_path[0], device%2);
488     SET_INT13DPT(regs, device_path[1], 0);
489     SET_INT13DPT(regs, device_path[2], 0);
490     SET_INT13DPT(regs, device_path[4], 0L);
491
492     sum = checksum(MAKE_FARPTR(regs->ds, 30), 34);
493     SET_INT13DPT(regs, checksum, ~sum);
494 }
495
496 // IBM/MS extended media change
497 static void
498 disk_1349(struct bregs *regs, u8 device)
499 {
500     // Always success for HD
501     disk_ret(regs, DISK_RET_SUCCESS);
502 }
503
504 static void
505 disk_134e01(struct bregs *regs, u8 device)
506 {
507     disk_ret(regs, DISK_RET_SUCCESS);
508 }
509
510 static void
511 disk_134e03(struct bregs *regs, u8 device)
512 {
513     disk_ret(regs, DISK_RET_SUCCESS);
514 }
515
516 static void
517 disk_134e04(struct bregs *regs, u8 device)
518 {
519     disk_ret(regs, DISK_RET_SUCCESS);
520 }
521
522 static void
523 disk_134e06(struct bregs *regs, u8 device)
524 {
525     disk_ret(regs, DISK_RET_SUCCESS);
526 }
527
528 static void
529 disk_134eXX(struct bregs *regs, u8 device)
530 {
531     disk_ret(regs, DISK_RET_EPARAM);
532 }
533
534 // IBM/MS set hardware configuration
535 static void
536 disk_134e(struct bregs *regs, u8 device)
537 {
538     switch (regs->al) {
539     case 0x01: disk_134e01(regs, device); break;
540     case 0x03: disk_134e03(regs, device); break;
541     case 0x04: disk_134e04(regs, device); break;
542     case 0x06: disk_134e06(regs, device); break;
543     default:   disk_134eXX(regs, device); break;
544     }
545 }
546
547 void
548 disk_13XX(struct bregs *regs, u8 device)
549 {
550     disk_ret(regs, DISK_RET_EPARAM);
551 }
552
553 void
554 disk_13(struct bregs *regs, u8 device)
555 {
556     //debug_stub(regs);
557
558     // clear completion flag
559     SET_BDA(disk_interrupt_flag, 0);
560
561     switch (regs->ah) {
562     case 0x00: disk_1300(regs, device); break;
563     case 0x01: disk_1301(regs, device); break;
564     case 0x02: disk_1302(regs, device); break;
565     case 0x03: disk_1303(regs, device); break;
566     case 0x04: disk_1304(regs, device); break;
567     case 0x05: disk_1305(regs, device); break;
568     case 0x08: disk_1308(regs, device); break;
569     case 0x09: disk_1309(regs, device); break;
570     case 0x0c: disk_130c(regs, device); break;
571     case 0x0d: disk_130d(regs, device); break;
572     case 0x10: disk_1310(regs, device); break;
573     case 0x11: disk_1311(regs, device); break;
574     case 0x14: disk_1314(regs, device); break;
575     case 0x15: disk_1315(regs, device); break;
576     case 0x41: disk_1341(regs, device); break;
577     case 0x42: disk_1342(regs, device); break;
578     case 0x43: disk_1343(regs, device); break;
579     case 0x44: disk_1344(regs, device); break;
580     case 0x45: disk_1345(regs, device); break;
581     case 0x46: disk_1346(regs, device); break;
582     case 0x47: disk_1347(regs, device); break;
583     case 0x48: disk_1348(regs, device); break;
584     case 0x49: disk_1349(regs, device); break;
585     case 0x4e: disk_134e(regs, device); break;
586     default:   disk_13XX(regs, device); break;
587     }
588 }
589
590
591 /****************************************************************
592  * Entry points
593  ****************************************************************/
594
595 static u8
596 get_device(struct bregs *regs, u8 iscd, u8 drive)
597 {
598     // basic check : device has to be defined
599     if (drive >= CONFIG_MAX_ATA_DEVICES) {
600         disk_ret(regs, DISK_RET_EPARAM);
601         return CONFIG_MAX_ATA_DEVICES;
602     }
603
604     // Get the ata channel
605     u8 device = GET_EBDA(ata.idmap[iscd][drive]);
606
607     // basic check : device has to be valid
608     if (device >= CONFIG_MAX_ATA_DEVICES) {
609         disk_ret(regs, DISK_RET_EPARAM);
610         return CONFIG_MAX_ATA_DEVICES;
611     }
612
613     return device;
614 }
615
616 static void
617 handle_legacy_disk(struct bregs *regs, u8 drive)
618 {
619     if (drive < 0x80) {
620         floppy_13(regs, drive);
621         return;
622     }
623
624     if (! CONFIG_ATA) {
625         // XXX - old code had other disk access method.
626         disk_ret(regs, DISK_RET_EPARAM);
627         return;
628     }
629
630     if (drive >= 0xe0) {
631         u8 device = get_device(regs, 1, drive - 0xe0);
632         if (device >= CONFIG_MAX_ATA_DEVICES)
633             return;
634         cdrom_13(regs, device);
635         return;
636     }
637
638     u8 device = get_device(regs, 0, drive - 0x80);
639     if (device >= CONFIG_MAX_ATA_DEVICES)
640         return;
641     disk_13(regs, device);
642 }
643
644 void VISIBLE16
645 handle_40(struct bregs *regs)
646 {
647     debug_enter(regs);
648     handle_legacy_disk(regs, regs->dl);
649 }
650
651 // INT 13h Fixed Disk Services Entry Point
652 void VISIBLE16
653 handle_13(struct bregs *regs)
654 {
655     //debug_enter(regs);
656     u8 drive = regs->dl;
657
658     if (CONFIG_CDROM_EMU) {
659         if (regs->ah == 0x4b) {
660             cdemu_134b(regs);
661             return;
662         }
663         if (GET_EBDA(cdemu.active)) {
664             if (drive == GET_EBDA(cdemu.emulated_drive)) {
665                 cdemu_13(regs);
666                 return;
667             }
668             if (drive < 0xe0)
669                 drive--;
670         }
671     }
672     handle_legacy_disk(regs, drive);
673 }
674
675 // record completion in BIOS task complete flag
676 void VISIBLE16
677 handle_76()
678 {
679     debug_isr();
680     SET_BDA(disk_interrupt_flag, 0xff);
681     eoi_both_pics();
682 }