Home | History | Annotate | Download | only in bios
      1 /////////////////////////////////////////////////////////////////////////
      2 // $Id$
      3 /////////////////////////////////////////////////////////////////////////
      4 //
      5 //  Copyright (C) 2002  MandrakeSoft S.A.
      6 //
      7 //    MandrakeSoft S.A.
      8 //    43, rue d'Aboukir
      9 //    75002 Paris - France
     10 //    http://www.linux-mandrake.com/
     11 //    http://www.mandrakesoft.com/
     12 //
     13 //  This library is free software; you can redistribute it and/or
     14 //  modify it under the terms of the GNU Lesser General Public
     15 //  License as published by the Free Software Foundation; either
     16 //  version 2 of the License, or (at your option) any later version.
     17 //
     18 //  This library is distributed in the hope that it will be useful,
     19 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
     20 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21 //  Lesser General Public License for more details.
     22 //
     23 //  You should have received a copy of the GNU Lesser General Public
     24 //  License along with this library; if not, write to the Free Software
     25 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
     26 
     27 // ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
     28 
     29 
     30 // ROM BIOS compatability entry points:
     31 // ===================================
     32 // $e05b ; POST Entry Point
     33 // $e2c3 ; NMI Handler Entry Point
     34 // $e3fe ; INT 13h Fixed Disk Services Entry Point
     35 // $e401 ; Fixed Disk Parameter Table
     36 // $e6f2 ; INT 19h Boot Load Service Entry Point
     37 // $e6f5 ; Configuration Data Table
     38 // $e729 ; Baud Rate Generator Table
     39 // $e739 ; INT 14h Serial Communications Service Entry Point
     40 // $e82e ; INT 16h Keyboard Service Entry Point
     41 // $e987 ; INT 09h Keyboard Service Entry Point
     42 // $ec59 ; INT 13h Diskette Service Entry Point
     43 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
     44 // $efc7 ; Diskette Controller Parameter Table
     45 // $efd2 ; INT 17h Printer Service Entry Point
     46 // $f045 ; INT 10 Functions 0-Fh Entry Point
     47 // $f065 ; INT 10h Video Support Service Entry Point
     48 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
     49 // $f841 ; INT 12h Memory Size Service Entry Point
     50 // $f84d ; INT 11h Equipment List Service Entry Point
     51 // $f859 ; INT 15h System Services Entry Point
     52 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
     53 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
     54 // $fea5 ; INT 08h System Timer ISR Entry Point
     55 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
     56 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
     57 // $ff54 ; INT 05h Print Screen Service Entry Point
     58 // $fff0 ; Power-up Entry Point
     59 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
     60 // $fffe ; System Model ID
     61 
     62 // NOTES for ATA/ATAPI driver (cbbochs (at) free.fr)
     63 //   Features
     64 //     - supports up to 4 ATA interfaces
     65 //     - device/geometry detection
     66 //     - 16bits/32bits device access
     67 //     - pchs/lba access
     68 //     - datain/dataout/packet command support
     69 //
     70 // NOTES for El-Torito Boot (cbbochs (at) free.fr)
     71 //   - CD-ROM booting is only available if ATA/ATAPI Driver is available
     72 //   - Current code is only able to boot mono-session cds
     73 //   - Current code can not boot and emulate a hard-disk
     74 //     the bios will panic otherwise
     75 //   - Current code also use memory in EBDA segement.
     76 //   - I used cmos byte 0x3D to store extended information on boot-device
     77 //   - Code has to be modified modified to handle multiple cdrom drives
     78 //   - Here are the cdrom boot failure codes:
     79 //       1 : no atapi device found
     80 //       2 : no atapi cdrom found
     81 //       3 : can not read cd - BRVD
     82 //       4 : cd is not eltorito (BRVD)
     83 //       5 : cd is not eltorito (ISO TAG)
     84 //       6 : cd is not eltorito (ELTORITO TAG)
     85 //       7 : can not read cd - boot catalog
     86 //       8 : boot catalog : bad header
     87 //       9 : boot catalog : bad platform
     88 //      10 : boot catalog : bad signature
     89 //      11 : boot catalog : bootable flag not set
     90 //      12 : can not read cd - boot image
     91 //
     92 //   ATA driver
     93 //   - EBDA segment.
     94 //     I used memory starting at 0x121 in the segment
     95 //   - the translation policy is defined in cmos regs 0x39 & 0x3a
     96 //
     97 // TODO :
     98 //
     99 //   int74
    100 //     - needs to be reworked.  Uses direct [bp] offsets. (?)
    101 //
    102 //   int13:
    103 //     - f04 (verify sectors) isn't complete  (?)
    104 //     - f02/03/04 should set current cyl,etc in BDA  (?)
    105 //     - rewrite int13_relocated & clean up int13 entry code
    106 //
    107 //   NOTES:
    108 //   - NMI access (bit7 of addr written to 70h)
    109 //
    110 //   ATA driver
    111 //   - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
    112 //   - could send the multiple-sector read/write commands
    113 //
    114 //   El-Torito
    115 //   - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
    116 //   - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
    117 //   - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
    118 //   - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
    119 //     This is ok. But DL should be reincremented afterwards.
    120 //   - Fix all "FIXME ElTorito Various"
    121 //   - should be able to boot any cdrom instead of the first one
    122 //
    123 //   BCC Bug: find a generic way to handle the bug of #asm after an "if"  (fixed in 0.16.7)
    124 
    125 #include "rombios.h"
    126 
    127 #define DEBUG_ATA          0
    128 #define DEBUG_INT13_HD     0
    129 #define DEBUG_INT13_CD     0
    130 #define DEBUG_INT13_ET     0
    131 #define DEBUG_INT13_FL     0
    132 #define DEBUG_INT15        0
    133 #define DEBUG_INT16        0
    134 #define DEBUG_INT1A        0
    135 #define DEBUG_INT74        0
    136 #define DEBUG_APM          0
    137 
    138 #define BX_CPU           3
    139 #define BX_USE_PS2_MOUSE 1
    140 #define BX_CALL_INT15_4F 1
    141 #define BX_USE_EBDA      1
    142 #define BX_SUPPORT_FLOPPY 1
    143 #define BX_FLOPPY_ON_CNT 37   /* 2 seconds */
    144 #define BX_PCIBIOS       1
    145 #define BX_APM           1
    146 
    147 #define BX_USE_ATADRV    1
    148 #define BX_ELTORITO_BOOT 1
    149 
    150 #define BX_MAX_ATA_INTERFACES   4
    151 #define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
    152 
    153 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
    154 #define BX_DEBUG_SERIAL  0 /* output to COM1 */
    155 
    156    /* model byte 0xFC = AT */
    157 #define SYS_MODEL_ID     0xFC
    158 #define SYS_SUBMODEL_ID  0x00
    159 #define BIOS_REVISION    1
    160 #define BIOS_CONFIG_TABLE 0xe6f5
    161 
    162 #ifndef BIOS_BUILD_DATE
    163 #  define BIOS_BUILD_DATE "06/23/99"
    164 #endif
    165 
    166   // 1K of base memory used for Extended Bios Data Area (EBDA)
    167   // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
    168 #define EBDA_SEG           0x9FC0
    169 #define EBDA_SIZE          1              // In KiB
    170 #define BASE_MEM_IN_K   (640 - EBDA_SIZE)
    171 
    172 /* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
    173 #define IPL_SEG              0x9ff0
    174 #define IPL_TABLE_OFFSET     0x0000
    175 #define IPL_TABLE_ENTRIES    8
    176 #define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
    177 #define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
    178 #define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
    179 #define IPL_SIZE             0xff
    180 #define IPL_TYPE_FLOPPY      0x01
    181 #define IPL_TYPE_HARDDISK    0x02
    182 #define IPL_TYPE_CDROM       0x03
    183 #define IPL_TYPE_BEV         0x80
    184 
    185   // Sanity Checks
    186 #if BX_USE_ATADRV && BX_CPU<3
    187 #    error The ATA/ATAPI Driver can only to be used with a 386+ cpu
    188 #endif
    189 #if BX_USE_ATADRV && !BX_USE_EBDA
    190 #    error ATA/ATAPI Driver can only be used if EBDA is available
    191 #endif
    192 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
    193 #    error El-Torito Boot can only be use if ATA/ATAPI Driver is available
    194 #endif
    195 #if BX_PCIBIOS && BX_CPU<3
    196 #    error PCI BIOS can only be used with 386+ cpu
    197 #endif
    198 #if BX_APM && BX_CPU<3
    199 #    error APM BIOS can only be used with 386+ cpu
    200 #endif
    201 
    202 // define this if you want to make PCIBIOS working on a specific bridge only
    203 // undef enables PCIBIOS when at least one PCI device is found
    204 // i440FX is emulated by Bochs and QEMU
    205 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
    206 
    207 // #20  is dec 20
    208 // #$20 is hex 20 = 32
    209 // #0x20 is hex 20 = 32
    210 // LDA  #$20
    211 // JSR  $E820
    212 // LDD  .i,S
    213 // JSR  $C682
    214 // mov al, #$20
    215 
    216 // all hex literals should be prefixed with '0x'
    217 //   grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
    218 // no mov SEG-REG, #value, must mov register into seg-reg
    219 //   grep -i "mov[ ]*.s" rombios.c
    220 
    221 // This is for compiling with gcc2 and gcc3
    222 #define ASM_START #asm
    223 #define ASM_END #endasm
    224 
    225 ASM_START
    226 .rom
    227 
    228 .org 0x0000
    229 
    230 #if BX_CPU >= 3
    231 use16 386
    232 #else
    233 use16 286
    234 #endif
    235 
    236 MACRO HALT
    237   ;; the HALT macro is called with the line number of the HALT call.
    238   ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex
    239   ;; to print a BX_PANIC message.  This will normally halt the simulation
    240   ;; with a message such as "BIOS panic at rombios.c, line 4091".
    241   ;; However, users can choose to make panics non-fatal and continue.
    242 #if BX_VIRTUAL_PORTS
    243   mov dx,#PANIC_PORT
    244   mov ax,#?1
    245   out dx,ax
    246 #else
    247   mov dx,#0x80
    248   mov ax,#?1
    249   out dx,al
    250 #endif
    251 MEND
    252 
    253 MACRO JMP_AP
    254   db 0xea
    255   dw ?2
    256   dw ?1
    257 MEND
    258 
    259 MACRO SET_INT_VECTOR
    260   mov ax, ?3
    261   mov ?1*4, ax
    262   mov ax, ?2
    263   mov ?1*4+2, ax
    264 MEND
    265 
    266 ASM_END
    267 
    268 typedef unsigned char  Bit8u;
    269 typedef unsigned short Bit16u;
    270 typedef unsigned short bx_bool;
    271 typedef unsigned long  Bit32u;
    272 
    273 
    274   void memsetb(seg,offset,value,count);
    275   void memcpyb(dseg,doffset,sseg,soffset,count);
    276   void memcpyd(dseg,doffset,sseg,soffset,count);
    277 
    278   // memset of count bytes
    279     void
    280   memsetb(seg,offset,value,count)
    281     Bit16u seg;
    282     Bit16u offset;
    283     Bit16u value;
    284     Bit16u count;
    285   {
    286   ASM_START
    287     push bp
    288     mov  bp, sp
    289 
    290       push ax
    291       push cx
    292       push es
    293       push di
    294 
    295       mov  cx, 10[bp] ; count
    296       test cx, cx
    297       je   memsetb_end
    298       mov  ax, 4[bp] ; segment
    299       mov  es, ax
    300       mov  ax, 6[bp] ; offset
    301       mov  di, ax
    302       mov  al, 8[bp] ; value
    303       cld
    304       rep
    305        stosb
    306 
    307   memsetb_end:
    308       pop di
    309       pop es
    310       pop cx
    311       pop ax
    312 
    313     pop bp
    314   ASM_END
    315   }
    316 
    317   // memcpy of count bytes
    318     void
    319   memcpyb(dseg,doffset,sseg,soffset,count)
    320     Bit16u dseg;
    321     Bit16u doffset;
    322     Bit16u sseg;
    323     Bit16u soffset;
    324     Bit16u count;
    325   {
    326   ASM_START
    327     push bp
    328     mov  bp, sp
    329 
    330       push ax
    331       push cx
    332       push es
    333       push di
    334       push ds
    335       push si
    336 
    337       mov  cx, 12[bp] ; count
    338       test cx, cx
    339       je   memcpyb_end
    340       mov  ax, 4[bp] ; dsegment
    341       mov  es, ax
    342       mov  ax, 6[bp] ; doffset
    343       mov  di, ax
    344       mov  ax, 8[bp] ; ssegment
    345       mov  ds, ax
    346       mov  ax, 10[bp] ; soffset
    347       mov  si, ax
    348       cld
    349       rep
    350        movsb
    351 
    352   memcpyb_end:
    353       pop si
    354       pop ds
    355       pop di
    356       pop es
    357       pop cx
    358       pop ax
    359 
    360     pop bp
    361   ASM_END
    362   }
    363 
    364   // memcpy of count dword
    365     void
    366   memcpyd(dseg,doffset,sseg,soffset,count)
    367     Bit16u dseg;
    368     Bit16u doffset;
    369     Bit16u sseg;
    370     Bit16u soffset;
    371     Bit16u count;
    372   {
    373   ASM_START
    374     push bp
    375     mov  bp, sp
    376 
    377       push ax
    378       push cx
    379       push es
    380       push di
    381       push ds
    382       push si
    383 
    384       mov  cx, 12[bp] ; count
    385       test cx, cx
    386       je   memcpyd_end
    387       mov  ax, 4[bp] ; dsegment
    388       mov  es, ax
    389       mov  ax, 6[bp] ; doffset
    390       mov  di, ax
    391       mov  ax, 8[bp] ; ssegment
    392       mov  ds, ax
    393       mov  ax, 10[bp] ; soffset
    394       mov  si, ax
    395       cld
    396       rep
    397        movsd
    398 
    399   memcpyd_end:
    400       pop si
    401       pop ds
    402       pop di
    403       pop es
    404       pop cx
    405       pop ax
    406 
    407     pop bp
    408   ASM_END
    409   }
    410 
    411   // read_dword and write_dword functions
    412   static Bit32u         read_dword();
    413   static void           write_dword();
    414 
    415     Bit32u
    416   read_dword(seg, offset)
    417     Bit16u seg;
    418     Bit16u offset;
    419   {
    420   ASM_START
    421     push bp
    422     mov  bp, sp
    423 
    424       push bx
    425       push ds
    426       mov  ax, 4[bp] ; segment
    427       mov  ds, ax
    428       mov  bx, 6[bp] ; offset
    429       mov  ax, [bx]
    430       add  bx, #2
    431       mov  dx, [bx]
    432       ;; ax = return value (word)
    433       ;; dx = return value (word)
    434       pop  ds
    435       pop  bx
    436 
    437     pop  bp
    438   ASM_END
    439   }
    440 
    441     void
    442   write_dword(seg, offset, data)
    443     Bit16u seg;
    444     Bit16u offset;
    445     Bit32u data;
    446   {
    447   ASM_START
    448     push bp
    449     mov  bp, sp
    450 
    451       push ax
    452       push bx
    453       push ds
    454       mov  ax, 4[bp] ; segment
    455       mov  ds, ax
    456       mov  bx, 6[bp] ; offset
    457       mov  ax, 8[bp] ; data word
    458       mov  [bx], ax  ; write data word
    459       add  bx, #2
    460       mov  ax, 10[bp] ; data word
    461       mov  [bx], ax  ; write data word
    462       pop  ds
    463       pop  bx
    464       pop  ax
    465 
    466     pop  bp
    467   ASM_END
    468   }
    469 
    470   // Bit32u (unsigned long) and long helper functions
    471   ASM_START
    472 
    473   ;; and function
    474   landl:
    475   landul:
    476     SEG SS
    477       and ax,[di]
    478     SEG SS
    479       and bx,2[di]
    480     ret
    481 
    482   ;; add function
    483   laddl:
    484   laddul:
    485     SEG SS
    486       add ax,[di]
    487     SEG SS
    488       adc bx,2[di]
    489     ret
    490 
    491   ;; cmp function
    492   lcmpl:
    493   lcmpul:
    494     and eax, #0x0000FFFF
    495     shl ebx, #16
    496     or  eax, ebx
    497     shr ebx, #16
    498     SEG SS
    499       cmp eax, dword ptr [di]
    500     ret
    501 
    502   ;; sub function
    503   lsubl:
    504   lsubul:
    505     SEG SS
    506     sub ax,[di]
    507     SEG SS
    508     sbb bx,2[di]
    509     ret
    510 
    511   ;; mul function
    512   lmull:
    513   lmulul:
    514     and eax, #0x0000FFFF
    515     shl ebx, #16
    516     or  eax, ebx
    517     SEG SS
    518     mul eax, dword ptr [di]
    519     mov ebx, eax
    520     shr ebx, #16
    521     ret
    522 
    523   ;; dec function
    524   ldecl:
    525   ldecul:
    526     SEG SS
    527     dec dword ptr [bx]
    528     ret
    529 
    530   ;; or function
    531   lorl:
    532   lorul:
    533     SEG SS
    534     or  ax,[di]
    535     SEG SS
    536     or  bx,2[di]
    537     ret
    538 
    539   ;; inc function
    540   lincl:
    541   lincul:
    542     SEG SS
    543     inc dword ptr [bx]
    544     ret
    545 
    546   ;; tst function
    547   ltstl:
    548   ltstul:
    549     and eax, #0x0000FFFF
    550     shl ebx, #16
    551     or  eax, ebx
    552     shr ebx, #16
    553     test eax, eax
    554     ret
    555 
    556   ;; sr function
    557   lsrul:
    558     mov  cx,di
    559     jcxz lsr_exit
    560     and  eax, #0x0000FFFF
    561     shl  ebx, #16
    562     or   eax, ebx
    563   lsr_loop:
    564     shr  eax, #1
    565     loop lsr_loop
    566     mov  ebx, eax
    567     shr  ebx, #16
    568   lsr_exit:
    569     ret
    570 
    571   ;; sl function
    572   lsll:
    573   lslul:
    574     mov  cx,di
    575     jcxz lsl_exit
    576     and  eax, #0x0000FFFF
    577     shl  ebx, #16
    578     or   eax, ebx
    579   lsl_loop:
    580     shl  eax, #1
    581     loop lsl_loop
    582     mov  ebx, eax
    583     shr  ebx, #16
    584   lsl_exit:
    585     ret
    586 
    587   idiv_:
    588     cwd
    589     idiv bx
    590     ret
    591 
    592   idiv_u:
    593     xor dx,dx
    594     div bx
    595     ret
    596 
    597   ldivul:
    598     and  eax, #0x0000FFFF
    599     shl  ebx, #16
    600     or   eax, ebx
    601     xor  edx, edx
    602     SEG SS
    603     mov  bx,  2[di]
    604     shl  ebx, #16
    605     SEG SS
    606     mov  bx,  [di]
    607     div  ebx
    608     mov  ebx, eax
    609     shr  ebx, #16
    610     ret
    611 
    612   ASM_END
    613 
    614 // for access to RAM area which is used by interrupt vectors
    615 // and BIOS Data Area
    616 
    617 typedef struct {
    618   unsigned char filler1[0x400];
    619   unsigned char filler2[0x6c];
    620   Bit16u ticks_low;
    621   Bit16u ticks_high;
    622   Bit8u  midnight_flag;
    623   } bios_data_t;
    624 
    625 #define BiosData ((bios_data_t  *) 0)
    626 
    627 #if BX_USE_ATADRV
    628   typedef struct {
    629     Bit16u heads;      // # heads
    630     Bit16u cylinders;  // # cylinders
    631     Bit16u spt;        // # sectors / track
    632     } chs_t;
    633 
    634   // DPTE definition
    635   typedef struct {
    636     Bit16u iobase1;
    637     Bit16u iobase2;
    638     Bit8u  prefix;
    639     Bit8u  unused;
    640     Bit8u  irq;
    641     Bit8u  blkcount;
    642     Bit8u  dma;
    643     Bit8u  pio;
    644     Bit16u options;
    645     Bit16u reserved;
    646     Bit8u  revision;
    647     Bit8u  checksum;
    648     } dpte_t;
    649 
    650   typedef struct {
    651     Bit8u  iface;        // ISA or PCI
    652     Bit16u iobase1;      // IO Base 1
    653     Bit16u iobase2;      // IO Base 2
    654     Bit8u  irq;          // IRQ
    655     } ata_channel_t;
    656 
    657   typedef struct {
    658     Bit8u  type;         // Detected type of ata (ata/atapi/none/unknown)
    659     Bit8u  device;       // Detected type of attached devices (hd/cd/none)
    660     Bit8u  removable;    // Removable device flag
    661     Bit8u  lock;         // Locks for removable devices
    662     Bit8u  mode;         // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
    663     Bit16u blksize;      // block size
    664 
    665     Bit8u  translation;  // type of translation
    666     chs_t  lchs;         // Logical CHS
    667     chs_t  pchs;         // Physical CHS
    668 
    669     Bit32u sectors_low;  // Total sectors count
    670     Bit32u sectors_high;
    671     } ata_device_t;
    672 
    673   typedef struct {
    674     // ATA channels info
    675     ata_channel_t channels[BX_MAX_ATA_INTERFACES];
    676 
    677     // ATA devices info
    678     ata_device_t  devices[BX_MAX_ATA_DEVICES];
    679     //
    680     // map between (bios hd id - 0x80) and ata channels
    681     Bit8u  hdcount, hdidmap[BX_MAX_ATA_DEVICES];
    682 
    683     // map between (bios cd id - 0xE0) and ata channels
    684     Bit8u  cdcount, cdidmap[BX_MAX_ATA_DEVICES];
    685 
    686     // Buffer for DPTE table
    687     dpte_t dpte;
    688 
    689     // Count of transferred sectors and bytes
    690     Bit16u trsfsectors;
    691     Bit32u trsfbytes;
    692 
    693     } ata_t;
    694 
    695 #if BX_ELTORITO_BOOT
    696   // ElTorito Device Emulation data
    697   typedef struct {
    698     Bit8u  active;
    699     Bit8u  media;
    700     Bit8u  emulated_drive;
    701     Bit8u  controller_index;
    702     Bit16u device_spec;
    703     Bit32u ilba;
    704     Bit16u buffer_segment;
    705     Bit16u load_segment;
    706     Bit16u sector_count;
    707 
    708     // Virtual device
    709     chs_t  vdevice;
    710     } cdemu_t;
    711 #endif // BX_ELTORITO_BOOT
    712 
    713   // for access to EBDA area
    714   //     The EBDA structure should conform to
    715   //     http://www.frontiernet.net/~fys/rombios.htm document
    716   //     I made the ata and cdemu structs begin at 0x121 in the EBDA seg
    717   // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot
    718   // device tables are at IPL_SEG
    719   typedef struct {
    720     unsigned char filler1[0x3D];
    721 
    722     // FDPT - Can be splitted in data members if needed
    723     unsigned char fdpt0[0x10];
    724     unsigned char fdpt1[0x10];
    725 
    726     unsigned char filler2[0xC4];
    727 
    728     // ATA Driver data
    729     ata_t   ata;
    730 
    731 #if BX_ELTORITO_BOOT
    732     // El Torito Emulation data
    733     cdemu_t cdemu;
    734 #endif // BX_ELTORITO_BOOT
    735 
    736     } ebda_data_t;
    737 
    738   #define EbdaData ((ebda_data_t *) 0)
    739 
    740   // for access to the int13ext structure
    741   typedef struct {
    742     Bit8u  size;
    743     Bit8u  reserved;
    744     Bit16u count;
    745     Bit16u offset;
    746     Bit16u segment;
    747     Bit32u lba1;
    748     Bit32u lba2;
    749     } int13ext_t;
    750 
    751   #define Int13Ext ((int13ext_t *) 0)
    752 
    753   // Disk Physical Table definition
    754   typedef struct {
    755     Bit16u  size;
    756     Bit16u  infos;
    757     Bit32u  cylinders;
    758     Bit32u  heads;
    759     Bit32u  spt;
    760     Bit32u  sector_count1;
    761     Bit32u  sector_count2;
    762     Bit16u  blksize;
    763     Bit16u  dpte_offset;
    764     Bit16u  dpte_segment;
    765     Bit16u  key;
    766     Bit8u   dpi_length;
    767     Bit8u   reserved1;
    768     Bit16u  reserved2;
    769     Bit8u   host_bus[4];
    770     Bit8u   iface_type[8];
    771     Bit8u   iface_path[8];
    772     Bit8u   device_path[8];
    773     Bit8u   reserved3;
    774     Bit8u   checksum;
    775     } dpt_t;
    776 
    777   #define Int13DPT ((dpt_t *) 0)
    778 
    779 #endif // BX_USE_ATADRV
    780 
    781 typedef struct {
    782   union {
    783     struct {
    784       Bit16u di, si, bp, sp;
    785       Bit16u bx, dx, cx, ax;
    786       } r16;
    787     struct {
    788       Bit16u filler[4];
    789       Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
    790       } r8;
    791     } u;
    792   } pusha_regs_t;
    793 
    794 typedef struct {
    795  union {
    796   struct {
    797     Bit32u edi, esi, ebp, esp;
    798     Bit32u ebx, edx, ecx, eax;
    799     } r32;
    800   struct {
    801     Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
    802     Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
    803     } r16;
    804   struct {
    805     Bit32u filler[4];
    806     Bit8u  bl, bh;
    807     Bit16u filler1;
    808     Bit8u  dl, dh;
    809     Bit16u filler2;
    810     Bit8u  cl, ch;
    811     Bit16u filler3;
    812     Bit8u  al, ah;
    813     Bit16u filler4;
    814     } r8;
    815   } u;
    816 } pushad_regs_t;
    817 
    818 typedef struct {
    819   union {
    820     struct {
    821       Bit16u flags;
    822       } r16;
    823     struct {
    824       Bit8u  flagsl;
    825       Bit8u  flagsh;
    826       } r8;
    827     } u;
    828   } flags_t;
    829 
    830 #define SetCF(x)   x.u.r8.flagsl |= 0x01
    831 #define SetZF(x)   x.u.r8.flagsl |= 0x40
    832 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
    833 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
    834 #define GetCF(x)   (x.u.r8.flagsl & 0x01)
    835 
    836 typedef struct {
    837   Bit16u ip;
    838   Bit16u cs;
    839   flags_t flags;
    840   } iret_addr_t;
    841 
    842 typedef struct {
    843   Bit16u type;
    844   Bit16u flags;
    845   Bit32u vector;
    846   Bit32u description;
    847   Bit32u reserved;
    848   } ipl_entry_t;
    849 
    850 
    851 
    852 static Bit8u          inb();
    853 static Bit8u          inb_cmos();
    854 static void           outb();
    855 static void           outb_cmos();
    856 static Bit16u         inw();
    857 static void           outw();
    858 static void           init_rtc();
    859 static bx_bool        rtc_updating();
    860 
    861 static Bit8u          read_byte();
    862 static Bit16u         read_word();
    863 static void           write_byte();
    864 static void           write_word();
    865 static void           bios_printf();
    866 
    867 static Bit8u          inhibit_mouse_int_and_events();
    868 static void           enable_mouse_int_and_events();
    869 static Bit8u          send_to_mouse_ctrl();
    870 static Bit8u          get_mouse_data();
    871 static void           set_kbd_command_byte();
    872 
    873 static void           int09_function();
    874 static void           int13_harddisk();
    875 static void           int13_cdrom();
    876 static void           int13_cdemu();
    877 static void           int13_eltorito();
    878 static void           int13_diskette_function();
    879 static void           int14_function();
    880 static void           int15_function();
    881 static void           int16_function();
    882 static void           int17_function();
    883 static void           int19_function();
    884 static void           int1a_function();
    885 static void           int70_function();
    886 static void           int74_function();
    887 static Bit16u         get_CS();
    888 static Bit16u         get_SS();
    889 static unsigned int   enqueue_key();
    890 static unsigned int   dequeue_key();
    891 static void           get_hd_geometry();
    892 static void           set_diskette_ret_status();
    893 static void           set_diskette_current_cyl();
    894 static void           determine_floppy_media();
    895 static bx_bool        floppy_drive_exists();
    896 static bx_bool        floppy_drive_recal();
    897 static bx_bool        floppy_media_known();
    898 static bx_bool        floppy_media_sense();
    899 static bx_bool        set_enable_a20();
    900 static void           debugger_on();
    901 static void           debugger_off();
    902 static void           keyboard_init();
    903 static void           keyboard_panic();
    904 static void           shutdown_status_panic();
    905 static void           nmi_handler_msg();
    906 static void           delay_ticks();
    907 static void           delay_ticks_and_check_for_keystroke();
    908 
    909 static void           interactive_bootkey();
    910 static void           print_bios_banner();
    911 static void           print_boot_device();
    912 static void           print_boot_failure();
    913 static void           print_cdromboot_failure();
    914 
    915 # if BX_USE_ATADRV
    916 
    917 // ATA / ATAPI driver
    918 void   ata_init();
    919 void   ata_detect();
    920 void   ata_reset();
    921 
    922 Bit16u ata_cmd_non_data();
    923 Bit16u ata_cmd_data_in();
    924 Bit16u ata_cmd_data_out();
    925 Bit16u ata_cmd_packet();
    926 
    927 Bit16u atapi_get_sense();
    928 Bit16u atapi_is_ready();
    929 Bit16u atapi_is_cdrom();
    930 
    931 #endif // BX_USE_ATADRV
    932 
    933 #if BX_ELTORITO_BOOT
    934 
    935 void   cdemu_init();
    936 Bit8u  cdemu_isactive();
    937 Bit8u  cdemu_emulated_drive();
    938 
    939 Bit16u cdrom_boot();
    940 
    941 #endif // BX_ELTORITO_BOOT
    942 
    943 static char bios_cvs_version_string[] = "$Revision$ $Date$";
    944 
    945 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
    946 
    947 #if DEBUG_ATA
    948 #  define BX_DEBUG_ATA(a...) BX_DEBUG(a)
    949 #else
    950 #  define BX_DEBUG_ATA(a...)
    951 #endif
    952 #if DEBUG_INT13_HD
    953 #  define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
    954 #else
    955 #  define BX_DEBUG_INT13_HD(a...)
    956 #endif
    957 #if DEBUG_INT13_CD
    958 #  define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
    959 #else
    960 #  define BX_DEBUG_INT13_CD(a...)
    961 #endif
    962 #if DEBUG_INT13_ET
    963 #  define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
    964 #else
    965 #  define BX_DEBUG_INT13_ET(a...)
    966 #endif
    967 #if DEBUG_INT13_FL
    968 #  define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
    969 #else
    970 #  define BX_DEBUG_INT13_FL(a...)
    971 #endif
    972 #if DEBUG_INT15
    973 #  define BX_DEBUG_INT15(a...) BX_DEBUG(a)
    974 #else
    975 #  define BX_DEBUG_INT15(a...)
    976 #endif
    977 #if DEBUG_INT16
    978 #  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
    979 #else
    980 #  define BX_DEBUG_INT16(a...)
    981 #endif
    982 #if DEBUG_INT1A
    983 #  define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
    984 #else
    985 #  define BX_DEBUG_INT1A(a...)
    986 #endif
    987 #if DEBUG_INT74
    988 #  define BX_DEBUG_INT74(a...) BX_DEBUG(a)
    989 #else
    990 #  define BX_DEBUG_INT74(a...)
    991 #endif
    992 
    993 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
    994 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
    995 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
    996 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
    997 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
    998 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
    999 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
   1000 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
   1001 
   1002 #define GET_AL() ( AX & 0x00ff )
   1003 #define GET_BL() ( BX & 0x00ff )
   1004 #define GET_CL() ( CX & 0x00ff )
   1005 #define GET_DL() ( DX & 0x00ff )
   1006 #define GET_AH() ( AX >> 8 )
   1007 #define GET_BH() ( BX >> 8 )
   1008 #define GET_CH() ( CX >> 8 )
   1009 #define GET_DH() ( DX >> 8 )
   1010 
   1011 #define GET_ELDL() ( ELDX & 0x00ff )
   1012 #define GET_ELDH() ( ELDX >> 8 )
   1013 
   1014 #define SET_CF()     FLAGS |= 0x0001
   1015 #define CLEAR_CF()   FLAGS &= 0xfffe
   1016 #define GET_CF()     (FLAGS & 0x0001)
   1017 
   1018 #define SET_ZF()     FLAGS |= 0x0040
   1019 #define CLEAR_ZF()   FLAGS &= 0xffbf
   1020 #define GET_ZF()     (FLAGS & 0x0040)
   1021 
   1022 #define UNSUPPORTED_FUNCTION 0x86
   1023 
   1024 #define none 0
   1025 #define MAX_SCAN_CODE 0x58
   1026 
   1027 static struct {
   1028   Bit16u normal;
   1029   Bit16u shift;
   1030   Bit16u control;
   1031   Bit16u alt;
   1032   Bit8u lock_flags;
   1033   } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
   1034       {   none,   none,   none,   none, none },
   1035       { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
   1036       { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
   1037       { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
   1038       { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
   1039       { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
   1040       { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
   1041       { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
   1042       { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
   1043       { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
   1044       { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
   1045       { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
   1046       { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
   1047       { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
   1048       { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
   1049       { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
   1050       { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
   1051       { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
   1052       { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
   1053       { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
   1054       { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
   1055       { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
   1056       { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
   1057       { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
   1058       { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
   1059       { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
   1060       { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
   1061       { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
   1062       { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
   1063       {   none,   none,   none,   none, none }, /* L Ctrl */
   1064       { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
   1065       { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
   1066       { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
   1067       { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
   1068       { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
   1069       { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
   1070       { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
   1071       { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
   1072       { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
   1073       { 0x273b, 0x273a,   none,   none, none }, /* ;: */
   1074       { 0x2827, 0x2822,   none,   none, none }, /* '" */
   1075       { 0x2960, 0x297e,   none,   none, none }, /* `~ */
   1076       {   none,   none,   none,   none, none }, /* L shift */
   1077       { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
   1078       { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
   1079       { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
   1080       { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
   1081       { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
   1082       { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
   1083       { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
   1084       { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
   1085       { 0x332c, 0x333c,   none,   none, none }, /* ,< */
   1086       { 0x342e, 0x343e,   none,   none, none }, /* .> */
   1087       { 0x352f, 0x353f,   none,   none, none }, /* /? */
   1088       {   none,   none,   none,   none, none }, /* R Shift */
   1089       { 0x372a, 0x372a,   none,   none, none }, /* * */
   1090       {   none,   none,   none,   none, none }, /* L Alt */
   1091       { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
   1092       {   none,   none,   none,   none, none }, /* caps lock */
   1093       { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
   1094       { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
   1095       { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
   1096       { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
   1097       { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
   1098       { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
   1099       { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
   1100       { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
   1101       { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
   1102       { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
   1103       {   none,   none,   none,   none, none }, /* Num Lock */
   1104       {   none,   none,   none,   none, none }, /* Scroll Lock */
   1105       { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
   1106       { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
   1107       { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
   1108       { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
   1109       { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
   1110       { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
   1111       { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
   1112       { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
   1113       { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
   1114       { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
   1115       { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
   1116       { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
   1117       { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
   1118       {   none,   none,   none,   none, none },
   1119       {   none,   none,   none,   none, none },
   1120       { 0x565c, 0x567c,   none,   none, none }, /* \| */
   1121       { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
   1122       { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
   1123       };
   1124 
   1125   Bit8u
   1126 inb(port)
   1127   Bit16u port;
   1128 {
   1129 ASM_START
   1130   push bp
   1131   mov  bp, sp
   1132 
   1133     push dx
   1134     mov  dx, 4[bp]
   1135     in   al, dx
   1136     pop  dx
   1137 
   1138   pop  bp
   1139 ASM_END
   1140 }
   1141 
   1142 #if BX_USE_ATADRV
   1143   Bit16u
   1144 inw(port)
   1145   Bit16u port;
   1146 {
   1147 ASM_START
   1148   push bp
   1149   mov  bp, sp
   1150 
   1151     push dx
   1152     mov  dx, 4[bp]
   1153     in   ax, dx
   1154     pop  dx
   1155 
   1156   pop  bp
   1157 ASM_END
   1158 }
   1159 #endif
   1160 
   1161   void
   1162 outb(port, val)
   1163   Bit16u port;
   1164   Bit8u  val;
   1165 {
   1166 ASM_START
   1167   push bp
   1168   mov  bp, sp
   1169 
   1170     push ax
   1171     push dx
   1172     mov  dx, 4[bp]
   1173     mov  al, 6[bp]
   1174     out  dx, al
   1175     pop  dx
   1176     pop  ax
   1177 
   1178   pop  bp
   1179 ASM_END
   1180 }
   1181 
   1182 #if BX_USE_ATADRV
   1183   void
   1184 outw(port, val)
   1185   Bit16u port;
   1186   Bit16u  val;
   1187 {
   1188 ASM_START
   1189   push bp
   1190   mov  bp, sp
   1191 
   1192     push ax
   1193     push dx
   1194     mov  dx, 4[bp]
   1195     mov  ax, 6[bp]
   1196     out  dx, ax
   1197     pop  dx
   1198     pop  ax
   1199 
   1200   pop  bp
   1201 ASM_END
   1202 }
   1203 #endif
   1204 
   1205   void
   1206 outb_cmos(cmos_reg, val)
   1207   Bit8u cmos_reg;
   1208   Bit8u val;
   1209 {
   1210 ASM_START
   1211   push bp
   1212   mov  bp, sp
   1213 
   1214     mov  al, 4[bp] ;; cmos_reg
   1215     out  0x70, al
   1216     mov  al, 6[bp] ;; val
   1217     out  0x71, al
   1218 
   1219   pop  bp
   1220 ASM_END
   1221 }
   1222 
   1223   Bit8u
   1224 inb_cmos(cmos_reg)
   1225   Bit8u cmos_reg;
   1226 {
   1227 ASM_START
   1228   push bp
   1229   mov  bp, sp
   1230 
   1231     mov  al, 4[bp] ;; cmos_reg
   1232     out 0x70, al
   1233     in  al, 0x71
   1234 
   1235   pop  bp
   1236 ASM_END
   1237 }
   1238 
   1239   void
   1240 init_rtc()
   1241 {
   1242   outb_cmos(0x0a, 0x26);
   1243   outb_cmos(0x0b, 0x02);
   1244   inb_cmos(0x0c);
   1245   inb_cmos(0x0d);
   1246 }
   1247 
   1248   bx_bool
   1249 rtc_updating()
   1250 {
   1251   // This function checks to see if the update-in-progress bit
   1252   // is set in CMOS Status Register A.  If not, it returns 0.
   1253   // If it is set, it tries to wait until there is a transition
   1254   // to 0, and will return 0 if such a transition occurs.  A 1
   1255   // is returned only after timing out.  The maximum period
   1256   // that this bit should be set is constrained to 244useconds.
   1257   // The count I use below guarantees coverage or more than
   1258   // this time, with any reasonable IPS setting.
   1259 
   1260   Bit16u count;
   1261 
   1262   count = 25000;
   1263   while (--count != 0) {
   1264     if ( (inb_cmos(0x0a) & 0x80) == 0 )
   1265       return(0);
   1266     }
   1267   return(1); // update-in-progress never transitioned to 0
   1268 }
   1269 
   1270 
   1271   Bit8u
   1272 read_byte(seg, offset)
   1273   Bit16u seg;
   1274   Bit16u offset;
   1275 {
   1276 ASM_START
   1277   push bp
   1278   mov  bp, sp
   1279 
   1280     push bx
   1281     push ds
   1282     mov  ax, 4[bp] ; segment
   1283     mov  ds, ax
   1284     mov  bx, 6[bp] ; offset
   1285     mov  al, [bx]
   1286     ;; al = return value (byte)
   1287     pop  ds
   1288     pop  bx
   1289 
   1290   pop  bp
   1291 ASM_END
   1292 }
   1293 
   1294   Bit16u
   1295 read_word(seg, offset)
   1296   Bit16u seg;
   1297   Bit16u offset;
   1298 {
   1299 ASM_START
   1300   push bp
   1301   mov  bp, sp
   1302 
   1303     push bx
   1304     push ds
   1305     mov  ax, 4[bp] ; segment
   1306     mov  ds, ax
   1307     mov  bx, 6[bp] ; offset
   1308     mov  ax, [bx]
   1309     ;; ax = return value (word)
   1310     pop  ds
   1311     pop  bx
   1312 
   1313   pop  bp
   1314 ASM_END
   1315 }
   1316 
   1317   void
   1318 write_byte(seg, offset, data)
   1319   Bit16u seg;
   1320   Bit16u offset;
   1321   Bit8u data;
   1322 {
   1323 ASM_START
   1324   push bp
   1325   mov  bp, sp
   1326 
   1327     push ax
   1328     push bx
   1329     push ds
   1330     mov  ax, 4[bp] ; segment
   1331     mov  ds, ax
   1332     mov  bx, 6[bp] ; offset
   1333     mov  al, 8[bp] ; data byte
   1334     mov  [bx], al  ; write data byte
   1335     pop  ds
   1336     pop  bx
   1337     pop  ax
   1338 
   1339   pop  bp
   1340 ASM_END
   1341 }
   1342 
   1343   void
   1344 write_word(seg, offset, data)
   1345   Bit16u seg;
   1346   Bit16u offset;
   1347   Bit16u data;
   1348 {
   1349 ASM_START
   1350   push bp
   1351   mov  bp, sp
   1352 
   1353     push ax
   1354     push bx
   1355     push ds
   1356     mov  ax, 4[bp] ; segment
   1357     mov  ds, ax
   1358     mov  bx, 6[bp] ; offset
   1359     mov  ax, 8[bp] ; data word
   1360     mov  [bx], ax  ; write data word
   1361     pop  ds
   1362     pop  bx
   1363     pop  ax
   1364 
   1365   pop  bp
   1366 ASM_END
   1367 }
   1368 
   1369   Bit16u
   1370 get_CS()
   1371 {
   1372 ASM_START
   1373   mov  ax, cs
   1374 ASM_END
   1375 }
   1376 
   1377   Bit16u
   1378 get_SS()
   1379 {
   1380 ASM_START
   1381   mov  ax, ss
   1382 ASM_END
   1383 }
   1384 
   1385 #if BX_DEBUG_SERIAL
   1386 /* serial debug port*/
   1387 #define BX_DEBUG_PORT 0x03f8
   1388 
   1389 /* data */
   1390 #define UART_RBR 0x00
   1391 #define UART_THR 0x00
   1392 
   1393 /* control */
   1394 #define UART_IER 0x01
   1395 #define UART_IIR 0x02
   1396 #define UART_FCR 0x02
   1397 #define UART_LCR 0x03
   1398 #define UART_MCR 0x04
   1399 #define UART_DLL 0x00
   1400 #define UART_DLM 0x01
   1401 
   1402 /* status */
   1403 #define UART_LSR 0x05
   1404 #define UART_MSR 0x06
   1405 #define UART_SCR 0x07
   1406 
   1407 int uart_can_tx_byte(base_port)
   1408     Bit16u base_port;
   1409 {
   1410     return inb(base_port + UART_LSR) & 0x20;
   1411 }
   1412 
   1413 void uart_wait_to_tx_byte(base_port)
   1414     Bit16u base_port;
   1415 {
   1416     while (!uart_can_tx_byte(base_port));
   1417 }
   1418 
   1419 void uart_wait_until_sent(base_port)
   1420     Bit16u base_port;
   1421 {
   1422     while (!(inb(base_port + UART_LSR) & 0x40));
   1423 }
   1424 
   1425 void uart_tx_byte(base_port, data)
   1426     Bit16u base_port;
   1427     Bit8u data;
   1428 {
   1429     uart_wait_to_tx_byte(base_port);
   1430     outb(base_port + UART_THR, data);
   1431     uart_wait_until_sent(base_port);
   1432 }
   1433 #endif
   1434 
   1435   void
   1436 wrch(c)
   1437   Bit8u  c;
   1438 {
   1439   ASM_START
   1440   push bp
   1441   mov  bp, sp
   1442 
   1443   push bx
   1444   mov  ah, #0x0e
   1445   mov  al, 4[bp]
   1446   xor  bx,bx
   1447   int  #0x10
   1448   pop  bx
   1449 
   1450   pop  bp
   1451   ASM_END
   1452 }
   1453 
   1454   void
   1455 send(action, c)
   1456   Bit16u action;
   1457   Bit8u  c;
   1458 {
   1459 #if BX_DEBUG_SERIAL
   1460   if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
   1461   uart_tx_byte(BX_DEBUG_PORT, c);
   1462 #endif
   1463 #if BX_VIRTUAL_PORTS
   1464   if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
   1465   if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
   1466 #endif
   1467   if (action & BIOS_PRINTF_SCREEN) {
   1468     if (c == '\n') wrch('\r');
   1469     wrch(c);
   1470   }
   1471 }
   1472 
   1473   void
   1474 put_int(action, val, width, neg)
   1475   Bit16u action;
   1476   short val, width;
   1477   bx_bool neg;
   1478 {
   1479   short nval = val / 10;
   1480   if (nval)
   1481     put_int(action, nval, width - 1, neg);
   1482   else {
   1483     while (--width > 0) send(action, ' ');
   1484     if (neg) send(action, '-');
   1485   }
   1486   send(action, val - (nval * 10) + '0');
   1487 }
   1488 
   1489   void
   1490 put_uint(action, val, width, neg)
   1491   Bit16u action;
   1492   unsigned short val;
   1493   short width;
   1494   bx_bool neg;
   1495 {
   1496   unsigned short nval = val / 10;
   1497   if (nval)
   1498     put_uint(action, nval, width - 1, neg);
   1499   else {
   1500     while (--width > 0) send(action, ' ');
   1501     if (neg) send(action, '-');
   1502   }
   1503   send(action, val - (nval * 10) + '0');
   1504 }
   1505 
   1506   void
   1507 put_luint(action, val, width, neg)
   1508   Bit16u action;
   1509   unsigned long val;
   1510   short width;
   1511   bx_bool neg;
   1512 {
   1513   unsigned long nval = val / 10;
   1514   if (nval)
   1515     put_luint(action, nval, width - 1, neg);
   1516   else {
   1517     while (--width > 0) send(action, ' ');
   1518     if (neg) send(action, '-');
   1519   }
   1520   send(action, val - (nval * 10) + '0');
   1521 }
   1522 
   1523 void put_str(action, segment, offset)
   1524   Bit16u action;
   1525   Bit16u segment;
   1526   Bit16u offset;
   1527 {
   1528   Bit8u c;
   1529 
   1530   while (c = read_byte(segment, offset)) {
   1531     send(action, c);
   1532     offset++;
   1533   }
   1534 }
   1535 
   1536   void
   1537 delay_ticks(ticks)
   1538   Bit16u ticks;
   1539 {
   1540   long ticks_to_wait, delta;
   1541   Bit32u prev_ticks, t;
   1542 
   1543    /*
   1544     * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
   1545     * We also have to be careful about interrupt storms.
   1546     */
   1547 ASM_START
   1548   pushf
   1549   sti
   1550 ASM_END
   1551   ticks_to_wait = ticks;
   1552   prev_ticks = read_dword(0x0, 0x46c);
   1553   do
   1554   {
   1555 ASM_START
   1556     hlt
   1557 ASM_END
   1558     t = read_dword(0x0, 0x46c);
   1559     if (t > prev_ticks)
   1560     {
   1561       delta = t - prev_ticks;     /* The temp var is required or bcc screws up. */
   1562       ticks_to_wait -= delta;
   1563     }
   1564     else if (t < prev_ticks)
   1565     {
   1566       ticks_to_wait -= t;         /* wrapped */
   1567     }
   1568 
   1569     prev_ticks = t;
   1570   } while (ticks_to_wait > 0);
   1571 ASM_START
   1572   cli
   1573   popf
   1574 ASM_END
   1575 }
   1576 
   1577   Bit8u
   1578 check_for_keystroke()
   1579 {
   1580 ASM_START
   1581   mov  ax, #0x100
   1582   int  #0x16
   1583   jz   no_key
   1584   mov  al, #1
   1585   jmp  done
   1586 no_key:
   1587   xor  al, al
   1588 done:
   1589 ASM_END
   1590 }
   1591 
   1592   Bit8u
   1593 get_keystroke()
   1594 {
   1595 ASM_START
   1596   mov  ax, #0x0
   1597   int  #0x16
   1598   xchg ah, al
   1599 ASM_END
   1600 }
   1601 
   1602   void
   1603 delay_ticks_and_check_for_keystroke(ticks, count)
   1604   Bit16u ticks, count;
   1605 {
   1606   Bit16u i;
   1607   for (i = 1; i <= count; i++) {
   1608     delay_ticks(ticks);
   1609     if (check_for_keystroke())
   1610       break;
   1611   }
   1612 }
   1613 
   1614 //--------------------------------------------------------------------------
   1615 // bios_printf()
   1616 //   A compact variable argument printf function.
   1617 //
   1618 //   Supports %[format_width][length]format
   1619 //   where format can be x,X,u,d,s,S,c
   1620 //   and the optional length modifier is l (ell)
   1621 //--------------------------------------------------------------------------
   1622   void
   1623 bios_printf(action, s)
   1624   Bit16u action;
   1625   Bit8u *s;
   1626 {
   1627   Bit8u c, format_char;
   1628   bx_bool  in_format;
   1629   short i;
   1630   Bit16u  *arg_ptr;
   1631   Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
   1632 
   1633   arg_ptr = &s;
   1634   arg_seg = get_SS();
   1635 
   1636   in_format = 0;
   1637   format_width = 0;
   1638 
   1639   if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
   1640 #if BX_VIRTUAL_PORTS
   1641     outb(PANIC_PORT2, 0x00);
   1642 #endif
   1643     bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
   1644   }
   1645 
   1646   while (c = read_byte(get_CS(), s)) {
   1647     if ( c == '%' ) {
   1648       in_format = 1;
   1649       format_width = 0;
   1650       }
   1651     else if (in_format) {
   1652       if ( (c>='0') && (c<='9') ) {
   1653         format_width = (format_width * 10) + (c - '0');
   1654         }
   1655       else {
   1656         arg_ptr++; // increment to next arg
   1657         arg = read_word(arg_seg, arg_ptr);
   1658         if (c == 'x' || c == 'X') {
   1659           if (format_width == 0)
   1660             format_width = 4;
   1661           if (c == 'x')
   1662             hexadd = 'a';
   1663           else
   1664             hexadd = 'A';
   1665           for (i=format_width-1; i>=0; i--) {
   1666             nibble = (arg >> (4 * i)) & 0x000f;
   1667             send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
   1668             }
   1669           }
   1670         else if (c == 'u') {
   1671           put_uint(action, arg, format_width, 0);
   1672           }
   1673         else if (c == 'l') {
   1674           s++;
   1675           c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
   1676           arg_ptr++; /* increment to next arg */
   1677           hibyte = read_word(arg_seg, arg_ptr);
   1678           if (c == 'd') {
   1679             if (hibyte & 0x8000)
   1680               put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
   1681             else
   1682               put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
   1683            }
   1684           else if (c == 'u') {
   1685             put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
   1686            }
   1687           else if (c == 'x' || c == 'X')
   1688            {
   1689             if (format_width == 0)
   1690               format_width = 8;
   1691             if (c == 'x')
   1692               hexadd = 'a';
   1693             else
   1694               hexadd = 'A';
   1695             for (i=format_width-1; i>=0; i--) {
   1696               nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
   1697               send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
   1698               }
   1699            }
   1700           }
   1701         else if (c == 'd') {
   1702           if (arg & 0x8000)
   1703             put_int(action, -arg, format_width - 1, 1);
   1704           else
   1705             put_int(action, arg, format_width, 0);
   1706           }
   1707         else if (c == 's') {
   1708           put_str(action, get_CS(), arg);
   1709           }
   1710         else if (c == 'S') {
   1711           hibyte = arg;
   1712           arg_ptr++;
   1713           arg = read_word(arg_seg, arg_ptr);
   1714           put_str(action, hibyte, arg);
   1715           }
   1716         else if (c == 'c') {
   1717           send(action, arg);
   1718           }
   1719         else
   1720           BX_PANIC("bios_printf: unknown format\n");
   1721           in_format = 0;
   1722         }
   1723       }
   1724     else {
   1725       send(action, c);
   1726       }
   1727     s ++;
   1728     }
   1729 
   1730   if (action & BIOS_PRINTF_HALT) {
   1731     // freeze in a busy loop.
   1732 ASM_START
   1733     cli
   1734  halt2_loop:
   1735     hlt
   1736     jmp halt2_loop
   1737 ASM_END
   1738     }
   1739 }
   1740 
   1741 //--------------------------------------------------------------------------
   1742 // keyboard_init
   1743 //--------------------------------------------------------------------------
   1744 // this file is based on LinuxBIOS implementation of keyboard.c
   1745 // could convert to #asm to gain space
   1746   void
   1747 keyboard_init()
   1748 {
   1749     Bit16u max;
   1750 
   1751     /* ------------------- Flush buffers ------------------------*/
   1752     /* Wait until buffer is empty */
   1753     max=0xffff;
   1754     while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
   1755 
   1756     /* flush incoming keys */
   1757     max=0x2000;
   1758     while (--max > 0) {
   1759         outb(0x80, 0x00);
   1760         if (inb(0x64) & 0x01) {
   1761             inb(0x60);
   1762             max = 0x2000;
   1763             }
   1764         }
   1765 
   1766     // Due to timer issues, and if the IPS setting is > 15000000,
   1767     // the incoming keys might not be flushed here. That will
   1768     // cause a panic a few lines below.  See sourceforge bug report :
   1769     // [ 642031 ] FATAL: Keyboard RESET error:993
   1770 
   1771     /* ------------------- controller side ----------------------*/
   1772     /* send cmd = 0xAA, self test 8042 */
   1773     outb(0x64, 0xaa);
   1774 
   1775     /* Wait until buffer is empty */
   1776     max=0xffff;
   1777     while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
   1778     if (max==0x0) keyboard_panic(00);
   1779 
   1780     /* Wait for data */
   1781     max=0xffff;
   1782     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
   1783     if (max==0x0) keyboard_panic(01);
   1784 
   1785     /* read self-test result, 0x55 should be returned from 0x60 */
   1786     if ((inb(0x60) != 0x55)){
   1787         keyboard_panic(991);
   1788     }
   1789 
   1790     /* send cmd = 0xAB, keyboard interface test */
   1791     outb(0x64,0xab);
   1792 
   1793     /* Wait until buffer is empty */
   1794     max=0xffff;
   1795     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
   1796     if (max==0x0) keyboard_panic(10);
   1797 
   1798     /* Wait for data */
   1799     max=0xffff;
   1800     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
   1801     if (max==0x0) keyboard_panic(11);
   1802 
   1803     /* read keyboard interface test result, */
   1804     /* 0x00 should be returned form 0x60 */
   1805     if ((inb(0x60) != 0x00)) {
   1806         keyboard_panic(992);
   1807     }
   1808 
   1809     /* Enable Keyboard clock */
   1810     outb(0x64,0xae);
   1811     outb(0x64,0xa8);
   1812 
   1813     /* ------------------- keyboard side ------------------------*/
   1814     /* reset kerboard and self test  (keyboard side) */
   1815     outb(0x60, 0xff);
   1816 
   1817     /* Wait until buffer is empty */
   1818     max=0xffff;
   1819     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
   1820     if (max==0x0) keyboard_panic(20);
   1821 
   1822     /* Wait for data */
   1823     max=0xffff;
   1824     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
   1825     if (max==0x0) keyboard_panic(21);
   1826 
   1827     /* keyboard should return ACK */
   1828     if ((inb(0x60) != 0xfa)) {
   1829         keyboard_panic(993);
   1830     }
   1831 
   1832     /* Wait for data */
   1833     max=0xffff;
   1834     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
   1835     if (max==0x0) keyboard_panic(31);
   1836 
   1837     if ((inb(0x60) != 0xaa)) {
   1838         keyboard_panic(994);
   1839     }
   1840 
   1841     /* Disable keyboard */
   1842     outb(0x60, 0xf5);
   1843 
   1844     /* Wait until buffer is empty */
   1845     max=0xffff;
   1846     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
   1847     if (max==0x0) keyboard_panic(40);
   1848 
   1849     /* Wait for data */
   1850     max=0xffff;
   1851     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
   1852     if (max==0x0) keyboard_panic(41);
   1853 
   1854     /* keyboard should return ACK */
   1855     if ((inb(0x60) != 0xfa)) {
   1856         keyboard_panic(995);
   1857     }
   1858 
   1859     /* Write Keyboard Mode */
   1860     outb(0x64, 0x60);
   1861 
   1862     /* Wait until buffer is empty */
   1863     max=0xffff;
   1864     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
   1865     if (max==0x0) keyboard_panic(50);
   1866 
   1867     /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
   1868     outb(0x60, 0x61);
   1869 
   1870     /* Wait until buffer is empty */
   1871     max=0xffff;
   1872     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
   1873     if (max==0x0) keyboard_panic(60);
   1874 
   1875     /* Enable keyboard */
   1876     outb(0x60, 0xf4);
   1877 
   1878     /* Wait until buffer is empty */
   1879     max=0xffff;
   1880     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
   1881     if (max==0x0) keyboard_panic(70);
   1882 
   1883     /* Wait for data */
   1884     max=0xffff;
   1885     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
   1886     if (max==0x0) keyboard_panic(70);
   1887 
   1888     /* keyboard should return ACK */
   1889     if ((inb(0x60) != 0xfa)) {
   1890         keyboard_panic(996);
   1891     }
   1892 
   1893     outb(0x80, 0x77);
   1894 }
   1895 
   1896 //--------------------------------------------------------------------------
   1897 // keyboard_panic
   1898 //--------------------------------------------------------------------------
   1899   void
   1900 keyboard_panic(status)
   1901   Bit16u status;
   1902 {
   1903   // If you're getting a 993 keyboard panic here,
   1904   // please see the comment in keyboard_init
   1905 
   1906   BX_PANIC("Keyboard error:%u\n",status);
   1907 }
   1908 
   1909 //--------------------------------------------------------------------------
   1910 // shutdown_status_panic
   1911 //   called when the shutdown statsu is not implemented, displays the status
   1912 //--------------------------------------------------------------------------
   1913   void
   1914 shutdown_status_panic(status)
   1915   Bit16u status;
   1916 {
   1917   BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
   1918 }
   1919 
   1920 void s3_resume_panic()
   1921 {
   1922   BX_PANIC("Returned from s3_resume.\n");
   1923 }
   1924 
   1925 //--------------------------------------------------------------------------
   1926 // print_bios_banner
   1927 //   displays a the bios version
   1928 //--------------------------------------------------------------------------
   1929 void
   1930 print_bios_banner()
   1931 {
   1932   printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
   1933     BIOS_BUILD_DATE, bios_cvs_version_string);
   1934   printf(
   1935 #if BX_APM
   1936   "apmbios "
   1937 #endif
   1938 #if BX_PCIBIOS
   1939   "pcibios "
   1940 #endif
   1941 #if BX_ELTORITO_BOOT
   1942   "eltorito "
   1943 #endif
   1944 #if BX_ROMBIOS32
   1945   "rombios32 "
   1946 #endif
   1947   "\n\n");
   1948 }
   1949 
   1950 //--------------------------------------------------------------------------
   1951 // BIOS Boot Specification 1.0.1 compatibility
   1952 //
   1953 // Very basic support for the BIOS Boot Specification, which allows expansion
   1954 // ROMs to register themselves as boot devices, instead of just stealing the
   1955 // INT 19h boot vector.
   1956 //
   1957 // This is a hack: to do it properly requires a proper PnP BIOS and we aren't
   1958 // one; we just lie to the option ROMs to make them behave correctly.
   1959 // We also don't support letting option ROMs register as bootable disk
   1960 // drives (BCVs), only as bootable devices (BEVs).
   1961 //
   1962 // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
   1963 //--------------------------------------------------------------------------
   1964 
   1965 static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
   1966 
   1967 static void
   1968 init_boot_vectors()
   1969 {
   1970   ipl_entry_t e;
   1971   Bit16u count = 0;
   1972   Bit16u ss = get_SS();
   1973 
   1974   /* Clear out the IPL table. */
   1975   memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
   1976 
   1977   /* User selected device not set */
   1978   write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
   1979 
   1980   /* Floppy drive */
   1981   e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
   1982   memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
   1983   count++;
   1984 
   1985   /* First HDD */
   1986   e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
   1987   memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
   1988   count++;
   1989 
   1990 #if BX_ELTORITO_BOOT
   1991   /* CDROM */
   1992   e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
   1993   memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
   1994   count++;
   1995 #endif
   1996 
   1997   /* Remember how many devices we have */
   1998   write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
   1999   /* Not tried booting anything yet */
   2000   write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
   2001 }
   2002 
   2003 static Bit8u
   2004 get_boot_vector(i, e)
   2005 Bit16u i; ipl_entry_t *e;
   2006 {
   2007   Bit16u count;
   2008   Bit16u ss = get_SS();
   2009   /* Get the count of boot devices, and refuse to overrun the array */
   2010   count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
   2011   if (i >= count) return 0;
   2012   /* OK to read this device */
   2013   memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
   2014   return 1;
   2015 }
   2016 
   2017 #if BX_ELTORITO_BOOT
   2018   void
   2019 interactive_bootkey()
   2020 {
   2021   ipl_entry_t e;
   2022   Bit16u count;
   2023   char description[33];
   2024   Bit8u scan_code;
   2025   Bit8u i;
   2026   Bit16u ss = get_SS();
   2027   Bit16u valid_choice = 0;
   2028 
   2029   while (check_for_keystroke())
   2030     get_keystroke();
   2031 
   2032   printf("Press F12 for boot menu.\n\n");
   2033 
   2034   delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
   2035   if (check_for_keystroke())
   2036   {
   2037     scan_code = get_keystroke();
   2038     if (scan_code == 0x86) /* F12 */
   2039     {
   2040       while (check_for_keystroke())
   2041         get_keystroke();
   2042 
   2043       printf("Select boot device:\n\n");
   2044 
   2045       count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
   2046       for (i = 0; i < count; i++)
   2047       {
   2048         memcpyb(ss, &e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
   2049         printf("%d. ", i+1);
   2050         switch(e.type)
   2051         {
   2052           case IPL_TYPE_FLOPPY:
   2053           case IPL_TYPE_HARDDISK:
   2054           case IPL_TYPE_CDROM:
   2055             printf("%s\n", drivetypes[e.type]);
   2056             break;
   2057           case IPL_TYPE_BEV:
   2058             printf("%s", drivetypes[4]);
   2059             if (e.description != 0)
   2060             {
   2061               memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
   2062               description[32] = 0;
   2063               printf(" [%S]", ss, description);
   2064            }
   2065            printf("\n");
   2066            break;
   2067         }
   2068       }
   2069 
   2070       count++;
   2071       while (!valid_choice) {
   2072         scan_code = get_keystroke();
   2073         if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
   2074         {
   2075           valid_choice = 1;
   2076         }
   2077         else if (scan_code <= count)
   2078         {
   2079           valid_choice = 1;
   2080           scan_code -= 1;
   2081           /* Set user selected device */
   2082           write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, scan_code);
   2083         }
   2084       }
   2085     printf("\n");
   2086     }
   2087   }
   2088 }
   2089 #endif // BX_ELTORITO_BOOT
   2090 
   2091 //--------------------------------------------------------------------------
   2092 // print_boot_device
   2093 //   displays the boot device
   2094 //--------------------------------------------------------------------------
   2095 
   2096 void
   2097 print_boot_device(e)
   2098   ipl_entry_t *e;
   2099 {
   2100   Bit16u type;
   2101   char description[33];
   2102   Bit16u ss = get_SS();
   2103   type = e->type;
   2104   /* NIC appears as type 0x80 */
   2105   if (type == IPL_TYPE_BEV) type = 0x4;
   2106   if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
   2107   printf("Booting from %s", drivetypes[type]);
   2108   /* print product string if BEV */
   2109   if (type == 4 && e->description != 0) {
   2110     /* first 32 bytes are significant */
   2111     memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
   2112     /* terminate string */
   2113     description[32] = 0;
   2114     printf(" [%S]", ss, description);
   2115   }
   2116   printf("...\n");
   2117 }
   2118 
   2119 //--------------------------------------------------------------------------
   2120 // print_boot_failure
   2121 //   displays the reason why boot failed
   2122 //--------------------------------------------------------------------------
   2123   void
   2124 print_boot_failure(type, reason)
   2125   Bit16u type; Bit8u reason;
   2126 {
   2127   if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
   2128 
   2129   printf("Boot failed");
   2130   if (type < 4) {
   2131     /* Report the reason too */
   2132     if (reason==0)
   2133       printf(": not a bootable disk");
   2134     else
   2135       printf(": could not read the boot disk");
   2136   }
   2137   printf("\n\n");
   2138 }
   2139 
   2140 //--------------------------------------------------------------------------
   2141 // print_cdromboot_failure
   2142 //   displays the reason why boot failed
   2143 //--------------------------------------------------------------------------
   2144   void
   2145 print_cdromboot_failure( code )
   2146   Bit16u code;
   2147 {
   2148   bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
   2149 
   2150   return;
   2151 }
   2152 
   2153 void
   2154 nmi_handler_msg()
   2155 {
   2156   BX_PANIC("NMI Handler called\n");
   2157 }
   2158 
   2159 void
   2160 int18_panic_msg()
   2161 {
   2162   BX_PANIC("INT18: BOOT FAILURE\n");
   2163 }
   2164 
   2165 void
   2166 log_bios_start()
   2167 {
   2168 #if BX_DEBUG_SERIAL
   2169   outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
   2170 #endif
   2171   BX_INFO("%s\n", bios_cvs_version_string);
   2172 }
   2173 
   2174   bx_bool
   2175 set_enable_a20(val)
   2176   bx_bool val;
   2177 {
   2178   Bit8u  oldval;
   2179 
   2180   // Use PS2 System Control port A to set A20 enable
   2181 
   2182   // get current setting first
   2183   oldval = inb(0x92);
   2184 
   2185   // change A20 status
   2186   if (val)
   2187     outb(0x92, oldval | 0x02);
   2188   else
   2189     outb(0x92, oldval & 0xfd);
   2190 
   2191   return((oldval & 0x02) != 0);
   2192 }
   2193 
   2194   void
   2195 debugger_on()
   2196 {
   2197   outb(0xfedc, 0x01);
   2198 }
   2199 
   2200   void
   2201 debugger_off()
   2202 {
   2203   outb(0xfedc, 0x00);
   2204 }
   2205 
   2206 int
   2207 s3_resume()
   2208 {
   2209     Bit32u s3_wakeup_vector;
   2210     Bit8u s3_resume_flag;
   2211 
   2212     s3_resume_flag = read_byte(0x40, 0xb0);
   2213     s3_wakeup_vector = read_dword(0x40, 0xb2);
   2214 
   2215     BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector);
   2216     if (s3_resume_flag != 0xFE || !s3_wakeup_vector)
   2217 	    return 0;
   2218 
   2219     write_byte(0x40, 0xb0, 0);
   2220 
   2221     /* setup wakeup vector */
   2222     write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */
   2223     write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */
   2224 
   2225     BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4),
   2226 		    (s3_wakeup_vector & 0xF));
   2227 ASM_START
   2228     jmpf [0x04b6]
   2229 ASM_END
   2230     return 1;
   2231 }
   2232 
   2233 #if BX_USE_ATADRV
   2234 
   2235 // ---------------------------------------------------------------------------
   2236 // Start of ATA/ATAPI Driver
   2237 // ---------------------------------------------------------------------------
   2238 
   2239 // Global defines -- ATA register and register bits.
   2240 // command block & control block regs
   2241 #define ATA_CB_DATA  0   // data reg         in/out pio_base_addr1+0
   2242 #define ATA_CB_ERR   1   // error            in     pio_base_addr1+1
   2243 #define ATA_CB_FR    1   // feature reg         out pio_base_addr1+1
   2244 #define ATA_CB_SC    2   // sector count     in/out pio_base_addr1+2
   2245 #define ATA_CB_SN    3   // sector number    in/out pio_base_addr1+3
   2246 #define ATA_CB_CL    4   // cylinder low     in/out pio_base_addr1+4
   2247 #define ATA_CB_CH    5   // cylinder high    in/out pio_base_addr1+5
   2248 #define ATA_CB_DH    6   // device head      in/out pio_base_addr1+6
   2249 #define ATA_CB_STAT  7   // primary status   in     pio_base_addr1+7
   2250 #define ATA_CB_CMD   7   // command             out pio_base_addr1+7
   2251 #define ATA_CB_ASTAT 6   // alternate status in     pio_base_addr2+6
   2252 #define ATA_CB_DC    6   // device control      out pio_base_addr2+6
   2253 #define ATA_CB_DA    7   // device address   in     pio_base_addr2+7
   2254 
   2255 #define ATA_CB_ER_ICRC 0x80    // ATA Ultra DMA bad CRC
   2256 #define ATA_CB_ER_BBK  0x80    // ATA bad block
   2257 #define ATA_CB_ER_UNC  0x40    // ATA uncorrected error
   2258 #define ATA_CB_ER_MC   0x20    // ATA media change
   2259 #define ATA_CB_ER_IDNF 0x10    // ATA id not found
   2260 #define ATA_CB_ER_MCR  0x08    // ATA media change request
   2261 #define ATA_CB_ER_ABRT 0x04    // ATA command aborted
   2262 #define ATA_CB_ER_NTK0 0x02    // ATA track 0 not found
   2263 #define ATA_CB_ER_NDAM 0x01    // ATA address mark not found
   2264 
   2265 #define ATA_CB_ER_P_SNSKEY 0xf0   // ATAPI sense key (mask)
   2266 #define ATA_CB_ER_P_MCR    0x08   // ATAPI Media Change Request
   2267 #define ATA_CB_ER_P_ABRT   0x04   // ATAPI command abort
   2268 #define ATA_CB_ER_P_EOM    0x02   // ATAPI End of Media
   2269 #define ATA_CB_ER_P_ILI    0x01   // ATAPI Illegal Length Indication
   2270 
   2271 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
   2272 #define ATA_CB_SC_P_TAG    0xf8   // ATAPI tag (mask)
   2273 #define ATA_CB_SC_P_REL    0x04   // ATAPI release
   2274 #define ATA_CB_SC_P_IO     0x02   // ATAPI I/O
   2275 #define ATA_CB_SC_P_CD     0x01   // ATAPI C/D
   2276 
   2277 // bits 7-4 of the device/head (CB_DH) reg
   2278 #define ATA_CB_DH_DEV0 0xa0    // select device 0
   2279 #define ATA_CB_DH_DEV1 0xb0    // select device 1
   2280 #define ATA_CB_DH_LBA 0x40    // use LBA
   2281 
   2282 // status reg (CB_STAT and CB_ASTAT) bits
   2283 #define ATA_CB_STAT_BSY  0x80  // busy
   2284 #define ATA_CB_STAT_RDY  0x40  // ready
   2285 #define ATA_CB_STAT_DF   0x20  // device fault
   2286 #define ATA_CB_STAT_WFT  0x20  // write fault (old name)
   2287 #define ATA_CB_STAT_SKC  0x10  // seek complete
   2288 #define ATA_CB_STAT_SERV 0x10  // service
   2289 #define ATA_CB_STAT_DRQ  0x08  // data request
   2290 #define ATA_CB_STAT_CORR 0x04  // corrected
   2291 #define ATA_CB_STAT_IDX  0x02  // index
   2292 #define ATA_CB_STAT_ERR  0x01  // error (ATA)
   2293 #define ATA_CB_STAT_CHK  0x01  // check (ATAPI)
   2294 
   2295 // device control reg (CB_DC) bits
   2296 #define ATA_CB_DC_HD15   0x08  // bit should always be set to one
   2297 #define ATA_CB_DC_SRST   0x04  // soft reset
   2298 #define ATA_CB_DC_NIEN   0x02  // disable interrupts
   2299 
   2300 // Most mandtory and optional ATA commands (from ATA-3),
   2301 #define ATA_CMD_CFA_ERASE_SECTORS            0xC0
   2302 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
   2303 #define ATA_CMD_CFA_TRANSLATE_SECTOR         0x87
   2304 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
   2305 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
   2306 #define ATA_CMD_CHECK_POWER_MODE1            0xE5
   2307 #define ATA_CMD_CHECK_POWER_MODE2            0x98
   2308 #define ATA_CMD_DEVICE_RESET                 0x08
   2309 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
   2310 #define ATA_CMD_FLUSH_CACHE                  0xE7
   2311 #define ATA_CMD_FORMAT_TRACK                 0x50
   2312 #define ATA_CMD_IDENTIFY_DEVICE              0xEC
   2313 #define ATA_CMD_IDENTIFY_DEVICE_PACKET       0xA1
   2314 #define ATA_CMD_IDENTIFY_PACKET_DEVICE       0xA1
   2315 #define ATA_CMD_IDLE1                        0xE3
   2316 #define ATA_CMD_IDLE2                        0x97
   2317 #define ATA_CMD_IDLE_IMMEDIATE1              0xE1
   2318 #define ATA_CMD_IDLE_IMMEDIATE2              0x95
   2319 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS  0x91
   2320 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
   2321 #define ATA_CMD_NOP                          0x00
   2322 #define ATA_CMD_PACKET                       0xA0
   2323 #define ATA_CMD_READ_BUFFER                  0xE4
   2324 #define ATA_CMD_READ_DMA                     0xC8
   2325 #define ATA_CMD_READ_DMA_QUEUED              0xC7
   2326 #define ATA_CMD_READ_MULTIPLE                0xC4
   2327 #define ATA_CMD_READ_SECTORS                 0x20
   2328 #define ATA_CMD_READ_VERIFY_SECTORS          0x40
   2329 #define ATA_CMD_RECALIBRATE                  0x10
   2330 #define ATA_CMD_REQUEST_SENSE                0x03
   2331 #define ATA_CMD_SEEK                         0x70
   2332 #define ATA_CMD_SET_FEATURES                 0xEF
   2333 #define ATA_CMD_SET_MULTIPLE_MODE            0xC6
   2334 #define ATA_CMD_SLEEP1                       0xE6
   2335 #define ATA_CMD_SLEEP2                       0x99
   2336 #define ATA_CMD_STANDBY1                     0xE2
   2337 #define ATA_CMD_STANDBY2                     0x96
   2338 #define ATA_CMD_STANDBY_IMMEDIATE1           0xE0
   2339 #define ATA_CMD_STANDBY_IMMEDIATE2           0x94
   2340 #define ATA_CMD_WRITE_BUFFER                 0xE8
   2341 #define ATA_CMD_WRITE_DMA                    0xCA
   2342 #define ATA_CMD_WRITE_DMA_QUEUED             0xCC
   2343 #define ATA_CMD_WRITE_MULTIPLE               0xC5
   2344 #define ATA_CMD_WRITE_SECTORS                0x30
   2345 #define ATA_CMD_WRITE_VERIFY                 0x3C
   2346 
   2347 #define ATA_IFACE_NONE    0x00
   2348 #define ATA_IFACE_ISA     0x00
   2349 #define ATA_IFACE_PCI     0x01
   2350 
   2351 #define ATA_TYPE_NONE     0x00
   2352 #define ATA_TYPE_UNKNOWN  0x01
   2353 #define ATA_TYPE_ATA      0x02
   2354 #define ATA_TYPE_ATAPI    0x03
   2355 
   2356 #define ATA_DEVICE_NONE  0x00
   2357 #define ATA_DEVICE_HD    0xFF
   2358 #define ATA_DEVICE_CDROM 0x05
   2359 
   2360 #define ATA_MODE_NONE    0x00
   2361 #define ATA_MODE_PIO16   0x00
   2362 #define ATA_MODE_PIO32   0x01
   2363 #define ATA_MODE_ISADMA  0x02
   2364 #define ATA_MODE_PCIDMA  0x03
   2365 #define ATA_MODE_USEIRQ  0x10
   2366 
   2367 #define ATA_TRANSLATION_NONE  0
   2368 #define ATA_TRANSLATION_LBA   1
   2369 #define ATA_TRANSLATION_LARGE 2
   2370 #define ATA_TRANSLATION_RECHS 3
   2371 
   2372 #define ATA_DATA_NO      0x00
   2373 #define ATA_DATA_IN      0x01
   2374 #define ATA_DATA_OUT     0x02
   2375 
   2376 // ---------------------------------------------------------------------------
   2377 // ATA/ATAPI driver : initialization
   2378 // ---------------------------------------------------------------------------
   2379 void ata_init( )
   2380 {
   2381   Bit16u ebda_seg=read_word(0x0040,0x000E);
   2382   Bit8u  channel, device;
   2383 
   2384   // Channels info init.
   2385   for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
   2386     write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
   2387     write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
   2388     write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
   2389     write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
   2390     }
   2391 
   2392   // Devices info init.
   2393   for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
   2394     write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
   2395     write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
   2396     write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
   2397     write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
   2398     write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
   2399     write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
   2400     write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
   2401     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
   2402     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
   2403     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
   2404     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
   2405     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
   2406     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
   2407 
   2408     write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L);
   2409     write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L);
   2410     }
   2411 
   2412   // hdidmap  and cdidmap init.
   2413   for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
   2414     write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
   2415     write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
   2416     }
   2417 
   2418   write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
   2419   write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
   2420 }
   2421 
   2422 #define TIMEOUT 0
   2423 #define BSY 1
   2424 #define NOT_BSY 2
   2425 #define NOT_BSY_DRQ 3
   2426 #define NOT_BSY_NOT_DRQ 4
   2427 #define NOT_BSY_RDY 5
   2428 
   2429 #define IDE_TIMEOUT 32000u //32 seconds max for IDE ops
   2430 
   2431 int await_ide();
   2432 static int await_ide(when_done,base,timeout)
   2433   Bit8u when_done;
   2434   Bit16u base;
   2435   Bit16u timeout;
   2436 {
   2437   Bit32u time=0,last=0;
   2438   Bit16u status;
   2439   Bit8u result;
   2440   status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away
   2441   for(;;) {
   2442     status = inb(base+ATA_CB_STAT);
   2443     time++;
   2444     if (when_done == BSY)
   2445       result = status & ATA_CB_STAT_BSY;
   2446     else if (when_done == NOT_BSY)
   2447       result = !(status & ATA_CB_STAT_BSY);
   2448     else if (when_done == NOT_BSY_DRQ)
   2449       result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ);
   2450     else if (when_done == NOT_BSY_NOT_DRQ)
   2451       result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ);
   2452     else if (when_done == NOT_BSY_RDY)
   2453       result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY);
   2454     else if (when_done == TIMEOUT)
   2455       result = 0;
   2456 
   2457     if (result) return 0;
   2458     if (time>>16 != last) // mod 2048 each 16 ms
   2459     {
   2460       last = time >>16;
   2461       BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
   2462     }
   2463     if (status & ATA_CB_STAT_ERR)
   2464     {
   2465       BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout);
   2466       return -1;
   2467     }
   2468     if ((timeout == 0) || ((time>>11) > timeout)) break;
   2469   }
   2470   BX_INFO("IDE time out\n");
   2471   return -1;
   2472 }
   2473 
   2474 // ---------------------------------------------------------------------------
   2475 // ATA/ATAPI driver : device detection
   2476 // ---------------------------------------------------------------------------
   2477 
   2478 void ata_detect( )
   2479 {
   2480   Bit16u ebda_seg=read_word(0x0040,0x000E);
   2481   Bit8u  hdcount, cdcount, device, type;
   2482   Bit8u  buffer[0x0200];
   2483 
   2484 #if BX_MAX_ATA_INTERFACES > 0
   2485   write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
   2486   write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
   2487   write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
   2488   write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
   2489 #endif
   2490 #if BX_MAX_ATA_INTERFACES > 1
   2491   write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
   2492   write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
   2493   write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
   2494   write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
   2495 #endif
   2496 #if BX_MAX_ATA_INTERFACES > 2
   2497   write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
   2498   write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
   2499   write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
   2500   write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
   2501 #endif
   2502 #if BX_MAX_ATA_INTERFACES > 3
   2503   write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
   2504   write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
   2505   write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
   2506   write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
   2507 #endif
   2508 #if BX_MAX_ATA_INTERFACES > 4
   2509 #error Please fill the ATA interface informations
   2510 #endif
   2511 
   2512   // Device detection
   2513   hdcount=cdcount=0;
   2514 
   2515   for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
   2516     Bit16u iobase1, iobase2;
   2517     Bit8u  channel, slave, shift;
   2518     Bit8u  sc, sn, cl, ch, st;
   2519 
   2520     channel = device / 2;
   2521     slave = device % 2;
   2522 
   2523     iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
   2524     iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
   2525 
   2526     // Disable interrupts
   2527     outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
   2528 
   2529     // Look for device
   2530     outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
   2531     outb(iobase1+ATA_CB_SC, 0x55);
   2532     outb(iobase1+ATA_CB_SN, 0xaa);
   2533     outb(iobase1+ATA_CB_SC, 0xaa);
   2534     outb(iobase1+ATA_CB_SN, 0x55);
   2535     outb(iobase1+ATA_CB_SC, 0x55);
   2536     outb(iobase1+ATA_CB_SN, 0xaa);
   2537 
   2538     // If we found something
   2539     sc = inb(iobase1+ATA_CB_SC);
   2540     sn = inb(iobase1+ATA_CB_SN);
   2541 
   2542     if ( (sc == 0x55) && (sn == 0xaa) ) {
   2543       write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
   2544 
   2545       // reset the channel
   2546       ata_reset(device);
   2547 
   2548       // check for ATA or ATAPI
   2549       outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
   2550       sc = inb(iobase1+ATA_CB_SC);
   2551       sn = inb(iobase1+ATA_CB_SN);
   2552       if ((sc==0x01) && (sn==0x01)) {
   2553         cl = inb(iobase1+ATA_CB_CL);
   2554         ch = inb(iobase1+ATA_CB_CH);
   2555         st = inb(iobase1+ATA_CB_STAT);
   2556 
   2557         if ((cl==0x14) && (ch==0xeb)) {
   2558           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
   2559         } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
   2560           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
   2561         } else if ((cl==0xff) && (ch==0xff)) {
   2562           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
   2563         }
   2564       }
   2565     }
   2566 
   2567     type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
   2568 
   2569     // Now we send a IDENTIFY command to ATA device
   2570     if(type == ATA_TYPE_ATA) {
   2571       Bit32u sectors_low, sectors_high;
   2572       Bit16u cylinders, heads, spt, blksize;
   2573       Bit8u  translation, removable, mode;
   2574 
   2575       //Temporary values to do the transfer
   2576       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
   2577       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
   2578 
   2579       if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 )
   2580         BX_PANIC("ata-detect: Failed to detect ATA device\n");
   2581 
   2582       removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
   2583       mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
   2584       blksize   = read_word(get_SS(),buffer+10);
   2585 
   2586       cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
   2587       heads     = read_word(get_SS(),buffer+(3*2)); // word 3
   2588       spt       = read_word(get_SS(),buffer+(6*2)); // word 6
   2589 
   2590       if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support
   2591         sectors_low  = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101
   2592         sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103
   2593       } else {
   2594         sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
   2595         sectors_high = 0;
   2596       }
   2597 
   2598       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
   2599       write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
   2600       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
   2601       write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
   2602       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
   2603       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
   2604       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
   2605       write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low);
   2606       write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high);
   2607       BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
   2608 
   2609       translation = inb_cmos(0x39 + channel/2);
   2610       for (shift=device%4; shift>0; shift--) translation >>= 2;
   2611       translation &= 0x03;
   2612 
   2613       write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
   2614 
   2615       switch (translation) {
   2616         case ATA_TRANSLATION_NONE:
   2617           BX_INFO("none");
   2618           break;
   2619         case ATA_TRANSLATION_LBA:
   2620           BX_INFO("lba");
   2621           break;
   2622         case ATA_TRANSLATION_LARGE:
   2623           BX_INFO("large");
   2624           break;
   2625         case ATA_TRANSLATION_RECHS:
   2626           BX_INFO("r-echs");
   2627           break;
   2628         }
   2629       switch (translation) {
   2630         case ATA_TRANSLATION_NONE:
   2631           break;
   2632         case ATA_TRANSLATION_LBA:
   2633           spt = 63;
   2634           sectors_low /= 63;
   2635           heads = sectors_low / 1024;
   2636           if (heads>128) heads = 255;
   2637           else if (heads>64) heads = 128;
   2638           else if (heads>32) heads = 64;
   2639           else if (heads>16) heads = 32;
   2640           else heads=16;
   2641           cylinders = sectors_low / heads;
   2642           break;
   2643         case ATA_TRANSLATION_RECHS:
   2644           // Take care not to overflow
   2645           if (heads==16) {
   2646             if(cylinders>61439) cylinders=61439;
   2647             heads=15;
   2648             cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
   2649             }
   2650           // then go through the large bitshift process
   2651         case ATA_TRANSLATION_LARGE:
   2652           while(cylinders > 1024) {
   2653             cylinders >>= 1;
   2654             heads <<= 1;
   2655 
   2656             // If we max out the head count
   2657             if (heads > 127) break;
   2658           }
   2659           break;
   2660         }
   2661       // clip to 1024 cylinders in lchs
   2662       if (cylinders > 1024) cylinders=1024;
   2663       BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
   2664 
   2665       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
   2666       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
   2667       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
   2668 
   2669       // fill hdidmap
   2670       write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
   2671       hdcount++;
   2672       }
   2673 
   2674     // Now we send a IDENTIFY command to ATAPI device
   2675     if(type == ATA_TYPE_ATAPI) {
   2676 
   2677       Bit8u  type, removable, mode;
   2678       Bit16u blksize;
   2679 
   2680       //Temporary values to do the transfer
   2681       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
   2682       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
   2683 
   2684       if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0)
   2685         BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
   2686 
   2687       type      = read_byte(get_SS(),buffer+1) & 0x1f;
   2688       removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
   2689       mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
   2690       blksize   = 2048;
   2691 
   2692       write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
   2693       write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
   2694       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
   2695       write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
   2696 
   2697       // fill cdidmap
   2698       write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
   2699       cdcount++;
   2700       }
   2701 
   2702       {
   2703       Bit32u sizeinmb;
   2704       Bit16u ataversion;
   2705       Bit8u  c, i, version, model[41];
   2706 
   2707       switch (type) {
   2708         case ATA_TYPE_ATA:
   2709           sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21)
   2710             | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11);
   2711         case ATA_TYPE_ATAPI:
   2712           // Read ATA/ATAPI version
   2713           ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
   2714           for(version=15;version>0;version--) {
   2715             if((ataversion&(1<<version))!=0)
   2716             break;
   2717             }
   2718 
   2719           // Read model name
   2720           for(i=0;i<20;i++){
   2721             write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
   2722             write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
   2723           }
   2724 
   2725           // Reformat
   2726           write_byte(get_SS(),model+40,0x00);
   2727           for(i=39;i>0;i--){
   2728             if(read_byte(get_SS(),model+i)==0x20)
   2729               write_byte(get_SS(),model+i,0x00);
   2730             else break;
   2731           }
   2732           if (i>36) {
   2733             write_byte(get_SS(),model+36,0x00);
   2734             for(i=35;i>32;i--){
   2735               write_byte(get_SS(),model+i,0x2E);
   2736             }
   2737           }
   2738           break;
   2739         }
   2740 
   2741       switch (type) {
   2742         case ATA_TYPE_ATA:
   2743           printf("ata%d %s: ",channel,slave?" slave":"master");
   2744           i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
   2745 	  if (sizeinmb < (1UL<<16))
   2746             printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb);
   2747 	  else
   2748             printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10));
   2749           break;
   2750         case ATA_TYPE_ATAPI:
   2751           printf("ata%d %s: ",channel,slave?" slave":"master");
   2752           i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
   2753           if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
   2754             printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
   2755           else
   2756             printf(" ATAPI-%d Device\n",version);
   2757           break;
   2758         case ATA_TYPE_UNKNOWN:
   2759           printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
   2760           break;
   2761         }
   2762       }
   2763     }
   2764 
   2765   // Store the devices counts
   2766   write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
   2767   write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
   2768   write_byte(0x40,0x75, hdcount);
   2769 
   2770   printf("\n");
   2771 
   2772   // FIXME : should use bios=cmos|auto|disable bits
   2773   // FIXME : should know about translation bits
   2774   // FIXME : move hard_drive_post here
   2775 
   2776 }
   2777 
   2778 // ---------------------------------------------------------------------------
   2779 // ATA/ATAPI driver : software reset
   2780 // ---------------------------------------------------------------------------
   2781 // ATA-3
   2782 // 8.2.1 Software reset - Device 0
   2783 
   2784 void   ata_reset(device)
   2785 Bit16u device;
   2786 {
   2787   Bit16u ebda_seg=read_word(0x0040,0x000E);
   2788   Bit16u iobase1, iobase2;
   2789   Bit8u  channel, slave, sn, sc;
   2790   Bit8u  type;
   2791   Bit16u max;
   2792 
   2793   channel = device / 2;
   2794   slave = device % 2;
   2795 
   2796   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   2797   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
   2798 
   2799   // Reset
   2800 
   2801 // 8.2.1 (a) -- set SRST in DC
   2802   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
   2803 
   2804 // 8.2.1 (b) -- wait for BSY
   2805   await_ide(BSY, iobase1, 20);
   2806 
   2807 // 8.2.1 (f) -- clear SRST
   2808   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
   2809 
   2810   type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
   2811   if (type != ATA_TYPE_NONE) {
   2812 
   2813 // 8.2.1 (g) -- check for sc==sn==0x01
   2814     // select device
   2815     outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
   2816     sc = inb(iobase1+ATA_CB_SC);
   2817     sn = inb(iobase1+ATA_CB_SN);
   2818 
   2819     if ( (sc==0x01) && (sn==0x01) ) {
   2820       if (type == ATA_TYPE_ATA) //ATA
   2821         await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT);
   2822       else //ATAPI
   2823         await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
   2824     }
   2825 
   2826 // 8.2.1 (h) -- wait for not BSY
   2827     await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
   2828   }
   2829 
   2830   // Enable interrupts
   2831   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
   2832 }
   2833 
   2834 // ---------------------------------------------------------------------------
   2835 // ATA/ATAPI driver : execute a non data command
   2836 // ---------------------------------------------------------------------------
   2837 
   2838 Bit16u ata_cmd_non_data()
   2839 {return 0;}
   2840 
   2841 // ---------------------------------------------------------------------------
   2842 // ATA/ATAPI driver : execute a data-in command
   2843 // ---------------------------------------------------------------------------
   2844       // returns
   2845       // 0 : no error
   2846       // 1 : BUSY bit set
   2847       // 2 : read error
   2848       // 3 : expected DRQ=1
   2849       // 4 : no sectors left to read/verify
   2850       // 5 : more sectors to read/verify
   2851       // 6 : no sectors left to write
   2852       // 7 : more sectors to write
   2853 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
   2854 Bit16u device, command, count, cylinder, head, sector, segment, offset;
   2855 Bit32u lba_low, lba_high;
   2856 {
   2857   Bit16u ebda_seg=read_word(0x0040,0x000E);
   2858   Bit16u iobase1, iobase2, blksize;
   2859   Bit8u  channel, slave;
   2860   Bit8u  status, current, mode;
   2861 
   2862   channel = device / 2;
   2863   slave   = device % 2;
   2864 
   2865   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   2866   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
   2867   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
   2868   blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
   2869   if (mode == ATA_MODE_PIO32) blksize>>=2;
   2870   else blksize>>=1;
   2871 
   2872   // Reset count of transferred data
   2873   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
   2874   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
   2875   current = 0;
   2876 
   2877   status = inb(iobase1 + ATA_CB_STAT);
   2878   if (status & ATA_CB_STAT_BSY) return 1;
   2879 
   2880   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
   2881 
   2882   // sector will be 0 only on lba access. Convert to lba-chs
   2883   if (sector == 0) {
   2884     if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
   2885       outb(iobase1 + ATA_CB_FR, 0x00);
   2886       outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
   2887       outb(iobase1 + ATA_CB_SN, lba_low >> 24);
   2888       outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
   2889       outb(iobase1 + ATA_CB_CH, lba_high >> 8);
   2890       command |= 0x04;
   2891       count &= (1UL << 8) - 1;
   2892       lba_low &= (1UL << 24) - 1;
   2893       }
   2894     sector = (Bit16u) (lba_low & 0x000000ffL);
   2895     cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
   2896     head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
   2897   }
   2898 
   2899   outb(iobase1 + ATA_CB_FR, 0x00);
   2900   outb(iobase1 + ATA_CB_SC, count);
   2901   outb(iobase1 + ATA_CB_SN, sector);
   2902   outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
   2903   outb(iobase1 + ATA_CB_CH, cylinder >> 8);
   2904   outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
   2905   outb(iobase1 + ATA_CB_CMD, command);
   2906 
   2907   await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
   2908   status = inb(iobase1 + ATA_CB_STAT);
   2909 
   2910   if (status & ATA_CB_STAT_ERR) {
   2911     BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
   2912     return 2;
   2913     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
   2914     BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
   2915     return 3;
   2916   }
   2917 
   2918   // FIXME : move seg/off translation here
   2919 
   2920 ASM_START
   2921         sti  ;; enable higher priority interrupts
   2922 ASM_END
   2923 
   2924   while (1) {
   2925 
   2926 ASM_START
   2927         push bp
   2928         mov  bp, sp
   2929         mov  di, _ata_cmd_data_in.offset + 2[bp]
   2930         mov  ax, _ata_cmd_data_in.segment + 2[bp]
   2931         mov  cx, _ata_cmd_data_in.blksize + 2[bp]
   2932 
   2933         ;; adjust if there will be an overrun. 2K max sector size
   2934         cmp   di, #0xf800 ;;
   2935         jbe   ata_in_no_adjust
   2936 
   2937 ata_in_adjust:
   2938         sub   di, #0x0800 ;; sub 2 kbytes from offset
   2939         add   ax, #0x0080 ;; add 2 Kbytes to segment
   2940 
   2941 ata_in_no_adjust:
   2942         mov   es, ax      ;; segment in es
   2943 
   2944         mov   dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
   2945 
   2946         mov  ah, _ata_cmd_data_in.mode + 2[bp]
   2947         cmp  ah, #ATA_MODE_PIO32
   2948         je   ata_in_32
   2949 
   2950 ata_in_16:
   2951         rep
   2952           insw ;; CX words transfered from port(DX) to ES:[DI]
   2953         jmp ata_in_done
   2954 
   2955 ata_in_32:
   2956         rep
   2957           insd ;; CX dwords transfered from port(DX) to ES:[DI]
   2958 
   2959 ata_in_done:
   2960         mov  _ata_cmd_data_in.offset + 2[bp], di
   2961         mov  _ata_cmd_data_in.segment + 2[bp], es
   2962         pop  bp
   2963 ASM_END
   2964 
   2965     current++;
   2966     write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
   2967     count--;
   2968     await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
   2969     status = inb(iobase1 + ATA_CB_STAT);
   2970     if (count == 0) {
   2971       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
   2972           != ATA_CB_STAT_RDY ) {
   2973         BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
   2974         return 4;
   2975         }
   2976       break;
   2977       }
   2978     else {
   2979       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
   2980           != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
   2981         BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
   2982         return 5;
   2983       }
   2984       continue;
   2985     }
   2986   }
   2987   // Enable interrupts
   2988   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
   2989   return 0;
   2990 }
   2991 
   2992 // ---------------------------------------------------------------------------
   2993 // ATA/ATAPI driver : execute a data-out command
   2994 // ---------------------------------------------------------------------------
   2995       // returns
   2996       // 0 : no error
   2997       // 1 : BUSY bit set
   2998       // 2 : read error
   2999       // 3 : expected DRQ=1
   3000       // 4 : no sectors left to read/verify
   3001       // 5 : more sectors to read/verify
   3002       // 6 : no sectors left to write
   3003       // 7 : more sectors to write
   3004 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset)
   3005 Bit16u device, command, count, cylinder, head, sector, segment, offset;
   3006 Bit32u lba_low, lba_high;
   3007 {
   3008   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3009   Bit16u iobase1, iobase2, blksize;
   3010   Bit8u  channel, slave;
   3011   Bit8u  status, current, mode;
   3012 
   3013   channel = device / 2;
   3014   slave   = device % 2;
   3015 
   3016   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   3017   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
   3018   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
   3019   blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
   3020   if (mode == ATA_MODE_PIO32) blksize>>=2;
   3021   else blksize>>=1;
   3022 
   3023   // Reset count of transferred data
   3024   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
   3025   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
   3026   current = 0;
   3027 
   3028   status = inb(iobase1 + ATA_CB_STAT);
   3029   if (status & ATA_CB_STAT_BSY) return 1;
   3030 
   3031   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
   3032 
   3033   // sector will be 0 only on lba access. Convert to lba-chs
   3034   if (sector == 0) {
   3035     if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) {
   3036       outb(iobase1 + ATA_CB_FR, 0x00);
   3037       outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff);
   3038       outb(iobase1 + ATA_CB_SN, lba_low >> 24);
   3039       outb(iobase1 + ATA_CB_CL, lba_high & 0xff);
   3040       outb(iobase1 + ATA_CB_CH, lba_high >> 8);
   3041       command |= 0x04;
   3042       count &= (1UL << 8) - 1;
   3043       lba_low &= (1UL << 24) - 1;
   3044       }
   3045     sector = (Bit16u) (lba_low & 0x000000ffL);
   3046     cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL);
   3047     head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA;
   3048   }
   3049 
   3050   outb(iobase1 + ATA_CB_FR, 0x00);
   3051   outb(iobase1 + ATA_CB_SC, count);
   3052   outb(iobase1 + ATA_CB_SN, sector);
   3053   outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
   3054   outb(iobase1 + ATA_CB_CH, cylinder >> 8);
   3055   outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
   3056   outb(iobase1 + ATA_CB_CMD, command);
   3057 
   3058   await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
   3059   status = inb(iobase1 + ATA_CB_STAT);
   3060 
   3061   if (status & ATA_CB_STAT_ERR) {
   3062     BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
   3063     return 2;
   3064     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
   3065     BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
   3066     return 3;
   3067     }
   3068 
   3069   // FIXME : move seg/off translation here
   3070 
   3071 ASM_START
   3072         sti  ;; enable higher priority interrupts
   3073 ASM_END
   3074 
   3075   while (1) {
   3076 
   3077 ASM_START
   3078         push bp
   3079         mov  bp, sp
   3080         mov  si, _ata_cmd_data_out.offset + 2[bp]
   3081         mov  ax, _ata_cmd_data_out.segment + 2[bp]
   3082         mov  cx, _ata_cmd_data_out.blksize + 2[bp]
   3083 
   3084         ;; adjust if there will be an overrun. 2K max sector size
   3085         cmp   si, #0xf800 ;;
   3086         jbe   ata_out_no_adjust
   3087 
   3088 ata_out_adjust:
   3089         sub   si, #0x0800 ;; sub 2 kbytes from offset
   3090         add   ax, #0x0080 ;; add 2 Kbytes to segment
   3091 
   3092 ata_out_no_adjust:
   3093         mov   es, ax      ;; segment in es
   3094 
   3095         mov   dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
   3096 
   3097         mov  ah, _ata_cmd_data_out.mode + 2[bp]
   3098         cmp  ah, #ATA_MODE_PIO32
   3099         je   ata_out_32
   3100 
   3101 ata_out_16:
   3102         seg ES
   3103         rep
   3104           outsw ;; CX words transfered from port(DX) to ES:[SI]
   3105         jmp ata_out_done
   3106 
   3107 ata_out_32:
   3108         seg ES
   3109         rep
   3110           outsd ;; CX dwords transfered from port(DX) to ES:[SI]
   3111 
   3112 ata_out_done:
   3113         mov  _ata_cmd_data_out.offset + 2[bp], si
   3114         mov  _ata_cmd_data_out.segment + 2[bp], es
   3115         pop  bp
   3116 ASM_END
   3117 
   3118     current++;
   3119     write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
   3120     count--;
   3121     status = inb(iobase1 + ATA_CB_STAT);
   3122     if (count == 0) {
   3123       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
   3124           != ATA_CB_STAT_RDY ) {
   3125         BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
   3126         return 6;
   3127         }
   3128       break;
   3129       }
   3130     else {
   3131       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
   3132           != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
   3133         BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
   3134         return 7;
   3135       }
   3136       continue;
   3137     }
   3138   }
   3139   // Enable interrupts
   3140   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
   3141   return 0;
   3142 }
   3143 
   3144 // ---------------------------------------------------------------------------
   3145 // ATA/ATAPI driver : execute a packet command
   3146 // ---------------------------------------------------------------------------
   3147       // returns
   3148       // 0 : no error
   3149       // 1 : error in parameters
   3150       // 2 : BUSY bit set
   3151       // 3 : error
   3152       // 4 : not ready
   3153 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
   3154 Bit8u  cmdlen,inout;
   3155 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
   3156 Bit16u header;
   3157 Bit32u length;
   3158 {
   3159   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3160   Bit16u iobase1, iobase2;
   3161   Bit16u lcount, lbefore, lafter, count;
   3162   Bit8u  channel, slave;
   3163   Bit8u  status, mode, lmode;
   3164   Bit32u total, transfer;
   3165 
   3166   channel = device / 2;
   3167   slave = device % 2;
   3168 
   3169   // Data out is not supported yet
   3170   if (inout == ATA_DATA_OUT) {
   3171     BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
   3172     return 1;
   3173     }
   3174 
   3175   // The header length must be even
   3176   if (header & 1) {
   3177     BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
   3178     return 1;
   3179     }
   3180 
   3181   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   3182   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
   3183   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
   3184   transfer= 0L;
   3185 
   3186   if (cmdlen < 12) cmdlen=12;
   3187   if (cmdlen > 12) cmdlen=16;
   3188   cmdlen>>=1;
   3189 
   3190   // Reset count of transferred data
   3191   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
   3192   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
   3193 
   3194   status = inb(iobase1 + ATA_CB_STAT);
   3195   if (status & ATA_CB_STAT_BSY) return 2;
   3196 
   3197   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
   3198   outb(iobase1 + ATA_CB_FR, 0x00);
   3199   outb(iobase1 + ATA_CB_SC, 0x00);
   3200   outb(iobase1 + ATA_CB_SN, 0x00);
   3201   outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
   3202   outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
   3203   outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
   3204   outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
   3205 
   3206   // Device should ok to receive command
   3207   await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
   3208   status = inb(iobase1 + ATA_CB_STAT);
   3209 
   3210   if (status & ATA_CB_STAT_ERR) {
   3211     BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
   3212     return 3;
   3213     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
   3214     BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
   3215     return 4;
   3216     }
   3217 
   3218   // Normalize address
   3219   cmdseg += (cmdoff / 16);
   3220   cmdoff %= 16;
   3221 
   3222   // Send command to device
   3223 ASM_START
   3224       sti  ;; enable higher priority interrupts
   3225 
   3226       push bp
   3227       mov  bp, sp
   3228 
   3229       mov  si, _ata_cmd_packet.cmdoff + 2[bp]
   3230       mov  ax, _ata_cmd_packet.cmdseg + 2[bp]
   3231       mov  cx, _ata_cmd_packet.cmdlen + 2[bp]
   3232       mov  es, ax      ;; segment in es
   3233 
   3234       mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
   3235 
   3236       seg ES
   3237       rep
   3238         outsw ;; CX words transfered from port(DX) to ES:[SI]
   3239 
   3240       pop  bp
   3241 ASM_END
   3242 
   3243   if (inout == ATA_DATA_NO) {
   3244     await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
   3245     status = inb(iobase1 + ATA_CB_STAT);
   3246     }
   3247   else {
   3248         Bit16u loops = 0;
   3249         Bit8u sc;
   3250   while (1) {
   3251 
   3252       if (loops == 0) {//first time through
   3253         status = inb(iobase2 + ATA_CB_ASTAT);
   3254         await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT);
   3255       }
   3256       else
   3257         await_ide(NOT_BSY, iobase1, IDE_TIMEOUT);
   3258       loops++;
   3259 
   3260       status = inb(iobase1 + ATA_CB_STAT);
   3261       sc = inb(iobase1 + ATA_CB_SC);
   3262 
   3263       // Check if command completed
   3264       if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) &&
   3265          ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break;
   3266 
   3267       if (status & ATA_CB_STAT_ERR) {
   3268         BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
   3269         return 3;
   3270       }
   3271 
   3272       // Normalize address
   3273       bufseg += (bufoff / 16);
   3274       bufoff %= 16;
   3275 
   3276       // Get the byte count
   3277       lcount =  ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
   3278 
   3279       // adjust to read what we want
   3280       if(header>lcount) {
   3281          lbefore=lcount;
   3282          header-=lcount;
   3283          lcount=0;
   3284          }
   3285       else {
   3286         lbefore=header;
   3287         header=0;
   3288         lcount-=lbefore;
   3289         }
   3290 
   3291       if(lcount>length) {
   3292         lafter=lcount-length;
   3293         lcount=length;
   3294         length=0;
   3295         }
   3296       else {
   3297         lafter=0;
   3298         length-=lcount;
   3299         }
   3300 
   3301       // Save byte count
   3302       count = lcount;
   3303 
   3304       BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
   3305       BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
   3306 
   3307       // If counts not dividable by 4, use 16bits mode
   3308       lmode = mode;
   3309       if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
   3310       if (lcount  & 0x03) lmode=ATA_MODE_PIO16;
   3311       if (lafter  & 0x03) lmode=ATA_MODE_PIO16;
   3312 
   3313       // adds an extra byte if count are odd. before is always even
   3314       if (lcount & 0x01) {
   3315         lcount+=1;
   3316         if ((lafter > 0) && (lafter & 0x01)) {
   3317           lafter-=1;
   3318           }
   3319         }
   3320 
   3321       if (lmode == ATA_MODE_PIO32) {
   3322         lcount>>=2; lbefore>>=2; lafter>>=2;
   3323         }
   3324       else {
   3325         lcount>>=1; lbefore>>=1; lafter>>=1;
   3326         }
   3327 
   3328        ;  // FIXME bcc bug
   3329 
   3330 ASM_START
   3331         push bp
   3332         mov  bp, sp
   3333 
   3334         mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
   3335 
   3336         mov  cx, _ata_cmd_packet.lbefore + 2[bp]
   3337         jcxz ata_packet_no_before
   3338 
   3339         mov  ah, _ata_cmd_packet.lmode + 2[bp]
   3340         cmp  ah, #ATA_MODE_PIO32
   3341         je   ata_packet_in_before_32
   3342 
   3343 ata_packet_in_before_16:
   3344         in   ax, dx
   3345         loop ata_packet_in_before_16
   3346         jmp  ata_packet_no_before
   3347 
   3348 ata_packet_in_before_32:
   3349         push eax
   3350 ata_packet_in_before_32_loop:
   3351         in   eax, dx
   3352         loop ata_packet_in_before_32_loop
   3353         pop  eax
   3354 
   3355 ata_packet_no_before:
   3356         mov  cx, _ata_cmd_packet.lcount + 2[bp]
   3357         jcxz ata_packet_after
   3358 
   3359         mov  di, _ata_cmd_packet.bufoff + 2[bp]
   3360         mov  ax, _ata_cmd_packet.bufseg + 2[bp]
   3361         mov  es, ax
   3362 
   3363         mov  ah, _ata_cmd_packet.lmode + 2[bp]
   3364         cmp  ah, #ATA_MODE_PIO32
   3365         je   ata_packet_in_32
   3366 
   3367 ata_packet_in_16:
   3368         rep
   3369           insw ;; CX words transfered tp port(DX) to ES:[DI]
   3370         jmp ata_packet_after
   3371 
   3372 ata_packet_in_32:
   3373         rep
   3374           insd ;; CX dwords transfered to port(DX) to ES:[DI]
   3375 
   3376 ata_packet_after:
   3377         mov  cx, _ata_cmd_packet.lafter + 2[bp]
   3378         jcxz ata_packet_done
   3379 
   3380         mov  ah, _ata_cmd_packet.lmode + 2[bp]
   3381         cmp  ah, #ATA_MODE_PIO32
   3382         je   ata_packet_in_after_32
   3383 
   3384 ata_packet_in_after_16:
   3385         in   ax, dx
   3386         loop ata_packet_in_after_16
   3387         jmp  ata_packet_done
   3388 
   3389 ata_packet_in_after_32:
   3390         push eax
   3391 ata_packet_in_after_32_loop:
   3392         in   eax, dx
   3393         loop ata_packet_in_after_32_loop
   3394         pop  eax
   3395 
   3396 ata_packet_done:
   3397         pop  bp
   3398 ASM_END
   3399 
   3400       // Compute new buffer address
   3401       bufoff += count;
   3402 
   3403       // Save transferred bytes count
   3404       transfer += count;
   3405       write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
   3406       }
   3407     }
   3408 
   3409   // Final check, device must be ready
   3410   if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) )
   3411          != ATA_CB_STAT_RDY ) {
   3412     BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
   3413     return 4;
   3414     }
   3415 
   3416   // Enable interrupts
   3417   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
   3418   return 0;
   3419 }
   3420 
   3421 // ---------------------------------------------------------------------------
   3422 // End of ATA/ATAPI Driver
   3423 // ---------------------------------------------------------------------------
   3424 
   3425 // ---------------------------------------------------------------------------
   3426 // Start of ATA/ATAPI generic functions
   3427 // ---------------------------------------------------------------------------
   3428 
   3429   Bit16u
   3430 atapi_get_sense(device, seg, asc, ascq)
   3431   Bit16u device;
   3432 {
   3433   Bit8u  atacmd[12];
   3434   Bit8u  buffer[18];
   3435   Bit8u i;
   3436 
   3437   memsetb(get_SS(),atacmd,0,12);
   3438 
   3439   // Request SENSE
   3440   atacmd[0]=ATA_CMD_REQUEST_SENSE;
   3441   atacmd[4]=sizeof(buffer);
   3442   if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0)
   3443     return 0x0002;
   3444 
   3445   write_byte(seg,asc,buffer[12]);
   3446   write_byte(seg,ascq,buffer[13]);
   3447 
   3448   return 0;
   3449 }
   3450 
   3451   Bit16u
   3452 atapi_is_ready(device)
   3453   Bit16u device;
   3454 {
   3455   Bit8u packet[12];
   3456   Bit8u buf[8];
   3457   Bit32u block_len;
   3458   Bit32u sectors;
   3459   Bit32u timeout; //measured in ms
   3460   Bit32u time;
   3461   Bit8u asc, ascq;
   3462   Bit8u in_progress;
   3463   Bit16u ebda_seg = read_word(0x0040,0x000E);
   3464   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) {
   3465     printf("not implemented for non-ATAPI device\n");
   3466     return -1;
   3467   }
   3468 
   3469   BX_DEBUG_ATA("ata_detect_medium: begin\n");
   3470   memsetb(get_SS(),packet, 0, sizeof packet);
   3471   packet[0] = 0x25; /* READ CAPACITY */
   3472 
   3473   /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT
   3474    * is reported by the device. If the device reports "IN PROGRESS",
   3475    * 30 seconds is added. */
   3476   timeout = 5000;
   3477   time = 0;
   3478   in_progress = 0;
   3479   while (time < timeout) {
   3480     if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0)
   3481       goto ok;
   3482 
   3483     if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) {
   3484       if (asc == 0x3a) { /* MEDIUM NOT PRESENT */
   3485         BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n");
   3486         return -1;
   3487       }
   3488 
   3489       if (asc == 0x04 && ascq == 0x01 && !in_progress) {
   3490         /* IN PROGRESS OF BECOMING READY */
   3491         printf("Waiting for device to detect medium... ");
   3492         /* Allow 30 seconds more */
   3493         timeout = 30000;
   3494         in_progress = 1;
   3495       }
   3496     }
   3497     time += 100;
   3498   }
   3499   BX_DEBUG_ATA("read capacity failed\n");
   3500   return -1;
   3501 ok:
   3502 
   3503   block_len = (Bit32u) buf[4] << 24
   3504     | (Bit32u) buf[5] << 16
   3505     | (Bit32u) buf[6] << 8
   3506     | (Bit32u) buf[7] << 0;
   3507   BX_DEBUG_ATA("block_len=%u\n", block_len);
   3508 
   3509   if (block_len!= 2048 && block_len!= 512)
   3510   {
   3511     printf("Unsupported sector size %u\n", block_len);
   3512     return -1;
   3513   }
   3514   write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len);
   3515 
   3516   sectors = (Bit32u) buf[0] << 24
   3517     | (Bit32u) buf[1] << 16
   3518     | (Bit32u) buf[2] << 8
   3519     | (Bit32u) buf[3] << 0;
   3520 
   3521   BX_DEBUG_ATA("sectors=%u\n", sectors);
   3522   if (block_len == 2048)
   3523     sectors <<= 2; /* # of sectors in 512-byte "soft" sector */
   3524   if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low))
   3525     printf("%dMB medium detected\n", sectors>>(20-9));
   3526   write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors);
   3527   return 0;
   3528 }
   3529 
   3530   Bit16u
   3531 atapi_is_cdrom(device)
   3532   Bit8u device;
   3533 {
   3534   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3535 
   3536   if (device >= BX_MAX_ATA_DEVICES)
   3537     return 0;
   3538 
   3539   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
   3540     return 0;
   3541 
   3542   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
   3543     return 0;
   3544 
   3545   return 1;
   3546 }
   3547 
   3548 // ---------------------------------------------------------------------------
   3549 // End of ATA/ATAPI generic functions
   3550 // ---------------------------------------------------------------------------
   3551 
   3552 #endif // BX_USE_ATADRV
   3553 
   3554 #if BX_ELTORITO_BOOT
   3555 
   3556 // ---------------------------------------------------------------------------
   3557 // Start of El-Torito boot functions
   3558 // ---------------------------------------------------------------------------
   3559 
   3560   void
   3561 cdemu_init()
   3562 {
   3563   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3564 
   3565   // the only important data is this one for now
   3566   write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
   3567 }
   3568 
   3569   Bit8u
   3570 cdemu_isactive()
   3571 {
   3572   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3573 
   3574   return(read_byte(ebda_seg,&EbdaData->cdemu.active));
   3575 }
   3576 
   3577   Bit8u
   3578 cdemu_emulated_drive()
   3579 {
   3580   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3581 
   3582   return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
   3583 }
   3584 
   3585 static char isotag[6]="CD001";
   3586 static char eltorito[24]="EL TORITO SPECIFICATION";
   3587 //
   3588 // Returns ah: emulated drive, al: error code
   3589 //
   3590   Bit16u
   3591 cdrom_boot()
   3592 {
   3593   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3594   Bit8u  atacmd[12], buffer[2048];
   3595   Bit32u lba;
   3596   Bit16u boot_segment, nbsectors, i, error;
   3597   Bit8u  device;
   3598 
   3599   // Find out the first cdrom
   3600   for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
   3601     if (atapi_is_cdrom(device)) break;
   3602     }
   3603 
   3604   // if not found
   3605   if(device >= BX_MAX_ATA_DEVICES) return 2;
   3606 
   3607   if(error = atapi_is_ready(device) != 0)
   3608     BX_INFO("ata_is_ready returned %d\n",error);
   3609 
   3610   // Read the Boot Record Volume Descriptor
   3611   memsetb(get_SS(),atacmd,0,12);
   3612   atacmd[0]=0x28;                      // READ command
   3613   atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
   3614   atacmd[8]=(0x01 & 0x00ff);           // Sectors
   3615   atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
   3616   atacmd[3]=(0x11 & 0x00ff0000) >> 16;
   3617   atacmd[4]=(0x11 & 0x0000ff00) >> 8;
   3618   atacmd[5]=(0x11 & 0x000000ff);
   3619   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
   3620     return 3;
   3621 
   3622   // Validity checks
   3623   if(buffer[0]!=0)return 4;
   3624   for(i=0;i<5;i++){
   3625     if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
   3626    }
   3627   for(i=0;i<23;i++)
   3628     if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
   3629 
   3630   // ok, now we calculate the Boot catalog address
   3631   lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
   3632 
   3633   // And we read the Boot Catalog
   3634   memsetb(get_SS(),atacmd,0,12);
   3635   atacmd[0]=0x28;                      // READ command
   3636   atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
   3637   atacmd[8]=(0x01 & 0x00ff);           // Sectors
   3638   atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
   3639   atacmd[3]=(lba & 0x00ff0000) >> 16;
   3640   atacmd[4]=(lba & 0x0000ff00) >> 8;
   3641   atacmd[5]=(lba & 0x000000ff);
   3642   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
   3643     return 7;
   3644 
   3645   // Validation entry
   3646   if(buffer[0x00]!=0x01)return 8;   // Header
   3647   if(buffer[0x01]!=0x00)return 9;   // Platform
   3648   if(buffer[0x1E]!=0x55)return 10;  // key 1
   3649   if(buffer[0x1F]!=0xAA)return 10;  // key 2
   3650 
   3651   // Initial/Default Entry
   3652   if(buffer[0x20]!=0x88)return 11; // Bootable
   3653 
   3654   write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
   3655   if(buffer[0x21]==0){
   3656     // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0.
   3657     // Win2000 cd boot needs to know it booted from cd
   3658     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
   3659     }
   3660   else if(buffer[0x21]<4)
   3661     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
   3662   else
   3663     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
   3664 
   3665   write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
   3666   write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
   3667 
   3668   boot_segment=buffer[0x23]*0x100+buffer[0x22];
   3669   if(boot_segment==0x0000)boot_segment=0x07C0;
   3670 
   3671   write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
   3672   write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
   3673 
   3674   nbsectors=buffer[0x27]*0x100+buffer[0x26];
   3675   write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
   3676 
   3677   lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
   3678   write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
   3679 
   3680   // And we read the image in memory
   3681   memsetb(get_SS(),atacmd,0,12);
   3682   atacmd[0]=0x28;                      // READ command
   3683   atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8;      // Sectors
   3684   atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff);           // Sectors
   3685   atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
   3686   atacmd[3]=(lba & 0x00ff0000) >> 16;
   3687   atacmd[4]=(lba & 0x0000ff00) >> 8;
   3688   atacmd[5]=(lba & 0x000000ff);
   3689   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
   3690     return 12;
   3691 
   3692   // Remember the media type
   3693   switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
   3694     case 0x01:  // 1.2M floppy
   3695       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
   3696       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
   3697       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
   3698       break;
   3699     case 0x02:  // 1.44M floppy
   3700       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
   3701       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
   3702       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
   3703       break;
   3704     case 0x03:  // 2.88M floppy
   3705       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
   3706       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
   3707       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
   3708       break;
   3709     case 0x04:  // Harddrive
   3710       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
   3711       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
   3712               (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
   3713       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
   3714       break;
   3715    }
   3716 
   3717   if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
   3718     // Increase bios installed hardware number of devices
   3719     if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
   3720       write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
   3721     else
   3722       write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
   3723    }
   3724 
   3725 
   3726   // everything is ok, so from now on, the emulation is active
   3727   if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
   3728     write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
   3729 
   3730   // return the boot drive + no error
   3731   return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
   3732 }
   3733 
   3734 // ---------------------------------------------------------------------------
   3735 // End of El-Torito boot functions
   3736 // ---------------------------------------------------------------------------
   3737 #endif // BX_ELTORITO_BOOT
   3738 
   3739   void
   3740 int14_function(regs, ds, iret_addr)
   3741   pusha_regs_t regs; // regs pushed from PUSHA instruction
   3742   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
   3743   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
   3744 {
   3745   Bit16u addr,timer,val16;
   3746   Bit8u timeout;
   3747 
   3748   ASM_START
   3749   sti
   3750   ASM_END
   3751 
   3752   addr = read_word(0x0040, (regs.u.r16.dx << 1));
   3753   timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
   3754   if ((regs.u.r16.dx < 4) && (addr > 0)) {
   3755     switch (regs.u.r8.ah) {
   3756       case 0:
   3757         outb(addr+3, inb(addr+3) | 0x80);
   3758         if (regs.u.r8.al & 0xE0 == 0) {
   3759           outb(addr, 0x17);
   3760           outb(addr+1, 0x04);
   3761         } else {
   3762           val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
   3763           outb(addr, val16 & 0xFF);
   3764           outb(addr+1, val16 >> 8);
   3765         }
   3766         outb(addr+3, regs.u.r8.al & 0x1F);
   3767         regs.u.r8.ah = inb(addr+5);
   3768         regs.u.r8.al = inb(addr+6);
   3769         ClearCF(iret_addr.flags);
   3770         break;
   3771       case 1:
   3772         timer = read_word(0x0040, 0x006C);
   3773         while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
   3774           val16 = read_word(0x0040, 0x006C);
   3775           if (val16 != timer) {
   3776             timer = val16;
   3777             timeout--;
   3778             }
   3779           }
   3780         if (timeout) outb(addr, regs.u.r8.al);
   3781         regs.u.r8.ah = inb(addr+5);
   3782         if (!timeout) regs.u.r8.ah |= 0x80;
   3783         ClearCF(iret_addr.flags);
   3784         break;
   3785       case 2:
   3786         timer = read_word(0x0040, 0x006C);
   3787         while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
   3788           val16 = read_word(0x0040, 0x006C);
   3789           if (val16 != timer) {
   3790             timer = val16;
   3791             timeout--;
   3792             }
   3793           }
   3794         if (timeout) {
   3795           regs.u.r8.ah = 0;
   3796           regs.u.r8.al = inb(addr);
   3797         } else {
   3798           regs.u.r8.ah = inb(addr+5);
   3799           }
   3800         ClearCF(iret_addr.flags);
   3801         break;
   3802       case 3:
   3803         regs.u.r8.ah = inb(addr+5);
   3804         regs.u.r8.al = inb(addr+6);
   3805         ClearCF(iret_addr.flags);
   3806         break;
   3807       default:
   3808         SetCF(iret_addr.flags); // Unsupported
   3809       }
   3810   } else {
   3811     SetCF(iret_addr.flags); // Unsupported
   3812     }
   3813 }
   3814 
   3815   void
   3816 int15_function(regs, ES, DS, FLAGS)
   3817   pusha_regs_t regs; // REGS pushed via pusha
   3818   Bit16u ES, DS, FLAGS;
   3819 {
   3820   Bit16u ebda_seg=read_word(0x0040,0x000E);
   3821   bx_bool prev_a20_enable;
   3822   Bit16u  base15_00;
   3823   Bit8u   base23_16;
   3824   Bit16u  ss;
   3825   Bit16u  CX,DX;
   3826 
   3827   Bit16u bRegister;
   3828   Bit8u irqDisable;
   3829 
   3830 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
   3831 
   3832   switch (regs.u.r8.ah) {
   3833     case 0x24: /* A20 Control */
   3834       switch (regs.u.r8.al) {
   3835         case 0x00:
   3836           set_enable_a20(0);
   3837           CLEAR_CF();
   3838           regs.u.r8.ah = 0;
   3839           break;
   3840         case 0x01:
   3841           set_enable_a20(1);
   3842           CLEAR_CF();
   3843           regs.u.r8.ah = 0;
   3844           break;
   3845         case 0x02:
   3846           regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
   3847           CLEAR_CF();
   3848           regs.u.r8.ah = 0;
   3849           break;
   3850         case 0x03:
   3851           CLEAR_CF();
   3852           regs.u.r8.ah = 0;
   3853           regs.u.r16.bx = 3;
   3854           break;
   3855         default:
   3856           BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
   3857           SET_CF();
   3858           regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   3859       }
   3860       break;
   3861 
   3862     case 0x41:
   3863       SET_CF();
   3864       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   3865       break;
   3866 
   3867     case 0x4f:
   3868       /* keyboard intercept */
   3869 #if BX_CPU < 2
   3870       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   3871 #else
   3872       // nop
   3873 #endif
   3874       SET_CF();
   3875       break;
   3876 
   3877     case 0x52:    // removable media eject
   3878       CLEAR_CF();
   3879       regs.u.r8.ah = 0;  // "ok ejection may proceed"
   3880       break;
   3881 
   3882     case 0x83: {
   3883       if( regs.u.r8.al == 0 ) {
   3884         // Set Interval requested.
   3885         if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
   3886           // Interval not already set.
   3887           write_byte( 0x40, 0xA0, 1 );  // Set status byte.
   3888           write_word( 0x40, 0x98, ES ); // Byte location, segment
   3889           write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
   3890           write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
   3891           write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
   3892           CLEAR_CF( );
   3893           irqDisable = inb( 0xA1 );
   3894           outb( 0xA1, irqDisable & 0xFE );
   3895           bRegister = inb_cmos( 0xB );  // Unmask IRQ8 so INT70 will get through.
   3896           outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
   3897         } else {
   3898           // Interval already set.
   3899           BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
   3900           SET_CF();
   3901           regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   3902         }
   3903       } else if( regs.u.r8.al == 1 ) {
   3904         // Clear Interval requested
   3905         write_byte( 0x40, 0xA0, 0 );  // Clear status byte
   3906         CLEAR_CF( );
   3907         bRegister = inb_cmos( 0xB );
   3908         outb_cmos( 0xB, bRegister & ~0x40 );  // Turn off the Periodic Interrupt timer
   3909       } else {
   3910         BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
   3911         SET_CF();
   3912         regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   3913         regs.u.r8.al--;
   3914       }
   3915 
   3916       break;
   3917     }
   3918 
   3919     case 0x87:
   3920 #if BX_CPU < 3
   3921 #  error "Int15 function 87h not supported on < 80386"
   3922 #endif
   3923       // +++ should probably have descriptor checks
   3924       // +++ should have exception handlers
   3925 
   3926  // turn off interrupts
   3927 ASM_START
   3928   cli
   3929 ASM_END
   3930 
   3931       prev_a20_enable = set_enable_a20(1); // enable A20 line
   3932 
   3933       // 128K max of transfer on 386+ ???
   3934       // source == destination ???
   3935 
   3936       // ES:SI points to descriptor table
   3937       // offset   use     initially  comments
   3938       // ==============================================
   3939       // 00..07   Unused  zeros      Null descriptor
   3940       // 08..0f   GDT     zeros      filled in by BIOS
   3941       // 10..17   source  ssssssss   source of data
   3942       // 18..1f   dest    dddddddd   destination of data
   3943       // 20..27   CS      zeros      filled in by BIOS
   3944       // 28..2f   SS      zeros      filled in by BIOS
   3945 
   3946       //es:si
   3947       //eeee0
   3948       //0ssss
   3949       //-----
   3950 
   3951 // check for access rights of source & dest here
   3952 
   3953       // Initialize GDT descriptor
   3954       base15_00 = (ES << 4) + regs.u.r16.si;
   3955       base23_16 = ES >> 12;
   3956       if (base15_00 < (ES<<4))
   3957         base23_16++;
   3958       write_word(ES, regs.u.r16.si+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
   3959       write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
   3960       write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
   3961       write_byte(ES, regs.u.r16.si+0x08+5, 0x93);     // access
   3962       write_word(ES, regs.u.r16.si+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
   3963 
   3964       // Initialize CS descriptor
   3965       write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
   3966       write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
   3967       write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
   3968       write_byte(ES, regs.u.r16.si+0x20+5, 0x9b);  // access
   3969       write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
   3970 
   3971       // Initialize SS descriptor
   3972       ss = get_SS();
   3973       base15_00 = ss << 4;
   3974       base23_16 = ss >> 12;
   3975       write_word(ES, regs.u.r16.si+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
   3976       write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
   3977       write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
   3978       write_byte(ES, regs.u.r16.si+0x28+5, 0x93);     // access
   3979       write_word(ES, regs.u.r16.si+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
   3980 
   3981       CX = regs.u.r16.cx;
   3982 ASM_START
   3983       // Compile generates locals offset info relative to SP.
   3984       // Get CX (word count) from stack.
   3985       mov  bx, sp
   3986       SEG SS
   3987         mov  cx, _int15_function.CX [bx]
   3988 
   3989       // since we need to set SS:SP, save them to the BDA
   3990       // for future restore
   3991       push eax
   3992       xor eax, eax
   3993       mov ds, ax
   3994       mov 0x0469, ss
   3995       mov 0x0467, sp
   3996 
   3997       SEG ES
   3998         lgdt [si + 0x08]
   3999       SEG CS
   4000         lidt [pmode_IDT_info]
   4001       ;;  perhaps do something with IDT here
   4002 
   4003       ;; set PE bit in CR0
   4004       mov  eax, cr0
   4005       or   al, #0x01
   4006       mov  cr0, eax
   4007       ;; far jump to flush CPU queue after transition to protected mode
   4008       JMP_AP(0x0020, protected_mode)
   4009 
   4010 protected_mode:
   4011       ;; GDT points to valid descriptor table, now load SS, DS, ES
   4012       mov  ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
   4013       mov  ss, ax
   4014       mov  ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
   4015       mov  ds, ax
   4016       mov  ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
   4017       mov  es, ax
   4018       xor  si, si
   4019       xor  di, di
   4020       cld
   4021       rep
   4022         movsw  ;; move CX words from DS:SI to ES:DI
   4023 
   4024       ;; make sure DS and ES limits are 64KB
   4025       mov ax, #0x28
   4026       mov ds, ax
   4027       mov es, ax
   4028 
   4029       ;; reset PG bit in CR0 ???
   4030       mov  eax, cr0
   4031       and  al, #0xFE
   4032       mov  cr0, eax
   4033 
   4034       ;; far jump to flush CPU queue after transition to real mode
   4035       JMP_AP(0xf000, real_mode)
   4036 
   4037 real_mode:
   4038       ;; restore IDT to normal real-mode defaults
   4039       SEG CS
   4040         lidt [rmode_IDT_info]
   4041 
   4042       // restore SS:SP from the BDA
   4043       xor ax, ax
   4044       mov ds, ax
   4045       mov ss, 0x0469
   4046       mov sp, 0x0467
   4047       pop eax
   4048 ASM_END
   4049 
   4050       set_enable_a20(prev_a20_enable);
   4051 
   4052  // turn back on interrupts
   4053 ASM_START
   4054   sti
   4055 ASM_END
   4056 
   4057       regs.u.r8.ah = 0;
   4058       CLEAR_CF();
   4059       break;
   4060 
   4061 
   4062     case 0x88:
   4063       // Get the amount of extended memory (above 1M)
   4064 #if BX_CPU < 2
   4065       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4066       SET_CF();
   4067 #else
   4068       regs.u.r8.al = inb_cmos(0x30);
   4069       regs.u.r8.ah = inb_cmos(0x31);
   4070 
   4071       // According to Ralf Brown's interrupt the limit should be 15M,
   4072       // but real machines mostly return max. 63M.
   4073       if(regs.u.r16.ax > 0xffc0)
   4074         regs.u.r16.ax = 0xffc0;
   4075 
   4076       CLEAR_CF();
   4077 #endif
   4078       break;
   4079 
   4080     case 0x90:
   4081       /* Device busy interrupt.  Called by Int 16h when no key available */
   4082       break;
   4083 
   4084     case 0x91:
   4085       /* Interrupt complete.  Called by Int 16h when key becomes available */
   4086       break;
   4087 
   4088     case 0xbf:
   4089       BX_INFO("*** int 15h function AH=bf not yet supported!\n");
   4090       SET_CF();
   4091       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4092       break;
   4093 
   4094     case 0xC0:
   4095 #if 0
   4096       SET_CF();
   4097       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4098       break;
   4099 #endif
   4100       CLEAR_CF();
   4101       regs.u.r8.ah = 0;
   4102       regs.u.r16.bx =  BIOS_CONFIG_TABLE;
   4103       ES = 0xF000;
   4104       break;
   4105 
   4106     case 0xc1:
   4107       ES = ebda_seg;
   4108       CLEAR_CF();
   4109       break;
   4110 
   4111     case 0xd8:
   4112       bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
   4113       SET_CF();
   4114       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4115       break;
   4116 
   4117     default:
   4118       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
   4119         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
   4120       SET_CF();
   4121       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4122       break;
   4123     }
   4124 }
   4125 
   4126 #if BX_USE_PS2_MOUSE
   4127   void
   4128 int15_function_mouse(regs, ES, DS, FLAGS)
   4129   pusha_regs_t regs; // REGS pushed via pusha
   4130   Bit16u ES, DS, FLAGS;
   4131 {
   4132   Bit16u ebda_seg=read_word(0x0040,0x000E);
   4133   Bit8u  mouse_flags_1, mouse_flags_2;
   4134   Bit16u mouse_driver_seg;
   4135   Bit16u mouse_driver_offset;
   4136   Bit8u  comm_byte, prev_command_byte;
   4137   Bit8u  ret, mouse_data1, mouse_data2, mouse_data3;
   4138 
   4139 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
   4140 
   4141   switch (regs.u.r8.ah) {
   4142     case 0xC2:
   4143       // Return Codes status in AH
   4144       // =========================
   4145       // 00: success
   4146       // 01: invalid subfunction (AL > 7)
   4147       // 02: invalid input value (out of allowable range)
   4148       // 03: interface error
   4149       // 04: resend command received from mouse controller,
   4150       //     device driver should attempt command again
   4151       // 05: cannot enable mouse, since no far call has been installed
   4152       // 80/86: mouse service not implemented
   4153 
   4154       switch (regs.u.r8.al) {
   4155         case 0: // Disable/Enable Mouse
   4156 BX_DEBUG_INT15("case 0:\n");
   4157           switch (regs.u.r8.bh) {
   4158             case 0: // Disable Mouse
   4159 BX_DEBUG_INT15("case 0: disable mouse\n");
   4160               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4161               ret = send_to_mouse_ctrl(0xF5); // disable mouse command
   4162               if (ret == 0) {
   4163                 ret = get_mouse_data(&mouse_data1);
   4164                 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
   4165                   CLEAR_CF();
   4166                   regs.u.r8.ah = 0;
   4167                   return;
   4168                   }
   4169                 }
   4170 
   4171               // error
   4172               SET_CF();
   4173               regs.u.r8.ah = ret;
   4174               return;
   4175               break;
   4176 
   4177             case 1: // Enable Mouse
   4178 BX_DEBUG_INT15("case 1: enable mouse\n");
   4179               mouse_flags_2 = read_byte(ebda_seg, 0x0027);
   4180               if ( (mouse_flags_2 & 0x80) == 0 ) {
   4181                 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
   4182                 SET_CF();  // error
   4183                 regs.u.r8.ah = 5; // no far call installed
   4184                 return;
   4185                 }
   4186               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4187               ret = send_to_mouse_ctrl(0xF4); // enable mouse command
   4188               if (ret == 0) {
   4189                 ret = get_mouse_data(&mouse_data1);
   4190                 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
   4191                   enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
   4192                   CLEAR_CF();
   4193                   regs.u.r8.ah = 0;
   4194                   return;
   4195                   }
   4196                 }
   4197               SET_CF();
   4198               regs.u.r8.ah = ret;
   4199               return;
   4200 
   4201             default: // invalid subfunction
   4202               BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
   4203               SET_CF();  // error
   4204               regs.u.r8.ah = 1; // invalid subfunction
   4205               return;
   4206             }
   4207           break;
   4208 
   4209         case 1: // Reset Mouse
   4210         case 5: // Initialize Mouse
   4211 BX_DEBUG_INT15("case 1 or 5:\n");
   4212           if (regs.u.r8.al == 5) {
   4213             if (regs.u.r8.bh != 3) {
   4214               SET_CF();
   4215               regs.u.r8.ah = 0x02; // invalid input
   4216               return;
   4217             }
   4218             mouse_flags_2 = read_byte(ebda_seg, 0x0027);
   4219             mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
   4220             mouse_flags_1 = 0x00;
   4221             write_byte(ebda_seg, 0x0026, mouse_flags_1);
   4222             write_byte(ebda_seg, 0x0027, mouse_flags_2);
   4223           }
   4224 
   4225           inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4226           ret = send_to_mouse_ctrl(0xFF); // reset mouse command
   4227           if (ret == 0) {
   4228             ret = get_mouse_data(&mouse_data3);
   4229             // if no mouse attached, it will return RESEND
   4230             if (mouse_data3 == 0xfe) {
   4231               SET_CF();
   4232               return;
   4233             }
   4234             if (mouse_data3 != 0xfa)
   4235               BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
   4236             if ( ret == 0 ) {
   4237               ret = get_mouse_data(&mouse_data1);
   4238               if ( ret == 0 ) {
   4239                 ret = get_mouse_data(&mouse_data2);
   4240                 if ( ret == 0 ) {
   4241                   // turn IRQ12 and packet generation on
   4242                   enable_mouse_int_and_events();
   4243                   CLEAR_CF();
   4244                   regs.u.r8.ah = 0;
   4245                   regs.u.r8.bl = mouse_data1;
   4246                   regs.u.r8.bh = mouse_data2;
   4247                   return;
   4248                   }
   4249                 }
   4250               }
   4251             }
   4252 
   4253           // error
   4254           SET_CF();
   4255           regs.u.r8.ah = ret;
   4256           return;
   4257 
   4258         case 2: // Set Sample Rate
   4259 BX_DEBUG_INT15("case 2:\n");
   4260           switch (regs.u.r8.bh) {
   4261             case 0: mouse_data1 = 10; break; //  10 reports/sec
   4262             case 1: mouse_data1 = 20; break; //  20 reports/sec
   4263             case 2: mouse_data1 = 40; break; //  40 reports/sec
   4264             case 3: mouse_data1 = 60; break; //  60 reports/sec
   4265             case 4: mouse_data1 = 80; break; //  80 reports/sec
   4266             case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
   4267             case 6: mouse_data1 = 200; break; // 200 reports/sec
   4268             default: mouse_data1 = 0;
   4269           }
   4270           if (mouse_data1 > 0) {
   4271             ret = send_to_mouse_ctrl(0xF3); // set sample rate command
   4272             if (ret == 0) {
   4273               ret = get_mouse_data(&mouse_data2);
   4274               ret = send_to_mouse_ctrl(mouse_data1);
   4275               ret = get_mouse_data(&mouse_data2);
   4276               CLEAR_CF();
   4277               regs.u.r8.ah = 0;
   4278             } else {
   4279               // error
   4280               SET_CF();
   4281               regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4282             }
   4283           } else {
   4284             // error
   4285             SET_CF();
   4286             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4287           }
   4288           break;
   4289 
   4290         case 3: // Set Resolution
   4291 BX_DEBUG_INT15("case 3:\n");
   4292           // BH:
   4293           //      0 =  25 dpi, 1 count  per millimeter
   4294           //      1 =  50 dpi, 2 counts per millimeter
   4295           //      2 = 100 dpi, 4 counts per millimeter
   4296           //      3 = 200 dpi, 8 counts per millimeter
   4297           comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4298           if (regs.u.r8.bh < 4) {
   4299             ret = send_to_mouse_ctrl(0xE8); // set resolution command
   4300             if (ret == 0) {
   4301               ret = get_mouse_data(&mouse_data1);
   4302               if (mouse_data1 != 0xfa)
   4303                 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
   4304               ret = send_to_mouse_ctrl(regs.u.r8.bh);
   4305               ret = get_mouse_data(&mouse_data1);
   4306               if (mouse_data1 != 0xfa)
   4307                 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
   4308               CLEAR_CF();
   4309               regs.u.r8.ah = 0;
   4310             } else {
   4311               // error
   4312               SET_CF();
   4313               regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4314             }
   4315           } else {
   4316             // error
   4317             SET_CF();
   4318             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4319           }
   4320           set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
   4321           break;
   4322 
   4323         case 4: // Get Device ID
   4324 BX_DEBUG_INT15("case 4:\n");
   4325           inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4326           ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
   4327           if (ret == 0) {
   4328             ret = get_mouse_data(&mouse_data1);
   4329             ret = get_mouse_data(&mouse_data2);
   4330             CLEAR_CF();
   4331             regs.u.r8.ah = 0;
   4332             regs.u.r8.bh = mouse_data2;
   4333           } else {
   4334             // error
   4335             SET_CF();
   4336             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4337           }
   4338           break;
   4339 
   4340         case 6: // Return Status & Set Scaling Factor...
   4341 BX_DEBUG_INT15("case 6:\n");
   4342           switch (regs.u.r8.bh) {
   4343             case 0: // Return Status
   4344               comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4345               ret = send_to_mouse_ctrl(0xE9); // get mouse info command
   4346               if (ret == 0) {
   4347                 ret = get_mouse_data(&mouse_data1);
   4348                 if (mouse_data1 != 0xfa)
   4349                   BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
   4350                 if (ret == 0) {
   4351                   ret = get_mouse_data(&mouse_data1);
   4352                   if ( ret == 0 ) {
   4353                     ret = get_mouse_data(&mouse_data2);
   4354                     if ( ret == 0 ) {
   4355                       ret = get_mouse_data(&mouse_data3);
   4356                       if ( ret == 0 ) {
   4357                         CLEAR_CF();
   4358                         regs.u.r8.ah = 0;
   4359                         regs.u.r8.bl = mouse_data1;
   4360                         regs.u.r8.cl = mouse_data2;
   4361                         regs.u.r8.dl = mouse_data3;
   4362                         set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
   4363                         return;
   4364                         }
   4365                       }
   4366                     }
   4367                   }
   4368                 }
   4369 
   4370               // error
   4371               SET_CF();
   4372               regs.u.r8.ah = ret;
   4373               set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
   4374               return;
   4375 
   4376             case 1: // Set Scaling Factor to 1:1
   4377             case 2: // Set Scaling Factor to 2:1
   4378               comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4379               if (regs.u.r8.bh == 1) {
   4380                 ret = send_to_mouse_ctrl(0xE6);
   4381               } else {
   4382                 ret = send_to_mouse_ctrl(0xE7);
   4383               }
   4384               if (ret == 0) {
   4385                 get_mouse_data(&mouse_data1);
   4386                 ret = (mouse_data1 != 0xFA);
   4387               }
   4388               if (ret == 0) {
   4389                 CLEAR_CF();
   4390                 regs.u.r8.ah = 0;
   4391               } else {
   4392                 // error
   4393                 SET_CF();
   4394                 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4395               }
   4396               set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
   4397               break;
   4398 
   4399             default:
   4400               BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
   4401             }
   4402           break;
   4403 
   4404         case 7: // Set Mouse Handler Address
   4405 BX_DEBUG_INT15("case 7:\n");
   4406           mouse_driver_seg = ES;
   4407           mouse_driver_offset = regs.u.r16.bx;
   4408           write_word(ebda_seg, 0x0022, mouse_driver_offset);
   4409           write_word(ebda_seg, 0x0024, mouse_driver_seg);
   4410           mouse_flags_2 = read_byte(ebda_seg, 0x0027);
   4411           if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
   4412             /* remove handler */
   4413             if ( (mouse_flags_2 & 0x80) != 0 ) {
   4414               mouse_flags_2 &= ~0x80;
   4415               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
   4416               }
   4417             }
   4418           else {
   4419             /* install handler */
   4420             mouse_flags_2 |= 0x80;
   4421             }
   4422           write_byte(ebda_seg, 0x0027, mouse_flags_2);
   4423           CLEAR_CF();
   4424           regs.u.r8.ah = 0;
   4425           break;
   4426 
   4427         default:
   4428 BX_DEBUG_INT15("case default:\n");
   4429           regs.u.r8.ah = 1; // invalid function
   4430           SET_CF();
   4431         }
   4432       break;
   4433 
   4434     default:
   4435       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
   4436         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
   4437       SET_CF();
   4438       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4439       break;
   4440     }
   4441 }
   4442 #endif // BX_USE_PS2_MOUSE
   4443 
   4444 
   4445 void set_e820_range(ES, DI, start, end, extra_start, extra_end, type)
   4446      Bit16u ES;
   4447      Bit16u DI;
   4448      Bit32u start;
   4449      Bit32u end;
   4450      Bit8u extra_start;
   4451      Bit8u extra_end;
   4452      Bit16u type;
   4453 {
   4454     write_word(ES, DI, start);
   4455     write_word(ES, DI+2, start >> 16);
   4456     write_word(ES, DI+4, extra_start);
   4457     write_word(ES, DI+6, 0x00);
   4458 
   4459     end -= start;
   4460     extra_end -= extra_start;
   4461     write_word(ES, DI+8, end);
   4462     write_word(ES, DI+10, end >> 16);
   4463     write_word(ES, DI+12, extra_end);
   4464     write_word(ES, DI+14, 0x0000);
   4465 
   4466     write_word(ES, DI+16, type);
   4467     write_word(ES, DI+18, 0x0);
   4468 }
   4469 
   4470   void
   4471 int15_function32(regs, ES, DS, FLAGS)
   4472   pushad_regs_t regs; // REGS pushed via pushad
   4473   Bit16u ES, DS, FLAGS;
   4474 {
   4475   Bit32u  extended_memory_size=0; // 64bits long
   4476   Bit32u  extra_lowbits_memory_size=0;
   4477   Bit16u  CX,DX;
   4478   Bit8u   extra_highbits_memory_size=0;
   4479 
   4480 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
   4481 
   4482   switch (regs.u.r8.ah) {
   4483     case 0x86:
   4484       // Wait for CX:DX microseconds. currently using the
   4485       // refresh request port 0x61 bit4, toggling every 15usec
   4486 
   4487       CX = regs.u.r16.cx;
   4488       DX = regs.u.r16.dx;
   4489 
   4490 ASM_START
   4491       sti
   4492 
   4493       ;; Get the count in eax
   4494       mov  bx, sp
   4495       SEG SS
   4496         mov  ax, _int15_function32.CX [bx]
   4497       shl  eax, #16
   4498       SEG SS
   4499         mov  ax, _int15_function32.DX [bx]
   4500 
   4501       ;; convert to numbers of 15usec ticks
   4502       mov ebx, #15
   4503       xor edx, edx
   4504       div eax, ebx
   4505       mov ecx, eax
   4506 
   4507       ;; wait for ecx number of refresh requests
   4508       in al, #0x61
   4509       and al,#0x10
   4510       mov ah, al
   4511 
   4512       or ecx, ecx
   4513       je int1586_tick_end
   4514 int1586_tick:
   4515       in al, #0x61
   4516       and al,#0x10
   4517       cmp al, ah
   4518       je  int1586_tick
   4519       mov ah, al
   4520       dec ecx
   4521       jnz int1586_tick
   4522 int1586_tick_end:
   4523 ASM_END
   4524 
   4525       break;
   4526 
   4527     case 0xe8:
   4528         switch(regs.u.r8.al)
   4529         {
   4530          case 0x20: // coded by osmaker aka K.J.
   4531             if(regs.u.r32.edx == 0x534D4150)
   4532             {
   4533                 extended_memory_size = inb_cmos(0x35);
   4534                 extended_memory_size <<= 8;
   4535                 extended_memory_size |= inb_cmos(0x34);
   4536                 extended_memory_size *= 64;
   4537                 // greater than EFF00000???
   4538                 if(extended_memory_size > 0x3bc000) {
   4539                     extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
   4540                 }
   4541                 extended_memory_size *= 1024;
   4542                 extended_memory_size += (16L * 1024 * 1024);
   4543 
   4544                 if(extended_memory_size <= (16L * 1024 * 1024)) {
   4545                     extended_memory_size = inb_cmos(0x31);
   4546                     extended_memory_size <<= 8;
   4547                     extended_memory_size |= inb_cmos(0x30);
   4548                     extended_memory_size *= 1024;
   4549                     extended_memory_size += (1L * 1024 * 1024);
   4550                 }
   4551 
   4552                 extra_lowbits_memory_size = inb_cmos(0x5c);
   4553                 extra_lowbits_memory_size <<= 8;
   4554                 extra_lowbits_memory_size |= inb_cmos(0x5b);
   4555                 extra_lowbits_memory_size *= 64;
   4556                 extra_lowbits_memory_size *= 1024;
   4557                 extra_highbits_memory_size = inb_cmos(0x5d);
   4558 
   4559                 switch(regs.u.r16.bx)
   4560                 {
   4561                     case 0:
   4562                         set_e820_range(ES, regs.u.r16.di,
   4563                                        0x0000000L, 0x0009f000L, 0, 0, 1);
   4564                         regs.u.r32.ebx = 1;
   4565                         break;
   4566                     case 1:
   4567                         set_e820_range(ES, regs.u.r16.di,
   4568                                        0x0009f000L, 0x000a0000L, 0, 0, 2);
   4569                         regs.u.r32.ebx = 2;
   4570                         break;
   4571                     case 2:
   4572                         set_e820_range(ES, regs.u.r16.di,
   4573                                        0x000e8000L, 0x00100000L, 0, 0, 2);
   4574                         regs.u.r32.ebx = 3;
   4575                         break;
   4576                     case 3:
   4577 #if BX_ROMBIOS32
   4578                         set_e820_range(ES, regs.u.r16.di,
   4579                                        0x00100000L,
   4580                                        extended_memory_size - ACPI_DATA_SIZE ,0, 0, 1);
   4581                         regs.u.r32.ebx = 4;
   4582 #else
   4583                         set_e820_range(ES, regs.u.r16.di,
   4584                                        0x00100000L,
   4585                                        extended_memory_size, 1);
   4586                         regs.u.r32.ebx = 5;
   4587 #endif
   4588                         break;
   4589                     case 4:
   4590                         set_e820_range(ES, regs.u.r16.di,
   4591                                        extended_memory_size - ACPI_DATA_SIZE,
   4592                                        extended_memory_size ,0, 0, 3); // ACPI RAM
   4593                         regs.u.r32.ebx = 5;
   4594                         break;
   4595                     case 5:
   4596                         /* 256KB BIOS area at the end of 4 GB */
   4597                         set_e820_range(ES, regs.u.r16.di,
   4598                                        0xfffc0000L, 0x00000000L ,0, 0, 2);
   4599                         if (extra_highbits_memory_size || extra_lowbits_memory_size)
   4600                             regs.u.r32.ebx = 6;
   4601                         else
   4602                             regs.u.r32.ebx = 0;
   4603                         break;
   4604                     case 6:
   4605                         /* Maping of memory above 4 GB */
   4606                         set_e820_range(ES, regs.u.r16.di, 0x00000000L,
   4607                         extra_lowbits_memory_size, 1, extra_highbits_memory_size
   4608                                        + 1, 1);
   4609                         regs.u.r32.ebx = 0;
   4610                         break;
   4611                     default:  /* AX=E820, DX=534D4150, BX unrecognized */
   4612                         goto int15_unimplemented;
   4613                         break;
   4614                 }
   4615                 regs.u.r32.eax = 0x534D4150;
   4616                 regs.u.r32.ecx = 0x14;
   4617                 CLEAR_CF();
   4618             } else {
   4619               // if DX != 0x534D4150)
   4620               goto int15_unimplemented;
   4621             }
   4622             break;
   4623 
   4624         case 0x01:
   4625           // do we have any reason to fail here ?
   4626           CLEAR_CF();
   4627 
   4628           // my real system sets ax and bx to 0
   4629           // this is confirmed by Ralph Brown list
   4630           // but syslinux v1.48 is known to behave
   4631           // strangely if ax is set to 0
   4632           // regs.u.r16.ax = 0;
   4633           // regs.u.r16.bx = 0;
   4634 
   4635           // Get the amount of extended memory (above 1M)
   4636           regs.u.r8.cl = inb_cmos(0x30);
   4637           regs.u.r8.ch = inb_cmos(0x31);
   4638 
   4639           // limit to 15M
   4640           if(regs.u.r16.cx > 0x3c00)
   4641           {
   4642             regs.u.r16.cx = 0x3c00;
   4643           }
   4644 
   4645           // Get the amount of extended memory above 16M in 64k blocs
   4646           regs.u.r8.dl = inb_cmos(0x34);
   4647           regs.u.r8.dh = inb_cmos(0x35);
   4648 
   4649           // Set configured memory equal to extended memory
   4650           regs.u.r16.ax = regs.u.r16.cx;
   4651           regs.u.r16.bx = regs.u.r16.dx;
   4652           break;
   4653         default:  /* AH=0xE8?? but not implemented */
   4654           goto int15_unimplemented;
   4655        }
   4656        break;
   4657     int15_unimplemented:
   4658        // fall into the default
   4659     default:
   4660       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
   4661         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
   4662       SET_CF();
   4663       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
   4664       break;
   4665     }
   4666 }
   4667 
   4668   void
   4669 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
   4670   Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
   4671 {
   4672   Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
   4673   Bit16u kbd_code, max;
   4674 
   4675   BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
   4676 
   4677   shift_flags = read_byte(0x0040, 0x17);
   4678   led_flags = read_byte(0x0040, 0x97);
   4679   if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) {
   4680 ASM_START
   4681     cli
   4682 ASM_END
   4683     outb(0x60, 0xed);
   4684     while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
   4685     if ((inb(0x60) == 0xfa)) {
   4686       led_flags &= 0xf8;
   4687       led_flags |= ((shift_flags >> 4) & 0x07);
   4688       outb(0x60, led_flags & 0x07);
   4689       while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21);
   4690       inb(0x60);
   4691       write_byte(0x0040, 0x97, led_flags);
   4692     }
   4693 ASM_START
   4694     sti
   4695 ASM_END
   4696   }
   4697 
   4698   switch (GET_AH()) {
   4699     case 0x00: /* read keyboard input */
   4700 
   4701       if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
   4702         BX_PANIC("KBD: int16h: out of keyboard input\n");
   4703         }
   4704       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
   4705       else if (ascii_code == 0xE0) ascii_code = 0;
   4706       AX = (scan_code << 8) | ascii_code;
   4707       break;
   4708 
   4709     case 0x01: /* check keyboard status */
   4710       if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
   4711         SET_ZF();
   4712         return;
   4713         }
   4714       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
   4715       else if (ascii_code == 0xE0) ascii_code = 0;
   4716       AX = (scan_code << 8) | ascii_code;
   4717       CLEAR_ZF();
   4718       break;
   4719 
   4720     case 0x02: /* get shift flag status */
   4721       shift_flags = read_byte(0x0040, 0x17);
   4722       SET_AL(shift_flags);
   4723       break;
   4724 
   4725     case 0x05: /* store key-stroke into buffer */
   4726       if ( !enqueue_key(GET_CH(), GET_CL()) ) {
   4727         SET_AL(1);
   4728         }
   4729       else {
   4730         SET_AL(0);
   4731         }
   4732       break;
   4733 
   4734     case 0x09: /* GET KEYBOARD FUNCTIONALITY */
   4735       // bit Bochs Description
   4736       //  7    0   reserved
   4737       //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
   4738       //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
   4739       //  4    1   INT 16/AH=0Ah supported
   4740       //  3    0   INT 16/AX=0306h supported
   4741       //  2    0   INT 16/AX=0305h supported
   4742       //  1    0   INT 16/AX=0304h supported
   4743       //  0    0   INT 16/AX=0300h supported
   4744       //
   4745       SET_AL(0x30);
   4746       break;
   4747 
   4748     case 0x0A: /* GET KEYBOARD ID */
   4749       count = 2;
   4750       kbd_code = 0x0;
   4751       outb(0x60, 0xf2);
   4752       /* Wait for data */
   4753       max=0xffff;
   4754       while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
   4755       if (max>0x0) {
   4756         if ((inb(0x60) == 0xfa)) {
   4757           do {
   4758             max=0xffff;
   4759             while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
   4760             if (max>0x0) {
   4761               kbd_code >>= 8;
   4762               kbd_code |= (inb(0x60) << 8);
   4763             }
   4764           } while (--count>0);
   4765         }
   4766       }
   4767       BX=kbd_code;
   4768       break;
   4769 
   4770     case 0x10: /* read MF-II keyboard input */
   4771 
   4772       if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
   4773         BX_PANIC("KBD: int16h: out of keyboard input\n");
   4774         }
   4775       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
   4776       AX = (scan_code << 8) | ascii_code;
   4777       break;
   4778 
   4779     case 0x11: /* check MF-II keyboard status */
   4780       if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
   4781         SET_ZF();
   4782         return;
   4783         }
   4784       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
   4785       AX = (scan_code << 8) | ascii_code;
   4786       CLEAR_ZF();
   4787       break;
   4788 
   4789     case 0x12: /* get extended keyboard status */
   4790       shift_flags = read_byte(0x0040, 0x17);
   4791       SET_AL(shift_flags);
   4792       shift_flags = read_byte(0x0040, 0x18) & 0x73;
   4793       shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
   4794       SET_AH(shift_flags);
   4795       BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
   4796       break;
   4797 
   4798     case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
   4799       SET_AH(0x80); // function int16 ah=0x10-0x12 supported
   4800       break;
   4801 
   4802     case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
   4803       // don't change AH : function int16 ah=0x20-0x22 NOT supported
   4804       break;
   4805 
   4806     case 0x6F:
   4807       if (GET_AL() == 0x08)
   4808         SET_AH(0x02); // unsupported, aka normal keyboard
   4809 
   4810     default:
   4811       BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
   4812     }
   4813 }
   4814 
   4815   unsigned int
   4816 dequeue_key(scan_code, ascii_code, incr)
   4817   Bit8u *scan_code;
   4818   Bit8u *ascii_code;
   4819   unsigned int incr;
   4820 {
   4821   Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
   4822   Bit16u ss;
   4823   Bit8u  acode, scode;
   4824 
   4825 #if BX_CPU < 2
   4826   buffer_start = 0x001E;
   4827   buffer_end   = 0x003E;
   4828 #else
   4829   buffer_start = read_word(0x0040, 0x0080);
   4830   buffer_end   = read_word(0x0040, 0x0082);
   4831 #endif
   4832 
   4833   buffer_head = read_word(0x0040, 0x001a);
   4834   buffer_tail = read_word(0x0040, 0x001c);
   4835 
   4836   if (buffer_head != buffer_tail) {
   4837     ss = get_SS();
   4838     acode = read_byte(0x0040, buffer_head);
   4839     scode = read_byte(0x0040, buffer_head+1);
   4840     write_byte(ss, ascii_code, acode);
   4841     write_byte(ss, scan_code, scode);
   4842 
   4843     if (incr) {
   4844       buffer_head += 2;
   4845       if (buffer_head >= buffer_end)
   4846         buffer_head = buffer_start;
   4847       write_word(0x0040, 0x001a, buffer_head);
   4848       }
   4849     return(1);
   4850     }
   4851   else {
   4852     return(0);
   4853     }
   4854 }
   4855 
   4856 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
   4857 
   4858   Bit8u
   4859 inhibit_mouse_int_and_events()
   4860 {
   4861   Bit8u command_byte, prev_command_byte;
   4862 
   4863   // Turn off IRQ generation and aux data line
   4864   if ( inb(0x64) & 0x02 )
   4865     BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
   4866   outb(0x64, 0x20); // get command byte
   4867   while ( (inb(0x64) & 0x01) != 0x01 );
   4868   prev_command_byte = inb(0x60);
   4869   command_byte = prev_command_byte;
   4870   //while ( (inb(0x64) & 0x02) );
   4871   if ( inb(0x64) & 0x02 )
   4872     BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
   4873   command_byte &= 0xfd; // turn off IRQ 12 generation
   4874   command_byte |= 0x20; // disable mouse serial clock line
   4875   outb(0x64, 0x60); // write command byte
   4876   outb(0x60, command_byte);
   4877   return(prev_command_byte);
   4878 }
   4879 
   4880   void
   4881 enable_mouse_int_and_events()
   4882 {
   4883   Bit8u command_byte;
   4884 
   4885   // Turn on IRQ generation and aux data line
   4886   if ( inb(0x64) & 0x02 )
   4887     BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
   4888   outb(0x64, 0x20); // get command byte
   4889   while ( (inb(0x64) & 0x01) != 0x01 );
   4890   command_byte = inb(0x60);
   4891   //while ( (inb(0x64) & 0x02) );
   4892   if ( inb(0x64) & 0x02 )
   4893     BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
   4894   command_byte |= 0x02; // turn on IRQ 12 generation
   4895   command_byte &= 0xdf; // enable mouse serial clock line
   4896   outb(0x64, 0x60); // write command byte
   4897   outb(0x60, command_byte);
   4898 }
   4899 
   4900   Bit8u
   4901 send_to_mouse_ctrl(sendbyte)
   4902   Bit8u sendbyte;
   4903 {
   4904   Bit8u response;
   4905 
   4906   // wait for chance to write to ctrl
   4907   if ( inb(0x64) & 0x02 )
   4908     BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
   4909   outb(0x64, 0xD4);
   4910   outb(0x60, sendbyte);
   4911   return(0);
   4912 }
   4913 
   4914 
   4915   Bit8u
   4916 get_mouse_data(data)
   4917   Bit8u *data;
   4918 {
   4919   Bit8u response;
   4920   Bit16u ss;
   4921 
   4922   while ( (inb(0x64) & 0x21) != 0x21 ) {
   4923     }
   4924 
   4925   response = inb(0x60);
   4926 
   4927   ss = get_SS();
   4928   write_byte(ss, data, response);
   4929   return(0);
   4930 }
   4931 
   4932   void
   4933 set_kbd_command_byte(command_byte)
   4934   Bit8u command_byte;
   4935 {
   4936   if ( inb(0x64) & 0x02 )
   4937     BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
   4938   outb(0x64, 0xD4);
   4939 
   4940   outb(0x64, 0x60); // write command byte
   4941   outb(0x60, command_byte);
   4942 }
   4943 
   4944   void
   4945 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
   4946   Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
   4947 {
   4948   Bit8u scancode, asciicode, shift_flags;
   4949   Bit8u mf2_flags, mf2_state;
   4950 
   4951   //
   4952   // DS has been set to F000 before call
   4953   //
   4954 
   4955 
   4956   scancode = GET_AL();
   4957 
   4958   if (scancode == 0) {
   4959     BX_INFO("KBD: int09 handler: AL=0\n");
   4960     return;
   4961     }
   4962 
   4963 
   4964   shift_flags = read_byte(0x0040, 0x17);
   4965   mf2_flags = read_byte(0x0040, 0x18);
   4966   mf2_state = read_byte(0x0040, 0x96);
   4967   asciicode = 0;
   4968 
   4969   switch (scancode) {
   4970     case 0x3a: /* Caps Lock press */
   4971       shift_flags ^= 0x40;
   4972       write_byte(0x0040, 0x17, shift_flags);
   4973       mf2_flags |= 0x40;
   4974       write_byte(0x0040, 0x18, mf2_flags);
   4975       break;
   4976     case 0xba: /* Caps Lock release */
   4977       mf2_flags &= ~0x40;
   4978       write_byte(0x0040, 0x18, mf2_flags);
   4979       break;
   4980 
   4981     case 0x2a: /* L Shift press */
   4982       shift_flags |= 0x02;
   4983       write_byte(0x0040, 0x17, shift_flags);
   4984       break;
   4985     case 0xaa: /* L Shift release */
   4986       shift_flags &= ~0x02;
   4987       write_byte(0x0040, 0x17, shift_flags);
   4988       break;
   4989 
   4990     case 0x36: /* R Shift press */
   4991       shift_flags |= 0x01;
   4992       write_byte(0x0040, 0x17, shift_flags);
   4993       break;
   4994     case 0xb6: /* R Shift release */
   4995       shift_flags &= ~0x01;
   4996       write_byte(0x0040, 0x17, shift_flags);
   4997       break;
   4998 
   4999     case 0x1d: /* Ctrl press */
   5000       if ((mf2_state & 0x01) == 0) {
   5001         shift_flags |= 0x04;
   5002         write_byte(0x0040, 0x17, shift_flags);
   5003         if (mf2_state & 0x02) {
   5004           mf2_state |= 0x04;
   5005           write_byte(0x0040, 0x96, mf2_state);
   5006         } else {
   5007           mf2_flags |= 0x01;
   5008           write_byte(0x0040, 0x18, mf2_flags);
   5009         }
   5010       }
   5011       break;
   5012     case 0x9d: /* Ctrl release */
   5013       if ((mf2_state & 0x01) == 0) {
   5014         shift_flags &= ~0x04;
   5015         write_byte(0x0040, 0x17, shift_flags);
   5016         if (mf2_state & 0x02) {
   5017           mf2_state &= ~0x04;
   5018           write_byte(0x0040, 0x96, mf2_state);
   5019         } else {
   5020           mf2_flags &= ~0x01;
   5021           write_byte(0x0040, 0x18, mf2_flags);
   5022         }
   5023       }
   5024       break;
   5025 
   5026     case 0x38: /* Alt press */
   5027       shift_flags |= 0x08;
   5028       write_byte(0x0040, 0x17, shift_flags);
   5029       if (mf2_state & 0x02) {
   5030         mf2_state |= 0x08;
   5031         write_byte(0x0040, 0x96, mf2_state);
   5032       } else {
   5033         mf2_flags |= 0x02;
   5034         write_byte(0x0040, 0x18, mf2_flags);
   5035       }
   5036       break;
   5037     case 0xb8: /* Alt release */
   5038       shift_flags &= ~0x08;
   5039       write_byte(0x0040, 0x17, shift_flags);
   5040       if (mf2_state & 0x02) {
   5041         mf2_state &= ~0x08;
   5042         write_byte(0x0040, 0x96, mf2_state);
   5043       } else {
   5044         mf2_flags &= ~0x02;
   5045         write_byte(0x0040, 0x18, mf2_flags);
   5046       }
   5047       break;
   5048 
   5049     case 0x45: /* Num Lock press */
   5050       if ((mf2_state & 0x03) == 0) {
   5051         mf2_flags |= 0x20;
   5052         write_byte(0x0040, 0x18, mf2_flags);
   5053         shift_flags ^= 0x20;
   5054         write_byte(0x0040, 0x17, shift_flags);
   5055       }
   5056       break;
   5057     case 0xc5: /* Num Lock release */
   5058       if ((mf2_state & 0x03) == 0) {
   5059         mf2_flags &= ~0x20;
   5060         write_byte(0x0040, 0x18, mf2_flags);
   5061       }
   5062       break;
   5063 
   5064     case 0x46: /* Scroll Lock press */
   5065       mf2_flags |= 0x10;
   5066       write_byte(0x0040, 0x18, mf2_flags);
   5067       shift_flags ^= 0x10;
   5068       write_byte(0x0040, 0x17, shift_flags);
   5069       break;
   5070 
   5071     case 0xc6: /* Scroll Lock release */
   5072       mf2_flags &= ~0x10;
   5073       write_byte(0x0040, 0x18, mf2_flags);
   5074       break;
   5075 
   5076     default:
   5077       if (scancode & 0x80) {
   5078         break; /* toss key releases ... */
   5079       }
   5080       if (scancode > MAX_SCAN_CODE) {
   5081         BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
   5082         return;
   5083       }
   5084       if (shift_flags & 0x08) { /* ALT */
   5085         asciicode = scan_to_scanascii[scancode].alt;
   5086         scancode = scan_to_scanascii[scancode].alt >> 8;
   5087       } else if (shift_flags & 0x04) { /* CONTROL */
   5088         asciicode = scan_to_scanascii[scancode].control;
   5089         scancode = scan_to_scanascii[scancode].control >> 8;
   5090       } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
   5091         /* extended keys handling */
   5092         asciicode = 0xe0;
   5093         scancode = scan_to_scanascii[scancode].normal >> 8;
   5094       } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
   5095         /* check if lock state should be ignored
   5096          * because a SHIFT key are pressed */
   5097 
   5098         if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
   5099           asciicode = scan_to_scanascii[scancode].normal;
   5100           scancode = scan_to_scanascii[scancode].normal >> 8;
   5101         } else {
   5102           asciicode = scan_to_scanascii[scancode].shift;
   5103           scancode = scan_to_scanascii[scancode].shift >> 8;
   5104         }
   5105       } else {
   5106         /* check if lock is on */
   5107         if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
   5108           asciicode = scan_to_scanascii[scancode].shift;
   5109           scancode = scan_to_scanascii[scancode].shift >> 8;
   5110         } else {
   5111           asciicode = scan_to_scanascii[scancode].normal;
   5112           scancode = scan_to_scanascii[scancode].normal >> 8;
   5113         }
   5114       }
   5115       if (scancode==0 && asciicode==0) {
   5116         BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
   5117       }
   5118       enqueue_key(scancode, asciicode);
   5119       break;
   5120   }
   5121   if ((scancode & 0x7f) != 0x1d) {
   5122     mf2_state &= ~0x01;
   5123   }
   5124   mf2_state &= ~0x02;
   5125   write_byte(0x0040, 0x96, mf2_state);
   5126 }
   5127 
   5128   unsigned int
   5129 enqueue_key(scan_code, ascii_code)
   5130   Bit8u scan_code, ascii_code;
   5131 {
   5132   Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
   5133 
   5134 #if BX_CPU < 2
   5135   buffer_start = 0x001E;
   5136   buffer_end   = 0x003E;
   5137 #else
   5138   buffer_start = read_word(0x0040, 0x0080);
   5139   buffer_end   = read_word(0x0040, 0x0082);
   5140 #endif
   5141 
   5142   buffer_head = read_word(0x0040, 0x001A);
   5143   buffer_tail = read_word(0x0040, 0x001C);
   5144 
   5145   temp_tail = buffer_tail;
   5146   buffer_tail += 2;
   5147   if (buffer_tail >= buffer_end)
   5148     buffer_tail = buffer_start;
   5149 
   5150   if (buffer_tail == buffer_head) {
   5151     return(0);
   5152     }
   5153 
   5154    write_byte(0x0040, temp_tail, ascii_code);
   5155    write_byte(0x0040, temp_tail+1, scan_code);
   5156    write_word(0x0040, 0x001C, buffer_tail);
   5157    return(1);
   5158 }
   5159 
   5160 
   5161   void
   5162 int74_function(make_farcall, Z, Y, X, status)
   5163   Bit16u make_farcall, Z, Y, X, status;
   5164 {
   5165   Bit16u ebda_seg=read_word(0x0040,0x000E);
   5166   Bit8u  in_byte, index, package_count;
   5167   Bit8u  mouse_flags_1, mouse_flags_2;
   5168 
   5169 BX_DEBUG_INT74("entering int74_function\n");
   5170   make_farcall = 0;
   5171 
   5172   in_byte = inb(0x64);
   5173   if ( (in_byte & 0x21) != 0x21 ) {
   5174     return;
   5175     }
   5176   in_byte = inb(0x60);
   5177 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
   5178 
   5179   mouse_flags_1 = read_byte(ebda_seg, 0x0026);
   5180   mouse_flags_2 = read_byte(ebda_seg, 0x0027);
   5181 
   5182   if ( (mouse_flags_2 & 0x80) != 0x80 ) {
   5183       return;
   5184   }
   5185 
   5186   package_count = mouse_flags_2 & 0x07;
   5187   index = mouse_flags_1 & 0x07;
   5188   write_byte(ebda_seg, 0x28 + index, in_byte);
   5189 
   5190   if ( (index+1) >= package_count ) {
   5191 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
   5192     status = read_byte(ebda_seg, 0x0028 + 0);
   5193     X      = read_byte(ebda_seg, 0x0028 + 1);
   5194     Y      = read_byte(ebda_seg, 0x0028 + 2);
   5195     Z      = 0;
   5196     mouse_flags_1 = 0;
   5197     // check if far call handler installed
   5198     if (mouse_flags_2 & 0x80)
   5199       make_farcall = 1;
   5200     }
   5201   else {
   5202     mouse_flags_1++;
   5203     }
   5204   write_byte(ebda_seg, 0x0026, mouse_flags_1);
   5205 }
   5206 
   5207 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
   5208 
   5209 #if BX_USE_ATADRV
   5210 
   5211   void
   5212 int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
   5213   Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
   5214 {
   5215   Bit32u lba_low, lba_high;
   5216   Bit16u ebda_seg=read_word(0x0040,0x000E);
   5217   Bit16u cylinder, head, sector;
   5218   Bit16u segment, offset;
   5219   Bit16u npc, nph, npspt, nlc, nlh, nlspt;
   5220   Bit16u size, count;
   5221   Bit8u  device, status;
   5222 
   5223   BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
   5224 
   5225   write_byte(0x0040, 0x008e, 0);  // clear completion flag
   5226 
   5227   // basic check : device has to be defined
   5228   if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
   5229     BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
   5230     goto int13_fail;
   5231     }
   5232 
   5233   // Get the ata channel
   5234   device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
   5235 
   5236   // basic check : device has to be valid
   5237   if (device >= BX_MAX_ATA_DEVICES) {
   5238     BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
   5239     goto int13_fail;
   5240     }
   5241 
   5242   switch (GET_AH()) {
   5243 
   5244     case 0x00: /* disk controller reset */
   5245       ata_reset (device);
   5246       goto int13_success;
   5247       break;
   5248 
   5249     case 0x01: /* read disk status */
   5250       status = read_byte(0x0040, 0x0074);
   5251       SET_AH(status);
   5252       SET_DISK_RET_STATUS(0);
   5253       /* set CF if error status read */
   5254       if (status) goto int13_fail_nostatus;
   5255       else        goto int13_success_noah;
   5256       break;
   5257 
   5258     case 0x02: // read disk sectors
   5259     case 0x03: // write disk sectors
   5260     case 0x04: // verify disk sectors
   5261 
   5262       count       = GET_AL();
   5263       cylinder    = GET_CH();
   5264       cylinder   |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
   5265       sector      = (GET_CL() & 0x3f);
   5266       head        = GET_DH();
   5267 
   5268       segment = ES;
   5269       offset  = BX;
   5270 
   5271       if ((count > 128) || (count == 0) || (sector == 0)) {
   5272         BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH());
   5273         goto int13_fail;
   5274       }
   5275 
   5276       nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
   5277       nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
   5278       nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
   5279 
   5280       // sanity check on cyl heads, sec
   5281       if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
   5282         BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
   5283         goto int13_fail;
   5284         }
   5285 
   5286       // FIXME verify
   5287       if ( GET_AH() == 0x04 ) goto int13_success;
   5288 
   5289       nph   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
   5290       npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
   5291 
   5292       // if needed, translate lchs to lba, and execute command
   5293       if ( (nph != nlh) || (npspt != nlspt)) {
   5294         lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
   5295         lba_high = 0;
   5296         sector = 0; // this forces the command to be lba
   5297         }
   5298 
   5299       if ( GET_AH() == 0x02 )
   5300         status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
   5301       else
   5302         status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset);
   5303 
   5304       // Set nb of sector transferred
   5305       SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
   5306 
   5307       if (status != 0) {
   5308         BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
   5309         SET_AH(0x0c);
   5310         goto int13_fail_noah;
   5311         }
   5312 
   5313       goto int13_success;
   5314       break;
   5315 
   5316     case 0x05: /* format disk track */
   5317       BX_INFO("format disk track called\n");
   5318       goto int13_success;
   5319       return;
   5320       break;
   5321 
   5322     case 0x08: /* read disk drive parameters */
   5323 
   5324       // Get logical geometry from table
   5325       nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
   5326       nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
   5327       nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
   5328       count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
   5329 
   5330       nlc = nlc - 2; /* 0 based , last sector not used */
   5331       SET_AL(0);
   5332       SET_CH(nlc & 0xff);
   5333       SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
   5334       SET_DH(nlh - 1);
   5335       SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
   5336 
   5337       // FIXME should set ES & DI
   5338 
   5339       goto int13_success;
   5340       break;
   5341 
   5342     case 0x10: /* check drive ready */
   5343       // should look at 40:8E also???
   5344 
   5345       // Read the status from controller
   5346       status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
   5347       if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
   5348         goto int13_success;
   5349         }
   5350       else {
   5351         SET_AH(0xAA);
   5352         goto int13_fail_noah;
   5353         }
   5354       break;
   5355 
   5356     case 0x15: /* read disk drive size */
   5357 
   5358       // Get logical geometry from table
   5359       nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
   5360       nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
   5361       nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
   5362 
   5363       // Compute sector count seen by int13
   5364       lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt;
   5365       CX = lba_low >> 16;
   5366       DX = lba_low & 0xffff;
   5367 
   5368       SET_AH(3);  // hard disk accessible
   5369       goto int13_success_noah;
   5370       break;
   5371 
   5372     case 0x41: // IBM/MS installation check
   5373       BX=0xaa55;     // install check
   5374       SET_AH(0x30);  // EDD 3.0
   5375       CX=0x0007;     // ext disk access and edd, removable supported
   5376       goto int13_success_noah;
   5377       break;
   5378 
   5379     case 0x42: // IBM/MS extended read
   5380     case 0x43: // IBM/MS extended write
   5381     case 0x44: // IBM/MS verify
   5382     case 0x47: // IBM/MS extended seek
   5383 
   5384       count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
   5385       segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
   5386       offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
   5387 
   5388       // Get 32 msb lba and check
   5389       lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
   5390       if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) {
   5391         BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
   5392         goto int13_fail;
   5393         }
   5394 
   5395       // Get 32 lsb lba and check
   5396       lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
   5397       if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high)
   5398           && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) {
   5399         BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
   5400         goto int13_fail;
   5401         }
   5402 
   5403       // If verify or seek
   5404       if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
   5405         goto int13_success;
   5406 
   5407       // Execute the command
   5408       if ( GET_AH() == 0x42 )
   5409         status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
   5410       else
   5411         status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset);
   5412 
   5413       count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
   5414       write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
   5415 
   5416       if (status != 0) {
   5417         BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
   5418         SET_AH(0x0c);
   5419         goto int13_fail_noah;
   5420         }
   5421 
   5422       goto int13_success;
   5423       break;
   5424 
   5425     case 0x45: // IBM/MS lock/unlock drive
   5426     case 0x49: // IBM/MS extended media change
   5427       goto int13_success;    // Always success for HD
   5428       break;
   5429 
   5430     case 0x46: // IBM/MS eject media
   5431       SET_AH(0xb2);          // Volume Not Removable
   5432       goto int13_fail_noah;  // Always fail for HD
   5433       break;
   5434 
   5435     case 0x48: // IBM/MS get drive parameters
   5436       size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
   5437 
   5438       // Buffer is too small
   5439       if(size < 0x1a)
   5440         goto int13_fail;
   5441 
   5442       // EDD 1.x
   5443       if(size >= 0x1a) {
   5444         Bit16u   blksize;
   5445 
   5446         npc     = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
   5447         nph     = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
   5448         npspt   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
   5449         lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low);
   5450         lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high);
   5451         blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
   5452 
   5453         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
   5454         if (lba_high || (lba_low/npspt)/nph > 0x3fff)
   5455         {
   5456           write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid
   5457           write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff);
   5458         }
   5459         else
   5460         {
   5461           write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
   5462           write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
   5463         }
   5464         write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
   5465         write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
   5466         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low);
   5467         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high);
   5468         write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
   5469         }
   5470 
   5471       // EDD 2.x
   5472       if(size >= 0x1e) {
   5473         Bit8u  channel, dev, irq, mode, checksum, i, translation;
   5474         Bit16u iobase1, iobase2, options;
   5475 
   5476         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
   5477 
   5478         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
   5479         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
   5480 
   5481         // Fill in dpte
   5482         channel = device / 2;
   5483         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   5484         iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
   5485         irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
   5486         mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
   5487         translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
   5488 
   5489         options  = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
   5490         options |= (1<<4); // lba translation
   5491         options |= (mode==ATA_MODE_PIO32?1:0)<<7;
   5492         options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
   5493         options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
   5494 
   5495         write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
   5496         write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
   5497         write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
   5498         write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
   5499         write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
   5500         write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
   5501         write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
   5502         write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
   5503         write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
   5504         write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
   5505         if (size >=0x42)
   5506           write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
   5507         else
   5508           write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10);
   5509 
   5510         checksum=0;
   5511         for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
   5512         checksum = ~checksum;
   5513         write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
   5514         }
   5515 
   5516       // EDD 3.x
   5517       if(size >= 0x42) {
   5518         Bit8u channel, iface, checksum, i;
   5519         Bit16u iobase1;
   5520 
   5521         channel = device / 2;
   5522         iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
   5523         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   5524 
   5525         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
   5526         write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
   5527         write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
   5528         write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
   5529         write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
   5530 
   5531         if (iface==ATA_IFACE_ISA) {
   5532           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
   5533           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
   5534           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
   5535           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
   5536           }
   5537         else {
   5538           // FIXME PCI
   5539           }
   5540         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
   5541         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
   5542         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
   5543         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
   5544 
   5545         if (iface==ATA_IFACE_ISA) {
   5546           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
   5547           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
   5548           write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
   5549           }
   5550         else {
   5551           // FIXME PCI
   5552           }
   5553         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
   5554         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
   5555         write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
   5556         write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
   5557 
   5558         checksum=0;
   5559         for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
   5560         checksum = ~checksum;
   5561         write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
   5562         }
   5563 
   5564       goto int13_success;
   5565       break;
   5566 
   5567     case 0x4e: // // IBM/MS set hardware configuration
   5568       // DMA, prefetch, PIO maximum not supported
   5569       switch (GET_AL()) {
   5570         case 0x01:
   5571         case 0x03:
   5572         case 0x04:
   5573         case 0x06:
   5574           goto int13_success;
   5575           break;
   5576         default :
   5577           goto int13_fail;
   5578         }
   5579       break;
   5580 
   5581     case 0x09: /* initialize drive parameters */
   5582     case 0x0c: /* seek to specified cylinder */
   5583     case 0x0d: /* alternate disk reset */
   5584     case 0x11: /* recalibrate */
   5585     case 0x14: /* controller internal diagnostic */
   5586       BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH());
   5587       goto int13_success;
   5588       break;
   5589 
   5590     case 0x0a: /* read disk sectors with ECC */
   5591     case 0x0b: /* write disk sectors with ECC */
   5592     case 0x18: // set media type for format
   5593     case 0x50: // IBM/MS send packet command
   5594     default:
   5595       BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
   5596       goto int13_fail;
   5597       break;
   5598     }
   5599 
   5600 int13_fail:
   5601     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
   5602 int13_fail_noah:
   5603     SET_DISK_RET_STATUS(GET_AH());
   5604 int13_fail_nostatus:
   5605     SET_CF();     // error occurred
   5606     return;
   5607 
   5608 int13_success:
   5609     SET_AH(0x00); // no error
   5610 int13_success_noah:
   5611     SET_DISK_RET_STATUS(0x00);
   5612     CLEAR_CF();   // no error
   5613     return;
   5614 }
   5615 
   5616 // ---------------------------------------------------------------------------
   5617 // Start of int13 for cdrom
   5618 // ---------------------------------------------------------------------------
   5619 
   5620   void
   5621 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
   5622   Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
   5623 {
   5624   Bit16u ebda_seg=read_word(0x0040,0x000E);
   5625   Bit8u  device, status, locks;
   5626   Bit8u  atacmd[12];
   5627   Bit32u lba;
   5628   Bit16u count, segment, offset, i, size;
   5629 
   5630   BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
   5631 
   5632   SET_DISK_RET_STATUS(0x00);
   5633 
   5634   /* basic check : device should be 0xE0+ */
   5635   if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
   5636     BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
   5637     goto int13_fail;
   5638     }
   5639 
   5640   // Get the ata channel
   5641   device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
   5642 
   5643   /* basic check : device has to be valid  */
   5644   if (device >= BX_MAX_ATA_DEVICES) {
   5645     BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
   5646     goto int13_fail;
   5647     }
   5648 
   5649   switch (GET_AH()) {
   5650 
   5651     // all those functions return SUCCESS
   5652     case 0x00: /* disk controller reset */
   5653     case 0x09: /* initialize drive parameters */
   5654     case 0x0c: /* seek to specified cylinder */
   5655     case 0x0d: /* alternate disk reset */
   5656     case 0x10: /* check drive ready */
   5657     case 0x11: /* recalibrate */
   5658     case 0x14: /* controller internal diagnostic */
   5659     case 0x16: /* detect disk change */
   5660       goto int13_success;
   5661       break;
   5662 
   5663     // all those functions return disk write-protected
   5664     case 0x03: /* write disk sectors */
   5665     case 0x05: /* format disk track */
   5666     case 0x43: // IBM/MS extended write
   5667       SET_AH(0x03);
   5668       goto int13_fail_noah;
   5669       break;
   5670 
   5671     case 0x01: /* read disk status */
   5672       status = read_byte(0x0040, 0x0074);
   5673       SET_AH(status);
   5674       SET_DISK_RET_STATUS(0);
   5675 
   5676       /* set CF if error status read */
   5677       if (status) goto int13_fail_nostatus;
   5678       else        goto int13_success_noah;
   5679       break;
   5680 
   5681     case 0x15: /* read disk drive size */
   5682       SET_AH(0x02);
   5683       goto int13_fail_noah;
   5684       break;
   5685 
   5686     case 0x41: // IBM/MS installation check
   5687       BX=0xaa55;     // install check
   5688       SET_AH(0x30);  // EDD 2.1
   5689       CX=0x0007;     // ext disk access, removable and edd
   5690       goto int13_success_noah;
   5691       break;
   5692 
   5693     case 0x42: // IBM/MS extended read
   5694     case 0x44: // IBM/MS verify sectors
   5695     case 0x47: // IBM/MS extended seek
   5696 
   5697       count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
   5698       segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
   5699       offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
   5700 
   5701       // Can't use 64 bits lba
   5702       lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
   5703       if (lba != 0L) {
   5704         BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
   5705         goto int13_fail;
   5706         }
   5707 
   5708       // Get 32 bits lba
   5709       lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
   5710 
   5711       // If verify or seek
   5712       if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
   5713         goto int13_success;
   5714 
   5715       memsetb(get_SS(),atacmd,0,12);
   5716       atacmd[0]=0x28;                      // READ command
   5717       atacmd[7]=(count & 0xff00) >> 8;     // Sectors
   5718       atacmd[8]=(count & 0x00ff);          // Sectors
   5719       atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
   5720       atacmd[3]=(lba & 0x00ff0000) >> 16;
   5721       atacmd[4]=(lba & 0x0000ff00) >> 8;
   5722       atacmd[5]=(lba & 0x000000ff);
   5723       status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset);
   5724 
   5725       count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
   5726       write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
   5727 
   5728       if (status != 0) {
   5729         BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
   5730         SET_AH(0x0c);
   5731         goto int13_fail_noah;
   5732         }
   5733 
   5734       goto int13_success;
   5735       break;
   5736 
   5737     case 0x45: // IBM/MS lock/unlock drive
   5738       if (GET_AL() > 2) goto int13_fail;
   5739 
   5740       locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
   5741 
   5742       switch (GET_AL()) {
   5743         case 0 :  // lock
   5744           if (locks == 0xff) {
   5745             SET_AH(0xb4);
   5746             SET_AL(1);
   5747             goto int13_fail_noah;
   5748             }
   5749           write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
   5750           SET_AL(1);
   5751           break;
   5752         case 1 :  // unlock
   5753           if (locks == 0x00) {
   5754             SET_AH(0xb0);
   5755             SET_AL(0);
   5756             goto int13_fail_noah;
   5757             }
   5758           write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
   5759           SET_AL(locks==0?0:1);
   5760           break;
   5761         case 2 :  // status
   5762           SET_AL(locks==0?0:1);
   5763           break;
   5764         }
   5765       goto int13_success;
   5766       break;
   5767 
   5768     case 0x46: // IBM/MS eject media
   5769       locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
   5770 
   5771       if (locks != 0) {
   5772         SET_AH(0xb1); // media locked
   5773         goto int13_fail_noah;
   5774         }
   5775       // FIXME should handle 0x31 no media in device
   5776       // FIXME should handle 0xb5 valid request failed
   5777 
   5778       // Call removable media eject
   5779       ASM_START
   5780         push bp
   5781         mov  bp, sp
   5782 
   5783         mov ah, #0x52
   5784         int #0x15
   5785         mov _int13_cdrom.status + 2[bp], ah
   5786         jnc int13_cdrom_rme_end
   5787         mov _int13_cdrom.status, #1
   5788 int13_cdrom_rme_end:
   5789         pop bp
   5790       ASM_END
   5791 
   5792       if (status != 0) {
   5793         SET_AH(0xb1); // media locked
   5794         goto int13_fail_noah;
   5795       }
   5796 
   5797       goto int13_success;
   5798       break;
   5799 
   5800     case 0x48: // IBM/MS get drive parameters
   5801       size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
   5802 
   5803       // Buffer is too small
   5804       if(size < 0x1a)
   5805         goto int13_fail;
   5806 
   5807       // EDD 1.x
   5808       if(size >= 0x1a) {
   5809         Bit16u   cylinders, heads, spt, blksize;
   5810 
   5811         blksize   = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
   5812 
   5813         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
   5814         write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
   5815         write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
   5816         write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
   5817         write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
   5818         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff);  // FIXME should be Bit64
   5819         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);
   5820         write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);
   5821         }
   5822 
   5823       // EDD 2.x
   5824       if(size >= 0x1e) {
   5825         Bit8u  channel, dev, irq, mode, checksum, i;
   5826         Bit16u iobase1, iobase2, options;
   5827 
   5828         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
   5829 
   5830         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);
   5831         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);
   5832 
   5833         // Fill in dpte
   5834         channel = device / 2;
   5835         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   5836         iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
   5837         irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
   5838         mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
   5839 
   5840         // FIXME atapi device
   5841         options  = (1<<4); // lba translation
   5842         options |= (1<<5); // removable device
   5843         options |= (1<<6); // atapi device
   5844         options |= (mode==ATA_MODE_PIO32?1:0<<7);
   5845 
   5846         write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
   5847         write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC);
   5848         write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
   5849         write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
   5850         write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
   5851         write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
   5852         write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
   5853         write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
   5854         write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
   5855         write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
   5856         write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
   5857 
   5858         checksum=0;
   5859         for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i);
   5860         checksum = ~checksum;
   5861         write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
   5862         }
   5863 
   5864       // EDD 3.x
   5865       if(size >= 0x42) {
   5866         Bit8u channel, iface, checksum, i;
   5867         Bit16u iobase1;
   5868 
   5869         channel = device / 2;
   5870         iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
   5871         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
   5872 
   5873         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
   5874         write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
   5875         write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
   5876         write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
   5877         write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
   5878 
   5879         if (iface==ATA_IFACE_ISA) {
   5880           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
   5881           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
   5882           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
   5883           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
   5884           }
   5885         else {
   5886           // FIXME PCI
   5887           }
   5888         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
   5889         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
   5890         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
   5891         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
   5892 
   5893         if (iface==ATA_IFACE_ISA) {
   5894           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
   5895           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
   5896           write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
   5897           }
   5898         else {
   5899           // FIXME PCI
   5900           }
   5901         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
   5902         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
   5903         write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
   5904         write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
   5905 
   5906         checksum=0;
   5907         for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
   5908         checksum = ~checksum;
   5909         write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
   5910         }
   5911 
   5912       goto int13_success;
   5913       break;
   5914 
   5915     case 0x49: // IBM/MS extended media change
   5916       // always send changed ??
   5917       SET_AH(06);
   5918       goto int13_fail_nostatus;
   5919       break;
   5920 
   5921     case 0x4e: // // IBM/MS set hardware configuration
   5922       // DMA, prefetch, PIO maximum not supported
   5923       switch (GET_AL()) {
   5924         case 0x01:
   5925         case 0x03:
   5926         case 0x04:
   5927         case 0x06:
   5928           goto int13_success;
   5929           break;
   5930         default :
   5931           goto int13_fail;
   5932         }
   5933       break;
   5934 
   5935     // all those functions return unimplemented
   5936     case 0x02: /* read sectors */
   5937     case 0x04: /* verify sectors */
   5938     case 0x08: /* read disk drive parameters */
   5939     case 0x0a: /* read disk sectors with ECC */
   5940     case 0x0b: /* write disk sectors with ECC */