Line 419... |
Line 419... |
.align 2
|
.align 2
|
lcmp_b_and_lt:
|
lcmp_b_and_lt:
|
dec bx
|
dec bx
|
ret
|
ret
|
|
|
|
lincl:
|
|
lincul:
|
|
inc word ptr [bx]
|
|
je LINC_HIGH_WORD
|
|
ret
|
|
.even
|
|
LINC_HIGH_WORD:
|
|
inc word ptr 2[bx]
|
|
ret
|
|
|
ASM_END
|
ASM_END
|
|
|
// for access to RAM area which is used by interrupt vectors
|
// for access to RAM area which is used by interrupt vectors
|
// and BIOS Data Area
|
// and BIOS Data Area
|
|
|
Line 1012... |
Line 1022... |
jmp halt2_loop
|
jmp halt2_loop
|
ASM_END
|
ASM_END
|
}
|
}
|
}
|
}
|
|
|
static char bios_svn_version_string[] = "$Revision: 1.13 $ $Date: 2009-03-05 00:26:53 $";
|
static char bios_svn_version_string[] = "$Version: 0.4.3 $ $Date: Tue, 10 Mar 2009 21:02:08 +0100 $";
|
|
|
|
#define BIOS_COPYRIGHT_STRING "(c) 2009 Zeus Gomez Marmolejo and (c) 2002 MandrakeSoft S.A."
|
|
|
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
// print_bios_banner
|
// print_bios_banner
|
// displays a the bios version
|
// displays a the bios version
|
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
Line 1040... |
Line 1052... |
// 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[][20]={"", "Floppy flash image" };
|
static char drivetypes[][20]={"", "Floppy flash image", "Compact Flash" };
|
|
|
static void
|
static void
|
init_boot_vectors()
|
init_boot_vectors()
|
{
|
{
|
ipl_entry_t e;
|
ipl_entry_t e;
|
Line 1060... |
Line 1072... |
/* Floppy drive */
|
/* Floppy drive */
|
e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
|
e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
|
memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
|
memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
|
count++;
|
count++;
|
|
|
|
/* First HDD */
|
|
e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0;
|
|
memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e));
|
|
count++;
|
|
|
/* 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);
|
}
|
}
|
Line 1499... |
Line 1516... |
|
|
void
|
void
|
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
|
int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS)
|
Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
|
Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS;
|
{
|
{
|
|
Bit8u drive, num_sectors, sector, head, status;
|
|
Bit8u drive_map;
|
|
Bit8u n_drives;
|
|
Bit16u max_cylinder, cylinder;
|
|
Bit16u hd_cylinders;
|
|
Bit8u hd_heads, hd_sectors;
|
|
Bit8u sector_count;
|
|
Bit16u tempbx;
|
|
|
|
Bit32u log_sector;
|
|
|
write_byte(0x0040, 0x008e, 0); // clear completion flag
|
write_byte(0x0040, 0x008e, 0); // clear completion flag
|
|
|
|
/* at this point, DL is >= 0x80 to be passed from the floppy int13h
|
|
handler code */
|
|
/* check how many disks first (cmos reg 0x12), return an error if
|
|
drive not present */
|
|
drive_map = 1;
|
|
n_drives = 1;
|
|
|
|
if (!(drive_map & (1<<(GET_ELDL()&0x7f)))) { /* allow 0, 1, or 2 disks */
|
|
SET_AH(0x01);
|
|
SET_DISK_RET_STATUS(0x01);
|
|
SET_CF(); /* error occurred */
|
|
return;
|
|
}
|
|
|
switch (GET_AH()) {
|
switch (GET_AH()) {
|
|
|
|
case 0x00: /* disk controller reset */
|
|
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
set_diskette_ret_status(0);
|
|
set_diskette_current_cyl(0, 0); /* current cylinder, diskette 1 */
|
|
set_diskette_current_cyl(1, 0); /* current cylinder, diskette 2 */
|
|
CLEAR_CF(); /* successful */
|
|
return;
|
|
break;
|
|
|
|
case 0x01: /* read disk status */
|
|
status = read_byte(0x0040, 0x0074);
|
|
SET_AH(status);
|
|
SET_DISK_RET_STATUS(0);
|
|
/* set CF if error status read */
|
|
if (status) SET_CF();
|
|
else CLEAR_CF();
|
|
return;
|
|
break;
|
|
|
|
case 0x04: // verify disk sectors
|
|
case 0x02: // read disk sectors
|
|
drive = GET_ELDL();
|
|
|
|
// get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
|
|
// fixed geometry:
|
|
hd_cylinders = 993;
|
|
hd_heads = 16;
|
|
hd_sectors = 63;
|
|
|
|
num_sectors = GET_AL();
|
|
cylinder = (GET_CL() & 0x00c0) << 2 | GET_CH();
|
|
sector = (GET_CL() & 0x3f);
|
|
head = GET_DH();
|
|
|
|
if ( (cylinder >= hd_cylinders) ||
|
|
(sector > hd_sectors) ||
|
|
(head >= hd_heads) ) {
|
|
SET_AH(1);
|
|
SET_DISK_RET_STATUS(1);
|
|
SET_CF(); /* error occurred */
|
|
return;
|
|
}
|
|
|
|
if ( GET_AH() == 0x04 ) {
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
CLEAR_CF();
|
|
return;
|
|
}
|
|
|
|
log_sector = ((Bit32u)cylinder) * ((Bit32u)hd_heads) * ((Bit32u)hd_sectors)
|
|
+ ((Bit32u)head) * ((Bit32u)hd_sectors)
|
|
+ ((Bit32u)sector) - 1;
|
|
|
|
sector_count = 0;
|
|
tempbx = BX;
|
|
|
|
ASM_START
|
|
sti ;; enable higher priority interrupts
|
|
ASM_END
|
|
|
|
while (1) {
|
|
ASM_START
|
|
;; store temp bx in real DI register
|
|
push bp
|
|
mov bp, sp
|
|
mov di, _int13_harddisk.tempbx + 2 [bp]
|
|
pop bp
|
|
|
|
;; adjust if there will be an overrun
|
|
cmp di, #0xfe00
|
|
jbe i13_f02_no_adjust
|
|
i13_f02_adjust:
|
|
sub di, #0x0200 ; sub 512 bytes from offset
|
|
mov ax, es
|
|
add ax, #0x0020 ; add 512 to segment
|
|
mov es, ax
|
|
|
|
i13_f02_no_adjust:
|
|
; timeout = TIMEOUT;
|
|
mov cx, #0xffff
|
|
|
|
; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_CFCMDRDY))) timeout--;
|
|
mov dx, #0xe204
|
|
|
|
i13_f02_ace_statusl2:
|
|
in ax, dx
|
|
and ax, #0x100
|
|
loopz i13_f02_ace_statusl2
|
|
|
|
; if(timeout == 0) return 0;
|
|
cmp cx, #0
|
|
jnz i13_f02_success2
|
|
ASM_END
|
|
printf("i13_f02(1): Timeout\n");
|
|
ASM_START
|
|
jmp _int13_fail
|
|
|
|
i13_f02_success2:
|
|
; CSR_ACE_MLBAL = blocknr & 0x0000ffff;
|
|
push bp
|
|
mov bp, sp
|
|
mov ax, _int13_harddisk.log_sector + 2 [bp]
|
|
mov dx, #0xe210
|
|
out dx, ax
|
|
|
|
; CSR_ACE_MLBAH = (blocknr & 0x0fff0000) >> 16;
|
|
mov ax, _int13_harddisk.log_sector + 4 [bp]
|
|
mov dx, #0xe212
|
|
out dx, ax
|
|
pop bp
|
|
|
|
; CSR_ACE_SECCMD = ACE_SECCMD_READ|0x01;
|
|
mov ax, #0x0301
|
|
mov dx, #0xe214
|
|
out dx, ax
|
|
|
|
; CSR_ACE_CTLL |= ACE_CTLL_CFGRESET;
|
|
mov dx, #0xe218
|
|
in ax, dx
|
|
or ax, #0x0080
|
|
out dx, ax
|
|
|
|
; buffer_count = 16;
|
|
mov si, #16
|
|
|
|
; while(buffer_count > 0) {
|
|
i13_f02_cond_loop:
|
|
cmp si, #0
|
|
jbe i13_f02_exit_loop
|
|
|
|
; timeout = TIMEOUT;
|
|
mov cx, #0xffff
|
|
mov bx, #0x000f
|
|
|
|
; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_DATARDY))) timeout--;
|
|
mov dx, #0xe204
|
|
i13_f02_ace_statusl3:
|
|
in ax, dx
|
|
and ax, #0x20
|
|
loopz i13_f02_ace_statusl3
|
|
|
|
; if(timeout == 0) return 0;
|
|
cmp cx, #0
|
|
jnz i13_f02_success3
|
|
dec bx
|
|
mov cx, #0xffff
|
|
jne i13_f02_ace_statusl3
|
|
ASM_END
|
|
printf("i13_f02(2): Timeout\n");
|
|
ASM_START
|
|
jmp _int13_fail
|
|
|
|
i13_f02_success3:
|
|
; for(i=0;i<16;i++) {
|
|
mov cx, #16
|
|
; *bufw = CSR_ACE_DATA;
|
|
mov dx, #0xe240
|
|
i13_f02_ace_data:
|
|
in ax, dx
|
|
eseg
|
|
mov [di], ax
|
|
; bufw++;
|
|
add di, #2
|
|
; }
|
|
loop i13_f02_ace_data
|
|
|
|
; buffer_count--;
|
|
dec si
|
|
jmp i13_f02_cond_loop
|
|
|
|
; }
|
|
|
|
i13_f02_exit_loop:
|
|
; CSR_ACE_CTLL &= ~ACE_CTLL_CFGRESET;
|
|
mov dx, #0xe218
|
|
in ax, dx
|
|
and ax, #0xff7f
|
|
out dx, ax
|
|
|
|
i13_f02_done:
|
|
;; store real DI register back to temp bx
|
|
push bp
|
|
mov bp, sp
|
|
mov _int13_harddisk.tempbx + 2 [bp], di
|
|
pop bp
|
|
ASM_END
|
|
|
|
sector_count++;
|
|
log_sector++;
|
|
num_sectors--;
|
|
if (num_sectors) continue;
|
|
else break;
|
|
}
|
|
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
SET_AL(sector_count);
|
|
CLEAR_CF(); /* successful */
|
|
return;
|
|
break;
|
|
|
|
case 0x03: /* write disk sectors */
|
|
drive = GET_ELDL ();
|
|
|
|
// get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
|
|
// fixed geometry:
|
|
hd_cylinders = 993;
|
|
hd_heads = 16;
|
|
hd_sectors = 63;
|
|
|
|
num_sectors = GET_AL();
|
|
cylinder = GET_CH();
|
|
cylinder |= ( ((Bit16u) GET_CL()) << 2) & 0x300;
|
|
sector = (GET_CL() & 0x3f);
|
|
head = GET_DH();
|
|
|
|
if ( (cylinder >= hd_cylinders) ||
|
|
(sector > hd_sectors) ||
|
|
(head >= hd_heads) ) {
|
|
SET_AH( 1);
|
|
SET_DISK_RET_STATUS(1);
|
|
SET_CF(); /* error occurred */
|
|
return;
|
|
}
|
|
|
|
log_sector = ((Bit32u)cylinder) * ((Bit32u)hd_heads) * ((Bit32u)hd_sectors)
|
|
+ ((Bit32u)head) * ((Bit32u)hd_sectors)
|
|
+ ((Bit32u)sector) - 1;
|
|
|
|
sector_count = 0;
|
|
tempbx = BX;
|
|
|
|
ASM_START
|
|
sti ;; enable higher priority interrupts
|
|
ASM_END
|
|
|
|
while (1) {
|
|
ASM_START
|
|
;; store temp bx in real SI register
|
|
push bp
|
|
mov bp, sp
|
|
mov si, _int13_harddisk.tempbx + 2 [bp]
|
|
pop bp
|
|
|
|
;; adjust if there will be an overrun
|
|
cmp si, #0xfe00
|
|
jbe i13_f03_no_adjust
|
|
i13_f03_adjust:
|
|
sub si, #0x0200 ; sub 512 bytes from offset
|
|
mov ax, es
|
|
add ax, #0x0020 ; add 512 to segment
|
|
mov es, ax
|
|
|
|
i13_f03_no_adjust:
|
|
; timeout = TIMEOUT;
|
|
mov cx, #0xffff
|
|
|
|
; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_CFCMDRDY))) timeout--;
|
|
mov dx, #0xe204
|
|
|
|
i13_f03_ace_statusl2:
|
|
in ax, dx
|
|
and ax, #0x100
|
|
loopz i13_f03_ace_statusl2
|
|
|
|
; if(timeout == 0) return 0;
|
|
cmp cx, #0
|
|
jnz i13_f03_success2
|
|
ASM_END
|
|
printf("i13_f03(1): Timeout\n");
|
|
ASM_START
|
|
jmp _int13_fail
|
|
|
|
i13_f03_success2:
|
|
; CSR_ACE_MLBAL = blocknr & 0x0000ffff;
|
|
push bp
|
|
mov bp, sp
|
|
mov ax, _int13_harddisk.log_sector + 2 [bp]
|
|
mov dx, #0xe210
|
|
out dx, ax
|
|
|
|
; CSR_ACE_MLBAH = (blocknr & 0x0fff0000) >> 16;
|
|
mov ax, _int13_harddisk.log_sector + 4 [bp]
|
|
mov dx, #0xe212
|
|
out dx, ax
|
|
pop bp
|
|
|
|
; CSR_ACE_SECCMD = ACE_SECCMD_WRITE|0x01;
|
|
mov ax, #0x0401
|
|
mov dx, #0xe214
|
|
out dx, ax
|
|
|
|
; CSR_ACE_CTLL |= ACE_CTLL_CFGRESET;
|
|
mov dx, #0xe218
|
|
in ax, dx
|
|
or ax, #0x0080
|
|
out dx, ax
|
|
|
|
; buffer_count = 16;
|
|
mov di, #16
|
|
|
|
; while(buffer_count > 0) {
|
|
i13_f03_cond_loop:
|
|
cmp di, #0
|
|
jbe i13_f03_exit_loop
|
|
|
|
; timeout = TIMEOUT;
|
|
mov cx, #0xffff
|
|
mov bx, #0x000f
|
|
|
|
; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_DATARDY))) timeout--;
|
|
mov dx, #0xe204
|
|
i13_f03_ace_statusl3:
|
|
in ax, dx
|
|
and ax, #0x20
|
|
loopz i13_f03_ace_statusl3
|
|
|
|
; if(timeout == 0) return 0;
|
|
cmp cx, #0
|
|
jnz i13_f03_success3
|
|
dec bx
|
|
mov cx, #0xffff
|
|
jne i13_f03_ace_statusl3
|
|
ASM_END
|
|
printf("i13_f03(2): Timeout\n");
|
|
ASM_START
|
|
jmp _int13_fail
|
|
|
|
i13_f03_success3:
|
|
; for(i=0;i<16;i++) {
|
|
mov cx, #16
|
|
; *bufw = CSR_ACE_DATA;
|
|
mov dx, #0xe240
|
|
i13_f03_ace_data:
|
|
eseg
|
|
mov ax, [si]
|
|
out dx, ax
|
|
; bufw++;
|
|
add si, #2
|
|
; }
|
|
loop i13_f03_ace_data
|
|
|
|
; buffer_count--;
|
|
dec di
|
|
jmp i13_f03_cond_loop
|
|
|
|
; }
|
|
|
|
i13_f03_exit_loop:
|
|
; CSR_ACE_CTLL &= ~ACE_CTLL_CFGRESET;
|
|
mov dx, #0xe218
|
|
in ax, dx
|
|
and ax, #0xff7f
|
|
out dx, ax
|
|
|
|
i13_f03_done:
|
|
;; store real SI register back to temp bx
|
|
push bp
|
|
mov bp, sp
|
|
mov _int13_harddisk.tempbx + 2 [bp], si
|
|
pop bp
|
|
ASM_END
|
|
|
|
sector_count++;
|
|
log_sector++;
|
|
num_sectors--;
|
|
if (num_sectors) continue;
|
|
else break;
|
|
}
|
|
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
SET_AL(sector_count);
|
|
CLEAR_CF(); /* successful */
|
|
return;
|
|
break;
|
|
|
case 0x08:
|
case 0x08:
|
|
|
|
drive = GET_ELDL ();
|
|
|
|
// get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
|
|
// fixed geometry:
|
|
hd_cylinders = 993;
|
|
hd_heads = 16;
|
|
hd_sectors = 63;
|
|
|
|
max_cylinder = hd_cylinders - 2; /* 0 based */
|
SET_AL(0);
|
SET_AL(0);
|
SET_CH(0);
|
SET_CH(max_cylinder & 0xff);
|
SET_CL(0);
|
SET_CL(((max_cylinder >> 2) & 0xc0) | (hd_sectors & 0x3f));
|
SET_DH(0);
|
SET_DH(hd_heads - 1);
|
SET_DL(0); /* FIXME returns 0, 1, or n hard drives */
|
SET_DL(n_drives); /* returns 0, 1, or 2 hard drives */
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
CLEAR_CF(); /* successful */
|
|
|
// FIXME should set ES & DI
|
return;
|
|
break;
|
|
|
goto int13_fail;
|
case 0x09: /* initialize drive parameters */
|
|
case 0x0c: /* seek to specified cylinder */
|
|
case 0x0d: /* alternate disk reset */
|
|
case 0x10: /* check drive ready */
|
|
case 0x11: /* recalibrate */
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
CLEAR_CF(); /* successful */
|
|
return;
|
|
break;
|
|
|
|
case 0x14: /* controller internal diagnostic */
|
|
SET_AH(0);
|
|
SET_DISK_RET_STATUS(0);
|
|
CLEAR_CF(); /* successful */
|
|
SET_AL(0);
|
|
return;
|
|
break;
|
|
|
|
case 0x15: /* read disk drive size */
|
|
drive = GET_ELDL();
|
|
// get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors);
|
|
// fixed geometry:
|
|
hd_cylinders = 993;
|
|
hd_heads = 16;
|
|
hd_sectors = 63;
|
|
|
|
ASM_START
|
|
push bp
|
|
mov bp, sp
|
|
mov al, _int13_harddisk.hd_heads + 2 [bp]
|
|
mov ah, _int13_harddisk.hd_sectors + 2 [bp]
|
|
mul al, ah ;; ax = heads * sectors
|
|
mov bx, _int13_harddisk.hd_cylinders + 2 [bp]
|
|
dec bx ;; use (cylinders - 1) ???
|
|
mul ax, bx ;; dx:ax = (cylinders -1) * (heads * sectors)
|
|
;; now we need to move the 32bit result dx:ax to what the
|
|
;; BIOS wants which is cx:dx.
|
|
;; and then into CX:DX on the stack
|
|
mov _int13_harddisk.CX + 2 [bp], dx
|
|
mov _int13_harddisk.DX + 2 [bp], ax
|
|
pop bp
|
|
ASM_END
|
|
SET_AH(3); // hard disk accessible
|
|
SET_DISK_RET_STATUS(0); // ??? should this be 0
|
|
CLEAR_CF(); // successful
|
|
return;
|
break;
|
break;
|
|
|
default:
|
default:
|
BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
|
BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH());
|
goto int13_fail;
|
goto int13_fail;
|
break;
|
break;
|
}
|
}
|
|
ASM_START
|
|
_int13_fail:
|
|
ASM_END
|
int13_fail:
|
int13_fail:
|
SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
|
SET_AH(0x01); // defaults to invalid function in AH or invalid parameter
|
int13_fail_noah:
|
int13_fail_noah:
|
SET_DISK_RET_STATUS(GET_AH());
|
SET_DISK_RET_STATUS(GET_AH());
|
int13_fail_nostatus:
|
int13_fail_nostatus:
|
Line 1679... |
Line 2164... |
void
|
void
|
set_diskette_current_cyl(drive, cyl)
|
set_diskette_current_cyl(drive, cyl)
|
Bit8u drive;
|
Bit8u drive;
|
Bit8u cyl;
|
Bit8u cyl;
|
{
|
{
|
/* TEMP HACK: FOR MSDOS */
|
/* TEMP HACK: FOR MSDOS
|
if (drive > 1)
|
if (drive > 1)
|
drive = 1;
|
drive = 1; */
|
/* BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
|
/* BX_PANIC("set_diskette_current_cyl(): drive > 1\n"); */
|
write_byte(0x0040, 0x0094+drive, cyl);
|
write_byte(0x0040, 0x0094+drive, cyl);
|
}
|
}
|
|
|
void
|
void
|
Line 1723... |
Line 2208... |
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;
|
*/
|
*/
|
bootdev = 0x1;
|
bootdev = 0x2; // 1: flopy disk, 2: hard disk
|
|
|
/* 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;
|
Line 1910... |
Line 2395... |
call _int13_harddisk
|
call _int13_harddisk
|
; pop ax
|
; pop ax
|
; shl eax, #16
|
; shl eax, #16
|
|
|
int13_out:
|
int13_out:
|
|
;
|
|
; ZEUS HACK: put IF flag on.
|
|
; Seems that MS-DOS does a 'cli' before calling this
|
|
; but after int13 it doesn't set the interrupts back
|
|
;
|
|
mov bp, sp
|
|
mov ax, 24[bp] ; FLAGS location
|
|
or ax, #0x0200 ; IF on
|
|
mov 24[bp], ax
|
|
|
pop ds
|
pop ds
|
pop es
|
pop es
|
; popa ; we do this instead:
|
; popa ; we do this instead:
|
pop di
|
pop di
|
pop si
|
pop si
|
pop bp
|
pop bp
|
add sp, #2
|
add sp, #2
|
pop bx
|
pop bx
|
pop dx
|
pop dx
|
pop cx
|
pop cx
|
pop ax
|
pop ax
|
|
|
iret
|
iret
|
|
|
;----------
|
;----------
|
;- 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
|
|
|
;----------
|
;----------
|
;- INT1Ch -
|
;- INT1Ch -
|
;----------
|
;----------
|
int1c_handler: ;; User Timer Tick
|
int1c_handler: ;; User Timer Tick
|
iret
|
iret
|
|
|
|
;--------------------
|
|
;- POST: HARD DRIVE -
|
|
;--------------------
|
|
; relocated here because the primary POST area isnt big enough.
|
|
hard_drive_post:
|
|
// IRQ 14 = INT 76h
|
|
// INT 76h calls INT 15h function ax=9100
|
|
|
|
xor ax, ax
|
|
mov ds, ax
|
|
mov 0x0474, al /* hard disk status of last operation */
|
|
mov 0x0477, al /* hard disk port offset (XT only ???) */
|
|
mov 0x048c, al /* hard disk status register */
|
|
mov 0x048d, al /* hard disk error register */
|
|
mov 0x048e, al /* hard disk task complete flag */
|
|
mov al, #0x01
|
|
mov 0x0475, al /* hard disk number attached */
|
|
mov al, #0xc0
|
|
mov 0x0476, al /* hard disk control byte */
|
|
SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
|
|
SET_INT_VECTOR(0x76, #0xF000, #int76_handler)
|
|
|
|
;; Initialize the sysace controller
|
|
; CSR_ACE_BUSMODE = ACE_BUSMODE_16BIT;
|
|
mov dx, #0xe200
|
|
mov ax, #0x0001
|
|
out dx, ax
|
|
|
|
; if(!(CSR_ACE_STATUSL & ACE_STATUSL_CFDETECT)) return 0;
|
|
mov dx, #0xe204
|
|
in ax, dx
|
|
and ax, #0x0010
|
|
jne cf_detect
|
|
hlt ;; error
|
|
|
|
cf_detect:
|
|
; if((CSR_ACE_ERRORL != 0) || (CSR_ACE_ERRORH != 0)) return 0;
|
|
mov dx, #0xe208
|
|
in ax, dx
|
|
cmp ax, #0x0
|
|
jne error_l
|
|
mov dx, #0xe20a
|
|
in ax, dx
|
|
cmp ax, #0x0
|
|
je lock_req
|
|
error_l:
|
|
hlt
|
|
|
|
lock_req:
|
|
; CSR_ACE_CTLL |= ACE_CTLL_LOCKREQ;
|
|
mov dx, #0xe218
|
|
in ax, dx
|
|
or ax, #0x2
|
|
out dx, ax
|
|
|
|
; timeout = TIMEOUT;
|
|
mov cx, #0xffff
|
|
|
|
; while((timeout > 0) && (!(CSR_ACE_STATUSL & ACE_STATUSL_MPULOCK))) timeout--;
|
|
mov dx, #0xe204
|
|
ace_statusl:
|
|
in ax, dx
|
|
and ax, #0x2
|
|
loopz ace_statusl
|
|
|
|
; if(timeout == 0) return 0;
|
|
cmp cx, #0x0
|
|
jnz success
|
|
hlt ;; error obtaining lock
|
|
|
;--------------------
|
success:
|
;- POST: EBDA segment
|
ret
|
;--------------------
|
|
; relocated here because the primary POST area isnt big enough.
|
|
ebda_post:
|
;--------------------
|
xor ax, ax ; mov EBDA seg into 40E
|
;- POST: EBDA segment
|
mov ds, ax
|
;--------------------
|
mov word ptr [0x40E], #EBDA_SEG
|
; relocated here because the primary POST area isnt big enough.
|
ret;;
|
ebda_post:
|
|
xor ax, ax ; mov EBDA seg into 40E
|
|
mov ds, ax
|
|
mov word ptr [0x40E], #EBDA_SEG
|
|
ret;;
|
|
|
|
;--------------------
|
|
int76_handler:
|
|
;; record completion in BIOS task complete flag
|
|
push ax
|
|
push ds
|
|
mov ax, #0x0040
|
|
mov ds, ax
|
|
mov 0x008E, #0xff
|
|
; call eoi_both_pics
|
|
pop ds
|
|
pop ax
|
|
iret
|
|
|
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 - not an 8086 valid operand
|
;; push #0x0003 ;; Push offset - not an 8086 valid operand
|
mov ax, #0x0003
|
mov ax, #0x0003
|
push ax
|
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)
|
|
|
;; User Timer Tick vector
|
;; User Timer Tick vector
|
SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
|
SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler)
|
|
|
;; Memory Size Check vector
|
;; Memory Size Check vector
|
SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
|
SET_INT_VECTOR(0x12, #0xF000, #int12_handler)
|
|
|
;; Equipment Configuration Check vector
|
;; Equipment Configuration Check vector
|
SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
|
SET_INT_VECTOR(0x11, #0xF000, #int11_handler)
|
|
|
;; EBDA setup
|
;; EBDA setup
|
call ebda_post
|
call ebda_post
|
|
|
;; Keyboard
|
;; PIT setup
|
SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
|
SET_INT_VECTOR(0x08, #0xF000, #int08_handler)
|
SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
|
;; int 1C already points at dummy_iret_handler (above)
|
|
|
|
;; Keyboard
|
|
SET_INT_VECTOR(0x09, #0xF000, #int09_handler)
|
|
SET_INT_VECTOR(0x16, #0xF000, #int16_handler)
|
|
|
|
xor ax, ax
|
|
mov ds, ax
|
|
mov 0x0417, al /* keyboard shift flags, set 1 */
|
|
mov 0x0418, al /* keyboard shift flags, set 2 */
|
|
mov 0x0419, al /* keyboard alt-numpad work area */
|
|
mov 0x0471, al /* keyboard ctrl-break flag */
|
|
mov 0x0497, al /* keyboard status flags 4 */
|
|
mov al, #0x10
|
|
mov 0x0496, al /* keyboard status flags 3 */
|
|
|
|
/* keyboard head of buffer pointer */
|
|
mov bx, #0x001E
|
|
mov 0x041A, bx
|
|
|
|
/* keyboard end of buffer pointer */
|
|
mov 0x041C, bx
|
|
|
|
/* keyboard pointer to start of buffer */
|
|
mov bx, #0x001E
|
|
mov 0x0480, bx
|
|
|
|
/* keyboard pointer to end of buffer */
|
|
mov bx, #0x003E
|
|
mov 0x0482, bx
|
|
|
xor ax, ax
|
;; CMOS RTC
|
mov ds, ax
|
SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
|
mov 0x0417, al /* keyboard shift flags, set 1 */
|
|
mov 0x0418, al /* keyboard shift flags, set 2 */
|
|
mov 0x0419, al /* keyboard alt-numpad work area */
|
|
mov 0x0471, al /* keyboard ctrl-break flag */
|
|
mov 0x0497, al /* keyboard status flags 4 */
|
|
mov al, #0x10
|
|
mov 0x0496, al /* keyboard status flags 3 */
|
|
|
|
/* keyboard head of buffer pointer */
|
|
mov bx, #0x001E
|
|
mov 0x041A, bx
|
|
|
|
/* keyboard end of buffer pointer */
|
|
mov 0x041C, bx
|
|
|
|
/* keyboard pointer to start of buffer */
|
|
mov bx, #0x001E
|
|
mov 0x0480, bx
|
|
|
|
/* keyboard pointer to end of buffer */
|
|
mov bx, #0x003E
|
|
mov 0x0482, bx
|
|
|
|
;; CMOS RTC
|
|
SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler)
|
|
|
|
;; 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
|
|
|
;; Floppy setup
|
;;
|
SET_INT_VECTOR(0x13, #0xF000, #int13_handler)
|
;; Hard Drive setup
|
|
;;
|
|
call hard_drive_post
|
|
|
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
|
|
|
;-------------------------------------------
|
;-------------------------------------------
|
;- INT 13h Fixed Disk Services Entry Point -
|
;- INT 13h Fixed Disk Services Entry Point -
|
;-------------------------------------------
|
;-------------------------------------------
|
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
|
.org 0xe3fe ; INT 13h Fixed Disk Services Entry Point
|
int13_handler:
|
int13_handler:
|
//JMPL(int13_relocated)
|
//JMPL(int13_relocated)
|
jmp int13_relocated
|
jmp int13_relocated
|
|
|
.org 0xe401 ; Fixed Disk Parameter Table
|
.org 0xe401 ; Fixed Disk Parameter Table
|
|
|
;----------
|
;----------
|
;- 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
|
|
|
|
|
;----------------------------------------
|
;----------------------------------------
|
;- INT 16h Keyboard Service Entry Point -
|
;- INT 16h Keyboard Service Entry Point -
|
;----------------------------------------
|
;----------------------------------------
|
.org 0xe82e
|
.org 0xe82e
|
int16_handler:
|
int16_handler:
|
|
|
sti
|
sti
|
push ds
|
push ds
|
pushf
|
pushf
|
;pusha ; we do this instead:
|
;pusha ; we do this instead:
|
push ax
|
push ax
|
push cx
|
push cx
|
push dx
|
push dx
|
push bx
|
push bx
|
push sp
|
push sp
|
mov bx, sp
|
mov bx, sp
|
sseg
|
sseg
|
add [bx], #10
|
add [bx], #10
|
sseg
|
sseg
|
mov bx, [bx+2]
|
mov bx, [bx+2]
|
push bp
|
push bp
|
push si
|
push si
|
push di
|
push di
|
|
|
cmp ah, #0x00
|
cmp ah, #0x00
|
je int16_F00
|
je int16_F00
|
cmp ah, #0x10
|
cmp ah, #0x10
|
je int16_F00
|
je int16_F00
|
|
|
mov bx, #0xf000
|
mov bx, #0xf000
|
mov ds, bx
|
mov ds, bx
|
call _int16_function
|
call _int16_function
|
; popa ; we do this instead:
|
; popa ; we do this instead:
|
pop di
|
pop di
|
pop si
|
pop si
|
pop bp
|
pop bp
|
add sp, #2
|
add sp, #2
|
pop bx
|
pop bx
|
pop dx
|
pop dx
|
pop cx
|
pop cx
|
pop ax
|
pop ax
|
popf
|
popf
|
pop ds
|
pop ds
|
jz int16_zero_set
|
jz int16_zero_set
|
|
|
int16_zero_clear:
|
int16_zero_clear:
|
push bp
|
push bp
|
mov bp, sp
|
mov bp, sp
|
//SEG SS
|
//SEG SS
|
and BYTE [bp + 0x06], #0xbf
|
and BYTE [bp + 0x06], #0xbf
|
pop bp
|
pop bp
|
iret
|
iret
|
|
|
int16_zero_set:
|
int16_zero_set:
|
push bp
|
push bp
|
mov bp, sp
|
mov bp, sp
|
//SEG SS
|
//SEG SS
|
or BYTE [bp + 0x06], #0x40
|
or BYTE [bp + 0x06], #0x40
|
pop bp
|
pop bp
|
iret
|
iret
|
|
|
int16_F00:
|
int16_F00:
|
mov bx, #0x0040
|
mov bx, #0x0040
|
mov ds, bx
|
mov ds, bx
|
|
|
int16_wait_for_key:
|
int16_wait_for_key:
|
cli
|
cli
|
mov bx, 0x001a
|
mov bx, 0x001a
|
cmp bx, 0x001c
|
cmp bx, 0x001c
|
jne int16_key_found
|
jne int16_key_found
|
sti
|
sti
|
nop
|
nop
|
#if 0
|
#if 0
|
/* no key yet, call int 15h, function AX=9002 */
|
/* no key yet, call int 15h, function AX=9002 */
|
0x50, /* push AX */
|
0x50, /* push AX */
|
0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
|
0xb8, 0x02, 0x90, /* mov AX, #0x9002 */
|
0xcd, 0x15, /* int 15h */
|
0xcd, 0x15, /* int 15h */
|
0x58, /* pop AX */
|
0x58, /* pop AX */
|
0xeb, 0xea, /* jmp WAIT_FOR_KEY */
|
0xeb, 0xea, /* jmp WAIT_FOR_KEY */
|
#endif
|
#endif
|
jmp int16_wait_for_key
|
jmp int16_wait_for_key
|
|
|
int16_key_found:
|
int16_key_found:
|
mov bx, #0xf000
|
mov bx, #0xf000
|
mov ds, bx
|
mov ds, bx
|
call _int16_function
|
call _int16_function
|
; popa ; we do this instead:
|
; popa ; we do this instead:
|
pop di
|
pop di
|
pop si
|
pop si
|
pop bp
|
pop bp
|
add sp, #2
|
add sp, #2
|
pop bx
|
pop bx
|
pop dx
|
pop dx
|
pop cx
|
pop cx
|
pop ax
|
pop ax
|
popf
|
popf
|
pop ds
|
pop ds
|
#if 0
|
#if 0
|
/* notify int16 complete w/ int 15h, function AX=9102 */
|
/* notify int16 complete w/ int 15h, function AX=9102 */
|
0x50, /* push AX */
|
0x50, /* push AX */
|
0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
|
0xb8, 0x02, 0x91, /* mov AX, #0x9102 */
|
0xcd, 0x15, /* int 15h */
|
0xcd, 0x15, /* int 15h */
|
0x58, /* pop AX */
|
0x58, /* pop AX */
|
#endif
|
#endif
|
iret
|
iret
|
|
|
|
|
|
|
;-------------------------------------------------
|
;-------------------------------------------------
|
;- INT09h : Keyboard Hardware Service Entry Point -
|
;- INT09h : Keyboard Hardware Service Entry Point -
|
;-------------------------------------------------
|
;-------------------------------------------------
|
.org 0xe987
|
.org 0xe987
|
int09_handler:
|
int09_handler:
|
cli
|
cli
|
push ax
|
push ax
|
in al, #0x60 ;;read key from keyboard controller
|
in al, #0x60 ;;read key from keyboard controller
|
sti
|
sti
|
|
|
push ds
|
push ds
|
;pusha ; we do this instead:
|
;pusha ; we do this instead:
|
|
|
push ax
|
push ax
|
push cx
|
push cx
|
push dx
|
push dx
|
push bx
|
push bx
|
push sp
|
push sp
|
mov bx, sp
|
mov bx, sp
|
sseg
|
sseg
|
add [bx], #10
|
add [bx], #10
|
sseg
|
sseg
|
mov bx, [bx+2]
|
mov bx, [bx+2]
|
push bp
|
push bp
|
push si
|
push si
|
push di
|
push di
|
|
|
;; check for extended key
|
;; check for extended key
|
cmp al, #0xe0
|
cmp al, #0xe0
|
jne int09_check_pause
|
jne int09_check_pause
|
xor ax, ax
|
xor ax, ax
|
mov ds, ax
|
mov ds, ax
|
mov al, BYTE [0x496] ;; mf2_state |= 0x02
|
mov al, BYTE [0x496] ;; mf2_state |= 0x02
|
or al, #0x02
|
or al, #0x02
|
mov BYTE [0x496], al
|
mov BYTE [0x496], al
|
jmp int09_done
|
jmp int09_done
|
|
|
int09_check_pause: ;; check for pause key
|
int09_check_pause: ;; check for pause key
|
cmp al, #0xe1
|
cmp al, #0xe1
|
jne int09_process_key
|
jne int09_process_key
|
xor ax, ax
|
xor ax, ax
|
mov ds, ax
|
mov ds, ax
|
mov al, BYTE [0x496] ;; mf2_state |= 0x01
|
mov al, BYTE [0x496] ;; mf2_state |= 0x01
|
or al, #0x01
|
or al, #0x01
|
mov BYTE [0x496], al
|
mov BYTE [0x496], al
|
jmp int09_done
|
jmp int09_done
|
|
|
int09_process_key:
|
int09_process_key:
|
mov bx, #0xf000
|
mov bx, #0xf000
|
mov ds, bx
|
mov ds, bx
|
call _int09_function
|
call _int09_function
|
int09_done:
|
int09_done:
|
; popa ; we do this instead:
|
; popa ; we do this instead:
|
pop di
|
pop di
|
pop si
|
pop si
|
pop bp
|
pop bp
|
add sp, #2
|
add sp, #2
|
pop bx
|
pop bx
|
pop dx
|
pop dx
|
pop cx
|
pop cx
|
pop ax
|
pop ax
|
|
|
Line 2473... |
Line 3061... |
cli
|
cli
|
pop ax
|
pop ax
|
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)
|
|
|
;----------
|
;----------
|
;- INT12h -
|
;- INT12h -
|
;----------
|
;----------
|
.org 0xf841 ; INT 12h Memory Size Service Entry Point
|
.org 0xf841 ; INT 12h Memory Size Service Entry Point
|
; ??? different for Pentium (machine check)?
|
; ??? different for Pentium (machine check)?
|
int12_handler:
|
int12_handler:
|
push ds
|
push ds
|
mov ax, #0x0040
|
mov ax, #0x0040
|
mov ds, ax
|
mov ds, ax
|
mov ax, 0x0013
|
mov ax, 0x0013
|
pop ds
|
pop ds
|
iret
|
iret
|
|
|
;----------
|
;----------
|
;- INT11h -
|
;- INT11h -
|
;----------
|
;----------
|
.org 0xf84d ; INT 11h Equipment List Service Entry Point
|
.org 0xf84d ; INT 11h Equipment List Service Entry Point
|
int11_handler:
|
int11_handler:
|
push ds
|
push ds
|
mov ax, #0x0040
|
mov ax, #0x0040
|
mov ds, ax
|
mov ds, ax
|
mov ax, 0x0010
|
mov ax, 0x0010
|
pop ds
|
pop ds
|
iret
|
iret
|
|
|
;----------
|
;----------
|
;- INT1Ah -
|
;- INT1Ah -
|
;----------
|
;----------
|
.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
|
.org 0xfe6e ; INT 1Ah Time-of-day Service Entry Point
|
int1a_handler:
|
int1a_handler:
|
push ds
|
push ds
|
;pusha ; we do this instead:
|
;pusha ; we do this instead:
|
push ax
|
push ax
|
push cx
|
push cx
|
push dx
|
push dx
|
push bx
|
push bx
|
push sp
|
push sp
|
mov bx, sp
|
mov bx, sp
|
sseg
|
sseg
|
add [bx], #10
|
add [bx], #10
|
sseg
|
sseg
|
mov bx, [bx+2]
|
mov bx, [bx+2]
|
push bp
|
push bp
|
push si
|
push si
|
push di
|
push di
|
|
|
xor ax, ax
|
xor ax, ax
|
mov ds, ax
|
mov ds, ax
|
int1a_callfunction:
|
int1a_callfunction:
|
call _int1a_function
|
call _int1a_function
|
; popa ; we do this instead:
|
; popa ; we do this instead:
|
pop di
|
pop di
|
pop si
|
pop si
|
pop bp
|
pop bp
|
add sp, #2
|
add sp, #2
|
pop bx
|
pop bx
|
pop dx
|
pop dx
|
pop cx
|
pop cx
|
pop ax
|
pop ax
|
|
|
pop ds
|
pop ds
|
iret
|
iret
|
|
|
;------------------------------------------------
|
;---------
|
;- IRET Instruction for Dummy Interrupt Handler -
|
;- INT08 -
|
;------------------------------------------------
|
;---------
|
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
|
.org 0xfea5 ; INT 08h System Timer ISR Entry Point
|
dummy_iret_handler:
|
int08_handler:
|
|
sti
|
|
push ax
|
|
push bx
|
|
push ds
|
|
xor ax, ax
|
|
mov ds, ax
|
|
|
|
mov ax, 0x046c ;; get ticks dword
|
|
mov bx, 0x046e
|
|
inc ax
|
|
jne i08_linc_done
|
|
inc bx ;; inc high word
|
|
|
|
i08_linc_done:
|
|
push bx
|
|
;; compare eax to one days worth of timer ticks at 18.2 hz
|
|
sub bx, #0x0018
|
|
jne i08_lcmp_done
|
|
cmp ax, #0x00B0
|
|
jb i08_lcmp_b_and_lt
|
|
jge i08_lcmp_done
|
|
inc bx
|
|
jmp i08_lcmp_done
|
|
|
|
i08_lcmp_b_and_lt:
|
|
dec bx
|
|
|
|
i08_lcmp_done:
|
|
pop bx
|
|
jb int08_store_ticks
|
|
;; there has been a midnight rollover at this point
|
|
xor ax, ax ;; zero out counter
|
|
xor bx, bx
|
|
inc BYTE 0x0470 ;; increment rollover flag
|
|
|
|
int08_store_ticks:
|
|
mov 0x046c, ax ;; store new ticks dword
|
|
mov 0x046e, bx
|
|
;; chain to user timer tick INT #0x1c
|
|
//pushf
|
|
//;; call_ep [ds:loc]
|
|
//CALL_EP( 0x1c << 2 )
|
|
int #0x1c
|
|
cli
|
|
;; call eoi_master_pic
|
|
pop ds
|
|
pop bx
|
|
pop ax
|
|
iret
|
|
|
|
.org 0xfef3 ; Initial Interrupt Vector Offsets Loaded by POST
|
|
|
|
|
|
.org 0xff00
|
|
.ascii BIOS_COPYRIGHT_STRING
|
|
|
|
;------------------------------------------------
|
|
;- IRET Instruction for Dummy Interrupt Handler -
|
|
;------------------------------------------------
|
|
.org 0xff53 ; IRET Instruction for Dummy Interrupt Handler
|
|
dummy_iret_handler:
|
iret
|
iret
|
|
|
.org 0xfff0 ; Power-up Entry Point
|
.org 0xfff0 ; Power-up Entry Point
|
; hlt
|
; hlt
|
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
|
|
|
No newline at end of file
|
No newline at end of file
|
|
|
No newline at end of file
|
No newline at end of file
|