Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Now manages to do ata_cmd_packet() (critical for cdrom boot)
[palacios.git] / palacios / src / vmboot / rombios / rombios.c
1 //  -*- fundamental -*-
2 /////////////////////////////////////////////////////////////////////////
3 // $Id: rombios.c,v 1.12 2008/07/11 22:59:38 pdinda Exp $
4 /////////////////////////////////////////////////////////////////////////
5 //
6 //  Copyright (C) 2002  MandrakeSoft S.A.
7 //
8 //    MandrakeSoft S.A.
9 //    43, rue d'Aboukir
10 //    75002 Paris - France
11 //    http://www.linux-mandrake.com/
12 //    http://www.mandrakesoft.com/
13 //
14 //  This library is free software; you can redistribute it and/or
15 //  modify it under the terms of the GNU Lesser General Public
16 //  License as published by the Free Software Foundation; either
17 //  version 2 of the License, or (at your option) any later version.
18 //
19 //  This library is distributed in the hope that it will be useful,
20 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 //  Lesser General Public License for more details.
23 //
24 //  You should have received a copy of the GNU Lesser General Public
25 //  License along with this library; if not, write to the Free Software
26 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
27
28 // ROM BIOS for use with Bochs/Plex x86 emulation environment
29
30 #define HVMASSIST
31 #undef HVMTEST
32
33 // Xen full virtualization does not handle unaligned IO with page crossing.
34 // Disable 32-bit PIO as a workaround.
35 #undef NO_PIO32
36
37
38 // ROM BIOS compatability entry points:
39 // ===================================
40 // $e05b ; POST Entry Point
41 // $e2c3 ; NMI Handler Entry Point
42 // $e3fe ; INT 13h Fixed Disk Services Entry Point
43 // $e401 ; Fixed Disk Parameter Table
44 // $e6f2 ; INT 19h Boot Load Service Entry Point
45 // $e6f5 ; Configuration Data Table
46 // $e729 ; Baud Rate Generator Table
47 // $e739 ; INT 14h Serial Communications Service Entry Point
48 // $e82e ; INT 16h Keyboard Service Entry Point
49 // $e987 ; INT 09h Keyboard Service Entry Point
50 // $ec59 ; INT 13h Diskette Service Entry Point
51 // $ef57 ; INT 0Eh Diskette Hardware ISR Entry Point
52 // $efc7 ; Diskette Controller Parameter Table
53 // $efd2 ; INT 17h Printer Service Entry Point
54 // $f045 ; INT 10 Functions 0-Fh Entry Point
55 // $f065 ; INT 10h Video Support Service Entry Point
56 // $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
57 // $f841 ; INT 12h Memory Size Service Entry Point
58 // $f84d ; INT 11h Equipment List Service Entry Point
59 // $f859 ; INT 15h System Services Entry Point
60 // $fa6e ; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
61 // $fe6e ; INT 1Ah Time-of-day Service Entry Point
62 /// $fea5 ; INT 08h System Timer ISR Entry Point
63 // $fef3 ; Initial Interrupt Vector Offsets Loaded by POST
64 // $ff53 ; IRET Instruction for Dummy Interrupt Handler
65 // $ff54 ; INT 05h Print Screen Service Entry Point
66 // $fff0 ; Power-up Entry Point
67 // $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
68 // $fffe ; System Model ID
69
70 // NOTES for ATA/ATAPI driver (cbbochs@free.fr)
71 //   Features
72 //     - supports up to 4 ATA interfaces
73 //     - device/geometry detection
74 //     - 16bits/32bits device access
75 //     - pchs/lba access
76 //     - datain/dataout/packet command support
77 //
78 // NOTES for El-Torito Boot (cbbochs@free.fr)
79 //   - CD-ROM booting is only available if ATA/ATAPI Driver is available
80 //   - Current code is only able to boot mono-session cds 
81 //   - Current code can not boot and emulate a hard-disk
82 //     the bios will panic otherwise
83 //   - Current code also use memory in EBDA segement. 
84 //   - I used cmos byte 0x3D to store extended information on boot-device
85 //   - Code has to be modified modified to handle multiple cdrom drives
86 //   - Here are the cdrom boot failure codes:
87 //       1 : no atapi device found
88 //       2 : no atapi cdrom found
89 //       3 : can not read cd - BRVD
90 //       4 : cd is not eltorito (BRVD)
91 //       5 : cd is not eltorito (ISO TAG)
92 //       6 : cd is not eltorito (ELTORITO TAG)
93 //       7 : can not read cd - boot catalog
94 //       8 : boot catalog : bad header
95 //       9 : boot catalog : bad platform
96 //      10 : boot catalog : bad signature
97 //      11 : boot catalog : bootable flag not set
98 //      12 : can not read cd - boot image
99 //
100 //   ATA driver
101 //   - EBDA segment. 
102 //     I used memory starting at 0x121 in the segment
103 //   - the translation policy is defined in cmos regs 0x39 & 0x3a
104 //
105 // TODO :
106 //
107 //   int74 
108 //     - needs to be reworked.  Uses direct [bp] offsets. (?)
109 //
110 //   int13:
111 //     - f04 (verify sectors) isn't complete  (?)
112 //     - f02/03/04 should set current cyl,etc in BDA  (?)
113 //     - rewrite int13_relocated & clean up int13 entry code
114 //
115 //   NOTES:
116 //   - NMI access (bit7 of addr written to 70h)
117 //
118 //   ATA driver
119 //   - should handle the "don't detect" bit (cmos regs 0x3b & 0x3c)
120 //   - could send the multiple-sector read/write commands
121 //
122 //   El-Torito
123 //   - Emulate a Hard-disk (currently only diskette can be emulated) see "FIXME ElTorito Harddisk"
124 //   - Implement remaining int13_cdemu functions (as defined by El-Torito specs)
125 //   - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded"
126 //   - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13.
127 //     This is ok. But DL should be reincremented afterwards. 
128 //   - Fix all "FIXME ElTorito Various"
129 //   - should be able to boot any cdrom instead of the first one
130 //
131 //   BCC Bug: find a generic way to handle the bug of #asm after an "if"  (fixed in 0.16.7)
132
133 #define DEBUG_ROMBIOS      1
134
135 #define DEBUG_ATA          0
136 #define DEBUG_INT13_HD     0
137 #define DEBUG_INT13_CD     0
138 #define DEBUG_INT13_ET     0
139 #define DEBUG_INT13_FL     0
140 #define DEBUG_INT15        0
141 #define DEBUG_INT16        0
142 #define DEBUG_INT1A        0
143 #define DEBUG_INT74        0
144 #define DEBUG_APM          0
145
146 #define BX_CPU           3
147 #define BX_USE_PS2_MOUSE 1
148 #define BX_CALL_INT15_4F 1
149 #define BX_USE_EBDA      1
150 #define BX_SUPPORT_FLOPPY 1
151 #define BX_FLOPPY_ON_CNT 37   /* 2 seconds */
152 #define BX_PCIBIOS       1
153 #define BX_APM           1
154
155 #define BX_USE_ATADRV    1
156 #define BX_ELTORITO_BOOT 1
157
158 #define BX_MAX_ATA_INTERFACES   4
159 #define BX_MAX_ATA_DEVICES      (BX_MAX_ATA_INTERFACES*2)
160
161 #define BX_VIRTUAL_PORTS 1 /* normal output to Bochs ports */
162 #define BX_DEBUG_SERIAL  0 /* output to COM1 */
163
164    /* model byte 0xFC = AT */
165 #define SYS_MODEL_ID     0xFC
166 #define SYS_SUBMODEL_ID  0x00
167 #define BIOS_REVISION    1
168 #define BIOS_CONFIG_TABLE 0xe6f5
169
170 #ifndef BIOS_BUILD_DATE
171 #  define BIOS_BUILD_DATE "06/23/99"
172 #endif
173
174   // 1K of base memory used for Extended Bios Data Area (EBDA)
175   // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
176 #define EBDA_SEG           0x9FC0
177 #define EBDA_SIZE          1              // In KiB
178 #define BASE_MEM_IN_K   (640 - EBDA_SIZE)
179
180   // Define the application NAME
181 #ifdef HVMASSIST
182 #  define BX_APPNAME "HVMAssist"
183 #elif PLEX86
184 #  define BX_APPNAME "Plex86"
185 #else
186 #  define BX_APPNAME "Bochs"
187 #endif
188
189   // Sanity Checks
190 #if BX_USE_ATADRV && BX_CPU<3
191 #    error The ATA/ATAPI Driver can only to be used with a 386+ cpu
192 #endif
193 #if BX_USE_ATADRV && !BX_USE_EBDA
194 #    error ATA/ATAPI Driver can only be used if EBDA is available
195 #endif
196 #if BX_ELTORITO_BOOT && !BX_USE_ATADRV
197 #    error El-Torito Boot can only be use if ATA/ATAPI Driver is available
198 #endif
199 #if BX_PCIBIOS && BX_CPU<3
200 #    error PCI BIOS can only be used with 386+ cpu
201 #endif
202 #if BX_APM && BX_CPU<3
203 #    error APM BIOS can only be used with 386+ cpu
204 #endif
205
206 #ifndef BX_SMP_PROCESSORS
207 #define BX_SMP_PROCESSORS 1
208 #    warning BX_SMP_PROCESSORS not defined, defaulting to 1
209 #endif
210   
211 #define PANIC_PORT  0x400
212 #define PANIC_PORT2 0x401
213 #define INFO_PORT   0x402
214 #define DEBUG_PORT  0x403
215
216 // #20  is dec 20
217 // #$20 is hex 20 = 32
218 // #0x20 is hex 20 = 32
219 // LDA  #$20
220 // JSR  $E820
221 // LDD  .i,S
222 // JSR  $C682
223 // mov al, #$20
224
225 // all hex literals should be prefixed with '0x'
226 //   grep "#[0-9a-fA-F][0-9a-fA-F]" rombios.c
227 // no mov SEG-REG, #value, must mov register into seg-reg
228 //   grep -i "mov[ ]*.s" rombios.c
229
230 // This is for compiling with gcc2 and gcc3
231 #define ASM_START #asm
232 #define ASM_END #endasm
233
234 ASM_START
235 .rom
236
237 .org 0x0000
238
239 #if BX_CPU >= 3
240 use16 386
241 #else
242 use16 286
243 #endif
244
245 MACRO HALT
246   ;; the HALT macro is called with the line number of the HALT call.
247   ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex 
248   ;; to print a BX_PANIC message.  This will normally halt the simulation
249   ;; with a message such as "BIOS panic at rombios.c, line 4091".
250   ;; However, users can choose to make panics non-fatal and continue.
251 #if BX_VIRTUAL_PORTS
252   mov dx,#PANIC_PORT
253   mov ax,#?1
254   out dx,ax
255 #else
256   mov dx,#0x80
257   mov ax,#?1
258   out dx,al
259 #endif
260 MEND
261
262 MACRO JMP_AP
263   db 0xea
264   dw ?2
265   dw ?1
266 MEND
267
268 MACRO SET_INT_VECTOR
269   mov ax, ?3
270   mov ?1*4, ax
271   mov ax, ?2
272   mov ?1*4+2, ax
273 MEND
274
275 ASM_END
276
277 typedef unsigned char  Bit8u;
278 typedef unsigned short Bit16u;
279 typedef unsigned short bx_bool;
280 typedef unsigned long  Bit32u;
281
282 #if BX_USE_ATADRV
283
284   void memsetb(seg,offset,value,count);
285   void memcpyb(dseg,doffset,sseg,soffset,count);
286   void memcpyd(dseg,doffset,sseg,soffset,count);
287   
288   // memset of count bytes
289     void 
290   memsetb(seg,offset,value,count)
291     Bit16u seg;
292     Bit16u offset;
293     Bit16u value;
294     Bit16u count;
295   {
296   ASM_START
297     push bp
298     mov  bp, sp
299   
300       push ax
301       push cx
302       push es
303       push di
304   
305       mov  cx, 10[bp] ; count
306       cmp  cx, #0x00
307       je   memsetb_end
308       mov  ax, 4[bp] ; segment
309       mov  es, ax
310       mov  ax, 6[bp] ; offset
311       mov  di, ax
312       mov  al, 8[bp] ; value
313       cld
314       rep
315        stosb
316   
317   memsetb_end:
318       pop di
319       pop es
320       pop cx
321       pop ax
322   
323     pop bp
324   ASM_END
325   }
326   
327   // memcpy of count bytes
328     void 
329   memcpyb(dseg,doffset,sseg,soffset,count)
330     Bit16u dseg;
331     Bit16u doffset;
332     Bit16u sseg;
333     Bit16u soffset;
334     Bit16u count;
335   {
336   ASM_START
337     push bp
338     mov  bp, sp
339   
340       push ax
341       push cx
342       push es
343       push di
344       push ds
345       push si
346   
347       mov  cx, 12[bp] ; count
348       cmp  cx, #0x0000
349       je   memcpyb_end
350       mov  ax, 4[bp] ; dsegment
351       mov  es, ax
352       mov  ax, 6[bp] ; doffset
353       mov  di, ax
354       mov  ax, 8[bp] ; ssegment
355       mov  ds, ax
356       mov  ax, 10[bp] ; soffset
357       mov  si, ax
358       cld
359       rep
360        movsb
361   
362   memcpyb_end:
363       pop si
364       pop ds
365       pop di
366       pop es
367       pop cx
368       pop ax
369   
370     pop bp
371   ASM_END
372   }
373
374 #if 0 
375   // memcpy of count dword
376     void 
377   memcpyd(dseg,doffset,sseg,soffset,count)
378     Bit16u dseg;
379     Bit16u doffset;
380     Bit16u sseg;
381     Bit16u soffset;
382     Bit16u count;
383   {
384   ASM_START
385     push bp
386     mov  bp, sp
387   
388       push ax
389       push cx
390       push es
391       push di
392       push ds
393       push si
394   
395       mov  cx, 12[bp] ; count
396       cmp  cx, #0x0000
397       je   memcpyd_end
398       mov  ax, 4[bp] ; dsegment
399       mov  es, ax
400       mov  ax, 6[bp] ; doffset
401       mov  di, ax
402       mov  ax, 8[bp] ; ssegment
403       mov  ds, ax
404       mov  ax, 10[bp] ; soffset
405       mov  si, ax
406       cld
407       rep
408        movsd
409   
410   memcpyd_end:
411       pop si
412       pop ds
413       pop di
414       pop es
415       pop cx
416       pop ax
417   
418     pop bp
419   ASM_END
420   }
421 #endif
422 #endif //BX_USE_ATADRV
423
424   // read_dword and write_dword functions
425   static Bit32u         read_dword();
426   static void           write_dword();
427   
428     Bit32u
429   read_dword(seg, offset)
430     Bit16u seg;
431     Bit16u offset;
432   {
433   ASM_START
434     push bp
435     mov  bp, sp
436   
437       push bx
438       push ds
439       mov  ax, 4[bp] ; segment
440       mov  ds, ax
441       mov  bx, 6[bp] ; offset
442       mov  ax, [bx]
443       inc  bx
444       inc  bx
445       mov  dx, [bx]
446       ;; ax = return value (word)
447       ;; dx = return value (word)
448       pop  ds
449       pop  bx
450   
451     pop  bp
452   ASM_END
453   }
454   
455     void
456   write_dword(seg, offset, data)
457     Bit16u seg;
458     Bit16u offset;
459     Bit32u data;
460   {
461   ASM_START
462     push bp
463     mov  bp, sp
464   
465       push ax
466       push bx
467       push ds
468       mov  ax, 4[bp] ; segment
469       mov  ds, ax
470       mov  bx, 6[bp] ; offset
471       mov  ax, 8[bp] ; data word
472       mov  [bx], ax  ; write data word
473       inc  bx
474       inc  bx
475       mov  ax, 10[bp] ; data word
476       mov  [bx], ax  ; write data word
477       pop  ds
478       pop  bx
479       pop  ax
480   
481     pop  bp
482   ASM_END
483   }
484   
485   // Bit32u (unsigned long) and long helper functions
486   ASM_START
487   
488   ;; and function
489   landl:
490   landul:
491     SEG SS 
492       and ax,[di]
493     SEG SS 
494       and bx,2[di]
495     ret
496   
497   ;; add function
498   laddl:
499   laddul:
500     SEG SS 
501       add ax,[di]
502     SEG SS 
503       adc bx,2[di]
504     ret
505   
506   ;; cmp function
507   lcmpl:
508   lcmpul:
509     and eax, #0x0000FFFF
510     shl ebx, #16
511     add eax, ebx
512     shr ebx, #16
513     SEG SS
514       cmp eax, dword ptr [di]
515     ret
516   
517   ;; sub function
518   lsubl:
519   lsubul:
520     SEG SS
521     sub ax,[di]
522     SEG SS
523     sbb bx,2[di]
524     ret
525   
526   ;; mul function
527   lmull:
528   lmulul:
529     and eax, #0x0000FFFF
530     shl ebx, #16
531     add eax, ebx
532     SEG SS
533     mul eax, dword ptr [di]
534     mov ebx, eax
535     shr ebx, #16
536     ret
537   
538   ;; dec function
539   ldecl:
540   ldecul:
541     SEG SS
542     dec dword ptr [bx]
543     ret
544   
545   ;; or function
546   lorl:
547   lorul:
548     SEG SS
549     or  ax,[di]
550     SEG SS
551     or  bx,2[di]
552     ret
553   
554   ;; inc function
555   lincl:
556   lincul:
557     SEG SS
558     inc dword ptr [bx]
559     ret
560   
561   ;; tst function
562   ltstl:
563   ltstul:
564     and eax, #0x0000FFFF
565     shl ebx, #16
566     add eax, ebx
567     shr ebx, #16
568     test eax, eax
569     ret
570   
571   ;; sr function
572   lsrul:
573     mov  cx,di
574     jcxz lsr_exit
575     and  eax, #0x0000FFFF
576     shl  ebx, #16
577     add  eax, ebx
578   lsr_loop:
579     shr  eax, #1
580     loop lsr_loop
581     mov  ebx, eax
582     shr  ebx, #16
583   lsr_exit:
584     ret
585   
586   ;; sl function
587   lsll:
588   lslul:
589     mov  cx,di
590     jcxz lsl_exit
591     and  eax, #0x0000FFFF
592     shl  ebx, #16
593     add  eax, ebx
594   lsl_loop: 
595     shl  eax, #1
596     loop lsl_loop
597     mov  ebx, eax
598     shr  ebx, #16
599   lsl_exit:
600     ret
601   
602   idiv_:
603     cwd
604     idiv bx
605     ret
606
607   idiv_u:
608     xor dx,dx
609     div bx
610     ret
611
612   ldivul:
613     and  eax, #0x0000FFFF
614     shl  ebx, #16
615     add  eax, ebx
616     xor  edx, edx
617     SEG SS
618     mov  bx,  2[di]
619     shl  ebx, #16
620     SEG SS
621     mov  bx,  [di]
622     div  ebx
623     mov  ebx, eax
624     shr  ebx, #16
625     ret
626
627   ASM_END
628
629 // for access to RAM area which is used by interrupt vectors
630 // and BIOS Data Area
631
632 typedef struct {
633   unsigned char filler1[0x400];
634   unsigned char filler2[0x6c];
635   Bit16u ticks_low;
636   Bit16u ticks_high;
637   Bit8u  midnight_flag;
638   } bios_data_t;
639
640 #define BiosData ((bios_data_t  *) 0)
641
642 #if BX_USE_ATADRV
643   typedef struct {
644     Bit16u heads;      // # heads
645     Bit16u cylinders;  // # cylinders
646     Bit16u spt;        // # sectors / track
647     } chs_t;
648
649   // DPTE definition
650   typedef struct {
651     Bit16u iobase1;
652     Bit16u iobase2;
653     Bit8u  prefix;
654     Bit8u  unused;
655     Bit8u  irq;
656     Bit8u  blkcount;
657     Bit8u  dma;
658     Bit8u  pio;
659     Bit16u options;
660     Bit16u reserved;
661     Bit8u  revision;
662     Bit8u  checksum;
663     } dpte_t;
664  
665   typedef struct {
666     Bit8u  iface;        // ISA or PCI
667     Bit16u iobase1;      // IO Base 1
668     Bit16u iobase2;      // IO Base 2
669     Bit8u  irq;          // IRQ
670     } ata_channel_t;
671
672   typedef struct {
673     Bit8u  type;         // Detected type of ata (ata/atapi/none/unknown)
674     Bit8u  device;       // Detected type of attached devices (hd/cd/none)
675     Bit8u  removable;    // Removable device flag
676     Bit8u  lock;         // Locks for removable devices
677     // Bit8u  lba_capable;  // LBA capable flag - always yes for bochs devices
678     Bit8u  mode;         // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA
679     Bit16u blksize;      // block size
680
681     Bit8u  translation;  // type of translation
682     chs_t  lchs;         // Logical CHS
683     chs_t  pchs;         // Physical CHS
684
685     Bit32u sectors;      // Total sectors count
686     } ata_device_t;
687
688   typedef struct {
689     // ATA channels info
690     ata_channel_t channels[BX_MAX_ATA_INTERFACES];
691
692     // ATA devices info
693     ata_device_t  devices[BX_MAX_ATA_DEVICES];
694     //
695     // map between (bios hd id - 0x80) and ata channels
696     Bit8u  hdcount, hdidmap[BX_MAX_ATA_DEVICES];                
697
698     // map between (bios cd id - 0xE0) and ata channels
699     Bit8u  cdcount, cdidmap[BX_MAX_ATA_DEVICES];                
700
701     // Buffer for DPTE table
702     dpte_t dpte;
703
704     // Count of transferred sectors and bytes
705     Bit16u trsfsectors;
706     Bit32u trsfbytes;
707
708     } ata_t;
709   
710 #if BX_ELTORITO_BOOT
711   // ElTorito Device Emulation data 
712   typedef struct {
713     Bit8u  active;
714     Bit8u  media;
715     Bit8u  emulated_drive;
716     Bit8u  controller_index;
717     Bit16u device_spec;
718     Bit32u ilba;
719     Bit16u buffer_segment;
720     Bit16u load_segment;
721     Bit16u sector_count;
722     
723     // Virtual device
724     chs_t  vdevice;
725     } cdemu_t;
726 #endif // BX_ELTORITO_BOOT
727   
728   // for access to EBDA area
729   //     The EBDA structure should conform to 
730   //     http://www.cybertrails.com/~fys/rombios.htm document
731   //     I made the ata and cdemu structs begin at 0x121 in the EBDA seg
732   typedef struct {
733     unsigned char filler1[0x3D];
734
735     // FDPT - Can be splitted in data members if needed
736     unsigned char fdpt0[0x10];
737     unsigned char fdpt1[0x10];
738
739     unsigned char filler2[0xC4];
740
741     // ATA Driver data
742     ata_t   ata;
743
744 #if BX_ELTORITO_BOOT
745     // El Torito Emulation data
746     cdemu_t cdemu;
747 #endif // BX_ELTORITO_BOOT
748
749     } ebda_data_t;
750   
751   #define EbdaData ((ebda_data_t *) 0)
752
753   // for access to the int13ext structure
754   typedef struct {
755     Bit8u  size;
756     Bit8u  reserved;
757     Bit16u count;
758     Bit16u offset;
759     Bit16u segment;
760     Bit32u lba1;
761     Bit32u lba2;
762     } int13ext_t;
763  
764   #define Int13Ext ((int13ext_t *) 0)
765
766   // Disk Physical Table definition
767   typedef struct {
768     Bit16u  size;
769     Bit16u  infos;
770     Bit32u  cylinders;
771     Bit32u  heads;
772     Bit32u  spt;
773     Bit32u  sector_count1;
774     Bit32u  sector_count2;
775     Bit16u  blksize;
776     Bit16u  dpte_segment;
777     Bit16u  dpte_offset;
778     Bit16u  key;
779     Bit8u   dpi_length;
780     Bit8u   reserved1;
781     Bit16u  reserved2;
782     Bit8u   host_bus[4];
783     Bit8u   iface_type[8];
784     Bit8u   iface_path[8];
785     Bit8u   device_path[8];
786     Bit8u   reserved3;
787     Bit8u   checksum;
788     } dpt_t;
789  
790   #define Int13DPT ((dpt_t *) 0)
791
792 #endif // BX_USE_ATADRV
793
794 typedef struct {
795   union {
796     struct {
797       Bit16u di, si, bp, sp;
798       Bit16u bx, dx, cx, ax;
799       } r16;
800     struct {
801       Bit16u filler[4];
802       Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
803       } r8;
804     } u;
805   } pusha_regs_t;
806
807 typedef struct {
808  union {
809   struct {
810     Bit32u edi, esi, ebp, esp;
811     Bit32u ebx, edx, ecx, eax;
812     } r32;
813   struct {
814     Bit16u di, filler1, si, filler2, bp, filler3, sp, filler4;
815     Bit16u bx, filler5, dx, filler6, cx, filler7, ax, filler8;
816     } r16;
817   struct {
818     Bit32u filler[4];
819     Bit8u  bl, bh; 
820     Bit16u filler1;
821     Bit8u  dl, dh; 
822     Bit16u filler2;
823     Bit8u  cl, ch;
824     Bit16u filler3;
825     Bit8u  al, ah;
826     Bit16u filler4;
827     } r8;
828   } u;
829 } pushad_regs_t;
830
831 typedef struct {
832   union {
833     struct {
834       Bit16u flags;
835       } r16;
836     struct {
837       Bit8u  flagsl;
838       Bit8u  flagsh;
839       } r8;
840     } u;
841   } flags_t;
842
843 #define SetCF(x)   x.u.r8.flagsl |= 0x01
844 #define SetZF(x)   x.u.r8.flagsl |= 0x40
845 #define ClearCF(x) x.u.r8.flagsl &= 0xfe
846 #define ClearZF(x) x.u.r8.flagsl &= 0xbf
847 #define GetCF(x)   (x.u.r8.flagsl & 0x01)
848
849 typedef struct {
850   Bit16u ip;
851   Bit16u cs;
852   flags_t flags;
853   } iret_addr_t;
854
855
856
857 static Bit8u          inb();
858 static Bit8u          inb_cmos();
859 static void           outb();
860 static void           outb_cmos();
861 static Bit16u         inw();
862 static void           outw();
863 static void           init_rtc();
864 static bx_bool        rtc_updating();
865
866 static Bit8u          read_byte();
867 static Bit16u         read_word();
868 static void           write_byte();
869 static void           write_word();
870 static void           bios_printf();
871 static void           copy_e820_table();
872
873 static Bit8u          inhibit_mouse_int_and_events();
874 static void           enable_mouse_int_and_events();
875 static Bit8u          send_to_mouse_ctrl();
876 static Bit8u          get_mouse_data();
877 static void           set_kbd_command_byte();
878
879 static void           int09_function();
880 static void           int13_harddisk();
881 static void           int13_cdrom();
882 static void           int13_cdemu();
883 static void           int13_eltorito();
884 static void           int13_diskette_function();
885 static void           int14_function();
886 static void           int15_function();
887 static void           int16_function();
888 static void           int17_function();
889 static Bit32u         int19_function();
890 static void           int1a_function();
891 static void           int70_function();
892 static void           int74_function();
893 static Bit16u         get_CS();
894 //static Bit16u         get_DS();
895 //static void           set_DS();
896 static Bit16u         get_SS();
897 static unsigned int   enqueue_key();
898 static unsigned int   dequeue_key();
899 static void           get_hd_geometry();
900 static void           set_diskette_ret_status();
901 static void           set_diskette_current_cyl();
902 static void           determine_floppy_media();
903 static bx_bool        floppy_drive_exists();
904 static bx_bool        floppy_drive_recal();
905 static bx_bool        floppy_media_known();
906 static bx_bool        floppy_media_sense();
907 static bx_bool        set_enable_a20();
908 static void           debugger_on();
909 static void           debugger_off();
910 static void           keyboard_init();
911 static void           keyboard_panic();
912 static void           shutdown_status_panic();
913 static void           nmi_handler_msg();
914
915 static void           print_bios_banner();
916 static void           print_boot_device();
917 static void           print_boot_failure();
918 static void           print_cdromboot_failure();
919
920 # if BX_USE_ATADRV
921
922 // ATA / ATAPI driver
923 void   ata_init();
924 void   ata_detect();
925 void   ata_reset();
926
927 Bit16u ata_cmd_non_data();
928 Bit16u ata_cmd_data_in();
929 Bit16u ata_cmd_data_out();
930 Bit16u ata_cmd_packet();
931
932 Bit16u atapi_get_sense();
933 Bit16u atapi_is_ready();
934 Bit16u atapi_is_cdrom();
935
936 #endif // BX_USE_ATADRV
937
938 #if BX_ELTORITO_BOOT
939
940 void   cdemu_init();
941 Bit8u  cdemu_isactive();
942 Bit8u  cdemu_emulated_drive();
943
944 Bit16u cdrom_boot();
945
946 #endif // BX_ELTORITO_BOOT
947
948 static char bios_cvs_version_string[] = "$Revision: 1.12 $";
949 static char bios_date_string[] = "$Date: 2008/07/11 22:59:38 $";
950
951 static char CVSID[] = "$Id: rombios.c,v 1.12 2008/07/11 22:59:38 pdinda Exp $";
952
953 /* Offset to skip the CVS $Id: prefix */ 
954 #define bios_version_string  (CVSID + 4)
955
956 #define BIOS_PRINTF_HALT     1
957 #define BIOS_PRINTF_SCREEN   2
958 #define BIOS_PRINTF_INFO     4
959 #define BIOS_PRINTF_DEBUG    8
960 #define BIOS_PRINTF_ALL      (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO)
961 #define BIOS_PRINTF_DEBHALT  (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT) 
962
963 #define printf(format, p...)  bios_printf(BIOS_PRINTF_SCREEN, format, ##p)
964
965 // Defines the output macros. 
966 // BX_DEBUG goes to INFO port until we can easily choose debug info on a 
967 // per-device basis. Debug info are sent only in debug mode
968 #if DEBUG_ROMBIOS
969 #  define BX_DEBUG(format, p...)  bios_printf(BIOS_PRINTF_ALL, format, ##p)    
970 #else
971 #  define BX_DEBUG(format, p...) 
972 #endif
973 #define BX_INFO(format, p...)   bios_printf(BIOS_PRINTF_INFO, format, ##p)
974 #define BX_PANIC(format, p...)  bios_printf(BIOS_PRINTF_DEBHALT, format, ##p)
975
976 #if DEBUG_ATA
977 #  define BX_DEBUG_ATA(a...) BX_DEBUG(a)
978 #else
979 #  define BX_DEBUG_ATA(a...)
980 #endif
981 #if DEBUG_INT13_HD
982 #  define BX_DEBUG_INT13_HD(a...) BX_DEBUG(a)
983 #else
984 #  define BX_DEBUG_INT13_HD(a...)
985 #endif
986 #if DEBUG_INT13_CD
987 #  define BX_DEBUG_INT13_CD(a...) BX_DEBUG(a)
988 #else
989 #  define BX_DEBUG_INT13_CD(a...)
990 #endif
991 #if DEBUG_INT13_ET
992 #  define BX_DEBUG_INT13_ET(a...) BX_DEBUG(a)
993 #else
994 #  define BX_DEBUG_INT13_ET(a...)
995 #endif
996 #if DEBUG_INT13_FL
997 #  define BX_DEBUG_INT13_FL(a...) BX_DEBUG(a)
998 #else
999 #  define BX_DEBUG_INT13_FL(a...)
1000 #endif
1001 #if DEBUG_INT15
1002 #  define BX_DEBUG_INT15(a...) BX_DEBUG(a)
1003 #else
1004 #  define BX_DEBUG_INT15(a...)
1005 #endif
1006 #if DEBUG_INT16
1007 #  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
1008 #else
1009 #  define BX_DEBUG_INT16(a...)
1010 #endif
1011 #if DEBUG_INT1A
1012 #  define BX_DEBUG_INT1A(a...) BX_DEBUG(a)
1013 #else
1014 #  define BX_DEBUG_INT1A(a...)
1015 #endif
1016 #if DEBUG_INT74
1017 #  define BX_DEBUG_INT74(a...) BX_DEBUG(a)
1018 #else
1019 #  define BX_DEBUG_INT74(a...)
1020 #endif
1021
1022 #define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
1023 #define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
1024 #define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
1025 #define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
1026 #define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
1027 #define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
1028 #define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
1029 #define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
1030
1031 #define GET_AL() ( AX & 0x00ff )
1032 #define GET_BL() ( BX & 0x00ff )
1033 #define GET_CL() ( CX & 0x00ff )
1034 #define GET_DL() ( DX & 0x00ff )
1035 #define GET_AH() ( AX >> 8 )
1036 #define GET_BH() ( BX >> 8 )
1037 #define GET_CH() ( CX >> 8 )
1038 #define GET_DH() ( DX >> 8 )
1039
1040 #define GET_ELDL() ( ELDX & 0x00ff )
1041 #define GET_ELDH() ( ELDX >> 8 )
1042
1043 #define SET_CF()     FLAGS |= 0x0001
1044 #define CLEAR_CF()   FLAGS &= 0xfffe
1045 #define GET_CF()     (FLAGS & 0x0001)
1046
1047 #define SET_ZF()     FLAGS |= 0x0040
1048 #define CLEAR_ZF()   FLAGS &= 0xffbf
1049 #define GET_ZF()     (FLAGS & 0x0040)
1050
1051 #define UNSUPPORTED_FUNCTION 0x86
1052
1053 #define none 0
1054 #define MAX_SCAN_CODE 0x53
1055
1056 static struct {
1057   Bit16u normal;
1058   Bit16u shift;
1059   Bit16u control;
1060   Bit16u alt;
1061   Bit8u lock_flags;
1062   } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
1063       {   none,   none,   none,   none, none },
1064       { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
1065       { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
1066       { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
1067       { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
1068       { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
1069       { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
1070       { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
1071       { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
1072       { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
1073       { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
1074       { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
1075       { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
1076       { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
1077       { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
1078       { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
1079       { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
1080       { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
1081       { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
1082       { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
1083       { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
1084       { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
1085       { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
1086       { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
1087       { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
1088       { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
1089       { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
1090       { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
1091       { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
1092       {   none,   none,   none,   none, none }, /* L Ctrl */
1093       { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
1094       { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
1095       { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
1096       { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
1097       { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
1098       { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
1099       { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
1100       { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
1101       { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
1102       { 0x273b, 0x273a,   none,   none, none }, /* ;: */
1103       { 0x2827, 0x2822,   none,   none, none }, /* '" */
1104       { 0x2960, 0x297e,   none,   none, none }, /* `~ */
1105       {   none,   none,   none,   none, none }, /* L shift */
1106       { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
1107       { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
1108       { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
1109       { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
1110       { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
1111       { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
1112       { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
1113       { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
1114       { 0x332c, 0x333c,   none,   none, none }, /* ,< */
1115       { 0x342e, 0x343e,   none,   none, none }, /* .> */
1116       { 0x352f, 0x353f,   none,   none, none }, /* /? */
1117       {   none,   none,   none,   none, none }, /* R Shift */
1118       { 0x372a, 0x372a,   none,   none, none }, /* * */
1119       {   none,   none,   none,   none, none }, /* L Alt */
1120       { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
1121       {   none,   none,   none,   none, none }, /* caps lock */
1122       { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
1123       { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
1124       { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
1125       { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
1126       { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
1127       { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
1128       { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
1129       { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
1130       { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
1131       { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
1132       {   none,   none,   none,   none, none }, /* Num Lock */
1133       {   none,   none,   none,   none, none }, /* Scroll Lock */
1134       { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
1135       { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
1136       { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
1137       { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
1138       { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
1139       { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
1140       { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
1141       { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
1142       { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
1143       { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
1144       { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
1145       { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
1146       { 0x5300, 0x532e,   none,   none, 0x20 }  /* Del */
1147       };
1148
1149   Bit8u
1150 inb(port)
1151   Bit16u port;
1152 {
1153 ASM_START
1154   push bp
1155   mov  bp, sp
1156
1157     push dx
1158     mov  dx, 4[bp]
1159     in   al, dx
1160     pop  dx
1161
1162   pop  bp
1163 ASM_END
1164 }
1165
1166 #if BX_USE_ATADRV
1167   Bit16u
1168 inw(port)
1169   Bit16u port;
1170 {
1171 ASM_START
1172   push bp
1173   mov  bp, sp
1174
1175     push dx
1176     mov  dx, 4[bp]
1177     in   ax, dx
1178     pop  dx
1179
1180   pop  bp
1181 ASM_END
1182 }
1183 #endif
1184
1185   void
1186 outb(port, val)
1187   Bit16u port;
1188   Bit8u  val;
1189 {
1190 ASM_START
1191   push bp
1192   mov  bp, sp
1193
1194     push ax
1195     push dx
1196     mov  dx, 4[bp]
1197     mov  al, 6[bp]
1198     out  dx, al
1199     pop  dx
1200     pop  ax
1201
1202   pop  bp
1203 ASM_END
1204 }
1205
1206 #if BX_USE_ATADRV
1207   void
1208 outw(port, val)
1209   Bit16u port;
1210   Bit16u  val;
1211 {
1212 ASM_START
1213   push bp
1214   mov  bp, sp
1215
1216     push ax
1217     push dx
1218     mov  dx, 4[bp]
1219     mov  ax, 6[bp]
1220     out  dx, ax
1221     pop  dx
1222     pop  ax
1223
1224   pop  bp
1225 ASM_END
1226 }
1227 #endif
1228
1229   void
1230 outb_cmos(cmos_reg, val)
1231   Bit8u cmos_reg;
1232   Bit8u val;
1233 {
1234 ASM_START
1235   push bp
1236   mov  bp, sp
1237
1238     mov  al, 4[bp] ;; cmos_reg
1239     out  0x70, al
1240     mov  al, 6[bp] ;; val
1241     out  0x71, al
1242
1243   pop  bp
1244 ASM_END
1245 }
1246
1247   Bit8u
1248 inb_cmos(cmos_reg)
1249   Bit8u cmos_reg;
1250 {
1251 ASM_START
1252   push bp
1253   mov  bp, sp
1254
1255     mov  al, 4[bp] ;; cmos_reg
1256     out 0x70, al
1257     in  al, 0x71
1258
1259   pop  bp
1260 ASM_END
1261 }
1262
1263   void
1264 init_rtc()
1265 {
1266   printf("rombios: init_rtc()\n");
1267   outb_cmos(0x0a, 0x26);
1268   outb_cmos(0x0b, 0x02);
1269   inb_cmos(0x0c);
1270   inb_cmos(0x0d);
1271 }
1272
1273   bx_bool
1274 rtc_updating()
1275 {
1276   // This function checks to see if the update-in-progress bit
1277   // is set in CMOS Status Register A.  If not, it returns 0.
1278   // If it is set, it tries to wait until there is a transition
1279   // to 0, and will return 0 if such a transition occurs.  A 1
1280   // is returned only after timing out.  The maximum period
1281   // that this bit should be set is constrained to 244useconds.
1282   // The count I use below guarantees coverage or more than
1283   // this time, with any reasonable IPS setting.
1284
1285   Bit16u count;
1286
1287   count = 25000;
1288   while (--count != 0) {
1289     if ( (inb_cmos(0x0a) & 0x80) == 0 )
1290       return(0);
1291     }
1292   return(1); // update-in-progress never transitioned to 0
1293 }
1294
1295
1296   Bit8u
1297 read_byte(seg, offset)
1298   Bit16u seg;
1299   Bit16u offset;
1300 {
1301 ASM_START
1302   push bp
1303   mov  bp, sp
1304
1305     push bx
1306     push ds
1307     mov  ax, 4[bp] ; segment
1308     mov  ds, ax
1309     mov  bx, 6[bp] ; offset
1310     mov  al, [bx]
1311     ;; al = return value (byte)
1312     pop  ds
1313     pop  bx
1314
1315   pop  bp
1316 ASM_END
1317 }
1318
1319   Bit16u
1320 read_word(seg, offset)
1321   Bit16u seg;
1322   Bit16u offset;
1323 {
1324 ASM_START
1325   push bp
1326   mov  bp, sp
1327
1328     push bx
1329     push ds
1330     mov  ax, 4[bp] ; segment
1331     mov  ds, ax
1332     mov  bx, 6[bp] ; offset
1333     mov  ax, [bx]
1334     ;; ax = return value (word)
1335     pop  ds
1336     pop  bx
1337
1338   pop  bp
1339 ASM_END
1340 }
1341
1342   void
1343 write_byte(seg, offset, data)
1344   Bit16u seg;
1345   Bit16u offset;
1346   Bit8u data;
1347 {
1348 ASM_START
1349   push bp
1350   mov  bp, sp
1351
1352     push ax
1353     push bx
1354     push ds
1355     mov  ax, 4[bp] ; segment
1356     mov  ds, ax
1357     mov  bx, 6[bp] ; offset
1358     mov  al, 8[bp] ; data byte
1359     mov  [bx], al  ; write data byte
1360     pop  ds
1361     pop  bx
1362     pop  ax
1363
1364   pop  bp
1365 ASM_END
1366 }
1367
1368   void
1369 write_word(seg, offset, data)
1370   Bit16u seg;
1371   Bit16u offset;
1372   Bit16u data;
1373 {
1374 ASM_START
1375   push bp
1376   mov  bp, sp
1377
1378     push ax
1379     push bx
1380     push ds
1381     mov  ax, 4[bp] ; segment
1382     mov  ds, ax
1383     mov  bx, 6[bp] ; offset
1384     mov  ax, 8[bp] ; data word
1385     mov  [bx], ax  ; write data word
1386     pop  ds
1387     pop  bx
1388     pop  ax
1389
1390   pop  bp
1391 ASM_END
1392 }
1393
1394   Bit16u
1395 get_CS()
1396 {
1397 ASM_START
1398   mov  ax, cs
1399 ASM_END
1400 }
1401
1402 //  Bit16u
1403 get_DS()
1404 {
1405 ASM_START
1406   mov  ax, ds
1407 ASM_END
1408 }
1409
1410 //
1411 //  void
1412 //set_DS(ds_selector)
1413 //  Bit16u ds_selector;
1414 //{
1415 //ASM_START
1416 //  push bp
1417 //  mov  bp, sp
1418 //
1419 //    push ax
1420 //    mov  ax, 4[bp] ; ds_selector
1421 //    mov  ds, ax
1422 //    pop  ax
1423 //
1424 //  pop  bp
1425 //ASM_END
1426 //}
1427
1428   Bit16u
1429 get_SS()
1430 {
1431 ASM_START
1432   mov  ax, ss
1433 ASM_END
1434 }
1435
1436 #ifdef HVMASSIST
1437 void
1438 copy_e820_table()
1439 {
1440   Bit8u nr_entries = read_byte(0x9000, 0x1e8);
1441   if (nr_entries > 32)
1442         nr_entries = 32;
1443   write_word(0xe000, 0x8, nr_entries);
1444   memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14);
1445 }
1446 #endif /* HVMASSIST */
1447
1448 #if BX_DEBUG_SERIAL
1449 /* serial debug port*/
1450 #define BX_DEBUG_PORT 0x03f8
1451
1452 /* data */
1453 #define UART_RBR 0x00
1454 #define UART_THR 0x00
1455
1456 /* control */
1457 #define UART_IER 0x01
1458 #define UART_IIR 0x02
1459 #define UART_FCR 0x02
1460 #define UART_LCR 0x03
1461 #define UART_MCR 0x04
1462 #define UART_DLL 0x00
1463 #define UART_DLM 0x01
1464
1465 /* status */
1466 #define UART_LSR 0x05
1467 #define UART_MSR 0x06
1468 #define UART_SCR 0x07
1469
1470 int uart_can_tx_byte(base_port)
1471     Bit16u base_port;
1472 {
1473     return inb(base_port + UART_LSR) & 0x20;
1474 }
1475
1476 void uart_wait_to_tx_byte(base_port)
1477     Bit16u base_port;
1478 {
1479     while (!uart_can_tx_byte(base_port));
1480 }
1481
1482 void uart_wait_until_sent(base_port)
1483     Bit16u base_port;
1484 {
1485     while (!(inb(base_port + UART_LSR) & 0x40));
1486 }
1487
1488 void uart_tx_byte(base_port, data)
1489     Bit16u base_port;
1490     Bit8u data;
1491 {
1492     uart_wait_to_tx_byte(base_port);
1493     outb(base_port + UART_THR, data);
1494     uart_wait_until_sent(base_port);
1495 }
1496 #endif
1497
1498   void
1499 wrch(c)
1500   Bit8u  c;
1501 {
1502   ASM_START
1503   push bp
1504   mov  bp, sp
1505
1506   push bx
1507   mov  ah, #0x0e
1508   mov  al, 4[bp]
1509   xor  bx,bx
1510   int  #0x10
1511   pop  bx
1512
1513   pop  bp
1514   ASM_END
1515 }
1516  
1517   void
1518 send(action, c)
1519   Bit16u action;
1520   Bit8u  c;
1521 {
1522 #if BX_DEBUG_SERIAL
1523   if (c == '\n') uart_tx_byte(BX_DEBUG_PORT, '\r');
1524   uart_tx_byte(BX_DEBUG_PORT, c);
1525 #endif
1526 #ifdef HVMASSIST
1527   outb(0xE9, c);
1528 #endif
1529 #if BX_VIRTUAL_PORTS
1530   if (action & BIOS_PRINTF_DEBUG) outb(DEBUG_PORT, c);
1531   if (action & BIOS_PRINTF_INFO) outb(INFO_PORT, c);
1532 #endif
1533   if (action & BIOS_PRINTF_SCREEN) {
1534     if (c == '\n') wrch('\r');
1535     wrch(c);
1536   }
1537 }
1538
1539   void
1540 put_int(action, val, width, neg)
1541   Bit16u action;
1542   short val, width;
1543   bx_bool neg;
1544 {
1545   short nval = val / 10;
1546   if (nval)
1547     put_int(action, nval, width - 1, neg);
1548   else {
1549     while (--width > 0) send(action, ' ');
1550     if (neg) send(action, '-');
1551   }
1552   send(action, val - (nval * 10) + '0');
1553 }
1554
1555   void
1556 put_uint(action, val, width, neg)
1557   Bit16u action;
1558   unsigned short val;
1559   short width;
1560   bx_bool neg;
1561 {
1562   unsigned short nval = val / 10;
1563   if (nval)
1564     put_uint(action, nval, width - 1, neg);
1565   else {
1566     while (--width > 0) send(action, ' ');
1567     if (neg) send(action, '-');
1568   }
1569   send(action, val - (nval * 10) + '0');
1570 }
1571
1572 //--------------------------------------------------------------------------
1573 // bios_printf()
1574 //   A compact variable argument printf function which prints its output via
1575 //   an I/O port so that it can be logged by Bochs/Plex.  
1576 //   Currently, only %x is supported (or %02x, %04x, etc).
1577 //
1578 //   Supports %[format_width][format]
1579 //   where format can be d,x,c,s
1580 //--------------------------------------------------------------------------
1581   void
1582 bios_printf(action, s)
1583   Bit16u action;
1584   Bit8u *s;
1585 {
1586   Bit8u c, format_char;
1587   bx_bool  in_format;
1588   short i;
1589   Bit16u  *arg_ptr;
1590   Bit16u   arg_seg, arg, nibble, shift_count, format_width;
1591
1592   arg_ptr = &s;
1593   arg_seg = get_SS();
1594
1595   in_format = 0;
1596   format_width = 0;
1597
1598   if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT) {
1599 #if BX_VIRTUAL_PORTS
1600     outb(PANIC_PORT2, 0x00);
1601 #endif
1602     bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
1603   }
1604
1605   while (c = read_byte(get_CS(), s)) {
1606     if ( c == '%' ) {
1607       in_format = 1;
1608       format_width = 0;
1609       }
1610     else if (in_format) {
1611       if ( (c>='0') && (c<='9') ) {
1612         format_width = (format_width * 10) + (c - '0');
1613         }
1614       else {
1615         arg_ptr++; // increment to next arg
1616         arg = read_word(arg_seg, arg_ptr);
1617         if (c == 'x') {
1618           if (format_width == 0)
1619             format_width = 4;
1620           for (i=format_width-1; i>=0; i--) {
1621             nibble = (arg >> (4 * i)) & 0x000f;
1622             send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A'));
1623             }
1624           }
1625         else if (c == 'u') {
1626           put_uint(action, arg, format_width, 0);
1627           }
1628         else if (c == 'd') {
1629           if (arg & 0x8000)
1630             put_int(action, -arg, format_width - 1, 1);
1631           else
1632             put_int(action, arg, format_width, 0);
1633           }
1634         else if (c == 's') {
1635           bios_printf(action & (~BIOS_PRINTF_HALT), arg);
1636           }
1637         else if (c == 'c') {
1638           send(action, arg);
1639           }
1640         else
1641           BX_PANIC("bios_printf: unknown format\n");
1642           in_format = 0;
1643         }
1644       }
1645     else {
1646       send(action, c);
1647       }
1648     s ++;
1649     }
1650
1651   if (action & BIOS_PRINTF_HALT) {
1652     // freeze in a busy loop.  
1653 ASM_START
1654     cli
1655  halt2_loop:
1656     hlt
1657     jmp halt2_loop
1658 ASM_END
1659     }
1660 }
1661
1662 //--------------------------------------------------------------------------
1663 // keyboard_init
1664 //--------------------------------------------------------------------------
1665 // this file is based on LinuxBIOS implementation of keyboard.c
1666 // could convert to #asm to gain space
1667   void
1668 keyboard_init()
1669 {
1670     Bit16u max;
1671     int rc;
1672
1673     BX_DEBUG("rombios: keyboard_init\n");
1674
1675     /* printf("Assuming keyboard already inited and returning\n");
1676        return; */
1677
1678     /* ------------------- Flush buffers ------------------------*/
1679     /* Wait until buffer is empty */
1680     max=0xffff;
1681     while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x00); 
1682
1683     /* flush incoming keys */
1684     // temporarily chaged for debug -PAD
1685     //    max=0x2000;  
1686     max=10;
1687     while (--max > 0) {
1688         outb(0x80, 0x01);
1689         if (inb(0x64) & 0x01) {
1690             inb(0x60);
1691             max = 0x2000;
1692             }
1693         }
1694   
1695     // Due to timer issues, and if the IPS setting is > 15000000, 
1696     // the incoming keys might not be flushed here. That will
1697     // cause a panic a few lines below.  See sourceforge bug report :
1698     // [ 642031 ] FATAL: Keyboard RESET error:993
1699
1700     /* ------------------- controller side ----------------------*/
1701     /* send cmd = 0xAA, self test 8042 */
1702     outb(0x64, 0xaa);
1703
1704     /* Wait until buffer is empty */
1705     max=0xffff;
1706     while ( (inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x02);
1707     if (max==0x0) keyboard_panic(00);
1708
1709     /* Wait for data */
1710     max=0xffff;
1711     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x03);
1712     if (max==0x0) keyboard_panic(01);
1713
1714     /* read self-test result, 0x55 should be returned from 0x60 */
1715     if ((inb(0x60) != 0x55)){
1716         keyboard_panic(991);
1717     }
1718
1719     /* send cmd = 0xAB, keyboard interface test */
1720     outb(0x64,0xab);
1721
1722     /* Wait until buffer is empty */
1723     max=0xffff;
1724     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x10);
1725     if (max==0x0) keyboard_panic(10);
1726
1727     /* Wait for data */
1728     max=0xffff;
1729     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x11);
1730     if (max==0x0) keyboard_panic(11);
1731
1732     /* read keyboard interface test result, */
1733     /* 0x00 should be returned form 0x60 */
1734     if ((inb(0x60) != 0x00)) {
1735         keyboard_panic(992);
1736     }
1737
1738     /* Enable Keyboard clock */
1739     outb(0x64,0xae);
1740     outb(0x64,0xa8);
1741
1742     /* ------------------- keyboard side ------------------------*/
1743     /* reset kerboard and self test  (keyboard side) */
1744     outb(0x60, 0xff);
1745
1746     /* Wait until buffer is empty */
1747     max=0xffff;
1748     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x20);
1749     if (max==0x0) keyboard_panic(20);
1750
1751     /* Wait for data */
1752     max=0xffff;
1753     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x21);
1754     if (max==0x0) keyboard_panic(21);
1755
1756     /* keyboard should return ACK */
1757     if ((inb(0x60) != 0xfa)) {
1758         keyboard_panic(993);
1759     }
1760
1761     /* Wait for data */
1762     max=0xffff;
1763     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x31);
1764     if (max==0x0) keyboard_panic(31);
1765
1766     if ((inb(0x60) != 0xaa)) {
1767         keyboard_panic(994);
1768     }
1769
1770     /* Disable keyboard */
1771     outb(0x60, 0xf5);
1772
1773     /* Wait until buffer is empty */
1774     max=0xffff;
1775     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x40);
1776     if (max==0x0) keyboard_panic(40);
1777
1778     /* Wait for data */
1779     max=0xffff;
1780     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x41);
1781     if (max==0x0) keyboard_panic(41);
1782
1783     /* keyboard should return ACK */
1784     rc=inb(0x60);
1785     if (rc != 0xfa) {
1786         printf("rc=0x%x\n",rc);
1787         keyboard_panic(995);
1788     }
1789
1790     /* Write Keyboard Mode */
1791     outb(0x64, 0x60);
1792
1793     /* Wait until buffer is empty */
1794     max=0xffff;
1795     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x50);
1796     if (max==0x0) keyboard_panic(50);
1797
1798     /* send cmd: scan code convert, disable mouse, enable IRQ 1 */
1799     outb(0x60, 0x61);
1800
1801     /* Wait until buffer is empty */
1802     max=0xffff;
1803     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x60);
1804     if (max==0x0) keyboard_panic(60);
1805
1806     /* Enable keyboard */
1807     outb(0x60, 0xf4);
1808
1809     /* Wait until buffer is empty */
1810     max=0xffff;
1811     while ((inb(0x64) & 0x02) && (--max>0)) outb(0x80, 0x70);
1812     if (max==0x0) keyboard_panic(70);
1813
1814     /* Wait for data */
1815     max=0xffff;
1816     while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x71);
1817     if (max==0x0) keyboard_panic(70);
1818
1819     /* keyboard should return ACK */
1820     if ((inb(0x60) != 0xfa)) {
1821         keyboard_panic(996);
1822     }
1823     
1824     outb(0x80, 0x77);
1825     printf("keyboard init done.\n");
1826 }
1827
1828 //--------------------------------------------------------------------------
1829 // keyboard_panic
1830 //--------------------------------------------------------------------------
1831   void
1832 keyboard_panic(status)
1833   Bit16u status;
1834 {
1835   // If you're getting a 993 keyboard panic here, 
1836   // please see the comment in keyboard_init
1837   printf("Keyboard error:%u CONTINUING\n",status); return;
1838   BX_PANIC("Keyboard error:%u\n",status);
1839 }
1840
1841 //--------------------------------------------------------------------------
1842 // shutdown_status_panic
1843 //   called when the shutdown statsu is not implemented, displays the status
1844 //--------------------------------------------------------------------------
1845   void
1846 shutdown_status_panic(status)
1847   Bit16u status;
1848 {
1849   BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
1850 }
1851
1852 //--------------------------------------------------------------------------
1853 // print_bios_banner
1854 //   displays a the bios version
1855 //--------------------------------------------------------------------------
1856 void
1857 print_bios_banner()
1858 {
1859   printf("Hi from peter's modified bios\n");
1860   printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":"");
1861   printf("%s %s\n", bios_cvs_version_string, bios_date_string);
1862   printf("\n");
1863 }
1864
1865 //--------------------------------------------------------------------------
1866 // print_boot_device
1867 //   displays the boot device
1868 //--------------------------------------------------------------------------
1869
1870 static char drivetypes[][10]={"Floppy","Hard Disk","CD-Rom"};
1871
1872 void
1873 print_boot_device(cdboot, drive)
1874   Bit8u cdboot; Bit16u drive;
1875 {
1876   Bit8u i;
1877
1878   // cdboot contains 0 if floppy/harddisk, 1 otherwise
1879   // drive contains real/emulated boot drive
1880
1881   if(cdboot)i=2;                    // CD-Rom
1882   else if((drive&0x0080)==0x00)i=0; // Floppy
1883   else if((drive&0x0080)==0x80)i=1; // Hard drive
1884   else return;
1885   
1886   printf("Booting from %s...\n",drivetypes[i]);
1887 }
1888
1889 //--------------------------------------------------------------------------
1890 // print_boot_failure
1891 //   displays the reason why boot failed
1892 //--------------------------------------------------------------------------
1893   void
1894 print_boot_failure(cdboot, drive, reason, lastdrive)
1895   Bit8u cdboot; Bit8u drive; Bit8u lastdrive;
1896 {
1897   Bit16u drivenum = drive&0x7f;
1898
1899   // cdboot: 1 if boot from cd, 0 otherwise
1900   // drive : drive number
1901   // reason: 0 signature check failed, 1 read error
1902   // lastdrive: 1 boot drive is the last one in boot sequence
1903  
1904   if (cdboot)
1905     bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s failed\n",drivetypes[2]);
1906   else if (drive & 0x80)
1907     bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[1],drivenum);
1908   else
1909     bios_printf(BIOS_PRINTF_INFO | BIOS_PRINTF_SCREEN, "Boot from %s %d failed\n", drivetypes[0],drivenum);
1910
1911   if (lastdrive==1) {
1912     if (reason==0)
1913       BX_PANIC("Not a bootable disk\n");
1914     else
1915       BX_PANIC("Could not read the boot disk\n");
1916   }
1917 }
1918
1919 //--------------------------------------------------------------------------
1920 // print_cdromboot_failure
1921 //   displays the reason why boot failed
1922 //--------------------------------------------------------------------------
1923   void
1924 print_cdromboot_failure( code )
1925   Bit16u code;
1926 {
1927   bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code);
1928   
1929   return;
1930 }
1931
1932 void
1933 nmi_handler_msg()
1934 {
1935   BX_PANIC("NMI Handler called\n");
1936 }
1937
1938 void
1939 int18_panic_msg()
1940 {
1941   BX_PANIC("INT18: BOOT FAILURE\n");
1942 }
1943
1944 void
1945 log_bios_start()
1946 {
1947 #if BX_DEBUG_SERIAL
1948   outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */
1949 #endif
1950   BX_INFO("%s\n", bios_version_string);
1951 }
1952
1953   bx_bool
1954 set_enable_a20(val)
1955   bx_bool val;
1956 {
1957   Bit8u  oldval;
1958
1959   // Use PS2 System Control port A to set A20 enable
1960
1961   // get current setting first
1962   oldval = inb(0x92);
1963
1964   // change A20 status
1965   if (val)
1966     outb(0x92, oldval | 0x02);
1967   else
1968     outb(0x92, oldval & 0xfd);
1969
1970   return((oldval & 0x02) != 0);
1971 }
1972
1973   void
1974 debugger_on()
1975 {
1976   outb(0xfedc, 0x01);
1977 }
1978
1979   void
1980 debugger_off()
1981 {
1982   outb(0xfedc, 0x00);
1983 }
1984
1985 #if BX_USE_ATADRV
1986
1987 // ---------------------------------------------------------------------------
1988 // Start of ATA/ATAPI Driver
1989 // ---------------------------------------------------------------------------
1990
1991 // Global defines -- ATA register and register bits.
1992 // command block & control block regs
1993 #define ATA_CB_DATA  0   // data reg         in/out pio_base_addr1+0
1994 #define ATA_CB_ERR   1   // error            in     pio_base_addr1+1
1995 #define ATA_CB_FR    1   // feature reg         out pio_base_addr1+1
1996 #define ATA_CB_SC    2   // sector count     in/out pio_base_addr1+2
1997 #define ATA_CB_SN    3   // sector number    in/out pio_base_addr1+3
1998 #define ATA_CB_CL    4   // cylinder low     in/out pio_base_addr1+4
1999 #define ATA_CB_CH    5   // cylinder high    in/out pio_base_addr1+5
2000 #define ATA_CB_DH    6   // device head      in/out pio_base_addr1+6
2001 #define ATA_CB_STAT  7   // primary status   in     pio_base_addr1+7
2002 #define ATA_CB_CMD   7   // command             out pio_base_addr1+7
2003 #define ATA_CB_ASTAT 6   // alternate status in     pio_base_addr2+6
2004 #define ATA_CB_DC    6   // device control      out pio_base_addr2+6
2005 #define ATA_CB_DA    7   // device address   in     pio_base_addr2+7
2006
2007 #define ATA_CB_ER_ICRC 0x80    // ATA Ultra DMA bad CRC
2008 #define ATA_CB_ER_BBK  0x80    // ATA bad block
2009 #define ATA_CB_ER_UNC  0x40    // ATA uncorrected error
2010 #define ATA_CB_ER_MC   0x20    // ATA media change
2011 #define ATA_CB_ER_IDNF 0x10    // ATA id not found
2012 #define ATA_CB_ER_MCR  0x08    // ATA media change request
2013 #define ATA_CB_ER_ABRT 0x04    // ATA command aborted
2014 #define ATA_CB_ER_NTK0 0x02    // ATA track 0 not found
2015 #define ATA_CB_ER_NDAM 0x01    // ATA address mark not found
2016
2017 #define ATA_CB_ER_P_SNSKEY 0xf0   // ATAPI sense key (mask)
2018 #define ATA_CB_ER_P_MCR    0x08   // ATAPI Media Change Request
2019 #define ATA_CB_ER_P_ABRT   0x04   // ATAPI command abort
2020 #define ATA_CB_ER_P_EOM    0x02   // ATAPI End of Media
2021 #define ATA_CB_ER_P_ILI    0x01   // ATAPI Illegal Length Indication
2022
2023 // ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
2024 #define ATA_CB_SC_P_TAG    0xf8   // ATAPI tag (mask)
2025 #define ATA_CB_SC_P_REL    0x04   // ATAPI release
2026 #define ATA_CB_SC_P_IO     0x02   // ATAPI I/O
2027 #define ATA_CB_SC_P_CD     0x01   // ATAPI C/D
2028
2029 // bits 7-4 of the device/head (CB_DH) reg
2030 #define ATA_CB_DH_DEV0 0xa0    // select device 0
2031 #define ATA_CB_DH_DEV1 0xb0    // select device 1
2032
2033 // status reg (CB_STAT and CB_ASTAT) bits
2034 #define ATA_CB_STAT_BSY  0x80  // busy
2035 #define ATA_CB_STAT_RDY  0x40  // ready
2036 #define ATA_CB_STAT_DF   0x20  // device fault
2037 #define ATA_CB_STAT_WFT  0x20  // write fault (old name)
2038 #define ATA_CB_STAT_SKC  0x10  // seek complete
2039 #define ATA_CB_STAT_SERV 0x10  // service
2040 #define ATA_CB_STAT_DRQ  0x08  // data request
2041 #define ATA_CB_STAT_CORR 0x04  // corrected
2042 #define ATA_CB_STAT_IDX  0x02  // index
2043 #define ATA_CB_STAT_ERR  0x01  // error (ATA)
2044 #define ATA_CB_STAT_CHK  0x01  // check (ATAPI)
2045
2046 // device control reg (CB_DC) bits
2047 #define ATA_CB_DC_HD15   0x08  // bit should always be set to one
2048 #define ATA_CB_DC_SRST   0x04  // soft reset
2049 #define ATA_CB_DC_NIEN   0x02  // disable interrupts
2050
2051 // Most mandtory and optional ATA commands (from ATA-3),
2052 #define ATA_CMD_CFA_ERASE_SECTORS            0xC0
2053 #define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE     0x03
2054 #define ATA_CMD_CFA_TRANSLATE_SECTOR         0x87
2055 #define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE  0xCD
2056 #define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE   0x38
2057 #define ATA_CMD_CHECK_POWER_MODE1            0xE5
2058 #define ATA_CMD_CHECK_POWER_MODE2            0x98
2059 #define ATA_CMD_DEVICE_RESET                 0x08
2060 #define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC    0x90
2061 #define ATA_CMD_FLUSH_CACHE                  0xE7
2062 #define ATA_CMD_FORMAT_TRACK                 0x50
2063 #define ATA_CMD_IDENTIFY_DEVICE              0xEC
2064 #define ATA_CMD_IDENTIFY_DEVICE_PACKET       0xA1
2065 #define ATA_CMD_IDENTIFY_PACKET_DEVICE       0xA1
2066 #define ATA_CMD_IDLE1                        0xE3
2067 #define ATA_CMD_IDLE2                        0x97
2068 #define ATA_CMD_IDLE_IMMEDIATE1              0xE1
2069 #define ATA_CMD_IDLE_IMMEDIATE2              0x95
2070 #define ATA_CMD_INITIALIZE_DRIVE_PARAMETERS  0x91
2071 #define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
2072 #define ATA_CMD_NOP                          0x00
2073 #define ATA_CMD_PACKET                       0xA0
2074 #define ATA_CMD_READ_BUFFER                  0xE4
2075 #define ATA_CMD_READ_DMA                     0xC8
2076 #define ATA_CMD_READ_DMA_QUEUED              0xC7
2077 #define ATA_CMD_READ_MULTIPLE                0xC4
2078 #define ATA_CMD_READ_SECTORS                 0x20
2079 #define ATA_CMD_READ_VERIFY_SECTORS          0x40
2080 #define ATA_CMD_RECALIBRATE                  0x10
2081 #define ATA_CMD_SEEK                         0x70
2082 #define ATA_CMD_SET_FEATURES                 0xEF
2083 #define ATA_CMD_SET_MULTIPLE_MODE            0xC6
2084 #define ATA_CMD_SLEEP1                       0xE6
2085 #define ATA_CMD_SLEEP2                       0x99
2086 #define ATA_CMD_STANDBY1                     0xE2
2087 #define ATA_CMD_STANDBY2                     0x96
2088 #define ATA_CMD_STANDBY_IMMEDIATE1           0xE0
2089 #define ATA_CMD_STANDBY_IMMEDIATE2           0x94
2090 #define ATA_CMD_WRITE_BUFFER                 0xE8
2091 #define ATA_CMD_WRITE_DMA                    0xCA
2092 #define ATA_CMD_WRITE_DMA_QUEUED             0xCC
2093 #define ATA_CMD_WRITE_MULTIPLE               0xC5
2094 #define ATA_CMD_WRITE_SECTORS                0x30
2095 #define ATA_CMD_WRITE_VERIFY                 0x3C
2096
2097 #define ATA_IFACE_NONE    0x00
2098 #define ATA_IFACE_ISA     0x00
2099 #define ATA_IFACE_PCI     0x01
2100
2101 #define ATA_TYPE_NONE     0x00
2102 #define ATA_TYPE_UNKNOWN  0x01
2103 #define ATA_TYPE_ATA      0x02
2104 #define ATA_TYPE_ATAPI    0x03
2105
2106 #define ATA_DEVICE_NONE  0x00
2107 #define ATA_DEVICE_HD    0xFF
2108 #define ATA_DEVICE_CDROM 0x05
2109
2110 #define ATA_MODE_NONE    0x00
2111 #define ATA_MODE_PIO16   0x00
2112 #define ATA_MODE_PIO32   0x01
2113 #define ATA_MODE_ISADMA  0x02
2114 #define ATA_MODE_PCIDMA  0x03
2115 #define ATA_MODE_USEIRQ  0x10
2116
2117 #define ATA_TRANSLATION_NONE  0
2118 #define ATA_TRANSLATION_LBA   1
2119 #define ATA_TRANSLATION_LARGE 2
2120 #define ATA_TRANSLATION_RECHS 3
2121
2122 #define ATA_DATA_NO      0x00
2123 #define ATA_DATA_IN      0x01
2124 #define ATA_DATA_OUT     0x02
2125   
2126 // ---------------------------------------------------------------------------
2127 // ATA/ATAPI driver : initialization
2128 // ---------------------------------------------------------------------------
2129 void ata_init( )
2130 {
2131   Bit16u ebda_seg=read_word(0x0040,0x000E);
2132   Bit8u  channel, device;
2133
2134   //BX_DEBUG("rombios: ata_init\n");
2135
2136   // Channels info init. 
2137   for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) {
2138     write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE);
2139     write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0);
2140     write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2,0x0);
2141     write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0);
2142     }
2143
2144   // Devices info init. 
2145   for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2146     write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE);
2147     write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE);
2148     write_byte(ebda_seg,&EbdaData->ata.devices[device].removable,0);
2149     write_byte(ebda_seg,&EbdaData->ata.devices[device].lock,0);
2150     write_byte(ebda_seg,&EbdaData->ata.devices[device].mode,ATA_MODE_NONE);
2151     write_word(ebda_seg,&EbdaData->ata.devices[device].blksize,0);
2152     write_byte(ebda_seg,&EbdaData->ata.devices[device].translation,ATA_TRANSLATION_NONE);
2153     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads,0);
2154     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders,0);
2155     write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt,0);
2156     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0);
2157     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0);
2158     write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0);
2159     
2160     write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L);
2161     }
2162
2163   // hdidmap  and cdidmap init. 
2164   for (device=0; device<BX_MAX_ATA_DEVICES; device++) {
2165     write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES);
2166     write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES);
2167     }
2168
2169   write_byte(ebda_seg,&EbdaData->ata.hdcount,0);
2170   write_byte(ebda_seg,&EbdaData->ata.cdcount,0);
2171 }
2172
2173 // ---------------------------------------------------------------------------
2174 // ATA/ATAPI driver : device detection
2175 // ---------------------------------------------------------------------------
2176
2177 void ata_detect( )
2178 {
2179   Bit16u ebda_seg=read_word(0x0040,0x000E);
2180   Bit8u  hdcount, cdcount, device, type;
2181   Bit8u  buffer[0x0200];
2182
2183   //BX_DEBUG("rombios: ata_detect\n");
2184
2185 #if BX_MAX_ATA_INTERFACES > 0
2186   write_byte(ebda_seg,&EbdaData->ata.channels[0].iface,ATA_IFACE_ISA);
2187   write_word(ebda_seg,&EbdaData->ata.channels[0].iobase1,0x1f0);
2188   write_word(ebda_seg,&EbdaData->ata.channels[0].iobase2,0x3f0);
2189   write_byte(ebda_seg,&EbdaData->ata.channels[0].irq,14);
2190 #endif
2191 #if BX_MAX_ATA_INTERFACES > 1
2192   write_byte(ebda_seg,&EbdaData->ata.channels[1].iface,ATA_IFACE_ISA);
2193   write_word(ebda_seg,&EbdaData->ata.channels[1].iobase1,0x170);
2194   write_word(ebda_seg,&EbdaData->ata.channels[1].iobase2,0x370);
2195   write_byte(ebda_seg,&EbdaData->ata.channels[1].irq,15);
2196 #endif
2197 #if BX_MAX_ATA_INTERFACES > 2
2198   write_byte(ebda_seg,&EbdaData->ata.channels[2].iface,ATA_IFACE_ISA);
2199   write_word(ebda_seg,&EbdaData->ata.channels[2].iobase1,0x1e8);
2200   write_word(ebda_seg,&EbdaData->ata.channels[2].iobase2,0x3e0);
2201   write_byte(ebda_seg,&EbdaData->ata.channels[2].irq,12);
2202 #endif
2203 #if BX_MAX_ATA_INTERFACES > 3
2204   write_byte(ebda_seg,&EbdaData->ata.channels[3].iface,ATA_IFACE_ISA);
2205   write_word(ebda_seg,&EbdaData->ata.channels[3].iobase1,0x168);
2206   write_word(ebda_seg,&EbdaData->ata.channels[3].iobase2,0x360);
2207   write_byte(ebda_seg,&EbdaData->ata.channels[3].irq,11);
2208 #endif
2209 #if BX_MAX_ATA_INTERFACES > 4
2210 #error Please fill the ATA interface informations
2211 #endif
2212
2213   // Device detection
2214   hdcount=cdcount=0;
2215   
2216   for(device=0; device<BX_MAX_ATA_DEVICES; device++) {
2217     Bit16u iobase1, iobase2;
2218     Bit8u  channel, slave, shift;
2219     Bit8u  sc, sn, cl, ch, st;
2220
2221     channel = device / 2;
2222     slave = device % 2;
2223
2224     iobase1 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1);
2225     iobase2 =read_word(ebda_seg,&EbdaData->ata.channels[channel].iobase2);
2226
2227     // Disable interrupts
2228     outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2229
2230     // Look for device
2231     outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2232     outb(iobase1+ATA_CB_SC, 0x55);
2233     outb(iobase1+ATA_CB_SN, 0xaa);
2234     outb(iobase1+ATA_CB_SC, 0xaa);
2235     outb(iobase1+ATA_CB_SN, 0x55);
2236     outb(iobase1+ATA_CB_SC, 0x55);
2237     outb(iobase1+ATA_CB_SN, 0xaa);
2238
2239     // If we found something
2240     sc = inb(iobase1+ATA_CB_SC);
2241     sn = inb(iobase1+ATA_CB_SN);
2242
2243     if ( (sc == 0x55) && (sn == 0xaa) ) {
2244       write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN);
2245     
2246       // reset the channel
2247       ata_reset (device);
2248       
2249       // check for ATA or ATAPI
2250       outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2251       sc = inb(iobase1+ATA_CB_SC);
2252       sn = inb(iobase1+ATA_CB_SN);
2253       if ( (sc==0x01) && (sn==0x01) ) {
2254         cl = inb(iobase1+ATA_CB_CL);
2255         ch = inb(iobase1+ATA_CB_CH);
2256         st = inb(iobase1+ATA_CB_STAT);
2257
2258         if ( (cl==0x14) && (ch==0xeb) ) {
2259           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI);
2260           }
2261         else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) {
2262           write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA);
2263           }
2264         }
2265       }
2266
2267     type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type);
2268     
2269     // Now we send a IDENTIFY command to ATA device 
2270     if(type == ATA_TYPE_ATA) {
2271       Bit32u sectors;
2272       Bit16u cylinders, heads, spt, blksize;
2273       Bit8u  translation, removable, mode;
2274
2275       // default mode to PIO16
2276       mode = ATA_MODE_PIO16;
2277
2278       //Temporary values to do the transfer
2279       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2280       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2281
2282       if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 )
2283         BX_PANIC("ata-detect: Failed to detect ATA device\n");
2284
2285       removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2286 #ifndef NO_PIO32
2287       mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2288 #endif
2289
2290       blksize   = read_word(get_SS(),buffer+10);
2291       
2292       cylinders = read_word(get_SS(),buffer+(1*2)); // word 1
2293       heads     = read_word(get_SS(),buffer+(3*2)); // word 3
2294       spt       = read_word(get_SS(),buffer+(6*2)); // word 6
2295
2296       sectors   = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61
2297
2298       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD);
2299       write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2300       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2301       write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2302       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads);
2303       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders);
2304       write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt);
2305       write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors);
2306       BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
2307
2308       translation = inb_cmos(0x39 + channel/2);
2309       for (shift=device%4; shift>0; shift--) translation >>= 2;
2310       translation &= 0x03;
2311
2312       write_byte(ebda_seg,&EbdaData->ata.devices[device].translation, translation);
2313
2314       switch (translation) {
2315         case ATA_TRANSLATION_NONE:
2316           BX_INFO("none");
2317           break;
2318         case ATA_TRANSLATION_LBA:
2319           BX_INFO("lba");
2320           break;
2321         case ATA_TRANSLATION_LARGE:
2322           BX_INFO("large");
2323           break;
2324         case ATA_TRANSLATION_RECHS:
2325           BX_INFO("r-echs");
2326           break;
2327         }
2328       switch (translation) {
2329         case ATA_TRANSLATION_NONE:
2330           break;
2331         case ATA_TRANSLATION_LBA:
2332           spt = 63;
2333           sectors /= 63;
2334           heads = sectors / 1024;
2335           if (heads>128) heads = 255;
2336           else if (heads>64) heads = 128;
2337           else if (heads>32) heads = 64;
2338           else if (heads>16) heads = 32;
2339           else heads=16;
2340           cylinders = sectors / heads;
2341           break;
2342         case ATA_TRANSLATION_RECHS:
2343           // Take care not to overflow
2344           if (heads==16) {
2345             if(cylinders>61439) cylinders=61439;
2346             heads=15;
2347             cylinders = (Bit16u)((Bit32u)(cylinders)*16/15);
2348             }
2349           // then go through the large bitshift process
2350         case ATA_TRANSLATION_LARGE:
2351           while(cylinders > 1024) {
2352             cylinders >>= 1;
2353             heads <<= 1;
2354
2355             // If we max out the head count
2356             if (heads > 127) break;
2357           }
2358           break;
2359         }
2360       // clip to 1024 cylinders in lchs
2361       if (cylinders > 1024) cylinders=1024;
2362       BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
2363
2364       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads);
2365       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders);
2366       write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt);
2367  
2368       // fill hdidmap 
2369       write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device);
2370       hdcount++;
2371       }
2372     
2373     // Now we send a IDENTIFY command to ATAPI device
2374     if(type == ATA_TYPE_ATAPI) {
2375  
2376       Bit8u  type, removable, mode;
2377       Bit16u blksize;
2378
2379       // default mode to PIO16
2380       mode = ATA_MODE_PIO16;
2381
2382       //Temporary values to do the transfer
2383       write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM);
2384       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16);
2385
2386       if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0)
2387         BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
2388
2389       type      = read_byte(get_SS(),buffer+1) & 0x1f;
2390       removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0;
2391 #ifndef NO_PIO32
2392       mode      = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
2393 #endif
2394       blksize   = 2048;
2395
2396       write_byte(ebda_seg,&EbdaData->ata.devices[device].device, type);
2397       write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable);
2398       write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode);
2399       write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize);
2400
2401       // fill cdidmap 
2402       write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device);
2403       cdcount++;
2404       }
2405   
2406       {
2407       Bit32u sizeinmb;
2408       Bit16u ataversion;
2409       Bit8u  c, i, version, model[41];
2410       
2411       switch (type) {
2412         case ATA_TYPE_ATA:
2413           sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors);
2414           sizeinmb >>= 11;
2415         case ATA_TYPE_ATAPI:
2416           // Read ATA/ATAPI version
2417           ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160);
2418           for(version=15;version>0;version--) { 
2419             if((ataversion&(1<<version))!=0)
2420             break;
2421             }
2422
2423           // Read model name
2424           for(i=0;i<20;i++){
2425             write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1));
2426             write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54));
2427             }
2428
2429           // Reformat
2430           write_byte(get_SS(),model+40,0x00);
2431           for(i=39;i>0;i--){
2432             if(read_byte(get_SS(),model+i)==0x20)
2433               write_byte(get_SS(),model+i,0x00);
2434             else break;
2435             }
2436           break;
2437         }
2438
2439       switch (type) {
2440         case ATA_TYPE_ATA:
2441           printf("ata%d %s: ",channel,slave?" slave":"master");
2442           i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2443           printf(" ATA-%d Hard-Disk (%d MBytes)\n",version,(Bit16u)sizeinmb);
2444           break;
2445         case ATA_TYPE_ATAPI:
2446           printf("ata%d %s: ",channel,slave?" slave":"master");
2447           i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c);
2448           if(read_byte(ebda_seg,&EbdaData->ata.devices[device].device)==ATA_DEVICE_CDROM)
2449             printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
2450           else
2451             printf(" ATAPI-%d Device\n",version);
2452           break;
2453         case ATA_TYPE_UNKNOWN:
2454           printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
2455           break;
2456         }
2457       }
2458     }
2459
2460   // Store the devices counts
2461   write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount);
2462   write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount);
2463   write_byte(0x40,0x75, hdcount);
2464  
2465   printf("\n");
2466
2467   // FIXME : should use bios=cmos|auto|disable bits
2468   // FIXME : should know about translation bits
2469   // FIXME : move hard_drive_post here 
2470   
2471 }
2472
2473 // ---------------------------------------------------------------------------
2474 // ATA/ATAPI driver : software reset 
2475 // ---------------------------------------------------------------------------
2476 // ATA-3
2477 // 8.2.1 Software reset - Device 0
2478
2479 void   ata_reset(device)
2480 Bit16u device;
2481 {
2482   Bit16u ebda_seg=read_word(0x0040,0x000E);
2483   Bit16u iobase1, iobase2;
2484   Bit8u  channel, slave, sn, sc; 
2485   Bit16u max;
2486
2487   channel = device / 2;
2488   slave = device % 2;
2489
2490   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2491   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2492
2493   // Reset
2494
2495 // 8.2.1 (a) -- set SRST in DC
2496   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST);
2497
2498 // 8.2.1 (b) -- wait for BSY
2499   max=0xff;
2500   while(--max>0) {
2501     Bit8u status = inb(iobase1+ATA_CB_STAT);
2502     if ((status & ATA_CB_STAT_BSY) != 0) break;
2503   }
2504
2505 // 8.2.1 (f) -- clear SRST
2506   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2507
2508   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) {
2509
2510 // 8.2.1 (g) -- check for sc==sn==0x01
2511     // select device
2512     outb(iobase1+ATA_CB_DH, slave?ATA_CB_DH_DEV1:ATA_CB_DH_DEV0);
2513     sc = inb(iobase1+ATA_CB_SC);
2514     sn = inb(iobase1+ATA_CB_SN);
2515
2516     if ( (sc==0x01) && (sn==0x01) ) {
2517
2518 // 8.2.1 (h) -- wait for not BSY
2519       max=0xff;
2520       while(--max>0) {
2521         Bit8u status = inb(iobase1+ATA_CB_STAT);
2522         if ((status & ATA_CB_STAT_BSY) == 0) break;
2523         }
2524       }
2525     }
2526
2527 // 8.2.1 (i) -- wait for DRDY
2528   max=0xfff;
2529   while(--max>0) {
2530     Bit8u status = inb(iobase1+ATA_CB_STAT);
2531       if ((status & ATA_CB_STAT_RDY) != 0) break;
2532   }
2533
2534   // Enable interrupts
2535   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2536 }
2537
2538 // ---------------------------------------------------------------------------
2539 // ATA/ATAPI driver : execute a non data command 
2540 // ---------------------------------------------------------------------------
2541
2542 Bit16u ata_cmd_non_data()
2543 {return 0;}
2544
2545 // ---------------------------------------------------------------------------
2546 // ATA/ATAPI driver : execute a data-in command
2547 // ---------------------------------------------------------------------------
2548       // returns
2549       // 0 : no error
2550       // 1 : BUSY bit set
2551       // 2 : read error
2552       // 3 : expected DRQ=1
2553       // 4 : no sectors left to read/verify
2554       // 5 : more sectors to read/verify
2555       // 6 : no sectors left to write
2556       // 7 : more sectors to write
2557 Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset)
2558 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2559 Bit32u lba;
2560 {
2561   Bit16u ebda_seg=read_word(0x0040,0x000E);
2562   Bit16u iobase1, iobase2, blksize;
2563   Bit8u  channel, slave;
2564   Bit8u  status, current, mode;
2565
2566   channel = device / 2;
2567   slave   = device % 2;
2568
2569   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2570   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2571   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2572   blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2573   if (mode == ATA_MODE_PIO32) blksize>>=2;
2574   else blksize>>=1;
2575
2576   // sector will be 0 only on lba access. Convert to lba-chs
2577   if (sector == 0) {
2578     sector = (Bit16u) (lba & 0x000000ffL);
2579     lba >>= 8;
2580     cylinder = (Bit16u) (lba & 0x0000ffffL);
2581     lba >>= 16;
2582     head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2583     }
2584
2585   // Reset count of transferred data
2586   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2587   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2588   current = 0;
2589
2590   status = inb(iobase1 + ATA_CB_STAT);
2591   if (status & ATA_CB_STAT_BSY) return 1;
2592
2593   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2594   outb(iobase1 + ATA_CB_FR, 0x00);
2595   outb(iobase1 + ATA_CB_SC, count);
2596   outb(iobase1 + ATA_CB_SN, sector);
2597   outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2598   outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2599   outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2600   outb(iobase1 + ATA_CB_CMD, command);
2601
2602   while (1) {
2603     status = inb(iobase1 + ATA_CB_STAT);
2604     if ( !(status & ATA_CB_STAT_BSY) ) break;
2605     }
2606
2607   if (status & ATA_CB_STAT_ERR) {
2608     BX_DEBUG_ATA("ata_cmd_data_in : read error\n");
2609     return 2;
2610     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2611     BX_DEBUG_ATA("ata_cmd_data_in : DRQ not set (status %02x)\n", (unsigned) status);
2612     return 3;
2613   }
2614
2615   // FIXME : move seg/off translation here
2616
2617 ASM_START
2618         sti  ;; enable higher priority interrupts
2619 ASM_END
2620
2621   while (1) {
2622
2623 ASM_START
2624         push bp
2625         mov  bp, sp
2626         mov  di, _ata_cmd_data_in.offset + 2[bp]  
2627         mov  ax, _ata_cmd_data_in.segment + 2[bp] 
2628         mov  cx, _ata_cmd_data_in.blksize + 2[bp] 
2629
2630         ;; adjust if there will be an overrun. 2K max sector size
2631         cmp   di, #0xf800 ;; 
2632         jbe   ata_in_no_adjust
2633
2634 ata_in_adjust:
2635         sub   di, #0x0800 ;; sub 2 kbytes from offset
2636         add   ax, #0x0080 ;; add 2 Kbytes to segment
2637
2638 ata_in_no_adjust:
2639         mov   es, ax      ;; segment in es
2640
2641         mov   dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port
2642
2643         mov  ah, _ata_cmd_data_in.mode + 2[bp] 
2644         cmp  ah, #ATA_MODE_PIO32
2645         je   ata_in_32
2646
2647 ata_in_16:
2648         rep
2649           insw ;; CX words transfered from port(DX) to ES:[DI]
2650         jmp ata_in_done
2651
2652 ata_in_32:
2653         rep
2654           insd ;; CX dwords transfered from port(DX) to ES:[DI]
2655
2656 ata_in_done:
2657         mov  _ata_cmd_data_in.offset + 2[bp], di
2658         mov  _ata_cmd_data_in.segment + 2[bp], es
2659         pop  bp
2660 ASM_END
2661
2662     current++;
2663     write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2664     count--;
2665     status = inb(iobase1 + ATA_CB_STAT);
2666     if (count == 0) {
2667       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
2668           != ATA_CB_STAT_RDY ) {
2669         BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status);
2670         return 4;
2671         }
2672       break;
2673       }
2674     else {
2675       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
2676           != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2677         BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status);
2678         return 5;
2679       }
2680       continue;
2681     }
2682   }
2683   // Enable interrupts
2684   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2685   return 0;
2686 }
2687
2688 // ---------------------------------------------------------------------------
2689 // ATA/ATAPI driver : execute a data-out command
2690 // ---------------------------------------------------------------------------
2691       // returns
2692       // 0 : no error
2693       // 1 : BUSY bit set
2694       // 2 : read error
2695       // 3 : expected DRQ=1
2696       // 4 : no sectors left to read/verify
2697       // 5 : more sectors to read/verify
2698       // 6 : no sectors left to write
2699       // 7 : more sectors to write
2700 Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset)
2701 Bit16u device, command, count, cylinder, head, sector, segment, offset;
2702 Bit32u lba;
2703 {
2704   Bit16u ebda_seg=read_word(0x0040,0x000E);
2705   Bit16u iobase1, iobase2, blksize;
2706   Bit8u  channel, slave;
2707   Bit8u  status, current, mode;
2708
2709   channel = device / 2;
2710   slave   = device % 2;
2711
2712   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2713   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2714   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2715   blksize = 0x200; // was = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
2716   if (mode == ATA_MODE_PIO32) blksize>>=2;
2717   else blksize>>=1;
2718
2719   // sector will be 0 only on lba access. Convert to lba-chs
2720   if (sector == 0) {
2721     sector = (Bit16u) (lba & 0x000000ffL);
2722     lba >>= 8;
2723     cylinder = (Bit16u) (lba & 0x0000ffffL);
2724     lba >>= 16;
2725     head = ((Bit16u) (lba & 0x0000000fL)) | 0x40;
2726     }
2727
2728   // Reset count of transferred data
2729   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2730   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2731   current = 0;
2732
2733   status = inb(iobase1 + ATA_CB_STAT);
2734   if (status & ATA_CB_STAT_BSY) return 1;
2735
2736   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2737   outb(iobase1 + ATA_CB_FR, 0x00);
2738   outb(iobase1 + ATA_CB_SC, count);
2739   outb(iobase1 + ATA_CB_SN, sector);
2740   outb(iobase1 + ATA_CB_CL, cylinder & 0x00ff);
2741   outb(iobase1 + ATA_CB_CH, cylinder >> 8);
2742   outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head );
2743   outb(iobase1 + ATA_CB_CMD, command);
2744
2745   while (1) {
2746     status = inb(iobase1 + ATA_CB_STAT);
2747     if ( !(status & ATA_CB_STAT_BSY) ) break;
2748     }
2749
2750   if (status & ATA_CB_STAT_ERR) {
2751     BX_DEBUG_ATA("ata_cmd_data_out : read error\n");
2752     return 2;
2753     } else if ( !(status & ATA_CB_STAT_DRQ) ) {
2754     BX_DEBUG_ATA("ata_cmd_data_out : DRQ not set (status %02x)\n", (unsigned) status);
2755     return 3;
2756     }
2757
2758   // FIXME : move seg/off translation here
2759
2760 ASM_START
2761         sti  ;; enable higher priority interrupts
2762 ASM_END
2763
2764   while (1) {
2765
2766 ASM_START
2767         push bp
2768         mov  bp, sp
2769         mov  si, _ata_cmd_data_out.offset + 2[bp]  
2770         mov  ax, _ata_cmd_data_out.segment + 2[bp] 
2771         mov  cx, _ata_cmd_data_out.blksize + 2[bp] 
2772
2773         ;; adjust if there will be an overrun. 2K max sector size
2774         cmp   si, #0xf800 ;; 
2775         jbe   ata_out_no_adjust
2776
2777 ata_out_adjust:
2778         sub   si, #0x0800 ;; sub 2 kbytes from offset
2779         add   ax, #0x0080 ;; add 2 Kbytes to segment
2780
2781 ata_out_no_adjust:
2782         mov   es, ax      ;; segment in es
2783
2784         mov   dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port
2785
2786         mov  ah, _ata_cmd_data_out.mode + 2[bp] 
2787         cmp  ah, #ATA_MODE_PIO32
2788         je   ata_out_32
2789
2790 ata_out_16:
2791         seg ES
2792         rep
2793           outsw ;; CX words transfered from port(DX) to ES:[SI]
2794         jmp ata_out_done
2795
2796 ata_out_32:
2797         seg ES
2798         rep
2799           outsd ;; CX dwords transfered from port(DX) to ES:[SI]
2800
2801 ata_out_done:
2802         mov  _ata_cmd_data_out.offset + 2[bp], si
2803         mov  _ata_cmd_data_out.segment + 2[bp], es
2804         pop  bp
2805 ASM_END
2806
2807     current++;
2808     write_word(ebda_seg, &EbdaData->ata.trsfsectors,current);
2809     count--;
2810     status = inb(iobase1 + ATA_CB_STAT);
2811     if (count == 0) {
2812       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
2813           != ATA_CB_STAT_RDY ) {
2814         BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status);
2815         return 6;
2816         }
2817       break;
2818       }
2819     else {
2820       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
2821           != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
2822         BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status);
2823         return 7;
2824       }
2825       continue;
2826     }
2827   }
2828   // Enable interrupts
2829   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
2830   return 0;
2831 }
2832
2833 // ---------------------------------------------------------------------------
2834 // ATA/ATAPI driver : execute a packet command
2835 // ---------------------------------------------------------------------------
2836       // returns
2837       // 0 : no error
2838       // 1 : error in parameters
2839       // 2 : BUSY bit set
2840       // 3 : error
2841       // 4 : not ready
2842 Bit16u ata_cmd_packet(device, cmdlen, cmdseg, cmdoff, header, length, inout, bufseg, bufoff)
2843 Bit8u  cmdlen,inout;
2844 Bit16u device,cmdseg, cmdoff, bufseg, bufoff;
2845 Bit16u header;
2846 Bit32u length;
2847 {
2848   Bit16u ebda_seg=read_word(0x0040,0x000E);
2849   Bit16u iobase1, iobase2;
2850   Bit16u lcount, lbefore, lafter, count;
2851   Bit8u  channel, slave;
2852   Bit8u  status, error, mode, lmode;
2853   Bit32u total, transfer;
2854
2855   channel = device / 2;
2856   slave = device % 2;
2857
2858   // Data out is not supported yet
2859   if (inout == ATA_DATA_OUT) {
2860     BX_INFO("ata_cmd_packet: DATA_OUT not supported yet\n");
2861     return 1;
2862     }
2863
2864   // The header length must be even
2865   if (header & 1) {
2866     BX_DEBUG_ATA("ata_cmd_packet : header must be even (%04x)\n",header);
2867     return 1;
2868     }
2869
2870   iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
2871   iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
2872   mode    = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
2873   transfer= 0L;
2874
2875   if (cmdlen < 12) cmdlen=12;
2876   if (cmdlen > 12) cmdlen=16;
2877   cmdlen>>=1;
2878
2879   // Reset count of transferred data
2880   write_word(ebda_seg, &EbdaData->ata.trsfsectors,0);
2881   write_dword(ebda_seg, &EbdaData->ata.trsfbytes,0L);
2882
2883 #define STATUS_WAIT_FOR(x) do { status=inb(iobase1+ATA_CB_STAT); } while (!(x)) 
2884 #define ALT_STATUS_WAIT_FOR(x) do { status=inb(iobase2+ATA_CB_ASTAT); } while (!(x)) 
2885 #define ERROR_UPDATE() do { error=inb(iobase1+ATA_CB_ERR); } while (0)
2886 #define STATUS_UPDATE() do { status=inb(iobase1+ATA_CB_STAT); } while (0)
2887 #define ALT_STATUS_UPDATE() do { status=inb(iobase1+ATA_CB_STAT); } while (0)
2888 #define WAIT_FOR_NOT_BUSY() STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0)
2889 #define WAIT_FOR_DATA_REQUEST() STATUS_WAIT_FOR((status&ATA_CB_STAT_DRQ))
2890 #define WAIT_FOR_DRIVE_READY() STATUS_WAIT_FOR((status&ATA_CB_STAT_RDY))
2891 #define WAIT_FOR_NOT_BUSY_AND_DRIVE_READY() STATUS_WAIT_FOR(((status&ATA_CB_STAT_BSY)==0)&&((status&ATA_CB_STAT_RDY)))
2892 #define WAIT_FOR_NOT_BUSY_AND_DATA_REQUEST() STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0)&&((status&ATA_CB_STAT_DRQ)))
2893
2894
2895
2896 retry_on_media_change:
2897
2898   WAIT_FOR_NOT_BUSY();
2899
2900   //BX_DEBUG_ATA("ata_cmd_packet: not busy done\n");
2901
2902   // We have already selected the appropriate controller (iobase1,2)
2903   // select master or slave
2904   outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0);
2905
2906   STATUS_UPDATE();
2907
2908   //BX_DEBUG_ATA("ata_cmd_packet: drive selected (%d) status=0x%x\n", slave,(unsigned)status);
2909
2910
2911   // Technically, we should be calling this here
2912   // but QEMU's device model appears to be broken and RDY never is assserted
2913   // on a drive change
2914   // WAIT_FOR_NOT_BUSY_AND_DRIVE_READY();
2915   WAIT_FOR_NOT_BUSY();
2916    
2917   //BX_DEBUG_ATA("ata_cmd_packet: not busy\n");
2918
2919   // set "noninterruptable"
2920   outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN);
2921   // no DMA
2922   outb(iobase1 + ATA_CB_FR, 0x00);
2923   // This conveys the maximum bytecount.  count&0xff in low, count>>8 in high
2924   // it is not actually doing anything with cylinders
2925   outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff);
2926   outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8);
2927   // Not sure about these 
2928   outb(iobase1 + ATA_CB_SC, 0x00);
2929   outb(iobase1 + ATA_CB_SN, 0x00);
2930
2931   //BX_DEBUG_ATA("ata_cmd_packet: configuration done\n");
2932
2933   // Issue command for packet 
2934   outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET);
2935
2936   //BX_DEBUG_ATA("ata_cmd_packet: A0 issued to drive\n");
2937  
2938   ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
2939
2940   //BX_DEBUG_ATA("ata_cmd_packet: alt status shows not busy\n");
2941
2942   STATUS_UPDATE();
2943
2944   //BX_DEBUG_ATA("ata_cmd_packet: main status shows 0x%x\n",(unsigned)status);
2945
2946   WAIT_FOR_DATA_REQUEST();
2947
2948   //BX_DEBUG_ATA("ata_cmd_packet: data request is set\n");
2949
2950   // Normalize address
2951   cmdseg += (cmdoff / 16);
2952   cmdoff %= 16;
2953
2954   // Send command to device
2955 ASM_START
2956       sti  ;; enable higher priority interrupts
2957  
2958       push bp
2959       mov  bp, sp
2960     
2961       mov  si, _ata_cmd_packet.cmdoff + 2[bp]  
2962       mov  ax, _ata_cmd_packet.cmdseg + 2[bp] 
2963       mov  cx, _ata_cmd_packet.cmdlen + 2[bp] 
2964       mov  es, ax      ;; segment in es
2965
2966       mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port
2967
2968       seg ES
2969       rep
2970         outsw ;; CX words transfered from port(DX) to ES:[SI]
2971
2972       pop  bp
2973 ASM_END
2974
2975
2976   ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
2977
2978   STATUS_UPDATE();
2979   ERROR_UPDATE();
2980
2981   BX_DEBUG_ATA("ata_cmd_packet: after packet: 0x%x error 0x%x\n",(unsigned)status,(unsigned)error);
2982
2983   if (status&ATA_CB_STAT_ERR && error&ATA_CB_ER_MC) {
2984      BX_DEBUG_ATA("ata_cmd_packet: caught unexpected media change.  Retrying\n");       
2985      goto retry_on_media_change;
2986   }
2987         
2988
2989
2990   if (inout == ATA_DATA_NO) {
2991         STATUS_UPDATE();
2992     }
2993   else {
2994     
2995     while (1) {
2996     
2997       // This while loop is quite bizarre
2998       // Under both success and failure, you'll go through it once
2999       // and then just a wee bit the second time - PAD
3000
3001       
3002       ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3003       
3004       STATUS_UPDATE();
3005       ERROR_UPDATE();
3006  
3007       BX_DEBUG_ATA("ata_cmd_packet/dataxferloop: status=0x%x, error=0x%x\n",(unsigned)status,(unsigned)error);
3008
3009
3010
3011 #if 0
3012 //
3013 // According to specatapi, the following is how you're supposed
3014 // To tell when there is no more data for you
3015 // But it doesn't work on at least some hardware - PAD
3016       if ((status&ATA_CB_STAT_BSY) && !(status&ATA_CB_STAT_DRQ)) { 
3017          // done with data tranfer
3018          // we wait for it to flip
3019          ALT_STATUS_WAIT_FOR((status&ATA_CB_STAT_BSY)==0);
3020          // then read one more time
3021          STATUS_UPDATE();
3022          // then we are done
3023          break;
3024        }
3025
3026 #else
3027
3028       // Check if command completed
3029       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break;
3030
3031 #endif      
3032       if (status & ATA_CB_STAT_ERR) {
3033         BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status);
3034         return 3;
3035       }
3036       
3037       // If we get here, we are ready and should have DRQ
3038       // and so data is available
3039       // Device must be ready to send data
3040       if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
3041            != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) {
3042         BX_DEBUG_ATA("ata_cmd_packet 1: not ready (status %02x)\n", status);
3043         return 4;
3044       }
3045       
3046       // Normalize address
3047       bufseg += (bufoff / 16);
3048       bufoff %= 16;
3049       
3050       // Get the byte count
3051       lcount =  ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL);
3052       
3053       // adjust to read what we want
3054       if(header>lcount) {
3055         lbefore=lcount;
3056         header-=lcount;
3057         lcount=0;
3058       }
3059       else {
3060         lbefore=header;
3061         header=0;
3062         lcount-=lbefore;
3063       }
3064       
3065       if(lcount>length) {
3066         lafter=lcount-length;
3067         lcount=length;
3068         length=0;
3069       }
3070       else {
3071         lafter=0;
3072         length-=lcount;
3073       }
3074       
3075       // Save byte count
3076       count = lcount;
3077       
3078       BX_DEBUG_ATA("Trying to read %04x bytes (%04x %04x %04x) ",lbefore+lcount+lafter,lbefore,lcount,lafter);
3079       BX_DEBUG_ATA("to 0x%04x:0x%04x\n",bufseg,bufoff);
3080
3081       // If counts not dividable by 4, use 16bits mode
3082       lmode = mode;
3083       if (lbefore & 0x03) lmode=ATA_MODE_PIO16;
3084       if (lcount  & 0x03) lmode=ATA_MODE_PIO16;
3085       if (lafter  & 0x03) lmode=ATA_MODE_PIO16;
3086
3087       // adds an extra byte if count are odd. before is always even
3088       if (lcount & 0x01) {
3089         lcount+=1;
3090         if ((lafter > 0) && (lafter & 0x01)) {
3091           lafter-=1;
3092           }
3093         }
3094
3095       if (lmode == ATA_MODE_PIO32) {
3096         lcount>>=2; lbefore>>=2; lafter>>=2;
3097         }
3098       else {
3099         lcount>>=1; lbefore>>=1; lafter>>=1;
3100         }
3101
3102        ;  // FIXME bcc bug
3103
3104 ASM_START
3105         push bp
3106         mov  bp, sp
3107
3108         mov  dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port
3109
3110         mov  cx, _ata_cmd_packet.lbefore + 2[bp] 
3111         jcxz ata_packet_no_before
3112
3113         mov  ah, _ata_cmd_packet.lmode + 2[bp] 
3114         cmp  ah, #ATA_MODE_PIO32
3115         je   ata_packet_in_before_32
3116
3117 ata_packet_in_before_16:
3118         in   ax, dx
3119         loop ata_packet_in_before_16
3120         jmp  ata_packet_no_before
3121
3122 ata_packet_in_before_32:
3123         push eax
3124 ata_packet_in_before_32_loop:
3125         in   eax, dx
3126         loop ata_packet_in_before_32_loop
3127         pop  eax
3128
3129 ata_packet_no_before:
3130         mov  cx, _ata_cmd_packet.lcount + 2[bp] 
3131         jcxz ata_packet_after
3132
3133         mov  di, _ata_cmd_packet.bufoff + 2[bp]  
3134         mov  ax, _ata_cmd_packet.bufseg + 2[bp] 
3135         mov  es, ax
3136
3137         mov  ah, _ata_cmd_packet.lmode + 2[bp] 
3138         cmp  ah, #ATA_MODE_PIO32
3139         je   ata_packet_in_32
3140
3141 ata_packet_in_16:
3142         rep
3143           insw ;; CX words transfered tp port(DX) to ES:[DI]
3144         jmp ata_packet_after
3145
3146 ata_packet_in_32:
3147         rep
3148           insd ;; CX dwords transfered to port(DX) to ES:[DI]
3149
3150 ata_packet_after:
3151         mov  cx, _ata_cmd_packet.lafter + 2[bp] 
3152         jcxz ata_packet_done
3153
3154         mov  ah, _ata_cmd_packet.lmode + 2[bp] 
3155         cmp  ah, #ATA_MODE_PIO32
3156         je   ata_packet_in_after_32
3157
3158 ata_packet_in_after_16:
3159         in   ax, dx
3160         loop ata_packet_in_after_16
3161         jmp  ata_packet_done
3162
3163 ata_packet_in_after_32:
3164         push eax
3165 ata_packet_in_after_32_loop:
3166         in   eax, dx
3167         loop ata_packet_in_after_32_loop
3168         pop  eax
3169
3170 ata_packet_done:
3171         pop  bp
3172 ASM_END
3173
3174       // Compute new buffer address
3175       bufoff += count;
3176
3177       // Save transferred bytes count
3178       transfer += count;
3179       write_dword(ebda_seg, &EbdaData->ata.trsfbytes,transfer);
3180       }
3181     }
3182
3183   // Final check, device must be ready
3184   if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) 
3185          != ATA_CB_STAT_RDY ) {
3186     BX_DEBUG_ATA("ata_cmd_packet 2 : not ready (status %02x)\n", (unsigned) status);
3187         return 4;
3188     }
3189
3190   // Enable interrupts
3191   outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15);
3192   return 0;
3193
3194 }
3195
3196 // ---------------------------------------------------------------------------
3197 // End of ATA/ATAPI Driver
3198 // ---------------------------------------------------------------------------
3199
3200
3201 // ---------------------------------------------------------------------------
3202 // Start of ATA/ATAPI generic functions
3203 // ---------------------------------------------------------------------------
3204
3205   Bit16u 
3206 atapi_get_sense(device)
3207   Bit16u device;
3208 {
3209   Bit8u  atacmd[12];
3210   Bit8u  buffer[16];
3211   Bit8u i;
3212
3213   memsetb(get_SS(),atacmd,0,12);
3214
3215   // Request SENSE 
3216   atacmd[0]=0x03;    
3217   atacmd[4]=0x20;    
3218   if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0)
3219     return 0x0002;
3220
3221   if ((buffer[0] & 0x7e) == 0x70) {
3222     return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12];
3223     }
3224
3225   return 0;
3226 }
3227
3228   Bit16u 
3229 atapi_is_ready(device)
3230   Bit16u device;
3231 {
3232   Bit8u  atacmd[12];
3233   Bit8u  buffer[];
3234
3235   memsetb(get_SS(),atacmd,0,12);
3236  
3237   // Test Unit Ready
3238   if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3239     return 0x000f;
3240
3241   if (atapi_get_sense(device) !=0 ) {
3242     memsetb(get_SS(),atacmd,0,12);
3243
3244     // try to send Test Unit Ready again
3245     if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0)
3246       return 0x000f;
3247
3248     return atapi_get_sense(device);
3249     }
3250   return 0;
3251 }
3252
3253   Bit16u 
3254 atapi_is_cdrom(device)
3255   Bit8u device;
3256 {
3257   Bit16u ebda_seg=read_word(0x0040,0x000E);
3258
3259   if (device >= BX_MAX_ATA_DEVICES)
3260     return 0;
3261
3262   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI)
3263     return 0;
3264
3265   if (read_byte(ebda_seg,&EbdaData->ata.devices[device].device) != ATA_DEVICE_CDROM)
3266     return 0;
3267
3268   return 1;
3269 }
3270
3271 // ---------------------------------------------------------------------------
3272 // End of ATA/ATAPI generic functions
3273 // ---------------------------------------------------------------------------
3274
3275 #endif // BX_USE_ATADRV
3276
3277 #if BX_ELTORITO_BOOT
3278
3279 // ---------------------------------------------------------------------------
3280 // Start of El-Torito boot functions
3281 // ---------------------------------------------------------------------------
3282
3283   void
3284 cdemu_init()
3285 {
3286   Bit16u ebda_seg=read_word(0x0040,0x000E);
3287
3288   //BX_DEBUG("rombios: cdemu_init\n");
3289
3290   // the only important data is this one for now
3291   write_byte(ebda_seg,&EbdaData->cdemu.active,0x00);
3292 }
3293
3294   Bit8u
3295 cdemu_isactive()
3296 {
3297   Bit16u ebda_seg=read_word(0x0040,0x000E);
3298
3299   return(read_byte(ebda_seg,&EbdaData->cdemu.active));
3300 }
3301
3302   Bit8u
3303 cdemu_emulated_drive()
3304 {
3305   Bit16u ebda_seg=read_word(0x0040,0x000E);
3306
3307   return(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
3308 }
3309
3310 static char isotag[6]="CD001";
3311 static char eltorito[24]="EL TORITO SPECIFICATION";
3312 //
3313 // Returns ah: emulated drive, al: error code
3314 //
3315   Bit16u 
3316 cdrom_boot()
3317 {
3318   Bit16u ebda_seg=read_word(0x0040,0x000E);
3319   Bit8u  atacmd[12], buffer[2048];
3320   Bit32u lba;
3321   Bit16u boot_segment, nbsectors, i, error;
3322   Bit8u  device;
3323
3324
3325   // Find out the first cdrom
3326   for (device=0; device<BX_MAX_ATA_DEVICES;device++) {
3327     if (atapi_is_cdrom(device)) break;
3328     }
3329   
3330   // if not found
3331   if(device >= BX_MAX_ATA_DEVICES) return 2;
3332
3333
3334
3335   // Read the Boot Record Volume Descriptor
3336   memsetb(get_SS(),atacmd,0,12);
3337   atacmd[0]=0x28;                      // READ command
3338   atacmd[1]=0x0 ;                      // reserved - not sure why this wasn't zeroed to begin with -PAD
3339   atacmd[6]=0x0 ;                      // reserved - ... -PAD
3340   atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
3341   atacmd[8]=(0x01 & 0x00ff);           // Sectors
3342   atacmd[2]=(0x11 & 0xff000000) >> 24; // LBA
3343   atacmd[3]=(0x11 & 0x00ff0000) >> 16;
3344   atacmd[4]=(0x11 & 0x0000ff00) >> 8;
3345   atacmd[5]=(0x11 & 0x000000ff);
3346   atacmd[9]=atacmd[10]=atacmd[11]=0x0;  // just to be safe -PAD
3347   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3348     return 3;
3349
3350
3351   // Validity checks
3352   if(buffer[0]!=0)return 4;
3353   for(i=0;i<5;i++){
3354     if(buffer[1+i]!=read_byte(0xf000,&isotag[i]))return 5;
3355    }
3356   for(i=0;i<23;i++)
3357     if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6;
3358   
3359   // ok, now we calculate the Boot catalog address
3360   lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47];
3361
3362   // And we read the Boot Catalog
3363   memsetb(get_SS(),atacmd,0,12);
3364   atacmd[0]=0x28;                      // READ command
3365   atacmd[7]=(0x01 & 0xff00) >> 8;      // Sectors
3366   atacmd[8]=(0x01 & 0x00ff);           // Sectors
3367   atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
3368   atacmd[3]=(lba & 0x00ff0000) >> 16;
3369   atacmd[4]=(lba & 0x0000ff00) >> 8;
3370   atacmd[5]=(lba & 0x000000ff);
3371   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0)
3372     return 7;
3373
3374
3375  
3376   // Validation entry
3377   if(buffer[0x00]!=0x01)return 8;   // Header
3378   if(buffer[0x01]!=0x00)return 9;   // Platform
3379   if(buffer[0x1E]!=0x55)return 10;  // key 1
3380   if(buffer[0x1F]!=0xAA)return 10;  // key 2
3381
3382   // Initial/Default Entry
3383   if(buffer[0x20]!=0x88)return 11; // Bootable
3384
3385   write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]);
3386   if(buffer[0x21]==0){
3387     // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. 
3388     // Win2000 cd boot needs to know it booted from cd
3389     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0);
3390     } 
3391   else if(buffer[0x21]<4)
3392     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00);
3393   else
3394     write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x80);
3395
3396   write_byte(ebda_seg,&EbdaData->cdemu.controller_index,device/2);
3397   write_byte(ebda_seg,&EbdaData->cdemu.device_spec,device%2);
3398
3399   boot_segment=buffer[0x23]*0x100+buffer[0x22];
3400   if(boot_segment==0x0000)boot_segment=0x07C0;
3401
3402   write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment);
3403   write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000);
3404   
3405   nbsectors=buffer[0x27]*0x100+buffer[0x26];
3406   write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors);
3407
3408   lba=buffer[0x2B]*0x1000000+buffer[0x2A]*0x10000+buffer[0x29]*0x100+buffer[0x28];
3409   write_dword(ebda_seg,&EbdaData->cdemu.ilba,lba);
3410
3411   // And we read the image in memory
3412   memsetb(get_SS(),atacmd,0,12);
3413   atacmd[0]=0x28;                      // READ command
3414   atacmd[7]=((1+(nbsectors-1)/4) & 0xff00) >> 8;      // Sectors
3415   atacmd[8]=((1+(nbsectors-1)/4) & 0x00ff);           // Sectors
3416   atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
3417   atacmd[3]=(lba & 0x00ff0000) >> 16;
3418   atacmd[4]=(lba & 0x0000ff00) >> 8;
3419   atacmd[5]=(lba & 0x000000ff);
3420   if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, nbsectors*512L, ATA_DATA_IN, boot_segment,0)) != 0)
3421     return 12;
3422
3423
3424   // Remember the media type
3425   switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
3426     case 0x01:  // 1.2M floppy
3427       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,15);
3428       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3429       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3430       break;
3431     case 0x02:  // 1.44M floppy
3432       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,18);
3433       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3434       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3435       break;
3436     case 0x03:  // 2.88M floppy
3437       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,36);
3438       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,80);
3439       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,2);
3440       break;
3441     case 0x04:  // Harddrive
3442       write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f);
3443       write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders,
3444               (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1);
3445       write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1);
3446       break;
3447    }
3448
3449   if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) {
3450     // Increase bios installed hardware number of devices
3451     if(read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)==0x00)
3452       write_byte(0x40,0x10,read_byte(0x40,0x10)|0x41);
3453     else
3454       write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1);
3455    }
3456
3457   
3458   // everything is ok, so from now on, the emulation is active
3459   if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0)
3460     write_byte(ebda_seg,&EbdaData->cdemu.active,0x01);
3461
3462   // return the boot drive + no error
3463   return (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive)*0x100)+0;
3464 }
3465
3466 // ---------------------------------------------------------------------------
3467 // End of El-Torito boot functions
3468 // ---------------------------------------------------------------------------
3469 #endif // BX_ELTORITO_BOOT
3470
3471   void
3472 int14_function(regs, ds, iret_addr)
3473   pusha_regs_t regs; // regs pushed from PUSHA instruction
3474   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
3475   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
3476 {
3477   Bit16u addr,timer,val16;
3478   Bit8u timeout;
3479
3480   ASM_START
3481   sti
3482   ASM_END
3483
3484   addr = read_word(0x0040, (regs.u.r16.dx << 1));
3485   timeout = read_byte(0x0040, 0x007C + regs.u.r16.dx);
3486   if ((regs.u.r16.dx < 4) && (addr > 0)) {
3487     switch (regs.u.r8.ah) {
3488       case 0:
3489         outb(addr+3, inb(addr+3) | 0x80);
3490         if (regs.u.r8.al & 0xE0 == 0) {
3491           outb(addr, 0x17);
3492           outb(addr+1, 0x04);
3493         } else {
3494           val16 = 0x600 >> ((regs.u.r8.al & 0xE0) >> 5);
3495           outb(addr, val16 & 0xFF);
3496           outb(addr+1, val16 >> 8);
3497         }
3498         outb(addr+3, regs.u.r8.al & 0x1F);
3499         regs.u.r8.ah = inb(addr+5);
3500         regs.u.r8.al = inb(addr+6);
3501         ClearCF(iret_addr.flags);
3502         break;
3503       case 1:
3504         timer = read_word(0x0040, 0x006C);
3505         while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) {
3506           val16 = read_word(0x0040, 0x006C);
3507           if (val16 != timer) {
3508             timer = val16;
3509             timeout--;
3510             }
3511           }
3512         if (timeout) outb(addr, regs.u.r8.al);
3513         regs.u.r8.ah = inb(addr+5);
3514         if (!timeout) regs.u.r8.ah |= 0x80;
3515         ClearCF(iret_addr.flags);
3516         break;
3517       case 2:
3518         timer = read_word(0x0040, 0x006C);
3519         while (((inb(addr+5) & 0x01) == 0) && (timeout)) {
3520           val16 = read_word(0x0040, 0x006C);
3521           if (val16 != timer) {
3522             timer = val16;
3523             timeout--;
3524             }
3525           }
3526         if (timeout) {
3527           regs.u.r8.ah = 0;
3528           regs.u.r8.al = inb(addr);
3529         } else {
3530           regs.u.r8.ah = inb(addr+5);
3531           }
3532         ClearCF(iret_addr.flags);
3533         break;
3534       case 3:
3535         regs.u.r8.ah = inb(addr+5);
3536         regs.u.r8.al = inb(addr+6);
3537         ClearCF(iret_addr.flags);
3538         break;
3539       default:
3540         SetCF(iret_addr.flags); // Unsupported
3541       }
3542   } else {
3543     SetCF(iret_addr.flags); // Unsupported
3544     }
3545 }
3546
3547   void
3548 int15_function(regs, ES, DS, FLAGS)
3549   pusha_regs_t regs; // REGS pushed via pusha
3550   Bit16u ES, DS, FLAGS;
3551 {
3552   Bit16u ebda_seg=read_word(0x0040,0x000E);
3553   bx_bool prev_a20_enable;
3554   Bit16u  base15_00;
3555   Bit8u   base23_16;
3556   Bit16u  ss;
3557   Bit16u  CX,DX;
3558
3559   Bit16u bRegister;
3560   Bit8u irqDisable;
3561
3562 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3563
3564   switch (regs.u.r8.ah) {
3565     case 0x24: /* A20 Control */
3566       switch (regs.u.r8.al) {
3567         case 0x00:
3568           set_enable_a20(0);
3569           CLEAR_CF();
3570           regs.u.r8.ah = 0;
3571           break;
3572         case 0x01:
3573           set_enable_a20(1);
3574           CLEAR_CF();
3575           regs.u.r8.ah = 0;
3576           break;
3577         case 0x02:
3578           regs.u.r8.al = (inb(0x92) >> 1) & 0x01;
3579           CLEAR_CF();
3580           regs.u.r8.ah = 0;
3581           break;
3582         case 0x03:
3583           CLEAR_CF();
3584           regs.u.r8.ah = 0;
3585           regs.u.r16.bx = 3;
3586           break;
3587         default:
3588           BX_INFO("int15: Func 24h, subfunc %02xh, A20 gate control not supported\n", (unsigned) regs.u.r8.al);
3589           SET_CF();
3590           regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3591       }
3592       break;
3593
3594     case 0x41:
3595       SET_CF();
3596       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3597       break;
3598
3599     case 0x4f:
3600       /* keyboard intercept */
3601 #if BX_CPU < 2
3602       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3603 #else
3604       // nop
3605 #endif
3606       SET_CF();
3607       break;
3608
3609     case 0x52:    // removable media eject
3610       CLEAR_CF();
3611       regs.u.r8.ah = 0;  // "ok ejection may proceed"
3612       break;
3613
3614     case 0x83: {
3615       if( regs.u.r8.al == 0 ) {
3616         // Set Interval requested.
3617         if( ( read_byte( 0x40, 0xA0 ) & 1 ) == 0 ) {
3618           // Interval not already set.
3619           write_byte( 0x40, 0xA0, 1 );  // Set status byte.
3620           write_word( 0x40, 0x98, ES ); // Byte location, segment
3621           write_word( 0x40, 0x9A, regs.u.r16.bx ); // Byte location, offset
3622           write_word( 0x40, 0x9C, regs.u.r16.dx ); // Low word, delay
3623           write_word( 0x40, 0x9E, regs.u.r16.cx ); // High word, delay.
3624           CLEAR_CF( );
3625           irqDisable = inb( 0xA1 );
3626           outb( 0xA1, irqDisable & 0xFE );
3627           bRegister = inb_cmos( 0xB );  // Unmask IRQ8 so INT70 will get through.
3628           outb_cmos( 0xB, bRegister | 0x40 ); // Turn on the Periodic Interrupt timer
3629         } else {
3630           // Interval already set.
3631           BX_DEBUG_INT15("int15: Func 83h, failed, already waiting.\n" );
3632           SET_CF();
3633           regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3634         }
3635       } else if( regs.u.r8.al == 1 ) {
3636         // Clear Interval requested
3637         write_byte( 0x40, 0xA0, 0 );  // Clear status byte
3638         CLEAR_CF( );
3639         bRegister = inb_cmos( 0xB );
3640         outb_cmos( 0xB, bRegister & ~0x40 );  // Turn off the Periodic Interrupt timer
3641       } else {
3642         BX_DEBUG_INT15("int15: Func 83h, failed.\n" );
3643         SET_CF();
3644         regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3645         regs.u.r8.al--;
3646       }
3647
3648       break;
3649     }
3650
3651     case 0x87:
3652 #if BX_CPU < 3
3653 #  error "Int15 function 87h not supported on < 80386"
3654 #endif
3655       // +++ should probably have descriptor checks
3656       // +++ should have exception handlers
3657
3658  // turn off interrupts
3659 ASM_START
3660   cli
3661 ASM_END
3662
3663       prev_a20_enable = set_enable_a20(1); // enable A20 line
3664
3665       // 128K max of transfer on 386+ ???
3666       // source == destination ???
3667
3668       // ES:SI points to descriptor table
3669       // offset   use     initially  comments
3670       // ==============================================
3671       // 00..07   Unused  zeros      Null descriptor
3672       // 08..0f   GDT     zeros      filled in by BIOS
3673       // 10..17   source  ssssssss   source of data
3674       // 18..1f   dest    dddddddd   destination of data
3675       // 20..27   CS      zeros      filled in by BIOS
3676       // 28..2f   SS      zeros      filled in by BIOS
3677
3678       //es:si
3679       //eeee0
3680       //0ssss
3681       //-----
3682
3683 // check for access rights of source & dest here
3684
3685       // Initialize GDT descriptor
3686       base15_00 = (ES << 4) + regs.u.r16.si;
3687       base23_16 = ES >> 12;
3688       if (base15_00 < (ES<<4))
3689         base23_16++;
3690       write_word(ES, regs.u.r16.si+0x08+0, 47);       // limit 15:00 = 6 * 8bytes/descriptor
3691       write_word(ES, regs.u.r16.si+0x08+2, base15_00);// base 15:00
3692       write_byte(ES, regs.u.r16.si+0x08+4, base23_16);// base 23:16
3693       write_byte(ES, regs.u.r16.si+0x08+5, 0x93);     // access
3694       write_word(ES, regs.u.r16.si+0x08+6, 0x0000);   // base 31:24/reserved/limit 19:16
3695
3696       // Initialize CS descriptor
3697       write_word(ES, regs.u.r16.si+0x20+0, 0xffff);// limit 15:00 = normal 64K limit
3698       write_word(ES, regs.u.r16.si+0x20+2, 0x0000);// base 15:00
3699       write_byte(ES, regs.u.r16.si+0x20+4, 0x000f);// base 23:16
3700       write_byte(ES, regs.u.r16.si+0x20+5, 0x9b);  // access
3701       write_word(ES, regs.u.r16.si+0x20+6, 0x0000);// base 31:24/reserved/limit 19:16
3702
3703       // Initialize SS descriptor
3704       ss = get_SS();
3705       base15_00 = ss << 4;
3706       base23_16 = ss >> 12;
3707       write_word(ES, regs.u.r16.si+0x28+0, 0xffff);   // limit 15:00 = normal 64K limit
3708       write_word(ES, regs.u.r16.si+0x28+2, base15_00);// base 15:00
3709       write_byte(ES, regs.u.r16.si+0x28+4, base23_16);// base 23:16
3710       write_byte(ES, regs.u.r16.si+0x28+5, 0x93);     // access
3711       write_word(ES, regs.u.r16.si+0x28+6, 0x0000);   // base 31:24/reserved/limit 19:16
3712
3713       CX = regs.u.r16.cx;
3714 ASM_START
3715       // Compile generates locals offset info relative to SP.
3716       // Get CX (word count) from stack.
3717       mov  bx, sp
3718       SEG SS
3719         mov  cx, _int15_function.CX [bx]
3720
3721       // since we need to set SS:SP, save them to the BDA
3722       // for future restore
3723       push eax
3724       xor eax, eax
3725       mov ds, ax
3726       mov 0x0469, ss
3727       mov 0x0467, sp
3728
3729       SEG ES
3730         lgdt [si + 0x08]
3731       SEG CS
3732         lidt [pmode_IDT_info]
3733       ;;  perhaps do something with IDT here
3734
3735       ;; set PE bit in CR0
3736       mov  eax, cr0
3737       or   al, #0x01
3738       mov  cr0, eax
3739       ;; far jump to flush CPU queue after transition to protected mode
3740       JMP_AP(0x0020, protected_mode)
3741
3742 protected_mode:
3743       ;; GDT points to valid descriptor table, now load SS, DS, ES
3744       mov  ax, #0x28 ;; 101 000 = 5th descriptor in table, TI=GDT, RPL=00
3745       mov  ss, ax
3746       mov  ax, #0x10 ;; 010 000 = 2nd descriptor in table, TI=GDT, RPL=00
3747       mov  ds, ax
3748       mov  ax, #0x18 ;; 011 000 = 3rd descriptor in table, TI=GDT, RPL=00
3749       mov  es, ax
3750       xor  si, si
3751       xor  di, di
3752       cld
3753       rep
3754         movsw  ;; move CX words from DS:SI to ES:DI
3755
3756       ;; make sure DS and ES limits are 64KB
3757       mov ax, #0x28
3758       mov ds, ax
3759       mov es, ax
3760
3761       ;; reset PG bit in CR0 ???
3762       mov  eax, cr0
3763       and  al, #0xFE
3764       mov  cr0, eax
3765
3766       ;; far jump to flush CPU queue after transition to real mode
3767       JMP_AP(0xf000, real_mode)
3768
3769 real_mode:
3770       ;; restore IDT to normal real-mode defaults
3771       SEG CS
3772         lidt [rmode_IDT_info]
3773
3774       // restore SS:SP from the BDA
3775       xor ax, ax
3776       mov ds, ax
3777       mov ss, 0x0469
3778       mov sp, 0x0467
3779       pop eax
3780 ASM_END
3781
3782       set_enable_a20(prev_a20_enable);
3783
3784  // turn back on interrupts
3785 ASM_START
3786   sti
3787 ASM_END
3788
3789       regs.u.r8.ah = 0;
3790       CLEAR_CF();
3791       break;
3792
3793
3794     case 0x88:
3795       // Get the amount of extended memory (above 1M)
3796 #if BX_CPU < 2
3797       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3798       SET_CF();
3799 #else
3800       regs.u.r8.al = inb_cmos(0x30);
3801       regs.u.r8.ah = inb_cmos(0x31);
3802
3803       // limit to 15M
3804       if(regs.u.r16.ax > 0x3c00)
3805         regs.u.r16.ax = 0x3c00;
3806
3807       CLEAR_CF();
3808 #endif
3809       break;
3810
3811     case 0x90:
3812       /* Device busy interrupt.  Called by Int 16h when no key available */
3813       break;
3814
3815     case 0x91:
3816       /* Interrupt complete.  Called by Int 16h when key becomes available */
3817       break;
3818
3819     case 0xbf:
3820       BX_INFO("*** int 15h function AH=bf not yet supported!\n");
3821       SET_CF();
3822       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3823       break;
3824
3825     case 0xC0:
3826 #if 0
3827       SET_CF();
3828       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3829       break;
3830 #endif
3831       CLEAR_CF();
3832       regs.u.r8.ah = 0;
3833       regs.u.r16.bx =  BIOS_CONFIG_TABLE;
3834       ES = 0xF000;
3835       break;
3836
3837     case 0xc1:
3838       ES = ebda_seg;
3839       CLEAR_CF();
3840       break;
3841
3842     case 0xd8:
3843       bios_printf(BIOS_PRINTF_DEBUG, "EISA BIOS not present\n");
3844       SET_CF();
3845       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3846       break;
3847
3848     default:
3849       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
3850         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
3851       SET_CF();
3852       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
3853       break;
3854     }
3855 }
3856
3857 #if BX_USE_PS2_MOUSE
3858   void
3859 int15_function_mouse(regs, ES, DS, FLAGS)
3860   pusha_regs_t regs; // REGS pushed via pusha
3861   Bit16u ES, DS, FLAGS;
3862 {
3863   Bit16u ebda_seg=read_word(0x0040,0x000E);
3864   Bit8u  mouse_flags_1, mouse_flags_2;
3865   Bit16u mouse_driver_seg;
3866   Bit16u mouse_driver_offset;
3867   Bit8u  comm_byte, prev_command_byte;
3868   Bit8u  ret, mouse_data1, mouse_data2, mouse_data3;
3869
3870 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
3871
3872   switch (regs.u.r8.ah) {
3873     case 0xC2:
3874       // Return Codes status in AH
3875       // =========================
3876       // 00: success
3877       // 01: invalid subfunction (AL > 7)
3878       // 02: invalid input value (out of allowable range)
3879       // 03: interface error
3880       // 04: resend command received from mouse controller,
3881       //     device driver should attempt command again
3882       // 05: cannot enable mouse, since no far call has been installed
3883       // 80/86: mouse service not implemented
3884
3885       switch (regs.u.r8.al) {
3886         case 0: // Disable/Enable Mouse
3887 BX_DEBUG_INT15("case 0:\n");
3888           switch (regs.u.r8.bh) {
3889             case 0: // Disable Mouse
3890 BX_DEBUG_INT15("case 0: disable mouse\n");
3891               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3892               ret = send_to_mouse_ctrl(0xF5); // disable mouse command
3893               if (ret == 0) {
3894                 ret = get_mouse_data(&mouse_data1);
3895                 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
3896                   CLEAR_CF();
3897                   regs.u.r8.ah = 0;
3898                   return;
3899                   }
3900                 }
3901
3902               // error
3903               SET_CF();
3904               regs.u.r8.ah = ret;
3905               return;
3906               break;
3907
3908             case 1: // Enable Mouse
3909 BX_DEBUG_INT15("case 1: enable mouse\n");
3910               mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3911               if ( (mouse_flags_2 & 0x80) == 0 ) {
3912                 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
3913                 SET_CF();  // error
3914                 regs.u.r8.ah = 5; // no far call installed
3915                 return;
3916                 }
3917               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3918               ret = send_to_mouse_ctrl(0xF4); // enable mouse command
3919               if (ret == 0) {
3920                 ret = get_mouse_data(&mouse_data1);
3921                 if ( (ret == 0) && (mouse_data1 == 0xFA) ) {
3922                   enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
3923                   CLEAR_CF();
3924                   regs.u.r8.ah = 0;
3925                   return;
3926                   }
3927                 }
3928               SET_CF();
3929               regs.u.r8.ah = ret;
3930               return;
3931
3932             default: // invalid subfunction
3933               BX_DEBUG_INT15("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
3934               SET_CF();  // error
3935               regs.u.r8.ah = 1; // invalid subfunction
3936               return;
3937             }
3938           break;
3939
3940         case 1: // Reset Mouse
3941         case 5: // Initialize Mouse
3942 BX_DEBUG_INT15("case 1 or 5:\n");
3943           if (regs.u.r8.al == 5) {
3944             if (regs.u.r8.bh != 3) {
3945               SET_CF();
3946               regs.u.r8.ah = 0x02; // invalid input
3947               return;
3948             }
3949             mouse_flags_2 = read_byte(ebda_seg, 0x0027);
3950             mouse_flags_2 = (mouse_flags_2 & 0x00) | regs.u.r8.bh;
3951             mouse_flags_1 = 0x00;
3952             write_byte(ebda_seg, 0x0026, mouse_flags_1);
3953             write_byte(ebda_seg, 0x0027, mouse_flags_2);
3954           }
3955
3956           inhibit_mouse_int_and_events(); // disable IRQ12 and packets
3957           ret = send_to_mouse_ctrl(0xFF); // reset mouse command
3958           if (ret == 0) {
3959             ret = get_mouse_data(&mouse_data3);
3960             // if no mouse attached, it will return RESEND
3961             if (mouse_data3 == 0xfe) {
3962               SET_CF();
3963               return;
3964             }
3965             if (mouse_data3 != 0xfa)
3966               BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
3967             if ( ret == 0 ) {
3968               ret = get_mouse_data(&mouse_data1);
3969               if ( ret == 0 ) {
3970                 ret = get_mouse_data(&mouse_data2);
3971                 if ( ret == 0 ) {
3972                   // turn IRQ12 and packet generation on
3973                   enable_mouse_int_and_events();
3974                   CLEAR_CF();
3975                   regs.u.r8.ah = 0;
3976                   regs.u.r8.bl = mouse_data1;
3977                   regs.u.r8.bh = mouse_data2;
3978                   return;
3979                   }
3980                 }
3981               }
3982             }
3983
3984           // error
3985           SET_CF();
3986           regs.u.r8.ah = ret;
3987           return;
3988
3989         case 2: // Set Sample Rate
3990 BX_DEBUG_INT15("case 2:\n");
3991           switch (regs.u.r8.bh) {
3992             case 0: mouse_data1 = 10; break; //  10 reports/sec
3993             case 1: mouse_data1 = 20; break; //  20 reports/sec
3994             case 2: mouse_data1 = 40; break; //  40 reports/sec
3995             case 3: mouse_data1 = 60; break; //  60 reports/sec
3996             case 4: mouse_data1 = 80; break; //  80 reports/sec
3997             case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
3998             case 6: mouse_data1 = 200; break; // 200 reports/sec
3999             default: mouse_data1 = 0;
4000           }
4001           if (mouse_data1 > 0) {
4002             ret = send_to_mouse_ctrl(0xF3); // set sample rate command
4003             if (ret == 0) {
4004               ret = get_mouse_data(&mouse_data2);
4005               ret = send_to_mouse_ctrl(mouse_data1);
4006               ret = get_mouse_data(&mouse_data2);
4007               CLEAR_CF();
4008               regs.u.r8.ah = 0;
4009             } else {
4010               // error
4011               SET_CF();
4012               regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4013             }
4014           } else {
4015             // error
4016             SET_CF();
4017             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4018           }
4019           break;
4020
4021         case 3: // Set Resolution
4022 BX_DEBUG_INT15("case 3:\n");
4023           // BX:
4024           //      0 =  25 dpi, 1 count  per millimeter
4025           //      1 =  50 dpi, 2 counts per millimeter
4026           //      2 = 100 dpi, 4 counts per millimeter
4027           //      3 = 200 dpi, 8 counts per millimeter
4028           CLEAR_CF();
4029           regs.u.r8.ah = 0;
4030           break;
4031
4032         case 4: // Get Device ID
4033 BX_DEBUG_INT15("case 4:\n");
4034           inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4035           ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
4036           if (ret == 0) {
4037             ret = get_mouse_data(&mouse_data1);
4038             ret = get_mouse_data(&mouse_data2);
4039             CLEAR_CF();
4040             regs.u.r8.ah = 0;
4041             regs.u.r8.bh = mouse_data2;
4042           } else {
4043             // error
4044             SET_CF();
4045             regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4046           }
4047           break;
4048
4049         case 6: // Return Status & Set Scaling Factor...
4050 BX_DEBUG_INT15("case 6:\n");
4051           switch (regs.u.r8.bh) {
4052             case 0: // Return Status
4053               comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4054               ret = send_to_mouse_ctrl(0xE9); // get mouse info command
4055               if (ret == 0) {
4056                 ret = get_mouse_data(&mouse_data1);
4057                 if (mouse_data1 != 0xfa)
4058                   BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
4059                 if (ret == 0) {
4060                   ret = get_mouse_data(&mouse_data1);
4061                   if ( ret == 0 ) {
4062                     ret = get_mouse_data(&mouse_data2);
4063                     if ( ret == 0 ) {
4064                       ret = get_mouse_data(&mouse_data3);
4065                       if ( ret == 0 ) {
4066                         CLEAR_CF();
4067                         regs.u.r8.ah = 0;
4068                         regs.u.r8.bl = mouse_data1;
4069                         regs.u.r8.cl = mouse_data2;
4070                         regs.u.r8.dl = mouse_data3;
4071                         set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4072                         return;
4073                         }
4074                       }
4075                     }
4076                   }
4077                 }
4078
4079               // error
4080               SET_CF();
4081               regs.u.r8.ah = ret;
4082               set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4083               return;
4084
4085             case 1: // Set Scaling Factor to 1:1
4086             case 2: // Set Scaling Factor to 2:1
4087               comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4088               if (regs.u.r8.bh == 1) {
4089                 ret = send_to_mouse_ctrl(0xE6);
4090               } else {
4091                 ret = send_to_mouse_ctrl(0xE7);
4092               }
4093               if (ret == 0) {
4094                 get_mouse_data(&mouse_data1);
4095                 ret = (mouse_data1 != 0xFA);
4096               }
4097               if (ret == 0) {
4098                 CLEAR_CF();
4099                 regs.u.r8.ah = 0;
4100               } else {
4101                 // error
4102                 SET_CF();
4103                 regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4104               }
4105               set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
4106               break;
4107
4108             default:
4109               BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
4110             }
4111           break;
4112
4113         case 7: // Set Mouse Handler Address
4114 BX_DEBUG_INT15("case 7:\n");
4115           mouse_driver_seg = ES;
4116           mouse_driver_offset = regs.u.r16.bx;
4117           write_word(ebda_seg, 0x0022, mouse_driver_offset);
4118           write_word(ebda_seg, 0x0024, mouse_driver_seg);
4119           mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4120           if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
4121             /* remove handler */
4122             if ( (mouse_flags_2 & 0x80) != 0 ) {
4123               mouse_flags_2 &= ~0x80;
4124               inhibit_mouse_int_and_events(); // disable IRQ12 and packets
4125               }
4126             }
4127           else {
4128             /* install handler */
4129             mouse_flags_2 |= 0x80;
4130             }
4131           write_byte(ebda_seg, 0x0027, mouse_flags_2);
4132           CLEAR_CF();
4133           regs.u.r8.ah = 0;
4134           break;
4135
4136         default:
4137 BX_DEBUG_INT15("case default:\n");
4138           regs.u.r8.ah = 1; // invalid function
4139           SET_CF();
4140         }
4141       break;
4142
4143     default:
4144       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4145         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4146       SET_CF();
4147       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4148       break;
4149     }
4150 }
4151 #endif
4152
4153   void
4154 int15_function32(regs, ES, DS, FLAGS)
4155   pushad_regs_t regs; // REGS pushed via pushad
4156   Bit16u ES, DS, FLAGS;
4157 {
4158   Bit32u  extended_memory_size=0; // 64bits long
4159   Bit16u  CX,DX;
4160
4161 BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
4162
4163   switch (regs.u.r8.ah) {
4164     case 0x86:
4165       // Wait for CX:DX microseconds. currently using the 
4166       // refresh request port 0x61 bit4, toggling every 15usec 
4167
4168       CX = regs.u.r16.cx;
4169       DX = regs.u.r16.dx;
4170
4171 ASM_START
4172       sti
4173
4174       ;; Get the count in eax
4175       mov  bx, sp
4176       SEG SS
4177         mov  ax, _int15_function.CX [bx]
4178       shl  eax, #16
4179       SEG SS
4180         mov  ax, _int15_function.DX [bx]
4181
4182       ;; convert to numbers of 15usec ticks
4183       mov ebx, #15
4184       xor edx, edx
4185       div eax, ebx
4186       mov ecx, eax
4187
4188       ;; wait for ecx number of refresh requests
4189       in al, #0x61
4190       and al,#0x10
4191       mov ah, al
4192
4193       or ecx, ecx
4194       je int1586_tick_end
4195 int1586_tick:
4196       in al, #0x61
4197       and al,#0x10
4198       cmp al, ah
4199       je  int1586_tick
4200       mov ah, al
4201       dec ecx
4202       jnz int1586_tick
4203 int1586_tick_end:
4204 ASM_END
4205
4206       break;
4207
4208     case 0xe8:
4209         switch(regs.u.r8.al)
4210         {
4211          case 0x20: // coded by osmaker aka K.J.
4212             if(regs.u.r32.edx == 0x534D4150) /* SMAP */
4213             {
4214 #if defined(HVMASSIST) && 0
4215                 if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
4216
4217                     Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
4218
4219                     BX_DEBUG_INT15("OK bx=%x\n",regs.u.r16.bx);
4220
4221                     if (regs.u.r16.bx + 0x14 <= e820_table_size) {
4222                         memcpyb(ES, regs.u.r16.di,
4223                                 0xe000, 0x10 + regs.u.r16.bx, 0x14);
4224                     }
4225                     regs.u.r32.ebx += 0x14;
4226                     if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
4227                         regs.u.r32.ebx = 0;
4228                     regs.u.r32.eax = 0x534D4150;
4229                     regs.u.r32.ecx = 0x14;
4230                     CLEAR_CF();
4231                     return;
4232                 } else if (regs.u.r16.bx == 1) {
4233                     extended_memory_size = inb_cmos(0x35);
4234                     extended_memory_size <<= 8;
4235                     extended_memory_size |= inb_cmos(0x34);
4236                     extended_memory_size *= 64;
4237                     if (extended_memory_size > 0x3bc000) // greater than EFF00000???
4238                     {
4239                         extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4240                     }
4241                     extended_memory_size *= 1024;
4242                     extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4243
4244                     if (extended_memory_size <= 15728640)
4245                     {
4246                         extended_memory_size = inb_cmos(0x31);
4247                         extended_memory_size <<= 8;
4248                         extended_memory_size |= inb_cmos(0x30);
4249                         extended_memory_size *= 1024;
4250                     }
4251
4252                     write_word(ES, regs.u.r16.di, 0x0000);
4253                     write_word(ES, regs.u.r16.di+2, 0x0010);
4254                     write_word(ES, regs.u.r16.di+4, 0x0000);
4255                     write_word(ES, regs.u.r16.di+6, 0x0000);
4256
4257                     write_word(ES, regs.u.r16.di+8, extended_memory_size);
4258                     extended_memory_size >>= 16;
4259                     write_word(ES, regs.u.r16.di+10, extended_memory_size);
4260                     extended_memory_size >>= 16;
4261                     write_word(ES, regs.u.r16.di+12, extended_memory_size);
4262                     extended_memory_size >>= 16;
4263                     write_word(ES, regs.u.r16.di+14, extended_memory_size);
4264
4265                     write_word(ES, regs.u.r16.di+16, 0x1);
4266                     write_word(ES, regs.u.r16.di+18, 0x0);
4267
4268                     regs.u.r32.ebx = 0;
4269                     regs.u.r32.eax = 0x534D4150;
4270                     regs.u.r32.ecx = 0x14;
4271                     CLEAR_CF();
4272                     return;
4273                 } else { /* AX=E820, DX=534D4150, BX unrecognized */
4274                     goto int15_unimplemented;
4275                 }
4276 #else
4277                 switch(regs.u.r16.bx)
4278                 {
4279                     case 0:
4280                         write_word(ES, regs.u.r16.di, 0x00);
4281                         write_word(ES, regs.u.r16.di+2, 0x00);
4282                         write_word(ES, regs.u.r16.di+4, 0x00);
4283                         write_word(ES, regs.u.r16.di+6, 0x00);
4284
4285                         write_word(ES, regs.u.r16.di+8, 0xFC00);
4286                         write_word(ES, regs.u.r16.di+10, 0x0009);
4287                         write_word(ES, regs.u.r16.di+12, 0x0000);
4288                         write_word(ES, regs.u.r16.di+14, 0x0000);
4289
4290                         write_word(ES, regs.u.r16.di+16, 0x1);
4291                         write_word(ES, regs.u.r16.di+18, 0x0);
4292
4293                         regs.u.r32.ebx = 1;
4294
4295                         regs.u.r32.eax = 0x534D4150;
4296                         regs.u.r32.ecx = 0x14;
4297                         CLEAR_CF();
4298                         return;
4299                         break;
4300                     case 1:
4301                         extended_memory_size = inb_cmos(0x35);
4302                         extended_memory_size <<= 8;
4303                         extended_memory_size |= inb_cmos(0x34);
4304                         extended_memory_size *= 64;
4305                         if(extended_memory_size > 0x3bc000) // greater than EFF00000???
4306                         {
4307                             extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
4308                         }
4309                         extended_memory_size *= 1024;
4310                         extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
4311
4312                         if(extended_memory_size <= 15728640)
4313                         {
4314                             extended_memory_size = inb_cmos(0x31);
4315                             extended_memory_size <<= 8;
4316                             extended_memory_size |= inb_cmos(0x30);
4317                             extended_memory_size *= 1024;
4318                         }
4319
4320                         write_word(ES, regs.u.r16.di, 0x0000);
4321                         write_word(ES, regs.u.r16.di+2, 0x0010);
4322                         write_word(ES, regs.u.r16.di+4, 0x0000);
4323                         write_word(ES, regs.u.r16.di+6, 0x0000);
4324
4325                         write_word(ES, regs.u.r16.di+8, extended_memory_size);
4326                         extended_memory_size >>= 16;
4327                         write_word(ES, regs.u.r16.di+10, extended_memory_size);
4328                         extended_memory_size >>= 16;
4329                         write_word(ES, regs.u.r16.di+12, extended_memory_size);
4330                         extended_memory_size >>= 16;
4331                         write_word(ES, regs.u.r16.di+14, extended_memory_size);
4332
4333                         write_word(ES, regs.u.r16.di+16, 0x1);
4334                         write_word(ES, regs.u.r16.di+18, 0x0);
4335
4336                         regs.u.r32.ebx = 0;
4337                         regs.u.r32.eax = 0x534D4150;
4338                         regs.u.r32.ecx = 0x14;
4339                         CLEAR_CF();
4340                         return;
4341                         break;
4342                     default:  /* AX=E820, DX=534D4150, BX unrecognized */
4343                         goto int15_unimplemented;
4344                         break;
4345                 }
4346 #endif
4347             } else {
4348               // if DX != 0x534D4150)
4349               goto int15_unimplemented;
4350             }
4351             break;
4352
4353         case 0x01: 
4354           // do we have any reason to fail here ?
4355           CLEAR_CF();
4356
4357           // my real system sets ax and bx to 0
4358           // this is confirmed by Ralph Brown list
4359           // but syslinux v1.48 is known to behave 
4360           // strangely if ax is set to 0
4361           // regs.u.r16.ax = 0;
4362           // regs.u.r16.bx = 0;
4363
4364           // Get the amount of extended memory (above 1M)
4365           regs.u.r8.cl = inb_cmos(0x30);
4366           regs.u.r8.ch = inb_cmos(0x31);
4367           
4368           // limit to 15M
4369           if(regs.u.r16.cx > 0x3c00)
4370           {
4371             regs.u.r16.cx = 0x3c00;
4372           }
4373
4374           // Get the amount of extended memory above 16M in 64k blocs
4375           regs.u.r8.dl = inb_cmos(0x34);
4376           regs.u.r8.dh = inb_cmos(0x35);
4377
4378           // Set configured memory equal to extended memory
4379           regs.u.r16.ax = regs.u.r16.cx;
4380           regs.u.r16.bx = regs.u.r16.dx;
4381           break;
4382         default:  /* AH=0xE8?? but not implemented */
4383           goto int15_unimplemented;
4384        }
4385        break;
4386     int15_unimplemented:
4387        // fall into the default
4388     default:
4389       BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n",
4390         (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx);
4391       SET_CF();
4392       regs.u.r8.ah = UNSUPPORTED_FUNCTION;
4393       break;
4394     }
4395 }
4396
4397   void
4398 int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
4399   Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
4400 {
4401   Bit8u scan_code, ascii_code, shift_flags, count;
4402   Bit16u kbd_code, max;
4403
4404   BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX);
4405
4406   switch (GET_AH()) {
4407     case 0x00: /* read keyboard input */
4408
4409       if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4410         BX_PANIC("KBD: int16h: out of keyboard input\n");
4411         }
4412       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4413       else if (ascii_code == 0xE0) ascii_code = 0;
4414       AX = (scan_code << 8) | ascii_code;
4415       break;
4416
4417     case 0x01: /* check keyboard status */
4418       if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4419         SET_ZF();
4420         return;
4421         }
4422       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4423       else if (ascii_code == 0xE0) ascii_code = 0;
4424       AX = (scan_code << 8) | ascii_code;
4425       CLEAR_ZF();
4426       break;
4427
4428     case 0x02: /* get shift flag status */
4429       shift_flags = read_byte(0x0040, 0x17);
4430       SET_AL(shift_flags);
4431       break;
4432
4433     case 0x05: /* store key-stroke into buffer */
4434       if ( !enqueue_key(GET_CH(), GET_CL()) ) {
4435         SET_AL(1);
4436         }
4437       else {
4438         SET_AL(0);
4439         }
4440       break;
4441
4442     case 0x09: /* GET KEYBOARD FUNCTIONALITY */
4443       // bit Bochs Description     
4444       //  7    0   reserved
4445       //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
4446       //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
4447       //  4    1   INT 16/AH=0Ah supported
4448       //  3    0   INT 16/AX=0306h supported
4449       //  2    0   INT 16/AX=0305h supported
4450       //  1    0   INT 16/AX=0304h supported
4451       //  0    0   INT 16/AX=0300h supported
4452       //
4453       SET_AL(0x30);
4454       break;
4455
4456     case 0x0A: /* GET KEYBOARD ID */
4457       count = 2;
4458       kbd_code = 0x0;
4459       outb(0x60, 0xf2);
4460       /* Wait for data */
4461       max=0xffff;
4462       while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4463       if (max>0x0) {
4464         if ((inb(0x60) == 0xfa)) {
4465           do {
4466             max=0xffff;
4467             while ( ((inb(0x64) & 0x01) == 0) && (--max>0) ) outb(0x80, 0x00);
4468             if (max>0x0) {
4469               kbd_code >>= 8;
4470               kbd_code |= (inb(0x60) << 8);
4471             }
4472           } while (--count>0);
4473         }
4474       }
4475       BX=kbd_code;
4476       break;
4477
4478     case 0x10: /* read MF-II keyboard input */
4479
4480       if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
4481         BX_PANIC("KBD: int16h: out of keyboard input\n");
4482         }
4483       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4484       AX = (scan_code << 8) | ascii_code;
4485       break;
4486
4487     case 0x11: /* check MF-II keyboard status */
4488       if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
4489         SET_ZF();
4490         return;
4491         }
4492       if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
4493       AX = (scan_code << 8) | ascii_code;
4494       CLEAR_ZF();
4495       break;
4496
4497     case 0x12: /* get extended keyboard status */
4498       shift_flags = read_byte(0x0040, 0x17);
4499       SET_AL(shift_flags);
4500       shift_flags = read_byte(0x0040, 0x18);
4501       SET_AH(shift_flags);
4502       BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
4503       break;
4504
4505     case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
4506       SET_AH(0x80); // function int16 ah=0x10-0x12 supported
4507       break;
4508
4509     case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
4510       // don't change AH : function int16 ah=0x20-0x22 NOT supported
4511       break;
4512
4513     case 0x6F:
4514       if (GET_AL() == 0x08)
4515         SET_AH(0x02); // unsupported, aka normal keyboard
4516
4517     default:
4518       BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
4519     }
4520 }
4521
4522   unsigned int
4523 dequeue_key(scan_code, ascii_code, incr)
4524   Bit8u *scan_code;
4525   Bit8u *ascii_code;
4526   unsigned int incr;
4527 {
4528   Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
4529   Bit16u ss;
4530   Bit8u  acode, scode;
4531
4532 #if BX_CPU < 2
4533   buffer_start = 0x001E;
4534   buffer_end   = 0x003E;
4535 #else
4536   buffer_start = read_word(0x0040, 0x0080);
4537   buffer_end   = read_word(0x0040, 0x0082);
4538 #endif
4539
4540   buffer_head = read_word(0x0040, 0x001a);
4541   buffer_tail = read_word(0x0040, 0x001c);
4542
4543   if (buffer_head != buffer_tail) {
4544     ss = get_SS();
4545     acode = read_byte(0x0040, buffer_head);
4546     scode = read_byte(0x0040, buffer_head+1);
4547     write_byte(ss, ascii_code, acode);
4548     write_byte(ss, scan_code, scode);
4549
4550     if (incr) {
4551       buffer_head += 2;
4552       if (buffer_head >= buffer_end)
4553         buffer_head = buffer_start;
4554       write_word(0x0040, 0x001a, buffer_head);
4555       }
4556     return(1);
4557     }
4558   else {
4559     return(0);
4560     }
4561 }
4562
4563 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
4564
4565   Bit8u
4566 inhibit_mouse_int_and_events()
4567 {
4568   Bit8u command_byte, prev_command_byte;
4569
4570   // Turn off IRQ generation and aux data line
4571   if ( inb(0x64) & 0x02 )
4572     BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4573   outb(0x64, 0x20); // get command byte
4574   while ( (inb(0x64) & 0x01) != 0x01 );
4575   prev_command_byte = inb(0x60);
4576   command_byte = prev_command_byte;
4577   //while ( (inb(0x64) & 0x02) );
4578   if ( inb(0x64) & 0x02 )
4579     BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
4580   command_byte &= 0xfd; // turn off IRQ 12 generation
4581   command_byte |= 0x20; // disable mouse serial clock line
4582   outb(0x64, 0x60); // write command byte
4583   outb(0x60, command_byte);
4584   return(prev_command_byte);
4585 }
4586
4587   void
4588 enable_mouse_int_and_events()
4589 {
4590   Bit8u command_byte;
4591
4592   // Turn on IRQ generation and aux data line
4593   if ( inb(0x64) & 0x02 )
4594     BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4595   outb(0x64, 0x20); // get command byte
4596   while ( (inb(0x64) & 0x01) != 0x01 );
4597   command_byte = inb(0x60);
4598   //while ( (inb(0x64) & 0x02) );
4599   if ( inb(0x64) & 0x02 )
4600     BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
4601   command_byte |= 0x02; // turn on IRQ 12 generation
4602   command_byte &= 0xdf; // enable mouse serial clock line
4603   outb(0x64, 0x60); // write command byte
4604   outb(0x60, command_byte);
4605 }
4606
4607   Bit8u
4608 send_to_mouse_ctrl(sendbyte)
4609   Bit8u sendbyte;
4610 {
4611   Bit8u response;
4612
4613   // wait for chance to write to ctrl
4614   if ( inb(0x64) & 0x02 )
4615     BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
4616   outb(0x64, 0xD4);
4617   outb(0x60, sendbyte);
4618   return(0);
4619 }
4620
4621
4622   Bit8u
4623 get_mouse_data(data)
4624   Bit8u *data;
4625 {
4626   Bit8u response;
4627   Bit16u ss;
4628
4629   while ( (inb(0x64) & 0x21) != 0x21 ) {
4630     }
4631
4632   response = inb(0x60);
4633
4634   ss = get_SS();
4635   write_byte(ss, data, response);
4636   return(0);
4637 }
4638
4639   void
4640 set_kbd_command_byte(command_byte)
4641   Bit8u command_byte;
4642 {
4643   if ( inb(0x64) & 0x02 )
4644     BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
4645   outb(0x64, 0xD4);
4646
4647   outb(0x64, 0x60); // write command byte
4648   outb(0x60, command_byte);
4649 }
4650
4651   void
4652 int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
4653   Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
4654 {
4655   Bit8u scancode, asciicode, shift_flags;
4656   Bit8u mf2_flags, mf2_state, led_flags;
4657
4658   //
4659   // DS has been set to F000 before call
4660   //
4661
4662
4663   scancode = GET_AL();
4664
4665   if (scancode == 0) {
4666     BX_INFO("KBD: int09 handler: AL=0\n");
4667     return;
4668     }
4669
4670
4671   shift_flags = read_byte(0x0040, 0x17);
4672   mf2_flags = read_byte(0x0040, 0x18);
4673   mf2_state = read_byte(0x0040, 0x96);
4674   led_flags = read_byte(0x0040, 0x97);
4675   asciicode = 0;
4676
4677   switch (scancode) {
4678     case 0x3a: /* Caps Lock press */
4679       shift_flags ^= 0x40;
4680       write_byte(0x0040, 0x17, shift_flags);
4681       mf2_flags |= 0x40;
4682       write_byte(0x0040, 0x18, mf2_flags);
4683       led_flags ^= 0x04;
4684       write_byte(0x0040, 0x97, led_flags);
4685       break;
4686     case 0xba: /* Caps Lock release */
4687       mf2_flags &= ~0x40;
4688       write_byte(0x0040, 0x18, mf2_flags);
4689       break;
4690
4691     case 0x2a: /* L Shift press */
4692       /*shift_flags &= ~0x40;*/
4693       shift_flags |= 0x02;
4694       write_byte(0x0040, 0x17, shift_flags);
4695       led_flags &= ~0x04;
4696       write_byte(0x0040, 0x97, led_flags);
4697       break;
4698     case 0xaa: /* L Shift release */
4699       shift_flags &= ~0x02;
4700       write_byte(0x0040, 0x17, shift_flags);
4701       break;
4702
4703     case 0x36: /* R Shift press */
4704       /*shift_flags &= ~0x40;*/
4705       shift_flags |= 0x01;
4706       write_byte(0x0040, 0x17, shift_flags);
4707       led_flags &= ~0x04;
4708       write_byte(0x0040, 0x97, led_flags);
4709       break;
4710     case 0xb6: /* R Shift release */
4711       shift_flags &= ~0x01;
4712       write_byte(0x0040, 0x17, shift_flags);
4713       break;
4714
4715     case 0x1d: /* Ctrl press */
4716       shift_flags |= 0x04;
4717       write_byte(0x0040, 0x17, shift_flags);
4718       if (mf2_state & 0x01) {
4719         mf2_flags |= 0x04;
4720       } else {
4721         mf2_flags |= 0x01;
4722         }
4723       write_byte(0x0040, 0x18, mf2_flags);
4724       break;
4725     case 0x9d: /* Ctrl release */
4726       shift_flags &= ~0x04;
4727       write_byte(0x0040, 0x17, shift_flags);
4728       if (mf2_state & 0x01) {
4729         mf2_flags &= ~0x04;
4730       } else {
4731         mf2_flags &= ~0x01;
4732         }
4733       write_byte(0x0040, 0x18, mf2_flags);
4734       break;
4735
4736     case 0x38: /* Alt press */
4737       shift_flags |= 0x08;
4738       write_byte(0x0040, 0x17, shift_flags);
4739       if (mf2_state & 0x01) {
4740         mf2_flags |= 0x08;
4741       } else {
4742         mf2_flags |= 0x02;
4743         }
4744       write_byte(0x0040, 0x18, mf2_flags);
4745       break;
4746     case 0xb8: /* Alt release */
4747       shift_flags &= ~0x08;
4748       write_byte(0x0040, 0x17, shift_flags);
4749       if (mf2_state & 0x01) {
4750         mf2_flags &= ~0x08;
4751       } else {
4752         mf2_flags &= ~0x02;
4753         }
4754       write_byte(0x0040, 0x18, mf2_flags);
4755       break;
4756
4757     case 0x45: /* Num Lock press */
4758       if ((mf2_state & 0x01) == 0) {
4759         mf2_flags |= 0x20;
4760         write_byte(0x0040, 0x18, mf2_flags);
4761         shift_flags ^= 0x20;
4762         led_flags ^= 0x02;
4763         write_byte(0x0040, 0x17, shift_flags);
4764         write_byte(0x0040, 0x97, led_flags);
4765         }
4766       break;
4767     case 0xc5: /* Num Lock release */
4768       if ((mf2_state & 0x01) == 0) {
4769         mf2_flags &= ~0x20;
4770         write_byte(0x0040, 0x18, mf2_flags);
4771         }
4772       break;
4773
4774     case 0x46: /* Scroll Lock press */
4775       mf2_flags |= 0x10;
4776       write_byte(0x0040, 0x18, mf2_flags);
4777       shift_flags ^= 0x10;
4778       led_flags ^= 0x01;
4779       write_byte(0x0040, 0x17, shift_flags);
4780       write_byte(0x0040, 0x97, led_flags);
4781       break;
4782
4783     case 0xc6: /* Scroll Lock release */
4784       mf2_flags &= ~0x10;
4785       write_byte(0x0040, 0x18, mf2_flags);
4786       break;
4787
4788     default:
4789       if (scancode & 0x80) return; /* toss key releases ... */
4790       if (scancode > MAX_SCAN_CODE) {
4791         BX_INFO("KBD: int09h_handler(): unknown scancode read!\n");
4792         return;
4793         }
4794       if (shift_flags & 0x08) { /* ALT */
4795         asciicode = scan_to_scanascii[scancode].alt;
4796         scancode = scan_to_scanascii[scancode].alt >> 8;
4797         }
4798       else if (shift_flags & 0x04) { /* CONTROL */
4799         asciicode = scan_to_scanascii[scancode].control;
4800         scancode = scan_to_scanascii[scancode].control >> 8;
4801         }
4802       else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
4803         /* check if lock state should be ignored 
4804          * because a SHIFT key are pressed */
4805          
4806         if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4807           asciicode = scan_to_scanascii[scancode].normal;
4808           scancode = scan_to_scanascii[scancode].normal >> 8;
4809           }
4810         else {
4811           asciicode = scan_to_scanascii[scancode].shift;
4812           scancode = scan_to_scanascii[scancode].shift >> 8;
4813           }
4814         }
4815       else {
4816         /* check if lock is on */
4817         if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
4818           asciicode = scan_to_scanascii[scancode].shift;
4819           scancode = scan_to_scanascii[scancode].shift >> 8;
4820           }
4821         else {
4822           asciicode = scan_to_scanascii[scancode].normal;
4823           scancode = scan_to_scanascii[scancode].normal >> 8;
4824           }
4825         }
4826       if (scancode==0 && asciicode==0) {
4827         BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
4828         }
4829       enqueue_key(scancode, asciicode);
4830       break;
4831     }
4832   mf2_state &= ~0x01;
4833 }
4834
4835   unsigned int
4836 enqueue_key(scan_code, ascii_code)
4837   Bit8u scan_code, ascii_code;
4838 {
4839   Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
4840
4841   //BX_INFO("KBD:   enqueue_key() called scan:%02x, ascii:%02x\n",
4842   //    scan_code, ascii_code);
4843
4844 #if BX_CPU < 2
4845   buffer_start = 0x001E;
4846   buffer_end   = 0x003E;
4847 #else
4848   buffer_start = read_word(0x0040, 0x0080);
4849   buffer_end   = read_word(0x0040, 0x0082);
4850 #endif
4851
4852   buffer_head = read_word(0x0040, 0x001A);
4853   buffer_tail = read_word(0x0040, 0x001C);
4854
4855   temp_tail = buffer_tail;
4856   buffer_tail += 2;
4857   if (buffer_tail >= buffer_end)
4858     buffer_tail = buffer_start;
4859
4860   if (buffer_tail == buffer_head) {
4861     return(0);
4862     }
4863
4864    write_byte(0x0040, temp_tail, ascii_code);
4865    write_byte(0x0040, temp_tail+1, scan_code);
4866    write_word(0x0040, 0x001C, buffer_tail);
4867    return(1);
4868 }
4869
4870
4871   void
4872 int74_function(make_farcall, Z, Y, X, status)
4873   Bit16u make_farcall, Z, Y, X, status;
4874 {
4875   Bit16u ebda_seg=read_word(0x0040,0x000E);
4876   Bit8u  in_byte, index, package_count;
4877   Bit8u  mouse_flags_1, mouse_flags_2;
4878
4879 BX_DEBUG_INT74("entering int74_function\n");
4880   make_farcall = 0;
4881
4882   in_byte = inb(0x64);
4883   if ( (in_byte & 0x21) != 0x21 ) {
4884     return;
4885     }
4886   in_byte = inb(0x60);
4887 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
4888
4889   mouse_flags_1 = read_byte(ebda_seg, 0x0026);
4890   mouse_flags_2 = read_byte(ebda_seg, 0x0027);
4891
4892   if ( (mouse_flags_2 & 0x80) != 0x80 ) {
4893       //    BX_PANIC("int74_function:\n");
4894       return;
4895     }
4896
4897   package_count = mouse_flags_2 & 0x07;
4898   index = mouse_flags_1 & 0x07;
4899   write_byte(ebda_seg, 0x28 + index, in_byte);
4900
4901   if ( (index+1) >= package_count ) {
4902 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
4903     status = read_byte(ebda_seg, 0x0028 + 0);
4904     X      = read_byte(ebda_seg, 0x0028 + 1);
4905     Y      = read_byte(ebda_seg, 0x0028 + 2);
4906     Z      = 0;
4907     mouse_flags_1 = 0;
4908     // check if far call handler installed
4909     if (mouse_flags_2 & 0x80)
4910       make_farcall = 1;
4911     }
4912   else {
4913     mouse_flags_1++;
4914     }
4915   write_byte(ebda_seg, 0x0026, mouse_flags_1);
4916 }
4917
4918 #define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
4919
4920 #if BX_USE_ATADRV
4921
4922   void
4923 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
4924   Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
4925 {
4926   Bit32u lba;
4927   Bit16u ebda_seg=read_word(0x0040,0x000E);
4928   Bit16u cylinder, head, sector;
4929   Bit16u segment, offset;
4930   Bit16u npc, nph, npspt, nlc, nlh, nlspt;
4931   Bit16u size, count;
4932   Bit8u  device, status;
4933
4934   BX_DEBUG_INT13_HD("int13_harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
4935
4936   write_byte(0x0040, 0x008e, 0);  // clear completion flag
4937
4938   // basic check : device has to be defined
4939   if ( (GET_ELDL() < 0x80) || (GET_ELDL() >= 0x80 + BX_MAX_ATA_DEVICES) ) {
4940     BX_INFO("int13_harddisk: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
4941     goto int13_fail;
4942     }
4943
4944   // Get the ata channel
4945   device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]);
4946
4947   // basic check : device has to be valid 
4948   if (device >= BX_MAX_ATA_DEVICES) {
4949     BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
4950     goto int13_fail;
4951     }
4952   
4953   switch (GET_AH()) {
4954
4955     case 0x00: /* disk controller reset */
4956       ata_reset (device);
4957       goto int13_success;
4958       break;
4959
4960     case 0x01: /* read disk status */
4961       status = read_byte(0x0040, 0x0074);
4962       SET_AH(status);
4963       SET_DISK_RET_STATUS(0);
4964       /* set CF if error status read */
4965       if (status) goto int13_fail_nostatus;
4966       else        goto int13_success_noah;
4967       break;
4968
4969     case 0x02: // read disk sectors
4970     case 0x03: // write disk sectors 
4971     case 0x04: // verify disk sectors
4972
4973       count       = GET_AL();
4974       cylinder    = GET_CH();
4975       cylinder   |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
4976       sector      = (GET_CL() & 0x3f);
4977       head        = GET_DH();
4978
4979       segment = ES;
4980       offset  = BX;
4981
4982       if ( (count > 128) || (count == 0) ) {
4983         BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH());
4984         goto int13_fail;
4985         }
4986
4987       nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
4988       nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
4989       nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
4990
4991       // sanity check on cyl heads, sec
4992       if( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
4993         BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector);
4994         goto int13_fail;
4995         }
4996       
4997       // FIXME verify
4998       if ( GET_AH() == 0x04 ) goto int13_success;
4999
5000       nph   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5001       npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5002
5003       // if needed, translate lchs to lba, and execute command
5004       if ( (nph != nlh) || (npspt != nlspt)) {
5005         lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1;
5006         sector = 0; // this forces the command to be lba
5007         }
5008
5009       if ( GET_AH() == 0x02 )
5010         status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5011       else
5012         status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset);
5013
5014       // Set nb of sector transferred
5015       SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors));
5016
5017       if (status != 0) {
5018         BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5019         SET_AH(0x0c);
5020         goto int13_fail_noah;
5021         }
5022
5023       goto int13_success;
5024       break;
5025
5026     case 0x05: /* format disk track */
5027       BX_INFO("format disk track called\n");
5028       goto int13_success;
5029       return;
5030       break;
5031
5032     case 0x08: /* read disk drive parameters */
5033       
5034       // Get logical geometry from table
5035       nlc   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders);
5036       nlh   = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads);
5037       nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt);
5038       count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
5039
5040       nlc = nlc - 2; /* 0 based , last sector not used */
5041       SET_AL(0);
5042       SET_CH(nlc & 0xff);
5043       SET_CL(((nlc >> 2) & 0xc0) | (nlspt & 0x3f));
5044       SET_DH(nlh - 1);
5045       SET_DL(count); /* FIXME returns 0, 1, or n hard drives */
5046
5047       // FIXME should set ES & DI
5048       
5049       goto int13_success;
5050       break;
5051
5052     case 0x10: /* check drive ready */
5053       // should look at 40:8E also???
5054       
5055       // Read the status from controller
5056       status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT);
5057       if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) {
5058         goto int13_success;
5059         }
5060       else {
5061         SET_AH(0xAA);
5062         goto int13_fail_noah;
5063         }
5064       break;
5065
5066     case 0x15: /* read disk drive size */
5067
5068       // Get physical geometry from table
5069       npc   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5070       nph   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5071       npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5072
5073       // Compute sector count seen by int13
5074       lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt;
5075       CX = lba >> 16;
5076       DX = lba & 0xffff;
5077
5078       SET_AH(3);  // hard disk accessible
5079       goto int13_success_noah;
5080       break;
5081
5082     case 0x41: // IBM/MS installation check
5083       BX=0xaa55;     // install check
5084       SET_AH(0x30);  // EDD 3.0
5085       CX=0x0007;     // ext disk access and edd, removable supported
5086       goto int13_success_noah;
5087       break;
5088
5089     case 0x42: // IBM/MS extended read
5090     case 0x43: // IBM/MS extended write
5091     case 0x44: // IBM/MS verify
5092     case 0x47: // IBM/MS extended seek
5093
5094       count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5095       segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5096       offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5097  
5098       // Can't use 64 bits lba
5099       lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5100       if (lba != 0L) {
5101         BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH());
5102         goto int13_fail;
5103         }
5104
5105       // Get 32 bits lba and check
5106       lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5107       if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) {
5108         BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH());
5109         goto int13_fail;
5110         }
5111
5112       // If verify or seek
5113       if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5114         goto int13_success;
5115       
5116       // Execute the command
5117       if ( GET_AH() == 0x42 )
5118         status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset);
5119       else
5120         status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset);
5121
5122       count=read_word(ebda_seg, &EbdaData->ata.trsfsectors);
5123       write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5124
5125       if (status != 0) {
5126         BX_INFO("int13_harddisk: function %02x, error %02x !\n",GET_AH(),status);
5127         SET_AH(0x0c);
5128         goto int13_fail_noah;
5129         }
5130
5131       goto int13_success;
5132       break;
5133
5134     case 0x45: // IBM/MS lock/unlock drive
5135     case 0x49: // IBM/MS extended media change
5136       goto int13_success;    // Always success for HD
5137       break;
5138       
5139     case 0x46: // IBM/MS eject media
5140       SET_AH(0xb2);          // Volume Not Removable
5141       goto int13_fail_noah;  // Always fail for HD
5142       break;
5143
5144     case 0x48: // IBM/MS get drive parameters
5145       size=read_word(DS,SI+(Bit16u)&Int13DPT->size);
5146
5147       // Buffer is too small
5148       if(size < 0x1a) 
5149         goto int13_fail;
5150
5151       // EDD 1.x
5152       if(size >= 0x1a) {
5153         Bit16u   blksize;
5154
5155         npc     = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders);
5156         nph     = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads);
5157         npspt   = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt);
5158         lba     = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors);
5159         blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5160
5161         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5162         write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid
5163         write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc);
5164         write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph);
5165         write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt);
5166         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba);  // FIXME should be Bit64
5167         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L);  
5168         write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);  
5169         }
5170
5171       // EDD 2.x
5172       if(size >= 0x1e) {
5173         Bit8u  channel, dev, irq, mode, checksum, i, translation;
5174         Bit16u iobase1, iobase2, options;
5175
5176         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5177
5178         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);  
5179         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);  
5180
5181         // Fill in dpte
5182         channel = device / 2;
5183         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5184         iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5185         irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5186         mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5187         translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation);
5188
5189         options  = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation
5190         options |= (1<<4); // lba translation
5191         options |= (mode==ATA_MODE_PIO32?1:0<<7);
5192         options |= (translation==ATA_TRANSLATION_LBA?1:0<<9); 
5193         options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9); 
5194
5195         write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5196         write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5197         write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5198         write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5199         write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5200         write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5201         write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5202         write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5203         write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5204         write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5205         write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5206  
5207         checksum=0;
5208         for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5209         checksum = ~checksum;
5210         write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5211         }
5212
5213       // EDD 3.x
5214       if(size >= 0x42) {
5215         Bit8u channel, iface, checksum, i;
5216         Bit16u iobase1;
5217
5218         channel = device / 2;
5219         iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5220         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5221
5222         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5223         write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5224         write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5225         write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5226         write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5227
5228         if (iface==ATA_IFACE_ISA) {
5229           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5230           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5231           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5232           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5233           }
5234         else { 
5235           // FIXME PCI
5236           }
5237         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5238         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5239         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5240         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5241
5242         if (iface==ATA_IFACE_ISA) {
5243           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5244           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5245           write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5246           }
5247         else { 
5248           // FIXME PCI
5249           }
5250         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5251         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5252         write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5253         write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5254
5255         checksum=0;
5256         for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5257         checksum = ~checksum;
5258         write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5259         }
5260
5261       goto int13_success;
5262       break;
5263
5264     case 0x4e: // // IBM/MS set hardware configuration
5265       // DMA, prefetch, PIO maximum not supported
5266       switch (GET_AL()) {
5267         case 0x01:
5268         case 0x03:
5269         case 0x04:
5270         case 0x06:
5271           goto int13_success;
5272           break;
5273         default :
5274           goto int13_fail;
5275         }
5276       break;
5277
5278     case 0x09: /* initialize drive parameters */
5279     case 0x0c: /* seek to specified cylinder */
5280     case 0x0d: /* alternate disk reset */
5281     case 0x11: /* recalibrate */
5282     case 0x14: /* controller internal diagnostic */
5283       BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH());
5284       goto int13_success;
5285       break;
5286
5287     case 0x0a: /* read disk sectors with ECC */
5288     case 0x0b: /* write disk sectors with ECC */
5289     case 0x18: // set media type for format
5290     case 0x50: // IBM/MS send packet command
5291     default:
5292       BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH());
5293       goto int13_fail;
5294       break;
5295     }
5296
5297 int13_fail:
5298     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5299 int13_fail_noah:
5300     SET_DISK_RET_STATUS(GET_AH());
5301 int13_fail_nostatus:
5302     SET_CF();     // error occurred
5303     return;
5304
5305 int13_success:
5306     SET_AH(0x00); // no error
5307 int13_success_noah:
5308     SET_DISK_RET_STATUS(0x00);
5309     CLEAR_CF();   // no error
5310     return;
5311 }
5312
5313 // ---------------------------------------------------------------------------
5314 // Start of int13 for cdrom
5315 // ---------------------------------------------------------------------------
5316
5317   void
5318 int13_cdrom(EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
5319   Bit16u EHBX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
5320 {
5321   Bit16u ebda_seg=read_word(0x0040,0x000E);
5322   Bit8u  device, status, locks;
5323   Bit8u  atacmd[12];
5324   Bit32u lba;
5325   Bit16u count, segment, offset, i, size;
5326
5327   BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5328   // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5329   
5330   SET_DISK_RET_STATUS(0x00);
5331
5332   /* basic check : device should be 0xE0+ */
5333   if( (GET_ELDL() < 0xE0) || (GET_ELDL() >= 0xE0+BX_MAX_ATA_DEVICES) ) {
5334     BX_INFO("int13_cdrom: function %02x, ELDL out of range %02x\n", GET_AH(), GET_ELDL());
5335     goto int13_fail;
5336     }
5337
5338   // Get the ata channel
5339   device=read_byte(ebda_seg,&EbdaData->ata.cdidmap[GET_ELDL()-0xE0]);
5340
5341   /* basic check : device has to be valid  */
5342   if (device >= BX_MAX_ATA_DEVICES) {
5343     BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL());
5344     goto int13_fail;
5345     }
5346   
5347   switch (GET_AH()) {
5348
5349     // all those functions return SUCCESS
5350     case 0x00: /* disk controller reset */
5351     case 0x09: /* initialize drive parameters */
5352     case 0x0c: /* seek to specified cylinder */
5353     case 0x0d: /* alternate disk reset */  
5354     case 0x10: /* check drive ready */    
5355     case 0x11: /* recalibrate */      
5356     case 0x14: /* controller internal diagnostic */
5357     case 0x16: /* detect disk change */
5358       goto int13_success;
5359       break;
5360
5361     // all those functions return disk write-protected
5362     case 0x03: /* write disk sectors */
5363     case 0x05: /* format disk track */
5364     case 0x43: // IBM/MS extended write
5365       SET_AH(0x03);
5366       goto int13_fail_noah;
5367       break;
5368
5369     case 0x01: /* read disk status */
5370       status = read_byte(0x0040, 0x0074);
5371       SET_AH(status);
5372       SET_DISK_RET_STATUS(0);
5373
5374       /* set CF if error status read */
5375       if (status) goto int13_fail_nostatus;
5376       else        goto int13_success_noah;
5377       break;      
5378
5379     case 0x15: /* read disk drive size */
5380       SET_AH(0x02);
5381       goto int13_fail_noah;
5382       break;
5383
5384     case 0x41: // IBM/MS installation check
5385       BX=0xaa55;     // install check
5386       SET_AH(0x30);  // EDD 2.1
5387       CX=0x0007;     // ext disk access, removable and edd
5388       goto int13_success_noah;
5389       break;
5390
5391     case 0x42: // IBM/MS extended read
5392     case 0x44: // IBM/MS verify sectors
5393     case 0x47: // IBM/MS extended seek
5394        
5395       count=read_word(DS, SI+(Bit16u)&Int13Ext->count);
5396       segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment);
5397       offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset);
5398  
5399       // Can't use 64 bits lba
5400       lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2);
5401       if (lba != 0L) {
5402         BX_PANIC("int13_cdrom: function %02x. Can't use 64bits lba\n",GET_AH());
5403         goto int13_fail;
5404         }
5405
5406       // Get 32 bits lba 
5407       lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1);
5408
5409       // If verify or seek
5410       if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 ))
5411         goto int13_success;
5412       
5413       memsetb(get_SS(),atacmd,0,12);
5414       atacmd[0]=0x28;                      // READ command
5415       atacmd[7]=(count & 0xff00) >> 8;     // Sectors
5416       atacmd[8]=(count & 0x00ff);          // Sectors
5417       atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
5418       atacmd[3]=(lba & 0x00ff0000) >> 16;
5419       atacmd[4]=(lba & 0x0000ff00) >> 8;
5420       atacmd[5]=(lba & 0x000000ff);
5421       status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset); 
5422
5423       count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11);
5424       write_word(DS, SI+(Bit16u)&Int13Ext->count, count);
5425
5426       if (status != 0) {
5427         BX_INFO("int13_cdrom: function %02x, status %02x !\n",GET_AH(),status);
5428         SET_AH(0x0c);
5429         goto int13_fail_noah;
5430         }
5431
5432       goto int13_success;
5433       break;
5434
5435     case 0x45: // IBM/MS lock/unlock drive
5436       if (GET_AL() > 2) goto int13_fail;
5437
5438       locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5439
5440       switch (GET_AL()) {
5441         case 0 :  // lock
5442           if (locks == 0xff) {
5443             SET_AH(0xb4);
5444             SET_AL(1);
5445             goto int13_fail_noah;
5446             }
5447           write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, ++locks);
5448           SET_AL(1);
5449           break;
5450         case 1 :  // unlock
5451           if (locks == 0x00) {
5452             SET_AH(0xb0);
5453             SET_AL(0);
5454             goto int13_fail_noah;
5455             }
5456           write_byte(ebda_seg, &EbdaData->ata.devices[device].lock, --locks);
5457           SET_AL(locks==0?0:1);
5458           break;
5459         case 2 :  // status
5460           SET_AL(locks==0?0:1);
5461           break;
5462         }
5463       goto int13_success;
5464       break;
5465
5466     case 0x46: // IBM/MS eject media
5467       locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock);
5468       
5469       if (locks != 0) {
5470         SET_AH(0xb1); // media locked
5471         goto int13_fail_noah;
5472         }
5473       // FIXME should handle 0x31 no media in device
5474       // FIXME should handle 0xb5 valid request failed
5475     
5476       // Call removable media eject
5477       ASM_START
5478         push bp
5479         mov  bp, sp
5480
5481         mov ah, #0x52
5482         int 15
5483         mov _int13_cdrom.status + 2[bp], ah
5484         jnc int13_cdrom_rme_end
5485         mov _int13_cdrom.status, #1
5486 int13_cdrom_rme_end:
5487         pop bp
5488       ASM_END
5489
5490       if (status != 0) {
5491         SET_AH(0xb1); // media locked
5492         goto int13_fail_noah;
5493       }
5494
5495       goto int13_success;
5496       break;
5497
5498     case 0x48: // IBM/MS get drive parameters
5499       size = read_word(DS,SI+(Bit16u)&Int13Ext->size);
5500
5501       // Buffer is too small
5502       if(size < 0x1a) 
5503         goto int13_fail;
5504
5505       // EDD 1.x
5506       if(size >= 0x1a) {
5507         Bit16u   cylinders, heads, spt, blksize;
5508
5509         blksize   = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize);
5510
5511         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a);
5512         write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x74); // removable, media change, lockable, max values
5513         write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0xffffffff);
5514         write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff);
5515         write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff);
5516         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff);  // FIXME should be Bit64
5517         write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff);  
5518         write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize);  
5519         }
5520
5521       // EDD 2.x
5522       if(size >= 0x1e) {
5523         Bit8u  channel, dev, irq, mode, checksum, i;
5524         Bit16u iobase1, iobase2, options;
5525
5526         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e);
5527
5528         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg);  
5529         write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte);  
5530
5531         // Fill in dpte
5532         channel = device / 2;
5533         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5534         iobase2 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase2);
5535         irq = read_byte(ebda_seg, &EbdaData->ata.channels[channel].irq);
5536         mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode);
5537
5538         // FIXME atapi device
5539         options  = (1<<4); // lba translation
5540         options |= (1<<5); // removable device
5541         options |= (1<<6); // atapi device
5542         options |= (mode==ATA_MODE_PIO32?1:0<<7);
5543
5544         write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1);
5545         write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2);
5546         write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 );
5547         write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb );
5548         write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq );
5549         write_byte(ebda_seg, &EbdaData->ata.dpte.blkcount, 1 );
5550         write_byte(ebda_seg, &EbdaData->ata.dpte.dma, 0 );
5551         write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 );
5552         write_word(ebda_seg, &EbdaData->ata.dpte.options, options);
5553         write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0);
5554         write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11);
5555
5556         checksum=0;
5557         for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i);
5558         checksum = ~checksum;
5559         write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum);
5560         }
5561
5562       // EDD 3.x
5563       if(size >= 0x42) {
5564         Bit8u channel, iface, checksum, i;
5565         Bit16u iobase1;
5566
5567         channel = device / 2;
5568         iface = read_byte(ebda_seg, &EbdaData->ata.channels[channel].iface);
5569         iobase1 = read_word(ebda_seg, &EbdaData->ata.channels[channel].iobase1);
5570
5571         write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x42);
5572         write_word(DS, SI+(Bit16u)&Int13DPT->key, 0xbedd);
5573         write_byte(DS, SI+(Bit16u)&Int13DPT->dpi_length, 0x24);
5574         write_byte(DS, SI+(Bit16u)&Int13DPT->reserved1, 0);
5575         write_word(DS, SI+(Bit16u)&Int13DPT->reserved2, 0);
5576
5577         if (iface==ATA_IFACE_ISA) {
5578           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[0], 'I');
5579           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[1], 'S');
5580           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A');
5581           write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0);
5582           }
5583         else { 
5584           // FIXME PCI
5585           }
5586         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A');
5587         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[1], 'T');
5588         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[2], 'A');
5589         write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[3], 0);
5590
5591         if (iface==ATA_IFACE_ISA) {
5592           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[0], iobase1);
5593           write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0);
5594           write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L);
5595           }
5596         else { 
5597           // FIXME PCI
5598           }
5599         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2);
5600         write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[1], 0);
5601         write_word(DS, SI+(Bit16u)&Int13DPT->device_path[2], 0);
5602         write_dword(DS, SI+(Bit16u)&Int13DPT->device_path[4], 0L);
5603
5604         checksum=0;
5605         for (i=30; i<64; i++) checksum+=read_byte(DS, SI + i);
5606         checksum = ~checksum;
5607         write_byte(DS, SI+(Bit16u)&Int13DPT->checksum, checksum);
5608         }
5609
5610       goto int13_success;
5611       break;
5612
5613     case 0x49: // IBM/MS extended media change
5614       // always send changed ??
5615       SET_AH(06);
5616       goto int13_fail_nostatus;
5617       break;
5618       
5619     case 0x4e: // // IBM/MS set hardware configuration
5620       // DMA, prefetch, PIO maximum not supported
5621       switch (GET_AL()) {
5622         case 0x01:
5623         case 0x03:
5624         case 0x04:
5625         case 0x06:
5626           goto int13_success;
5627           break;
5628         default :
5629           goto int13_fail;
5630         }
5631       break;
5632
5633     // all those functions return unimplemented
5634     case 0x02: /* read sectors */
5635     case 0x04: /* verify sectors */
5636     case 0x08: /* read disk drive parameters */
5637     case 0x0a: /* read disk sectors with ECC */
5638     case 0x0b: /* write disk sectors with ECC */
5639     case 0x18: /* set media type for format */
5640     case 0x50: // ? - send packet command
5641     default:
5642       BX_INFO("int13_cdrom: unsupported AH=%02x\n", GET_AH());
5643       goto int13_fail;
5644       break;
5645     }
5646
5647 int13_fail:
5648     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5649 int13_fail_noah:
5650     SET_DISK_RET_STATUS(GET_AH());
5651 int13_fail_nostatus:
5652     SET_CF();     // error occurred
5653     return;
5654
5655 int13_success:
5656     SET_AH(0x00); // no error
5657 int13_success_noah:
5658     SET_DISK_RET_STATUS(0x00);
5659     CLEAR_CF();   // no error
5660     return;
5661 }
5662
5663 // ---------------------------------------------------------------------------
5664 // End of int13 for cdrom
5665 // ---------------------------------------------------------------------------
5666
5667 #if BX_ELTORITO_BOOT
5668 // ---------------------------------------------------------------------------
5669 // Start of int13 for eltorito functions
5670 // ---------------------------------------------------------------------------
5671
5672   void
5673 int13_eltorito(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5674   Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5675 {
5676   Bit16u ebda_seg=read_word(0x0040,0x000E);
5677
5678   BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5679   // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI);
5680   
5681   switch (GET_AH()) {
5682
5683     // FIXME ElTorito Various. Should be implemented
5684     case 0x4a: // ElTorito - Initiate disk emu
5685     case 0x4c: // ElTorito - Initiate disk emu and boot
5686     case 0x4d: // ElTorito - Return Boot catalog
5687       BX_PANIC("Int13 eltorito call with AX=%04x. Please report\n",AX);
5688       goto int13_fail;
5689       break;
5690
5691     case 0x4b: // ElTorito - Terminate disk emu
5692       // FIXME ElTorito Hardcoded
5693       write_byte(DS,SI+0x00,0x13);
5694       write_byte(DS,SI+0x01,read_byte(ebda_seg,&EbdaData->cdemu.media));
5695       write_byte(DS,SI+0x02,read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive));
5696       write_byte(DS,SI+0x03,read_byte(ebda_seg,&EbdaData->cdemu.controller_index));
5697       write_dword(DS,SI+0x04,read_dword(ebda_seg,&EbdaData->cdemu.ilba));
5698       write_word(DS,SI+0x08,read_word(ebda_seg,&EbdaData->cdemu.device_spec));
5699       write_word(DS,SI+0x0a,read_word(ebda_seg,&EbdaData->cdemu.buffer_segment));
5700       write_word(DS,SI+0x0c,read_word(ebda_seg,&EbdaData->cdemu.load_segment));
5701       write_word(DS,SI+0x0e,read_word(ebda_seg,&EbdaData->cdemu.sector_count));
5702       write_byte(DS,SI+0x10,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.cylinders));
5703       write_byte(DS,SI+0x11,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.spt));
5704       write_byte(DS,SI+0x12,read_byte(ebda_seg,&EbdaData->cdemu.vdevice.heads));
5705
5706       // If we have to terminate emulation
5707       if(GET_AL() == 0x00) {
5708         // FIXME ElTorito Various. Should be handled accordingly to spec
5709         write_byte(ebda_seg,&EbdaData->cdemu.active, 0x00); // bye bye
5710         }
5711
5712       goto int13_success;
5713       break;
5714
5715     default:
5716       BX_INFO("int13_eltorito: unsupported AH=%02x\n", GET_AH());
5717       goto int13_fail;
5718       break;
5719     }
5720
5721 int13_fail:
5722     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5723     SET_DISK_RET_STATUS(GET_AH());
5724     SET_CF();     // error occurred
5725     return;
5726
5727 int13_success:
5728     SET_AH(0x00); // no error
5729     SET_DISK_RET_STATUS(0x00);
5730     CLEAR_CF();   // no error
5731     return;
5732 }
5733
5734 // ---------------------------------------------------------------------------
5735 // End of int13 for eltorito functions
5736 // ---------------------------------------------------------------------------
5737
5738 // ---------------------------------------------------------------------------
5739 // Start of int13 when emulating a device from the cd
5740 // ---------------------------------------------------------------------------
5741
5742   void
5743 int13_cdemu(DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS)
5744   Bit16u DS, ES, DI, SI, BP, SP, BX, DX, CX, AX, IP, CS, FLAGS;
5745 {
5746   Bit16u ebda_seg=read_word(0x0040,0x000E);
5747   Bit8u  device, status;
5748   Bit16u vheads, vspt, vcylinders;
5749   Bit16u head, sector, cylinder, nbsectors;
5750   Bit32u vlba, ilba, slba, elba;
5751   Bit16u before, segment, offset;
5752   Bit8u  atacmd[12];
5753
5754   BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
5755   //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI);
5756   
5757   /* at this point, we are emulating a floppy/harddisk */
5758   
5759   // Recompute the device number 
5760   device  = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2;
5761   device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec);
5762
5763   SET_DISK_RET_STATUS(0x00);
5764
5765   /* basic checks : emulation should be active, dl should equal the emulated drive */
5766   if( (read_byte(ebda_seg,&EbdaData->cdemu.active) ==0 )
5767    || (read_byte(ebda_seg,&EbdaData->cdemu.emulated_drive ) != GET_DL())) {
5768     BX_INFO("int13_cdemu: function %02x, emulation not active for DL= %02x\n", GET_AH(), GET_DL());
5769     goto int13_fail;
5770     }
5771   
5772   switch (GET_AH()) {
5773
5774     // all those functions return SUCCESS
5775     case 0x00: /* disk controller reset */
5776     case 0x09: /* initialize drive parameters */
5777     case 0x0c: /* seek to specified cylinder */
5778     case 0x0d: /* alternate disk reset */  // FIXME ElTorito Various. should really reset ?
5779     case 0x10: /* check drive ready */     // FIXME ElTorito Various. should check if ready ?
5780     case 0x11: /* recalibrate */      
5781     case 0x14: /* controller internal diagnostic */
5782     case 0x16: /* detect disk change */
5783       goto int13_success;
5784       break;
5785
5786     // all those functions return disk write-protected
5787     case 0x03: /* write disk sectors */
5788     case 0x05: /* format disk track */
5789       SET_AH(0x03);
5790       goto int13_fail_noah;
5791       break;
5792
5793     case 0x01: /* read disk status */
5794       status=read_byte(0x0040, 0x0074);
5795       SET_AH(status);
5796       SET_DISK_RET_STATUS(0);
5797
5798       /* set CF if error status read */
5799       if (status) goto int13_fail_nostatus;
5800       else        goto int13_success_noah;
5801       break;
5802
5803     case 0x02: // read disk sectors
5804     case 0x04: // verify disk sectors
5805       vspt       = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); 
5806       vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders); 
5807       vheads     = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads); 
5808
5809       ilba       = read_dword(ebda_seg,&EbdaData->cdemu.ilba);
5810
5811       sector    = GET_CL() & 0x003f;
5812       cylinder  = (GET_CL() & 0x00c0) << 2 | GET_CH();
5813       head      = GET_DH();
5814       nbsectors = GET_AL();
5815       segment   = ES;
5816       offset    = BX;
5817
5818       // no sector to read ?
5819       if(nbsectors==0) goto int13_success;
5820
5821       // sanity checks sco openserver needs this!
5822       if ((sector   >  vspt)
5823        || (cylinder >= vcylinders)
5824        || (head     >= vheads)) {
5825         goto int13_fail;
5826         }
5827
5828       // After controls, verify do nothing
5829       if (GET_AH() == 0x04) goto int13_success;
5830
5831       segment = ES+(BX / 16);
5832       offset  = BX % 16;
5833
5834       // calculate the virtual lba inside the image
5835       vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1));
5836  
5837       // In advance so we don't loose the count
5838       SET_AL(nbsectors);
5839
5840       // start lba on cd
5841       slba  = (Bit32u)vlba/4; 
5842       before= (Bit16u)vlba%4;
5843
5844       // end lba on cd
5845       elba = (Bit32u)(vlba+nbsectors-1)/4;
5846       
5847       memsetb(get_SS(),atacmd,0,12);
5848       atacmd[0]=0x28;                      // READ command
5849       atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors
5850       atacmd[8]=((Bit16u)(elba-slba+1) & 0x00ff);      // Sectors
5851       atacmd[2]=(ilba+slba & 0xff000000) >> 24;  // LBA
5852       atacmd[3]=(ilba+slba & 0x00ff0000) >> 16;
5853       atacmd[4]=(ilba+slba & 0x0000ff00) >> 8;
5854       atacmd[5]=(ilba+slba & 0x000000ff);
5855       if((status = ata_cmd_packet(device, 12, get_SS(), atacmd, before*512, nbsectors*512L, ATA_DATA_IN, segment,offset)) != 0) {
5856         BX_INFO("int13_cdemu: function %02x, error %02x !\n",GET_AH(),status);
5857         SET_AH(0x02);
5858         SET_AL(0);
5859         goto int13_fail_noah;
5860         }
5861
5862       goto int13_success;
5863       break;
5864
5865     case 0x08: /* read disk drive parameters */
5866       vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); 
5867       vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1; 
5868       vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1; 
5869  
5870       SET_AL( 0x00 );
5871       SET_BL( 0x00 );
5872       SET_CH( vcylinders & 0xff );
5873       SET_CL((( vcylinders >> 2) & 0xc0) | ( vspt  & 0x3f ));
5874       SET_DH( vheads );
5875       SET_DL( 0x02 );   // FIXME ElTorito Various. should send the real count of drives 1 or 2
5876                         // FIXME ElTorito Harddisk. should send the HD count
5877  
5878       switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) {
5879         case 0x01: SET_BL( 0x02 ); break;
5880         case 0x02: SET_BL( 0x04 ); break;
5881         case 0x03: SET_BL( 0x06 ); break;
5882         }
5883
5884 ASM_START
5885       push bp
5886       mov  bp, sp
5887       mov ax, #diskette_param_table2
5888       mov _int13_cdemu.DI+2[bp], ax
5889       mov _int13_cdemu.ES+2[bp], cs
5890       pop  bp
5891 ASM_END
5892       goto int13_success;
5893       break;
5894
5895     case 0x15: /* read disk drive size */
5896       // FIXME ElTorito Harddisk. What geometry to send ?
5897       SET_AH(0x03);
5898       goto int13_success_noah;
5899       break;
5900
5901     // all those functions return unimplemented
5902     case 0x0a: /* read disk sectors with ECC */
5903     case 0x0b: /* write disk sectors with ECC */
5904     case 0x18: /* set media type for format */
5905     case 0x41: // IBM/MS installation check
5906       // FIXME ElTorito Harddisk. Darwin would like to use EDD
5907     case 0x42: // IBM/MS extended read
5908     case 0x43: // IBM/MS extended write
5909     case 0x44: // IBM/MS verify sectors
5910     case 0x45: // IBM/MS lock/unlock drive
5911     case 0x46: // IBM/MS eject media
5912     case 0x47: // IBM/MS extended seek
5913     case 0x48: // IBM/MS get drive parameters 
5914     case 0x49: // IBM/MS extended media change
5915     case 0x4e: // ? - set hardware configuration
5916     case 0x50: // ? - send packet command
5917     default:
5918       BX_INFO("int13_cdemu function AH=%02x unsupported, returns fail\n", GET_AH());
5919       goto int13_fail;
5920       break;
5921     }
5922
5923 int13_fail:
5924     SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
5925 int13_fail_noah:
5926     SET_DISK_RET_STATUS(GET_AH());
5927 int13_fail_nostatus:
5928     SET_CF();     // error occurred
5929     return;
5930
5931 int13_success:
5932     SET_AH(0x00); // no error
5933 int13_success_noah:
5934     SET_DISK_RET_STATUS(0x00);
5935     CLEAR_CF();   // no error
5936     return;
5937 }
5938
5939 // ---------------------------------------------------------------------------
5940 // End of int13 when emulating a device from the cd
5941 // ---------------------------------------------------------------------------
5942
5943 #endif // BX_ELTORITO_BOOT
5944
5945 #else //BX_USE_ATADRV
5946
5947   void
5948 outLBA(cylinder,hd_heads,head,hd_sectors,sector,dl)
5949   Bit16u cylinder;
5950   Bit16u hd_heads;
5951   Bit16u head;
5952   Bit16u hd_sectors;
5953   Bit16u sector;
5954   Bit16u dl;
5955 {
5956 ASM_START
5957         push   bp
5958         mov    bp, sp
5959         push   eax
5960         push   ebx
5961         push   edx
5962         xor    eax,eax
5963         mov    ax,4[bp]  // cylinder
5964         xor    ebx,ebx
5965         mov    bl,6[bp]  // hd_heads
5966         imul   ebx
5967
5968         mov    bl,8[bp]  // head
5969         add    eax,ebx
5970         mov    bl,10[bp] // hd_sectors
5971         imul   ebx
5972         mov    bl,12[bp] // sector
5973         add    eax,ebx
5974
5975         dec    eax
5976         mov    dx,#0x1f3
5977         out    dx,al
5978         mov    dx,#0x1f4
5979         mov    al,ah
5980         out    dx,al
5981         shr    eax,#16
5982         mov    dx,#0x1f5
5983         out    dx,al
5984         and    ah,#0xf
5985         mov    bl,14[bp] // dl
5986         and    bl,#1
5987         shl    bl,#4
5988         or     ah,bl
5989         or     ah,#0xe0
5990         mov    al,ah
5991         mov    dx,#0x01f6
5992         out    dx,al
5993         pop    edx
5994         pop    ebx
5995         pop    eax
5996         pop    bp
5997 ASM_END
5998 }
5999
6000   void
6001 int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6002   Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6003 {
6004   Bit8u    drive, num_sectors, sector, head, status, mod;
6005   Bit8u    drive_map;
6006   Bit8u    n_drives;
6007   Bit16u   cyl_mod, ax;
6008   Bit16u   max_cylinder, cylinder, total_sectors;
6009   Bit16u   hd_cylinders;
6010   Bit8u    hd_heads, hd_sectors;
6011   Bit16u   val16;
6012   Bit8u    sector_count;
6013   unsigned int i;
6014   Bit16u   tempbx;
6015   Bit16u   dpsize;
6016
6017   Bit16u   count, segment, offset;
6018   Bit32u   lba;
6019   Bit16u   error;
6020
6021   BX_DEBUG_INT13_HD("int13 harddisk: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6022
6023   write_byte(0x0040, 0x008e, 0);  // clear completion flag
6024
6025   /* at this point, DL is >= 0x80 to be passed from the floppy int13h
6026      handler code */
6027   /* check how many disks first (cmos reg 0x12), return an error if
6028      drive not present */
6029   drive_map = inb_cmos(0x12);
6030   drive_map = (((drive_map & 0xf0)==0) ? 0 : 1) |
6031               (((drive_map & 0x0f)==0) ? 0 : 2);
6032   n_drives = (drive_map==0) ? 0 :
6033     ((drive_map==3) ? 2 : 1);
6034
6035   if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
6036     SET_AH(0x01);
6037     SET_DISK_RET_STATUS(0x01);
6038     SET_CF(); /* error occurred */
6039     return;
6040     }
6041
6042   switch (GET_AH()) {
6043
6044     case 0x00: /* disk controller reset */
6045 BX_DEBUG_INT13_HD("int13_f00\n");
6046
6047       SET_AH(0);
6048       SET_DISK_RET_STATUS(0);
6049       set_diskette_ret_status(0);
6050       set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
6051       set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
6052       CLEAR_CF(); /* successful */
6053       return;
6054       break;
6055
6056     case 0x01: /* read disk status */
6057 BX_DEBUG_INT13_HD("int13_f01\n");
6058       status = read_byte(0x0040, 0x0074);
6059       SET_AH(status);
6060       SET_DISK_RET_STATUS(0);
6061       /* set CF if error status read */
6062       if (status) SET_CF();
6063       else        CLEAR_CF();
6064       return;
6065       break;
6066
6067     case 0x04: // verify disk sectors
6068     case 0x02: // read disk sectors
6069       drive = GET_ELDL();
6070       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6071
6072       num_sectors = GET_AL();
6073       cylinder    = (GET_CL() & 0x00c0) << 2 | GET_CH();
6074       sector      = (GET_CL() & 0x3f);
6075       head        = GET_DH();
6076
6077
6078       if (hd_cylinders > 1024) {
6079         if (hd_cylinders <= 2048) {
6080           cylinder <<= 1;
6081           }
6082         else if (hd_cylinders <= 4096) {
6083           cylinder <<= 2;
6084           }
6085         else if (hd_cylinders <= 8192) {
6086           cylinder <<= 3;
6087           }
6088         else { // hd_cylinders <= 16384
6089           cylinder <<= 4;
6090           }
6091
6092         ax = head / hd_heads;
6093         cyl_mod = ax & 0xff;
6094         head    = ax >> 8;
6095         cylinder |= cyl_mod;
6096         }
6097
6098       if ( (cylinder >= hd_cylinders) ||
6099            (sector > hd_sectors) ||
6100            (head >= hd_heads) ) {
6101         SET_AH(1);
6102         SET_DISK_RET_STATUS(1);
6103         SET_CF(); /* error occurred */
6104         return;
6105         }
6106
6107       if ( (num_sectors > 128) || (num_sectors == 0) )
6108         BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6109
6110       if (head > 15)
6111         BX_PANIC("hard drive BIOS:(read/verify) head > 15\n");
6112
6113       if ( GET_AH() == 0x04 ) {
6114         SET_AH(0);
6115         SET_DISK_RET_STATUS(0);
6116         CLEAR_CF();
6117         return;
6118         }
6119
6120       status = inb(0x1f7);
6121       if (status & 0x80) {
6122         BX_PANIC("hard drive BIOS:(read/verify) BUSY bit set\n");
6123         }
6124       outb(0x01f2, num_sectors);
6125       /* activate LBA? (tomv) */
6126       if (hd_heads > 16) {
6127 BX_DEBUG_INT13_HD("CHS: %x %x %x\n", cylinder, head, sector);
6128         outLBA(cylinder,hd_heads,head,hd_sectors,sector,drive);
6129         }
6130       else {
6131         outb(0x01f3, sector);
6132         outb(0x01f4, cylinder & 0x00ff);
6133         outb(0x01f5, cylinder >> 8);
6134         outb(0x01f6, 0xa0 | ((drive & 0x01)<<4) | (head & 0x0f));
6135         }
6136       outb(0x01f7, 0x20);
6137
6138       while (1) {
6139         status = inb(0x1f7);
6140         if ( !(status & 0x80) ) break;
6141         }
6142
6143       if (status & 0x01) {
6144         BX_PANIC("hard drive BIOS:(read/verify) read error\n");
6145       } else if ( !(status & 0x08) ) {
6146         BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6147         BX_PANIC("hard drive BIOS:(read/verify) expected DRQ=1\n");
6148       }
6149
6150       sector_count = 0;
6151       tempbx = BX;
6152
6153 ASM_START
6154   sti  ;; enable higher priority interrupts
6155 ASM_END
6156
6157       while (1) {
6158 ASM_START
6159         ;; store temp bx in real DI register
6160         push bp
6161         mov  bp, sp
6162         mov  di, _int13_harddisk.tempbx + 2 [bp]
6163         pop  bp
6164
6165         ;; adjust if there will be an overrun
6166         cmp   di, #0xfe00
6167         jbe   i13_f02_no_adjust
6168 i13_f02_adjust:
6169         sub   di, #0x0200 ; sub 512 bytes from offset
6170         mov   ax, es
6171         add   ax, #0x0020 ; add 512 to segment
6172         mov   es, ax
6173
6174 i13_f02_no_adjust:
6175         mov  cx, #0x0100   ;; counter (256 words = 512b)
6176         mov  dx, #0x01f0  ;; AT data read port
6177
6178         rep
6179           insw ;; CX words transfered from port(DX) to ES:[DI]
6180
6181 i13_f02_done:
6182         ;; store real DI register back to temp bx
6183         push bp
6184         mov  bp, sp
6185         mov  _int13_harddisk.tempbx + 2 [bp], di
6186         pop  bp
6187 ASM_END
6188
6189         sector_count++;
6190         num_sectors--;
6191         if (num_sectors == 0) {
6192           status = inb(0x1f7);
6193           if ( (status & 0xc9) != 0x40 )
6194             BX_PANIC("no sectors left to read/verify, status is %02x\n", (unsigned) status);
6195           break;
6196           }
6197         else {
6198           status = inb(0x1f7);
6199           if ( (status & 0xc9) != 0x48 )
6200             BX_PANIC("more sectors left to read/verify, status is %02x\n", (unsigned) status);
6201           continue;
6202           }
6203         }
6204
6205       SET_AH(0);
6206       SET_DISK_RET_STATUS(0);
6207       SET_AL(sector_count);
6208       CLEAR_CF(); /* successful */
6209       return;
6210       break;
6211
6212
6213     case 0x03: /* write disk sectors */
6214 BX_DEBUG_INT13_HD("int13_f03\n");
6215       drive = GET_ELDL ();
6216       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6217
6218       num_sectors = GET_AL();
6219       cylinder    = GET_CH();
6220       cylinder    |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
6221       sector      = (GET_CL() & 0x3f);
6222       head        = GET_DH();
6223
6224       if (hd_cylinders > 1024) {
6225         if (hd_cylinders <= 2048) {
6226           cylinder <<= 1;
6227           }
6228         else if (hd_cylinders <= 4096) {
6229           cylinder <<= 2;
6230           }
6231         else if (hd_cylinders <= 8192) {
6232           cylinder <<= 3;
6233           }
6234         else { // hd_cylinders <= 16384
6235           cylinder <<= 4;
6236           }
6237
6238         ax = head / hd_heads;
6239         cyl_mod = ax & 0xff;
6240         head    = ax >> 8;
6241         cylinder |= cyl_mod;
6242         }
6243
6244       if ( (cylinder >= hd_cylinders) ||
6245            (sector > hd_sectors) ||
6246            (head >= hd_heads) ) {
6247         SET_AH( 1);
6248         SET_DISK_RET_STATUS(1);
6249         SET_CF(); /* error occurred */
6250         return;
6251         }
6252
6253       if ( (num_sectors > 128) || (num_sectors == 0) )
6254         BX_PANIC("int13_harddisk(): num_sectors out of range!\n");
6255
6256       if (head > 15)
6257         BX_PANIC("hard drive BIOS:(read) head > 15\n");
6258
6259       status = inb(0x1f7);
6260       if (status & 0x80) {
6261         BX_PANIC("hard drive BIOS:(read) BUSY bit set\n");
6262         }
6263 // should check for Drive Ready Bit also in status reg
6264       outb(0x01f2, num_sectors);
6265
6266       /* activate LBA? (tomv) */
6267       if (hd_heads > 16) {
6268 BX_DEBUG_INT13_HD("CHS (write): %x %x %x\n", cylinder, head, sector);
6269         outLBA(cylinder,hd_heads,head,hd_sectors,sector,GET_ELDL());
6270         }
6271       else {
6272         outb(0x01f3, sector);
6273         outb(0x01f4, cylinder & 0x00ff);
6274         outb(0x01f5, cylinder >> 8);
6275         outb(0x01f6, 0xa0 | ((GET_ELDL() & 0x01)<<4) | (head & 0x0f));
6276         }
6277       outb(0x01f7, 0x30);
6278
6279       // wait for busy bit to turn off after seeking
6280       while (1) {
6281         status = inb(0x1f7);
6282         if ( !(status & 0x80) ) break;
6283         }
6284
6285       if ( !(status & 0x08) ) {
6286         BX_DEBUG_INT13_HD("status was %02x\n", (unsigned) status);
6287         BX_PANIC("hard drive BIOS:(write) data-request bit not set\n");
6288         }
6289
6290       sector_count = 0;
6291       tempbx = BX;
6292
6293 ASM_START
6294   sti  ;; enable higher priority interrupts
6295 ASM_END
6296
6297       while (1) {
6298 ASM_START
6299         ;; store temp bx in real SI register
6300         push bp
6301         mov  bp, sp
6302         mov  si, _int13_harddisk.tempbx + 2 [bp]
6303         pop  bp
6304
6305         ;; adjust if there will be an overrun
6306         cmp   si, #0xfe00
6307         jbe   i13_f03_no_adjust
6308 i13_f03_adjust:
6309         sub   si, #0x0200 ; sub 512 bytes from offset
6310         mov   ax, es
6311         add   ax, #0x0020 ; add 512 to segment
6312         mov   es, ax
6313
6314 i13_f03_no_adjust:
6315         mov  cx, #0x0100   ;; counter (256 words = 512b)
6316         mov  dx, #0x01f0  ;; AT data read port
6317
6318         seg ES
6319         rep
6320           outsw ;; CX words tranfered from ES:[SI] to port(DX)
6321
6322         ;; store real SI register back to temp bx
6323         push bp
6324         mov  bp, sp
6325         mov  _int13_harddisk.tempbx + 2 [bp], si
6326         pop  bp
6327 ASM_END
6328
6329         sector_count++;
6330         num_sectors--;
6331         if (num_sectors == 0) {
6332           status = inb(0x1f7);
6333           if ( (status & 0xe9) != 0x40 )
6334             BX_PANIC("no sectors left to write, status is %02x\n", (unsigned) status);
6335           break;
6336           }
6337         else {
6338           status = inb(0x1f7);
6339           if ( (status & 0xc9) != 0x48 )
6340             BX_PANIC("more sectors left to write, status is %02x\n", (unsigned) status);
6341           continue;
6342           }
6343         }
6344
6345       SET_AH(0);
6346       SET_DISK_RET_STATUS(0);
6347       SET_AL(sector_count);
6348       CLEAR_CF(); /* successful */
6349       return;
6350       break;
6351
6352     case 0x05: /* format disk track */
6353 BX_DEBUG_INT13_HD("int13_f05\n");
6354       BX_PANIC("format disk track called\n");
6355       /* nop */
6356       SET_AH(0);
6357       SET_DISK_RET_STATUS(0);
6358       CLEAR_CF(); /* successful */
6359       return;
6360       break;
6361
6362     case 0x08: /* read disk drive parameters */
6363 BX_DEBUG_INT13_HD("int13_f08\n");
6364       
6365       drive = GET_ELDL ();
6366       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6367
6368       // translate CHS
6369       //
6370       if (hd_cylinders <= 1024) {
6371         // hd_cylinders >>= 0;
6372         // hd_heads <<= 0;
6373         }
6374       else if (hd_cylinders <= 2048) {
6375         hd_cylinders >>= 1;
6376         hd_heads <<= 1;
6377         }
6378       else if (hd_cylinders <= 4096) {
6379         hd_cylinders >>= 2;
6380         hd_heads <<= 2;
6381         }
6382       else if (hd_cylinders <= 8192) {
6383         hd_cylinders >>= 3;
6384         hd_heads <<= 3;
6385         }
6386       else { // hd_cylinders <= 16384
6387         hd_cylinders >>= 4;
6388         hd_heads <<= 4;
6389         }
6390
6391       max_cylinder = hd_cylinders - 2; /* 0 based */
6392       SET_AL(0);
6393       SET_CH(max_cylinder & 0xff);
6394       SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
6395       SET_DH(hd_heads - 1);
6396       SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
6397       SET_AH(0);
6398       SET_DISK_RET_STATUS(0);
6399       CLEAR_CF(); /* successful */
6400
6401       return;
6402       break;
6403
6404     case 0x09: /* initialize drive parameters */
6405 BX_DEBUG_INT13_HD("int13_f09\n");
6406       SET_AH(0);
6407       SET_DISK_RET_STATUS(0);
6408       CLEAR_CF(); /* successful */
6409       return;
6410       break;
6411
6412     case 0x0a: /* read disk sectors with ECC */
6413 BX_DEBUG_INT13_HD("int13_f0a\n");
6414     case 0x0b: /* write disk sectors with ECC */
6415 BX_DEBUG_INT13_HD("int13_f0b\n");
6416       BX_PANIC("int13h Functions 0Ah & 0Bh not implemented!\n");
6417       return;
6418       break;
6419
6420     case 0x0c: /* seek to specified cylinder */
6421 BX_DEBUG_INT13_HD("int13_f0c\n");
6422       BX_INFO("int13h function 0ch (seek) not implemented!\n");
6423       SET_AH(0);
6424       SET_DISK_RET_STATUS(0);
6425       CLEAR_CF(); /* successful */
6426       return;
6427       break;
6428
6429     case 0x0d: /* alternate disk reset */
6430 BX_DEBUG_INT13_HD("int13_f0d\n");
6431       SET_AH(0);
6432       SET_DISK_RET_STATUS(0);
6433       CLEAR_CF(); /* successful */
6434       return;
6435       break;
6436
6437     case 0x10: /* check drive ready */
6438 BX_DEBUG_INT13_HD("int13_f10\n");
6439       //SET_AH(0);
6440       //SET_DISK_RET_STATUS(0);
6441       //CLEAR_CF(); /* successful */
6442       //return;
6443       //break;
6444
6445       // should look at 40:8E also???
6446       status = inb(0x01f7);
6447       if ( (status & 0xc0) == 0x40 ) {
6448         SET_AH(0);
6449         SET_DISK_RET_STATUS(0);
6450         CLEAR_CF(); // drive ready
6451         return;
6452         }
6453       else {
6454         SET_AH(0xAA);
6455         SET_DISK_RET_STATUS(0xAA);
6456         SET_CF(); // not ready
6457         return;
6458         }
6459       break;
6460
6461     case 0x11: /* recalibrate */
6462 BX_DEBUG_INT13_HD("int13_f11\n");
6463       SET_AH(0);
6464       SET_DISK_RET_STATUS(0);
6465       CLEAR_CF(); /* successful */
6466       return;
6467       break;
6468
6469     case 0x14: /* controller internal diagnostic */
6470 BX_DEBUG_INT13_HD("int13_f14\n");
6471       SET_AH(0);
6472       SET_DISK_RET_STATUS(0);
6473       CLEAR_CF(); /* successful */
6474       SET_AL(0);
6475       return;
6476       break;
6477
6478     case 0x15: /* read disk drive size */
6479       drive = GET_ELDL();
6480       get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
6481 ASM_START
6482       push bp
6483       mov  bp, sp
6484       mov  al, _int13_harddisk.hd_heads + 2 [bp]
6485       mov  ah, _int13_harddisk.hd_sectors + 2 [bp]
6486       mul  al, ah ;; ax = heads * sectors
6487       mov  bx, _int13_harddisk.hd_cylinders + 2 [bp]
6488       dec  bx     ;; use (cylinders - 1) ???
6489       mul  ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
6490       ;; now we need to move the 32bit result dx:ax to what the
6491       ;; BIOS wants which is cx:dx.
6492       ;; and then into CX:DX on the stack
6493       mov  _int13_harddisk.CX + 2 [bp], dx
6494       mov  _int13_harddisk.DX + 2 [bp], ax
6495       pop  bp
6496 ASM_END
6497       SET_AH(3);  // hard disk accessible
6498       SET_DISK_RET_STATUS(0); // ??? should this be 0
6499       CLEAR_CF(); // successful
6500       return;
6501       break;
6502
6503     case 0x18: // set media type for format
6504     case 0x41: // IBM/MS 
6505     case 0x42: // IBM/MS 
6506     case 0x43: // IBM/MS 
6507     case 0x44: // IBM/MS 
6508     case 0x45: // IBM/MS lock/unlock drive
6509     case 0x46: // IBM/MS eject media
6510     case 0x47: // IBM/MS extended seek
6511     case 0x49: // IBM/MS extended media change
6512     case 0x50: // IBM/MS send packet command
6513     default:
6514       BX_INFO("int13_harddisk: unsupported AH=%02x\n", GET_AH());
6515
6516       SET_AH(1);  // code=invalid function in AH or invalid parameter
6517       SET_DISK_RET_STATUS(1);
6518       SET_CF(); /* unsuccessful */
6519       return;
6520       break;
6521     }
6522 }
6523
6524 static char panic_msg_reg12h[] = "HD%d cmos reg 12h not type F\n";
6525 static char panic_msg_reg19h[] = "HD%d cmos reg %02xh not user definable type 47\n";
6526
6527   void
6528 get_hd_geometry(drive, hd_cylinders, hd_heads, hd_sectors)
6529   Bit8u drive;
6530   Bit16u *hd_cylinders;
6531   Bit8u  *hd_heads;
6532   Bit8u  *hd_sectors;
6533 {
6534   Bit8u hd_type;
6535   Bit16u ss;
6536   Bit16u cylinders;
6537   Bit8u iobase;
6538
6539   ss = get_SS();
6540   if (drive == 0x80) {
6541     hd_type = inb_cmos(0x12) & 0xf0;
6542     if (hd_type != 0xf0)
6543       BX_INFO(panic_msg_reg12h,0);
6544     hd_type = inb_cmos(0x19); // HD0: extended type
6545     if (hd_type != 47)
6546       BX_INFO(panic_msg_reg19h,0,0x19);
6547     iobase = 0x1b;
6548   } else {
6549     hd_type = inb_cmos(0x12) & 0x0f;
6550     if (hd_type != 0x0f)
6551       BX_INFO(panic_msg_reg12h,1);
6552     hd_type = inb_cmos(0x1a); // HD0: extended type
6553     if (hd_type != 47)
6554       BX_INFO(panic_msg_reg19h,0,0x1a);
6555     iobase = 0x24;
6556   }
6557
6558   // cylinders
6559   cylinders = inb_cmos(iobase) | (inb_cmos(iobase+1) << 8);
6560   write_word(ss, hd_cylinders, cylinders);
6561
6562   // heads
6563   write_byte(ss, hd_heads, inb_cmos(iobase+2));
6564
6565   // sectors per track
6566   write_byte(ss, hd_sectors, inb_cmos(iobase+8));
6567 }
6568
6569 #endif //else BX_USE_ATADRV
6570
6571
6572 //////////////////////
6573 // FLOPPY functions //
6574 //////////////////////
6575
6576   bx_bool
6577 floppy_media_known(drive)
6578   Bit16u drive;
6579 {
6580   Bit8u  val8;
6581   Bit16u media_state_offset;
6582
6583   val8 = read_byte(0x0040, 0x003e); // diskette recal status
6584   if (drive)
6585     val8 >>= 1;
6586   val8 &= 0x01;
6587   if (val8 == 0)
6588     return(0);
6589
6590   media_state_offset = 0x0090;
6591   if (drive)
6592     media_state_offset += 1;
6593
6594   val8 = read_byte(0x0040, media_state_offset);
6595   val8 = (val8 >> 4) & 0x01;
6596   if (val8 == 0)
6597     return(0);
6598
6599   // check pass, return KNOWN
6600   return(1);
6601 }
6602
6603   bx_bool
6604 floppy_media_sense(drive)
6605   Bit16u drive;
6606 {
6607   bx_bool retval;
6608   Bit16u  media_state_offset;
6609   Bit8u   drive_type, config_data, media_state;
6610
6611   if (floppy_drive_recal(drive) == 0) {
6612     return(0);
6613     }
6614
6615   // for now cheat and get drive type from CMOS,
6616   // assume media is same as drive type
6617
6618   // ** config_data **
6619   // Bitfields for diskette media control:
6620   // Bit(s)  Description (Table M0028)
6621   //  7-6  last data rate set by controller
6622   //        00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6623   //  5-4  last diskette drive step rate selected
6624   //        00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
6625   //  3-2  {data rate at start of operation}
6626   //  1-0  reserved
6627
6628   // ** media_state **
6629   // Bitfields for diskette drive media state:
6630   // Bit(s)  Description (Table M0030)
6631   //  7-6  data rate
6632   //    00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
6633   //  5  double stepping required (e.g. 360kB in 1.2MB)
6634   //  4  media type established
6635   //  3  drive capable of supporting 4MB media
6636   //  2-0  on exit from BIOS, contains
6637   //    000 trying 360kB in 360kB
6638   //    001 trying 360kB in 1.2MB
6639   //    010 trying 1.2MB in 1.2MB
6640   //    011 360kB in 360kB established
6641   //    100 360kB in 1.2MB established
6642   //    101 1.2MB in 1.2MB established
6643   //    110 reserved
6644   //    111 all other formats/drives
6645
6646   drive_type = inb_cmos(0x10);
6647   if (drive == 0)
6648     drive_type >>= 4;
6649   else
6650     drive_type &= 0x0f;
6651   if ( drive_type == 1 ) {
6652     // 360K 5.25" drive
6653     config_data = 0x00; // 0000 0000
6654     media_state = 0x25; // 0010 0101
6655     retval = 1;
6656     }
6657   else if ( drive_type == 2 ) {
6658     // 1.2 MB 5.25" drive
6659     config_data = 0x00; // 0000 0000
6660     media_state = 0x25; // 0010 0101   // need double stepping??? (bit 5)
6661     retval = 1;
6662     }
6663   else if ( drive_type == 3 ) {
6664     // 720K 3.5" drive
6665     config_data = 0x00; // 0000 0000 ???
6666     media_state = 0x17; // 0001 0111
6667     retval = 1;
6668     }
6669   else if ( drive_type == 4 ) {
6670     // 1.44 MB 3.5" drive
6671     config_data = 0x00; // 0000 0000
6672     media_state = 0x17; // 0001 0111
6673     retval = 1;
6674     }
6675   else if ( drive_type == 5 ) {
6676     // 2.88 MB 3.5" drive
6677     config_data = 0xCC; // 1100 1100
6678     media_state = 0xD7; // 1101 0111
6679     retval = 1;
6680     }
6681   //
6682   // Extended floppy size uses special cmos setting 
6683   else if ( drive_type == 6 ) {
6684     // 160k 5.25" drive
6685     config_data = 0x00; // 0000 0000
6686     media_state = 0x27; // 0010 0111
6687     retval = 1;
6688     }
6689   else if ( drive_type == 7 ) {
6690     // 180k 5.25" drive
6691     config_data = 0x00; // 0000 0000
6692     media_state = 0x27; // 0010 0111
6693     retval = 1;
6694     }
6695   else if ( drive_type == 8 ) {
6696     // 320k 5.25" drive
6697     config_data = 0x00; // 0000 0000
6698     media_state = 0x27; // 0010 0111
6699     retval = 1;
6700     }
6701
6702   else {
6703     // not recognized
6704     config_data = 0x00; // 0000 0000
6705     media_state = 0x00; // 0000 0000
6706     retval = 0;
6707     }
6708
6709   if (drive == 0)
6710     media_state_offset = 0x90;
6711   else
6712     media_state_offset = 0x91;
6713   write_byte(0x0040, 0x008B, config_data);
6714   write_byte(0x0040, media_state_offset, media_state);
6715
6716   return(retval);
6717 }
6718
6719   bx_bool
6720 floppy_drive_recal(drive)
6721   Bit16u drive;
6722 {
6723   Bit8u  val8, dor;
6724   Bit16u curr_cyl_offset;
6725
6726   // set 40:3e bit 7 to 0
6727   val8 = read_byte(0x0000, 0x043e);
6728   val8 &= 0x7f;
6729   write_byte(0x0000, 0x043e, val8);
6730
6731   // turn on motor of selected drive, DMA & int enabled, normal operation
6732   if (drive)
6733     dor = 0x20;
6734   else
6735     dor = 0x10;
6736   dor |= 0x0c;
6737   dor |= drive;
6738   outb(0x03f2, dor);
6739
6740   // reset the disk motor timeout value of INT 08
6741   write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6742
6743   // check port 3f4 for drive readiness
6744   val8 = inb(0x3f4);
6745   if ( (val8 & 0xf0) != 0x80 )
6746     BX_PANIC("floppy recal:f07: ctrl not ready\n");
6747
6748   // send Recalibrate command (2 bytes) to controller
6749   outb(0x03f5, 0x07);  // 07: Recalibrate
6750   outb(0x03f5, drive); // 0=drive0, 1=drive1
6751
6752  // turn on interrupts
6753 ASM_START
6754   sti
6755 ASM_END
6756
6757   // wait on 40:3e bit 7 to become 1
6758   val8 = (read_byte(0x0000, 0x043e) & 0x80);
6759   while ( val8 == 0 ) {
6760     val8 = (read_byte(0x0000, 0x043e) & 0x80);
6761     }
6762
6763  val8 = 0; // separate asm from while() loop
6764  // turn off interrupts
6765 ASM_START
6766   cli
6767 ASM_END
6768
6769   // set 40:3e bit 7 to 0, and calibrated bit
6770   val8 = read_byte(0x0000, 0x043e);
6771   val8 &= 0x7f;
6772   if (drive) {
6773     val8 |= 0x02; // Drive 1 calibrated
6774     curr_cyl_offset = 0x0095;
6775     }
6776   else {
6777     val8 |= 0x01; // Drive 0 calibrated
6778     curr_cyl_offset = 0x0094;
6779     }
6780   write_byte(0x0040, 0x003e, val8);
6781   write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
6782
6783   return(1);
6784 }
6785
6786
6787
6788   bx_bool
6789 floppy_drive_exists(drive)
6790   Bit16u drive;
6791 {
6792   Bit8u  drive_type;
6793
6794   // just tell it both drives exist - PAD
6795   return 1;
6796
6797   // check CMOS to see if drive exists
6798   drive_type = inb_cmos(0x10);
6799   if (drive == 0)
6800     drive_type >>= 4;
6801   else
6802     drive_type &= 0x0f;
6803   if ( drive_type == 0 )
6804     return(0);
6805   else
6806     return(1);
6807 }
6808
6809 #if BX_SUPPORT_FLOPPY
6810   void
6811 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
6812   Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
6813 {
6814   Bit8u  drive, num_sectors, track, sector, head, status;
6815   Bit16u base_address, base_count, base_es;
6816   Bit8u  page, mode_register, val8, dor;
6817   Bit8u  return_status[7];
6818   Bit8u  drive_type, num_floppies, ah;
6819   Bit16u es, last_addr;
6820
6821
6822   //printf("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES);
6823   BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(),get_DS(), ES, DI, SI);
6824
6825   ah = GET_AH();
6826
6827   switch ( ah ) {
6828     case 0x00: // diskette controller reset
6829       BX_DEBUG_INT13_FL("floppy f00\n");
6830       drive = GET_ELDL();
6831       if (drive > 1) {
6832         SET_AH(1); // invalid param
6833         set_diskette_ret_status(1);
6834         SET_CF();
6835         return;
6836         }
6837       drive_type = inb_cmos(0x10);
6838
6839       if (drive == 0)
6840         drive_type >>= 4;
6841       else
6842         drive_type &= 0x0f;
6843       if (drive_type == 0) {
6844         SET_AH(0x80); // drive not responding
6845         set_diskette_ret_status(0x80);
6846         SET_CF();
6847         return;
6848         }
6849       SET_AH(0);
6850       set_diskette_ret_status(0);
6851       CLEAR_CF(); // successful
6852       set_diskette_current_cyl(drive, 0); // current cylinder
6853       return;
6854
6855     case 0x01: // Read Diskette Status
6856       CLEAR_CF();
6857       val8 = read_byte(0x0000, 0x0441);
6858       SET_AH(val8);
6859       if (val8) {
6860         SET_CF();
6861         }
6862       return;
6863
6864     case 0x02: // Read Diskette Sectors
6865     case 0x03: // Write Diskette Sectors
6866     case 0x04: // Verify Diskette Sectors
6867       num_sectors = GET_AL();
6868       track       = GET_CH();
6869       sector      = GET_CL();
6870       head        = GET_DH();
6871       drive       = GET_ELDL();
6872
6873       if ( (drive > 1) || (head > 1) ||
6874            (num_sectors == 0) || (num_sectors > 72) ) {
6875 BX_INFO("floppy: drive>1 || head>1 ...\n");
6876         SET_AH(1);
6877         set_diskette_ret_status(1);
6878         SET_AL(0); // no sectors read
6879         SET_CF(); // error occurred
6880         return;
6881         }
6882
6883       // see if drive exists
6884       if (floppy_drive_exists(drive) == 0) {
6885         SET_AH(0x80); // not responding
6886         set_diskette_ret_status(0x80);
6887         SET_AL(0); // no sectors read
6888         SET_CF(); // error occurred
6889         return;
6890         }
6891
6892       // see if media in drive, and type is known
6893       if (floppy_media_known(drive) == 0) {
6894         if (floppy_media_sense(drive) == 0) {
6895           SET_AH(0x0C); // Media type not found
6896           set_diskette_ret_status(0x0C);
6897           SET_AL(0); // no sectors read
6898           SET_CF(); // error occurred
6899           return;
6900           }
6901         }
6902
6903       if (ah == 0x02) {
6904         // Read Diskette Sectors
6905
6906         //-----------------------------------
6907         // set up DMA controller for transfer
6908         //-----------------------------------
6909
6910         // es:bx = pointer to where to place information from diskette
6911         // port 04: DMA-1 base and current address, channel 2
6912         // port 05: DMA-1 base and current count, channel 2
6913         page = (ES >> 12);   // upper 4 bits
6914         base_es = (ES << 4); // lower 16bits contributed by ES
6915         base_address = base_es + BX; // lower 16 bits of address
6916                                      // contributed by ES:BX
6917         if ( base_address < base_es ) {
6918           // in case of carry, adjust page by 1
6919           page++;
6920           }
6921         base_count = (num_sectors * 512) - 1;
6922
6923         // check for 64K boundary overrun
6924         last_addr = base_address + base_count;
6925         if (last_addr < base_address) {
6926           SET_AH(0x09);
6927           set_diskette_ret_status(0x09);
6928           SET_AL(0); // no sectors read
6929           SET_CF(); // error occurred
6930           return;
6931           }
6932
6933         BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
6934         outb(0x000a, 0x06);
6935
6936   BX_DEBUG_INT13_FL("clear flip-flop\n");
6937         outb(0x000c, 0x00); // clear flip-flop
6938         outb(0x0004, base_address);
6939         outb(0x0004, base_address>>8);
6940   BX_DEBUG_INT13_FL("clear flip-flop\n");
6941         outb(0x000c, 0x00); // clear flip-flop
6942         outb(0x0005, base_count);
6943         outb(0x0005, base_count>>8);
6944
6945         // port 0b: DMA-1 Mode Register
6946         mode_register = 0x46; // single mode, increment, autoinit disable,
6947                               // transfer type=write, channel 2
6948   BX_DEBUG_INT13_FL("setting mode register\n");
6949         outb(0x000b, mode_register);
6950
6951   BX_DEBUG_INT13_FL("setting page register\n");
6952         // port 81: DMA-1 Page Register, channel 2
6953         outb(0x0081, page);
6954
6955   BX_DEBUG_INT13_FL("unmask chan 2\n");
6956         outb(0x000a, 0x02); // unmask channel 2
6957
6958         BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
6959         outb(0x000a, 0x02);
6960
6961         //--------------------------------------
6962         // set up floppy controller for transfer
6963         //--------------------------------------
6964
6965         // set 40:3e bit 7 to 0
6966         val8 = read_byte(0x0000, 0x043e);
6967         val8 &= 0x7f;
6968         write_byte(0x0000, 0x043e, val8);
6969
6970         // turn on motor of selected drive, DMA & int enabled, normal operation
6971         if (drive)
6972           dor = 0x20;
6973         else
6974           dor = 0x10;
6975         dor |= 0x0c;
6976         dor |= drive;
6977         outb(0x03f2, dor);
6978
6979         // reset the disk motor timeout value of INT 08
6980         write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
6981
6982         // check port 3f4 for drive readiness
6983         val8 = inb(0x3f4);
6984         if ( (val8 & 0xf0) != 0x80 )
6985           BX_PANIC("int13_diskette:f02: ctrl not ready\n");
6986
6987         // send read-normal-data command (9 bytes) to controller
6988         outb(0x03f5, 0xe6); // e6: read normal data
6989         outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
6990         outb(0x03f5, track);
6991         outb(0x03f5, head);
6992         outb(0x03f5, sector);
6993         outb(0x03f5, 2); // 512 byte sector size
6994         outb(0x03f5, 0); // last sector number possible on track
6995         outb(0x03f5, 0); // Gap length
6996         outb(0x03f5, 0xff); // Gap length
6997
6998        // turn on interrupts 
6999  ASM_START
7000         sti
7001   ASM_END
7002
7003         // wait on 40:3e bit 7 to become 1
7004         val8 = (read_byte(0x0000, 0x043e) & 0x80);
7005         while ( val8 == 0 ) {
7006           val8 = (read_byte(0x0000, 0x043e) & 0x80);
7007           }
7008
7009        val8 = 0; // separate asm from while() loop
7010        // turn off interrupts
7011   ASM_START
7012         cli
7013   ASM_END
7014
7015         // set 40:3e bit 7 to 0
7016         val8 = read_byte(0x0000, 0x043e);
7017         val8 &= 0x7f;
7018         write_byte(0x0000, 0x043e, val8);
7019
7020         // check port 3f4 for accessibility to status bytes
7021         val8 = inb(0x3f4);
7022         if ( (val8 & 0xc0) != 0xc0 )
7023           BX_PANIC("int13_diskette: ctrl not ready\n");
7024
7025         // read 7 return status bytes from controller
7026         // using loop index broken, have to unroll...
7027         return_status[0] = inb(0x3f5);
7028         return_status[1] = inb(0x3f5);
7029         return_status[2] = inb(0x3f5);
7030         return_status[3] = inb(0x3f5);
7031         return_status[4] = inb(0x3f5);
7032         return_status[5] = inb(0x3f5);
7033         return_status[6] = inb(0x3f5);
7034         // record in BIOS Data Area
7035         write_byte(0x0040, 0x0042, return_status[0]);
7036         write_byte(0x0040, 0x0043, return_status[1]);
7037         write_byte(0x0040, 0x0044, return_status[2]);
7038         write_byte(0x0040, 0x0045, return_status[3]);
7039         write_byte(0x0040, 0x0046, return_status[4]);
7040         write_byte(0x0040, 0x0047, return_status[5]);
7041         write_byte(0x0040, 0x0048, return_status[6]);
7042
7043         if ( (return_status[0] & 0xc0) != 0 ) {
7044           SET_AH(0x20);
7045           set_diskette_ret_status(0x20);
7046           SET_AL(0); // no sectors read
7047           SET_CF(); // error occurred
7048           return;
7049           }
7050
7051         // ??? should track be new val from return_status[3] ?
7052         set_diskette_current_cyl(drive, track);
7053         // AL = number of sectors read (same value as passed)
7054         SET_AH(0x00); // success
7055         CLEAR_CF();   // success
7056         return;
7057         }
7058       else if (ah == 0x03) {
7059         // Write Diskette Sectors
7060
7061         //-----------------------------------
7062         // set up DMA controller for transfer
7063         //-----------------------------------
7064
7065         // es:bx = pointer to where to place information from diskette
7066         // port 04: DMA-1 base and current address, channel 2
7067         // port 05: DMA-1 base and current count, channel 2
7068         page = (ES >> 12);   // upper 4 bits
7069         base_es = (ES << 4); // lower 16bits contributed by ES
7070         base_address = base_es + BX; // lower 16 bits of address
7071                                      // contributed by ES:BX
7072         if ( base_address < base_es ) {
7073           // in case of carry, adjust page by 1
7074           page++;
7075           }
7076         base_count = (num_sectors * 512) - 1;
7077
7078         // check for 64K boundary overrun
7079         last_addr = base_address + base_count;
7080         if (last_addr < base_address) {
7081           SET_AH(0x09);
7082           set_diskette_ret_status(0x09);
7083           SET_AL(0); // no sectors read
7084           SET_CF(); // error occurred
7085           return;
7086           }
7087
7088         BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
7089         outb(0x000a, 0x06);
7090
7091         outb(0x000c, 0x00); // clear flip-flop
7092         outb(0x0004, base_address);
7093         outb(0x0004, base_address>>8);
7094         outb(0x000c, 0x00); // clear flip-flop
7095         outb(0x0005, base_count);
7096         outb(0x0005, base_count>>8);
7097
7098         // port 0b: DMA-1 Mode Register
7099         mode_register = 0x4a; // single mode, increment, autoinit disable,
7100                               // transfer type=read, channel 2
7101         outb(0x000b, mode_register);
7102
7103         // port 81: DMA-1 Page Register, channel 2
7104         outb(0x0081, page);
7105
7106         BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
7107         outb(0x000a, 0x02);
7108
7109         //--------------------------------------
7110         // set up floppy controller for transfer
7111         //--------------------------------------
7112
7113         // set 40:3e bit 7 to 0
7114         val8 = read_byte(0x0000, 0x043e);
7115         val8 &= 0x7f;
7116         write_byte(0x0000, 0x043e, val8);
7117
7118         // turn on motor of selected drive, DMA & int enabled, normal operation
7119         if (drive)
7120           dor = 0x20;
7121         else
7122           dor = 0x10;
7123         dor |= 0x0c;
7124         dor |= drive;
7125         outb(0x03f2, dor);
7126
7127         // reset the disk motor timeout value of INT 08
7128         write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7129
7130         // check port 3f4 for drive readiness
7131         val8 = inb(0x3f4);
7132         if ( (val8 & 0xf0) != 0x80 )
7133           BX_PANIC("int13_diskette:f03: ctrl not ready\n");
7134
7135         // send read-normal-data command (9 bytes) to controller
7136         outb(0x03f5, 0xc5); // c5: write normal data
7137         outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7138         outb(0x03f5, track);
7139         outb(0x03f5, head);
7140         outb(0x03f5, sector);
7141         outb(0x03f5, 2); // 512 byte sector size
7142         outb(0x03f5, 0); // last sector number possible on track
7143         outb(0x03f5, 0); // Gap length
7144         outb(0x03f5, 0xff); // Gap length
7145
7146        // turn on interrupts
7147   ASM_START
7148         sti
7149   ASM_END
7150
7151         // wait on 40:3e bit 7 to become 1
7152         val8 = (read_byte(0x0000, 0x043e) & 0x80);
7153         while ( val8 == 0 ) {
7154           val8 = (read_byte(0x0000, 0x043e) & 0x80);
7155           }
7156
7157        val8 = 0; // separate asm from while() loop
7158        // turn off interrupts
7159   ASM_START
7160         cli
7161   ASM_END
7162
7163         // set 40:3e bit 7 to 0
7164         val8 = read_byte(0x0000, 0x043e);
7165         val8 &= 0x7f;
7166         write_byte(0x0000, 0x043e, val8);
7167
7168         // check port 3f4 for accessibility to status bytes
7169         val8 = inb(0x3f4);
7170         if ( (val8 & 0xc0) != 0xc0 )
7171           BX_PANIC("int13_diskette: ctrl not ready\n");
7172
7173         // read 7 return status bytes from controller
7174         // using loop index broken, have to unroll...
7175         return_status[0] = inb(0x3f5);
7176         return_status[1] = inb(0x3f5);
7177         return_status[2] = inb(0x3f5);
7178         return_status[3] = inb(0x3f5);
7179         return_status[4] = inb(0x3f5);
7180         return_status[5] = inb(0x3f5);
7181         return_status[6] = inb(0x3f5);
7182         // record in BIOS Data Area
7183         write_byte(0x0040, 0x0042, return_status[0]);
7184         write_byte(0x0040, 0x0043, return_status[1]);
7185         write_byte(0x0040, 0x0044, return_status[2]);
7186         write_byte(0x0040, 0x0045, return_status[3]);
7187         write_byte(0x0040, 0x0046, return_status[4]);
7188         write_byte(0x0040, 0x0047, return_status[5]);
7189         write_byte(0x0040, 0x0048, return_status[6]);
7190
7191         if ( (return_status[0] & 0xc0) != 0 ) {
7192           if ( (return_status[1] & 0x02) != 0 ) {
7193             // diskette not writable.
7194             // AH=status code=0x03 (tried to write on write-protected disk)
7195             // AL=number of sectors written=0
7196             AX = 0x0300;
7197             SET_CF();
7198             return;
7199           } else {
7200             BX_PANIC("int13_diskette_function: read error\n");
7201           }
7202         }
7203
7204         // ??? should track be new val from return_status[3] ?
7205         set_diskette_current_cyl(drive, track);
7206         // AL = number of sectors read (same value as passed)
7207         SET_AH(0x00); // success
7208         CLEAR_CF();   // success
7209         return;
7210         }
7211       else {  // if (ah == 0x04)
7212         // Verify Diskette Sectors
7213
7214         // ??? should track be new val from return_status[3] ?
7215         set_diskette_current_cyl(drive, track);
7216         // AL = number of sectors verified (same value as passed)
7217         CLEAR_CF();   // success
7218         SET_AH(0x00); // success
7219         return;
7220         }
7221
7222
7223     case 0x05: // format diskette track
7224 BX_DEBUG_INT13_FL("floppy f05\n");
7225
7226       num_sectors = GET_AL();
7227       track       = GET_CH();
7228       head        = GET_DH();
7229       drive       = GET_ELDL();
7230
7231       if ((drive > 1) || (head > 1) || (track > 79) ||
7232           (num_sectors == 0) || (num_sectors > 18)) {
7233         SET_AH(1);
7234         set_diskette_ret_status(1);
7235         SET_CF(); // error occurred
7236         }
7237
7238       // see if drive exists
7239       if (floppy_drive_exists(drive) == 0) {
7240         SET_AH(0x80); // drive not responding
7241         set_diskette_ret_status(0x80);
7242         SET_CF(); // error occurred
7243         return;
7244         }
7245
7246       // see if media in drive, and type is known
7247       if (floppy_media_known(drive) == 0) {
7248         if (floppy_media_sense(drive) == 0) {
7249           SET_AH(0x0C); // Media type not found
7250           set_diskette_ret_status(0x0C);
7251           SET_AL(0); // no sectors read
7252           SET_CF(); // error occurred
7253           return;
7254           }
7255         }
7256
7257       // set up DMA controller for transfer
7258       page = (ES >> 12);   // upper 4 bits
7259       base_es = (ES << 4); // lower 16bits contributed by ES
7260       base_address = base_es + BX; // lower 16 bits of address
7261                                    // contributed by ES:BX
7262       if ( base_address < base_es ) {
7263         // in case of carry, adjust page by 1
7264         page++;
7265         }
7266       base_count = (num_sectors * 4) - 1;
7267
7268       // check for 64K boundary overrun
7269       last_addr = base_address + base_count;
7270       if (last_addr < base_address) {
7271         SET_AH(0x09);
7272         set_diskette_ret_status(0x09);
7273         SET_AL(0); // no sectors read
7274         SET_CF(); // error occurred
7275         return;
7276         }
7277
7278       outb(0x000a, 0x06);
7279       outb(0x000c, 0x00); // clear flip-flop
7280       outb(0x0004, base_address);
7281       outb(0x0004, base_address>>8);
7282       outb(0x000c, 0x00); // clear flip-flop
7283       outb(0x0005, base_count);
7284       outb(0x0005, base_count>>8);
7285       mode_register = 0x4a; // single mode, increment, autoinit disable,
7286                             // transfer type=read, channel 2
7287       outb(0x000b, mode_register);
7288       // port 81: DMA-1 Page Register, channel 2
7289       outb(0x0081, page);
7290       outb(0x000a, 0x02);
7291
7292       // set up floppy controller for transfer
7293       val8 = read_byte(0x0000, 0x043e);
7294       val8 &= 0x7f;
7295       write_byte(0x0000, 0x043e, val8);
7296       // turn on motor of selected drive, DMA & int enabled, normal operation
7297       if (drive)
7298         dor = 0x20;
7299       else
7300         dor = 0x10;
7301       dor |= 0x0c;
7302       dor |= drive;
7303       outb(0x03f2, dor);
7304
7305       // reset the disk motor timeout value of INT 08
7306       write_byte(0x40,0x40, BX_FLOPPY_ON_CNT);
7307
7308       // check port 3f4 for drive readiness
7309       val8 = inb(0x3f4);
7310       if ( (val8 & 0xf0) != 0x80 )
7311         BX_PANIC("int13_diskette:f05: ctrl not ready\n");
7312
7313       // send read-normal-data command (6 bytes) to controller
7314       outb(0x03f5, 0x4d); // 4d: format track
7315       outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
7316       outb(0x03f5, 2); // 512 byte sector size
7317       outb(0x03f5, num_sectors); // number of sectors per track
7318       outb(0x03f5, 0); // Gap length
7319       outb(0x03f5, 0xf6); // Fill byte
7320       // turn on interrupts
7321   ASM_START
7322       sti
7323   ASM_END
7324       // wait on 40:3e bit 7 to become 1
7325       val8 = (read_byte(0x0000, 0x043e) & 0x80);
7326       while ( val8 == 0 ) {
7327         val8 = (read_byte(0x0000, 0x043e) & 0x80);
7328         }
7329      val8 = 0; // separate asm from while() loop
7330      // turn off interrupts
7331   ASM_START
7332       cli
7333   ASM_END
7334       // set 40:3e bit 7 to 0
7335       val8 = read_byte(0x0000, 0x043e);
7336       val8 &= 0x7f;
7337       write_byte(0x0000, 0x043e, val8);
7338       // check port 3f4 for accessibility to status bytes
7339       val8 = inb(0x3f4);
7340       if ( (val8 & 0xc0) != 0xc0 )
7341         BX_PANIC("int13_diskette: ctrl not ready\n");
7342
7343       // read 7 return status bytes from controller
7344       // using loop index broken, have to unroll...
7345       return_status[0] = inb(0x3f5);
7346       return_status[1] = inb(0x3f5);
7347       return_status[2] = inb(0x3f5);
7348       return_status[3] = inb(0x3f5);
7349       return_status[4] = inb(0x3f5);
7350       return_status[5] = inb(0x3f5);
7351       return_status[6] = inb(0x3f5);
7352       // record in BIOS Data Area
7353       write_byte(0x0040, 0x0042, return_status[0]);
7354       write_byte(0x0040, 0x0043, return_status[1]);
7355       write_byte(0x0040, 0x0044, return_status[2]);
7356       write_byte(0x0040, 0x0045, return_status[3]);
7357       write_byte(0x0040, 0x0046, return_status[4]);
7358       write_byte(0x0040, 0x0047, return_status[5]);
7359       write_byte(0x0040, 0x0048, return_status[6]);
7360
7361       if ( (return_status[0] & 0xc0) != 0 ) {
7362         if ( (return_status[1] & 0x02) != 0 ) {
7363           // diskette not writable.
7364           // AH=status code=0x03 (tried to write on write-protected disk)
7365           // AL=number of sectors written=0
7366           AX = 0x0300;
7367           SET_CF();
7368           return;
7369         } else {
7370           BX_PANIC("int13_diskette_function: write error\n");
7371         }
7372       }
7373
7374       SET_AH(0);
7375       set_diskette_ret_status(0);
7376       set_diskette_current_cyl(drive, 0);
7377       CLEAR_CF(); // successful
7378       return;
7379
7380
7381     case 0x08: // read diskette drive parameters
7382 BX_DEBUG_INT13_FL("floppy f08\n");
7383       drive = GET_ELDL();
7384
7385       if (drive > 1) {
7386         AX = 0;
7387         BX = 0;
7388         CX = 0;
7389         DX = 0;
7390         ES = 0;
7391         DI = 0;
7392         SET_DL(num_floppies);
7393         SET_CF();
7394         return;
7395         }
7396
7397       drive_type = inb_cmos(0x10);
7398       num_floppies = 0;
7399       if (drive_type & 0xf0)
7400         num_floppies++;
7401       if (drive_type & 0x0f)
7402         num_floppies++;
7403
7404       if (drive == 0)
7405         drive_type >>= 4;
7406       else
7407         drive_type &= 0x0f;
7408
7409       SET_BH(0);
7410       SET_BL(drive_type);
7411       SET_AH(0);
7412       SET_AL(0);
7413       SET_DL(num_floppies);
7414
7415       switch (drive_type) {
7416         case 0: // none
7417           CX = 0;
7418           SET_DH(0); // max head #
7419           break;
7420
7421         case 1: // 360KB, 5.25"
7422           CX = 0x2709; // 40 tracks, 9 sectors
7423           SET_DH(1); // max head #
7424           break;
7425
7426         case 2: // 1.2MB, 5.25"
7427           CX = 0x4f0f; // 80 tracks, 15 sectors
7428           SET_DH(1); // max head #
7429           break;
7430
7431         case 3: // 720KB, 3.5"
7432           CX = 0x4f09; // 80 tracks, 9 sectors
7433           SET_DH(1); // max head #
7434           break;
7435
7436         case 4: // 1.44MB, 3.5"
7437           CX = 0x4f12; // 80 tracks, 18 sectors
7438           SET_DH(1); // max head #
7439           break;
7440
7441         case 5: // 2.88MB, 3.5"
7442           CX = 0x4f24; // 80 tracks, 36 sectors
7443           SET_DH(1); // max head #
7444           break;
7445
7446         case 6: // 160k, 5.25"
7447           CX = 0x2708; // 40 tracks, 8 sectors
7448           SET_DH(0); // max head #
7449           break;
7450
7451         case 7: // 180k, 5.25"
7452           CX = 0x2709; // 40 tracks, 9 sectors
7453           SET_DH(0); // max head #
7454           break;
7455
7456         case 8: // 320k, 5.25"
7457           CX = 0x2708; // 40 tracks, 8 sectors
7458           SET_DH(1); // max head #
7459           break;
7460
7461         default: // ?
7462           BX_PANIC("floppy: int13: bad floppy type\n");
7463         }
7464
7465       /* set es & di to point to 11 byte diskette param table in ROM */
7466 ASM_START
7467       push bp
7468       mov  bp, sp
7469       mov ax, #diskette_param_table2
7470       mov _int13_diskette_function.DI+2[bp], ax
7471       mov _int13_diskette_function.ES+2[bp], cs
7472       pop  bp
7473 ASM_END
7474       CLEAR_CF(); // success
7475       /* disk status not changed upon success */
7476       return;
7477
7478
7479     case 0x15: // read diskette drive type
7480 BX_DEBUG_INT13_FL("floppy f15\n");
7481       drive = GET_ELDL();
7482       if (drive > 1) {
7483         SET_AH(0); // only 2 drives supported
7484         // set_diskette_ret_status here ???
7485         SET_CF();
7486         return;
7487         }
7488       drive_type = inb_cmos(0x10);
7489
7490       if (drive == 0)
7491         drive_type >>= 4;
7492       else
7493         drive_type &= 0x0f;
7494       CLEAR_CF(); // successful, not present
7495       if (drive_type==0) {
7496         SET_AH(0); // drive not present
7497         }
7498       else {
7499         SET_AH(1); // drive present, does not support change line
7500         }
7501
7502       return;
7503
7504     case 0x16: // get diskette change line status
7505 BX_DEBUG_INT13_FL("floppy f16\n");
7506       drive = GET_ELDL();
7507       if (drive > 1) {
7508         SET_AH(0x01); // invalid drive
7509         set_diskette_ret_status(0x01);
7510         SET_CF();
7511         return;
7512         }
7513
7514       SET_AH(0x06); // change line not supported
7515       set_diskette_ret_status(0x06);
7516       SET_CF();
7517       return;
7518
7519     case 0x17: // set diskette type for format(old)
7520 BX_DEBUG_INT13_FL("floppy f17\n");
7521       /* not used for 1.44M floppies */
7522       SET_AH(0x01); // not supported
7523       set_diskette_ret_status(1); /* not supported */
7524       SET_CF();
7525       return;
7526
7527     case 0x18: // set diskette type for format(new)
7528 BX_DEBUG_INT13_FL("floppy f18\n");
7529       SET_AH(0x01); // do later
7530       set_diskette_ret_status(1);
7531       SET_CF();
7532       return;
7533
7534     default:
7535         BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
7536
7537       // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
7538         SET_AH(0x01); // ???
7539         set_diskette_ret_status(1);
7540         SET_CF();
7541         return;
7542       //   }
7543     }
7544 }
7545 #else  // #if BX_SUPPORT_FLOPPY
7546   void
7547 int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
7548   Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
7549 {
7550   Bit8u  val8;
7551
7552   switch ( GET_AH() ) {
7553
7554     case 0x01: // Read Diskette Status
7555       CLEAR_CF();
7556       val8 = read_byte(0x0000, 0x0441);
7557       SET_AH(val8);
7558       if (val8) {
7559         SET_CF();
7560         }
7561       return;
7562
7563     default:
7564       SET_CF();
7565       write_byte(0x0000, 0x0441, 0x01);
7566       SET_AH(0x01);
7567     }
7568 }
7569 #endif  // #if BX_SUPPORT_FLOPPY
7570
7571  void
7572 set_diskette_ret_status(value)
7573   Bit8u value;
7574 {
7575   write_byte(0x0040, 0x0041, value);
7576 }
7577
7578   void
7579 set_diskette_current_cyl(drive, cyl)
7580   Bit8u drive;
7581   Bit8u cyl;
7582 {
7583   if (drive > 1)
7584     BX_PANIC("set_diskette_current_cyl(): drive > 1\n");
7585   write_byte(0x0040, 0x0094+drive, cyl);
7586 }
7587
7588   void
7589 determine_floppy_media(drive)
7590   Bit16u drive;
7591 {
7592 #if 0
7593   Bit8u  val8, DOR, ctrl_info;
7594
7595   ctrl_info = read_byte(0x0040, 0x008F);
7596   if (drive==1)
7597     ctrl_info >>= 4;
7598   else
7599     ctrl_info &= 0x0f;
7600
7601 #if 0
7602   if (drive == 0) {
7603     DOR = 0x1c; // DOR: drive0 motor on, DMA&int enabled, normal op, drive select 0
7604     }
7605   else {
7606     DOR = 0x2d; // DOR: drive1 motor on, DMA&int enabled, normal op, drive select 1
7607     }
7608 #endif
7609
7610   if ( (ctrl_info & 0x04) != 0x04 ) {
7611     // Drive not determined means no drive exists, done.
7612     return;
7613     }
7614
7615 #if 0
7616   // check Main Status Register for readiness
7617   val8 = inb(0x03f4) & 0x80; // Main Status Register
7618   if (val8 != 0x80)
7619     BX_PANIC("d_f_m: MRQ bit not set\n");
7620
7621   // change line
7622
7623   // existing BDA values
7624
7625   // turn on drive motor
7626   outb(0x03f2, DOR); // Digital Output Register
7627   //
7628 #endif
7629   BX_PANIC("d_f_m: OK so far\n");
7630 #endif
7631 }
7632
7633   void
7634 int17_function(regs, ds, iret_addr)
7635   pusha_regs_t regs; // regs pushed from PUSHA instruction
7636   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7637   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
7638 {
7639   Bit16u addr,timeout;
7640   Bit8u val8;
7641
7642   ASM_START
7643   sti
7644   ASM_END
7645
7646   addr = read_word(0x0040, (regs.u.r16.dx << 1) + 8);
7647   if ((regs.u.r8.ah < 3) && (regs.u.r16.dx < 3) && (addr > 0)) {
7648     timeout = read_byte(0x0040, 0x0078 + regs.u.r16.dx) << 8;
7649     if (regs.u.r8.ah == 0) {
7650       outb(addr, regs.u.r8.al);
7651       val8 = inb(addr+2);
7652       outb(addr+2, val8 | 0x01); // send strobe
7653       ASM_START
7654       nop
7655       ASM_END
7656       outb(addr+2, val8 & ~0x01);
7657       while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) {
7658         timeout--;
7659       }
7660     }
7661     if (regs.u.r8.ah == 1) {
7662       val8 = inb(addr+2);
7663       outb(addr+2, val8 & ~0x04); // send init
7664       ASM_START
7665       nop
7666       ASM_END
7667       outb(addr+2, val8 | 0x04);
7668     }
7669     val8 = inb(addr+1);
7670     regs.u.r8.ah = (val8 ^ 0x48);
7671     if (!timeout) regs.u.r8.ah |= 0x01;
7672     ClearCF(iret_addr.flags);
7673   } else {
7674     SetCF(iret_addr.flags); // Unsupported
7675   }
7676 }
7677
7678 // returns bootsegment in ax, drive in bl
7679   Bit32u 
7680 int19_function(bseqnr)
7681 Bit8u bseqnr;
7682 {
7683   Bit16u ebda_seg=read_word(0x0040,0x000E);
7684   Bit16u bootseq;
7685   Bit8u  bootdrv;
7686   Bit8u  bootcd;
7687   Bit8u  bootchk;
7688   Bit16u bootseg;
7689   Bit16u status;
7690   Bit8u  lastdrive=0;
7691  
7692   //  BX_DEBUG("rombios: int19 (%d)\n",bseqnr);
7693
7694   // if BX_ELTORITO_BOOT is not defined, old behavior
7695   //   check bit 5 in CMOS reg 0x2d.  load either 0x00 or 0x80 into DL
7696   //   in preparation for the intial INT 13h (0=floppy A:, 0x80=C:)
7697   //     0: system boot sequence, first drive C: then A:
7698   //     1: system boot sequence, first drive A: then C:
7699   // else BX_ELTORITO_BOOT is defined
7700   //   CMOS regs 0x3D and 0x38 contain the boot sequence:
7701   //     CMOS reg 0x3D & 0x0f : 1st boot device
7702   //     CMOS reg 0x3D & 0xf0 : 2nd boot device
7703   //     CMOS reg 0x38 & 0xf0 : 3rd boot device
7704   //   boot device codes:
7705   //     0x00 : not defined
7706   //     0x01 : first floppy 
7707   //     0x02 : first harddrive
7708   //     0x03 : first cdrom
7709   //     else : boot failure
7710
7711   // Get the boot sequence
7712 #if BX_ELTORITO_BOOT
7713   bootseq=inb_cmos(0x3d);
7714   bootseq|=((inb_cmos(0x38) & 0xf0) << 4);
7715
7716   if (bseqnr==2) bootseq >>= 4;
7717   if (bseqnr==3) bootseq >>= 8;
7718   if (bootseq<0x10) lastdrive = 1;
7719   bootdrv=0x00; bootcd=0;
7720   switch(bootseq & 0x0f) {
7721     case 0x01: bootdrv=0x00; bootcd=0; break;
7722     case 0x02: bootdrv=0x80; bootcd=0; break;
7723     case 0x03: bootdrv=0x00; bootcd=1; break;
7724     default:   return 0x00000000;
7725     }
7726 #else
7727   bootseq=inb_cmos(0x2d);
7728
7729   if (bseqnr==2) {
7730     bootseq ^= 0x20;
7731     lastdrive = 1;
7732   }
7733   bootdrv=0x00; bootcd=0;
7734   if((bootseq&0x20)==0) bootdrv=0x80;
7735 #endif // BX_ELTORITO_BOOT
7736
7737 #if BX_ELTORITO_BOOT
7738   // We have to boot from cd
7739   if (bootcd != 0) {
7740     status = cdrom_boot();
7741
7742     BX_DEBUG("CDBoot:%x\n",status);
7743         
7744
7745     // If failure
7746     if ( (status & 0x00ff) !=0 ) {
7747       print_cdromboot_failure(status);
7748       print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7749       return 0x00000000;
7750     }
7751     
7752     bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
7753     bootdrv = (Bit8u)(status>>8);
7754   }
7755
7756 #endif // BX_ELTORITO_BOOT
7757
7758   // We have to boot from harddisk or floppy
7759   if (bootcd == 0) {
7760     bootseg=0x07c0;
7761
7762     
7763
7764 ASM_START
7765     push bp
7766     mov  bp, sp
7767
7768     mov  ax, #0x0000
7769     mov  _int19_function.status + 2[bp], ax
7770     mov  dl, _int19_function.bootdrv + 2[bp]
7771     mov  ax, _int19_function.bootseg + 2[bp]
7772     mov  es, ax         ;; segment
7773     mov  bx, #0x0000    ;; offset
7774     mov  ah, #0x02      ;; function 2, read diskette sector
7775     mov  al, #0x01      ;; read 1 sector
7776     mov  ch, #0x00      ;; track 0
7777     mov  cl, #0x01      ;; sector 1
7778     mov  dh, #0x00      ;; head 0
7779     int  #0x13          ;; read sector
7780     jnc  int19_load_done
7781     mov  ax, #0x0001
7782     mov  _int19_function.status + 2[bp], ax
7783
7784 int19_load_done:
7785     pop  bp
7786 ASM_END
7787     
7788
7789     if (status != 0) {
7790       print_boot_failure(bootcd, bootdrv, 1, lastdrive);
7791       return 0x00000000;
7792       }
7793     }
7794
7795   // check signature if instructed by cmos reg 0x38, only for floppy
7796   // bootchk = 1 : signature check disabled
7797   // bootchk = 0 : signature check enabled
7798   if (bootdrv != 0) bootchk = 0;
7799   else bootchk = inb_cmos(0x38) & 0x01;
7800
7801 #if BX_ELTORITO_BOOT
7802   // if boot from cd, no signature check
7803   if (bootcd != 0)
7804     bootchk = 1;
7805 #endif // BX_ELTORITO_BOOT
7806
7807   if (bootchk == 0) {
7808     if (read_word(bootseg,0x1fe) != 0xaa55) {
7809       print_boot_failure(bootcd, bootdrv, 0, lastdrive);
7810       return 0x00000000;
7811       }
7812     }
7813   
7814 #if BX_ELTORITO_BOOT
7815   // Print out the boot string
7816   BX_DEBUG("cdrom_boot: %x\n",status);
7817   print_boot_device(bootcd, bootdrv);
7818 #else // BX_ELTORITO_BOOT
7819   print_boot_device(0, bootdrv);
7820 #endif // BX_ELTORITO_BOOT
7821
7822   BX_DEBUG("boot to %x\n", (((Bit32u)bootdrv) << 16) + bootseg);
7823
7824   // return the boot segment
7825   return (((Bit32u)bootdrv) << 16) + bootseg;
7826 }
7827
7828   void
7829 int1a_function(regs, ds, iret_addr)
7830   pusha_regs_t regs; // regs pushed from PUSHA instruction
7831   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
7832   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
7833 {
7834   Bit8u val8;
7835
7836   BX_DEBUG_INT1A("int1a: AX=%04x BX=%04x CX=%04x DX=%04x DS=%04x\n", regs.u.r16.ax, regs.u.r16.bx, regs.u.r16.cx, regs.u.r16.dx, ds);
7837
7838   ASM_START
7839   sti
7840   ASM_END
7841
7842   switch (regs.u.r8.ah) {
7843     case 0: // get current clock count
7844       ASM_START
7845       cli
7846       ASM_END
7847       regs.u.r16.cx = BiosData->ticks_high;
7848       regs.u.r16.dx = BiosData->ticks_low;
7849       regs.u.r8.al  = BiosData->midnight_flag;
7850       BiosData->midnight_flag = 0; // reset flag
7851       ASM_START
7852       sti
7853       ASM_END
7854       // AH already 0
7855       ClearCF(iret_addr.flags); // OK
7856       break;
7857
7858     case 1: // Set Current Clock Count
7859       ASM_START
7860       cli
7861       ASM_END
7862       BiosData->ticks_high = regs.u.r16.cx;
7863       BiosData->ticks_low  = regs.u.r16.dx;
7864       BiosData->midnight_flag = 0; // reset flag
7865       ASM_START
7866       sti
7867       ASM_END
7868       regs.u.r8.ah = 0;
7869       ClearCF(iret_addr.flags); // OK
7870       break;
7871
7872
7873     case 2: // Read CMOS Time
7874       if (rtc_updating()) {
7875         SetCF(iret_addr.flags);
7876         break;
7877         }
7878
7879       regs.u.r8.dh = inb_cmos(0x00); // Seconds
7880       regs.u.r8.cl = inb_cmos(0x02); // Minutes
7881       regs.u.r8.ch = inb_cmos(0x04); // Hours
7882       regs.u.r8.dl = inb_cmos(0x0b) & 0x01; // Stat Reg B
7883       regs.u.r8.ah = 0;
7884       regs.u.r8.al = regs.u.r8.ch;
7885       ClearCF(iret_addr.flags); // OK
7886       break;
7887
7888     case 3: // Set CMOS Time
7889       // Using a debugger, I notice the following masking/setting
7890       // of bits in Status Register B, by setting Reg B to
7891       // a few values and getting its value after INT 1A was called.
7892       //
7893       //        try#1       try#2       try#3
7894       // before 1111 1101   0111 1101   0000 0000
7895       // after  0110 0010   0110 0010   0000 0010
7896       //
7897       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7898       // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
7899       if (rtc_updating()) {
7900         init_rtc();
7901         // fall through as if an update were not in progress
7902         }
7903       outb_cmos(0x00, regs.u.r8.dh); // Seconds
7904       outb_cmos(0x02, regs.u.r8.cl); // Minutes
7905       outb_cmos(0x04, regs.u.r8.ch); // Hours
7906       // Set Daylight Savings time enabled bit to requested value
7907       val8 = (inb_cmos(0x0b) & 0x60) | 0x02 | (regs.u.r8.dl & 0x01);
7908       // (reg B already selected)
7909       outb_cmos(0x0b, val8);
7910       regs.u.r8.ah = 0;
7911       regs.u.r8.al = val8; // val last written to Reg B
7912       ClearCF(iret_addr.flags); // OK
7913       break;
7914
7915     case 4: // Read CMOS Date
7916       regs.u.r8.ah = 0;
7917       if (rtc_updating()) {
7918         SetCF(iret_addr.flags);
7919         break;
7920         }
7921       regs.u.r8.cl = inb_cmos(0x09); // Year
7922       regs.u.r8.dh = inb_cmos(0x08); // Month
7923       regs.u.r8.dl = inb_cmos(0x07); // Day of Month
7924       regs.u.r8.ch = inb_cmos(0x32); // Century
7925       regs.u.r8.al = regs.u.r8.ch;
7926       ClearCF(iret_addr.flags); // OK
7927       break;
7928
7929     case 5: // Set CMOS Date
7930       // Using a debugger, I notice the following masking/setting
7931       // of bits in Status Register B, by setting Reg B to
7932       // a few values and getting its value after INT 1A was called.
7933       //
7934       //        try#1       try#2       try#3       try#4
7935       // before 1111 1101   0111 1101   0000 0010   0000 0000
7936       // after  0110 1101   0111 1101   0000 0010   0000 0000
7937       //
7938       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7939       // My assumption: RegB = (RegB & 01111111b)
7940       if (rtc_updating()) {
7941         init_rtc();
7942         SetCF(iret_addr.flags);
7943         break;
7944         }
7945       outb_cmos(0x09, regs.u.r8.cl); // Year
7946       outb_cmos(0x08, regs.u.r8.dh); // Month
7947       outb_cmos(0x07, regs.u.r8.dl); // Day of Month
7948       outb_cmos(0x32, regs.u.r8.ch); // Century
7949       val8 = inb_cmos(0x0b) & 0x7f; // clear halt-clock bit
7950       outb_cmos(0x0b, val8);
7951       regs.u.r8.ah = 0;
7952       regs.u.r8.al = val8; // AL = val last written to Reg B
7953       ClearCF(iret_addr.flags); // OK
7954       break;
7955
7956     case 6: // Set Alarm Time in CMOS
7957       // Using a debugger, I notice the following masking/setting
7958       // of bits in Status Register B, by setting Reg B to
7959       // a few values and getting its value after INT 1A was called.
7960       //
7961       //        try#1       try#2       try#3
7962       // before 1101 1111   0101 1111   0000 0000
7963       // after  0110 1111   0111 1111   0010 0000
7964       //
7965       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7966       // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
7967       val8 = inb_cmos(0x0b); // Get Status Reg B
7968       regs.u.r16.ax = 0;
7969       if (val8 & 0x20) {
7970         // Alarm interrupt enabled already
7971         SetCF(iret_addr.flags); // Error: alarm in use
7972         break;
7973         }
7974       if (rtc_updating()) {
7975         init_rtc();
7976         // fall through as if an update were not in progress
7977         }
7978       outb_cmos(0x01, regs.u.r8.dh); // Seconds alarm
7979       outb_cmos(0x03, regs.u.r8.cl); // Minutes alarm
7980       outb_cmos(0x05, regs.u.r8.ch); // Hours alarm
7981       outb(0xa1, inb(0xa1) & 0xfe); // enable IRQ 8
7982       // enable Status Reg B alarm bit, clear halt clock bit
7983       outb_cmos(0x0b, (val8 & 0x7f) | 0x20);
7984       ClearCF(iret_addr.flags); // OK
7985       break;
7986
7987     case 7: // Turn off Alarm
7988       // Using a debugger, I notice the following masking/setting
7989       // of bits in Status Register B, by setting Reg B to
7990       // a few values and getting its value after INT 1A was called.
7991       //
7992       //        try#1       try#2       try#3       try#4
7993       // before 1111 1101   0111 1101   0010 0000   0010 0010
7994       // after  0100 0101   0101 0101   0000 0000   0000 0010
7995       //
7996       // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
7997       // My assumption: RegB = (RegB & 01010111b)
7998       val8 = inb_cmos(0x0b); // Get Status Reg B
7999       // clear clock-halt bit, disable alarm bit
8000       outb_cmos(0x0b, val8 & 0x57); // disable alarm bit
8001       regs.u.r8.ah = 0;
8002       regs.u.r8.al = val8; // val last written to Reg B
8003       ClearCF(iret_addr.flags); // OK
8004       break;
8005 #if BX_PCIBIOS
8006     case 0xb1:
8007       // real mode PCI BIOS functions now handled in assembler code
8008       // this C code handles the error code for information only
8009       if (regs.u.r8.bl == 0xff) {
8010         BX_INFO("PCI BIOS: PCI not present\n");
8011       } else if (regs.u.r8.bl == 0x81) {
8012         BX_INFO("unsupported PCI BIOS function 0x%02x\n", regs.u.r8.al);
8013       } else if (regs.u.r8.bl == 0x83) {
8014         BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx);
8015       } else if (regs.u.r8.bl == 0x86) {
8016         BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx);
8017       }
8018       regs.u.r8.ah = regs.u.r8.bl;
8019       SetCF(iret_addr.flags);
8020       break;
8021 #endif
8022
8023     default:
8024       SetCF(iret_addr.flags); // Unsupported
8025     }
8026 }
8027
8028   void
8029 int70_function(regs, ds, iret_addr)
8030   pusha_regs_t regs; // regs pushed from PUSHA instruction
8031   Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
8032   iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
8033 {
8034   // INT 70h: IRQ 8 - CMOS RTC interrupt from periodic or alarm modes
8035   Bit8u registerB = 0, registerC = 0;
8036
8037   // Check which modes are enabled and have occurred.
8038   registerB = inb_cmos( 0xB );
8039   registerC = inb_cmos( 0xC );
8040
8041   if( ( registerB & 0x60 ) != 0 ) {
8042     if( ( registerC & 0x20 ) != 0 ) {
8043       // Handle Alarm Interrupt.
8044 ASM_START
8045       sti
8046       int #0x4a
8047       cli
8048 ASM_END
8049     }
8050     if( ( registerC & 0x40 ) != 0 ) {
8051       // Handle Periodic Interrupt.
8052
8053       if( read_byte( 0x40, 0xA0 ) != 0 ) {
8054         // Wait Interval (Int 15, AH=83) active.
8055         Bit32u time, toggle;
8056
8057         time = read_dword( 0x40, 0x9C );  // Time left in microseconds.
8058         if( time < 0x3D1 ) {
8059           // Done waiting.
8060           Bit16u segment, offset;
8061
8062           offset = read_word( 0x40, 0x98 );
8063           segment = read_word( 0x40, 0x9A );
8064           write_byte( 0x40, 0xA0, 0 );  // Turn of status byte.
8065           outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt.
8066           write_byte( segment, offset, 0x80 );  // Write to specified flag byte.
8067         } else {
8068           // Continue waiting.
8069           time -= 0x3D1;
8070           write_dword( 0x40, 0x9C, time );
8071         }
8072       }
8073     }
8074   }
8075
8076 ASM_START
8077   call eoi_both_pics
8078 ASM_END
8079 }
8080
8081
8082 ASM_START
8083 ;------------------------------------------
8084 ;- INT74h : PS/2 mouse hardware interrupt -
8085 ;------------------------------------------
8086 int74_handler:
8087   sti
8088   pusha
8089   push ds         ;; save DS
8090   push #0x00 ;; placeholder for status
8091   push #0x00 ;; placeholder for X
8092   push #0x00 ;; placeholder for Y
8093   push #0x00 ;; placeholder for Z
8094   push #0x00 ;; placeholder for make_far_call boolean
8095   call _int74_function
8096   pop  cx      ;; remove make_far_call from stack
8097   jcxz int74_done
8098
8099   ;; make far call to EBDA:0022
8100   push #0x00
8101   pop ds
8102   push 0x040E     ;; push 0000:040E (opcodes 0xff, 0x36, 0x0E, 0x04)
8103   pop ds
8104   //CALL_EP(0x0022) ;; call far routine (call_Ep DS:0022 :opcodes 0xff, 0x1e, 0x22, 0x00)
8105   call far ptr[0x22]
8106 int74_done:
8107   cli
8108   call eoi_both_pics
8109   add sp, #8     ;; pop status, x, y, z
8110
8111   pop ds          ;; restore DS
8112   popa
8113   iret
8114
8115
8116 ;; This will perform an IRET, but will retain value of current CF
8117 ;; by altering flags on stack.  Better than RETF #02.
8118 iret_modify_cf:
8119   jc   carry_set
8120   push bp
8121   mov  bp, sp
8122   and  BYTE [bp + 0x06], #0xfe
8123   pop  bp
8124   iret
8125 carry_set:
8126   push bp
8127   mov  bp, sp
8128   or   BYTE [bp + 0x06], #0x01
8129   pop  bp
8130   iret
8131
8132
8133 ;----------------------
8134 ;- INT13h (relocated) -
8135 ;----------------------
8136 ;
8137 ; int13_relocated is a little bit messed up since I played with it
8138 ; I have to rewrite it:
8139 ;   - call a function that detect which function to call
8140 ;   - make all called C function get the same parameters list
8141 ;
8142 int13_relocated:
8143
8144 #if BX_ELTORITO_BOOT
8145   ;; check for an eltorito function
8146   cmp   ah,#0x4a
8147   jb    int13_not_eltorito
8148   cmp   ah,#0x4d
8149   ja    int13_not_eltorito
8150
8151   pusha
8152   push  es
8153   push  ds
8154   push  ss
8155   pop   ds
8156
8157   push  #int13_out
8158   jmp   _int13_eltorito      ;; ELDX not used
8159
8160 int13_not_eltorito:
8161   push  ax
8162   push  bx
8163   push  cx
8164   push  dx
8165
8166   ;; check if emulation active
8167   call  _cdemu_isactive
8168   cmp   al,#0x00
8169   je    int13_cdemu_inactive
8170
8171   ;; check if access to the emulated drive
8172   call  _cdemu_emulated_drive
8173   pop   dx
8174   push  dx
8175   cmp   al,dl                ;; int13 on emulated drive
8176   jne   int13_nocdemu
8177
8178   pop   dx
8179   pop   cx
8180   pop   bx
8181   pop   ax
8182
8183   pusha
8184   push  es
8185   push  ds
8186   push  ss
8187   pop   ds
8188
8189   push  #int13_out
8190   jmp   _int13_cdemu         ;; ELDX not used
8191
8192 int13_nocdemu:
8193   and   dl,#0xE0             ;; mask to get device class, including cdroms
8194   cmp   al,dl                ;; al is 0x00 or 0x80
8195   jne   int13_cdemu_inactive ;; inactive for device class
8196
8197   pop   dx
8198   pop   cx
8199   pop   bx
8200   pop   ax
8201
8202   push  ax
8203   push  cx
8204   push  dx
8205   push  bx
8206
8207   dec   dl                   ;; real drive is dl - 1
8208   jmp   int13_legacy
8209
8210 int13_cdemu_inactive:
8211   pop   dx
8212   pop   cx
8213   pop   bx
8214   pop   ax
8215
8216 #endif // BX_ELTORITO_BOOT
8217
8218 int13_noeltorito:
8219
8220   push  ax
8221   push  cx
8222   push  dx
8223   push  bx
8224
8225 int13_legacy:
8226
8227   push  dx                   ;; push eltorito value of dx instead of sp
8228
8229   push  bp
8230   push  si
8231   push  di
8232
8233   push  es
8234   push  ds
8235   push  ss
8236   pop   ds
8237
8238   ;; now the 16-bit registers can be restored with:
8239   ;; pop ds; pop es; popa; iret
8240   ;; arguments passed to functions should be
8241   ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
8242
8243   test  dl, #0x80
8244   jnz   int13_notfloppy
8245
8246   push #int13_out
8247   jmp _int13_diskette_function
8248
8249 int13_notfloppy:
8250
8251 #if BX_USE_ATADRV
8252
8253   cmp   dl, #0xE0
8254   jb    int13_notcdrom
8255
8256   // ebx is modified: BSD 5.2.1 boot loader problem
8257   // someone should figure out which 32 bit register that actually are used
8258
8259   shr   ebx, #16
8260   push  bx
8261
8262   call  _int13_cdrom
8263
8264   pop   bx
8265   shl   ebx, #16
8266
8267   jmp int13_out
8268
8269 int13_notcdrom:
8270
8271 #endif
8272
8273 int13_disk:
8274   call  _int13_harddisk
8275
8276 int13_out:
8277   pop ds
8278   pop es
8279   popa
8280   iret 
8281
8282
8283 ;----------
8284 ;- INT18h -
8285 ;----------
8286 int18_handler: ;; Boot Failure routing
8287   call _int18_panic_msg
8288   hlt
8289   iret
8290
8291 ;----------
8292 ;- INT19h -
8293 ;----------
8294 int19_relocated: ;; Boot function, relocated
8295
8296   ;; int19 was beginning to be really complex, so now it
8297   ;; just calls an C function, that does the work
8298   ;; it returns in BL the boot drive, and in AX the boot segment
8299   ;; the boot segment will be 0x0000 if something has failed
8300
8301   push bp
8302   mov  bp, sp
8303
8304   ;; drop ds
8305   xor  ax, ax
8306   mov  ds, ax
8307
8308   ;; 1st boot device
8309   mov  ax, #0x0001
8310   push ax
8311   call _int19_function
8312   inc  sp
8313   inc  sp
8314   ;; bl contains the boot drive
8315   ;; ax contains the boot segment or 0 if failure
8316
8317   test       ax, ax  ;; if ax is 0 try next boot device
8318   jnz        boot_setup
8319
8320   ;; 2nd boot device
8321   mov  ax, #0x0002
8322   push ax
8323   call _int19_function
8324   inc  sp
8325   inc  sp
8326   test       ax, ax  ;; if ax is 0 try next boot device
8327   jnz        boot_setup
8328
8329   ;; 3rd boot device
8330   mov  ax, #0x0003
8331   push ax
8332   call _int19_function
8333   inc  sp
8334   inc  sp
8335   test       ax, ax  ;; if ax is 0 call int18
8336   jz         int18_handler
8337
8338 boot_setup:
8339   mov dl,    bl      ;; set drive so guest os find it
8340   shl eax,   #0x04   ;; convert seg to ip
8341   mov 2[bp], ax      ;; set ip
8342
8343   shr eax,   #0x04   ;; get cs back
8344   and ax,    #0xF000 ;; remove what went in ip
8345   mov 4[bp], ax      ;; set cs
8346   xor ax,    ax
8347   mov es,    ax      ;; set es to zero fixes [ 549815 ]
8348   mov [bp],  ax      ;; set bp to zero
8349   mov ax,    #0xaa55 ;; set ok flag
8350
8351
8352   pop bp
8353
8354   iret               ;; Beam me up Scotty
8355
8356 ;----------
8357 ;- INT1Ch -
8358 ;----------
8359 int1c_handler: ;; User Timer Tick
8360   iret
8361
8362
8363 ;----------------------
8364 ;- POST: Floppy Drive -
8365 ;----------------------
8366 floppy_drive_post:
8367   mov  ax, #0x0000
8368   mov  ds, ax
8369
8370   mov  al, #0x00
8371   mov  0x043e, al ;; drive 0 & 1 uncalibrated, no interrupt has occurred
8372
8373   mov  0x043f, al  ;; diskette motor status: read op, drive0, motors off
8374
8375   mov  0x0440, al  ;; diskette motor timeout counter: not active
8376   mov  0x0441, al  ;; diskette controller status return code
8377
8378   mov  0x0442, al  ;; disk & diskette controller status register 0
8379   mov  0x0443, al  ;; diskette controller status register 1
8380   mov  0x0444, al  ;; diskette controller status register 2
8381   mov  0x0445, al  ;; diskette controller cylinder number
8382   mov  0x0446, al  ;; diskette controller head number
8383   mov  0x0447, al  ;; diskette controller sector number
8384   mov  0x0448, al  ;; diskette controller bytes written
8385
8386   mov  0x048b, al  ;; diskette configuration data
8387
8388   ;; -----------------------------------------------------------------
8389   ;; (048F) diskette controller information
8390   ;;
8391   mov  al, #0x10   ;; get CMOS diskette drive type
8392   out  0x70, AL
8393   in   AL, 0x71
8394   mov  ah, al      ;; save byte to AH
8395
8396 look_drive0:
8397   shr  al, #4      ;; look at top 4 bits for drive 0
8398   jz   f0_missing  ;; jump if no drive0
8399   mov  bl, #0x07   ;; drive0 determined, multi-rate, has changed line
8400   jmp  look_drive1
8401 f0_missing:
8402   mov  bl, #0x00   ;; no drive0
8403
8404 look_drive1:
8405   mov  al, ah      ;; restore from AH
8406   and  al, #0x0f   ;; look at bottom 4 bits for drive 1
8407   jz   f1_missing  ;; jump if no drive1
8408   or   bl, #0x70   ;; drive1 determined, multi-rate, has changed line
8409 f1_missing:
8410                    ;; leave high bits in BL zerod
8411   mov  0x048f, bl  ;; put new val in BDA (diskette controller information)
8412   ;; -----------------------------------------------------------------
8413
8414   mov  al, #0x00
8415   mov  0x0490, al  ;; diskette 0 media state
8416   mov  0x0491, al  ;; diskette 1 media state
8417
8418                    ;; diskette 0,1 operational starting state
8419                    ;; drive type has not been determined,
8420                    ;; has no changed detection line
8421   mov  0x0492, al
8422   mov  0x0493, al
8423
8424   mov  0x0494, al  ;; diskette 0 current cylinder
8425   mov  0x0495, al  ;; diskette 1 current cylinder
8426
8427   mov  al, #0x02
8428   out  #0x0a, al   ;; clear DMA-1 channel 2 mask bit
8429
8430   SET_INT_VECTOR(0x1E, #0xF000, #diskette_param_table2)
8431   SET_INT_VECTOR(0x40, #0xF000, #int13_diskette)
8432   SET_INT_VECTOR(0x0E, #0xF000, #int0e_handler) ;; IRQ 6
8433
8434   ret
8435
8436
8437 ;--------------------
8438 ;- POST: HARD DRIVE -
8439 ;--------------------
8440 ; relocated here because the primary POST area isnt big enough.
8441 hard_drive_post:
8442   // IRQ 14 = INT 76h
8443   // INT 76h calls INT 15h function ax=9100
8444
8445   mov  al, #0x0a   ; 0000 1010 = reserved, disable IRQ 14
8446   mov  dx, #0x03f6
8447   out  dx, al
8448
8449   mov  ax, #0x0000
8450   mov  ds, ax
8451   mov  0x0474, al /* hard disk status of last operation */
8452   mov  0x0477, al /* hard disk port offset (XT only ???) */
8453   mov  0x048c, al /* hard disk status register */
8454   mov  0x048d, al /* hard disk error register */
8455   mov  0x048e, al /* hard disk task complete flag */
8456   mov  al, #0x01
8457   mov  0x0475, al /* hard disk number attached */
8458   mov  al, #0xc0
8459   mov  0x0476, al /* hard disk control byte */
8460   SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
8461   SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
8462   ;; INT 41h: hard disk 0 configuration pointer
8463   ;; INT 46h: hard disk 1 configuration pointer
8464   SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D)
8465   SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D)
8466
8467   ;; move disk geometry data from CMOS to EBDA disk parameter table(s)
8468   mov  al, #0x12
8469   out  #0x70, al
8470   in   al, #0x71
8471   and  al, #0xf0
8472   cmp  al, #0xf0
8473   je   post_d0_extended
8474   jmp check_for_hd1
8475 post_d0_extended:
8476   mov  al, #0x19
8477   out  #0x70, al
8478   in   al, #0x71
8479   cmp  al, #47  ;; decimal 47 - user definable
8480   je   post_d0_type47
8481   HALT(__LINE__)
8482 post_d0_type47:
8483   ;; CMOS  purpose                  param table offset
8484   ;; 1b    cylinders low            0
8485   ;; 1c    cylinders high           1
8486   ;; 1d    heads                    2
8487   ;; 1e    write pre-comp low       5
8488   ;; 1f    write pre-comp high      6
8489   ;; 20    retries/bad map/heads>8  8
8490   ;; 21    landing zone low         C
8491   ;; 22    landing zone high        D
8492   ;; 23    sectors/track            E
8493
8494   mov  ax, #EBDA_SEG
8495   mov  ds, ax
8496
8497   ;;; Filling EBDA table for hard disk 0.
8498   mov  al, #0x1f
8499   out  #0x70, al
8500   in   al, #0x71
8501   mov  ah, al
8502   mov  al, #0x1e
8503   out  #0x70, al
8504   in   al, #0x71
8505   mov   (0x003d + 0x05), ax ;; write precomp word
8506
8507   mov  al, #0x20
8508   out  #0x70, al
8509   in   al, #0x71
8510   mov   (0x003d + 0x08), al ;; drive control byte
8511
8512   mov  al, #0x22
8513   out  #0x70, al
8514   in   al, #0x71
8515   mov  ah, al
8516   mov  al, #0x21
8517   out  #0x70, al
8518   in   al, #0x71
8519   mov   (0x003d + 0x0C), ax ;; landing zone word
8520
8521   mov  al, #0x1c   ;; get cylinders word in AX
8522   out  #0x70, al
8523   in   al, #0x71   ;; high byte
8524   mov  ah, al
8525   mov  al, #0x1b
8526   out  #0x70, al
8527   in   al, #0x71   ;; low byte
8528   mov  bx, ax      ;; BX = cylinders
8529
8530   mov  al, #0x1d
8531   out  #0x70, al
8532   in   al, #0x71
8533   mov  cl, al      ;; CL = heads
8534
8535   mov  al, #0x23
8536   out  #0x70, al
8537   in   al, #0x71
8538   mov  dl, al      ;; DL = sectors
8539
8540   cmp  bx, #1024
8541   jnbe hd0_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8542
8543 hd0_post_physical_chs:
8544   ;; no logical CHS mapping used, just physical CHS
8545   ;; use Standard Fixed Disk Parameter Table (FDPT)
8546   mov   (0x003d + 0x00), bx ;; number of physical cylinders
8547   mov   (0x003d + 0x02), cl ;; number of physical heads
8548   mov   (0x003d + 0x0E), dl ;; number of physical sectors
8549   jmp check_for_hd1
8550
8551 hd0_post_logical_chs:
8552   ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8553   mov   (0x003d + 0x09), bx ;; number of physical cylinders
8554   mov   (0x003d + 0x0b), cl ;; number of physical heads
8555   mov   (0x003d + 0x04), dl ;; number of physical sectors
8556   mov   (0x003d + 0x0e), dl ;; number of logical sectors (same)
8557   mov al, #0xa0
8558   mov   (0x003d + 0x03), al ;; A0h signature, indicates translated table
8559
8560   cmp bx, #2048
8561   jnbe hd0_post_above_2048
8562   ;; 1024 < c <= 2048 cylinders
8563   shr bx, #0x01
8564   shl cl, #0x01
8565   jmp hd0_post_store_logical
8566
8567 hd0_post_above_2048:
8568   cmp bx, #4096
8569   jnbe hd0_post_above_4096
8570   ;; 2048 < c <= 4096 cylinders
8571   shr bx, #0x02
8572   shl cl, #0x02
8573   jmp hd0_post_store_logical
8574
8575 hd0_post_above_4096:
8576   cmp bx, #8192
8577   jnbe hd0_post_above_8192
8578   ;; 4096 < c <= 8192 cylinders
8579   shr bx, #0x03
8580   shl cl, #0x03
8581   jmp hd0_post_store_logical
8582
8583 hd0_post_above_8192:
8584   ;; 8192 < c <= 16384 cylinders
8585   shr bx, #0x04
8586   shl cl, #0x04
8587
8588 hd0_post_store_logical:
8589   mov   (0x003d + 0x00), bx ;; number of physical cylinders
8590   mov   (0x003d + 0x02), cl ;; number of physical heads
8591   ;; checksum
8592   mov   cl, #0x0f     ;; repeat count
8593   mov   si, #0x003d   ;; offset to disk0 FDPT
8594   mov   al, #0x00     ;; sum
8595 hd0_post_checksum_loop:
8596   add   al, [si]
8597   inc   si
8598   dec   cl
8599   jnz hd0_post_checksum_loop
8600   not   al  ;; now take 2s complement
8601   inc   al
8602   mov   [si], al
8603 ;;; Done filling EBDA table for hard disk 0.
8604
8605
8606 check_for_hd1:
8607   ;; is there really a second hard disk?  if not, return now
8608   mov  al, #0x12
8609   out  #0x70, al
8610   in   al, #0x71
8611   and  al, #0x0f
8612   jnz   post_d1_exists
8613   ret
8614 post_d1_exists:
8615   ;; check that the hd type is really 0x0f.
8616   cmp al, #0x0f
8617   jz post_d1_extended
8618   HALT(__LINE__)
8619 post_d1_extended:
8620   ;; check that the extended type is 47 - user definable
8621   mov  al, #0x1a
8622   out  #0x70, al
8623   in   al, #0x71
8624   cmp  al, #47  ;; decimal 47 - user definable
8625   je   post_d1_type47
8626   HALT(__LINE__)
8627 post_d1_type47:
8628   ;; Table for disk1.
8629   ;; CMOS  purpose                  param table offset
8630   ;; 0x24    cylinders low            0
8631   ;; 0x25    cylinders high           1
8632   ;; 0x26    heads                    2
8633   ;; 0x27    write pre-comp low       5
8634   ;; 0x28    write pre-comp high      6
8635   ;; 0x29    heads>8                  8
8636   ;; 0x2a    landing zone low         C
8637   ;; 0x2b    landing zone high        D
8638   ;; 0x2c    sectors/track            E
8639 ;;; Fill EBDA table for hard disk 1.
8640   mov  ax, #EBDA_SEG
8641   mov  ds, ax
8642   mov  al, #0x28
8643   out  #0x70, al
8644   in   al, #0x71
8645   mov  ah, al
8646   mov  al, #0x27
8647   out  #0x70, al
8648   in   al, #0x71
8649   mov   (0x004d + 0x05), ax ;; write precomp word
8650
8651   mov  al, #0x29
8652   out  #0x70, al
8653   in   al, #0x71
8654   mov   (0x004d + 0x08), al ;; drive control byte
8655
8656   mov  al, #0x2b
8657   out  #0x70, al
8658   in   al, #0x71
8659   mov  ah, al
8660   mov  al, #0x2a
8661   out  #0x70, al
8662   in   al, #0x71
8663   mov   (0x004d + 0x0C), ax ;; landing zone word
8664
8665   mov  al, #0x25   ;; get cylinders word in AX
8666   out  #0x70, al
8667   in   al, #0x71   ;; high byte
8668   mov  ah, al
8669   mov  al, #0x24
8670   out  #0x70, al
8671   in   al, #0x71   ;; low byte
8672   mov  bx, ax      ;; BX = cylinders
8673
8674   mov  al, #0x26
8675   out  #0x70, al
8676   in   al, #0x71
8677   mov  cl, al      ;; CL = heads
8678
8679   mov  al, #0x2c
8680   out  #0x70, al
8681   in   al, #0x71
8682   mov  dl, al      ;; DL = sectors
8683
8684   cmp  bx, #1024
8685   jnbe hd1_post_logical_chs ;; if cylinders > 1024, use translated style CHS
8686
8687 hd1_post_physical_chs:
8688   ;; no logical CHS mapping used, just physical CHS
8689   ;; use Standard Fixed Disk Parameter Table (FDPT)
8690   mov   (0x004d + 0x00), bx ;; number of physical cylinders
8691   mov   (0x004d + 0x02), cl ;; number of physical heads
8692   mov   (0x004d + 0x0E), dl ;; number of physical sectors
8693   ret
8694
8695 hd1_post_logical_chs:
8696   ;; complies with Phoenix style Translated Fixed Disk Parameter Table (FDPT)
8697   mov   (0x004d + 0x09), bx ;; number of physical cylinders
8698   mov   (0x004d + 0x0b), cl ;; number of physical heads
8699   mov   (0x004d + 0x04), dl ;; number of physical sectors
8700   mov   (0x004d + 0x0e), dl ;; number of logical sectors (same)
8701   mov al, #0xa0
8702   mov   (0x004d + 0x03), al ;; A0h signature, indicates translated table
8703
8704   cmp bx, #2048
8705   jnbe hd1_post_above_2048
8706   ;; 1024 < c <= 2048 cylinders
8707   shr bx, #0x01
8708   shl cl, #0x01
8709   jmp hd1_post_store_logical
8710
8711 hd1_post_above_2048:
8712   cmp bx, #4096
8713   jnbe hd1_post_above_4096
8714   ;; 2048 < c <= 4096 cylinders
8715   shr bx, #0x02
8716   shl cl, #0x02
8717   jmp hd1_post_store_logical
8718
8719 hd1_post_above_4096:
8720   cmp bx, #8192
8721   jnbe hd1_post_above_8192
8722   ;; 4096 < c <= 8192 cylinders
8723   shr bx, #0x03
8724   shl cl, #0x03
8725   jmp hd1_post_store_logical
8726
8727 hd1_post_above_8192:
8728   ;; 8192 < c <= 16384 cylinders
8729   shr bx, #0x04
8730   shl cl, #0x04
8731
8732 hd1_post_store_logical:
8733   mov   (0x004d + 0x00), bx ;; number of physical cylinders
8734   mov   (0x004d + 0x02), cl ;; number of physical heads
8735   ;; checksum
8736   mov   cl, #0x0f     ;; repeat count
8737   mov   si, #0x004d   ;; offset to disk0 FDPT
8738   mov   al, #0x00     ;; sum
8739 hd1_post_checksum_loop:
8740   add   al, [si]
8741   inc   si
8742   dec   cl
8743   jnz hd1_post_checksum_loop
8744   not   al  ;; now take 2s complement
8745   inc   al
8746   mov   [si], al
8747 ;;; Done filling EBDA table for hard disk 1.
8748
8749   ret
8750
8751 ;--------------------
8752 ;- POST: EBDA segment
8753 ;--------------------
8754 ; relocated here because the primary POST area isnt big enough.
8755 ebda_post:
8756 #if BX_USE_EBDA
8757   mov ax, #EBDA_SEG
8758   mov ds, ax
8759   mov byte ptr [0x0], #EBDA_SIZE
8760 #endif
8761   xor ax, ax            ; mov EBDA seg into 40E
8762   mov ds, ax
8763   mov word ptr [0x40E], #EBDA_SEG
8764   ret;;
8765
8766 ;--------------------
8767 ;- POST: EOI + jmp via [0x40:67)
8768 ;--------------------
8769 ; relocated here because the primary POST area isnt big enough.
8770 eoi_jmp_post:
8771   call eoi_both_pics
8772
8773   xor ax, ax
8774   mov ds, ax
8775
8776   jmp far ptr [0x467]
8777
8778
8779 ;--------------------
8780 eoi_both_pics:
8781   mov   al, #0x20
8782   out   #0xA0, al ;; slave  PIC EOI
8783 eoi_master_pic:
8784   mov   al, #0x20
8785   out   #0x20, al ;; master PIC EOI
8786   ret
8787
8788 ;--------------------
8789 BcdToBin:
8790   ;; in:  AL in BCD format
8791   ;; out: AL in binary format, AH will always be 0
8792   ;; trashes BX
8793   mov  bl, al
8794   and  bl, #0x0f ;; bl has low digit
8795   shr  al, #4    ;; al has high digit
8796   mov  bh, #10
8797   mul  al, bh    ;; multiply high digit by 10 (result in AX)
8798   add  al, bl    ;;   then add low digit
8799   ret
8800
8801 ;--------------------
8802 timer_tick_post:
8803   ;; Setup the Timer Ticks Count (0x46C:dword) and
8804   ;;   Timer Ticks Roller Flag (0x470:byte)
8805   ;; The Timer Ticks Count needs to be set according to
8806   ;; the current CMOS time, as if ticks have been occurring
8807   ;; at 18.2hz since midnight up to this point.  Calculating
8808   ;; this is a little complicated.  Here are the factors I gather
8809   ;; regarding this.  14,318,180 hz was the original clock speed,
8810   ;; chosen so it could be divided by either 3 to drive the 5Mhz CPU
8811   ;; at the time, or 4 to drive the CGA video adapter.  The div3
8812   ;; source was divided again by 4 to feed a 1.193Mhz signal to
8813   ;; the timer.  With a maximum 16bit timer count, this is again
8814   ;; divided down by 65536 to 18.2hz.
8815   ;;
8816   ;; 14,318,180 Hz clock
8817   ;;   /3 = 4,772,726 Hz fed to orginal 5Mhz CPU
8818   ;;   /4 = 1,193,181 Hz fed to timer
8819   ;;   /65536 (maximum timer count) = 18.20650736 ticks/second
8820   ;; 1 second = 18.20650736 ticks
8821   ;; 1 minute = 1092.390442 ticks
8822   ;; 1 hour   = 65543.42651 ticks
8823   ;;
8824   ;; Given the values in the CMOS clock, one could calculate
8825   ;; the number of ticks by the following:
8826   ;;   ticks = (BcdToBin(seconds) * 18.206507) +
8827   ;;           (BcdToBin(minutes) * 1092.3904)
8828   ;;           (BcdToBin(hours)   * 65543.427)
8829   ;; To get a little more accuracy, since Im using integer
8830   ;; arithmatic, I use:
8831   ;;   ticks = (BcdToBin(seconds) * 18206507) / 1000000 +
8832   ;;           (BcdToBin(minutes) * 10923904) / 10000 +
8833   ;;           (BcdToBin(hours)   * 65543427) / 1000
8834
8835   ;; assuming DS=0000
8836
8837   ;; get CMOS seconds
8838   xor  eax, eax ;; clear EAX
8839   mov  al, #0x00
8840   out  #0x70, al
8841   in   al, #0x71 ;; AL has CMOS seconds in BCD
8842   call BcdToBin  ;; EAX now has seconds in binary
8843   mov  edx, #18206507
8844   mul  eax, edx
8845   mov  ebx, #1000000
8846   xor  edx, edx
8847   div  eax, ebx
8848   mov  ecx, eax  ;; ECX will accumulate total ticks
8849
8850   ;; get CMOS minutes
8851   xor  eax, eax ;; clear EAX
8852   mov  al, #0x02
8853   out  #0x70, al
8854   in   al, #0x71 ;; AL has CMOS minutes in BCD
8855   call BcdToBin  ;; EAX now has minutes in binary
8856   mov  edx, #10923904
8857   mul  eax, edx
8858   mov  ebx, #10000
8859   xor  edx, edx
8860   div  eax, ebx
8861   add  ecx, eax  ;; add to total ticks
8862
8863   ;; get CMOS hours
8864   xor  eax, eax ;; clear EAX
8865   mov  al, #0x04
8866   out  #0x70, al
8867   in   al, #0x71 ;; AL has CMOS hours in BCD
8868   call BcdToBin  ;; EAX now has hours in binary
8869   mov  edx, #65543427
8870   mul  eax, edx
8871   mov  ebx, #1000
8872   xor  edx, edx
8873   div  eax, ebx
8874   add  ecx, eax  ;; add to total ticks
8875
8876   mov  0x46C, ecx ;; Timer Ticks Count
8877   xor  al, al
8878   mov  0x470, al  ;; Timer Ticks Rollover Flag
8879   ret
8880
8881 ;--------------------
8882 int76_handler:
8883   ;; record completion in BIOS task complete flag
8884   push  ax
8885   push  ds
8886   mov   ax, #0x0040
8887   mov   ds, ax
8888   mov   0x008E, #0xff
8889   call  eoi_both_pics
8890   pop   ds  
8891   pop   ax
8892   iret
8893
8894
8895 ;--------------------
8896 #if BX_APM
8897
8898 use32 386
8899 #define APM_PROT32
8900 #include "apmbios.S"
8901
8902 use16 386
8903 #define APM_PROT16
8904 #include "apmbios.S"
8905
8906 #define APM_REAL
8907 #include "apmbios.S"
8908
8909 #endif
8910
8911 ;--------------------
8912 #if BX_PCIBIOS
8913 use32 386
8914 .align 16
8915 bios32_structure:
8916   db 0x5f, 0x33, 0x32, 0x5f  ;; "_32_" signature
8917   dw bios32_entry_point, 0xf ;; 32 bit physical address
8918   db 0             ;; revision level
8919   ;; length in paragraphs and checksum stored in a word to prevent errors
8920   dw (~(((bios32_entry_point >> 8) + (bios32_entry_point & 0xff) + 0x32) \
8921         & 0xff) << 8) + 0x01
8922   db 0,0,0,0,0     ;; reserved
8923
8924 .align 16
8925 bios32_entry_point:
8926   pushf
8927   cmp eax, #0x49435024
8928   jne unknown_service
8929   mov eax, #0x80000000
8930   mov dx, #0x0cf8
8931   out dx, eax
8932   mov dx, #0x0cfc
8933   in  eax, dx
8934   cmp eax, #0x12378086
8935   jne unknown_service
8936   mov ebx, #0x000f0000
8937   mov ecx, #0
8938   mov edx, #pcibios_protected
8939   xor al, al
8940   jmp bios32_end
8941 unknown_service:
8942   mov al, #0x80
8943 bios32_end:
8944   popf
8945   retf
8946
8947 .align 16
8948 pcibios_protected:
8949   pushf
8950   cli
8951   push esi
8952   push edi
8953   cmp al, #0x01 ;; installation check
8954   jne pci_pro_f02
8955   mov bx, #0x0210
8956   mov cx, #0
8957   mov edx, #0x20494350
8958   mov al, #0x01
8959   jmp pci_pro_ok
8960 pci_pro_f02: ;; find pci device
8961   cmp al, #0x02
8962   jne pci_pro_f08
8963   shl ecx, #16
8964   mov cx, dx
8965   mov bx, #0x0000
8966   mov di, #0x00
8967 pci_pro_devloop:
8968   call pci_pro_select_reg
8969   mov dx, #0x0cfc
8970   in  eax, dx
8971   cmp eax, ecx
8972   jne pci_pro_nextdev
8973   cmp si, #0
8974   je  pci_pro_ok
8975   dec si
8976 pci_pro_nextdev:
8977   inc bx
8978   cmp bx, #0x0100
8979   jne pci_pro_devloop
8980   mov ah, #0x86
8981   jmp pci_pro_fail
8982 pci_pro_f08: ;; read configuration byte
8983   cmp al, #0x08
8984   jne pci_pro_f09
8985   call pci_pro_select_reg
8986   push edx
8987   mov dx, di
8988   and dx, #0x03
8989   add dx, #0x0cfc
8990   in  al, dx
8991   pop edx
8992   mov cl, al
8993   jmp pci_pro_ok
8994 pci_pro_f09: ;; read configuration word
8995   cmp al, #0x09
8996   jne pci_pro_f0a
8997   call pci_pro_select_reg
8998   push edx
8999   mov dx, di
9000   and dx, #0x02
9001   add dx, #0x0cfc
9002   in  ax, dx
9003   pop edx
9004   mov cx, ax
9005   jmp pci_pro_ok
9006 pci_pro_f0a: ;; read configuration dword
9007   cmp al, #0x0a
9008   jne pci_pro_f0b
9009   call pci_pro_select_reg
9010   push edx
9011   mov dx, #0x0cfc
9012   in  eax, dx
9013   pop edx
9014   mov ecx, eax
9015   jmp pci_pro_ok
9016 pci_pro_f0b: ;; write configuration byte
9017   cmp al, #0x0b
9018   jne pci_pro_f0c
9019   call pci_pro_select_reg
9020   push edx
9021   mov dx, di
9022   and dx, #0x03
9023   add dx, #0x0cfc
9024   mov al, cl
9025   out dx, al
9026   pop edx
9027   jmp pci_pro_ok
9028 pci_pro_f0c: ;; write configuration word
9029   cmp al, #0x0c
9030   jne pci_pro_f0d
9031   call pci_pro_select_reg
9032   push edx
9033   mov dx, di
9034   and dx, #0x02
9035   add dx, #0x0cfc
9036   mov ax, cx
9037   out dx, ax
9038   pop edx
9039   jmp pci_pro_ok
9040 pci_pro_f0d: ;; write configuration dword
9041   cmp al, #0x0d
9042   jne pci_pro_unknown
9043   call pci_pro_select_reg
9044   push edx
9045   mov dx, #0x0cfc
9046   mov eax, ecx
9047   out dx, eax
9048   pop edx
9049   jmp pci_pro_ok
9050 pci_pro_unknown:
9051   mov ah, #0x81
9052 pci_pro_fail:
9053   pop edi
9054   pop esi
9055   sti
9056   popf
9057   stc
9058   retf
9059 pci_pro_ok:
9060   xor ah, ah
9061   pop edi
9062   pop esi
9063   sti
9064   popf
9065   clc
9066   retf
9067
9068 pci_pro_select_reg:
9069   push edx
9070   mov eax, #0x800000
9071   mov ax,  bx
9072   shl eax, #8
9073   and di,  #0xff
9074   or  ax,  di
9075   and al,  #0xfc
9076   mov dx, #0x0cf8
9077   out dx,  eax
9078   pop edx
9079   ret
9080
9081 use16 386
9082
9083 pcibios_real:
9084   push eax
9085   push dx
9086   mov eax, #0x80000000
9087   mov dx, #0x0cf8
9088   out dx, eax
9089   mov dx, #0x0cfc
9090   in  eax, dx
9091   cmp eax, #0x12378086
9092   je  pci_present
9093   pop dx
9094   pop eax
9095   mov ah, #0xff
9096   stc
9097   ret
9098 pci_present:
9099   pop dx
9100   pop eax
9101   cmp al, #0x01 ;; installation check
9102   jne pci_real_f02
9103   mov ax, #0x0001
9104   mov bx, #0x0210
9105   mov cx, #0
9106   mov edx, #0x20494350
9107   mov edi, #0xf0000
9108   mov di, #pcibios_protected
9109   clc
9110   ret
9111 pci_real_f02: ;; find pci device
9112   push esi
9113   push edi
9114   cmp al, #0x02
9115   jne pci_real_f08
9116   shl ecx, #16
9117   mov cx, dx
9118   mov bx, #0x0000
9119   mov di, #0x00
9120 pci_real_devloop:
9121   call pci_real_select_reg
9122   mov dx, #0x0cfc
9123   in  eax, dx
9124   cmp eax, ecx
9125   jne pci_real_nextdev
9126   cmp si, #0
9127   je  pci_real_ok
9128   dec si
9129 pci_real_nextdev:
9130   inc bx
9131   cmp bx, #0x0100
9132   jne pci_real_devloop
9133   mov dx, cx
9134   shr ecx, #16
9135   mov ah, #0x86
9136   jmp pci_real_fail
9137 pci_real_f08: ;; read configuration byte
9138   cmp al, #0x08
9139   jne pci_real_f09
9140   call pci_real_select_reg
9141   push dx
9142   mov dx, di
9143   and dx, #0x03
9144   add dx, #0x0cfc
9145   in  al, dx
9146   pop dx
9147   mov cl, al
9148   jmp pci_real_ok
9149 pci_real_f09: ;; read configuration word
9150   cmp al, #0x09
9151   jne pci_real_f0a
9152   call pci_real_select_reg
9153   push dx
9154   mov dx, di
9155   and dx, #0x02
9156   add dx, #0x0cfc
9157   in  ax, dx
9158   pop dx
9159   mov cx, ax
9160   jmp pci_real_ok
9161 pci_real_f0a: ;; read configuration dword
9162   cmp al, #0x0a
9163   jne pci_real_f0b
9164   call pci_real_select_reg
9165   push dx
9166   mov dx, #0x0cfc
9167   in  eax, dx
9168   pop dx
9169   mov ecx, eax
9170   jmp pci_real_ok
9171 pci_real_f0b: ;; write configuration byte
9172   cmp al, #0x0b
9173   jne pci_real_f0c
9174   call pci_real_select_reg
9175   push dx
9176   mov dx, di
9177   and dx, #0x03
9178   add dx, #0x0cfc
9179   mov al, cl
9180   out dx, al
9181   pop dx
9182   jmp pci_real_ok
9183 pci_real_f0c: ;; write configuration word
9184   cmp al, #0x0c
9185   jne pci_real_f0d
9186   call pci_real_select_reg
9187   push dx
9188   mov dx, di
9189   and dx, #0x02
9190   add dx, #0x0cfc
9191   mov ax, cx
9192   out dx, ax
9193   pop dx
9194   jmp pci_real_ok
9195 pci_real_f0d: ;; write configuration dword
9196   cmp al, #0x0d
9197   jne pci_real_unknown
9198   call pci_real_select_reg
9199   push dx
9200   mov dx, #0x0cfc
9201   mov eax, ecx
9202   out dx, eax
9203   pop dx
9204   jmp pci_real_ok
9205 pci_real_unknown:
9206   mov ah, #0x81
9207 pci_real_fail:
9208   pop edi
9209   pop esi
9210   stc
9211   ret
9212 pci_real_ok:
9213   xor ah, ah
9214   pop edi
9215   pop esi
9216   clc
9217   ret
9218
9219 pci_real_select_reg:
9220   push dx
9221   mov eax, #0x800000
9222   mov ax,  bx
9223   shl eax, #8
9224   and di,  #0xff
9225   or  ax,  di
9226   and al,  #0xfc
9227   mov dx,  #0x0cf8
9228   out dx,  eax
9229   pop dx
9230   ret
9231   
9232 .align 16
9233 pci_routing_table_structure:
9234   db 0x24, 0x50, 0x49, 0x52  ;; "$PIR" signature
9235   db 0, 1 ;; version
9236   dw 32 + (6 * 16) ;; table size
9237   db 0 ;; PCI interrupt router bus
9238   db 0x08 ;; PCI interrupt router DevFunc
9239   dw 0x0000 ;; PCI exclusive IRQs 
9240   dw 0x8086 ;; compatible PCI interrupt router vendor ID
9241   dw 0x7000 ;; compatible PCI interrupt router device ID
9242   dw 0,0 ;; Miniport data
9243   db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved
9244   db 0x07 ;; checksum
9245   ;; first slot entry PCI-to-ISA (embedded)
9246   db 0 ;; pci bus number
9247   db 0x08 ;; pci device number (bit 7-3)
9248   db 0x60 ;; link value INTA#: pointer into PCI2ISA config space
9249   dw 0xdef8 ;; IRQ bitmap INTA# 
9250   db 0x61 ;; link value INTB#
9251   dw 0xdef8 ;; IRQ bitmap INTB# 
9252   db 0x62 ;; link value INTC#
9253   dw 0xdef8 ;; IRQ bitmap INTC# 
9254   db 0x63 ;; link value INTD#
9255   dw 0xdef8 ;; IRQ bitmap INTD#
9256   db 0 ;; physical slot (0 = embedded)
9257   db 0 ;; reserved
9258   ;; second slot entry: 1st PCI slot
9259   db 0 ;; pci bus number
9260   db 0x10 ;; pci device number (bit 7-3)
9261   db 0x61 ;; link value INTA#
9262   dw 0xdef8 ;; IRQ bitmap INTA# 
9263   db 0x62 ;; link value INTB#
9264   dw 0xdef8 ;; IRQ bitmap INTB# 
9265   db 0x63 ;; link value INTC#
9266   dw 0xdef8 ;; IRQ bitmap INTC# 
9267   db 0x60 ;; link value INTD#
9268   dw 0xdef8 ;; IRQ bitmap INTD#
9269   db 1 ;; physical slot (0 = embedded)
9270   db 0 ;; reserved
9271   ;; third slot entry: 2nd PCI slot
9272   db 0 ;; pci bus number
9273   db 0x18 ;; pci device number (bit 7-3)
9274   db 0x62 ;; link value INTA#
9275   dw 0xdef8 ;; IRQ bitmap INTA# 
9276   db 0x63 ;; link value INTB#
9277   dw 0xdef8 ;; IRQ bitmap INTB# 
9278   db 0x60 ;; link value INTC#
9279   dw 0xdef8 ;; IRQ bitmap INTC# 
9280   db 0x61 ;; link value INTD#
9281   dw 0xdef8 ;; IRQ bitmap INTD#
9282   db 2 ;; physical slot (0 = embedded)
9283   db 0 ;; reserved
9284   ;; 4th slot entry: 3rd PCI slot
9285   db 0 ;; pci bus number
9286   db 0x20 ;; pci device number (bit 7-3)
9287   db 0x63 ;; link value INTA#
9288   dw 0xdef8 ;; IRQ bitmap INTA# 
9289   db 0x60 ;; link value INTB#
9290   dw 0xdef8 ;; IRQ bitmap INTB# 
9291   db 0x61 ;; link value INTC#
9292   dw 0xdef8 ;; IRQ bitmap INTC# 
9293   db 0x62 ;; link value INTD#
9294   dw 0xdef8 ;; IRQ bitmap INTD#
9295   db 3 ;; physical slot (0 = embedded)
9296   db 0 ;; reserved
9297   ;; 5th slot entry: 4rd PCI slot
9298   db 0 ;; pci bus number
9299   db 0x28 ;; pci device number (bit 7-3)
9300   db 0x60 ;; link value INTA#
9301   dw 0xdef8 ;; IRQ bitmap INTA# 
9302   db 0x61 ;; link value INTB#
9303   dw 0xdef8 ;; IRQ bitmap INTB# 
9304   db 0x62 ;; link value INTC#
9305   dw 0xdef8 ;; IRQ bitmap INTC# 
9306   db 0x63 ;; link value INTD#
9307   dw 0xdef8 ;; IRQ bitmap INTD#
9308   db 4 ;; physical slot (0 = embedded)
9309   db 0 ;; reserved
9310   ;; 6th slot entry: 5rd PCI slot
9311   db 0 ;; pci bus number
9312   db 0x30 ;; pci device number (bit 7-3)
9313   db 0x61 ;; link value INTA#
9314   dw 0xdef8 ;; IRQ bitmap INTA# 
9315   db 0x62 ;; link value INTB#
9316   dw 0xdef8 ;; IRQ bitmap INTB# 
9317   db 0x63 ;; link value INTC#
9318   dw 0xdef8 ;; IRQ bitmap INTC# 
9319   db 0x60 ;; link value INTD#
9320   dw 0xdef8 ;; IRQ bitmap INTD#
9321   db 5 ;; physical slot (0 = embedded)
9322   db 0 ;; reserved
9323
9324 pci_irq_list:
9325   db 11, 10, 9, 5;
9326
9327 pcibios_init_sel_reg:
9328   push eax
9329   mov eax, #0x800000
9330   mov ax,  bx
9331   shl eax, #8
9332   and dl,  #0xfc
9333   or  al,  dl
9334   mov dx,  #0x0cf8
9335   out dx,  eax
9336   pop eax
9337   ret
9338   
9339 pcibios_init_set_elcr:
9340   push ax
9341   push cx
9342   mov  dx, #0x04d0
9343   test al, #0x08
9344   jz   is_master_pic
9345   inc  dx
9346   and  al, #0x07
9347 is_master_pic:
9348   mov  cl, al
9349   mov  bl, #0x01
9350   shl  bl, cl
9351   in   al, dx
9352   or   al, bl
9353   out  dx, al
9354   pop  cx
9355   pop  ax
9356   ret
9357
9358 pcibios_init:
9359   push ds
9360   push bp
9361   mov  ax, #0xf000
9362   mov  ds, ax
9363   mov  dx, #0x04d0 ;; reset ELCR1 + ELCR2
9364   mov  al, #0x00
9365   out  dx, al
9366   inc  dx
9367   out  dx, al
9368   mov  si, #pci_routing_table_structure
9369   mov  bh, [si+8]
9370   mov  bl, [si+9]
9371   mov  dl, #0x00
9372   call pcibios_init_sel_reg
9373   mov  dx, #0x0cfc
9374   in   eax, dx
9375   cmp  eax, [si+12] ;; check irq router
9376   jne  pci_init_end
9377   mov  dl, [si+34]
9378   call pcibios_init_sel_reg
9379   push bx ;; save irq router bus + devfunc
9380   mov  dx, #0x0cfc
9381   mov  ax, #0x8080
9382   out  dx, ax ;; reset PIRQ route control
9383   inc  dx
9384   inc  dx
9385   out  dx, ax
9386   mov  ax, [si+6]
9387   sub  ax, #0x20
9388   shr  ax, #4
9389   mov  cx, ax
9390   add  si, #0x20 ;; set pointer to 1st entry
9391   mov  bp, sp
9392   mov  ax, #pci_irq_list
9393   push ax
9394   xor  ax, ax
9395   push ax
9396 pci_init_loop1:
9397   mov  bh, [si]
9398   mov  bl, [si+1]
9399 pci_init_loop2:
9400   mov  dl, #0x00
9401   call pcibios_init_sel_reg
9402   mov  dx, #0x0cfc
9403   in   ax, dx
9404   cmp  ax, #0xffff
9405   jnz  pci_test_int_pin
9406   test bl, #0x07
9407   jz   next_pir_entry
9408   jmp  next_pci_func
9409 pci_test_int_pin:
9410   mov  dl, #0x3c
9411   call pcibios_init_sel_reg
9412   mov  dx, #0x0cfd
9413   in   al, dx
9414   and  al, #0x07
9415   jz   next_pci_func
9416   dec  al ;; determine pirq reg
9417   mov  dl, #0x03
9418   mul  al, dl
9419   add  al, #0x02
9420   xor  ah, ah
9421   mov  bx, ax
9422   mov  al, [si+bx]
9423   mov  dl, al
9424   mov  bx, [bp]
9425   call pcibios_init_sel_reg
9426   mov  dx, #0x0cfc
9427   and  al, #0x03
9428   add  dl, al
9429   in   al, dx
9430   cmp  al, #0x80
9431   jb   pirq_found
9432   mov  bx, [bp-2] ;; pci irq list pointer
9433   mov  al, [bx]
9434   out  dx, al
9435   inc  bx
9436   mov  [bp-2], bx
9437   call pcibios_init_set_elcr
9438 pirq_found:
9439   mov  bh, [si]
9440   mov  bl, [si+1]
9441   add  bl, [bp-3] ;; pci function number
9442   mov  dl, #0x3c
9443   call pcibios_init_sel_reg
9444   mov  dx, #0x0cfc
9445   out  dx, al
9446 next_pci_func:
9447   inc  byte ptr[bp-3]
9448   inc  bl
9449   test bl, #0x07
9450   jnz  pci_init_loop2
9451 next_pir_entry:
9452   add  si, #0x10
9453   mov  byte ptr[bp-3], #0x00
9454   loop pci_init_loop1
9455   mov  sp, bp
9456   pop  bx
9457 pci_init_end:
9458   pop  bp
9459   pop  ds
9460   ret
9461 #endif // BX_PCIBIOS
9462
9463 ; parallel port detection: base address in DX, index in BX, timeout in CL
9464 detect_parport:
9465   push dx
9466   add  dx, #2
9467   in   al, dx
9468   and  al, #0xdf ; clear input mode
9469   out  dx, al
9470   pop  dx
9471   mov  al, #0xaa
9472   out  dx, al
9473   in   al, dx
9474   cmp  al, #0xaa
9475   jne  no_parport
9476   push bx
9477   shl  bx, #1
9478   mov  [bx+0x408], dx ; Parallel I/O address
9479   pop  bx
9480   mov  [bx+0x478], cl ; Parallel printer timeout
9481   inc  bx
9482 no_parport:
9483   ret
9484
9485 ; serial port detection: base address in DX, index in BX, timeout in CL
9486 detect_serial:
9487 ; no serial port in the VM -PAD
9488   ret
9489
9490   push dx
9491   inc  dx
9492   mov  al, #0x02
9493   out  dx, al
9494   in   al, dx
9495   cmp  al, #0x02
9496   jne  no_serial
9497   inc  dx
9498   in   al, dx
9499   cmp  al, #0x02
9500   jne  no_serial
9501   dec  dx
9502   xor  al, al
9503   out  dx, al
9504   pop  dx
9505   push bx
9506   shl  bx, #1
9507   mov  [bx+0x400], dx ; Serial I/O address
9508   pop  bx
9509   mov  [bx+0x47c], cl ; Serial timeout
9510   inc  bx
9511   ret
9512 no_serial:
9513   pop  dx
9514   ret
9515
9516 rom_checksum:
9517   push ax
9518   push bx
9519   push cx
9520   xor  ax, ax
9521   xor  bx, bx
9522   xor  cx, cx
9523   mov  ch, [2]
9524   shl  cx, #1
9525 checksum_loop:
9526   add  al, [bx]
9527   inc  bx
9528   loop checksum_loop
9529   and  al, #0xff
9530   pop  cx
9531   pop  bx
9532   pop  ax
9533   ret
9534
9535 rom_scan:
9536   ;; Scan for existence of valid expansion ROMS.
9537   ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
9538   ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
9539   ;;   System  ROM: only 0xE0000
9540   ;;
9541   ;; Header:
9542   ;;   Offset    Value
9543   ;;   0         0x55
9544   ;;   1         0xAA
9545   ;;   2         ROM length in 512-byte blocks
9546   ;;   3         ROM initialization entry point (FAR CALL)
9547
9548   mov  cx, #0xc000
9549 rom_scan_loop:
9550   mov  ds, cx
9551   mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
9552   cmp [0], #0xAA55 ;; look for signature
9553   jne  rom_scan_increment
9554   call rom_checksum
9555   jnz  rom_scan_increment
9556
9557   mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
9558
9559   ;; We want our increment in 512-byte quantities, rounded to
9560   ;; the nearest 2k quantity, since we only scan at 2k intervals.
9561   test al, #0x03
9562   jz   block_count_rounded
9563   and  al, #0xfc ;; needs rounding up
9564   add  al, #0x04
9565 block_count_rounded:
9566
9567   xor  bx, bx   ;; Restore DS back to 0000:
9568   mov  ds, bx
9569   push ax       ;; Save AX
9570   ;; Push addr of ROM entry point
9571   push cx       ;; Push seg
9572   push #0x0003  ;; Push offset
9573   mov  bp, sp   ;; Call ROM init routine using seg:off on stack
9574   db   0xff     ;; call_far ss:[bp+0]
9575   db   0x5e
9576   db   0
9577   cli           ;; In case expansion ROM BIOS turns IF on
9578   add  sp, #2   ;; Pop offset value
9579   pop  cx       ;; Pop seg value (restore CX)
9580   pop  ax       ;; Restore AX
9581 rom_scan_increment:
9582   shl  ax, #5   ;; convert 512-bytes blocks to 16-byte increments
9583                 ;; because the segment selector is shifted left 4 bits.
9584   add  cx, ax
9585   cmp  cx, #0xe000
9586   jbe  rom_scan_loop
9587
9588   xor  ax, ax   ;; Restore DS back to 0000:
9589   mov  ds, ax
9590   ret
9591
9592 #ifdef HVMASSIST
9593
9594 ; Copy the SMBIOS entry point over from 0x9f000, where hvmloader left it.
9595 ; The entry point must be somewhere in 0xf0000-0xfffff on a 16-byte boundary,
9596 ; but the tables themeselves can be elsewhere.
9597 smbios_init:
9598   push ax
9599   push cx
9600   push es
9601   push ds
9602   push di
9603   push si
9604
9605   mov cx, #0x001f ; 0x1f bytes to copy
9606   mov ax, #0xf000
9607   mov es, ax      ; destination segment is 0xf0000
9608   mov di, #smbios_entry_point ; destination offset
9609   mov ax, #0x9f00
9610   mov ds, ax      ; source segment is 0x9f000
9611   mov si, #0x0000 ; source offset is 0
9612   cld
9613   rep
9614     movsb
9615
9616   pop si
9617   pop di
9618   pop ds
9619   pop es
9620   pop cx
9621   pop ax
9622
9623   ret
9624
9625 #endif
9626
9627
9628
9629 ;; for 'C' strings and other data, insert them here with
9630 ;; a the following hack:
9631 ;; DATA_SEG_DEFS_HERE
9632
9633
9634 ;--------
9635 ;- POST -
9636 ;--------
9637 .org 0xe05b ; POST Entry Point
9638 post:
9639
9640   xor ax, ax
9641
9642   ;; first reset the DMA controllers
9643   out 0x0d,al
9644   out 0xda,al
9645
9646   ;; then initialize the DMA controllers
9647   mov al, #0xC0
9648   out 0xD6, al ; cascade mode of channel 4 enabled
9649   mov al, #0x00
9650   out 0xD4, al ; unmask channel 4
9651
9652   ;; Examine CMOS shutdown status.
9653   mov AL, #0x0f
9654   out 0x70, AL
9655   in  AL, 0x71
9656
9657   ;; backup status
9658   mov bl, al
9659
9660   ;; Reset CMOS shutdown status.
9661   mov AL, #0x0f
9662   out 0x70, AL          ; select CMOS register Fh
9663   mov AL, #0x00
9664   out 0x71, AL          ; set shutdown action to normal
9665
9666   ;; Examine CMOS shutdown status.
9667   mov al, bl
9668
9669   ;; 0x00, 0x09, 0x0D+ = normal startup
9670   cmp AL, #0x00
9671   jz normal_post
9672   cmp AL, #0x0d
9673   jae normal_post
9674   cmp AL, #0x09
9675   je normal_post
9676
9677   ;; 0x05 = eoi + jmp via [0x40:0x67] jump
9678   cmp al, #0x05
9679   je  eoi_jmp_post
9680
9681   ;; Examine CMOS shutdown status.
9682   ;;  0x01,0x02,0x03,0x04,0x06,0x07,0x08, 0x0a, 0x0b, 0x0c = Unimplemented shutdown status.
9683   push bx
9684   call _shutdown_status_panic
9685
9686 #if 0 
9687   HALT(__LINE__)
9688   ;
9689   ;#if 0
9690   ;  0xb0, 0x20,       /* mov al, #0x20 */
9691   ;  0xe6, 0x20,       /* out 0x20, al    ;send EOI to PIC */
9692   ;#endif
9693   ;
9694   pop es
9695   pop ds
9696   popa
9697   iret
9698 #endif
9699
9700 normal_post:
9701   ; case 0: normal startup
9702
9703   cli
9704   mov  ax, #0xfffe
9705   mov  sp, ax
9706   mov  ax, #0x0000
9707   mov  ds, ax
9708   mov  ss, ax
9709
9710   ;; zero out BIOS data area (40:00..40:ff)
9711   mov  es, ax
9712   mov  cx, #0x0080 ;; 128 words
9713   mov  di, #0x0400
9714   cld
9715   rep
9716     stosw
9717
9718   call _log_bios_start
9719
9720   ;; set all interrupts to default handler
9721   mov  bx, #0x0000    ;; offset index
9722   mov  cx, #0x0100    ;; counter (256 interrupts)
9723   mov  ax, #dummy_iret_handler
9724   mov  dx, #0xF000
9725
9726 post_default_ints:
9727   mov  [bx], ax
9728   inc  bx
9729   inc  bx
9730   mov  [bx], dx
9731   inc  bx
9732   inc  bx
9733   loop post_default_ints
9734
9735   ;; set vector 0x79 to zero
9736   ;; this is used by 'gardian angel' protection system
9737   SET_INT_VECTOR(0x79, #0, #0)
9738
9739   ;; base memory in K 40:13 (word)
9740   mov  ax, #BASE_MEM_IN_K
9741   mov  0x0413, ax
9742
9743
9744   ;; Manufacturing Test 40:12
9745   ;;   zerod out above
9746
9747   ;; Warm Boot Flag 0040:0072
9748   ;;   value of 1234h = skip memory checks
9749   ;;   zerod out above
9750
9751
9752   ;; Printer Services vector
9753   SET_INT_VECTOR(0x17, #0xF000, #int17_handler)
9754
9755   ;; Bootstrap failure vector
9756   SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
9757
9758   ;; Bootstrap Loader vector
9759   SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
9760
9761   ;; User Timer Tick vector
9762   SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
9763
9764   ;; Memory Size Check vector
9765   SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
9766
9767   ;; Equipment Configuration Check vector
9768   SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
9769
9770   ;; System Services
9771   SET_INT_VECTOR(0x15, #0xF000, #int15_handler)
9772
9773   ;; EBDA setup
9774   call ebda_post
9775
9776   ;; PIT setup
9777   SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
9778   ;; int 1C already points at dummy_iret_handler (above)
9779   mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
9780   out 0x43, al
9781 #ifdef HVMASSIST
9782   mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support)
9783   out 0x40, al ; lsb
9784   mov al, #0xe9
9785   out 0x40, al ; msb
9786 #else
9787   mov al, #0x00 ; maximum count of 0000H = 18.2Hz
9788   out 0x40, al
9789   out 0x40, al
9790 #endif
9791
9792   ;; Keyboard
9793   SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
9794   SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
9795
9796   xor  ax, ax
9797   mov  ds, ax
9798   mov  0x0417, al /* keyboard shift flags, set 1 */
9799   mov  0x0418, al /* keyboard shift flags, set 2 */
9800   mov  0x0419, al /* keyboard alt-numpad work area */
9801   mov  0x0471, al /* keyboard ctrl-break flag */
9802   mov  0x0497, al /* keyboard status flags 4 */
9803   mov  al, #0x10
9804   mov  0x0496, al /* keyboard status flags 3 */
9805
9806
9807   /* keyboard head of buffer pointer */
9808   mov  bx, #0x001E
9809   mov  0x041A, bx
9810
9811   /* keyboard end of buffer pointer */
9812   mov  0x041C, bx
9813
9814   /* keyboard pointer to start of buffer */
9815   mov  bx, #0x001E
9816   mov  0x0480, bx
9817
9818   /* keyboard pointer to end of buffer */
9819   mov  bx, #0x003E
9820   mov  0x0482, bx
9821
9822   /* init the keyboard */
9823   call _keyboard_init
9824
9825   ;; mov CMOS Equipment Byte to BDA Equipment Word
9826   mov  ax, 0x0410
9827   mov  al, #0x14
9828   out  0x70, al
9829   in   al, 0x71
9830   mov  0x0410, ax
9831
9832
9833   ;; Parallel setup
9834   SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler)
9835   xor ax, ax
9836   mov ds, ax
9837   xor bx, bx
9838   mov cl, #0x14 ; timeout value
9839   mov dx, #0x378 ; Parallel I/O address, port 1
9840   call detect_parport
9841   mov dx, #0x278 ; Parallel I/O address, port 2
9842   call detect_parport
9843   shl bx, #0x0e
9844   mov ax, 0x410   ; Equipment word bits 14..15 determing # parallel ports
9845   and ax, #0x3fff
9846   or  ax, bx ; set number of parallel ports
9847   mov 0x410, ax
9848
9849   ;; Serial setup
9850   SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler)
9851   SET_INT_VECTOR(0x14, #0xF000, #int14_handler)
9852   xor bx, bx
9853   mov cl, #0x0a ; timeout value
9854   mov dx, #0x03f8 ; Serial I/O address, port 1
9855   call detect_serial
9856   mov dx, #0x02f8 ; Serial I/O address, port 2
9857   call detect_serial
9858   mov dx, #0x03e8 ; Serial I/O address, port 3
9859   call detect_serial
9860   mov dx, #0x02e8 ; Serial I/O address, port 4
9861   call detect_serial
9862   shl bx, #0x09
9863   mov ax, 0x410   ; Equipment word bits 9..11 determing # serial ports
9864   and ax, #0xf1ff
9865   or  ax, bx ; set number of serial port
9866   mov 0x410, ax
9867
9868   ;; CMOS RTC
9869   SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
9870   SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler)
9871   SET_INT_VECTOR(0x70, #0xF000, #int70_handler)
9872   ;; BIOS DATA AREA 0x4CE ???
9873   call timer_tick_post
9874
9875   ;; PS/2 mouse setup
9876   SET_INT_VECTOR(0x74, #0xF000, #int74_handler)
9877
9878   ;; IRQ13 (FPU exception) setup
9879   SET_INT_VECTOR(0x75, #0xF000, #int75_handler)
9880
9881   ;; Video setup
9882   SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
9883
9884
9885
9886   ;; PIC
9887   mov al, #0x11 ; send initialisation commands
9888   out 0x20, al
9889   out 0xa0, al
9890   mov al, #0x08
9891   out 0x21, al
9892   mov al, #0x70
9893   out 0xa1, al
9894   mov al, #0x04
9895   out 0x21, al
9896   mov al, #0x02
9897   out 0xa1, al
9898   mov al, #0x01
9899   out 0x21, al
9900   out 0xa1, al
9901   mov  al, #0xb8
9902   out  0x21, AL ;master pic: unmask IRQ 0, 1, 2, 6
9903 #if BX_USE_PS2_MOUSE
9904   mov  al, #0x8f
9905 #else
9906   mov  al, #0x9f
9907 #endif
9908   out  0xa1, AL ;slave  pic: unmask IRQ 12, 13, 14
9909
9910 #ifdef HVMASSIST
9911   call _copy_e820_table
9912   call smbios_init
9913 #endif
9914
9915   call rom_scan
9916
9917
9918   ;; JRL CHANGE
9919   ;;push ax
9920   ;;push bx
9921   ;;mov  ah, #0x0e
9922   ;;mov  al, #0x41
9923   ;;xor  bx,bx
9924   ;;int  #0x10
9925   ;;pop  bx
9926   ;;pop ax
9927
9928
9929
9930   call _print_bios_banner 
9931
9932   ;;
9933   ;; Floppy setup
9934   ;;
9935   call floppy_drive_post
9936
9937 #if BX_USE_ATADRV
9938
9939   ;;
9940   ;; Hard Drive setup
9941   ;;
9942   call hard_drive_post
9943
9944   ;;
9945   ;; ATA/ATAPI driver setup
9946   ;;
9947   call _ata_init
9948   call _ata_detect
9949   ;;
9950 #else // BX_USE_ATADRV
9951
9952   ;;
9953   ;; Hard Drive setup
9954   ;;
9955   call hard_drive_post
9956
9957 #endif // BX_USE_ATADRV
9958
9959 #if BX_ELTORITO_BOOT
9960   ;;
9961   ;; eltorito floppy/harddisk emulation from cd
9962   ;;
9963   call _cdemu_init
9964   ;;
9965 #endif // BX_ELTORITO_BOOT
9966  
9967   int  #0x19
9968   //JMP_EP(0x0064) ; INT 19h location
9969
9970
9971 .org 0xe2c3 ; NMI Handler Entry Point
9972 nmi:
9973   ;; FIXME the NMI handler should not panic
9974   ;; but iret when called from int75 (fpu exception)
9975   call _nmi_handler_msg
9976   iret
9977
9978 int75_handler:
9979   out  0xf0, al         // clear irq13 
9980   call eoi_both_pics    // clear interrupt
9981   int  2                // legacy nmi call
9982   iret
9983
9984 ;-------------------------------------------
9985 ;- INT 13h Fixed Disk Services Entry Point -
9986 ;-------------------------------------------
9987 .org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
9988 int13_handler:
9989   //JMPL(int13_relocated)
9990   jmp int13_relocated
9991
9992 .org 0xe401 ; Fixed Disk Parameter Table
9993
9994 ;----------
9995 ;- INT19h -
9996 ;----------
9997 .org 0xe6f2 ; INT 19h Boot Load Service Entry Point
9998 int19_handler:
9999
10000   jmp int19_relocated
10001 ;-------------------------------------------
10002 ;- System BIOS Configuration Data Table
10003 ;-------------------------------------------
10004 .org BIOS_CONFIG_TABLE
10005 db 0x08                  ; Table size (bytes) -Lo
10006 db 0x00                  ; Table size (bytes) -Hi
10007 db SYS_MODEL_ID
10008 db SYS_SUBMODEL_ID
10009 db BIOS_REVISION
10010 ; Feature byte 1
10011 ; b7: 1=DMA channel 3 used by hard disk
10012 ; b6: 1=2 interrupt controllers present
10013 ; b5: 1=RTC present
10014 ; b4: 1=BIOS calls int 15h/4Fh every key
10015 ; b3: 1=wait for extern event supported (Int 15h/41h)
10016 ; b2: 1=extended BIOS data area used
10017 ; b1: 0=AT or ESDI bus, 1=MicroChannel
10018 ; b0: 1=Dual bus (MicroChannel + ISA)
10019 db (0 << 7) | \
10020    (1 << 6) | \
10021    (1 << 5) | \
10022    (BX_CALL_INT15_4F << 4) | \
10023    (0 << 3) | \
10024    (BX_USE_EBDA << 2) | \
10025    (0 << 1) | \
10026    (0 << 0)
10027 ; Feature byte 2
10028 ; b7: 1=32-bit DMA supported
10029 ; b6: 1=int16h, function 9 supported
10030 ; b5: 1=int15h/C6h (get POS data) supported
10031 ; b4: 1=int15h/C7h (get mem map info) supported
10032 ; b3: 1=int15h/C8h (en/dis CPU) supported
10033 ; b2: 1=non-8042 kb controller
10034 ; b1: 1=data streaming supported
10035 ; b0: reserved
10036 db (0 << 7) | \
10037    (1 << 6) | \
10038    (0 << 5) | \
10039    (0 << 4) | \
10040    (0 << 3) | \
10041    (0 << 2) | \
10042    (0 << 1) | \
10043    (0 << 0)
10044 ; Feature byte 3
10045 ; b7: not used
10046 ; b6: reserved
10047 ; b5: reserved
10048 ; b4: POST supports ROM-to-RAM enable/disable
10049 ; b3: SCSI on system board
10050 ; b2: info panel installed
10051 ; b1: Initial Machine Load (IML) system - BIOS on disk
10052 ; b0: SCSI supported in IML
10053 db 0x00
10054 ; Feature byte 4
10055 ; b7: IBM private
10056 ; b6: EEPROM present
10057 ; b5-3: ABIOS presence (011 = not supported)
10058 ; b2: private
10059 ; b1: memory split above 16Mb supported
10060 ; b0: POSTEXT directly supported by POST
10061 db 0x00
10062 ; Feature byte 5 (IBM)
10063 ; b1: enhanced mouse
10064 ; b0: flash EPROM
10065 db 0x00
10066
10067
10068
10069 .org 0xe729 ; Baud Rate Generator Table
10070
10071 ;----------
10072 ;- INT14h -
10073 ;----------
10074 .org 0xe739 ; INT 14h Serial Communications Service Entry Point
10075 int14_handler:
10076   push ds
10077   pusha
10078   mov  ax, #0x0000
10079   mov  ds, ax
10080   call _int14_function
10081   popa
10082   pop  ds
10083   iret
10084
10085
10086 ;----------------------------------------
10087 ;- INT 16h Keyboard Service Entry Point -
10088 ;----------------------------------------
10089 .org 0xe82e
10090 int16_handler:
10091
10092   sti
10093   push  ds
10094   pushf
10095   pusha
10096
10097   cmp   ah, #0x00
10098   je    int16_F00
10099   cmp   ah, #0x10
10100   je    int16_F00
10101
10102   mov  bx, #0xf000
10103   mov  ds, bx
10104   call _int16_function
10105   popa
10106   popf
10107   pop  ds
10108   jz   int16_zero_set
10109
10110 int16_zero_clear:
10111   push bp
10112   mov  bp, sp
10113   //SEG SS
10114   and  BYTE [bp + 0x06], #0xbf
10115   pop  bp
10116   iret
10117
10118 int16_zero_set:
10119   push bp
10120   mov  bp, sp
10121   //SEG SS
10122   or   BYTE [bp + 0x06], #0x40
10123   pop  bp
10124   iret
10125
10126 int16_F00:
10127   mov  bx, #0x0040
10128   mov  ds, bx
10129
10130 int16_wait_for_key:
10131   cli
10132   mov  bx, 0x001a
10133   cmp  bx, 0x001c
10134   jne  int16_key_found
10135   sti
10136   nop
10137 #if 0
10138                            /* no key yet, call int 15h, function AX=9002 */
10139   0x50,                    /* push AX */
10140   0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
10141   0xcd, 0x15,              /* int 15h */
10142   0x58,                    /* pop  AX */
10143   0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
10144 #endif
10145   jmp  int16_wait_for_key
10146
10147 int16_key_found:
10148   mov  bx, #0xf000
10149   mov  ds, bx
10150   call _int16_function
10151   popa
10152   popf
10153   pop  ds
10154 #if 0
10155                            /* notify int16 complete w/ int 15h, function AX=9102 */
10156   0x50,                    /* push AX */
10157   0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
10158   0xcd, 0x15,              /* int 15h */
10159   0x58,                    /* pop  AX */
10160 #endif
10161   iret
10162
10163
10164
10165 ;-------------------------------------------------
10166 ;- INT09h : Keyboard Hardware Service Entry Point -
10167 ;-------------------------------------------------
10168 .org 0xe987
10169 int09_handler:
10170   cli
10171   push ax
10172
10173   mov al, #0xAD      ;;disable keyboard
10174   out #0x64, al
10175
10176   mov al, #0x0B
10177   out #0x20, al
10178   in  al, #0x20
10179   and al, #0x02
10180   jz  int09_finish
10181
10182   in  al, #0x60             ;;read key from keyboard controller
10183   //test al, #0x80            ;;look for key release
10184   //jnz  int09_process_key    ;; dont pass releases to intercept?
10185
10186   ;; check for extended key
10187   cmp  al, #0xe0
10188   jne int09_call_int15_4f
10189   
10190   push ds
10191   xor  ax, ax
10192   mov  ds, ax
10193   mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
10194   or   al, #0x01
10195   mov  BYTE [0x496], al
10196   pop  ds
10197   
10198   in  al, #0x60             ;;read another key from keyboard controller
10199
10200   sti
10201
10202 int09_call_int15_4f:
10203   push  ds
10204   pusha
10205 #ifdef BX_CALL_INT15_4F
10206   mov  ah, #0x4f     ;; allow for keyboard intercept
10207   stc
10208   int  #0x15
10209   jnc  int09_done
10210 #endif
10211
10212
10213 //int09_process_key:
10214   mov   bx, #0xf000
10215   mov   ds, bx
10216   call  _int09_function
10217
10218 int09_done:
10219   popa
10220   pop   ds
10221   cli
10222   call eoi_master_pic
10223
10224 int09_finish:
10225   mov al, #0xAE      ;;enable keyboard
10226   out #0x64, al
10227   pop ax
10228   iret
10229
10230
10231
10232
10233 ;----------------------------------------
10234 ;- INT 13h Diskette Service Entry Point -
10235 ;----------------------------------------
10236 .org 0xec59
10237 int13_diskette:
10238   jmp int13_noeltorito
10239
10240 ;---------------------------------------------
10241 ;- INT 0Eh Diskette Hardware ISR Entry Point -
10242 ;---------------------------------------------
10243 .org 0xef57 ; INT 0Eh Diskette Hardware ISR Entry Point
10244 int0e_handler:
10245   push ax
10246   push dx
10247   mov  dx, #0x03f4
10248   in   al, dx
10249   and  al, #0xc0
10250   cmp  al, #0xc0
10251   je   int0e_normal
10252   mov  dx, #0x03f5
10253   mov  al, #0x08 ; sense interrupt status
10254   out  dx, al
10255 int0e_loop1:
10256   mov  dx, #0x03f4
10257   in   al, dx
10258   and  al, #0xc0
10259   cmp  al, #0xc0
10260   jne  int0e_loop1
10261 int0e_loop2:
10262   mov  dx, #0x03f5
10263   in   al, dx
10264   mov  dx, #0x03f4
10265   in   al, dx
10266   and  al, #0xc0
10267   cmp  al, #0xc0
10268   je int0e_loop2
10269 int0e_normal:
10270   push ds
10271   mov  ax, #0x0000 ;; segment 0000
10272   mov  ds, ax
10273   call eoi_master_pic
10274   mov  al, 0x043e
10275   or   al, #0x80 ;; diskette interrupt has occurred
10276   mov  0x043e, al
10277   pop  ds
10278   pop  dx
10279   pop  ax
10280   iret
10281
10282
10283 .org 0xefc7 ; Diskette Controller Parameter Table
10284 diskette_param_table:
10285 ;;  Since no provisions are made for multiple drive types, most
10286 ;;  values in this table are ignored.  I set parameters for 1.44M
10287 ;;  floppy here
10288 db  0xAF
10289 db  0x02 ;; head load time 0000001, DMA used
10290 db  0x25
10291 db  0x02
10292 db    18
10293 db  0x1B
10294 db  0xFF
10295 db  0x6C
10296 db  0xF6
10297 db  0x0F
10298 db  0x08
10299
10300
10301 ;----------------------------------------
10302 ;- INT17h : Printer Service Entry Point -
10303 ;----------------------------------------
10304 .org 0xefd2
10305 int17_handler:
10306   push ds
10307   pusha
10308   mov  ax, #0x0000
10309   mov  ds, ax
10310   call _int17_function
10311   popa
10312   pop  ds
10313   iret
10314
10315 diskette_param_table2:
10316 ;;  New diskette parameter table adding 3 parameters from IBM
10317 ;;  Since no provisions are made for multiple drive types, most
10318 ;;  values in this table are ignored.  I set parameters for 1.44M
10319 ;;  floppy here
10320 db  0xAF
10321 db  0x02 ;; head load time 0000001, DMA used
10322 db  0x25
10323 db  0x02
10324 db    18
10325 db  0x1B
10326 db  0xFF
10327 db  0x6C
10328 db  0xF6
10329 db  0x0F
10330 db  0x08
10331 db    79 ;; maximum track
10332 db     0 ;; data transfer rate
10333 db     4 ;; drive type in cmos
10334
10335 .org 0xf045 ; INT 10 Functions 0-Fh Entry Point
10336   HALT(__LINE__)
10337   iret
10338
10339 ;----------
10340 ;- INT10h -
10341 ;----------
10342 .org 0xf065 ; INT 10h Video Support Service Entry Point
10343 int10_handler:
10344   ;; dont do anything, since the VGA BIOS handles int10h requests
10345   iret
10346
10347 .org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
10348
10349 ;----------
10350 ;- INT12h -
10351 ;----------
10352 .org 0xf841 ; INT 12h Memory Size Service Entry Point
10353 ; ??? different for Pentium (machine check)?
10354 int12_handler:
10355   push ds
10356   mov  ax, #0x0040
10357   mov  ds, ax
10358   mov  ax, 0x0013
10359   pop  ds
10360   iret
10361
10362 ;----------
10363 ;- INT11h -
10364 ;----------
10365 .org 0xf84d ; INT 11h Equipment List Service Entry Point
10366 int11_handler:
10367   push ds
10368   mov  ax, #0x0040
10369   mov  ds, ax
10370   mov  ax, 0x0010
10371   pop  ds
10372   iret
10373
10374 ;----------
10375 ;- INT15h -
10376 ;----------
10377 .org 0xf859 ; INT 15h System Services Entry Point
10378 int15_handler:
10379   pushf
10380 #if BX_APM
10381   cmp ah, #0x53
10382   je apm_call
10383 #endif
10384   push  ds
10385   push  es
10386   cmp  ah, #0x86
10387   je int15_handler32
10388   cmp  ah, #0xE8
10389   je int15_handler32
10390   pusha
10391 #if BX_USE_PS2_MOUSE
10392   cmp  ah, #0xC2
10393   je int15_handler_mouse
10394 #endif
10395   call _int15_function
10396 int15_handler_mouse_ret:
10397   popa
10398 int15_handler32_ret:
10399   pop   es
10400   pop   ds
10401   popf
10402   jmp iret_modify_cf
10403 #if BX_APM
10404 apm_call:
10405   jmp _apmreal_entry
10406 #endif
10407
10408 #if BX_USE_PS2_MOUSE
10409 int15_handler_mouse:
10410   call _int15_function_mouse
10411   jmp int15_handler_mouse_ret
10412 #endif
10413
10414 int15_handler32:
10415   pushad
10416   call _int15_function32
10417   popad
10418   jmp int15_handler32_ret
10419
10420 ;; Protected mode IDT descriptor
10421 ;;
10422 ;; I just make the limit 0, so the machine will shutdown
10423 ;; if an exception occurs during protected mode memory
10424 ;; transfers.
10425 ;;
10426 ;; Set base to f0000 to correspond to beginning of BIOS,
10427 ;; in case I actually define an IDT later
10428 ;; Set limit to 0
10429
10430 pmode_IDT_info:
10431 dw 0x0000  ;; limit 15:00
10432 dw 0x0000  ;; base  15:00
10433 db 0x0f    ;; base  23:16
10434
10435 ;; Real mode IDT descriptor
10436 ;;
10437 ;; Set to typical real-mode values.
10438 ;; base  = 000000
10439 ;; limit =   03ff
10440
10441 rmode_IDT_info:
10442 dw 0x03ff  ;; limit 15:00
10443 dw 0x0000  ;; base  15:00
10444 db 0x00    ;; base  23:16
10445
10446
10447 ;----------
10448 ;- INT1Ah -
10449 ;----------
10450 .org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
10451 int1a_handler:
10452 #if BX_PCIBIOS
10453   cmp  ah, #0xb1
10454   jne  int1a_normal
10455   call pcibios_real
10456   jc   pcibios_error
10457   retf 2
10458 pcibios_error:
10459   mov  bl, ah
10460   mov  ah, #0xb1
10461   push ds
10462   pusha
10463   mov ax, ss  ; set readable descriptor to ds, for calling pcibios
10464   mov ds, ax  ;  on 16bit protected mode.
10465   jmp int1a_callfunction
10466 int1a_normal:
10467 #endif
10468   push ds
10469   pusha
10470   xor  ax, ax
10471   mov  ds, ax
10472 int1a_callfunction:
10473   call _int1a_function
10474   popa
10475   pop  ds
10476   iret
10477
10478 ;;
10479 ;; int70h: IRQ8 - CMOS RTC
10480 ;;
10481 int70_handler:
10482   push ds
10483   pusha
10484   xor  ax, ax
10485   mov  ds, ax
10486   call _int70_function
10487   popa
10488   pop  ds
10489   iret
10490
10491 ;---------
10492 ;- INT08 -
10493 ;---------
10494 .org 0xfea5 ; INT 08h System Timer ISR Entry Point
10495 int08_handler:
10496   sti
10497   push eax
10498   push ds
10499   xor ax, ax
10500   mov ds, ax
10501
10502   ;; time to turn off drive(s)?
10503   mov  al,0x0440
10504   or   al,al
10505   jz   int08_floppy_off
10506   dec  al
10507   mov  0x0440,al
10508   jnz  int08_floppy_off
10509   ;; turn motor(s) off
10510   push dx
10511   mov  dx,#0x03f2
10512   in   al,dx
10513   and  al,#0xcf
10514   out  dx,al
10515   pop  dx
10516 int08_floppy_off:
10517
10518   mov eax, 0x046c ;; get ticks dword
10519   inc eax
10520
10521   ;; compare eax to one days worth of timer ticks at 18.2 hz
10522   cmp eax, #0x001800B0
10523   jb  int08_store_ticks
10524   ;; there has been a midnight rollover at this point
10525   xor eax, eax    ;; zero out counter
10526   inc BYTE 0x0470 ;; increment rollover flag
10527
10528 int08_store_ticks:
10529   mov 0x046c, eax ;; store new ticks dword
10530   ;; chain to user timer tick INT #0x1c
10531   //pushf
10532   //;; call_ep [ds:loc]
10533   //CALL_EP( 0x1c << 2 )
10534   int #0x1c
10535   cli
10536   call eoi_master_pic
10537   pop ds
10538   pop eax
10539   iret
10540
10541 .org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
10542
10543
10544 .org 0xff00
10545 .ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team."
10546
10547 ;------------------------------------------------
10548 ;- IRET Instruction for Dummy Interrupt Handler -
10549 ;------------------------------------------------
10550 .org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
10551 dummy_iret_handler:
10552   iret
10553
10554 .org 0xff54 ; INT 05h Print Screen Service Entry Point
10555   HALT(__LINE__)
10556   iret
10557
10558 #ifdef HVMTEST
10559 .org 0xffe0
10560   jmp 0xf000:post;
10561 #endif
10562
10563 .org 0xfff0 ; Power-up Entry Point
10564 #ifdef HVMTEST
10565   jmp 0xd000:0x0003;
10566 #else
10567   jmp 0xf000:post
10568 #endif
10569
10570 .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10571 .ascii BIOS_BUILD_DATE
10572
10573 .org 0xfffe ; System Model ID
10574 db SYS_MODEL_ID
10575 db 0x00   ; filler
10576
10577 .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
10578 ASM_END
10579 /*
10580  * This font comes from the fntcol16.zip package (c) by  Joseph Gil 
10581  * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
10582  * This font is public domain
10583  */ 
10584 static Bit8u vgafont8[128*8]=
10585 {
10586  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10587  0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
10588  0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
10589  0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10590  0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
10591  0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
10592  0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
10593  0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
10594  0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
10595  0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
10596  0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
10597  0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
10598  0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
10599  0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
10600  0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
10601  0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
10602  0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
10603  0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
10604  0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
10605  0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
10606  0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
10607  0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
10608  0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
10609  0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
10610  0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
10611  0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
10612  0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
10613  0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
10614  0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
10615  0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
10616  0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
10617  0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
10618  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10619  0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
10620  0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
10621  0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
10622  0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
10623  0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
10624  0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
10625  0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
10626  0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
10627  0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
10628  0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
10629  0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
10630  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
10631  0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
10632  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
10633  0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
10634  0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
10635  0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
10636  0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
10637  0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
10638  0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
10639  0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
10640  0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
10641  0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
10642  0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
10643  0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
10644  0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
10645  0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
10646  0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
10647  0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
10648  0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
10649  0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
10650  0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
10651  0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
10652  0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
10653  0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
10654  0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
10655  0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
10656  0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
10657  0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
10658  0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
10659  0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10660  0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
10661  0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
10662  0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
10663  0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
10664  0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
10665  0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
10666  0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
10667  0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
10668  0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
10669  0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
10670  0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10671  0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
10672  0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10673  0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
10674  0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
10675  0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
10676  0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
10677  0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
10678  0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
10679  0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
10680  0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
10681  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
10682  0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
10683  0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
10684  0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
10685  0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
10686  0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
10687  0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
10688  0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
10689  0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10690  0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
10691  0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
10692  0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
10693  0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
10694  0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
10695  0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
10696  0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
10697  0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
10698  0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
10699  0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
10700  0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
10701  0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
10702  0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
10703  0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
10704  0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
10705  0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
10706  0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
10707  0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
10708  0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
10709  0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
10710  0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
10711  0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
10712  0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10713  0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
10714 };
10715
10716 #ifdef HVMASSIST
10717 //
10718 // MP Tables
10719 // just carve out some blank space for HVMLOADER to write the MP tables to
10720 //
10721 // NOTE: There should be enough space for a 32 processor entry MP table
10722 //
10723 ASM_START
10724 .org 0xcc00
10725 db 0x5F, 0x5F, 0x5F, 0x48, 0x56, 0x4D, 0x4D, 0x50 ;; ___HVMMP
10726 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;;  64 bytes
10727 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 128 bytes
10728 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 192 bytes
10729 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 256 bytes
10730 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 320 bytes
10731 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 384 bytes
10732 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 448 bytes
10733 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 512 bytes
10734 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 576 bytes
10735 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 640 bytes
10736 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 704 bytes
10737 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 768 bytes
10738 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 832 bytes
10739 dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;; 896 bytes
10740
10741 .align 16
10742 smbios_entry_point:
10743 db 0,0,0,0,0,0,0,0 ; 8 bytes
10744 db 0,0,0,0,0,0,0,0 ; 16 bytes
10745 db 0,0,0,0,0,0,0,0 ; 24 bytes
10746 db 0,0,0,0,0,0,0   ; 31 bytes
10747 ASM_END
10748
10749 #else // !HVMASSIST
10750
10751 ASM_START
10752 .org 0xcc00
10753 // bcc-generated data will be placed here
10754
10755 // For documentation of this config structure, look on developer.intel.com and
10756 // search for multiprocessor specification.  Note that when you change anything
10757 // you must update the checksum (a pain!).  It would be better to construct this
10758 // with C structures, or at least fill in the checksum automatically.
10759 //
10760 // Maybe this structs could be moved elsewhere than d000
10761
10762 #if (BX_SMP_PROCESSORS==1)
10763   // no structure necessary.
10764 #elif (BX_SMP_PROCESSORS==2)
10765 // define the Intel MP Configuration Structure for 2 processors at
10766 // APIC ID 0,1.  I/O APIC at ID=2.
10767 .align 16
10768 mp_config_table:
10769   db 0x50, 0x43, 0x4d, 0x50  ;; "PCMP" signature
10770   dw (mp_config_end-mp_config_table)  ;; table length
10771   db 4 ;; spec rev
10772   db 0x65 ;; checksum
10773   .ascii "BOCHSCPU"     ;; OEM id = "BOCHSCPU"
10774   db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1         "
10775   db 0x20, 0x20, 0x20, 0x20 
10776   db 0x20, 0x20, 0x20, 0x20
10777   dw 0,0 ;; oem table ptr
10778   dw 0 ;; oem table size
10779   dw 20 ;; entry count
10780   dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10781   dw 0 ;; extended table length
10782   db 0 ;; extended table checksum
10783   db 0 ;; reserved
10784 mp_config_proc0:
10785   db 0 ;; entry type=processor
10786   db 0 ;; local APIC id
10787   db 0x11 ;; local APIC version number
10788   db 3 ;; cpu flags: enabled, bootstrap processor
10789   db 0,6,0,0 ;; cpu signature
10790   dw 0x201,0 ;; feature flags
10791   dw 0,0 ;; reserved
10792   dw 0,0 ;; reserved
10793 mp_config_proc1:
10794   db 0 ;; entry type=processor
10795   db 1 ;; local APIC id
10796   db 0x11 ;; local APIC version number
10797   db 1 ;; cpu flags: enabled
10798   db 0,6,0,0 ;; cpu signature
10799   dw 0x201,0 ;; feature flags
10800   dw 0,0 ;; reserved
10801   dw 0,0 ;; reserved
10802 mp_config_isa_bus:
10803   db 1 ;; entry type=bus
10804   db 0 ;; bus ID
10805   db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20  ;; bus type="ISA   "
10806 mp_config_ioapic:
10807   db 2 ;; entry type=I/O APIC
10808   db 2 ;; apic id=2. linux will set.
10809   db 0x11 ;; I/O APIC version number
10810   db 1 ;; flags=1=enabled
10811   dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10812 mp_config_irqs:
10813   db 3 ;; entry type=I/O interrupt
10814   db 0 ;; interrupt type=vectored interrupt
10815   db 0,0 ;; flags po=0, el=0 (linux uses as default)
10816   db 0 ;; source bus ID is ISA
10817   db 0 ;; source bus IRQ
10818   db 2 ;; destination I/O APIC ID
10819   db 0 ;; destination I/O APIC interrrupt in
10820   ;; repeat pattern for interrupts 0-15
10821   db 3,0,0,0,0,1,2,1
10822   db 3,0,0,0,0,2,2,2
10823   db 3,0,0,0,0,3,2,3
10824   db 3,0,0,0,0,4,2,4
10825   db 3,0,0,0,0,5,2,5
10826   db 3,0,0,0,0,6,2,6
10827   db 3,0,0,0,0,7,2,7
10828   db 3,0,0,0,0,8,2,8
10829   db 3,0,0,0,0,9,2,9
10830   db 3,0,0,0,0,10,2,10
10831   db 3,0,0,0,0,11,2,11
10832   db 3,0,0,0,0,12,2,12
10833   db 3,0,0,0,0,13,2,13
10834   db 3,0,0,0,0,14,2,14
10835   db 3,0,0,0,0,15,2,15
10836 #elif (BX_SMP_PROCESSORS==4)
10837 // define the Intel MP Configuration Structure for 4 processors at
10838 // APIC ID 0,1,2,3.  I/O APIC at ID=4.
10839 .align 16
10840 mp_config_table:
10841   db 0x50, 0x43, 0x4d, 0x50  ;; "PCMP" signature
10842   dw (mp_config_end-mp_config_table)  ;; table length
10843   db 4 ;; spec rev
10844   db 0xdd ;; checksum
10845   .ascii "BOCHSCPU"     ;; OEM id = "BOCHSCPU"
10846   db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1         "
10847   db 0x20, 0x20, 0x20, 0x20 
10848   db 0x20, 0x20, 0x20, 0x20
10849   dw 0,0 ;; oem table ptr
10850   dw 0 ;; oem table size
10851   dw 22 ;; entry count
10852   dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10853   dw 0 ;; extended table length
10854   db 0 ;; extended table checksum
10855   db 0 ;; reserved
10856 mp_config_proc0:
10857   db 0 ;; entry type=processor
10858   db 0 ;; local APIC id
10859   db 0x11 ;; local APIC version number
10860   db 3 ;; cpu flags: enabled, bootstrap processor
10861   db 0,6,0,0 ;; cpu signature
10862   dw 0x201,0 ;; feature flags
10863   dw 0,0 ;; reserved
10864   dw 0,0 ;; reserved
10865 mp_config_proc1:
10866   db 0 ;; entry type=processor
10867   db 1 ;; local APIC id
10868   db 0x11 ;; local APIC version number
10869   db 1 ;; cpu flags: enabled
10870   db 0,6,0,0 ;; cpu signature
10871   dw 0x201,0 ;; feature flags
10872   dw 0,0 ;; reserved
10873   dw 0,0 ;; reserved
10874 mp_config_proc2:
10875   db 0 ;; entry type=processor
10876   db 2 ;; local APIC id
10877   db 0x11 ;; local APIC version number
10878   db 1 ;; cpu flags: enabled
10879   db 0,6,0,0 ;; cpu signature
10880   dw 0x201,0 ;; feature flags
10881   dw 0,0 ;; reserved
10882   dw 0,0 ;; reserved
10883 mp_config_proc3:
10884   db 0 ;; entry type=processor
10885   db 3 ;; local APIC id
10886   db 0x11 ;; local APIC version number
10887   db 1 ;; cpu flags: enabled
10888   db 0,6,0,0 ;; cpu signature
10889   dw 0x201,0 ;; feature flags
10890   dw 0,0 ;; reserved
10891   dw 0,0 ;; reserved
10892 mp_config_isa_bus:
10893   db 1 ;; entry type=bus
10894   db 0 ;; bus ID
10895   db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20  ;; bus type="ISA   "
10896 mp_config_ioapic:
10897   db 2 ;; entry type=I/O APIC
10898   db 4 ;; apic id=4. linux will set.
10899   db 0x11 ;; I/O APIC version number
10900   db 1 ;; flags=1=enabled
10901   dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
10902 mp_config_irqs:
10903   db 3 ;; entry type=I/O interrupt
10904   db 0 ;; interrupt type=vectored interrupt
10905   db 0,0 ;; flags po=0, el=0 (linux uses as default)
10906   db 0 ;; source bus ID is ISA
10907   db 0 ;; source bus IRQ
10908   db 4 ;; destination I/O APIC ID
10909   db 0 ;; destination I/O APIC interrrupt in
10910   ;; repeat pattern for interrupts 0-15
10911   db 3,0,0,0,0,1,4,1
10912   db 3,0,0,0,0,2,4,2
10913   db 3,0,0,0,0,3,4,3
10914   db 3,0,0,0,0,4,4,4
10915   db 3,0,0,0,0,5,4,5
10916   db 3,0,0,0,0,6,4,6
10917   db 3,0,0,0,0,7,4,7
10918   db 3,0,0,0,0,8,4,8
10919   db 3,0,0,0,0,9,4,9
10920   db 3,0,0,0,0,10,4,10
10921   db 3,0,0,0,0,11,4,11
10922   db 3,0,0,0,0,12,4,12
10923   db 3,0,0,0,0,13,4,13
10924   db 3,0,0,0,0,14,4,14
10925   db 3,0,0,0,0,15,4,15
10926 #elif (BX_SMP_PROCESSORS==8)
10927 // define the Intel MP Configuration Structure for 8 processors at
10928 // APIC ID 0,1,2,3,4,5,6,7.  I/O APIC at ID=8.
10929 .align 16
10930 mp_config_table:
10931   db 0x50, 0x43, 0x4d, 0x50  ;; "PCMP" signature
10932   dw (mp_config_end-mp_config_table)  ;; table length
10933   db 4 ;; spec rev
10934   db 0xc3 ;; checksum
10935   .ascii "BOCHSCPU"     ;; OEM id = "BOCHSCPU"
10936   db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1         "
10937   db 0x20, 0x20, 0x20, 0x20 
10938   db 0x20, 0x20, 0x20, 0x20
10939   dw 0,0 ;; oem table ptr
10940   dw 0 ;; oem table size
10941   dw 26 ;; entry count
10942   dw 0x0000, 0xfee0 ;; memory mapped address of local APIC
10943   dw 0 ;; extended table length
10944   db 0 ;; extended table checksum
10945   db 0 ;; reserved
10946 mp_config_proc0:
10947   db 0 ;; entry type=processor
10948   db 0 ;; local APIC id
10949   db 0x11 ;; local APIC version number
10950   db 3 ;; cpu flags: enabled, bootstrap processor
10951   db 0,6,0,0 ;; cpu signature
10952   dw 0x201,0 ;; feature flags
10953   dw 0,0 ;; reserved
10954   dw 0,0 ;; reserved
10955 mp_config_proc1:
10956   db 0 ;; entry type=processor
10957   db 1 ;; local APIC id
10958   db 0x11 ;; local APIC version number
10959   db 1 ;; cpu flags: enabled
10960   db 0,6,0,0 ;; cpu signature
10961   dw 0x201,0 ;; feature flags
10962   dw 0,0 ;; reserved
10963   dw 0,0 ;; reserved
10964 mp_config_proc2:
10965   db 0 ;; entry type=processor
10966   db 2 ;; local APIC id
10967   db 0x11 ;; local APIC version number
10968   db 1 ;; cpu flags: enabled
10969   db 0,6,0,0 ;; cpu signature
10970   dw 0x201,0 ;; feature flags
10971   dw 0,0 ;; reserved
10972   dw 0,0 ;; reserved
10973 mp_config_proc3:
10974   db 0 ;; entry type=processor
10975   db 3 ;; local APIC id
10976   db 0x11 ;; local APIC version number
10977   db 1 ;; cpu flags: enabled
10978   db 0,6,0,0 ;; cpu signature
10979   dw 0x201,0 ;; feature flags
10980   dw 0,0 ;; reserved
10981   dw 0,0 ;; reserved
10982 mp_config_proc4:
10983   db 0 ;; entry type=processor
10984   db 4 ;; local APIC id
10985   db 0x11 ;; local APIC version number
10986   db 1 ;; cpu flags: enabled
10987   db 0,6,0,0 ;; cpu signature
10988   dw 0x201,0 ;; feature flags
10989   dw 0,0 ;; reserved
10990   dw 0,0 ;; reserved
10991 mp_config_proc5:
10992   db 0 ;; entry type=processor
10993   db 5 ;; local APIC id
10994   db 0x11 ;; local APIC version number
10995   db 1 ;; cpu flags: enabled
10996   db 0,6,0,0 ;; cpu signature
10997   dw 0x201,0 ;; feature flags
10998   dw 0,0 ;; reserved
10999   dw 0,0 ;; reserved
11000 mp_config_proc6:
11001   db 0 ;; entry type=processor
11002   db 6 ;; local APIC id
11003   db 0x11 ;; local APIC version number
11004   db 1 ;; cpu flags: enabled
11005   db 0,6,0,0 ;; cpu signature
11006   dw 0x201,0 ;; feature flags
11007   dw 0,0 ;; reserved
11008   dw 0,0 ;; reserved
11009 mp_config_proc7:
11010   db 0 ;; entry type=processor
11011   db 7 ;; local APIC id
11012   db 0x11 ;; local APIC version number
11013   db 1 ;; cpu flags: enabled
11014   db 0,6,0,0 ;; cpu signature
11015   dw 0x201,0 ;; feature flags
11016   dw 0,0 ;; reserved
11017   dw 0,0 ;; reserved
11018 mp_config_isa_bus:
11019   db 1 ;; entry type=bus
11020   db 0 ;; bus ID
11021   db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20  ;; bus type="ISA   "
11022 mp_config_ioapic:
11023   db 2 ;; entry type=I/O APIC
11024   db 8 ;; apic id=8
11025   db 0x11 ;; I/O APIC version number
11026   db 1 ;; flags=1=enabled
11027   dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC
11028 mp_config_irqs:
11029   db 3 ;; entry type=I/O interrupt
11030   db 0 ;; interrupt type=vectored interrupt
11031   db 0,0 ;; flags po=0, el=0 (linux uses as default)
11032   db 0 ;; source bus ID is ISA
11033   db 0 ;; source bus IRQ
11034   db 8 ;; destination I/O APIC ID
11035   db 0 ;; destination I/O APIC interrrupt in
11036   ;; repeat pattern for interrupts 0-15
11037   db 3,0,0,0,0,1,8,1
11038   db 3,0,0,0,0,2,8,2
11039   db 3,0,0,0,0,3,8,3
11040   db 3,0,0,0,0,4,8,4
11041   db 3,0,0,0,0,5,8,5
11042   db 3,0,0,0,0,6,8,6
11043   db 3,0,0,0,0,7,8,7
11044   db 3,0,0,0,0,8,8,8
11045   db 3,0,0,0,0,9,8,9
11046   db 3,0,0,0,0,10,8,10
11047   db 3,0,0,0,0,11,8,11
11048   db 3,0,0,0,0,12,8,12
11049   db 3,0,0,0,0,13,8,13
11050   db 3,0,0,0,0,14,8,14
11051   db 3,0,0,0,0,15,8,15
11052 #else
11053 #  error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors.
11054 #endif  // if (BX_SMP_PROCESSORS==...)
11055
11056 mp_config_end:   // this label used to find length of mp structure
11057  db 0
11058
11059 #if (BX_SMP_PROCESSORS>1)
11060 .align 16
11061 mp_floating_pointer_structure:
11062 db 0x5f, 0x4d, 0x50, 0x5f   ; "_MP_" signature
11063 dw mp_config_table, 0xf ;; pointer to MP configuration table
11064 db 1     ;; length of this struct in 16-bit byte chunks
11065 db 4     ;; MP spec revision
11066 db 0xc1  ;; checksum
11067 db 0     ;; MP feature byte 1.  value 0 means look at the config table
11068 db 0,0,0,0     ;; MP feature bytes 2-5.
11069 #endif
11070
11071 ASM_END
11072
11073 #endif // HVMASSIST