- 論壇徽章:
- 0
|
'kernel/head.S' Detail Comment
/***************************************************************************
32位啟動(dòng)代碼:
編譯程序在鏈接內(nèi)核vmlinux的時(shí)候,將vmlinux起始位置鏈接到0xC0000000 + 0x100000,這
樣所有的符號(hào)地址=0xC0000000+符號(hào)。在編譯后的文件中的偏移地址。因此在頁(yè)面影射沒有啟動(dòng)之前,
如果需要訪問符號(hào)的物理地址,必須要減去0xC0000000。需要說明幾點(diǎn):
1.內(nèi)核vmlinux被加載的時(shí)候,其存放在物理地址為0x100000處。CPU在執(zhí)行這些指令的時(shí)候,如該
文件中的第一條指令,CS=0,IP=0x100000, 由于該條指令的物理地址依然在0x100000,故CPU順
序往下執(zhí)行,而無須程序作任何其他調(diào)整;
2.但是,在鏈接vmlinux的時(shí)候, 鏈接程序?qū)⒃撛闯绦蛑兴械姆?hào),例如符號(hào)empty_zero_page,
在最后形成的二進(jìn)制文件中都替換為固定的值,這個(gè)固定的值就是:
0xC0000000 + 0x100000 + 其在最后形成的二進(jìn)制文件中的偏移
這樣在沒有啟動(dòng)頁(yè)面映射之前,如果直接訪問該地址,由于該地址是在3G + offset, 在物理上基本上
是不存在的,所以會(huì)出錯(cuò)。為了訪問到該符號(hào)所標(biāo)識(shí)的數(shù)據(jù)所在的物理地址,需要減去0xC0000000,這
樣便得到了該符號(hào)在該映射文件中的偏移值 + 0x100000, 由于內(nèi)核在加載的時(shí)候剛好被加載在內(nèi)存
0x100000處, 故該符號(hào)在該映射文件中的偏移值+0x100000就是該符號(hào)在物理內(nèi)存中的地址。
在/arch/i386/vmlinux.lds中可以看到相關(guān)的設(shè)置信息,objdump -D vmlinux命令來獲取所
有的符號(hào)以及這些符號(hào)的地址。
***************************************************************************/
.text
#include <linux/config.h>
#include <linux/threads.h>
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/desc.h>
#define OLD_CL_MAGIC_ADDR 0x90020
#define OLD_CL_MAGIC 0xA33F
#define OLD_CL_BASE_ADDR 0x90000
#define OLD_CL_OFFSET 0x90022
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
/*
* References to members of the boot_cpu_data structure.
*/
#define CPU_PARAMS SYMBOL_NAME(boot_cpu_data)
#define X86 CPU_PARAMS+0
#define X86_VENDOR CPU_PARAMS+1
#define X86_MODEL CPU_PARAMS+2
#define X86_MASK CPU_PARAMS+3
#define X86_HARD_MATH CPU_PARAMS+6
#define X86_CPUID CPU_PARAMS+8
#define X86_CAPABILITY CPU_PARAMS+12
#define X86_VENDOR_ID CPU_PARAMS+16
/*
* swapper_pg_dir is the main page directory, address 0x00101000
* On entry, %esi points to the real-mode code as a 32-bit pointer=0x90000.
*/
ENTRY(stext)
ENTRY(_stext)
startup_32:
/*
* Set segments to known values
*/
cld
movl $(__KERNEL_DS),%eax
movl %eax,%ds
movl %eax,%es
movl %eax,%fs
movl %eax,%gs
#ifdef CONFIG_SMP
......
#endif
/***************************************************************************
#define __PAGE_OFFSET (0xC0000000)
這里是用來初始化pg0以及pg1兩個(gè)頁(yè)表,每個(gè)頁(yè)表項(xiàng)的結(jié)構(gòu):
31 12 11 9 8 7 6 5 4 3 2 1 0
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| | | |P| | |P|P|U|R| |
| page-table base | |G|A|D|A|C|W|/|/|P|
| | | |T| | |D|T|S|W| |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* PAT: 0表示4k,1表示4M
* D: 1表示已經(jīng)寫過,在不需要該頁(yè)面的時(shí)候,應(yīng)該清除該標(biāo)志位
* A: 表示已經(jīng)訪問過
* PCD: 如果為1表示關(guān)閉緩沖存儲(chǔ)器
* PWT: 用于緩沖存儲(chǔ)器
* U/S: 0表示系統(tǒng)權(quán)限,1表示用戶權(quán)限
* R/W: 0-只讀,1-可寫
* P: 0表示相應(yīng)的頁(yè)面不再內(nèi)存中
1、首先獲取pg0的物理地址,并存放到edi中;
2、設(shè)置eax的值為007,準(zhǔn)備將后面每個(gè)表項(xiàng)的P,R/W,U/S全部設(shè)置為1,即PRESENT+RW+USER;
3、將pg0/pg1中的共2048個(gè)表項(xiàng)的base設(shè)置為:0,1,2,3,4,.....,2047。這樣0-8M的物理地址
空間分別被映射到0,1,2,3,4,...表項(xiàng)中;
***************************************************************************/
movl $pg0-__PAGE_OFFSET,%edi
movl $007,%eax
/***************************************************************************
stosl store EAX at address ES:(E)DI;EDI+=4。stosl指令相當(dāng)于將eax中的值保存到
ES:(E)DI指向的地址中。
if ($empty_zero_page-__PAGE_OFFSET - %edi == 0)
ZF = 1
也就是數(shù)如果兩者相等則ZF=1,不相等ZF=0
其實(shí)這里是一個(gè)循環(huán), 將2000H-4000H之間的所有的頁(yè)表項(xiàng)都設(shè)置完畢,填寫完畢后,退出循環(huán),繼續(xù)
往下走,這樣,每個(gè)頁(yè)表項(xiàng)的內(nèi)容分別為:
Base phy Address option
0000*4096 007
0001*4096 007
0002*4096 007
0003*4096 007
0004*4096 007
0005*4096 007
0006*4096 007
...........................
8191*4096 007
***************************************************************************/
2: stosl
add $0x1000,%eax
cmp $empty_zero_page-__PAGE_OFFSET,%edi
jne 2b
/***************************************************************************
Enable paging:
設(shè)置頁(yè)目錄所在的物理地址為0x101000/4096,也就是0x101000除以4K(每個(gè)頁(yè)面的大小)后的基地
址,而cr3的其他的標(biāo)志被順帶初始化成了0。cr3寄存器中存放的就是頁(yè)目錄的基地址。
31 12 11 5 4 3 2 1 0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| | |P|P| |
| page-directory base | |C|W| | CR3
| | |D|T| |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
***************************************************************************/
3:
movl $swapper_pg_dir-__PAGE_OFFSET,%eax
movl %eax,%cr3 /* set the page table pointer.. */
/***************************************************************************
設(shè)置cr0寄存器的PG0標(biāo)志位為1,一旦該標(biāo)志位被設(shè)置, cpu便
進(jìn)入了頁(yè)地址映射階段。CR0:
31 0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|P| |
|G| |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
***************************************************************************/
movl %cr0,%eax
orl $0x80000000,%eax
movl %eax,%cr0 /* ..and set paging (PG) bit */
/******************************************************************************
這條指令時(shí)Intel 386手冊(cè)建議的,其起到了丟棄CPU取指令流水線緩沖的作用。
這里為什么用個(gè)跳轉(zhuǎn)呢?是因?yàn)镃PU不只一條指令管線(instruction pipeline), 所以會(huì)預(yù)先提取指令
(instruction fetching)并譯碼(decoding),但同樣的指令在保護(hù)模式和實(shí)模式中的譯碼結(jié)果是不同
的, 所以要將指令管線中在實(shí)模式譯碼的部分清掉,怎么清呢?執(zhí)行會(huì)產(chǎn)生"過程控制權(quán)轉(zhuǎn)移"的指令即可,如:
jmp,jxx,call,ret,int,iret 等指令。
到現(xiàn)在為止EIP依然在100000H之上的幾兆真實(shí)空間之內(nèi),我們知道內(nèi)核中所有的符號(hào)都被編址在C0100000H
之上,因此在開啟了頁(yè)面映射的情況下,我們應(yīng)該將EIP重定位到0c0100000以上,采用如下指令就可以將eip
重定位到0c0100000以上:
movl $1f,%eax
jmp *%eax
$1f值為0xc01000xx!(為什么是0xc01000xx呢?是因?yàn)橥ㄟ^在jmp后加個(gè)*,gas編譯器和cpu知道是絕
對(duì)跳, 其實(shí)就是當(dāng)作符號(hào)來編譯,也就是要跳到0xc01000xx這個(gè)地址。 從而EIP被重定位到0c0100000以
上。)
而jmp 1f則是相對(duì)跳,gas會(huì)計(jì)算1f跟當(dāng)前計(jì)數(shù)器值的差,弄成個(gè)相對(duì)跳機(jī)器碼,故eip+這個(gè)差值,沒有實(shí)現(xiàn)
reload eip.
*******************************************************************************/
jmp 1f /* flush the prefetch-queue */
1:
movl $1f,%eax
jmp *%eax /* make sure eip is relocated */
1:
/******************************************************************************
Set up the stack pointer:
這里lss SYMBOL_NAME(stack_start),%esp將SS設(shè)置成DS,而SP-->stack_start,從而形成
了8K的系統(tǒng)堆棧,棧頂為init_task_union-->stack的最后一個(gè)元素的地址:
union task_union {
struct task_struct task;
unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
};
| |
|------------|<---SP init_task_union-->stack[2048](long)
| |
| |
|------------|init_task_union
| |
| |
| |
|____________|<---SS
另外這里SS指向的段描述符和DS的完全一樣,而段描述符類型中的ED比特位說明了指定段的擴(kuò)張方向,而非棧
的操作壓入方向。因此雖然DS段中的ED=1,其表示了該段的擴(kuò)展方向是向上的,但是并不會(huì)影響堆棧操作的壓
入方向。這里大概也能猜出內(nèi)核的堆?臻g大概為8K。
這個(gè)堆棧也就作為了Linux內(nèi)核系統(tǒng)的堆棧一直使用下去!!!!!!!!
******************************************************************************/
lss stack_start,%esp
#ifdef CONFIG_SMP
......
#endif CONFIG_SMP
/******************************************************************************
Clear BSS first so that there are no surprises...
No need to cld as DF is already clear from cld above...
把bss對(duì)應(yīng)的空間都通通清0.__bss_start _end都在vmlinux.lds里有,它們的值都比較大(對(duì)應(yīng)的虛
擬地址和物理地址也就比較高)。
******************************************************************************/
xorl %eax,%eax
movl $ SYMBOL_NAME(__bss_start),%edi
movl $ SYMBOL_NAME(_end),%ecx
subl %edi,%ecx
rep /* rep stosb: Fill (E)CX bytes at ES:[(E)DI] with AL.*/
stosb
/******************************************************************************
開始32位系統(tǒng)的建立。我們需要重復(fù)做一些16位模式下建立16位系統(tǒng)的類似事情。
******************************************************************************/
call setup_idt /* 建立中斷向量表 */
/******************************************************************************
在切換到保護(hù)模式之前,最好初始化所有該初始化的。
這里將psw中所有值清為0,用于初始化eflags,注意在compressed/head.S中也有這樣的初始化代碼,這
里為什么要再次初始化一下呢?是因?yàn)樵谶@過程中,eflags由于各種計(jì)算的原因,很多標(biāo)識(shí)已經(jīng)不為0了!!!
******************************************************************************/
pushl $0
popfl
/******************************************************************************
Note: %esi still has the pointer to the real-mode data.0x90000
Copy bootup parameters out of the way. First 2kB of_empty_zero_page is for
boot parameters, second 2kB is for the command line.
將0x90000代碼中的2k東西拷貝到empty_zero_page開始的2K處,同時(shí)將empty_zero_page隨后的2K
清零。這里還要解釋下這里esi既然為90000H,為什么還可以繼續(xù)訪問呢? 很顯然90000H對(duì)應(yīng)的的頁(yè)目錄中
表項(xiàng)的索引為0,而0號(hào)頁(yè)目錄表項(xiàng)指向的就是pg0,而pg0中90H表項(xiàng)對(duì)應(yīng)的頁(yè)地址為90H*4096=90000H,因
此其實(shí)就是和物理地址完全對(duì)應(yīng)的,這就是為什么將swapper_pg_dir中0、1兩條表項(xiàng)設(shè)置成物理地址其實(shí)和
線性地址完全一一對(duì)應(yīng)的道理了,從而即使通過前面的實(shí)模式地址也可以正確訪問到物理地址中的正確數(shù)據(jù)。
******************************************************************************/
movl $ SYMBOL_NAME(empty_zero_page),%edi
movl $512,%ecx
cld
rep
movsl /* rep movsl: Move (E)CX doublewords from DS:[(E)SI] to ES:[(E)DI].edi++,esi++ */
xorl %eax,%eax
movl $512,%ecx
rep
stosl /* rep stosl:Fill (E)CX doublewords at ES:[(E)DI] with EAX.edi++ */
/******************************************************************************
拷貝命令行!!! arch\i386\setup.c中的如下定義均用于初始化命令行:
#define PARAM ((unsigned char *)empty_zero_page)
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
#define E820_MAP_NR (*(char*) (PARAM+E820NR))
#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
#define COMMAND_LINE ((char *) (PARAM+2048))
#define COMMAND_LINE_SIZE 256
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
esi=empty_zero_page+0x228
edi=empty_zero_page+0x800
將從esi= SYMBOL_NAME(empty_zero_page)+0x228開始處的512*4=2K字節(jié)
拷貝到edi處,這里會(huì)導(dǎo)致2k開始的228字節(jié)和empty_zero_page+2048+(2048-228)處重復(fù)。
將新的2k command line弄到empty_zero_page+2048開始處*/
******************************************************************************/
movl SYMBOL_NAME(empty_zero_page)+NEW_CL_POINTER,%esi
andl %esi,%esi
jnz 2f /* New command line protocol,如果該處不為0,表示使用了新命令行,則跳轉(zhuǎn) */
/* JNZ 如果剛剛計(jì)算的結(jié)果不為0則跳轉(zhuǎn)(Jump short if not zero (ZF=0)) */
cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR /* 判斷90020H的值是否為0xA33F(通過頁(yè)表0找到該地址) */
jne 1f
movzwl OLD_CL_OFFSET,%esi
addl $(OLD_CL_BASE_ADDR),%esi
2:
movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
movl $512,%ecx
rep
movsl /* rep movsl: Move (E)CX doublewords from DS:[(E)SI] to ES:[(E)DI].edi++,esi++ */
1:
#ifdef CONFIG_SMP
checkCPUtype:
#endif
/******************************************************************************
檢查cpu類型,首先將boot_cpu_data.cpuid_level:
struct cpuinfo_x86 {
__u8 x86; /* CPU family */
__u8 x86_vendor; /* CPU vendor */
__u8 x86_model;
__u8 x86_mask;
char wp_works_ok; /* It doesn't on 386's */
char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
char hard_math;
char rfu;
int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
__u32 x86_capability[NCAPINTS];
char x86_vendor_id[16];
char x86_model_id[64];
int x86_cache_size; /* in KB - valid for CPUS which support this call */
int fdiv_bug;
int f00f_bug;
int coma_bug;
unsigned long loops_per_jiffy;
unsigned long *pgd_quick;
unsigned long *pmd_quick;
unsigned long *pte_quick;
unsigned long pgtable_cache_sz;
};
#define CPU_PARAMS SYMBOL_NAME(boot_cpu_data)
#define X86 CPU_PARAMS+0
#define X86_VENDOR CPU_PARAMS+1
#define X86_MODEL CPU_PARAMS+2
#define X86_MASK CPU_PARAMS+3
#define X86_HARD_MATH CPU_PARAMS+6
#define X86_CPUID CPU_PARAMS+8
#define X86_CAPABILITY CPU_PARAMS+12
#define X86_VENDOR_ID CPU_PARAMS+16
*/
******************************************************************************/
movl $-1,X86_CPUID /* -1 for no CPUID initially */
/*
* check if it is 486 or 386.
* XXX - this does a lot of unnecessary setup. Alignment checks don't
* apply at our cpl of 0 and the stack ought to be aligned already, and
* we don't need to preserve eflags.
*/
/* 判斷是否是386,先設(shè)置boot_cpu_data.x86=3(386) */
movl $3,X86 # at least 386
pushfl # push EFLAGS
popl %eax # get EFLAGS
movl %eax,%ecx # save original EFLAGS
xorl $0x40000,%eax # flip AC bit in EFLAGS
pushl %eax # copy to EFLAGS
popfl # set EFLAGS
pushfl # get new EFLAGS
popl %eax # put it in eax
xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed
je is386 # 是386則跳轉(zhuǎn)
/* 判斷是否是486,設(shè)置boot_cpu_data.x86=4(486) */
movl $4,X86 # at least 486
movl %ecx,%eax
xorl $0x200000,%eax # check ID flag
pushl %eax
popfl # if we are on a straight 486DX, SX, or
pushfl # 487SX we can't change it
popl %eax
xorl %ecx,%eax
pushl %ecx # restore original EFLAGS
popfl
andl $0x200000,%eax
je is486 # 是486則跳轉(zhuǎn)
/* get vendor info,如果不是486,則獲取供應(yīng)商ID并保存到boot_cpu_data中 */
xorl %eax,%eax # call CPUID with 0 -> return vendor ID
cpuid
movl %eax,X86_CPUID # save CPUID level
movl %ebx,X86_VENDOR_ID # lo 4 chars
movl %edx,X86_VENDOR_ID+4 # next 4 chars
movl %ecx,X86_VENDOR_ID+8 # last 4 chars
orl %eax,%eax # do we have processor info as well?
je is486
/* 獲取CPU類型 */
movl $1,%eax # Use the CPUID instruction to get CPU type
cpuid
movb %al,%cl # save reg for future use
andb $0x0f,%ah # mask processor family
movb %ah,X86
andb $0xf0,%al # mask model
shrb $4,%al
movb %al,X86_MODEL
andb $0x0f,%cl # mask mask revision
movb %cl,X86_MASK
movl %edx,X86_CAPABILITY
is486:
movl %cr0,%eax # 486 or better
andl $0x80000011,%eax # Save PG,PE,ET
orl $0x50022,%eax # set AM, WP, NE and MP
jmp 2f
is386: pushl %ecx # restore original EFLAGS
popfl
movl %cr0,%eax # 386
andl $0x80000011,%eax # Save PG(開啟頁(yè)面映射),PE,ET(開啟保護(hù)模式)
orl $2,%eax # set MP
2: movl %eax,%cr0
call check_x87
#ifdef CONFIG_SMP
incb ready
#endif
/* 加載段描述符表和中斷描述表 */
lgdt gdt_descr
lidt idt_descr
/* 重新加載所有的段寄存器 */
ljmp $(__KERNEL_CS),$1f
1: movl $(__KERNEL_DS),%eax
movl %eax,%ds
movl %eax,%es
movl %eax,%fs
movl %eax,%gs
#ifdef CONFIG_SMP
......
#else
lss stack_start,%esp # Load processor stack,重新設(shè)置堆棧
#endif
xorl %eax,%eax
lldt %ax # LLDT:Load Local Descriptor Table Register,這里ax=0,沒有使用ldtr
#Clears the DF flag in the EFLAGS register.
cld # gcc2 wants the direction flag cleared at all times
#ifdef CONFIG_SMP
.......
#endif
# 進(jìn)入start_kernel內(nèi)核
call SYMBOL_NAME(start_kernel)
L6:
.......
ret
/******************************************************************************
setup_idt:
sets up a idt with 256 entries pointing to ignore_int, interrupt gates. It
doesn't actually load idt - that can be done only after paging has been enabled
and the kernel moved to PAGE_OFFSET. Interrupts are enabled elsewhere, when we
can be relatively sure everything is ok.
struct desc_struct idt_table[256]
__attribute__((__section__(".data.idt"))) = { {0, 0}, };
31 16 15 13 12 8 5 4 0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| | |D | | | |
| offset 31...16 |P|P |0 D 1 1 0|0 0 0| | 高4字節(jié)
| | |L | | | |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
31 16 0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| | |
| segment selector | offset 15...0 | 低4字節(jié)
| | |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
這里 D: 1表示32位,0表示16位
P: 1表示在內(nèi)存
DPL: 描述符優(yōu)先級(jí)
可見下面的代碼將256個(gè)中斷描述符表項(xiàng)的段描述符設(shè)置成CS,將中斷處理程序的地址設(shè)置為ignore_int,
而將相關(guān)的標(biāo)志位設(shè)置成0x8E00,也就是P=1,DPL=0,D=1.
每個(gè)中斷描述符的中斷處理函數(shù)僅僅打印出"Unknown interrupt".
注意:每個(gè)中斷描述符表項(xiàng)中的偏移地址存放的均為邏輯地址
******************************************************************************/
/******************************************************************************
1:準(zhǔn)備好用于初始化的中斷描述符表項(xiàng)的初始值,將默認(rèn)中斷處理程序ignore_int的32位邏輯地址存放到
edx中,edx為即將設(shè)置的每條中斷描述符表項(xiàng)的高32字節(jié)
******************************************************************************/
setup_idt:
lea ignore_int,%edx /* lea mStore,r32 effective address for m in register r32. */
/* 將當(dāng)前中斷對(duì)應(yīng)的段描述符存到eax的高16字節(jié)中,eax為即將設(shè)置的每條中斷描述符表項(xiàng)的低32字節(jié) */
movl $(__KERNEL_CS << 16),%eax
/******************************************************************************
將ignore_int的邏輯地址低16為保存到eax的低16位中去,到這里為止我們已經(jīng)將每條中斷描述符表項(xiàng)
的低32字節(jié)(eax)設(shè)置完畢
******************************************************************************/
movw %dx,%ax /* selector = 0x0010 = cs */
/******************************************************************************
設(shè)置好每條中斷描述符表項(xiàng)的高32字節(jié)中的低16字節(jié),也就是每條中斷描述符表項(xiàng)權(quán)限,到這里為止,我們
已經(jīng)將每條中斷描述符表項(xiàng)的低32字節(jié)(eax)設(shè)置完畢
******************************************************************************/
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
/******************************************************************************
2.準(zhǔn)備好我們將要操作的中斷描述符表項(xiàng)
******************************************************************************/
lea SYMBOL_NAME(idt_table),%edi
mov $256,%ecx
/******************************************************************************
3.在次循環(huán)中我們將所有的共256條中斷描述符表項(xiàng)統(tǒng)統(tǒng)初始化為一樣。
附注:頁(yè)面地址--->物理地址的過程:
邏輯地址addr-->(add>>20)獲取頁(yè)目錄中對(duì)應(yīng)表項(xiàng)-->((add<<10)>>22)獲取頁(yè)表中的表項(xiàng)
--->add & 0xFFF獲取在頁(yè)面中偏移-->線性地址+依據(jù)指令屬性獲取對(duì)應(yīng)的段寄存器-->
在GDTR尋找到該段對(duì)應(yīng)的表項(xiàng)--->獲取其中的基地址+線性地址--->物理地址
******************************************************************************/
rp_sidt:
movl %eax,(%edi)
movl %edx,4(%edi)
addl $8,%edi /* 下一個(gè)中斷描述符表項(xiàng) */
dec %ecx
jne rp_sidt
ret
[ 本帖最后由 alasijiabandao 于 2007-9-19 16:17 編輯 ] |
|