VirtualBox

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

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

BIOS: Initial AHCI CD-ROM support.

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