blob: ece77a064660d7b747efa0c1b9613a3fd5b3af7b [file] [log] [blame]
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -05001// 16bit code to access cdrom 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'Connor31d8c8a2008-03-04 19:56:41 -05007
8#include "disk.h" // cdrom_13
9#include "util.h" // memset
Kevin O'Connor9521e262008-07-04 13:04:29 -040010#include "bregs.h" // struct bregs
11#include "biosvar.h" // GET_EBDA
Kevin O'Connor4524bf72008-12-31 00:31:03 -050012#include "atabits.h" // ATA_TYPE_ATAPI
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050013
14
15/****************************************************************
16 * CDROM functions
17 ****************************************************************/
18
19// read disk drive size
20static void
21cdrom_1315(struct bregs *regs, u8 device)
22{
23 disk_ret(regs, DISK_RET_EADDRNOTFOUND);
24}
25
26// lock
27static void
28cdrom_134500(struct bregs *regs, u8 device)
29{
Kevin O'Connor08815372008-12-29 21:16:31 -050030 u16 ebda_seg = get_ebda_seg();
31 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050032 if (locks == 0xff) {
33 regs->al = 1;
34 disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
35 return;
36 }
Kevin O'Connor08815372008-12-29 21:16:31 -050037 SET_EBDA2(ebda_seg, cdrom_locks[device], locks + 1);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050038 regs->al = 1;
39 disk_ret(regs, DISK_RET_SUCCESS);
40}
41
42// unlock
43static void
44cdrom_134501(struct bregs *regs, u8 device)
45{
Kevin O'Connor08815372008-12-29 21:16:31 -050046 u16 ebda_seg = get_ebda_seg();
47 u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050048 if (locks == 0x00) {
49 regs->al = 0;
50 disk_ret(regs, DISK_RET_ENOTLOCKED);
51 return;
52 }
53 locks--;
Kevin O'Connor08815372008-12-29 21:16:31 -050054 SET_EBDA2(ebda_seg, cdrom_locks[device], locks);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050055 regs->al = (locks ? 1 : 0);
56 disk_ret(regs, DISK_RET_SUCCESS);
57}
58
59// status
60static void
61cdrom_134502(struct bregs *regs, u8 device)
62{
Kevin O'Connor609da232008-12-28 23:18:57 -050063 u8 locks = GET_EBDA(cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050064 regs->al = (locks ? 1 : 0);
65 disk_ret(regs, DISK_RET_SUCCESS);
66}
67
68static void
69cdrom_1345XX(struct bregs *regs, u8 device)
70{
71 disk_ret(regs, DISK_RET_EPARAM);
72}
73
74// IBM/MS lock/unlock drive
75static void
76cdrom_1345(struct bregs *regs, u8 device)
77{
78 switch (regs->al) {
79 case 0x00: cdrom_134500(regs, device); break;
80 case 0x01: cdrom_134501(regs, device); break;
81 case 0x02: cdrom_134502(regs, device); break;
82 default: cdrom_1345XX(regs, device); break;
83 }
84}
85
86// IBM/MS eject media
87static void
88cdrom_1346(struct bregs *regs, u8 device)
89{
Kevin O'Connor609da232008-12-28 23:18:57 -050090 u8 locks = GET_EBDA(cdrom_locks[device]);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -050091 if (locks != 0) {
92 disk_ret(regs, DISK_RET_ELOCKED);
93 return;
94 }
95
96 // FIXME should handle 0x31 no media in device
97 // FIXME should handle 0xb5 valid request failed
98
99 // Call removable media eject
100 struct bregs br;
101 memset(&br, 0, sizeof(br));
102 br.ah = 0x52;
103 call16_int(0x15, &br);
104
105 if (br.ah || br.flags & F_CF) {
106 disk_ret(regs, DISK_RET_ELOCKED);
107 return;
108 }
109 disk_ret(regs, DISK_RET_SUCCESS);
110}
111
112// IBM/MS extended media change
113static void
114cdrom_1349(struct bregs *regs, u8 device)
115{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400116 set_fail(regs);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500117 // always send changed ??
118 regs->ah = DISK_RET_ECHANGED;
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500119}
120
121static void
122cdrom_ok(struct bregs *regs, u8 device)
123{
124 disk_ret(regs, DISK_RET_SUCCESS);
125}
126
127static void
128cdrom_wp(struct bregs *regs, u8 device)
129{
130 disk_ret(regs, DISK_RET_EWRITEPROTECT);
131}
132
133void
134cdrom_13(struct bregs *regs, u8 device)
135{
136 //debug_stub(regs);
137
138 switch (regs->ah) {
139 case 0x15: cdrom_1315(regs, device); break;
140 case 0x45: cdrom_1345(regs, device); break;
141 case 0x46: cdrom_1346(regs, device); break;
142 case 0x49: cdrom_1349(regs, device); break;
143
144 // These functions are the same as for hard disks
145 case 0x01:
146 case 0x41:
147 case 0x42:
148 case 0x44:
149 case 0x47:
150 case 0x48:
151 case 0x4e:
152 disk_13(regs, device);
153 break;
154
155 // all these functions return SUCCESS
156 case 0x00: // disk controller reset
157 case 0x09: // initialize drive parameters
158 case 0x0c: // seek to specified cylinder
159 case 0x0d: // alternate disk reset
160 case 0x10: // check drive ready
161 case 0x11: // recalibrate
162 case 0x14: // controller internal diagnostic
163 case 0x16: // detect disk change
164 cdrom_ok(regs, device);
165 break;
166
167 // all these functions return disk write-protected
168 case 0x03: // write disk sectors
169 case 0x05: // format disk track
170 case 0x43: // IBM/MS extended write
171 cdrom_wp(regs, device);
172 break;
173
174 default: disk_13XX(regs, device); break;
175 }
176}
177
178
179/****************************************************************
180 * CD emulation
181 ****************************************************************/
182
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500183// read disk drive parameters
184static void
185cdemu_1308(struct bregs *regs, u8 device)
186{
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500187 u16 ebda_seg = get_ebda_seg();
188 u16 nlc = GET_EBDA2(ebda_seg, cdemu.cylinders) - 1;
189 u16 nlh = GET_EBDA2(ebda_seg, cdemu.heads) - 1;
190 u16 nlspt = GET_EBDA2(ebda_seg, cdemu.spt);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500191
192 regs->al = 0x00;
193 regs->bl = 0x00;
194 regs->ch = nlc & 0xff;
195 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
196 regs->dh = nlh;
197 // FIXME ElTorito Various. should send the real count of drives 1 or 2
198 // FIXME ElTorito Harddisk. should send the HD count
199 regs->dl = 0x02;
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500200 u8 media = GET_EBDA2(ebda_seg, cdemu.media);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500201 if (media <= 3)
202 regs->bl = media * 2;
203
204 regs->es = SEG_BIOS;
Kevin O'Connor117fc212008-04-13 18:17:02 -0400205 regs->di = (u32)&diskette_param_table2;
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500206
207 disk_ret(regs, DISK_RET_SUCCESS);
208}
209
210void
211cdemu_13(struct bregs *regs)
212{
213 //debug_stub(regs);
214
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500215 u16 ebda_seg = get_ebda_seg();
216 u8 device = GET_EBDA2(ebda_seg, cdemu.controller_index) * 2;
217 device += GET_EBDA2(ebda_seg, cdemu.device_spec);
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500218
219 switch (regs->ah) {
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400220 // These functions are the same as for hard disks
221 case 0x02:
222 case 0x04:
223 disk_13(regs, device);
224 break;
225
Kevin O'Connoraa7ddd72008-03-22 23:58:26 -0400226 // These functions are the same as standard CDROM.
227 case 0x00:
228 case 0x01:
229 case 0x03:
230 case 0x05:
231 case 0x09:
232 case 0x0c:
233 case 0x0d:
234 case 0x10:
235 case 0x11:
236 case 0x14:
237 case 0x15:
238 case 0x16:
239 cdrom_13(regs, device);
240 break;
241
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500242 case 0x08: cdemu_1308(regs, device); break;
Kevin O'Connoraa2590c2008-03-22 23:13:24 -0400243
Kevin O'Connoraa7ddd72008-03-22 23:58:26 -0400244 default: disk_13XX(regs, device); break;
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500245 }
246}
247
248struct eltorito_s {
249 u8 size;
250 u8 media;
251 u8 emulated_drive;
252 u8 controller_index;
253 u32 ilba;
254 u16 device_spec;
255 u16 buffer_segment;
256 u16 load_segment;
257 u16 sector_count;
258 u8 cylinders;
259 u8 sectors;
260 u8 heads;
261};
262
263#define SET_INT13ET(regs,var,val) \
264 SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
265
266// ElTorito - Terminate disk emu
267void
268cdemu_134b(struct bregs *regs)
269{
270 // FIXME ElTorito Hardcoded
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500271 u16 ebda_seg = get_ebda_seg();
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500272 SET_INT13ET(regs, size, 0x13);
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500273 SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
274 SET_INT13ET(regs, emulated_drive, GET_EBDA2(ebda_seg, cdemu.emulated_drive));
275 SET_INT13ET(regs, controller_index
276 , GET_EBDA2(ebda_seg, cdemu.controller_index));
277 SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
278 SET_INT13ET(regs, device_spec, GET_EBDA2(ebda_seg, cdemu.device_spec));
279 SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
280 SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
281 SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
282 SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.cylinders));
283 SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.spt));
284 SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.heads));
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500285
286 // If we have to terminate emulation
287 if (regs->al == 0x00) {
288 // FIXME ElTorito Various. Should be handled accordingly to spec
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500289 SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
Kevin O'Connor31d8c8a2008-03-04 19:56:41 -0500290 }
291
292 disk_ret(regs, DISK_RET_SUCCESS);
293}
Kevin O'Connor180a9592008-03-04 22:50:53 -0500294
295
296/****************************************************************
297 * CD booting
298 ****************************************************************/
299
300// Request SENSE
Kevin O'Connora05223c2008-06-28 12:15:57 -0400301static int
Kevin O'Connora0c68792009-02-12 20:47:59 -0500302atapi_get_sense(int device, u8 *asc, u8 *ascq)
Kevin O'Connor180a9592008-03-04 22:50:53 -0500303{
Kevin O'Connora0c68792009-02-12 20:47:59 -0500304 u8 atacmd[12], buffer[18];
Kevin O'Connor180a9592008-03-04 22:50:53 -0500305 memset(atacmd, 0, sizeof(atacmd));
306 atacmd[0] = ATA_CMD_REQUEST_SENSE;
307 atacmd[4] = sizeof(buffer);
Kevin O'Connora05223c2008-06-28 12:15:57 -0400308 int ret = ata_cmd_packet(device, atacmd, sizeof(atacmd), sizeof(buffer)
Kevin O'Connor35ae7262009-01-19 15:44:44 -0500309 , MAKE_FLATPTR(GET_SEG(SS), buffer));
Kevin O'Connora0c68792009-02-12 20:47:59 -0500310 if (ret)
Kevin O'Connora05223c2008-06-28 12:15:57 -0400311 return ret;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500312
313 *asc = buffer[12];
314 *ascq = buffer[13];
315
316 return 0;
317}
318
Kevin O'Connora0c68792009-02-12 20:47:59 -0500319// Request capacity
320static int
321atapi_read_capacity(int device, u32 *blksize, u32 *sectors)
322{
323 u8 packet[12], buf[8];
324 memset(packet, 0, sizeof(packet));
325 packet[0] = 0x25; /* READ CAPACITY */
326 int ret = ata_cmd_packet(device, packet, sizeof(packet), sizeof(buf)
327 , MAKE_FLATPTR(GET_SEG(SS), buf));
328 if (ret)
329 return ret;
330
331 *blksize = (((u32)buf[4] << 24) | ((u32)buf[5] << 16)
332 | ((u32)buf[6] << 8) | ((u32)buf[7] << 0));
333 *sectors = (((u32)buf[0] << 24) | ((u32)buf[1] << 16)
334 | ((u32)buf[2] << 8) | ((u32)buf[3] << 0));
335
336 return 0;
337}
338
Kevin O'Connora05223c2008-06-28 12:15:57 -0400339static int
Kevin O'Connor180a9592008-03-04 22:50:53 -0500340atapi_is_ready(u16 device)
341{
Kevin O'Connora0c68792009-02-12 20:47:59 -0500342 dprintf(6, "atapi_is_ready (device=%d)\n", device);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500343
Kevin O'Connora0c68792009-02-12 20:47:59 -0500344 /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
345 * reported by the device. If the device reports "IN PROGRESS",
Kevin O'Connor180a9592008-03-04 22:50:53 -0500346 * 30 seconds is added. */
Kevin O'Connora0c68792009-02-12 20:47:59 -0500347 u32 blksize, sectors;
348 int in_progress = 0;
349 u64 end = calc_future_tsc(5000);
350 for (;;) {
351 if (rdtscll() > end) {
Kevin O'Connora05223c2008-06-28 12:15:57 -0400352 dprintf(1, "read capacity failed\n");
Kevin O'Connor180a9592008-03-04 22:50:53 -0500353 return -1;
354 }
Kevin O'Connora0c68792009-02-12 20:47:59 -0500355
356 int ret = atapi_read_capacity(device, &blksize, &sectors);
357 if (!ret)
358 // Success
Kevin O'Connor180a9592008-03-04 22:50:53 -0500359 break;
360
Kevin O'Connora0c68792009-02-12 20:47:59 -0500361 u8 asc, ascq;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500362 ret = atapi_get_sense(device, &asc, &ascq);
Kevin O'Connora0c68792009-02-12 20:47:59 -0500363 if (ret)
364 // Error - retry.
Kevin O'Connor180a9592008-03-04 22:50:53 -0500365 continue;
366
Kevin O'Connora0c68792009-02-12 20:47:59 -0500367 // Sense succeeded.
Kevin O'Connor180a9592008-03-04 22:50:53 -0500368 if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
Kevin O'Connora05223c2008-06-28 12:15:57 -0400369 dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
Kevin O'Connor180a9592008-03-04 22:50:53 -0500370 return -1;
371 }
372
373 if (asc == 0x04 && ascq == 0x01 && !in_progress) {
374 /* IN PROGRESS OF BECOMING READY */
375 printf("Waiting for device to detect medium... ");
376 /* Allow 30 seconds more */
Kevin O'Connora0c68792009-02-12 20:47:59 -0500377 end = calc_future_tsc(30000);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500378 in_progress = 1;
379 }
380 }
381
Kevin O'Connora0c68792009-02-12 20:47:59 -0500382 if (blksize != GET_GLOBAL(ATA.devices[device].blksize)) {
383 printf("Unsupported sector size %u\n", blksize);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500384 return -1;
385 }
Kevin O'Connor180a9592008-03-04 22:50:53 -0500386
Kevin O'Connora05223c2008-06-28 12:15:57 -0400387 dprintf(6, "sectors=%u\n", sectors);
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500388 printf("%dMB medium detected\n", sectors>>(20-11));
Kevin O'Connor180a9592008-03-04 22:50:53 -0500389 return 0;
390}
391
Kevin O'Connora05223c2008-06-28 12:15:57 -0400392static int
Kevin O'Connor180a9592008-03-04 22:50:53 -0500393atapi_is_cdrom(u8 device)
394{
395 if (device >= CONFIG_MAX_ATA_DEVICES)
396 return 0;
397
Kevin O'Connor609da232008-12-28 23:18:57 -0500398 if (GET_GLOBAL(ATA.devices[device].type) != ATA_TYPE_ATAPI)
Kevin O'Connor180a9592008-03-04 22:50:53 -0500399 return 0;
400
Kevin O'Connor609da232008-12-28 23:18:57 -0500401 if (GET_GLOBAL(ATA.devices[device].device) != ATA_DEVICE_CDROM)
Kevin O'Connor180a9592008-03-04 22:50:53 -0500402 return 0;
403
404 return 1;
405}
406
407// Compare a string on the stack to one in the code segment.
408static int
409streq_cs(u8 *s1, char *cs_s2)
410{
411 u8 *s2 = (u8*)cs_s2;
412 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500413 if (*s1 != GET_GLOBAL(*s2))
Kevin O'Connor180a9592008-03-04 22:50:53 -0500414 return 0;
415 if (! *s1)
416 return 1;
417 s1++;
418 s2++;
419 }
420}
421
Kevin O'Connora05223c2008-06-28 12:15:57 -0400422int
Kevin O'Connor180a9592008-03-04 22:50:53 -0500423cdrom_boot()
424{
425 // Find out the first cdrom
426 u8 device;
427 for (device=0; device<CONFIG_MAX_ATA_DEVICES; device++)
428 if (atapi_is_cdrom(device))
429 break;
Kevin O'Connor37ef9ae2008-11-09 17:35:05 -0500430 if (device >= CONFIG_MAX_ATA_DEVICES)
431 // cdrom not found
432 return 2;
Kevin O'Connor180a9592008-03-04 22:50:53 -0500433
Kevin O'Connora05223c2008-06-28 12:15:57 -0400434 int ret = atapi_is_ready(device);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500435 if (ret)
Kevin O'Connor65e63422008-07-19 14:12:32 -0400436 dprintf(1, "atapi_is_ready returned %d\n", ret);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500437
438 // Read the Boot Record Volume Descriptor
439 u8 buffer[2048];
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500440 struct disk_op_s dop;
441 dop.driveid = device;
442 dop.lba = 0x11;
443 dop.count = 1;
Kevin O'Connor35ae7262009-01-19 15:44:44 -0500444 dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500445 ret = cdrom_read(&dop);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500446 if (ret)
447 return 3;
448
449 // Validity checks
450 if (buffer[0])
451 return 4;
452 if (!streq_cs(&buffer[1], "CD001\001EL TORITO SPECIFICATION"))
453 return 5;
454
455 // ok, now we calculate the Boot catalog address
456 u32 lba = *(u32*)&buffer[0x47];
457
458 // And we read the Boot Catalog
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500459 dop.lba = lba;
460 ret = cdrom_read(&dop);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500461 if (ret)
462 return 7;
463
464 // Validation entry
465 if (buffer[0x00] != 0x01)
466 return 8; // Header
467 if (buffer[0x01] != 0x00)
468 return 9; // Platform
469 if (buffer[0x1E] != 0x55)
470 return 10; // key 1
471 if (buffer[0x1F] != 0xAA)
472 return 10; // key 2
473
474 // Initial/Default Entry
475 if (buffer[0x20] != 0x88)
476 return 11; // Bootable
477
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500478 u16 ebda_seg = get_ebda_seg();
Kevin O'Connordfa16502008-03-22 20:13:08 -0400479 u8 media = buffer[0x21];
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500480 SET_EBDA2(ebda_seg, cdemu.media, media);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500481
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500482 SET_EBDA2(ebda_seg, cdemu.controller_index, device/2);
483 SET_EBDA2(ebda_seg, cdemu.device_spec, device%2);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500484
485 u16 boot_segment = *(u16*)&buffer[0x22];
486 if (!boot_segment)
487 boot_segment = 0x07C0;
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500488 SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
489 SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500490
491 u16 nbsectors = *(u16*)&buffer[0x26];
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500492 SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500493
494 lba = *(u32*)&buffer[0x28];
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500495 SET_EBDA2(ebda_seg, cdemu.ilba, lba);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500496
497 // And we read the image in memory
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500498 dop.lba = lba * 4;
499 dop.count = nbsectors;
Kevin O'Connor35ae7262009-01-19 15:44:44 -0500500 dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
Kevin O'Connor4524bf72008-12-31 00:31:03 -0500501 ret = cdrom_read_512(&dop);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500502 if (ret)
503 return 12;
504
Kevin O'Connordfa16502008-03-22 20:13:08 -0400505 if (media == 0) {
506 // No emulation requested - return success.
507
508 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
509 // Win2000 cd boot needs to know it booted from cd
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500510 SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0xE0);
Kevin O'Connordfa16502008-03-22 20:13:08 -0400511
512 return 0;
513 }
514
515 // Emulation of a floppy/harddisk requested
516 if (! CONFIG_CDROM_EMU)
517 return 13;
518
519 // Set emulated drive id and increase bios installed hardware
520 // number of devices
521 if (media < 4) {
522 // Floppy emulation
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500523 SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0x00);
Kevin O'Connordfa16502008-03-22 20:13:08 -0400524 SETBITS_BDA(equipment_list_flags, 0x41);
Kevin O'Connor95827c42009-02-07 00:04:57 -0500525
526 switch (media) {
527 case 0x01: // 1.2M floppy
528 SET_EBDA2(ebda_seg, cdemu.spt, 15);
529 SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
530 SET_EBDA2(ebda_seg, cdemu.heads, 2);
531 break;
532 case 0x02: // 1.44M floppy
533 SET_EBDA2(ebda_seg, cdemu.spt, 18);
534 SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
535 SET_EBDA2(ebda_seg, cdemu.heads, 2);
536 break;
537 case 0x03: // 2.88M floppy
538 SET_EBDA2(ebda_seg, cdemu.spt, 36);
539 SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
540 SET_EBDA2(ebda_seg, cdemu.heads, 2);
541 break;
542 }
Kevin O'Connordfa16502008-03-22 20:13:08 -0400543 } else {
544 // Harddrive emulation
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500545 SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0x80);
546 SET_BDA(hdcount, GET_BDA(hdcount) + 1);
Kevin O'Connordfa16502008-03-22 20:13:08 -0400547
Kevin O'Connor95827c42009-02-07 00:04:57 -0500548 // Peak at partition table to get chs.
549 struct mbr_s *mbr = (void*)0;
550 u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
551 u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
552 u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
553
554 SET_EBDA2(ebda_seg, cdemu.spt, sptcyl & 0x3f);
555 SET_EBDA2(ebda_seg, cdemu.cylinders, ((sptcyl<<2)&0x300) + cyllow + 1);
556 SET_EBDA2(ebda_seg, cdemu.heads, heads + 1);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500557 }
558
Kevin O'Connordfa16502008-03-22 20:13:08 -0400559 // everything is ok, so from now on, the emulation is active
Kevin O'Connor4a16ef62008-12-31 00:09:28 -0500560 SET_EBDA2(ebda_seg, cdemu.active, 0x01);
Kevin O'Connora05223c2008-06-28 12:15:57 -0400561 dprintf(6, "cdemu media=%d\n", media);
Kevin O'Connor180a9592008-03-04 22:50:53 -0500562
563 return 0;
564}