呵呵,94年我还上大学的时候玩过这个,是在我的386sx上。做了一个可以在引导时选择从哪个
分区引导或者隐藏哪个分区等等。后来想做个支持汉字的,用TC来写,但是紧接着就毕业
了,忙,没有下文啦:)。
不过主引导区程序的原理却很简单:BIOS启动后会读取硬盘的第一个扇区512字节到内存地
址0000:7200的位置,然后跳转到这个位置,引导程序开始执行。引导程序处须读出和分析
相对偏移01BE开始的引导区记录,每条记录16字节,一共四条。至于引导区记录的字段含
意,嘿嘿,我记不得了,你自己看着办吧。(可以拿Norton DiskEdit来分析一下,不难)
引导程序分析引导记录可以得到各个分区的起始扇区位置,引导程序必须将其中某个分区
的起始扇区内容512字节读到0000:7200位置,然后跳转到该位置,将控制权移交给该分区
的引导程序。
下面贴出来的是很早以前写的代码,有一部份注释,可能有某些问题,可能不能编译运行。
因为代码正处在从纯汇编代码到汇编+C的改造过程中,是一个未完成的程序。
而最早完成的纯汇编的主引导程序的源程序找不到了:)。
++++++++++++++++++++++++++++++++++++++++++++++
概要:
一、引导时的内存分配情况:
地址范围 说明
0000:0000 - 0000:03ff 中断向量表
0000:0400 - 0000:7bff BIOS数据区
0000:7c00 - 0000:7dff 主引导程序被装载的位置
0000:7e00 - 空闲
8000:0000 - 8000:ffff 副引导程序被装载的位置
9000:0000 - 9000:ffff 堆栈
二、引导程序的程序头结构
1、 主引导程序
偏移量 长度 内容
0000 2 byte EB01, 一个短转移指令
0002 1 byte 副引导程序的长度(扇区数)
0003 443byte 主引导程序
01be 16 byte 第一分区信息
01ce 16 byte 第二分区信息
01de 16 byte 第三分区信息
01ee 16 byte 第四分区信息
01fe 2 byte 55AA, 引导程序有效标志
2、 副引导程序
偏移量 长度 内容
0000 1 word 副引导程序起始偏移
0002 ?? byte 副引导程序参数区
???? 16 byte 菜单标题内容
???? 32 byte 第一分区的菜单项
???? 32 byte 第二分区的菜单项
???? 32 byte 第三分区的菜单项
???? 32 byte 第四分区的菜单项
3、副引导程序参数区
0000 1 byte 菜单标题颜色
0001 1 byte 菜单边框颜色
0002 1 byte 菜单普通颜色
0003 1 byte 菜单加亮颜色
0004 6 byte 菜单边框字符串(LU,LR,BU,BR,H,V)
000C 1 byte 等待时限(秒),0 = 不等待
000D ?? byte 口令内容
???? 1 byte 缺省的引导分区,-1 = 无缺省引导分区
三、主引导程序的工作总述:
1、 汇编语言编程,要求简短,精致
2、 设置堆栈指针到 9000:fffe
3、 读副引导程序扇区到 8000:0000
5、 将ds设为8000
6、 根据 8000:0000中的程序起始偏移转向副引导程序
四、副引导程序的工作总述:
1、 C/C++编程,必要时用汇编语言进行优化,要求精炼且有较强的可扩
展性
2、 通过菜单选择当前的活动分区,并确定分区的可引导性(C/C++)
3、 如果活动分区被改变,则更新主引导扇区(ASM)
4、 判断当前活动分区的工作模式与CMOS工作模式是否一致,若不一致则
更新CMOS工作模式(ASM)
5、 读入活动分区的引导程序(ASM)
6、 转向分区引导程序(ASM)
五、副引导程序的可扩展性描述:
1、 引导时可设置DOS分区对DOS/Windows的可见性
2、 引导时可进行主引导区病毒的检查工作
3、 可选择在引导时驻留一个防病毒模块,以防止病毒对主引导程序的破坏
(分禁止引导柱面写,禁止主引导扇区写,仅允许写分区信息等方式)
六、安装程序总述:
1、 用C++ 编程力求有较强的可扩展性
2、 根据用户编辑的菜单设置文件配置引导菜单和分区工作模式
3、 将配置后的主引导程序和副引导程序写入引导柱面
七、安装程序的可扩展性描述:
1、 实现 FDISK的全部工作
2、 实现 DISKEDIT 的分区信息编辑工作
+++++++++++++++++++++++++++++++++
主引导程序Major.ASM,用Tasm编译,TLink连接
.286
MODEL tiny
NEED_BOOT_MENU EQU 00000001B
DO_BOOT_MENU EQU 00000010B
START_OFFSET EQU 7C00H
CODESEG
ORG START_OFFSET
start:
; force a near jump, only two bytes allowed.
jmp short begin
; this byte will be updated by install program, it's absolute offset
; must be 2.
minor_boot_sectors db 4
boot_flag db NEED_BOOT_MENU OR DO_BOOT_MENU
begin:
; set stack pointer to 9000h:ffffh
cli
mov sp,9000h
mov ss,sp
mov sp,0fffeh
sti
; let ds=cs
push cs
pop ds
; load minor boot program to 8000:0000
mov ah,2
mov al,[minor_boot_sectors]
mov bx,8000h
push bx
mov es,bx
xor bx,bx
mov cx,2
mov dx,80h
int 13h
jnc next_1
error_trap:
jmp error_trap
next_1:
; assume 8000:0000 = start offset pointer of minor boot program
; jump to minor boot program
xor bx,bx
mov ax,es:[bx]
push ax
retf
END start
+++++++++++++++++++++++++++++++++
实现C初始化代码的Minor_B.ASM,该程序调用C函数_main然后依据需要
更新分区表内容(允许用户在引导时修改分区表),并根据分区表活动
标志引导指定的分区。
.286
.MODEL tiny
LOCALS
;============================== struct definition ===========================
HD_NORMAL_MODE EQU 00000000B
HD_LBA_MODE EQU 00000100B
HD_LARGE_MODE EQU 00001000B
MENU_ITEM_SIZE EQU 32
NEED_BOOT_MENU EQU 00000001B
DO_BOOT_MENU EQU 00000010B
MAX_PASSWORD_SIZE EQU 8
MENU_OPTIONS STRUC
bg_color db 30h ; Background Color
t_color db 1Fh ; Title Color
f_color db 1Eh ; Frame Color
n_color db 17h ; Normal Color
h_color db 3Fh ; High Light Color
framechar db '谀烦涸图' ; Frame Character Set
; (TL,TH,TR,LV,RV,BL,BH,BR)
timeout db 0 ; Timeout (in second), 0 = no timeout
password db MAX_PASSWORD_SIZE dup(0) ; Password
default_choice db 0 ; Default Choice (current none)
MENU_OPTIONS ENDS
MENU_ITEM STRUC
cmos_mode db 0 ; CMOS Hard Disk Work Mode
menu_str db 31 dup(0) ; Menu String
MENU_ITEM ENDS
MENU_ARRAY STRUC
menu_0 MENU_ITEM <HD_LBA_MODE, 'Internet Port'>
menu_1 MENU_ITEM <HD_LBA_MODE, 'Work Shop'>
menu_2 MENU_ITEM <HD_LBA_MODE, 'Data Disk'>
menu_3 MENU_ITEM <HD_LBA_MODE, 'None'>
MENU_ARRAY ENDS
;================================ program start =============================
CODESEG
ORG 0
start_offset dw offset start
_menu_options MENU_OPTIONS <,,,,,,,'hello!',0>
_menu_title MENU_ITEM <0,'Boot Menu'>
_menu_array MENU_ARRAY <>
; address pointer of main boot record
mboot_ptr label dword
mboot_ofs dw 1beh
mboot_seg dw 7c0h
pboot_addr dw ?
dw ?
need_update dw 0
;================== minor boot program start up code begin ==================
start proc near
; cs=8000, ss:sp=9000:fffe
; let ds=cs
push cs
pop ds
IFDEF DEBUG
; load partition table for DEBUG
call load_partition
ENDIF
; test whether need boot menu
mov bx,[mboot_seg]
mov es,bx
mov bx,3
test byte ptr es:[bx],NEED_BOOT_MENU
jnz @@do_menu
test byte ptr es:[bx],DO_BOOT_MENU
jz @@skip_menu
or byte ptr es:[bx],NEED_BOOT_MENU
mov [need_update],1
jmp @@skip_menu
@@do_menu:
; choice active partition
call _main ; C 主函数,用于选择活动的分区,修改活动的分区等
@@skip_menu:
IFDEF DEBUG
; exit to dos
mov ax,4c00h
int 21h
start endp
ELSE
; update partition table
mov ax,[need_update]
or ax,ax
jz @@next_0
call update1
@@next_0:
; get last choice
call _last_choice
; adjust hard disk work mode
; ax=index of last choice
; es:bx=pointer of last active partition
mov si,offset _menu_array
mov cx,ax
@@loop_1:
jcxz @@next_1
add si,MENU_ITEM_SIZE
loop @@loop_1
@@next_1:
mov ah,[si] ; get current disk work mode
mov dx,70h ; index CMOS memory
mov al,3Bh
out dx,al
call sleep1 ; read CMOS set
inc dx
in al,dx
mov cl,al
and al,00001100B
cmp ah,al ; is the correct set ?
jz @@next_2
call sleep1 ; adjust CMOS set
mov al,cl
and al,11110011B
or al,ah
out dx,al
mov bx,[mboot_seg] ; disable menu in next time
mov es,bx
mov bx,3
and byte ptr es:[bx],NOT NEED_BOOT_MENU
call update1
xor ax,ax ; reboot again
mov es,ax
dec ax
push ax
push es
mov ax,1234h
mov [es:0472h],ax
retf
@@next_2:
; load partition boot program
; assume es:bx=last active partition
mov ax,0201h
mov dx,es:[bx]
mov cx,es:[bx+2]
; save partition startup sector address
mov bx,offset pboot_addr
mov [bx],dx
mov [bx+2],cx
xor bx,bx
int 13h
@@error_trap:
jc @@error_trap
; jump to partition boot program
mov si,offset pboot_addr
push 0
push 7c00h
retf
start endp
ENDIF
;================================ sub function ==============================
;----------------------------------------------------------------------------
; void load_partition(void);
; load_partition (for Assembler Call only)
;----------------------------------------------------------------------------
IFDEF DEBUG
load_partition proc near
mov ax,cs
add ax,2000h
mov es,ax
mov [mboot_seg],ax
mov ax,0201h
xor bx,bx
mov cx,1
mov dx,80h
int 13h
ret
load_partition endp
ENDIF
;----------------------------------------------------------------------------
; void sleep1(void);
; sleep (for Assembler Call only)
;----------------------------------------------------------------------------
IFNDEF DEBUG
sleep1 proc near
mov @@step,0
@@loop_1:
inc @@step
cmp @@step,10h
jc @@loop_1
ret
@@step db 0
sleep1 endp
ENDIF
;----------------------------------------------------------------------------
; void update1(void);
; update partition table to hard disk (for Assembler Call only)
;----------------------------------------------------------------------------
update1 proc near
IFNDEF DEBUG
; disable BIOS anti-virus options
mov ax,40h
mov es,ax
push es
mov bx,0DAh
push bx
mov al,es:[bx]
push ax
and al,7fh
mov es:[0DAh],al
; save partition table
mov ax,[mboot_seg]
mov es,ax
mov ax,0301h
xor bx,bx
mov cx,1
mov dx,80h
int 13h
; restore BIOS anti-virus options
pop ax
pop bx
pop es
mov es:[bx],al ; restore old anti-virus options
ENDIF
ret
update1 endp
;----------------------------------------------------------------------------
; int last_choice(void);
; analyse partition table, search active partition
; entry: none
; return: ax=index of last choice (for C/C++ Call)
; es:bx=pointer of last active partition (for Assembler Call)
;----------------------------------------------------------------------------
_last_choice proc near
les bx,[mboot_ptr]
mov dl,80h
mov ax,4
mov cx,ax
@@loop_1:
cmp dl,es:[bx] ; is active partition ?
jz @@next_1 ; yes, jump
add bx,10h ; check next
loop @@loop_1
mov cx,ax ; if not active partition found,
; default is 0
@@next_1:
sub ax,cx
ret
_last_choice endp
;----------------------------------------------------------------------------
; int _new_choice(int choice);
; update new choice, if choice was changed, save new choice to
; hard disk
; entry: new choice
; return: none;
;----------------------------------------------------------------------------
_new_choice proc near
ARG choice:word
push bp
mov bp,sp
les bx,[mboot_ptr]
mov ax,80h
mov cx,[choice]
and cl,3
; update new choice
@@loop_1:
cmp ch,cl ; is the new choice ?
jnz @@test_1 ; no, jump
cmp al,es:[bx] ; is it currently active ?
jz @@exit_1 ; yes, exit
mov es:[bx],al ; active it
@@next_1:
inc ch
cmp ch,4 ; search over ?
jge @@save_1 ; yes, save new choice
add bx,10h
jmp @@loop_1 ; loop
@@test_1:
cmp al,es:[bx] ; is a active partition ?
jnz @@next_1 ; no, next
mov es:[bx],ah ; disactive it
jmp @@next_1 ; next
@@save_1:
mov [need_update],1
@@exit_1:
pop bp
ret
_new_choice endp
;----------------------------------------------------------------------------
; int _last_type(int index);
; get partition type of specified partition item
; entry: index of specified partition item
; return: partition type
;----------------------------------------------------------------------------
_last_type proc near
ARG index:word
push bp
mov bp,sp
les bx,[mboot_ptr]
mov ax,[index]
and ax,3
shl ax,4
add bx,ax
mov al,es:[bx+4]
xor ah,ah
pop bp
ret
_last_type endp
;----------------------------------------------------------------------------
; void _new_type(int index,int newtype);
; set new partition type of specified partition item
; entry: index of specified partition item, new type
; return: none
;----------------------------------------------------------------------------
_new_type proc near
ARG index:word,newtype:word
push bp
mov bp,sp
les bx,[mboot_ptr]
mov ax,[index]
and ax,3
shl ax,4
add bx,ax
mov ax,[newtype]
cmp al,es:[bx+4]
jz @@next_1
mov es:[bx+4],al
mov [need_update],1
@@next_1:
pop bp
ret
_new_type endp
EXTRN _main:near
PUBLIC _menu_options
PUBLIC _menu_title
PUBLIC _menu_array
PUBLIC _last_choice
PUBLIC _new_choice
PUBLIC _last_type
PUBLIC _new_type
END start
+++++++++++++++++++++++++++
C主程序MBoot.C
#include "minor_b.h"
#include "conio.h"
#include "delay.h"
#include "mboot.h"
#define FALSE 0
#define TRUE !FALSE
#define LEFT 19
#define TOP 8
#define RIGHT 61
#define BOTTOM 13
#define PTYPES 28
#define BOOTABLES 11
#define ZHL_START 20
#define DELAY_TIMES 3000
byte ptype[PTYPES]=
{
P_UNUSED,
P_DOS12,
P_XENIX,
P_DOS16,
P_DOSEXT,
P_BIGDOS,
P_HPFS,
P_SPLIT,
P_FAT32,
P_DM,
P_GB,
P_SPEED,
P_386IX,
P_NOVELL286,
P_NOVELL386,
P_PCIX,
P_CPM,
P_BBT,
P_LINUXSWAP,
P_LINUX,
Z_DOS12,
Z_DOS16,
Z_BIGDOS,
Z_XENIX,
Z_386IX,
Z_FAT32,
Z_DOSEXT,
Z_LINUX
};
char *pname[PTYPES+1]=
{
"UNUSED ",
"DOS-12 ",
"XENIX ",
"DOS-16 ",
"DOSEXT ",
"BIGDOS ",
"NTFS ",
"SPLIT ",
"FAT32 ",
"DM ",
"GB ",
"SPEED ",
"UNIX ",
"NOVEL286 ",
"NOVEL386 ",
"PC/IX ",
"CP/M ",
"BBT ",
"LINUXSWAP",
"LINUX ",
"ZHLDOS12 ",
"ZHLDOS16 ",
"ZHLBIGDOS",
"ZHLXENIX ",
"ZHLUNIX ",
"ZHLFAT32 ",
"ZHLDOSEXT",
"ZHLLINUX ",
"UNKNOWN "
};
byte bootable[BOOTABLES]=
{
P_DOS12,
P_XENIX,
P_DOS16,
P_DOSEXT,
P_BIGDOS,
P_HPFS,
P_FAT32,
P_386IX,
P_LINUX,
P_PCIX,
P_CPM
};
int is_boot_able(int pt)
{
int i;
for(i=0;i<BOOTABLES;i++) if(bootable
==pt) return 1;
return 0;
}
int strncmp(char *s1, char *s2, int maxlen)
{
int i,j;
for(i=0;i<maxlen;i++)
{
if((j=s1-s2)!=0) break;
if(!s1) break;
}
return(j);
}
int check_password(void)
{
char passwd[9];
int i;
for(;
{
// If no password entered, then load default choice
puts("password:");
if(getpassword(passwd,MAX_PASSWORD_SIZE)==0)
{
i=menu_options.default_choice;
// if no default choice, halt system
if(i>3) for(puts("You can't use this system !");;
// if last choice is not default choice, and
// default choice is boot able partition then
if(last_choice()!=i && is_boot_able(i))
new_choice(menu_options.default_choice);
return FALSE;
};
// if password correct, return true
if(!strncmp(passwd,(char *)&menu_options.password,MAX_PASSWORD_SIZE))
return TRUE;
else
{
// wait and retry
puts("/nIncorrect password !/nWait for try again .../n");
delay(DELAY_TIMES);
}
}
}
void draw_menu_item(int col,int row,int maxcol,int idx)
{
int i,j;
j=last_type(idx);
for(i=0;i<PTYPES;i++) if(ptype==j) break;
gotoxy(col,row);
putch(' ',1);
if(i<ZHL_START)
putsxy(col+1,row,pname);
else
putsxy(col+1,row,"DISABLED ");
putch(' ',1);
putsxy(col+11,row,(char *)&menu_array[idx].menu_str);
i=wherex()-1;
if(maxcol>i) putch(' ',maxcol-i);
}
void main(void)
{
int i,j,key,last,menu_end;
// Initialize screen
initscr();
// Check password
if(menu_options.password[0])
if(!check_password()) return;
// Clear background screen
textattr=menu_options.bg_color;
clrbox(0,0,79,24);
// Draw menu B & menu title
textattr=menu_options.f_color;
drawbox(LEFT,TOP,RIGHT,BOTTOM,(char *)&menu_options.framechar);
textattr=menu_options.t_color;
putsxy(LEFT+2,TOP,(char *)&menu_title.menu_str);
textattr=menu_options.bg_color;
shadowbox(LEFT,TOP,RIGHT,BOTTOM);
// Draw menu item with normal color
textattr=menu_options.n_color;
for(i=0;i<4;i++) draw_menu_item(LEFT+1,TOP+1+i,RIGHT-1,i);
// Draw active menu item with high color
textattr=menu_options.h_color;
last=last_choice();
draw_menu_item(LEFT+1,TOP+1+last,RIGHT-1,last);
// Do menu choice
for(j=last,menu_end=0;!menu_end
{
i=j;
switch(key=getch())
{
case KEY_LEFT:
case KEY_UP: if(i>0) j=i-1; break;
case KEY_RIGHT:
case KEY_DOWN: if(i<3) j=i+1; break;
case KEY_CTRL_TAB:
{
j=i;i=4;
switch(last_type(j))
{
case P_DOS12:
new_type(j,Z_DOS12);break;
case P_DOS16:
new_type(j,Z_DOS16);break;
case P_DOSEXT:
new_type(j,Z_DOSEXT);break;
case P_BIGDOS:
new_type(j,Z_BIGDOS);break;
case P_XENIX:
new_type(j,Z_XENIX);break;
case P_386IX:
new_type(j,Z_386IX);break;
case P_FAT32:
new_type(j,Z_FAT32);break;
case P_LINUX:
new_type(j,Z_LINUX);break;
case Z_DOS12:
new_type(j,P_DOS12);break;
case Z_DOS16:
new_type(j,P_DOS16);break;
case Z_DOSEXT:
new_type(j,P_DOSEXT);break;
case Z_BIGDOS:
new_type(j,P_BIGDOS);break;
case Z_XENIX:
new_type(j,P_XENIX);break;
case Z_386IX:
new_type(j,P_386IX);break;
case Z_FAT32:
new_type(j,P_FAT32);break;
case Z_LINUX:
new_type(j,P_LINUX);break;
default:
i=j;
}
if(i!=j)
{
textattr=menu_options.h_color;
draw_menu_item(LEFT+1,TOP+1+j,RIGHT-1,j);
i=j;
}
} break;
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4: j=(key&0x000F)-1; break;
case KEY_ENTER:
case PAD_ENTER:
if(is_boot_able(last_type(i))) menu_end=1;break;
}
if(j!=i)
{
textattr=menu_options.n_color;
draw_menu_item(LEFT+1,TOP+1+i,RIGHT-1,i);
textattr=menu_options.h_color;
draw_menu_item(LEFT+1,TOP+1+j,RIGHT-1,j);
}
}
if(i!=last) new_choice(i);
dinitscr();
}
++++++++++++++++++++++++
MBoot.h
// Partition type definition
#define P_UNUSED 0x00
#define P_DOS12 0x01
#define P_XENIX 0x02
#define P_DOS16 0x04
#define P_DOSEXT 0x05
#define P_BIGDOS 0x06
#define P_HPFS 0x07
#define P_SPLIT 0x08
#define P_FAT32 0x0B
#define P_DM 0x50
#define P_GB 0x56
#define P_SPEED 0x61
#define P_386IX 0x63
#define P_NOVELL286 0x64
#define P_NOVELL386 0x65
#define P_PCIX 0x75
#define P_LINUXSWAP 0x82
#define P_LINUX 0x83
#define P_CPM 0xDB
#define P_BBT 0xFF
#define Z_DOS12 0x81
#define Z_DOS16 0x8A
#define Z_BIGDOS 0x84
#define Z_XENIX 0x85
#define Z_386IX 0x86
#define Z_FAT32 0x87
#define Z_DOSEXT 0x88
#define Z_LINUX 0x89
+++++++++++++++++++++
Delay.h
#ifdef __cplusplus
extern "C" {
#endif
extern void delay( unsigned milliseconds );
#ifdef __cplusplus
}
#endif
+++++++++++++++++++++++++
Delay.c
/*---------------------------------------------------------------------------
* filename - delay.cas
*
* function(s)
* delay - wait for specified period.
*--------------------------------------------------------------------------*/
/*
* C/C++ Run Time Library - Version 5.0
*
* Copyright (c) 1987, 1992 by Borland International
* All Rights Reserved.
*
*/
#pragma inline
static unsigned long multiplier = 1193*2L;
static void near dummy (void) {}
/*--------------------------------------------------------------------------*
Name readtimer - read the complemented value of timer 0
Usage unsigned readtimer (void);
Prototype in local
Description Obtain the complement of the value in timer 0. The
complement is used so that the timer will appear to
count up rather than down. The value returned will
range from 0 to 0xffff.
Return value The complement of the value in timer 0.
*---------------------------------------------------------------------------*/
static unsigned near readtimer (void)
{
asm pushf /* Save interrupt flag */
asm cli /* Disable interrupts */
asm mov al,0h /* Latch timer 0 */
asm out 43h,al
dummy(); /* Waste some time */
asm in al,40h /* Counter --> bx */
asm mov bl,al /* LSB in BL */
dummy(); /* Waste some time */
asm in al,40h
asm mov bh,al /* MSB in BH */
asm not bx /* Need ascending counter */
asm popf /* Restore interrupt flag */
return( _BX );
}
/*--------------------------------------------------------------------------*
Name timer_init - initialize multiplier for delay function
Usage void timer_init (void);
Prototype in local
Description Determine the multiplier required to convert milliseconds
to an equivalent interval timer value. Interval timer 0
is normally programmed in mode 3 (square wave), where
the timer is decremented by two every 840 nanoseconds;
in this case the multiplier is 2386. However, some
programs and device drivers reprogram the timer in mode 2,
where the timer is decremented by one every 840 ns; in this
case the multiplier is halved, i.e. 1193.
When the timer is in mode 3, it will never have an odd value.
In mode 2, the timer can have both odd and even values.
Therefore, if we read the timer 100 times and never
see an odd value, it's a pretty safe assumption that
it's in mode 3. This is the method used in timer_init.
Return value None
*---------------------------------------------------------------------------*/
static void timer_init(void)
{
int i;
for (i = 0; i < 100; i++)
if ((readtimer() & 1) == 0) /* readtimer() returns complement */
{
multiplier = 1193L;
return;
}
}
#pragma startup timer_init 16
/*--------------------------------------------------------------------------*
Name delay - wait for specified period.
Usage void delay(unsigned milliseconds);
Prototype in dos.h
Description The current thread of execution is suspended for the specified
number of milliseconds.
Return value None
*---------------------------------------------------------------------------*/
void delay( unsigned milliseconds )
{
unsigned long stop;
unsigned cur, prev;
stop = (prev = readtimer()) + (milliseconds * multiplier);
while ((cur = readtimer()) < stop)
{
if (cur < prev) /* Check for timer wraparound */
{
if (stop < 0x10000L)
break;
stop -= 0x10000L;
}
prev = cur;
}
}
++++++++++++++++++++++++++++
conio.c
#include "conio.h"
#define SCR_SEGMENT 0xb800
#define SCR_WIDTH 80
#define SCR_HEIGHT 25
unsigned char textattr=0x07;
unsigned short wherexy=0;
void initscr(void) // Initialize & clear screen
{
asm {
mov ax,3
int 10h
mov ah,1
mov cx,100h
int 10h
}
}
void dinitscr(void)
{
asm {
mov ax,3
int 10h
}
}
void gotoxy(int col,int row)
{
asm {
mov ax,row
mov cl,80
mul cl
add ax,col
shl ax,1
mov wherexy,ax
}
}
void putch(int c,int n)
{
asm {
mov di,SCR_SEGMENT
mov es,di
mov di,wherexy
mov ax,c
mov ah,textattr
mov cx,n
cld
rep stosw
mov wherexy,di
}
}
void clrbox(int left,int top,int right,int bottom)
{
int i;
for(i=top;i<=bottom;i++)
{
gotoxy(left,i);
putch(' ',right-left+1);
}
}
void drawbox(int left,int top,int right,int bottom,char *chrset)
{
int i;
gotoxy(left,top);
putch(chrset[0],1);
putch(chrset[1],right-left-1);
putch(chrset[2],1);
for(i=top+1;i<bottom;i++)
{
gotoxy(left,i); putch(chrset[3],1);
gotoxy(right,i); putch(chrset[4],1);
}
gotoxy(left,bottom);
putch(chrset[5],1);
putch(chrset[6],right-left-1);
putch(chrset[7],1);
}
void shadowbox(int left,int top,int right,int bottom)
{
int i;
gotoxy(right+1,top);
putch('?,1);
for(i=top+1;i<=bottom;i++)
{
gotoxy(right+1,i);
putch('?,1);
}
gotoxy(left+1,bottom+1);
putch('?,right-left+1);
}
void puts(char *str)
{
int i,j;
for(j=wherey(),i=0;str;i++)
if(str=='/n' || str=='/r')
{
if(j<SCR_HEIGHT-1)
gotoxy(0,++j);
else
gotoxy(0,j);
putch(' ',SCR_WIDTH);
gotoxy(0,j);
}
else putch(str,1);
}
void putsxy(int col,int row,char *str)
{
gotoxy(col,row);
puts(str);
}
int getch(void)
{
asm {
mov ah,10h
int 16h
}
}
int getpassword(char *passwd,int maxlen)
{
int i;
for(i=0;i<maxlen;i++)
{
passwd=getch();
if(passwd==0x0D)
{
passwd='/0';
return(i);
}
}
for(;(getch()&0x7F)!=0x0D;
return(i);
}
+++++++++++++++++
conio.h
// Keyboard value definition
#define KEY_ESC 0x011B
#define KEY_1 0x0231
#define KEY_2 0x0332
#define KEY_3 0x0433
#define KEY_4 0x0534
#define KEY_ENTER 0x1C0D
#define PAD_ENTER 0xE00D
#define KEY_UP 0x48E0
#define KEY_DOWN 0x50E0
#define KEY_LEFT 0x4BE0
#define KEY_RIGHT 0x4DE0
#define KEY_CTRL_TAB 0x9400
extern unsigned char textattr;
extern unsigned short wherexy;
#define wherex() (wherexy>>1) % 80
#define wherey() (wherexy>>1) / 80
#ifdef __cplusplus
extern "C" {
#endif
extern void initscr(void);
extern void dinitscr(void);
extern void gotoxy(int col,int row);
extern void putch(int c,int n);
extern void clrbox(int left,int top,int right,int bottom);
extern void drawbox(int left,int top,int right,int bottom,char *chrset);
extern void shadowbox(int left,int top,int right,int bootom);
extern void puts(char *str);
extern void putsxy(int col,int row,char *str);
extern int getch(void);
extern int getpassword(char *passwd,int maxlen);
#ifdef __cplusplus
}
#endif
++++++++++++++++++++++++++++
minor_b.h
#define HD_NORMAL_MODE 0
#define HD_LBA_MODE 4
#define HD_LARGE_MODE 8
#define MENU_ITEM_SIZE 32
#define MAX_PASSWORD_SIZE 8
typedef unsigned char byte;
typedef unsigned short word;
typedef struct
{
byte bg_color; // Background Color
byte t_color; // Title Color
byte f_color; // Frame Color
byte n_color; // Normal Color
byte h_color; // High Light Color
byte framechar[8]; // Frame Character Set
// (TL,TH,TR,LV,RV,BL,BH,BR)
byte timeout; // Timeout (in second), 0 = no timeout
byte password[MAX_PASSWORD_SIZE]; // Password
byte default_choice; // Default partition
} MENU_OPTIONS;
typedef struct
{
byte cmos_mode; // Hard Disk Work Mode in CMOS
// (Normal=0,LBA=4,Large=8)
byte menu_str[31]; // Menu String
} MENU_ITEM;
typedef MENU_ITEM MENU_ARRAY[4];
extern const MENU_OPTIONS menu_options;
extern const MENU_ITEM menu_title;
extern const MENU_ARRAY menu_array;
#ifdef __cplusplus
extern "C" {
#endif
extern int last_choice(void);
extern void new_choice(int choice);
extern int last_type(int index);
extern void new_type(int index,int newtype);
#ifdef __cplusplus
}
#endif
++++++++++++++++++
要提醒一下的就是,你应该把Major_b.asm编译成一个EXE文件,把Major_b和conio.c,
mboot.c,delay.c编译成另一个EXE文件。然后把它们的EXE文件头去掉。得到的Major_b
应该放在硬盘的第一个扇区内,得到的Major_b应放在接下来的第二个扇区开如的62个扇区
内。这62个扇区是保留扇区,一般不会有程序用到它。
另外调试和编译引导程序你最好用DOS操作系统,这样引导比较快。还有最好不要在存有重
要数据的硬盘上调试,以免发生意外:)。