免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1529 | 回复: 0
打印 上一主题 下一主题

netbsd mbr code annotation [复制链接]

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-12-08 22:49 |只看该作者 |倒序浏览

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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP