Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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