OpenCores
URL https://opencores.org/ocsvn/zet86/zet86/trunk

Subversion Repositories zet86

[/] [zet86/] [trunk/] [soc/] [bios/] [rombios.c] - Blame information for rev 52

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 zeus
// ROM BIOS compatability entry points:
2
// ===================================
3
// $e05b ; POST Entry Point
4
// $e6f2 ; INT 19h Boot Load Service Entry Point
5
// $f045 ; INT 10 Functions 0-Fh Entry Point
6
// $f065 ; INT 10h Video Support Service Entry Point
7
// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
8
// $fff0 ; Power-up Entry Point
9
// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
10
// $fffe ; System Model ID
11
 
12
#include "rombios.h"
13
 
14 45 zeus
#define BX_CPU           0
15
 
16 26 zeus
   /* model byte 0xFC = AT */
17
#define SYS_MODEL_ID     0xFC
18
 
19
#ifndef BIOS_BUILD_DATE
20
#  define BIOS_BUILD_DATE "06/23/99"
21
#endif
22
 
23
  // 1K of base memory used for Extended Bios Data Area (EBDA)
24
  // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
25
#define EBDA_SEG           0x9FC0
26
#define EBDA_SIZE          1              // In KiB
27
#define BASE_MEM_IN_K   (640 - EBDA_SIZE)
28
 
29
/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
30
#define IPL_SEG              0x9ff0
31
#define IPL_TABLE_OFFSET     0x0000
32
#define IPL_TABLE_ENTRIES    8
33
#define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
34
#define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
35
#define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
36
#define IPL_SIZE             0xff
37
#define IPL_TYPE_FLOPPY      0x01
38
#define IPL_TYPE_HARDDISK    0x02
39
#define IPL_TYPE_CDROM       0x03
40
#define IPL_TYPE_BEV         0x80
41
 
42
// This is for compiling with gcc2 and gcc3
43
#define ASM_START #asm
44
#define ASM_END #endasm
45
 
46
ASM_START
47
.rom
48
 
49
.org 0x0000
50
 
51
use16 8086
52
 
53
MACRO SET_INT_VECTOR
54
  mov ax, ?3
55
  mov ?1*4, ax
56
  mov ax, ?2
57
  mov ?1*4+2, ax
58
MEND
59
 
60
ASM_END
61
 
62
typedef unsigned char  Bit8u;
63
typedef unsigned short Bit16u;
64
typedef unsigned short bx_bool;
65
typedef unsigned long  Bit32u;
66
 
67
 
68
  void memsetb(seg,offset,value,count);
69
  void memcpyb(dseg,doffset,sseg,soffset,count);
70
  void memcpyd(dseg,doffset,sseg,soffset,count);
71
 
72
  // memset of count bytes
73
    void
74
  memsetb(seg,offset,value,count)
75
    Bit16u seg;
76
    Bit16u offset;
77
    Bit16u value;
78
    Bit16u count;
79
  {
80
  ASM_START
81
    push bp
82
    mov  bp, sp
83
 
84
      push ax
85
      push cx
86
      push es
87
      push di
88
 
89
      mov  cx, 10[bp] ; count
90
      test cx, cx
91
      je   memsetb_end
92
      mov  ax, 4[bp] ; segment
93
      mov  es, ax
94
      mov  ax, 6[bp] ; offset
95
      mov  di, ax
96
      mov  al, 8[bp] ; value
97
      cld
98
      rep
99
       stosb
100
 
101
  memsetb_end:
102
      pop di
103
      pop es
104
      pop cx
105
      pop ax
106
 
107
    pop bp
108
  ASM_END
109
  }
110
 
111
  // memcpy of count bytes
112
    void
113
  memcpyb(dseg,doffset,sseg,soffset,count)
114
    Bit16u dseg;
115
    Bit16u doffset;
116
    Bit16u sseg;
117
    Bit16u soffset;
118
    Bit16u count;
119
  {
120
  ASM_START
121
    push bp
122
    mov  bp, sp
123
 
124
      push ax
125
      push cx
126
      push es
127
      push di
128
      push ds
129
      push si
130
 
131
      mov  cx, 12[bp] ; count
132
      test cx, cx
133
      je   memcpyb_end
134
      mov  ax, 4[bp] ; dsegment
135
      mov  es, ax
136
      mov  ax, 6[bp] ; doffset
137
      mov  di, ax
138
      mov  ax, 8[bp] ; ssegment
139
      mov  ds, ax
140
      mov  ax, 10[bp] ; soffset
141
      mov  si, ax
142
      cld
143
      rep
144
       movsb
145
 
146
  memcpyb_end:
147
      pop si
148
      pop ds
149
      pop di
150
      pop es
151
      pop cx
152
      pop ax
153
 
154
    pop bp
155
  ASM_END
156
  }
157
 
158
  // Bit32u (unsigned long) and long helper functions
159
  ASM_START
160
 
161
  idiv_u:
162
    xor dx,dx
163
    div bx
164
    ret
165
 
166
  ldivul:
167
    mov     cx,[di]
168
    mov     di,2[di]
169
    call    ludivmod
170
    xchg    ax,cx
171
    xchg    bx,di
172
    ret
173
 
174
.align 2
175
ldivmod:
176
    mov     dx,di           ; sign byte of b in dh
177
    mov     dl,bh           ; sign byte of a in dl
178
    test    di,di
179
    jns     set_asign
180
    neg     di
181
    neg     cx
182
    sbb     di,*0
183
set_asign:
184
    test    bx,bx
185
    jns     got_signs       ; leave r = a positive
186
    neg     bx
187
    neg     ax
188
    sbb     bx,*0
189
    j       got_signs
190
 
191
.align 2
192
ludivmod:
193
    xor     dx,dx           ; both sign bytes 0
194
got_signs:
195
    push    bp
196
    push    si
197
    mov     bp,sp
198
    push    di              ; remember b
199
    push    cx
200
b0  =       -4
201
b16 =       -2
202
 
203
    test    di,di
204
    jne     divlarge
205
    test    cx,cx
206
    je      divzero
207
    cmp     bx,cx
208
    jae     divlarge        ; would overflow
209
    xchg    dx,bx           ; a in dx:ax, signs in bx
210
    div     cx
211
    xchg    cx,ax           ; q in di:cx, junk in ax
212
    xchg    ax,bx           ; signs in ax, junk in bx
213
    xchg    ax,dx           ; r in ax, signs back in dx
214
    mov     bx,di           ; r in bx:ax
215
    j       zdivu1
216
 
217
divzero:                        ; return q = 0 and r = a
218
    test    dl,dl
219
    jns     return
220
    j       negr            ; a initially minus, restore it
221
 
222
divlarge:
223
    push    dx              ; remember sign bytes
224
    mov     si,di           ; w in si:dx, initially b from di:cx
225
    mov     dx,cx
226
    xor     cx,cx           ; q in di:cx, initially 0
227
    mov     di,cx
228
                            ; r in bx:ax, initially a
229
                            ; use di:cx rather than dx:cx in order
230
                            ; to have dx free for a byte pair later
231
    cmp     si,bx
232
    jb      loop1
233
    ja      zdivu           ; finished if b > r
234
    cmp     dx,ax
235
    ja      zdivu
236
 
237
; rotate w (= b) to greatest dyadic multiple of b <= r
238
 
239
loop1:
240
    shl     dx,*1           ; w = 2*w
241
    rcl     si,*1
242
    jc      loop1_exit      ; w was > r counting overflow (unsigned)
243
    cmp     si,bx           ; while w <= r (unsigned)
244
    jb      loop1
245
    ja      loop1_exit
246
    cmp     dx,ax
247
    jbe     loop1           ; else exit with carry clear for rcr
248
loop1_exit:
249
    rcr     si,*1
250
    rcr     dx,*1
251
loop2:
252
    shl     cx,*1           ; q = 2*q
253
    rcl     di,*1
254
    cmp     si,bx           ; if w <= r
255
    jb      loop2_over
256
    ja      loop2_test
257
    cmp     dx,ax
258
    ja      loop2_test
259
loop2_over:
260
    add     cx,*1           ; q++
261
    adc     di,*0
262
    sub     ax,dx           ; r = r-w
263
    sbb     bx,si
264
loop2_test:
265
    shr     si,*1           ; w = w/2
266
    rcr     dx,*1
267
    cmp     si,b16[bp]      ; while w >= b
268
    ja      loop2
269
    jb      zdivu
270
    cmp     dx,b0[bp]
271
    jae     loop2
272
 
273
zdivu:
274
    pop     dx              ; sign bytes
275
zdivu1:
276
    test    dh,dh
277
    js      zbminus
278
    test    dl,dl
279
    jns     return          ; else a initially minus, b plus
280
    mov     dx,ax           ; -a = b * q + r ==> a = b * (-q) + (-r)
281
    or      dx,bx
282
    je      negq            ; use if r = 0
283
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b - r)
284
    sbb     bx,b16[bp]
285
    not     cx              ; q = -1 - q (same as complement)
286
    not     di
287
negr:
288
    neg     bx
289
    neg     ax
290
    sbb     bx,*0
291
return:
292
    mov     sp,bp
293
    pop     si
294
    pop     bp
295
    ret
296
 
297
.align 2
298
zbminus:
299
    test    dl,dl           ; (-a) = (-b) * q + r ==> a = b * q + (-r)
300
    js      negr            ; use if initial a was minus
301
    mov     dx,ax           ; a = (-b) * q + r ==> a = b * (-q) + r
302
    or      dx,bx
303
    je      negq            ; use if r = 0
304
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b + r)
305
                                ; (b is now -b)
306
    sbb     bx,b16[bp]
307
    not     cx
308
    not     di
309
    mov     sp,bp
310
    pop     si
311
    pop     bp
312
    ret
313
 
314
.align 2
315
negq:
316
    neg     di
317
    neg     cx
318
    sbb     di,*0
319
    mov     sp,bp
320
    pop     si
321
    pop     bp
322
    ret
323
 
324
.align 2
325
ltstl:
326
ltstul:
327
    test    bx,bx
328
    je      ltst_not_sure
329
    ret
330
 
331
.align 2
332
ltst_not_sure:
333
    test    ax,ax
334
    js      ltst_fix_sign
335
    ret
336
 
337
.align 2
338
ltst_fix_sign:
339
    inc     bx
340
    ret
341
 
342
.align 2
343
lmull:
344
lmulul:
345
    mov     cx,ax
346
    mul     word ptr 2[di]
347
    xchg    ax,bx
348
    mul     word ptr [di]
349
    add     bx,ax
350
    mov     ax,ptr [di]
351
    mul     cx
352
    add     bx,dx
353
    ret
354
 
355
.align 2
356
lsubl:
357
lsubul:
358
    sub     ax,[di]
359
    sbb     bx,2[di]
360
    ret
361
 
362
.align 2
363
laddl:
364
laddul:
365
    add     ax,[di]
366
    adc     bx,2[di]
367
    ret
368
 
369
.align 2
370
lorl:
371
lorul:
372
    or      ax,[di]
373
    or      bx,2[di]
374
    ret
375
 
376
.align 2
377
lsrul:
378
    mov     cx,di
379
    jcxz    lsru_exit
380
    cmp     cx,*32
381
    jae     lsru_zero
382
lsru_loop:
383
    shr     bx,*1
384
    rcr     ax,*1
385
    loop    lsru_loop
386
lsru_exit:
387
    ret
388
 
389
.align 2
390
lsru_zero:
391
    xor     ax,ax
392
    mov     bx,ax
393
    ret
394
 
395
.align 2
396
landl:
397
landul:
398
    and     ax,[di]
399
    and     bx,2[di]
400
    ret
401
 
402
.align 2
403
lcmpl:
404
lcmpul:
405
    sub     bx,2[di]
406
    je      lcmp_not_sure
407
    ret
408
 
409
.align 2
410
lcmp_not_sure:
411
    cmp     ax,[di]
412
    jb      lcmp_b_and_lt
413
    jge     lcmp_exit
414
 
415
    inc     bx
416
lcmp_exit:
417
    ret
418
 
419
.align 2
420
lcmp_b_and_lt:
421
    dec     bx
422
    ret
423
 
424 52 zeus
lincl:
425
lincul:
426
    inc     word ptr [bx]
427
    je      LINC_HIGH_WORD
428
    ret
429
    .even
430
LINC_HIGH_WORD:
431
    inc     word ptr 2[bx]
432
    ret
433
 
434 26 zeus
  ASM_END
435
 
436 47 zeus
// for access to RAM area which is used by interrupt vectors
437
// and BIOS Data Area
438
 
439 26 zeus
typedef struct {
440 47 zeus
  unsigned char filler1[0x400];
441
  unsigned char filler2[0x6c];
442
  Bit16u ticks_low;
443
  Bit16u ticks_high;
444
  Bit8u  midnight_flag;
445
  } bios_data_t;
446
 
447
#define BiosData ((bios_data_t  *) 0)
448
 
449
typedef struct {
450
  union {
451
    struct {
452
      Bit16u di, si, bp, sp;
453
      Bit16u bx, dx, cx, ax;
454
      } r16;
455
    struct {
456
      Bit16u filler[4];
457
      Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
458
      } r8;
459
    } u;
460
  } pusha_regs_t;
461
 
462
typedef struct {
463
  union {
464
    struct {
465
      Bit16u flags;
466
      } r16;
467
    struct {
468
      Bit8u  flagsl;
469
      Bit8u  flagsh;
470
      } r8;
471
    } u;
472
  } flags_t;
473
 
474
#define SetCF(x)   x.u.r8.flagsl |= 0x01
475
#define SetZF(x)   x.u.r8.flagsl |= 0x40
476
#define ClearCF(x) x.u.r8.flagsl &= 0xfe
477
#define ClearZF(x) x.u.r8.flagsl &= 0xbf
478
#define GetCF(x)   (x.u.r8.flagsl & 0x01)
479
 
480
typedef struct {
481
  Bit16u ip;
482
  Bit16u cs;
483
  flags_t flags;
484
  } iret_addr_t;
485
 
486
typedef struct {
487 26 zeus
  Bit16u type;
488
  Bit16u flags;
489
  Bit32u vector;
490
  Bit32u description;
491
  Bit32u reserved;
492
  } ipl_entry_t;
493
 
494 39 zeus
static Bit16u         inw();
495
static void           outw();
496 26 zeus
 
497
static Bit8u          read_byte();
498
static Bit16u         read_word();
499
static void           write_byte();
500
static void           write_word();
501
static void           bios_printf();
502
 
503 43 zeus
static void           int09_function();
504 39 zeus
static void           int13_harddisk();
505 46 zeus
static void           transf_sect();
506 39 zeus
static void           int13_diskette_function();
507 43 zeus
static void           int16_function();
508 26 zeus
static void           int19_function();
509 47 zeus
static void           int1a_function();
510 26 zeus
static Bit16u         get_CS();
511
static Bit16u         get_SS();
512 43 zeus
static unsigned int   enqueue_key();
513
static unsigned int   dequeue_key();
514 39 zeus
static void           set_diskette_ret_status();
515
static void           set_diskette_current_cyl();
516 26 zeus
 
517
static void           print_bios_banner();
518
static void           print_boot_device();
519 39 zeus
static void           print_boot_failure();
520 26 zeus
 
521 43 zeus
#if DEBUG_INT16
522
#  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
523
#else
524
#  define BX_DEBUG_INT16(a...)
525
#endif
526
 
527 39 zeus
#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
528
#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
529
#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
530
#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
531
#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
532
#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
533
#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
534
#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
535
 
536
#define GET_AL() ( AX & 0x00ff )
537
#define GET_BL() ( BX & 0x00ff )
538
#define GET_CL() ( CX & 0x00ff )
539
#define GET_DL() ( DX & 0x00ff )
540
#define GET_AH() ( AX >> 8 )
541
#define GET_BH() ( BX >> 8 )
542
#define GET_CH() ( CX >> 8 )
543
#define GET_DH() ( DX >> 8 )
544
 
545
#define GET_ELDL() ( ELDX & 0x00ff )
546
#define GET_ELDH() ( ELDX >> 8 )
547
 
548
#define SET_CF()     FLAGS |= 0x0001
549
#define CLEAR_CF()   FLAGS &= 0xfffe
550
#define GET_CF()     (FLAGS & 0x0001)
551
 
552
#define SET_ZF()     FLAGS |= 0x0040
553
#define CLEAR_ZF()   FLAGS &= 0xffbf
554
#define GET_ZF()     (FLAGS & 0x0040)
555
 
556 43 zeus
#define UNSUPPORTED_FUNCTION 0x86
557
 
558
#define none 0
559
#define MAX_SCAN_CODE 0x58
560
 
561
static struct {
562
  Bit16u normal;
563
  Bit16u shift;
564
  Bit16u control;
565
  Bit16u alt;
566
  Bit8u lock_flags;
567
  } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
568
      {   none,   none,   none,   none, none },
569
      { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
570
      { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
571
      { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
572
      { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
573
      { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
574
      { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
575
      { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
576
      { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
577
      { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
578
      { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
579
      { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
580
      { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
581
      { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
582
      { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
583
      { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
584
      { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
585
      { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
586
      { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
587
      { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
588
      { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
589
      { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
590
      { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
591
      { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
592
      { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
593
      { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
594
      { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
595
      { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
596
      { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
597
      {   none,   none,   none,   none, none }, /* L Ctrl */
598
      { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
599
      { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
600
      { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
601
      { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
602
      { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
603
      { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
604
      { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
605
      { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
606
      { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
607
      { 0x273b, 0x273a,   none,   none, none }, /* ;: */
608
      { 0x2827, 0x2822,   none,   none, none }, /* '" */
609
      { 0x2960, 0x297e,   none,   none, none }, /* `~ */
610
      {   none,   none,   none,   none, none }, /* L shift */
611
      { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
612
      { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
613
      { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
614
      { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
615
      { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
616
      { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
617
      { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
618
      { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
619
      { 0x332c, 0x333c,   none,   none, none }, /* ,< */
620
      { 0x342e, 0x343e,   none,   none, none }, /* .> */
621
      { 0x352f, 0x353f,   none,   none, none }, /* /? */
622
      {   none,   none,   none,   none, none }, /* R Shift */
623
      { 0x372a, 0x372a,   none,   none, none }, /* * */
624
      {   none,   none,   none,   none, none }, /* L Alt */
625
      { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
626
      {   none,   none,   none,   none, none }, /* caps lock */
627
      { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
628
      { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
629
      { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
630
      { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
631
      { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
632
      { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
633
      { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
634
      { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
635
      { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
636
      { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
637
      {   none,   none,   none,   none, none }, /* Num Lock */
638
      {   none,   none,   none,   none, none }, /* Scroll Lock */
639
      { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
640
      { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
641
      { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
642
      { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
643
      { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
644
      { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
645
      { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
646
      { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
647
      { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
648
      { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
649
      { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
650
      { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
651
      { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
652
      {   none,   none,   none,   none, none },
653
      {   none,   none,   none,   none, none },
654
      { 0x565c, 0x567c,   none,   none, none }, /* \| */
655
      { 0x5700, 0x5700,   none,   none, none }, /* F11 */
656
      { 0x5800, 0x5800,   none,   none, none }  /* F12 */
657
      };
658
 
659 39 zeus
  Bit16u
660
inw(port)
661
  Bit16u port;
662 26 zeus
{
663
ASM_START
664
  push bp
665
  mov  bp, sp
666
 
667 39 zeus
    push dx
668
    mov  dx, 4[bp]
669
    in   ax, dx
670
    pop  dx
671 26 zeus
 
672
  pop  bp
673
ASM_END
674
}
675
 
676 39 zeus
  void
677
outw(port, val)
678
  Bit16u port;
679
  Bit16u  val;
680
{
681
ASM_START
682
  push bp
683
  mov  bp, sp
684
 
685
    push ax
686
    push dx
687
    mov  dx, 4[bp]
688
    mov  ax, 6[bp]
689
    out  dx, ax
690
    pop  dx
691
    pop  ax
692
 
693
  pop  bp
694
ASM_END
695
}
696
 
697 26 zeus
  Bit8u
698
read_byte(seg, offset)
699
  Bit16u seg;
700
  Bit16u offset;
701
{
702
ASM_START
703
  push bp
704
  mov  bp, sp
705
 
706
    push bx
707
    push ds
708
    mov  ax, 4[bp] ; segment
709
    mov  ds, ax
710
    mov  bx, 6[bp] ; offset
711
    mov  al, [bx]
712
    ;; al = return value (byte)
713
    pop  ds
714
    pop  bx
715
 
716
  pop  bp
717
ASM_END
718
}
719
 
720
  Bit16u
721
read_word(seg, offset)
722
  Bit16u seg;
723
  Bit16u offset;
724
{
725
ASM_START
726
  push bp
727
  mov  bp, sp
728
 
729
    push bx
730
    push ds
731
    mov  ax, 4[bp] ; segment
732
    mov  ds, ax
733
    mov  bx, 6[bp] ; offset
734
    mov  ax, [bx]
735
    ;; ax = return value (word)
736
    pop  ds
737
    pop  bx
738
 
739
  pop  bp
740
ASM_END
741
}
742
 
743
  void
744
write_byte(seg, offset, data)
745
  Bit16u seg;
746
  Bit16u offset;
747
  Bit8u data;
748
{
749
ASM_START
750
  push bp
751
  mov  bp, sp
752
 
753
    push ax
754
    push bx
755
    push ds
756
    mov  ax, 4[bp] ; segment
757
    mov  ds, ax
758
    mov  bx, 6[bp] ; offset
759
    mov  al, 8[bp] ; data byte
760
    mov  [bx], al  ; write data byte
761
    pop  ds
762
    pop  bx
763
    pop  ax
764
 
765
  pop  bp
766
ASM_END
767
}
768
 
769
  void
770
write_word(seg, offset, data)
771
  Bit16u seg;
772
  Bit16u offset;
773
  Bit16u data;
774
{
775
ASM_START
776
  push bp
777
  mov  bp, sp
778
 
779
    push ax
780
    push bx
781
    push ds
782
    mov  ax, 4[bp] ; segment
783
    mov  ds, ax
784
    mov  bx, 6[bp] ; offset
785
    mov  ax, 8[bp] ; data word
786
    mov  [bx], ax  ; write data word
787
    pop  ds
788
    pop  bx
789
    pop  ax
790
 
791
  pop  bp
792
ASM_END
793
}
794
 
795
  Bit16u
796
get_CS()
797
{
798
ASM_START
799
  mov  ax, cs
800
ASM_END
801
}
802
 
803
  Bit16u
804
get_SS()
805
{
806
ASM_START
807
  mov  ax, ss
808
ASM_END
809
}
810
 
811
  void
812
wrch(c)
813
  Bit8u  c;
814
{
815
  ASM_START
816
  push bp
817
  mov  bp, sp
818
 
819
  push bx
820
  mov  ah, #0x0e
821
  mov  al, 4[bp]
822
  xor  bx,bx
823
  int  #0x10
824
  pop  bx
825
 
826
  pop  bp
827
  ASM_END
828
}
829
 
830
  void
831
send(action, c)
832
  Bit16u action;
833
  Bit8u  c;
834
{
835
  if (action & BIOS_PRINTF_SCREEN) {
836
    if (c == '\n') wrch('\r');
837
    wrch(c);
838
  }
839
}
840
 
841
  void
842
put_int(action, val, width, neg)
843
  Bit16u action;
844
  short val, width;
845
  bx_bool neg;
846
{
847
  short nval = val / 10;
848
  if (nval)
849
    put_int(action, nval, width - 1, neg);
850
  else {
851
    while (--width > 0) send(action, ' ');
852
    if (neg) send(action, '-');
853
  }
854
  send(action, val - (nval * 10) + '0');
855
}
856
 
857
  void
858
put_uint(action, val, width, neg)
859
  Bit16u action;
860
  unsigned short val;
861
  short width;
862
  bx_bool neg;
863
{
864
  unsigned short nval = val / 10;
865
  if (nval)
866
    put_uint(action, nval, width - 1, neg);
867
  else {
868
    while (--width > 0) send(action, ' ');
869
    if (neg) send(action, '-');
870
  }
871
  send(action, val - (nval * 10) + '0');
872
}
873
 
874
  void
875
put_luint(action, val, width, neg)
876
  Bit16u action;
877
  unsigned long val;
878
  short width;
879
  bx_bool neg;
880
{
881
  unsigned long nval = val / 10;
882
  if (nval)
883
    put_luint(action, nval, width - 1, neg);
884
  else {
885
    while (--width > 0) send(action, ' ');
886
    if (neg) send(action, '-');
887
  }
888
  send(action, val - (nval * 10) + '0');
889
}
890
 
891
void put_str(action, segment, offset)
892
  Bit16u action;
893
  Bit16u segment;
894
  Bit16u offset;
895
{
896
  Bit8u c;
897
 
898
  while (c = read_byte(segment, offset)) {
899
    send(action, c);
900
    offset++;
901
  }
902
}
903
 
904
//--------------------------------------------------------------------------
905
// bios_printf()
906
//   A compact variable argument printf function.
907
//
908
//   Supports %[format_width][length]format
909
//   where format can be x,X,u,d,s,S,c
910
//   and the optional length modifier is l (ell)
911
//--------------------------------------------------------------------------
912
  void
913
bios_printf(action, s)
914
  Bit16u action;
915
  Bit8u *s;
916
{
917
  Bit8u c, format_char;
918
  bx_bool  in_format;
919
  short i;
920
  Bit16u  *arg_ptr;
921
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
922
 
923
  arg_ptr = &s;
924
  arg_seg = get_SS();
925
 
926
  in_format = 0;
927
  format_width = 0;
928
 
929
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
930
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
931
 
932
  while (c = read_byte(get_CS(), s)) {
933
    if ( c == '%' ) {
934
      in_format = 1;
935
      format_width = 0;
936
      }
937
    else if (in_format) {
938
      if ( (c>='0') && (c<='9') ) {
939
        format_width = (format_width * 10) + (c - '0');
940
        }
941
      else {
942
        arg_ptr++; // increment to next arg
943
        arg = read_word(arg_seg, arg_ptr);
944
        if (c == 'x' || c == 'X') {
945
          if (format_width == 0)
946
            format_width = 4;
947
          if (c == 'x')
948
            hexadd = 'a';
949
          else
950
            hexadd = 'A';
951
          for (i=format_width-1; i>=0; i--) {
952
            nibble = (arg >> (4 * i)) & 0x000f;
953
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
954
            }
955
          }
956
        else if (c == 'u') {
957
          put_uint(action, arg, format_width, 0);
958
          }
959
        else if (c == 'l') {
960
          s++;
961
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
962
          arg_ptr++; /* increment to next arg */
963
          hibyte = read_word(arg_seg, arg_ptr);
964
          if (c == 'd') {
965
            if (hibyte & 0x8000)
966
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
967
            else
968
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
969
           }
970
          else if (c == 'u') {
971
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
972
           }
973
          else if (c == 'x' || c == 'X')
974
           {
975
            if (format_width == 0)
976
              format_width = 8;
977
            if (c == 'x')
978
              hexadd = 'a';
979
            else
980
              hexadd = 'A';
981
            for (i=format_width-1; i>=0; i--) {
982
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
983
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
984
              }
985
           }
986
          }
987
        else if (c == 'd') {
988
          if (arg & 0x8000)
989
            put_int(action, -arg, format_width - 1, 1);
990
          else
991
            put_int(action, arg, format_width, 0);
992
          }
993
        else if (c == 's') {
994
          put_str(action, get_CS(), arg);
995
          }
996
        else if (c == 'S') {
997
          hibyte = arg;
998
          arg_ptr++;
999
          arg = read_word(arg_seg, arg_ptr);
1000
          put_str(action, hibyte, arg);
1001
          }
1002
        else if (c == 'c') {
1003
          send(action, arg);
1004
          }
1005
        else
1006
          BX_PANIC("bios_printf: unknown format\n");
1007
          in_format = 0;
1008
        }
1009
      }
1010
    else {
1011
      send(action, c);
1012
      }
1013
    s ++;
1014
    }
1015
 
1016
  if (action & BIOS_PRINTF_HALT) {
1017
    // freeze in a busy loop.
1018
ASM_START
1019
    cli
1020
 halt2_loop:
1021
    hlt
1022
    jmp halt2_loop
1023
ASM_END
1024
    }
1025
}
1026
 
1027 52 zeus
static char bios_svn_version_string[] = "$Version: 0.4.3 $ $Date: Tue, 10 Mar 2009 21:02:08 +0100 $";
1028 26 zeus
 
1029 52 zeus
#define BIOS_COPYRIGHT_STRING "(c) 2009 Zeus Gomez Marmolejo and (c) 2002 MandrakeSoft S.A."
1030
 
1031 26 zeus
//--------------------------------------------------------------------------
1032
// print_bios_banner
1033
//   displays a the bios version
1034
//--------------------------------------------------------------------------
1035
void
1036
print_bios_banner()
1037
{
1038 37 zeus
  printf("Zet ROMBIOS - build: %s\n%s\n\n",
1039 26 zeus
    BIOS_BUILD_DATE, bios_svn_version_string);
1040
}
1041
 
1042
//--------------------------------------------------------------------------
1043
// BIOS Boot Specification 1.0.1 compatibility
1044
//
1045
// Very basic support for the BIOS Boot Specification, which allows expansion
1046
// ROMs to register themselves as boot devices, instead of just stealing the
1047
// INT 19h boot vector.
1048
//
1049
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1050
// one; we just lie to the option ROMs to make them behave correctly.
1051
// We also don't support letting option ROMs register as bootable disk
1052
// drives (BCVs), only as bootable devices (BEVs).
1053
//
1054
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1055
//--------------------------------------------------------------------------
1056
 
1057 52 zeus
static char drivetypes[][20]={"", "Floppy flash image", "Compact Flash" };
1058 26 zeus
 
1059
static void
1060
init_boot_vectors()
1061
{
1062
  ipl_entry_t e;
1063
  Bit16u count = 0;
1064
  Bit16u ss = get_SS();
1065
 
1066
  /* Clear out the IPL table. */
1067
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
1068
 
1069
  /* User selected device not set */
1070
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
1071
 
1072 39 zeus
  /* Floppy drive */
1073
  e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1074
  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1075
  count++;
1076 26 zeus
 
1077 52 zeus
  /* First HDD */
1078
  e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1079
  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1080
  count++;
1081
 
1082 26 zeus
  /* Remember how many devices we have */
1083
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
1084
  /* Not tried booting anything yet */
1085
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
1086
}
1087
 
1088
static Bit8u
1089
get_boot_vector(i, e)
1090
Bit16u i; ipl_entry_t *e;
1091
{
1092
  Bit16u count;
1093
  Bit16u ss = get_SS();
1094
  /* Get the count of boot devices, and refuse to overrun the array */
1095
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
1096
  if (i >= count) return 0;
1097
  /* OK to read this device */
1098
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
1099
  return 1;
1100
}
1101
 
1102
//--------------------------------------------------------------------------
1103
// print_boot_device
1104
//   displays the boot device
1105
//--------------------------------------------------------------------------
1106
 
1107
void
1108
print_boot_device(e)
1109
  ipl_entry_t *e;
1110
{
1111
  Bit16u type;
1112
  char description[33];
1113
  Bit16u ss = get_SS();
1114
  type = e->type;
1115
  /* NIC appears as type 0x80 */
1116
  if (type == IPL_TYPE_BEV) type = 0x4;
1117
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
1118
  printf("Booting from %s", drivetypes[type]);
1119
  /* print product string if BEV */
1120
  if (type == 4 && e->description != 0) {
1121
    /* first 32 bytes are significant */
1122
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
1123
    /* terminate string */
1124
    description[32] = 0;
1125
    printf(" [%S]", ss, description);
1126
  }
1127 39 zeus
  printf("...\n\n");
1128 26 zeus
}
1129
 
1130 39 zeus
//--------------------------------------------------------------------------
1131
// print_boot_failure
1132
//   displays the reason why boot failed
1133
//--------------------------------------------------------------------------
1134
  void
1135
print_boot_failure(type, reason)
1136
  Bit16u type; Bit8u reason;
1137
{
1138
  if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
1139
 
1140
  printf("Boot failed");
1141
  if (type < 4) {
1142
    /* Report the reason too */
1143
    if (reason==0)
1144
      printf(": not a bootable disk");
1145
    else
1146
      printf(": could not read the boot disk");
1147
  }
1148
  printf("\n\n");
1149
}
1150
 
1151
 
1152 43 zeus
  void
1153
int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
1154
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
1155
{
1156
  Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
1157
  Bit16u kbd_code, max;
1158
 
1159
  shift_flags = read_byte(0x0040, 0x17);
1160
  led_flags = read_byte(0x0040, 0x97);
1161
 
1162
  switch (GET_AH()) {
1163
    case 0x00: /* read keyboard input */
1164
 
1165
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
1166
        BX_PANIC("KBD: int16h: out of keyboard input\n");
1167
        }
1168
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1169
      else if (ascii_code == 0xE0) ascii_code = 0;
1170
      AX = (scan_code << 8) | ascii_code;
1171
      break;
1172
 
1173
    case 0x01: /* check keyboard status */
1174
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
1175
        SET_ZF();
1176
        return;
1177
        }
1178
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1179
      else if (ascii_code == 0xE0) ascii_code = 0;
1180
      AX = (scan_code << 8) | ascii_code;
1181
      CLEAR_ZF();
1182
      break;
1183
 
1184
    case 0x02: /* get shift flag status */
1185
      shift_flags = read_byte(0x0040, 0x17);
1186
      SET_AL(shift_flags);
1187
      break;
1188
 
1189
    case 0x05: /* store key-stroke into buffer */
1190
      if ( !enqueue_key(GET_CH(), GET_CL()) ) {
1191
        SET_AL(1);
1192
        }
1193
      else {
1194
        SET_AL(0);
1195
        }
1196
      break;
1197
 
1198
    case 0x09: /* GET KEYBOARD FUNCTIONALITY */
1199
      // bit Bochs Description
1200
      //  7    0   reserved
1201
      //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
1202
      //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
1203
      //  4    1   INT 16/AH=0Ah supported
1204
      //  3    0   INT 16/AX=0306h supported
1205
      //  2    0   INT 16/AX=0305h supported
1206
      //  1    0   INT 16/AX=0304h supported
1207
      //  0    0   INT 16/AX=0300h supported
1208
      //
1209
      SET_AL(0x30);
1210
      break;
1211
 
1212
    case 0x10: /* read MF-II keyboard input */
1213
 
1214
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
1215
        BX_PANIC("KBD: int16h: out of keyboard input\n");
1216
        }
1217
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1218
      AX = (scan_code << 8) | ascii_code;
1219
      break;
1220
 
1221
    case 0x11: /* check MF-II keyboard status */
1222
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
1223
        SET_ZF();
1224
        return;
1225
        }
1226
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1227
      AX = (scan_code << 8) | ascii_code;
1228
      CLEAR_ZF();
1229
      break;
1230
 
1231
    case 0x12: /* get extended keyboard status */
1232
      shift_flags = read_byte(0x0040, 0x17);
1233
      SET_AL(shift_flags);
1234
      shift_flags = read_byte(0x0040, 0x18) & 0x73;
1235
      shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
1236
      SET_AH(shift_flags);
1237
      BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
1238
      break;
1239
 
1240
    case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
1241
      SET_AH(0x80); // function int16 ah=0x10-0x12 supported
1242
      break;
1243
 
1244
    case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
1245
      // don't change AH : function int16 ah=0x20-0x22 NOT supported
1246
      break;
1247
 
1248
    case 0x6F:
1249
      if (GET_AL() == 0x08)
1250
        SET_AH(0x02); // unsupported, aka normal keyboard
1251
 
1252
    default:
1253
      BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
1254
    }
1255
}
1256
 
1257
  unsigned int
1258
dequeue_key(scan_code, ascii_code, incr)
1259
  Bit8u *scan_code;
1260
  Bit8u *ascii_code;
1261
  unsigned int incr;
1262
{
1263
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
1264
  Bit16u ss;
1265
  Bit8u  acode, scode;
1266
 
1267
#if BX_CPU < 2
1268
  buffer_start = 0x001E;
1269
  buffer_end   = 0x003E;
1270
#else
1271
  buffer_start = read_word(0x0040, 0x0080);
1272
  buffer_end   = read_word(0x0040, 0x0082);
1273
#endif
1274
 
1275
  buffer_head = read_word(0x0040, 0x001a);
1276
  buffer_tail = read_word(0x0040, 0x001c);
1277
 
1278
  if (buffer_head != buffer_tail) {
1279
    ss = get_SS();
1280
    acode = read_byte(0x0040, buffer_head);
1281
    scode = read_byte(0x0040, buffer_head+1);
1282
    write_byte(ss, ascii_code, acode);
1283
    write_byte(ss, scan_code, scode);
1284
 
1285
    if (incr) {
1286
      buffer_head += 2;
1287
      if (buffer_head >= buffer_end)
1288
        buffer_head = buffer_start;
1289
      write_word(0x0040, 0x001a, buffer_head);
1290
      }
1291
    return(1);
1292
    }
1293
  else {
1294
    return(0);
1295
    }
1296
}
1297
 
1298
  void
1299
int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
1300
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
1301
{
1302
  Bit8u scancode, asciicode, shift_flags;
1303
  Bit8u mf2_flags, mf2_state;
1304
 
1305
  //
1306
  // DS has been set to F000 before call
1307
  //
1308
 
1309
 
1310
  scancode = GET_AL();
1311
 
1312
  if (scancode == 0) {
1313
    BX_INFO("KBD: int09 handler: AL=0\n");
1314
    return;
1315
    }
1316
 
1317
 
1318
  shift_flags = read_byte(0x0040, 0x17);
1319
  mf2_flags = read_byte(0x0040, 0x18);
1320
  mf2_state = read_byte(0x0040, 0x96);
1321
  asciicode = 0;
1322
 
1323
  switch (scancode) {
1324
    case 0x3a: /* Caps Lock press */
1325
      shift_flags ^= 0x40;
1326
      write_byte(0x0040, 0x17, shift_flags);
1327
      mf2_flags |= 0x40;
1328
      write_byte(0x0040, 0x18, mf2_flags);
1329
      break;
1330
    case 0xba: /* Caps Lock release */
1331
      mf2_flags &= ~0x40;
1332
      write_byte(0x0040, 0x18, mf2_flags);
1333
      break;
1334
 
1335
    case 0x2a: /* L Shift press */
1336
      shift_flags |= 0x02;
1337
      write_byte(0x0040, 0x17, shift_flags);
1338
      break;
1339
    case 0xaa: /* L Shift release */
1340
      shift_flags &= ~0x02;
1341
      write_byte(0x0040, 0x17, shift_flags);
1342
      break;
1343
 
1344
    case 0x36: /* R Shift press */
1345
      shift_flags |= 0x01;
1346
      write_byte(0x0040, 0x17, shift_flags);
1347
      break;
1348
    case 0xb6: /* R Shift release */
1349
      shift_flags &= ~0x01;
1350
      write_byte(0x0040, 0x17, shift_flags);
1351
      break;
1352
 
1353
    case 0x1d: /* Ctrl press */
1354
      if ((mf2_state & 0x01) == 0) {
1355
        shift_flags |= 0x04;
1356
        write_byte(0x0040, 0x17, shift_flags);
1357
        if (mf2_state & 0x02) {
1358
          mf2_state |= 0x04;
1359
          write_byte(0x0040, 0x96, mf2_state);
1360
        } else {
1361
          mf2_flags |= 0x01;
1362
          write_byte(0x0040, 0x18, mf2_flags);
1363
        }
1364
      }
1365
      break;
1366
    case 0x9d: /* Ctrl release */
1367
      if ((mf2_state & 0x01) == 0) {
1368
        shift_flags &= ~0x04;
1369
        write_byte(0x0040, 0x17, shift_flags);
1370
        if (mf2_state & 0x02) {
1371
          mf2_state &= ~0x04;
1372
          write_byte(0x0040, 0x96, mf2_state);
1373
        } else {
1374
          mf2_flags &= ~0x01;
1375
          write_byte(0x0040, 0x18, mf2_flags);
1376
        }
1377
      }
1378
      break;
1379
 
1380
    case 0x38: /* Alt press */
1381
      shift_flags |= 0x08;
1382
      write_byte(0x0040, 0x17, shift_flags);
1383
      if (mf2_state & 0x02) {
1384
        mf2_state |= 0x08;
1385
        write_byte(0x0040, 0x96, mf2_state);
1386
      } else {
1387
        mf2_flags |= 0x02;
1388
        write_byte(0x0040, 0x18, mf2_flags);
1389
      }
1390
      break;
1391
    case 0xb8: /* Alt release */
1392
      shift_flags &= ~0x08;
1393
      write_byte(0x0040, 0x17, shift_flags);
1394
      if (mf2_state & 0x02) {
1395
        mf2_state &= ~0x08;
1396
        write_byte(0x0040, 0x96, mf2_state);
1397
      } else {
1398
        mf2_flags &= ~0x02;
1399
        write_byte(0x0040, 0x18, mf2_flags);
1400
      }
1401
      break;
1402
 
1403
    case 0x45: /* Num Lock press */
1404
      if ((mf2_state & 0x03) == 0) {
1405
        mf2_flags |= 0x20;
1406
        write_byte(0x0040, 0x18, mf2_flags);
1407
        shift_flags ^= 0x20;
1408
        write_byte(0x0040, 0x17, shift_flags);
1409
      }
1410
      break;
1411
    case 0xc5: /* Num Lock release */
1412
      if ((mf2_state & 0x03) == 0) {
1413
        mf2_flags &= ~0x20;
1414
        write_byte(0x0040, 0x18, mf2_flags);
1415
      }
1416
      break;
1417
 
1418
    case 0x46: /* Scroll Lock press */
1419
      mf2_flags |= 0x10;
1420
      write_byte(0x0040, 0x18, mf2_flags);
1421
      shift_flags ^= 0x10;
1422
      write_byte(0x0040, 0x17, shift_flags);
1423
      break;
1424
 
1425
    case 0xc6: /* Scroll Lock release */
1426
      mf2_flags &= ~0x10;
1427
      write_byte(0x0040, 0x18, mf2_flags);
1428
      break;
1429
 
1430
    default:
1431
      if (scancode & 0x80) {
1432
        break; /* toss key releases ... */
1433
      }
1434
      if (scancode > MAX_SCAN_CODE) {
1435
        BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
1436
        return;
1437
      }
1438
      if (shift_flags & 0x08) { /* ALT */
1439
        asciicode = scan_to_scanascii[scancode].alt;
1440
        scancode = scan_to_scanascii[scancode].alt >> 8;
1441
      } else if (shift_flags & 0x04) { /* CONTROL */
1442
        asciicode = scan_to_scanascii[scancode].control;
1443
        scancode = scan_to_scanascii[scancode].control >> 8;
1444
      } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
1445
        /* extended keys handling */
1446
        asciicode = 0xe0;
1447
        scancode = scan_to_scanascii[scancode].normal >> 8;
1448
      } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
1449
        /* check if lock state should be ignored
1450
         * because a SHIFT key are pressed */
1451
 
1452
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
1453
          asciicode = scan_to_scanascii[scancode].normal;
1454
          scancode = scan_to_scanascii[scancode].normal >> 8;
1455
        } else {
1456
          asciicode = scan_to_scanascii[scancode].shift;
1457
          scancode = scan_to_scanascii[scancode].shift >> 8;
1458
        }
1459
      } else {
1460
        /* check if lock is on */
1461
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
1462
          asciicode = scan_to_scanascii[scancode].shift;
1463
          scancode = scan_to_scanascii[scancode].shift >> 8;
1464
        } else {
1465
          asciicode = scan_to_scanascii[scancode].normal;
1466
          scancode = scan_to_scanascii[scancode].normal >> 8;
1467
        }
1468
      }
1469
      if (scancode==0 && asciicode==0) {
1470
        BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
1471
      }
1472
      enqueue_key(scancode, asciicode);
1473
      break;
1474
  }
1475
  if ((scancode & 0x7f) != 0x1d) {
1476
    mf2_state &= ~0x01;
1477
  }
1478
  mf2_state &= ~0x02;
1479
  write_byte(0x0040, 0x96, mf2_state);
1480
}
1481
 
1482
  unsigned int
1483
enqueue_key(scan_code, ascii_code)
1484
  Bit8u scan_code, ascii_code;
1485
{
1486
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
1487
 
1488
#if BX_CPU < 2
1489
  buffer_start = 0x001E;
1490
  buffer_end   = 0x003E;
1491
#else
1492
  buffer_start = read_word(0x0040, 0x0080);
1493
  buffer_end   = read_word(0x0040, 0x0082);
1494
#endif
1495
 
1496
  buffer_head = read_word(0x0040, 0x001A);
1497
  buffer_tail = read_word(0x0040, 0x001C);
1498
 
1499
  temp_tail = buffer_tail;
1500
  buffer_tail += 2;
1501
  if (buffer_tail >= buffer_end)
1502
    buffer_tail = buffer_start;
1503
 
1504
  if (buffer_tail == buffer_head) {
1505
    return(0);
1506
    }
1507
 
1508
   write_byte(0x0040, temp_tail, ascii_code);
1509
   write_byte(0x0040, temp_tail+1, scan_code);
1510
   write_word(0x0040, 0x001C, buffer_tail);
1511
   return(1);
1512
}
1513
 
1514
 
1515 39 zeus
#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
1516
 
1517
  void
1518
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
1519
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
1520
{
1521 52 zeus
  Bit8u    drive, num_sectors, sector, head, status;
1522
  Bit8u    drive_map;
1523
  Bit8u    n_drives;
1524
  Bit16u   max_cylinder, cylinder;
1525
  Bit16u   hd_cylinders;
1526
  Bit8u    hd_heads, hd_sectors;
1527
  Bit8u    sector_count;
1528
  Bit16u   tempbx;
1529
 
1530
  Bit32u   log_sector;
1531
 
1532 39 zeus
  write_byte(0x0040, 0x008e, 0);  // clear completion flag
1533
 
1534 52 zeus
  /* at this point, DL is >= 0x80 to be passed from the floppy int13h
1535
     handler code */
1536
  /* check how many disks first (cmos reg 0x12), return an error if
1537
     drive not present */
1538
  drive_map = 1;
1539
  n_drives = 1;
1540
 
1541
  if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
1542
    SET_AH(0x01);
1543
    SET_DISK_RET_STATUS(0x01);
1544
    SET_CF(); /* error occurred */
1545
    return;
1546
    }
1547
 
1548 39 zeus
  switch (GET_AH()) {
1549 52 zeus
 
1550
    case 0x00: /* disk controller reset */
1551
 
1552
      SET_AH(0);
1553
      SET_DISK_RET_STATUS(0);
1554
      set_diskette_ret_status(0);
1555
      set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
1556
      set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
1557
      CLEAR_CF(); /* successful */
1558
      return;
1559
      break;
1560
 
1561
    case 0x01: /* read disk status */
1562
      status = read_byte(0x0040, 0x0074);
1563
      SET_AH(status);
1564
      SET_DISK_RET_STATUS(0);
1565
      /* set CF if error status read */
1566
      if (status) SET_CF();
1567
      else        CLEAR_CF();
1568
      return;
1569
      break;
1570
 
1571
    case 0x04: // verify disk sectors
1572
    case 0x02: // read disk sectors
1573
      drive = GET_ELDL();
1574
 
1575
      // get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
1576
      // fixed geometry:
1577
      hd_cylinders = 993;
1578
      hd_heads     = 16;
1579
      hd_sectors   = 63;
1580
 
1581
      num_sectors = GET_AL();
1582
      cylinder    = (GET_CL() & 0x00c0) << 2 | GET_CH();
1583
      sector      = (GET_CL() & 0x3f);
1584
      head        = GET_DH();
1585
 
1586
      if ( (cylinder >= hd_cylinders) ||
1587
           (sector > hd_sectors) ||
1588
           (head >= hd_heads) ) {
1589
        SET_AH(1);
1590
        SET_DISK_RET_STATUS(1);
1591
        SET_CF(); /* error occurred */
1592
        return;
1593
        }
1594
 
1595
      if ( GET_AH() == 0x04 ) {
1596
        SET_AH(0);
1597
        SET_DISK_RET_STATUS(0);
1598
        CLEAR_CF();
1599
        return;
1600
        }
1601
 
1602
      log_sector = ((Bit32u)cylinder) * ((Bit32u)hd_heads) * ((Bit32u)hd_sectors)
1603
                 + ((Bit32u)head) * ((Bit32u)hd_sectors)
1604
                 + ((Bit32u)sector) - 1;
1605
 
1606
      sector_count = 0;
1607
      tempbx = BX;
1608
 
1609
ASM_START
1610
  sti  ;; enable higher priority interrupts
1611
ASM_END
1612
 
1613
      while (1) {
1614
ASM_START
1615
        ;; store temp bx in real DI register
1616
        push bp
1617
        mov  bp, sp
1618
        mov  di, _int13_harddisk.tempbx + 2 [bp]
1619
        pop  bp
1620
 
1621
        ;; adjust if there will be an overrun
1622
        cmp   di, #0xfe00
1623
        jbe   i13_f02_no_adjust
1624
i13_f02_adjust:
1625
        sub   di, #0x0200 ; sub 512 bytes from offset
1626
        mov   ax, es
1627
        add   ax, #0x0020 ; add 512 to segment
1628
        mov   es, ax
1629
 
1630
i13_f02_no_adjust:
1631
        ; timeout = TIMEOUT;
1632
        mov   cx, #0xffff
1633
 
1634
        ; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_CFCMDRDY))) timeout--;
1635
        mov   dx, #0xe204
1636
 
1637
i13_f02_ace_statusl2:
1638
        in    ax, dx
1639
        and   ax, #0x100
1640
        loopz i13_f02_ace_statusl2
1641
 
1642
        ; if(timeout == 0) return 0;
1643
        cmp   cx, #0
1644
        jnz   i13_f02_success2
1645
ASM_END
1646
        printf("i13_f02(1): Timeout\n");
1647
ASM_START
1648
        jmp   _int13_fail
1649
 
1650
i13_f02_success2:
1651
        ; CSR_ACE_MLBAL = blocknr & 0x0000ffff;
1652
        push  bp
1653
        mov   bp, sp
1654
        mov   ax, _int13_harddisk.log_sector + 2 [bp]
1655
        mov   dx, #0xe210
1656
        out   dx, ax
1657
 
1658
        ; CSR_ACE_MLBAH = (blocknr & 0x0fff0000) >> 16;
1659
        mov   ax, _int13_harddisk.log_sector + 4 [bp]
1660
        mov   dx, #0xe212
1661
        out   dx, ax
1662
        pop   bp
1663
 
1664
        ; CSR_ACE_SECCMD = ACE_SECCMD_READ|0x01;
1665
        mov   ax, #0x0301
1666
        mov   dx, #0xe214
1667
        out   dx, ax
1668
 
1669
        ; CSR_ACE_CTLL |= ACE_CTLL_CFGRESET;
1670
        mov   dx, #0xe218
1671
        in    ax, dx
1672
        or    ax, #0x0080
1673
        out   dx, ax
1674
 
1675
        ; buffer_count = 16;
1676
        mov   si, #16
1677
 
1678
        ; while(buffer_count > 0) {
1679
i13_f02_cond_loop:
1680
        cmp   si, #0
1681
        jbe   i13_f02_exit_loop
1682
 
1683
        ; timeout = TIMEOUT;
1684
        mov   cx, #0xffff
1685
        mov   bx, #0x000f
1686
 
1687
        ; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_DATARDY))) timeout--;
1688
        mov   dx, #0xe204
1689
i13_f02_ace_statusl3:
1690
        in    ax, dx
1691
        and   ax, #0x20
1692
        loopz i13_f02_ace_statusl3
1693
 
1694
        ; if(timeout == 0) return 0;
1695
        cmp   cx, #0
1696
        jnz  i13_f02_success3
1697
        dec   bx
1698
        mov   cx, #0xffff
1699
        jne   i13_f02_ace_statusl3
1700
ASM_END
1701
        printf("i13_f02(2): Timeout\n");
1702
ASM_START
1703
        jmp   _int13_fail
1704
 
1705
i13_f02_success3:
1706
        ; for(i=0;i<16;i++) {
1707
        mov   cx, #16
1708
        ; *bufw = CSR_ACE_DATA;
1709
        mov   dx, #0xe240
1710
i13_f02_ace_data:
1711
        in    ax, dx
1712
        eseg
1713
              mov   [di], ax
1714
        ; bufw++;
1715
        add   di, #2
1716
        ; }
1717
        loop  i13_f02_ace_data
1718
 
1719
        ; buffer_count--;
1720
        dec   si
1721
        jmp   i13_f02_cond_loop
1722
 
1723
        ; }
1724
 
1725
i13_f02_exit_loop:
1726
        ; CSR_ACE_CTLL &= ~ACE_CTLL_CFGRESET;
1727
        mov   dx, #0xe218
1728
        in    ax, dx
1729
        and   ax, #0xff7f
1730
        out   dx, ax
1731
 
1732
i13_f02_done:
1733
        ;; store real DI register back to temp bx
1734
        push bp
1735
        mov  bp, sp
1736
        mov  _int13_harddisk.tempbx + 2 [bp], di
1737
        pop  bp
1738
ASM_END
1739
 
1740
        sector_count++;
1741
        log_sector++;
1742
        num_sectors--;
1743
        if (num_sectors) continue;
1744
        else break;
1745
      }
1746
 
1747
      SET_AH(0);
1748
      SET_DISK_RET_STATUS(0);
1749
      SET_AL(sector_count);
1750
      CLEAR_CF(); /* successful */
1751
      return;
1752
      break;
1753
 
1754
    case 0x03: /* write disk sectors */
1755
      drive = GET_ELDL ();
1756
 
1757
      // get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
1758
      // fixed geometry:
1759
      hd_cylinders = 993;
1760
      hd_heads     = 16;
1761
      hd_sectors   = 63;
1762
 
1763
      num_sectors = GET_AL();
1764
      cylinder    = GET_CH();
1765
      cylinder    |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
1766
      sector      = (GET_CL() & 0x3f);
1767
      head        = GET_DH();
1768
 
1769
      if ( (cylinder >= hd_cylinders) ||
1770
           (sector > hd_sectors) ||
1771
           (head >= hd_heads) ) {
1772
        SET_AH( 1);
1773
        SET_DISK_RET_STATUS(1);
1774
        SET_CF(); /* error occurred */
1775
        return;
1776
        }
1777
 
1778
      log_sector = ((Bit32u)cylinder) * ((Bit32u)hd_heads) * ((Bit32u)hd_sectors)
1779
                 + ((Bit32u)head) * ((Bit32u)hd_sectors)
1780
                 + ((Bit32u)sector) - 1;
1781
 
1782
      sector_count = 0;
1783
      tempbx = BX;
1784
 
1785
ASM_START
1786
  sti  ;; enable higher priority interrupts
1787
ASM_END
1788
 
1789
      while (1) {
1790
ASM_START
1791
        ;; store temp bx in real SI register
1792
        push bp
1793
        mov  bp, sp
1794
        mov  si, _int13_harddisk.tempbx + 2 [bp]
1795
        pop  bp
1796
 
1797
        ;; adjust if there will be an overrun
1798
        cmp   si, #0xfe00
1799
        jbe   i13_f03_no_adjust
1800
i13_f03_adjust:
1801
        sub   si, #0x0200 ; sub 512 bytes from offset
1802
        mov   ax, es
1803
        add   ax, #0x0020 ; add 512 to segment
1804
        mov   es, ax
1805
 
1806
i13_f03_no_adjust:
1807
        ; timeout = TIMEOUT;
1808
        mov   cx, #0xffff
1809
 
1810
        ; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_CFCMDRDY))) timeout--;
1811
        mov   dx, #0xe204
1812
 
1813
i13_f03_ace_statusl2:
1814
        in    ax, dx
1815
        and   ax, #0x100
1816
        loopz i13_f03_ace_statusl2
1817
 
1818
        ; if(timeout == 0) return 0;
1819
        cmp   cx, #0
1820
        jnz   i13_f03_success2
1821
ASM_END
1822
        printf("i13_f03(1): Timeout\n");
1823
ASM_START
1824
        jmp   _int13_fail
1825
 
1826
i13_f03_success2:
1827
        ; CSR_ACE_MLBAL = blocknr & 0x0000ffff;
1828
        push  bp
1829
        mov   bp, sp
1830
        mov   ax, _int13_harddisk.log_sector + 2 [bp]
1831
        mov   dx, #0xe210
1832
        out   dx, ax
1833
 
1834
        ; CSR_ACE_MLBAH = (blocknr & 0x0fff0000) >> 16;
1835
        mov   ax, _int13_harddisk.log_sector + 4 [bp]
1836
        mov   dx, #0xe212
1837
        out   dx, ax
1838
        pop   bp
1839
 
1840
        ; CSR_ACE_SECCMD = ACE_SECCMD_WRITE|0x01;
1841
        mov   ax, #0x0401
1842
        mov   dx, #0xe214
1843
        out   dx, ax
1844
 
1845
        ; CSR_ACE_CTLL |= ACE_CTLL_CFGRESET;
1846
        mov   dx, #0xe218
1847
        in    ax, dx
1848
        or    ax, #0x0080
1849
        out   dx, ax
1850
 
1851
        ; buffer_count = 16;
1852
        mov   di, #16
1853
 
1854
        ; while(buffer_count > 0) {
1855
i13_f03_cond_loop:
1856
        cmp   di, #0
1857
        jbe   i13_f03_exit_loop
1858
 
1859
        ; timeout = TIMEOUT;
1860
        mov   cx, #0xffff
1861
        mov   bx, #0x000f
1862
 
1863
        ; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_DATARDY))) timeout--;
1864
        mov   dx, #0xe204
1865
i13_f03_ace_statusl3:
1866
        in    ax, dx
1867
        and   ax, #0x20
1868
        loopz i13_f03_ace_statusl3
1869
 
1870
        ; if(timeout == 0) return 0;
1871
        cmp   cx, #0
1872
        jnz   i13_f03_success3
1873
        dec   bx
1874
        mov   cx, #0xffff
1875
        jne   i13_f03_ace_statusl3
1876
ASM_END
1877
        printf("i13_f03(2): Timeout\n");
1878
ASM_START
1879
        jmp   _int13_fail
1880
 
1881
i13_f03_success3:
1882
        ; for(i=0;i<16;i++) {
1883
        mov   cx, #16
1884
        ; *bufw = CSR_ACE_DATA;
1885
        mov   dx, #0xe240
1886
i13_f03_ace_data:
1887
        eseg
1888
              mov   ax, [si]
1889
        out   dx, ax
1890
        ; bufw++;
1891
        add   si, #2
1892
        ; }
1893
        loop  i13_f03_ace_data
1894
 
1895
        ; buffer_count--;
1896
        dec   di
1897
        jmp   i13_f03_cond_loop
1898
 
1899
        ; }
1900
 
1901
i13_f03_exit_loop:
1902
        ; CSR_ACE_CTLL &= ~ACE_CTLL_CFGRESET;
1903
        mov   dx, #0xe218
1904
        in    ax, dx
1905
        and   ax, #0xff7f
1906
        out   dx, ax
1907
 
1908
i13_f03_done:
1909
        ;; store real SI register back to temp bx
1910
        push bp
1911
        mov  bp, sp
1912
        mov  _int13_harddisk.tempbx + 2 [bp], si
1913
        pop  bp
1914
ASM_END
1915
 
1916
        sector_count++;
1917
        log_sector++;
1918
        num_sectors--;
1919
        if (num_sectors) continue;
1920
        else break;
1921
      }
1922
 
1923
      SET_AH(0);
1924
      SET_DISK_RET_STATUS(0);
1925
      SET_AL(sector_count);
1926
      CLEAR_CF(); /* successful */
1927
      return;
1928
      break;
1929
 
1930 39 zeus
    case 0x08:
1931 52 zeus
 
1932
      drive = GET_ELDL ();
1933
 
1934
      // get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
1935
      // fixed geometry:
1936
      hd_cylinders = 993;
1937
      hd_heads     = 16;
1938
      hd_sectors   = 63;
1939
 
1940
      max_cylinder = hd_cylinders - 2; /* 0 based */
1941 39 zeus
      SET_AL(0);
1942 52 zeus
      SET_CH(max_cylinder & 0xff);
1943
      SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
1944
      SET_DH(hd_heads - 1);
1945
      SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
1946
      SET_AH(0);
1947
      SET_DISK_RET_STATUS(0);
1948
      CLEAR_CF(); /* successful */
1949 39 zeus
 
1950 52 zeus
      return;
1951
      break;
1952 39 zeus
 
1953 52 zeus
    case 0x09: /* initialize drive parameters */
1954
    case 0x0c: /* seek to specified cylinder */
1955
    case 0x0d: /* alternate disk reset */
1956
    case 0x10: /* check drive ready */
1957
    case 0x11: /* recalibrate */
1958
      SET_AH(0);
1959
      SET_DISK_RET_STATUS(0);
1960
      CLEAR_CF(); /* successful */
1961
      return;
1962 39 zeus
      break;
1963
 
1964 52 zeus
    case 0x14: /* controller internal diagnostic */
1965
      SET_AH(0);
1966
      SET_DISK_RET_STATUS(0);
1967
      CLEAR_CF(); /* successful */
1968
      SET_AL(0);
1969
      return;
1970
      break;
1971
 
1972
    case 0x15: /* read disk drive size */
1973
      drive = GET_ELDL();
1974
      // get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
1975
      // fixed geometry:
1976
      hd_cylinders = 993;
1977
      hd_heads     = 16;
1978
      hd_sectors   = 63;
1979
 
1980
ASM_START
1981
      push bp
1982
      mov  bp, sp
1983
      mov  al, _int13_harddisk.hd_heads + 2 [bp]
1984
      mov  ah, _int13_harddisk.hd_sectors + 2 [bp]
1985
      mul  al, ah ;; ax = heads * sectors
1986
      mov  bx, _int13_harddisk.hd_cylinders + 2 [bp]
1987
      dec  bx     ;; use (cylinders - 1) ???
1988
      mul  ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
1989
      ;; now we need to move the 32bit result dx:ax to what the
1990
      ;; BIOS wants which is cx:dx.
1991
      ;; and then into CX:DX on the stack
1992
      mov  _int13_harddisk.CX + 2 [bp], dx
1993
      mov  _int13_harddisk.DX + 2 [bp], ax
1994
      pop  bp
1995
ASM_END
1996
      SET_AH(3);  // hard disk accessible
1997
      SET_DISK_RET_STATUS(0); // ??? should this be 0
1998
      CLEAR_CF(); // successful
1999
      return;
2000
      break;
2001
 
2002 39 zeus
    default:
2003
      BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
2004
      goto int13_fail;
2005
      break;
2006
    }
2007 52 zeus
ASM_START
2008
_int13_fail:
2009
ASM_END
2010 39 zeus
int13_fail:
2011
    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
2012
int13_fail_noah:
2013
    SET_DISK_RET_STATUS(GET_AH());
2014
int13_fail_nostatus:
2015
    SET_CF();     // error occurred
2016
    return;
2017
 
2018
int13_success:
2019
    SET_AH(0x00); // no error
2020
int13_success_noah:
2021
    SET_DISK_RET_STATUS(0x00);
2022
    CLEAR_CF();   // no error
2023
    return;
2024
}
2025
 
2026
  void
2027 46 zeus
transf_sect(seg, offset)
2028
  Bit16u seg;
2029
  Bit16u offset;
2030
{
2031
ASM_START
2032
  push bp
2033
  mov  bp, sp
2034
 
2035
    push ax
2036
    push bx
2037
    push cx
2038
    push dx
2039
    push di
2040
    push ds
2041
 
2042
    mov  ax, 4[bp] ; segment
2043
    mov  ds, ax
2044
    mov  bx, 6[bp] ; offset
2045
    mov  dx, #0xe000
2046
    mov  cx, #256
2047
    xor  di, di
2048
 
2049
one_sect:
2050
    in   ax, dx    ; read word from flash
2051
    mov  [bx+di], ax ; write word
2052
    inc  dx
2053
    inc  dx
2054
    inc  di
2055
    inc  di
2056
    loop one_sect
2057
 
2058
    pop  ds
2059
    pop  di
2060
    pop  dx
2061
    pop  cx
2062
    pop  bx
2063
    pop  ax
2064
 
2065
  pop  bp
2066
ASM_END
2067
}
2068
 
2069
  void
2070 39 zeus
int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
2071
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
2072
{
2073
  Bit8u  drive, num_sectors, track, sector, head, status;
2074
  Bit16u base_address, base_count, base_es;
2075
  Bit8u  page, mode_register, val8, dor;
2076
  Bit8u  return_status[7];
2077
  Bit8u  drive_type, num_floppies, ah;
2078
  Bit16u es, last_addr;
2079
  Bit16u log_sector, tmp, i, j;
2080
 
2081
  ah = GET_AH();
2082
 
2083
  switch ( ah ) {
2084
    case 0x00: // diskette controller reset
2085
      SET_AH(0);
2086
      set_diskette_ret_status(0);
2087
      CLEAR_CF(); // successful
2088
      set_diskette_current_cyl(drive, 0); // current cylinder
2089
      return;
2090
 
2091
    case 0x02: // Read Diskette Sectors
2092
      num_sectors = GET_AL();
2093
      track       = GET_CH();
2094
      sector      = GET_CL();
2095
      head        = GET_DH();
2096
      drive       = GET_ELDL();
2097
 
2098
      if ((drive > 1) || (head > 1) || (sector == 0) ||
2099
          (num_sectors == 0) || (num_sectors > 72)) {
2100
        BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
2101
        SET_AH(1);
2102
        set_diskette_ret_status(1);
2103
        SET_AL(0); // no sectors read
2104
        SET_CF(); // error occurred
2105
        return;
2106
      }
2107
 
2108
        page = (ES >> 12);   // upper 4 bits
2109
        base_es = (ES << 4); // lower 16bits contributed by ES
2110
        base_address = base_es + BX; // lower 16 bits of address
2111
                                     // contributed by ES:BX
2112
        if ( base_address < base_es ) {
2113
          // in case of carry, adjust page by 1
2114
          page++;
2115
        }
2116
        base_count = (num_sectors * 512) - 1;
2117
 
2118
        // check for 64K boundary overrun
2119
        last_addr = base_address + base_count;
2120
        if (last_addr < base_address) {
2121
          SET_AH(0x09);
2122
          set_diskette_ret_status(0x09);
2123
          SET_AL(0); // no sectors read
2124
          SET_CF(); // error occurred
2125
          return;
2126
        }
2127
 
2128
        log_sector = track * 36 + head * 18 + sector - 1;
2129
        last_addr = page << 12;
2130
 
2131
        // Configure the sector address
2132
        for (j=0; j<num_sectors; j++)
2133
          {
2134
            outw(0xe000, log_sector+j);
2135
            base_count = base_address + (j << 9);
2136 46 zeus
            transf_sect (last_addr, base_count);
2137 39 zeus
          }
2138
 
2139
        // ??? should track be new val from return_status[3] ?
2140
        set_diskette_current_cyl(drive, track);
2141
        // AL = number of sectors read (same value as passed)
2142
        SET_AH(0x00); // success
2143
        CLEAR_CF();   // success
2144
        return;
2145
    default:
2146
        BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
2147
 
2148
      // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
2149
        SET_AH(0x01); // ???
2150
        set_diskette_ret_status(1);
2151
        SET_CF();
2152
        return;
2153
      //   }
2154
    }
2155
}
2156
 
2157
 void
2158
set_diskette_ret_status(value)
2159
  Bit8u value;
2160
{
2161
  write_byte(0x0040, 0x0041, value);
2162
}
2163
 
2164
  void
2165
set_diskette_current_cyl(drive, cyl)
2166
  Bit8u drive;
2167
  Bit8u cyl;
2168
{
2169 52 zeus
/* TEMP HACK: FOR MSDOS
2170 39 zeus
  if (drive > 1)
2171 52 zeus
    drive = 1; */
2172 39 zeus
  /*  BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
2173
  write_byte(0x0040, 0x0094+drive, cyl);
2174
}
2175
 
2176 26 zeus
void
2177
int19_function(seq_nr)
2178
Bit16u seq_nr;
2179
{
2180
  Bit16u ebda_seg=read_word(0x0040,0x000E);
2181
  Bit16u bootdev;
2182
  Bit8u  bootdrv;
2183
  Bit8u  bootchk;
2184
  Bit16u bootseg;
2185
  Bit16u bootip;
2186
  Bit16u status;
2187
  Bit16u bootfirst;
2188
 
2189
  ipl_entry_t e;
2190
 
2191
  // Here we assume that BX_ELTORITO_BOOT is defined, so
2192
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
2193
  //     CMOS reg 0x3D & 0x0f : 1st boot device
2194
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
2195
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
2196
  //   boot device codes:
2197
  //     0x00 : not defined
2198
  //     0x01 : first floppy
2199
  //     0x02 : first harddrive
2200
  //     0x03 : first cdrom
2201
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
2202
  //     else : boot failure
2203
 
2204
  // Get the boot sequence
2205 39 zeus
/*
2206
 * Zet: we don't have a CMOS device
2207
 *
2208 26 zeus
  bootdev = inb_cmos(0x3d);
2209
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
2210
  bootdev >>= 4 * seq_nr;
2211
  bootdev &= 0xf;
2212 39 zeus
*/
2213 52 zeus
  bootdev = 0x2;  // 1: flopy disk, 2: hard disk
2214 26 zeus
 
2215
  /* Read user selected device */
2216
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
2217
  if (bootfirst != 0xFFFF) {
2218
    bootdev = bootfirst;
2219
    /* User selected device not set */
2220
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
2221
    /* Reset boot sequence */
2222
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
2223
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
2224
 
2225
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
2226
  bootdev -= 1;
2227
 
2228
  /* Read the boot device from the IPL table */
2229
  if (get_boot_vector(bootdev, &e) == 0) {
2230
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
2231
    return;
2232
  }
2233
 
2234
  /* Do the loading, and set up vector as a far pointer to the boot
2235
   * address, and bootdrv as the boot drive */
2236
  print_boot_device(&e);
2237
 
2238
  switch(e.type) {
2239 39 zeus
  case IPL_TYPE_FLOPPY: /* FDD */
2240
  case IPL_TYPE_HARDDISK: /* HDD */
2241 26 zeus
 
2242 39 zeus
    bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
2243
    bootseg = 0x07c0;
2244
    status = 0;
2245
 
2246
ASM_START
2247
    push bp
2248
    mov  bp, sp
2249
    push ax
2250
    push bx
2251
    push cx
2252
    push dx
2253
 
2254
    mov  dl, _int19_function.bootdrv + 2[bp]
2255
    mov  ax, _int19_function.bootseg + 2[bp]
2256
    mov  es, ax         ;; segment
2257
    xor  bx, bx         ;; offset
2258
    mov  ah, #0x02      ;; function 2, read diskette sector
2259
    mov  al, #0x01      ;; read 1 sector
2260
    mov  ch, #0x00      ;; track 0
2261
    mov  cl, #0x01      ;; sector 1
2262
    mov  dh, #0x00      ;; head 0
2263
    int  #0x13          ;; read sector
2264
    jnc  int19_load_done
2265
    mov  ax, #0x0001
2266
    mov  _int19_function.status + 2[bp], ax
2267
 
2268
int19_load_done:
2269
    pop  dx
2270
    pop  cx
2271
    pop  bx
2272
    pop  ax
2273
    pop  bp
2274
ASM_END
2275
 
2276
    if (status != 0) {
2277
      print_boot_failure(e.type, 1);
2278
      return;
2279
    }
2280
 
2281
    /* Canonicalize bootseg:bootip */
2282
    bootip = (bootseg & 0x0fff) << 4;
2283
    bootseg &= 0xf000;
2284
  break;
2285
 
2286 26 zeus
  default: return;
2287
  }
2288
 
2289
  /* Debugging info */
2290
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
2291
 
2292
  /* Jump to the boot vector */
2293
ASM_START
2294
    mov  bp, sp
2295
    ;; Build an iret stack frame that will take us to the boot vector.
2296
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
2297
    pushf
2298
    mov  ax, _int19_function.bootseg + 0[bp]
2299
    push ax
2300
    mov  ax, _int19_function.bootip + 0[bp]
2301
    push ax
2302
    ;; Set the magic number in ax and the boot drive in dl.
2303
    mov  ax, #0xaa55
2304
    mov  dl, _int19_function.bootdrv + 0[bp]
2305
    ;; Zero some of the other registers.
2306
    xor  bx, bx
2307
    mov  ds, bx
2308
    mov  es, bx
2309
    mov  bp, bx
2310
    ;; Go!
2311
    iret
2312
ASM_END
2313
}
2314
 
2315 47 zeus
  void
2316
int1a_function(regs, ds, iret_addr)
2317
  pusha_regs_t regs; // regs pushed from PUSHA instruction
2318
  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
2319
  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
2320
{
2321
  Bit8u val8;
2322
 
2323
  ASM_START
2324
  sti
2325
  ASM_END
2326
 
2327
  switch (regs.u.r8.ah) {
2328
    case 0: // get current clock count
2329
      ASM_START
2330
      cli
2331
      ASM_END
2332
      regs.u.r16.cx = BiosData->ticks_high;
2333
      regs.u.r16.dx = BiosData->ticks_low;
2334
      regs.u.r8.al  = BiosData->midnight_flag;
2335
      BiosData->midnight_flag = 0; // reset flag
2336
      ASM_START
2337
      sti
2338
      ASM_END
2339
      // AH already 0
2340
      ClearCF(iret_addr.flags); // OK
2341
      break;
2342
 
2343
    default:
2344
      SetCF(iret_addr.flags); // Unsupported
2345
    }
2346
}
2347
 
2348 26 zeus
ASM_START
2349 39 zeus
;----------------------
2350
;- INT13h (relocated) -
2351
;----------------------
2352
;
2353
; int13_relocated is a little bit messed up since I played with it
2354
; I have to rewrite it:
2355
;   - call a function that detect which function to call
2356
;   - make all called C function get the same parameters list
2357
;
2358
int13_relocated:
2359
  push  ax
2360
  push  cx
2361
  push  dx
2362
  push  bx
2363
 
2364
int13_legacy:
2365
 
2366
  push  dx                   ;; push eltorito value of dx instead of sp
2367
 
2368
  push  bp
2369
  push  si
2370
  push  di
2371
 
2372
  push  es
2373
  push  ds
2374
  push  ss
2375
  pop   ds
2376
 
2377
  ;; now the 16-bit registers can be restored with:
2378
  ;; pop ds; pop es; popa; iret
2379
  ;; arguments passed to functions should be
2380
  ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
2381
 
2382
  test  dl, #0x80
2383
  jnz   int13_notfloppy
2384
 
2385
  mov  ax, #int13_out
2386
  push ax
2387
  jmp _int13_diskette_function
2388
 
2389
int13_notfloppy:
2390
 
2391
int13_disk:
2392
  ;; int13_harddisk modifies high word of EAX
2393
;  shr   eax, #16
2394
;  push  ax
2395
  call  _int13_harddisk
2396
;  pop   ax
2397
;  shl   eax, #16
2398
 
2399
int13_out:
2400 52 zeus
;
2401
; ZEUS HACK: put IF flag on.
2402
;  Seems that MS-DOS does a 'cli' before calling this
2403
;  but after int13 it doesn't set the interrupts back
2404
;
2405
  mov bp, sp
2406
  mov ax, 24[bp]  ; FLAGS location
2407
  or  ax, #0x0200 ; IF on
2408
  mov 24[bp], ax
2409
 
2410 39 zeus
  pop ds
2411
  pop es
2412
  ; popa ; we do this instead:
2413
  pop di
2414
  pop si
2415
  pop bp
2416
  add sp, #2
2417
  pop bx
2418
  pop dx
2419
  pop cx
2420
  pop ax
2421
 
2422
  iret
2423
 
2424 26 zeus
;----------
2425
;- INT18h -
2426
;----------
2427
int18_handler: ;; Boot Failure recovery: try the next device.
2428
 
2429
  ;; Reset SP and SS
2430
  mov  ax, #0xfffe
2431
  mov  sp, ax
2432
  xor  ax, ax
2433
  mov  ss, ax
2434
 
2435
  ;; Get the boot sequence number out of the IPL memory
2436
  mov  bx, #IPL_SEG
2437
  mov  ds, bx                     ;; Set segment
2438
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
2439
  inc  bx                         ;; ++
2440
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
2441
  mov  ds, ax                     ;; and reset the segment to zero.
2442
 
2443
  ;; Carry on in the INT 19h handler, using the new sequence number
2444
  push bx
2445
 
2446
  jmp  int19_next_boot
2447
 
2448
;----------
2449
;- INT19h -
2450
;----------
2451
int19_relocated: ;; Boot function, relocated
2452
 
2453
  ;; int19 was beginning to be really complex, so now it
2454
  ;; just calls a C function that does the work
2455
 
2456
  push bp
2457
  mov  bp, sp
2458
 
2459
  ;; Reset SS and SP
2460
  mov  ax, #0xfffe
2461
  mov  sp, ax
2462
  xor  ax, ax
2463
  mov  ss, ax
2464
 
2465
  ;; Start from the first boot device (0, in AX)
2466
  mov  bx, #IPL_SEG
2467
  mov  ds, bx                     ;; Set segment to write to the IPL memory
2468
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
2469
  mov  ds, ax                     ;; and reset the segment.
2470
 
2471
  push ax
2472
 
2473
int19_next_boot:
2474
 
2475
  ;; Call the C code for the next boot device
2476
  call _int19_function
2477
 
2478
  ;; Boot failed: invoke the boot recovery function
2479
  int  #0x18
2480
 
2481 39 zeus
;----------
2482
;- INT1Ch -
2483
;----------
2484
int1c_handler: ;; User Timer Tick
2485
  iret
2486
 
2487 52 zeus
;--------------------
2488
;- POST: HARD DRIVE -
2489
;--------------------
2490
; relocated here because the primary POST area isnt big enough.
2491
hard_drive_post:
2492
  // IRQ 14 = INT 76h
2493
  // INT 76h calls INT 15h function ax=9100
2494 39 zeus
 
2495 52 zeus
  xor  ax, ax
2496
  mov  ds, ax
2497
  mov  0x0474, al /* hard disk status of last operation */
2498
  mov  0x0477, al /* hard disk port offset (XT only ???) */
2499
  mov  0x048c, al /* hard disk status register */
2500
  mov  0x048d, al /* hard disk error register */
2501
  mov  0x048e, al /* hard disk task complete flag */
2502
  mov  al, #0x01
2503
  mov  0x0475, al /* hard disk number attached */
2504
  mov  al, #0xc0
2505
  mov  0x0476, al /* hard disk control byte */
2506
  SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
2507
  SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
2508
 
2509
  ;; Initialize the sysace controller
2510
  ; CSR_ACE_BUSMODE = ACE_BUSMODE_16BIT;
2511
  mov  dx, #0xe200
2512
  mov  ax, #0x0001
2513
  out  dx, ax
2514
 
2515
  ; if(!(CSR_ACE_STATUSL & ACE_STATUSL_CFDETECT)) return 0;
2516
  mov  dx, #0xe204
2517
  in   ax,  dx
2518
  and  ax, #0x0010
2519
  jne  cf_detect
2520
  hlt  ;; error
2521
 
2522
cf_detect:
2523
  ; if((CSR_ACE_ERRORL != 0) || (CSR_ACE_ERRORH != 0)) return 0;
2524
  mov  dx, #0xe208
2525
  in   ax, dx
2526
  cmp  ax, #0x0
2527
jne  error_l
2528
  mov  dx, #0xe20a
2529
  in   ax, dx
2530
  cmp  ax, #0x0
2531
  je   lock_req
2532
error_l:
2533
  hlt
2534
 
2535
lock_req:
2536
  ; CSR_ACE_CTLL |= ACE_CTLL_LOCKREQ;
2537
  mov  dx, #0xe218
2538
  in   ax, dx
2539
  or   ax, #0x2
2540
  out  dx, ax
2541
 
2542
  ; timeout = TIMEOUT;
2543
  mov  cx, #0xffff
2544
 
2545
  ; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_MPULOCK))) timeout--;
2546
  mov  dx, #0xe204
2547
ace_statusl:
2548
  in   ax, dx
2549
  and  ax, #0x2
2550
  loopz ace_statusl
2551
 
2552
  ; if(timeout == 0) return 0;
2553
  cmp  cx, #0x0
2554
  jnz  success
2555
  hlt  ;; error obtaining lock
2556
 
2557
success:
2558
  ret
2559
 
2560
 
2561 26 zeus
;--------------------
2562
;- POST: EBDA segment
2563
;--------------------
2564
; relocated here because the primary POST area isnt big enough.
2565
ebda_post:
2566
  xor ax, ax            ; mov EBDA seg into 40E
2567
  mov ds, ax
2568
  mov word ptr [0x40E], #EBDA_SEG
2569
  ret;;
2570
 
2571 52 zeus
;--------------------
2572
int76_handler:
2573
  ;; record completion in BIOS task complete flag
2574
  push  ax
2575
  push  ds
2576
  mov   ax, #0x0040
2577
  mov   ds, ax
2578
  mov   0x008E, #0xff
2579
;  call  eoi_both_pics
2580
  pop   ds
2581
  pop   ax
2582
  iret
2583
 
2584
 
2585 26 zeus
rom_checksum:
2586
  push ax
2587
  push bx
2588
  push cx
2589
  xor  ax, ax
2590
  xor  bx, bx
2591
  xor  cx, cx
2592
  mov  ch, [2]
2593
  shl  cx, #1
2594
checksum_loop:
2595
  add  al, [bx]
2596
  inc  bx
2597
  loop checksum_loop
2598
  and  al, #0xff
2599
  pop  cx
2600
  pop  bx
2601
  pop  ax
2602
  ret
2603
 
2604
 
2605
;; We need a copy of this string, but we are not actually a PnP BIOS,
2606
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
2607
.align 16
2608
  db 0
2609
pnp_string:
2610
  .ascii "$PnP"
2611
 
2612
 
2613
rom_scan:
2614
  ;; Scan for existence of valid expansion ROMS.
2615
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
2616
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
2617
  ;;   System  ROM: only 0xE0000
2618
  ;;
2619
  ;; Header:
2620
  ;;   Offset    Value
2621
  ;;   0         0x55
2622
  ;;   1         0xAA
2623
  ;;   2         ROM length in 512-byte blocks
2624
  ;;   3         ROM initialization entry point (FAR CALL)
2625
 
2626
rom_scan_loop:
2627
  push ax       ;; Save AX
2628
  mov  ds, cx
2629
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
2630
  cmp [0], #0xAA55 ;; look for signature
2631
  jne  rom_scan_increment
2632
  call rom_checksum
2633
  jnz  rom_scan_increment
2634
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
2635
 
2636
  ;; We want our increment in 512-byte quantities, rounded to
2637
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
2638
  test al, #0x03
2639
  jz   block_count_rounded
2640
  and  al, #0xfc ;; needs rounding up
2641
  add  al, #0x04
2642
block_count_rounded:
2643
 
2644
  xor  bx, bx   ;; Restore DS back to 0000:
2645
  mov  ds, bx
2646
  push ax       ;; Save AX
2647
  push di       ;; Save DI
2648
  ;; Push addr of ROM entry point
2649
  push cx       ;; Push seg
2650 34 zeus
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
2651
  mov ax, #0x0003
2652
  push ax
2653 26 zeus
 
2654
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
2655
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
2656
  mov  ax, #0xf000
2657
  mov  es, ax
2658
  lea  di, pnp_string
2659
 
2660
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
2661
  db   0xff     ;; call_far ss:[bp+0]
2662
  db   0x5e
2663
  db   0
2664
  cli           ;; In case expansion ROM BIOS turns IF on
2665
  add  sp, #2   ;; Pop offset value
2666
  pop  cx       ;; Pop seg value (restore CX)
2667
 
2668
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
2669
  ;; to init all the ROMs and then go back and build an IPL table of
2670
  ;; all the bootable devices, but we can get away with one pass.
2671
  mov  ds, cx       ;; ROM base
2672
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
2673
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
2674
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
2675
  jne  no_bev
2676
  mov  ax, 2[bx]
2677
  cmp  ax, #0x506e
2678
  jne  no_bev
2679
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
2680
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
2681
  je   no_bev
2682
 
2683
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
2684
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
2685
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
2686
  mov  ds, bx
2687
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
2688
  cmp  bx, #IPL_TABLE_ENTRIES
2689
  je   no_bev                  ;; Get out if the table is full
2690
  push cx
2691
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
2692
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
2693
  pop  cx
2694
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
2695
  mov  6[bx], cx               ;; Build a far pointer from the segment...
2696
  mov  4[bx], ax               ;; and the offset
2697
  cmp  di, #0x0000
2698
  je   no_prod_str
2699
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
2700
  mov  8[bx], di               ;; and the offset
2701
no_prod_str:
2702
  push cx
2703
  mov  cx, #0x4
2704
  shr  bx, cl                  ;; Turn the offset back into a count
2705
  pop  cx
2706
  inc  bx                      ;; We have one more entry now
2707
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
2708
 
2709
no_bev:
2710
  pop  di       ;; Restore DI
2711
  pop  ax       ;; Restore AX
2712
rom_scan_increment:
2713
  push cx
2714
  mov  cx, #5
2715
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
2716
                ;; because the segment selector is shifted left 4 bits.
2717
  pop  cx
2718
  add  cx, ax
2719
  pop  ax       ;; Restore AX
2720
  cmp  cx, ax
2721
  jbe  rom_scan_loop
2722
 
2723
  xor  ax, ax   ;; Restore DS back to 0000:
2724
  mov  ds, ax
2725
  ret
2726
 
2727
;; for 'C' strings and other data, insert them here with
2728
;; a the following hack:
2729
;; DATA_SEG_DEFS_HERE
2730
 
2731
 
2732
;; the following area can be used to write dynamically generated tables
2733
  .align 16
2734
bios_table_area_start:
2735
  dd 0xaafb4442
2736
  dd bios_table_area_end - bios_table_area_start - 8;
2737
 
2738
;--------
2739
;- POST -
2740
;--------
2741
.org 0xe05b ; POST Entry Point
2742
post:
2743
  xor ax, ax
2744
 
2745
normal_post:
2746
  ; case 0: normal startup
2747
 
2748
  cli
2749
  mov  ax, #0xfffe
2750
  mov  sp, ax
2751
  xor  ax, ax
2752
  mov  ds, ax
2753
  mov  ss, ax
2754
 
2755
  ;; zero out BIOS data area (40:00..40:ff)
2756
  mov  es, ax
2757
  mov  cx, #0x0080 ;; 128 words
2758
  mov  di, #0x0400
2759
  cld
2760
  rep
2761
    stosw
2762
 
2763
  ;; set all interrupts to default handler
2764
  xor  bx, bx         ;; offset index
2765
  mov  cx, #0x0100    ;; counter (256 interrupts)
2766
  mov  ax, #dummy_iret_handler
2767
  mov  dx, #0xF000
2768
 
2769
post_default_ints:
2770
  mov  [bx], ax
2771
  add  bx, #2
2772
  mov  [bx], dx
2773
  add  bx, #2
2774
  loop post_default_ints
2775
 
2776
  ;; set vector 0x79 to zero
2777
  ;; this is used by 'gardian angel' protection system
2778
  SET_INT_VECTOR(0x79, #0, #0)
2779
 
2780
  ;; base memory in K 40:13 (word)
2781
  mov  ax, #BASE_MEM_IN_K
2782
  mov  0x0413, ax
2783
 
2784
 
2785
  ;; Manufacturing Test 40:12
2786
  ;;   zerod out above
2787
 
2788
  ;; Warm Boot Flag 0040:0072
2789
  ;;   value of 1234h = skip memory checks
2790
  ;;   zerod out above
2791
 
2792
  ;; Bootstrap failure vector
2793
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
2794
 
2795
  ;; Bootstrap Loader vector
2796
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
2797
 
2798 39 zeus
  ;; User Timer Tick vector
2799
  SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
2800
 
2801
  ;; Memory Size Check vector
2802
  SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
2803
 
2804
  ;; Equipment Configuration Check vector
2805
  SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
2806
 
2807 26 zeus
  ;; EBDA setup
2808
  call ebda_post
2809
 
2810 52 zeus
  ;; PIT setup
2811
  SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
2812
  ;; int 1C already points at dummy_iret_handler (above)
2813
 
2814 39 zeus
  ;; Keyboard
2815 43 zeus
  SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
2816 47 zeus
  SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
2817 39 zeus
 
2818 43 zeus
  xor  ax, ax
2819
  mov  ds, ax
2820
  mov  0x0417, al /* keyboard shift flags, set 1 */
2821
  mov  0x0418, al /* keyboard shift flags, set 2 */
2822
  mov  0x0419, al /* keyboard alt-numpad work area */
2823
  mov  0x0471, al /* keyboard ctrl-break flag */
2824
  mov  0x0497, al /* keyboard status flags 4 */
2825
  mov  al, #0x10
2826
  mov  0x0496, al /* keyboard status flags 3 */
2827
 
2828
  /* keyboard head of buffer pointer */
2829
  mov  bx, #0x001E
2830
  mov  0x041A, bx
2831
 
2832
  /* keyboard end of buffer pointer */
2833
  mov  0x041C, bx
2834
 
2835
  /* keyboard pointer to start of buffer */
2836
  mov  bx, #0x001E
2837
  mov  0x0480, bx
2838
 
2839
  /* keyboard pointer to end of buffer */
2840
  mov  bx, #0x003E
2841
  mov  0x0482, bx
2842
 
2843 47 zeus
  ;; CMOS RTC
2844
  SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
2845
 
2846 26 zeus
  ;; Video setup
2847
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
2848
 
2849
  mov  cx, #0xc000  ;; init vga bios
2850
  mov  ax, #0xc780
2851 37 zeus
 
2852 26 zeus
  call rom_scan
2853
 
2854
  call _print_bios_banner
2855 37 zeus
 
2856 52 zeus
  ;;
2857
  ;; Hard Drive setup
2858
  ;;
2859
  call hard_drive_post
2860 39 zeus
 
2861 26 zeus
  call _init_boot_vectors
2862
 
2863
  mov  cx, #0xc800  ;; init option roms
2864
  mov  ax, #0xe000
2865
  call rom_scan
2866
 
2867
  sti        ;; enable interrupts
2868
  int  #0x19
2869
 
2870 39 zeus
;-------------------------------------------
2871
;- INT 13h Fixed Disk Services Entry Point -
2872
;-------------------------------------------
2873
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
2874
int13_handler:
2875
  //JMPL(int13_relocated)
2876
  jmp int13_relocated
2877
 
2878
.org 0xe401 ; Fixed Disk Parameter Table
2879
 
2880 26 zeus
;----------
2881
;- INT19h -
2882
;----------
2883
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
2884
int19_handler:
2885
 
2886
  jmp int19_relocated
2887
 
2888 43 zeus
 
2889 39 zeus
;----------------------------------------
2890
;- INT 16h Keyboard Service Entry Point -
2891
;----------------------------------------
2892
.org 0xe82e
2893
int16_handler:
2894 43 zeus
 
2895
  sti
2896
  push  ds
2897
  pushf
2898
  ;pusha ; we do this instead:
2899
  push ax
2900
  push cx
2901
  push dx
2902
  push bx
2903
  push sp
2904
  mov  bx, sp
2905 45 zeus
  sseg
2906
    add  [bx], #10
2907
  sseg
2908
    mov  bx, [bx+2]
2909 43 zeus
  push bp
2910
  push si
2911
  push di
2912
 
2913
  cmp   ah, #0x00
2914
  je    int16_F00
2915
  cmp   ah, #0x10
2916
  je    int16_F00
2917
 
2918
  mov  bx, #0xf000
2919
  mov  ds, bx
2920
  call _int16_function
2921
  ; popa ; we do this instead:
2922
  pop di
2923
  pop si
2924
  pop bp
2925
  add sp, #2
2926
  pop bx
2927
  pop dx
2928
  pop cx
2929
  pop ax
2930
  popf
2931
  pop  ds
2932
  jz   int16_zero_set
2933
 
2934
int16_zero_clear:
2935
  push bp
2936
  mov  bp, sp
2937
  //SEG SS
2938
  and  BYTE [bp + 0x06], #0xbf
2939
  pop  bp
2940 39 zeus
  iret
2941 43 zeus
 
2942
int16_zero_set:
2943 39 zeus
  push bp
2944
  mov  bp, sp
2945
  //SEG SS
2946
  or   BYTE [bp + 0x06], #0x40
2947
  pop  bp
2948
  iret
2949
 
2950 43 zeus
int16_F00:
2951
  mov  bx, #0x0040
2952
  mov  ds, bx
2953
 
2954
int16_wait_for_key:
2955
  cli
2956
  mov  bx, 0x001a
2957
  cmp  bx, 0x001c
2958
  jne  int16_key_found
2959
  sti
2960
  nop
2961
#if 0
2962
                           /* no key yet, call int 15h, function AX=9002 */
2963
  0x50,                    /* push AX */
2964
  0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
2965
  0xcd, 0x15,              /* int 15h */
2966
  0x58,                    /* pop  AX */
2967
  0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
2968
#endif
2969
  jmp  int16_wait_for_key
2970
 
2971
int16_key_found:
2972
  mov  bx, #0xf000
2973
  mov  ds, bx
2974
  call _int16_function
2975
  ; popa ; we do this instead:
2976
  pop di
2977
  pop si
2978
  pop bp
2979
  add sp, #2
2980
  pop bx
2981
  pop dx
2982
  pop cx
2983
  pop ax
2984
  popf
2985
  pop  ds
2986
#if 0
2987
                           /* notify int16 complete w/ int 15h, function AX=9102 */
2988
  0x50,                    /* push AX */
2989
  0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
2990
  0xcd, 0x15,              /* int 15h */
2991
  0x58,                    /* pop  AX */
2992
#endif
2993 26 zeus
  iret
2994
 
2995 43 zeus
 
2996
 
2997
;-------------------------------------------------
2998
;- INT09h : Keyboard Hardware Service Entry Point -
2999
;-------------------------------------------------
3000
.org 0xe987
3001
int09_handler:
3002
  cli
3003
  push ax
3004
  in  al, #0x60             ;;read key from keyboard controller
3005
  sti
3006 45 zeus
 
3007 43 zeus
  push  ds
3008
  ;pusha ; we do this instead:
3009
 
3010
  push ax
3011
  push cx
3012
  push dx
3013
  push bx
3014
  push sp
3015
  mov  bx, sp
3016 45 zeus
  sseg
3017
    add  [bx], #10
3018
  sseg
3019
    mov  bx, [bx+2]
3020 43 zeus
  push bp
3021
  push si
3022
  push di
3023
 
3024
  ;; check for extended key
3025
  cmp  al, #0xe0
3026
  jne int09_check_pause
3027
  xor  ax, ax
3028
  mov  ds, ax
3029
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x02
3030
  or   al, #0x02
3031
  mov  BYTE [0x496], al
3032
  jmp int09_done
3033
 
3034
int09_check_pause: ;; check for pause key
3035
  cmp  al, #0xe1
3036
  jne int09_process_key
3037
  xor  ax, ax
3038
  mov  ds, ax
3039
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
3040
  or   al, #0x01
3041
  mov  BYTE [0x496], al
3042
  jmp int09_done
3043
 
3044
int09_process_key:
3045
  mov   bx, #0xf000
3046
  mov   ds, bx
3047
  call  _int09_function
3048
int09_done:
3049
  ; popa ; we do this instead:
3050
  pop di
3051
  pop si
3052
  pop bp
3053
  add sp, #2
3054
  pop bx
3055
  pop dx
3056
  pop cx
3057
  pop ax
3058
 
3059
  pop   ds
3060 45 zeus
 
3061 43 zeus
  cli
3062
  pop ax
3063
  iret
3064
 
3065
 
3066 26 zeus
;----------
3067
;- INT10h -
3068
;----------
3069
.org 0xf065 ; INT 10h Video Support Service Entry Point
3070
int10_handler:
3071
  ;; dont do anything, since the VGA BIOS handles int10h requests
3072
  iret
3073
 
3074
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
3075
 
3076 39 zeus
;----------
3077
;- INT12h -
3078
;----------
3079
.org 0xf841 ; INT 12h Memory Size Service Entry Point
3080
; ??? different for Pentium (machine check)?
3081
int12_handler:
3082
  push ds
3083
  mov  ax, #0x0040
3084
  mov  ds, ax
3085
  mov  ax, 0x0013
3086
  pop  ds
3087
  iret
3088
 
3089
;----------
3090
;- INT11h -
3091
;----------
3092
.org 0xf84d ; INT 11h Equipment List Service Entry Point
3093
int11_handler:
3094
  push ds
3095
  mov  ax, #0x0040
3096
  mov  ds, ax
3097
  mov  ax, 0x0010
3098
  pop  ds
3099
  iret
3100
 
3101 47 zeus
;----------
3102
;- INT1Ah -
3103
;----------
3104
.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
3105
int1a_handler:
3106
  push ds
3107
  ;pusha ; we do this instead:
3108
  push ax
3109
  push cx
3110
  push dx
3111
  push bx
3112
  push sp
3113
  mov  bx, sp
3114
  sseg
3115
    add  [bx], #10
3116
  sseg
3117
    mov  bx, [bx+2]
3118
  push bp
3119
  push si
3120
  push di
3121
 
3122
  xor  ax, ax
3123
  mov  ds, ax
3124
int1a_callfunction:
3125
  call _int1a_function
3126
  ; popa ; we do this instead:
3127
  pop di
3128
  pop si
3129
  pop bp
3130
  add sp, #2
3131
  pop bx
3132
  pop dx
3133
  pop cx
3134
  pop ax
3135
 
3136
  pop  ds
3137
  iret
3138
 
3139 52 zeus
;---------
3140
;- INT08 -
3141
;---------
3142
.org 0xfea5 ; INT 08h System Timer ISR Entry Point
3143
int08_handler:
3144
  sti
3145
  push ax
3146
  push bx
3147
  push ds
3148
  xor ax, ax
3149
  mov ds, ax
3150
 
3151
  mov ax, 0x046c ;; get ticks dword
3152
  mov bx, 0x046e
3153
  inc ax
3154
  jne i08_linc_done
3155
  inc bx         ;; inc high word
3156
 
3157
i08_linc_done:
3158
  push bx
3159
  ;; compare eax to one days worth of timer ticks at 18.2 hz
3160
  sub bx, #0x0018
3161
  jne i08_lcmp_done
3162
  cmp ax, #0x00B0
3163
  jb  i08_lcmp_b_and_lt
3164
  jge i08_lcmp_done
3165
  inc bx
3166
  jmp i08_lcmp_done
3167
 
3168
i08_lcmp_b_and_lt:
3169
  dec bx
3170
 
3171
i08_lcmp_done:
3172
  pop bx
3173
  jb  int08_store_ticks
3174
  ;; there has been a midnight rollover at this point
3175
  xor ax, ax      ;; zero out counter
3176
  xor bx, bx
3177
  inc BYTE 0x0470 ;; increment rollover flag
3178
 
3179
int08_store_ticks:
3180
  mov 0x046c, ax ;; store new ticks dword
3181
  mov 0x046e, bx
3182
  ;; chain to user timer tick INT #0x1c
3183
  //pushf
3184
  //;; call_ep [ds:loc]
3185
  //CALL_EP( 0x1c << 2 )
3186
  int #0x1c
3187
  cli
3188
  ;; call eoi_master_pic
3189
  pop ds
3190
  pop bx
3191
  pop ax
3192
  iret
3193
 
3194
.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
3195
 
3196
 
3197
.org 0xff00
3198
.ascii BIOS_COPYRIGHT_STRING
3199
 
3200 26 zeus
;------------------------------------------------
3201
;- IRET Instruction for Dummy Interrupt Handler -
3202
;------------------------------------------------
3203
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
3204
dummy_iret_handler:
3205
  iret
3206
 
3207
.org 0xfff0 ; Power-up Entry Point
3208 39 zeus
;  hlt
3209 26 zeus
  jmp 0xf000:post
3210
 
3211
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
3212
.ascii BIOS_BUILD_DATE
3213
 
3214
.org 0xfffe ; System Model ID
3215
db SYS_MODEL_ID
3216
db 0x00   ; filler
3217
ASM_END
3218
 
3219
ASM_START
3220
.org 0xcc00
3221
bios_table_area_end:
3222
// bcc-generated data will be placed here
3223
ASM_END

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.