blob: 0ccbe42009368b3f4ed5883332e7d966f72fed36 [file] [log] [blame]
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05001// 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
Kevin O'Connor3491e8b2008-02-29 00:22:27 -050010#include "config.h" // CONFIG_*
11#include "cmos.h" // inb_cmos
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050012#include "util.h" // debug_enter
Kevin O'Connor3491e8b2008-02-29 00:22:27 -050013#include "ata.h" // ATA_*
14
Kevin O'Connorf205f9f2008-03-09 16:11:49 -040015#define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
16#define DEBUGF(fmt, args...)
17
Kevin O'Connorb74102d2008-03-03 21:57:30 -050018
19/****************************************************************
20 * Helper functions
21 ****************************************************************/
22
Kevin O'Connore43df9e2008-03-01 22:16:32 -050023#define DISK_STUB(regs) do { \
24 struct bregs *__regs = (regs); \
25 debug_stub(__regs); \
26 disk_ret(__regs, DISK_RET_SUCCESS); \
27 } while (0)
28
29static u8
30checksum_seg(u16 seg, u16 offset, u32 len)
31{
32 u32 i;
33 u8 sum = 0;
34 for (i=0; i<len; i++)
35 sum += GET_FARVAR(seg, *(u8*)(offset+i));
36 return sum;
37}
38
39static void
40basic_access(struct bregs *regs, u8 device, u16 command)
41{
42 u16 count = regs->al;
43 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
44 u16 sector = regs->cl & 0x3f;
45 u16 head = regs->dh;
46
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040047 if (count > 128 || count == 0 || sector == 0) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -050048 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n"
49 , regs->ah);
50 disk_ret(regs, DISK_RET_EPARAM);
51 return;
52 }
53
54 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
55 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
56 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
57 u16 nph = GET_EBDA(ata.devices[device].pchs.heads);
58 u16 npspt = GET_EBDA(ata.devices[device].pchs.spt);
59
60 // sanity check on cyl heads, sec
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040061 if (cylinder >= nlc || head >= nlh || sector > nlspt) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -050062 BX_INFO("int13_harddisk: function %02x, parameters out of"
63 " range %04x/%04x/%04x!\n"
64 , regs->ah, cylinder, head, sector);
65 disk_ret(regs, DISK_RET_EPARAM);
66 return;
67 }
68
Kevin O'Connor3a049632008-03-11 11:48:04 -040069 if (!command) {
70 // If verify or seek
Kevin O'Connore43df9e2008-03-01 22:16:32 -050071 disk_ret(regs, DISK_RET_SUCCESS);
72 return;
73 }
74
Kevin O'Connor3a049632008-03-11 11:48:04 -040075 u16 segment = regs->es;
76 u16 offset = regs->bx;
77
Kevin O'Connor74799df2008-03-12 20:49:07 -040078 irq_enable();
79
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040080 u8 status;
81 u32 lba;
82 if (nph != nlh || npspt != nlspt) {
83 // translate lchs to lba
84 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
85 + (u32)sector - 1);
Kevin O'Connorefde6092008-03-12 20:33:15 -040086 status = ata_cmd_data(device, command, lba, count
87 , MAKE_32_PTR(segment, offset));
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040088 } else {
89 // XXX - see if lba access can always be used.
90 status = ata_cmd_data_chs(device, command
Kevin O'Connorefde6092008-03-12 20:33:15 -040091 , cylinder, head, sector, count
92 , MAKE_32_PTR(segment, offset));
Kevin O'Connor1fcf1442008-03-11 19:42:41 -040093 }
Kevin O'Connor3a049632008-03-11 11:48:04 -040094
Kevin O'Connor74799df2008-03-12 20:49:07 -040095 irq_disable();
96
Kevin O'Connore43df9e2008-03-01 22:16:32 -050097 // Set nb of sector transferred
98 regs->al = GET_EBDA(ata.trsfsectors);
99
100 if (status != 0) {
101 BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
102 disk_ret(regs, DISK_RET_EBADTRACK);
103 }
104 disk_ret(regs, DISK_RET_SUCCESS);
105}
106
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500107void
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500108emu_access(struct bregs *regs, u8 device, u16 command)
109{
Kevin O'Connor180a9592008-03-04 22:50:53 -0500110 u16 count = regs->al;
111 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
112 u16 sector = regs->cl & 0x3f;
113 u16 head = regs->dh;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500114
Kevin O'Connor180a9592008-03-04 22:50:53 -0500115 if ((count > 128) || (count == 0) || (sector == 0)) {
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500116 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n"
117 , regs->ah);
118 disk_ret(regs, DISK_RET_EPARAM);
119 return;
120 }
121
122 u16 nlc = GET_EBDA(cdemu.vdevice.cylinders);
123 u16 nlh = GET_EBDA(cdemu.vdevice.heads);
124 u16 nlspt = GET_EBDA(cdemu.vdevice.spt);
125
126 // sanity check on cyl heads, sec
127 if ( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
128 BX_INFO("int13_harddisk: function %02x, parameters out of"
129 " range %04x/%04x/%04x!\n"
130 , regs->ah, cylinder, head, sector);
131 disk_ret(regs, DISK_RET_EPARAM);
132 return;
133 }
134
135 if (!command) {
136 // If verify or seek
137 disk_ret(regs, DISK_RET_SUCCESS);
138 return;
139 }
140
141 u32 ilba = GET_EBDA(cdemu.ilba);
142 // calculate the virtual lba inside the image
143 u32 vlba= (((((u32)cylinder*(u32)nlh)+(u32)head)*(u32)nlspt)
144 +((u32)(sector-1)));
145 // start lba on cd
146 u32 slba = (u32)vlba/4;
147 u16 before= (u16)vlba%4;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500148 u32 lba = ilba + slba;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500149
150 u16 segment = regs->es;
151 u16 offset = regs->bx;
152
Kevin O'Connor74799df2008-03-12 20:49:07 -0400153 irq_enable();
Kevin O'Connorefde6092008-03-12 20:33:15 -0400154 u8 status = cdrom_read(device, lba, count*512
155 , MAKE_32_PTR(segment, offset), before*512);
Kevin O'Connor74799df2008-03-12 20:49:07 -0400156 irq_disable();
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500157 if (status != 0) {
158 BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
159 regs->al = 0;
160 disk_ret(regs, DISK_RET_EBADTRACK);
161 }
Kevin O'Connor180a9592008-03-04 22:50:53 -0500162 regs->al = count;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500163 disk_ret(regs, DISK_RET_SUCCESS);
164}
165
Kevin O'Connored128492008-03-11 11:14:59 -0400166static void
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500167extended_access(struct bregs *regs, u8 device, u16 command)
168{
169 u16 count = GET_INT13EXT(regs, count);
170 u16 segment = GET_INT13EXT(regs, segment);
171 u16 offset = GET_INT13EXT(regs, offset);
172
173 // Can't use 64 bits lba
174 u32 lba = GET_INT13EXT(regs, lba2);
175 if (lba != 0L) {
176 BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n"
177 , regs->ah);
178 disk_ret(regs, DISK_RET_EPARAM);
179 return;
180 }
181
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500182 u8 type = GET_EBDA(ata.devices[device].type);
183
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500184 // Get 32 bits lba and check
185 lba = GET_INT13EXT(regs, lba1);
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500186 if (type == ATA_TYPE_ATA
187 && lba >= GET_EBDA(ata.devices[device].sectors)) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500188 BX_INFO("int13_harddisk: function %02x. LBA out of range\n", regs->ah);
189 disk_ret(regs, DISK_RET_EPARAM);
190 return;
191 }
192
Kevin O'Connor3a049632008-03-11 11:48:04 -0400193 if (!command) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500194 // If verify or seek
195 disk_ret(regs, DISK_RET_SUCCESS);
196 return;
197 }
198
Kevin O'Connor74799df2008-03-12 20:49:07 -0400199 irq_enable();
200
Kevin O'Connor3a049632008-03-11 11:48:04 -0400201 u8 status;
202 if (type == ATA_TYPE_ATA)
Kevin O'Connorefde6092008-03-12 20:33:15 -0400203 status = ata_cmd_data(device, command, lba, count
204 , MAKE_32_PTR(segment, offset));
Kevin O'Connor3a049632008-03-11 11:48:04 -0400205 else
Kevin O'Connorefde6092008-03-12 20:33:15 -0400206 status = cdrom_read(device, lba, count*2048
207 , MAKE_32_PTR(segment, offset), 0);
Kevin O'Connor3a049632008-03-11 11:48:04 -0400208
Kevin O'Connor74799df2008-03-12 20:49:07 -0400209 irq_disable();
210
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500211 SET_INT13EXT(regs, count, GET_EBDA(ata.trsfsectors));
212
213 if (status != 0) {
214 BX_INFO("int13_harddisk: function %02x, error %02x !\n"
215 , regs->ah, status);
216 disk_ret(regs, DISK_RET_EBADTRACK);
217 return;
218 }
219 disk_ret(regs, DISK_RET_SUCCESS);
220}
221
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500222
223/****************************************************************
224 * Hard Drive functions
225 ****************************************************************/
226
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500227// disk controller reset
228static void
229disk_1300(struct bregs *regs, u8 device)
230{
231 ata_reset(device);
232}
233
234// read disk status
235static void
236disk_1301(struct bregs *regs, u8 device)
237{
238 regs->ah = GET_BDA(disk_last_status);
239 disk_ret(regs, DISK_RET_SUCCESS);
240}
241
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500242// read disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500243static void
244disk_1302(struct bregs *regs, u8 device)
245{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500246 basic_access(regs, device, ATA_CMD_READ_SECTORS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500247}
248
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500249// write disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500250static void
251disk_1303(struct bregs *regs, u8 device)
252{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500253 basic_access(regs, device, ATA_CMD_WRITE_SECTORS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500254}
255
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500256// verify disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500257static void
258disk_1304(struct bregs *regs, u8 device)
259{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500260 basic_access(regs, device, 0);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500261 // FIXME verify
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500262}
263
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500264// format disk track
265static void
266disk_1305(struct bregs *regs, u8 device)
267{
268 DISK_STUB(regs);
269}
270
271// read disk drive parameters
272static void
273disk_1308(struct bregs *regs, u8 device)
274{
275 // Get logical geometry from table
276 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
277 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
278 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
279 u16 count = GET_EBDA(ata.hdcount);
280
281 nlc = nlc - 2; /* 0 based , last sector not used */
282 regs->al = 0;
283 regs->ch = nlc & 0xff;
284 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
285 regs->dh = nlh - 1;
286 regs->dl = count; /* FIXME returns 0, 1, or n hard drives */
287
288 // FIXME should set ES & DI
289 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500290}
291
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500292// initialize drive parameters
293static void
294disk_1309(struct bregs *regs, u8 device)
295{
296 DISK_STUB(regs);
297}
298
299// seek to specified cylinder
300static void
301disk_130c(struct bregs *regs, u8 device)
302{
303 DISK_STUB(regs);
304}
305
306// alternate disk reset
307static void
308disk_130d(struct bregs *regs, u8 device)
309{
310 DISK_STUB(regs);
311}
312
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500313// check drive ready
314static void
315disk_1310(struct bregs *regs, u8 device)
316{
317 // should look at 40:8E also???
318
319 // Read the status from controller
320 u8 status = inb(GET_EBDA(ata.channels[device/2].iobase1) + ATA_CB_STAT);
321 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY )
322 disk_ret(regs, DISK_RET_SUCCESS);
323 else
324 disk_ret(regs, DISK_RET_ENOTREADY);
325}
326
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500327// recalibrate
328static void
329disk_1311(struct bregs *regs, u8 device)
330{
331 DISK_STUB(regs);
332}
333
334// controller internal diagnostic
335static void
336disk_1314(struct bregs *regs, u8 device)
337{
338 DISK_STUB(regs);
339}
340
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500341// read disk drive size
342static void
343disk_1315(struct bregs *regs, u8 device)
344{
345 // Get logical geometry from table
346 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
347 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
348 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
349
350 // Compute sector count seen by int13
351 u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
352 regs->cx = lba >> 16;
353 regs->dx = lba & 0xffff;
354
Kevin O'Connordcc7a4f2008-03-08 23:25:16 -0500355 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500356 regs->ah = 3; // hard disk accessible
357}
358
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500359// IBM/MS installation check
360static void
361disk_1341(struct bregs *regs, u8 device)
362{
363 regs->bx = 0xaa55; // install check
364 regs->cx = 0x0007; // ext disk access and edd, removable supported
365 disk_ret(regs, DISK_RET_SUCCESS);
366 regs->ah = 0x30; // EDD 3.0
367}
368
369// IBM/MS extended read
370static void
371disk_1342(struct bregs *regs, u8 device)
372{
373 extended_access(regs, device, ATA_CMD_READ_SECTORS);
374}
375
376// IBM/MS extended write
377static void
378disk_1343(struct bregs *regs, u8 device)
379{
380 extended_access(regs, device, ATA_CMD_WRITE_SECTORS);
381}
382
383// IBM/MS verify
384static void
385disk_1344(struct bregs *regs, u8 device)
386{
387 extended_access(regs, device, 0);
388}
389
390// IBM/MS lock/unlock drive
391static void
392disk_1345(struct bregs *regs, u8 device)
393{
394 // Always success for HD
395 disk_ret(regs, DISK_RET_SUCCESS);
396}
397
398// IBM/MS eject media
399static void
400disk_1346(struct bregs *regs, u8 device)
401{
402 // Volume Not Removable
403 disk_ret(regs, DISK_RET_ENOTREMOVABLE);
404}
405
406// IBM/MS extended seek
407static void
408disk_1347(struct bregs *regs, u8 device)
409{
410 extended_access(regs, device, 0);
411}
412
413// IBM/MS get drive parameters
414static void
415disk_1348(struct bregs *regs, u8 device)
416{
417 u16 size = GET_INT13DPT(regs, size);
418
419 // Buffer is too small
420 if (size < 0x1a) {
421 disk_ret(regs, DISK_RET_EPARAM);
422 return;
423 }
424
425 // EDD 1.x
426
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500427 u8 type = GET_EBDA(ata.devices[device].type);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500428 u16 npc = GET_EBDA(ata.devices[device].pchs.cylinders);
429 u16 nph = GET_EBDA(ata.devices[device].pchs.heads);
430 u16 npspt = GET_EBDA(ata.devices[device].pchs.spt);
431 u32 lba = GET_EBDA(ata.devices[device].sectors);
432 u16 blksize = GET_EBDA(ata.devices[device].blksize);
433
434 SET_INT13DPT(regs, size, 0x1a);
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500435 if (type == ATA_TYPE_ATA) {
436 if ((lba/npspt)/nph > 0x3fff) {
437 SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
438 SET_INT13DPT(regs, cylinders, 0x3fff);
439 } else {
440 SET_INT13DPT(regs, infos, 0x02); // geometry is valid
441 SET_INT13DPT(regs, cylinders, (u32)npc);
442 }
443 SET_INT13DPT(regs, heads, (u32)nph);
444 SET_INT13DPT(regs, spt, (u32)npspt);
445 SET_INT13DPT(regs, sector_count1, lba); // FIXME should be Bit64
446 SET_INT13DPT(regs, sector_count2, 0L);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500447 } else {
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500448 // ATAPI
449 // 0x74 = removable, media change, lockable, max values
450 SET_INT13DPT(regs, infos, 0x74);
451 SET_INT13DPT(regs, cylinders, 0xffffffff);
452 SET_INT13DPT(regs, heads, 0xffffffff);
453 SET_INT13DPT(regs, spt, 0xffffffff);
454 SET_INT13DPT(regs, sector_count1, 0xffffffff); // FIXME should be Bit64
455 SET_INT13DPT(regs, sector_count2, 0xffffffff);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500456 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500457 SET_INT13DPT(regs, blksize, blksize);
458
459 if (size < 0x1e) {
460 disk_ret(regs, DISK_RET_SUCCESS);
461 return;
462 }
463
464 // EDD 2.x
465
466 SET_INT13DPT(regs, size, 0x1e);
467
468 SET_INT13DPT(regs, dpte_segment, EBDA_SEG);
469 SET_INT13DPT(regs, dpte_offset
470 , offsetof(struct extended_bios_data_area_s, ata.dpte));
471
472 // Fill in dpte
473 u8 channel = device / 2;
474 u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1);
475 u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2);
476 u8 irq = GET_EBDA(ata.channels[channel].irq);
477 u8 mode = GET_EBDA(ata.devices[device].mode);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500478
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500479 u16 options;
480 if (type == ATA_TYPE_ATA) {
481 u8 translation = GET_EBDA(ata.devices[device].translation);
482 options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
483 options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
484 options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
485 } else {
486 // ATAPI
487 options = (1<<5); // removable device
488 options |= (1<<6); // atapi device
489 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500490 options |= (1<<4); // lba translation
491 options |= (mode==ATA_MODE_PIO32?1:0)<<7;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500492
493 SET_EBDA(ata.dpte.iobase1, iobase1);
494 SET_EBDA(ata.dpte.iobase2, iobase2 + ATA_CB_DC);
495 SET_EBDA(ata.dpte.prefix, (0xe | (device % 2))<<4 );
496 SET_EBDA(ata.dpte.unused, 0xcb );
497 SET_EBDA(ata.dpte.irq, irq );
498 SET_EBDA(ata.dpte.blkcount, 1 );
499 SET_EBDA(ata.dpte.dma, 0 );
500 SET_EBDA(ata.dpte.pio, 0 );
501 SET_EBDA(ata.dpte.options, options);
502 SET_EBDA(ata.dpte.reserved, 0);
503 if (size >= 0x42)
504 SET_EBDA(ata.dpte.revision, 0x11);
505 else
506 SET_EBDA(ata.dpte.revision, 0x10);
507
508 u8 sum = checksum_seg(EBDA_SEG
509 , offsetof(struct extended_bios_data_area_s, ata.dpte)
510 , 15);
511 SET_EBDA(ata.dpte.checksum, ~sum);
512
513 if (size < 0x42) {
514 disk_ret(regs, DISK_RET_SUCCESS);
515 return;
516 }
517
518 // EDD 3.x
519 channel = device / 2;
520 u8 iface = GET_EBDA(ata.channels[channel].iface);
521 iobase1 = GET_EBDA(ata.channels[channel].iobase1);
522
523 SET_INT13DPT(regs, size, 0x42);
524 SET_INT13DPT(regs, key, 0xbedd);
525 SET_INT13DPT(regs, dpi_length, 0x24);
526 SET_INT13DPT(regs, reserved1, 0);
527 SET_INT13DPT(regs, reserved2, 0);
528
529 if (iface==ATA_IFACE_ISA) {
530 SET_INT13DPT(regs, host_bus[0], 'I');
531 SET_INT13DPT(regs, host_bus[1], 'S');
532 SET_INT13DPT(regs, host_bus[2], 'A');
533 SET_INT13DPT(regs, host_bus[3], 0);
534 } else {
535 // FIXME PCI
536 }
537 SET_INT13DPT(regs, iface_type[0], 'A');
538 SET_INT13DPT(regs, iface_type[1], 'T');
539 SET_INT13DPT(regs, iface_type[2], 'A');
540 SET_INT13DPT(regs, iface_type[3], 0);
541
542 if (iface==ATA_IFACE_ISA) {
543 SET_INT13DPT(regs, iface_path[0], iobase1);
544 SET_INT13DPT(regs, iface_path[2], 0);
545 SET_INT13DPT(regs, iface_path[4], 0L);
546 } else {
547 // FIXME PCI
548 }
549 SET_INT13DPT(regs, device_path[0], device%2);
550 SET_INT13DPT(regs, device_path[1], 0);
551 SET_INT13DPT(regs, device_path[2], 0);
552 SET_INT13DPT(regs, device_path[4], 0L);
553
554 sum = checksum_seg(regs->ds, 30, 34);
555 SET_INT13DPT(regs, checksum, ~sum);
556}
557
558// IBM/MS extended media change
559static void
560disk_1349(struct bregs *regs, u8 device)
561{
562 // Always success for HD
563 disk_ret(regs, DISK_RET_SUCCESS);
564}
565
566static void
567disk_134e01(struct bregs *regs, u8 device)
568{
569 disk_ret(regs, DISK_RET_SUCCESS);
570}
571
572static void
573disk_134e03(struct bregs *regs, u8 device)
574{
575 disk_ret(regs, DISK_RET_SUCCESS);
576}
577
578static void
579disk_134e04(struct bregs *regs, u8 device)
580{
581 disk_ret(regs, DISK_RET_SUCCESS);
582}
583
584static void
585disk_134e06(struct bregs *regs, u8 device)
586{
587 disk_ret(regs, DISK_RET_SUCCESS);
588}
589
590static void
591disk_134eXX(struct bregs *regs, u8 device)
592{
593 debug_stub(regs);
594 disk_ret(regs, DISK_RET_EPARAM);
595}
596
597// IBM/MS set hardware configuration
598static void
599disk_134e(struct bregs *regs, u8 device)
600{
601 switch (regs->al) {
602 case 0x01: disk_134e01(regs, device); break;
603 case 0x03: disk_134e03(regs, device); break;
604 case 0x04: disk_134e04(regs, device); break;
605 case 0x06: disk_134e06(regs, device); break;
606 default: disk_134eXX(regs, device); break;
607 }
608}
609
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500610void
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500611disk_13XX(struct bregs *regs, u8 device)
612{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500613 debug_stub(regs);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500614 disk_ret(regs, DISK_RET_EPARAM);
615}
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500616
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500617void
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500618disk_13(struct bregs *regs, u8 device)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500619{
Kevin O'Connor15aee2e2008-03-01 13:34:04 -0500620 //debug_stub(regs);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500621
622 // clear completion flag
623 SET_BDA(disk_interrupt_flag, 0);
624
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500625 switch (regs->ah) {
626 case 0x00: disk_1300(regs, device); break;
627 case 0x01: disk_1301(regs, device); break;
628 case 0x02: disk_1302(regs, device); break;
629 case 0x03: disk_1303(regs, device); break;
630 case 0x04: disk_1304(regs, device); break;
631 case 0x05: disk_1305(regs, device); break;
632 case 0x08: disk_1308(regs, device); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500633 case 0x09: disk_1309(regs, device); break;
634 case 0x0c: disk_130c(regs, device); break;
635 case 0x0d: disk_130d(regs, device); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500636 case 0x10: disk_1310(regs, device); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500637 case 0x11: disk_1311(regs, device); break;
638 case 0x14: disk_1314(regs, device); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500639 case 0x15: disk_1315(regs, device); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500640 case 0x41: disk_1341(regs, device); break;
641 case 0x42: disk_1342(regs, device); break;
642 case 0x43: disk_1343(regs, device); break;
643 case 0x44: disk_1344(regs, device); break;
644 case 0x45: disk_1345(regs, device); break;
645 case 0x46: disk_1346(regs, device); break;
646 case 0x47: disk_1347(regs, device); break;
647 case 0x48: disk_1348(regs, device); break;
648 case 0x49: disk_1349(regs, device); break;
649 case 0x4e: disk_134e(regs, device); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500650 default: disk_13XX(regs, device); break;
651 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500652}
653
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500654
655/****************************************************************
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500656 * Entry points
657 ****************************************************************/
658
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500659static u8
Kevin O'Connor180a9592008-03-04 22:50:53 -0500660get_device(struct bregs *regs, u8 iscd, u8 drive)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500661{
662 // basic check : device has to be defined
663 if (drive >= CONFIG_MAX_ATA_DEVICES) {
664 disk_ret(regs, DISK_RET_EPARAM);
665 return CONFIG_MAX_ATA_DEVICES;
666 }
667
668 // Get the ata channel
Kevin O'Connor180a9592008-03-04 22:50:53 -0500669 u8 device = GET_EBDA(ata.idmap[iscd][drive]);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500670
671 // basic check : device has to be valid
672 if (device >= CONFIG_MAX_ATA_DEVICES) {
673 disk_ret(regs, DISK_RET_EPARAM);
674 return CONFIG_MAX_ATA_DEVICES;
675 }
676
677 return device;
678}
679
680static void
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500681handle_legacy_disk(struct bregs *regs, u8 drive)
682{
683 if (drive < 0x80) {
684 floppy_13(regs, drive);
685 return;
686 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500687
688 if (! CONFIG_ATA) {
689 // XXX - old code had other disk access method.
690 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500691 return;
692 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500693
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500694 if (drive >= 0xe0) {
Kevin O'Connor180a9592008-03-04 22:50:53 -0500695 u8 device = get_device(regs, 1, drive - 0xe0);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500696 if (device >= CONFIG_MAX_ATA_DEVICES)
697 return;
698 cdrom_13(regs, device);
699 return;
700 }
701
Kevin O'Connor180a9592008-03-04 22:50:53 -0500702 u8 device = get_device(regs, 0, drive - 0x80);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500703 if (device >= CONFIG_MAX_ATA_DEVICES)
704 return;
705 disk_13(regs, device);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500706}
707
Kevin O'Connor19786762008-03-05 21:09:59 -0500708void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500709handle_40(struct bregs *regs)
710{
711 debug_enter(regs);
712 handle_legacy_disk(regs, regs->dl);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500713}
714
715// INT 13h Fixed Disk Services Entry Point
Kevin O'Connor19786762008-03-05 21:09:59 -0500716void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500717handle_13(struct bregs *regs)
718{
Kevin O'Connor127cbd72008-03-08 11:34:28 -0500719 //debug_enter(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500720 u8 drive = regs->dl;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500721
Kevin O'Connor180a9592008-03-04 22:50:53 -0500722 if (CONFIG_CDROM_BOOT) {
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500723 if (regs->ah == 0x4b) {
724 cdemu_134b(regs);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400725 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500726 }
727 if (GET_EBDA(cdemu.active)) {
728 if (drive == GET_EBDA(cdemu.emulated_drive)) {
729 cdemu_13(regs);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400730 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500731 }
Kevin O'Connor180a9592008-03-04 22:50:53 -0500732 if (drive < 0xe0)
733 drive--;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500734 }
735 }
736 handle_legacy_disk(regs, drive);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500737}
738
739// record completion in BIOS task complete flag
Kevin O'Connor19786762008-03-05 21:09:59 -0500740void VISIBLE16
Kevin O'Connored128492008-03-11 11:14:59 -0400741handle_76()
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500742{
Kevin O'Connored128492008-03-11 11:14:59 -0400743 debug_isr();
744 SET_BDA(disk_interrupt_flag, 0xff);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500745 eoi_both_pics();
746}