rombios.c

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////
00002 // $Id: rombios.c,v 1.163 2006/07/07 16:10:37 vruppert Exp $
00003 /////////////////////////////////////////////////////////////////////////
00004 //
00005 //  Copyright (C) 2002  MandrakeSoft S.A.
00006 //
00007 //    MandrakeSoft S.A.
00008 //    43, rue d'Aboukir
00009 //    75002 Paris - France
00010 //    http://www.linux-mandrake.com/
00011 //    http://www.mandrakesoft.com/
00012 //
00013 //  This library is free software; you can redistribute it and/or
00014 //  modify it under the terms of the GNU Lesser General Public
00015 //  License as published by the Free Software Foundation; either
00016 //  version 2 of the License, or (at your option) any later version.
00017 //
00018 //  This library is distributed in the hope that it will be useful,
00019 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 //  Lesser General Public License for more details.
00022 //
00023 //  You should have received a copy of the GNU Lesser General Public
00024 //  License along with this library; if not, write to the Free Software
00025 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
00026 
00027 // ROM BIOS for use with Bochs/Plex x86 emulation environment
00028 
00029 
00030 // ROM BIOS compatability entry points:
00031 // ===================================
00032 // $e05b ; POST Entry Point
00033 // $e2c3 ; NMI Handler Entry Point
00034 // $e3fe ; INT 13h Fixed Disk Services Entry Point
00035 // $e401 ; Fixed Disk Parameter Table
00036 // $e6f2 ; INT 19h Boot Load Service Entry Point
00037 // $e6f5 ; Configuration Data Table
00038 // $e729 ; Baud Rate Generator Table
00039 // $e739 ; INT 14h Serial Communications Service Entry Point
00040 // $e82e ; INT 16h Keyboard Service Entry Point
00041 // $e987 ; INT 09h Keyboard Service Entry Point
00042 // $ec59 ; INT 13h Diskette Service Entry Point
00043 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
00044 // $efc7 ; Diskette Controller Parameter Table
00045 // $efd2 ; INT 17h Printer Service Entry Point
00046 // $f045 ; INT 10 Functions 0-Fh Entry Point
00047 // $f065 ; INT 10h Video Support Service Entry Point
00048 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
00049 // $f841 ; INT 12h Memory Size Service Entry Point
00050 // $f84d ; INT 11h Equipment List Service Entry Point
00051 // $f859 ; INT 15h System Services Entry Point
00052 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
00053 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
00054 // $fea5 ; INT 08h System Timer ISR Entry Point
00055 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
00056 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
00057 // $ff54 ; INT 05h Print Screen Service Entry Point
00058 // $fff0 ; Power-up Entry Point
00059 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
00060 // $fffe ; System Model ID
00061 
00062 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
00063 //   Features
00064 //     - supports up to 4 ATA interfaces
00065 //     - device/geometry detection
00066 //     - 16bits/32bits device access
00067 //     - pchs/lba access
00068 //     - datain/dataout/packet command support
00069 //
00070 // NOTES for El-Torito Boot (cbbochs@free.fr)
00071 //   - CD-ROM booting is only available if ATA/ATAPI Driver is available
00072 //   - Current code is only able to boot mono-session cds 
00073 //   - Current code can not boot and emulate a hard-disk
00074 //     the bios will panic otherwise
00075 //   - Current code also use memory in EBDA segement. 
00076 //   - I used cmos byte 0x3D to store extended information on boot-device
00077 //   - Code has to be modified modified to handle multiple cdrom drives
00078 //   - Here are the cdrom boot failure codes:
00079 //       1 : no atapi device found
00080 //       2 : no atapi cdrom found
00081 //       3 : can not read cd - BRVD
00082 //       4 : cd is not eltorito (BRVD)
00083 //       5 : cd is not eltorito (ISO TAG)
00084 //       6 : cd is not eltorito (ELTORITO TAG)
00085 //       7 : can not read cd - boot catalog
00086 //       8 : boot catalog : bad header
00087 //       9 : boot catalog : bad platform
00088 //      10 : boot catalog : bad signature
00089 //      11 : boot catalog : bootable flag not set
00090 //      12 : can not read cd - boot image
00091 //
00092 //   ATA driver
00093 //   - EBDA segment. 
00094 //     I used memory starting at 0x121 in the segment
00095 //   - the translation policy is defined in cmos regs 0x39 & 0x3a
00096 //
00097 // TODO :
00098 //
00099 //   int74 
00100 //     - needs to be reworked.  Uses direct [bp] offsets. (?)
00101 //
00102 //   int13:
00103 //     - f04 (verify sectors) isn't complete  (?)
00104 //     - f02/03/04 should set current cyl,etc in BDA  (?)
00105 //     - rewrite int13_relocated & clean up int13 entry code
00106 //
00107 //   NOTES:
00108 //   - NMI access (bit7 of addr written to 70h)
00109 //
00110 //   ATA driver
00111 //   - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
00112 //   - could send the multiple-sector read/write commands
00113 //
00114 //   El-Torito
00115 //   - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
00116 //   - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
00117 //   - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
00118 //   - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
00119 //     This is ok. But DL should be reincremented afterwards. 
00120 //   - Fix all "FIXME ElTorito Various"
00121 //   - should be able to boot any cdrom instead of the first one
00122 //
00123 //   BCC Bug: find a generic way to handle the bug of #asm after an "if"  (fixed in 0.16.7)
00124 
00125 #define DEBUG_ROMBIOS      1
00126 
00127 #define DEBUG_ATA          0
00128 #define DEBUG_INT13_HD     0
00129 #define DEBUG_INT13_CD     0
00130 #define DEBUG_INT13_ET     0
00131 #define DEBUG_INT13_FL     0
00132 #define DEBUG_INT15        0
00133 #define DEBUG_INT16        0
00134 #define DEBUG_INT1A        0
00135 #define DEBUG_INT74        0
00136 #define DEBUG_APM          0
00137 
00138 #define BX_CPU           3
00139 #define BX_USE_PS2_MOUSE 1
00140 #define BX_CALL_INT15_4F 1
00141 #define BX_USE_EBDA      1
00142 #define BX_SUPPORT_FLOPPY 1
00143 #define BX_FLOPPY_ON_CNT 37   /* 2 seconds */
00144 //#define BX_PCIBIOS       1
00145 #define BX_APM           0
00146 
00147 #define COREBOOT        1
00148 
00149 #define BX_USE_ATADRV    1
00150 //#define BX_ELTORITO_BOOT 1
00151 
00152 #define BX_MAX_ATA_INTERFACES   4
00153 #define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
00154 
00155 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
00156 #define BX_DEBUG_SERIAL  1 /* output to COM1 */
00157 
00158    /* model byte 0xFC = AT */
00159 #define SYS_MODEL_ID     0xFC
00160 #define SYS_SUBMODEL_ID  0x00
00161 #define BIOS_REVISION    1
00162 #define BIOS_CONFIG_TABLE 0xe6f5
00163 
00164 #ifndef BIOS_BUILD_DATE
00165 #  define BIOS_BUILD_DATE "06/23/99"
00166 #endif
00167 
00168   // 1K of base memory used for Extended Bios Data Area (EBDA)
00169   // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
00170 #define EBDA_SEG           0x9FC0
00171 #define EBDA_SIZE          1              // In KiB
00172 #define BASE_MEM_IN_K   (640 - EBDA_SIZE)
00173 
00174   // Define the application NAME
00175 #ifdef PLEX86
00176 #  define BX_APPNAME "Plex86"
00177 #else
00178 #  define BX_APPNAME "Bochs"
00179 #endif
00180 
00181   // Sanity Checks
00182 #if BX_USE_ATADRV && BX_CPU<3
00183 #    error The ATA/ATAPI Driver can only to be used with a 386+ cpu
00184 #endif
00185 #if BX_USE_ATADRV && !BX_USE_EBDA
00186 #    error ATA/ATAPI Driver can only be used if EBDA is available
00187 #endif
00188 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
00189 #    error El-Torito Boot can only be use if ATA/ATAPI Driver is available
00190 #endif
00191 #if BX_PCIBIOS && BX_CPU<3
00192 #    error PCI BIOS can only be used with 386+ cpu
00193 #endif
00194 #if BX_APM && BX_CPU<3
00195 #    error APM BIOS can only be used with 386+ cpu
00196 #endif
00197 
00198 #define PANIC_PORT  0x400
00199 #define PANIC_PORT2 0x401
00200 #define INFO_PORT   0x402
00201 #define DEBUG_PORT  0x403
00202 
00203 // define this if you want to make PCIBIOS working on a specific bridge only
00204 // undef enables PCIBIOS when at least one PCI device is found
00205 // i440FX is emulated by Bochs and QEMU
00206 #define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge
00207 
00208 // #20  is dec 20
00209 // #$20 is hex 20 = 32
00210 // #0x20 is hex 20 = 32
00211 // LDA  #$20
00212 // JSR  $E820
00213 // LDD  .i,S
00214 // JSR  $C682
00215 // mov al, #$20
00216 
00217 // all hex literals should be prefixed with '0x'
00218 //   grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
00219 // no mov SEG-REG, #value, must mov register into seg-reg
00220 //   grep -i "mov[ ]*.s" rombios.c
00221 
00222 // This is for compiling with gcc2 and gcc3
00223 #define ASM_START #asm
00224 #define ASM_END #endasm
00225 
00226 ASM_START
00227 .rom
00228 
00229 .org 0x0000
00230 
00231 #if BX_CPU >= 3
00232 use16 386
00233 #else
00234 use16 286
00235 #endif
00236 
00237 MACRO HALT
00238   ;; the HALT macro is called with the line number of the HALT call.
00239   ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex 
00240   ;; to print a BX_PANIC message.  This will normally halt the simulation
00241   ;; with a message such as "BIOS panic at rombios.c, line 4091".
00242   ;; However, users can choose to make panics non-fatal and continue.
00243 #if BX_VIRTUAL_PORTS
00244   mov dx,#PANIC_PORT
00245   mov ax,#?1
00246   out dx,ax
00247 #else
00248   mov dx,#0x80
00249   mov ax,#?1
00250   out dx,al
00251 #endif
00252 MEND
00253 
00254 MACRO JMP_AP
00255   db 0xea
00256   dw ?2
00257   dw ?1
00258 MEND
00259 
00260 MACRO SET_INT_VECTOR
00261   mov ax, ?3
00262   mov ?1*4, ax
00263   mov ax, ?2
00264   mov ?1*4+2, ax
00265 MEND
00266 
00267 ASM_END
00268 
00269 typedef unsigned char  Bit8u;
00270 typedef unsigned short Bit16u;
00271 typedef unsigned short bx_bool;
00272 typedef unsigned long  Bit32u;
00273 
00274 #if BX_USE_ATADRV
00275 
00276   void memsetb(seg,offset,value,count);
00277   void memcpyb(dseg,doffset,sseg,soffset,count);
00278   void memcpyd(dseg,doffset,sseg,soffset,count);
00279   
00280   // memset of count bytes
00281     void 
00282   memsetb(seg,offset,value,count)
00283     Bit16u seg;
00284     Bit16u offset;
00285     Bit16u value;
00286     Bit16u count;
00287   {
00288   ASM_START
00289     push bp
00290     mov  bp, sp
00291   
00292       push ax
00293       push cx
00294       push es
00295       push di
00296   
00297       mov  cx, 10[bp] ; count
00298       cmp  cx, #0x00
00299       je   memsetb_end
00300       mov  ax, 4[bp] ; segment
00301       mov  es, ax
00302       mov  ax, 6[bp] ; offset
00303       mov  di, ax
00304       mov  al, 8[bp] ; value
00305       cld
00306       rep
00307        stosb
00308   
00309   memsetb_end:
00310       pop di
00311       pop es
00312       pop cx
00313       pop ax
00314   
00315     pop bp
00316   ASM_END
00317   }
00318   
00319 #if 0 
00320   // memcpy of count bytes
00321     void 
00322   memcpyb(dseg,doffset,sseg,soffset,count)
00323     Bit16u dseg;
00324     Bit16u doffset;
00325     Bit16u sseg;
00326     Bit16u soffset;
00327     Bit16u count;
00328   {
00329   ASM_START
00330     push bp
00331     mov  bp, sp
00332   
00333       push ax
00334       push cx
00335       push es
00336       push di
00337       push ds
00338       push si
00339   
00340       mov  cx, 12[bp] ; count
00341       cmp  cx, #0x0000
00342       je   memcpyb_end
00343       mov  ax, 4[bp] ; dsegment
00344       mov  es, ax
00345       mov  ax, 6[bp] ; doffset
00346       mov  di, ax
00347       mov  ax, 8[bp] ; ssegment
00348       mov  ds, ax
00349       mov  ax, 10[bp] ; soffset
00350       mov  si, ax
00351       cld
00352       rep
00353        movsb
00354   
00355   memcpyb_end:
00356       pop si
00357       pop ds
00358       pop di
00359       pop es
00360       pop cx
00361       pop ax
00362   
00363     pop bp
00364   ASM_END
00365   }
00366 
00367   // memcpy of count dword
00368     void 
00369   memcpyd(dseg,doffset,sseg,soffset,count)
00370     Bit16u dseg;
00371     Bit16u doffset;
00372     Bit16u sseg;
00373     Bit16u soffset;
00374     Bit16u count;
00375   {
00376   ASM_START
00377     push bp
00378     mov  bp, sp
00379   
00380       push ax
00381       push cx
00382       push es
00383       push di
00384       push ds
00385       push si
00386   
00387       mov  cx, 12[bp] ; count
00388       cmp  cx, #0x0000
00389       je   memcpyd_end
00390       mov  ax, 4[bp] ; dsegment
00391       mov  es, ax
00392       mov  ax, 6[bp] ; doffset
00393       mov  di, ax
00394       mov  ax, 8[bp] ; ssegment
00395       mov  ds, ax
00396       mov  ax, 10[bp] ; soffset
00397       mov  si, ax
00398       cld
00399       rep
00400        movsd
00401   
00402   memcpyd_end:
00403       pop si
00404       pop ds
00405       pop di
00406       pop es
00407       pop cx
00408       pop ax
00409   
00410     pop bp
00411   ASM_END
00412   }
00413 #endif
00414 #endif //BX_USE_ATADRV
00415 
00416   // read_dword and write_dword functions
00417   static Bit32u         read_dword();
00418   static void           write_dword();
00419   
00420     Bit32u
00421   read_dword(seg, offset)
00422     Bit16u seg;
00423     Bit16u offset;
00424   {
00425   ASM_START
00426     push bp
00427     mov  bp, sp
00428   
00429       push bx
00430       push ds
00431       mov  ax, 4[bp] ; segment
00432       mov  ds, ax
00433       mov  bx, 6[bp] ; offset
00434       mov  ax, [bx]
00435       inc  bx
00436       inc  bx
00437       mov  dx, [bx]
00438       ;; ax = return value (word)
00439       ;; dx = return value (word)
00440       pop  ds
00441       pop  bx
00442   
00443     pop  bp
00444   ASM_END
00445   }
00446   
00447     void
00448   write_dword(seg, offset, data)
00449     Bit16u seg;
00450     Bit16u offset;
00451     Bit32u data;
00452   {
00453   ASM_START
00454     push bp
00455     mov  bp, sp
00456   
00457       push ax
00458       push bx
00459       push ds
00460       mov  ax, 4[bp] ; segment
00461       mov  ds, ax
00462       mov  bx, 6[bp] ; offset
00463       mov  ax, 8[bp] ; data word
00464       mov  [bx], ax  ; write data word
00465       inc  bx
00466       inc  bx
00467       mov  ax, 10[bp] ; data word
00468       mov  [bx], ax  ; write data word
00469       pop  ds
00470       pop  bx
00471       pop  ax
00472   
00473     pop  bp
00474   ASM_END
00475   }
00476   
00477   // Bit32u (unsigned long) and long helper functions
00478   ASM_START
00479   
00480   ;; and function
00481   landl:
00482   landul:
00483     SEG SS 
00484       and ax,[di]
00485     SEG SS 
00486       and bx,2[di]
00487     ret
00488   
00489   ;; add function
00490   laddl:
00491   laddul:
00492     SEG SS 
00493       add ax,[di]
00494     SEG SS 
00495       adc bx,2[di]
00496     ret
00497   
00498   ;; cmp function
00499   lcmpl:
00500   lcmpul:
00501     and eax, #0x0000FFFF
00502     shl ebx, #16
00503     add eax, ebx
00504     shr ebx, #16
00505     SEG SS
00506       cmp eax, dword ptr [di]
00507     ret
00508   
00509   ;; sub function
00510   lsubl:
00511   lsubul:
00512     SEG SS
00513     sub ax,[di]
00514     SEG SS
00515     sbb bx,2[di]
00516     ret
00517   
00518   ;; mul function
00519   lmull:
00520   lmulul:
00521     and eax, #0x0000FFFF
00522     shl ebx, #16
00523     add eax, ebx
00524     SEG SS
00525     mul eax, dword ptr [di]
00526     mov ebx, eax
00527     shr ebx, #16
00528     ret
00529   
00530   ;; dec function
00531   ldecl:
00532   ldecul:
00533     SEG SS
00534     dec dword ptr [bx]
00535     ret
00536   
00537   ;; or function
00538   lorl:
00539   lorul:
00540     SEG SS
00541     or  ax,[di]
00542     SEG SS
00543     or  bx,2[di]
00544     ret
00545   
00546   ;; inc function
00547   lincl:
00548   lincul:
00549     SEG SS
00550     inc dword ptr [bx]
00551     ret
00552   
00553   ;; tst function
00554   ltstl:
00555   ltstul:
00556     and eax, #0x0000FFFF
00557     shl ebx, #16
00558     add eax, ebx
00559     shr ebx, #16
00560     test eax, eax
00561     ret
00562   
00563   ;; sr function
00564   lsrul:
00565     mov  cx,di
00566     jcxz lsr_exit
00567     and  eax, #0x0000FFFF
00568     shl  ebx, #16
00569     add  eax, ebx
00570   lsr_loop:
00571     shr  eax, #1
00572     loop lsr_loop
00573     mov  ebx, eax
00574     shr  ebx, #16
00575   lsr_exit:
00576     ret
00577   
00578   ;; sl function
00579   lsll:
00580   lslul:
00581     mov  cx,di
00582     jcxz lsl_exit
00583     and  eax, #0x0000FFFF
00584     shl  ebx, #16
00585     add  eax, ebx
00586   lsl_loop: 
00587     shl  eax, #1
00588     loop lsl_loop
00589     mov  ebx, eax
00590     shr  ebx, #16
00591   lsl_exit:
00592     ret
00593   
00594   idiv_:
00595     cwd
00596     idiv bx
00597     ret
00598 
00599   idiv_u:
00600     xor dx,dx
00601     div bx
00602     ret
00603 
00604   ldivul:
00605     and  eax, #0x0000FFFF
00606     shl  ebx, #16
00607     add  eax, ebx
00608     xor  edx, edx
00609     SEG SS
00610     mov  bx,  2[di]
00611     shl  ebx, #16
00612     SEG SS
00613     mov  bx,  [di]
00614     div  ebx
00615     mov  ebx, eax
00616     shr  ebx, #16
00617     ret
00618 
00619   ASM_END
00620 
00621 // for access to RAM area which is used by interrupt vectors
00622 // and BIOS Data Area
00623 
00624 typedef struct {
00625   unsigned char filler1[0x400];
00626   unsigned char filler2[0x6c];
00627   Bit16u ticks_low;
00628   Bit16u ticks_high;
00629   Bit8u  midnight_flag;
00630   } bios_data_t;
00631 
00632 #define BiosData ((bios_data_t  *) 0)
00633 
00634 #if BX_USE_ATADRV
00635   typedef struct {
00636     Bit16u heads;      // # heads
00637     Bit16u cylinders;  // # cylinders
00638     Bit16u spt;        // # sectors / track
00639     } chs_t;
00640 
00641   // DPTE definition
00642   typedef struct {
00643     Bit16u iobase1;
00644     Bit16u iobase2;
00645     Bit8u  prefix;
00646     Bit8u  unused;
00647     Bit8u  irq;
00648     Bit8u  blkcount;
00649     Bit8u  dma;
00650     Bit8u  pio;
00651     Bit16u options;
00652     Bit16u reserved;
00653     Bit8u  revision;
00654     Bit8u  checksum;
00655     } dpte_t;
00656  
00657   typedef struct {
00658     Bit8u  iface;        // ISA or PCI
00659     Bit16u iobase1;      // IO Base 1
00660     Bit16u iobase2;      // IO Base 2
00661     Bit8u  irq;          // IRQ
00662     } ata_channel_t;
00663 
00664   typedef struct {
00665     Bit8u  type;         // Detected type of ata (ata/atapi/none/unknown)
00666     Bit8u  device;       // Detected type of attached devices (hd/cd/none)
00667     Bit8u  removable;    // Removable device flag
00668     Bit8u  lock;         // Locks for removable devices
00669     // Bit8u  lba_capable;  // LBA capable flag - always yes for bochs devices
00670     Bit8u  mode;         // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
00671     Bit16u blksize;      // block size
00672 
00673     Bit8u  translation;  // type of translation
00674     chs_t  lchs;         // Logical CHS
00675     chs_t  pchs;         // Physical CHS
00676 
00677     Bit32u sectors;      // Total sectors count
00678     } ata_device_t;
00679 
00680   typedef struct {
00681     // ATA channels info
00682     ata_channel_t channels[BX_MAX_ATA_INTERFACES];
00683 
00684     // ATA devices info
00685     ata_device_t  devices[BX_MAX_ATA_DEVICES];
00686     //
00687     // map between (bios hd id - 0x80) and ata channels
00688     Bit8u  hdcount, hdidmap[BX_MAX_ATA_DEVICES];                
00689 
00690     // map between (bios cd id - 0xE0) and ata channels
00691     Bit8u  cdcount, cdidmap[BX_MAX_ATA_DEVICES];                
00692 
00693     // Buffer for DPTE table
00694     dpte_t dpte;
00695 
00696     // Count of transferred sectors and bytes
00697     Bit16u trsfsectors;
00698     Bit32u trsfbytes;
00699 
00700     } ata_t;
00701   
00702 #if BX_ELTORITO_BOOT
00703   // ElTorito Device Emulation data 
00704   typedef struct {
00705     Bit8u  active;
00706     Bit8u  media;
00707     Bit8u  emulated_drive;
00708     Bit8u  controller_index;
00709     Bit16u device_spec;
00710     Bit32u ilba;
00711     Bit16u buffer_segment;
00712     Bit16u load_segment;
00713     Bit16u sector_count;
00714     
00715     // Virtual device
00716     chs_t  vdevice;
00717     } cdemu_t;
00718 #endif // BX_ELTORITO_BOOT
00719   
00720   // for access to EBDA area
00721   //     The EBDA structure should conform to 
00722   //     http://www.frontiernet.net/~fys/rombios.htm document
00723   //     I made the ata and cdemu structs begin at 0x121 in the EBDA seg
00724   typedef struct {
00725     unsigned char filler1[0x3D];
00726 
00727     // FDPT - Can be splitted in data members if needed
00728     unsigned char fdpt0[0x10];
00729     unsigned char fdpt1[0x10];
00730 
00731     unsigned char filler2[0xC4];
00732 
00733     // ATA Driver data
00734     ata_t   ata;
00735 
00736 #if BX_ELTORITO_BOOT
00737     // El Torito Emulation data
00738     cdemu_t cdemu;
00739 #endif // BX_ELTORITO_BOOT
00740 
00741     } ebda_data_t;
00742   
00743   #define EbdaData ((ebda_data_t *) 0)
00744 
00745   // for access to the int13ext structure
00746   typedef struct {
00747     Bit8u  size;
00748     Bit8u  reserved;
00749     Bit16u count;
00750     Bit16u offset;
00751     Bit16u segment;
00752     Bit32u lba1;
00753     Bit32u lba2;
00754     } int13ext_t;
00755  
00756   #define Int13Ext ((int13ext_t *) 0)
00757 
00758   // Disk Physical Table definition
00759   typedef struct {
00760     Bit16u  size;
00761     Bit16u  infos;
00762     Bit32u  cylinders;
00763     Bit32u  heads;
00764     Bit32u  spt;
00765     Bit32u  sector_count1;
00766     Bit32u  sector_count2;
00767     Bit16u  blksize;
00768     Bit16u  dpte_segment;
00769     Bit16u  dpte_offset;
00770     Bit16u  key;
00771     Bit8u   dpi_length;
00772     Bit8u   reserved1;
00773     Bit16u  reserved2;
00774     Bit8u   host_bus[4];
00775     Bit8u   iface_type[8];
00776     Bit8u   iface_path[8];
00777     Bit8u   device_path[8];
00778     Bit8u   reserved3;
00779     Bit8u   checksum;
00780     } dpt_t;
00781  
00782   #define Int13DPT ((dpt_t *) 0)
00783 
00784 #endif // BX_USE_ATADRV
00785 
00786 typedef struct {
00787   union {
00788     struct {
00789       Bit16u di, si, bp, sp;
00790       Bit16u bx, dx, cx, ax;
00791       } r16;
00792     struct {
00793       Bit16u filler[4];
00794       Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
00795       } r8;
00796     } u;
00797   } pusha_regs_t;
00798 
00799 typedef struct {
00800  union {
00801   struct {
00802     Bit32u edi, esi, ebp, esp;
00803     Bit32u ebx, edx, ecx, eax;
00804     } r32;
00805   struct {
00806     Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
00807     Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
00808     } r16;
00809   struct {
00810     Bit32u filler[4];
00811     Bit8u  bl, bh; 
00812     Bit16u filler1;
00813     Bit8u  dl, dh; 
00814     Bit16u filler2;
00815     Bit8u  cl, ch;
00816     Bit16u filler3;
00817     Bit8u  al, ah;
00818     Bit16u filler4;
00819     } r8;
00820   } u;
00821 } pushad_regs_t;
00822 
00823 typedef struct {
00824   union {
00825     struct {
00826       Bit16u flags;
00827       } r16;
00828     struct {
00829       Bit8u  flagsl;
00830       Bit8u  flagsh;
00831       } r8;
00832     } u;
00833   } flags_t;
00834 
00835 #define SetCF(x)   x.u.r8.flagsl |= 0x01
00836 #define SetZF(x)   x.u.r8.flagsl |= 0x40
00837 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
00838 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
00839 #define GetCF(x)   (x.u.r8.flagsl & 0x01)
00840 
00841 typedef struct {
00842   Bit16u ip;
00843   Bit16u cs;
00844   flags_t flags;
00845   } iret_addr_t;
00846 
00847 
00848 
00849 static Bit8u          inb();
00850 static Bit8u          inb_cmos();
00851 static void           outb();
00852 static void           outb_cmos();
00853 static Bit16u         inw();
00854 static void           outw();
00855 static void           init_rtc();
00856 static bx_bool        rtc_updating();
00857 
00858 static Bit8u          read_byte();
00859 static Bit16u         read_word();
00860 static void           write_byte();
00861 static void           write_word();
00862 static void           bios_printf();
00863 
00864 static Bit8u          inhibit_mouse_int_and_events();
00865 static void           enable_mouse_int_and_events();
00866 static Bit8u          send_to_mouse_ctrl();
00867 static Bit8u          get_mouse_data();
00868 static void           set_kbd_command_byte();
00869 
00870 static void           int09_function();
00871 static void           int13_harddisk();
00872 static void           int13_cdrom();
00873 static void           int13_cdemu();
00874 static void           int13_eltorito();
00875 static void           int13_diskette_function();
00876 static void           int14_function();
00877 static void           int15_function();
00878 static void           int16_function();
00879 static void           int17_function();
00880 static Bit32u         int19_function();
00881 static void           int1a_function();
00882 static void           int70_function();
00883 static void           int74_function();
00884 static Bit16u         get_CS();
00885 static Bit16u         get_SS();
00886 static unsigned int   enqueue_key();
00887 static unsigned int   dequeue_key();
00888 static void           get_hd_geometry();
00889 static void           set_diskette_ret_status();
00890 static void           set_diskette_current_cyl();
00891 static void           determine_floppy_media();
00892 static bx_bool        floppy_drive_exists();
00893 static bx_bool        floppy_drive_recal();
00894 static bx_bool        floppy_media_known();
00895 static bx_bool        floppy_media_sense();
00896 static bx_bool        set_enable_a20();
00897 static void           debugger_on();
00898 static void           debugger_off();
00899 static void           keyboard_init();
00900 static void           keyboard_panic();
00901 static void           shutdown_status_panic();
00902 static void           nmi_handler_msg();
00903 
00904 static void           print_bios_banner();
00905 static void           print_boot_device();
00906 static void           print_boot_failure();
00907 static void           print_cdromboot_failure();
00908 
00909 # if BX_USE_ATADRV
00910 
00911 // ATA / ATAPI driver
00912 void   ata_init();
00913 void   ata_detect();
00914 void   ata_reset();
00915 
00916 Bit16u ata_cmd_non_data();
00917 Bit16u ata_cmd_data_in();
00918 Bit16u ata_cmd_data_out();
00919 Bit16u ata_cmd_packet();
00920 
00921 Bit16u atapi_get_sense();
00922 Bit16u atapi_is_ready();
00923 Bit16u atapi_is_cdrom();
00924 
00925 #endif // BX_USE_ATADRV
00926 
00927 #if BX_ELTORITO_BOOT
00928 
00929 void   cdemu_init();
00930 Bit8u  cdemu_isactive();
00931 Bit8u  cdemu_emulated_drive();
00932 
00933 Bit16u cdrom_boot();
00934 
00935 #endif // BX_ELTORITO_BOOT
00936 
00937 static char bios_cvs_version_string[] = "$Revision: 1.163 $ $Date: 2006/07/07 16:10:37 $";
00938 
00939 #define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
00940 
00941 #define BIOS_PRINTF_HALT     1
00942 #define BIOS_PRINTF_SCREEN   2
00943 #define BIOS_PRINTF_INFO     4
00944 #define BIOS_PRINTF_DEBUG    8
00945 #define BIOS_PRINTF_ALL      (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
00946 #define BIOS_PRINTF_DEBHALT  (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT)
00947 
00948 #define printf(format, p...)  bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
00949 
00950 // Defines the output macros. 
00951 // BX_DEBUG goes to INFO port until we can easily choose debug info on a 
00952 // per-device basis. Debug info are sent only in debug mode
00953 #if DEBUG_ROMBIOS
00954 #  define BX_DEBUG(format, p...)  bios_printf(BIOS_PRINTF_INFO, format, ##p)    
00955 #else
00956 #  define BX_DEBUG(format, p...) 
00957 #endif
00958 #define BX_INFO(format, p...)   bios_printf(BIOS_PRINTF_INFO, format, ##p)
00959 #define BX_PANIC(format, p...)  bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
00960 
00961 #if DEBUG_ATA
00962 #  define BX_DEBUG_ATA(a...) BX_DEBUG(a)
00963 #else
00964 #  define BX_DEBUG_ATA(a...)
00965 #endif
00966 #if DEBUG_INT13_HD
00967 #  define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
00968 #else
00969 #  define BX_DEBUG_INT13_HD(a...)
00970 #endif
00971 #if DEBUG_INT13_CD
00972 #  define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
00973 #else
00974 #  define BX_DEBUG_INT13_CD(a...)
00975 #endif
00976 #if DEBUG_INT13_ET
00977 #  define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
00978 #else
00979 #  define BX_DEBUG_INT13_ET(a...)
00980 #endif
00981 #if DEBUG_INT13_FL
00982 #  define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
00983 #else
00984 #  define BX_DEBUG_INT13_FL(a...)
00985 #endif
00986 #if DEBUG_INT15
00987 #  define BX_DEBUG_INT15(a...) BX_DEBUG(a)
00988 #else
00989 #  define BX_DEBUG_INT15(a...)
00990 #endif
00991 #if DEBUG_INT16
00992 #  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
00993 #else
00994 #  define BX_DEBUG_INT16(a...)
00995 #endif
00996 #if DEBUG_INT1A
00997 #  define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
00998 #else
00999 #  define BX_DEBUG_INT1A(a...)
01000 #endif
01001 #if DEBUG_INT74
01002 #  define BX_DEBUG_INT74(a...) BX_DEBUG(a)
01003 #else
01004 #  define BX_DEBUG_INT74(a...)
01005 #endif
01006 
01007 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
01008 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
01009 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
01010 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
01011 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
01012 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
01013 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
01014 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
01015 
01016 #define GET_AL() ( AX & 0x00ff )
01017 #define GET_BL() ( BX & 0x00ff )
01018 #define GET_CL() ( CX & 0x00ff )
01019 #define GET_DL() ( DX & 0x00ff )
01020 #define GET_AH() ( AX >> 8 )
01021 #define GET_BH() ( BX >> 8 )
01022 #define GET_CH() ( CX >> 8 )
01023 #define GET_DH() ( DX >> 8 )
01024 
01025 #define GET_ELDL() ( ELDX & 0x00ff )
01026 #define GET_ELDH() ( ELDX >> 8 )
01027 
01028 #define SET_CF()     FLAGS |= 0x0001
01029 #define CLEAR_CF()   FLAGS &= 0xfffe
01030 #define GET_CF()     (FLAGS & 0x0001)
01031 
01032 #define SET_ZF()     FLAGS |= 0x0040
01033 #define CLEAR_ZF()   FLAGS &= 0xffbf
01034 #define GET_ZF()     (FLAGS & 0x0040)
01035 
01036 #define UNSUPPORTED_FUNCTION 0x86
01037 
01038 #define none 0
01039 #define MAX_SCAN_CODE 0x58
01040 
01041 static struct {
01042   Bit16u normal;
01043   Bit16u shift;
01044   Bit16u control;
01045   Bit16u alt;
01046   Bit8u lock_flags;
01047   } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
01048       {   none,   none,   none,   none, none },
01049       { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
01050       { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
01051       { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
01052       { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
01053       { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
01054       { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
01055       { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
01056       { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
01057       { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
01058       { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
01059       { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
01060       { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
01061       { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
01062       { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
01063       { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
01064       { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
01065       { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
01066       { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
01067       { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
01068       { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
01069       { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
01070       { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
01071       { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
01072       { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
01073       { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
01074       { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
01075       { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
01076       { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
01077       {   none,   none,   none,   none, none }, /* L Ctrl */
01078       { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
01079       { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
01080       { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
01081       { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
01082       { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
01083       { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
01084       { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
01085       { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
01086       { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
01087       { 0x273b, 0x273a,   none,   none, none }, /* ;: */
01088       { 0x2827, 0x2822,   none,   none, none }, /* '" */
01089       { 0x2960, 0x297e,   none,   none, none }, /* `~ */
01090       {   none,   none,   none,   none, none }, /* L shift */
01091       { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
01092       { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
01093       { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
01094       { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
01095       { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
01096       { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
01097       { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
01098       { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
01099       { 0x332c, 0x333c,   none,   none, none }, /* ,< */
01100       { 0x342e, 0x343e,   none,   none, none }, /* .> */
01101       { 0x352f, 0x353f,   none,   none, none }, /* /? */
01102       {   none,   none,   none,   none, none }, /* R Shift */
01103       { 0x372a, 0x372a,   none,   none, none }, /* * */
01104       {   none,   none,   none,   none, none }, /* L Alt */
01105       { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
01106       {   none,   none,   none,   none, none }, /* caps lock */
01107       { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
01108       { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
01109       { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
01110       { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
01111       { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
01112       { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
01113       { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
01114       { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
01115       { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
01116       { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
01117       {   none,   none,   none,   none, none }, /* Num Lock */
01118       {   none,   none,   none,   none, none }, /* Scroll Lock */
01119       { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
01120       { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
01121       { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
01122       { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
01123       { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
01124       { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
01125       { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
01126       { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
01127       { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
01128       { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
01129       { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
01130       { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
01131       { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
01132       {   none,   none,   none,   none, none },
01133       {   none,   none,   none,   none, none },
01134       {   none,   none,   none,   none, none },
01135       { 0x5700, 0x5700,   none,   none, none }, /* F11 */
01136       { 0x5800, 0x5800,   none,   none, none }  /* F12 */
01137       };
01138 
01139   Bit8u
01140 inb(port)
01141   Bit16u port;
01142 {
01143 ASM_START
01144   push bp
01145   mov  bp, sp
01146 
01147     push dx
01148     mov  dx, 4[bp]
01149     in   al, dx
01150     pop  dx
01151 
01152   pop  bp
01153 ASM_END
01154 }
01155 
01156 #if BX_USE_ATADRV
01157   Bit16u
01158 inw(port)
01159   Bit16u port;
01160 {
01161 ASM_START
01162   push bp
01163   mov  bp, sp
01164 
01165     push dx
01166     mov  dx, 4[bp]
01167     in   ax, dx
01168     pop  dx
01169 
01170   pop  bp
01171 ASM_END
01172 }
01173 #endif
01174 
01175   void
01176 outb(port, val)
01177   Bit16u port;
01178   Bit8u  val;
01179 {
01180 ASM_START
01181   push bp
01182   mov  bp, sp
01183 
01184     push ax
01185     push dx
01186     mov  dx, 4[bp]
01187     mov  al, 6[bp]
01188     out  dx, al
01189     pop  dx
01190     pop  ax
01191 
01192   pop  bp
01193 ASM_END
01194 }
01195 
01196 #if BX_USE_ATADRV
01197   void
01198 outw(port, val)
01199   Bit16u port;
01200   Bit16u  val;
01201 {
01202 ASM_START
01203   push bp
01204   mov  bp, sp
01205 
01206     push ax
01207     push dx
01208     mov  dx, 4[bp]
01209     mov  ax, 6[bp]
01210     out  dx, ax
01211     pop  dx
01212     pop  ax
01213 
01214   pop  bp
01215 ASM_END
01216 }
01217 #endif
01218 
01219   void
01220 outb_cmos(cmos_reg, val)
01221   Bit8u cmos_reg;
01222   Bit8u val;
01223 {
01224 ASM_START
01225   push bp
01226   mov  bp, sp
01227 
01228     mov  al, 4[bp] ;; cmos_reg
01229     out  0x70, al
01230     mov  al, 6[bp] ;; val
01231     out  0x71, al
01232 
01233   pop  bp
01234 ASM_END
01235 }
01236 
01237   Bit8u
01238 inb_cmos(cmos_reg)
01239   Bit8u cmos_reg;
01240 {
01241 ASM_START
01242   push bp
01243   mov  bp, sp
01244 
01245     mov  al, 4[bp] ;; cmos_reg
01246     out 0x70, al
01247     in  al, 0x71
01248 
01249   pop  bp
01250 ASM_END
01251 }
01252 
01253   void
01254 init_rtc()
01255 {
01256   outb_cmos(0x0a, 0x26);
01257   outb_cmos(0x0b, 0x02);
01258   inb_cmos(0x0c);
01259   inb_cmos(0x0d);
01260 }
01261 
01262   bx_bool
01263 rtc_updating()
01264 {
01265   // This function checks to see if the update-in-progress bit
01266   // is set in CMOS Status Register A.  If not, it returns 0.
01267   // If it is set, it tries to wait until there is a transition
01268   // to 0, and will return 0 if such a transition occurs.  A 1
01269   // is returned only after timing out.  The maximum period
01270   // that this bit should be set is constrained to 244useconds.
01271   // The count I use below guarantees coverage or more than
01272   // this time, with any reasonable IPS setting.
01273 
01274   Bit16u count;
01275 
01276   count = 25000;
01277   while (--count != 0) {
01278     if ( (inb_cmos(0x0a) & 0x80) == 0 )
01279       return(0);
01280     }
01281   return(1); // update-in-progress never transitioned to 0
01282 }
01283 
01284 
01285   Bit8u
01286 read_byte(seg, offset)
01287   Bit16u seg;
01288   Bit16u offset;
01289 {
01290 ASM_START
01291   push bp
01292   mov  bp, sp
01293 
01294     push bx
01295     push ds
01296     mov  ax, 4[bp] ; segment
01297     mov  ds, ax
01298     mov  bx, 6[bp] ; offset
01299     mov  al, [bx]
01300     ;; al = return value (byte)
01301     pop  ds
01302     pop  bx
01303 
01304   pop  bp
01305 ASM_END
01306 }
01307 
01308   Bit16u
01309 read_word(seg, offset)
01310   Bit16u seg;
01311   Bit16u offset;
01312 {
01313 ASM_START
01314   push bp
01315   mov  bp, sp
01316 
01317     push bx
01318     push ds
01319     mov  ax, 4[bp] ; segment
01320     mov  ds, ax
01321     mov  bx, 6[bp] ; offset
01322     mov  ax, [bx]
01323     ;; ax = return value (word)
01324     pop  ds
01325     pop  bx
01326 
01327   pop  bp
01328 ASM_END
01329 }
01330 
01331   void
01332 write_byte(seg, offset, data)
01333   Bit16u seg;
01334   Bit16u offset;
01335   Bit8u data;
01336 {
01337 ASM_START
01338   push bp
01339   mov  bp, sp
01340 
01341     push ax
01342     push bx
01343     push ds
01344     mov  ax, 4[bp] ; segment
01345     mov  ds, ax
01346     mov  bx, 6[bp] ; offset
01347     mov  al, 8[bp] ; data byte
01348     mov  [bx], al  ; write data byte
01349     pop  ds
01350     pop  bx
01351     pop  ax
01352 
01353   pop  bp
01354 ASM_END
01355 }
01356 
01357   void
01358 write_word(seg, offset, data)
01359   Bit16u seg;
01360   Bit16u offset;
01361   Bit16u data;
01362 {
01363 ASM_START
01364   push bp
01365   mov  bp, sp
01366 
01367     push ax
01368     push bx
01369     push ds
01370     mov  ax, 4[bp] ; segment
01371     mov  ds, ax
01372     mov  bx, 6[bp] ; offset
01373     mov  ax, 8[bp] ; data word
01374     mov  [bx], ax  ; write data word
01375     pop  ds
01376     pop  bx
01377     pop  ax
01378 
01379   pop  bp
01380 ASM_END
01381 }
01382 
01383   Bit16u
01384 get_CS()
01385 {
01386 ASM_START
01387   mov  ax, cs
01388 ASM_END
01389 }
01390 
01391   Bit16u
01392 get_SS()
01393 {
01394 ASM_START
01395   mov  ax, ss
01396 ASM_END
01397 }
01398 
01399 #if BX_DEBUG_SERIAL
01400 /* serial debug port*/
01401 #define BX_DEBUG_PORT 0x03f8
01402 
01403 /* data */
01404 #define UART_RBR 0x00
01405 #define UART_THR 0x00
01406 
01407 /* control */
01408 #define UART_IER 0x01
01409 #define UART_IIR 0x02
01410 #define UART_FCR 0x02
01411 #define UART_LCR 0x03
01412 #define UART_MCR 0x04
01413 #define UART_DLL 0x00
01414 #define UART_DLM 0x01
01415 
01416 /* status */
01417 #define UART_LSR 0x05
01418 #define UART_MSR 0x06
01419 #define UART_SCR 0x07
01420 
01421 int uart_can_tx_byte(base_port)
01422     Bit16u base_port;
01423 {
01424     return inb(base_port + UART_LSR) & 0x20;
01425 }
01426 
01427 void uart_wait_to_tx_byte(base_port)
01428     Bit16u base_port;
01429 {
01430     while (!uart_can_tx_byte(base_port));
01431 }
01432 
01433 void uart_wait_until_sent(base_port)
01434     Bit16u base_port;
01435 {
01436     while (!(inb(base_port + UART_LSR) & 0x40));
01437 }
01438 
01439 void uart_tx_byte(base_port, data)
01440     Bit16u base_port;
01441     Bit8u data;
01442 {
01443     uart_wait_to_tx_byte(base_port);
01444     outb(base_port + UART_THR, data);
01445     uart_wait_until_sent(base_port);
01446 }
01447 #endif
01448 
01449   void
01450 wrch(c)
01451   Bit8u  c;
01452 {
01453   ASM_START
01454   push bp
01455   mov  bp, sp
01456 
01457   push bx
01458   mov  ah, #0x0e
01459   mov  al, 4[bp]
01460   xor  bx,bx
01461   int  #0x10
01462   pop  bx
01463 
01464   pop  bp
01465   ASM_END
01466 }
01467  
01468   void
01469 send(action, c)
01470   Bit16u action;
01471   Bit8u  c;
01472 {
01473 #if BX_DEBUG_SERIAL
01474   if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
01475   uart_tx_byte(BX_DEBUG_PORT, c);
01476 #endif
01477 #if BX_VIRTUAL_PORTS
01478   if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
01479   if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
01480 #endif
01481   if (action & BIOS_PRINTF_SCREEN) {
01482     if (c == '\n') wrch('\r');
01483     wrch(c);
01484   }
01485 }
01486 
01487   void
01488 put_int(action, val, width, neg)
01489   Bit16u action;
01490   short val, width;
01491   bx_bool neg;
01492 {
01493   short nval = val / 10;
01494   if (nval)
01495     put_int(action, nval, width - 1, neg);
01496   else {
01497     while (--width > 0) send(action, ' ');
01498     if (neg) send(action, '-');
01499   }
01500   send(action, val - (nval * 10) + '0');
01501 }
01502 
01503   void
01504 put_uint(action, val, width, neg)
01505   Bit16u action;
01506   unsigned short val;
01507   short width;
01508   bx_bool neg;
01509 {
01510   unsigned short nval = val / 10;
01511   if (nval)
01512     put_uint(action, nval, width - 1, neg);
01513   else {
01514     while (--width > 0) send(action, ' ');
01515     if (neg) send(action, '-');
01516   }
01517   send(action, val - (nval * 10) + '0');
01518 }
01519 
01520   void
01521 put_luint(action, val, width, neg)
01522   Bit16u action;
01523   unsigned long val;
01524   short width;
01525   bx_bool neg;
01526 {
01527   unsigned long nval = val / 10;
01528   if (nval)
01529     put_luint(action, nval, width - 1, neg);
01530   else {
01531     while (--width > 0) send(action, ' ');
01532     if (neg) send(action, '-');
01533   }
01534   send(action, val - (nval * 10) + '0');
01535 }
01536 
01537 //--------------------------------------------------------------------------
01538 // bios_printf()
01539 //   A compact variable argument printf function which prints its output via
01540 //   an I/O port so that it can be logged by Bochs/Plex.  
01541 //   Currently, only %x is supported (or %02x, %04x, etc).
01542 //
01543 //   Supports %[format_width][format]
01544 //   where format can be d,x,c,s
01545 //--------------------------------------------------------------------------
01546   void
01547 bios_printf(action, s)
01548   Bit16u action;
01549   Bit8u *s;
01550 {
01551   Bit8u c, format_char;
01552   bx_bool  in_format;
01553   short i;
01554   Bit16u  *arg_ptr;
01555   Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width;
01556 
01557   arg_ptr = &s;
01558   arg_seg = get_SS();
01559 
01560   in_format = 0;
01561   format_width = 0;
01562 
01563   if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
01564 #if BX_VIRTUAL_PORTS
01565     outb(PANIC_PORT2, 0x00);
01566 #endif
01567     bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
01568   }
01569 
01570   while (c = read_byte(get_CS(), s)) {
01571     if ( c == '%' ) {
01572       in_format = 1;
01573       format_width = 0;
01574       }
01575     else if (in_format) {
01576       if ( (c>='0') && (c<='9') ) {
01577         format_width = (format_width * 10) + (c - '0');
01578         }
01579       else {
01580         arg_ptr++; // increment to next arg
01581         arg = read_word(arg_seg, arg_ptr);
01582         if (c == 'x') {
01583           if (format_width == 0)
01584             format_width = 4;
01585           for (i=format_width-1; i>=0; i--) {
01586             nibble = (arg >> (4 * i)) & 0x000f;
01587             send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
01588             }
01589           }
01590         else if (c == 'u') {
01591           put_uint(action, arg, format_width, 0);
01592           }
01593         else if (c == 'l') {
01594           s++;
01595           arg_ptr++; /* increment to next arg */
01596           hibyte = read_word(arg_seg, arg_ptr);
01597           put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
01598           }
01599         else if (c == 'd') {
01600           if (arg & 0x8000)
01601             put_int(action, -arg, format_width - 1, 1);
01602           else
01603             put_int(action, arg, format_width, 0);
01604           }
01605         else if (c == 's') {
01606           bios_printf(action & (~BIOS_PRINTF_HALT), arg);
01607           }
01608         else if (c == 'c') {
01609           send(action, arg);
01610           }
01611         else
01612           BX_PANIC("bios_printf: unknown format\n");
01613           in_format = 0;
01614         }
01615       }
01616     else {
01617       send(action, c);
01618       }
01619     s ++;
01620     }
01621 
01622   if (action & BIOS_PRINTF_HALT) {
01623     // freeze in a busy loop.  
01624 ASM_START
01625     cli
01626  halt2_loop:
01627     hlt
01628     jmp halt2_loop
01629 ASM_END
01630     }
01631 }
01632 
01633 //--------------------------------------------------------------------------
01634 // keyboard_init
01635 //--------------------------------------------------------------------------
01636 // this file is based on coreboot implementation of keyboard.c
01637 // could convert to #asm to gain space
01638   void
01639 keyboard_init()
01640 {
01641 #ifndef COREBOOT 
01642     Bit16u max;
01643 
01644     /* ------------------- Flush buffers ------------------------*/
01645     /* Wait until buffer is empty */
01646     max=0xffff;
01647     while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
01648 
01649     /* flush incoming keys */
01650     max=0x2000;
01651     while (--max > 0) {
01652         outb(0x80, 0x00);
01653         if (inb(0x64) & 0x01) {
01654             inb(0x60);
01655             max = 0x2000;
01656             }
01657         }
01658   
01659     // Due to timer issues, and if the IPS setting is > 15000000, 
01660     // the incoming keys might not be flushed here. That will
01661     // cause a panic a few lines below.  See sourceforge bug report :
01662     // [ 642031 ] FATAL: Keyboard RESET error:993
01663 
01664     /* ------------------- controller side ----------------------*/
01665     /* send cmd = 0xAA, self test 8042 */
01666     outb(0x64, 0xaa);
01667 
01668     /* Wait until buffer is empty */
01669     max=0xffff;
01670     while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00);
01671     if (max==0x0) keyboard_panic(00);
01672 
01673     /* Wait for data */
01674     max=0xffff;
01675     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x01);
01676     if (max==0x0) keyboard_panic(01);
01677 
01678     /* read self-test result, 0x55 should be returned from 0x60 */
01679     if ((inb(0x60) != 0x55)){
01680         keyboard_panic(991);
01681     }
01682 
01683     /* send cmd = 0xAB, keyboard interface test */
01684     outb(0x64,0xab);
01685 
01686     /* Wait until buffer is empty */
01687     max=0xffff;
01688     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
01689     if (max==0x0) keyboard_panic(10);
01690 
01691     /* Wait for data */
01692     max=0xffff;
01693     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
01694     if (max==0x0) keyboard_panic(11);
01695 
01696     /* read keyboard interface test result, */
01697     /* 0x00 should be returned form 0x60 */
01698     if ((inb(0x60) != 0x00)) {
01699         keyboard_panic(992);
01700     }
01701 
01702     /* Enable Keyboard clock */
01703     outb(0x64,0xae);
01704     outb(0x64,0xa8);
01705 
01706     /* ------------------- keyboard side ------------------------*/
01707     /* reset kerboard and self test  (keyboard side) */
01708     outb(0x60, 0xff);
01709 
01710     /* Wait until buffer is empty */
01711     max=0xffff;
01712     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
01713     if (max==0x0) keyboard_panic(20);
01714 
01715     /* Wait for data */
01716     max=0xffff;
01717     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
01718     if (max==0x0) keyboard_panic(21);
01719 
01720     /* keyboard should return ACK */
01721     if ((inb(0x60) != 0xfa)) {
01722         keyboard_panic(993);
01723     }
01724 
01725     /* Wait for data */
01726     max=0xffff;
01727     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
01728     if (max==0x0) keyboard_panic(31);
01729 
01730     if ((inb(0x60) != 0xaa)) {
01731         keyboard_panic(994);
01732     }
01733 
01734     /* Disable keyboard */
01735     outb(0x60, 0xf5);
01736 
01737     /* Wait until buffer is empty */
01738     max=0xffff;
01739     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
01740     if (max==0x0) keyboard_panic(40);
01741 
01742     /* Wait for data */
01743     max=0xffff;
01744     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
01745     if (max==0x0) keyboard_panic(41);
01746 
01747     /* keyboard should return ACK */
01748     if ((inb(0x60) != 0xfa)) {
01749         keyboard_panic(995);
01750     }
01751 
01752     /* Write Keyboard Mode */
01753     outb(0x64, 0x60);
01754 
01755     /* Wait until buffer is empty */
01756     max=0xffff;
01757     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
01758     if (max==0x0) keyboard_panic(50);
01759 
01760     /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
01761     outb(0x60, 0x61);
01762 
01763     /* Wait until buffer is empty */
01764     max=0xffff;
01765     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
01766     if (max==0x0) keyboard_panic(60);
01767 
01768     /* Enable keyboard */
01769     outb(0x60, 0xf4);
01770 
01771     /* Wait until buffer is empty */
01772     max=0xffff;
01773     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
01774     if (max==0x0) keyboard_panic(70);
01775 
01776     /* Wait for data */
01777     max=0xffff;
01778     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
01779     if (max==0x0) keyboard_panic(70);
01780 
01781     /* keyboard should return ACK */
01782     if ((inb(0x60) != 0xfa)) {
01783         keyboard_panic(996);
01784     }
01785 
01786     outb(0x80, 0x77);
01787 #endif
01788 }
01789 
01790 //--------------------------------------------------------------------------
01791 // keyboard_panic
01792 //--------------------------------------------------------------------------
01793   void
01794 keyboard_panic(status)
01795   Bit16u status;
01796 {
01797   // If you're getting a 993 keyboard panic here, 
01798   // please see the comment in keyboard_init
01799   
01800   BX_PANIC("Keyboard error:%u\n",status);
01801 }
01802 
01803 //--------------------------------------------------------------------------
01804 // shutdown_status_panic
01805 //   called when the shutdown statsu is not implemented, displays the status
01806 //--------------------------------------------------------------------------
01807   void
01808 shutdown_status_panic(status)
01809   Bit16u status;
01810 {
01811   BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
01812 }
01813 
01814 //--------------------------------------------------------------------------
01815 // print_bios_banner
01816 //   displays a the bios version
01817 //--------------------------------------------------------------------------
01818 void
01819 print_bios_banner()
01820 {
01821   printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
01822     BIOS_BUILD_DATE, bios_cvs_version_string);
01823   printf(
01824 #ifdef BX_PCIBIOS
01825   "pcibios "
01826 #endif
01827 #ifdef BX_ELTORITO_BOOT
01828   "eltorito "
01829 #endif
01830   "\n\n");
01831 }
01832 
01833 //--------------------------------------------------------------------------
01834 // print_boot_device
01835 //   displays the boot device
01836 //--------------------------------------------------------------------------
01837 
01838 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
01839 
01840 void
01841 print_boot_device(cdboot, drive)
01842   Bit8u cdboot; Bit16u drive;
01843 {
01844   Bit8u i;
01845 
01846   // cdboot contains 0 if floppy/harddisk, 1 otherwise
01847   // drive contains real/emulated boot drive
01848 
01849   if(cdboot)i=2;                    // CD-Rom
01850   else if((drive&0x0080)==0x00)i=0; // Floppy
01851   else if((drive&0x0080)==0x80)i=1; // Hard drive
01852   else return;
01853   
01854   printf("Booting from %s...\n",drivetypes[i]);
01855 }
01856 
01857 //--------------------------------------------------------------------------
01858 // print_boot_failure
01859 //   displays the reason why boot failed
01860 //--------------------------------------------------------------------------
01861   void
01862 print_boot_failure(cdboot, drive, reason, lastdrive)
01863   Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
01864 {
01865   Bit16u drivenum = drive&0x7f;
01866 
01867   // cdboot: 1 if boot from cd, 0 otherwise
01868   // drive : drive number
01869   // reason: 0 signature check failed, 1 read error
01870   // lastdrive: 1 boot drive is the last one in boot sequence
01871  
01872   if (cdboot)
01873     bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
01874   else if (drive & 0x80)
01875     bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
01876   else
01877     bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
01878 
01879   if (lastdrive==1) {
01880     if (reason==0)
01881       BX_PANIC("Not a bootable disk\n");
01882     else
01883       BX_PANIC("Could not read the boot disk\n");
01884   }
01885 }
01886 
01887 //--------------------------------------------------------------------------
01888 // print_cdromboot_failure
01889 //   displays the reason why boot failed
01890 //--------------------------------------------------------------------------
01891   void
01892 print_cdromboot_failure( code )
01893   Bit16u code;
01894 {
01895   bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
01896   
01897   return;
01898 }
01899 
01900 void
01901 nmi_handler_msg()
01902 {
01903   BX_PANIC("NMI Handler called\n");
01904 }
01905 
01906 void
01907 int18_panic_msg()
01908 {
01909   BX_PANIC("INT18: BOOT FAILURE\n");
01910 }
01911 
01912 void
01913 log_bios_start()
01914 {
01915 #if BX_DEBUG_SERIAL
01916   outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
01917 #endif
01918   BX_INFO("%s\n", bios_cvs_version_string);
01919 }
01920 
01921   bx_bool
01922 set_enable_a20(val)
01923   bx_bool val;
01924 {
01925   Bit8u  oldval;
01926 
01927   // Use PS2 System Control port A to set A20 enable
01928 
01929   // get current setting first
01930   oldval = inb(0x92);
01931 
01932   // change A20 status
01933   if (val)
01934     outb(0x92, oldval | 0x02);
01935   else
01936     outb(0x92, oldval & 0xfd);
01937 
01938   return((oldval & 0x02) != 0);
01939 }
01940 
01941   void
01942 debugger_on()
01943 {
01944   outb(0xfedc, 0x01);
01945 }
01946 
01947   void
01948 debugger_off()
01949 {
01950   outb(0xfedc, 0x00);
01951 }
01952 
01953 #if BX_USE_ATADRV
01954 
01955 // ---------------------------------------------------------------------------
01956 // Start of ATA/ATAPI Driver
01957 // ---------------------------------------------------------------------------
01958 
01959 // Global defines -- ATA register and register bits.
01960 // command block & control block regs
01961 #define ATA_CB_DATA  0   // data reg         in/out pio_base_addr1+0
01962 #define ATA_CB_ERR   1   // error            in     pio_base_addr1+1
01963 #define ATA_CB_FR    1   // feature reg         out pio_base_addr1+1
01964 #define ATA_CB_SC    2   // sector count     in/out pio_base_addr1+2
01965 #define ATA_CB_SN    3   // sector number    in/out pio_base_addr1+3
01966 #define ATA_CB_CL    4   // cylinder low     in/out pio_base_addr1+4
01967 #define ATA_CB_CH    5   // cylinder high    in/out pio_base_addr1+5
01968 #define ATA_CB_DH    6   // device head      in/out pio_base_addr1+6
01969 #define ATA_CB_STAT  7   // primary status   in     pio_base_addr1+7
01970 #define ATA_CB_CMD   7   // command             out pio_base_addr1+7
01971 #define ATA_CB_ASTAT 6   // alternate status in     pio_base_addr2+6
01972 #define ATA_CB_DC    6   // device control      out pio_base_addr2+6
01973 #define ATA_CB_DA    7   // device address   in     pio_base_addr2+7
01974 
01975 #define ATA_CB_ER_ICRC 0x80    // ATA Ultra DMA bad CRC
01976 #define ATA_CB_ER_BBK  0x80    // ATA bad block
01977 #define ATA_CB_ER_UNC  0x40    // ATA uncorrected error
01978 #define ATA_CB_ER_MC   0x20    // ATA media change
01979 #define ATA_CB_ER_IDNF 0x10    // ATA id not found
01980 #define ATA_CB_ER_MCR  0x08    // ATA media change request
01981 #define ATA_CB_ER_ABRT 0x04    // ATA command aborted
01982 #define ATA_CB_ER_NTK0 0x02    // ATA track 0 not found
01983 #define ATA_CB_ER_NDAM 0x01    // ATA address mark not found
01984 
01985 #define ATA_CB_ER_P_SNSKEY 0xf0   // ATAPI sense key (mask)
01986 #define ATA_CB_ER_P_MCR    0x08   // ATAPI Media Change Request
01987 #define ATA_CB_ER_P_ABRT   0x04   // ATAPI command abort
01988 #define ATA_CB_ER_P_EOM    0x02   // ATAPI End of Media
01989 #define ATA_CB_ER_P_ILI    0x01   // ATAPI Illegal Length Indication
01990 
01991 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
01992 #define ATA_CB_SC_P_TAG    0xf8   // ATAPI tag (mask)
01993 #define ATA_CB_SC_P_REL    0x04   // ATAPI release
01994 #define ATA_CB_SC_P_IO     0x02   // ATAPI I/O
01995 #define ATA_CB_SC_P_CD     0x01   // ATAPI C/D
01996 
01997 // bits 7-4 of the device/head (CB_DH) reg
01998 #define ATA_CB_DH_DEV0 0xa0    // select device 0
01999 #define ATA_CB_DH_DEV1 0xb0    // select device 1
02000 
02001 // status reg (CB_STAT and CB_ASTAT) bits
02002 #define ATA_CB_STAT_BSY  0x80  // busy
02003 #define ATA_CB_STAT_RDY  0x40  // ready
02004 #define ATA_CB_STAT_DF   0x20  // device fault
02005 #define ATA_CB_STAT_WFT  0x20  // write fault (old name)
02006 #define ATA_CB_STAT_SKC  0x10  // seek complete
02007 #define ATA_CB_STAT_SERV 0x10  // service
02008 #define ATA_CB_STAT_DRQ  0x08  // data request
02009 #define ATA_CB_STAT_CORR 0x04  // corrected
02010 #define ATA_CB_STAT_IDX  0x02  // index
02011 #define ATA_CB_STAT_ERR  0x01  // error (ATA)
02012 #define ATA_CB_STAT_CHK  0x01  // check (ATAPI)
02013 
02014 // device control reg (CB_DC) bits
02015 #define ATA_CB_DC_HD15   0x08  // bit should always be set to one
02016 #define ATA_CB_DC_SRST   0x04  // soft reset
02017 #define ATA_CB_DC_NIEN   0x02  // disable interrupts
02018 
02019 // Most mandtory and optional ATA commands (from ATA-3),
02020 #define ATA_CMD_CFA_ERASE_SECTORS            0xC0
02021 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
02022 #define ATA_CMD_CFA_TRANSLATE_SECTOR         0x87
02023 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
02024 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
02025 #define ATA_CMD_CHECK_POWER_MODE1            0xE5
02026 #define ATA_CMD_CHECK_POWER_MODE2            0x98
02027 #define ATA_CMD_DEVICE_RESET                 0x08
02028 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
02029 #define ATA_CMD_FLUSH_CACHE                  0xE7
02030 #define ATA_CMD_FORMAT_TRACK                 0x50
02031 #define ATA_CMD_IDENTIFY_DEVICE              0xEC
02032 #define ATA_CMD_IDENTIFY_DEVICE_PACKET       0xA1
02033 #define ATA_CMD_IDENTIFY_PACKET_DEVICE       0xA1
02034 #define ATA_CMD_IDLE1                        0xE3
02035 #define ATA_CMD_IDLE2                        0x97
02036 #define ATA_CMD_IDLE_IMMEDIATE1              0xE1
02037 #define ATA_CMD_IDLE_IMMEDIATE2              0x95
02038 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS  0x91
02039 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
02040 #define ATA_CMD_NOP                          0x00
02041 #define ATA_CMD_PACKET                       0xA0
02042 #define ATA_CMD_READ_BUFFER                  0xE4
02043 #define ATA_CMD_READ_DMA                     0xC8
02044 #define ATA_CMD_READ_DMA_QUEUED              0xC7
02045 #define ATA_CMD_READ_MULTIPLE                0xC4
02046 #define ATA_CMD_READ_SECTORS                 0x20
02047 #define ATA_CMD_READ_VERIFY_SECTORS          0x40
02048 #define ATA_CMD_RECALIBRATE                  0x10
02049 #define ATA_CMD_SEEK                         0x70
02050 #define ATA_CMD_SET_FEATURES                 0xEF
02051 #define ATA_CMD_SET_MULTIPLE_MODE            0xC6
02052 #define ATA_CMD_SLEEP1                       0xE6
02053 #define ATA_CMD_SLEEP2                       0x99
02054 #define ATA_CMD_STANDBY1                     0xE2
02055 #define ATA_CMD_STANDBY2                     0x96
02056 #define ATA_CMD_STANDBY_IMMEDIATE1           0xE0
02057 #define ATA_CMD_STANDBY_IMMEDIATE2           0x94
02058 #define ATA_CMD_WRITE_BUFFER                 0xE8
02059 #define ATA_CMD_WRITE_DMA                    0xCA
02060 #define ATA_CMD_WRITE_DMA_QUEUED             0xCC
02061 #define ATA_CMD_WRITE_MULTIPLE               0xC5
02062 #define ATA_CMD_WRITE_SECTORS                0x30
02063 #define ATA_CMD_WRITE_VERIFY                 0x3C
02064 
02065 #define ATA_IFACE_NONE    0x00
02066 #define ATA_IFACE_ISA     0x00
02067 #define ATA_IFACE_PCI     0x01
02068 
02069 #define ATA_TYPE_NONE     0x00
02070 #define ATA_TYPE_UNKNOWN  0x01
02071 #define ATA_TYPE_ATA      0x02
02072 #define ATA_TYPE_ATAPI    0x03
02073 
02074 #define ATA_DEVICE_NONE  0x00
02075 #define ATA_DEVICE_HD    0xFF
02076 #define ATA_DEVICE_CDROM 0x05
02077 
02078 #define ATA_MODE_NONE    0x00
02079 #define ATA_MODE_PIO16   0x00
02080 #define ATA_MODE_PIO32   0x01
02081 #define ATA_MODE_ISADMA  0x02
02082 #define ATA_MODE_PCIDMA  0x03
02083 #define ATA_MODE_USEIRQ  0x10
02084 
02085 #define ATA_TRANSLATION_NONE  0
02086 #define ATA_TRANSLATION_LBA   1
02087 #define ATA_TRANSLATION_LARGE 2
02088 #define ATA_TRANSLATION_RECHS 3
02089 
02090 #define ATA_DATA_NO      0x00
02091 #define ATA_DATA_IN      0x01
02092 #define ATA_DATA_OUT     0x02
02093   
02094 // ---------------------------------------------------------------------------
02095 // ATA/ATAPI driver : initialization
02096 // ---------------------------------------------------------------------------
02097 void ata_init( )
02098 {
02099   Bit16u ebda_seg=read_word(0x0040,0x000E);
02100   Bit8u  channel, device;
02101 
02102   // Channels info init. 
02103   for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
02104     write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
02105     write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
02106     write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
02107     write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
02108     }
02109 
02110   // Devices info init. 
02111   for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
02112     write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
02113     write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
02114     write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
02115     write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
02116     write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
02117     write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
02118     write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
02119     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
02120     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
02121     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
02122     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
02123     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
02124     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
02125     
02126     write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
02127     }
02128 
02129   // hdidmap  and cdidmap init. 
02130   for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
02131     write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
02132     write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
02133     }
02134 
02135   write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
02136   write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
02137 }
02138 
02139 // ---------------------------------------------------------------------------
02140 // ATA/ATAPI driver : device detection
02141 // ---------------------------------------------------------------------------
02142 
02143 void ata_detect( )
02144 {
02145   Bit16u ebda_seg=read_word(0x0040,0x000E);
02146   Bit8u  hdcount, cdcount, device, type;
02147   Bit8u  buffer[0x0200];
02148   Bit16u i;
02149 
02150 #if BX_MAX_ATA_INTERFACES > 0
02151   write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
02152   write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
02153   write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
02154   write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
02155 #endif
02156 #if BX_MAX_ATA_INTERFACES > 1
02157   write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
02158   write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
02159   write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
02160   write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
02161 #endif
02162 #if BX_MAX_ATA_INTERFACES > 2
02163   write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
02164   write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
02165   write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
02166   write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
02167 #endif
02168 #if BX_MAX_ATA_INTERFACES > 3
02169   write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
02170   write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
02171   write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
02172   write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
02173 #endif
02174 #if BX_MAX_ATA_INTERFACES > 4
02175 #error Please fill the ATA interface informations
02176 #endif
02177 
02178   // Device detection
02179   hdcount=cdcount=0;
02180   
02181   for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
02182     Bit16u iobase1, iobase2;
02183     Bit8u  channel, slave, shift;
02184     Bit8u  sc, sn, cl, ch, st;
02185 
02186     channel = device / 2;
02187     slave = device % 2;
02188 
02189     iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
02190     iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
02191 
02192     // Disable interrupts
02193     outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
02194 
02195     // Look for device
02196     outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
02197     outb(iobase1+ATA_CB_SC, 0x55);
02198     outb(iobase1+ATA_CB_SN, 0xaa);
02199     outb(iobase1+ATA_CB_SC, 0xaa);
02200     outb(iobase1+ATA_CB_SN, 0x55);
02201     outb(iobase1+ATA_CB_SC, 0x55);
02202     outb(iobase1+ATA_CB_SN, 0xaa);
02203 
02204     // If we found something
02205     sc = inb(iobase1+ATA_CB_SC);
02206     sn = inb(iobase1+ATA_CB_SN);
02207 
02208     if ( (sc == 0x55) && (sn == 0xaa) ) {
02209       write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
02210     
02211       // reset the channel
02212       ata_reset(device);
02213       
02214       // check for ATA or ATAPI
02215       outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
02216       sc = inb(iobase1+ATA_CB_SC);
02217       sn = inb(iobase1+ATA_CB_SN);
02218       if ((sc==0x01) && (sn==0x01)) {
02219         cl = inb(iobase1+ATA_CB_CL);
02220         ch = inb(iobase1+ATA_CB_CH);
02221         st = inb(iobase1+ATA_CB_STAT);
02222 
02223         if ((cl==0x14) && (ch==0xeb)) {
02224           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
02225         } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
02226           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
02227         } else if ((cl==0xff) && (ch==0xff)) {
02228           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
02229         }
02230       }
02231     }
02232 
02233     type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
02234     
02235     // Now we send a IDENTIFY command to ATA device 
02236     if(type == ATA_TYPE_ATA) {
02237       Bit32u sectors;
02238       Bit16u cylinders, heads, spt, blksize;
02239       Bit8u  translation, removable, mode;
02240 
02241       //Temporary values to do the transfer
02242       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
02243       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
02244 
02245       if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
02246         BX_PANIC("ata-detect: Failed to detect ATA device\n");
02247 
02248       removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
02249       mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
02250       blksize   = read_word(get_SS(),buffer+10);
02251       
02252       cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
02253       heads     = read_word(get_SS(),buffer+(3*2)); // word 3
02254       spt       = read_word(get_SS(),buffer+(6*2)); // word 6
02255 
02256       sectors   = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
02257 
02258       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
02259       write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
02260       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
02261       write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
02262       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
02263       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
02264       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
02265       write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
02266       BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
02267 
02268       translation = inb_cmos(0x39 + channel/2);
02269       for (shift=device%4; shift>0; shift--) translation >>= 2;
02270       translation &= 0x03;
02271 
02272       write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
02273 
02274       switch (translation) {
02275         case ATA_TRANSLATION_NONE:
02276           BX_INFO("none");
02277           break;
02278         case ATA_TRANSLATION_LBA:
02279           BX_INFO("lba");
02280           break;
02281         case ATA_TRANSLATION_LARGE:
02282           BX_INFO("large");
02283           break;
02284         case ATA_TRANSLATION_RECHS:
02285           BX_INFO("r-echs");
02286           break;
02287         }
02288       switch (translation) {
02289         case ATA_TRANSLATION_NONE:
02290           break;
02291         case ATA_TRANSLATION_LBA:
02292           spt = 63;
02293           sectors /= 63;
02294           heads = sectors / 1024;
02295           if (heads>128) heads = 255;
02296           else if (heads>64) heads = 128;
02297           else if (heads>32) heads = 64;
02298           else if (heads>16) heads = 32;
02299           else heads=16;
02300           cylinders = sectors / heads;
02301           break;
02302         case ATA_TRANSLATION_RECHS:
02303           // Take care not to overflow
02304           if (heads==16) {
02305             if(cylinders>61439) cylinders=61439;
02306             heads=15;
02307             cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
02308             }
02309           // then go through the large bitshift process
02310         case ATA_TRANSLATION_LARGE:
02311           while(cylinders > 1024) {
02312             cylinders >>= 1;
02313             heads <<= 1;
02314 
02315             // If we max out the head count
02316             if (heads > 127) break;
02317           }
02318           break;
02319         }
02320       // clip to 1024 cylinders in lchs
02321       if (cylinders > 1024) cylinders=1024;
02322       BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
02323 
02324       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
02325       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
02326       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
02327  
02328       // fill hdidmap 
02329       write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
02330       hdcount++;
02331       }
02332     
02333     // Now we send a IDENTIFY command to ATAPI device
02334     if(type == ATA_TYPE_ATAPI) {
02335  
02336       Bit8u  type, removable, mode;
02337       Bit16u blksize;
02338 
02339       //Temporary values to do the transfer
02340       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
02341       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
02342 
02343       if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
02344         BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
02345 
02346       type      = read_byte(get_SS(),buffer+1) & 0x1f;
02347       removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
02348       mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
02349       blksize   = 2048;
02350 
02351       write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
02352       write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
02353       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
02354       write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
02355 
02356       // fill cdidmap 
02357       write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
02358       cdcount++;
02359       }
02360   
02361       {
02362       Bit32u sizeinmb;
02363       Bit16u ataversion;
02364       Bit8u  c, i, version, model[41];
02365       
02366       switch (type) {
02367         case ATA_TYPE_ATA:
02368           sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
02369           sizeinmb >>= 11;
02370         case ATA_TYPE_ATAPI:
02371           // Read ATA/ATAPI version
02372           ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
02373           for(version=15;version>0;version--) { 
02374             if((ataversion&(1<<version))!=0)
02375             break;
02376             }
02377 
02378           // Read model name
02379           for(i=0;i<20;i++){
02380             write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
02381             write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
02382             }
02383 
02384           // Reformat
02385           write_byte(get_SS(),model+40,0x00);
02386           for(i=39;i>0;i--){
02387             if(read_byte(get_SS(),model+i)==0x20)
02388               write_byte(get_SS(),model+i,0x00);
02389             else break;
02390             }
02391           break;
02392         }
02393 
02394       switch (type) {
02395         case ATA_TYPE_ATA:
02396           printf("ata%d %s: ",channel,slave?" slave":"master");
02397           i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
02398           printf(" ATA-%d Hard-Disk (%lu MBytes)\n", version, sizeinmb);
02399           break;
02400         case ATA_TYPE_ATAPI:
02401           printf("ata%d %s: ",channel,slave?" slave":"master");
02402           i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
02403           if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
02404             printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
02405           else
02406             printf(" ATAPI-%d Device\n",version);
02407           break;
02408         case ATA_TYPE_UNKNOWN:
02409           printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
02410           break;
02411         }
02412       }
02413     }
02414 
02415   // Store the devices counts
02416   write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
02417   write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
02418   write_byte(0x40,0x75, hdcount);
02419  
02420   printf("\n");
02421 
02422   // FIXME : should use bios=cmos|auto|disable bits
02423   // FIXME : should know about translation bits
02424   // FIXME : move hard_drive_post here 
02425   
02426 }
02427 
02428 // ---------------------------------------------------------------------------
02429 // ATA/ATAPI driver : software reset 
02430 // ---------------------------------------------------------------------------
02431 // ATA-3
02432 // 8.2.1 Software reset - Device 0
02433 
02434 void   ata_reset(device)
02435 Bit16u device;
02436 {
02437   Bit16u ebda_seg=read_word(0x0040,0x000E);
02438   Bit16u iobase1, iobase2;
02439   Bit8u  channel, slave, sn, sc; 
02440   Bit16u max;
02441 
02442   channel = device / 2;
02443   slave = device % 2;
02444 
02445   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
02446   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
02447 
02448   // Reset
02449 
02450 // 8.2.1 (a) -- set SRST in DC
02451   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
02452 
02453 // 8.2.1 (b) -- wait for BSY
02454   max=0xff;
02455   while(--max>0) {
02456     Bit8u status = inb(iobase1+ATA_CB_STAT);
02457     if ((status & ATA_CB_STAT_BSY) != 0) break;
02458   }
02459 
02460 // 8.2.1 (f) -- clear SRST
02461   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
02462 
02463   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
02464 
02465 // 8.2.1 (g) -- check for sc==sn==0x01
02466     // select device
02467     outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
02468     sc = inb(iobase1+ATA_CB_SC);
02469     sn = inb(iobase1+ATA_CB_SN);
02470 
02471     if ( (sc==0x01) && (sn==0x01) ) {
02472 
02473 // 8.2.1 (h) -- wait for not BSY
02474       max=0xff;
02475       while(--max>0) {
02476         Bit8u status = inb(iobase1+ATA_CB_STAT);
02477         if ((status & ATA_CB_STAT_BSY) == 0) break;
02478         }
02479       }
02480     }
02481 
02482 // 8.2.1 (i) -- wait for DRDY
02483   max=0xfff;
02484   while(--max>0) {
02485     Bit8u status = inb(iobase1+ATA_CB_STAT);
02486       if ((status & ATA_CB_STAT_RDY) != 0) break;
02487   }
02488 
02489   // Enable interrupts
02490   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
02491 }
02492 
02493 // ---------------------------------------------------------------------------
02494 // ATA/ATAPI driver : execute a non data command 
02495 // ---------------------------------------------------------------------------
02496 
02497 Bit16u ata_cmd_non_data()
02498 {return 0;}
02499 
02500 // ---------------------------------------------------------------------------
02501 // ATA/ATAPI driver : execute a data-in command
02502 // ---------------------------------------------------------------------------
02503       // returns
02504       // 0 : no error
02505       // 1 : BUSY bit set
02506       // 2 : read error
02507       // 3 : expected DRQ=1
02508       // 4 : no sectors left to read/verify
02509       // 5 : more sectors to read/verify
02510       // 6 : no sectors left to write
02511       // 7 : more sectors to write
02512 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
02513 Bit16u device, command, count, cylinder, head, sector, segment, offset;
02514 Bit32u lba;
02515 {
02516   Bit16u ebda_seg=read_word(0x0040,0x000E);
02517   Bit16u iobase1, iobase2, blksize;
02518   Bit8u  channel, slave;
02519   Bit8u  status, current, mode;
02520 
02521   channel = device / 2;
02522   slave   = device % 2;
02523 
02524   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
02525   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
02526   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
02527   blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
02528   if (mode == ATA_MODE_PIO32) blksize>>=2;
02529   else blksize>>=1;
02530 
02531   // sector will be 0 only on lba access. Convert to lba-chs
02532   if (sector == 0) {
02533     sector = (Bit16u) (lba & 0x000000ffL);
02534     lba >>= 8;
02535     cylinder = (Bit16u) (lba & 0x0000ffffL);
02536     lba >>= 16;
02537     head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
02538     }
02539 
02540   // Reset count of transferred data
02541   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
02542   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
02543   current = 0;
02544 
02545   status = inb(iobase1 + ATA_CB_STAT);
02546   if (status & ATA_CB_STAT_BSY) return 1;
02547 
02548   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
02549   outb(iobase1 + ATA_CB_FR, 0x00);
02550   outb(iobase1 + ATA_CB_SC, count);
02551   outb(iobase1 + ATA_CB_SN, sector);
02552   outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
02553   outb(iobase1 + ATA_CB_CH, cylinder >> 8);
02554   outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
02555   outb(iobase1 + ATA_CB_CMD, command);
02556 
02557   while (1) {
02558     status = inb(iobase1 + ATA_CB_STAT);
02559     if ( !(status & ATA_CB_STAT_BSY) ) break;
02560     }
02561 
02562   if (status & ATA_CB_STAT_ERR) {
02563     BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
02564     return 2;
02565     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
02566     BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
02567     return 3;
02568   }
02569 
02570   // FIXME : move seg/off translation here
02571 
02572 ASM_START
02573         sti  ;; enable higher priority interrupts
02574 ASM_END
02575 
02576   while (1) {
02577 
02578 ASM_START
02579         push bp
02580         mov  bp, sp
02581         mov  di, _ata_cmd_data_in.offset + 2[bp]  
02582         mov  ax, _ata_cmd_data_in.segment + 2[bp] 
02583         mov  cx, _ata_cmd_data_in.blksize + 2[bp] 
02584 
02585         ;; adjust if there will be an overrun. 2K max sector size
02586         cmp   di, #0xf800 ;; 
02587         jbe   ata_in_no_adjust
02588 
02589 ata_in_adjust:
02590         sub   di, #0x0800 ;; sub 2 kbytes from offset
02591         add   ax, #0x0080 ;; add 2 Kbytes to segment
02592 
02593 ata_in_no_adjust:
02594         mov   es, ax      ;; segment in es
02595 
02596         mov   dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
02597 
02598         mov  ah, _ata_cmd_data_in.mode + 2[bp] 
02599         cmp  ah, #ATA_MODE_PIO32
02600         je   ata_in_32
02601 
02602 ata_in_16:
02603         rep
02604           insw ;; CX words transfered from port(DX) to ES:[DI]
02605         jmp ata_in_done
02606 
02607 ata_in_32:
02608         rep
02609           insd ;; CX dwords transfered from port(DX) to ES:[DI]
02610 
02611 ata_in_done:
02612         mov  _ata_cmd_data_in.offset + 2[bp], di
02613         mov  _ata_cmd_data_in.segment + 2[bp], es
02614         pop  bp
02615 ASM_END
02616 
02617     current++;
02618     write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
02619     count--;
02620     status = inb(iobase1 + ATA_CB_STAT);
02621     if (count == 0) {
02622       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
02623           != ATA_CB_STAT_RDY ) {
02624         BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
02625         return 4;
02626         }
02627       break;
02628       }
02629     else {
02630       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
02631           != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
02632         BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
02633         return 5;
02634       }
02635       continue;
02636     }
02637   }
02638   // Enable interrupts
02639   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
02640   return 0;
02641 }
02642 
02643 // ---------------------------------------------------------------------------
02644 // ATA/ATAPI driver : execute a data-out command
02645 // ---------------------------------------------------------------------------
02646       // returns
02647       // 0 : no error
02648       // 1 : BUSY bit set
02649       // 2 : read error
02650       // 3 : expected DRQ=1
02651       // 4 : no sectors left to read/verify
02652       // 5 : more sectors to read/verify
02653       // 6 : no sectors left to write
02654       // 7 : more sectors to write
02655 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
02656 Bit16u device, command, count, cylinder, head, sector, segment, offset;
02657 Bit32u lba;
02658 {
02659   Bit16u ebda_seg=read_word(0x0040,0x000E);
02660   Bit16u iobase1, iobase2, blksize;
02661   Bit8u  channel, slave;
02662   Bit8u  status, current, mode;
02663 
02664   channel = device / 2;
02665   slave   = device % 2;
02666 
02667   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
02668   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
02669   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
02670   blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
02671   if (mode == ATA_MODE_PIO32) blksize>>=2;
02672   else blksize>>=1;
02673 
02674   // sector will be 0 only on lba access. Convert to lba-chs
02675   if (sector == 0) {
02676     sector = (Bit16u) (lba & 0x000000ffL);
02677     lba >>= 8;
02678     cylinder = (Bit16u) (lba & 0x0000ffffL);
02679     lba >>= 16;
02680     head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
02681     }
02682 
02683   // Reset count of transferred data
02684   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
02685   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
02686   current = 0;
02687 
02688   status = inb(iobase1 + ATA_CB_STAT);
02689   if (status & ATA_CB_STAT_BSY) return 1;
02690 
02691   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
02692   outb(iobase1 + ATA_CB_FR, 0x00);
02693   outb(iobase1 + ATA_CB_SC, count);
02694   outb(iobase1 + ATA_CB_SN, sector);
02695   outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
02696   outb(iobase1 + ATA_CB_CH, cylinder >> 8);
02697   outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
02698   outb(iobase1 + ATA_CB_CMD, command);
02699 
02700   while (1) {
02701     status = inb(iobase1 + ATA_CB_STAT);
02702     if ( !(status & ATA_CB_STAT_BSY) ) break;
02703     }
02704 
02705   if (status & ATA_CB_STAT_ERR) {
02706     BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
02707     return 2;
02708     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
02709     BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
02710     return 3;
02711     }
02712 
02713   // FIXME : move seg/off translation here
02714 
02715 ASM_START
02716         sti  ;; enable higher priority interrupts
02717 ASM_END
02718 
02719   while (1) {
02720 
02721 ASM_START
02722         push bp
02723         mov  bp, sp
02724         mov  si, _ata_cmd_data_out.offset + 2[bp]  
02725         mov  ax, _ata_cmd_data_out.segment + 2[bp] 
02726         mov  cx, _ata_cmd_data_out.blksize + 2[bp] 
02727 
02728         ;; adjust if there will be an overrun. 2K max sector size
02729         cmp   si, #0xf800 ;; 
02730         jbe   ata_out_no_adjust
02731 
02732 ata_out_adjust:
02733         sub   si, #0x0800 ;; sub 2 kbytes from offset
02734         add   ax, #0x0080 ;; add 2 Kbytes to segment
02735 
02736 ata_out_no_adjust:
02737         mov   es, ax      ;; segment in es
02738 
02739         mov   dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
02740 
02741         mov  ah, _ata_cmd_data_out.mode + 2[bp] 
02742         cmp  ah, #ATA_MODE_PIO32
02743         je   ata_out_32
02744 
02745 ata_out_16:
02746         seg ES
02747         rep
02748           outsw ;; CX words transfered from port(DX) to ES:[SI]
02749         jmp ata_out_done
02750 
02751 ata_out_32:
02752         seg ES
02753         rep
02754           outsd ;; CX dwords transfered from port(DX) to ES:[SI]
02755 
02756 ata_out_done:
02757         mov  _ata_cmd_data_out.offset + 2[bp], si
02758         mov  _ata_cmd_data_out.segment + 2[bp], es
02759         pop  bp
02760 ASM_END
02761 
02762     current++;
02763     write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
02764     count--;
02765     status = inb(iobase1 + ATA_CB_STAT);
02766     if (count == 0) {
02767       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
02768           != ATA_CB_STAT_RDY ) {
02769         BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
02770         return 6;
02771         }
02772       break;
02773       }
02774     else {
02775       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
02776           != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
02777         BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
02778         return 7;
02779       }
02780       continue;
02781     }
02782   }
02783   // Enable interrupts
02784   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
02785   return 0;
02786 }
02787 
02788 // ---------------------------------------------------------------------------
02789 // ATA/ATAPI driver : execute a packet command
02790 // ---------------------------------------------------------------------------
02791       // returns
02792       // 0 : no error
02793       // 1 : error in parameters
02794       // 2 : BUSY bit set
02795       // 3 : error
02796       // 4 : not ready
02797 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
02798 Bit8u  cmdlen,inout;
02799 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
02800 Bit16u header;
02801 Bit32u length;
02802 {
02803   Bit16u ebda_seg=read_word(0x0040,0x000E);
02804   Bit16u iobase1, iobase2;
02805   Bit16u lcount, lbefore, lafter, count;
02806   Bit8u  channel, slave;
02807   Bit8u  status, mode, lmode;
02808   Bit32u total, transfer;
02809 
02810   channel = device / 2;
02811   slave = device % 2;
02812 
02813   // Data out is not supported yet
02814   if (inout == ATA_DATA_OUT) {
02815     BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
02816     return 1;
02817     }
02818 
02819   // The header length must be even
02820   if (header & 1) {
02821     BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
02822     return 1;
02823     }
02824 
02825   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
02826   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
02827   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
02828   transfer= 0L;
02829 
02830   if (cmdlen < 12) cmdlen=12;
02831   if (cmdlen > 12) cmdlen=16;
02832   cmdlen>>=1;
02833 
02834   // Reset count of transferred data
02835   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
02836   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
02837 
02838   status = inb(iobase1 + ATA_CB_STAT);
02839   if (status & ATA_CB_STAT_BSY) return 2;
02840 
02841   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
02842   // outb(iobase1 + ATA_CB_FR, 0x00);
02843   // outb(iobase1 + ATA_CB_SC, 0x00);
02844   // outb(iobase1 + ATA_CB_SN, 0x00);
02845   outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
02846   outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
02847   outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
02848   outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
02849 
02850   // Device should ok to receive command
02851   while (1) {
02852     status = inb(iobase1 + ATA_CB_STAT);
02853     if ( !(status & ATA_CB_STAT_BSY) ) break;
02854     }
02855 
02856   if (status & ATA_CB_STAT_ERR) {
02857     BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status);
02858     return 3;
02859     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
02860     BX_DEBUG_ATA("ata_cmd_packet : DRQ not set (status %02x)\n", (unsigned) status);
02861     return 4;
02862     }
02863 
02864   // Normalize address
02865   cmdseg += (cmdoff / 16);
02866   cmdoff %= 16;
02867 
02868   // Send command to device
02869 ASM_START
02870       sti  ;; enable higher priority interrupts
02871  
02872       push bp
02873       mov  bp, sp
02874     
02875       mov  si, _ata_cmd_packet.cmdoff + 2[bp]  
02876       mov  ax, _ata_cmd_packet.cmdseg + 2[bp] 
02877       mov  cx, _ata_cmd_packet.cmdlen + 2[bp] 
02878       mov  es, ax      ;; segment in es
02879 
02880       mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
02881 
02882       seg ES
02883       rep
02884         outsw ;; CX words transfered from port(DX) to ES:[SI]
02885 
02886       pop  bp
02887 ASM_END
02888 
02889   if (inout == ATA_DATA_NO) {
02890     status = inb(iobase1 + ATA_CB_STAT);
02891     }
02892   else {
02893   while (1) {
02894 
02895       status = inb(iobase1 + ATA_CB_STAT);
02896 
02897       // Check if command completed
02898       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
02899 
02900       if (status & ATA_CB_STAT_ERR) {
02901         BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
02902         return 3;
02903       }
02904 
02905       // Device must be ready to send data
02906       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
02907             != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
02908         BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status);
02909         return 4;
02910         }
02911 
02912       // Normalize address
02913       bufseg += (bufoff / 16);
02914       bufoff %= 16;
02915     
02916       // Get the byte count
02917       lcount =  ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
02918 
02919       // adjust to read what we want
02920       if(header>lcount) {
02921          lbefore=lcount;
02922          header-=lcount;
02923          lcount=0;
02924          }
02925       else {
02926         lbefore=header;
02927         header=0;
02928         lcount-=lbefore;
02929         }
02930 
02931       if(lcount>length) {
02932         lafter=lcount-length;
02933         lcount=length;
02934         length=0;
02935         }
02936       else {
02937         lafter=0;
02938         length-=lcount;
02939         }
02940 
02941       // Save byte count
02942       count = lcount;
02943 
02944       BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
02945       BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
02946 
02947       // If counts not dividable by 4, use 16bits mode
02948       lmode = mode;
02949       if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
02950       if (lcount  & 0x03) lmode=ATA_MODE_PIO16;
02951       if (lafter  & 0x03) lmode=ATA_MODE_PIO16;
02952 
02953       // adds an extra byte if count are odd. before is always even
02954       if (lcount & 0x01) {
02955         lcount+=1;
02956         if ((lafter > 0) && (lafter & 0x01)) {
02957           lafter-=1;
02958           }
02959         }
02960 
02961       if (lmode == ATA_MODE_PIO32) {
02962         lcount>>=2; lbefore>>=2; lafter>>=2;
02963         }
02964       else {
02965         lcount>>=1; lbefore>>=1; lafter>>=1;
02966         }
02967 
02968        ;  // FIXME bcc bug
02969 
02970 ASM_START
02971         push bp
02972         mov  bp, sp
02973 
02974         mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
02975 
02976         mov  cx, _ata_cmd_packet.lbefore + 2[bp] 
02977         jcxz ata_packet_no_before
02978 
02979         mov  ah, _ata_cmd_packet.lmode + 2[bp] 
02980         cmp  ah, #ATA_MODE_PIO32
02981         je   ata_packet_in_before_32
02982 
02983 ata_packet_in_before_16:
02984         in   ax, dx
02985         loop ata_packet_in_before_16
02986         jmp  ata_packet_no_before
02987 
02988 ata_packet_in_before_32:
02989         push eax
02990 ata_packet_in_before_32_loop:
02991         in   eax, dx
02992         loop ata_packet_in_before_32_loop
02993         pop  eax
02994 
02995 ata_packet_no_before:
02996         mov  cx, _ata_cmd_packet.lcount + 2[bp] 
02997         jcxz ata_packet_after
02998 
02999         mov  di, _ata_cmd_packet.bufoff + 2[bp]  
03000         mov  ax, _ata_cmd_packet.bufseg + 2[bp] 
03001         mov  es, ax
03002 
03003         mov  ah, _ata_cmd_packet.lmode + 2[bp] 
03004         cmp  ah, #ATA_MODE_PIO32
03005         je   ata_packet_in_32
03006 
03007 ata_packet_in_16:
03008         rep
03009           insw ;; CX words transfered tp port(DX) to ES:[DI]
03010         jmp ata_packet_after
03011 
03012 ata_packet_in_32:
03013         rep
03014           insd ;; CX dwords transfered to port(DX) to ES:[DI]
03015 
03016 ata_packet_after:
03017         mov  cx, _ata_cmd_packet.lafter + 2[bp] 
03018         jcxz ata_packet_done
03019 
03020         mov  ah, _ata_cmd_packet.lmode + 2[bp] 
03021         cmp  ah, #ATA_MODE_PIO32
03022         je   ata_packet_in_after_32
03023 
03024 ata_packet_in_after_16:
03025         in   ax, dx
03026         loop ata_packet_in_after_16
03027         jmp  ata_packet_done
03028 
03029 ata_packet_in_after_32:
03030         push eax
03031 ata_packet_in_after_32_loop:
03032         in   eax, dx
03033         loop ata_packet_in_after_32_loop
03034         pop  eax
03035 
03036 ata_packet_done:
03037         pop  bp
03038 ASM_END
03039 
03040       // Compute new buffer address
03041       bufoff += count;
03042 
03043       // Save transferred bytes count
03044       transfer += count;
03045       write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
03046       }
03047     }
03048 
03049   // Final check, device must be ready
03050   if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
03051          != ATA_CB_STAT_RDY ) {
03052     BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status);
03053     return 4;
03054     }
03055 
03056   // Enable interrupts
03057   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
03058   return 0;
03059 }
03060 
03061 // ---------------------------------------------------------------------------
03062 // End of ATA/ATAPI Driver
03063 // ---------------------------------------------------------------------------
03064 
03065 // ---------------------------------------------------------------------------
03066 // Start of ATA/ATAPI generic functions
03067 // ---------------------------------------------------------------------------
03068 
03069   Bit16u 
03070 atapi_get_sense(device)
03071   Bit16u device;
03072 {
03073   Bit8u  atacmd[12];
03074   Bit8u  buffer[16];
03075   Bit8u i;
03076 
03077   memsetb(get_SS(),atacmd,0,12);
03078 
03079   // Request SENSE 
03080   atacmd[0]=0x03;    
03081   atacmd[4]=0x20;    
03082   if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
03083     return 0x0002;
03084 
03085   if ((buffer[0] & 0x7e) == 0x70) {
03086     return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
03087     }
03088 
03089   return 0;
03090 }
03091 
03092   Bit16u 
03093 atapi_is_ready(device)
03094   Bit16u device;
03095 {
03096   Bit8u  atacmd[12];
03097   Bit8u  buffer[];
03098 
03099   memsetb(get_SS(),atacmd,0,12);
03100  
03101   // Test Unit Ready
03102   if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
03103     return 0x000f;
03104 
03105   if (atapi_get_sense(device) !=0 ) {
03106     memsetb(get_SS(),atacmd,0,12);
03107 
03108     // try to send Test Unit Ready again
03109     if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
03110       return 0x000f;
03111 
03112     return atapi_get_sense(device);
03113     }
03114   return 0;
03115 }
03116 
03117   Bit16u 
03118 atapi_is_cdrom(device)
03119   Bit8u device;
03120 {
03121   Bit16u ebda_seg=read_word(0x0040,0x000E);
03122 
03123   if (device >= BX_MAX_ATA_DEVICES)
03124     return 0;
03125 
03126   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
03127     return 0;
03128 
03129   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
03130     return 0;
03131 
03132   return 1;
03133 }
03134 
03135 // ---------------------------------------------------------------------------
03136 // End of ATA/ATAPI generic functions
03137 // ---------------------------------------------------------------------------
03138 
03139 #endif // BX_USE_ATADRV
03140 
03141 #if BX_ELTORITO_BOOT
03142 
03143 // ---------------------------------------------------------------------------
03144 // Start of El-Torito boot functions
03145 // ---------------------------------------------------------------------------
03146 
03147   void
03148 cdemu_init()
03149 {
03150   Bit16u ebda_seg=read_word(0x0040,0x000E);
03151 
03152   // the only important data is this one for now
03153   write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
03154 }
03155 
03156   Bit8u
03157 cdemu_isactive()
03158 {
03159   Bit16u ebda_seg=read_word(0x0040,0x000E);
03160 
03161   return(read_byte(ebda_seg,&EbdaData->cdemu.active));
03162 }
03163 
03164   Bit8u
03165 cdemu_emulated_drive()
03166 {
03167   Bit16u ebda_seg=read_word(0x0040,0x000E);
03168 
03169   return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
03170 }
03171 
03172 static char isotag[6]="CD001";
03173 static char eltorito[24]="EL TORITO SPECIFICATION";
03174 //
03175 // Returns ah: emulated drive, al: error code
03176 //
03177   Bit16u 
03178 cdrom_boot()
03179 {
03180   Bit16u ebda_seg=read_word(0x0040,0x000E);
03181   Bit8u  atacmd[12], buffer[2048];
03182   Bit32u lba;
03183   Bit16u boot_segment, nbsectors, i, error;
03184   Bit8u  device;
03185 
03186   // Find out the first cdrom
03187   for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
03188     if (atapi_is_cdrom(device)) break;
03189     }
03190   
03191   // if not found
03192   if(device >= BX_MAX_ATA_DEVICES) return 2;
03193 
03194   // Read the Boot Record Volume Descriptor
03195   memsetb(get_SS(),atacmd,0,12);
03196   atacmd[0]=0x28;                      // READ command
03197   atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
03198   atacmd[8]=(0x01 & 0x00ff);           // Sectors
03199   atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
03200   atacmd[3]=(0x11 & 0x00ff0000) >> 16;
03201   atacmd[4]=(0x11 & 0x0000ff00) >> 8;
03202   atacmd[5]=(0x11 & 0x000000ff);
03203   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
03204     return 3;
03205 
03206   // Validity checks
03207   if(buffer[0]!=0)return 4;
03208   for(i=0;i<5;i++){
03209     if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
03210    }
03211   for(i=0;i<23;i++)
03212     if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
03213   
03214   // ok, now we calculate the Boot catalog address
03215   lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
03216 
03217   // And we read the Boot Catalog
03218   memsetb(get_SS(),atacmd,0,12);
03219   atacmd[0]=0x28;                      // READ command
03220   atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
03221   atacmd[8]=(0x01 & 0x00ff);           // Sectors
03222   atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
03223   atacmd[3]=(lba & 0x00ff0000) >> 16;
03224   atacmd[4]=(lba & 0x0000ff00) >> 8;
03225   atacmd[5]=(lba & 0x000000ff);
03226   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
03227     return 7;
03228  
03229   // Validation entry
03230   if(buffer[0x00]!=0x01)return 8;   // Header
03231   if(buffer[0x01]!=0x00)return 9;   // Platform
03232   if(buffer[0x1E]!=0x55)return 10;  // key 1
03233   if(buffer[0x1F]!=0xAA)return 10;  // key 2
03234 
03235   // Initial/Default Entry
03236   if(buffer[0x20]!=0x88)return 11; // Bootable
03237 
03238   write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
03239   if(buffer[0x21]==0){
03240     // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. 
03241     // Win2000 cd boot needs to know it booted from cd
03242     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
03243     } 
03244   else if(buffer[0x21]<4)
03245     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
03246   else
03247     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
03248 
03249   write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
03250   write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
03251 
03252   boot_segment=buffer[0x23]*0x100+buffer[0x22];
03253   if(boot_segment==0x0000)boot_segment=0x07C0;
03254 
03255   write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
03256   write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
03257   
03258   nbsectors=buffer[0x27]*0x100+buffer[0x26];
03259   write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
03260 
03261   lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
03262   write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
03263 
03264   // And we read the image in memory
03265   memsetb(get_SS(),atacmd,0,12);
03266   atacmd[0]=0x28;                      // READ command
03267   atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8;      // Sectors
03268   atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff);           // Sectors
03269   atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
03270   atacmd[3]=(lba & 0x00ff0000) >> 16;
03271   atacmd[4]=(lba & 0x0000ff00) >> 8;
03272   atacmd[5]=(lba & 0x000000ff);
03273   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
03274     return 12;
03275 
03276   // Remember the media type
03277   switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
03278     case 0x01:  // 1.2M floppy
03279       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
03280       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
03281       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
03282       break;
03283     case 0x02:  // 1.44M floppy
03284       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
03285       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
03286       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
03287       break;
03288     case 0x03:  // 2.88M floppy
03289       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
03290       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
03291       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
03292       break;
03293     case 0x04:  // Harddrive
03294       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
03295       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
03296               (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
03297       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
03298       break;
03299    }
03300 
03301   if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
03302     // Increase bios installed hardware number of devices
03303     if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
03304       write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
03305     else
03306       write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
03307    }
03308 
03309   
03310   // everything is ok, so from now on, the emulation is active
03311   if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
03312     write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
03313 
03314   // return the boot drive + no error
03315   return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
03316 }
03317 
03318 // ---------------------------------------------------------------------------
03319 // End of El-Torito boot functions
03320 // ---------------------------------------------------------------------------
03321 #endif // BX_ELTORITO_BOOT
03322 
03323   void
03324 int14_function(regs, ds, iret_addr)
03325   pusha_regs_t regs; // regs pushed from PUSHA instruction
03326   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
03327   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
03328 {
03329   Bit16u addr,timer,val16;
03330   Bit8u timeout;
03331 
03332   ASM_START
03333   sti
03334   ASM_END
03335 
03336   addr = read_word(0x0040, (regs.u.r16.dx << 1));
03337   timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
03338   if ((regs.u.r16.dx < 4) && (addr > 0)) {
03339     switch (regs.u.r8.ah) {
03340       case 0:
03341         outb(addr+3, inb(addr+3) | 0x80);
03342         if (regs.u.r8.al & 0xE0 == 0) {
03343           outb(addr, 0x17);
03344           outb(addr+1, 0x04);
03345         } else {
03346           val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
03347           outb(addr, val16 & 0xFF);
03348           outb(addr+1, val16 >> 8);
03349         }
03350         outb(addr+3, regs.u.r8.al & 0x1F);
03351         regs.u.r8.ah = inb(addr+5);
03352         regs.u.r8.al = inb(addr+6);
03353         ClearCF(iret_addr.flags);
03354         break;
03355       case 1:
03356         timer = read_word(0x0040, 0x006C);
03357         while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
03358           val16 = read_word(0x0040, 0x006C);
03359           if (val16 != timer) {
03360             timer = val16;
03361             timeout--;
03362             }
03363           }
03364         if (timeout) outb(addr, regs.u.r8.al);
03365         regs.u.r8.ah = inb(addr+5);
03366         if (!timeout) regs.u.r8.ah |= 0x80;
03367         ClearCF(iret_addr.flags);
03368         break;
03369       case 2:
03370         timer = read_word(0x0040, 0x006C);
03371         while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
03372           val16 = read_word(0x0040, 0x006C);
03373           if (val16 != timer) {
03374             timer = val16;
03375             timeout--;
03376             }
03377           }
03378         if (timeout) {
03379           regs.u.r8.ah = 0;
03380           regs.u.r8.al = inb(addr);
03381         } else {
03382           regs.u.r8.ah = inb(addr+5);
03383           }
03384         ClearCF(iret_addr.flags);
03385         break;
03386       case 3:
03387         regs.u.r8.ah = inb(addr+5);
03388         regs.u.r8.al = inb(addr+6);
03389         ClearCF(iret_addr.flags);
03390         break;
03391       default:
03392         SetCF(iret_addr.flags); // Unsupported
03393       }
03394   } else {
03395     SetCF(iret_addr.flags); // Unsupported
03396     }
03397 }
03398 
03399   void
03400 int15_function(regs, ES, DS, FLAGS)
03401   pusha_regs_t regs; // REGS pushed via pusha
03402   Bit16u ES, DS, FLAGS;
03403 {
03404   Bit16u ebda_seg=read_word(0x0040,0x000E);
03405   bx_bool prev_a20_enable;
03406   Bit16u  base15_00;
03407   Bit8u   base23_16;
03408   Bit16u  ss;
03409   Bit16u  CX,DX;
03410 
03411   Bit16u bRegister;
03412   Bit8u irqDisable;
03413 
03414 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
03415 
03416   switch (regs.u.r8.ah) {
03417     case 0x24: /* A20 Control */
03418       switch (regs.u.r8.al) {
03419         case 0x00:
03420           set_enable_a20(0);
03421           CLEAR_CF();
03422           regs.u.r8.ah = 0;
03423           break;
03424         case 0x01:
03425           set_enable_a20(1);
03426           CLEAR_CF();
03427           regs.u.r8.ah = 0;
03428           break;
03429         case 0x02:
03430           regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
03431           CLEAR_CF();
03432           regs.u.r8.ah = 0;
03433           break;
03434         case 0x03:
03435           CLEAR_CF();
03436           regs.u.r8.ah = 0;
03437           regs.u.r16.bx = 3;
03438           break;
03439         default:
03440           BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
03441           SET_CF();
03442           regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03443       }
03444       break;
03445 
03446     case 0x41:
03447       SET_CF();
03448       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03449       break;
03450 
03451     case 0x4f:
03452       /* keyboard intercept */
03453 #if BX_CPU < 2
03454       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03455 #else
03456       // nop
03457 #endif
03458       SET_CF();
03459       break;
03460 
03461     case 0x52:    // removable media eject
03462       CLEAR_CF();
03463       regs.u.r8.ah = 0;  // "ok ejection may proceed"
03464       break;
03465 
03466     case 0x83: {
03467       if( regs.u.r8.al == 0 ) {
03468         // Set Interval requested.
03469         if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
03470           // Interval not already set.
03471           write_byte( 0x40, 0xA0, 1 );  // Set status byte.
03472           write_word( 0x40, 0x98, ES ); // Byte location, segment
03473           write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
03474           write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
03475           write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
03476           CLEAR_CF( );
03477           irqDisable = inb( 0xA1 );
03478           outb( 0xA1, irqDisable & 0xFE );
03479           bRegister = inb_cmos( 0xB );  // Unmask IRQ8 so INT70 will get through.
03480           outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
03481         } else {
03482           // Interval already set.
03483           BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
03484           SET_CF();
03485           regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03486         }
03487       } else if( regs.u.r8.al == 1 ) {
03488         // Clear Interval requested
03489         write_byte( 0x40, 0xA0, 0 );  // Clear status byte
03490         CLEAR_CF( );
03491         bRegister = inb_cmos( 0xB );
03492         outb_cmos( 0xB, bRegister & ~0x40 );  // Turn off the Periodic Interrupt timer
03493       } else {
03494         BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
03495         SET_CF();
03496         regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03497         regs.u.r8.al--;
03498       }
03499 
03500       break;
03501     }
03502 
03503     case 0x87:
03504 #if BX_CPU < 3
03505 #  error "Int15 function 87h not supported on < 80386"
03506 #endif
03507       // +++ should probably have descriptor checks
03508       // +++ should have exception handlers
03509 
03510  // turn off interrupts
03511 ASM_START
03512   cli
03513 ASM_END
03514 
03515       prev_a20_enable = set_enable_a20(1); // enable A20 line
03516 
03517       // 128K max of transfer on 386+ ???
03518       // source == destination ???
03519 
03520       // ES:SI points to descriptor table
03521       // offset   use     initially  comments
03522       // ==============================================
03523       // 00..07   Unused  zeros      Null descriptor
03524       // 08..0f   GDT     zeros      filled in by BIOS
03525       // 10..17   source  ssssssss   source of data
03526       // 18..1f   dest    dddddddd   destination of data
03527       // 20..27   CS      zeros      filled in by BIOS
03528       // 28..2f   SS      zeros      filled in by BIOS
03529 
03530       //es:si
03531       //eeee0
03532       //0ssss
03533       //-----
03534 
03535 // check for access rights of source & dest here
03536 
03537       // Initialize GDT descriptor
03538       base15_00 = (ES << 4) + regs.u.r16.si;
03539       base23_16 = ES >> 12;
03540       if (base15_00 < (ES<<4))
03541         base23_16++;
03542       write_word(ES, regs.u.r16.si+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
03543       write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
03544       write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
03545       write_byte(ES, regs.u.r16.si+0x08+5, 0x93);     // access
03546       write_word(ES, regs.u.r16.si+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
03547 
03548       // Initialize CS descriptor
03549       write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
03550       write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
03551       write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
03552       write_byte(ES, regs.u.r16.si+0x20+5, 0x9b);  // access
03553       write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
03554 
03555       // Initialize SS descriptor
03556       ss = get_SS();
03557       base15_00 = ss << 4;
03558       base23_16 = ss >> 12;
03559       write_word(ES, regs.u.r16.si+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
03560       write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
03561       write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
03562       write_byte(ES, regs.u.r16.si+0x28+5, 0x93);     // access
03563       write_word(ES, regs.u.r16.si+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
03564 
03565       CX = regs.u.r16.cx;
03566 ASM_START
03567       // Compile generates locals offset info relative to SP.
03568       // Get CX (word count) from stack.
03569       mov  bx, sp
03570       SEG SS
03571         mov  cx, _int15_function.CX [bx]
03572 
03573       // since we need to set SS:SP, save them to the BDA
03574       // for future restore
03575       push eax
03576       xor eax, eax
03577       mov ds, ax
03578       mov 0x0469, ss
03579       mov 0x0467, sp
03580 
03581       SEG ES
03582         lgdt [si + 0x08]
03583       SEG CS
03584         lidt [pmode_IDT_info]
03585       ;;  perhaps do something with IDT here
03586 
03587       ;; set PE bit in CR0
03588       mov  eax, cr0
03589       or   al, #0x01
03590       mov  cr0, eax
03591       ;; far jump to flush CPU queue after transition to protected mode
03592       JMP_AP(0x0020, protected_mode)
03593 
03594 protected_mode:
03595       ;; GDT points to valid descriptor table, now load SS, DS, ES
03596       mov  ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
03597       mov  ss, ax
03598       mov  ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
03599       mov  ds, ax
03600       mov  ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
03601       mov  es, ax
03602       xor  si, si
03603       xor  di, di
03604       cld
03605       rep
03606         movsw  ;; move CX words from DS:SI to ES:DI
03607 
03608       ;; make sure DS and ES limits are 64KB
03609       mov ax, #0x28
03610       mov ds, ax
03611       mov es, ax
03612 
03613       ;; reset PG bit in CR0 ???
03614       mov  eax, cr0
03615       and  al, #0xFE
03616       mov  cr0, eax
03617 
03618       ;; far jump to flush CPU queue after transition to real mode
03619       JMP_AP(0xf000, real_mode)
03620 
03621 real_mode:
03622       ;; restore IDT to normal real-mode defaults
03623       SEG CS
03624         lidt [rmode_IDT_info]
03625 
03626       // restore SS:SP from the BDA
03627       xor ax, ax
03628       mov ds, ax
03629       mov ss, 0x0469
03630       mov sp, 0x0467
03631       pop eax
03632 ASM_END
03633 
03634       set_enable_a20(prev_a20_enable);
03635 
03636  // turn back on interrupts
03637 ASM_START
03638   sti
03639 ASM_END
03640 
03641       regs.u.r8.ah = 0;
03642       CLEAR_CF();
03643       break;
03644 
03645 
03646     case 0x88:
03647       // Get the amount of extended memory (above 1M)
03648 #if BX_CPU < 2
03649       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03650       SET_CF();
03651 #else
03652       regs.u.r8.al = inb_cmos(0x30);
03653       regs.u.r8.ah = inb_cmos(0x31);
03654 
03655       // limit to 15M
03656       if(regs.u.r16.ax > 0x3c00)
03657         regs.u.r16.ax = 0x3c00;
03658 
03659       CLEAR_CF();
03660 #endif
03661       break;
03662 
03663     case 0x90:
03664       /* Device busy interrupt.  Called by Int 16h when no key available */
03665       break;
03666 
03667     case 0x91:
03668       /* Interrupt complete.  Called by Int 16h when key becomes available */
03669       break;
03670 
03671     case 0xbf:
03672       BX_INFO("*** int 15h function AH=bf not yet supported!\n");
03673       SET_CF();
03674       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03675       break;
03676 
03677     case 0xC0:
03678 #if 0
03679       SET_CF();
03680       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03681       break;
03682 #endif
03683       CLEAR_CF();
03684       regs.u.r8.ah = 0;
03685       regs.u.r16.bx =  BIOS_CONFIG_TABLE;
03686       ES = 0xF000;
03687       break;
03688 
03689     case 0xc1:
03690       ES = ebda_seg;
03691       CLEAR_CF();
03692       break;
03693 
03694     case 0xd8:
03695       bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
03696       SET_CF();
03697       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03698       break;
03699 
03700     default:
03701       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
03702         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
03703       SET_CF();
03704       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03705       break;
03706     }
03707 }
03708 
03709 #if BX_USE_PS2_MOUSE
03710   void
03711 int15_function_mouse(regs, ES, DS, FLAGS)
03712   pusha_regs_t regs; // REGS pushed via pusha
03713   Bit16u ES, DS, FLAGS;
03714 {
03715   Bit16u ebda_seg=read_word(0x0040,0x000E);
03716   Bit8u  mouse_flags_1, mouse_flags_2;
03717   Bit16u mouse_driver_seg;
03718   Bit16u mouse_driver_offset;
03719   Bit8u  comm_byte, prev_command_byte;
03720   Bit8u  ret, mouse_data1, mouse_data2, mouse_data3;
03721 
03722 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
03723 
03724   switch (regs.u.r8.ah) {
03725     case 0xC2:
03726       // Return Codes status in AH
03727       // =========================
03728       // 00: success
03729       // 01: invalid subfunction (AL > 7)
03730       // 02: invalid input value (out of allowable range)
03731       // 03: interface error
03732       // 04: resend command received from mouse controller,
03733       //     device driver should attempt command again
03734       // 05: cannot enable mouse, since no far call has been installed
03735       // 80/86: mouse service not implemented
03736 
03737       switch (regs.u.r8.al) {
03738         case 0: // Disable/Enable Mouse
03739 BX_DEBUG_INT15("case 0:\n");
03740           switch (regs.u.r8.bh) {
03741             case 0: // Disable Mouse
03742 BX_DEBUG_INT15("case 0: disable mouse\n");
03743               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03744               ret = send_to_mouse_ctrl(0xF5); // disable mouse command
03745               if (ret == 0) {
03746                 ret = get_mouse_data(&mouse_data1);
03747                 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
03748                   CLEAR_CF();
03749                   regs.u.r8.ah = 0;
03750                   return;
03751                   }
03752                 }
03753 
03754               // error
03755               SET_CF();
03756               regs.u.r8.ah = ret;
03757               return;
03758               break;
03759 
03760             case 1: // Enable Mouse
03761 BX_DEBUG_INT15("case 1: enable mouse\n");
03762               mouse_flags_2 = read_byte(ebda_seg, 0x0027);
03763               if ( (mouse_flags_2 & 0x80) == 0 ) {
03764                 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
03765                 SET_CF();  // error
03766                 regs.u.r8.ah = 5; // no far call installed
03767                 return;
03768                 }
03769               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03770               ret = send_to_mouse_ctrl(0xF4); // enable mouse command
03771               if (ret == 0) {
03772                 ret = get_mouse_data(&mouse_data1);
03773                 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
03774                   enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
03775                   CLEAR_CF();
03776                   regs.u.r8.ah = 0;
03777                   return;
03778                   }
03779                 }
03780               SET_CF();
03781               regs.u.r8.ah = ret;
03782               return;
03783 
03784             default: // invalid subfunction
03785               BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
03786               SET_CF();  // error
03787               regs.u.r8.ah = 1; // invalid subfunction
03788               return;
03789             }
03790           break;
03791 
03792         case 1: // Reset Mouse
03793         case 5: // Initialize Mouse
03794 BX_DEBUG_INT15("case 1 or 5:\n");
03795           if (regs.u.r8.al == 5) {
03796             if (regs.u.r8.bh != 3) {
03797               SET_CF();
03798               regs.u.r8.ah = 0x02; // invalid input
03799               return;
03800             }
03801             mouse_flags_2 = read_byte(ebda_seg, 0x0027);
03802             mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
03803             mouse_flags_1 = 0x00;
03804             write_byte(ebda_seg, 0x0026, mouse_flags_1);
03805             write_byte(ebda_seg, 0x0027, mouse_flags_2);
03806           }
03807 
03808           inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03809           ret = send_to_mouse_ctrl(0xFF); // reset mouse command
03810           if (ret == 0) {
03811             ret = get_mouse_data(&mouse_data3);
03812             // if no mouse attached, it will return RESEND
03813             if (mouse_data3 == 0xfe) {
03814               SET_CF();
03815               return;
03816             }
03817             if (mouse_data3 != 0xfa)
03818               BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
03819             if ( ret == 0 ) {
03820               ret = get_mouse_data(&mouse_data1);
03821               if ( ret == 0 ) {
03822                 ret = get_mouse_data(&mouse_data2);
03823                 if ( ret == 0 ) {
03824                   // turn IRQ12 and packet generation on
03825                   enable_mouse_int_and_events();
03826                   CLEAR_CF();
03827                   regs.u.r8.ah = 0;
03828                   regs.u.r8.bl = mouse_data1;
03829                   regs.u.r8.bh = mouse_data2;
03830                   return;
03831                   }
03832                 }
03833               }
03834             }
03835 
03836           // error
03837           SET_CF();
03838           regs.u.r8.ah = ret;
03839           return;
03840 
03841         case 2: // Set Sample Rate
03842 BX_DEBUG_INT15("case 2:\n");
03843           switch (regs.u.r8.bh) {
03844             case 0: mouse_data1 = 10; break; //  10 reports/sec
03845             case 1: mouse_data1 = 20; break; //  20 reports/sec
03846             case 2: mouse_data1 = 40; break; //  40 reports/sec
03847             case 3: mouse_data1 = 60; break; //  60 reports/sec
03848             case 4: mouse_data1 = 80; break; //  80 reports/sec
03849             case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
03850             case 6: mouse_data1 = 200; break; // 200 reports/sec
03851             default: mouse_data1 = 0;
03852           }
03853           if (mouse_data1 > 0) {
03854             ret = send_to_mouse_ctrl(0xF3); // set sample rate command
03855             if (ret == 0) {
03856               ret = get_mouse_data(&mouse_data2);
03857               ret = send_to_mouse_ctrl(mouse_data1);
03858               ret = get_mouse_data(&mouse_data2);
03859               CLEAR_CF();
03860               regs.u.r8.ah = 0;
03861             } else {
03862               // error
03863               SET_CF();
03864               regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03865             }
03866           } else {
03867             // error
03868             SET_CF();
03869             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03870           }
03871           break;
03872 
03873         case 3: // Set Resolution
03874 BX_DEBUG_INT15("case 3:\n");
03875           // BX:
03876           //      0 =  25 dpi, 1 count  per millimeter
03877           //      1 =  50 dpi, 2 counts per millimeter
03878           //      2 = 100 dpi, 4 counts per millimeter
03879           //      3 = 200 dpi, 8 counts per millimeter
03880           CLEAR_CF();
03881           regs.u.r8.ah = 0;
03882           break;
03883 
03884         case 4: // Get Device ID
03885 BX_DEBUG_INT15("case 4:\n");
03886           inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03887           ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
03888           if (ret == 0) {
03889             ret = get_mouse_data(&mouse_data1);
03890             ret = get_mouse_data(&mouse_data2);
03891             CLEAR_CF();
03892             regs.u.r8.ah = 0;
03893             regs.u.r8.bh = mouse_data2;
03894           } else {
03895             // error
03896             SET_CF();
03897             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03898           }
03899           break;
03900 
03901         case 6: // Return Status & Set Scaling Factor...
03902 BX_DEBUG_INT15("case 6:\n");
03903           switch (regs.u.r8.bh) {
03904             case 0: // Return Status
03905               comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03906               ret = send_to_mouse_ctrl(0xE9); // get mouse info command
03907               if (ret == 0) {
03908                 ret = get_mouse_data(&mouse_data1);
03909                 if (mouse_data1 != 0xfa)
03910                   BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
03911                 if (ret == 0) {
03912                   ret = get_mouse_data(&mouse_data1);
03913                   if ( ret == 0 ) {
03914                     ret = get_mouse_data(&mouse_data2);
03915                     if ( ret == 0 ) {
03916                       ret = get_mouse_data(&mouse_data3);
03917                       if ( ret == 0 ) {
03918                         CLEAR_CF();
03919                         regs.u.r8.ah = 0;
03920                         regs.u.r8.bl = mouse_data1;
03921                         regs.u.r8.cl = mouse_data2;
03922                         regs.u.r8.dl = mouse_data3;
03923                         set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
03924                         return;
03925                         }
03926                       }
03927                     }
03928                   }
03929                 }
03930 
03931               // error
03932               SET_CF();
03933               regs.u.r8.ah = ret;
03934               set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
03935               return;
03936 
03937             case 1: // Set Scaling Factor to 1:1
03938             case 2: // Set Scaling Factor to 2:1
03939               comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03940               if (regs.u.r8.bh == 1) {
03941                 ret = send_to_mouse_ctrl(0xE6);
03942               } else {
03943                 ret = send_to_mouse_ctrl(0xE7);
03944               }
03945               if (ret == 0) {
03946                 get_mouse_data(&mouse_data1);
03947                 ret = (mouse_data1 != 0xFA);
03948               }
03949               if (ret == 0) {
03950                 CLEAR_CF();
03951                 regs.u.r8.ah = 0;
03952               } else {
03953                 // error
03954                 SET_CF();
03955                 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
03956               }
03957               set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
03958               break;
03959 
03960             default:
03961               BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
03962             }
03963           break;
03964 
03965         case 7: // Set Mouse Handler Address
03966 BX_DEBUG_INT15("case 7:\n");
03967           mouse_driver_seg = ES;
03968           mouse_driver_offset = regs.u.r16.bx;
03969           write_word(ebda_seg, 0x0022, mouse_driver_offset);
03970           write_word(ebda_seg, 0x0024, mouse_driver_seg);
03971           mouse_flags_2 = read_byte(ebda_seg, 0x0027);
03972           if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
03973             /* remove handler */
03974             if ( (mouse_flags_2 & 0x80) != 0 ) {
03975               mouse_flags_2 &= ~0x80;
03976               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
03977               }
03978             }
03979           else {
03980             /* install handler */
03981             mouse_flags_2 |= 0x80;
03982             }
03983           write_byte(ebda_seg, 0x0027, mouse_flags_2);
03984           CLEAR_CF();
03985           regs.u.r8.ah = 0;
03986           break;
03987 
03988         default:
03989 BX_DEBUG_INT15("case default:\n");
03990           regs.u.r8.ah = 1; // invalid function
03991           SET_CF();
03992         }
03993       break;
03994 
03995     default:
03996       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
03997         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
03998       SET_CF();
03999       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
04000       break;
04001     }
04002 }
04003 #endif
04004 
04005 
04006 void set_e820_range(ES, DI, start, end, type)
04007      Bit16u ES; 
04008      Bit16u DI;
04009      Bit32u start;
04010      Bit32u end; 
04011      Bit16u type;
04012 {
04013     write_word(ES, DI, start);
04014     write_word(ES, DI+2, start >> 16);
04015     write_word(ES, DI+4, 0x00);
04016     write_word(ES, DI+6, 0x00);
04017     
04018     end -= start;
04019     write_word(ES, DI+8, end);
04020     write_word(ES, DI+10, end >> 16);
04021     write_word(ES, DI+12, 0x0000);
04022     write_word(ES, DI+14, 0x0000);
04023     
04024     write_word(ES, DI+16, type);
04025     write_word(ES, DI+18, 0x0);
04026 }
04027 
04028   void
04029 int15_function32(regs, ES, DS, FLAGS)
04030   pushad_regs_t regs; // REGS pushed via pushad
04031   Bit16u ES, DS, FLAGS;
04032 {
04033   Bit32u  extended_memory_size=0; // 64bits long
04034   Bit16u  CX,DX;
04035 
04036 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
04037 
04038   switch (regs.u.r8.ah) {
04039     case 0x86:
04040       // Wait for CX:DX microseconds. currently using the 
04041       // refresh request port 0x61 bit4, toggling every 15usec 
04042 
04043       CX = regs.u.r16.cx;
04044       DX = regs.u.r16.dx;
04045 
04046 ASM_START
04047       sti
04048 
04049       ;; Get the count in eax
04050       mov  bx, sp
04051       SEG SS
04052         mov  ax, _int15_function.CX [bx]
04053       shl  eax, #16
04054       SEG SS
04055         mov  ax, _int15_function.DX [bx]
04056 
04057       ;; convert to numbers of 15usec ticks
04058       mov ebx, #15
04059       xor edx, edx
04060       div eax, ebx
04061       mov ecx, eax
04062 
04063       ;; wait for ecx number of refresh requests
04064       in al, #0x61
04065       and al,#0x10
04066       mov ah, al
04067 
04068       or ecx, ecx
04069       je int1586_tick_end
04070 int1586_tick:
04071       in al, #0x61
04072       and al,#0x10
04073       cmp al, ah
04074       je  int1586_tick
04075       mov ah, al
04076       dec ecx
04077       jnz int1586_tick
04078 int1586_tick_end:
04079 ASM_END
04080 
04081       break;
04082 
04083     case 0xe8:
04084         switch(regs.u.r8.al)
04085         {
04086          case 0x20: // coded by osmaker aka K.J.
04087             if(regs.u.r32.edx == 0x534D4150)
04088             {
04089                 switch(regs.u.r16.bx)
04090                 {
04091                     case 0:
04092                         set_e820_range(ES, regs.u.r16.di, 
04093                                        0x0000000L, 0x0009fc00L, 1);
04094                         regs.u.r32.ebx = 1;
04095                         regs.u.r32.eax = 0x534D4150;
04096                         regs.u.r32.ecx = 0x14;
04097                         CLEAR_CF();
04098                         return;
04099                         break;
04100                     case 1:
04101                         set_e820_range(ES, regs.u.r16.di, 
04102                                        0x0009fc00L, 0x000a0000L, 2);
04103                         regs.u.r32.ebx = 2;
04104                         regs.u.r32.eax = 0x534D4150;
04105                         regs.u.r32.ecx = 0x14;
04106                         CLEAR_CF();
04107                         return;
04108                         break;
04109                     case 2:
04110                         set_e820_range(ES, regs.u.r16.di, 
04111                                        0x000e8000L, 0x00100000L, 2);
04112                         regs.u.r32.ebx = 3;
04113                         regs.u.r32.eax = 0x534D4150;
04114                         regs.u.r32.ecx = 0x14;
04115                         CLEAR_CF();
04116                         return;
04117                         break;
04118                     case 3:
04119                         extended_memory_size = inb_cmos(0x35);
04120                         extended_memory_size <<= 8;
04121                         extended_memory_size |= inb_cmos(0x34);
04122                         extended_memory_size *= 64;
04123                         if(extended_memory_size > 0x3bc000) // greater than EFF00000???
04124                         {
04125                             extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
04126                         }
04127                         extended_memory_size *= 1024;
04128                         extended_memory_size += (16L * 1024 * 1024);
04129 
04130                         if(extended_memory_size <= (16L * 1024 * 1024))
04131                         {
04132                             extended_memory_size = inb_cmos(0x31);
04133                             extended_memory_size <<= 8;
04134                             extended_memory_size |= inb_cmos(0x30);
04135                             extended_memory_size *= 1024;
04136                         }
04137 
04138                         set_e820_range(ES, regs.u.r16.di, 
04139                                        0x00100000L, extended_memory_size, 1);
04140                         regs.u.r32.ebx = 4;
04141                         regs.u.r32.eax = 0x534D4150;
04142                         regs.u.r32.ecx = 0x14;
04143                         CLEAR_CF();
04144                         return;
04145                         break;
04146                     case 4:
04147                         /* 256KB BIOS area at the end of 4 GB */
04148