VirtualBox

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

Last change on this file since 89384 was 89384, checked in by vboxsync, 4 years ago

Devices/PC/BIOS: Allocate the bounce buffer only when booting from a CD drive to avoid stealing memory always, rename atapi_read to cdrom_read, bugref:4841

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