VirtualBox

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

Last change on this file was 100713, checked in by vboxsync, 9 months ago

BIOS: Needed to adjust int13_cdrom() signature after orgs.asm changes, duh.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use