VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS-new/eltorito.c@ 39571

Last change on this file since 39571 was 39571, checked in by vboxsync, 13 years ago

Made ATAPI command building somewhat sane.

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

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