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

Subversion Repositories zet86

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

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
 
433
 
434
static Bit8u          inb_cmos();
435
 
436
static Bit8u          read_byte();
437
static Bit16u         read_word();
438
static void           write_byte();
439
static void           write_word();
440
static void           bios_printf();
441
 
442
static void           int19_function();
443
static Bit16u         get_CS();
444
static Bit16u         get_SS();
445
 
446
static void           print_bios_banner();
447
static void           print_boot_device();
448
 
449
  Bit8u
450
inb_cmos(cmos_reg)
451
  Bit8u cmos_reg;
452
{
453
ASM_START
454
  push bp
455
  mov  bp, sp
456
 
457
    mov  al, 4[bp] ;; cmos_reg
458
    out 0x70, al
459
    in  al, 0x71
460
 
461
  pop  bp
462
ASM_END
463
}
464
 
465
  Bit8u
466
read_byte(seg, offset)
467
  Bit16u seg;
468
  Bit16u offset;
469
{
470
ASM_START
471
  push bp
472
  mov  bp, sp
473
 
474
    push bx
475
    push ds
476
    mov  ax, 4[bp] ; segment
477
    mov  ds, ax
478
    mov  bx, 6[bp] ; offset
479
    mov  al, [bx]
480
    ;; al = return value (byte)
481
    pop  ds
482
    pop  bx
483
 
484
  pop  bp
485
ASM_END
486
}
487
 
488
  Bit16u
489
read_word(seg, offset)
490
  Bit16u seg;
491
  Bit16u offset;
492
{
493
ASM_START
494
  push bp
495
  mov  bp, sp
496
 
497
    push bx
498
    push ds
499
    mov  ax, 4[bp] ; segment
500
    mov  ds, ax
501
    mov  bx, 6[bp] ; offset
502
    mov  ax, [bx]
503
    ;; ax = return value (word)
504
    pop  ds
505
    pop  bx
506
 
507
  pop  bp
508
ASM_END
509
}
510
 
511
  void
512
write_byte(seg, offset, data)
513
  Bit16u seg;
514
  Bit16u offset;
515
  Bit8u data;
516
{
517
ASM_START
518
  push bp
519
  mov  bp, sp
520
 
521
    push ax
522
    push bx
523
    push ds
524
    mov  ax, 4[bp] ; segment
525
    mov  ds, ax
526
    mov  bx, 6[bp] ; offset
527
    mov  al, 8[bp] ; data byte
528
    mov  [bx], al  ; write data byte
529
    pop  ds
530
    pop  bx
531
    pop  ax
532
 
533
  pop  bp
534
ASM_END
535
}
536
 
537
  void
538
write_word(seg, offset, data)
539
  Bit16u seg;
540
  Bit16u offset;
541
  Bit16u data;
542
{
543
ASM_START
544
  push bp
545
  mov  bp, sp
546
 
547
    push ax
548
    push bx
549
    push ds
550
    mov  ax, 4[bp] ; segment
551
    mov  ds, ax
552
    mov  bx, 6[bp] ; offset
553
    mov  ax, 8[bp] ; data word
554
    mov  [bx], ax  ; write data word
555
    pop  ds
556
    pop  bx
557
    pop  ax
558
 
559
  pop  bp
560
ASM_END
561
}
562
 
563
  Bit16u
564
get_CS()
565
{
566
ASM_START
567
  mov  ax, cs
568
ASM_END
569
}
570
 
571
  Bit16u
572
get_SS()
573
{
574
ASM_START
575
  mov  ax, ss
576
ASM_END
577
}
578
 
579
  void
580
wrch(c)
581
  Bit8u  c;
582
{
583
  ASM_START
584
  push bp
585
  mov  bp, sp
586
 
587
  push bx
588
  mov  ah, #0x0e
589
  mov  al, 4[bp]
590
  xor  bx,bx
591
  int  #0x10
592
  pop  bx
593
 
594
  pop  bp
595
  ASM_END
596
}
597
 
598
  void
599
send(action, c)
600
  Bit16u action;
601
  Bit8u  c;
602
{
603
  if (action & BIOS_PRINTF_SCREEN) {
604
    if (c == '\n') wrch('\r');
605
    wrch(c);
606
  }
607
}
608
 
609
  void
610
put_int(action, val, width, neg)
611
  Bit16u action;
612
  short val, width;
613
  bx_bool neg;
614
{
615
  short nval = val / 10;
616
  if (nval)
617
    put_int(action, nval, width - 1, neg);
618
  else {
619
    while (--width > 0) send(action, ' ');
620
    if (neg) send(action, '-');
621
  }
622
  send(action, val - (nval * 10) + '0');
623
}
624
 
625
  void
626
put_uint(action, val, width, neg)
627
  Bit16u action;
628
  unsigned short val;
629
  short width;
630
  bx_bool neg;
631
{
632
  unsigned short nval = val / 10;
633
  if (nval)
634
    put_uint(action, nval, width - 1, neg);
635
  else {
636
    while (--width > 0) send(action, ' ');
637
    if (neg) send(action, '-');
638
  }
639
  send(action, val - (nval * 10) + '0');
640
}
641
 
642
  void
643
put_luint(action, val, width, neg)
644
  Bit16u action;
645
  unsigned long val;
646
  short width;
647
  bx_bool neg;
648
{
649
  unsigned long nval = val / 10;
650
  if (nval)
651
    put_luint(action, nval, width - 1, neg);
652
  else {
653
    while (--width > 0) send(action, ' ');
654
    if (neg) send(action, '-');
655
  }
656
  send(action, val - (nval * 10) + '0');
657
}
658
 
659
void put_str(action, segment, offset)
660
  Bit16u action;
661
  Bit16u segment;
662
  Bit16u offset;
663
{
664
  Bit8u c;
665
 
666
  while (c = read_byte(segment, offset)) {
667
    send(action, c);
668
    offset++;
669
  }
670
}
671
 
672
//--------------------------------------------------------------------------
673
// bios_printf()
674
//   A compact variable argument printf function.
675
//
676
//   Supports %[format_width][length]format
677
//   where format can be x,X,u,d,s,S,c
678
//   and the optional length modifier is l (ell)
679
//--------------------------------------------------------------------------
680
  void
681
bios_printf(action, s)
682
  Bit16u action;
683
  Bit8u *s;
684
{
685
  Bit8u c, format_char;
686
  bx_bool  in_format;
687
  short i;
688
  Bit16u  *arg_ptr;
689
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
690
 
691
  arg_ptr = &s;
692
  arg_seg = get_SS();
693
 
694
  in_format = 0;
695
  format_width = 0;
696
 
697
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
698
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
699
 
700
  while (c = read_byte(get_CS(), s)) {
701
    if ( c == '%' ) {
702
      in_format = 1;
703
      format_width = 0;
704
      }
705
    else if (in_format) {
706
      if ( (c>='0') && (c<='9') ) {
707
        format_width = (format_width * 10) + (c - '0');
708
        }
709
      else {
710
        arg_ptr++; // increment to next arg
711
        arg = read_word(arg_seg, arg_ptr);
712
        if (c == 'x' || c == 'X') {
713
          if (format_width == 0)
714
            format_width = 4;
715
          if (c == 'x')
716
            hexadd = 'a';
717
          else
718
            hexadd = 'A';
719
          for (i=format_width-1; i>=0; i--) {
720
            nibble = (arg >> (4 * i)) & 0x000f;
721
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
722
            }
723
          }
724
        else if (c == 'u') {
725
          put_uint(action, arg, format_width, 0);
726
          }
727
        else if (c == 'l') {
728
          s++;
729
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
730
          arg_ptr++; /* increment to next arg */
731
          hibyte = read_word(arg_seg, arg_ptr);
732
          if (c == 'd') {
733
            if (hibyte & 0x8000)
734
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
735
            else
736
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
737
           }
738
          else if (c == 'u') {
739
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
740
           }
741
          else if (c == 'x' || c == 'X')
742
           {
743
            if (format_width == 0)
744
              format_width = 8;
745
            if (c == 'x')
746
              hexadd = 'a';
747
            else
748
              hexadd = 'A';
749
            for (i=format_width-1; i>=0; i--) {
750
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
751
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
752
              }
753
           }
754
          }
755
        else if (c == 'd') {
756
          if (arg & 0x8000)
757
            put_int(action, -arg, format_width - 1, 1);
758
          else
759
            put_int(action, arg, format_width, 0);
760
          }
761
        else if (c == 's') {
762
          put_str(action, get_CS(), arg);
763
          }
764
        else if (c == 'S') {
765
          hibyte = arg;
766
          arg_ptr++;
767
          arg = read_word(arg_seg, arg_ptr);
768
          put_str(action, hibyte, arg);
769
          }
770
        else if (c == 'c') {
771
          send(action, arg);
772
          }
773
        else
774
          BX_PANIC("bios_printf: unknown format\n");
775
          in_format = 0;
776
        }
777
      }
778
    else {
779
      send(action, c);
780
      }
781
    s ++;
782
    }
783
 
784
  if (action & BIOS_PRINTF_HALT) {
785
    // freeze in a busy loop.
786
ASM_START
787
    cli
788
 halt2_loop:
789
    hlt
790
    jmp halt2_loop
791
ASM_END
792
    }
793
}
794
 
795 34 zeus
static char bios_svn_version_string[] = "$Revision: 1.3 $ $Date: 2008-10-13 00:24:30 $";
796 26 zeus
 
797
//--------------------------------------------------------------------------
798
// print_bios_banner
799
//   displays a the bios version
800
//--------------------------------------------------------------------------
801
void
802
print_bios_banner()
803
{
804
  printf("Zet BIOS - build: %s\n%s\n",
805
    BIOS_BUILD_DATE, bios_svn_version_string);
806
}
807
 
808
//--------------------------------------------------------------------------
809
// BIOS Boot Specification 1.0.1 compatibility
810
//
811
// Very basic support for the BIOS Boot Specification, which allows expansion
812
// ROMs to register themselves as boot devices, instead of just stealing the
813
// INT 19h boot vector.
814
//
815
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
816
// one; we just lie to the option ROMs to make them behave correctly.
817
// We also don't support letting option ROMs register as bootable disk
818
// drives (BCVs), only as bootable devices (BEVs).
819
//
820
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
821
//--------------------------------------------------------------------------
822
 
823
static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
824
 
825
static void
826
init_boot_vectors()
827
{
828
  ipl_entry_t e;
829
  Bit16u count = 0;
830
  Bit16u ss = get_SS();
831
 
832
  /* Clear out the IPL table. */
833
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
834
 
835
  /* User selected device not set */
836
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
837
 
838
  /*
839
   * Zet: We don't have support for floppy, hdd or cdrom
840
   */
841
 
842
  /* Remember how many devices we have */
843
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
844
  /* Not tried booting anything yet */
845
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
846
}
847
 
848
static Bit8u
849
get_boot_vector(i, e)
850
Bit16u i; ipl_entry_t *e;
851
{
852
  Bit16u count;
853
  Bit16u ss = get_SS();
854
  /* Get the count of boot devices, and refuse to overrun the array */
855
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
856
  if (i >= count) return 0;
857
  /* OK to read this device */
858
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
859
  return 1;
860
}
861
 
862
//--------------------------------------------------------------------------
863
// print_boot_device
864
//   displays the boot device
865
//--------------------------------------------------------------------------
866
 
867
void
868
print_boot_device(e)
869
  ipl_entry_t *e;
870
{
871
  Bit16u type;
872
  char description[33];
873
  Bit16u ss = get_SS();
874
  type = e->type;
875
  /* NIC appears as type 0x80 */
876
  if (type == IPL_TYPE_BEV) type = 0x4;
877
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
878
  printf("Booting from %s", drivetypes[type]);
879
  /* print product string if BEV */
880
  if (type == 4 && e->description != 0) {
881
    /* first 32 bytes are significant */
882
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
883
    /* terminate string */
884
    description[32] = 0;
885
    printf(" [%S]", ss, description);
886
  }
887
  printf("...\n");
888
}
889
 
890
void
891
int19_function(seq_nr)
892
Bit16u seq_nr;
893
{
894
  Bit16u ebda_seg=read_word(0x0040,0x000E);
895
  Bit16u bootdev;
896
  Bit8u  bootdrv;
897
  Bit8u  bootchk;
898
  Bit16u bootseg;
899
  Bit16u bootip;
900
  Bit16u status;
901
  Bit16u bootfirst;
902
 
903
  ipl_entry_t e;
904
 
905
  // Here we assume that BX_ELTORITO_BOOT is defined, so
906
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
907
  //     CMOS reg 0x3D & 0x0f : 1st boot device
908
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
909
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
910
  //   boot device codes:
911
  //     0x00 : not defined
912
  //     0x01 : first floppy
913
  //     0x02 : first harddrive
914
  //     0x03 : first cdrom
915
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
916
  //     else : boot failure
917
 
918
  // Get the boot sequence
919
  bootdev = inb_cmos(0x3d);
920
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
921
  bootdev >>= 4 * seq_nr;
922
  bootdev &= 0xf;
923
 
924
  /* Read user selected device */
925
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
926
  if (bootfirst != 0xFFFF) {
927
    bootdev = bootfirst;
928
    /* User selected device not set */
929
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
930
    /* Reset boot sequence */
931
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
932
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
933
 
934
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
935
  bootdev -= 1;
936
 
937
  /* Read the boot device from the IPL table */
938
  if (get_boot_vector(bootdev, &e) == 0) {
939
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
940
    return;
941
  }
942
 
943
  /* Do the loading, and set up vector as a far pointer to the boot
944
   * address, and bootdrv as the boot drive */
945
  print_boot_device(&e);
946
 
947
  switch(e.type) {
948
  case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
949
    bootseg = e.vector >> 16;
950
    bootip = e.vector & 0xffff;
951
    break;
952
 
953
  default: return;
954
  }
955
 
956
  /* Debugging info */
957
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
958
 
959
  /* Jump to the boot vector */
960
ASM_START
961
    mov  bp, sp
962
    ;; Build an iret stack frame that will take us to the boot vector.
963
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
964
    pushf
965
    mov  ax, _int19_function.bootseg + 0[bp]
966
    push ax
967
    mov  ax, _int19_function.bootip + 0[bp]
968
    push ax
969
    ;; Set the magic number in ax and the boot drive in dl.
970
    mov  ax, #0xaa55
971
    mov  dl, _int19_function.bootdrv + 0[bp]
972
    ;; Zero some of the other registers.
973
    xor  bx, bx
974
    mov  ds, bx
975
    mov  es, bx
976
    mov  bp, bx
977
    ;; Go!
978
    iret
979
ASM_END
980
}
981
 
982
ASM_START
983
;----------
984
;- INT18h -
985
;----------
986
int18_handler: ;; Boot Failure recovery: try the next device.
987
 
988
  ;; Reset SP and SS
989
  mov  ax, #0xfffe
990
  mov  sp, ax
991
  xor  ax, ax
992
  mov  ss, ax
993
 
994
  ;; Get the boot sequence number out of the IPL memory
995
  mov  bx, #IPL_SEG
996
  mov  ds, bx                     ;; Set segment
997
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
998
  inc  bx                         ;; ++
999
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
1000
  mov  ds, ax                     ;; and reset the segment to zero.
1001
 
1002
  ;; Carry on in the INT 19h handler, using the new sequence number
1003
  push bx
1004
 
1005
  jmp  int19_next_boot
1006
 
1007
;----------
1008
;- INT19h -
1009
;----------
1010
int19_relocated: ;; Boot function, relocated
1011
 
1012
  ;; int19 was beginning to be really complex, so now it
1013
  ;; just calls a C function that does the work
1014
 
1015
  push bp
1016
  mov  bp, sp
1017
 
1018
  ;; Reset SS and SP
1019
  mov  ax, #0xfffe
1020
  mov  sp, ax
1021
  xor  ax, ax
1022
  mov  ss, ax
1023
 
1024
  ;; Start from the first boot device (0, in AX)
1025
  mov  bx, #IPL_SEG
1026
  mov  ds, bx                     ;; Set segment to write to the IPL memory
1027
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
1028
  mov  ds, ax                     ;; and reset the segment.
1029
 
1030
  push ax
1031
 
1032
int19_next_boot:
1033
 
1034
  ;; Call the C code for the next boot device
1035
  call _int19_function
1036
 
1037
  ;; Boot failed: invoke the boot recovery function
1038
  int  #0x18
1039
 
1040
;--------------------
1041
;- POST: EBDA segment
1042
;--------------------
1043
; relocated here because the primary POST area isnt big enough.
1044
ebda_post:
1045
  xor ax, ax            ; mov EBDA seg into 40E
1046
  mov ds, ax
1047
  mov word ptr [0x40E], #EBDA_SEG
1048
  ret;;
1049
 
1050
rom_checksum:
1051
  push ax
1052
  push bx
1053
  push cx
1054
  xor  ax, ax
1055
  xor  bx, bx
1056
  xor  cx, cx
1057
  mov  ch, [2]
1058
  shl  cx, #1
1059
checksum_loop:
1060
  add  al, [bx]
1061
  inc  bx
1062
  loop checksum_loop
1063
  and  al, #0xff
1064
  pop  cx
1065
  pop  bx
1066
  pop  ax
1067
  ret
1068
 
1069
 
1070
;; We need a copy of this string, but we are not actually a PnP BIOS,
1071
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
1072
.align 16
1073
  db 0
1074
pnp_string:
1075
  .ascii "$PnP"
1076
 
1077
 
1078
rom_scan:
1079
  ;; Scan for existence of valid expansion ROMS.
1080
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
1081
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
1082
  ;;   System  ROM: only 0xE0000
1083
  ;;
1084
  ;; Header:
1085
  ;;   Offset    Value
1086
  ;;   0         0x55
1087
  ;;   1         0xAA
1088
  ;;   2         ROM length in 512-byte blocks
1089
  ;;   3         ROM initialization entry point (FAR CALL)
1090
 
1091
rom_scan_loop:
1092
  push ax       ;; Save AX
1093
  mov  ds, cx
1094
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
1095
  cmp [0], #0xAA55 ;; look for signature
1096
  jne  rom_scan_increment
1097
  call rom_checksum
1098
  jnz  rom_scan_increment
1099
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
1100
 
1101
  ;; We want our increment in 512-byte quantities, rounded to
1102
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
1103
  test al, #0x03
1104
  jz   block_count_rounded
1105
  and  al, #0xfc ;; needs rounding up
1106
  add  al, #0x04
1107
block_count_rounded:
1108
 
1109
  xor  bx, bx   ;; Restore DS back to 0000:
1110
  mov  ds, bx
1111
  push ax       ;; Save AX
1112
  push di       ;; Save DI
1113
  ;; Push addr of ROM entry point
1114
  push cx       ;; Push seg
1115 34 zeus
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
1116
  mov ax, #0x0003
1117
  push ax
1118 26 zeus
 
1119
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
1120
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
1121
  mov  ax, #0xf000
1122
  mov  es, ax
1123
  lea  di, pnp_string
1124
 
1125
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
1126
  db   0xff     ;; call_far ss:[bp+0]
1127
  db   0x5e
1128
  db   0
1129
  cli           ;; In case expansion ROM BIOS turns IF on
1130
  add  sp, #2   ;; Pop offset value
1131
  pop  cx       ;; Pop seg value (restore CX)
1132
 
1133
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
1134
  ;; to init all the ROMs and then go back and build an IPL table of
1135
  ;; all the bootable devices, but we can get away with one pass.
1136
  mov  ds, cx       ;; ROM base
1137
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
1138
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
1139
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
1140
  jne  no_bev
1141
  mov  ax, 2[bx]
1142
  cmp  ax, #0x506e
1143
  jne  no_bev
1144
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
1145
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
1146
  je   no_bev
1147
 
1148
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
1149
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
1150
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
1151
  mov  ds, bx
1152
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
1153
  cmp  bx, #IPL_TABLE_ENTRIES
1154
  je   no_bev                  ;; Get out if the table is full
1155
  push cx
1156
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
1157
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
1158
  pop  cx
1159
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
1160
  mov  6[bx], cx               ;; Build a far pointer from the segment...
1161
  mov  4[bx], ax               ;; and the offset
1162
  cmp  di, #0x0000
1163
  je   no_prod_str
1164
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
1165
  mov  8[bx], di               ;; and the offset
1166
no_prod_str:
1167
  push cx
1168
  mov  cx, #0x4
1169
  shr  bx, cl                  ;; Turn the offset back into a count
1170
  pop  cx
1171
  inc  bx                      ;; We have one more entry now
1172
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
1173
 
1174
no_bev:
1175
  pop  di       ;; Restore DI
1176
  pop  ax       ;; Restore AX
1177
rom_scan_increment:
1178
  push cx
1179
  mov  cx, #5
1180
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
1181
                ;; because the segment selector is shifted left 4 bits.
1182
  pop  cx
1183
  add  cx, ax
1184
  pop  ax       ;; Restore AX
1185
  cmp  cx, ax
1186
  jbe  rom_scan_loop
1187
 
1188
  xor  ax, ax   ;; Restore DS back to 0000:
1189
  mov  ds, ax
1190
  ret
1191
 
1192
;; for 'C' strings and other data, insert them here with
1193
;; a the following hack:
1194
;; DATA_SEG_DEFS_HERE
1195
 
1196
 
1197
;; the following area can be used to write dynamically generated tables
1198
  .align 16
1199
bios_table_area_start:
1200
  dd 0xaafb4442
1201
  dd bios_table_area_end - bios_table_area_start - 8;
1202
 
1203
;--------
1204
;- POST -
1205
;--------
1206
.org 0xe05b ; POST Entry Point
1207
post:
1208
 
1209
  xor ax, ax
1210
 
1211
normal_post:
1212
  ; case 0: normal startup
1213
 
1214
  cli
1215
  mov  ax, #0xfffe
1216
  mov  sp, ax
1217
  xor  ax, ax
1218
  mov  ds, ax
1219
  mov  ss, ax
1220
 
1221
  ;; zero out BIOS data area (40:00..40:ff)
1222
  mov  es, ax
1223
  mov  cx, #0x0080 ;; 128 words
1224
  mov  di, #0x0400
1225
  cld
1226
  rep
1227
    stosw
1228
 
1229
  ;; set all interrupts to default handler
1230
  xor  bx, bx         ;; offset index
1231
  mov  cx, #0x0100    ;; counter (256 interrupts)
1232
  mov  ax, #dummy_iret_handler
1233
  mov  dx, #0xF000
1234
 
1235
post_default_ints:
1236
  mov  [bx], ax
1237
  add  bx, #2
1238
  mov  [bx], dx
1239
  add  bx, #2
1240
  loop post_default_ints
1241
 
1242
  ;; set vector 0x79 to zero
1243
  ;; this is used by 'gardian angel' protection system
1244
  SET_INT_VECTOR(0x79, #0, #0)
1245
 
1246
  ;; base memory in K 40:13 (word)
1247
  mov  ax, #BASE_MEM_IN_K
1248
  mov  0x0413, ax
1249
 
1250
 
1251
  ;; Manufacturing Test 40:12
1252
  ;;   zerod out above
1253
 
1254
  ;; Warm Boot Flag 0040:0072
1255
  ;;   value of 1234h = skip memory checks
1256
  ;;   zerod out above
1257
 
1258
  ;; Bootstrap failure vector
1259
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
1260
 
1261
  ;; Bootstrap Loader vector
1262
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
1263
 
1264
  ;; EBDA setup
1265
  call ebda_post
1266
 
1267
  ;; Video setup
1268
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
1269
 
1270
  mov  cx, #0xc000  ;; init vga bios
1271
  mov  ax, #0xc780
1272
  call rom_scan
1273
 
1274
  call _print_bios_banner
1275 34 zeus
hlt
1276 26 zeus
  call _init_boot_vectors
1277
 
1278
  mov  cx, #0xc800  ;; init option roms
1279
  mov  ax, #0xe000
1280
  call rom_scan
1281
 
1282
  sti        ;; enable interrupts
1283
  int  #0x19
1284
 
1285
;----------
1286
;- INT19h -
1287
;----------
1288
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
1289
int19_handler:
1290
 
1291
  jmp int19_relocated
1292
 
1293
.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
1294
  ;; HALT(__LINE__)
1295
  iret
1296
 
1297
;----------
1298
;- INT10h -
1299
;----------
1300
.org 0xf065 ; INT 10h Video Support Service Entry Point
1301
int10_handler:
1302
  ;; dont do anything, since the VGA BIOS handles int10h requests
1303
  iret
1304
 
1305
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
1306
 
1307
;------------------------------------------------
1308
;- IRET Instruction for Dummy Interrupt Handler -
1309
;------------------------------------------------
1310
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
1311
dummy_iret_handler:
1312
  iret
1313
 
1314
.org 0xfff0 ; Power-up Entry Point
1315
  jmp 0xf000:post
1316
 
1317
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
1318
.ascii BIOS_BUILD_DATE
1319
 
1320
.org 0xfffe ; System Model ID
1321
db SYS_MODEL_ID
1322
db 0x00   ; filler
1323
ASM_END
1324
 
1325
ASM_START
1326
.org 0xcc00
1327
bios_table_area_end:
1328
// bcc-generated data will be placed here
1329
ASM_END

powered by: WebSVN 2.1.0

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