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.


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