GRUB(三) ASM.S註釋

ASM.S生成的代碼將放置到第三扇區,緊跟Start.S生成的第二扇區代碼。如上一篇代碼中展現的這個代碼將被start.s加載到內存地址的0x8200或者0x2200中執行。

#define ASM_FILE

#include "shared.h"

#ifdef STAGE1_5
# define    ABS(x)    ((x) - EXT_C(main) + 0x2200)
#else
# define    ABS(x)    ((x) - EXT_C(main) + 0x8200)
#endif
    
    .file    "asm.S"

    .text

    /* GAS生成16位代碼 */
    .code16

#ifndef STAGE1_5
    /* 
     * 在階段2中不要將start.S和剩餘源碼直接鏈接
     * so define the start symbols here just to
     * force ld quiet. These are not referred anyway.
     */
    .globl    start, _start
start:
_start:
#endif /* ! STAGE1_5 */
    
ENTRY(main) //stage2的入口
    /*
     * 確保"main"加載在0x0:0x8200(stage2)或者加載在0x0:0x2200(stage1.5).
     * 如果不是,下面的跳轉指令會跑飛。
     */
    ljmp $0, $ABS(codestart)

//    /* control byte
//     * Currently only bit 0 is used.
//     * bit 0    disable the "unconditional command-line entrance" feature
//     */
//
//    . = EXT_C(main) + 0x5
//    .byte    0

    /*
     *  兼容性版本號
     *
     *  它們必須在可執行鏡像字節偏移等於6和7的位置中
     *  不要移動它!!!
     */
    . = EXT_C(main) + 0x6
    .byte    COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR

    /*
     *  以上是一塊8字節的特殊區域。
     */

    . = EXT_C(main) + 0x8

VARIABLE(install_partition)
    .long    0xFFFFFF
/* 因爲是歷史原因這個變量放在這裏,沒有其他用處*/
VARIABLE(saved_entryno)
#if defined(STAGE1_5) /* || ! defined(PRESET_MENU_STRING) */
    .long    0
#else

/* Note: GRUB4DOS 使用這個作爲命令行“preset_menu”.
 * 用GRUB.EXE的命令行可以嵌入preset_menu.
 * 一個新的preset_menu可以覆蓋內置的preset_menu.
 * 如果未改變該變量,並且config_file的第一個字節爲0,
 * 那麼位於0x0800的新菜單將起作用。
 * 如果變量被設置爲0, 或者config_file的第一個字節不爲0
 * 那麼將使用內置的preset_menu.
 *
 * 不要將這個變量的值設置爲非0的其他值.
 */
 
    .long    preset_menu
#endif
VARIABLE(stage2_id)
    .byte    STAGE2_ID
VARIABLE(force_lba)
    .byte    0
VARIABLE(version_string)
    .string VERSION
VARIABLE(config_file)
#ifndef STAGE1_5
    .string "/boot/grub/menu.lst"
#else   /* STAGE1_5 */
    .long    0xffffffff
    .string "/boot/grub/stage2"
#endif  /* STAGE1_5 */

    /*
     *  爲config文件名騰出一些空間
     */

    . = EXT_C(main) + 0x6C  #; bss開始地址,BSS段通常是指用來存放程序中未初始化的或者初始化爲0的全局變量和靜態變量的一塊內存區域。
#ifndef STAGE1_5
#if defined(HAVE_USCORE_USCORE_BSS_START_SYMBOL)
    //.word    (__bss_start - main) & 0x0F, (__bss_start - main) >> 4
    .long    __bss_start
#elif defined(HAVE_USCORE_EDATA_SYMBOL)
    //.word    (_edata - main) & 0x0F, (_edata - main) >> 4
    .long    _edata
#elif defined(HAVE_EDATA_SYMBOL)
    //.word    (edata - main) & 0x0F, (edata - main) >> 4
    .long    edata
#else
#error no bss starting address
#endif
#endif

    . = EXT_C(main) + 0x70

/* 這裏繼續實模式的代碼 */
codestart:
    cli        /* 禁止軟中斷 */

    /* %ds = %ss = %es = 0, esp = 2000h 注意這裏重置了棧*/
    xorw    %ax, %ax
    movw    %ax, %ds
    movw    %ax, %es
    movw    %ax, %ss
    movl    $STACKOFF, %esp

#ifndef STAGE1_5
    movb    0x0410, %al
    /* floppies_orig = *(byte*)0x0410 */
    movb    %al, ABS(floppies_orig) 
    movb    0x0475, %al
    /* harddrives_orig = *(byte*)0x0475 */
    movb    %al, ABS(harddrives_orig) 

    //movb    $((int13_handler_end - int13_handler + 0x3ff) / 0x400), ABS(int13_handler)

	/* BIOS在程序最開始的位置,即0x00000,用1K的內存空間(0x00000~0x003FF)構建中斷向量表,
	並在緊挨他的位置用256字節的內存空間構建BIOS數據區(0x00400~0x004FF),在大約56K的位置(0x0E2CE)
	加載了8K左右的與中斷向量表相應的若干中斷服務程序。中斷向量表中有256箇中斷向量,
	每個中斷向量佔有4個字節空間,其中2個字節是CS的值,2個是IP的值,
	每個中斷向量都指向一個具體的中斷服務程序。*/
	
    movl    0x4C, %eax
	/* int13中斷向量表偏移 = 0x13 * 4 = 0x4C; 
	這裏將這個值保存到int13_offset和(int13_offset + 0x113 - 0x1C)的地方
    等同於int13_offset = *(DWORD*)0x4c
     */
    movl    %eax, ABS(int13_offset) 
    movl    %eax, ABS(int13_offset) + 0x113 - 0x1C  
	
    cmpl    $0xC0000000, %eax 
    jnb    1f
    cmpl    $0x9A000000, %eax
    jb    1f 
    
    /* 取中斷向量的低22位,該值(其中低16位是offset)必須等於0x100 */
	andl    $0x3FFFFF, %eax 
    cmpl    $0x100, %eax
    jnz    1f
	
    /* 在0x413處存放的是RAM剩餘大小,以KB爲單位 */
    movw    0x413, %ax   
    shlw    $6, %ax
    cmpw    0x4E, %ax    /* (4E = 0x13 * 4 + 2) 中斷向量的高2字節(CS) */
    jne    1f

    movw    %ax, %ds            /* DS=old int13 code segment */
    movl    0x1C, %eax          /* ROM int 13 vector */
    cmpl    $0x9A000000, %eax
    jb    2f

    movl    0x0C, %eax            /* ROM int 15 vector */
    cmpl    $0x9A000000, %eax
    jb    2f

    /* restore old emu data, except the first byte of handler size. */
    movw    $(0x140 - 1), %cx
    movw    $1, %si
    movw    $ABS(int13_handler + 1), %di
    cld
    repz movsb

    ///* restore old int13_dup */
    //movl    (int13_dup - int13_handler), %eax
    //movl    %eax, %es:ABS(int13_dup)

    ///* restore old safe_mbr_hook */
    //movl    (safe_mbr_hook - int13_handler), %eax
    //movl    %eax, %es:ABS(safe_mbr_hook)

2:
    xorw    %ax, %ax
    movw    %ax, %ds            /* DS=0 */
1:
	/*ROM_int15 默認爲0,不確定會不會在寫入扇區的時候被改寫*/
    movl    ABS(ROM_int15), %eax
    cmpl    $0x9A000000, %eax
    jnb    1f
	/* 變量ROM_int15的值 = INT15在中斷向量表中的偏移 = 0x15*4 = 0x0054*/
    movl    0x0054, %eax
    movl    %eax, ABS(ROM_int15) /* ROM_int15 = *(DWORD*)0x0054 */
1:
    /* 檢查BIOS類型 (當前僅檢查Bochs) ,檢查從0xFF00開始的字符是否爲"(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team.\0"*/
    movw    $0xF000, %ax
    movw    %ax, %es            /* ES=0xF000 */
    movw    $0xFF00, %di
    movw    $ABS(bochs_copygrght_string), %si
    movw    $0x22, %cx
    repz cmpsw
    setz    ABS(bios_id)    /* 爲bochs時設置bios_id=1, 否則爲0. */
    xorw    %ax, %ax
    movw    %ax, %es            /* ES=0 */

#endif  /* STAGE1_5 */
#ifndef SUPPORT_DISKLESS
    /*
     * Save the sector number of the second sector (i.e. this sector)
     * in INSTALL_SECOND_SECTOR. See also "stage2/start.S".
     */
    ADDR32    movl    %ebp, EXT_C(install_second_sector)
#endif
    
    ///* set up the real mode/BIOS stack */
    //movl    $STACKOFF, %ebp
    //movl    %ebp, %esp

    /* for usb keyboard hack here, disable interrupt */
    //sti        /* we're safe again */

	/* 保存DX */
    pushw    %dx

	/*設置ES = DS = AX = 0*/
    xorw    %ax, %ax
    movw    %ax, %ds
    movw    %ax, %es


    /* 禁用虛擬磁盤服務(clear VDS),配置在內存地址0x47B中。
	0xd7 = 1101 0111(b),即置零第3和第5位 */
    andb    $0xD7, 0x47B
	
	/* 恢復DX */
    popw    %dx

    cli

#ifndef SUPPORT_DISKLESS
    /* save boot drive reference */
    ADDR32    movb    %dl, EXT_C(boot_drive)

    movw    $ABS(reset_disk_string),%si
    call    print_message    /* will not change DX */

    xorw    %ax, %ax
	
    /* 重啓磁盤系統 INT 13 (%ah = 0) 
	INT 13,0 - Reset Disk System
  	AH = 00
  	DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
	
	
	on return:
  	AH = disk operation status  (see INT 13,STATUS)
  	CF = 0 if successful
     	= 1 if error
	
	- clears reset flag in controller and pulls heads to track 0
	- setting the controller reset flag causes the disk to recalibrate
	  on the next disk operation
	- if bit 7 is set, the diskette drive indicated by the lower 7 bits
	  will reset then the hard disk will follow; return code in AH is
	  for the drive requested
	*/
#ifdef STAGE1_5
    int    $0x13
#else
    /* safe_int13會重置INT0~7的中斷向量表,當程序發生故障時
	將調用我們設定的異常處理程序,調用返回前恢復原有的值*/
    call    safe_int13
#endif
    movw    $ABS(reset_disk_failure_string),%si
    jc    1f
    movw    $ABS(reset_disk_success_string),%si
1:
    call    print_message    /* 打印Failure或者Success,DX不會發生變化 */
#endif

    xorw    %ax, %ax
    movw    %ax, %ds
    movw    %ax, %es

#ifndef STAGE1_5

    movl    $1, %ebx

    /* BIOS的地址0x5FC中保存了DUCE標識 */
    cmpl    $0x45435544, 0x5FC
    jz    1f

    /* 檢查用戶是否輸入了'c' */

    pushl    %ebx
    movb    $0x01, %ah
    /*INT16/1用來查詢鍵盤緩衝區,對鍵盤掃描但不等待,並設置ZF標誌。
	若有按鍵操作(即鍵盤緩衝區不空),則ZF=0,AL中存放的是
	輸入的ASCII碼,AH中存放輸入字符的擴展碼。若無鍵按下,則
	標誌位ZF=1。*/
	int    $0x16
    popl    %ebx

    jz    1f        /* 沒有按鍵 */
    orb    $0x20, %al
    cmpb    $0x63, %al
    jne    1f        /* 按鍵不是'c' */

    /* 如果用戶按下了C鍵,則跳過配置文件中後續的啓動 */
    movl    $0, %ebx
1:
#endif

    /* 從實模式切換到保護模式 */
    DATA32    call EXT_C(real_to_prot)

    /* ".code32" 讓GAS編譯32位代碼. */
    .code32

#ifndef STAGE1_5
    /* 如果用戶按下了C鍵則EBX=0,此時需要設置use_config_file = 0 */
    testl    %ebx, %ebx   
    jnz    1f
    movl    %ebx, EXT_C(use_config_file)
1:
#endif

    /* clean out the bss */

    /* 讓%edi等於BSS的開始地址,BSS的介紹在前面 */
#if defined(HAVE_USCORE_USCORE_BSS_START_SYMBOL)
    movl    $__bss_start, %edi
#elif defined(HAVE_USCORE_EDATA_SYMBOL)
    movl    $_edata, %edi
#elif defined(HAVE_EDATA_SYMBOL)
    movl    $edata, %edi
#else
#error no bss starting address
#endif

    /* 讓%ecx等於BSS的結束地址 */    
#if defined(HAVE_END_SYMBOL)
    movl    $end, %ecx
#elif defined(HAVE_USCORE_END_SYMBOL)
    movl    $_end, %ecx
#else
#error no bss ending address
#endif

    /* 計算BSS的長度,保存在ECX */
    subl    %edi, %ecx
    
    /* %al = 0 */
    xorb    %al, %al

    /* set the direction */
    cld
    
    /* BSS的內容全部置零 */
    rep
    stosb
    
    /* 如果config_file == 0(用戶按下了C時)不做任何事情。
	否則將EBX設置爲preset_menu。詳見前面preset_menu變量處的介紹。 */
    //movb    config_file, %al
    //testb    %al, %al
    cmpb    %al, config_file    /* 注:此時AL == 0 */
    jnz    1f
    movl    saved_entryno, %ebx /* 檢查saved_entryno,這個值默認爲0*/
    testl    %ebx, %ebx
    jz    1f
    movl    $0x0800, (%ebx)     /* 採用位於0x0800處的內置菜單 */
1:
    
    /*
     *  調用C代碼入口init_bios_info函數, 它在調用cmain前會做一些初始化工作。
     */
    call EXT_C(init_bios_info)

這個過程中調用的其他函數

	
safe_int13:

    .code16

    /* 設置我們的故障恢復處理程序(重寫INT 0~7中斷向量表) */

    call    set_fault_recovery_handler

    /* 備份寄存器的值到original_registers. Note: CS=0 */

    movw    %ds, %cs:ABS(original_registers)
    movw    %es, %cs:ABS(original_registers) + 4
    movw    %ss, %cs:ABS(original_registers) + 8
    movl    %esp, %cs:ABS(original_registers) + 12
    movl    %eax, %cs:ABS(original_registers) + 16
    movl    %ebx, %cs:ABS(original_registers) + 20
    movl    %ecx, %cs:ABS(original_registers) + 24
    movl    %edx, %cs:ABS(original_registers) + 28
    movl    %esi, %cs:ABS(original_registers) + 32
    movl    %edi, %cs:ABS(original_registers) + 36
    movl    %ebp, %cs:ABS(original_registers) + 40

    pushw    %bp
    pushw    %ax
    movw    %sp, %bp
    movw    (%bp), %ax
    movw    %ax, %cs:ABS(original_registers) + 44    #; return IP
    popw    %ax
    popw    %bp

    int    $0x13

	/* 從備份中恢復故障恢復程序(中斷向量表INT 0~7)*/
    call    unset_fault_recovery_handler

    ret

/* 替換INT0~INT7 
 * CPU exceptions 0 - 7
 *    0    Divide
 *    1    Debug
 *    2    NMI
 *    3    Break point
 *    4    Overflow
 *    5    Bound
 *    6    Invalid Instruction
 *    7    no coprocessor
 * 保存INT00到INT07的中斷向量到int_00_07_vectors,INT 0-7的中斷向量保存在地址爲0000 - 0020的32個字節中。
 * 並設置新的中斷向量表,將fault_recovery_handler開始地址存放的32個字節複製到0000 - 0020
 */

set_fault_recovery_handler:

    .code16

    pushfw
    pushw    %ds
    pushw    %es
    pushaw

    xorw    %ax, %ax
    movw    %ax, %ds
    movw    %ax, %es
    xorw    %si, %si 
    movw    $ABS(int_00_07_vectors), %di
    movw    $16, %cx
    cld
    repz movsw /*拷貝從0000:0000開始的32個字節到int_00_07_vectors*/

    xorw    %ax, %ax
    movw    %ax, %ds
    movw    %ax, %es
    xorw    %si, %si
    movw    $ABS(int_00_07_vectors), %di

    pushl    %eax

    xorw    %di, %di
    movl    $ABS(fault_recovery_handler), %eax    /* 0000:fault_recovery_handler */
    movw    $8, %cx
    cld
	/*stosl將EAX中的值保存到ES:EDI指向的地址中*/
    repz stosl 

    popl    %eax

    popaw
    popw    %es
    popw    %ds
    popfw
    ret

	
/* 恢復中斷向量表的前32個字節,從int_00_07_vectors拷貝32個字節到0000 - 0020 */
unset_fault_recovery_handler:

    .code16

    pushfw
    pushw    %ds
    pushw    %es
    pushaw


    xorw    %ax, %ax
    movw    %ax, %ds
    movw    %ax, %es
    xorw    %di, %di
    movw    $ABS(int_00_07_vectors), %si
    movw    $16, %cx
    cld
    repz movsw

    popaw
    popw    %es
    popw    %ds
    popfw
    ret

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章