- 论坛徽章:
- 2
|
netbsd的mbr流程,sys/arch/i386/stand/mbr/mbr.S
由于篇幅,省略了版权声明,源文件里的注释是/**/,我添加的注释是//,因为是抽时间写的,因此一些 #ifdefine 的地方没有跟踪,需要的可以自己跟下去。
发完了财看见有一篇类似文章分析freebsd5.2的,呵呵。问题不大
xi
/* $NetBSD: mbr.S,v 1.12 2004/09/12 08:41:47 dsl Exp $ */
/*
* i386 master boot code
*/
/* Compile options:
* BOOTSEL - bootselector code
* BOOT_EXTENDED - scan extended partition list (LBA reads)
* TERSE_ERROR - terse error messages
* NO_CHS - all reads are LBA
* NO_LBA_CHECK - no check if bios supports LBA reads
* NO_BANNER - do not output 'banner'
*/
#ifdef BOOT_EXTENDED
#define NO_CHS 1
#define BOOTSEL 1
#endif
#ifdef BOOTSEL
#define TERSE_ERROR 1
#endif
#include
#include
#define BOOTADDR 0x7c00
#define LOADADDR 0x0600 /* address were are linked to */
#define TABENTRYSIZE (MBR_BS_PARTNAMESIZE + 1)
#define NAMETABSIZE (MBR_PART_COUNT * TABENTRYSIZE)
/* Scan values for the various keys we use, as returned by the BIOS */
#define SCAN_ENTER 0x1c // ENTER键的键盘扫描码(不是ANSII码)
#define SCAN_F1 0x3b // F1键的键盘扫描码(不是ANSII码)
#define SCAN_1 0x2 // 大键盘上数字键1的键盘扫描码(不是ANSII码)
/*
* Minimum and maximum drive number that is considered to be valid.
*/
#define MINDRV 0x80
#define MAXDRV 0x8f
#ifdef TERSE_ERROR
/*
* Error codes. Done this way to save space.
*/
#define ERR_INVPART '1' /* Invalid partition table */
#define ERR_READ '2' /* Read error */
#define ERR_NOOS '3' /* Magic no. check failed for part. */
#define ERR_KEY '?' /* unknown key press */
#define ERR_NO_LBA 'L' /* sector above chs limit */
#define set_err(err) movb $err, %al
#else
#define set_err(err) mov $err, %ax
#endif
.text
.code16
/*
* Move ourselves out of the way first.
* (to the address we are linked at - 0x600)
* and zero our bss
*/
ENTRY(start) // master bootstrap loader的入口地址,mbr被拷贝到内存并检查合法后BIOS将执行权力传递到 // 这里
xor %ax, %ax // ax = 0
mov %ax, %ss // 堆栈段基址 = 0
movw $BOOTADDR, %sp // 栈顶指针 = 0x7c00
mov %ax, %es
mov %ax, %ds // es(扩展段) = ds(数据段) = 0
mov %sp, %si // si(原地址) = 0x7c00
movw $start, %di // di(目的地址) = 0x600,在链接时,start被连接在地址0x600上(参见相关Makefile文件)
movw $(bss_start - start)/2, %cx // 计算从DS:SI(0x0000:0x7c00)拷贝到ES:DI(0x0000:0x600)的word的个数(也就是mbr
// 的大小512B).由于一次拷贝的是word(由movsw完成),因此计算时相应的除以2
rep
movsw /* relocate code */ // 拷贝%cx = 256个字到0x600
mov $(bss_end - bss_start + 1)/2, %cx // 计算bss段的长度(以字word为单位), bss_end=bss_start+bss_off // ,bss_off = 256*4,bss_end-bss_start 的计算将bss_start排 // 除在外,而bss段包含bss_start在内,因此需要加回来
rep
stosw /* zero bss */ // 从ES:DI = 0x600 + 512B 开始,填充ax中的内容,此时ax = 0,
// 即将bss段放在mbr之后,bss段清0
ljmp $0, $mbr /* leap into copy of code */ // 长跳转到下面执行.跳转地址为 $0:$mbr.由于链
// 接时是从0x600处开始的,因此对于下面的符号解析都是
// 相对于0x600为基址
/*
* Sanity check the drive number passed by the BIOS. Some BIOSs may not
* do this and pass garbage.
*/
mbr: // 地址 $0:$mbr
cmpb $MAXDRV, %dl /* relies on MINDRV being 0x80 */
jle 1f // %dl bx
#ifdef BOOT_EXTENDED // no define BOOT_EXTENDED
xorl %ecx, %ecx /* base of extended partition */
next_extended:
xorl %edx, %edx /* for next extended partition */
#endif
lea parttab - nametab(%bx), %bp // 求值顺序为[%bx+(parttab-nametab)] -> %bp, parttab是mbr中分区表的地址
// parttab = start+MBR_PART_OFFSET =0x600+0x1BE,又%bx = nametab,最后求值为
// parttab->%bp,该步骤取得堆栈栈底地址,下面以堆栈方式访问分区表中的数据
next_ptn: // 寻找分区表
movb 4(%bp), %al /* partition type */ // 取得分区类型(见后面附表1),在分区表的4h偏移处,分区表结构如
// Format of partition record:
// Offset Size Description
// 00h BYTE boot indicator (80h = active partition)
// 01h BYTE partition start head
// 02h BYTE partition start sector (bits 0-5)
// 03h BYTE partition start track (bits 8,9 in bits 6,7 of sector)
// 04h BYTE operating system indicator
// 05h BYTE partition end head
// 06h BYTE partition end sector (bits 0-5)
// 07h BYTE partition end track (bits 8,9 in bits 6,7 of sector)
// 08h DWORD sectors preceding partition
// 0Ch DWORD length of partition in sectors
#ifdef NO_CHS // no define NO_CHS
movl 8(%bp), %edi /* partition sector number */
#ifdef BOOT_EXTENDED
cmpb $MBR_PTYPE_EXT, %al /* Extended partition */
je 1f
cmpb $MBR_PTYPE_EXT_LBA, %al /* Extended LBA partition */
je 1f
cmpb $MBR_PTYPE_EXT_LNX, %al /* Linux extended partition */
jne 2f
1: movl %edi, %edx /* save next extended ptn */
jmp 4f
2:
#endif
addl lba_sector, %edi /* add in extended ptn base */
#endif // pass all
test %al, %al /* undefined partition */ // 测试分区类型,如果al=0,则表示"empty partition-table
// entry"
je 4f // 跳转去寻找下一个分区表
cmpb $0x80, (%bp) /* check for active partition */// 当前分区表是某种类型(type)的分区表,现在检查它是否 // 是活动分区
jne 3f /* jump if not... */ // 如果不是活动分区,则继续寻找下一个分区表
#define ENTER (4 * ((SCAN_ENTER - SCAN_F1) & 0xff)) // 4 * 0xE1 = 0x384 note ???
#ifdef NO_CHS // no define
movl %edi, ptn_list + ENTER /* save location of active ptn */ // pass
#else
mov %bp, ptn_list + ENTER // 当前分区是活动分区,
// ptn_list=bss_start=0x600+512B=0x800
// (parttab[0-3]) -> 0x800 + 0x384
#endif
#undef ENTER
3:
#ifdef BOOTSEL // 没有定义BOOTSEL
cmpb $0, (%bx) /* check for prompt */
jz 4f
/* output menu item */
movw $prefix, %si
incb (%si)
call message /* menu number */
mov (%si), %si /* ':' << 8 | '1' + count */
shl $2, %si /* const + count * 4 */
#define CONST (4 * ((':' << 8) + '1' - ((SCAN_1 - SCAN_F1) & 0xff)))
#ifdef NO_CHS
movl %edi, ptn_list - CONST(%si) /* sector to read */
#else
mov %bp, ptn_list - CONST(%si) /* partition info */
#endif
#undef CONST
mov %bx, %si
call message_crlf /* prompt */
#endif // BOOTSEL
4:
add $0x10, %bp // 下一个分区表入口(每一个分区表16字节)
add $TABENTRYSIZE, %bx // TABENTRYSIZE = MBR_BS_PARTNAMESIZE + 1 = 8 + 1 = 名称长度+字符串结束符NUL
// %bx = 名称表中的下一个表项(共4个,每个表项包括NUL为9字节)
cmpb $(nametab - start - 0x100) + 4 * TABENTRYSIZE, %bl
// $(nametab - start - 0x100) + 4 * TABENTRYSIZE = (404-0-256)+4*9=184=0xB8
// 判断是否是最后一个nametab入口,开始时%bx=$nametab=0x194,每次循环bx+=9,因此,bx的低
// 8位(即bl)分别为0x194, 0x194+9=0x19D, 0x19D+9=0x1A6, 0x1A6+9=0x1AF, 0x1AF+9=0x1B8
// ??? note ??? why need a so complicated formula to result 0xB8
jne next_ptn // 寻找下一个分区表
#ifdef BOOT_EXTENDED // 没有定义BOOT_EXTENDED
/*
* Now check extended partition chain
*/
testl %edx, %edx
je wait_key
testl %ecx, %ecx
jne 1f
xchg %ecx, %edx /* save base of ext ptn chain */
1: addl %ecx, %edx /* sector to read */
movl %edx, lba_sector
movw $lba_info, %si
movb $0x42, %ah
pop %dx /* recover drive # */
push %dx /* save drive */
int $0x13
jc wait_key /* abort menu on read fail */
cmpw $MBR_MAGIC, LOADADDR + MBR_MAGIC_OFFSET
movw $nametab - LOADADDR + BOOTADDR, %bx
je next_extended
#endif // pass
/*
* The non-bootsel code traverses this code path, it needs the
* correct keycode to select the active partition.
*/
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/11799/showart_60616.html |
|