VirtualBox

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

Last change on this file since 78374 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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