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.


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