VirtualBox

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

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

PC/BIOS: Added LGPL disclaimer text where appropriate.

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

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