VirtualBox

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

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

Converted system BIOS to Watcom C.

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