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.


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