一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

《linux內(nèi)核完全剖析》筆記01-啟動(dòng)分析

 山峰云繞 2023-04-29 發(fā)布于貴州
  • https://blog.csdn.net/body100123/article/details/54315830


  • https://blog.csdn.net/body100123/article/details/54315830

  • 啟動(dòng)代碼分析-《linux 0.12內(nèi)核完全剖析》筆記

  • 導(dǎo)語:

  • linux 0.12的啟動(dòng)代碼能夠給我們分析最新的linux代碼給予一定的啟示,啟動(dòng)代碼雖然只有三個(gè)文件,但是對(duì)讀者分析能力的要求比較高,主要是在對(duì)匯編語言以及x86編程體系的理解


  • 一. 對(duì)linux 0.12啟動(dòng)代碼的分析

  • bootsect.S文件主要的目的是加載setup.S和內(nèi)核模塊

  • setup.S 主要目的是通過biso中斷讀取機(jī)器的系統(tǒng)數(shù)據(jù)

  • head.s 主要目的是內(nèi)核初始化之前的環(huán)境配置,也就是32位保護(hù)模式運(yùn)行做準(zhǔn)備

筆記重點(diǎn):

1. 三段代碼都涉及代碼的移動(dòng)

主要目的是為了空間復(fù)用,代碼是從0x7C00開始執(zhí)行,第一段代碼就將bootsect.S的代碼移動(dòng)到絕對(duì)地址0x9000處然后再執(zhí)行

entry start
start:
    mov ax,#BOOTSEG     "BOOTSEG為0x7C0
    mov ds,ax
    mov ax,#INITSEG     "0x9000
    mov es,ax
    mov cx,#256         "512字節(jié)
    sub si,si           "si = 0x0000
    sub di,di           "di = 0x0000
    rep                 "cx遞減1 直到cx為0
    movw                "移動(dòng)一個(gè)字
    jmpi    go,INITSEG  "跳轉(zhuǎn)到0x9000執(zhí)行

2. 機(jī)器的系統(tǒng)數(shù)據(jù)都是通過BIOS的功能獲取到的,內(nèi)核初始化的時(shí)候都要利用到這些數(shù)據(jù)

  • 最初讀取加載內(nèi)核代碼是使用的BIOS的INT 0x13

  • setup.S中利用BIOS的INT 0x15功能讀取內(nèi)存的大小

  • 其他硬件數(shù)據(jù)

3. setup.S的主要目的是設(shè)置中斷向量表述表和全局描述符表,以開啟內(nèi)核的32位保護(hù)模式

描述符表的定義是在setup.S的567行開始

gdt:
    .word   0,0,0,0     ! dummy

    .word   0x07FF      ! 8Mb - limit=2047 (2048*4096=8Mb)
    .word   0x0000      ! base address=0
    .word   0x9A00      ! code read/exec
    .word   0x00C0      ! granularity=4096, 386

    .word   0x07FF      ! 8Mb - limit=2047 (2048*4096=8Mb)
    .word   0x0000      ! base address=0
    .word   0x9200      ! data read/write
    .word   0x00C0      ! granularity=4096, 386

idt_48:
    .word   0           ! idt limit=0
    .word   0,0         ! idt base=0L

gdt_48:
    .word   0x800       ! gdt limit=2048, 256 GDT entries
    .word   512+gdt,0x9 ! gdt base = 0X9xxxx

設(shè)置GDT寄存器和IDT寄存器是在139行

lidt idt_48
lgdt gdt_48

idt_48h和gdt_48就是上面定義的
是一個(gè)6字節(jié)長(zhǎng)的數(shù)據(jù),前2字節(jié)是表的長(zhǎng)度,后4字節(jié)是表的基地址,設(shè)置cr0的第0位為1開啟保護(hù)模式

4. 這里有非常詳細(xì)的8259A的編程資料

沒有學(xué)過微機(jī)接口的同學(xué)可能對(duì)8259A的結(jié)構(gòu)不夠了解也是沒有關(guān)系,了解這些對(duì)中斷系統(tǒng)的了解比較關(guān)鍵

5. head.s最關(guān)鍵的地方是在32位保護(hù)模式下開啟內(nèi)存的分頁處理機(jī)制

cr3寄存器是記錄頁目錄的基地址,cr0的PG位置1就是開啟分頁處理,然后重新設(shè)置IDT和GDT,第一次設(shè)置IDT和GDT是為了head.s運(yùn)行32位保護(hù)模式,設(shè)置頁目錄而臨時(shí)設(shè)置,這個(gè)時(shí)候還不是分頁模式,不能分配內(nèi)存給GDT和IDT,第一次設(shè)置時(shí)IDT是空表,GDT只有3個(gè)描述符,這次設(shè)置GDT的大小是256*8-1,IDT的大小也是256,這是我認(rèn)為的最主要區(qū)別。

idt_descr:
    .word 256*8-1       "idt 包含256項(xiàng)
    .long _idt
.align 2
.word 0
gdt_descr:
    .word 256*8-1       "gdt 包含256項(xiàng)
    .long _gdt          "地址為下面的_gdt標(biāo)記

    .align 3
_idt:
    .fill 256,8,0       "idt存放的地方

_gdt:   
    .quad 0x0000000000000000    /* NULL descriptor */
    .quad 0x00c09a0000000fff    /* 16Mb */
    .quad 0x00c0920000000fff    /* 16Mb */
    .quad 0x0000000000000000    /* TEMPORARY - don't use */
    .fill 252,8,0           /* space for LDT's and TSS's etc */

結(jié)論:通過對(duì)linux 0.12啟動(dòng)代碼的分析,可以知道linux啟動(dòng)的三大步驟。

  • 首先是通過BIOS提供的功能,加載linux初始化之前的環(huán)境初始化代碼,setup.S和head.s;

  • 然后setup.S通過BIOS的中斷服務(wù)獲取系統(tǒng)硬件的一些參數(shù)并保存,準(zhǔn)備給linux進(jìn)行初始化提供參考;

  • 然后通過head.s設(shè)置系統(tǒng)的32位保護(hù)模式,并開啟內(nèi)存的分頁模式

二. linux 4.9啟動(dòng)代碼分析

導(dǎo)語:

根據(jù)以上對(duì)linux 0.12的分析,知道啟動(dòng)必須經(jīng)過的三個(gè)階段,現(xiàn)在的啟動(dòng)過程,bootsect.S和setup.S部分
的功能已經(jīng)由grub等bootloader來承擔(dān),現(xiàn)在主要分析等同于linux 0.12的head.s部分功能的代碼,現(xiàn)在的內(nèi)核代碼因?yàn)闅v史原因,也因?yàn)樾枰獙?duì)有限內(nèi)存的嵌入式的支持,對(duì)內(nèi)核進(jìn)行了壓縮,在這里暫不對(duì)這些代碼進(jìn)行分析

代碼分析之前有幾點(diǎn)說明
首先是所有標(biāo)號(hào)地址都在編譯內(nèi)核的時(shí)候,多偏移3G
目的是在設(shè)置虛擬地址以后,內(nèi)核映射在進(jìn)程的3G~4G的位置上
因此不管是pa宏還是其他標(biāo)號(hào)地址都在未啟用虛擬地址之前,要減去PAGE_OFFSET

1.先來看.data段中對(duì)GDT和IDT的定義

linux/arch/x86/kernel/head_32.S的727行

  • 734行定義了GDT全局描述符,前兩個(gè)字節(jié)表示表的長(zhǎng)度,后四個(gè)字節(jié)是表的基地址
    boot_gdt - __PAGE_OFFSET為實(shí)際的內(nèi)存物理地址

  • 739行定義IDT描述符,中斷表描述符

  • 740行IDT_ENTRIES為中斷表的大小

  • 755行GDT_ENTRY_BOOT_CS為全局描述符表大小

720 /*
721  * The IDT and GDT 'descriptors' are a strange 48-bit object
722  * only used by the lidt and lgdt instructions. They are not
723  * like usual segment descriptors - they consist of a 16-bit
724  * segment size, and 32-bit linear address value:
725  */
726 
727 .data
728 .globl boot_gdt_descr
729 .globl idt_descr
730 
731         ALIGN
732 # early boot GDT descriptor (must use 1:1 address mapping)
733         .word 0                         # 32 bit align gdt_desc.address
734 boot_gdt_descr:
735         .word __BOOT_DS+7
736         .long boot_gdt - __PAGE_OFFSET
737 
738         .word 0                         # 32-bit align idt_desc.address
739 idt_descr:
740         .word IDT_ENTRIES*8-1           # idt contains 256 entries
741         .long idt_table
742 
743 # boot GDT descriptor (later on used by CPU#0):
744         .word 0                         # 32 bit align gdt_desc.address
745 ENTRY(early_gdt_descr)
746         .word GDT_ENTRIES*8-1
747         .long gdt_page                  /* Overwritten for secondary CPUs */
748 
749 /*
750  * The boot_gdt must mirror the equivalent in setup.S and is
751  * used only for booting.
752  */
753         .align L1_CACHE_BYTES
754 ENTRY(boot_gdt)
755         .fill GDT_ENTRY_BOOT_CS,8,0
756         .quad 0x00cf9a000000ffff        /* kernel 4GB code at 0x00000000 */
757         .quad 0x00cf92000000ffff        /* kernel 4GB data at 0x00000000 */

2.初始化頁目錄表和頁表

linux/arch/x86/kernel/head_32.S的727行

  • 217行是得到內(nèi)核__PAGE_OFFSET位置的頁目錄項(xiàng), 首先虛擬地址的組成是

10位12位10 位
頁目錄項(xiàng)索引頁目錄表索引物理偏移

物理地址偏移向右偏移22位得到頁目錄項(xiàng)索引,每項(xiàng)頁目錄項(xiàng)索引占4字節(jié),左移2位得到特定的頁目錄項(xiàng)索引
* 228行~227行是填充頁目錄項(xiàng)
* 229行~231行是填充頁表項(xiàng)
* 238行~245行是填充最后一頁的對(duì)齊處理

216 
217 page_pde_offset = (__PAGE_OFFSET >> 20);
218 
219         movl $pa(__brk_base), %edi              /* 將__brk_base地址給%edi*/
220         movl $pa(initial_page_table), %edx      /* 將initial_page_table物理地址給%edx*/
221         movl $PTE_IDENT_ATTR, %eax              /* PTE_IDENT_ATTR 是定義頁目錄的屬性的*/
222 10:
223         leal PDE_IDENT_ATTR(%edi),%ecx          /* Create PDE entry */
224         movl %ecx,(%edx)                        /* Store identity PDE entry */
225         movl %ecx,page_pde_offset(%edx)         /* Store kernel PDE entry */
226         addl $4,%edx                            /* 頁目錄項(xiàng)每項(xiàng)占4字節(jié)*/
227         movl $1024, %ecx                        /* 一個(gè)頁目錄項(xiàng)占1024項(xiàng)頁表*/
228 11:
229         stosl                                   /* 將eax的內(nèi)容填充到%edi地址處,并%edi + 4,%eax是頁表項(xiàng)的內(nèi)容*/
230         addl $0x1000,%eax                       /* 0x1000 = 2^12 = 4096*/
231         loop 11b
232         /*
233          * End condition: we must map up to the end + MAPPING_BEYOND_END.
234          */
235         movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
236         cmpl %ebp,%eax
237         jb 10b
238         addl $__PAGE_OFFSET, %edi
239         movl %edi, pa(_brk_end)
240         shrl $12, %eax
241         movl %eax, pa(max_pfn_mapped)
242 
243         /* Do early initialization of the fixmap area */
244         movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
245         movl %eax,pa(initial_page_table+0xffc)

3.啟動(dòng)分頁

linux/arch/x86/kernel/head_32.S的398行

393 enable_paging:
394 
395 /*
396  * Enable paging
397  */
398         movl $pa(initial_page_table), %eax
399         movl %eax,%cr3          /* set the page table pointer.. */
400         movl $CR0_STATE,%eax
401         movl %eax,%cr0          /* ..and set paging (PG) bit */
402         ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */
403 1:
404         /* Shift the stack pointer to a virtual address */
405         addl $__PAGE_OFFSET, %esp

4.設(shè)置IDT

406 
407 /*
408  * start system 32-bit setup. We need to re-do some of the things done
409  * in 16-bit mode for the "real" operations.
410  */
411         movl setup_once_ref,%eax
412         andl %eax,%eax
413         jz 1f                           # Did we do this already?
414         call *%eax

5.設(shè)置內(nèi)核運(yùn)行環(huán)境并跳轉(zhuǎn)到start_kernel

447 is486:
448         movl $0x50022,%ecx      # set AM, WP, NE and MP
449         movl %cr0,%eax
450         andl $0x80000011,%eax   # Save PG,PE,ET
451         orl %ecx,%eax
452         movl %eax,%cr0
453 
454         lgdt early_gdt_descr
455         lidt idt_descr
456         ljmp $(__KERNEL_CS),$1f
457 1:      movl $(__KERNEL_DS),%eax        # reload all the segment registers
458         movl %eax,%ss                   # after changing gdt.
459 
460         movl $(__USER_DS),%eax          # DS/ES contains default USER segment
461         movl %eax,%ds
462         movl %eax,%es
463 
464         movl $(__KERNEL_PERCPU), %eax
465         movl %eax,%fs                   # set this cpu's percpu
466 
467         movl $(__KERNEL_STACK_CANARY),%eax
468         movl %eax,%gs
469 
470         xorl %eax,%eax                  # Clear LDT
471         lldt %ax
472 
473         pushl $0                # fake return address for unwinder
474         jmp *(initial_code)

initial_code的定義如下

654 ENTRY(initial_code)
655         .long i386_start_kernel
656 ENTRY(setup_once_ref)
657         .long setup_once

6.啟動(dòng)入口分析

第97行

 96 __HEAD
 97 ENTRY(startup_32)
 98         movl pa(initial_stack),%ecx         #將堆的初始地址給ecx
 99         
100 /*
    *esi存放了boot_param結(jié)構(gòu)體的地址
    *OFFSET(BP_loadflags,boot_params,hdr.loadflag)
    *位于arch/x86/kernel/asm-offsets.c的84行
    *從bootloader傳過來的參數(shù)告訴內(nèi)核
    *是否需要設(shè)置保護(hù)模式
    *不需要?jiǎng)t跳轉(zhuǎn)到下標(biāo)為的語句
    */
102         testb $KEEP_SEGMENTS, BP_loadflags(%esi)
103         jnz 2f
104 
105 /*
106  * 重新設(shè)置一下保護(hù)模式
     * 加載ds,es,fs,gs,ss
107  */
108         lgdt pa(boot_gdt_descr)
109         movl $(__BOOT_DS),%eax
110         movl %eax,%ds
111         movl %eax,%es
112         movl %eax,%fs
113         movl %eax,%gs
114         movl %eax,%ss
115 2:
116         leal -__PAGE_OFFSET(%ecx),%esp
117 
118 /*
119  * 清空BSS
120  */
121         cld
122         xorl %eax,%eax
123         movl $pa(__bss_start),%edi
124         movl $pa(__bss_stop),%ecx
125         subl %edi,%ecx
126         shrl $2,%ecx
127         rep ; stosl
128 /*
129  * 拷貝boot_params結(jié)構(gòu)體的內(nèi)容到內(nèi)核中
135  */
136         movl $pa(boot_params),%edi
137         movl $(PARAM_SIZE/4),%ecx
138         cld
139         rep
140         movsl
141         movl pa(boot_params) + NEW_CL_POINTER,%esi
142         andl %esi,%esi
143         jz 1f                   # No command line
144         movl $pa(boot_command_line),%edi
145         movl $(COMMAND_LINE_SIZE/4),%ecx
146         rep
147         movsl
148 1:
149

結(jié)論:

經(jīng)過分析,基本了解head_32.S是linux進(jìn)入start_kernel之前,為內(nèi)核初始化準(zhǔn)備環(huán)境,設(shè)置GDT,IDT,開啟32位保護(hù)模式,開啟分頁模式。和linux 0.12的head.s的功能如出一轍。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美一级特黄大片做受大屁股| 日韩欧美一区二区黄色| 国产不卡免费高清视频| 日本一区不卡在线观看| 日韩精品在线观看完整版| 日韩人妻一区二区欧美| 视频一区中文字幕日韩| 亚洲欧美日韩另类第一页| 福利视频一区二区在线| 欧美野外在线刺激在线观看| 99久久人妻中文字幕| 91偷拍视频久久精品| 亚洲国产欧美精品久久| 爱草草在线观看免费视频| 日本精品中文字幕在线视频 | 国产精品欧美一区二区三区不卡| 欧美视频在线观看一区| 欧美日韩欧美国产另类| 一区二区三区精品人妻| 日韩免费av一区二区三区| 久久碰国产一区二区三区| 性感少妇无套内射在线视频| 五月综合激情婷婷丁香| 日本精品最新字幕视频播放| 日本免费一本一二区三区| 99久久国产精品免费| 欧美人禽色视频免费看| 人妻少妇av中文字幕乱码高清| 人妻少妇久久中文字幕久久| 午夜福利国产精品不卡| 亚洲综合一区二区三区在线| 日韩精品少妇人妻一区二区| 国产日韩精品激情在线观看| 欧美日韩一区二区三区色拉拉| 中文字幕一区二区久久综合| 很黄很污在线免费观看| 国产精品免费自拍视频| 日韩成人午夜福利免费视频| 亚洲欧美日本视频一区二区| 国产精品福利一级久久| 麻豆果冻传媒一二三区|