VirtualBox

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

Last change on this file since 44528 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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