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.


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