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

Subversion Repositories zet86

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

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 39 zeus
static void           int13_harddisk();
442
static void           int13_diskette_function();
443 26 zeus
static void           int19_function();
444
static Bit16u         get_CS();
445
static Bit16u         get_SS();
446 39 zeus
static void           set_diskette_ret_status();
447
static void           set_diskette_current_cyl();
448 26 zeus
 
449
static void           print_bios_banner();
450
static void           print_boot_device();
451 39 zeus
static void           print_boot_failure();
452 26 zeus
 
453 39 zeus
#define SET_AL(val8) AX = ((AX & 0xff00) | (val8))
454
#define SET_BL(val8) BX = ((BX & 0xff00) | (val8))
455
#define SET_CL(val8) CX = ((CX & 0xff00) | (val8))
456
#define SET_DL(val8) DX = ((DX & 0xff00) | (val8))
457
#define SET_AH(val8) AX = ((AX & 0x00ff) | ((val8) << 8))
458
#define SET_BH(val8) BX = ((BX & 0x00ff) | ((val8) << 8))
459
#define SET_CH(val8) CX = ((CX & 0x00ff) | ((val8) << 8))
460
#define SET_DH(val8) DX = ((DX & 0x00ff) | ((val8) << 8))
461
 
462
#define GET_AL() ( AX & 0x00ff )
463
#define GET_BL() ( BX & 0x00ff )
464
#define GET_CL() ( CX & 0x00ff )
465
#define GET_DL() ( DX & 0x00ff )
466
#define GET_AH() ( AX >> 8 )
467
#define GET_BH() ( BX >> 8 )
468
#define GET_CH() ( CX >> 8 )
469
#define GET_DH() ( DX >> 8 )
470
 
471
#define GET_ELDL() ( ELDX & 0x00ff )
472
#define GET_ELDH() ( ELDX >> 8 )
473
 
474
#define SET_CF()     FLAGS |= 0x0001
475
#define CLEAR_CF()   FLAGS &= 0xfffe
476
#define GET_CF()     (FLAGS & 0x0001)
477
 
478
#define SET_ZF()     FLAGS |= 0x0040
479
#define CLEAR_ZF()   FLAGS &= 0xffbf
480
#define GET_ZF()     (FLAGS & 0x0040)
481
 
482
  Bit16u
483
inw(port)
484
  Bit16u port;
485 26 zeus
{
486
ASM_START
487
  push bp
488
  mov  bp, sp
489
 
490 39 zeus
    push dx
491
    mov  dx, 4[bp]
492
    in   ax, dx
493
    pop  dx
494 26 zeus
 
495
  pop  bp
496
ASM_END
497
}
498
 
499 39 zeus
  void
500
outw(port, val)
501
  Bit16u port;
502
  Bit16u  val;
503
{
504
ASM_START
505
  push bp
506
  mov  bp, sp
507
 
508
    push ax
509
    push dx
510
    mov  dx, 4[bp]
511
    mov  ax, 6[bp]
512
    out  dx, ax
513
    pop  dx
514
    pop  ax
515
 
516
  pop  bp
517
ASM_END
518
}
519
 
520 26 zeus
  Bit8u
521
read_byte(seg, offset)
522
  Bit16u seg;
523
  Bit16u offset;
524
{
525
ASM_START
526
  push bp
527
  mov  bp, sp
528
 
529
    push bx
530
    push ds
531
    mov  ax, 4[bp] ; segment
532
    mov  ds, ax
533
    mov  bx, 6[bp] ; offset
534
    mov  al, [bx]
535
    ;; al = return value (byte)
536
    pop  ds
537
    pop  bx
538
 
539
  pop  bp
540
ASM_END
541
}
542
 
543
  Bit16u
544
read_word(seg, offset)
545
  Bit16u seg;
546
  Bit16u offset;
547
{
548
ASM_START
549
  push bp
550
  mov  bp, sp
551
 
552
    push bx
553
    push ds
554
    mov  ax, 4[bp] ; segment
555
    mov  ds, ax
556
    mov  bx, 6[bp] ; offset
557
    mov  ax, [bx]
558
    ;; ax = return value (word)
559
    pop  ds
560
    pop  bx
561
 
562
  pop  bp
563
ASM_END
564
}
565
 
566
  void
567
write_byte(seg, offset, data)
568
  Bit16u seg;
569
  Bit16u offset;
570
  Bit8u data;
571
{
572
ASM_START
573
  push bp
574
  mov  bp, sp
575
 
576
    push ax
577
    push bx
578
    push ds
579
    mov  ax, 4[bp] ; segment
580
    mov  ds, ax
581
    mov  bx, 6[bp] ; offset
582
    mov  al, 8[bp] ; data byte
583
    mov  [bx], al  ; write data byte
584
    pop  ds
585
    pop  bx
586
    pop  ax
587
 
588
  pop  bp
589
ASM_END
590
}
591
 
592
  void
593
write_word(seg, offset, data)
594
  Bit16u seg;
595
  Bit16u offset;
596
  Bit16u data;
597
{
598
ASM_START
599
  push bp
600
  mov  bp, sp
601
 
602
    push ax
603
    push bx
604
    push ds
605
    mov  ax, 4[bp] ; segment
606
    mov  ds, ax
607
    mov  bx, 6[bp] ; offset
608
    mov  ax, 8[bp] ; data word
609
    mov  [bx], ax  ; write data word
610
    pop  ds
611
    pop  bx
612
    pop  ax
613
 
614
  pop  bp
615
ASM_END
616
}
617
 
618
  Bit16u
619
get_CS()
620
{
621
ASM_START
622
  mov  ax, cs
623
ASM_END
624
}
625
 
626
  Bit16u
627
get_SS()
628
{
629
ASM_START
630
  mov  ax, ss
631
ASM_END
632
}
633
 
634
  void
635
wrch(c)
636
  Bit8u  c;
637
{
638
  ASM_START
639
  push bp
640
  mov  bp, sp
641
 
642
  push bx
643
  mov  ah, #0x0e
644
  mov  al, 4[bp]
645
  xor  bx,bx
646
  int  #0x10
647
  pop  bx
648
 
649
  pop  bp
650
  ASM_END
651
}
652
 
653
  void
654
send(action, c)
655
  Bit16u action;
656
  Bit8u  c;
657
{
658
  if (action & BIOS_PRINTF_SCREEN) {
659
    if (c == '\n') wrch('\r');
660
    wrch(c);
661
  }
662
}
663
 
664
  void
665
put_int(action, val, width, neg)
666
  Bit16u action;
667
  short val, width;
668
  bx_bool neg;
669
{
670
  short nval = val / 10;
671
  if (nval)
672
    put_int(action, nval, width - 1, neg);
673
  else {
674
    while (--width > 0) send(action, ' ');
675
    if (neg) send(action, '-');
676
  }
677
  send(action, val - (nval * 10) + '0');
678
}
679
 
680
  void
681
put_uint(action, val, width, neg)
682
  Bit16u action;
683
  unsigned short val;
684
  short width;
685
  bx_bool neg;
686
{
687
  unsigned short nval = val / 10;
688
  if (nval)
689
    put_uint(action, nval, width - 1, neg);
690
  else {
691
    while (--width > 0) send(action, ' ');
692
    if (neg) send(action, '-');
693
  }
694
  send(action, val - (nval * 10) + '0');
695
}
696
 
697
  void
698
put_luint(action, val, width, neg)
699
  Bit16u action;
700
  unsigned long val;
701
  short width;
702
  bx_bool neg;
703
{
704
  unsigned long nval = val / 10;
705
  if (nval)
706
    put_luint(action, nval, width - 1, neg);
707
  else {
708
    while (--width > 0) send(action, ' ');
709
    if (neg) send(action, '-');
710
  }
711
  send(action, val - (nval * 10) + '0');
712
}
713
 
714
void put_str(action, segment, offset)
715
  Bit16u action;
716
  Bit16u segment;
717
  Bit16u offset;
718
{
719
  Bit8u c;
720
 
721
  while (c = read_byte(segment, offset)) {
722
    send(action, c);
723
    offset++;
724
  }
725
}
726
 
727
//--------------------------------------------------------------------------
728
// bios_printf()
729
//   A compact variable argument printf function.
730
//
731
//   Supports %[format_width][length]format
732
//   where format can be x,X,u,d,s,S,c
733
//   and the optional length modifier is l (ell)
734
//--------------------------------------------------------------------------
735
  void
736
bios_printf(action, s)
737
  Bit16u action;
738
  Bit8u *s;
739
{
740
  Bit8u c, format_char;
741
  bx_bool  in_format;
742
  short i;
743
  Bit16u  *arg_ptr;
744
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
745
 
746
  arg_ptr = &s;
747
  arg_seg = get_SS();
748
 
749
  in_format = 0;
750
  format_width = 0;
751
 
752
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
753
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
754
 
755
  while (c = read_byte(get_CS(), s)) {
756
    if ( c == '%' ) {
757
      in_format = 1;
758
      format_width = 0;
759
      }
760
    else if (in_format) {
761
      if ( (c>='0') && (c<='9') ) {
762
        format_width = (format_width * 10) + (c - '0');
763
        }
764
      else {
765
        arg_ptr++; // increment to next arg
766
        arg = read_word(arg_seg, arg_ptr);
767
        if (c == 'x' || c == 'X') {
768
          if (format_width == 0)
769
            format_width = 4;
770
          if (c == 'x')
771
            hexadd = 'a';
772
          else
773
            hexadd = 'A';
774
          for (i=format_width-1; i>=0; i--) {
775
            nibble = (arg >> (4 * i)) & 0x000f;
776
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
777
            }
778
          }
779
        else if (c == 'u') {
780
          put_uint(action, arg, format_width, 0);
781
          }
782
        else if (c == 'l') {
783
          s++;
784
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
785
          arg_ptr++; /* increment to next arg */
786
          hibyte = read_word(arg_seg, arg_ptr);
787
          if (c == 'd') {
788
            if (hibyte & 0x8000)
789
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
790
            else
791
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
792
           }
793
          else if (c == 'u') {
794
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
795
           }
796
          else if (c == 'x' || c == 'X')
797
           {
798
            if (format_width == 0)
799
              format_width = 8;
800
            if (c == 'x')
801
              hexadd = 'a';
802
            else
803
              hexadd = 'A';
804
            for (i=format_width-1; i>=0; i--) {
805
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
806
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
807
              }
808
           }
809
          }
810
        else if (c == 'd') {
811
          if (arg & 0x8000)
812
            put_int(action, -arg, format_width - 1, 1);
813
          else
814
            put_int(action, arg, format_width, 0);
815
          }
816
        else if (c == 's') {
817
          put_str(action, get_CS(), arg);
818
          }
819
        else if (c == 'S') {
820
          hibyte = arg;
821
          arg_ptr++;
822
          arg = read_word(arg_seg, arg_ptr);
823
          put_str(action, hibyte, arg);
824
          }
825
        else if (c == 'c') {
826
          send(action, arg);
827
          }
828
        else
829
          BX_PANIC("bios_printf: unknown format\n");
830
          in_format = 0;
831
        }
832
      }
833
    else {
834
      send(action, c);
835
      }
836
    s ++;
837
    }
838
 
839
  if (action & BIOS_PRINTF_HALT) {
840
    // freeze in a busy loop.
841
ASM_START
842
    cli
843
 halt2_loop:
844
    hlt
845
    jmp halt2_loop
846
ASM_END
847
    }
848
}
849
 
850 39 zeus
static char bios_svn_version_string[] = "$Revision: 1.5 $ $Date: 2008-11-14 03:31:19 $";
851 26 zeus
 
852
//--------------------------------------------------------------------------
853
// print_bios_banner
854
//   displays a the bios version
855
//--------------------------------------------------------------------------
856
void
857
print_bios_banner()
858
{
859 37 zeus
  printf("Zet ROMBIOS - build: %s\n%s\n\n",
860 26 zeus
    BIOS_BUILD_DATE, bios_svn_version_string);
861
}
862
 
863
//--------------------------------------------------------------------------
864
// BIOS Boot Specification 1.0.1 compatibility
865
//
866
// Very basic support for the BIOS Boot Specification, which allows expansion
867
// ROMs to register themselves as boot devices, instead of just stealing the
868
// INT 19h boot vector.
869
//
870
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
871
// one; we just lie to the option ROMs to make them behave correctly.
872
// We also don't support letting option ROMs register as bootable disk
873
// drives (BCVs), only as bootable devices (BEVs).
874
//
875
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
876
//--------------------------------------------------------------------------
877
 
878 39 zeus
static char drivetypes[][20]={"", "Floppy flash image" };
879 26 zeus
 
880
static void
881
init_boot_vectors()
882
{
883
  ipl_entry_t e;
884
  Bit16u count = 0;
885
  Bit16u ss = get_SS();
886
 
887
  /* Clear out the IPL table. */
888
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
889
 
890
  /* User selected device not set */
891
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
892
 
893 39 zeus
  /* Floppy drive */
894
  e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
895
  memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
896
  count++;
897 26 zeus
 
898
  /* Remember how many devices we have */
899
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
900
  /* Not tried booting anything yet */
901
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
902
}
903
 
904
static Bit8u
905
get_boot_vector(i, e)
906
Bit16u i; ipl_entry_t *e;
907
{
908
  Bit16u count;
909
  Bit16u ss = get_SS();
910
  /* Get the count of boot devices, and refuse to overrun the array */
911
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
912
  if (i >= count) return 0;
913
  /* OK to read this device */
914
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
915
  return 1;
916
}
917
 
918
//--------------------------------------------------------------------------
919
// print_boot_device
920
//   displays the boot device
921
//--------------------------------------------------------------------------
922
 
923
void
924
print_boot_device(e)
925
  ipl_entry_t *e;
926
{
927
  Bit16u type;
928
  char description[33];
929
  Bit16u ss = get_SS();
930
  type = e->type;
931
  /* NIC appears as type 0x80 */
932
  if (type == IPL_TYPE_BEV) type = 0x4;
933
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
934
  printf("Booting from %s", drivetypes[type]);
935
  /* print product string if BEV */
936
  if (type == 4 && e->description != 0) {
937
    /* first 32 bytes are significant */
938
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
939
    /* terminate string */
940
    description[32] = 0;
941
    printf(" [%S]", ss, description);
942
  }
943 39 zeus
  printf("...\n\n");
944 26 zeus
}
945
 
946 39 zeus
//--------------------------------------------------------------------------
947
// print_boot_failure
948
//   displays the reason why boot failed
949
//--------------------------------------------------------------------------
950
  void
951
print_boot_failure(type, reason)
952
  Bit16u type; Bit8u reason;
953
{
954
  if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n");
955
 
956
  printf("Boot failed");
957
  if (type < 4) {
958
    /* Report the reason too */
959
    if (reason==0)
960
      printf(": not a bootable disk");
961
    else
962
      printf(": could not read the boot disk");
963
  }
964
  printf("\n\n");
965
}
966
 
967
 
968
#define SET_DISK_RET_STATUS(status) write_byte(0x0040, 0x0074, status)
969
 
970
  void
971
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
972
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
973
{
974
  write_byte(0x0040, 0x008e, 0);  // clear completion flag
975
 
976
  switch (GET_AH()) {
977
    case 0x08:
978
      SET_AL(0);
979
      SET_CH(0);
980
      SET_CL(0);
981
      SET_DH(0);
982
      SET_DL(0); /* FIXME returns 0, 1, or n hard drives */
983
 
984
      // FIXME should set ES & DI
985
 
986
      goto int13_fail;
987
      break;
988
 
989
    default:
990
      BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
991
      goto int13_fail;
992
      break;
993
    }
994
 
995
int13_fail:
996
    SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
997
int13_fail_noah:
998
    SET_DISK_RET_STATUS(GET_AH());
999
int13_fail_nostatus:
1000
    SET_CF();     // error occurred
1001
    return;
1002
 
1003
int13_success:
1004
    SET_AH(0x00); // no error
1005
int13_success_noah:
1006
    SET_DISK_RET_STATUS(0x00);
1007
    CLEAR_CF();   // no error
1008
    return;
1009
}
1010
 
1011
  void
1012
int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
1013
  Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
1014
{
1015
  Bit8u  drive, num_sectors, track, sector, head, status;
1016
  Bit16u base_address, base_count, base_es;
1017
  Bit8u  page, mode_register, val8, dor;
1018
  Bit8u  return_status[7];
1019
  Bit8u  drive_type, num_floppies, ah;
1020
  Bit16u es, last_addr;
1021
  Bit16u log_sector, tmp, i, j;
1022
 
1023
  ah = GET_AH();
1024
 
1025
  switch ( ah ) {
1026
    case 0x00: // diskette controller reset
1027
      SET_AH(0);
1028
      set_diskette_ret_status(0);
1029
      CLEAR_CF(); // successful
1030
      set_diskette_current_cyl(drive, 0); // current cylinder
1031
      return;
1032
 
1033
    case 0x02: // Read Diskette Sectors
1034
      num_sectors = GET_AL();
1035
      track       = GET_CH();
1036
      sector      = GET_CL();
1037
      head        = GET_DH();
1038
      drive       = GET_ELDL();
1039
 
1040
      if ((drive > 1) || (head > 1) || (sector == 0) ||
1041
          (num_sectors == 0) || (num_sectors > 72)) {
1042
        BX_INFO("int13_diskette: read/write/verify: parameter out of range\n");
1043
        SET_AH(1);
1044
        set_diskette_ret_status(1);
1045
        SET_AL(0); // no sectors read
1046
        SET_CF(); // error occurred
1047
        return;
1048
      }
1049
 
1050
        page = (ES >> 12);   // upper 4 bits
1051
        base_es = (ES << 4); // lower 16bits contributed by ES
1052
        base_address = base_es + BX; // lower 16 bits of address
1053
                                     // contributed by ES:BX
1054
        if ( base_address < base_es ) {
1055
          // in case of carry, adjust page by 1
1056
          page++;
1057
        }
1058
        base_count = (num_sectors * 512) - 1;
1059
 
1060
        // check for 64K boundary overrun
1061
        last_addr = base_address + base_count;
1062
        if (last_addr < base_address) {
1063
          SET_AH(0x09);
1064
          set_diskette_ret_status(0x09);
1065
          SET_AL(0); // no sectors read
1066
          SET_CF(); // error occurred
1067
          return;
1068
        }
1069
 
1070
        log_sector = track * 36 + head * 18 + sector - 1;
1071
        last_addr = page << 12;
1072
 
1073
        // Configure the sector address
1074
        for (j=0; j<num_sectors; j++)
1075
          {
1076
            outw(0xe000, log_sector+j);
1077
            base_count = base_address + (j << 9);
1078
              for (i=0; i<512; i+=2)
1079
              {
1080
                tmp = inw (0xe000+i);
1081
                write_word (last_addr, base_count+i, tmp);
1082
              }
1083
          }
1084
 
1085
        // ??? should track be new val from return_status[3] ?
1086
        set_diskette_current_cyl(drive, track);
1087
        // AL = number of sectors read (same value as passed)
1088
        SET_AH(0x00); // success
1089
        CLEAR_CF();   // success
1090
        return;
1091
    default:
1092
        BX_INFO("int13_diskette: unsupported AH=%02x\n", GET_AH());
1093
 
1094
      // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
1095
        SET_AH(0x01); // ???
1096
        set_diskette_ret_status(1);
1097
        SET_CF();
1098
        return;
1099
      //   }
1100
    }
1101
}
1102
 
1103
 void
1104
set_diskette_ret_status(value)
1105
  Bit8u value;
1106
{
1107
  write_byte(0x0040, 0x0041, value);
1108
}
1109
 
1110
  void
1111
set_diskette_current_cyl(drive, cyl)
1112
  Bit8u drive;
1113
  Bit8u cyl;
1114
{
1115
/* TEMP HACK: FOR MSDOS */
1116
  if (drive > 1)
1117
    drive = 1;
1118
  /*  BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
1119
  write_byte(0x0040, 0x0094+drive, cyl);
1120
}
1121
 
1122 26 zeus
void
1123
int19_function(seq_nr)
1124
Bit16u seq_nr;
1125
{
1126
  Bit16u ebda_seg=read_word(0x0040,0x000E);
1127
  Bit16u bootdev;
1128
  Bit8u  bootdrv;
1129
  Bit8u  bootchk;
1130
  Bit16u bootseg;
1131
  Bit16u bootip;
1132
  Bit16u status;
1133
  Bit16u bootfirst;
1134
 
1135
  ipl_entry_t e;
1136
 
1137
  // Here we assume that BX_ELTORITO_BOOT is defined, so
1138
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
1139
  //     CMOS reg 0x3D & 0x0f : 1st boot device
1140
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
1141
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
1142
  //   boot device codes:
1143
  //     0x00 : not defined
1144
  //     0x01 : first floppy
1145
  //     0x02 : first harddrive
1146
  //     0x03 : first cdrom
1147
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
1148
  //     else : boot failure
1149
 
1150
  // Get the boot sequence
1151 39 zeus
/*
1152
 * Zet: we don't have a CMOS device
1153
 *
1154 26 zeus
  bootdev = inb_cmos(0x3d);
1155
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
1156
  bootdev >>= 4 * seq_nr;
1157
  bootdev &= 0xf;
1158 39 zeus
*/
1159
  bootdev = 0x1;
1160 26 zeus
 
1161
  /* Read user selected device */
1162
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
1163
  if (bootfirst != 0xFFFF) {
1164
    bootdev = bootfirst;
1165
    /* User selected device not set */
1166
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
1167
    /* Reset boot sequence */
1168
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
1169
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
1170
 
1171
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
1172
  bootdev -= 1;
1173
 
1174
  /* Read the boot device from the IPL table */
1175
  if (get_boot_vector(bootdev, &e) == 0) {
1176
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
1177
    return;
1178
  }
1179
 
1180
  /* Do the loading, and set up vector as a far pointer to the boot
1181
   * address, and bootdrv as the boot drive */
1182
  print_boot_device(&e);
1183
 
1184
  switch(e.type) {
1185 39 zeus
  case IPL_TYPE_FLOPPY: /* FDD */
1186
  case IPL_TYPE_HARDDISK: /* HDD */
1187 26 zeus
 
1188 39 zeus
    bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00;
1189
    bootseg = 0x07c0;
1190
    status = 0;
1191
 
1192
ASM_START
1193
    push bp
1194
    mov  bp, sp
1195
    push ax
1196
    push bx
1197
    push cx
1198
    push dx
1199
 
1200
    mov  dl, _int19_function.bootdrv + 2[bp]
1201
    mov  ax, _int19_function.bootseg + 2[bp]
1202
    mov  es, ax         ;; segment
1203
    xor  bx, bx         ;; offset
1204
    mov  ah, #0x02      ;; function 2, read diskette sector
1205
    mov  al, #0x01      ;; read 1 sector
1206
    mov  ch, #0x00      ;; track 0
1207
    mov  cl, #0x01      ;; sector 1
1208
    mov  dh, #0x00      ;; head 0
1209
    int  #0x13          ;; read sector
1210
    jnc  int19_load_done
1211
    mov  ax, #0x0001
1212
    mov  _int19_function.status + 2[bp], ax
1213
 
1214
int19_load_done:
1215
    pop  dx
1216
    pop  cx
1217
    pop  bx
1218
    pop  ax
1219
    pop  bp
1220
ASM_END
1221
 
1222
    if (status != 0) {
1223
      print_boot_failure(e.type, 1);
1224
      return;
1225
    }
1226
 
1227
    /* Canonicalize bootseg:bootip */
1228
    bootip = (bootseg & 0x0fff) << 4;
1229
    bootseg &= 0xf000;
1230
  break;
1231
 
1232 26 zeus
  default: return;
1233
  }
1234
 
1235
  /* Debugging info */
1236
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
1237
 
1238
  /* Jump to the boot vector */
1239
ASM_START
1240
    mov  bp, sp
1241
    ;; Build an iret stack frame that will take us to the boot vector.
1242
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
1243
    pushf
1244
    mov  ax, _int19_function.bootseg + 0[bp]
1245
    push ax
1246
    mov  ax, _int19_function.bootip + 0[bp]
1247
    push ax
1248
    ;; Set the magic number in ax and the boot drive in dl.
1249
    mov  ax, #0xaa55
1250
    mov  dl, _int19_function.bootdrv + 0[bp]
1251
    ;; Zero some of the other registers.
1252
    xor  bx, bx
1253
    mov  ds, bx
1254
    mov  es, bx
1255
    mov  bp, bx
1256
    ;; Go!
1257
    iret
1258
ASM_END
1259
}
1260
 
1261
ASM_START
1262 39 zeus
;----------------------
1263
;- INT13h (relocated) -
1264
;----------------------
1265
;
1266
; int13_relocated is a little bit messed up since I played with it
1267
; I have to rewrite it:
1268
;   - call a function that detect which function to call
1269
;   - make all called C function get the same parameters list
1270
;
1271
int13_relocated:
1272
  push  ax
1273
  push  cx
1274
  push  dx
1275
  push  bx
1276
 
1277
int13_legacy:
1278
 
1279
  push  dx                   ;; push eltorito value of dx instead of sp
1280
 
1281
  push  bp
1282
  push  si
1283
  push  di
1284
 
1285
  push  es
1286
  push  ds
1287
  push  ss
1288
  pop   ds
1289
 
1290
  ;; now the 16-bit registers can be restored with:
1291
  ;; pop ds; pop es; popa; iret
1292
  ;; arguments passed to functions should be
1293
  ;; DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS
1294
 
1295
  test  dl, #0x80
1296
  jnz   int13_notfloppy
1297
 
1298
  mov  ax, #int13_out
1299
  push ax
1300
  jmp _int13_diskette_function
1301
 
1302
int13_notfloppy:
1303
 
1304
int13_disk:
1305
  ;; int13_harddisk modifies high word of EAX
1306
;  shr   eax, #16
1307
;  push  ax
1308
  call  _int13_harddisk
1309
;  pop   ax
1310
;  shl   eax, #16
1311
 
1312
int13_out:
1313
  pop ds
1314
  pop es
1315
  ; popa ; we do this instead:
1316
  pop di
1317
  pop si
1318
  pop bp
1319
  add sp, #2
1320
  pop bx
1321
  pop dx
1322
  pop cx
1323
  pop ax
1324
 
1325
  iret
1326
 
1327 26 zeus
;----------
1328
;- INT18h -
1329
;----------
1330
int18_handler: ;; Boot Failure recovery: try the next device.
1331
 
1332
  ;; Reset SP and SS
1333
  mov  ax, #0xfffe
1334
  mov  sp, ax
1335
  xor  ax, ax
1336
  mov  ss, ax
1337
 
1338
  ;; Get the boot sequence number out of the IPL memory
1339
  mov  bx, #IPL_SEG
1340
  mov  ds, bx                     ;; Set segment
1341
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
1342
  inc  bx                         ;; ++
1343
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
1344
  mov  ds, ax                     ;; and reset the segment to zero.
1345
 
1346
  ;; Carry on in the INT 19h handler, using the new sequence number
1347
  push bx
1348
 
1349
  jmp  int19_next_boot
1350
 
1351
;----------
1352
;- INT19h -
1353
;----------
1354
int19_relocated: ;; Boot function, relocated
1355
 
1356
  ;; int19 was beginning to be really complex, so now it
1357
  ;; just calls a C function that does the work
1358
 
1359
  push bp
1360
  mov  bp, sp
1361
 
1362
  ;; Reset SS and SP
1363
  mov  ax, #0xfffe
1364
  mov  sp, ax
1365
  xor  ax, ax
1366
  mov  ss, ax
1367
 
1368
  ;; Start from the first boot device (0, in AX)
1369
  mov  bx, #IPL_SEG
1370
  mov  ds, bx                     ;; Set segment to write to the IPL memory
1371
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
1372
  mov  ds, ax                     ;; and reset the segment.
1373
 
1374
  push ax
1375
 
1376
int19_next_boot:
1377
 
1378
  ;; Call the C code for the next boot device
1379
  call _int19_function
1380
 
1381
  ;; Boot failed: invoke the boot recovery function
1382
  int  #0x18
1383
 
1384 39 zeus
;----------
1385
;- INT1Ch -
1386
;----------
1387
int1c_handler: ;; User Timer Tick
1388
  iret
1389
 
1390
 
1391 26 zeus
;--------------------
1392
;- POST: EBDA segment
1393
;--------------------
1394
; relocated here because the primary POST area isnt big enough.
1395
ebda_post:
1396
  xor ax, ax            ; mov EBDA seg into 40E
1397
  mov ds, ax
1398
  mov word ptr [0x40E], #EBDA_SEG
1399
  ret;;
1400
 
1401
rom_checksum:
1402
  push ax
1403
  push bx
1404
  push cx
1405
  xor  ax, ax
1406
  xor  bx, bx
1407
  xor  cx, cx
1408
  mov  ch, [2]
1409
  shl  cx, #1
1410
checksum_loop:
1411
  add  al, [bx]
1412
  inc  bx
1413
  loop checksum_loop
1414
  and  al, #0xff
1415
  pop  cx
1416
  pop  bx
1417
  pop  ax
1418
  ret
1419
 
1420
 
1421
;; We need a copy of this string, but we are not actually a PnP BIOS,
1422
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
1423
.align 16
1424
  db 0
1425
pnp_string:
1426
  .ascii "$PnP"
1427
 
1428
 
1429
rom_scan:
1430
  ;; Scan for existence of valid expansion ROMS.
1431
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
1432
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
1433
  ;;   System  ROM: only 0xE0000
1434
  ;;
1435
  ;; Header:
1436
  ;;   Offset    Value
1437
  ;;   0         0x55
1438
  ;;   1         0xAA
1439
  ;;   2         ROM length in 512-byte blocks
1440
  ;;   3         ROM initialization entry point (FAR CALL)
1441
 
1442
rom_scan_loop:
1443
  push ax       ;; Save AX
1444
  mov  ds, cx
1445
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
1446
  cmp [0], #0xAA55 ;; look for signature
1447
  jne  rom_scan_increment
1448
  call rom_checksum
1449
  jnz  rom_scan_increment
1450
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
1451
 
1452
  ;; We want our increment in 512-byte quantities, rounded to
1453
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
1454
  test al, #0x03
1455
  jz   block_count_rounded
1456
  and  al, #0xfc ;; needs rounding up
1457
  add  al, #0x04
1458
block_count_rounded:
1459
 
1460
  xor  bx, bx   ;; Restore DS back to 0000:
1461
  mov  ds, bx
1462
  push ax       ;; Save AX
1463
  push di       ;; Save DI
1464
  ;; Push addr of ROM entry point
1465
  push cx       ;; Push seg
1466 34 zeus
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
1467
  mov ax, #0x0003
1468
  push ax
1469 26 zeus
 
1470
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
1471
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
1472
  mov  ax, #0xf000
1473
  mov  es, ax
1474
  lea  di, pnp_string
1475
 
1476
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
1477
  db   0xff     ;; call_far ss:[bp+0]
1478
  db   0x5e
1479
  db   0
1480
  cli           ;; In case expansion ROM BIOS turns IF on
1481
  add  sp, #2   ;; Pop offset value
1482
  pop  cx       ;; Pop seg value (restore CX)
1483
 
1484
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
1485
  ;; to init all the ROMs and then go back and build an IPL table of
1486
  ;; all the bootable devices, but we can get away with one pass.
1487
  mov  ds, cx       ;; ROM base
1488
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
1489
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
1490
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
1491
  jne  no_bev
1492
  mov  ax, 2[bx]
1493
  cmp  ax, #0x506e
1494
  jne  no_bev
1495
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
1496
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
1497
  je   no_bev
1498
 
1499
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
1500
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
1501
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
1502
  mov  ds, bx
1503
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
1504
  cmp  bx, #IPL_TABLE_ENTRIES
1505
  je   no_bev                  ;; Get out if the table is full
1506
  push cx
1507
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
1508
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
1509
  pop  cx
1510
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
1511
  mov  6[bx], cx               ;; Build a far pointer from the segment...
1512
  mov  4[bx], ax               ;; and the offset
1513
  cmp  di, #0x0000
1514
  je   no_prod_str
1515
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
1516
  mov  8[bx], di               ;; and the offset
1517
no_prod_str:
1518
  push cx
1519
  mov  cx, #0x4
1520
  shr  bx, cl                  ;; Turn the offset back into a count
1521
  pop  cx
1522
  inc  bx                      ;; We have one more entry now
1523
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
1524
 
1525
no_bev:
1526
  pop  di       ;; Restore DI
1527
  pop  ax       ;; Restore AX
1528
rom_scan_increment:
1529
  push cx
1530
  mov  cx, #5
1531
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
1532
                ;; because the segment selector is shifted left 4 bits.
1533
  pop  cx
1534
  add  cx, ax
1535
  pop  ax       ;; Restore AX
1536
  cmp  cx, ax
1537
  jbe  rom_scan_loop
1538
 
1539
  xor  ax, ax   ;; Restore DS back to 0000:
1540
  mov  ds, ax
1541
  ret
1542
 
1543
;; for 'C' strings and other data, insert them here with
1544
;; a the following hack:
1545
;; DATA_SEG_DEFS_HERE
1546
 
1547
 
1548
;; the following area can be used to write dynamically generated tables
1549
  .align 16
1550
bios_table_area_start:
1551
  dd 0xaafb4442
1552
  dd bios_table_area_end - bios_table_area_start - 8;
1553
 
1554
;--------
1555
;- POST -
1556
;--------
1557
.org 0xe05b ; POST Entry Point
1558
post:
1559
  xor ax, ax
1560
 
1561
normal_post:
1562
  ; case 0: normal startup
1563
 
1564
  cli
1565
  mov  ax, #0xfffe
1566
  mov  sp, ax
1567
  xor  ax, ax
1568
  mov  ds, ax
1569
  mov  ss, ax
1570
 
1571
  ;; zero out BIOS data area (40:00..40:ff)
1572
  mov  es, ax
1573
  mov  cx, #0x0080 ;; 128 words
1574
  mov  di, #0x0400
1575
  cld
1576
  rep
1577
    stosw
1578
 
1579
  ;; set all interrupts to default handler
1580
  xor  bx, bx         ;; offset index
1581
  mov  cx, #0x0100    ;; counter (256 interrupts)
1582
  mov  ax, #dummy_iret_handler
1583
  mov  dx, #0xF000
1584
 
1585
post_default_ints:
1586
  mov  [bx], ax
1587
  add  bx, #2
1588
  mov  [bx], dx
1589
  add  bx, #2
1590
  loop post_default_ints
1591
 
1592
  ;; set vector 0x79 to zero
1593
  ;; this is used by 'gardian angel' protection system
1594
  SET_INT_VECTOR(0x79, #0, #0)
1595
 
1596
  ;; base memory in K 40:13 (word)
1597
  mov  ax, #BASE_MEM_IN_K
1598
  mov  0x0413, ax
1599
 
1600
 
1601
  ;; Manufacturing Test 40:12
1602
  ;;   zerod out above
1603
 
1604
  ;; Warm Boot Flag 0040:0072
1605
  ;;   value of 1234h = skip memory checks
1606
  ;;   zerod out above
1607
 
1608
  ;; Bootstrap failure vector
1609
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
1610
 
1611
  ;; Bootstrap Loader vector
1612
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
1613
 
1614 39 zeus
  ;; User Timer Tick vector
1615
  SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
1616
 
1617
  ;; Memory Size Check vector
1618
  SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
1619
 
1620
  ;; Equipment Configuration Check vector
1621
  SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
1622
 
1623 26 zeus
  ;; EBDA setup
1624
  call ebda_post
1625
 
1626 39 zeus
  ;; Keyboard
1627
  SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
1628
 
1629 26 zeus
  ;; Video setup
1630
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
1631
 
1632
  mov  cx, #0xc000  ;; init vga bios
1633
  mov  ax, #0xc780
1634 37 zeus
 
1635 26 zeus
  call rom_scan
1636
 
1637
  call _print_bios_banner
1638 37 zeus
 
1639 39 zeus
  ;; Floppy setup
1640
  SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
1641
 
1642 26 zeus
  call _init_boot_vectors
1643
 
1644
  mov  cx, #0xc800  ;; init option roms
1645
  mov  ax, #0xe000
1646
  call rom_scan
1647
 
1648
  sti        ;; enable interrupts
1649
  int  #0x19
1650
 
1651 39 zeus
;-------------------------------------------
1652
;- INT 13h Fixed Disk Services Entry Point -
1653
;-------------------------------------------
1654
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
1655
int13_handler:
1656
  //JMPL(int13_relocated)
1657
  jmp int13_relocated
1658
 
1659
.org 0xe401 ; Fixed Disk Parameter Table
1660
 
1661 26 zeus
;----------
1662
;- INT19h -
1663
;----------
1664
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
1665
int19_handler:
1666
 
1667
  jmp int19_relocated
1668
 
1669 39 zeus
;----------------------------------------
1670
;- INT 16h Keyboard Service Entry Point -
1671
;----------------------------------------
1672
.org 0xe82e
1673
int16_handler:
1674
  cmp   ah, #0x01
1675
  je    int16_01
1676
  cmp   ah, #0x02
1677
  je    int16_02
1678
  iret
1679
int16_02:
1680
  mov  al, #0x0
1681
  iret
1682
int16_01:
1683
  push bp
1684
  mov  bp, sp
1685
  //SEG SS
1686
  or   BYTE [bp + 0x06], #0x40
1687
  pop  bp
1688
  iret
1689
 
1690 26 zeus
.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
1691
  ;; HALT(__LINE__)
1692
  iret
1693
 
1694
;----------
1695
;- INT10h -
1696
;----------
1697
.org 0xf065 ; INT 10h Video Support Service Entry Point
1698
int10_handler:
1699
  ;; dont do anything, since the VGA BIOS handles int10h requests
1700
  iret
1701
 
1702
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
1703
 
1704 39 zeus
;----------
1705
;- INT12h -
1706
;----------
1707
.org 0xf841 ; INT 12h Memory Size Service Entry Point
1708
; ??? different for Pentium (machine check)?
1709
int12_handler:
1710
  push ds
1711
  mov  ax, #0x0040
1712
  mov  ds, ax
1713
  mov  ax, 0x0013
1714
  pop  ds
1715
  iret
1716
 
1717
;----------
1718
;- INT11h -
1719
;----------
1720
.org 0xf84d ; INT 11h Equipment List Service Entry Point
1721
int11_handler:
1722
  push ds
1723
  mov  ax, #0x0040
1724
  mov  ds, ax
1725
  mov  ax, 0x0010
1726
  pop  ds
1727
  iret
1728
 
1729 26 zeus
;------------------------------------------------
1730
;- IRET Instruction for Dummy Interrupt Handler -
1731
;------------------------------------------------
1732
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
1733
dummy_iret_handler:
1734
  iret
1735
 
1736
.org 0xfff0 ; Power-up Entry Point
1737 39 zeus
;  hlt
1738 26 zeus
  jmp 0xf000:post
1739
 
1740
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
1741
.ascii BIOS_BUILD_DATE
1742
 
1743
.org 0xfffe ; System Model ID
1744
db SYS_MODEL_ID
1745
db 0x00   ; filler
1746
ASM_END
1747
 
1748
ASM_START
1749
.org 0xcc00
1750
bios_table_area_end:
1751
// bcc-generated data will be placed here
1752
ASM_END

powered by: WebSVN 2.1.0

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