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.


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