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

Subversion Repositories zet86

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

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

powered by: WebSVN 2.1.0

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