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.


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