實模式到保護模式的過渡

本文主要參考《深刻分析linux內核》,配圖都來自這本書,加入了一些本身的理解。linux

頁目錄項的位定義編程

頁表項定義app

本文只會對012位解釋,0present表示是否在內存中oop

  1 /*
  2 * .org new-lc,fill,這條彙編程序指令將本節的位置計數器提早至new-lc(New Location Counter)處,中間的字節被填充fill值,默認爲0
  3 * .fill repeat,size,value 若是size大於8也只會取8,以size爲一組,重複repeat次,填充value值
  4 * 只能在本節中往前,計數器只能增長,因此第一條將位置計數器變爲0xc000000+0x100000+0x1000,由於編譯後這些地址都是虛擬地址,因此
  5 * 爲內核地址須要加上__PAGE_OFFSET,而內核前1M有特殊用途,因此從1M以後開始初始化內存
  6 * swapper_pg_dir爲全局頁目錄起始地址,第0,1項是映射的pg0和pg1,共8M,第3-767項爲空,第768,769項也爲pg0和pg1,第770-1023項爲空
  7 * 因此0x1000手動完成了全局頁目錄的初始化,用戶區和內核區的開始兩項的映射相同
  8 */
  9 .org 0x1000
 10 ENTRY(swapper_pg_dir)
 11 .long 0x00102007
 12 .long 0x00103007
 13 .fill BOOT_USER_PGD_PTRS - 2, 4, 0
 14 /* default: 766 entries */
 15 .long 0x00102007
 16 .long 0x00103007
 17 /* default: 254 entries */
 18 .fill BOOT_KERNEL_PGD_PTRS - 2, 4, 0
 19 
 20 /*
 21 * The page tables are initialized to only 8MB here - the final page
 22 * tables are set up later depending on memory size.
 23 * 後文會介紹完成對這兩個頁表的初始化
 24 */
 25 .org 0x2000
 26 ENTRY(pg0)
 27 
 28 .org 0x3000
 29 ENTRY(pg1)
 30 
 31 /*
 32 * empty_zero_page must immediately follow the page tables ! (The
 33 * initialization loop counts until empty_zero_page)
 34 * 0頁表是不容許訪問的,全是0
 35 */
 36 
 37 .org 0x4000
 38 ENTRY(empty_zero_page)
 39 
 40 .org 0x5000
 41 
 42 /*
 43 * Real beginning of normal "text" segment
 44 * 這裏開始存放內核的代碼段
 45 */
 46 ENTRY(stext)
 47 ENTRY(_stext)
 48 
 49 /*
 50 * This starts the data section. Note that the above is all
 51 * in the text section because it has alignment requirements
 52 * that we cannot fulfill any other way.
 53 * 內核data段
 54 */
 55 .data
 56 
 57 ALIGN
 58 
 59 
 60 /*
 61 * Initialize page tables
 62 * 開始初始化pg0和pg1兩組頁表,pg0- __PAGE_OFFSET就是pg0的起始物理地址0x102000
 63 */
 64 movl $pg0 - __PAGE_OFFSET, %edi /* initialize page tables */
 65 movl $007, %eax        
 66 /* "007" doesn't mean with right to kill, but PRESENT+RW+USER
 67 */
 68 2:
 69 /* 將eax中的值存入edi指定的位置中,於是第一次回在pg0第0項處存入0x007,對應的頁就是起始物理地址爲0的4KB物理內存,edi自動增長4,一項爲4個byte*/
 70 stosl
 71 /* eax+4K,表明下一頁*/
 72 add $0x1000, %eax
 73 /* 若是edi還未到0x4000,繼續循環,即初始化了pg0和pg1兩張頁表 */
 74 cmp $empty_zero_page - __PAGE_OFFSET, %edi
 75 jne 2b
 76 
 77 /*
 78 * Enable paging
 79 */
 80 3:
 81 movl $swapper_pg_dir - __PAGE_OFFSET, %eax
 82 movl %eax, %cr3        /* set the page table pointer.. */
 83 movl %cr0, %eax
 84 orl $0x80000000, %eax
 85 /* 此處啓用cr0的最高位PG容許位,表示開啓分頁機制,但由於eip中存儲的仍爲內存的物理地址,因此cpu對eip中的地址經過分頁機制解析出來將是用戶區
 86 * 的,若是不映射到內存開始8M位置,那兒eip解析出來的物理地址就是無效的,後面的指令就沒法執行了,而咱們須要的是按當前順序繼續執行下去,完成從
 87 * 實模式到保護模式的平穩過渡,內核初始化完成以後會刪除用戶區的這兩個映射
 88 *  ..and set paging (PG) bit
 89 */
 90 movl %eax, %cr0
 91 /* flush the prefetch-queue,這是intel所建議的操做,邏輯上無做用,但能夠將流水線上其餘指令丟棄,避免亂序執行的影響 */
 92 jmp 1f            
 93 1:
 94 /* 上面的jmp是短跳轉,EIP中仍然是物理地址,因此須要手動去完成EIP刷新,下一個1:在編譯生成的時候採用的是虛擬地址,因此跳轉到這個虛擬地址就
 95 * 真正的完成了EIP的虛擬地址更新,也就完成了實模式到保護模式的過渡
 96 */
 97 movl $1f, %eax
 98 jmp *%eax        /* make sure eip is relocated */
 99 1 :
100 /* Set up the stack pointer */
101 lss stack_start, %esp

此時內存映射關係fetch

 

 

以後linux會根據開機加電後的BIOS探測到的物理內存信息進行內存的初始化,生成一張內存構成圖,下一節將會是這些內容。ui

相關文章
相關標籤/搜索