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 */
   5941     case 0x18: /* set media type for format */
   5942     case 0x50: // ? - send packet command
   5943     default:
   5944       BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
   5945       goto int13_fail;
   5946       break;
   5947     }
   5948 
   5949 int13_fail:
   5950     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
   5951 int13_fail_noah:
   5952     SET_DISK_RET_STATUS(GET_AH());
   5953 int13_fail_nostatus:
   5954     SET_CF();     // error occurred
   5955     return;
   5956 
   5957 int13_success:
   5958     SET_AH(0x00); // no error
   5959 int13_success_noah:
   5960     SET_DISK_RET_STATUS(0x00);
   5961     CLEAR_CF();   // no error
   5962     return;
   5963 }
   5964 
   5965 // ---------------------------------------------------------------------------
   5966 // End of int13 for cdrom
   5967 // ---------------------------------------------------------------------------
   5968 
   5969 #if BX_ELTORITO_BOOT
   5970 // ---------------------------------------------------------------------------
   5971 // Start of int13 for eltorito functions
   5972 // ---------------------------------------------------------------------------
   5973 
   5974   void
   5975 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
   5976   Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
   5977 {
   5978   Bit16u ebda_seg=read_word(0x0040,0x000E);
   5979 
   5980   BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
   5981   // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
   5982 
   5983   switch (GET_AH()) {
   5984 
   5985     // FIXME ElTorito Various. Should be implemented
   5986     case 0x4a: // ElTorito - Initiate disk emu
   5987     case 0x4c: // ElTorito - Initiate disk emu and boot
   5988     case 0x4d: // ElTorito - Return Boot catalog
   5989       BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
   5990       goto int13_fail;
   5991       break;
   5992 
   5993     case 0x4b: // ElTorito - Terminate disk emu
   5994       // FIXME ElTorito Hardcoded
   5995       write_byte(DS,SI+0x00,0x13);
   5996       write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
   5997       write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
   5998       write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
   5999       write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
   6000       write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
   6001       write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
   6002       write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
   6003       write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
   6004       write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
   6005       write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
   6006       write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
   6007 
   6008       // If we have to terminate emulation
   6009       if(GET_AL() == 0x00) {
   6010         // FIXME ElTorito Various. Should be handled accordingly to spec
   6011         write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
   6012         }
   6013 
   6014       goto int13_success;
   6015       break;
   6016 
   6017     default:
   6018       BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
   6019       goto int13_fail;
   6020       break;
   6021     }
   6022 
   6023 int13_fail:
   6024     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
   6025     SET_DISK_RET_STATUS(GET_AH());
   6026     SET_CF();     // error occurred
   6027     return;
   6028 
   6029 int13_success:
   6030     SET_AH(0x00); // no error
   6031     SET_DISK_RET_STATUS(0x00);
   6032     CLEAR_CF();   // no error
   6033     return;
   6034 }
   6035 
   6036 // ---------------------------------------------------------------------------
   6037 // End of int13 for eltorito functions
   6038 // ---------------------------------------------------------------------------
   6039 
   6040 // ---------------------------------------------------------------------------
   6041 // Start of int13 when emulating a device from the cd
   6042 // ---------------------------------------------------------------------------
   6043 
   6044   void
   6045 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
   6046   Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
   6047 {
   6048   Bit16u ebda_seg=read_word(0x0040,0x000E);
   6049   Bit8u  device, status;
   6050   Bit16u vheads, vspt, vcylinders;
   6051   Bit16u head, sector, cylinder, nbsectors;
   6052   Bit32u vlba, ilba, slba, elba;
   6053   Bit16u before, segment, offset;
   6054   Bit8u  atacmd[12];
   6055 
   6056   BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
   6057 
   6058   /* at this point, we are emulating a floppy/harddisk */
   6059 
   6060   // Recompute the device number
   6061   device  = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
   6062   device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
   6063 
   6064   SET_DISK_RET_STATUS(0x00);
   6065 
   6066   /* basic checks : emulation should be active, dl should equal the emulated drive */
   6067   if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
   6068    || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
   6069     BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
   6070     goto int13_fail;
   6071     }
   6072 
   6073   switch (GET_AH()) {
   6074 
   6075     // all those functions return SUCCESS
   6076     case 0x00: /* disk controller reset */
   6077     case 0x09: /* initialize drive parameters */
   6078     case 0x0c: /* seek to specified cylinder */
   6079     case 0x0d: /* alternate disk reset */  // FIXME ElTorito Various. should really reset ?
   6080     case 0x10: /* check drive ready */     // FIXME ElTorito Various. should check if ready ?
   6081     case 0x11: /* recalibrate */
   6082     case 0x14: /* controller internal diagnostic */
   6083     case 0x16: /* detect disk change */
   6084       goto int13_success;
   6085       break;
   6086 
   6087     // all those functions return disk write-protected
   6088     case 0x03: /* write disk sectors */
   6089     case 0x05: /* format disk track */
   6090       SET_AH(0x03);
   6091       goto int13_fail_noah;
   6092       break;
   6093 
   6094     case 0x01: /* read disk status */
   6095       status=read_byte(0x0040, 0x0074);
   6096       SET_AH(status);
   6097       SET_DISK_RET_STATUS(0);
   6098 
   6099       /* set CF if error status read */
   6100       if (status) goto int13_fail_nostatus;
   6101       else        goto int13_success_noah;
   6102       break;
   6103 
   6104     case 0x02: // read disk sectors
   6105     case 0x04: // verify disk sectors
   6106       vspt       = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
   6107       vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders);
   6108       vheads     = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads);
   6109 
   6110       ilba       = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
   6111 
   6112       sector    = GET_CL() & 0x003f;
   6113       cylinder  = (GET_CL() & 0x00c0) << 2 | GET_CH();
   6114       head      = GET_DH();
   6115       nbsectors = GET_AL();
   6116       segment   = ES;
   6117       offset    = BX;
   6118 
   6119       // no sector to read ?
   6120       if(nbsectors==0) goto int13_success;
   6121 
   6122       // sanity checks sco openserver needs this!
   6123       if ((sector   >  vspt)
   6124        || (cylinder >= vcylinders)
   6125        || (head     >= vheads)) {
   6126         goto int13_fail;
   6127         }
   6128 
   6129       // After controls, verify do nothing
   6130       if (GET_AH() == 0x04) goto int13_success;
   6131 
   6132       segment = ES+(BX / 16);
   6133       offset  = BX % 16;
   6134 
   6135       // calculate the virtual lba inside the image
   6136       vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
   6137 
   6138       // In advance so we don't loose the count
   6139       SET_AL(nbsectors);
   6140 
   6141       // start lba on cd
   6142       slba  = (Bit32u)vlba/4;
   6143       before= (Bit16u)vlba%4;
   6144 
   6145       // end lba on cd
   6146       elba = (Bit32u)(vlba+nbsectors-1)/4;
   6147 
   6148       memsetb(get_SS(),atacmd,0,12);
   6149       atacmd[0]=0x28;                      // READ command
   6150       atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
   6151       atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff);      // Sectors
   6152       atacmd[2]=(ilba+slba & 0xff000000) >> 24;  // LBA
   6153       atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
   6154       atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
   6155       atacmd[5]=(ilba+slba & 0x000000ff);
   6156       if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
   6157         BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
   6158         SET_AH(0x02);
   6159         SET_AL(0);
   6160         goto int13_fail_noah;
   6161         }
   6162 
   6163       goto int13_success;
   6164       break;
   6165 
   6166     case 0x08: /* read disk drive parameters */
   6167       vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt);
   6168       vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1;
   6169       vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1;
   6170 
   6171       SET_AL( 0x00 );
   6172       SET_BL( 0x00 );
   6173       SET_CH( vcylinders & 0xff );
   6174       SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt  & 0x3f ));
   6175       SET_DH( vheads );
   6176       SET_DL( 0x02 );   // FIXME ElTorito Various. should send the real count of drives 1 or 2
   6177                         // FIXME ElTorito Harddisk. should send the HD count
   6178 
   6179       switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
   6180         case 0x01: SET_BL( 0x02 ); break;
   6181         case 0x02: SET_BL( 0x04 ); break;
   6182         case 0x03: SET_BL( 0x06 ); break;
   6183         }
   6184 
   6185 ASM_START
   6186       push bp
   6187       mov  bp, sp
   6188       mov ax, #diskette_param_table2
   6189       mov _int13_cdemu.DI+2[bp], ax
   6190       mov _int13_cdemu.ES+2[bp], cs
   6191       pop  bp
   6192 ASM_END
   6193       goto int13_success;
   6194       break;
   6195 
   6196     case 0x15: /* read disk drive size */
   6197       // FIXME ElTorito Harddisk. What geometry to send ?
   6198       SET_AH(0x03);
   6199       goto int13_success_noah;
   6200       break;
   6201 
   6202     // all those functions return unimplemented
   6203     case 0x0a: /* read disk sectors with ECC */
   6204     case 0x0b: /* write disk sectors with ECC */
   6205     case 0x18: /* set media type for format */
   6206     case 0x41: // IBM/MS installation check
   6207       // FIXME ElTorito Harddisk. Darwin would like to use EDD
   6208     case 0x42: // IBM/MS extended read
   6209     case 0x43: // IBM/MS extended write
   6210     case 0x44: // IBM/MS verify sectors
   6211     case 0x45: // IBM/MS lock/unlock drive
   6212     case 0x46: // IBM/MS eject media
   6213     case 0x47: // IBM/MS extended seek
   6214     case 0x48: // IBM/MS get drive parameters
   6215     case 0x49: // IBM/MS extended media change
   6216     case 0x4e: // ? - set hardware configuration
   6217     case 0x50: // ? - send packet command
   6218     default:
   6219       BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
   6220       goto int13_fail;
   6221       break;
   6222     }
   6223 
   6224 int13_fail:
   6225     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
   6226 int13_fail_noah:
   6227     SET_DISK_RET_STATUS(GET_AH());
   6228 int13_fail_nostatus:
   6229     SET_CF();     // error occurred
   6230     return;
   6231 
   6232 int13_success:
   6233     SET_AH(0x00); // no error
   6234 int13_success_noah:
   6235     SET_DISK_RET_STATUS(0x00);
   6236     CLEAR_CF();   // no error
   6237     return;
   6238 }
   6239 
   6240 // ---------------------------------------------------------------------------
   6241 // End of int13 when emulating a device from the cd
   6242 // ---------------------------------------------------------------------------
   6243 
   6244 #endif // BX_ELTORITO_BOOT
   6245 
   6246 #else //BX_USE_ATADRV
   6247 
   6248   void
   6249 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
   6250   Bit16u cylinder;
   6251   Bit16u hd_heads;
   6252   Bit16u head;
   6253   Bit16u hd_sectors;
   6254   Bit16u sector;
   6255   Bit16u dl;
   6256 {
   6257 ASM_START
   6258         push   bp
   6259         mov    bp, sp
   6260         push   eax
   6261         push   ebx
   6262         push   edx
   6263         xor    eax,eax
   6264         mov    ax,4[bp]  // cylinder
   6265         xor    ebx,ebx
   6266         mov    bl,6[bp]  // hd_heads
   6267         imul   ebx
   6268 
   6269         mov    bl,8[bp]  // head
   6270         add    eax,ebx
   6271         mov    bl,10[bp] // hd_sectors
   6272         imul   ebx
   6273         mov    bl,12[bp] // sector
   6274         add    eax,ebx
   6275 
   6276         dec    eax
   6277         mov    dx,#0x1f3
   6278         out    dx,al
   6279         mov    dx,#0x1f4
   6280         mov    al,ah
   6281         out    dx,al
   6282         shr    eax,#16
   6283         mov    dx,#0x1f5
   6284         out    dx,al
   6285         and    ah,#0xf
   6286         mov    bl,14[bp] // dl
   6287         and    bl,#1
   6288         shl    bl,#4
   6289         or     ah,bl
   6290         or     ah,#0xe0
   6291         mov    al,ah
   6292         mov    dx,#0x01f6
   6293         out    dx,al
   6294         pop    edx
   6295         pop    ebx
   6296         pop    eax
   6297         pop    bp
   6298 ASM_END
   6299 }
   6300 
   6301   void
   6302 int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
   6303   Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
   6304 {
   6305   Bit8u    drive, num_sectors, sector, head, status, mod;
   6306   Bit8u    drive_map;
   6307   Bit8u    n_drives;
   6308   Bit16u   cyl_mod, ax;
   6309   Bit16u   max_cylinder, cylinder, total_sectors;
   6310   Bit16u   hd_cylinders;
   6311   Bit8u    hd_heads, hd_sectors;
   6312   Bit16u   val16;
   6313   Bit8u    sector_count;
   6314   unsigned int i;
   6315   Bit16u   tempbx;
   6316   Bit16u   dpsize;
   6317 
   6318   Bit16u   count, segment, offset;
   6319   Bit32u   lba;
   6320   Bit16u   error;
   6321 
   6322   BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
   6323 
   6324   write_byte(0x0040, 0x008e, 0);  // clear completion flag
   6325 
   6326   /* at this point, DL is >= 0x80 to be passed from the floppy int13h
   6327      handler code */
   6328   /* check how many disks first (cmos reg 0x12), return an error if
   6329      drive not present */
   6330   drive_map = inb_cmos(0x12);
   6331   drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
   6332               (((drive_map & 0x0f)==0) ? 0 : 2);
   6333   n_drives = (drive_map==0) ? 0 :
   6334     ((drive_map==3) ? 2 : 1);
   6335 
   6336   if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
   6337     SET_AH(0x01);
   6338     SET_DISK_RET_STATUS(0x01);
   6339     SET_CF(); /* error occurred */
   6340     return;
   6341     }
   6342 
   6343   switch (GET_AH()) {
   6344 
   6345     case 0x00: /* disk controller reset */
   6346 BX_DEBUG_INT13_HD("int13_f00\n");
   6347 
   6348       SET_AH(0);
   6349       SET_DISK_RET_STATUS(0);
   6350       set_diskette_ret_status(0);
   6351       set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
   6352       set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
   6353       CLEAR_CF(); /* successful */
   6354       return;
   6355       break;
   6356 
   6357     case 0x01: /* read disk status */
   6358 BX_DEBUG_INT13_HD("int13_f01\n");
   6359       status = read_byte(0x0040, 0x0074);
   6360       SET_AH(status);
   6361       SET_DISK_RET_STATUS(0);
   6362       /* set CF if error status read */
   6363       if (status) SET_CF();
   6364       else        CLEAR_CF();
   6365       return;
   6366       break;
   6367 
   6368     case 0x04: // verify disk sectors
   6369     case 0x02: // read disk sectors
   6370       drive = GET_ELDL();
   6371       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
   6372 
   6373       num_sectors = GET_AL();
   6374       cylinder    = (GET_CL() & 0x00c0) << 2 | GET_CH();
   6375       sector      = (GET_CL() & 0x3f);
   6376       head        = GET_DH();
   6377 
   6378 
   6379       if (hd_cylinders > 1024) {
   6380         if (hd_cylinders <= 2048) {
   6381           cylinder <<= 1;
   6382           }
   6383         else if (hd_cylinders <= 4096) {
   6384           cylinder <<= 2;
   6385           }
   6386         else if (hd_cylinders <= 8192) {
   6387           cylinder <<= 3;
   6388           }
   6389         else { // hd_cylinders <= 16384
   6390           cylinder <<= 4;
   6391           }
   6392 
   6393         ax = head / hd_heads;
   6394         cyl_mod = ax & 0xff;
   6395         head    = ax >> 8;
   6396         cylinder |= cyl_mod;
   6397         }
   6398 
   6399       if ( (cylinder >= hd_cylinders) ||
   6400            (sector > hd_sectors) ||
   6401            (head >= hd_heads) ) {
   6402         SET_AH(1);
   6403         SET_DISK_RET_STATUS(1);
   6404         SET_CF(); /* error occurred */
   6405         return;
   6406         }
   6407 
   6408       if ( (num_sectors > 128) || (num_sectors == 0) )
   6409         BX_PANIC("int13_harddisk: num_sectors out of range!\n");
   6410 
   6411       if (head > 15)
   6412         BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
   6413 
   6414       if ( GET_AH() == 0x04 ) {
   6415         SET_AH(0);
   6416         SET_DISK_RET_STATUS(0);
   6417         CLEAR_CF();
   6418         return;
   6419         }
   6420 
   6421       status = inb(0x1f7);
   6422       if (status & 0x80) {
   6423         BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
   6424         }
   6425       outb(0x01f2, num_sectors);
   6426       /* activate LBA? (tomv) */
   6427       if (hd_heads > 16) {
   6428 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
   6429         outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
   6430         }
   6431       else {
   6432         outb(0x01f3, sector);
   6433         outb(0x01f4, cylinder & 0x00ff);
   6434         outb(0x01f5, cylinder >> 8);
   6435         outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
   6436         }
   6437       outb(0x01f7, 0x20);
   6438 
   6439       while (1) {
   6440         status = inb(0x1f7);
   6441         if ( !(status & 0x80) ) break;
   6442         }
   6443 
   6444       if (status & 0x01) {
   6445         BX_PANIC("hard drive BIOS:(read/verify) read error\n");
   6446       } else if ( !(status & 0x08) ) {
   6447         BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
   6448         BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
   6449       }
   6450 
   6451       sector_count = 0;
   6452       tempbx = BX;
   6453 
   6454 ASM_START
   6455   sti  ;; enable higher priority interrupts
   6456 ASM_END
   6457 
   6458       while (1) {
   6459 ASM_START
   6460         ;; store temp bx in real DI register
   6461         push bp
   6462         mov  bp, sp
   6463         mov  di, _int13_harddisk.tempbx + 2 [bp]
   6464         pop  bp
   6465 
   6466         ;; adjust if there will be an overrun
   6467         cmp   di, #0xfe00
   6468         jbe   i13_f02_no_adjust
   6469 i13_f02_adjust:
   6470         sub   di, #0x0200 ; sub 512 bytes from offset
   6471         mov   ax, es
   6472         add   ax, #0x0020 ; add 512 to segment
   6473         mov   es, ax
   6474 
   6475 i13_f02_no_adjust:
   6476         mov  cx, #0x0100   ;; counter (256 words = 512b)
   6477         mov  dx, #0x01f0  ;; AT data read port
   6478 
   6479         rep
   6480           insw ;; CX words transfered from port(DX) to ES:[DI]
   6481 
   6482 i13_f02_done:
   6483         ;; store real DI register back to temp bx
   6484         push bp
   6485         mov  bp, sp
   6486         mov  _int13_harddisk.tempbx + 2 [bp], di
   6487         pop  bp
   6488 ASM_END
   6489 
   6490         sector_count++;
   6491         num_sectors--;
   6492         if (num_sectors == 0) {
   6493           status = inb(0x1f7);
   6494           if ( (status & 0xc9) != 0x40 )
   6495             BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
   6496           break;
   6497           }
   6498         else {
   6499           status = inb(0x1f7);
   6500           if ( (status & 0xc9) != 0x48 )
   6501             BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
   6502           continue;
   6503           }
   6504         }
   6505 
   6506       SET_AH(0);
   6507       SET_DISK_RET_STATUS(0);
   6508       SET_AL(sector_count);
   6509       CLEAR_CF(); /* successful */
   6510       return;
   6511       break;
   6512 
   6513 
   6514     case 0x03: /* write disk sectors */
   6515 BX_DEBUG_INT13_HD("int13_f03\n");
   6516       drive = GET_ELDL ();
   6517       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
   6518 
   6519       num_sectors = GET_AL();
   6520       cylinder    = GET_CH();
   6521       cylinder    |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
   6522       sector      = (GET_CL() & 0x3f);
   6523       head        = GET_DH();
   6524 
   6525       if (hd_cylinders > 1024) {
   6526         if (hd_cylinders <= 2048) {
   6527           cylinder <<= 1;
   6528           }
   6529         else if (hd_cylinders <= 4096) {
   6530           cylinder <<= 2;
   6531           }
   6532         else if (hd_cylinders <= 8192) {
   6533           cylinder <<= 3;
   6534           }
   6535         else { // hd_cylinders <= 16384
   6536           cylinder <<= 4;
   6537           }
   6538 
   6539         ax = head / hd_heads;
   6540         cyl_mod = ax & 0xff;
   6541         head    = ax >> 8;
   6542         cylinder |= cyl_mod;
   6543         }
   6544 
   6545       if ( (cylinder >= hd_cylinders) ||
   6546            (sector > hd_sectors) ||
   6547            (head >= hd_heads) ) {
   6548         SET_AH( 1);
   6549         SET_DISK_RET_STATUS(1);
   6550         SET_CF(); /* error occurred */
   6551         return;
   6552         }
   6553 
   6554       if ( (num_sectors > 128) || (num_sectors == 0) )
   6555         BX_PANIC("int13_harddisk: num_sectors out of range!\n");
   6556 
   6557       if (head > 15)
   6558         BX_PANIC("hard drive BIOS:(read) head > 15\n");
   6559 
   6560       status = inb(0x1f7);
   6561       if (status & 0x80) {
   6562         BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
   6563         }
   6564 // should check for Drive Ready Bit also in status reg
   6565       outb(0x01f2, num_sectors);
   6566 
   6567       /* activate LBA? (tomv) */
   6568       if (hd_heads > 16) {
   6569 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
   6570         outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
   6571         }
   6572       else {
   6573         outb(0x01f3, sector);
   6574         outb(0x01f4, cylinder & 0x00ff);
   6575         outb(0x01f5, cylinder >> 8);
   6576         outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
   6577         }
   6578       outb(0x01f7, 0x30);
   6579 
   6580       // wait for busy bit to turn off after seeking
   6581       while (1) {
   6582         status = inb(0x1f7);
   6583         if ( !(status & 0x80) ) break;
   6584         }
   6585 
   6586       if ( !(status & 0x08) ) {
   6587         BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
   6588         BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
   6589         }
   6590 
   6591       sector_count = 0;
   6592       tempbx = BX;
   6593 
   6594 ASM_START
   6595   sti  ;; enable higher priority interrupts
   6596 ASM_END
   6597 
   6598       while (1) {
   6599 ASM_START
   6600         ;; store temp bx in real SI register
   6601         push bp
   6602         mov  bp, sp
   6603         mov  si, _int13_harddisk.tempbx + 2 [bp]
   6604         pop  bp
   6605 
   6606         ;; adjust if there will be an overrun
   6607         cmp   si, #0xfe00
   6608         jbe   i13_f03_no_adjust
   6609 i13_f03_adjust:
   6610         sub   si, #0x0200 ; sub 512 bytes from offset
   6611         mov   ax, es
   6612         add   ax, #0x0020 ; add 512 to segment
   6613         mov   es, ax
   6614 
   6615 i13_f03_no_adjust:
   6616         mov  cx, #0x0100   ;; counter (256 words = 512b)
   6617         mov  dx, #0x01f0  ;; AT data read port
   6618 
   6619         seg ES
   6620         rep
   6621           outsw ;; CX words tranfered from ES:[SI] to port(DX)
   6622 
   6623         ;; store real SI register back to temp bx
   6624         push bp
   6625         mov  bp, sp
   6626         mov  _int13_harddisk.tempbx + 2 [bp], si
   6627         pop  bp
   6628 ASM_END
   6629 
   6630         sector_count++;
   6631         num_sectors--;
   6632         if (num_sectors == 0) {
   6633           status = inb(0x1f7);
   6634           if ( (status & 0xe9) != 0x40 )
   6635             BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
   6636           break;
   6637           }
   6638         else {
   6639           status = inb(0x1f7);
   6640           if ( (status & 0xc9) != 0x48 )
   6641             BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
   6642           continue;
   6643           }
   6644         }
   6645 
   6646       SET_AH(0);
   6647       SET_DISK_RET_STATUS(0);
   6648       SET_AL(sector_count);
   6649       CLEAR_CF(); /* successful */
   6650       return;
   6651       break;
   6652 
   6653     case 0x05: /* format disk track */
   6654 BX_DEBUG_INT13_HD("int13_f05\n");
   6655       BX_PANIC("format disk track called\n");
   6656       /* nop */
   6657       SET_AH(0);
   6658       SET_DISK_RET_STATUS(0);
   6659       CLEAR_CF(); /* successful */
   6660       return;
   6661       break;
   6662 
   6663     case 0x08: /* read disk drive parameters */
   6664 BX_DEBUG_INT13_HD("int13_f08\n");
   6665 
   6666       drive = GET_ELDL ();
   6667       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
   6668 
   6669       // translate CHS
   6670       //
   6671       if (hd_cylinders <= 1024) {
   6672         // hd_cylinders >>= 0;
   6673         // hd_heads <<= 0;
   6674         }
   6675       else if (hd_cylinders <= 2048) {
   6676         hd_cylinders >>= 1;
   6677         hd_heads <<= 1;
   6678         }
   6679       else if (hd_cylinders <= 4096) {
   6680         hd_cylinders >>= 2;
   6681         hd_heads <<= 2;
   6682         }
   6683       else if (hd_cylinders <= 8192) {
   6684         hd_cylinders >>= 3;
   6685         hd_heads <<= 3;
   6686         }
   6687       else { // hd_cylinders <= 16384
   6688         hd_cylinders >>= 4;
   6689         hd_heads <<= 4;
   6690         }
   6691 
   6692       max_cylinder = hd_cylinders - 2; /* 0 based */
   6693       SET_AL(0);
   6694       SET_CH(max_cylinder & 0xff);
   6695       SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
   6696       SET_DH(hd_heads - 1);
   6697       SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
   6698       SET_AH(0);
   6699       SET_DISK_RET_STATUS(0);
   6700       CLEAR_CF(); /* successful */
   6701 
   6702       return;
   6703       break;
   6704 
   6705     case 0x09: /* initialize drive parameters */
   6706 BX_DEBUG_INT13_HD("int13_f09\n");
   6707       SET_AH(0);
   6708       SET_DISK_RET_STATUS(0);
   6709       CLEAR_CF(); /* successful */
   6710       return;
   6711       break;
   6712 
   6713     case 0x0a: /* read disk sectors with ECC */
   6714 BX_DEBUG_INT13_HD("int13_f0a\n");
   6715     case 0x0b: /* write disk sectors with ECC */
   6716 BX_DEBUG_INT13_HD("int13_f0b\n");
   6717       BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
   6718       return;
   6719       break;
   6720 
   6721     case 0x0c: /* seek to specified cylinder */
   6722 BX_DEBUG_INT13_HD("int13_f0c\n");
   6723       BX_INFO("int13h function 0ch (seek) not implemented!\n");
   6724       SET_AH(0);
   6725       SET_DISK_RET_STATUS(0);
   6726       CLEAR_CF(); /* successful */
   6727       return;
   6728       break;
   6729 
   6730     case 0x0d: /* alternate disk reset */
   6731 BX_DEBUG_INT13_HD("int13_f0d\n");
   6732       SET_AH(0);
   6733       SET_DISK_RET_STATUS(0);
   6734       CLEAR_CF(); /* successful */
   6735       return;
   6736       break;
   6737 
   6738     case 0x10: /* check drive ready */
   6739 BX_DEBUG_INT13_HD("int13_f10\n");
   6740       //SET_AH(0);
   6741       //SET_DISK_RET_STATUS(0);
   6742       //CLEAR_CF(); /* successful */
   6743       //return;
   6744       //break;
   6745 
   6746       // should look at 40:8E also???
   6747       status = inb(0x01f7);
   6748       if ( (status & 0xc0) == 0x40 ) {
   6749         SET_AH(0);
   6750         SET_DISK_RET_STATUS(0);
   6751         CLEAR_CF(); // drive ready
   6752         return;
   6753         }
   6754       else {
   6755         SET_AH(0xAA);
   6756         SET_DISK_RET_STATUS(0xAA);
   6757         SET_CF(); // not ready
   6758         return;
   6759         }
   6760       break;
   6761 
   6762     case 0x11: /* recalibrate */
   6763 BX_DEBUG_INT13_HD("int13_f11\n");
   6764       SET_AH(0);
   6765       SET_DISK_RET_STATUS(0);
   6766       CLEAR_CF(); /* successful */
   6767       return;
   6768       break;
   6769 
   6770     case 0x14: /* controller internal diagnostic */
   6771 BX_DEBUG_INT13_HD("int13_f14\n");
   6772       SET_AH(0);
   6773       SET_DISK_RET_STATUS(0);
   6774       CLEAR_CF(); /* successful */
   6775       SET_AL(0);
   6776       return;
   6777       break;
   6778 
   6779     case 0x15: /* read disk drive size */
   6780       drive = GET_ELDL();
   6781       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
   6782 ASM_START
   6783       push bp
   6784       mov  bp, sp
   6785       mov  al, _int13_harddisk.hd_heads + 2 [bp]
   6786       mov  ah, _int13_harddisk.hd_sectors + 2 [bp]
   6787       mul  al, ah ;; ax = heads * sectors
   6788       mov  bx, _int13_harddisk.hd_cylinders + 2 [bp]
   6789       dec  bx     ;; use (cylinders - 1) ???
   6790       mul  ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
   6791       ;; now we need to move the 32bit result dx:ax to what the
   6792       ;; BIOS wants which is cx:dx.
   6793       ;; and then into CX:DX on the stack
   6794       mov  _int13_harddisk.CX + 2 [bp], dx
   6795       mov  _int13_harddisk.DX + 2 [bp], ax
   6796       pop  bp
   6797 ASM_END
   6798       SET_AH(3);  // hard disk accessible
   6799       SET_DISK_RET_STATUS(0); // ??? should this be 0
   6800       CLEAR_CF(); // successful
   6801       return;
   6802       break;
   6803 
   6804     case 0x18: // set media type for format
   6805     case 0x41: // IBM/MS
   6806     case 0x42: // IBM/MS
   6807     case 0x43: // IBM/MS
   6808     case 0x44: // IBM/MS
   6809     case 0x45: // IBM/MS lock/unlock drive
   6810     case 0x46: // IBM/MS eject media
   6811     case 0x47: // IBM/MS extended seek
   6812     case 0x49: // IBM/MS extended media change
   6813     case 0x50: // IBM/MS send packet command
   6814     default:
   6815       BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
   6816 
   6817       SET_AH(1);  // code=invalid function in AH or invalid parameter
   6818       SET_DISK_RET_STATUS(1);
   6819       SET_CF(); /* unsuccessful */
   6820       return;
   6821       break;
   6822     }
   6823 }
   6824 
   6825 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
   6826 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
   6827 
   6828   void
   6829 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
   6830   Bit8u drive;
   6831   Bit16u *hd_cylinders;
   6832   Bit8u  *hd_heads;
   6833   Bit8u  *hd_sectors;
   6834 {
   6835   Bit8u hd_type;
   6836   Bit16u ss;
   6837   Bit16u cylinders;
   6838   Bit8u iobase;
   6839 
   6840   ss = get_SS();
   6841   if (drive == 0x80) {
   6842     hd_type = inb_cmos(0x12) & 0xf0;
   6843     if (hd_type != 0xf0)
   6844       BX_INFO(panic_msg_reg12h,0);
   6845     hd_type = inb_cmos(0x19); // HD0: extended type
   6846     if (hd_type != 47)
   6847       BX_INFO(panic_msg_reg19h,0,0x19);
   6848     iobase = 0x1b;
   6849   } else {
   6850     hd_type = inb_cmos(0x12) & 0x0f;
   6851     if (hd_type != 0x0f)
   6852       BX_INFO(panic_msg_reg12h,1);
   6853     hd_type = inb_cmos(0x1a); // HD1: extended type
   6854     if (hd_type != 47)
   6855       BX_INFO(panic_msg_reg19h,0,0x1a);
   6856     iobase = 0x24;
   6857   }
   6858 
   6859   // cylinders
   6860   cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
   6861   write_word(ss, hd_cylinders, cylinders);
   6862 
   6863   // heads
   6864   write_byte(ss, hd_heads, inb_cmos(iobase+2));
   6865 
   6866   // sectors per track
   6867   write_byte(ss, hd_sectors, inb_cmos(iobase+8));
   6868 }
   6869 
   6870 #endif //else BX_USE_ATADRV
   6871 
   6872 #if BX_SUPPORT_FLOPPY
   6873 
   6874 //////////////////////
   6875 // FLOPPY functions //
   6876 //////////////////////
   6877 
   6878 void floppy_reset_controller()
   6879 {
   6880   Bit8u val8;
   6881 
   6882   // Reset controller
   6883   val8 = inb(0x03f2);
   6884   outb(0x03f2, val8 & ~0x04);
   6885   outb(0x03f2, val8 | 0x04);
   6886 
   6887   // Wait for controller to come out of reset
   6888   do {
   6889     val8 = inb(0x3f4);
   6890   } while ( (val8 & 0xc0) != 0x80 );
   6891 }
   6892 
   6893 void floppy_prepare_controller(drive)
   6894   Bit16u drive;
   6895 {
   6896   Bit8u  val8, dor, prev_reset;
   6897 
   6898   // set 40:3e bit 7 to 0
   6899   val8 = read_byte(0x0040, 0x003e);
   6900   val8 &= 0x7f;
   6901   write_byte(0x0040, 0x003e, val8);
   6902 
   6903   // turn on motor of selected drive, DMA & int enabled, normal operation
   6904   prev_reset = inb(0x03f2) & 0x04;
   6905   if (drive)
   6906     dor = 0x20;
   6907   else
   6908     dor = 0x10;
   6909   dor |= 0x0c;
   6910   dor |= drive;
   6911   outb(0x03f2, dor);
   6912 
   6913   // reset the disk motor timeout value of INT 08
   6914   write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
   6915 
   6916   // wait for drive readiness
   6917   do {
   6918     val8 = inb(0x3f4);
   6919   } while ( (val8 & 0xc0) != 0x80 );
   6920 
   6921   if (prev_reset == 0) {
   6922     // turn on interrupts
   6923 ASM_START
   6924     sti
   6925 ASM_END
   6926     // wait on 40:3e bit 7 to become 1
   6927     do {
   6928       val8 = read_byte(0x0040, 0x003e);
   6929     } while ( (val8 & 0x80) == 0 );
   6930     val8 &= 0x7f;
   6931 ASM_START
   6932     cli
   6933 ASM_END
   6934     write_byte(0x0040, 0x003e, val8);
   6935   }
   6936 }
   6937 
   6938   bx_bool
   6939 floppy_media_known(drive)
   6940   Bit16u drive;
   6941 {
   6942   Bit8u  val8;
   6943   Bit16u media_state_offset;
   6944 
   6945   val8 = read_byte(0x0040, 0x003e); // diskette recal status
   6946   if (drive)
   6947     val8 >>= 1;
   6948   val8 &= 0x01;
   6949   if (val8 == 0)
   6950     return(0);
   6951 
   6952   media_state_offset = 0x0090;
   6953   if (drive)
   6954     media_state_offset += 1;
   6955 
   6956   val8 = read_byte(0x0040, media_state_offset);
   6957   val8 = (val8 >> 4) & 0x01;
   6958   if (val8 == 0)
   6959     return(0);
   6960 
   6961   // check pass, return KNOWN
   6962   return(1);
   6963 }
   6964 
   6965   bx_bool
   6966 floppy_media_sense(drive)
   6967   Bit16u drive;
   6968 {
   6969   bx_bool retval;
   6970   Bit16u  media_state_offset;
   6971   Bit8u   drive_type, config_data, media_state;
   6972 
   6973   if (floppy_drive_recal(drive) == 0) {
   6974     return(0);
   6975     }
   6976 
   6977   // for now cheat and get drive type from CMOS,
   6978   // assume media is same as drive type
   6979 
   6980   // ** config_data **
   6981   // Bitfields for diskette media control:
   6982   // Bit(s)  Description (Table M0028)
   6983   //  7-6  last data rate set by controller
   6984   //        00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
   6985   //  5-4  last diskette drive step rate selected
   6986   //        00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
   6987   //  3-2  {data rate at start of operation}
   6988   //  1-0  reserved
   6989 
   6990   // ** media_state **
   6991   // Bitfields for diskette drive media state:
   6992   // Bit(s)  Description (Table M0030)
   6993   //  7-6  data rate
   6994   //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
   6995   //  5  double stepping required (e.g. 360kB in 1.2MB)
   6996   //  4  media type established
   6997   //  3  drive capable of supporting 4MB media
   6998   //  2-0  on exit from BIOS, contains
   6999   //    000 trying 360kB in 360kB
   7000   //    001 trying 360kB in 1.2MB
   7001   //    010 trying 1.2MB in 1.2MB
   7002   //    011 360kB in 360kB established
   7003   //    100 360kB in 1.2MB established
   7004   //    101 1.2MB in 1.2MB established
   7005   //    110 reserved
   7006   //    111 all other formats/drives
   7007 
   7008   drive_type = inb_cmos(0x10);
   7009   if (drive == 0)
   7010     drive_type >>= 4;
   7011   else
   7012     drive_type &= 0x0f;
   7013   if ( drive_type == 1 ) {
   7014     // 360K 5.25" drive
   7015     config_data = 0x00; // 0000 0000
   7016     media_state = 0x25; // 0010 0101
   7017     retval = 1;
   7018     }
   7019   else if ( drive_type == 2 ) {
   7020     // 1.2 MB 5.25" drive
   7021     config_data = 0x00; // 0000 0000
   7022     media_state = 0x25; // 0010 0101   // need double stepping??? (bit 5)
   7023     retval = 1;
   7024     }
   7025   else if ( drive_type == 3 ) {
   7026     // 720K 3.5" drive
   7027     config_data = 0x00; // 0000 0000 ???
   7028     media_state = 0x17; // 0001 0111
   7029     retval = 1;
   7030     }
   7031   else if ( drive_type == 4 ) {
   7032     // 1.44 MB 3.5" drive
   7033     config_data = 0x00; // 0000 0000
   7034     media_state = 0x17; // 0001 0111
   7035     retval = 1;
   7036     }
   7037   else if ( drive_type == 5 ) {
   7038     // 2.88 MB 3.5" drive
   7039     config_data = 0xCC; // 1100 1100
   7040     media_state = 0xD7; // 1101 0111
   7041     retval = 1;
   7042     }
   7043   //
   7044   // Extended floppy size uses special cmos setting
   7045   else if ( drive_type == 6 ) {
   7046     // 160k 5.25" drive
   7047     config_data = 0x00; // 0000 0000
   7048     media_state = 0x27; // 0010 0111
   7049     retval = 1;
   7050     }
   7051   else if ( drive_type == 7 ) {
   7052     // 180k 5.25" drive
   7053     config_data = 0x00; // 0000 0000
   7054     media_state = 0x27; // 0010 0111
   7055     retval = 1;
   7056     }
   7057   else if ( drive_type == 8 ) {
   7058     // 320k 5.25" drive
   7059     config_data = 0x00; // 0000 0000
   7060     media_state = 0x27; // 0010 0111
   7061     retval = 1;
   7062     }
   7063 
   7064   else {
   7065     // not recognized
   7066     config_data = 0x00; // 0000 0000
   7067     media_state = 0x00; // 0000 0000
   7068     retval = 0;
   7069     }
   7070 
   7071   if (drive == 0)
   7072     media_state_offset = 0x90;
   7073   else
   7074     media_state_offset = 0x91;
   7075   write_byte(0x0040, 0x008B, config_data);
   7076   write_byte(0x0040, media_state_offset, media_state);
   7077 
   7078   return(retval);
   7079 }
   7080 
   7081   bx_bool
   7082 floppy_drive_recal(drive)
   7083   Bit16u drive;
   7084 {
   7085   Bit8u  val8;
   7086   Bit16u curr_cyl_offset;
   7087 
   7088   floppy_prepare_controller(drive);
   7089 
   7090   // send Recalibrate command (2 bytes) to controller
   7091   outb(0x03f5, 0x07);  // 07: Recalibrate
   7092   outb(0x03f5, drive); // 0=drive0, 1=drive1
   7093 
   7094   // turn on interrupts
   7095 ASM_START
   7096   sti
   7097 ASM_END
   7098 
   7099   // wait on 40:3e bit 7 to become 1
   7100   do {
   7101     val8 = (read_byte(0x0040, 0x003e) & 0x80);
   7102   } while ( val8 == 0 );
   7103 
   7104   val8 = 0; // separate asm from while() loop
   7105   // turn off interrupts
   7106 ASM_START
   7107   cli
   7108 ASM_END
   7109 
   7110   // set 40:3e bit 7 to 0, and calibrated bit
   7111   val8 = read_byte(0x0040, 0x003e);
   7112   val8 &= 0x7f;
   7113   if (drive) {
   7114     val8 |= 0x02; // Drive 1 calibrated
   7115     curr_cyl_offset = 0x0095;
   7116   } else {
   7117     val8 |= 0x01; // Drive 0 calibrated
   7118     curr_cyl_offset = 0x0094;
   7119   }
   7120   write_byte(0x0040, 0x003e, val8);
   7121   write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
   7122 
   7123   return(1);
   7124 }
   7125 
   7126 
   7127 
   7128   bx_bool
   7129 floppy_drive_exists(drive)
   7130   Bit16u drive;
   7131 {
   7132   Bit8u  drive_type;
   7133 
   7134   // check CMOS to see if drive exists
   7135   drive_type = inb_cmos(0x10);
   7136   if (drive == 0)
   7137     drive_type >>= 4;
   7138   else
   7139     drive_type &= 0x0f;
   7140   if ( drive_type == 0 )
   7141     return(0);
   7142   else
   7143     return(1);
   7144 }
   7145 
   7146   void
   7147 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
   7148   Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
   7149 {
   7150   Bit8u  drive, num_sectors, track, sector, head, status;
   7151   Bit16u base_address, base_count, base_es;
   7152   Bit8u  page, mode_register, val8, dor;
   7153   Bit8u  return_status[7];
   7154   Bit8u  drive_type, num_floppies, ah;
   7155   Bit16u es, last_addr;
   7156 
   7157   BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
   7158 
   7159   ah = GET_AH();
   7160 
   7161   switch ( ah ) {
   7162     case 0x00: // diskette controller reset
   7163 BX_DEBUG_INT13_FL("floppy f00\n");
   7164       drive = GET_ELDL();
   7165       if (drive > 1) {
   7166         SET_AH(1); // invalid param
   7167         set_diskette_ret_status(1);
   7168         SET_CF();
   7169         return;
   7170       }
   7171       drive_type = inb_cmos(0x10);
   7172 
   7173       if (drive == 0)
   7174         drive_type >>= 4;
   7175       else
   7176         drive_type &= 0x0f;
   7177       if (drive_type == 0) {
   7178         SET_AH(0x80); // drive not responding
   7179         set_diskette_ret_status(0x80);
   7180         SET_CF();
   7181         return;
   7182       }
   7183       SET_AH(0);
   7184       set_diskette_ret_status(0);
   7185       CLEAR_CF(); // successful
   7186       set_diskette_current_cyl(drive, 0); // current cylinder
   7187       return;
   7188 
   7189     case 0x01: // Read Diskette Status
   7190       CLEAR_CF();
   7191       val8 = read_byte(0x0000, 0x0441);
   7192       SET_AH(val8);
   7193       if (val8) {
   7194         SET_CF();
   7195       }
   7196       return;
   7197 
   7198     case 0x02: // Read Diskette Sectors
   7199     case 0x03: // Write Diskette Sectors
   7200     case 0x04: // Verify Diskette Sectors
   7201       num_sectors = GET_AL();
   7202       track       = GET_CH();
   7203       sector      = GET_CL();
   7204       head        = GET_DH();
   7205       drive       = GET_ELDL();
   7206 
   7207       if ((drive > 1) || (head > 1) || (sector == 0) ||
   7208           (num_sectors == 0) || (num_sectors > 72)) {
   7209         BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
   7210         SET_AH(1);
   7211         set_diskette_ret_status(1);
   7212         SET_AL(0); // no sectors read
   7213         SET_CF(); // error occurred
   7214         return;
   7215       }
   7216 
   7217       // see if drive exists
   7218       if (floppy_drive_exists(drive) == 0) {
   7219         SET_AH(0x80); // not responding
   7220         set_diskette_ret_status(0x80);
   7221         SET_AL(0); // no sectors read
   7222         SET_CF(); // error occurred
   7223         return;
   7224       }
   7225 
   7226       // see if media in drive, and type is known
   7227       if (floppy_media_known(drive) == 0) {
   7228         if (floppy_media_sense(drive) == 0) {
   7229           SET_AH(0x0C); // Media type not found
   7230           set_diskette_ret_status(0x0C);
   7231           SET_AL(0); // no sectors read
   7232           SET_CF(); // error occurred
   7233           return;
   7234         }
   7235       }
   7236 
   7237       if (ah == 0x02) {
   7238         // Read Diskette Sectors
   7239 
   7240         //-----------------------------------
   7241         // set up DMA controller for transfer
   7242         //-----------------------------------
   7243 
   7244         // es:bx = pointer to where to place information from diskette
   7245         // port 04: DMA-1 base and current address, channel 2
   7246         // port 05: DMA-1 base and current count, channel 2
   7247         page = (ES >> 12);   // upper 4 bits
   7248         base_es = (ES << 4); // lower 16bits contributed by ES
   7249         base_address = base_es + BX; // lower 16 bits of address
   7250                                      // contributed by ES:BX
   7251         if ( base_address < base_es ) {
   7252           // in case of carry, adjust page by 1
   7253           page++;
   7254         }
   7255         base_count = (num_sectors * 512) - 1;
   7256 
   7257         // check for 64K boundary overrun
   7258         last_addr = base_address + base_count;
   7259         if (last_addr < base_address) {
   7260           SET_AH(0x09);
   7261           set_diskette_ret_status(0x09);
   7262           SET_AL(0); // no sectors read
   7263           SET_CF(); // error occurred
   7264           return;
   7265         }
   7266 
   7267         BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
   7268         outb(0x000a, 0x06);
   7269 
   7270   BX_DEBUG_INT13_FL("clear flip-flop\n");
   7271         outb(0x000c, 0x00); // clear flip-flop
   7272         outb(0x0004, base_address);
   7273         outb(0x0004, base_address>>8);
   7274   BX_DEBUG_INT13_FL("clear flip-flop\n");
   7275         outb(0x000c, 0x00); // clear flip-flop
   7276         outb(0x0005, base_count);
   7277         outb(0x0005, base_count>>8);
   7278 
   7279         // port 0b: DMA-1 Mode Register
   7280         mode_register = 0x46; // single mode, increment, autoinit disable,
   7281                               // transfer type=write, channel 2
   7282   BX_DEBUG_INT13_FL("setting mode register\n");
   7283         outb(0x000b, mode_register);
   7284 
   7285   BX_DEBUG_INT13_FL("setting page register\n");
   7286         // port 81: DMA-1 Page Register, channel 2
   7287         outb(0x0081, page);
   7288 
   7289   BX_DEBUG_INT13_FL("unmask chan 2\n");
   7290         outb(0x000a, 0x02); // unmask channel 2
   7291 
   7292         BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
   7293         outb(0x000a, 0x02);
   7294 
   7295         //--------------------------------------
   7296         // set up floppy controller for transfer
   7297         //--------------------------------------
   7298         floppy_prepare_controller(drive);
   7299 
   7300         // send read-normal-data command (9 bytes) to controller
   7301         outb(0x03f5, 0xe6); // e6: read normal data
   7302         outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
   7303         outb(0x03f5, track);
   7304         outb(0x03f5, head);
   7305         outb(0x03f5, sector);
   7306         outb(0x03f5, 2); // 512 byte sector size
   7307         outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
   7308         outb(0x03f5, 0); // Gap length
   7309         outb(0x03f5, 0xff); // Gap length
   7310 
   7311         // turn on interrupts
   7312   ASM_START
   7313         sti
   7314   ASM_END
   7315 
   7316         // wait on 40:3e bit 7 to become 1
   7317         do {
   7318           val8 = read_byte(0x0040, 0x0040);
   7319           if (val8 == 0) {
   7320             floppy_reset_controller();
   7321             SET_AH(0x80); // drive not ready (timeout)
   7322             set_diskette_ret_status(0x80);
   7323             SET_AL(0); // no sectors read
   7324             SET_CF(); // error occurred
   7325             return;
   7326           }
   7327           val8 = (read_byte(0x0040, 0x003e) & 0x80);
   7328         } while ( val8 == 0 );
   7329 
   7330         val8 = 0; // separate asm from while() loop
   7331         // turn off interrupts
   7332   ASM_START
   7333         cli
   7334   ASM_END
   7335 
   7336         // set 40:3e bit 7 to 0
   7337         val8 = read_byte(0x0040, 0x003e);
   7338         val8 &= 0x7f;
   7339         write_byte(0x0040, 0x003e, val8);
   7340 
   7341         // check port 3f4 for accessibility to status bytes
   7342         val8 = inb(0x3f4);
   7343         if ( (val8 & 0xc0) != 0xc0 )
   7344           BX_PANIC("int13_diskette: ctrl not ready\n");
   7345 
   7346         // read 7 return status bytes from controller
   7347         // using loop index broken, have to unroll...
   7348         return_status[0] = inb(0x3f5);
   7349         return_status[1] = inb(0x3f5);
   7350         return_status[2] = inb(0x3f5);
   7351         return_status[3] = inb(0x3f5);
   7352         return_status[4] = inb(0x3f5);
   7353         return_status[5] = inb(0x3f5);
   7354         return_status[6] = inb(0x3f5);
   7355         // record in BIOS Data Area
   7356         write_byte(0x0040, 0x0042, return_status[0]);
   7357         write_byte(0x0040, 0x0043, return_status[1]);
   7358         write_byte(0x0040, 0x0044, return_status[2]);
   7359         write_byte(0x0040, 0x0045, return_status[3]);
   7360         write_byte(0x0040, 0x0046, return_status[4]);
   7361         write_byte(0x0040, 0x0047, return_status[5]);
   7362         write_byte(0x0040, 0x0048, return_status[6]);
   7363 
   7364         if ( (return_status[0] & 0xc0) != 0 ) {
   7365           SET_AH(0x20);
   7366           set_diskette_ret_status(0x20);
   7367           SET_AL(0); // no sectors read
   7368           SET_CF(); // error occurred
   7369           return;
   7370         }
   7371 
   7372         // ??? should track be new val from return_status[3] ?
   7373         set_diskette_current_cyl(drive, track);
   7374         // AL = number of sectors read (same value as passed)
   7375         SET_AH(0x00); // success
   7376         CLEAR_CF();   // success
   7377         return;
   7378       } else if (ah == 0x03) {
   7379         // Write Diskette Sectors
   7380 
   7381         //-----------------------------------
   7382         // set up DMA controller for transfer
   7383         //-----------------------------------
   7384 
   7385         // es:bx = pointer to where to place information from diskette
   7386         // port 04: DMA-1 base and current address, channel 2
   7387         // port 05: DMA-1 base and current count, channel 2
   7388         page = (ES >> 12);   // upper 4 bits
   7389         base_es = (ES << 4); // lower 16bits contributed by ES
   7390         base_address = base_es + BX; // lower 16 bits of address
   7391                                      // contributed by ES:BX
   7392         if ( base_address < base_es ) {
   7393           // in case of carry, adjust page by 1
   7394           page++;
   7395         }
   7396         base_count = (num_sectors * 512) - 1;
   7397 
   7398         // check for 64K boundary overrun
   7399         last_addr = base_address + base_count;
   7400         if (last_addr < base_address) {
   7401           SET_AH(0x09);
   7402           set_diskette_ret_status(0x09);
   7403           SET_AL(0); // no sectors read
   7404           SET_CF(); // error occurred
   7405           return;
   7406         }
   7407 
   7408         BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
   7409         outb(0x000a, 0x06);
   7410 
   7411         outb(0x000c, 0x00); // clear flip-flop
   7412         outb(0x0004, base_address);
   7413         outb(0x0004, base_address>>8);
   7414         outb(0x000c, 0x00); // clear flip-flop
   7415         outb(0x0005, base_count);
   7416         outb(0x0005, base_count>>8);
   7417 
   7418         // port 0b: DMA-1 Mode Register
   7419         mode_register = 0x4a; // single mode, increment, autoinit disable,
   7420                               // transfer type=read, channel 2
   7421         outb(0x000b, mode_register);
   7422 
   7423         // port 81: DMA-1 Page Register, channel 2
   7424         outb(0x0081, page);
   7425 
   7426         BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
   7427         outb(0x000a, 0x02);
   7428 
   7429         //--------------------------------------
   7430         // set up floppy controller for transfer
   7431         //--------------------------------------
   7432         floppy_prepare_controller(drive);
   7433 
   7434         // send write-normal-data command (9 bytes) to controller
   7435         outb(0x03f5, 0xc5); // c5: write normal data
   7436         outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
   7437         outb(0x03f5, track);
   7438         outb(0x03f5, head);
   7439         outb(0x03f5, sector);
   7440         outb(0x03f5, 2); // 512 byte sector size
   7441         outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
   7442         outb(0x03f5, 0); // Gap length
   7443         outb(0x03f5, 0xff); // Gap length
   7444 
   7445         // turn on interrupts
   7446   ASM_START
   7447         sti
   7448   ASM_END
   7449 
   7450         // wait on 40:3e bit 7 to become 1
   7451         do {
   7452           val8 = read_byte(0x0040, 0x0040);
   7453           if (val8 == 0) {
   7454             floppy_reset_controller();
   7455             SET_AH(0x80); // drive not ready (timeout)
   7456             set_diskette_ret_status(0x80);
   7457             SET_AL(0); // no sectors written
   7458             SET_CF(); // error occurred
   7459             return;
   7460           }
   7461           val8 = (read_byte(0x0040, 0x003e) & 0x80);
   7462         } while ( val8 == 0 );
   7463 
   7464         val8 = 0; // separate asm from while() loop
   7465         // turn off interrupts
   7466   ASM_START
   7467         cli
   7468   ASM_END
   7469 
   7470         // set 40:3e bit 7 to 0
   7471         val8 = read_byte(0x0040, 0x003e);
   7472         val8 &= 0x7f;
   7473         write_byte(0x0040, 0x003e, val8);
   7474 
   7475         // check port 3f4 for accessibility to status bytes
   7476         val8 = inb(0x3f4);
   7477         if ( (val8 & 0xc0) != 0xc0 )
   7478           BX_PANIC("int13_diskette: ctrl not ready\n");
   7479 
   7480         // read 7 return status bytes from controller
   7481         // using loop index broken, have to unroll...
   7482         return_status[0] = inb(0x3f5);
   7483         return_status[1] = inb(0x3f5);
   7484         return_status[2] = inb(0x3f5);
   7485         return_status[3] = inb(0x3f5);
   7486         return_status[4] = inb(0x3f5);
   7487         return_status[5] = inb(0x3f5);
   7488         return_status[6] = inb(0x3f5);
   7489         // record in BIOS Data Area
   7490         write_byte(0x0040, 0x0042, return_status[0]);
   7491         write_byte(0x0040, 0x0043, return_status[1]);
   7492         write_byte(0x0040, 0x0044, return_status[2]);
   7493         write_byte(0x0040, 0x0045, return_status[3]);
   7494         write_byte(0x0040, 0x0046, return_status[4]);
   7495         write_byte(0x0040, 0x0047, return_status[5]);
   7496         write_byte(0x0040, 0x0048, return_status[6]);
   7497 
   7498         if ( (return_status[0] & 0xc0) != 0 ) {
   7499           if ( (return_status[1] & 0x02) != 0 ) {
   7500             // diskette not writable.
   7501             // AH=status code=0x03 (tried to write on write-protected disk)
   7502             // AL=number of sectors written=0
   7503             AX = 0x0300;
   7504             SET_CF();
   7505             return;
   7506           } else {
   7507             BX_PANIC("int13_diskette_function: read error\n");
   7508           }
   7509         }
   7510 
   7511         // ??? should track be new val from return_status[3] ?
   7512         set_diskette_current_cyl(drive, track);
   7513         // AL = number of sectors read (same value as passed)
   7514         SET_AH(0x00); // success
   7515         CLEAR_CF();   // success
   7516         return;
   7517       } else {  // if (ah == 0x04)
   7518         // Verify Diskette Sectors
   7519 
   7520         // ??? should track be new val from return_status[3] ?
   7521         set_diskette_current_cyl(drive, track);
   7522         // AL = number of sectors verified (same value as passed)
   7523         CLEAR_CF();   // success
   7524         SET_AH(0x00); // success
   7525         return;
   7526       }
   7527       break;
   7528 
   7529     case 0x05: // format diskette track
   7530 BX_DEBUG_INT13_FL("floppy f05\n");
   7531 
   7532       num_sectors = GET_AL();
   7533       track       = GET_CH();
   7534       head        = GET_DH();
   7535       drive       = GET_ELDL();
   7536 
   7537       if ((drive > 1) || (head > 1) || (track > 79) ||
   7538           (num_sectors == 0) || (num_sectors > 18)) {
   7539         SET_AH(1);
   7540         set_diskette_ret_status(1);
   7541         SET_CF(); // error occurred
   7542       }
   7543 
   7544       // see if drive exists
   7545       if (floppy_drive_exists(drive) == 0) {
   7546         SET_AH(0x80); // drive not responding
   7547         set_diskette_ret_status(0x80);
   7548         SET_CF(); // error occurred
   7549         return;
   7550       }
   7551 
   7552       // see if media in drive, and type is known
   7553       if (floppy_media_known(drive) == 0) {
   7554         if (floppy_media_sense(drive) == 0) {
   7555           SET_AH(0x0C); // Media type not found
   7556           set_diskette_ret_status(0x0C);
   7557           SET_AL(0); // no sectors read
   7558           SET_CF(); // error occurred
   7559           return;
   7560         }
   7561       }
   7562 
   7563       // set up DMA controller for transfer
   7564       page = (ES >> 12);   // upper 4 bits
   7565       base_es = (ES << 4); // lower 16bits contributed by ES
   7566       base_address = base_es + BX; // lower 16 bits of address
   7567                                    // contributed by ES:BX
   7568       if ( base_address < base_es ) {
   7569         // in case of carry, adjust page by 1
   7570         page++;
   7571       }
   7572       base_count = (num_sectors * 4) - 1;
   7573 
   7574       // check for 64K boundary overrun
   7575       last_addr = base_address + base_count;
   7576       if (last_addr < base_address) {
   7577         SET_AH(0x09);
   7578         set_diskette_ret_status(0x09);
   7579         SET_AL(0); // no sectors read
   7580         SET_CF(); // error occurred
   7581         return;
   7582       }
   7583 
   7584       outb(0x000a, 0x06);
   7585       outb(0x000c, 0x00); // clear flip-flop
   7586       outb(0x0004, base_address);
   7587       outb(0x0004, base_address>>8);
   7588       outb(0x000c, 0x00); // clear flip-flop
   7589       outb(0x0005, base_count);
   7590       outb(0x0005, base_count>>8);
   7591       mode_register = 0x4a; // single mode, increment, autoinit disable,
   7592                             // transfer type=read, channel 2
   7593       outb(0x000b, mode_register);
   7594       // port 81: DMA-1 Page Register, channel 2
   7595       outb(0x0081, page);
   7596       outb(0x000a, 0x02);
   7597 
   7598       // set up floppy controller for transfer
   7599       floppy_prepare_controller(drive);
   7600 
   7601       // send format-track command (6 bytes) to controller
   7602       outb(0x03f5, 0x4d); // 4d: format track
   7603       outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
   7604       outb(0x03f5, 2); // 512 byte sector size
   7605       outb(0x03f5, num_sectors); // number of sectors per track
   7606       outb(0x03f5, 0); // Gap length
   7607       outb(0x03f5, 0xf6); // Fill byte
   7608       // turn on interrupts
   7609   ASM_START
   7610       sti
   7611   ASM_END
   7612 
   7613       // wait on 40:3e bit 7 to become 1
   7614       do {
   7615         val8 = read_byte(0x0040, 0x0040);
   7616         if (val8 == 0) {
   7617           floppy_reset_controller();
   7618           SET_AH(0x80); // drive not ready (timeout)
   7619           set_diskette_ret_status(0x80);
   7620           SET_CF(); // error occurred
   7621           return;
   7622         }
   7623         val8 = (read_byte(0x0040, 0x003e) & 0x80);
   7624       } while ( val8 == 0 );
   7625 
   7626       val8 = 0; // separate asm from while() loop
   7627       // turn off interrupts
   7628   ASM_START
   7629       cli
   7630   ASM_END
   7631       // set 40:3e bit 7 to 0
   7632       val8 = read_byte(0x0040, 0x003e);
   7633       val8 &= 0x7f;
   7634       write_byte(0x0040, 0x003e, val8);
   7635       // check port 3f4 for accessibility to status bytes
   7636       val8 = inb(0x3f4);
   7637       if ( (val8 & 0xc0) != 0xc0 )
   7638         BX_PANIC("int13_diskette: ctrl not ready\n");
   7639 
   7640       // read 7 return status bytes from controller
   7641       // using loop index broken, have to unroll...
   7642       return_status[0] = inb(0x3f5);
   7643       return_status[1] = inb(0x3f5);
   7644       return_status[2] = inb(0x3f5);
   7645       return_status[3] = inb(0x3f5);
   7646       return_status[4] = inb(0x3f5);
   7647       return_status[5] = inb(0x3f5);
   7648       return_status[6] = inb(0x3f5);
   7649       // record in BIOS Data Area
   7650       write_byte(0x0040, 0x0042, return_status[0]);
   7651       write_byte(0x0040, 0x0043, return_status[1]);
   7652       write_byte(0x0040, 0x0044, return_status[2]);
   7653       write_byte(0x0040, 0x0045, return_status[3]);
   7654       write_byte(0x0040, 0x0046, return_status[4]);
   7655       write_byte(0x0040, 0x0047, return_status[5]);
   7656       write_byte(0x0040, 0x0048, return_status[6]);
   7657 
   7658       if ( (return_status[0] & 0xc0) != 0 ) {
   7659         if ( (return_status[1] & 0x02) != 0 ) {
   7660           // diskette not writable.
   7661           // AH=status code=0x03 (tried to write on write-protected disk)
   7662           // AL=number of sectors written=0
   7663           AX = 0x0300;
   7664           SET_CF();
   7665           return;
   7666         } else {
   7667           BX_PANIC("int13_diskette_function: write error\n");
   7668         }
   7669       }
   7670 
   7671       SET_AH(0);
   7672       set_diskette_ret_status(0);
   7673       set_diskette_current_cyl(drive, 0);
   7674       CLEAR_CF(); // successful
   7675       return;
   7676 
   7677 
   7678     case 0x08: // read diskette drive parameters
   7679 BX_DEBUG_INT13_FL("floppy f08\n");
   7680       drive = GET_ELDL();
   7681 
   7682       if (drive > 1) {
   7683         AX = 0;
   7684         BX = 0;
   7685         CX = 0;
   7686         DX = 0;
   7687         ES = 0;
   7688         DI = 0;
   7689         SET_DL(num_floppies);
   7690         SET_CF();
   7691         return;
   7692         }
   7693 
   7694       drive_type = inb_cmos(0x10);
   7695       num_floppies = 0;
   7696       if (drive_type & 0xf0)
   7697         num_floppies++;
   7698       if (drive_type & 0x0f)
   7699         num_floppies++;
   7700 
   7701       if (drive == 0)
   7702         drive_type >>= 4;
   7703       else
   7704         drive_type &= 0x0f;
   7705 
   7706       SET_BH(0);
   7707       SET_BL(drive_type);
   7708       SET_AH(0);
   7709       SET_AL(0);
   7710       SET_DL(num_floppies);
   7711 
   7712       switch (drive_type) {
   7713         case 0: // none
   7714           CX = 0;
   7715           SET_DH(0); // max head #
   7716           break;
   7717 
   7718         case 1: // 360KB, 5.25"
   7719           CX = 0x2709; // 40 tracks, 9 sectors
   7720           SET_DH(1); // max head #
   7721           break;
   7722 
   7723         case 2: // 1.2MB, 5.25"
   7724           CX = 0x4f0f; // 80 tracks, 15 sectors
   7725           SET_DH(1); // max head #
   7726           break;
   7727 
   7728         case 3: // 720KB, 3.5"
   7729           CX = 0x4f09; // 80 tracks, 9 sectors
   7730           SET_DH(1); // max head #
   7731           break;
   7732 
   7733         case 4: // 1.44MB, 3.5"
   7734           CX = 0x4f12; // 80 tracks, 18 sectors
   7735           SET_DH(1); // max head #
   7736           break;
   7737 
   7738         case 5: // 2.88MB, 3.5"
   7739           CX = 0x4f24; // 80 tracks, 36 sectors
   7740           SET_DH(1); // max head #
   7741           break;
   7742 
   7743         case 6: // 160k, 5.25"
   7744           CX = 0x2708; // 40 tracks, 8 sectors
   7745           SET_DH(0); // max head #
   7746           break;
   7747 
   7748         case 7: // 180k, 5.25"
   7749           CX = 0x2709; // 40 tracks, 9 sectors
   7750           SET_DH(0); // max head #
   7751           break;
   7752 
   7753         case 8: // 320k, 5.25"
   7754           CX = 0x2708; // 40 tracks, 8 sectors
   7755           SET_DH(1); // max head #
   7756           break;
   7757 
   7758         default: // ?
   7759           BX_PANIC("floppy: int13: bad floppy type\n");
   7760         }
   7761 
   7762       /* set es & di to point to 11 byte diskette param table in ROM */
   7763 ASM_START
   7764       push bp
   7765       mov  bp, sp
   7766       mov ax, #diskette_param_table2
   7767       mov _int13_diskette_function.DI+2[bp], ax
   7768       mov _int13_diskette_function.ES+2[bp], cs
   7769       pop  bp
   7770 ASM_END
   7771       CLEAR_CF(); // success
   7772       /* disk status not changed upon success */
   7773       return;
   7774 
   7775 
   7776     case 0x15: // read diskette drive type
   7777 BX_DEBUG_INT13_FL("floppy f15\n");
   7778       drive = GET_ELDL();
   7779       if (drive > 1) {
   7780         SET_AH(0); // only 2 drives supported
   7781         // set_diskette_ret_status here ???
   7782         SET_CF();
   7783         return;
   7784         }
   7785       drive_type = inb_cmos(0x10);
   7786 
   7787       if (drive == 0)
   7788         drive_type >>= 4;
   7789       else
   7790         drive_type &= 0x0f;
   7791       CLEAR_CF(); // successful, not present
   7792       if (drive_type==0) {
   7793         SET_AH(0); // drive not present
   7794         }
   7795       else {
   7796         SET_AH(1); // drive present, does not support change line
   7797         }
   7798 
   7799       return;
   7800 
   7801     case 0x16: // get diskette change line status
   7802 BX_DEBUG_INT13_FL("floppy f16\n");
   7803       drive = GET_ELDL();
   7804       if (drive > 1) {
   7805         SET_AH(0x01); // invalid drive
   7806         set_diskette_ret_status(0x01);
   7807         SET_CF();
   7808         return;
   7809         }
   7810 
   7811       SET_AH(0x06); // change line not supported
   7812       set_diskette_ret_status(0x06);
   7813       SET_CF();
   7814       return;
   7815 
   7816     case 0x17: // set diskette type for format(old)
   7817 BX_DEBUG_INT13_FL("floppy f17\n");
   7818       /* not used for 1.44M floppies */
   7819       SET_AH(0x01); // not supported
   7820       set_diskette_ret_status(1); /* not supported */
   7821       SET_CF();
   7822       return;
   7823 
   7824     case 0x18: // set diskette type for format(new)
   7825 BX_DEBUG_INT13_FL("floppy f18\n");
   7826       SET_AH(0x01); // do later
   7827       set_diskette_ret_status(1);
   7828       SET_CF();
   7829       return;
   7830 
   7831     default:
   7832         BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
   7833 
   7834       // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
   7835         SET_AH(0x01); // ???
   7836         set_diskette_ret_status(1);
   7837         SET_CF();
   7838         return;
   7839       //   }
   7840     }
   7841 }
   7842 #else  // #if BX_SUPPORT_FLOPPY
   7843   void
   7844 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
   7845   Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
   7846 {
   7847   Bit8u  val8;
   7848 
   7849   switch ( GET_AH() ) {
   7850 
   7851     case 0x01: // Read Diskette Status
   7852       CLEAR_CF();
   7853       val8 = read_byte(0x0000, 0x0441);
   7854       SET_AH(val8);
   7855       if (val8) {
   7856         SET_CF();
   7857         }
   7858       return;
   7859 
   7860     default:
   7861       SET_CF();
   7862       write_byte(0x0000, 0x0441, 0x01);
   7863       SET_AH(0x01);
   7864     }
   7865 }
   7866 #endif  // #if BX_SUPPORT_FLOPPY
   7867 
   7868  void
   7869 set_diskette_ret_status(value)
   7870   Bit8u value;
   7871 {
   7872   write_byte(0x0040, 0x0041, value);
   7873 }
   7874 
   7875   void
   7876 set_diskette_current_cyl(drive, cyl)
   7877   Bit8u drive;
   7878   Bit8u cyl;
   7879 {
   7880   if (drive > 1)
   7881     BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
   7882   write_byte(0x0040, 0x0094+drive, cyl);
   7883 }
   7884 
   7885   void
   7886 determine_floppy_media(drive)
   7887   Bit16u drive;
   7888 {
   7889 #if 0
   7890   Bit8u  val8, DOR, ctrl_info;
   7891 
   7892   ctrl_info = read_byte(0x0040, 0x008F);
   7893   if (drive==1)
   7894     ctrl_info >>= 4;
   7895   else
   7896     ctrl_info &= 0x0f;
   7897 
   7898 #if 0
   7899   if (drive == 0) {
   7900     DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
   7901     }
   7902   else {
   7903     DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
   7904     }
   7905 #endif
   7906 
   7907   if ( (ctrl_info & 0x04) != 0x04 ) {
   7908     // Drive not determined means no drive exists, done.
   7909     return;
   7910     }
   7911 
   7912 #if 0
   7913   // check Main Status Register for readiness
   7914   val8 = inb(0x03f4) & 0x80; // Main Status Register
   7915   if (val8 != 0x80)
   7916     BX_PANIC("d_f_m: MRQ bit not set\n");
   7917 
   7918   // change line
   7919 
   7920   // existing BDA values
   7921 
   7922   // turn on drive motor
   7923   outb(0x03f2, DOR); // Digital Output Register
   7924   //
   7925 #endif
   7926   BX_PANIC("d_f_m: OK so far\n");
   7927 #endif
   7928 }
   7929 
   7930   void
   7931 int17_function(regs, ds, iret_addr)
   7932   pusha_regs_t regs; // regs pushed from PUSHA instruction
   7933   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
   7934   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
   7935 {
   7936   Bit16u addr,timeout;
   7937   Bit8u val8;
   7938 
   7939   ASM_START
   7940   sti
   7941   ASM_END
   7942 
   7943   addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
   7944   if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
   7945     timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
   7946     if (regs.u.r8.ah == 0) {
   7947       outb(addr, regs.u.r8.al);
   7948       val8 = inb(addr+2);
   7949       outb(addr+2, val8 | 0x01); // send strobe
   7950       ASM_START
   7951       nop
   7952       ASM_END
   7953       outb(addr+2, val8 & ~0x01);
   7954       while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
   7955         timeout--;
   7956       }
   7957     }
   7958     if (regs.u.r8.ah == 1) {
   7959       val8 = inb(addr+2);
   7960       outb(addr+2, val8 & ~0x04); // send init
   7961       ASM_START
   7962       nop
   7963       ASM_END
   7964       outb(addr+2, val8 | 0x04);
   7965     }
   7966     val8 = inb(addr+1);
   7967     regs.u.r8.ah = (val8 ^ 0x48);
   7968     if (!timeout) regs.u.r8.ah |= 0x01;
   7969     ClearCF(iret_addr.flags);
   7970   } else {
   7971     SetCF(iret_addr.flags); // Unsupported
   7972   }
   7973 }
   7974 
   7975 void
   7976 int19_function(seq_nr)
   7977 Bit16u seq_nr;
   7978 {
   7979   Bit16u ebda_seg=read_word(0x0040,0x000E);
   7980   Bit16u bootdev;
   7981   Bit8u  bootdrv;
   7982   Bit8u  bootchk;
   7983   Bit16u bootseg;
   7984   Bit16u bootip;
   7985   Bit16u status;
   7986   Bit16u bootfirst;
   7987 
   7988   ipl_entry_t e;
   7989 
   7990   // if BX_ELTORITO_BOOT is not defined, old behavior
   7991   //   check bit 5 in CMOS reg 0x2d.  load either 0x00 or 0x80 into DL
   7992   //   in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
   7993   //     0: system boot sequence, first drive C: then A:
   7994   //     1: system boot sequence, first drive A: then C:
   7995   // else BX_ELTORITO_BOOT is defined
   7996   //   CMOS regs 0x3D and 0x38 contain the boot sequence:
   7997   //     CMOS reg 0x3D & 0x0f : 1st boot device
   7998   //     CMOS reg 0x3D & 0xf0 : 2nd boot device
   7999   //     CMOS reg 0x38 & 0xf0 : 3rd boot device
   8000   //   boot device codes:
   8001   //     0x00 : not defined
   8002   //     0x01 : first floppy
   8003   //     0x02 : first harddrive
   8004   //     0x03 : first cdrom
   8005   //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
   8006   //     else : boot failure
   8007 
   8008   // Get the boot sequence
   8009 #if BX_ELTORITO_BOOT
   8010   bootdev = inb_cmos(0x3d);
   8011   bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
   8012   bootdev >>= 4 * seq_nr;
   8013   bootdev &= 0xf;
   8014 
   8015   /* Read user selected device */
   8016   bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
   8017   if (bootfirst != 0xFFFF) {
   8018     bootdev = bootfirst;
   8019     /* User selected device not set */
   8020     write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
   8021     /* Reset boot sequence */
   8022     write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
   8023   } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
   8024 
   8025   /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
   8026   bootdev -= 1;
   8027 #else
   8028   if (seq_nr ==2) BX_PANIC("No more boot devices.");
   8029   if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1))
   8030       /* Boot from floppy if the bit is set or it's the second boot */
   8031     bootdev = 0x00;
   8032   else
   8033     bootdev = 0x01;
   8034 #endif
   8035 
   8036   /* Read the boot device from the IPL table */
   8037   if (get_boot_vector(bootdev, &e) == 0) {
   8038     BX_INFO("Invalid boot device (0x%x)\n", bootdev);
   8039     return;
   8040   }
   8041 
   8042   /* Do the loading, and set up vector as a far pointer to the boot
   8043    * address, and bootdrv as the boot drive */
   8044   print_boot_device(&e);
   8045 
   8046   switch(e.type) {
   8047   case IPL_TYPE_FLOPPY: /* FDD */
   8048   case IPL_TYPE_HARDDISK: /* HDD */
   8049 
   8050     bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
   8051     bootseg = 0x07c0;
   8052     status = 0;
   8053 
   8054 ASM_START
   8055     push bp
   8056     mov  bp, sp
   8057     push ax
   8058     push bx
   8059     push cx
   8060     push dx
   8061 
   8062     mov  dl, _int19_function.bootdrv + 2[bp]
   8063     mov  ax, _int19_function.bootseg + 2[bp]
   8064     mov  es, ax         ;; segment
   8065     xor  bx, bx         ;; offset
   8066     mov  ah, #0x02      ;; function 2, read diskette sector
   8067     mov  al, #0x01      ;; read 1 sector
   8068     mov  ch, #0x00      ;; track 0
   8069     mov  cl, #0x01      ;; sector 1
   8070     mov  dh, #0x00      ;; head 0
   8071     int  #0x13          ;; read sector
   8072     jnc  int19_load_done
   8073     mov  ax, #0x0001
   8074     mov  _int19_function.status + 2[bp], ax
   8075 
   8076 int19_load_done:
   8077     pop  dx
   8078     pop  cx
   8079     pop  bx
   8080     pop  ax
   8081     pop  bp
   8082 ASM_END
   8083 
   8084     if (status != 0) {
   8085       print_boot_failure(e.type, 1);
   8086       return;
   8087     }
   8088 
   8089     /* Always check the signature on a HDD boot sector; on FDD, only do
   8090      * the check if the CMOS doesn't tell us to skip it */
   8091     if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) {
   8092       if (read_word(bootseg,0x1fe) != 0xaa55) {
   8093         print_boot_failure(e.type, 0);
   8094         return;
   8095       }
   8096     }
   8097 
   8098     /* Canonicalize bootseg:bootip */
   8099     bootip = (bootseg & 0x0fff) << 4;
   8100     bootseg &= 0xf000;
   8101   break;
   8102 
   8103 #if BX_ELTORITO_BOOT
   8104   case IPL_TYPE_CDROM: /* CD-ROM */
   8105     status = cdrom_boot();
   8106 
   8107     // If failure
   8108     if ( (status & 0x00ff) !=0 ) {
   8109       print_cdromboot_failure(status);
   8110       print_boot_failure(e.type, 1);
   8111       return;
   8112     }
   8113 
   8114     bootdrv = (Bit8u)(status>>8);
   8115     bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
   8116     bootip = 0;
   8117     break;
   8118 #endif
   8119 
   8120   case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
   8121     bootseg = e.vector >> 16;
   8122     bootip = e.vector & 0xffff;
   8123     break;
   8124 
   8125   default: return;
   8126   }
   8127 
   8128   /* Debugging info */
   8129   BX_INFO("Booting from %x:%x\n", bootseg, bootip);
   8130 
   8131   /* Jump to the boot vector */
   8132 ASM_START
   8133     mov  bp, sp
   8134     push cs
   8135     push #int18_handler
   8136     ;; Build an iret stack frame that will take us to the boot vector.
   8137     ;; iret pops ip, then cs, then flags, so push them in the opposite order.
   8138     pushf
   8139     mov  ax, _int19_function.bootseg + 0[bp]
   8140     push ax
   8141     mov  ax, _int19_function.bootip + 0[bp]
   8142     push ax
   8143     ;; Set the magic number in ax and the boot drive in dl.
   8144     mov  ax, #0xaa55
   8145     mov  dl, _int19_function.bootdrv + 0[bp]
   8146     ;; Zero some of the other registers.
   8147     xor  bx, bx
   8148     mov  ds, bx
   8149     mov  es, bx
   8150     mov  bp, bx
   8151     ;; Go!
   8152     iret
   8153 ASM_END
   8154 }
   8155 
   8156   void
   8157 int1a_function(regs, ds, iret_addr)
   8158   pusha_regs_t regs; // regs pushed from PUSHA instruction
   8159   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
   8160   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
   8161 {
   8162   Bit8u val8;
   8163 
   8164   BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
   8165 
   8166   ASM_START
   8167   sti
   8168   ASM_END
   8169 
   8170   switch (regs.u.r8.ah) {
   8171     case 0: // get current clock count
   8172       ASM_START
   8173       cli
   8174       ASM_END
   8175       regs.u.r16.cx = BiosData->ticks_high;
   8176       regs.u.r16.dx = BiosData->ticks_low;
   8177       regs.u.r8.al  = BiosData->midnight_flag;
   8178       BiosData->midnight_flag = 0; // reset flag
   8179       ASM_START
   8180       sti
   8181       ASM_END
   8182       // AH already 0
   8183       ClearCF(iret_addr.flags); // OK
   8184       break;
   8185 
   8186     case 1: // Set Current Clock Count
   8187       ASM_START
   8188       cli
   8189       ASM_END
   8190       BiosData->ticks_high = regs.u.r16.cx;
   8191       BiosData->ticks_low  = regs.u.r16.dx;
   8192       BiosData->midnight_flag = 0; // reset flag
   8193       ASM_START
   8194       sti
   8195       ASM_END
   8196       regs.u.r8.ah = 0;
   8197       ClearCF(iret_addr.flags); // OK
   8198       break;
   8199 
   8200 
   8201     case 2: // Read CMOS Time
   8202       if (rtc_updating()) {
   8203         SetCF(iret_addr.flags);
   8204         break;
   8205         }
   8206 
   8207       regs.u.r8.dh = inb_cmos(0x00); // Seconds
   8208       regs.u.r8.cl = inb_cmos(0x02); // Minutes
   8209       regs.u.r8.ch = inb_cmos(0x04); // Hours
   8210       regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
   8211       regs.u.r8.ah = 0;
   8212       regs.u.r8.al = regs.u.r8.ch;
   8213       ClearCF(iret_addr.flags); // OK
   8214       break;
   8215 
   8216     case 3: // Set CMOS Time
   8217       // Using a debugger, I notice the following masking/setting
   8218       // of bits in Status Register B, by setting Reg B to
   8219       // a few values and getting its value after INT 1A was called.
   8220       //
   8221       //        try#1       try#2       try#3
   8222       // before 1111 1101   0111 1101   0000 0000
   8223       // after  0110 0010   0110 0010   0000 0010
   8224       //
   8225       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
   8226       // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
   8227       if (rtc_updating()) {
   8228         init_rtc();
   8229         // fall through as if an update were not in progress
   8230         }
   8231       outb_cmos(0x00, regs.u.r8.dh); // Seconds
   8232       outb_cmos(0x02, regs.u.r8.cl); // Minutes
   8233       outb_cmos(0x04, regs.u.r8.ch); // Hours
   8234       // Set Daylight Savings time enabled bit to requested value
   8235       val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
   8236       // (reg B already selected)
   8237       outb_cmos(0x0b, val8);
   8238       regs.u.r8.ah = 0;
   8239       regs.u.r8.al = val8; // val last written to Reg B
   8240       ClearCF(iret_addr.flags); // OK
   8241       break;
   8242 
   8243     case 4: // Read CMOS Date
   8244       regs.u.r8.ah = 0;
   8245       if (rtc_updating()) {
   8246         SetCF(iret_addr.flags);
   8247         break;
   8248         }
   8249       regs.u.r8.cl = inb_cmos(0x09); // Year
   8250       regs.u.r8.dh = inb_cmos(0x08); // Month
   8251       regs.u.r8.dl = inb_cmos(0x07); // Day of Month
   8252       regs.u.r8.ch = inb_cmos(0x32); // Century
   8253       regs.u.r8.al = regs.u.r8.ch;
   8254       ClearCF(iret_addr.flags); // OK
   8255       break;
   8256 
   8257     case 5: // Set CMOS Date
   8258       // Using a debugger, I notice the following masking/setting
   8259       // of bits in Status Register B, by setting Reg B to
   8260       // a few values and getting its value after INT 1A was called.
   8261       //
   8262       //        try#1       try#2       try#3       try#4
   8263       // before 1111 1101   0111 1101   0000 0010   0000 0000
   8264       // after  0110 1101   0111 1101   0000 0010   0000 0000
   8265       //
   8266       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
   8267       // My assumption: RegB = (RegB & 01111111b)
   8268       if (rtc_updating()) {
   8269         init_rtc();
   8270         SetCF(iret_addr.flags);
   8271         break;
   8272         }
   8273       outb_cmos(0x09, regs.u.r8.cl); // Year
   8274       outb_cmos(0x08, regs.u.r8.dh); // Month
   8275       outb_cmos(0x07, regs.u.r8.dl); // Day of Month
   8276       outb_cmos(0x32, regs.u.r8.ch); // Century
   8277       val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
   8278       outb_cmos(0x0b, val8);
   8279       regs.u.r8.ah = 0;
   8280       regs.u.r8.al = val8; // AL = val last written to Reg B
   8281       ClearCF(iret_addr.flags); // OK
   8282       break;
   8283 
   8284     case 6: // Set Alarm Time in CMOS
   8285       // Using a debugger, I notice the following masking/setting
   8286       // of bits in Status Register B, by setting Reg B to
   8287       // a few values and getting its value after INT 1A was called.
   8288       //
   8289       //        try#1       try#2       try#3
   8290       // before 1101 1111   0101 1111   0000 0000
   8291       // after  0110 1111   0111 1111   0010 0000
   8292       //
   8293       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
   8294       // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
   8295       val8 = inb_cmos(0x0b); // Get Status Reg B
   8296       regs.u.r16.ax = 0;
   8297       if (val8 & 0x20) {
   8298         // Alarm interrupt enabled already
   8299         SetCF(iret_addr.flags); // Error: alarm in use
   8300         break;
   8301         }
   8302       if (rtc_updating()) {
   8303         init_rtc();
   8304         // fall through as if an update were not in progress
   8305         }
   8306       outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
   8307       outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
   8308       outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
   8309       outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
   8310       // enable Status Reg B alarm bit, clear halt clock bit
   8311       outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
   8312       ClearCF(iret_addr.flags); // OK
   8313       break;
   8314 
   8315     case 7: // Turn off Alarm
   8316       // Using a debugger, I notice the following masking/setting
   8317       // of bits in Status Register B, by setting Reg B to
   8318       // a few values and getting its value after INT 1A was called.
   8319       //
   8320       //        try#1       try#2       try#3       try#4
   8321       // before 1111 1101   0111 1101   0010 0000   0010 0010
   8322       // after  0100 0101   0101 0101   0000 0000   0000 0010
   8323       //
   8324       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
   8325       // My assumption: RegB = (RegB & 01010111b)
   8326       val8 = inb_cmos(0x0b); // Get Status Reg B
   8327       // clear clock-halt bit, disable alarm bit
   8328       outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
   8329       regs.u.r8.ah = 0;
   8330       regs.u.r8.al = val8; // val last written to Reg B
   8331       ClearCF(iret_addr.flags); // OK
   8332       break;
   8333 #if BX_PCIBIOS
   8334     case 0xb1:
   8335       // real mode PCI BIOS functions now handled in assembler code
   8336       // this C code handles the error code for information only
   8337       if (regs.u.r8.bl == 0xff) {
   8338         BX_INFO("PCI BIOS: PCI not present\n");
   8339       } else if (regs.u.r8.bl == 0x81) {
   8340         BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
   8341       } else if (regs.u.r8.bl == 0x83) {
   8342         BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
   8343       } else if (regs.u.r8.bl == 0x86) {
   8344         if (regs.u.r8.al == 0x02) {
   8345           BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si);
   8346         } else {
   8347           BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs.u.r8.cl, regs.u.r16.dx, regs.u.r16.si);
   8348         }
   8349       }
   8350       regs.u.r8.ah = regs.u.r8.bl;
   8351       SetCF(iret_addr.flags);
   8352       break;
   8353 #endif
   8354 
   8355     default:
   8356       SetCF(iret_addr.flags); // Unsupported
   8357     }
   8358 }
   8359 
   8360   void
   8361 int70_function(regs, ds, iret_addr)
   8362   pusha_regs_t regs; // regs pushed from PUSHA instruction
   8363   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
   8364   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
   8365 {
   8366   // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
   8367   Bit8u registerB = 0, registerC = 0;
   8368 
   8369   // Check which modes are enabled and have occurred.
   8370   registerB = inb_cmos( 0xB );
   8371   registerC = inb_cmos( 0xC );
   8372 
   8373   if( ( registerB & 0x60 ) != 0 ) {
   8374     if( ( registerC & 0x20 ) != 0 ) {
   8375       // Handle Alarm Interrupt.
   8376 ASM_START
   8377       sti
   8378       int #0x4a
   8379       cli
   8380 ASM_END
   8381     }
   8382     if( ( registerC & 0x40 ) != 0 ) {
   8383       // Handle Periodic Interrupt.
   8384 
   8385       if( read_byte( 0x40, 0xA0 ) != 0 ) {
   8386         // Wait Interval (Int 15, AH=83) active.
   8387         Bit32u time, toggle;
   8388 
   8389         time = read_dword( 0x40, 0x9C );  // Time left in microseconds.
   8390         if( time < 0x3D1 ) {
   8391           // Done waiting.
   8392           Bit16u segment, offset;
   8393 
   8394           segment = read_word( 0x40, 0x98 );
   8395           offset = read_word( 0x40, 0x9A );
   8396           write_byte( 0x40, 0xA0, 0 );  // Turn of status byte.
   8397           outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
   8398           write_byte(segment, offset, read_byte(segment, offset) | 0x80 );  // Write to specified flag byte.
   8399         } else {
   8400           // Continue waiting.
   8401           time -= 0x3D1;
   8402           write_dword( 0x40, 0x9C, time );
   8403         }
   8404       }
   8405     }
   8406   }
   8407 
   8408 ASM_START
   8409   call eoi_both_pics
   8410 ASM_END
   8411 }
   8412 
   8413 
   8414 ASM_START
   8415 ;------------------------------------------
   8416 ;- INT74h : PS/2 mouse hardware interrupt -
   8417 ;------------------------------------------
   8418 int74_handler:
   8419   sti
   8420   pusha
   8421   push ds         ;; save DS
   8422   push #0x00 ;; placeholder for status
   8423   push #0x00 ;; placeholder for X
   8424   push #0x00 ;; placeholder for Y
   8425   push #0x00 ;; placeholder for Z
   8426   push #0x00 ;; placeholder for make_far_call boolean
   8427   call _int74_function
   8428   pop  cx      ;; remove make_far_call from stack
   8429   jcxz int74_done
   8430 
   8431   ;; make far call to EBDA:0022
   8432   push #0x00
   8433   pop ds
   8434   push 0x040E     ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
   8435   pop ds
   8436   //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
   8437   call far ptr[0x22]
   8438 int74_done:
   8439   cli
   8440   call eoi_both_pics
   8441   add sp, #8     ;; pop status, x, y, z
   8442 
   8443   pop ds          ;; restore DS
   8444   popa
   8445   iret
   8446 
   8447 
   8448 ;; This will perform an IRET, but will retain value of current CF
   8449 ;; by altering flags on stack.  Better than RETF #02.
   8450 iret_modify_cf:
   8451   jc   carry_set
   8452   push bp
   8453   mov  bp, sp
   8454   and  BYTE [bp + 0x06], #0xfe
   8455   pop  bp
   8456   iret
   8457 carry_set:
   8458   push bp
   8459   mov  bp, sp
   8460   or   BYTE [bp + 0x06], #0x01
   8461   pop  bp
   8462   iret
   8463 
   8464 
   8465 ;----------------------
   8466 ;- INT13h (relocated) -
   8467 ;----------------------
   8468 ;
   8469 ; int13_relocated is a little bit messed up since I played with it
   8470 ; I have to rewrite it:
   8471 ;   - call a function that detect which function to call
   8472 ;   - make all called C function get the same parameters list
   8473 ;
   8474 int13_relocated:
   8475 
   8476 #if BX_ELTORITO_BOOT
   8477   ;; check for an eltorito function
   8478   cmp   ah,#0x4a
   8479   jb    int13_not_eltorito
   8480   cmp   ah,#0x4d
   8481   ja    int13_not_eltorito
   8482 
   8483   pusha
   8484   push  es
   8485   push  ds
   8486   push  ss
   8487   pop   ds
   8488 
   8489   push  #int13_out
   8490   jmp   _int13_eltorito      ;; ELDX not used
   8491 
   8492 int13_not_eltorito:
   8493   push  ax
   8494   push  bx
   8495   push  cx
   8496   push  dx
   8497 
   8498   ;; check if emulation active
   8499   call  _cdemu_isactive
   8500   cmp   al,#0x00
   8501   je    int13_cdemu_inactive
   8502 
   8503   ;; check if access to the emulated drive
   8504   call  _cdemu_emulated_drive
   8505   pop   dx
   8506   push  dx
   8507   cmp   al,dl                ;; int13 on emulated drive
   8508   jne   int13_nocdemu
   8509 
   8510   pop   dx
   8511   pop   cx
   8512   pop   bx
   8513   pop   ax
   8514 
   8515   pusha
   8516   push  es
   8517   push  ds
   8518   push  ss
   8519   pop   ds
   8520 
   8521   push  #int13_out
   8522   jmp   _int13_cdemu         ;; ELDX not used
   8523 
   8524 int13_nocdemu:
   8525   and   dl,#0xE0             ;; mask to get device class, including cdroms
   8526   cmp   al,dl                ;; al is 0x00 or 0x80
   8527   jne   int13_cdemu_inactive ;; inactive for device class
   8528 
   8529   pop   dx
   8530   pop   cx
   8531   pop   bx
   8532   pop   ax
   8533 
   8534   push  ax
   8535   push  cx
   8536   push  dx
   8537   push  bx
   8538 
   8539   dec   dl                   ;; real drive is dl - 1
   8540   jmp   int13_legacy
   8541 
   8542 int13_cdemu_inactive:
   8543   pop   dx
   8544   pop   cx
   8545   pop   bx
   8546   pop   ax
   8547 
   8548 #endif // BX_ELTORITO_BOOT
   8549 
   8550 int13_noeltorito:
   8551 
   8552   push  ax
   8553   push  cx
   8554   push  dx
   8555   push  bx
   8556 
   8557 int13_legacy:
   8558 
   8559   push  dx                   ;; push eltorito value of dx instead of sp
   8560 
   8561   push  bp
   8562   push  si
   8563   push  di
   8564 
   8565   push  es
   8566   push  ds
   8567   push  ss
   8568   pop   ds
   8569 
   8570   ;; now the 16-bit registers can be restored with:
   8571   ;; pop ds; pop es; popa; iret
   8572   ;; arguments passed to functions should be
   8573   ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
   8574 
   8575   test  dl, #0x80
   8576   jnz   int13_notfloppy
   8577 
   8578   push #int13_out
   8579   jmp _int13_diskette_function
   8580 
   8581 int13_notfloppy:
   8582 
   8583 #if BX_USE_ATADRV
   8584 
   8585   cmp   dl, #0xE0
   8586   jb    int13_notcdrom
   8587 
   8588   // ebx is modified: BSD 5.2.1 boot loader problem
   8589   // someone should figure out which 32 bit register that actually are used
   8590 
   8591   shr   ebx, #16
   8592   push  bx
   8593 
   8594   call  _int13_cdrom
   8595 
   8596   pop   bx
   8597   shl   ebx, #16
   8598 
   8599   jmp int13_out
   8600 
   8601 int13_notcdrom:
   8602 
   8603 #endif
   8604 
   8605 int13_disk:
   8606   ;; int13_harddisk modifies high word of EAX
   8607   shr   eax, #16
   8608   push  ax
   8609   call  _int13_harddisk
   8610   pop   ax
   8611   shl   eax, #16
   8612 
   8613 int13_out:
   8614   pop ds
   8615   pop es
   8616   popa
   8617   iret
   8618 
   8619 ;----------
   8620 ;- INT18h -
   8621 ;----------
   8622 int18_handler: ;; Boot Failure recovery: try the next device.
   8623 
   8624   ;; Reset SP and SS
   8625   mov  ax, #0xfffe
   8626   mov  sp, ax
   8627   xor  ax, ax
   8628   mov  ss, ax
   8629 
   8630   ;; Get the boot sequence number out of the IPL memory
   8631   mov  bx, #IPL_SEG
   8632   mov  ds, bx                     ;; Set segment
   8633   mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
   8634   inc  bx                         ;; ++
   8635   mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
   8636   mov  ds, ax                     ;; and reset the segment to zero.
   8637 
   8638   ;; Carry on in the INT 19h handler, using the new sequence number
   8639   push bx
   8640 
   8641   jmp  int19_next_boot
   8642 
   8643 ;----------
   8644 ;- INT19h -
   8645 ;----------
   8646 int19_relocated: ;; Boot function, relocated
   8647 
   8648   ;; int19 was beginning to be really complex, so now it
   8649   ;; just calls a C function that does the work
   8650 
   8651   push bp
   8652   mov  bp, sp
   8653 
   8654   ;; Reset SS and SP
   8655   mov  ax, #0xfffe
   8656   mov  sp, ax
   8657   xor  ax, ax
   8658   mov  ss, ax
   8659 
   8660   ;; Start from the first boot device (0, in AX)
   8661   mov  bx, #IPL_SEG
   8662   mov  ds, bx                     ;; Set segment to write to the IPL memory
   8663   mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
   8664   mov  ds, ax                     ;; and reset the segment.
   8665 
   8666   push ax
   8667 
   8668 int19_next_boot:
   8669 
   8670   ;; Call the C code for the next boot device
   8671   call _int19_function
   8672 
   8673   ;; Boot failed: invoke the boot recovery function
   8674   int  #0x18
   8675 
   8676 ;----------
   8677 ;- INT1Ch -
   8678 ;----------
   8679 int1c_handler: ;; User Timer Tick
   8680   iret
   8681 
   8682 
   8683 ;----------------------
   8684 ;- POST: Floppy Drive -
   8685 ;----------------------
   8686 floppy_drive_post:
   8687   xor  ax, ax
   8688   mov  ds, ax
   8689 
   8690   mov  al, #0x00
   8691   mov  0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
   8692 
   8693   mov  0x043f, al  ;; diskette motor status: read op, drive0, motors off
   8694 
   8695   mov  0x0440, al  ;; diskette motor timeout counter: not active
   8696   mov  0x0441, al  ;; diskette controller status return code
   8697 
   8698   mov  0x0442, al  ;; disk & diskette controller status register 0
   8699   mov  0x0443, al  ;; diskette controller status register 1
   8700   mov  0x0444, al  ;; diskette controller status register 2
   8701   mov  0x0445, al  ;; diskette controller cylinder number
   8702   mov  0x0446, al  ;; diskette controller head number
   8703   mov  0x0447, al  ;; diskette controller sector number
   8704   mov  0x0448, al  ;; diskette controller bytes written
   8705 
   8706   mov  0x048b, al  ;; diskette configuration data
   8707 
   8708   ;; -----------------------------------------------------------------
   8709   ;; (048F) diskette controller information
   8710   ;;
   8711   mov  al, #0x10   ;; get CMOS diskette drive type
   8712   out  0x70, AL
   8713   in   AL, 0x71
   8714   mov  ah, al      ;; save byte to AH
   8715 
   8716 look_drive0:
   8717   shr  al, #4      ;; look at top 4 bits for drive 0
   8718   jz   f0_missing  ;; jump if no drive0
   8719   mov  bl, #0x07   ;; drive0 determined, multi-rate, has changed line
   8720   jmp  look_drive1
   8721 f0_missing:
   8722   mov  bl, #0x00   ;; no drive0
   8723 
   8724 look_drive1:
   8725   mov  al, ah      ;; restore from AH
   8726   and  al, #0x0f   ;; look at bottom 4 bits for drive 1
   8727   jz   f1_missing  ;; jump if no drive1
   8728   or   bl, #0x70   ;; drive1 determined, multi-rate, has changed line
   8729 f1_missing:
   8730                    ;; leave high bits in BL zerod
   8731   mov  0x048f, bl  ;; put new val in BDA (diskette controller information)
   8732   ;; -----------------------------------------------------------------
   8733 
   8734   mov  al, #0x00
   8735   mov  0x0490, al  ;; diskette 0 media state
   8736   mov  0x0491, al  ;; diskette 1 media state
   8737 
   8738                    ;; diskette 0,1 operational starting state
   8739                    ;; drive type has not been determined,
   8740                    ;; has no changed detection line
   8741   mov  0x0492, al
   8742   mov  0x0493, al
   8743 
   8744   mov  0x0494, al  ;; diskette 0 current cylinder
   8745   mov  0x0495, al  ;; diskette 1 current cylinder
   8746 
   8747   mov  al, #0x02
   8748   out  #0x0a, al   ;; clear DMA-1 channel 2 mask bit
   8749 
   8750   SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
   8751   SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
   8752   SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
   8753 
   8754   ret
   8755 
   8756 
   8757 ;--------------------
   8758 ;- POST: HARD DRIVE -
   8759 ;--------------------
   8760 ; relocated here because the primary POST area isnt big enough.
   8761 hard_drive_post:
   8762   // IRQ 14 = INT 76h
   8763   // INT 76h calls INT 15h function ax=9100
   8764 
   8765   mov  al, #0x0a   ; 0000 1010 = reserved, disable IRQ 14
   8766   mov  dx, #0x03f6
   8767   out  dx, al
   8768 
   8769   xor  ax, ax
   8770   mov  ds, ax
   8771   mov  0x0474, al /* hard disk status of last operation */
   8772   mov  0x0477, al /* hard disk port offset (XT only ???) */
   8773   mov  0x048c, al /* hard disk status register */
   8774   mov  0x048d, al /* hard disk error register */
   8775   mov  0x048e, al /* hard disk task complete flag */
   8776   mov  al, #0x01
   8777   mov  0x0475, al /* hard disk number attached */
   8778   mov  al, #0xc0
   8779   mov  0x0476, al /* hard disk control byte */
   8780   SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
   8781   SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
   8782   ;; INT 41h: hard disk 0 configuration pointer
   8783   ;; INT 46h: hard disk 1 configuration pointer
   8784   SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
   8785   SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
   8786 
   8787   ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
   8788   mov  al, #0x12
   8789   out  #0x70, al
   8790   in   al, #0x71
   8791   and  al, #0xf0
   8792   cmp  al, #0xf0
   8793   je   post_d0_extended
   8794   jmp check_for_hd1
   8795 post_d0_extended:
   8796   mov  al, #0x19
   8797   out  #0x70, al
   8798   in   al, #0x71
   8799   cmp  al, #47  ;; decimal 47 - user definable
   8800   je   post_d0_type47
   8801   HALT(__LINE__)
   8802 post_d0_type47:
   8803   ;; CMOS  purpose                  param table offset
   8804   ;; 1b    cylinders low            0
   8805   ;; 1c    cylinders high           1
   8806   ;; 1d    heads                    2
   8807   ;; 1e    write pre-comp low       5
   8808   ;; 1f    write pre-comp high      6
   8809   ;; 20    retries/bad map/heads>8  8
   8810   ;; 21    landing zone low         C
   8811   ;; 22    landing zone high        D
   8812   ;; 23    sectors/track            E
   8813 
   8814   mov  ax, #EBDA_SEG
   8815   mov  ds, ax
   8816 
   8817   ;;; Filling EBDA table for hard disk 0.
   8818   mov  al, #0x1f
   8819   out  #0x70, al
   8820   in   al, #0x71
   8821   mov  ah, al
   8822   mov  al, #0x1e
   8823   out  #0x70, al
   8824   in   al, #0x71
   8825   mov   (0x003d + 0x05), ax ;; write precomp word
   8826 
   8827   mov  al, #0x20
   8828   out  #0x70, al
   8829   in   al, #0x71
   8830   mov   (0x003d + 0x08), al ;; drive control byte
   8831 
   8832   mov  al, #0x22
   8833   out  #0x70, al
   8834   in   al, #0x71
   8835   mov  ah, al
   8836   mov  al, #0x21
   8837   out  #0x70, al
   8838   in   al, #0x71
   8839   mov   (0x003d + 0x0C), ax ;; landing zone word
   8840 
   8841   mov  al, #0x1c   ;; get cylinders word in AX
   8842   out  #0x70, al
   8843   in   al, #0x71   ;; high byte
   8844   mov  ah, al
   8845   mov  al, #0x1b
   8846   out  #0x70, al
   8847   in   al, #0x71   ;; low byte
   8848   mov  bx, ax      ;; BX = cylinders
   8849 
   8850   mov  al, #0x1d
   8851   out  #0x70, al
   8852   in   al, #0x71
   8853   mov  cl, al      ;; CL = heads
   8854 
   8855   mov  al, #0x23
   8856   out  #0x70, al
   8857   in   al, #0x71
   8858   mov  dl, al      ;; DL = sectors
   8859 
   8860   cmp  bx, #1024
   8861   jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
   8862 
   8863 hd0_post_physical_chs:
   8864   ;; no logical CHS mapping used, just physical CHS
   8865   ;; use Standard Fixed Disk Parameter Table (FDPT)
   8866   mov   (0x003d + 0x00), bx ;; number of physical cylinders
   8867   mov   (0x003d + 0x02), cl ;; number of physical heads
   8868   mov   (0x003d + 0x0E), dl ;; number of physical sectors
   8869   jmp check_for_hd1
   8870 
   8871 hd0_post_logical_chs:
   8872   ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
   8873   mov   (0x003d + 0x09), bx ;; number of physical cylinders
   8874   mov   (0x003d + 0x0b), cl ;; number of physical heads
   8875   mov   (0x003d + 0x04), dl ;; number of physical sectors
   8876   mov   (0x003d + 0x0e), dl ;; number of logical sectors (same)
   8877   mov al, #0xa0
   8878   mov   (0x003d + 0x03), al ;; A0h signature, indicates translated table
   8879 
   8880   cmp bx, #2048
   8881   jnbe hd0_post_above_2048
   8882   ;; 1024 < c <= 2048 cylinders
   8883   shr bx, #0x01
   8884   shl cl, #0x01
   8885   jmp hd0_post_store_logical
   8886 
   8887 hd0_post_above_2048:
   8888   cmp bx, #4096
   8889   jnbe hd0_post_above_4096
   8890   ;; 2048 < c <= 4096 cylinders
   8891   shr bx, #0x02
   8892   shl cl, #0x02
   8893   jmp hd0_post_store_logical
   8894 
   8895 hd0_post_above_4096:
   8896   cmp bx, #8192
   8897   jnbe hd0_post_above_8192
   8898   ;; 4096 < c <= 8192 cylinders
   8899   shr bx, #0x03
   8900   shl cl, #0x03
   8901   jmp hd0_post_store_logical
   8902 
   8903 hd0_post_above_8192:
   8904   ;; 8192 < c <= 16384 cylinders
   8905   shr bx, #0x04
   8906   shl cl, #0x04
   8907 
   8908 hd0_post_store_logical:
   8909   mov   (0x003d + 0x00), bx ;; number of physical cylinders
   8910   mov   (0x003d + 0x02), cl ;; number of physical heads
   8911   ;; checksum
   8912   mov   cl, #0x0f     ;; repeat count
   8913   mov   si, #0x003d   ;; offset to disk0 FDPT
   8914   mov   al, #0x00     ;; sum
   8915 hd0_post_checksum_loop:
   8916   add   al, [si]
   8917   inc   si
   8918   dec   cl
   8919   jnz hd0_post_checksum_loop
   8920   not   al  ;; now take 2s complement
   8921   inc   al
   8922   mov   [si], al
   8923 ;;; Done filling EBDA table for hard disk 0.
   8924 
   8925 
   8926 check_for_hd1:
   8927   ;; is there really a second hard disk?  if not, return now
   8928   mov  al, #0x12
   8929   out  #0x70, al
   8930   in   al, #0x71
   8931   and  al, #0x0f
   8932   jnz   post_d1_exists
   8933   ret
   8934 post_d1_exists:
   8935   ;; check that the hd type is really 0x0f.
   8936   cmp al, #0x0f
   8937   jz post_d1_extended
   8938   HALT(__LINE__)
   8939 post_d1_extended:
   8940   ;; check that the extended type is 47 - user definable
   8941   mov  al, #0x1a
   8942   out  #0x70, al
   8943   in   al, #0x71
   8944   cmp  al, #47  ;; decimal 47 - user definable
   8945   je   post_d1_type47
   8946   HALT(__LINE__)
   8947 post_d1_type47:
   8948   ;; Table for disk1.
   8949   ;; CMOS  purpose                  param table offset
   8950   ;; 0x24    cylinders low            0
   8951   ;; 0x25    cylinders high           1
   8952   ;; 0x26    heads                    2
   8953   ;; 0x27    write pre-comp low       5
   8954   ;; 0x28    write pre-comp high      6
   8955   ;; 0x29    heads>8                  8
   8956   ;; 0x2a    landing zone low         C
   8957   ;; 0x2b    landing zone high        D
   8958   ;; 0x2c    sectors/track            E
   8959 ;;; Fill EBDA table for hard disk 1.
   8960   mov  ax, #EBDA_SEG
   8961   mov  ds, ax
   8962   mov  al, #0x28
   8963   out  #0x70, al
   8964   in   al, #0x71
   8965   mov  ah, al
   8966   mov  al, #0x27
   8967   out  #0x70, al
   8968   in   al, #0x71
   8969   mov   (0x004d + 0x05), ax ;; write precomp word
   8970 
   8971   mov  al, #0x29
   8972   out  #0x70, al
   8973   in   al, #0x71
   8974   mov   (0x004d + 0x08), al ;; drive control byte
   8975 
   8976   mov  al, #0x2b
   8977   out  #0x70, al
   8978   in   al, #0x71
   8979   mov  ah, al
   8980   mov  al, #0x2a
   8981   out  #0x70, al
   8982   in   al, #0x71
   8983   mov   (0x004d + 0x0C), ax ;; landing zone word
   8984 
   8985   mov  al, #0x25   ;; get cylinders word in AX
   8986   out  #0x70, al
   8987   in   al, #0x71   ;; high byte
   8988   mov  ah, al
   8989   mov  al, #0x24
   8990   out  #0x70, al
   8991   in   al, #0x71   ;; low byte
   8992   mov  bx, ax      ;; BX = cylinders
   8993 
   8994   mov  al, #0x26
   8995   out  #0x70, al
   8996   in   al, #0x71
   8997   mov  cl, al      ;; CL = heads
   8998 
   8999   mov  al, #0x2c
   9000   out  #0x70, al
   9001   in   al, #0x71
   9002   mov  dl, al      ;; DL = sectors
   9003 
   9004   cmp  bx, #1024
   9005   jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
   9006 
   9007 hd1_post_physical_chs:
   9008   ;; no logical CHS mapping used, just physical CHS
   9009   ;; use Standard Fixed Disk Parameter Table (FDPT)
   9010   mov   (0x004d + 0x00), bx ;; number of physical cylinders
   9011   mov   (0x004d + 0x02), cl ;; number of physical heads
   9012   mov   (0x004d + 0x0E), dl ;; number of physical sectors
   9013   ret
   9014 
   9015 hd1_post_logical_chs:
   9016   ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
   9017   mov   (0x004d + 0x09), bx ;; number of physical cylinders
   9018   mov   (0x004d + 0x0b), cl ;; number of physical heads
   9019   mov   (0x004d + 0x04), dl ;; number of physical sectors
   9020   mov   (0x004d + 0x0e), dl ;; number of logical sectors (same)
   9021   mov al, #0xa0
   9022   mov   (0x004d + 0x03), al ;; A0h signature, indicates translated table
   9023 
   9024   cmp bx, #2048
   9025   jnbe hd1_post_above_2048
   9026   ;; 1024 < c <= 2048 cylinders
   9027   shr bx, #0x01
   9028   shl cl, #0x01
   9029   jmp hd1_post_store_logical
   9030 
   9031 hd1_post_above_2048:
   9032   cmp bx, #4096
   9033   jnbe hd1_post_above_4096
   9034   ;; 2048 < c <= 4096 cylinders
   9035   shr bx, #0x02
   9036   shl cl, #0x02
   9037   jmp hd1_post_store_logical
   9038 
   9039 hd1_post_above_4096:
   9040   cmp bx, #8192
   9041   jnbe hd1_post_above_8192
   9042   ;; 4096 < c <= 8192 cylinders
   9043   shr bx, #0x03
   9044   shl cl, #0x03
   9045   jmp hd1_post_store_logical
   9046 
   9047 hd1_post_above_8192:
   9048   ;; 8192 < c <= 16384 cylinders
   9049   shr bx, #0x04
   9050   shl cl, #0x04
   9051 
   9052 hd1_post_store_logical:
   9053   mov   (0x004d + 0x00), bx ;; number of physical cylinders
   9054   mov   (0x004d + 0x02), cl ;; number of physical heads
   9055   ;; checksum
   9056   mov   cl, #0x0f     ;; repeat count
   9057   mov   si, #0x004d   ;; offset to disk0 FDPT
   9058   mov   al, #0x00     ;; sum
   9059 hd1_post_checksum_loop:
   9060   add   al, [si]
   9061   inc   si
   9062   dec   cl
   9063   jnz hd1_post_checksum_loop
   9064   not   al  ;; now take 2s complement
   9065   inc   al
   9066   mov   [si], al
   9067 ;;; Done filling EBDA table for hard disk 1.
   9068 
   9069   ret
   9070 
   9071 ;--------------------
   9072 ;- POST: EBDA segment
   9073 ;--------------------
   9074 ; relocated here because the primary POST area isnt big enough.
   9075 ebda_post:
   9076 #if BX_USE_EBDA
   9077   mov ax, #EBDA_SEG
   9078   mov ds, ax
   9079   mov byte ptr [0x0], #EBDA_SIZE
   9080 #endif
   9081   xor ax, ax            ; mov EBDA seg into 40E
   9082   mov ds, ax
   9083   mov word ptr [0x40E], #EBDA_SEG
   9084   ret;;
   9085 
   9086 ;--------------------
   9087 ;- POST: EOI + jmp via [0x40:67)
   9088 ;--------------------
   9089 ; relocated here because the primary POST area isnt big enough.
   9090 eoi_jmp_post:
   9091   mov   al, #0x20
   9092   out   #0xA0, al ;; slave  PIC EOI
   9093   mov   al, #0x20
   9094   out   #0x20, al ;; master PIC EOI
   9095 
   9096 jmp_post_0x467:
   9097   xor ax, ax
   9098   mov ds, ax
   9099 
   9100   jmp far ptr [0x467]
   9101 
   9102 iret_post_0x467:
   9103   xor ax, ax
   9104   mov ds, ax
   9105 
   9106   mov sp, [0x467]
   9107   mov ss, [0x469]
   9108   iret
   9109 
   9110 retf_post_0x467:
   9111   xor ax, ax
   9112   mov ds, ax
   9113 
   9114   mov sp, [0x467]
   9115   mov ss, [0x469]
   9116   retf
   9117 
   9118 s3_post:
   9119   mov sp, #0xffe
   9120 #if BX_ROMBIOS32
   9121   call rombios32_init
   9122 #endif
   9123   call _s3_resume
   9124   mov bl, #0x00
   9125   and ax, ax
   9126   jz normal_post
   9127   call _s3_resume_panic
   9128 
   9129 ;--------------------
   9130 eoi_both_pics:
   9131   mov   al, #0x20
   9132   out   #0xA0, al ;; slave  PIC EOI
   9133 eoi_master_pic:
   9134   mov   al, #0x20
   9135   out   #0x20, al ;; master PIC EOI
   9136   ret
   9137 
   9138 ;--------------------
   9139 BcdToBin:
   9140   ;; in:  AL in BCD format
   9141   ;; out: AL in binary format, AH will always be 0
   9142   ;; trashes BX
   9143   mov  bl, al
   9144   and  bl, #0x0f ;; bl has low digit
   9145   shr  al, #4    ;; al has high digit
   9146   mov  bh, #10
   9147   mul  al, bh    ;; multiply high digit by 10 (result in AX)
   9148   add  al, bl    ;;   then add low digit
   9149   ret
   9150 
   9151 ;--------------------
   9152 timer_tick_post:
   9153   ;; Setup the Timer Ticks Count (0x46C:dword) and
   9154   ;;   Timer Ticks Roller Flag (0x470:byte)
   9155   ;; The Timer Ticks Count needs to be set according to
   9156   ;; the current CMOS time, as if ticks have been occurring
   9157   ;; at 18.2hz since midnight up to this point.  Calculating
   9158   ;; this is a little complicated.  Here are the factors I gather
   9159   ;; regarding this.  14,318,180 hz was the original clock speed,
   9160   ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
   9161   ;; at the time, or 4 to drive the CGA video adapter.  The div3
   9162   ;; source was divided again by 4 to feed a 1.193Mhz signal to
   9163   ;; the timer.  With a maximum 16bit timer count, this is again
   9164   ;; divided down by 65536 to 18.2hz.
   9165   ;;
   9166   ;; 14,318,180 Hz clock
   9167   ;;   /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
   9168   ;;   /4 = 1,193,181 Hz fed to timer
   9169   ;;   /65536 (maximum timer count) = 18.20650736 ticks/second
   9170   ;; 1 second = 18.20650736 ticks
   9171   ;; 1 minute = 1092.390442 ticks
   9172   ;; 1 hour   = 65543.42651 ticks
   9173   ;;
   9174   ;; Given the values in the CMOS clock, one could calculate
   9175   ;; the number of ticks by the following:
   9176   ;;   ticks = (BcdToBin(seconds) * 18.206507) +
   9177   ;;           (BcdToBin(minutes) * 1092.3904)
   9178   ;;           (BcdToBin(hours)   * 65543.427)
   9179   ;; To get a little more accuracy, since Im using integer
   9180   ;; arithmatic, I use:
   9181   ;;   ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
   9182   ;;           (BcdToBin(minutes) * 10923904) / 10000 +
   9183   ;;           (BcdToBin(hours)   * 65543427) / 1000
   9184 
   9185   ;; assuming DS=0000
   9186 
   9187   ;; get CMOS seconds
   9188   xor  eax, eax ;; clear EAX
   9189   mov  al, #0x00
   9190   out  #0x70, al
   9191   in   al, #0x71 ;; AL has CMOS seconds in BCD
   9192   call BcdToBin  ;; EAX now has seconds in binary
   9193   mov  edx, #18206507
   9194   mul  eax, edx
   9195   mov  ebx, #1000000
   9196   xor  edx, edx
   9197   div  eax, ebx
   9198   mov  ecx, eax  ;; ECX will accumulate total ticks
   9199 
   9200   ;; get CMOS minutes
   9201   xor  eax, eax ;; clear EAX
   9202   mov  al, #0x02
   9203   out  #0x70, al
   9204   in   al, #0x71 ;; AL has CMOS minutes in BCD
   9205   call BcdToBin  ;; EAX now has minutes in binary
   9206   mov  edx, #10923904
   9207   mul  eax, edx
   9208   mov  ebx, #10000
   9209   xor  edx, edx
   9210   div  eax, ebx
   9211   add  ecx, eax  ;; add to total ticks
   9212 
   9213   ;; get CMOS hours
   9214   xor  eax, eax ;; clear EAX
   9215   mov  al, #0x04
   9216   out  #0x70, al
   9217   in   al, #0x71 ;; AL has CMOS hours in BCD
   9218   call BcdToBin  ;; EAX now has hours in binary
   9219   mov  edx, #65543427
   9220   mul  eax, edx
   9221   mov  ebx, #1000
   9222   xor  edx, edx
   9223   div  eax, ebx
   9224   add  ecx, eax  ;; add to total ticks
   9225 
   9226   mov  0x46C, ecx ;; Timer Ticks Count
   9227   xor  al, al
   9228   mov  0x470, al  ;; Timer Ticks Rollover Flag
   9229   ret
   9230 
   9231 ;--------------------
   9232 int76_handler:
   9233   ;; record completion in BIOS task complete flag
   9234   push  ax
   9235   push  ds
   9236   mov   ax, #0x0040
   9237   mov   ds, ax
   9238   mov   0x008E, #0xff
   9239   call  eoi_both_pics
   9240   pop   ds
   9241   pop   ax
   9242   iret
   9243 
   9244 
   9245 ;--------------------
   9246 #if BX_APM
   9247 
   9248 use32 386
   9249 #define APM_PROT32
   9250 #include "apmbios.S"
   9251 
   9252 use16 386
   9253 #define APM_PROT16
   9254 #include "apmbios.S"
   9255 
   9256 #define APM_REAL
   9257 #include "apmbios.S"
   9258 
   9259 #endif
   9260 
   9261 ;--------------------
   9262 #if BX_PCIBIOS
   9263 use32 386
   9264 .align 16
   9265 bios32_structure:
   9266   db 0x5f, 0x33, 0x32, 0x5f  ;; "_32_" signature
   9267   dw bios32_entry_point, 0xf ;; 32 bit physical address
   9268   db 0             ;; revision level
   9269   ;; length in paragraphs and checksum stored in a word to prevent errors
   9270   dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
   9271         & 0xff) << 8) + 0x01
   9272   db 0,0,0,0,0     ;; reserved
   9273 
   9274 .align 16
   9275 bios32_entry_point:
   9276   pushfd
   9277   cmp eax, #0x49435024 ;; "$PCI"
   9278   jne unknown_service
   9279   mov eax, #0x80000000
   9280   mov dx, #0x0cf8
   9281   out dx, eax
   9282   mov dx, #0x0cfc
   9283   in  eax, dx
   9284 #ifdef PCI_FIXED_HOST_BRIDGE
   9285   cmp eax, #PCI_FIXED_HOST_BRIDGE
   9286   jne unknown_service
   9287 #else
   9288   ;; say ok if a device is present
   9289   cmp eax, #0xffffffff
   9290   je unknown_service
   9291 #endif
   9292   mov ebx, #0x000f0000
   9293   mov ecx, #0
   9294   mov edx, #pcibios_protected
   9295   xor al, al
   9296   jmp bios32_end
   9297 unknown_service:
   9298   mov al, #0x80
   9299 bios32_end:
   9300 #ifdef BX_QEMU
   9301   and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
   9302 #endif
   9303   popfd
   9304   retf
   9305 
   9306 .align 16
   9307 pcibios_protected:
   9308   pushfd
   9309   cli
   9310   push esi
   9311   push edi
   9312   cmp al, #0x01 ;; installation check
   9313   jne pci_pro_f02
   9314   mov bx, #0x0210
   9315   mov cx, #0
   9316   mov edx, #0x20494350 ;; "PCI "
   9317   mov al, #0x01
   9318   jmp pci_pro_ok
   9319 pci_pro_f02: ;; find pci device
   9320   cmp al, #0x02
   9321   jne pci_pro_f03
   9322   shl ecx, #16
   9323   mov cx, dx
   9324   xor bx, bx
   9325   mov di, #0x00
   9326 pci_pro_devloop:
   9327   call pci_pro_select_reg
   9328   mov dx, #0x0cfc
   9329   in  eax, dx
   9330   cmp eax, ecx
   9331   jne pci_pro_nextdev
   9332   cmp si, #0
   9333   je  pci_pro_ok
   9334   dec si
   9335 pci_pro_nextdev:
   9336   inc bx
   9337   cmp bx, #0x0100
   9338   jne pci_pro_devloop
   9339   mov ah, #0x86
   9340   jmp pci_pro_fail
   9341 pci_pro_f03: ;; find class code
   9342   cmp al, #0x03
   9343   jne pci_pro_f08
   9344   xor bx, bx
   9345   mov di, #0x08
   9346 pci_pro_devloop2:
   9347   call pci_pro_select_reg
   9348   mov dx, #0x0cfc
   9349   in  eax, dx
   9350   shr eax, #8
   9351   cmp eax, ecx
   9352   jne pci_pro_nextdev2
   9353   cmp si, #0
   9354   je  pci_pro_ok
   9355   dec si
   9356 pci_pro_nextdev2:
   9357   inc bx
   9358   cmp bx, #0x0100
   9359   jne pci_pro_devloop2
   9360   mov ah, #0x86
   9361   jmp pci_pro_fail
   9362 pci_pro_f08: ;; read configuration byte
   9363   cmp al, #0x08
   9364   jne pci_pro_f09
   9365   call pci_pro_select_reg
   9366   push edx
   9367   mov dx, di
   9368   and dx, #0x03
   9369   add dx, #0x0cfc
   9370   in  al, dx
   9371   pop edx
   9372   mov cl, al
   9373   jmp pci_pro_ok
   9374 pci_pro_f09: ;; read configuration word
   9375   cmp al, #0x09
   9376   jne pci_pro_f0a
   9377   call pci_pro_select_reg
   9378   push edx
   9379   mov dx, di
   9380   and dx, #0x02
   9381   add dx, #0x0cfc
   9382   in  ax, dx
   9383   pop edx
   9384   mov cx, ax
   9385   jmp pci_pro_ok
   9386 pci_pro_f0a: ;; read configuration dword
   9387   cmp al, #0x0a
   9388   jne pci_pro_f0b
   9389   call pci_pro_select_reg
   9390   push edx
   9391   mov dx, #0x0cfc
   9392   in  eax, dx
   9393   pop edx
   9394   mov ecx, eax
   9395   jmp pci_pro_ok
   9396 pci_pro_f0b: ;; write configuration byte
   9397   cmp al, #0x0b
   9398   jne pci_pro_f0c
   9399   call pci_pro_select_reg
   9400   push edx
   9401   mov dx, di
   9402   and dx, #0x03
   9403   add dx, #0x0cfc
   9404   mov al, cl
   9405   out dx, al
   9406   pop edx
   9407   jmp pci_pro_ok
   9408 pci_pro_f0c: ;; write configuration word
   9409   cmp al, #0x0c
   9410   jne pci_pro_f0d
   9411   call pci_pro_select_reg
   9412   push edx
   9413   mov dx, di
   9414   and dx, #0x02
   9415   add dx, #0x0cfc
   9416   mov ax, cx
   9417   out dx, ax
   9418   pop edx
   9419   jmp pci_pro_ok
   9420 pci_pro_f0d: ;; write configuration dword
   9421   cmp al, #0x0d
   9422   jne pci_pro_unknown
   9423   call pci_pro_select_reg
   9424   push edx
   9425   mov dx, #0x0cfc
   9426   mov eax, ecx
   9427   out dx, eax
   9428   pop edx
   9429   jmp pci_pro_ok
   9430 pci_pro_unknown:
   9431   mov ah, #0x81
   9432 pci_pro_fail:
   9433   pop edi
   9434   pop esi
   9435 #ifdef BX_QEMU
   9436   and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
   9437 #endif
   9438   popfd
   9439   stc
   9440   retf
   9441 pci_pro_ok:
   9442   xor ah, ah
   9443   pop edi
   9444   pop esi
   9445 #ifdef BX_QEMU
   9446   and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu
   9447 #endif
   9448   popfd
   9449   clc
   9450   retf
   9451 
   9452 pci_pro_select_reg:
   9453   push edx
   9454   mov eax, #0x800000
   9455   mov ax,  bx
   9456   shl eax, #8
   9457   and di,  #0xff
   9458   or  ax,  di
   9459   and al,  #0xfc
   9460   mov dx, #0x0cf8
   9461   out dx,  eax
   9462   pop edx
   9463   ret
   9464 
   9465 use16 386
   9466 
   9467 pcibios_real:
   9468   push eax
   9469   push dx
   9470   mov eax, #0x80000000
   9471   mov dx, #0x0cf8
   9472   out dx, eax
   9473   mov dx, #0x0cfc
   9474   in  eax, dx
   9475 #ifdef PCI_FIXED_HOST_BRIDGE
   9476   cmp eax, #PCI_FIXED_HOST_BRIDGE
   9477   je  pci_present
   9478 #else
   9479   ;; say ok if a device is present
   9480   cmp eax, #0xffffffff
   9481   jne  pci_present
   9482 #endif
   9483   pop dx
   9484   pop eax
   9485   mov ah, #0xff
   9486   stc
   9487   ret
   9488 pci_present:
   9489   pop dx
   9490   pop eax
   9491   cmp al, #0x01 ;; installation check
   9492   jne pci_real_f02
   9493   mov ax, #0x0001
   9494   mov bx, #0x0210
   9495   mov cx, #0
   9496   mov edx, #0x20494350 ;; "PCI "
   9497   mov edi, #0xf0000
   9498   mov di, #pcibios_protected
   9499   clc
   9500   ret
   9501 pci_real_f02: ;; find pci device
   9502   push esi
   9503   push edi
   9504   cmp al, #0x02
   9505   jne pci_real_f03
   9506   shl ecx, #16
   9507   mov cx, dx
   9508   xor bx, bx
   9509   mov di, #0x00
   9510 pci_real_devloop:
   9511   call pci_real_select_reg
   9512   mov dx, #0x0cfc
   9513   in  eax, dx
   9514   cmp eax, ecx
   9515   jne pci_real_nextdev
   9516   cmp si, #0
   9517   je  pci_real_ok
   9518   dec si
   9519 pci_real_nextdev:
   9520   inc bx
   9521   cmp bx, #0x0100
   9522   jne pci_real_devloop
   9523   mov dx, cx
   9524   shr ecx, #16
   9525   mov ax, #0x8602
   9526   jmp pci_real_fail
   9527 pci_real_f03: ;; find class code
   9528   cmp al, #0x03
   9529   jne pci_real_f08
   9530   xor bx, bx
   9531   mov di, #0x08
   9532 pci_real_devloop2:
   9533   call pci_real_select_reg
   9534   mov dx, #0x0cfc
   9535   in  eax, dx
   9536   shr eax, #8
   9537   cmp eax, ecx
   9538   jne pci_real_nextdev2
   9539   cmp si, #0
   9540   je  pci_real_ok
   9541   dec si
   9542 pci_real_nextdev2:
   9543   inc bx
   9544   cmp bx, #0x0100
   9545   jne pci_real_devloop2
   9546   mov dx, cx
   9547   shr ecx, #16
   9548   mov ax, #0x8603
   9549   jmp pci_real_fail
   9550 pci_real_f08: ;; read configuration byte
   9551   cmp al, #0x08
   9552   jne pci_real_f09
   9553   call pci_real_select_reg
   9554   push dx
   9555   mov dx, di
   9556   and dx, #0x03
   9557   add dx, #0x0cfc
   9558   in  al, dx
   9559   pop dx
   9560   mov cl, al
   9561   jmp pci_real_ok
   9562 pci_real_f09: ;; read configuration word
   9563   cmp al, #0x09
   9564   jne pci_real_f0a
   9565   call pci_real_select_reg
   9566   push dx
   9567   mov dx, di
   9568   and dx, #0x02
   9569   add dx, #0x0cfc
   9570   in  ax, dx
   9571   pop dx
   9572   mov cx, ax
   9573   jmp pci_real_ok
   9574 pci_real_f0a: ;; read configuration dword
   9575   cmp al, #0x0a
   9576   jne pci_real_f0b
   9577   call pci_real_select_reg
   9578   push dx
   9579   mov dx, #0x0cfc
   9580   in  eax, dx
   9581   pop dx
   9582   mov ecx, eax
   9583   jmp pci_real_ok
   9584 pci_real_f0b: ;; write configuration byte
   9585   cmp al, #0x0b
   9586   jne pci_real_f0c
   9587   call pci_real_select_reg
   9588   push dx
   9589   mov dx, di
   9590   and dx, #0x03
   9591   add dx, #0x0cfc
   9592   mov al, cl
   9593   out dx, al
   9594   pop dx
   9595   jmp pci_real_ok
   9596 pci_real_f0c: ;; write configuration word
   9597   cmp al, #0x0c
   9598   jne pci_real_f0d
   9599   call pci_real_select_reg
   9600   push dx
   9601   mov dx, di
   9602   and dx, #0x02
   9603   add dx, #0x0cfc
   9604   mov ax, cx
   9605   out dx, ax
   9606   pop dx
   9607   jmp pci_real_ok
   9608 pci_real_f0d: ;; write configuration dword
   9609   cmp al, #0x0d
   9610   jne pci_real_f0e
   9611   call pci_real_select_reg
   9612   push dx
   9613   mov dx, #0x0cfc
   9614   mov eax, ecx
   9615   out dx, eax
   9616   pop dx
   9617   jmp pci_real_ok
   9618 pci_real_f0e: ;; get irq routing options
   9619   cmp al, #0x0e
   9620   jne pci_real_unknown
   9621   SEG ES
   9622   cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
   9623   jb pci_real_too_small
   9624   SEG ES
   9625   mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
   9626   pushf
   9627   push ds
   9628   push es
   9629   push cx
   9630   push si
   9631   push di
   9632   cld
   9633   mov si, #pci_routing_table_structure_start
   9634   push cs
   9635   pop ds
   9636   SEG ES
   9637   mov cx, [di+2]
   9638   SEG ES
   9639   mov es, [di+4]
   9640   mov di, cx
   9641   mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start
   9642   rep
   9643       movsb
   9644   pop di
   9645   pop si
   9646   pop cx
   9647   pop es
   9648   pop ds
   9649   popf
   9650   mov bx, #(1 << 9) | (1 << 11)   ;; irq 9 and 11 are used
   9651   jmp pci_real_ok
   9652 pci_real_too_small:
   9653   SEG ES
   9654   mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start
   9655   mov ah, #0x89
   9656   jmp pci_real_fail
   9657 
   9658 pci_real_unknown:
   9659   mov ah, #0x81
   9660 pci_real_fail:
   9661   pop edi
   9662   pop esi
   9663   stc
   9664   ret
   9665 pci_real_ok:
   9666   xor ah, ah
   9667   pop edi
   9668   pop esi
   9669   clc
   9670   ret
   9671 
   9672 pci_real_select_reg:
   9673   push dx
   9674   mov eax, #0x800000
   9675   mov ax,  bx
   9676   shl eax, #8
   9677   and di,  #0xff
   9678   or  ax,  di
   9679   and al,  #0xfc
   9680   mov dx,  #0x0cf8
   9681   out dx,  eax
   9682   pop dx
   9683   ret
   9684 
   9685 .align 16
   9686 pci_routing_table_structure:
   9687   db 0x24, 0x50, 0x49, 0x52  ;; "$PIR" signature
   9688   db 0, 1 ;; version
   9689   dw 32 + (6 * 16) ;; table size
   9690   db 0 ;; PCI interrupt router bus
   9691   db 0x08 ;; PCI interrupt router DevFunc
   9692   dw 0x0000 ;; PCI exclusive IRQs
   9693   dw 0x8086 ;; compatible PCI interrupt router vendor ID
   9694   dw 0x122e ;; compatible PCI interrupt router device ID
   9695   dw 0,0 ;; Miniport data
   9696   db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
   9697   db 0x37 ;; checksum
   9698 pci_routing_table_structure_start:
   9699   ;; first slot entry PCI-to-ISA (embedded)
   9700   db 0 ;; pci bus number
   9701   db 0x08 ;; pci device number (bit 7-3)
   9702   db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
   9703   dw 0xdef8 ;; IRQ bitmap INTA#
   9704   db 0x61 ;; link value INTB#
   9705   dw 0xdef8 ;; IRQ bitmap INTB#
   9706   db 0x62 ;; link value INTC#
   9707   dw 0xdef8 ;; IRQ bitmap INTC#
   9708   db 0x63 ;; link value INTD#
   9709   dw 0xdef8 ;; IRQ bitmap INTD#
   9710   db 0 ;; physical slot (0 = embedded)
   9711   db 0 ;; reserved
   9712   ;; second slot entry: 1st PCI slot
   9713   db 0 ;; pci bus number
   9714   db 0x10 ;; pci device number (bit 7-3)
   9715   db 0x61 ;; link value INTA#
   9716   dw 0xdef8 ;; IRQ bitmap INTA#
   9717   db 0x62 ;; link value INTB#
   9718   dw 0xdef8 ;; IRQ bitmap INTB#
   9719   db 0x63 ;; link value INTC#
   9720   dw 0xdef8 ;; IRQ bitmap INTC#
   9721   db 0x60 ;; link value INTD#
   9722   dw 0xdef8 ;; IRQ bitmap INTD#
   9723   db 1 ;; physical slot (0 = embedded)
   9724   db 0 ;; reserved
   9725   ;; third slot entry: 2nd PCI slot
   9726   db 0 ;; pci bus number
   9727   db 0x18 ;; pci device number (bit 7-3)
   9728   db 0x62 ;; link value INTA#
   9729   dw 0xdef8 ;; IRQ bitmap INTA#
   9730   db 0x63 ;; link value INTB#
   9731   dw 0xdef8 ;; IRQ bitmap INTB#
   9732   db 0x60 ;; link value INTC#
   9733   dw 0xdef8 ;; IRQ bitmap INTC#
   9734   db 0x61 ;; link value INTD#
   9735   dw 0xdef8 ;; IRQ bitmap INTD#
   9736   db 2 ;; physical slot (0 = embedded)
   9737   db 0 ;; reserved
   9738   ;; 4th slot entry: 3rd PCI slot
   9739   db 0 ;; pci bus number
   9740   db 0x20 ;; pci device number (bit 7-3)
   9741   db 0x63 ;; link value INTA#
   9742   dw 0xdef8 ;; IRQ bitmap INTA#
   9743   db 0x60 ;; link value INTB#
   9744   dw 0xdef8 ;; IRQ bitmap INTB#
   9745   db 0x61 ;; link value INTC#
   9746   dw 0xdef8 ;; IRQ bitmap INTC#
   9747   db 0x62 ;; link value INTD#
   9748   dw 0xdef8 ;; IRQ bitmap INTD#
   9749   db 3 ;; physical slot (0 = embedded)
   9750   db 0 ;; reserved
   9751   ;; 5th slot entry: 4rd PCI slot
   9752   db 0 ;; pci bus number
   9753   db 0x28 ;; pci device number (bit 7-3)
   9754   db 0x60 ;; link value INTA#
   9755   dw 0xdef8 ;; IRQ bitmap INTA#
   9756   db 0x61 ;; link value INTB#
   9757   dw 0xdef8 ;; IRQ bitmap INTB#
   9758   db 0x62 ;; link value INTC#
   9759   dw 0xdef8 ;; IRQ bitmap INTC#
   9760   db 0x63 ;; link value INTD#
   9761   dw 0xdef8 ;; IRQ bitmap INTD#
   9762   db 4 ;; physical slot (0 = embedded)
   9763   db 0 ;; reserved
   9764   ;; 6th slot entry: 5rd PCI slot
   9765   db 0 ;; pci bus number
   9766   db 0x30 ;; pci device number (bit 7-3)
   9767   db 0x61 ;; link value INTA#
   9768   dw 0xdef8 ;; IRQ bitmap INTA#
   9769   db 0x62 ;; link value INTB#
   9770   dw 0xdef8 ;; IRQ bitmap INTB#
   9771   db 0x63 ;; link value INTC#
   9772   dw 0xdef8 ;; IRQ bitmap INTC#
   9773   db 0x60 ;; link value INTD#
   9774   dw 0xdef8 ;; IRQ bitmap INTD#
   9775   db 5 ;; physical slot (0 = embedded)
   9776   db 0 ;; reserved
   9777 pci_routing_table_structure_end:
   9778 
   9779 #if !BX_ROMBIOS32
   9780 pci_irq_list:
   9781   db 11, 10, 9, 5;
   9782 
   9783 pcibios_init_sel_reg:
   9784   push eax
   9785   mov eax, #0x800000
   9786   mov ax,  bx
   9787   shl eax, #8
   9788   and dl,  #0xfc
   9789   or  al,  dl
   9790   mov dx,  #0x0cf8
   9791   out dx,  eax
   9792   pop eax
   9793   ret
   9794 
   9795 pcibios_init_iomem_bases:
   9796   push bp
   9797   mov  bp, sp
   9798   mov  eax, #0xe0000000 ;; base for memory init
   9799   push eax
   9800   mov  ax, #0xc000 ;; base for i/o init
   9801   push ax
   9802   mov  ax, #0x0010 ;; start at base address #0
   9803   push ax
   9804   mov  bx, #0x0008
   9805 pci_init_io_loop1:
   9806   mov  dl, #0x00
   9807   call pcibios_init_sel_reg
   9808   mov  dx, #0x0cfc
   9809   in   ax, dx
   9810   cmp  ax, #0xffff
   9811   jz   next_pci_dev
   9812   mov  dl, #0x04 ;; disable i/o and memory space access
   9813   call pcibios_init_sel_reg
   9814   mov  dx, #0x0cfc
   9815   in   al, dx
   9816   and  al, #0xfc
   9817   out  dx, al
   9818 pci_init_io_loop2:
   9819   mov  dl, [bp-8]
   9820   call pcibios_init_sel_reg
   9821   mov  dx, #0x0cfc
   9822   in   eax, dx
   9823   test al, #0x01
   9824   jnz  init_io_base
   9825   mov  ecx, eax
   9826   mov  eax, #0xffffffff
   9827   out  dx, eax
   9828   in   eax, dx
   9829   cmp  eax, ecx
   9830   je   next_pci_base
   9831   xor  eax, #0xffffffff
   9832   mov  ecx, eax
   9833   mov  eax, [bp-4]
   9834   out  dx, eax
   9835   add  eax, ecx ;; calculate next free mem base
   9836   add  eax, #0x01000000
   9837   and  eax, #0xff000000
   9838   mov  [bp-4], eax
   9839   jmp  next_pci_base
   9840 init_io_base:
   9841   mov  cx, ax
   9842   mov  ax, #0xffff
   9843   out  dx, ax
   9844   in   ax, dx
   9845   cmp  ax, cx
   9846   je   next_pci_base
   9847   xor  ax, #0xfffe
   9848   mov  cx, ax
   9849   mov  ax, [bp-6]
   9850   out  dx, ax
   9851   add  ax, cx ;; calculate next free i/o base
   9852   add  ax, #0x0100
   9853   and  ax, #0xff00
   9854   mov  [bp-6], ax
   9855 next_pci_base:
   9856   mov  al, [bp-8]
   9857   add  al, #0x04
   9858   cmp  al, #0x28
   9859   je   enable_iomem_space
   9860   mov  byte ptr[bp-8], al
   9861   jmp  pci_init_io_loop2
   9862 enable_iomem_space:
   9863   mov  dl, #0x04 ;; enable i/o and memory space access if available
   9864   call pcibios_init_sel_reg
   9865   mov  dx, #0x0cfc
   9866   in   al, dx
   9867   or   al, #0x07
   9868   out  dx, al
   9869 next_pci_dev:
   9870   mov  byte ptr[bp-8], #0x10
   9871   inc  bx
   9872   cmp  bx, #0x0100
   9873   jne  pci_init_io_loop1
   9874   mov  sp, bp
   9875   pop  bp
   9876   ret
   9877 
   9878 pcibios_init_set_elcr:
   9879   push ax
   9880   push cx
   9881   mov  dx, #0x04d0
   9882   test al, #0x08
   9883   jz   is_master_pic
   9884   inc  dx
   9885   and  al, #0x07
   9886 is_master_pic:
   9887   mov  cl, al
   9888   mov  bl, #0x01
   9889   shl  bl, cl
   9890   in   al, dx
   9891   or   al, bl
   9892   out  dx, al
   9893   pop  cx
   9894   pop  ax
   9895   ret
   9896 
   9897 pcibios_init_irqs:
   9898   push ds
   9899   push bp
   9900   mov  ax, #0xf000
   9901   mov  ds, ax
   9902   mov  dx, #0x04d0 ;; reset ELCR1 + ELCR2
   9903   mov  al, #0x00
   9904   out  dx, al
   9905   inc  dx
   9906   out  dx, al
   9907   mov  si, #pci_routing_table_structure
   9908   mov  bh, [si+8]
   9909   mov  bl, [si+9]
   9910   mov  dl, #0x00
   9911   call pcibios_init_sel_reg
   9912   mov  dx, #0x0cfc
   9913   in   ax, dx
   9914   cmp  ax, [si+12] ;; check irq router
   9915   jne  pci_init_end
   9916   mov  dl, [si+34]
   9917   call pcibios_init_sel_reg
   9918   push bx ;; save irq router bus + devfunc
   9919   mov  dx, #0x0cfc
   9920   mov  ax, #0x8080
   9921   out  dx, ax ;; reset PIRQ route control
   9922   add  dx, #2
   9923   out  dx, ax
   9924   mov  ax, [si+6]
   9925   sub  ax, #0x20
   9926   shr  ax, #4
   9927   mov  cx, ax
   9928   add  si, #0x20 ;; set pointer to 1st entry
   9929   mov  bp, sp
   9930   mov  ax, #pci_irq_list
   9931   push ax
   9932   xor  ax, ax
   9933   push ax
   9934 pci_init_irq_loop1:
   9935   mov  bh, [si]
   9936   mov  bl, [si+1]
   9937 pci_init_irq_loop2:
   9938   mov  dl, #0x00
   9939   call pcibios_init_sel_reg
   9940   mov  dx, #0x0cfc
   9941   in   ax, dx
   9942   cmp  ax, #0xffff
   9943   jnz  pci_test_int_pin
   9944   test bl, #0x07
   9945   jz   next_pir_entry
   9946   jmp  next_pci_func
   9947 pci_test_int_pin:
   9948   mov  dl, #0x3c
   9949   call pcibios_init_sel_reg
   9950   mov  dx, #0x0cfd
   9951   in   al, dx
   9952   and  al, #0x07
   9953   jz   next_pci_func
   9954   dec  al ;; determine pirq reg
   9955   mov  dl, #0x03
   9956   mul  al, dl
   9957   add  al, #0x02
   9958   xor  ah, ah
   9959   mov  bx, ax
   9960   mov  al, [si+bx]
   9961   mov  dl, al
   9962   mov  bx, [bp]
   9963   call pcibios_init_sel_reg
   9964   mov  dx, #0x0cfc
   9965   and  al, #0x03
   9966   add  dl, al
   9967   in   al, dx
   9968   cmp  al, #0x80
   9969   jb   pirq_found
   9970   mov  bx, [bp-2] ;; pci irq list pointer
   9971   mov  al, [bx]
   9972   out  dx, al
   9973   inc  bx
   9974   mov  [bp-2], bx
   9975   call pcibios_init_set_elcr
   9976 pirq_found:
   9977   mov  bh, [si]
   9978   mov  bl, [si+1]
   9979   add  bl, [bp-3] ;; pci function number
   9980   mov  dl, #0x3c
   9981   call pcibios_init_sel_reg
   9982   mov  dx, #0x0cfc
   9983   out  dx, al
   9984 next_pci_func:
   9985   inc  byte ptr[bp-3]
   9986   inc  bl
   9987   test bl, #0x07
   9988   jnz  pci_init_irq_loop2
   9989 next_pir_entry:
   9990   add  si, #0x10
   9991   mov  byte ptr[bp-3], #0x00
   9992   loop pci_init_irq_loop1
   9993   mov  sp, bp
   9994   pop  bx
   9995 pci_init_end:
   9996   pop  bp
   9997   pop  ds
   9998   ret
   9999 #endif // !BX_ROMBIOS32
   10000 #endif // BX_PCIBIOS
   10001 
   10002 #if BX_ROMBIOS32
   10003 rombios32_init:
   10004   ;; save a20 and enable it
   10005   in al, 0x92
   10006   push ax
   10007   or al, #0x02
   10008   out 0x92, al
   10009 
   10010   ;; save SS:SP to the BDA
   10011   xor ax, ax
   10012   mov ds, ax
   10013   mov 0x0469, ss
   10014   mov 0x0467, sp
   10015 
   10016   SEG CS
   10017     lidt [pmode_IDT_info]
   10018   SEG CS
   10019     lgdt [rombios32_gdt_48]
   10020   ;; set PE bit in CR0
   10021   mov  eax, cr0
   10022   or   al, #0x01
   10023   mov  cr0, eax
   10024   ;; start protected mode code: ljmpl 0x10:rombios32_init1
   10025   db 0x66, 0xea
   10026   dw rombios32_05
   10027   dw 0x000f       ;; high 16 bit address
   10028   dw 0x0010
   10029 
   10030 use32 386
   10031 rombios32_05:
   10032   ;; init data segments
   10033   mov eax, #0x18
   10034   mov ds, ax
   10035   mov es, ax
   10036   mov ss, ax
   10037   xor eax, eax
   10038   mov fs, ax
   10039   mov gs, ax
   10040   cld
   10041 
   10042   ;; init the stack pointer to point below EBDA
   10043   mov ax, [0x040e]
   10044   shl eax, #4
   10045   mov esp, #-0x10
   10046   add esp, eax
   10047 
   10048   ;; pass pointer to s3_resume_flag and s3_resume_vector to rombios32
   10049   push #0x04b0
   10050   push #0x04b2
   10051 
   10052   ;; call rombios32 code
   10053   mov eax, #0x000e0000
   10054   call eax
   10055 
   10056   ;; return to 16 bit protected mode first
   10057   db 0xea
   10058   dd rombios32_10
   10059   dw 0x20
   10060 
   10061 use16 386
   10062 rombios32_10:
   10063   ;; restore data segment limits to 0xffff
   10064   mov ax, #0x28
   10065   mov ds, ax
   10066   mov es, ax
   10067   mov ss, ax
   10068   mov fs, ax
   10069   mov gs, ax
   10070 
   10071   ;; reset PE bit in CR0
   10072   mov  eax, cr0
   10073   and  al, #0xFE
   10074   mov  cr0, eax
   10075 
   10076   ;; far jump to flush CPU queue after transition to real mode
   10077   JMP_AP(0xf000, rombios32_real_mode)
   10078 
   10079 rombios32_real_mode:
   10080   ;; restore IDT to normal real-mode defaults
   10081   SEG CS
   10082     lidt [rmode_IDT_info]
   10083 
   10084   xor ax, ax
   10085   mov ds, ax
   10086   mov es, ax
   10087   mov fs, ax
   10088   mov gs, ax
   10089 
   10090   ;; restore SS:SP from the BDA
   10091   mov ss, 0x0469
   10092   xor esp, esp
   10093   mov sp, 0x0467
   10094   ;; restore a20
   10095   pop ax
   10096   out 0x92, al
   10097   ret
   10098 
   10099 rombios32_gdt_48:
   10100   dw 0x30
   10101   dw rombios32_gdt
   10102   dw 0x000f
   10103 
   10104 rombios32_gdt:
   10105   dw 0, 0, 0, 0
   10106   dw 0, 0, 0, 0
   10107   dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10)
   10108   dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18)
   10109   dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff
   10110   dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff
   10111 #endif // BX_ROMBIOS32
   10112 
   10113 
   10114 ; parallel port detection: base address in DX, index in BX, timeout in CL
   10115 detect_parport:
   10116   push dx
   10117   add  dx, #2
   10118   in   al, dx
   10119   and  al, #0xdf ; clear input mode
   10120   out  dx, al
   10121   pop  dx
   10122   mov  al, #0xaa
   10123   out  dx, al
   10124   in   al, dx
   10125   cmp  al, #0xaa
   10126   jne  no_parport
   10127   push bx
   10128   shl  bx, #1
   10129   mov  [bx+0x408], dx ; Parallel I/O address
   10130   pop  bx
   10131   mov  [bx+0x478], cl ; Parallel printer timeout
   10132   inc  bx
   10133 no_parport:
   10134   ret
   10135 
   10136 ; serial port detection: base address in DX, index in BX, timeout in CL
   10137 detect_serial:
   10138   push dx
   10139   inc  dx
   10140   mov  al, #0x02
   10141   out  dx, al
   10142   in   al, dx
   10143   cmp  al, #0x02
   10144   jne  no_serial
   10145   inc  dx
   10146   in   al, dx
   10147   cmp  al, #0x02
   10148   jne  no_serial
   10149   dec  dx
   10150   xor  al, al
   10151   out  dx, al
   10152   pop  dx
   10153   push bx
   10154   shl  bx, #1
   10155   mov  [bx+0x400], dx ; Serial I/O address
   10156   pop  bx
   10157   mov  [bx+0x47c], cl ; Serial timeout
   10158   inc  bx
   10159   ret
   10160 no_serial:
   10161   pop  dx
   10162   ret
   10163 
   10164 rom_checksum:
   10165   push ax
   10166   push bx
   10167   push cx
   10168   xor  ax, ax
   10169   xor  bx, bx
   10170   xor  cx, cx
   10171   mov  ch, [2]
   10172   shl  cx, #1
   10173 checksum_loop:
   10174   add  al, [bx]
   10175   inc  bx
   10176   loop checksum_loop
   10177   and  al, #0xff
   10178   pop  cx
   10179   pop  bx
   10180   pop  ax
   10181   ret
   10182 
   10183 
   10184 ;; We need a copy of this string, but we are not actually a PnP BIOS,
   10185 ;; so make sure it is *not* aligned, so OSes will not see it if they scan.
   10186 .align 16
   10187   db 0
   10188 pnp_string:
   10189   .ascii "$PnP"
   10190 
   10191 
   10192 rom_scan:
   10193   ;; Scan for existence of valid expansion ROMS.
   10194   ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
   10195   ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
   10196   ;;   System  ROM: only 0xE0000
   10197   ;;
   10198   ;; Header:
   10199   ;;   Offset    Value
   10200   ;;   0         0x55
   10201   ;;   1         0xAA
   10202   ;;   2         ROM length in 512-byte blocks
   10203   ;;   3         ROM initialization entry point (FAR CALL)
   10204 
   10205 rom_scan_loop:
   10206   push ax       ;; Save AX
   10207   mov  ds, cx
   10208   mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
   10209   cmp [0], #0xAA55 ;; look for signature
   10210   jne  rom_scan_increment
   10211   call rom_checksum
   10212   jnz  rom_scan_increment
   10213   mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
   10214 
   10215   ;; We want our increment in 512-byte quantities, rounded to
   10216   ;; the nearest 2k quantity, since we only scan at 2k intervals.
   10217   test al, #0x03
   10218   jz   block_count_rounded
   10219   and  al, #0xfc ;; needs rounding up
   10220   add  al, #0x04
   10221 block_count_rounded:
   10222 
   10223   xor  bx, bx   ;; Restore DS back to 0000:
   10224   mov  ds, bx
   10225   push ax       ;; Save AX
   10226   push di       ;; Save DI
   10227   ;; Push addr of ROM entry point
   10228   push cx       ;; Push seg
   10229   push #0x0003  ;; Push offset
   10230 
   10231   ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
   10232   ;; That should stop it grabbing INT 19h; we will use its BEV instead.
   10233   mov  ax, #0xf000
   10234   mov  es, ax
   10235   lea  di, pnp_string
   10236 
   10237   mov  bp, sp   ;; Call ROM init routine using seg:off on stack
   10238   db   0xff     ;; call_far ss:[bp+0]
   10239   db   0x5e
   10240   db   0
   10241   cli           ;; In case expansion ROM BIOS turns IF on
   10242   add  sp, #2   ;; Pop offset value
   10243   pop  cx       ;; Pop seg value (restore CX)
   10244 
   10245   ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
   10246   ;; to init all the ROMs and then go back and build an IPL table of
   10247   ;; all the bootable devices, but we can get away with one pass.
   10248   mov  ds, cx       ;; ROM base
   10249   mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
   10250   mov  ax, [bx]     ;; the offset of PnP expansion header, where...
   10251   cmp  ax, #0x5024  ;; we look for signature "$PnP"
   10252   jne  no_bev
   10253   mov  ax, 2[bx]
   10254   cmp  ax, #0x506e
   10255   jne  no_bev
   10256 
   10257   mov  ax, 0x16[bx] ;; 0x16 is the offset of Boot Connection Vector
   10258   cmp  ax, #0x0000
   10259   je   no_bcv
   10260 
   10261   ;; Option ROM has BCV. Run it now.
   10262   push cx       ;; Push seg
   10263   push ax       ;; Push offset
   10264 
   10265   ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
   10266   mov  bx, #0xf000
   10267   mov  es, bx
   10268   lea  di, pnp_string
   10269   /* jump to BCV function entry pointer */
   10270   mov  bp, sp   ;; Call ROM BCV routine using seg:off on stack
   10271   db   0xff     ;; call_far ss:[bp+0]
   10272   db   0x5e
   10273   db   0
   10274   cli           ;; In case expansion ROM BIOS turns IF on
   10275   add  sp, #2   ;; Pop offset value
   10276   pop  cx       ;; Pop seg value (restore CX)
   10277   jmp   no_bev
   10278 
   10279 no_bcv:
   10280   mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
   10281   cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
   10282   je   no_bev
   10283 
   10284   ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
   10285   mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
   10286   mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
   10287   mov  ds, bx
   10288   mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
   10289   cmp  bx, #IPL_TABLE_ENTRIES
   10290   je   no_bev                  ;; Get out if the table is full
   10291   shl  bx, #0x4                ;; Turn count into offset (entries are 16 bytes)
   10292   mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
   10293   mov  6[bx], cx               ;; Build a far pointer from the segment...
   10294   mov  4[bx], ax               ;; and the offset
   10295   cmp  di, #0x0000
   10296   je   no_prod_str
   10297   mov  0xA[bx], cx             ;; Build a far pointer from the segment...
   10298   mov  8[bx], di               ;; and the offset
   10299 no_prod_str:
   10300   shr  bx, #0x4                ;; Turn the offset back into a count
   10301   inc  bx                      ;; We have one more entry now
   10302   mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
   10303 
   10304 no_bev:
   10305   pop  di       ;; Restore DI
   10306   pop  ax       ;; Restore AX
   10307 rom_scan_increment:
   10308   shl  ax, #5   ;; convert 512-bytes blocks to 16-byte increments
   10309                 ;; because the segment selector is shifted left 4 bits.
   10310   add  cx, ax
   10311   pop  ax       ;; Restore AX
   10312   cmp  cx, ax
   10313   jbe  rom_scan_loop
   10314 
   10315   xor  ax, ax   ;; Restore DS back to 0000:
   10316   mov  ds, ax
   10317   ret
   10318 
   10319 post_init_pic:
   10320   mov al, #0x11 ; send initialisation commands
   10321   out 0x20, al
   10322   out 0xa0, al
   10323   mov al, #0x08
   10324   out 0x21, al
   10325   mov al, #0x70
   10326   out 0xa1, al
   10327   mov al, #0x04
   10328   out 0x21, al
   10329   mov al, #0x02
   10330   out 0xa1, al
   10331   mov al, #0x01
   10332   out 0x21, al
   10333   out 0xa1, al
   10334   mov  al, #0xb8
   10335   out  0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
   10336 #if BX_USE_PS2_MOUSE
   10337   mov  al, #0x8f
   10338 #else
   10339   mov  al, #0x9f
   10340 #endif
   10341   out  0xa1, AL ;slave  pic: unmask IRQ 12, 13, 14
   10342   ret
   10343 
   10344 ;; the following area can be used to write dynamically generated tables
   10345   .align 16
   10346 bios_table_area_start:
   10347   dd 0xaafb4442
   10348   dd bios_table_area_end - bios_table_area_start - 8;
   10349 
   10350 ;--------
   10351 ;- POST -
   10352 ;--------
   10353 .org 0xe05b ; POST Entry Point
   10354 post:
   10355 
   10356   xor ax, ax
   10357 
   10358   ;; first reset the DMA controllers
   10359   out 0x0d,al
   10360   out 0xda,al
   10361 
   10362   ;; then initialize the DMA controllers
   10363   mov al, #0xC0
   10364   out 0xD6, al ; cascade mode of channel 4 enabled
   10365   mov al, #0x00
   10366   out 0xD4, al ; unmask channel 4
   10367 
   10368   ;; Examine CMOS shutdown status.
   10369   mov AL, #0x0f
   10370   out 0x70, AL
   10371   in  AL, 0x71
   10372 
   10373   ;; backup status
   10374   mov bl, al
   10375 
   10376   ;; Reset CMOS shutdown status.
   10377   mov AL, #0x0f
   10378   out 0x70, AL          ; select CMOS register Fh
   10379   mov AL, #0x00
   10380   out 0x71, AL          ; set shutdown action to normal
   10381 
   10382   ;; Examine CMOS shutdown status.
   10383   mov al, bl
   10384 
   10385   ;; 0x00, 0x09, 0x0D+ = normal startup
   10386   cmp AL, #0x00
   10387   jz normal_post
   10388   cmp AL, #0x0d
   10389   jae normal_post
   10390   cmp AL, #0x09
   10391   je normal_post
   10392 
   10393   ;; 0x05 = eoi + jmp via [0x40:0x67] jump
   10394   cmp al, #0x05
   10395   je  eoi_jmp_post
   10396 
   10397   ;; 0x0A = jmp via [0x40:0x67] jump
   10398   cmp al, #0x0a
   10399   je  jmp_post_0x467
   10400 
   10401   ;; 0x0B = iret via [0x40:0x67]
   10402   cmp al, #0x0b
   10403   je  iret_post_0x467
   10404 
   10405   ;; 0x0C = retf via [0x40:0x67]
   10406   cmp al, #0x0c
   10407   je  retf_post_0x467
   10408 
   10409   ;; Examine CMOS shutdown status.
   10410   ;;  0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status.
   10411   push bx
   10412   call _shutdown_status_panic
   10413 
   10414 #if 0
   10415   HALT(__LINE__)
   10416   ;
   10417   ;#if 0
   10418   ;  0xb0, 0x20,       /* mov al, #0x20 */
   10419   ;  0xe6, 0x20,       /* out 0x20, al    ;send EOI to PIC */
   10420   ;#endif
   10421   ;
   10422   pop es
   10423   pop ds
   10424   popa
   10425   iret
   10426 #endif
   10427 
   10428 normal_post:
   10429   ; case 0: normal startup
   10430 
   10431   cli
   10432   mov  ax, #0xfffe
   10433   mov  sp, ax
   10434   xor  ax, ax
   10435   mov  ds, ax
   10436   mov  ss, ax
   10437 
   10438   ;; Save shutdown status
   10439   mov 0x04b0, bl
   10440 
   10441   cmp bl, #0xfe
   10442   jz s3_post
   10443 
   10444   ;; zero out BIOS data area (40:00..40:ff)
   10445   mov  es, ax
   10446   mov  cx, #0x0080 ;; 128 words
   10447   mov  di, #0x0400
   10448   cld
   10449   rep
   10450     stosw
   10451 
   10452   call _log_bios_start
   10453 
   10454   ;; set all interrupts to default handler
   10455   xor  bx, bx         ;; offset index
   10456   mov  cx, #0x0100    ;; counter (256 interrupts)
   10457   mov  ax, #dummy_iret_handler
   10458   mov  dx, #0xF000
   10459 
   10460 post_default_ints:
   10461   mov  [bx], ax
   10462   add  bx, #2
   10463   mov  [bx], dx
   10464   add  bx, #2
   10465   loop post_default_ints
   10466 
   10467   ;; set vector 0x79 to zero
   10468   ;; this is used by 'gardian angel' protection system
   10469   SET_INT_VECTOR(0x79, #0, #0)
   10470 
   10471   ;; base memory in K 40:13 (word)
   10472   mov  ax, #BASE_MEM_IN_K
   10473   mov  0x0413, ax
   10474 
   10475 
   10476   ;; Manufacturing Test 40:12
   10477   ;;   zerod out above
   10478 
   10479   ;; Warm Boot Flag 0040:0072
   10480   ;;   value of 1234h = skip memory checks
   10481   ;;   zerod out above
   10482 
   10483 
   10484   ;; Printer Services vector
   10485   SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
   10486 
   10487   ;; Bootstrap failure vector
   10488   SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
   10489 
   10490   ;; Bootstrap Loader vector
   10491   SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
   10492 
   10493   ;; User Timer Tick vector
   10494   SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
   10495 
   10496   ;; Memory Size Check vector
   10497   SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
   10498 
   10499   ;; Equipment Configuration Check vector
   10500   SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
   10501 
   10502   ;; System Services
   10503   SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
   10504 
   10505   ;; EBDA setup
   10506   call ebda_post
   10507 
   10508   ;; PIT setup
   10509   SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
   10510   ;; int 1C already points at dummy_iret_handler (above)
   10511   mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
   10512   out 0x43, al
   10513   mov al, #0x00 ; maximum count of 0000H = 18.2Hz
   10514   out 0x40, al
   10515   out 0x40, al
   10516 
   10517   ;; Keyboard
   10518   SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
   10519   SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
   10520 
   10521   xor  ax, ax
   10522   mov  ds, ax
   10523   mov  0x0417, al /* keyboard shift flags, set 1 */
   10524   mov  0x0418, al /* keyboard shift flags, set 2 */
   10525   mov  0x0419, al /* keyboard alt-numpad work area */
   10526   mov  0x0471, al /* keyboard ctrl-break flag */
   10527   mov  0x0497, al /* keyboard status flags 4 */
   10528   mov  al, #0x10
   10529   mov  0x0496, al /* keyboard status flags 3 */
   10530 
   10531 
   10532   /* keyboard head of buffer pointer */
   10533   mov  bx, #0x001E
   10534   mov  0x041A, bx
   10535 
   10536   /* keyboard end of buffer pointer */
   10537   mov  0x041C, bx
   10538 
   10539   /* keyboard pointer to start of buffer */
   10540   mov  bx, #0x001E
   10541   mov  0x0480, bx
   10542 
   10543   /* keyboard pointer to end of buffer */
   10544   mov  bx, #0x003E
   10545   mov  0x0482, bx
   10546 
   10547   /* init the keyboard */
   10548   call _keyboard_init
   10549 
   10550   ;; mov CMOS Equipment Byte to BDA Equipment Word
   10551   mov  ax, 0x0410
   10552   mov  al, #0x14
   10553   out  0x70, al
   10554   in   al, 0x71
   10555   mov  0x0410, ax
   10556 
   10557 
   10558   ;; Parallel setup
   10559   SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
   10560   xor ax, ax
   10561   mov ds, ax
   10562   xor bx, bx
   10563   mov cl, #0x14 ; timeout value
   10564   mov dx, #0x378 ; Parallel I/O address, port 1
   10565   call detect_parport
   10566   mov dx, #0x278 ; Parallel I/O address, port 2
   10567   call detect_parport
   10568   shl bx, #0x0e
   10569   mov ax, 0x410   ; Equipment word bits 14..15 determing # parallel ports
   10570   and ax, #0x3fff
   10571   or  ax, bx ; set number of parallel ports
   10572   mov 0x410, ax
   10573 
   10574   ;; Serial setup
   10575   SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
   10576   SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
   10577   xor bx, bx
   10578   mov cl, #0x0a ; timeout value
   10579   mov dx, #0x03f8 ; Serial I/O address, port 1
   10580   call detect_serial
   10581   mov dx, #0x02f8 ; Serial I/O address, port 2
   10582   call detect_serial
   10583   mov dx, #0x03e8 ; Serial I/O address, port 3
   10584   call detect_serial
   10585   mov dx, #0x02e8 ; Serial I/O address, port 4
   10586   call detect_serial
   10587   shl bx, #0x09
   10588   mov ax, 0x410   ; Equipment word bits 9..11 determing # serial ports
   10589   and ax, #0xf1ff
   10590   or  ax, bx ; set number of serial port
   10591   mov 0x410, ax
   10592 
   10593   ;; CMOS RTC
   10594   SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
   10595   SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
   10596   SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
   10597   ;; BIOS DATA AREA 0x4CE ???
   10598   call timer_tick_post
   10599 
   10600   ;; PS/2 mouse setup
   10601   SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
   10602 
   10603   ;; IRQ13 (FPU exception) setup
   10604   SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
   10605 
   10606   ;; Video setup
   10607   SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
   10608 
   10609   ;; PIC
   10610   call post_init_pic
   10611 
   10612   mov  cx, #0xc000  ;; init vga bios
   10613   mov  ax, #0xc780
   10614   call rom_scan
   10615 
   10616   call _print_bios_banner
   10617 
   10618 #if BX_ROMBIOS32
   10619   call rombios32_init
   10620 #else
   10621 #if BX_PCIBIOS
   10622   call pcibios_init_iomem_bases
   10623   call pcibios_init_irqs
   10624 #endif //BX_PCIBIOS
   10625 #endif
   10626 
   10627   ;;
   10628   ;; Floppy setup
   10629   ;;
   10630   call floppy_drive_post
   10631 
   10632   ;;
   10633   ;; Hard Drive setup
   10634   ;;
   10635   call hard_drive_post
   10636 
   10637 #if BX_USE_ATADRV
   10638 
   10639   ;;
   10640   ;; ATA/ATAPI driver setup
   10641   ;;
   10642   call _ata_init
   10643   call _ata_detect
   10644   ;;
   10645 
   10646 #endif // BX_USE_ATADRV
   10647 
   10648 #if BX_ELTORITO_BOOT
   10649   ;;
   10650   ;; eltorito floppy/harddisk emulation from cd
   10651   ;;
   10652   call _cdemu_init
   10653   ;;
   10654 #endif // BX_ELTORITO_BOOT
   10655 
   10656   call _init_boot_vectors
   10657 
   10658   mov  cx, #0xc800  ;; init option roms
   10659   mov  ax, #0xe000
   10660   call rom_scan
   10661 
   10662 #if BX_ELTORITO_BOOT
   10663   call _interactive_bootkey
   10664 #endif // BX_ELTORITO_BOOT
   10665 
   10666   sti        ;; enable interrupts
   10667   int  #0x19
   10668 
   10669 .org 0xe2c3 ; NMI Handler Entry Point
   10670 nmi:
   10671   ;; FIXME the NMI handler should not panic
   10672   ;; but iret when called from int75 (fpu exception)
   10673   call _nmi_handler_msg
   10674   iret
   10675 
   10676 int75_handler:
   10677   out  0xf0, al         // clear irq13
   10678   call eoi_both_pics    // clear interrupt
   10679   int  2                // legacy nmi call
   10680   iret
   10681 
   10682 ;-------------------------------------------
   10683 ;- INT 13h Fixed Disk Services Entry Point -
   10684 ;-------------------------------------------
   10685 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
   10686 int13_handler:
   10687   //JMPL(int13_relocated)
   10688   jmp int13_relocated
   10689 
   10690 .org 0xe401 ; Fixed Disk Parameter Table
   10691 
   10692 ;----------
   10693 ;- INT19h -
   10694 ;----------
   10695 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
   10696 int19_handler:
   10697 
   10698   jmp int19_relocated
   10699 ;-------------------------------------------
   10700 ;- System BIOS Configuration Data Table
   10701 ;-------------------------------------------
   10702 .org BIOS_CONFIG_TABLE
   10703 db 0x08                  ; Table size (bytes) -Lo
   10704 db 0x00                  ; Table size (bytes) -Hi
   10705 db SYS_MODEL_ID
   10706 db SYS_SUBMODEL_ID
   10707 db BIOS_REVISION
   10708 ; Feature byte 1
   10709 ; b7: 1=DMA channel 3 used by hard disk
   10710 ; b6: 1=2 interrupt controllers present
   10711 ; b5: 1=RTC present
   10712 ; b4: 1=BIOS calls int 15h/4Fh every key
   10713 ; b3: 1=wait for extern event supported (Int 15h/41h)
   10714 ; b2: 1=extended BIOS data area used
   10715 ; b1: 0=AT or ESDI bus, 1=MicroChannel
   10716 ; b0: 1=Dual bus (MicroChannel + ISA)
   10717 db (0 << 7) | \
   10718    (1 << 6) | \
   10719    (1 << 5) | \
   10720    (BX_CALL_INT15_4F << 4) | \
   10721    (0 << 3) | \
   10722    (BX_USE_EBDA << 2) | \
   10723    (0 << 1) | \
   10724    (0 << 0)
   10725 ; Feature byte 2
   10726 ; b7: 1=32-bit DMA supported
   10727 ; b6: 1=int16h, function 9 supported
   10728 ; b5: 1=int15h/C6h (get POS data) supported
   10729 ; b4: 1=int15h/C7h (get mem map info) supported
   10730 ; b3: 1=int15h/C8h (en/dis CPU) supported
   10731 ; b2: 1=non-8042 kb controller
   10732 ; b1: 1=data streaming supported
   10733 ; b0: reserved
   10734 db (0 << 7) | \
   10735    (1 << 6) | \
   10736    (0 << 5) | \
   10737    (0 << 4) | \
   10738    (0 << 3) | \
   10739    (0 << 2) | \
   10740    (0 << 1) | \
   10741    (0 << 0)
   10742 ; Feature byte 3
   10743 ; b7: not used
   10744 ; b6: reserved
   10745 ; b5: reserved
   10746 ; b4: POST supports ROM-to-RAM enable/disable
   10747 ; b3: SCSI on system board
   10748 ; b2: info panel installed
   10749 ; b1: Initial Machine Load (IML) system - BIOS on disk
   10750 ; b0: SCSI supported in IML
   10751 db 0x00
   10752 ; Feature byte 4
   10753 ; b7: IBM private
   10754 ; b6: EEPROM present
   10755 ; b5-3: ABIOS presence (011 = not supported)
   10756 ; b2: private
   10757 ; b1: memory split above 16Mb supported
   10758 ; b0: POSTEXT directly supported by POST
   10759 db 0x00
   10760 ; Feature byte 5 (IBM)
   10761 ; b1: enhanced mouse
   10762 ; b0: flash EPROM
   10763 db 0x00
   10764 
   10765 
   10766 
   10767 .org 0xe729 ; Baud Rate Generator Table
   10768 
   10769 ;----------
   10770 ;- INT14h -
   10771 ;----------
   10772 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
   10773 int14_handler:
   10774   push ds
   10775   pusha
   10776   xor  ax, ax
   10777   mov  ds, ax
   10778   call _int14_function
   10779   popa
   10780   pop  ds
   10781   iret
   10782 
   10783 
   10784 ;----------------------------------------
   10785 ;- INT 16h Keyboard Service Entry Point -
   10786 ;----------------------------------------
   10787 .org 0xe82e
   10788 int16_handler:
   10789 
   10790   sti
   10791   push  ds
   10792   pushf
   10793   pusha
   10794 
   10795   cmp   ah, #0x00
   10796   je    int16_F00
   10797   cmp   ah, #0x10
   10798   je    int16_F00
   10799 
   10800   mov  bx, #0xf000
   10801   mov  ds, bx
   10802   call _int16_function
   10803   popa
   10804   popf
   10805   pop  ds
   10806   jz   int16_zero_set
   10807 
   10808 int16_zero_clear:
   10809   push bp
   10810   mov  bp, sp
   10811   //SEG SS
   10812   and  BYTE [bp + 0x06], #0xbf
   10813   pop  bp
   10814   iret
   10815 
   10816 int16_zero_set:
   10817   push bp
   10818   mov  bp, sp
   10819   //SEG SS
   10820   or   BYTE [bp + 0x06], #0x40
   10821   pop  bp
   10822   iret
   10823 
   10824 int16_F00:
   10825   mov  bx, #0x0040
   10826   mov  ds, bx
   10827 
   10828 int16_wait_for_key:
   10829   cli
   10830   mov  bx, 0x001a
   10831   cmp  bx, 0x001c
   10832   jne  int16_key_found
   10833   sti
   10834   nop
   10835 #if 0
   10836                            /* no key yet, call int 15h, function AX=9002 */
   10837   0x50,                    /* push AX */
   10838   0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
   10839   0xcd, 0x15,              /* int 15h */
   10840   0x58,                    /* pop  AX */
   10841   0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
   10842 #endif
   10843   jmp  int16_wait_for_key
   10844 
   10845 int16_key_found:
   10846   mov  bx, #0xf000
   10847   mov  ds, bx
   10848   call _int16_function
   10849   popa
   10850   popf
   10851   pop  ds
   10852 #if 0
   10853                            /* notify int16 complete w/ int 15h, function AX=9102 */
   10854   0x50,                    /* push AX */
   10855   0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
   10856   0xcd, 0x15,              /* int 15h */
   10857   0x58,                    /* pop  AX */
   10858 #endif
   10859   iret
   10860 
   10861 
   10862 
   10863 ;-------------------------------------------------
   10864 ;- INT09h : Keyboard Hardware Service Entry Point -
   10865 ;-------------------------------------------------
   10866 .org 0xe987
   10867 int09_handler:
   10868   cli
   10869   push ax
   10870 
   10871   mov al, #0xAD      ;;disable keyboard
   10872   out #0x64, al
   10873 
   10874   mov al, #0x0B
   10875   out #0x20, al
   10876   in  al, #0x20
   10877   and al, #0x02
   10878   jz  int09_finish
   10879 
   10880   in  al, #0x60             ;;read key from keyboard controller
   10881   sti
   10882   push  ds
   10883   pusha
   10884 #ifdef BX_CALL_INT15_4F
   10885   mov  ah, #0x4f     ;; allow for keyboard intercept
   10886   stc
   10887   int  #0x15
   10888   jnc  int09_done
   10889 #endif
   10890 
   10891   ;; check for extended key
   10892   cmp  al, #0xe0
   10893   jne int09_check_pause
   10894   xor  ax, ax
   10895   mov  ds, ax
   10896   mov  al, BYTE [0x496]     ;; mf2_state |= 0x02
   10897   or   al, #0x02
   10898   mov  BYTE [0x496], al
   10899   jmp int09_done
   10900 
   10901 int09_check_pause: ;; check for pause key
   10902   cmp  al, #0xe1
   10903   jne int09_process_key
   10904   xor  ax, ax
   10905   mov  ds, ax
   10906   mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
   10907   or   al, #0x01
   10908   mov  BYTE [0x496], al
   10909   jmp int09_done
   10910 
   10911 int09_process_key:
   10912   mov   bx, #0xf000
   10913   mov   ds, bx
   10914   call  _int09_function
   10915 
   10916 int09_done:
   10917   popa
   10918   pop   ds
   10919   cli
   10920   call eoi_master_pic
   10921 
   10922 int09_finish:
   10923   mov al, #0xAE      ;;enable keyboard
   10924   out #0x64, al
   10925   pop ax
   10926   iret
   10927 
   10928 
   10929 ;----------------------------------------
   10930 ;- INT 13h Diskette Service Entry Point -
   10931 ;----------------------------------------
   10932 .org 0xec59
   10933 int13_diskette:
   10934   jmp int13_noeltorito
   10935 
   10936 ;---------------------------------------------
   10937 ;- INT 0Eh Diskette Hardware ISR Entry Point -
   10938 ;---------------------------------------------
   10939 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
   10940 int0e_handler:
   10941   push ax
   10942   push dx
   10943   mov  dx, #0x03f4
   10944   in   al, dx
   10945   and  al, #0xc0
   10946   cmp  al, #0xc0
   10947   je   int0e_normal
   10948   mov  dx, #0x03f5
   10949   mov  al, #0x08 ; sense interrupt status
   10950   out  dx, al
   10951 int0e_loop1:
   10952   mov  dx, #0x03f4
   10953   in   al, dx
   10954   and  al, #0xc0
   10955   cmp  al, #0xc0
   10956   jne  int0e_loop1
   10957 int0e_loop2:
   10958   mov  dx, #0x03f5
   10959   in   al, dx
   10960   mov  dx, #0x03f4
   10961   in   al, dx
   10962   and  al, #0xc0
   10963   cmp  al, #0xc0
   10964   je int0e_loop2
   10965 int0e_normal:
   10966   push ds
   10967   xor  ax, ax ;; segment 0000
   10968   mov  ds, ax
   10969   call eoi_master_pic
   10970   mov  al, 0x043e
   10971   or   al, #0x80 ;; diskette interrupt has occurred
   10972   mov  0x043e, al
   10973   pop  ds
   10974   pop  dx
   10975   pop  ax
   10976   iret
   10977 
   10978 
   10979 .org 0xefc7 ; Diskette Controller Parameter Table
   10980 diskette_param_table:
   10981 ;;  Since no provisions are made for multiple drive types, most
   10982 ;;  values in this table are ignored.  I set parameters for 1.44M
   10983 ;;  floppy here
   10984 db  0xAF
   10985 db  0x02 ;; head load time 0000001, DMA used
   10986 db  0x25
   10987 db  0x02
   10988 db    18
   10989 db  0x1B
   10990 db  0xFF
   10991 db  0x6C
   10992 db  0xF6
   10993 db  0x0F
   10994 db  0x08
   10995 
   10996 
   10997 ;----------------------------------------
   10998 ;- INT17h : Printer Service Entry Point -
   10999 ;----------------------------------------
   11000 .org 0xefd2
   11001 int17_handler:
   11002   push ds
   11003   pusha
   11004   xor  ax, ax
   11005   mov  ds, ax
   11006   call _int17_function
   11007   popa
   11008   pop  ds
   11009   iret
   11010 
   11011 diskette_param_table2:
   11012 ;;  New diskette parameter table adding 3 parameters from IBM
   11013 ;;  Since no provisions are made for multiple drive types, most
   11014 ;;  values in this table are ignored.  I set parameters for 1.44M
   11015 ;;  floppy here
   11016 db  0xAF
   11017 db  0x02 ;; head load time 0000001, DMA used
   11018 db  0x25
   11019 db  0x02
   11020 db    18
   11021 db  0x1B
   11022 db  0xFF
   11023 db  0x6C
   11024 db  0xF6
   11025 db  0x0F
   11026 db  0x08
   11027 db    79 ;; maximum track
   11028 db     0 ;; data transfer rate
   11029 db     4 ;; drive type in cmos
   11030 
   11031 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
   11032   HALT(__LINE__)
   11033   iret
   11034 
   11035 ;----------
   11036 ;- INT10h -
   11037 ;----------
   11038 .org 0xf065 ; INT 10h Video Support Service Entry Point
   11039 int10_handler:
   11040   ;; dont do anything, since the VGA BIOS handles int10h requests
   11041   iret
   11042 
   11043 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
   11044 
   11045 ;----------
   11046 ;- INT12h -
   11047 ;----------
   11048 .org 0xf841 ; INT 12h Memory Size Service Entry Point
   11049 ; ??? different for Pentium (machine check)?
   11050 int12_handler:
   11051   push ds
   11052   mov  ax, #0x0040
   11053   mov  ds, ax
   11054   mov  ax, 0x0013
   11055   pop  ds
   11056   iret
   11057 
   11058 ;----------
   11059 ;- INT11h -
   11060 ;----------
   11061 .org 0xf84d ; INT 11h Equipment List Service Entry Point
   11062 int11_handler:
   11063   push ds
   11064   mov  ax, #0x0040
   11065   mov  ds, ax
   11066   mov  ax, 0x0010
   11067   pop  ds
   11068   iret
   11069 
   11070 ;----------
   11071 ;- INT15h -
   11072 ;----------
   11073 .org 0xf859 ; INT 15h System Services Entry Point
   11074 int15_handler:
   11075   pushf
   11076 #if BX_APM
   11077   cmp ah, #0x53
   11078   je apm_call
   11079 #endif
   11080   push  ds
   11081   push  es
   11082   cmp  ah, #0x86
   11083   je int15_handler32
   11084   cmp  ah, #0xE8
   11085   je int15_handler32
   11086   pusha
   11087 #if BX_USE_PS2_MOUSE
   11088   cmp  ah, #0xC2
   11089   je int15_handler_mouse
   11090 #endif
   11091   call _int15_function
   11092 int15_handler_mouse_ret:
   11093   popa
   11094 int15_handler32_ret:
   11095   pop   es
   11096   pop   ds
   11097   popf
   11098   jmp iret_modify_cf
   11099 #if BX_APM
   11100 apm_call:
   11101   jmp _apmreal_entry
   11102 #endif
   11103 
   11104 #if BX_USE_PS2_MOUSE
   11105 int15_handler_mouse:
   11106   call _int15_function_mouse
   11107   jmp int15_handler_mouse_ret
   11108 #endif
   11109 
   11110 int15_handler32:
   11111   pushad
   11112   call _int15_function32
   11113   popad
   11114   jmp int15_handler32_ret
   11115 
   11116 ;; Protected mode IDT descriptor
   11117 ;;
   11118 ;; I just make the limit 0, so the machine will shutdown
   11119 ;; if an exception occurs during protected mode memory
   11120 ;; transfers.
   11121 ;;
   11122 ;; Set base to f0000 to correspond to beginning of BIOS,
   11123 ;; in case I actually define an IDT later
   11124 ;; Set limit to 0
   11125 
   11126 pmode_IDT_info:
   11127 dw 0x0000  ;; limit 15:00
   11128 dw 0x0000  ;; base  15:00
   11129 db 0x0f    ;; base  23:16
   11130 
   11131 ;; Real mode IDT descriptor
   11132 ;;
   11133 ;; Set to typical real-mode values.
   11134 ;; base  = 000000
   11135 ;; limit =   03ff
   11136 
   11137 rmode_IDT_info:
   11138 dw 0x03ff  ;; limit 15:00
   11139 dw 0x0000  ;; base  15:00
   11140 db 0x00    ;; base  23:16
   11141 
   11142 
   11143 ;----------
   11144 ;- INT1Ah -
   11145 ;----------
   11146 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
   11147 int1a_handler:
   11148 #if BX_PCIBIOS
   11149   cmp  ah, #0xb1
   11150   jne  int1a_normal
   11151   call pcibios_real
   11152   jc   pcibios_error
   11153   retf 2
   11154 pcibios_error:
   11155   mov  bl, ah
   11156   mov  ah, #0xb1
   11157   push ds
   11158   pusha
   11159   mov ax, ss  ; set readable descriptor to ds, for calling pcibios
   11160   mov ds, ax  ;  on 16bit protected mode.
   11161   jmp int1a_callfunction
   11162 int1a_normal:
   11163 #endif
   11164   push ds
   11165   pusha
   11166   xor  ax, ax
   11167   mov  ds, ax
   11168 int1a_callfunction:
   11169   call _int1a_function
   11170   popa
   11171   pop  ds
   11172   iret
   11173 
   11174 ;;
   11175 ;; int70h: IRQ8 - CMOS RTC
   11176 ;;
   11177 int70_handler:
   11178   push ds
   11179   pushad
   11180   xor  ax, ax
   11181   mov  ds, ax
   11182   call _int70_function
   11183   popad
   11184   pop  ds
   11185   iret
   11186 
   11187 ;---------
   11188 ;- INT08 -
   11189 ;---------
   11190 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
   11191 int08_handler:
   11192   sti
   11193   push eax
   11194   push ds
   11195   xor ax, ax
   11196   mov ds, ax
   11197 
   11198   ;; time to turn off drive(s)?
   11199   mov  al,0x0440
   11200   or   al,al
   11201   jz   int08_floppy_off
   11202   dec  al
   11203   mov  0x0440,al
   11204   jnz  int08_floppy_off
   11205   ;; turn motor(s) off
   11206   push dx
   11207   mov  dx,#0x03f2
   11208   in   al,dx
   11209   and  al,#0xcf
   11210   out  dx,al
   11211   pop  dx
   11212 int08_floppy_off:
   11213 
   11214   mov eax, 0x046c ;; get ticks dword
   11215   inc eax
   11216 
   11217   ;; compare eax to one days worth of timer ticks at 18.2 hz
   11218   cmp eax, #0x001800B0
   11219   jb  int08_store_ticks
   11220   ;; there has been a midnight rollover at this point
   11221   xor eax, eax    ;; zero out counter
   11222   inc BYTE 0x0470 ;; increment rollover flag
   11223 
   11224 int08_store_ticks:
   11225   mov 0x046c, eax ;; store new ticks dword
   11226   ;; chain to user timer tick INT #0x1c
   11227   //pushf
   11228   //;; call_ep [ds:loc]
   11229   //CALL_EP( 0x1c << 2 )
   11230   int #0x1c
   11231   cli
   11232   call eoi_master_pic
   11233   pop ds
   11234   pop eax
   11235   iret
   11236 
   11237 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
   11238 
   11239 
   11240 .org 0xff00
   11241 .ascii BIOS_COPYRIGHT_STRING
   11242 
   11243 ;------------------------------------------------
   11244 ;- IRET Instruction for Dummy Interrupt Handler -
   11245 ;------------------------------------------------
   11246 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
   11247 dummy_iret_handler:
   11248   iret
   11249 
   11250 .org 0xff54 ; INT 05h Print Screen Service Entry Point
   11251   HALT(__LINE__)
   11252   iret
   11253 
   11254 .org 0xfff0 ; Power-up Entry Point
   11255   jmp 0xf000:post
   11256 
   11257 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
   11258 .ascii BIOS_BUILD_DATE
   11259 
   11260 .org 0xfffe ; System Model ID
   11261 db SYS_MODEL_ID
   11262 db 0x00   ; filler
   11263 
   11264 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
   11265 ASM_END
   11266 /*
   11267  * This font comes from the fntcol16.zip package (c) by  Joseph Gil
   11268  * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
   11269  * This font is public domain
   11270  */
   11271 static Bit8u vgafont8[128*8]=
   11272 {
   11273  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   11274  0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
   11275  0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
   11276  0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
   11277  0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
   11278  0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
   11279  0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
   11280  0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
   11281  0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
   11282  0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
   11283  0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
   11284  0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
   11285  0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
   11286  0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
   11287  0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
   11288  0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
   11289  0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
   11290  0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
   11291  0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
   11292  0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
   11293  0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
   11294  0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
   11295  0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
   11296  0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
   11297  0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
   11298  0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
   11299  0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
   11300  0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
   11301  0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
   11302  0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
   11303  0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
   11304  0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
   11305  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   11306  0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
   11307  0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
   11308  0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
   11309  0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
   11310  0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
   11311  0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
   11312  0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
   11313  0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
   11314  0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
   11315  0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
   11316  0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
   11317  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
   11318  0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
   11319  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
   11320  0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
   11321  0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
   11322  0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
   11323  0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
   11324  0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
   11325  0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
   11326  0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
   11327  0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
   11328  0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
   11329  0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
   11330  0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
   11331  0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
   11332  0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
   11333  0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
   11334  0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
   11335  0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
   11336  0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
   11337  0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
   11338  0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
   11339  0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
   11340  0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
   11341  0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
   11342  0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
   11343  0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
   11344  0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
   11345  0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
   11346  0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
   11347  0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
   11348  0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
   11349  0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
   11350  0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
   11351  0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
   11352  0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
   11353  0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
   11354  0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
   11355  0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
   11356  0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
   11357  0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
   11358  0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
   11359  0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
   11360  0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
   11361  0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
   11362  0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
   11363  0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
   11364  0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
   11365  0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
   11366  0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
   11367  0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
   11368  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
   11369  0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
   11370  0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
   11371  0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
   11372  0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
   11373  0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
   11374  0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
   11375  0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
   11376  0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
   11377  0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
   11378  0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
   11379  0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
   11380  0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
   11381  0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
   11382  0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
   11383  0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
   11384  0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
   11385  0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
   11386  0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
   11387  0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
   11388  0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
   11389  0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
   11390  0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
   11391  0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
   11392  0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
   11393  0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
   11394  0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
   11395  0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
   11396  0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
   11397  0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
   11398  0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
   11399  0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   11400  0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
   11401 };
   11402 
   11403 ASM_START
   11404 .org 0xcc00
   11405 bios_table_area_end:
   11406 // bcc-generated data will be placed here
   11407 ASM_END
   11408