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