blob: f7bfe9c523ef16104c65c1fc4a5902e25778c3c7 [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//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05007
8#include "disk.h" // floppy_13
Kevin O'Connor9521e262008-07-04 13:04:29 -04009#include "biosvar.h" // SET_BDA
Kevin O'Connor3491e8b2008-02-29 00:22:27 -050010#include "config.h" // CONFIG_*
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050011#include "util.h" // debug_enter
Kevin O'Connorf54c1502008-06-14 15:56:16 -040012#include "pic.h" // eoi_pic2
Kevin O'Connor9521e262008-07-04 13:04:29 -040013#include "bregs.h" // struct bregs
Kevin O'Connor53236cc2008-08-31 11:16:33 -040014#include "pci.h" // pci_bdf_to_bus
Kevin O'Connorc892b132009-08-11 21:59:37 -040015#include "ata.h" // ATA_CB_DC
Kevin O'Connor3491e8b2008-02-29 00:22:27 -050016
Kevin O'Connorb74102d2008-03-03 21:57:30 -050017
18/****************************************************************
19 * Helper functions
20 ****************************************************************/
21
Kevin O'Connor567e4e32008-04-05 11:37:51 -040022void
Kevin O'Connor05600342009-01-02 13:10:58 -050023__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connor567e4e32008-04-05 11:37:51 -040024{
Kevin O'Connor05600342009-01-02 13:10:58 -050025 u8 code = linecode;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -040026 if (regs->dl < EXTSTART_HD)
Kevin O'Connor48410fd2009-08-16 14:13:36 -040027 SET_BDA(floppy_last_status, code);
28 else
29 SET_BDA(disk_last_status, code);
Kevin O'Connor567e4e32008-04-05 11:37:51 -040030 if (code)
Kevin O'Connordfefeb52009-12-13 13:04:17 -050031 __set_code_invalid(regs, linecode, fname);
Kevin O'Connor567e4e32008-04-05 11:37:51 -040032 else
33 set_code_success(regs);
34}
35
Kevin O'Connordfefeb52009-12-13 13:04:17 -050036void
37__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
38{
39 u8 code = linecode;
40 if (regs->dl < EXTSTART_HD)
41 SET_BDA(floppy_last_status, code);
42 else
43 SET_BDA(disk_last_status, code);
44 __set_code_unimplemented(regs, linecode, fname);
45}
46
Kevin O'Connor567e4e32008-04-05 11:37:51 -040047static void
Kevin O'Connor05600342009-01-02 13:10:58 -050048__disk_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor567e4e32008-04-05 11:37:51 -040049{
Kevin O'Connordfefeb52009-12-13 13:04:17 -050050 __warn_unimplemented(regs, lineno, fname);
Kevin O'Connor05600342009-01-02 13:10:58 -050051 __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
Kevin O'Connor567e4e32008-04-05 11:37:51 -040052}
53
Kevin O'Connor05600342009-01-02 13:10:58 -050054#define DISK_STUB(regs) \
55 __disk_stub((regs), __LINE__, __func__)
Kevin O'Connore43df9e2008-03-01 22:16:32 -050056
Kevin O'Connor5c99b6c2009-12-30 12:36:22 -050057// Get the cylinders/heads/sectors for the given drive.
Kevin O'Connor36c93a52009-09-12 19:35:04 -040058static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -040059fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
Kevin O'Connore43df9e2008-03-01 22:16:32 -050060{
Kevin O'Connor8f469b92010-02-28 01:28:11 -050061 if (CONFIG_CDROM_EMU
62 && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) {
Kevin O'Connor36c93a52009-09-12 19:35:04 -040063 // Emulated drive - get info from ebda. (It's not possible to
64 // populate the geometry directly in the driveid because the
65 // geometry is only known after the bios segment is made
66 // read-only).
67 u16 ebda_seg = get_ebda_seg();
68 *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
69 *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
70 *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
71 return;
Kevin O'Connor0cdac0e2008-03-29 12:45:53 -040072 }
Kevin O'Connor77d227b2009-10-22 21:48:39 -040073 *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
74 *nlh = GET_GLOBAL(drive_g->lchs.heads);
75 *nlspt = GET_GLOBAL(drive_g->lchs.spt);
Kevin O'Connor1625a752009-08-09 13:08:21 -040076}
77
78// Perform read/write/verify using old-style chs accesses
79static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -040080basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
Kevin O'Connor1625a752009-08-09 13:08:21 -040081{
82 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -040083 dop.drive_g = drive_g;
Kevin O'Connor1625a752009-08-09 13:08:21 -040084 dop.command = command;
Kevin O'Connor36c93a52009-09-12 19:35:04 -040085
86 u8 count = regs->al;
87 u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
88 u16 sector = regs->cl & 0x3f;
89 u16 head = regs->dh;
90
91 if (count > 128 || count == 0 || sector == 0) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -050092 warn_invalid(regs);
Kevin O'Connor36c93a52009-09-12 19:35:04 -040093 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connor1625a752009-08-09 13:08:21 -040094 return;
Kevin O'Connor36c93a52009-09-12 19:35:04 -040095 }
96 dop.count = count;
97
98 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -040099 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400100
101 // sanity check on cyl heads, sec
102 if (cylinder >= nlc || head >= nlh || sector > nlspt) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500103 warn_invalid(regs);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400104 disk_ret(regs, DISK_RET_EPARAM);
105 return;
106 }
107
108 // translate lchs to lba
109 dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
110 + (u32)sector - 1);
111
Kevin O'Connorb68ac712009-08-09 17:25:19 -0400112 dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400113
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500114 int status = send_disk_op(&dop);
Kevin O'Connor74799df2008-03-12 20:49:07 -0400115
Kevin O'Connor1625a752009-08-09 13:08:21 -0400116 regs->al = dop.count;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500117
Kevin O'Connor126eac62009-08-16 13:32:24 -0400118 disk_ret(regs, status);
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500119}
120
Kevin O'Connor1625a752009-08-09 13:08:21 -0400121// Perform read/write/verify using new-style "int13ext" accesses.
Kevin O'Connored128492008-03-11 11:14:59 -0400122static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400123extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500124{
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500125 struct disk_op_s dop;
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400126 // Get lba and check.
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500127 dop.lba = GET_INT13EXT(regs, lba);
128 dop.command = command;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400129 dop.drive_g = drive_g;
130 if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500131 warn_invalid(regs);
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400132 disk_ret(regs, DISK_RET_EPARAM);
133 return;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500134 }
135
Kevin O'Connor9f985422009-09-09 11:34:39 -0400136 dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500137 dop.count = GET_INT13EXT(regs, count);
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400138
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500139 int status = send_disk_op(&dop);
Kevin O'Connor74799df2008-03-12 20:49:07 -0400140
Kevin O'Connor1625a752009-08-09 13:08:21 -0400141 SET_INT13EXT(regs, count, dop.count);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500142
Kevin O'Connor126eac62009-08-16 13:32:24 -0400143 disk_ret(regs, status);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500144}
145
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500146
147/****************************************************************
148 * Hard Drive functions
149 ****************************************************************/
150
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500151// disk controller reset
152static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400153disk_1300(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500154{
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400155 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400156 dop.drive_g = drive_g;
Kevin O'Connor3f6c2782009-08-09 19:17:11 -0400157 dop.command = CMD_RESET;
Kevin O'Connor126eac62009-08-16 13:32:24 -0400158 int status = send_disk_op(&dop);
159 disk_ret(regs, status);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500160}
161
162// read disk status
163static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400164disk_1301(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500165{
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400166 u8 v;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400167 if (regs->dl < EXTSTART_HD)
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400168 // Floppy
169 v = GET_BDA(floppy_last_status);
170 else
171 v = GET_BDA(disk_last_status);
Kevin O'Connorfad2da82008-03-22 20:37:44 -0400172 regs->ah = v;
173 set_cf(regs, v);
174 // XXX - clear disk_last_status?
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500175}
176
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500177// read disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500178static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400179disk_1302(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500180{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400181 basic_access(regs, drive_g, CMD_READ);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500182}
183
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500184// write disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500185static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400186disk_1303(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500187{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400188 basic_access(regs, drive_g, CMD_WRITE);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500189}
190
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500191// verify disk sectors
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500192static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400193disk_1304(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500194{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400195 basic_access(regs, drive_g, CMD_VERIFY);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500196}
197
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500198// format disk track
199static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400200disk_1305(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500201{
Kevin O'Connor4d9d4002009-11-25 19:35:01 -0500202 debug_stub(regs);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400203
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400204 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400205 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400206
207 u8 num_sectors = regs->al;
208 u8 head = regs->dh;
209
210 if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
211 disk_ret(regs, DISK_RET_EPARAM);
212 return;
213 }
214
215 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400216 dop.drive_g = drive_g;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400217 dop.command = CMD_FORMAT;
218 dop.lba = head;
219 dop.count = num_sectors;
220 dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
221 int status = send_disk_op(&dop);
222 disk_ret(regs, status);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500223}
224
225// read disk drive parameters
226static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400227disk_1308(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500228{
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400229 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500230 // Get logical geometry from table
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400231 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400232 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400233 nlc--;
234 nlh--;
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400235 u8 count;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400236 if (regs->dl < EXTSTART_HD) {
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400237 // Floppy
Kevin O'Connora0842f82010-12-29 11:05:46 -0500238 count = GET_GLOBAL(FloppyCount);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500239
Kevin O'Connor8f469b92010-02-28 01:28:11 -0500240 if (CONFIG_CDROM_EMU
241 && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf)))
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400242 regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
243 else
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400244 regs->bx = GET_GLOBAL(drive_g->floppy_type);
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400245
246 // set es & di to point to 11 byte diskette param table in ROM
247 regs->es = SEG_BIOS;
248 regs->di = (u32)&diskette_param_table2;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400249 } else if (regs->dl < EXTSTART_CD) {
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400250 // Hard drive
251 count = GET_BDA(hdcount);
252 nlc--; // last sector reserved
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400253 } else {
254 // Not supported on CDROM
255 disk_ret(regs, DISK_RET_EPARAM);
256 return;
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400257 }
258
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400259 if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
260 u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
261 if (((emudrive ^ regs->dl) & 0x80) == 0)
262 // Note extra drive due to emulation.
263 count++;
264 if (regs->dl < EXTSTART_HD && count > 2)
265 // Max of two floppy drives.
266 count = 2;
267 }
268
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500269 regs->al = 0;
270 regs->ch = nlc & 0xff;
271 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400272 regs->dh = nlh;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500273
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500274 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400275 regs->dl = count;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500276}
277
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500278// initialize drive parameters
279static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400280disk_1309(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500281{
282 DISK_STUB(regs);
283}
284
285// seek to specified cylinder
286static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400287disk_130c(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500288{
289 DISK_STUB(regs);
290}
291
292// alternate disk reset
293static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400294disk_130d(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500295{
296 DISK_STUB(regs);
297}
298
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500299// check drive ready
300static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400301disk_1310(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500302{
303 // should look at 40:8E also???
304
Kevin O'Connor42337662009-08-10 00:06:37 -0400305 struct disk_op_s dop;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400306 dop.drive_g = drive_g;
Kevin O'Connor42337662009-08-10 00:06:37 -0400307 dop.command = CMD_ISREADY;
308 int status = send_disk_op(&dop);
Kevin O'Connor126eac62009-08-16 13:32:24 -0400309 disk_ret(regs, status);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500310}
311
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500312// recalibrate
313static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400314disk_1311(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500315{
316 DISK_STUB(regs);
317}
318
319// controller internal diagnostic
320static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400321disk_1314(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500322{
323 DISK_STUB(regs);
324}
325
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500326// read disk drive size
327static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400328disk_1315(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500329{
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400330 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400331 if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
332 // Floppy or cdrom
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400333 regs->ah = 1;
334 return;
335 }
336 // Hard drive
337
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500338 // Get logical geometry from table
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400339 u16 nlc, nlh, nlspt;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400340 fillLCHS(drive_g, &nlc, &nlh, &nlspt);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500341
342 // Compute sector count seen by int13
343 u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
344 regs->cx = lba >> 16;
345 regs->dx = lba & 0xffff;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500346 regs->ah = 3; // hard disk accessible
347}
348
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400349static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400350disk_1316(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400351{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400352 if (regs->dl >= EXTSTART_HD) {
Kevin O'Connor48410fd2009-08-16 14:13:36 -0400353 // Hard drive
354 disk_ret(regs, DISK_RET_EPARAM);
355 return;
356 }
357 disk_ret(regs, DISK_RET_ECHANGED);
358}
359
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500360// IBM/MS installation check
361static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400362disk_1341(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500363{
364 regs->bx = 0xaa55; // install check
365 regs->cx = 0x0007; // ext disk access and edd, removable supported
366 disk_ret(regs, DISK_RET_SUCCESS);
367 regs->ah = 0x30; // EDD 3.0
368}
369
370// IBM/MS extended read
371static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400372disk_1342(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500373{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400374 extended_access(regs, drive_g, CMD_READ);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500375}
376
377// IBM/MS extended write
378static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400379disk_1343(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500380{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400381 extended_access(regs, drive_g, CMD_WRITE);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500382}
383
384// IBM/MS verify
385static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400386disk_1344(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500387{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400388 extended_access(regs, drive_g, CMD_VERIFY);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500389}
390
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400391// lock
392static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400393disk_134500(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400394{
395 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400396 int cdid = regs->dl - EXTSTART_CD;
397 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400398 if (locks == 0xff) {
399 regs->al = 1;
400 disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
401 return;
402 }
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400403 SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400404 regs->al = 1;
405 disk_ret(regs, DISK_RET_SUCCESS);
406}
407
408// unlock
409static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400410disk_134501(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400411{
412 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400413 int cdid = regs->dl - EXTSTART_CD;
414 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400415 if (locks == 0x00) {
416 regs->al = 0;
417 disk_ret(regs, DISK_RET_ENOTLOCKED);
418 return;
419 }
420 locks--;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400421 SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400422 regs->al = (locks ? 1 : 0);
423 disk_ret(regs, DISK_RET_SUCCESS);
424}
425
426// status
427static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400428disk_134502(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400429{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400430 int cdid = regs->dl - EXTSTART_CD;
431 u8 locks = GET_EBDA(cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400432 regs->al = (locks ? 1 : 0);
433 disk_ret(regs, DISK_RET_SUCCESS);
434}
435
436static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400437disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400438{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500439 disk_ret_unimplemented(regs, DISK_RET_EPARAM);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400440}
441
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500442// IBM/MS lock/unlock drive
443static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400444disk_1345(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500445{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400446 if (regs->dl < EXTSTART_CD) {
447 // Always success for HD
448 disk_ret(regs, DISK_RET_SUCCESS);
449 return;
450 }
451
452 switch (regs->al) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400453 case 0x00: disk_134500(regs, drive_g); break;
454 case 0x01: disk_134501(regs, drive_g); break;
455 case 0x02: disk_134502(regs, drive_g); break;
456 default: disk_1345XX(regs, drive_g); break;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400457 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500458}
459
460// IBM/MS eject media
461static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400462disk_1346(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500463{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400464 if (regs->dl < EXTSTART_CD) {
465 // Volume Not Removable
466 disk_ret(regs, DISK_RET_ENOTREMOVABLE);
467 return;
468 }
469
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400470 int cdid = regs->dl - EXTSTART_CD;
471 u8 locks = GET_EBDA(cdrom_locks[cdid]);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400472 if (locks != 0) {
473 disk_ret(regs, DISK_RET_ELOCKED);
474 return;
475 }
476
477 // FIXME should handle 0x31 no media in device
478 // FIXME should handle 0xb5 valid request failed
479
480 // Call removable media eject
481 struct bregs br;
482 memset(&br, 0, sizeof(br));
483 br.ah = 0x52;
Kevin O'Connor74152702010-03-20 17:53:40 -0400484 br.dl = regs->dl;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400485 call16_int(0x15, &br);
486
487 if (br.ah || br.flags & F_CF) {
488 disk_ret(regs, DISK_RET_ELOCKED);
489 return;
490 }
491 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500492}
493
494// IBM/MS extended seek
495static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400496disk_1347(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500497{
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400498 extended_access(regs, drive_g, CMD_SEEK);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500499}
500
501// IBM/MS get drive parameters
502static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400503disk_1348(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500504{
505 u16 size = GET_INT13DPT(regs, size);
506
507 // Buffer is too small
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400508 if (size < 26) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500509 disk_ret(regs, DISK_RET_EPARAM);
510 return;
511 }
512
513 // EDD 1.x
514
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400515 u8 type = GET_GLOBAL(drive_g->type);
516 u16 npc = GET_GLOBAL(drive_g->pchs.cylinders);
517 u16 nph = GET_GLOBAL(drive_g->pchs.heads);
518 u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
519 u64 lba = GET_GLOBAL(drive_g->sectors);
520 u16 blksize = GET_GLOBAL(drive_g->blksize);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500521
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400522 dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
523 , size, type, npc, nph, npspt, (u32)lba, blksize);
524
525 SET_INT13DPT(regs, size, 26);
Kevin O'Connorb1144362009-08-11 20:43:38 -0400526 if (type == DTYPE_ATAPI) {
527 // 0x74 = removable, media change, lockable, max values
528 SET_INT13DPT(regs, infos, 0x74);
529 SET_INT13DPT(regs, cylinders, 0xffffffff);
530 SET_INT13DPT(regs, heads, 0xffffffff);
531 SET_INT13DPT(regs, spt, 0xffffffff);
532 SET_INT13DPT(regs, sector_count, (u64)-1);
533 } else {
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400534 if (lba > (u64)npspt*nph*0x3fff) {
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500535 SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
536 SET_INT13DPT(regs, cylinders, 0x3fff);
537 } else {
538 SET_INT13DPT(regs, infos, 0x02); // geometry is valid
539 SET_INT13DPT(regs, cylinders, (u32)npc);
540 }
541 SET_INT13DPT(regs, heads, (u32)nph);
542 SET_INT13DPT(regs, spt, (u32)npspt);
Kevin O'Connor1bb3b5c2008-05-14 00:43:13 -0400543 SET_INT13DPT(regs, sector_count, lba);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500544 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500545 SET_INT13DPT(regs, blksize, blksize);
546
Gleb Natapovf77e1792010-12-23 11:29:35 +0200547 if (size < 30 ||
548 (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500549 disk_ret(regs, DISK_RET_SUCCESS);
550 return;
551 }
552
553 // EDD 2.x
554
Gleb Natapovf77e1792010-12-23 11:29:35 +0200555 int bdf;
556 u16 iobase1;
557 u64 device_path;
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400558 SET_INT13DPT(regs, size, 30);
Gleb Natapovf77e1792010-12-23 11:29:35 +0200559 if (type == DTYPE_ATA || type == DTYPE_ATAPI) {
560 u16 ebda_seg = get_ebda_seg();
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500561
Gleb Natapovf77e1792010-12-23 11:29:35 +0200562 SET_INT13DPT(regs, dpte_segment, ebda_seg);
563 SET_INT13DPT(regs, dpte_offset
564 , offsetof(struct extended_bios_data_area_s, dpte));
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500565
Gleb Natapovf77e1792010-12-23 11:29:35 +0200566 // Fill in dpte
567 struct atadrive_s *adrive_g = container_of(
568 drive_g, struct atadrive_s, drive);
569 struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
570 u8 slave = GET_GLOBAL(adrive_g->slave);
571 u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
572 u8 irq = GET_GLOBALFLAT(chan_gf->irq);
573 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
574 bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
575 device_path = slave;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500576
Gleb Natapovf77e1792010-12-23 11:29:35 +0200577 u16 options = 0;
578 if (type == DTYPE_ATA) {
579 u8 translation = GET_GLOBAL(drive_g->translation);
580 if (translation != TRANSLATION_NONE) {
581 options |= 1<<3; // CHS translation
582 if (translation == TRANSLATION_LBA)
583 options |= 1<<9;
584 if (translation == TRANSLATION_RECHS)
585 options |= 3<<9;
586 }
587 } else {
588 // ATAPI
589 options |= 1<<5; // removable device
590 options |= 1<<6; // atapi device
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400591 }
Gleb Natapovf77e1792010-12-23 11:29:35 +0200592 options |= 1<<4; // lba translation
593 if (CONFIG_ATA_PIO32)
594 options |= 1<<7;
595
596 SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
597 SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
598 SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
599 | ATA_CB_DH_LBA));
600 SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
601 SET_EBDA2(ebda_seg, dpte.irq, irq);
602 SET_EBDA2(ebda_seg, dpte.blkcount, 1);
603 SET_EBDA2(ebda_seg, dpte.dma, 0);
604 SET_EBDA2(ebda_seg, dpte.pio, 0);
605 SET_EBDA2(ebda_seg, dpte.options, options);
606 SET_EBDA2(ebda_seg, dpte.reserved, 0);
607 SET_EBDA2(ebda_seg, dpte.revision, 0x11);
608
609 u8 sum = checksum_far(
610 ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
611 SET_EBDA2(ebda_seg, dpte.checksum, -sum);
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500612 } else {
Gleb Natapovf77e1792010-12-23 11:29:35 +0200613 SET_INT13DPT(regs, dpte_segment, 0);
614 SET_INT13DPT(regs, dpte_offset, 0);
615 bdf = GET_GLOBAL(drive_g->cntl_id);
616 device_path = 0;
617 iobase1 = 0;
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500618 }
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500619
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400620 if (size < 66) {
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500621 disk_ret(regs, DISK_RET_SUCCESS);
622 return;
623 }
624
625 // EDD 3.x
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500626 SET_INT13DPT(regs, key, 0xbedd);
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400627 SET_INT13DPT(regs, dpi_length, 36);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500628 SET_INT13DPT(regs, reserved1, 0);
629 SET_INT13DPT(regs, reserved2, 0);
630
Kevin O'Connor4ccb2312009-12-05 11:25:09 -0500631 if (bdf != -1) {
632 SET_INT13DPT(regs, host_bus[0], 'P');
633 SET_INT13DPT(regs, host_bus[1], 'C');
634 SET_INT13DPT(regs, host_bus[2], 'I');
635 SET_INT13DPT(regs, host_bus[3], 0);
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400636
Kevin O'Connor4ccb2312009-12-05 11:25:09 -0500637 u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
638 | (pci_bdf_to_fn(bdf) << 16));
639 SET_INT13DPT(regs, iface_path, path);
640 } else {
641 // ISA
642 SET_INT13DPT(regs, host_bus[0], 'I');
643 SET_INT13DPT(regs, host_bus[1], 'S');
644 SET_INT13DPT(regs, host_bus[2], 'A');
645 SET_INT13DPT(regs, host_bus[3], 0);
646
647 SET_INT13DPT(regs, iface_path, iobase1);
648 }
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400649
Gleb Natapovf77e1792010-12-23 11:29:35 +0200650 if (type != DTYPE_VIRTIO) {
651 SET_INT13DPT(regs, iface_type[0], 'A');
652 SET_INT13DPT(regs, iface_type[1], 'T');
653 SET_INT13DPT(regs, iface_type[2], 'A');
654 SET_INT13DPT(regs, iface_type[3], 0);
655 } else {
656 SET_INT13DPT(regs, iface_type[0], 'S');
657 SET_INT13DPT(regs, iface_type[1], 'C');
658 SET_INT13DPT(regs, iface_type[2], 'S');
659 SET_INT13DPT(regs, iface_type[3], 'I');
660 }
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400661 SET_INT13DPT(regs, iface_type[4], 0);
662 SET_INT13DPT(regs, iface_type[5], 0);
663 SET_INT13DPT(regs, iface_type[6], 0);
664 SET_INT13DPT(regs, iface_type[7], 0);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500665
Gleb Natapovf77e1792010-12-23 11:29:35 +0200666 SET_INT13DPT(regs, device_path, device_path);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500667
Kevin O'Connor7d108212009-01-21 19:13:21 -0500668 SET_INT13DPT(regs, checksum
669 , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
Kevin O'Connor53236cc2008-08-31 11:16:33 -0400670
671 disk_ret(regs, DISK_RET_SUCCESS);
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500672}
673
674// IBM/MS extended media change
675static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400676disk_1349(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500677{
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400678 if (regs->dl < EXTSTART_CD) {
679 // Always success for HD
680 disk_ret(regs, DISK_RET_SUCCESS);
681 return;
682 }
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500683 set_invalid(regs);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400684 // always send changed ??
685 regs->ah = DISK_RET_ECHANGED;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500686}
687
688static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400689disk_134e01(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500690{
691 disk_ret(regs, DISK_RET_SUCCESS);
692}
693
694static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400695disk_134e03(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500696{
697 disk_ret(regs, DISK_RET_SUCCESS);
698}
699
700static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400701disk_134e04(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500702{
703 disk_ret(regs, DISK_RET_SUCCESS);
704}
705
706static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400707disk_134e06(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500708{
709 disk_ret(regs, DISK_RET_SUCCESS);
710}
711
712static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400713disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500714{
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500715 disk_ret(regs, DISK_RET_EPARAM);
716}
717
718// IBM/MS set hardware configuration
719static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400720disk_134e(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500721{
722 switch (regs->al) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400723 case 0x01: disk_134e01(regs, drive_g); break;
724 case 0x03: disk_134e03(regs, drive_g); break;
725 case 0x04: disk_134e04(regs, drive_g); break;
726 case 0x06: disk_134e06(regs, drive_g); break;
727 default: disk_134eXX(regs, drive_g); break;
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500728 }
729}
730
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400731static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400732disk_13XX(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500733{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500734 disk_ret_unimplemented(regs, DISK_RET_EPARAM);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500735}
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500736
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400737static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400738disk_13(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500739{
Kevin O'Connor15aee2e2008-03-01 13:34:04 -0500740 //debug_stub(regs);
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500741
742 // clear completion flag
743 SET_BDA(disk_interrupt_flag, 0);
744
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500745 switch (regs->ah) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400746 case 0x00: disk_1300(regs, drive_g); break;
747 case 0x01: disk_1301(regs, drive_g); break;
748 case 0x02: disk_1302(regs, drive_g); break;
749 case 0x03: disk_1303(regs, drive_g); break;
750 case 0x04: disk_1304(regs, drive_g); break;
751 case 0x05: disk_1305(regs, drive_g); break;
752 case 0x08: disk_1308(regs, drive_g); break;
753 case 0x09: disk_1309(regs, drive_g); break;
754 case 0x0c: disk_130c(regs, drive_g); break;
755 case 0x0d: disk_130d(regs, drive_g); break;
756 case 0x10: disk_1310(regs, drive_g); break;
757 case 0x11: disk_1311(regs, drive_g); break;
758 case 0x14: disk_1314(regs, drive_g); break;
759 case 0x15: disk_1315(regs, drive_g); break;
760 case 0x16: disk_1316(regs, drive_g); break;
761 case 0x41: disk_1341(regs, drive_g); break;
762 case 0x42: disk_1342(regs, drive_g); break;
763 case 0x43: disk_1343(regs, drive_g); break;
764 case 0x44: disk_1344(regs, drive_g); break;
765 case 0x45: disk_1345(regs, drive_g); break;
766 case 0x46: disk_1346(regs, drive_g); break;
767 case 0x47: disk_1347(regs, drive_g); break;
768 case 0x48: disk_1348(regs, drive_g); break;
769 case 0x49: disk_1349(regs, drive_g); break;
770 case 0x4e: disk_134e(regs, drive_g); break;
771 default: disk_13XX(regs, drive_g); break;
Kevin O'Connor3491e8b2008-02-29 00:22:27 -0500772 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500773}
774
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400775static void
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400776floppy_13(struct bregs *regs, struct drive_s *drive_g)
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400777{
778 // Only limited commands are supported on floppies.
779 switch (regs->ah) {
780 case 0x00:
781 case 0x01:
782 case 0x02:
783 case 0x03:
784 case 0x04:
785 case 0x05:
786 case 0x08:
787 case 0x15:
788 case 0x16:
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400789 disk_13(regs, drive_g);
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400790 break;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400791 default: disk_13XX(regs, drive_g); break;
Kevin O'Connoraf5aabb2009-08-16 18:48:38 -0400792 }
793}
794
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500795
796/****************************************************************
Kevin O'Connorb74102d2008-03-03 21:57:30 -0500797 * Entry points
798 ****************************************************************/
799
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500800static void
Kevin O'Connor707298a2009-08-11 22:27:51 -0400801handle_legacy_disk(struct bregs *regs, u8 extdrive)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500802{
Kevin O'Connorc892b132009-08-11 21:59:37 -0400803 if (! CONFIG_DRIVES) {
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400804 // XXX - support handle_1301 anyway?
Kevin O'Connore43df9e2008-03-01 22:16:32 -0500805 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500806 return;
807 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500808
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400809 if (extdrive < EXTSTART_HD) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400810 struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
811 if (!drive_g)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400812 goto fail;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400813 floppy_13(regs, drive_g);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400814 return;
815 }
816
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400817 struct drive_s *drive_g;
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400818 if (extdrive >= EXTSTART_CD)
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400819 drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400820 else
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400821 drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
822 if (!drive_g)
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400823 goto fail;
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400824 disk_13(regs, drive_g);
Kevin O'Connor0a0e42e2009-08-16 12:09:44 -0400825 return;
826
827fail:
828 // XXX - support 1301/1308/1315 anyway?
829 disk_ret(regs, DISK_RET_EPARAM);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500830}
831
Kevin O'Connor19786762008-03-05 21:09:59 -0500832void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500833handle_40(struct bregs *regs)
834{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400835 debug_enter(regs, DEBUG_HDL_40);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500836 handle_legacy_disk(regs, regs->dl);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500837}
838
839// INT 13h Fixed Disk Services Entry Point
Kevin O'Connor19786762008-03-05 21:09:59 -0500840void VISIBLE16
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500841handle_13(struct bregs *regs)
842{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400843 debug_enter(regs, DEBUG_HDL_13);
Kevin O'Connor707298a2009-08-11 22:27:51 -0400844 u8 extdrive = regs->dl;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500845
Kevin O'Connordfa16502008-03-22 20:13:08 -0400846 if (CONFIG_CDROM_EMU) {
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500847 if (regs->ah == 0x4b) {
848 cdemu_134b(regs);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400849 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500850 }
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500851 u16 ebda_seg = get_ebda_seg();
852 if (GET_EBDA2(ebda_seg, cdemu.active)) {
Kevin O'Connor669e6442009-08-11 22:36:30 -0400853 u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
Kevin O'Connor707298a2009-08-11 22:27:51 -0400854 if (extdrive == emudrive) {
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400855 // Access to an emulated drive.
Kevin O'Connor8f469b92010-02-28 01:28:11 -0500856 struct drive_s *cdemu_g;
857 cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf));
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400858 if (regs->ah > 0x16) {
859 // Only old-style commands supported.
Kevin O'Connor8f469b92010-02-28 01:28:11 -0500860 disk_13XX(regs, cdemu_g);
Kevin O'Connor36c93a52009-09-12 19:35:04 -0400861 return;
862 }
Kevin O'Connor8f469b92010-02-28 01:28:11 -0500863 disk_13(regs, cdemu_g);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400864 return;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500865 }
Kevin O'Connor51cfbe72009-08-18 22:38:49 -0400866 if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
Kevin O'Connor77d227b2009-10-22 21:48:39 -0400867 // Adjust id to make room for emulated drive.
Kevin O'Connor707298a2009-08-11 22:27:51 -0400868 extdrive--;
Kevin O'Connor941d3e42008-03-04 19:45:04 -0500869 }
870 }
Kevin O'Connor707298a2009-08-11 22:27:51 -0400871 handle_legacy_disk(regs, extdrive);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500872}
873
874// record completion in BIOS task complete flag
Kevin O'Connor19786762008-03-05 21:09:59 -0500875void VISIBLE16
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500876handle_76(void)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500877{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400878 debug_isr(DEBUG_ISR_76);
Kevin O'Connored128492008-03-11 11:14:59 -0400879 SET_BDA(disk_interrupt_flag, 0xff);
Kevin O'Connorf54c1502008-06-14 15:56:16 -0400880 eoi_pic2();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500881}
Kevin O'Connor30853762009-01-17 18:49:20 -0500882
883// Old Fixed Disk Parameter Table (newer tables are in the ebda).
884struct fdpt_s OldFDPT VAR16FIXED(0xe401);