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.


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