全部博文(290)
分类: LINUX
2010-11-14 22:52:04
/*****************************************
MBR结构偏移以宏的方式定义在stage1.h中
*****************************************/
#include
/*重定位宏*/
#define ABS(x) (x-_start+0x7c00)
/*****************************************
打印字符串宏定义
*****************************************/
#define MSG(x) movw $ABS(x), %si; call message
#define MOV_MEM_TO_AL(x) .byte 0xa0; .word x
/*****************************************
.file op 指定和目标文件关联的源文件名
*****************************************/
.file "stage1.S"
/*****************************************
.text代码段声明; .code16使用实模式
*****************************************/
.text
.code16
/*****************************************
代码段入口 .globl 全局符号定义
*****************************************/
.globl _start; _start:
/*****************************************
MBR开始跳转指令,跳转到真正的引导代码处
后跟一个NOP指令,占MBR偏移的: 0x00-0x03
更确切的说,这应该是DBR
*****************************************/
jmp after_BPB
nop
/*****************************************
.程序引用计数器,这里应该是对齐
*****************************************/
. = _start + 4
/* 以下定义为int13扩展使用的的参数结构
* 扇区号 :sectors
* 磁头号: heads
* 柱面: cylinders
* 在int 13H调用时使用
*/
mode:
.byte 0
disk_address_packet:
sectors:
.long 0
heads:
.long 0
cylinders:
.word 0
sector_start:
.byte 0
head_start:
.byte 0
cylinder_start:
.word 0
/*****************************************
MBR偏移0x0B开始是BPB部分,占用50或者80字节
这里占用50字节,故此
#define STAGE1_BPBEND 0x3e
*****************************************/
. = _start + STAGE1_BPBEND
/*
*stage1版本定义,版本号在stage1中以宏的方式定义
* #define COMPAT_VERSION_MAJOR 3
* #define COMPAT_VERSION_MINOR 2
* #define COMPAT_VERSION ((COMPAT_VERSION_MINOR << 8) \
* | COMPAT_VERSION_MAJOR)
*boot_drive 用于指出stage1需要装载的代码在何处
*后面是stage2的载入地址定义
************************************************************************/
stage1_version:
.byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR
boot_drive:
.byte 0xFF
force_lba: ;强制LBA模式
.byte 0
stage2_address: ;stage2装入地址
.word 0x8000
stage2_sector: ;stage2在磁盘上的扇区
.long 1
stage2_segment:
.word 0x800
/*****************************************
引导区代码
*****************************************/
after_BPB:
cli ;关中断
/*
* Drive Table
* DL = 00h 1st floppy disk ( "drive A:" )
* DL = 01h 2nd floppy disk ( "drive B:" )
* DL = 80h 1st hard disk
* DL = 81h 2nd hard disk
*/
boot_drive_check:
jmp 1f
testb $0x80, %dl ;BIOS加载完启动代码会把%dl设置成启动盘号(boot drive number):
jnz 1f
movb $0x80, %dl
1:
ljmp $0, $ABS(real_start) ;跳转到真正的引导代码处,远跳转
real_start:
xorw %ax, %ax
movw %ax, %ds
movw %ax, %ss ;段寄存器初始化
movw $STAGE1_STACKSEG, %sp ;堆栈地址初始化, 宏定义:#define STAGE1_STACKSEG 0x2000
sti ;关中断
MOV_MEM_TO_AL(ABS(boot_drive))
cmpb $0xFF, %al ;检查是否设置了启动磁盘,如果不是,dl送al,将dx入栈后在屏幕上显示“GRUB”
je 1f ;如果是,调整后一个1:处
movb %al, %dl
1:
pushw %dx
MSG(notification_string)
testb $STAGE1_BIOS_HD_FLAG, %dl ;测试启动磁盘是否是硬盘,DL内的值有BIOS设置
jz chs_mode ;不是硬盘则使用CHS模式
movb $0x41, %ah
movw $0x55aa, %bx
int $0x13 ; int 13 0x41 扩展判断是否支持LBA模式 ,
popw %dx ;恢复dl值
pushw %dx ;保存dx值
jc chs_mode
cmpw $0xaa55, %bx ;是否支持LBA模式,不支持则启用CHS模式
jne chs_mode
MOV_MEM_TO_AL(ABS(force_lba)) ;相当于 movb ABS(force_lba), %al
testb %al, %al ;是否强制使用LBA模式
jnz lba_mode
andw $1, %cx
jz chs_mode
/******************************************************************************
struct DiskAddressPacket
{
BYTE PacketSize; // 数据包尺寸:
//(固定值,恒等于16,即10H,指本结构所占用的存储空间)
BYTE Reserved; // ==0
WORD BlockCount; // 要传输的数据块个数(以扇区为单位)
DWORD BufferAddr; // 传输缓冲地址(segment:offset)
QWORD BlockNum; // 磁盘起始绝对块地址 8个字节
};
PacketSize 保存了 DAP 结构的尺寸, 以便将来对其进行扩充. 在
目前使用的扩展 Int13H 版本中 PacketSize 恒等于 16. 如果它小于
16, 扩展 Int13H 将返回错误码( AH=01, CF=1 ).
BlockCount 对于输入来说是需要传输的数据块总数, 对于输出来说
是实际传输的数据块个数. BlockCount = 0 表示不传输任何数据块.
BufferAddr 是传输数据缓冲区的 32 位地址 (段地址:偏移量). 数据
缓冲区必须位于常规内存以内(1M).
BlockNum 表示的是从磁盘开始算起的绝对块地址(以扇区为单位),
与分区无关. 第一个块地址为 0. 一般来说, BlockNum 与 CHS 地址的关系
是:
BlockNum =
(cylinder * NumberOfHeads + head) * SectorsPerTrack + sector - 1;
其中 cylinder, head, sector 是 CHS 地址, NumberOfHeads 是磁盘
的磁头数, SectorsPerTrack 是磁盘每磁道的扇区数.
也就是说 BlockNum 是沿着 扇区->磁道->柱面 的顺序记数的. 这一顺
序是由磁盘控制器虚拟的, 磁盘表面数据块的实际排列顺序可能与此不同
(如为了提高磁盘速度而设置的间隔因子将会打乱扇区的排列顺序).
*****************************************************************************/
lba_mode: ;使用LBA方式读入下一个扇区
movl 0x10(%si), %ecx
movw $ABS(disk_address_packet), %si ;esi保存 stDiskAddressPacket结构体
movb $1, -1(%si)
movl ABS(stage2_sector), %ebx
movw $0x0010, (%si) ;PacketSize 保存了 DAP 结构的尺寸,恒等于0x10
movw $1, 2(%si) ;输入的数据块个数 [esi +2]
movl %ebx, 8(%si) ;磁盘起始绝对块地址 [esi +8] 起8个字节为绝对块地址
movw $STAGE1_BUFFERSEG, 6(%si) ;读数据的缓冲区 [esi +6 ]
xorl %eax, %eax ;eax清零
movw %ax, 4(%si) ;[esi +4] == 0
movl %eax, 12(%si) ; [esi +12] == 0
/*
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
* Call with %ah = 0x42
* %dl = drive number
* %ds:%si = segment:offset of disk address packet
* Return:
* %al = 0x0 on success; err code on failure
*/
movb $0x42, %ah
int $0x13
jc chs_mode ;Jump if ECX is Zero
movw $STAGE1_BUFFERSEG, %bx
jmp copy_buffer
chs_mode:
movb $8, %ah
int $0x13 ;int 08h中断读磁盘参数 ,读磁盘参数
jnc final_init ;cx不为0跳走,调用int 13 2号功能读取数据
testb $STAGE1_BIOS_HD_FLAG, %dl
jz floppy_probe ;是否是软盘
jmp hd_probe_error ;硬盘可能出错
final_init:
movw $ABS(sectors), %si
movb $0, -1(%si)
xorl %eax, %eax
movb %dh, %al
incw %ax
movl %eax, 4(%si)
xorw %dx, %dx
movb %cl, %dl
shlw $2, %dx
movb %ch, %al
movb %dh, %ah
incw %ax
movw %ax, 8(%si)
xorw %ax, %ax
movb %dl, %al
shrb $2, %al
movl %eax, (%si)
setup_sectors:
movl ABS(stage2_sector), %eax
xorl %edx, %edx
divl (%si)
movb %dl, 10(%si)
xorl %edx, %edx
divl 4(%si)
movb %dl, 11(%si)
movw %ax, 12(%si)
cmpw 8(%si), %ax
jge geometry_error
movb 13(%si), %dl
shlb $6, %dl
movb 10(%si), %cl
incb %cl
orb %dl, %cl
movb 12(%si), %ch
popw %dx
movb 11(%si), %dh
/*
* BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
* Call with %ah = 0x2
* %al = number of sectors
* %ch = cylinder
* %cl = sector (bits 6-7 are high bits of "cylinder")
* %dh = head
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
* %es:%bx = segment:offset of buffer
* Return:
* %al = 0x0 on success; err code on failure
*/
movw $STAGE1_BUFFERSEG, %bx
movw %bx, %es
xorw %bx, %bx
movw $0x0201, %ax
int $0x13
jc read_error ;cx为0,则读取错误
movw %es, %bx
copy_buffer:
movw ABS(stage2_segment), %es ;stage寄存器入ES段
pusha ;环境保存
pushw %ds ;dl保存
movw $0x100, %cx ;因为使用的是movsw,所以字MBR字节数减半
movw %bx, %ds ;读出的数据地址初始化DS段;
xorw %si, %si
xorw %di, %di
cld ;设置方向标志,+
rep
movsw ;movsw es:[di},ds:[si}
popw %ds
popa
jmp *(stage2_address) ;跳转执行stage2代码;
/************************************************
错误处理
*************************************************/
geometry_error:
MSG(geometry_error_string)
jmp general_error
hd_probe_error:
MSG(hd_probe_error_string)
jmp general_error
read_error:
MSG(read_error_string)
general_error:
MSG(general_error_string)
stop: jmp stop ;死循环
notification_string: .string "GRUB "
geometry_error_string: .string "Geom"
hd_probe_error_string: .string "Hard Disk"
read_error_string: .string "Read"
general_error_string: .string " Error"
/* BIOS int 10号中断 0号功能以打印机模式显示字符
* AH = 功能号 0EH
* AL = 打印的字符
* BH = 页号
* BL = 前景颜色
*16位色彩编码表 (D7 D6 D5 D4为背景色,D3 D2 D1 D0为前景色)
*/
1:
movw $0x0001, %bx
movb $0xe, %ah
int $0x10
message:
lodsb
cmpb $0, %al
jne 1b
ret
. = _start + STAGE1_WINDOWS_NT_MAGIC
nt_magic:
.long 0
.word 0
part_start:
. = _start + STAGE1_PARTSTART
probe_values:
.byte 36, 18, 15, 9, 0
floppy_probe:
movw $ABS(probe_values-1), %si
probe_loop:
xorw %ax, %ax
int $0x13
incw %si
movb (%si), %cl
cmpb $0, %cl
jne 1f
MSG(fd_probe_error_string)
jmp general_error
fd_probe_error_string: .string "Floppy"
1:
movw $STAGE1_BUFFERSEG, %bx
movw $0x201, %ax
movb $0, %ch
movb $0, %dh
int $0x13
jc probe_loop
movb $1, %dh
movb $79, %ch
jmp final_init
. = _start + STAGE1_PARTEND
.word STAGE1_SIGNATURE