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.


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