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

Subversion Repositories zet86

[/] [zet86/] [trunk/] [soc/] [bios/] [rombios.c] - Diff between revs 27 and 34

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 27 Rev 34
// ROM BIOS compatability entry points:
// ROM BIOS compatability entry points:
// ===================================
// ===================================
// $e05b ; POST Entry Point
// $e05b ; POST Entry Point
// $e6f2 ; INT 19h Boot Load Service Entry Point
// $e6f2 ; INT 19h Boot Load Service Entry Point
// $f045 ; INT 10 Functions 0-Fh Entry Point
// $f045 ; INT 10 Functions 0-Fh Entry Point
// $f065 ; INT 10h Video Support Service Entry Point
// $f065 ; INT 10h Video Support Service Entry Point
// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
// $f0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
// $fff0 ; Power-up Entry Point
// $fff0 ; Power-up Entry Point
// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
// $fff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
// $fffe ; System Model ID
// $fffe ; System Model ID
 
 
#include "rombios.h"
#include "rombios.h"
 
 
   /* model byte 0xFC = AT */
   /* model byte 0xFC = AT */
#define SYS_MODEL_ID     0xFC
#define SYS_MODEL_ID     0xFC
 
 
#ifndef BIOS_BUILD_DATE
#ifndef BIOS_BUILD_DATE
#  define BIOS_BUILD_DATE "06/23/99"
#  define BIOS_BUILD_DATE "06/23/99"
#endif
#endif
 
 
  // 1K of base memory used for Extended Bios Data Area (EBDA)
  // 1K of base memory used for Extended Bios Data Area (EBDA)
  // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
  // EBDA is used for PS/2 mouse support, and IDE BIOS, etc.
#define EBDA_SEG           0x9FC0
#define EBDA_SEG           0x9FC0
#define EBDA_SIZE          1              // In KiB
#define EBDA_SIZE          1              // In KiB
#define BASE_MEM_IN_K   (640 - EBDA_SIZE)
#define BASE_MEM_IN_K   (640 - EBDA_SIZE)
 
 
/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */
#define IPL_SEG              0x9ff0
#define IPL_SEG              0x9ff0
#define IPL_TABLE_OFFSET     0x0000
#define IPL_TABLE_OFFSET     0x0000
#define IPL_TABLE_ENTRIES    8
#define IPL_TABLE_ENTRIES    8
#define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
#define IPL_COUNT_OFFSET     0x0080  /* u16: number of valid table entries */
#define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
#define IPL_SEQUENCE_OFFSET  0x0082  /* u16: next boot device */
#define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
#define IPL_BOOTFIRST_OFFSET 0x0084  /* u16: user selected device */
#define IPL_SIZE             0xff
#define IPL_SIZE             0xff
#define IPL_TYPE_FLOPPY      0x01
#define IPL_TYPE_FLOPPY      0x01
#define IPL_TYPE_HARDDISK    0x02
#define IPL_TYPE_HARDDISK    0x02
#define IPL_TYPE_CDROM       0x03
#define IPL_TYPE_CDROM       0x03
#define IPL_TYPE_BEV         0x80
#define IPL_TYPE_BEV         0x80
 
 
// This is for compiling with gcc2 and gcc3
// This is for compiling with gcc2 and gcc3
#define ASM_START #asm
#define ASM_START #asm
#define ASM_END #endasm
#define ASM_END #endasm
 
 
ASM_START
ASM_START
.rom
.rom
 
 
.org 0x0000
.org 0x0000
 
 
use16 8086
use16 8086
 
 
MACRO SET_INT_VECTOR
MACRO SET_INT_VECTOR
  mov ax, ?3
  mov ax, ?3
  mov ?1*4, ax
  mov ?1*4, ax
  mov ax, ?2
  mov ax, ?2
  mov ?1*4+2, ax
  mov ?1*4+2, ax
MEND
MEND
 
 
ASM_END
ASM_END
 
 
typedef unsigned char  Bit8u;
typedef unsigned char  Bit8u;
typedef unsigned short Bit16u;
typedef unsigned short Bit16u;
typedef unsigned short bx_bool;
typedef unsigned short bx_bool;
typedef unsigned long  Bit32u;
typedef unsigned long  Bit32u;
 
 
 
 
  void memsetb(seg,offset,value,count);
  void memsetb(seg,offset,value,count);
  void memcpyb(dseg,doffset,sseg,soffset,count);
  void memcpyb(dseg,doffset,sseg,soffset,count);
  void memcpyd(dseg,doffset,sseg,soffset,count);
  void memcpyd(dseg,doffset,sseg,soffset,count);
 
 
  // memset of count bytes
  // memset of count bytes
    void
    void
  memsetb(seg,offset,value,count)
  memsetb(seg,offset,value,count)
    Bit16u seg;
    Bit16u seg;
    Bit16u offset;
    Bit16u offset;
    Bit16u value;
    Bit16u value;
    Bit16u count;
    Bit16u count;
  {
  {
  ASM_START
  ASM_START
    push bp
    push bp
    mov  bp, sp
    mov  bp, sp
 
 
      push ax
      push ax
      push cx
      push cx
      push es
      push es
      push di
      push di
 
 
      mov  cx, 10[bp] ; count
      mov  cx, 10[bp] ; count
      test cx, cx
      test cx, cx
      je   memsetb_end
      je   memsetb_end
      mov  ax, 4[bp] ; segment
      mov  ax, 4[bp] ; segment
      mov  es, ax
      mov  es, ax
      mov  ax, 6[bp] ; offset
      mov  ax, 6[bp] ; offset
      mov  di, ax
      mov  di, ax
      mov  al, 8[bp] ; value
      mov  al, 8[bp] ; value
      cld
      cld
      rep
      rep
       stosb
       stosb
 
 
  memsetb_end:
  memsetb_end:
      pop di
      pop di
      pop es
      pop es
      pop cx
      pop cx
      pop ax
      pop ax
 
 
    pop bp
    pop bp
  ASM_END
  ASM_END
  }
  }
 
 
  // memcpy of count bytes
  // memcpy of count bytes
    void
    void
  memcpyb(dseg,doffset,sseg,soffset,count)
  memcpyb(dseg,doffset,sseg,soffset,count)
    Bit16u dseg;
    Bit16u dseg;
    Bit16u doffset;
    Bit16u doffset;
    Bit16u sseg;
    Bit16u sseg;
    Bit16u soffset;
    Bit16u soffset;
    Bit16u count;
    Bit16u count;
  {
  {
  ASM_START
  ASM_START
    push bp
    push bp
    mov  bp, sp
    mov  bp, sp
 
 
      push ax
      push ax
      push cx
      push cx
      push es
      push es
      push di
      push di
      push ds
      push ds
      push si
      push si
 
 
      mov  cx, 12[bp] ; count
      mov  cx, 12[bp] ; count
      test cx, cx
      test cx, cx
      je   memcpyb_end
      je   memcpyb_end
      mov  ax, 4[bp] ; dsegment
      mov  ax, 4[bp] ; dsegment
      mov  es, ax
      mov  es, ax
      mov  ax, 6[bp] ; doffset
      mov  ax, 6[bp] ; doffset
      mov  di, ax
      mov  di, ax
      mov  ax, 8[bp] ; ssegment
      mov  ax, 8[bp] ; ssegment
      mov  ds, ax
      mov  ds, ax
      mov  ax, 10[bp] ; soffset
      mov  ax, 10[bp] ; soffset
      mov  si, ax
      mov  si, ax
      cld
      cld
      rep
      rep
       movsb
       movsb
 
 
  memcpyb_end:
  memcpyb_end:
      pop si
      pop si
      pop ds
      pop ds
      pop di
      pop di
      pop es
      pop es
      pop cx
      pop cx
      pop ax
      pop ax
 
 
    pop bp
    pop bp
  ASM_END
  ASM_END
  }
  }
 
 
  // Bit32u (unsigned long) and long helper functions
  // Bit32u (unsigned long) and long helper functions
  ASM_START
  ASM_START
 
 
  idiv_u:
  idiv_u:
    xor dx,dx
    xor dx,dx
    div bx
    div bx
    ret
    ret
 
 
  ldivul:
  ldivul:
    mov     cx,[di]
    mov     cx,[di]
    mov     di,2[di]
    mov     di,2[di]
    call    ludivmod
    call    ludivmod
    xchg    ax,cx
    xchg    ax,cx
    xchg    bx,di
    xchg    bx,di
    ret
    ret
 
 
.align 2
.align 2
ldivmod:
ldivmod:
    mov     dx,di           ; sign byte of b in dh
    mov     dx,di           ; sign byte of b in dh
    mov     dl,bh           ; sign byte of a in dl
    mov     dl,bh           ; sign byte of a in dl
    test    di,di
    test    di,di
    jns     set_asign
    jns     set_asign
    neg     di
    neg     di
    neg     cx
    neg     cx
    sbb     di,*0
    sbb     di,*0
set_asign:
set_asign:
    test    bx,bx
    test    bx,bx
    jns     got_signs       ; leave r = a positive
    jns     got_signs       ; leave r = a positive
    neg     bx
    neg     bx
    neg     ax
    neg     ax
    sbb     bx,*0
    sbb     bx,*0
    j       got_signs
    j       got_signs
 
 
.align 2
.align 2
ludivmod:
ludivmod:
    xor     dx,dx           ; both sign bytes 0
    xor     dx,dx           ; both sign bytes 0
got_signs:
got_signs:
    push    bp
    push    bp
    push    si
    push    si
    mov     bp,sp
    mov     bp,sp
    push    di              ; remember b
    push    di              ; remember b
    push    cx
    push    cx
b0  =       -4
b0  =       -4
b16 =       -2
b16 =       -2
 
 
    test    di,di
    test    di,di
    jne     divlarge
    jne     divlarge
    test    cx,cx
    test    cx,cx
    je      divzero
    je      divzero
    cmp     bx,cx
    cmp     bx,cx
    jae     divlarge        ; would overflow
    jae     divlarge        ; would overflow
    xchg    dx,bx           ; a in dx:ax, signs in bx
    xchg    dx,bx           ; a in dx:ax, signs in bx
    div     cx
    div     cx
    xchg    cx,ax           ; q in di:cx, junk in ax
    xchg    cx,ax           ; q in di:cx, junk in ax
    xchg    ax,bx           ; signs in ax, junk in bx
    xchg    ax,bx           ; signs in ax, junk in bx
    xchg    ax,dx           ; r in ax, signs back in dx
    xchg    ax,dx           ; r in ax, signs back in dx
    mov     bx,di           ; r in bx:ax
    mov     bx,di           ; r in bx:ax
    j       zdivu1
    j       zdivu1
 
 
divzero:                        ; return q = 0 and r = a
divzero:                        ; return q = 0 and r = a
    test    dl,dl
    test    dl,dl
    jns     return
    jns     return
    j       negr            ; a initially minus, restore it
    j       negr            ; a initially minus, restore it
 
 
divlarge:
divlarge:
    push    dx              ; remember sign bytes
    push    dx              ; remember sign bytes
    mov     si,di           ; w in si:dx, initially b from di:cx
    mov     si,di           ; w in si:dx, initially b from di:cx
    mov     dx,cx
    mov     dx,cx
    xor     cx,cx           ; q in di:cx, initially 0
    xor     cx,cx           ; q in di:cx, initially 0
    mov     di,cx
    mov     di,cx
                            ; r in bx:ax, initially a
                            ; r in bx:ax, initially a
                            ; use di:cx rather than dx:cx in order
                            ; use di:cx rather than dx:cx in order
                            ; to have dx free for a byte pair later
                            ; to have dx free for a byte pair later
    cmp     si,bx
    cmp     si,bx
    jb      loop1
    jb      loop1
    ja      zdivu           ; finished if b > r
    ja      zdivu           ; finished if b > r
    cmp     dx,ax
    cmp     dx,ax
    ja      zdivu
    ja      zdivu
 
 
; rotate w (= b) to greatest dyadic multiple of b <= r
; rotate w (= b) to greatest dyadic multiple of b <= r
 
 
loop1:
loop1:
    shl     dx,*1           ; w = 2*w
    shl     dx,*1           ; w = 2*w
    rcl     si,*1
    rcl     si,*1
    jc      loop1_exit      ; w was > r counting overflow (unsigned)
    jc      loop1_exit      ; w was > r counting overflow (unsigned)
    cmp     si,bx           ; while w <= r (unsigned)
    cmp     si,bx           ; while w <= r (unsigned)
    jb      loop1
    jb      loop1
    ja      loop1_exit
    ja      loop1_exit
    cmp     dx,ax
    cmp     dx,ax
    jbe     loop1           ; else exit with carry clear for rcr
    jbe     loop1           ; else exit with carry clear for rcr
loop1_exit:
loop1_exit:
    rcr     si,*1
    rcr     si,*1
    rcr     dx,*1
    rcr     dx,*1
loop2:
loop2:
    shl     cx,*1           ; q = 2*q
    shl     cx,*1           ; q = 2*q
    rcl     di,*1
    rcl     di,*1
    cmp     si,bx           ; if w <= r
    cmp     si,bx           ; if w <= r
    jb      loop2_over
    jb      loop2_over
    ja      loop2_test
    ja      loop2_test
    cmp     dx,ax
    cmp     dx,ax
    ja      loop2_test
    ja      loop2_test
loop2_over:
loop2_over:
    add     cx,*1           ; q++
    add     cx,*1           ; q++
    adc     di,*0
    adc     di,*0
    sub     ax,dx           ; r = r-w
    sub     ax,dx           ; r = r-w
    sbb     bx,si
    sbb     bx,si
loop2_test:
loop2_test:
    shr     si,*1           ; w = w/2
    shr     si,*1           ; w = w/2
    rcr     dx,*1
    rcr     dx,*1
    cmp     si,b16[bp]      ; while w >= b
    cmp     si,b16[bp]      ; while w >= b
    ja      loop2
    ja      loop2
    jb      zdivu
    jb      zdivu
    cmp     dx,b0[bp]
    cmp     dx,b0[bp]
    jae     loop2
    jae     loop2
 
 
zdivu:
zdivu:
    pop     dx              ; sign bytes
    pop     dx              ; sign bytes
zdivu1:
zdivu1:
    test    dh,dh
    test    dh,dh
    js      zbminus
    js      zbminus
    test    dl,dl
    test    dl,dl
    jns     return          ; else a initially minus, b plus
    jns     return          ; else a initially minus, b plus
    mov     dx,ax           ; -a = b * q + r ==> a = b * (-q) + (-r)
    mov     dx,ax           ; -a = b * q + r ==> a = b * (-q) + (-r)
    or      dx,bx
    or      dx,bx
    je      negq            ; use if r = 0
    je      negq            ; use if r = 0
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b - r)
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b - r)
    sbb     bx,b16[bp]
    sbb     bx,b16[bp]
    not     cx              ; q = -1 - q (same as complement)
    not     cx              ; q = -1 - q (same as complement)
    not     di
    not     di
negr:
negr:
    neg     bx
    neg     bx
    neg     ax
    neg     ax
    sbb     bx,*0
    sbb     bx,*0
return:
return:
    mov     sp,bp
    mov     sp,bp
    pop     si
    pop     si
    pop     bp
    pop     bp
    ret
    ret
 
 
.align 2
.align 2
zbminus:
zbminus:
    test    dl,dl           ; (-a) = (-b) * q + r ==> a = b * q + (-r)
    test    dl,dl           ; (-a) = (-b) * q + r ==> a = b * q + (-r)
    js      negr            ; use if initial a was minus
    js      negr            ; use if initial a was minus
    mov     dx,ax           ; a = (-b) * q + r ==> a = b * (-q) + r
    mov     dx,ax           ; a = (-b) * q + r ==> a = b * (-q) + r
    or      dx,bx
    or      dx,bx
    je      negq            ; use if r = 0
    je      negq            ; use if r = 0
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b + r)
    sub     ax,b0[bp]       ; use a = b * (-1 - q) + (b + r)
                                ; (b is now -b)
                                ; (b is now -b)
    sbb     bx,b16[bp]
    sbb     bx,b16[bp]
    not     cx
    not     cx
    not     di
    not     di
    mov     sp,bp
    mov     sp,bp
    pop     si
    pop     si
    pop     bp
    pop     bp
    ret
    ret
 
 
.align 2
.align 2
negq:
negq:
    neg     di
    neg     di
    neg     cx
    neg     cx
    sbb     di,*0
    sbb     di,*0
    mov     sp,bp
    mov     sp,bp
    pop     si
    pop     si
    pop     bp
    pop     bp
    ret
    ret
 
 
.align 2
.align 2
ltstl:
ltstl:
ltstul:
ltstul:
    test    bx,bx
    test    bx,bx
    je      ltst_not_sure
    je      ltst_not_sure
    ret
    ret
 
 
.align 2
.align 2
ltst_not_sure:
ltst_not_sure:
    test    ax,ax
    test    ax,ax
    js      ltst_fix_sign
    js      ltst_fix_sign
    ret
    ret
 
 
.align 2
.align 2
ltst_fix_sign:
ltst_fix_sign:
    inc     bx
    inc     bx
    ret
    ret
 
 
.align 2
.align 2
lmull:
lmull:
lmulul:
lmulul:
    mov     cx,ax
    mov     cx,ax
    mul     word ptr 2[di]
    mul     word ptr 2[di]
    xchg    ax,bx
    xchg    ax,bx
    mul     word ptr [di]
    mul     word ptr [di]
    add     bx,ax
    add     bx,ax
    mov     ax,ptr [di]
    mov     ax,ptr [di]
    mul     cx
    mul     cx
    add     bx,dx
    add     bx,dx
    ret
    ret
 
 
.align 2
.align 2
lsubl:
lsubl:
lsubul:
lsubul:
    sub     ax,[di]
    sub     ax,[di]
    sbb     bx,2[di]
    sbb     bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
laddl:
laddl:
laddul:
laddul:
    add     ax,[di]
    add     ax,[di]
    adc     bx,2[di]
    adc     bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
lorl:
lorl:
lorul:
lorul:
    or      ax,[di]
    or      ax,[di]
    or      bx,2[di]
    or      bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
lsrul:
lsrul:
    mov     cx,di
    mov     cx,di
    jcxz    lsru_exit
    jcxz    lsru_exit
    cmp     cx,*32
    cmp     cx,*32
    jae     lsru_zero
    jae     lsru_zero
lsru_loop:
lsru_loop:
    shr     bx,*1
    shr     bx,*1
    rcr     ax,*1
    rcr     ax,*1
    loop    lsru_loop
    loop    lsru_loop
lsru_exit:
lsru_exit:
    ret
    ret
 
 
.align 2
.align 2
lsru_zero:
lsru_zero:
    xor     ax,ax
    xor     ax,ax
    mov     bx,ax
    mov     bx,ax
    ret
    ret
 
 
.align 2
.align 2
landl:
landl:
landul:
landul:
    and     ax,[di]
    and     ax,[di]
    and     bx,2[di]
    and     bx,2[di]
    ret
    ret
 
 
.align 2
.align 2
lcmpl:
lcmpl:
lcmpul:
lcmpul:
    sub     bx,2[di]
    sub     bx,2[di]
    je      lcmp_not_sure
    je      lcmp_not_sure
    ret
    ret
 
 
.align 2
.align 2
lcmp_not_sure:
lcmp_not_sure:
    cmp     ax,[di]
    cmp     ax,[di]
    jb      lcmp_b_and_lt
    jb      lcmp_b_and_lt
    jge     lcmp_exit
    jge     lcmp_exit
 
 
    inc     bx
    inc     bx
lcmp_exit:
lcmp_exit:
    ret
    ret
 
 
.align 2
.align 2
lcmp_b_and_lt:
lcmp_b_and_lt:
    dec     bx
    dec     bx
    ret
    ret
 
 
  ASM_END
  ASM_END
 
 
typedef struct {
typedef struct {
  Bit16u type;
  Bit16u type;
  Bit16u flags;
  Bit16u flags;
  Bit32u vector;
  Bit32u vector;
  Bit32u description;
  Bit32u description;
  Bit32u reserved;
  Bit32u reserved;
  } ipl_entry_t;
  } ipl_entry_t;
 
 
 
 
 
 
static Bit8u          inb_cmos();
static Bit8u          inb_cmos();
 
 
static Bit8u          read_byte();
static Bit8u          read_byte();
static Bit16u         read_word();
static Bit16u         read_word();
static void           write_byte();
static void           write_byte();
static void           write_word();
static void           write_word();
static void           bios_printf();
static void           bios_printf();
 
 
static void           int19_function();
static void           int19_function();
static Bit16u         get_CS();
static Bit16u         get_CS();
static Bit16u         get_SS();
static Bit16u         get_SS();
 
 
static void           print_bios_banner();
static void           print_bios_banner();
static void           print_boot_device();
static void           print_boot_device();
 
 
  Bit8u
  Bit8u
inb_cmos(cmos_reg)
inb_cmos(cmos_reg)
  Bit8u cmos_reg;
  Bit8u cmos_reg;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    mov  al, 4[bp] ;; cmos_reg
    mov  al, 4[bp] ;; cmos_reg
    out 0x70, al
    out 0x70, al
    in  al, 0x71
    in  al, 0x71
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  Bit8u
  Bit8u
read_byte(seg, offset)
read_byte(seg, offset)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  al, [bx]
    mov  al, [bx]
    ;; al = return value (byte)
    ;; al = return value (byte)
    pop  ds
    pop  ds
    pop  bx
    pop  bx
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  Bit16u
  Bit16u
read_word(seg, offset)
read_word(seg, offset)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  ax, [bx]
    mov  ax, [bx]
    ;; ax = return value (word)
    ;; ax = return value (word)
    pop  ds
    pop  ds
    pop  bx
    pop  bx
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  void
  void
write_byte(seg, offset, data)
write_byte(seg, offset, data)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
  Bit8u data;
  Bit8u data;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push ax
    push ax
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  al, 8[bp] ; data byte
    mov  al, 8[bp] ; data byte
    mov  [bx], al  ; write data byte
    mov  [bx], al  ; write data byte
    pop  ds
    pop  ds
    pop  bx
    pop  bx
    pop  ax
    pop  ax
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  void
  void
write_word(seg, offset, data)
write_word(seg, offset, data)
  Bit16u seg;
  Bit16u seg;
  Bit16u offset;
  Bit16u offset;
  Bit16u data;
  Bit16u data;
{
{
ASM_START
ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
    push ax
    push ax
    push bx
    push bx
    push ds
    push ds
    mov  ax, 4[bp] ; segment
    mov  ax, 4[bp] ; segment
    mov  ds, ax
    mov  ds, ax
    mov  bx, 6[bp] ; offset
    mov  bx, 6[bp] ; offset
    mov  ax, 8[bp] ; data word
    mov  ax, 8[bp] ; data word
    mov  [bx], ax  ; write data word
    mov  [bx], ax  ; write data word
    pop  ds
    pop  ds
    pop  bx
    pop  bx
    pop  ax
    pop  ax
 
 
  pop  bp
  pop  bp
ASM_END
ASM_END
}
}
 
 
  Bit16u
  Bit16u
get_CS()
get_CS()
{
{
ASM_START
ASM_START
  mov  ax, cs
  mov  ax, cs
ASM_END
ASM_END
}
}
 
 
  Bit16u
  Bit16u
get_SS()
get_SS()
{
{
ASM_START
ASM_START
  mov  ax, ss
  mov  ax, ss
ASM_END
ASM_END
}
}
 
 
  void
  void
wrch(c)
wrch(c)
  Bit8u  c;
  Bit8u  c;
{
{
  ASM_START
  ASM_START
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
  push bx
  push bx
  mov  ah, #0x0e
  mov  ah, #0x0e
  mov  al, 4[bp]
  mov  al, 4[bp]
  xor  bx,bx
  xor  bx,bx
  int  #0x10
  int  #0x10
  pop  bx
  pop  bx
 
 
  pop  bp
  pop  bp
  ASM_END
  ASM_END
}
}
 
 
  void
  void
send(action, c)
send(action, c)
  Bit16u action;
  Bit16u action;
  Bit8u  c;
  Bit8u  c;
{
{
  if (action & BIOS_PRINTF_SCREEN) {
  if (action & BIOS_PRINTF_SCREEN) {
    if (c == '\n') wrch('\r');
    if (c == '\n') wrch('\r');
    wrch(c);
    wrch(c);
  }
  }
}
}
 
 
  void
  void
put_int(action, val, width, neg)
put_int(action, val, width, neg)
  Bit16u action;
  Bit16u action;
  short val, width;
  short val, width;
  bx_bool neg;
  bx_bool neg;
{
{
  short nval = val / 10;
  short nval = val / 10;
  if (nval)
  if (nval)
    put_int(action, nval, width - 1, neg);
    put_int(action, nval, width - 1, neg);
  else {
  else {
    while (--width > 0) send(action, ' ');
    while (--width > 0) send(action, ' ');
    if (neg) send(action, '-');
    if (neg) send(action, '-');
  }
  }
  send(action, val - (nval * 10) + '0');
  send(action, val - (nval * 10) + '0');
}
}
 
 
  void
  void
put_uint(action, val, width, neg)
put_uint(action, val, width, neg)
  Bit16u action;
  Bit16u action;
  unsigned short val;
  unsigned short val;
  short width;
  short width;
  bx_bool neg;
  bx_bool neg;
{
{
  unsigned short nval = val / 10;
  unsigned short nval = val / 10;
  if (nval)
  if (nval)
    put_uint(action, nval, width - 1, neg);
    put_uint(action, nval, width - 1, neg);
  else {
  else {
    while (--width > 0) send(action, ' ');
    while (--width > 0) send(action, ' ');
    if (neg) send(action, '-');
    if (neg) send(action, '-');
  }
  }
  send(action, val - (nval * 10) + '0');
  send(action, val - (nval * 10) + '0');
}
}
 
 
  void
  void
put_luint(action, val, width, neg)
put_luint(action, val, width, neg)
  Bit16u action;
  Bit16u action;
  unsigned long val;
  unsigned long val;
  short width;
  short width;
  bx_bool neg;
  bx_bool neg;
{
{
  unsigned long nval = val / 10;
  unsigned long nval = val / 10;
  if (nval)
  if (nval)
    put_luint(action, nval, width - 1, neg);
    put_luint(action, nval, width - 1, neg);
  else {
  else {
    while (--width > 0) send(action, ' ');
    while (--width > 0) send(action, ' ');
    if (neg) send(action, '-');
    if (neg) send(action, '-');
  }
  }
  send(action, val - (nval * 10) + '0');
  send(action, val - (nval * 10) + '0');
}
}
 
 
void put_str(action, segment, offset)
void put_str(action, segment, offset)
  Bit16u action;
  Bit16u action;
  Bit16u segment;
  Bit16u segment;
  Bit16u offset;
  Bit16u offset;
{
{
  Bit8u c;
  Bit8u c;
 
 
  while (c = read_byte(segment, offset)) {
  while (c = read_byte(segment, offset)) {
    send(action, c);
    send(action, c);
    offset++;
    offset++;
  }
  }
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// bios_printf()
// bios_printf()
//   A compact variable argument printf function.
//   A compact variable argument printf function.
//
//
//   Supports %[format_width][length]format
//   Supports %[format_width][length]format
//   where format can be x,X,u,d,s,S,c
//   where format can be x,X,u,d,s,S,c
//   and the optional length modifier is l (ell)
//   and the optional length modifier is l (ell)
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
  void
  void
bios_printf(action, s)
bios_printf(action, s)
  Bit16u action;
  Bit16u action;
  Bit8u *s;
  Bit8u *s;
{
{
  Bit8u c, format_char;
  Bit8u c, format_char;
  bx_bool  in_format;
  bx_bool  in_format;
  short i;
  short i;
  Bit16u  *arg_ptr;
  Bit16u  *arg_ptr;
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
  Bit16u   arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd;
 
 
  arg_ptr = &s;
  arg_ptr = &s;
  arg_seg = get_SS();
  arg_seg = get_SS();
 
 
  in_format = 0;
  in_format = 0;
  format_width = 0;
  format_width = 0;
 
 
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
  if ((action & BIOS_PRINTF_DEBHALT) == BIOS_PRINTF_DEBHALT)
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
    bios_printf (BIOS_PRINTF_SCREEN, "FATAL: ");
 
 
  while (c = read_byte(get_CS(), s)) {
  while (c = read_byte(get_CS(), s)) {
    if ( c == '%' ) {
    if ( c == '%' ) {
      in_format = 1;
      in_format = 1;
      format_width = 0;
      format_width = 0;
      }
      }
    else if (in_format) {
    else if (in_format) {
      if ( (c>='0') && (c<='9') ) {
      if ( (c>='0') && (c<='9') ) {
        format_width = (format_width * 10) + (c - '0');
        format_width = (format_width * 10) + (c - '0');
        }
        }
      else {
      else {
        arg_ptr++; // increment to next arg
        arg_ptr++; // increment to next arg
        arg = read_word(arg_seg, arg_ptr);
        arg = read_word(arg_seg, arg_ptr);
        if (c == 'x' || c == 'X') {
        if (c == 'x' || c == 'X') {
          if (format_width == 0)
          if (format_width == 0)
            format_width = 4;
            format_width = 4;
          if (c == 'x')
          if (c == 'x')
            hexadd = 'a';
            hexadd = 'a';
          else
          else
            hexadd = 'A';
            hexadd = 'A';
          for (i=format_width-1; i>=0; i--) {
          for (i=format_width-1; i>=0; i--) {
            nibble = (arg >> (4 * i)) & 0x000f;
            nibble = (arg >> (4 * i)) & 0x000f;
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
            send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
            }
            }
          }
          }
        else if (c == 'u') {
        else if (c == 'u') {
          put_uint(action, arg, format_width, 0);
          put_uint(action, arg, format_width, 0);
          }
          }
        else if (c == 'l') {
        else if (c == 'l') {
          s++;
          s++;
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
          c = read_byte(get_CS(), s); /* is it ld,lx,lu? */
          arg_ptr++; /* increment to next arg */
          arg_ptr++; /* increment to next arg */
          hibyte = read_word(arg_seg, arg_ptr);
          hibyte = read_word(arg_seg, arg_ptr);
          if (c == 'd') {
          if (c == 'd') {
            if (hibyte & 0x8000)
            if (hibyte & 0x8000)
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
              put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1);
            else
            else
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
              put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
           }
           }
          else if (c == 'u') {
          else if (c == 'u') {
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
            put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0);
           }
           }
          else if (c == 'x' || c == 'X')
          else if (c == 'x' || c == 'X')
           {
           {
            if (format_width == 0)
            if (format_width == 0)
              format_width = 8;
              format_width = 8;
            if (c == 'x')
            if (c == 'x')
              hexadd = 'a';
              hexadd = 'a';
            else
            else
              hexadd = 'A';
              hexadd = 'A';
            for (i=format_width-1; i>=0; i--) {
            for (i=format_width-1; i>=0; i--) {
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
              nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f;
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
              send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd));
              }
              }
           }
           }
          }
          }
        else if (c == 'd') {
        else if (c == 'd') {
          if (arg & 0x8000)
          if (arg & 0x8000)
            put_int(action, -arg, format_width - 1, 1);
            put_int(action, -arg, format_width - 1, 1);
          else
          else
            put_int(action, arg, format_width, 0);
            put_int(action, arg, format_width, 0);
          }
          }
        else if (c == 's') {
        else if (c == 's') {
          put_str(action, get_CS(), arg);
          put_str(action, get_CS(), arg);
          }
          }
        else if (c == 'S') {
        else if (c == 'S') {
          hibyte = arg;
          hibyte = arg;
          arg_ptr++;
          arg_ptr++;
          arg = read_word(arg_seg, arg_ptr);
          arg = read_word(arg_seg, arg_ptr);
          put_str(action, hibyte, arg);
          put_str(action, hibyte, arg);
          }
          }
        else if (c == 'c') {
        else if (c == 'c') {
          send(action, arg);
          send(action, arg);
          }
          }
        else
        else
          BX_PANIC("bios_printf: unknown format\n");
          BX_PANIC("bios_printf: unknown format\n");
          in_format = 0;
          in_format = 0;
        }
        }
      }
      }
    else {
    else {
      send(action, c);
      send(action, c);
      }
      }
    s ++;
    s ++;
    }
    }
 
 
  if (action & BIOS_PRINTF_HALT) {
  if (action & BIOS_PRINTF_HALT) {
    // freeze in a busy loop.
    // freeze in a busy loop.
ASM_START
ASM_START
    cli
    cli
 halt2_loop:
 halt2_loop:
    hlt
    hlt
    jmp halt2_loop
    jmp halt2_loop
ASM_END
ASM_END
    }
    }
}
}
 
 
static char bios_svn_version_string[] = "$Revision: 1.2 $ $Date: 2008-10-04 23:11:53 $";
static char bios_svn_version_string[] = "$Revision: 1.3 $ $Date: 2008-10-13 00:24:30 $";
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// print_bios_banner
// print_bios_banner
//   displays a the bios version
//   displays a the bios version
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
void
void
print_bios_banner()
print_bios_banner()
{
{
  printf("Zet BIOS - build: %s\n%s\n",
  printf("Zet BIOS - build: %s\n%s\n",
    BIOS_BUILD_DATE, bios_svn_version_string);
    BIOS_BUILD_DATE, bios_svn_version_string);
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// BIOS Boot Specification 1.0.1 compatibility
// BIOS Boot Specification 1.0.1 compatibility
//
//
// Very basic support for the BIOS Boot Specification, which allows expansion
// Very basic support for the BIOS Boot Specification, which allows expansion
// ROMs to register themselves as boot devices, instead of just stealing the
// ROMs to register themselves as boot devices, instead of just stealing the
// INT 19h boot vector.
// INT 19h boot vector.
//
//
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
// This is a hack: to do it properly requires a proper PnP BIOS and we aren't
// one; we just lie to the option ROMs to make them behave correctly.
// one; we just lie to the option ROMs to make them behave correctly.
// We also don't support letting option ROMs register as bootable disk
// We also don't support letting option ROMs register as bootable disk
// drives (BCVs), only as bootable devices (BEVs).
// drives (BCVs), only as bootable devices (BEVs).
//
//
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
// http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
 
 
static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"};
 
 
static void
static void
init_boot_vectors()
init_boot_vectors()
{
{
  ipl_entry_t e;
  ipl_entry_t e;
  Bit16u count = 0;
  Bit16u count = 0;
  Bit16u ss = get_SS();
  Bit16u ss = get_SS();
 
 
  /* Clear out the IPL table. */
  /* Clear out the IPL table. */
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
  memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, IPL_SIZE);
 
 
  /* User selected device not set */
  /* User selected device not set */
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
  write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
 
 
  /*
  /*
   * Zet: We don't have support for floppy, hdd or cdrom
   * Zet: We don't have support for floppy, hdd or cdrom
   */
   */
 
 
  /* Remember how many devices we have */
  /* Remember how many devices we have */
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
  write_word(IPL_SEG, IPL_COUNT_OFFSET, count);
  /* Not tried booting anything yet */
  /* Not tried booting anything yet */
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
  write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff);
}
}
 
 
static Bit8u
static Bit8u
get_boot_vector(i, e)
get_boot_vector(i, e)
Bit16u i; ipl_entry_t *e;
Bit16u i; ipl_entry_t *e;
{
{
  Bit16u count;
  Bit16u count;
  Bit16u ss = get_SS();
  Bit16u ss = get_SS();
  /* Get the count of boot devices, and refuse to overrun the array */
  /* Get the count of boot devices, and refuse to overrun the array */
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
  count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
  if (i >= count) return 0;
  if (i >= count) return 0;
  /* OK to read this device */
  /* OK to read this device */
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
  memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e));
  return 1;
  return 1;
}
}
 
 
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// print_boot_device
// print_boot_device
//   displays the boot device
//   displays the boot device
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
 
 
void
void
print_boot_device(e)
print_boot_device(e)
  ipl_entry_t *e;
  ipl_entry_t *e;
{
{
  Bit16u type;
  Bit16u type;
  char description[33];
  char description[33];
  Bit16u ss = get_SS();
  Bit16u ss = get_SS();
  type = e->type;
  type = e->type;
  /* NIC appears as type 0x80 */
  /* NIC appears as type 0x80 */
  if (type == IPL_TYPE_BEV) type = 0x4;
  if (type == IPL_TYPE_BEV) type = 0x4;
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
  if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n");
  printf("Booting from %s", drivetypes[type]);
  printf("Booting from %s", drivetypes[type]);
  /* print product string if BEV */
  /* print product string if BEV */
  if (type == 4 && e->description != 0) {
  if (type == 4 && e->description != 0) {
    /* first 32 bytes are significant */
    /* first 32 bytes are significant */
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
    memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32);
    /* terminate string */
    /* terminate string */
    description[32] = 0;
    description[32] = 0;
    printf(" [%S]", ss, description);
    printf(" [%S]", ss, description);
  }
  }
  printf("...\n");
  printf("...\n");
}
}
 
 
void
void
int19_function(seq_nr)
int19_function(seq_nr)
Bit16u seq_nr;
Bit16u seq_nr;
{
{
  Bit16u ebda_seg=read_word(0x0040,0x000E);
  Bit16u ebda_seg=read_word(0x0040,0x000E);
  Bit16u bootdev;
  Bit16u bootdev;
  Bit8u  bootdrv;
  Bit8u  bootdrv;
  Bit8u  bootchk;
  Bit8u  bootchk;
  Bit16u bootseg;
  Bit16u bootseg;
  Bit16u bootip;
  Bit16u bootip;
  Bit16u status;
  Bit16u status;
  Bit16u bootfirst;
  Bit16u bootfirst;
 
 
  ipl_entry_t e;
  ipl_entry_t e;
 
 
  // Here we assume that BX_ELTORITO_BOOT is defined, so
  // Here we assume that BX_ELTORITO_BOOT is defined, so
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
  //   CMOS regs 0x3D and 0x38 contain the boot sequence:
  //     CMOS reg 0x3D & 0x0f : 1st boot device
  //     CMOS reg 0x3D & 0x0f : 1st boot device
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
  //     CMOS reg 0x3D & 0xf0 : 2nd boot device
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
  //     CMOS reg 0x38 & 0xf0 : 3rd boot device
  //   boot device codes:
  //   boot device codes:
  //     0x00 : not defined
  //     0x00 : not defined
  //     0x01 : first floppy
  //     0x01 : first floppy
  //     0x02 : first harddrive
  //     0x02 : first harddrive
  //     0x03 : first cdrom
  //     0x03 : first cdrom
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
  //     0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot)
  //     else : boot failure
  //     else : boot failure
 
 
  // Get the boot sequence
  // Get the boot sequence
  bootdev = inb_cmos(0x3d);
  bootdev = inb_cmos(0x3d);
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
  bootdev |= ((inb_cmos(0x38) & 0xf0) << 4);
  bootdev >>= 4 * seq_nr;
  bootdev >>= 4 * seq_nr;
  bootdev &= 0xf;
  bootdev &= 0xf;
 
 
  /* Read user selected device */
  /* Read user selected device */
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
  bootfirst = read_word(IPL_SEG, IPL_BOOTFIRST_OFFSET);
  if (bootfirst != 0xFFFF) {
  if (bootfirst != 0xFFFF) {
    bootdev = bootfirst;
    bootdev = bootfirst;
    /* User selected device not set */
    /* User selected device not set */
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
    write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, 0xFFFF);
    /* Reset boot sequence */
    /* Reset boot sequence */
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
    write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xFFFF);
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
  } else if (bootdev == 0) BX_PANIC("No bootable device.\n");
 
 
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
  /* Translate from CMOS runes to an IPL table offset by subtracting 1 */
  bootdev -= 1;
  bootdev -= 1;
 
 
  /* Read the boot device from the IPL table */
  /* Read the boot device from the IPL table */
  if (get_boot_vector(bootdev, &e) == 0) {
  if (get_boot_vector(bootdev, &e) == 0) {
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
    BX_INFO("Invalid boot device (0x%x)\n", bootdev);
    return;
    return;
  }
  }
 
 
  /* Do the loading, and set up vector as a far pointer to the boot
  /* Do the loading, and set up vector as a far pointer to the boot
   * address, and bootdrv as the boot drive */
   * address, and bootdrv as the boot drive */
  print_boot_device(&e);
  print_boot_device(&e);
 
 
  switch(e.type) {
  switch(e.type) {
  case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
  case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */
    bootseg = e.vector >> 16;
    bootseg = e.vector >> 16;
    bootip = e.vector & 0xffff;
    bootip = e.vector & 0xffff;
    break;
    break;
 
 
  default: return;
  default: return;
  }
  }
 
 
  /* Debugging info */
  /* Debugging info */
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
  BX_INFO("Booting from %x:%x\n", bootseg, bootip);
 
 
  /* Jump to the boot vector */
  /* Jump to the boot vector */
ASM_START
ASM_START
    mov  bp, sp
    mov  bp, sp
    ;; Build an iret stack frame that will take us to the boot vector.
    ;; Build an iret stack frame that will take us to the boot vector.
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
    ;; iret pops ip, then cs, then flags, so push them in the opposite order.
    pushf
    pushf
    mov  ax, _int19_function.bootseg + 0[bp]
    mov  ax, _int19_function.bootseg + 0[bp]
    push ax
    push ax
    mov  ax, _int19_function.bootip + 0[bp]
    mov  ax, _int19_function.bootip + 0[bp]
    push ax
    push ax
    ;; Set the magic number in ax and the boot drive in dl.
    ;; Set the magic number in ax and the boot drive in dl.
    mov  ax, #0xaa55
    mov  ax, #0xaa55
    mov  dl, _int19_function.bootdrv + 0[bp]
    mov  dl, _int19_function.bootdrv + 0[bp]
    ;; Zero some of the other registers.
    ;; Zero some of the other registers.
    xor  bx, bx
    xor  bx, bx
    mov  ds, bx
    mov  ds, bx
    mov  es, bx
    mov  es, bx
    mov  bp, bx
    mov  bp, bx
    ;; Go!
    ;; Go!
    iret
    iret
ASM_END
ASM_END
}
}
 
 
ASM_START
ASM_START
;----------
;----------
;- INT18h -
;- INT18h -
;----------
;----------
int18_handler: ;; Boot Failure recovery: try the next device.
int18_handler: ;; Boot Failure recovery: try the next device.
 
 
  ;; Reset SP and SS
  ;; Reset SP and SS
  mov  ax, #0xfffe
  mov  ax, #0xfffe
  mov  sp, ax
  mov  sp, ax
  xor  ax, ax
  xor  ax, ax
  mov  ss, ax
  mov  ss, ax
 
 
  ;; Get the boot sequence number out of the IPL memory
  ;; Get the boot sequence number out of the IPL memory
  mov  bx, #IPL_SEG
  mov  bx, #IPL_SEG
  mov  ds, bx                     ;; Set segment
  mov  ds, bx                     ;; Set segment
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
  mov  bx, IPL_SEQUENCE_OFFSET    ;; BX is now the sequence number
  inc  bx                         ;; ++
  inc  bx                         ;; ++
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
  mov  IPL_SEQUENCE_OFFSET, bx    ;; Write it back
  mov  ds, ax                     ;; and reset the segment to zero.
  mov  ds, ax                     ;; and reset the segment to zero.
 
 
  ;; Carry on in the INT 19h handler, using the new sequence number
  ;; Carry on in the INT 19h handler, using the new sequence number
  push bx
  push bx
 
 
  jmp  int19_next_boot
  jmp  int19_next_boot
 
 
;----------
;----------
;- INT19h -
;- INT19h -
;----------
;----------
int19_relocated: ;; Boot function, relocated
int19_relocated: ;; Boot function, relocated
 
 
  ;; int19 was beginning to be really complex, so now it
  ;; int19 was beginning to be really complex, so now it
  ;; just calls a C function that does the work
  ;; just calls a C function that does the work
 
 
  push bp
  push bp
  mov  bp, sp
  mov  bp, sp
 
 
  ;; Reset SS and SP
  ;; Reset SS and SP
  mov  ax, #0xfffe
  mov  ax, #0xfffe
  mov  sp, ax
  mov  sp, ax
  xor  ax, ax
  xor  ax, ax
  mov  ss, ax
  mov  ss, ax
 
 
  ;; Start from the first boot device (0, in AX)
  ;; Start from the first boot device (0, in AX)
  mov  bx, #IPL_SEG
  mov  bx, #IPL_SEG
  mov  ds, bx                     ;; Set segment to write to the IPL memory
  mov  ds, bx                     ;; Set segment to write to the IPL memory
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
  mov  IPL_SEQUENCE_OFFSET, ax    ;; Save the sequence number
  mov  ds, ax                     ;; and reset the segment.
  mov  ds, ax                     ;; and reset the segment.
 
 
  push ax
  push ax
 
 
int19_next_boot:
int19_next_boot:
 
 
  ;; Call the C code for the next boot device
  ;; Call the C code for the next boot device
  call _int19_function
  call _int19_function
 
 
  ;; Boot failed: invoke the boot recovery function
  ;; Boot failed: invoke the boot recovery function
  int  #0x18
  int  #0x18
 
 
;--------------------
;--------------------
;- POST: EBDA segment
;- POST: EBDA segment
;--------------------
;--------------------
; relocated here because the primary POST area isnt big enough.
; relocated here because the primary POST area isnt big enough.
ebda_post:
ebda_post:
  xor ax, ax            ; mov EBDA seg into 40E
  xor ax, ax            ; mov EBDA seg into 40E
  mov ds, ax
  mov ds, ax
  mov word ptr [0x40E], #EBDA_SEG
  mov word ptr [0x40E], #EBDA_SEG
  ret;;
  ret;;
 
 
rom_checksum:
rom_checksum:
  push ax
  push ax
  push bx
  push bx
  push cx
  push cx
  xor  ax, ax
  xor  ax, ax
  xor  bx, bx
  xor  bx, bx
  xor  cx, cx
  xor  cx, cx
  mov  ch, [2]
  mov  ch, [2]
  shl  cx, #1
  shl  cx, #1
checksum_loop:
checksum_loop:
  add  al, [bx]
  add  al, [bx]
  inc  bx
  inc  bx
  loop checksum_loop
  loop checksum_loop
  and  al, #0xff
  and  al, #0xff
  pop  cx
  pop  cx
  pop  bx
  pop  bx
  pop  ax
  pop  ax
  ret
  ret
 
 
 
 
;; We need a copy of this string, but we are not actually a PnP BIOS,
;; We need a copy of this string, but we are not actually a PnP BIOS,
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
;; so make sure it is *not* aligned, so OSes will not see it if they scan.
.align 16
.align 16
  db 0
  db 0
pnp_string:
pnp_string:
  .ascii "$PnP"
  .ascii "$PnP"
 
 
 
 
rom_scan:
rom_scan:
  ;; Scan for existence of valid expansion ROMS.
  ;; Scan for existence of valid expansion ROMS.
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
  ;;   Video ROM:   from 0xC0000..0xC7FFF in 2k increments
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
  ;;   General ROM: from 0xC8000..0xDFFFF in 2k increments
  ;;   System  ROM: only 0xE0000
  ;;   System  ROM: only 0xE0000
  ;;
  ;;
  ;; Header:
  ;; Header:
  ;;   Offset    Value
  ;;   Offset    Value
  ;;   0         0x55
  ;;   0         0x55
  ;;   1         0xAA
  ;;   1         0xAA
  ;;   2         ROM length in 512-byte blocks
  ;;   2         ROM length in 512-byte blocks
  ;;   3         ROM initialization entry point (FAR CALL)
  ;;   3         ROM initialization entry point (FAR CALL)
 
 
rom_scan_loop:
rom_scan_loop:
  push ax       ;; Save AX
  push ax       ;; Save AX
  mov  ds, cx
  mov  ds, cx
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
  mov  ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k
  cmp [0], #0xAA55 ;; look for signature
  cmp [0], #0xAA55 ;; look for signature
  jne  rom_scan_increment
  jne  rom_scan_increment
  call rom_checksum
  call rom_checksum
  jnz  rom_scan_increment
  jnz  rom_scan_increment
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
  mov  al, [2]  ;; change increment to ROM length in 512-byte blocks
 
 
  ;; We want our increment in 512-byte quantities, rounded to
  ;; We want our increment in 512-byte quantities, rounded to
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
  ;; the nearest 2k quantity, since we only scan at 2k intervals.
  test al, #0x03
  test al, #0x03
  jz   block_count_rounded
  jz   block_count_rounded
  and  al, #0xfc ;; needs rounding up
  and  al, #0xfc ;; needs rounding up
  add  al, #0x04
  add  al, #0x04
block_count_rounded:
block_count_rounded:
 
 
  xor  bx, bx   ;; Restore DS back to 0000:
  xor  bx, bx   ;; Restore DS back to 0000:
  mov  ds, bx
  mov  ds, bx
  push ax       ;; Save AX
  push ax       ;; Save AX
  push di       ;; Save DI
  push di       ;; Save DI
  ;; Push addr of ROM entry point
  ;; Push addr of ROM entry point
  push cx       ;; Push seg
  push cx       ;; Push seg
  push #0x0003  ;; Push offset
  ;; push #0x0003  ;; Push offset - not an 8086 valid operand
 
  mov ax, #0x0003
 
  push ax
 
 
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
  ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS.
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
  ;; That should stop it grabbing INT 19h; we will use its BEV instead.
  mov  ax, #0xf000
  mov  ax, #0xf000
  mov  es, ax
  mov  es, ax
  lea  di, pnp_string
  lea  di, pnp_string
 
 
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
  mov  bp, sp   ;; Call ROM init routine using seg:off on stack
  db   0xff     ;; call_far ss:[bp+0]
  db   0xff     ;; call_far ss:[bp+0]
  db   0x5e
  db   0x5e
  db   0
  db   0
  cli           ;; In case expansion ROM BIOS turns IF on
  cli           ;; In case expansion ROM BIOS turns IF on
  add  sp, #2   ;; Pop offset value
  add  sp, #2   ;; Pop offset value
  pop  cx       ;; Pop seg value (restore CX)
  pop  cx       ;; Pop seg value (restore CX)
 
 
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
  ;; Look at the ROM's PnP Expansion header.  Properly, we're supposed
  ;; to init all the ROMs and then go back and build an IPL table of
  ;; to init all the ROMs and then go back and build an IPL table of
  ;; all the bootable devices, but we can get away with one pass.
  ;; all the bootable devices, but we can get away with one pass.
  mov  ds, cx       ;; ROM base
  mov  ds, cx       ;; ROM base
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
  mov  bx, 0x001a   ;; 0x1A is the offset into ROM header that contains...
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
  mov  ax, [bx]     ;; the offset of PnP expansion header, where...
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
  cmp  ax, #0x5024  ;; we look for signature "$PnP"
  jne  no_bev
  jne  no_bev
  mov  ax, 2[bx]
  mov  ax, 2[bx]
  cmp  ax, #0x506e
  cmp  ax, #0x506e
  jne  no_bev
  jne  no_bev
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
  mov  ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of...
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
  cmp  ax, #0x0000  ;; the Bootstrap Entry Vector, or zero if there is none.
  je   no_bev
  je   no_bev
 
 
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
  ;; Found a device that thinks it can boot the system.  Record its BEV and product name string.
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
  mov  di, 0x10[bx]            ;; Pointer to the product name string or zero if none
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
  mov  bx, #IPL_SEG            ;; Go to the segment where the IPL table lives
  mov  ds, bx
  mov  ds, bx
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
  mov  bx, IPL_COUNT_OFFSET    ;; Read the number of entries so far
  cmp  bx, #IPL_TABLE_ENTRIES
  cmp  bx, #IPL_TABLE_ENTRIES
  je   no_bev                  ;; Get out if the table is full
  je   no_bev                  ;; Get out if the table is full
  push cx
  push cx
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
  mov  cx, #0x4                ;; Zet: Needed to be compatible with 8086
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
  shl  bx, cl                  ;; Turn count into offset (entries are 16 bytes)
  pop  cx
  pop  cx
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
  mov  0[bx], #IPL_TYPE_BEV    ;; This entry is a BEV device
  mov  6[bx], cx               ;; Build a far pointer from the segment...
  mov  6[bx], cx               ;; Build a far pointer from the segment...
  mov  4[bx], ax               ;; and the offset
  mov  4[bx], ax               ;; and the offset
  cmp  di, #0x0000
  cmp  di, #0x0000
  je   no_prod_str
  je   no_prod_str
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
  mov  0xA[bx], cx             ;; Build a far pointer from the segment...
  mov  8[bx], di               ;; and the offset
  mov  8[bx], di               ;; and the offset
no_prod_str:
no_prod_str:
  push cx
  push cx
  mov  cx, #0x4
  mov  cx, #0x4
  shr  bx, cl                  ;; Turn the offset back into a count
  shr  bx, cl                  ;; Turn the offset back into a count
  pop  cx
  pop  cx
  inc  bx                      ;; We have one more entry now
  inc  bx                      ;; We have one more entry now
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
  mov  IPL_COUNT_OFFSET, bx    ;; Remember that.
 
 
no_bev:
no_bev:
  pop  di       ;; Restore DI
  pop  di       ;; Restore DI
  pop  ax       ;; Restore AX
  pop  ax       ;; Restore AX
rom_scan_increment:
rom_scan_increment:
  push cx
  push cx
  mov  cx, #5
  mov  cx, #5
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
  shl  ax, cl   ;; convert 512-bytes blocks to 16-byte increments
                ;; because the segment selector is shifted left 4 bits.
                ;; because the segment selector is shifted left 4 bits.
  pop  cx
  pop  cx
  add  cx, ax
  add  cx, ax
  pop  ax       ;; Restore AX
  pop  ax       ;; Restore AX
  cmp  cx, ax
  cmp  cx, ax
  jbe  rom_scan_loop
  jbe  rom_scan_loop
 
 
  xor  ax, ax   ;; Restore DS back to 0000:
  xor  ax, ax   ;; Restore DS back to 0000:
  mov  ds, ax
  mov  ds, ax
  ret
  ret
 
 
;; for 'C' strings and other data, insert them here with
;; for 'C' strings and other data, insert them here with
;; a the following hack:
;; a the following hack:
;; DATA_SEG_DEFS_HERE
;; DATA_SEG_DEFS_HERE
 
 
 
 
;; the following area can be used to write dynamically generated tables
;; the following area can be used to write dynamically generated tables
  .align 16
  .align 16
bios_table_area_start:
bios_table_area_start:
  dd 0xaafb4442
  dd 0xaafb4442
  dd bios_table_area_end - bios_table_area_start - 8;
  dd bios_table_area_end - bios_table_area_start - 8;
 
 
;--------
;--------
;- POST -
;- POST -
;--------
;--------
.org 0xe05b ; POST Entry Point
.org 0xe05b ; POST Entry Point
post:
post:
 
 
  xor ax, ax
  xor ax, ax
 
 
normal_post:
normal_post:
  ; case 0: normal startup
  ; case 0: normal startup
 
 
  cli
  cli
  mov  ax, #0xfffe
  mov  ax, #0xfffe
  mov  sp, ax
  mov  sp, ax
  xor  ax, ax
  xor  ax, ax
  mov  ds, ax
  mov  ds, ax
  mov  ss, ax
  mov  ss, ax
 
 
  ;; zero out BIOS data area (40:00..40:ff)
  ;; zero out BIOS data area (40:00..40:ff)
  mov  es, ax
  mov  es, ax
  mov  cx, #0x0080 ;; 128 words
  mov  cx, #0x0080 ;; 128 words
  mov  di, #0x0400
  mov  di, #0x0400
  cld
  cld
  rep
  rep
    stosw
    stosw
 
 
  ;; set all interrupts to default handler
  ;; set all interrupts to default handler
  xor  bx, bx         ;; offset index
  xor  bx, bx         ;; offset index
  mov  cx, #0x0100    ;; counter (256 interrupts)
  mov  cx, #0x0100    ;; counter (256 interrupts)
  mov  ax, #dummy_iret_handler
  mov  ax, #dummy_iret_handler
  mov  dx, #0xF000
  mov  dx, #0xF000
 
 
post_default_ints:
post_default_ints:
  mov  [bx], ax
  mov  [bx], ax
  add  bx, #2
  add  bx, #2
  mov  [bx], dx
  mov  [bx], dx
  add  bx, #2
  add  bx, #2
  loop post_default_ints
  loop post_default_ints
 
 
  ;; set vector 0x79 to zero
  ;; set vector 0x79 to zero
  ;; this is used by 'gardian angel' protection system
  ;; this is used by 'gardian angel' protection system
  SET_INT_VECTOR(0x79, #0, #0)
  SET_INT_VECTOR(0x79, #0, #0)
 
 
  ;; base memory in K 40:13 (word)
  ;; base memory in K 40:13 (word)
  mov  ax, #BASE_MEM_IN_K
  mov  ax, #BASE_MEM_IN_K
  mov  0x0413, ax
  mov  0x0413, ax
 
 
 
 
  ;; Manufacturing Test 40:12
  ;; Manufacturing Test 40:12
  ;;   zerod out above
  ;;   zerod out above
 
 
  ;; Warm Boot Flag 0040:0072
  ;; Warm Boot Flag 0040:0072
  ;;   value of 1234h = skip memory checks
  ;;   value of 1234h = skip memory checks
  ;;   zerod out above
  ;;   zerod out above
 
 
  ;; Bootstrap failure vector
  ;; Bootstrap failure vector
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
  SET_INT_VECTOR(0x18, #0xF000, #int18_handler)
 
 
  ;; Bootstrap Loader vector
  ;; Bootstrap Loader vector
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
  SET_INT_VECTOR(0x19, #0xF000, #int19_handler)
 
 
  ;; EBDA setup
  ;; EBDA setup
  call ebda_post
  call ebda_post
 
 
  ;; Video setup
  ;; Video setup
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
  SET_INT_VECTOR(0x10, #0xF000, #int10_handler)
 
 
  mov  cx, #0xc000  ;; init vga bios
  mov  cx, #0xc000  ;; init vga bios
  mov  ax, #0xc780
  mov  ax, #0xc780
  call rom_scan
  call rom_scan
 
 
  call _print_bios_banner
  call _print_bios_banner
 
hlt
  call _init_boot_vectors
  call _init_boot_vectors
 
 
  mov  cx, #0xc800  ;; init option roms
  mov  cx, #0xc800  ;; init option roms
  mov  ax, #0xe000
  mov  ax, #0xe000
  call rom_scan
  call rom_scan
 
 
  sti        ;; enable interrupts
  sti        ;; enable interrupts
  int  #0x19
  int  #0x19
 
 
;----------
;----------
;- INT19h -
;- INT19h -
;----------
;----------
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
.org 0xe6f2 ; INT 19h Boot Load Service Entry Point
int19_handler:
int19_handler:
 
 
  jmp int19_relocated
  jmp int19_relocated
 
 
.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
.org 0xf045 ; INT 10 Functions 0-Fh Entry Point
  ;; HALT(__LINE__)
  ;; HALT(__LINE__)
  iret
  iret
 
 
;----------
;----------
;- INT10h -
;- INT10h -
;----------
;----------
.org 0xf065 ; INT 10h Video Support Service Entry Point
.org 0xf065 ; INT 10h Video Support Service Entry Point
int10_handler:
int10_handler:
  ;; dont do anything, since the VGA BIOS handles int10h requests
  ;; dont do anything, since the VGA BIOS handles int10h requests
  iret
  iret
 
 
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
.org 0xf0a4 ; MDA/CGA Video Parameter Table (INT 1Dh)
 
 
;------------------------------------------------
;------------------------------------------------
;- IRET Instruction for Dummy Interrupt Handler -
;- IRET Instruction for Dummy Interrupt Handler -
;------------------------------------------------
;------------------------------------------------
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
dummy_iret_handler:
dummy_iret_handler:
  iret
  iret
 
 
.org 0xfff0 ; Power-up Entry Point
.org 0xfff0 ; Power-up Entry Point
  jmp 0xf000:post
  jmp 0xf000:post
 
 
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
.org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY
.ascii BIOS_BUILD_DATE
.ascii BIOS_BUILD_DATE
 
 
.org 0xfffe ; System Model ID
.org 0xfffe ; System Model ID
db SYS_MODEL_ID
db SYS_MODEL_ID
db 0x00   ; filler
db 0x00   ; filler
ASM_END
ASM_END
 
 
ASM_START
ASM_START
.org 0xcc00
.org 0xcc00
bios_table_area_end:
bios_table_area_end:
// bcc-generated data will be placed here
// bcc-generated data will be placed here
ASM_END
ASM_END
 
 

powered by: WebSVN 2.1.0

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