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

Subversion Repositories zet86

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

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

powered by: WebSVN 2.1.0

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