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

Subversion Repositories zet86

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

Go to most recent revision | 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
  ASM_END
425
 
426 47 zeus
// for access to RAM area which is used by interrupt vectors
427
// and BIOS Data Area
428
 
429 26 zeus
typedef struct {
430 47 zeus
  unsigned char filler1[0x400];
431
  unsigned char filler2[0x6c];
432
  Bit16u ticks_low;
433
  Bit16u ticks_high;
434
  Bit8u  midnight_flag;
435
  } bios_data_t;
436
 
437
#define BiosData ((bios_data_t  *) 0)
438
 
439
typedef struct {
440
  union {
441
    struct {
442
      Bit16u di, si, bp, sp;
443
      Bit16u bx, dx, cx, ax;
444
      } r16;
445
    struct {
446
      Bit16u filler[4];
447
      Bit8u  bl, bh, dl, dh, cl, ch, al, ah;
448
      } r8;
449
    } u;
450
  } pusha_regs_t;
451
 
452
typedef struct {
453
  union {
454
    struct {
455
      Bit16u flags;
456
      } r16;
457
    struct {
458
      Bit8u  flagsl;
459
      Bit8u  flagsh;
460
      } r8;
461
    } u;
462
  } flags_t;
463
 
464
#define SetCF(x)   x.u.r8.flagsl |= 0x01
465
#define SetZF(x)   x.u.r8.flagsl |= 0x40
466
#define ClearCF(x) x.u.r8.flagsl &= 0xfe
467
#define ClearZF(x) x.u.r8.flagsl &= 0xbf
468
#define GetCF(x)   (x.u.r8.flagsl & 0x01)
469
 
470
typedef struct {
471
  Bit16u ip;
472
  Bit16u cs;
473
  flags_t flags;
474
  } iret_addr_t;
475
 
476
typedef struct {
477 26 zeus
  Bit16u type;
478
  Bit16u flags;
479
  Bit32u vector;
480
  Bit32u description;
481
  Bit32u reserved;
482
  } ipl_entry_t;
483
 
484 39 zeus
static Bit16u         inw();
485
static void           outw();
486 26 zeus
 
487
static Bit8u          read_byte();
488
static Bit16u         read_word();
489
static void           write_byte();
490
static void           write_word();
491
static void           bios_printf();
492
 
493 43 zeus
static void           int09_function();
494 39 zeus
static void           int13_harddisk();
495 46 zeus
static void           transf_sect();
496 39 zeus
static void           int13_diskette_function();
497 43 zeus
static void           int16_function();
498 26 zeus
static void           int19_function();
499 47 zeus
static void           int1a_function();
500 26 zeus
static Bit16u         get_CS();
501
static Bit16u         get_SS();
502 43 zeus
static unsigned int   enqueue_key();
503
static unsigned int   dequeue_key();
504 39 zeus
static void           set_diskette_ret_status();
505
static void           set_diskette_current_cyl();
506 26 zeus
 
507
static void           print_bios_banner();
508
static void           print_boot_device();
509 39 zeus
static void           print_boot_failure();
510 26 zeus
 
511 43 zeus
#if DEBUG_INT16
512
#  define BX_DEBUG_INT16(a...) BX_DEBUG(a)
513
#else
514
#  define BX_DEBUG_INT16(a...)
515
#endif
516
 
517 39 zeus
#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
518
#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
519
#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
520
#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
521
#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
522
#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
523
#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
524
#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
525
 
526
#define GET_AL() ( AX & 0x00ff )
527
#define GET_BL() ( BX & 0x00ff )
528
#define GET_CL() ( CX & 0x00ff )
529
#define GET_DL() ( DX & 0x00ff )
530
#define GET_AH() ( AX >> 8 )
531
#define GET_BH() ( BX >> 8 )
532
#define GET_CH() ( CX >> 8 )
533
#define GET_DH() ( DX >> 8 )
534
 
535
#define GET_ELDL() ( ELDX & 0x00ff )
536
#define GET_ELDH() ( ELDX >> 8 )
537
 
538
#define SET_CF()     FLAGS |= 0x0001
539
#define CLEAR_CF()   FLAGS &= 0xfffe
540
#define GET_CF()     (FLAGS & 0x0001)
541
 
542
#define SET_ZF()     FLAGS |= 0x0040
543
#define CLEAR_ZF()   FLAGS &= 0xffbf
544
#define GET_ZF()     (FLAGS & 0x0040)
545
 
546 43 zeus
#define UNSUPPORTED_FUNCTION 0x86
547
 
548
#define none 0
549
#define MAX_SCAN_CODE 0x58
550
 
551
static struct {
552
  Bit16u normal;
553
  Bit16u shift;
554
  Bit16u control;
555
  Bit16u alt;
556
  Bit8u lock_flags;
557
  } scan_to_scanascii[MAX_SCAN_CODE + 1] = {
558
      {   none,   none,   none,   none, none },
559
      { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
560
      { 0x0231, 0x0221,   none, 0x7800, none }, /* 1! */
561
      { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
562
      { 0x0433, 0x0423,   none, 0x7a00, none }, /* 3# */
563
      { 0x0534, 0x0524,   none, 0x7b00, none }, /* 4$ */
564
      { 0x0635, 0x0625,   none, 0x7c00, none }, /* 5% */
565
      { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
566
      { 0x0837, 0x0826,   none, 0x7e00, none }, /* 7& */
567
      { 0x0938, 0x092a,   none, 0x7f00, none }, /* 8* */
568
      { 0x0a39, 0x0a28,   none, 0x8000, none }, /* 9( */
569
      { 0x0b30, 0x0b29,   none, 0x8100, none }, /* 0) */
570
      { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
571
      { 0x0d3d, 0x0d2b,   none, 0x8300, none }, /* =+ */
572
      { 0x0e08, 0x0e08, 0x0e7f,   none, none }, /* backspace */
573
      { 0x0f09, 0x0f00,   none,   none, none }, /* tab */
574
      { 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
575
      { 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
576
      { 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
577
      { 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
578
      { 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
579
      { 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
580
      { 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
581
      { 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
582
      { 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
583
      { 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
584
      { 0x1a5b, 0x1a7b, 0x1a1b,   none, none }, /* [{ */
585
      { 0x1b5d, 0x1b7d, 0x1b1d,   none, none }, /* ]} */
586
      { 0x1c0d, 0x1c0d, 0x1c0a,   none, none }, /* Enter */
587
      {   none,   none,   none,   none, none }, /* L Ctrl */
588
      { 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
589
      { 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
590
      { 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
591
      { 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
592
      { 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
593
      { 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
594
      { 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
595
      { 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
596
      { 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
597
      { 0x273b, 0x273a,   none,   none, none }, /* ;: */
598
      { 0x2827, 0x2822,   none,   none, none }, /* '" */
599
      { 0x2960, 0x297e,   none,   none, none }, /* `~ */
600
      {   none,   none,   none,   none, none }, /* L shift */
601
      { 0x2b5c, 0x2b7c, 0x2b1c,   none, none }, /* |\ */
602
      { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
603
      { 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
604
      { 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
605
      { 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
606
      { 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
607
      { 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
608
      { 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
609
      { 0x332c, 0x333c,   none,   none, none }, /* ,< */
610
      { 0x342e, 0x343e,   none,   none, none }, /* .> */
611
      { 0x352f, 0x353f,   none,   none, none }, /* /? */
612
      {   none,   none,   none,   none, none }, /* R Shift */
613
      { 0x372a, 0x372a,   none,   none, none }, /* * */
614
      {   none,   none,   none,   none, none }, /* L Alt */
615
      { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
616
      {   none,   none,   none,   none, none }, /* caps lock */
617
      { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
618
      { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
619
      { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
620
      { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
621
      { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
622
      { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
623
      { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
624
      { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
625
      { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
626
      { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
627
      {   none,   none,   none,   none, none }, /* Num Lock */
628
      {   none,   none,   none,   none, none }, /* Scroll Lock */
629
      { 0x4700, 0x4737, 0x7700,   none, 0x20 }, /* 7 Home */
630
      { 0x4800, 0x4838,   none,   none, 0x20 }, /* 8 UP */
631
      { 0x4900, 0x4939, 0x8400,   none, 0x20 }, /* 9 PgUp */
632
      { 0x4a2d, 0x4a2d,   none,   none, none }, /* - */
633
      { 0x4b00, 0x4b34, 0x7300,   none, 0x20 }, /* 4 Left */
634
      { 0x4c00, 0x4c35,   none,   none, 0x20 }, /* 5 */
635
      { 0x4d00, 0x4d36, 0x7400,   none, 0x20 }, /* 6 Right */
636
      { 0x4e2b, 0x4e2b,   none,   none, none }, /* + */
637
      { 0x4f00, 0x4f31, 0x7500,   none, 0x20 }, /* 1 End */
638
      { 0x5000, 0x5032,   none,   none, 0x20 }, /* 2 Down */
639
      { 0x5100, 0x5133, 0x7600,   none, 0x20 }, /* 3 PgDn */
640
      { 0x5200, 0x5230,   none,   none, 0x20 }, /* 0 Ins */
641
      { 0x5300, 0x532e,   none,   none, 0x20 }, /* Del */
642
      {   none,   none,   none,   none, none },
643
      {   none,   none,   none,   none, none },
644
      { 0x565c, 0x567c,   none,   none, none }, /* \| */
645
      { 0x5700, 0x5700,   none,   none, none }, /* F11 */
646
      { 0x5800, 0x5800,   none,   none, none }  /* F12 */
647
      };
648
 
649 39 zeus
  Bit16u
650
inw(port)
651
  Bit16u port;
652 26 zeus
{
653
ASM_START
654
  push bp
655
  mov  bp, sp
656
 
657 39 zeus
    push dx
658
    mov  dx, 4[bp]
659
    in   ax, dx
660
    pop  dx
661 26 zeus
 
662
  pop  bp
663
ASM_END
664
}
665
 
666 39 zeus
  void
667
outw(port, val)
668
  Bit16u port;
669
  Bit16u  val;
670
{
671
ASM_START
672
  push bp
673
  mov  bp, sp
674
 
675
    push ax
676
    push dx
677
    mov  dx, 4[bp]
678
    mov  ax, 6[bp]
679
    out  dx, ax
680
    pop  dx
681
    pop  ax
682
 
683
  pop  bp
684
ASM_END
685
}
686
 
687 26 zeus
  Bit8u
688
read_byte(seg, offset)
689
  Bit16u seg;
690
  Bit16u offset;
691
{
692
ASM_START
693
  push bp
694
  mov  bp, sp
695
 
696
    push bx
697
    push ds
698
    mov  ax, 4[bp] ; segment
699
    mov  ds, ax
700
    mov  bx, 6[bp] ; offset
701
    mov  al, [bx]
702
    ;; al = return value (byte)
703
    pop  ds
704
    pop  bx
705
 
706
  pop  bp
707
ASM_END
708
}
709
 
710
  Bit16u
711
read_word(seg, offset)
712
  Bit16u seg;
713
  Bit16u offset;
714
{
715
ASM_START
716
  push bp
717
  mov  bp, sp
718
 
719
    push bx
720
    push ds
721
    mov  ax, 4[bp] ; segment
722
    mov  ds, ax
723
    mov  bx, 6[bp] ; offset
724
    mov  ax, [bx]
725
    ;; ax = return value (word)
726
    pop  ds
727
    pop  bx
728
 
729
  pop  bp
730
ASM_END
731
}
732
 
733
  void
734
write_byte(seg, offset, data)
735
  Bit16u seg;
736
  Bit16u offset;
737
  Bit8u data;
738
{
739
ASM_START
740
  push bp
741
  mov  bp, sp
742
 
743
    push ax
744
    push bx
745
    push ds
746
    mov  ax, 4[bp] ; segment
747
    mov  ds, ax
748
    mov  bx, 6[bp] ; offset
749
    mov  al, 8[bp] ; data byte
750
    mov  [bx], al  ; write data byte
751
    pop  ds
752
    pop  bx
753
    pop  ax
754
 
755
  pop  bp
756
ASM_END
757
}
758
 
759
  void
760
write_word(seg, offset, data)
761
  Bit16u seg;
762
  Bit16u offset;
763
  Bit16u data;
764
{
765
ASM_START
766
  push bp
767
  mov  bp, sp
768
 
769
    push ax
770
    push bx
771
    push ds
772
    mov  ax, 4[bp] ; segment
773
    mov  ds, ax
774
    mov  bx, 6[bp] ; offset
775
    mov  ax, 8[bp] ; data word
776
    mov  [bx], ax  ; write data word
777
    pop  ds
778
    pop  bx
779
    pop  ax
780
 
781
  pop  bp
782
ASM_END
783
}
784
 
785
  Bit16u
786
get_CS()
787
{
788
ASM_START
789
  mov  ax, cs
790
ASM_END
791
}
792
 
793
  Bit16u
794
get_SS()
795
{
796
ASM_START
797
  mov  ax, ss
798
ASM_END
799
}
800
 
801
  void
802
wrch(c)
803
  Bit8u  c;
804
{
805
  ASM_START
806
  push bp
807
  mov  bp, sp
808
 
809
  push bx
810
  mov  ah, #0x0e
811
  mov  al, 4[bp]
812
  xor  bx,bx
813
  int  #0x10
814
  pop  bx
815
 
816
  pop  bp
817
  ASM_END
818
}
819
 
820
  void
821
send(action, c)
822
  Bit16u action;
823
  Bit8u  c;
824
{
825
  if (action & BIOS_PRINTF_SCREEN) {
826
    if (c == '\n') wrch('\r');
827
    wrch(c);
828
  }
829
}
830
 
831
  void
832
put_int(action, val, width, neg)
833
  Bit16u action;
834
  short val, width;
835
  bx_bool neg;
836
{
837
  short nval = val / 10;
838
  if (nval)
839
    put_int(action, nval, width - 1, neg);
840
  else {
841
    while (--width > 0) send(action, ' ');
842
    if (neg) send(action, '-');
843
  }
844
  send(action, val - (nval * 10) + '0');
845
}
846
 
847
  void
848
put_uint(action, val, width, neg)
849
  Bit16u action;
850
  unsigned short val;
851
  short width;
852
  bx_bool neg;
853
{
854
  unsigned short nval = val / 10;
855
  if (nval)
856
    put_uint(action, nval, width - 1, neg);
857
  else {
858
    while (--width > 0) send(action, ' ');
859
    if (neg) send(action, '-');
860
  }
861
  send(action, val - (nval * 10) + '0');
862
}
863
 
864
  void
865
put_luint(action, val, width, neg)
866
  Bit16u action;
867
  unsigned long val;
868
  short width;
869
  bx_bool neg;
870
{
871
  unsigned long nval = val / 10;
872
  if (nval)
873
    put_luint(action, nval, width - 1, neg);
874
  else {
875
    while (--width > 0) send(action, ' ');
876
    if (neg) send(action, '-');
877
  }
878
  send(action, val - (nval * 10) + '0');
879
}
880
 
881
void put_str(action, segment, offset)
882
  Bit16u action;
883
  Bit16u segment;
884
  Bit16u offset;
885
{
886
  Bit8u c;
887
 
888
  while (c = read_byte(segment, offset)) {
889
    send(action, c);
890
    offset++;
891
  }
892
}
893
 
894
//--------------------------------------------------------------------------
895
// bios_printf()
896
//   A compact variable argument printf function.
897
//
898
//   Supports %[format_width][length]format
899
//   where format can be x,X,u,d,s,S,c
900
//   and the optional length modifier is l (ell)
901
//--------------------------------------------------------------------------
902
  void
903
bios_printf(action, s)
904
  Bit16u action;
905
  Bit8u *s;
906
{
907
  Bit8u c, format_char;
908
  bx_bool  in_format;
909
  short i;
910
  Bit16u  *arg_ptr;
911
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
912
 
913
  arg_ptr = &s;
914
  arg_seg = get_SS();
915
 
916
  in_format = 0;
917
  format_width = 0;
918
 
919
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
920
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
921
 
922
  while (c = read_byte(get_CS(), s)) {
923
    if ( c == '%' ) {
924
      in_format = 1;
925
      format_width = 0;
926
      }
927
    else if (in_format) {
928
      if ( (c>='0') && (c<='9') ) {
929
        format_width = (format_width * 10) + (c - '0');
930
        }
931
      else {
932
        arg_ptr++; // increment to next arg
933
        arg = read_word(arg_seg, arg_ptr);
934
        if (c == 'x' || c == 'X') {
935
          if (format_width == 0)
936
            format_width = 4;
937
          if (c == 'x')
938
            hexadd = 'a';
939
          else
940
            hexadd = 'A';
941
          for (i=format_width-1; i>=0; i--) {
942
            nibble = (arg >> (4 * i)) & 0x000f;
943
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
944
            }
945
          }
946
        else if (c == 'u') {
947
          put_uint(action, arg, format_width, 0);
948
          }
949
        else if (c == 'l') {
950
          s++;
951
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
952
          arg_ptr++; /* increment to next arg */
953
          hibyte = read_word(arg_seg, arg_ptr);
954
          if (c == 'd') {
955
            if (hibyte & 0x8000)
956
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
957
            else
958
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
959
           }
960
          else if (c == 'u') {
961
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
962
           }
963
          else if (c == 'x' || c == 'X')
964
           {
965
            if (format_width == 0)
966
              format_width = 8;
967
            if (c == 'x')
968
              hexadd = 'a';
969
            else
970
              hexadd = 'A';
971
            for (i=format_width-1; i>=0; i--) {
972
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
973
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
974
              }
975
           }
976
          }
977
        else if (c == 'd') {
978
          if (arg & 0x8000)
979
            put_int(action, -arg, format_width - 1, 1);
980
          else
981
            put_int(action, arg, format_width, 0);
982
          }
983
        else if (c == 's') {
984
          put_str(action, get_CS(), arg);
985
          }
986
        else if (c == 'S') {
987
          hibyte = arg;
988
          arg_ptr++;
989
          arg = read_word(arg_seg, arg_ptr);
990
          put_str(action, hibyte, arg);
991
          }
992
        else if (c == 'c') {
993
          send(action, arg);
994
          }
995
        else
996
          BX_PANIC("bios_printf: unknown format\n");
997
          in_format = 0;
998
        }
999
      }
1000
    else {
1001
      send(action, c);
1002
      }
1003
    s ++;
1004
    }
1005
 
1006
  if (action & BIOS_PRINTF_HALT) {
1007
    // freeze in a busy loop.
1008
ASM_START
1009
    cli
1010
 halt2_loop:
1011
    hlt
1012
    jmp halt2_loop
1013
ASM_END
1014
    }
1015
}
1016
 
1017 47 zeus
static char bios_svn_version_string[] = "$Revision: 1.13 $ $Date: 2009-03-05 00:26:53 $";
1018 26 zeus
 
1019
//--------------------------------------------------------------------------
1020
// print_bios_banner
1021
//   displays a the bios version
1022
//--------------------------------------------------------------------------
1023
void
1024
print_bios_banner()
1025
{
1026 37 zeus
  printf("Zet ROMBIOS - build: %s\n%s\n\n",
1027 26 zeus
    BIOS_BUILD_DATE, bios_svn_version_string);
1028
}
1029
 
1030
//--------------------------------------------------------------------------
1031
// BIOS Boot Specification 1.0.1 compatibility
1032
//
1033
// Very basic support for the BIOS Boot Specification, which allows expansion
1034
// ROMs to register themselves as boot devices, instead of just stealing the
1035
// INT 19h boot vector.
1036
//
1037
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
1038
// one; we just lie to the option ROMs to make them behave correctly.
1039
// We also don't support letting option ROMs register as bootable disk
1040
// drives (BCVs), only as bootable devices (BEVs).
1041
//
1042
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
1043
//--------------------------------------------------------------------------
1044
 
1045 39 zeus
static char drivetypes[][20]={"", "Floppy flash image" };
1046 26 zeus
 
1047
static void
1048
init_boot_vectors()
1049
{
1050
  ipl_entry_t e;
1051
  Bit16u count = 0;
1052
  Bit16u ss = get_SS();
1053
 
1054
  /* Clear out the IPL table. */
1055
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
1056
 
1057
  /* User selected device not set */
1058
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
1059
 
1060 39 zeus
  /* Floppy drive */
1061
  e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
1062
  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
1063
  count++;
1064 26 zeus
 
1065
  /* Remember how many devices we have */
1066
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
1067
  /* Not tried booting anything yet */
1068
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
1069
}
1070
 
1071
static Bit8u
1072
get_boot_vector(i, e)
1073
Bit16u i; ipl_entry_t *e;
1074
{
1075
  Bit16u count;
1076
  Bit16u ss = get_SS();
1077
  /* Get the count of boot devices, and refuse to overrun the array */
1078
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
1079
  if (i >= count) return 0;
1080
  /* OK to read this device */
1081
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
1082
  return 1;
1083
}
1084
 
1085
//--------------------------------------------------------------------------
1086
// print_boot_device
1087
//   displays the boot device
1088
//--------------------------------------------------------------------------
1089
 
1090
void
1091
print_boot_device(e)
1092
  ipl_entry_t *e;
1093
{
1094
  Bit16u type;
1095
  char description[33];
1096
  Bit16u ss = get_SS();
1097
  type = e->type;
1098
  /* NIC appears as type 0x80 */
1099
  if (type == IPL_TYPE_BEV) type = 0x4;
1100
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
1101
  printf("Booting from %s", drivetypes[type]);
1102
  /* print product string if BEV */
1103
  if (type == 4 && e->description != 0) {
1104
    /* first 32 bytes are significant */
1105
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
1106
    /* terminate string */
1107
    description[32] = 0;
1108
    printf(" [%S]", ss, description);
1109
  }
1110 39 zeus
  printf("...\n\n");
1111 26 zeus
}
1112
 
1113 39 zeus
//--------------------------------------------------------------------------
1114
// print_boot_failure
1115
//   displays the reason why boot failed
1116
//--------------------------------------------------------------------------
1117
  void
1118
print_boot_failure(type, reason)
1119
  Bit16u type; Bit8u reason;
1120
{
1121
  if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
1122
 
1123
  printf("Boot failed");
1124
  if (type < 4) {
1125
    /* Report the reason too */
1126
    if (reason==0)
1127
      printf(": not a bootable disk");
1128
    else
1129
      printf(": could not read the boot disk");
1130
  }
1131
  printf("\n\n");
1132
}
1133
 
1134
 
1135 43 zeus
  void
1136
int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS)
1137
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS;
1138
{
1139
  Bit8u scan_code, ascii_code, shift_flags, led_flags, count;
1140
  Bit16u kbd_code, max;
1141
 
1142
  shift_flags = read_byte(0x0040, 0x17);
1143
  led_flags = read_byte(0x0040, 0x97);
1144
 
1145
  switch (GET_AH()) {
1146
    case 0x00: /* read keyboard input */
1147
 
1148
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
1149
        BX_PANIC("KBD: int16h: out of keyboard input\n");
1150
        }
1151
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1152
      else if (ascii_code == 0xE0) ascii_code = 0;
1153
      AX = (scan_code << 8) | ascii_code;
1154
      break;
1155
 
1156
    case 0x01: /* check keyboard status */
1157
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
1158
        SET_ZF();
1159
        return;
1160
        }
1161
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1162
      else if (ascii_code == 0xE0) ascii_code = 0;
1163
      AX = (scan_code << 8) | ascii_code;
1164
      CLEAR_ZF();
1165
      break;
1166
 
1167
    case 0x02: /* get shift flag status */
1168
      shift_flags = read_byte(0x0040, 0x17);
1169
      SET_AL(shift_flags);
1170
      break;
1171
 
1172
    case 0x05: /* store key-stroke into buffer */
1173
      if ( !enqueue_key(GET_CH(), GET_CL()) ) {
1174
        SET_AL(1);
1175
        }
1176
      else {
1177
        SET_AL(0);
1178
        }
1179
      break;
1180
 
1181
    case 0x09: /* GET KEYBOARD FUNCTIONALITY */
1182
      // bit Bochs Description
1183
      //  7    0   reserved
1184
      //  6    0   INT 16/AH=20h-22h supported (122-key keyboard support)
1185
      //  5    1   INT 16/AH=10h-12h supported (enhanced keyboard support)
1186
      //  4    1   INT 16/AH=0Ah supported
1187
      //  3    0   INT 16/AX=0306h supported
1188
      //  2    0   INT 16/AX=0305h supported
1189
      //  1    0   INT 16/AX=0304h supported
1190
      //  0    0   INT 16/AX=0300h supported
1191
      //
1192
      SET_AL(0x30);
1193
      break;
1194
 
1195
    case 0x10: /* read MF-II keyboard input */
1196
 
1197
      if ( !dequeue_key(&scan_code, &ascii_code, 1) ) {
1198
        BX_PANIC("KBD: int16h: out of keyboard input\n");
1199
        }
1200
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1201
      AX = (scan_code << 8) | ascii_code;
1202
      break;
1203
 
1204
    case 0x11: /* check MF-II keyboard status */
1205
      if ( !dequeue_key(&scan_code, &ascii_code, 0) ) {
1206
        SET_ZF();
1207
        return;
1208
        }
1209
      if (scan_code !=0 && ascii_code == 0xF0) ascii_code = 0;
1210
      AX = (scan_code << 8) | ascii_code;
1211
      CLEAR_ZF();
1212
      break;
1213
 
1214
    case 0x12: /* get extended keyboard status */
1215
      shift_flags = read_byte(0x0040, 0x17);
1216
      SET_AL(shift_flags);
1217
      shift_flags = read_byte(0x0040, 0x18) & 0x73;
1218
      shift_flags |= read_byte(0x0040, 0x96) & 0x0c;
1219
      SET_AH(shift_flags);
1220
      BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
1221
      break;
1222
 
1223
    case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
1224
      SET_AH(0x80); // function int16 ah=0x10-0x12 supported
1225
      break;
1226
 
1227
    case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
1228
      // don't change AH : function int16 ah=0x20-0x22 NOT supported
1229
      break;
1230
 
1231
    case 0x6F:
1232
      if (GET_AL() == 0x08)
1233
        SET_AH(0x02); // unsupported, aka normal keyboard
1234
 
1235
    default:
1236
      BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH());
1237
    }
1238
}
1239
 
1240
  unsigned int
1241
dequeue_key(scan_code, ascii_code, incr)
1242
  Bit8u *scan_code;
1243
  Bit8u *ascii_code;
1244
  unsigned int incr;
1245
{
1246
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail;
1247
  Bit16u ss;
1248
  Bit8u  acode, scode;
1249
 
1250
#if BX_CPU < 2
1251
  buffer_start = 0x001E;
1252
  buffer_end   = 0x003E;
1253
#else
1254
  buffer_start = read_word(0x0040, 0x0080);
1255
  buffer_end   = read_word(0x0040, 0x0082);
1256
#endif
1257
 
1258
  buffer_head = read_word(0x0040, 0x001a);
1259
  buffer_tail = read_word(0x0040, 0x001c);
1260
 
1261
  if (buffer_head != buffer_tail) {
1262
    ss = get_SS();
1263
    acode = read_byte(0x0040, buffer_head);
1264
    scode = read_byte(0x0040, buffer_head+1);
1265
    write_byte(ss, ascii_code, acode);
1266
    write_byte(ss, scan_code, scode);
1267
 
1268
    if (incr) {
1269
      buffer_head += 2;
1270
      if (buffer_head >= buffer_end)
1271
        buffer_head = buffer_start;
1272
      write_word(0x0040, 0x001a, buffer_head);
1273
      }
1274
    return(1);
1275
    }
1276
  else {
1277
    return(0);
1278
    }
1279
}
1280
 
1281
  void
1282
int09_function(DI, SI, BP, SP, BX, DX, CX, AX)
1283
  Bit16u DI, SI, BP, SP, BX, DX, CX, AX;
1284
{
1285
  Bit8u scancode, asciicode, shift_flags;
1286
  Bit8u mf2_flags, mf2_state;
1287
 
1288
  //
1289
  // DS has been set to F000 before call
1290
  //
1291
 
1292
 
1293
  scancode = GET_AL();
1294
 
1295
  if (scancode == 0) {
1296
    BX_INFO("KBD: int09 handler: AL=0\n");
1297
    return;
1298
    }
1299
 
1300
 
1301
  shift_flags = read_byte(0x0040, 0x17);
1302
  mf2_flags = read_byte(0x0040, 0x18);
1303
  mf2_state = read_byte(0x0040, 0x96);
1304
  asciicode = 0;
1305
 
1306
  switch (scancode) {
1307
    case 0x3a: /* Caps Lock press */
1308
      shift_flags ^= 0x40;
1309
      write_byte(0x0040, 0x17, shift_flags);
1310
      mf2_flags |= 0x40;
1311
      write_byte(0x0040, 0x18, mf2_flags);
1312
      break;
1313
    case 0xba: /* Caps Lock release */
1314
      mf2_flags &= ~0x40;
1315
      write_byte(0x0040, 0x18, mf2_flags);
1316
      break;
1317
 
1318
    case 0x2a: /* L Shift press */
1319
      shift_flags |= 0x02;
1320
      write_byte(0x0040, 0x17, shift_flags);
1321
      break;
1322
    case 0xaa: /* L Shift release */
1323
      shift_flags &= ~0x02;
1324
      write_byte(0x0040, 0x17, shift_flags);
1325
      break;
1326
 
1327
    case 0x36: /* R Shift press */
1328
      shift_flags |= 0x01;
1329
      write_byte(0x0040, 0x17, shift_flags);
1330
      break;
1331
    case 0xb6: /* R Shift release */
1332
      shift_flags &= ~0x01;
1333
      write_byte(0x0040, 0x17, shift_flags);
1334
      break;
1335
 
1336
    case 0x1d: /* Ctrl press */
1337
      if ((mf2_state & 0x01) == 0) {
1338
        shift_flags |= 0x04;
1339
        write_byte(0x0040, 0x17, shift_flags);
1340
        if (mf2_state & 0x02) {
1341
          mf2_state |= 0x04;
1342
          write_byte(0x0040, 0x96, mf2_state);
1343
        } else {
1344
          mf2_flags |= 0x01;
1345
          write_byte(0x0040, 0x18, mf2_flags);
1346
        }
1347
      }
1348
      break;
1349
    case 0x9d: /* Ctrl release */
1350
      if ((mf2_state & 0x01) == 0) {
1351
        shift_flags &= ~0x04;
1352
        write_byte(0x0040, 0x17, shift_flags);
1353
        if (mf2_state & 0x02) {
1354
          mf2_state &= ~0x04;
1355
          write_byte(0x0040, 0x96, mf2_state);
1356
        } else {
1357
          mf2_flags &= ~0x01;
1358
          write_byte(0x0040, 0x18, mf2_flags);
1359
        }
1360
      }
1361
      break;
1362
 
1363
    case 0x38: /* Alt press */
1364
      shift_flags |= 0x08;
1365
      write_byte(0x0040, 0x17, shift_flags);
1366
      if (mf2_state & 0x02) {
1367
        mf2_state |= 0x08;
1368
        write_byte(0x0040, 0x96, mf2_state);
1369
      } else {
1370
        mf2_flags |= 0x02;
1371
        write_byte(0x0040, 0x18, mf2_flags);
1372
      }
1373
      break;
1374
    case 0xb8: /* Alt release */
1375
      shift_flags &= ~0x08;
1376
      write_byte(0x0040, 0x17, shift_flags);
1377
      if (mf2_state & 0x02) {
1378
        mf2_state &= ~0x08;
1379
        write_byte(0x0040, 0x96, mf2_state);
1380
      } else {
1381
        mf2_flags &= ~0x02;
1382
        write_byte(0x0040, 0x18, mf2_flags);
1383
      }
1384
      break;
1385
 
1386
    case 0x45: /* Num Lock press */
1387
      if ((mf2_state & 0x03) == 0) {
1388
        mf2_flags |= 0x20;
1389
        write_byte(0x0040, 0x18, mf2_flags);
1390
        shift_flags ^= 0x20;
1391
        write_byte(0x0040, 0x17, shift_flags);
1392
      }
1393
      break;
1394
    case 0xc5: /* Num Lock release */
1395
      if ((mf2_state & 0x03) == 0) {
1396
        mf2_flags &= ~0x20;
1397
        write_byte(0x0040, 0x18, mf2_flags);
1398
      }
1399
      break;
1400
 
1401
    case 0x46: /* Scroll Lock press */
1402
      mf2_flags |= 0x10;
1403
      write_byte(0x0040, 0x18, mf2_flags);
1404
      shift_flags ^= 0x10;
1405
      write_byte(0x0040, 0x17, shift_flags);
1406
      break;
1407
 
1408
    case 0xc6: /* Scroll Lock release */
1409
      mf2_flags &= ~0x10;
1410
      write_byte(0x0040, 0x18, mf2_flags);
1411
      break;
1412
 
1413
    default:
1414
      if (scancode & 0x80) {
1415
        break; /* toss key releases ... */
1416
      }
1417
      if (scancode > MAX_SCAN_CODE) {
1418
        BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode);
1419
        return;
1420
      }
1421
      if (shift_flags & 0x08) { /* ALT */
1422
        asciicode = scan_to_scanascii[scancode].alt;
1423
        scancode = scan_to_scanascii[scancode].alt >> 8;
1424
      } else if (shift_flags & 0x04) { /* CONTROL */
1425
        asciicode = scan_to_scanascii[scancode].control;
1426
        scancode = scan_to_scanascii[scancode].control >> 8;
1427
      } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) {
1428
        /* extended keys handling */
1429
        asciicode = 0xe0;
1430
        scancode = scan_to_scanascii[scancode].normal >> 8;
1431
      } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */
1432
        /* check if lock state should be ignored
1433
         * because a SHIFT key are pressed */
1434
 
1435
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
1436
          asciicode = scan_to_scanascii[scancode].normal;
1437
          scancode = scan_to_scanascii[scancode].normal >> 8;
1438
        } else {
1439
          asciicode = scan_to_scanascii[scancode].shift;
1440
          scancode = scan_to_scanascii[scancode].shift >> 8;
1441
        }
1442
      } else {
1443
        /* check if lock is on */
1444
        if (shift_flags & scan_to_scanascii[scancode].lock_flags) {
1445
          asciicode = scan_to_scanascii[scancode].shift;
1446
          scancode = scan_to_scanascii[scancode].shift >> 8;
1447
        } else {
1448
          asciicode = scan_to_scanascii[scancode].normal;
1449
          scancode = scan_to_scanascii[scancode].normal >> 8;
1450
        }
1451
      }
1452
      if (scancode==0 && asciicode==0) {
1453
        BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
1454
      }
1455
      enqueue_key(scancode, asciicode);
1456
      break;
1457
  }
1458
  if ((scancode & 0x7f) != 0x1d) {
1459
    mf2_state &= ~0x01;
1460
  }
1461
  mf2_state &= ~0x02;
1462
  write_byte(0x0040, 0x96, mf2_state);
1463
}
1464
 
1465
  unsigned int
1466
enqueue_key(scan_code, ascii_code)
1467
  Bit8u scan_code, ascii_code;
1468
{
1469
  Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail;
1470
 
1471
#if BX_CPU < 2
1472
  buffer_start = 0x001E;
1473
  buffer_end   = 0x003E;
1474
#else
1475
  buffer_start = read_word(0x0040, 0x0080);
1476
  buffer_end   = read_word(0x0040, 0x0082);
1477
#endif
1478
 
1479
  buffer_head = read_word(0x0040, 0x001A);
1480
  buffer_tail = read_word(0x0040, 0x001C);
1481
 
1482
  temp_tail = buffer_tail;
1483
  buffer_tail += 2;
1484
  if (buffer_tail >= buffer_end)
1485
    buffer_tail = buffer_start;
1486
 
1487
  if (buffer_tail == buffer_head) {
1488
    return(0);
1489
    }
1490
 
1491
   write_byte(0x0040, temp_tail, ascii_code);
1492
   write_byte(0x0040, temp_tail+1, scan_code);
1493
   write_word(0x0040, 0x001C, buffer_tail);
1494
   return(1);
1495
}
1496
 
1497
 
1498 39 zeus
#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
1499
 
1500
  void
1501
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
1502
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
1503
{
1504
  write_byte(0x0040, 0x008e, 0);  // clear completion flag
1505
 
1506
  switch (GET_AH()) {
1507
    case 0x08:
1508
      SET_AL(0);
1509
      SET_CH(0);
1510
      SET_CL(0);
1511
      SET_DH(0);
1512
      SET_DL(0); /* FIXME returns 0, 1, or n hard drives */
1513
 
1514
      // FIXME should set ES & DI
1515
 
1516
      goto int13_fail;
1517
      break;
1518
 
1519
    default:
1520
      BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
1521
      goto int13_fail;
1522
      break;
1523
    }
1524
 
1525
int13_fail:
1526
    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
1527
int13_fail_noah:
1528
    SET_DISK_RET_STATUS(GET_AH());
1529
int13_fail_nostatus:
1530
    SET_CF();     // error occurred
1531
    return;
1532
 
1533
int13_success:
1534
    SET_AH(0x00); // no error
1535
int13_success_noah:
1536
    SET_DISK_RET_STATUS(0x00);
1537
    CLEAR_CF();   // no error
1538
    return;
1539
}
1540
 
1541
  void
1542 46 zeus
transf_sect(seg, offset)
1543
  Bit16u seg;
1544
  Bit16u offset;
1545
{
1546
ASM_START
1547
  push bp
1548
  mov  bp, sp
1549
 
1550
    push ax
1551
    push bx
1552
    push cx
1553
    push dx
1554
    push di
1555
    push ds
1556
 
1557
    mov  ax, 4[bp] ; segment
1558
    mov  ds, ax
1559
    mov  bx, 6[bp] ; offset
1560
    mov  dx, #0xe000
1561
    mov  cx, #256
1562
    xor  di, di
1563
 
1564
one_sect:
1565
    in   ax, dx    ; read word from flash
1566
    mov  [bx+di], ax ; write word
1567
    inc  dx
1568
    inc  dx
1569
    inc  di
1570
    inc  di
1571
    loop one_sect
1572
 
1573
    pop  ds
1574
    pop  di
1575
    pop  dx
1576
    pop  cx
1577
    pop  bx
1578
    pop  ax
1579
 
1580
  pop  bp
1581
ASM_END
1582
}
1583
 
1584
  void
1585 39 zeus
int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
1586
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
1587
{
1588
  Bit8u  drive, num_sectors, track, sector, head, status;
1589
  Bit16u base_address, base_count, base_es;
1590
  Bit8u  page, mode_register, val8, dor;
1591
  Bit8u  return_status[7];
1592
  Bit8u  drive_type, num_floppies, ah;
1593
  Bit16u es, last_addr;
1594
  Bit16u log_sector, tmp, i, j;
1595
 
1596
  ah = GET_AH();
1597
 
1598
  switch ( ah ) {
1599
    case 0x00: // diskette controller reset
1600
      SET_AH(0);
1601
      set_diskette_ret_status(0);
1602
      CLEAR_CF(); // successful
1603
      set_diskette_current_cyl(drive, 0); // current cylinder
1604
      return;
1605
 
1606
    case 0x02: // Read Diskette Sectors
1607
      num_sectors = GET_AL();
1608
      track       = GET_CH();
1609
      sector      = GET_CL();
1610
      head        = GET_DH();
1611
      drive       = GET_ELDL();
1612
 
1613
      if ((drive > 1) || (head > 1) || (sector == 0) ||
1614
          (num_sectors == 0) || (num_sectors > 72)) {
1615
        BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
1616
        SET_AH(1);
1617
        set_diskette_ret_status(1);
1618
        SET_AL(0); // no sectors read
1619
        SET_CF(); // error occurred
1620
        return;
1621
      }
1622
 
1623
        page = (ES >> 12);   // upper 4 bits
1624
        base_es = (ES << 4); // lower 16bits contributed by ES
1625
        base_address = base_es + BX; // lower 16 bits of address
1626
                                     // contributed by ES:BX
1627
        if ( base_address < base_es ) {
1628
          // in case of carry, adjust page by 1
1629
          page++;
1630
        }
1631
        base_count = (num_sectors * 512) - 1;
1632
 
1633
        // check for 64K boundary overrun
1634
        last_addr = base_address + base_count;
1635
        if (last_addr < base_address) {
1636
          SET_AH(0x09);
1637
          set_diskette_ret_status(0x09);
1638
          SET_AL(0); // no sectors read
1639
          SET_CF(); // error occurred
1640
          return;
1641
        }
1642
 
1643
        log_sector = track * 36 + head * 18 + sector - 1;
1644
        last_addr = page << 12;
1645
 
1646
        // Configure the sector address
1647
        for (j=0; j<num_sectors; j++)
1648
          {
1649
            outw(0xe000, log_sector+j);
1650
            base_count = base_address + (j << 9);
1651 46 zeus
            transf_sect (last_addr, base_count);
1652 39 zeus
          }
1653
 
1654
        // ??? should track be new val from return_status[3] ?
1655
        set_diskette_current_cyl(drive, track);
1656
        // AL = number of sectors read (same value as passed)
1657
        SET_AH(0x00); // success
1658
        CLEAR_CF();   // success
1659
        return;
1660
    default:
1661
        BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
1662
 
1663
      // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
1664
        SET_AH(0x01); // ???
1665
        set_diskette_ret_status(1);
1666
        SET_CF();
1667
        return;
1668
      //   }
1669
    }
1670
}
1671
 
1672
 void
1673
set_diskette_ret_status(value)
1674
  Bit8u value;
1675
{
1676
  write_byte(0x0040, 0x0041, value);
1677
}
1678
 
1679
  void
1680
set_diskette_current_cyl(drive, cyl)
1681
  Bit8u drive;
1682
  Bit8u cyl;
1683
{
1684
/* TEMP HACK: FOR MSDOS */
1685
  if (drive > 1)
1686
    drive = 1;
1687
  /*  BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
1688
  write_byte(0x0040, 0x0094+drive, cyl);
1689
}
1690
 
1691 26 zeus
void
1692
int19_function(seq_nr)
1693
Bit16u seq_nr;
1694
{
1695
  Bit16u ebda_seg=read_word(0x0040,0x000E);
1696
  Bit16u bootdev;
1697
  Bit8u  bootdrv;
1698
  Bit8u  bootchk;
1699
  Bit16u bootseg;
1700
  Bit16u bootip;
1701
  Bit16u status;
1702
  Bit16u bootfirst;
1703
 
1704
  ipl_entry_t e;
1705
 
1706
  // Here we assume that BX_ELTORITO_BOOT is defined, so
1707
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
1708
  //     CMOS reg 0x3D & 0x0f : 1st boot device
1709
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
1710
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
1711
  //   boot device codes:
1712
  //     0x00 : not defined
1713
  //     0x01 : first floppy
1714
  //     0x02 : first harddrive
1715
  //     0x03 : first cdrom
1716
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
1717
  //     else : boot failure
1718
 
1719
  // Get the boot sequence
1720 39 zeus
/*
1721
 * Zet: we don't have a CMOS device
1722
 *
1723 26 zeus
  bootdev = inb_cmos(0x3d);
1724
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
1725
  bootdev >>= 4 * seq_nr;
1726
  bootdev &= 0xf;
1727 39 zeus
*/
1728
  bootdev = 0x1;
1729 26 zeus
 
1730
  /* Read user selected device */
1731
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
1732
  if (bootfirst != 0xFFFF) {
1733
    bootdev = bootfirst;
1734
    /* User selected device not set */
1735
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
1736
    /* Reset boot sequence */
1737
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
1738
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
1739
 
1740
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
1741
  bootdev -= 1;
1742
 
1743
  /* Read the boot device from the IPL table */
1744
  if (get_boot_vector(bootdev, &e) == 0) {
1745
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
1746
    return;
1747
  }
1748
 
1749
  /* Do the loading, and set up vector as a far pointer to the boot
1750
   * address, and bootdrv as the boot drive */
1751
  print_boot_device(&e);
1752
 
1753
  switch(e.type) {
1754 39 zeus
  case IPL_TYPE_FLOPPY: /* FDD */
1755
  case IPL_TYPE_HARDDISK: /* HDD */
1756 26 zeus
 
1757 39 zeus
    bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
1758
    bootseg = 0x07c0;
1759
    status = 0;
1760
 
1761
ASM_START
1762
    push bp
1763
    mov  bp, sp
1764
    push ax
1765
    push bx
1766
    push cx
1767
    push dx
1768
 
1769
    mov  dl, _int19_function.bootdrv + 2[bp]
1770
    mov  ax, _int19_function.bootseg + 2[bp]
1771
    mov  es, ax         ;; segment
1772
    xor  bx, bx         ;; offset
1773
    mov  ah, #0x02      ;; function 2, read diskette sector
1774
    mov  al, #0x01      ;; read 1 sector
1775
    mov  ch, #0x00      ;; track 0
1776
    mov  cl, #0x01      ;; sector 1
1777
    mov  dh, #0x00      ;; head 0
1778
    int  #0x13          ;; read sector
1779
    jnc  int19_load_done
1780
    mov  ax, #0x0001
1781
    mov  _int19_function.status + 2[bp], ax
1782
 
1783
int19_load_done:
1784
    pop  dx
1785
    pop  cx
1786
    pop  bx
1787
    pop  ax
1788
    pop  bp
1789
ASM_END
1790
 
1791
    if (status != 0) {
1792
      print_boot_failure(e.type, 1);
1793
      return;
1794
    }
1795
 
1796
    /* Canonicalize bootseg:bootip */
1797
    bootip = (bootseg & 0x0fff) << 4;
1798
    bootseg &= 0xf000;
1799
  break;
1800
 
1801 26 zeus
  default: return;
1802
  }
1803
 
1804
  /* Debugging info */
1805
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
1806
 
1807
  /* Jump to the boot vector */
1808
ASM_START
1809
    mov  bp, sp
1810
    ;; Build an iret stack frame that will take us to the boot vector.
1811
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
1812
    pushf
1813
    mov  ax, _int19_function.bootseg + 0[bp]
1814
    push ax
1815
    mov  ax, _int19_function.bootip + 0[bp]
1816
    push ax
1817
    ;; Set the magic number in ax and the boot drive in dl.
1818
    mov  ax, #0xaa55
1819
    mov  dl, _int19_function.bootdrv + 0[bp]
1820
    ;; Zero some of the other registers.
1821
    xor  bx, bx
1822
    mov  ds, bx
1823
    mov  es, bx
1824
    mov  bp, bx
1825
    ;; Go!
1826
    iret
1827
ASM_END
1828
}
1829
 
1830 47 zeus
  void
1831
int1a_function(regs, ds, iret_addr)
1832
  pusha_regs_t regs; // regs pushed from PUSHA instruction
1833
  Bit16u ds; // previous DS:, DS set to 0x0000 by asm wrapper
1834
  iret_addr_t  iret_addr; // CS,IP,Flags pushed from original INT call
1835
{
1836
  Bit8u val8;
1837
 
1838
  ASM_START
1839
  sti
1840
  ASM_END
1841
 
1842
  switch (regs.u.r8.ah) {
1843
    case 0: // get current clock count
1844
      ASM_START
1845
      cli
1846
      ASM_END
1847
      regs.u.r16.cx = BiosData->ticks_high;
1848
      regs.u.r16.dx = BiosData->ticks_low;
1849
      regs.u.r8.al  = BiosData->midnight_flag;
1850
      BiosData->midnight_flag = 0; // reset flag
1851
      ASM_START
1852
      sti
1853
      ASM_END
1854
      // AH already 0
1855
      ClearCF(iret_addr.flags); // OK
1856
      break;
1857
 
1858
    default:
1859
      SetCF(iret_addr.flags); // Unsupported
1860
    }
1861
}
1862
 
1863 26 zeus
ASM_START
1864 39 zeus
;----------------------
1865
;- INT13h (relocated) -
1866
;----------------------
1867
;
1868
; int13_relocated is a little bit messed up since I played with it
1869
; I have to rewrite it:
1870
;   - call a function that detect which function to call
1871
;   - make all called C function get the same parameters list
1872
;
1873
int13_relocated:
1874
  push  ax
1875
  push  cx
1876
  push  dx
1877
  push  bx
1878
 
1879
int13_legacy:
1880
 
1881
  push  dx                   ;; push eltorito value of dx instead of sp
1882
 
1883
  push  bp
1884
  push  si
1885
  push  di
1886
 
1887
  push  es
1888
  push  ds
1889
  push  ss
1890
  pop   ds
1891
 
1892
  ;; now the 16-bit registers can be restored with:
1893
  ;; pop ds; pop es; popa; iret
1894
  ;; arguments passed to functions should be
1895
  ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
1896
 
1897
  test  dl, #0x80
1898
  jnz   int13_notfloppy
1899
 
1900
  mov  ax, #int13_out
1901
  push ax
1902
  jmp _int13_diskette_function
1903
 
1904
int13_notfloppy:
1905
 
1906
int13_disk:
1907
  ;; int13_harddisk modifies high word of EAX
1908
;  shr   eax, #16
1909
;  push  ax
1910
  call  _int13_harddisk
1911
;  pop   ax
1912
;  shl   eax, #16
1913
 
1914
int13_out:
1915
  pop ds
1916
  pop es
1917
  ; popa ; we do this instead:
1918
  pop di
1919
  pop si
1920
  pop bp
1921
  add sp, #2
1922
  pop bx
1923
  pop dx
1924
  pop cx
1925
  pop ax
1926
 
1927
  iret
1928
 
1929 26 zeus
;----------
1930
;- INT18h -
1931
;----------
1932
int18_handler: ;; Boot Failure recovery: try the next device.
1933
 
1934
  ;; Reset SP and SS
1935
  mov  ax, #0xfffe
1936
  mov  sp, ax
1937
  xor  ax, ax
1938
  mov  ss, ax
1939
 
1940
  ;; Get the boot sequence number out of the IPL memory
1941
  mov  bx, #IPL_SEG
1942
  mov  ds, bx                     ;; Set segment
1943
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
1944
  inc  bx                         ;; ++
1945
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
1946
  mov  ds, ax                     ;; and reset the segment to zero.
1947
 
1948
  ;; Carry on in the INT 19h handler, using the new sequence number
1949
  push bx
1950
 
1951
  jmp  int19_next_boot
1952
 
1953
;----------
1954
;- INT19h -
1955
;----------
1956
int19_relocated: ;; Boot function, relocated
1957
 
1958
  ;; int19 was beginning to be really complex, so now it
1959
  ;; just calls a C function that does the work
1960
 
1961
  push bp
1962
  mov  bp, sp
1963
 
1964
  ;; Reset SS and SP
1965
  mov  ax, #0xfffe
1966
  mov  sp, ax
1967
  xor  ax, ax
1968
  mov  ss, ax
1969
 
1970
  ;; Start from the first boot device (0, in AX)
1971
  mov  bx, #IPL_SEG
1972
  mov  ds, bx                     ;; Set segment to write to the IPL memory
1973
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
1974
  mov  ds, ax                     ;; and reset the segment.
1975
 
1976
  push ax
1977
 
1978
int19_next_boot:
1979
 
1980
  ;; Call the C code for the next boot device
1981
  call _int19_function
1982
 
1983
  ;; Boot failed: invoke the boot recovery function
1984
  int  #0x18
1985
 
1986 39 zeus
;----------
1987
;- INT1Ch -
1988
;----------
1989
int1c_handler: ;; User Timer Tick
1990
  iret
1991
 
1992
 
1993 26 zeus
;--------------------
1994
;- POST: EBDA segment
1995
;--------------------
1996
; relocated here because the primary POST area isnt big enough.
1997
ebda_post:
1998
  xor ax, ax            ; mov EBDA seg into 40E
1999
  mov ds, ax
2000
  mov word ptr [0x40E], #EBDA_SEG
2001
  ret;;
2002
 
2003
rom_checksum:
2004
  push ax
2005
  push bx
2006
  push cx
2007
  xor  ax, ax
2008
  xor  bx, bx
2009
  xor  cx, cx
2010
  mov  ch, [2]
2011
  shl  cx, #1
2012
checksum_loop:
2013
  add  al, [bx]
2014
  inc  bx
2015
  loop checksum_loop
2016
  and  al, #0xff
2017
  pop  cx
2018
  pop  bx
2019
  pop  ax
2020
  ret
2021
 
2022
 
2023
;; We need a copy of this string, but we are not actually a PnP BIOS,
2024
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
2025
.align 16
2026
  db 0
2027
pnp_string:
2028
  .ascii "$PnP"
2029
 
2030
 
2031
rom_scan:
2032
  ;; Scan for existence of valid expansion ROMS.
2033
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
2034
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
2035
  ;;   System  ROM: only 0xE0000
2036
  ;;
2037
  ;; Header:
2038
  ;;   Offset    Value
2039
  ;;   0         0x55
2040
  ;;   1         0xAA
2041
  ;;   2         ROM length in 512-byte blocks
2042
  ;;   3         ROM initialization entry point (FAR CALL)
2043
 
2044
rom_scan_loop:
2045
  push ax       ;; Save AX
2046
  mov  ds, cx
2047
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
2048
  cmp [0], #0xAA55 ;; look for signature
2049
  jne  rom_scan_increment
2050
  call rom_checksum
2051
  jnz  rom_scan_increment
2052
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
2053
 
2054
  ;; We want our increment in 512-byte quantities, rounded to
2055
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
2056
  test al, #0x03
2057
  jz   block_count_rounded
2058
  and  al, #0xfc ;; needs rounding up
2059
  add  al, #0x04
2060
block_count_rounded:
2061
 
2062
  xor  bx, bx   ;; Restore DS back to 0000:
2063
  mov  ds, bx
2064
  push ax       ;; Save AX
2065
  push di       ;; Save DI
2066
  ;; Push addr of ROM entry point
2067
  push cx       ;; Push seg
2068 34 zeus
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
2069
  mov ax, #0x0003
2070
  push ax
2071 26 zeus
 
2072
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
2073
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
2074
  mov  ax, #0xf000
2075
  mov  es, ax
2076
  lea  di, pnp_string
2077
 
2078
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
2079
  db   0xff     ;; call_far ss:[bp+0]
2080
  db   0x5e
2081
  db   0
2082
  cli           ;; In case expansion ROM BIOS turns IF on
2083
  add  sp, #2   ;; Pop offset value
2084
  pop  cx       ;; Pop seg value (restore CX)
2085
 
2086
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
2087
  ;; to init all the ROMs and then go back and build an IPL table of
2088
  ;; all the bootable devices, but we can get away with one pass.
2089
  mov  ds, cx       ;; ROM base
2090
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
2091
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
2092
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
2093
  jne  no_bev
2094
  mov  ax, 2[bx]
2095
  cmp  ax, #0x506e
2096
  jne  no_bev
2097
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
2098
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
2099
  je   no_bev
2100
 
2101
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
2102
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
2103
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
2104
  mov  ds, bx
2105
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
2106
  cmp  bx, #IPL_TABLE_ENTRIES
2107
  je   no_bev                  ;; Get out if the table is full
2108
  push cx
2109
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
2110
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
2111
  pop  cx
2112
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
2113
  mov  6[bx], cx               ;; Build a far pointer from the segment...
2114
  mov  4[bx], ax               ;; and the offset
2115
  cmp  di, #0x0000
2116
  je   no_prod_str
2117
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
2118
  mov  8[bx], di               ;; and the offset
2119
no_prod_str:
2120
  push cx
2121
  mov  cx, #0x4
2122
  shr  bx, cl                  ;; Turn the offset back into a count
2123
  pop  cx
2124
  inc  bx                      ;; We have one more entry now
2125
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
2126
 
2127
no_bev:
2128
  pop  di       ;; Restore DI
2129
  pop  ax       ;; Restore AX
2130
rom_scan_increment:
2131
  push cx
2132
  mov  cx, #5
2133
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
2134
                ;; because the segment selector is shifted left 4 bits.
2135
  pop  cx
2136
  add  cx, ax
2137
  pop  ax       ;; Restore AX
2138
  cmp  cx, ax
2139
  jbe  rom_scan_loop
2140
 
2141
  xor  ax, ax   ;; Restore DS back to 0000:
2142
  mov  ds, ax
2143
  ret
2144
 
2145
;; for 'C' strings and other data, insert them here with
2146
;; a the following hack:
2147
;; DATA_SEG_DEFS_HERE
2148
 
2149
 
2150
;; the following area can be used to write dynamically generated tables
2151
  .align 16
2152
bios_table_area_start:
2153
  dd 0xaafb4442
2154
  dd bios_table_area_end - bios_table_area_start - 8;
2155
 
2156
;--------
2157
;- POST -
2158
;--------
2159
.org 0xe05b ; POST Entry Point
2160
post:
2161
  xor ax, ax
2162
 
2163
normal_post:
2164
  ; case 0: normal startup
2165
 
2166
  cli
2167
  mov  ax, #0xfffe
2168
  mov  sp, ax
2169
  xor  ax, ax
2170
  mov  ds, ax
2171
  mov  ss, ax
2172
 
2173
  ;; zero out BIOS data area (40:00..40:ff)
2174
  mov  es, ax
2175
  mov  cx, #0x0080 ;; 128 words
2176
  mov  di, #0x0400
2177
  cld
2178
  rep
2179
    stosw
2180
 
2181
  ;; set all interrupts to default handler
2182
  xor  bx, bx         ;; offset index
2183
  mov  cx, #0x0100    ;; counter (256 interrupts)
2184
  mov  ax, #dummy_iret_handler
2185
  mov  dx, #0xF000
2186
 
2187
post_default_ints:
2188
  mov  [bx], ax
2189
  add  bx, #2
2190
  mov  [bx], dx
2191
  add  bx, #2
2192
  loop post_default_ints
2193
 
2194
  ;; set vector 0x79 to zero
2195
  ;; this is used by 'gardian angel' protection system
2196
  SET_INT_VECTOR(0x79, #0, #0)
2197
 
2198
  ;; base memory in K 40:13 (word)
2199
  mov  ax, #BASE_MEM_IN_K
2200
  mov  0x0413, ax
2201
 
2202
 
2203
  ;; Manufacturing Test 40:12
2204
  ;;   zerod out above
2205
 
2206
  ;; Warm Boot Flag 0040:0072
2207
  ;;   value of 1234h = skip memory checks
2208
  ;;   zerod out above
2209
 
2210
  ;; Bootstrap failure vector
2211
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
2212
 
2213
  ;; Bootstrap Loader vector
2214
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
2215
 
2216 39 zeus
  ;; User Timer Tick vector
2217
  SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
2218
 
2219
  ;; Memory Size Check vector
2220
  SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
2221
 
2222
  ;; Equipment Configuration Check vector
2223
  SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
2224
 
2225 26 zeus
  ;; EBDA setup
2226
  call ebda_post
2227
 
2228 39 zeus
  ;; Keyboard
2229 43 zeus
  SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
2230 47 zeus
  SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
2231 39 zeus
 
2232 43 zeus
  xor  ax, ax
2233
  mov  ds, ax
2234
  mov  0x0417, al /* keyboard shift flags, set 1 */
2235
  mov  0x0418, al /* keyboard shift flags, set 2 */
2236
  mov  0x0419, al /* keyboard alt-numpad work area */
2237
  mov  0x0471, al /* keyboard ctrl-break flag */
2238
  mov  0x0497, al /* keyboard status flags 4 */
2239
  mov  al, #0x10
2240
  mov  0x0496, al /* keyboard status flags 3 */
2241
 
2242
  /* keyboard head of buffer pointer */
2243
  mov  bx, #0x001E
2244
  mov  0x041A, bx
2245
 
2246
  /* keyboard end of buffer pointer */
2247
  mov  0x041C, bx
2248
 
2249
  /* keyboard pointer to start of buffer */
2250
  mov  bx, #0x001E
2251
  mov  0x0480, bx
2252
 
2253
  /* keyboard pointer to end of buffer */
2254
  mov  bx, #0x003E
2255
  mov  0x0482, bx
2256
 
2257 47 zeus
  ;; CMOS RTC
2258
  SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
2259
 
2260 26 zeus
  ;; Video setup
2261
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
2262
 
2263
  mov  cx, #0xc000  ;; init vga bios
2264
  mov  ax, #0xc780
2265 37 zeus
 
2266 26 zeus
  call rom_scan
2267
 
2268
  call _print_bios_banner
2269 37 zeus
 
2270 39 zeus
  ;; Floppy setup
2271
  SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
2272
 
2273 26 zeus
  call _init_boot_vectors
2274
 
2275
  mov  cx, #0xc800  ;; init option roms
2276
  mov  ax, #0xe000
2277
  call rom_scan
2278
 
2279
  sti        ;; enable interrupts
2280
  int  #0x19
2281
 
2282 39 zeus
;-------------------------------------------
2283
;- INT 13h Fixed Disk Services Entry Point -
2284
;-------------------------------------------
2285
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
2286
int13_handler:
2287
  //JMPL(int13_relocated)
2288
  jmp int13_relocated
2289
 
2290
.org 0xe401 ; Fixed Disk Parameter Table
2291
 
2292 26 zeus
;----------
2293
;- INT19h -
2294
;----------
2295
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
2296
int19_handler:
2297
 
2298
  jmp int19_relocated
2299
 
2300 43 zeus
 
2301 39 zeus
;----------------------------------------
2302
;- INT 16h Keyboard Service Entry Point -
2303
;----------------------------------------
2304
.org 0xe82e
2305
int16_handler:
2306 43 zeus
 
2307
  sti
2308
  push  ds
2309
  pushf
2310
  ;pusha ; we do this instead:
2311
  push ax
2312
  push cx
2313
  push dx
2314
  push bx
2315
  push sp
2316
  mov  bx, sp
2317 45 zeus
  sseg
2318
    add  [bx], #10
2319
  sseg
2320
    mov  bx, [bx+2]
2321 43 zeus
  push bp
2322
  push si
2323
  push di
2324
 
2325
  cmp   ah, #0x00
2326
  je    int16_F00
2327
  cmp   ah, #0x10
2328
  je    int16_F00
2329
 
2330
  mov  bx, #0xf000
2331
  mov  ds, bx
2332
  call _int16_function
2333
  ; popa ; we do this instead:
2334
  pop di
2335
  pop si
2336
  pop bp
2337
  add sp, #2
2338
  pop bx
2339
  pop dx
2340
  pop cx
2341
  pop ax
2342
  popf
2343
  pop  ds
2344
  jz   int16_zero_set
2345
 
2346
int16_zero_clear:
2347
  push bp
2348
  mov  bp, sp
2349
  //SEG SS
2350
  and  BYTE [bp + 0x06], #0xbf
2351
  pop  bp
2352 39 zeus
  iret
2353 43 zeus
 
2354
int16_zero_set:
2355 39 zeus
  push bp
2356
  mov  bp, sp
2357
  //SEG SS
2358
  or   BYTE [bp + 0x06], #0x40
2359
  pop  bp
2360
  iret
2361
 
2362 43 zeus
int16_F00:
2363
  mov  bx, #0x0040
2364
  mov  ds, bx
2365
 
2366
int16_wait_for_key:
2367
  cli
2368
  mov  bx, 0x001a
2369
  cmp  bx, 0x001c
2370
  jne  int16_key_found
2371
  sti
2372
  nop
2373
#if 0
2374
                           /* no key yet, call int 15h, function AX=9002 */
2375
  0x50,                    /* push AX */
2376
  0xb8, 0x02, 0x90,        /* mov AX, #0x9002 */
2377
  0xcd, 0x15,              /* int 15h */
2378
  0x58,                    /* pop  AX */
2379
  0xeb, 0xea,              /* jmp   WAIT_FOR_KEY */
2380
#endif
2381
  jmp  int16_wait_for_key
2382
 
2383
int16_key_found:
2384
  mov  bx, #0xf000
2385
  mov  ds, bx
2386
  call _int16_function
2387
  ; popa ; we do this instead:
2388
  pop di
2389
  pop si
2390
  pop bp
2391
  add sp, #2
2392
  pop bx
2393
  pop dx
2394
  pop cx
2395
  pop ax
2396
  popf
2397
  pop  ds
2398
#if 0
2399
                           /* notify int16 complete w/ int 15h, function AX=9102 */
2400
  0x50,                    /* push AX */
2401
  0xb8, 0x02, 0x91,        /* mov AX, #0x9102 */
2402
  0xcd, 0x15,              /* int 15h */
2403
  0x58,                    /* pop  AX */
2404
#endif
2405 26 zeus
  iret
2406
 
2407 43 zeus
 
2408
 
2409
;-------------------------------------------------
2410
;- INT09h : Keyboard Hardware Service Entry Point -
2411
;-------------------------------------------------
2412
.org 0xe987
2413
int09_handler:
2414
  cli
2415
  push ax
2416
  in  al, #0x60             ;;read key from keyboard controller
2417
  sti
2418 45 zeus
 
2419 43 zeus
  push  ds
2420
  ;pusha ; we do this instead:
2421
 
2422
  push ax
2423
  push cx
2424
  push dx
2425
  push bx
2426
  push sp
2427
  mov  bx, sp
2428 45 zeus
  sseg
2429
    add  [bx], #10
2430
  sseg
2431
    mov  bx, [bx+2]
2432 43 zeus
  push bp
2433
  push si
2434
  push di
2435
 
2436
  ;; check for extended key
2437
  cmp  al, #0xe0
2438
  jne int09_check_pause
2439
  xor  ax, ax
2440
  mov  ds, ax
2441
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x02
2442
  or   al, #0x02
2443
  mov  BYTE [0x496], al
2444
  jmp int09_done
2445
 
2446
int09_check_pause: ;; check for pause key
2447
  cmp  al, #0xe1
2448
  jne int09_process_key
2449
  xor  ax, ax
2450
  mov  ds, ax
2451
  mov  al, BYTE [0x496]     ;; mf2_state |= 0x01
2452
  or   al, #0x01
2453
  mov  BYTE [0x496], al
2454
  jmp int09_done
2455
 
2456
int09_process_key:
2457
  mov   bx, #0xf000
2458
  mov   ds, bx
2459
  call  _int09_function
2460
int09_done:
2461
  ; popa ; we do this instead:
2462
  pop di
2463
  pop si
2464
  pop bp
2465
  add sp, #2
2466
  pop bx
2467
  pop dx
2468
  pop cx
2469
  pop ax
2470
 
2471
  pop   ds
2472 45 zeus
 
2473 43 zeus
  cli
2474
  pop ax
2475
  iret
2476
 
2477
 
2478 26 zeus
;----------
2479
;- INT10h -
2480
;----------
2481
.org 0xf065 ; INT 10h Video Support Service Entry Point
2482
int10_handler:
2483
  ;; dont do anything, since the VGA BIOS handles int10h requests
2484
  iret
2485
 
2486
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
2487
 
2488 39 zeus
;----------
2489
;- INT12h -
2490
;----------
2491
.org 0xf841 ; INT 12h Memory Size Service Entry Point
2492
; ??? different for Pentium (machine check)?
2493
int12_handler:
2494
  push ds
2495
  mov  ax, #0x0040
2496
  mov  ds, ax
2497
  mov  ax, 0x0013
2498
  pop  ds
2499
  iret
2500
 
2501
;----------
2502
;- INT11h -
2503
;----------
2504
.org 0xf84d ; INT 11h Equipment List Service Entry Point
2505
int11_handler:
2506
  push ds
2507
  mov  ax, #0x0040
2508
  mov  ds, ax
2509
  mov  ax, 0x0010
2510
  pop  ds
2511
  iret
2512
 
2513 47 zeus
;----------
2514
;- INT1Ah -
2515
;----------
2516
.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
2517
int1a_handler:
2518
  push ds
2519
  ;pusha ; we do this instead:
2520
  push ax
2521
  push cx
2522
  push dx
2523
  push bx
2524
  push sp
2525
  mov  bx, sp
2526
  sseg
2527
    add  [bx], #10
2528
  sseg
2529
    mov  bx, [bx+2]
2530
  push bp
2531
  push si
2532
  push di
2533
 
2534
  xor  ax, ax
2535
  mov  ds, ax
2536
int1a_callfunction:
2537
  call _int1a_function
2538
  ; popa ; we do this instead:
2539
  pop di
2540
  pop si
2541
  pop bp
2542
  add sp, #2
2543
  pop bx
2544
  pop dx
2545
  pop cx
2546
  pop ax
2547
 
2548
  pop  ds
2549
  iret
2550
 
2551 26 zeus
;------------------------------------------------
2552
;- IRET Instruction for Dummy Interrupt Handler -
2553
;------------------------------------------------
2554
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
2555
dummy_iret_handler:
2556
  iret
2557
 
2558
.org 0xfff0 ; Power-up Entry Point
2559 39 zeus
;  hlt
2560 26 zeus
  jmp 0xf000:post
2561
 
2562
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
2563
.ascii BIOS_BUILD_DATE
2564
 
2565
.org 0xfffe ; System Model ID
2566
db SYS_MODEL_ID
2567
db 0x00   ; filler
2568
ASM_END
2569
 
2570
ASM_START
2571
.org 0xcc00
2572
bios_table_area_end:
2573
// bcc-generated data will be placed here
2574
ASM_END

powered by: WebSVN 2.1.0

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