VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/eltorito.c@ 55998

Last change on this file since 55998 was 48947, checked in by vboxsync, 11 years ago

Devices: Whitespace and svn:keyword cleanups by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.1 KB
Line 
1/*
2 * Copyright (C) 2006-2013 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 * --------------------------------------------------------------------
12 *
13 * This code is based on:
14 *
15 * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
16 *
17 * Copyright (C) 2002 MandrakeSoft S.A.
18 *
19 * MandrakeSoft S.A.
20 * 43, rue d'Aboukir
21 * 75002 Paris - France
22 * http://www.linux-mandrake.com/
23 * http://www.mandrakesoft.com/
24 *
25 * This library is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU Lesser General Public
27 * License as published by the Free Software Foundation; either
28 * version 2 of the License, or (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * Lesser General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public
36 * License along with this library; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
38 *
39 */
40
41
42#include <stdint.h>
43#include <string.h>
44#include "inlines.h"
45#include "biosint.h"
46#include "ebda.h"
47#include "ata.h"
48
49#if DEBUG_ELTORITO
50# define BX_DEBUG_INT13_ET(...) BX_DEBUG(__VA_ARGS__)
51#else
52# define BX_DEBUG_INT13_ET(...)
53#endif
54
55#if DEBUG_INT13_CD
56# define BX_DEBUG_INT13_CD(...) BX_DEBUG(__VA_ARGS__)
57#else
58# define BX_DEBUG_INT13_CD(...)
59#endif
60
61#if DEBUG_CD_BOOT
62# define BX_DEBUG_ELTORITO(...) BX_DEBUG(__VA_ARGS__)
63#else
64# define BX_DEBUG_ELTORITO(...)
65#endif
66
67
68//@todo: put in a header
69#define AX r.gr.u.r16.ax
70#define BX r.gr.u.r16.bx
71#define CX r.gr.u.r16.cx
72#define DX r.gr.u.r16.dx
73#define SI r.gr.u.r16.si
74#define DI r.gr.u.r16.di
75#define BP r.gr.u.r16.bp
76#define ELDX r.gr.u.r16.sp
77#define DS r.ds
78#define ES r.es
79#define FLAGS r.ra.flags.u.r16.flags
80
81#pragma pack(1)
82
83/* READ_10/WRITE_10 CDB padded to 12 bytes for ATAPI. */
84typedef struct {
85 uint16_t command; /* Command. */
86 uint32_t lba; /* LBA, MSB first! */
87 uint8_t pad1; /* Unused. */
88 uint16_t nsect; /* Sector count, MSB first! */
89 uint8_t pad2[3]; /* Unused. */
90} cdb_atapi;
91
92#pragma pack()
93
94ct_assert(sizeof(cdb_atapi) == 12);
95
96/* Generic ATAPI/SCSI CD-ROM access routine signature. */
97typedef uint16_t (* cd_pkt_func)(uint16_t device_id, uint8_t cmdlen, char __far *cmdbuf,
98 uint16_t header, uint32_t length, uint8_t inout, char __far *buffer);
99
100/* Pointers to HW specific CD-ROM access routines. */
101cd_pkt_func pktacc[DSKTYP_CNT] = {
102 [DSK_TYPE_ATAPI] = { ata_cmd_packet },
103#ifdef VBOX_WITH_AHCI
104 [DSK_TYPE_AHCI] = { ahci_cmd_packet },
105#endif
106#ifdef VBOX_WITH_SCSI
107 [DSK_TYPE_SCSI] = { scsi_cmd_packet },
108#endif
109};
110
111#if defined(VBOX_WITH_AHCI) || defined(VBOX_WITH_SCSI)
112uint16_t dummy_soft_reset(uint16_t device_id)
113{
114 return 0;
115}
116#endif
117
118/* Generic reset routine signature. */
119typedef uint16_t (* cd_rst_func)(uint16_t device_id);
120
121/* Pointers to HW specific CD-ROM reset routines. */
122cd_rst_func softrst[DSKTYP_CNT] = {
123 [DSK_TYPE_ATAPI] = { ata_soft_reset },
124#ifdef VBOX_WITH_AHCI
125 [DSK_TYPE_AHCI] = { dummy_soft_reset },
126#endif
127#ifdef VBOX_WITH_SCSI
128 [DSK_TYPE_SCSI] = { dummy_soft_reset },
129#endif
130};
131
132
133// ---------------------------------------------------------------------------
134// Start of El-Torito boot functions
135// ---------------------------------------------------------------------------
136
137// !! TODO !! convert EBDA accesses to far pointers
138
139extern int diskette_param_table;
140
141
142void BIOSCALL cdemu_init(void)
143{
144 // @TODO: a macro or a function for getting the EBDA segment
145 uint16_t ebda_seg = read_word(0x0040,0x000E);
146
147 // the only important data is this one for now
148 write_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.active, 0x00);
149}
150
151uint8_t BIOSCALL cdemu_isactive(void)
152{
153 // @TODO: a macro or a function for getting the EBDA segment
154 uint16_t ebda_seg = read_word(0x0040,0x000E);
155
156 return read_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.active);
157}
158
159uint8_t BIOSCALL cdemu_emulated_drive(void)
160{
161 // @TODO: a macro or a function for getting the EBDA segment
162 uint16_t ebda_seg = read_word(0x0040,0x000E);
163
164 return read_byte(ebda_seg,(uint16_t)&EbdaData->cdemu.emulated_drive);
165}
166
167// ---------------------------------------------------------------------------
168// Start of int13 for eltorito functions
169// ---------------------------------------------------------------------------
170
171void BIOSCALL int13_eltorito(disk_regs_t r)
172{
173 // @TODO: a macro or a function for getting the EBDA segment
174 uint16_t ebda_seg=read_word(0x0040,0x000E);
175 cdemu_t __far *cdemu;
176
177 cdemu = ebda_seg :> &EbdaData->cdemu;
178
179
180 BX_DEBUG_INT13_ET("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
181 // BX_DEBUG_INT13_ET("%s: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n", __func__, get_SS(), DS, ES, DI, SI);
182
183 switch (GET_AH()) {
184
185 // FIXME ElTorito Various. Not implemented in many real BIOSes.
186 case 0x4a: // ElTorito - Initiate disk emu
187 case 0x4c: // ElTorito - Initiate disk emu and boot
188 case 0x4d: // ElTorito - Return Boot catalog
189 BX_INFO("%s: call with AX=%04x not implemented.\n", __func__, AX);
190 goto int13_fail;
191 break;
192
193 case 0x4b: // ElTorito - Terminate disk emu
194 // FIXME ElTorito Hardcoded
195 //@todo: maybe our cdemu struct should match El Torito to allow memcpy()?
196 write_byte(DS,SI+0x00,0x13);
197 write_byte(DS,SI+0x01,cdemu->media);
198 write_byte(DS,SI+0x02,cdemu->emulated_drive);
199 write_byte(DS,SI+0x03,cdemu->controller_index);
200 write_dword(DS,SI+0x04,cdemu->ilba);
201 write_word(DS,SI+0x08,cdemu->device_spec);
202 write_word(DS,SI+0x0a,cdemu->buffer_segment);
203 write_word(DS,SI+0x0c,cdemu->load_segment);
204 write_word(DS,SI+0x0e,cdemu->sector_count);
205 write_byte(DS,SI+0x10,cdemu->vdevice.cylinders);
206 write_byte(DS,SI+0x11,cdemu->vdevice.spt);
207 write_byte(DS,SI+0x12,cdemu->vdevice.heads);
208
209 // If we have to terminate emulation
210 if(GET_AL() == 0x00) {
211 // FIXME ElTorito Various. Should be handled accordingly to spec
212 cdemu->active = 0; // bye bye
213 }
214
215 goto int13_success;
216 break;
217
218 default:
219 BX_INFO("%s: unsupported AH=%02x\n", __func__, GET_AH());
220 goto int13_fail;
221 break;
222 }
223
224int13_fail:
225 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
226 SET_DISK_RET_STATUS(GET_AH());
227 SET_CF(); // error occurred
228 return;
229
230int13_success:
231 SET_AH(0x00); // no error
232 SET_DISK_RET_STATUS(0x00);
233 CLEAR_CF(); // no error
234 return;
235}
236
237// ---------------------------------------------------------------------------
238// End of int13 for eltorito functions
239// ---------------------------------------------------------------------------
240
241/* Utility routine to check if a device is a CD-ROM. */
242//@todo: this function is kinda useless as the ATAPI type check is obsolete.
243static uint16_t device_is_cdrom(uint8_t device)
244{
245 bio_dsk_t __far *bios_dsk;
246
247 bios_dsk = read_word(0x0040, 0x000E) :> &EbdaData->bdisk;
248
249 if (device >= BX_MAX_STORAGE_DEVICES)
250 return 0;
251
252// if (bios_dsk->devices[device].type != DSK_TYPE_ATAPI)
253// return 0;
254
255 if (bios_dsk->devices[device].device != DSK_DEVICE_CDROM)
256 return 0;
257
258 return 1;
259}
260
261// ---------------------------------------------------------------------------
262// End of ATA/ATAPI generic functions
263// ---------------------------------------------------------------------------
264static const char isotag[]="CD001";
265static const char eltorito[]="EL TORITO SPECIFICATION";
266//
267// Returns ah: emulated drive, al: error code
268//
269uint16_t cdrom_boot(void)
270{
271 // @TODO: a macro or a function for getting the EBDA segment
272 uint16_t ebda_seg=read_word(0x0040,0x000E);
273 uint8_t buffer[2048];
274 cdb_atapi atapicmd;
275 uint32_t lba;
276 uint16_t boot_segment, nbsectors, i, error;
277 uint8_t device;
278 uint8_t read_try;
279 cdemu_t __far *cdemu;
280 bio_dsk_t __far *bios_dsk;
281
282 cdemu = ebda_seg :> &EbdaData->cdemu;
283 bios_dsk = ebda_seg :> &EbdaData->bdisk;
284
285 /* Find the first CD-ROM. */
286 for (device = 0; device < BX_MAX_STORAGE_DEVICES; ++device) {
287 if (device_is_cdrom(device))
288 break;
289 }
290
291 /* Fail if not found. */
292 if (device >= BX_MAX_STORAGE_DEVICES)
293 return 2;
294
295 /* Read the Boot Record Volume Descriptor (BRVD). */
296 _fmemset(&atapicmd, 0, sizeof(atapicmd));
297 atapicmd.command = 0x28; // READ 10 command
298 atapicmd.lba = swap_32(0x11);
299 atapicmd.nsect = swap_16(1);
300
301 bios_dsk->drqp.nsect = 1;
302 bios_dsk->drqp.sect_sz = 2048;
303
304 for (read_try = 0; read_try <= 4; ++read_try)
305 {
306 error = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, 2048L, ATA_DATA_IN, &buffer);
307 if (!error)
308 break;
309 }
310 if (error)
311 return 3;
312
313 /* Check for a valid BRVD. */
314 if (buffer[0] != 0)
315 return 4;
316 //@todo: what's wrong with memcmp()?
317 for (i = 0; i < 5; ++i) {
318 if (buffer[1+i] != isotag[i])
319 return 5;
320 }
321 for (i = 0; i < 23; ++i)
322 if (buffer[7+i] != eltorito[i])
323 return 6;
324
325 // ok, now we calculate the Boot catalog address
326 lba = *((uint32_t *)&buffer[0x47]);
327 BX_DEBUG_ELTORITO("BRVD at LBA %lx\n", lba);
328
329 /* Now we read the Boot Catalog. */
330 atapicmd.command = 0x28; // READ 10 command
331 atapicmd.lba = swap_32(lba);
332 atapicmd.nsect = swap_16(1);
333
334#if 0 // Not necessary as long as previous values are reused
335 bios_dsk->drqp.nsect = 1;
336 bios_dsk->drqp.sect_sz = 512;
337#endif
338
339 error = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, 2048L, ATA_DATA_IN, &buffer);
340 if (error != 0)
341 return 7;
342
343 //@todo: Define a struct for the Boot Catalog, the hardcoded offsets are so dumb...
344
345 /* Check if the Boot Catalog looks valid. */
346 if (buffer[0x00] != 0x01)
347 return 8; // Header
348 if (buffer[0x01] != 0x00)
349 return 9; // Platform
350 if (buffer[0x1E] != 0x55)
351 return 10; // key 1
352 if (buffer[0x1F] != 0xAA)
353 return 10; // key 2
354
355 // Initial/Default Entry
356 if (buffer[0x20] != 0x88)
357 return 11; // Bootable
358
359 cdemu->media = buffer[0x21];
360 if (buffer[0x21] == 0) {
361 // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
362 // Win2000 cd boot needs to know it booted from cd
363 cdemu->emulated_drive = 0xE0;
364 }
365 else if (buffer[0x21] < 4)
366 cdemu->emulated_drive = 0x00;
367 else
368 cdemu->emulated_drive = 0x80;
369
370 cdemu->controller_index = device / 2;
371 cdemu->device_spec = device % 2;
372
373 boot_segment = *((uint16_t *)&buffer[0x22]);
374 if (boot_segment == 0)
375 boot_segment = 0x07C0;
376
377 cdemu->load_segment = boot_segment;
378 cdemu->buffer_segment = 0x0000;
379
380 nbsectors = ((uint16_t *)buffer)[0x26 / 2];
381 cdemu->sector_count = nbsectors;
382
383 /* Sanity check the sector count. In incorrectly mastered CDs, it might
384 * be zero. If it's more than 512K, reject it as well.
385 */
386 if (nbsectors == 0 || nbsectors > 1024)
387 return 12;
388
389 lba = *((uint32_t *)&buffer[0x28]);
390 cdemu->ilba = lba;
391
392 BX_DEBUG_ELTORITO("Emulate drive %02x, type %02x, LBA %lu\n",
393 cdemu->emulated_drive, cdemu->media, cdemu->ilba);
394
395 /* Read the disk image's boot sector into memory. */
396 atapicmd.command = 0x28; // READ 10 command
397 atapicmd.lba = swap_32(lba);
398 atapicmd.nsect = swap_16(1 + (nbsectors - 1) / 4);
399
400 bios_dsk->drqp.nsect = 1 + (nbsectors - 1) / 4;
401 bios_dsk->drqp.sect_sz = 512;
402
403 bios_dsk->drqp.skip_a = (2048 - nbsectors * 512) % 2048;
404
405 error = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, nbsectors*512L, ATA_DATA_IN, MK_FP(boot_segment,0));
406
407 bios_dsk->drqp.skip_a = 0;
408
409 if (error != 0)
410 return 13;
411
412 BX_DEBUG_ELTORITO("Emulate drive %02x, type %02x, LBA %lu\n",
413 cdemu->emulated_drive, cdemu->media, cdemu->ilba);
414 /* Set up emulated drive geometry based on the media type. */
415 switch (cdemu->media) {
416 case 0x01: /* 1.2M floppy */
417 cdemu->vdevice.spt = 15;
418 cdemu->vdevice.cylinders = 80;
419 cdemu->vdevice.heads = 2;
420 break;
421 case 0x02: /* 1.44M floppy */
422 cdemu->vdevice.spt = 18;
423 cdemu->vdevice.cylinders = 80;
424 cdemu->vdevice.heads = 2;
425 break;
426 case 0x03: /* 2.88M floppy */
427 cdemu->vdevice.spt = 36;
428 cdemu->vdevice.cylinders = 80;
429 cdemu->vdevice.heads = 2;
430 break;
431 case 0x04: /* Hard disk */
432 cdemu->vdevice.spt = read_byte(boot_segment,446+6)&0x3f;
433 cdemu->vdevice.cylinders = (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1;
434 cdemu->vdevice.heads = read_byte(boot_segment,446+5) + 1;
435 break;
436 }
437 BX_DEBUG_ELTORITO("VCHS=%u/%u/%u\n", cdemu->vdevice.cylinders,
438 cdemu->vdevice.heads, cdemu->vdevice.spt);
439
440 if (cdemu->media != 0) {
441 /* Increase BIOS installed number of drives (floppy or fixed). */
442 if (cdemu->emulated_drive == 0x00)
443 write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
444 else
445 write_byte(ebda_seg,(uint16_t)&EbdaData->bdisk.hdcount, read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.hdcount) + 1);
446 }
447
448 // everything is ok, so from now on, the emulation is active
449 if (cdemu->media != 0)
450 cdemu->active = 0x01;
451
452 // return the boot drive + no error
453 return (cdemu->emulated_drive*0x100)+0;
454}
455
456// ---------------------------------------------------------------------------
457// End of El-Torito boot functions
458// ---------------------------------------------------------------------------
459
460// ---------------------------------------------------------------------------
461// Start of int13 when emulating a device from the cd
462// ---------------------------------------------------------------------------
463
464void BIOSCALL int13_cdemu(disk_regs_t r)
465{
466 // @TODO: a macro or a function for getting the EBDA segment
467 uint16_t ebda_seg=read_word(0x0040,0x000E);
468 uint8_t device, status;
469 uint16_t vheads, vspt, vcylinders;
470 uint16_t head, sector, cylinder, nbsectors;
471 uint32_t vlba, ilba, slba, elba;
472 uint16_t before, segment, offset;
473 cdb_atapi atapicmd;
474 cdemu_t __far *cdemu;
475 bio_dsk_t __far *bios_dsk;
476
477 cdemu = ebda_seg :> &EbdaData->cdemu;
478 bios_dsk = ebda_seg :> &EbdaData->bdisk;
479
480 BX_DEBUG_INT13_ET("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
481
482 /* at this point, we are emulating a floppy/harddisk */
483
484 // Recompute the device number
485 device = cdemu->controller_index * 2;
486 device += cdemu->device_spec;
487
488 SET_DISK_RET_STATUS(0x00);
489
490 /* basic checks : emulation should be active, dl should equal the emulated drive */
491 if (!cdemu->active || (cdemu->emulated_drive != GET_DL())) {
492 BX_INFO("%s: function %02x, emulation not active for DL= %02x\n", __func__, GET_AH(), GET_DL());
493 goto int13_fail;
494 }
495
496 switch (GET_AH()) {
497
498 case 0x00: /* disk controller reset */
499 if (pktacc[bios_dsk->devices[device].type])
500 {
501 status = softrst[bios_dsk->devices[device].type](device);
502 }
503 goto int13_success;
504 break;
505 // all those functions return SUCCESS
506 case 0x09: /* initialize drive parameters */
507 case 0x0c: /* seek to specified cylinder */
508 case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ?
509 case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ?
510 case 0x11: /* recalibrate */
511 case 0x14: /* controller internal diagnostic */
512 case 0x16: /* detect disk change */
513 goto int13_success;
514 break;
515
516 // all those functions return disk write-protected
517 case 0x03: /* write disk sectors */
518 case 0x05: /* format disk track */
519 SET_AH(0x03);
520 goto int13_fail_noah;
521 break;
522
523 case 0x01: /* read disk status */
524 status=read_byte(0x0040, 0x0074);
525 SET_AH(status);
526 SET_DISK_RET_STATUS(0);
527
528 /* set CF if error status read */
529 if (status)
530 goto int13_fail_nostatus;
531 else
532 goto int13_success_noah;
533 break;
534
535 case 0x02: // read disk sectors
536 case 0x04: // verify disk sectors
537 vspt = cdemu->vdevice.spt;
538 vcylinders = cdemu->vdevice.cylinders;
539 vheads = cdemu->vdevice.heads;
540 ilba = cdemu->ilba;
541
542 sector = GET_CL() & 0x003f;
543 cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
544 head = GET_DH();
545 nbsectors = GET_AL();
546 segment = ES;
547 offset = BX;
548
549 BX_DEBUG_INT13_ET("%s: read to %04x:%04x @ VCHS %u/%u/%u (%u sectors)\n", __func__,
550 ES, BX, cylinder, head, sector, nbsectors);
551
552 // no sector to read ?
553 if(nbsectors==0)
554 goto int13_success;
555
556 // sanity checks sco openserver needs this!
557 if ((sector > vspt)
558 || (cylinder >= vcylinders)
559 || (head >= vheads)) {
560 goto int13_fail;
561 }
562
563 // After validating the input, verify does nothing
564 if (GET_AH() == 0x04)
565 goto int13_success;
566
567 segment = ES+(BX / 16);
568 offset = BX % 16;
569
570 // calculate the virtual lba inside the image
571 vlba=((((uint32_t)cylinder*(uint32_t)vheads)+(uint32_t)head)*(uint32_t)vspt)+((uint32_t)(sector-1));
572
573 // In advance so we don't lose the count
574 SET_AL(nbsectors);
575
576 // start lba on cd
577 slba = (uint32_t)vlba / 4;
578 before = (uint32_t)vlba % 4;
579
580 // end lba on cd
581 elba = (uint32_t)(vlba + nbsectors - 1) / 4;
582
583 _fmemset(&atapicmd, 0, sizeof(atapicmd));
584 atapicmd.command = 0x28; // READ 10 command
585 atapicmd.lba = swap_32(ilba + slba);
586 atapicmd.nsect = swap_16(elba - slba + 1);
587
588 bios_dsk->drqp.nsect = nbsectors;
589 bios_dsk->drqp.sect_sz = 512;
590
591 bios_dsk->drqp.skip_b = before * 512;
592 bios_dsk->drqp.skip_a = ((4 - nbsectors % 4 - before) * 512) % 2048;
593
594 status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, before*512, nbsectors*512L, ATA_DATA_IN, MK_FP(segment,offset));
595
596 bios_dsk->drqp.skip_b = 0;
597 bios_dsk->drqp.skip_a = 0;
598
599 if (status != 0) {
600 BX_INFO("%s: function %02x, error %02x !\n", __func__, GET_AH(), status);
601 SET_AH(0x02);
602 SET_AL(0);
603 goto int13_fail_noah;
604 }
605
606 goto int13_success;
607 break;
608
609 case 0x08: /* read disk drive parameters */
610 vspt = cdemu->vdevice.spt;
611 vcylinders = cdemu->vdevice.cylinders - 1;
612 vheads = cdemu->vdevice.heads - 1;
613
614 SET_AL( 0x00 );
615 SET_BL( 0x00 );
616 SET_CH( vcylinders & 0xff );
617 SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt & 0x3f ));
618 SET_DH( vheads );
619 SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2
620 // FIXME ElTorito Harddisk. should send the HD count
621
622 switch (cdemu->media) {
623 case 0x01: SET_BL( 0x02 ); break; /* 1.2 MB */
624 case 0x02: SET_BL( 0x04 ); break; /* 1.44 MB */
625 case 0x03: SET_BL( 0x05 ); break; /* 2.88 MB */
626 }
627
628 /* Only set the DPT pointer for emulated floppies. */
629 if (cdemu->media < 4) {
630 DI = (uint16_t)&diskette_param_table; // @todo: should this depend on emulated medium?
631 ES = 0xF000; // @todo: how to make this relocatable?
632 }
633 goto int13_success;
634 break;
635
636 case 0x15: /* read disk drive size */
637 // FIXME ElTorito Harddisk. What geometry to send ?
638 SET_AH(0x03);
639 goto int13_success_noah;
640 break;
641
642 // all those functions return unimplemented
643 case 0x0a: /* read disk sectors with ECC */
644 case 0x0b: /* write disk sectors with ECC */
645 case 0x18: /* set media type for format */
646 case 0x41: // IBM/MS installation check
647 // FIXME ElTorito Harddisk. Darwin would like to use EDD
648 case 0x42: // IBM/MS extended read
649 case 0x43: // IBM/MS extended write
650 case 0x44: // IBM/MS verify sectors
651 case 0x45: // IBM/MS lock/unlock drive
652 case 0x46: // IBM/MS eject media
653 case 0x47: // IBM/MS extended seek
654 case 0x48: // IBM/MS get drive parameters
655 case 0x49: // IBM/MS extended media change
656 case 0x4e: // ? - set hardware configuration
657 case 0x50: // ? - send packet command
658 default:
659 BX_INFO("%s: function AH=%02x unsupported, returns fail\n", __func__, GET_AH());
660 goto int13_fail;
661 break;
662 }
663
664int13_fail:
665 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
666int13_fail_noah:
667 SET_DISK_RET_STATUS(GET_AH());
668int13_fail_nostatus:
669 SET_CF(); // error occurred
670 return;
671
672int13_success:
673 SET_AH(0x00); // no error
674int13_success_noah:
675 SET_DISK_RET_STATUS(0x00);
676 CLEAR_CF(); // no error
677 return;
678}
679
680// ---------------------------------------------------------------------------
681// Start of int13 for cdrom
682// ---------------------------------------------------------------------------
683
684void BIOSCALL int13_cdrom(uint16_t EHBX, disk_regs_t r)
685{
686 uint16_t ebda_seg = read_word(0x0040,0x000E);
687 uint8_t device, status, locks;
688 cdb_atapi atapicmd;
689 uint32_t lba;
690 uint16_t count, segment, offset, size;
691 bio_dsk_t __far *bios_dsk;
692 int13ext_t __far *i13x;
693 dpt_t __far *dpt;
694
695 bios_dsk = ebda_seg :> &EbdaData->bdisk;
696
697 BX_DEBUG_INT13_CD("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
698
699 SET_DISK_RET_STATUS(0x00);
700
701 /* basic check : device should be 0xE0+ */
702 if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0 + BX_MAX_STORAGE_DEVICES) ) {
703 BX_DEBUG("%s: function %02x, ELDL out of range %02x\n", __func__, GET_AH(), GET_ELDL());
704 goto int13_fail;
705 }
706
707 // Get the ata channel
708 device = bios_dsk->cdidmap[GET_ELDL()-0xE0];
709
710 /* basic check : device has to be valid */
711 if (device >= BX_MAX_STORAGE_DEVICES) {
712 BX_DEBUG("%s: function %02x, unmapped device for ELDL=%02x\n", __func__, GET_AH(), GET_ELDL());
713 goto int13_fail;
714 }
715
716 switch (GET_AH()) {
717
718 // all those functions return SUCCESS
719 case 0x00: /* disk controller reset */
720 case 0x09: /* initialize drive parameters */
721 case 0x0c: /* seek to specified cylinder */
722 case 0x0d: /* alternate disk reset */
723 case 0x10: /* check drive ready */
724 case 0x11: /* recalibrate */
725 case 0x14: /* controller internal diagnostic */
726 case 0x16: /* detect disk change */
727 goto int13_success;
728 break;
729
730 // all those functions return disk write-protected
731 case 0x03: /* write disk sectors */
732 case 0x05: /* format disk track */
733 case 0x43: // IBM/MS extended write
734 SET_AH(0x03);
735 goto int13_fail_noah;
736 break;
737
738 case 0x01: /* read disk status */
739 status = read_byte(0x0040, 0x0074);
740 SET_AH(status);
741 SET_DISK_RET_STATUS(0);
742
743 /* set CF if error status read */
744 if (status)
745 goto int13_fail_nostatus;
746 else
747 goto int13_success_noah;
748 break;
749
750 case 0x15: /* read disk drive size */
751 SET_AH(0x02);
752 goto int13_fail_noah;
753 break;
754
755 case 0x41: // IBM/MS installation check
756 BX = 0xaa55; // install check
757 SET_AH(0x30); // EDD 2.1
758 CX = 0x0007; // ext disk access, removable and edd
759 goto int13_success_noah;
760 break;
761
762 case 0x42: // IBM/MS extended read
763 case 0x44: // IBM/MS verify sectors
764 case 0x47: // IBM/MS extended seek
765
766 /* Load the I13X struct pointer. */
767 i13x = MK_FP(DS, SI);
768
769 count = i13x->count;
770 segment = i13x->segment;
771 offset = i13x->offset;
772
773 // Can't use 64 bits lba
774 lba = i13x->lba2;
775 if (lba != 0L) {
776 BX_PANIC("%s: function %02x. Can't use 64bits lba\n", __func__, GET_AH());
777 goto int13_fail;
778 }
779
780 // Get 32 bits lba
781 lba = i13x->lba1;
782
783 // If verify or seek
784 if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
785 goto int13_success;
786
787 BX_DEBUG_INT13_CD("%s: read %u sectors @ LBA %lu to %04X:%04X\n",
788 __func__, count, lba, segment, offset);
789
790 _fmemset(&atapicmd, 0, sizeof(atapicmd));
791 atapicmd.command = 0x28; // READ 10 command
792 atapicmd.lba = swap_32(lba);
793 atapicmd.nsect = swap_16(count);
794
795 bios_dsk->drqp.nsect = count;
796 bios_dsk->drqp.sect_sz = 2048;
797
798 status = pktacc[bios_dsk->devices[device].type](device, 12, (char __far *)&atapicmd, 0, count*2048L, ATA_DATA_IN, MK_FP(segment,offset));
799
800 count = (uint16_t)(bios_dsk->drqp.trsfbytes >> 11);
801 i13x->count = count;
802
803 if (status != 0) {
804 BX_INFO("%s: function %02x, status %02x !\n", __func__, GET_AH(), status);
805 SET_AH(0x0c);
806 goto int13_fail_noah;
807 }
808
809 goto int13_success;
810 break;
811
812 case 0x45: // IBM/MS lock/unlock drive
813 if (GET_AL() > 2)
814 goto int13_fail;
815
816 locks = bios_dsk->devices[device].lock;
817
818 switch (GET_AL()) {
819 case 0 : // lock
820 if (locks == 0xff) {
821 SET_AH(0xb4);
822 SET_AL(1);
823 goto int13_fail_noah;
824 }
825 bios_dsk->devices[device].lock = ++locks;
826 SET_AL(1);
827 break;
828 case 1 : // unlock
829 if (locks == 0x00) {
830 SET_AH(0xb0);
831 SET_AL(0);
832 goto int13_fail_noah;
833 }
834 bios_dsk->devices[device].lock = --locks;
835 SET_AL(locks==0?0:1);
836 break;
837 case 2 : // status
838 SET_AL(locks==0?0:1);
839 break;
840 }
841 goto int13_success;
842 break;
843
844 case 0x46: // IBM/MS eject media
845 locks = bios_dsk->devices[device].lock;
846
847 if (locks != 0) {
848 SET_AH(0xb1); // media locked
849 goto int13_fail_noah;
850 }
851 // FIXME should handle 0x31 no media in device
852 // FIXME should handle 0xb5 valid request failed
853
854#if 0 //@todo: implement!
855 // Call removable media eject
856 ASM_START
857 push bp
858 mov bp, sp
859
860 mov ah, #0x52
861 int #0x15
862 mov _int13_cdrom.status + 2[bp], ah
863 jnc int13_cdrom_rme_end
864 mov _int13_cdrom.status, #1
865int13_cdrom_rme_end:
866 pop bp
867 ASM_END
868#endif
869
870 if (status != 0) {
871 SET_AH(0xb1); // media locked
872 goto int13_fail_noah;
873 }
874
875 goto int13_success;
876 break;
877
878 //@todo: Part of this should be merged with analogous code in disk.c
879 case 0x48: // IBM/MS get drive parameters
880 dpt = DS :> (dpt_t *)SI;
881 size = dpt->size;
882
883 // Buffer is too small
884 if (size < 0x1a)
885 goto int13_fail;
886
887 // EDD 1.x
888 if (size >= 0x1a) {
889 uint16_t blksize;
890
891 blksize = bios_dsk->devices[device].blksize;
892
893 dpt->size = 0x1a;
894 dpt->infos = 0x74; /* Removable, media change, lockable, max values */
895 dpt->cylinders = 0xffffffff;
896 dpt->heads = 0xffffffff;
897 dpt->spt = 0xffffffff;
898 dpt->blksize = blksize;
899 dpt->sector_count1 = 0xffffffff; // FIXME should be Bit64
900 dpt->sector_count2 = 0xffffffff;
901 }
902
903 // EDD 2.x
904 if(size >= 0x1e) {
905 uint8_t channel, irq, mode, checksum, i;
906 uint16_t iobase1, iobase2, options;
907
908 dpt->size = 0x1e;
909 dpt->dpte_segment = ebda_seg;
910 dpt->dpte_offset = (uint16_t)&EbdaData->bdisk.dpte;
911
912 // Fill in dpte
913 channel = device / 2;
914 iobase1 = bios_dsk->channels[channel].iobase1;
915 iobase2 = bios_dsk->channels[channel].iobase2;
916 irq = bios_dsk->channels[channel].irq;
917 mode = bios_dsk->devices[device].mode;
918
919 // FIXME atapi device
920 options = (1<<4); // lba translation
921 options |= (1<<5); // removable device
922 options |= (1<<6); // atapi device
923 options |= (mode==ATA_MODE_PIO32?1:0<<7);
924
925 bios_dsk->dpte.iobase1 = iobase1;
926 bios_dsk->dpte.iobase2 = iobase2;
927 bios_dsk->dpte.prefix = (0xe | (device % 2))<<4;
928 bios_dsk->dpte.unused = 0xcb;
929 bios_dsk->dpte.irq = irq;
930 bios_dsk->dpte.blkcount = 1 ;
931 bios_dsk->dpte.dma = 0;
932 bios_dsk->dpte.pio = 0;
933 bios_dsk->dpte.options = options;
934 bios_dsk->dpte.reserved = 0;
935 bios_dsk->dpte.revision = 0x11;
936
937 checksum = 0;
938 for (i = 0; i < 15; ++i)
939 checksum += read_byte(ebda_seg, (uint16_t)&EbdaData->bdisk.dpte + i);
940 checksum = -checksum;
941 bios_dsk->dpte.checksum = checksum;
942 }
943
944 // EDD 3.x
945 if(size >= 0x42) {
946 uint8_t channel, iface, checksum, i;
947 uint16_t iobase1;
948
949 channel = device / 2;
950 iface = bios_dsk->channels[channel].iface;
951 iobase1 = bios_dsk->channels[channel].iobase1;
952
953 dpt->size = 0x42;
954 dpt->key = 0xbedd;
955 dpt->dpi_length = 0x24;
956 dpt->reserved1 = 0;
957 dpt->reserved2 = 0;
958
959 if (iface == ATA_IFACE_ISA) {
960 dpt->host_bus[0] = 'I';
961 dpt->host_bus[1] = 'S';
962 dpt->host_bus[2] = 'A';
963 dpt->host_bus[3] = ' ';
964 }
965 else {
966 // FIXME PCI
967 }
968 dpt->iface_type[0] = 'A';
969 dpt->iface_type[1] = 'T';
970 dpt->iface_type[2] = 'A';
971 dpt->iface_type[3] = ' ';
972 dpt->iface_type[4] = ' ';
973 dpt->iface_type[5] = ' ';
974 dpt->iface_type[6] = ' ';
975 dpt->iface_type[7] = ' ';
976
977 if (iface == ATA_IFACE_ISA) {
978 ((uint16_t __far *)dpt->iface_path)[0] = iobase1;
979 ((uint16_t __far *)dpt->iface_path)[1] = 0;
980 ((uint32_t __far *)dpt->iface_path)[1] = 0;
981 }
982 else {
983 // FIXME PCI
984 }
985 ((uint16_t __far *)dpt->device_path)[0] = device & 1;
986 ((uint16_t __far *)dpt->device_path)[1] = 0;
987 ((uint32_t __far *)dpt->device_path)[1] = 0;
988
989 checksum = 0;
990 for (i = 30; i < 64; ++i)
991 checksum += ((uint8_t __far *)dpt)[i];
992 checksum = -checksum;
993 dpt->checksum = checksum;
994 }
995
996 goto int13_success;
997 break;
998
999 case 0x49: // IBM/MS extended media change
1000 // always send changed ??
1001 SET_AH(06);
1002 goto int13_fail_nostatus;
1003 break;
1004
1005 case 0x4e: // // IBM/MS set hardware configuration
1006 // DMA, prefetch, PIO maximum not supported
1007 switch (GET_AL()) {
1008 case 0x01:
1009 case 0x03:
1010 case 0x04:
1011 case 0x06:
1012 goto int13_success;
1013 break;
1014 default :
1015 goto int13_fail;
1016 }
1017 break;
1018
1019 // all those functions return unimplemented
1020 case 0x02: /* read sectors */
1021 case 0x04: /* verify sectors */
1022 case 0x08: /* read disk drive parameters */
1023 case 0x0a: /* read disk sectors with ECC */
1024 case 0x0b: /* write disk sectors with ECC */
1025 case 0x18: /* set media type for format */
1026 case 0x50: // ? - send packet command
1027 default:
1028 BX_INFO("%s: unsupported AH=%02x\n", __func__, GET_AH());
1029 goto int13_fail;
1030 break;
1031 }
1032
1033int13_fail:
1034 SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
1035int13_fail_noah:
1036 SET_DISK_RET_STATUS(GET_AH());
1037int13_fail_nostatus:
1038 SET_CF(); // error occurred
1039 return;
1040
1041int13_success:
1042 SET_AH(0x00); // no error
1043int13_success_noah:
1044 SET_DISK_RET_STATUS(0x00);
1045 CLEAR_CF(); // no error
1046 return;
1047}
1048
1049// ---------------------------------------------------------------------------
1050// End of int13 for cdrom
1051// ---------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette