亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問板塊 發(fā)新帖
查看: 8088 | 回復(fù): 3
打印 上一主題 下一主題

前段時(shí)間arch/i386/kernel/head.S注解 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2007-09-19 15:30 |只看該作者 |正序?yàn)g覽
'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 編輯 ]

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2007-09-19 15:36 |只看該作者
原帖由 alasijiabandao 于 2007-9-19 15:34 發(fā)表
中間的好多小人頭怎么回事,能否去掉?


編輯帖子,在左邊勾上「禁用Smiles」即可

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2007-09-19 15:34 |只看該作者
中間的好多小人頭怎么回事,能否去掉?

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2007-09-19 15:32 |只看該作者

回復(fù) #1 alasijiabandao 的帖子

/**********************************************************************
init_task_union為task_union聯(lián)合體變量,注意這里是聯(lián)合體:
union task_union {
struct task_struct task;
unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
};
***********************************************************************/
ENTRY(stack_start)
.long SYMBOL_NAME(init_task_union)+8192
.long __KERNEL_DS

/* This is the default interrupt "handler" :-) */
int_msg:
.asciz "Unknown interrupt\n"
ALIGN
ignore_int:
cld
pushl %eax
pushl %ecx
pushl %edx
pushl %es
pushl %ds
movl $(__KERNEL_DS),%eax
movl %eax,%ds
movl %eax,%es
pushl $int_msg
call SYMBOL_NAME(printk)
popl %eax
popl %ds
popl %es
popl %edx
popl %ecx
popl %eax
iret

/**********************************************************************
The interrupt descriptor table has room for 256 idt's,the global
descriptor table is dependent on the number of tasks we can have..
***********************************************************************/
#define IDT_ENTRIES 256
#define GDT_ENTRIES (__TSS(NR_CPUS)) #=16


.globl SYMBOL_NAME(idt)
.globl SYMBOL_NAME(gdt)

ALIGN
.word 0
idt_descr:
.word IDT_ENTRIES*8-1 # idt contains 256 entries
SYMBOL_NAME(idt):
.long SYMBOL_NAME(idt_table)

.word 0

/***********************************************************************
The layout of the GDT under Linux:

0 - null
1 - not used
2 - kernel code segment
3 - kernel data segment
4 - user code segment <-- new cacheline
5 - user data segment
6 - not used
7 - not used
8 - APM BIOS support <-- new cacheline
9 - APM BIOS support
10 - APM BIOS support
11 - APM BIOS support

The TSS+LDT descriptors are spread out a bit so that every CPU
has an exclusive cacheline for the per-CPU TSS and LDT:

12 - CPU#0 TSS <-- new cacheline
13 - CPU#0 LDT
14 - not used
15 - not used
**********************************************************************/
gdt_descr:
.word GDT_ENTRIES*8-1
SYMBOL_NAME(gdt):
.long SYMBOL_NAME(gdt_table)

/***********************************************************************
This is initialized to create an identity-mapping at 0-8M (for bootup
purposes) and another mapping of the 0-8M area at virtual address
PAGE_OFFSET.

每個(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|S| |A|C|W|/|/|P|
| | | | | | |D|T|S|W| |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

PS: 0表示4k,1表示4M
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)存中
page-table base: 頁(yè)表的物理地址/4096

.long 0x00102007 表示第一個(gè)頁(yè)表的物理地址在0x00102000,也就是指向下面的pg0
.long 0x00102007 表示第二個(gè)頁(yè)表的物理地址在0x00103000,也就是指向下面的pg1
這兩個(gè)表項(xiàng)共同指定了8M的空間。

.fill BOOT_USER_PGD_PTRS-2,4,0表示連續(xù)設(shè)置了766個(gè)值全部為0的表項(xiàng)這里共設(shè)置了
1024個(gè)表項(xiàng),因?yàn)檫壿嫷刂返淖罡?0位表示頁(yè)表目錄的偏移,而2^10=1024,故表示可尋址最大
索引為1024, 也就頁(yè)表是只要有1024項(xiàng)就可以了。

這里前3個(gè)表項(xiàng)表示開始3G的用戶空間,后3個(gè)表項(xiàng)表示后續(xù)1G的內(nèi)核空間,他們的前8M空間都由
第1.2.4.5來表示。
**********************************************************************/
.org 0x1000
ENTRY(swapper_pg_dir)
.long 0x00102007 # 0
.long 0x00103007 # 1
.fill BOOT_USER_PGD_PTRS-2,4,0 # area 766

/***********************************************************************
由于內(nèi)核位于C0000000H以上的內(nèi)存單元,故其邏輯地址中的最高10位,也就是其在頁(yè)目錄表中對(duì)應(yīng)
的索引號(hào),很顯然為768及768以后的表項(xiàng),我們知道每個(gè)頁(yè)目錄表項(xiàng)可以代表4M空間,這樣2個(gè)頁(yè)目錄
表項(xiàng)就可以代表8M空間了每個(gè)頁(yè)目錄表項(xiàng)的作用其實(shí)就是指定了對(duì)應(yīng)頁(yè)表的物理地址
**********************************************************************/
.long 0x00102007
.long 0x00103007

/* default: 254 entries */
.fill BOOT_KERNEL_PGD_PTRS-2,4,0 /* 1024-768-2個(gè)剩余的暫時(shí)不用的頁(yè)目錄表項(xiàng) */

/***********************************************************************
The page tables are initialized to only 8MB here - the final page
tables are set up later depending on memory size.

偽指令org用來規(guī)定目標(biāo)程序存放單元的偏移量。比如,如果在源程序的第一條指令前用了如下指
令: org 200h。那么,匯編程序會(huì)把指令指針的ip的值設(shè)成200h,即目標(biāo)程序的第一個(gè)字節(jié)放
在200h處,后面的內(nèi)容則順序存放,除非遇上另一個(gè)org 語句。

另外需要注意的是,這里的200h是相對(duì)于當(dāng)前section的偏移。例如這里的偏移就是0x2000,
section就是.text, 而.text所在的地址就是0x100000,故這里其實(shí)就是地址0x102000。
**********************************************************************/
.org 0x2000
ENTRY(pg0)

.org 0x3000
ENTRY(pg1)

/***********************************************************************
empty_zero_page must immediately follow the page tables ! (The
initialization loop counts until empty_zero_page)
**********************************************************************/

.org 0x4000
ENTRY(empty_zero_page)

.org 0x5000
ENTRY(empty_bad_page)

.org 0x6000
ENTRY(empty_bad_pte_table)

#if CONFIG_X86_PAE

.org 0x7000
ENTRY(empty_bad_pmd_table)

.org 0x8000

#else

.org 0x7000

#endif

/***********************************************************************
This starts the data section. Note that the above is all in the
text section because it has alignment requirements that we cannot
fulfill any other way.
**********************************************************************/
.data

ALIGN
/***********************************************************************
This contains typically 140 quadwords, depending on NR_CPUS.

NOTE! Make sure the gdt descriptor in head.S matches this if you
change anything.
**********************************************************************/
ENTRY(gdt_table)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* not used */
.quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */
.quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */
.quad 0x00cffa000000ffff /* 0x23 user 4GB code at 0x00000000 */
.quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */
.quad 0x0000000000000000 /* not used */
.quad 0x0000000000000000 /* not used */
/*
* The APM segments have byte granularity and their bases
* and limits are set at run time.
*/
.quad 0x0040920000000000 /* 0x40 APM set up for bad BIOS's */
.quad 0x00409a0000000000 /* 0x48 APM CS code */
.quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */
.quad 0x0040920000000000 /* 0x58 APM DS data */
.fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */

/*
* This is to aid debugging, the various locking macros will be putting
* code fragments here. When an oops occurs we'd rather know that it's
* inside the .text.lock section rather than as some offset from whatever
* function happens to be last in the .text segment.
*/
.section .text.lock
ENTRY(stext_lock)

[ 本帖最后由 alasijiabandao 于 2007-9-19 16:18 編輯 ]
  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP