VirtualBox

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

最後變更 在這個檔案從69496是 69496,由 vboxsync 提交於 7 年 前

*: scm --update-copyright-year

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

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