// 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
|
|
|