ARM64的启动过程之(二):创建启动阶段的页表
原文地址: http://www.wowotech.net/linux_kenrel/create_page_tables.html
一、前言
本文主要描述了ARM64啟動過程中,如何建立初始化階段頁表的過程。我們知道,從bootloader到kernel的時候,MMU是off的(順帶的負(fù)作用是無法打開data cache),為了提高性能,加快初始化速度,我們必須某個階段(越早越好)打開MMU和cache,而在此之前,我們必須要設(shè)定好頁表。
在初始化階段,我們mapping三段地址,一段是identity mapping,其實就是把物理地址mapping到物理地址上去,在打開MMU的時候需要這樣的mapping(不知道是不是ARM ARCH才這么要求)。第二段是kernel image mapping,內(nèi)核代碼歡快的執(zhí)行當(dāng)然需要將kernel running需要的地址(kernel txt、dernel rodata、data、bss等等)進(jìn)行映射了,第三段是blob memory對應(yīng)的mapping。
在本文中,我們會混用下面的概念:page table和translation table、PGD和Level 0 translation table、PUD和Level 1 translation table、PMD和Level 2 translation table、PTE和Level 3 translation table。最后,還是說明一下,本文來自4.1.10內(nèi)核,有興趣的讀者可以下載來對照閱讀本文。
二、基礎(chǔ)知識
為了更好的理解__create_page_tables的代碼,我們需要準(zhǔn)備一些基礎(chǔ)知識。由于ARM64太復(fù)雜了,各種exception level、各種stage translation、各種地址寬度配置等等讓虛擬地址到物理地址的映射變得非常復(fù)雜,因此,本文focus在一種配置:Non-secure EL1和EL0、stage 1 translation、VA和PA的地址寬度都是48個bit。
1、虛擬地址空間的size是多少?
在32-bit的ARM時代,這個問題問的有點白癡,大家都是耳熟能詳?shù)囊痪湓捑褪敲恳粋€進(jìn)程都有4G的獨立的虛擬地址空間。對于ARM64而言,進(jìn)程需要完全使用2^64那么多的虛擬地址空間嗎?如果需要,那么CPU的MMU單元需要能接受來自處理器發(fā)出的64根地址線的輸入信號,并對其進(jìn)行翻譯,這也就意味著MMU需要更多的晶體管來支持64根地址線的輸入,而CPU也需要驅(qū)動更多的地址線,但是實際上,在短期內(nèi),沒有看出有2^64那么多的虛擬地址空間的需求,因此,ARMv8實際上提供了TCR_EL1 (Translation Control Register (EL1)可以對MMU的輸入地址(也就是虛擬地址)進(jìn)行配置。為了不把問題復(fù)雜化,我們先不考慮TCR_EL2和TCR_EL3這兩個寄存器。通過TCR_EL1寄存器中的TxSZ域可以控制虛擬地址空間的size。對于ARM64(是指處于AArch64狀態(tài)的處理器)而言,最大的虛擬地址的寬度是48 bit,因此虛擬地址空間的范圍是0x0000_0000_0000_0000 ~ 0x0000_FFFF_FFFF_FFFF,總共256TB。
2、物理地址空間的size是多少?
問過虛擬地址空間的size是多少這個問題之后,很自然的會考慮物理地址空間?;靖拍詈蜕弦还?jié)類似,符合ARMv8的PE最大支持的物理地址寬度也是48個bit,當(dāng)然,具體的實現(xiàn)可以自己定義(不能超過48個bit),具體的配置可以通過ID_AA64MMFR0_EL1 (AArch64 Memory Model Feature Register 0)這個RO寄存器獲取。
3、虛擬地址空間到物理地址空間的映射
MMU主要負(fù)責(zé)從VA(virutal address)到PA(Physical address)的翻譯、memory的訪問控制以及memory attribute的控制,這里我們暫時只關(guān)注地址翻譯功能。不同的exception level和security state有自己獨立的地址翻譯過程,當(dāng)然我們這里暫時只關(guān)注Non-secure EL1和EL0,在這種狀態(tài)下,地址翻譯可以分成兩個stage,不過兩個stage是為虛擬化考慮的,因此,為了簡化問題,我們先只考慮一個stage。OK,做了這么多的簡化之后,我們可以來看看地址翻譯過程了(也就是Non-secure EL1和EL0 stage 1情況下的地址翻譯過程)。
一個很有意思的改變(針對ARM32而言)是虛擬地址空間被分成了兩個VA subrange:
Lower VA subrange : 從0x0000_0000_0000_0000 到 (2^(64-T0SZ) - 1)?
Upper VA subrange : 從(2^64 - 2^(64-T1SZ)) 到 0xFFFF_FFFF_FFFF_FFFF
為什么呢?熟悉ARM平臺的工程師都形成了固定的印象,當(dāng)進(jìn)程切換地址空間的時候,實際上切換了內(nèi)核地址空間+用戶地址空間(total 4G地址空間),而實際上,每次進(jìn)程切換的時候,內(nèi)核地址空間都是不變的,實際變化的只有userspace而已。如果硬件支持了VA subrange,那么我們可以這樣使用:
Lower VA subrange : process-specific地址空間?
Upper VA subrange : kernel地址空間
這樣,當(dāng)進(jìn)程切換的時候,我們不必切換kernel space,只要切換userspace就OK了。
地址映射的粒度怎么配置呢?地址映射的粒度用通俗的語言講就是page size(也可能是block size),傳統(tǒng)的page size都是4K,ARM64的MMU支持4K、16K和64K的page size。除了地址映射的粒度還有一個地址映射的level的概念,在ARM32的時代,2 level或者3 level是比較常見的配置,對于ARM64,這和page size、物理地址和虛擬地址的寬度都是有關(guān)系的,具體請參考ARM ARM文檔。
4、AArch64 Linux中虛擬地址空間的布局
把事情搞的太復(fù)雜了往往迷失了重點,我們這里再做一個簡化就是固定page size是4K,并且VA寬度是48個bit,在這種情況下,虛擬地址空間的布局如下:
具體的映射過程如下:
整個地址翻譯的過程是這樣的:首先通過虛擬地址的高位可以知道是屬于userspace還是kernel spce,從而分別選擇TTBR0_EL1(Translation Table Base Register 0 (EL1))或者TTBR1_EL1(Translation Table Base Register 1 (EL1))。這個寄存器中保存了PGD的基地址,該地址指向了一個lookup table,每一個entry都是描述符,可能是Table descriptor、block descriptor或者是page descriptor。如果命中了一個block descriptor,那么地址翻譯過程就結(jié)束了,當(dāng)然對于4-level的地址翻譯過程,PGD中當(dāng)然保存的是Table descriptor,從而指向了下一節(jié)的Translation table,在kernel中稱之PUD。隨后的地址翻譯概念類似,是一個PMD過程,最后一個level是PTE,也就是傳說中的page table entry了,到了最后的地址翻譯階段。這時候PTE中都是一個個的page descriptor,完成最后的地址翻譯過程。
三、代碼分析
本文涉及的代碼就是__create_page_tables這個函數(shù)。
1、initial translation tables的位置。
initial translation tables定義在鏈接腳本文件中(參考arch/arm64/kernel下的vmlinux.lds.S),如下:
. = ALIGN(PAGE_SIZE);?
idmap_pg_dir = .;?
. += IDMAP_DIR_SIZE;?
swapper_pg_dir = .;?
. += SWAPPER_DIR_SIZE;
ARM32的的時候,kernel image在RAM開始的位置讓出了32KB的memory保存了bootloader到kernel傳遞的tag參數(shù)以及內(nèi)核空間的頁表。ARM64中,initial translation tables被放到了kernel image的后面,位于bss段之后。此外,由于虛擬地址空間變大了,因此我們需要更多的page來完成啟動階段的initial translation tables的構(gòu)建。根據(jù)前面的描述,我們知道,內(nèi)核空間的地址大小是256T,48 bit的地址被分成9 + 9 + 9 + 9 + 12,因此PGD(Level 0)、PUD(Level 1)、PMD(Level 2)、PTE(Level 3)的translation table中的entry都是512項,每個描述符是8個byte,因此這些translation table都是4KB,恰好是一個page size。
根據(jù)鏈接腳本中的定義,idmap和swapper page tables (或者叫做translation table)分別保留了3個page的頁面。3個page分別是3個level的translation table。等等,讀者可能會問:上面不是說48 bit VA加上4K page size需要4階translation table嗎?這里怎么只有3個level?實際上,3級映射是PGD/PUM/PMD(每個table占據(jù)一個page),只不過PMD的內(nèi)容不是下一級的table descriptor,而是基于2M block的mapping(或者說PMD中的描述符是block descriptor)。
2、創(chuàng)建頁表前的準(zhǔn)備
? 代碼如下:
__create_page_tables:?
??? adrp??? x25, idmap_pg_dir ------獲取idmap的頁表基地址(物理地址)?
??? adrp??? x26, swapper_pg_dir -----獲取kernel space的頁表基地址(物理地址)?
??? mov??? x27, lr ------保存lr
??? mov??? x0, x25 ----------準(zhǔn)備要invalid cache的地址段的首地址?
??? add??? x1, x26, #SWAPPER_DIR_SIZE -------準(zhǔn)備要invalid cache的地址段的尾地址?
??? bl??? __inval_cache_range ----將idmap和swapper頁表地址段對應(yīng)的cacheline設(shè)定為無效
??? mov??? x0, x25 -------這一段代碼是將idmap和swapper頁表內(nèi)容設(shè)定為0?
??? add??? x6, x26, #SWAPPER_DIR_SIZE ----x0是開始地址,x6是結(jié)束地址?
1:??? stp??? xzr, xzr, [x0], #16?
??? stp??? xzr, xzr, [x0], #16?
??? stp??? xzr, xzr, [x0], #16?
??? stp??? xzr, xzr, [x0], #16?
??? cmp??? x0, x6?
??? b.lo??? 1b
這段代碼沒有什么特別要說明的,除了adrp這條指令。adrp是計算指定的符號地址到run time PC值的相對偏移(不過,這個offset沒有那么精確,是以4K為單位,或者說,低12個bit是0)。在指令編碼的時候,符號地址占據(jù)21個bit,此外,由于偏移計算是按照4K進(jìn)行的,因此符號地址必須要在該指令的-4G和4G之間。由于執(zhí)行該指令的時候,還沒有打開MMU,因此通過adrp獲取的都是物理地址,當(dāng)然該物理地址的低12個bit是全零的。因此,在鏈接腳本中idmap_pg_dir和swapper_pg_dir是page size aligned是必要的。
順便再提一句,將idmap和swapper頁表內(nèi)容設(shè)定為0是有意義的。實際上這些translation table中的大部分entry都是沒有使用的,PGD和PUD都是只有一個entry是有用的,而PMD中有效的entry數(shù)目是和mapping的地址size有關(guān)。將頁表內(nèi)容清零也就是意味著將頁表中所有的描述符設(shè)定為invalid(描述符的bit 0指示是否有效,等于0表示無效描述符)。
3、創(chuàng)建identity mapping
identity mapping實際上就是建立了整個內(nèi)核(從KERNEL_START到KERNEL_END)的一致性mapping,就是將物理地址所在的虛擬地址段mapping到物理地址上去。由于打開MMU操作的時候,內(nèi)核代碼歡快的執(zhí)行,這時候有一個地址映射ON/OFF的切換過程,這種一致性映射可以保證在在打開MMU那一點附近的程序代碼可以平滑切換。具體的操作分成兩個階段,第一個階段是通過create_pgd_entry建立中間level(也就是PGD和PUD)的描述符,第二個階段是創(chuàng)建PMD的描述符,由于PMD的描述符是block descriptor,因此,完成PMD的設(shè)定后就完成了整個identity mapping頁表的設(shè)定。具體代碼如下:
??? ldr??? x7, =MM_MMUFLAGS??
??? mov??? x0, x25---------x0保存了idmap_pg_dir變量的物理地址?
??? adrp??? x3, KERNEL_START---x3保存了內(nèi)核image的物理地址
??? create_pgd_entry x0, x3, x5, x6?
??? mov??? x5, x3??????????????? // __pa(KERNEL_START)?
??? adr_l??? x6, KERNEL_END??????????? // __pa(KERNEL_END)?
??? create_block_map x0, x7, x3, x5, x6
create_pgd_entry用來在PGD(level 0 translation table)中創(chuàng)建一個描述符,如果需要下一級的translation table,也需要同時建立,最終的要求是能夠完成所有中間level的translation table的建立(其實每個table中都是只建立了一個描述符),對于identity mapping,這里需要PGD和PUD就OK了。該函數(shù)需要四個參數(shù):x0是pgd的地址,具體要創(chuàng)建哪一個地址的描述符由x3指定,x5和x6是臨時變量,create_pgd_entry具體代碼如下:
??? .macro??? create_pgd_entry, tbl, virt, tmp1, tmp2?
??? create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2?
??? create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2?
??? .endm
create_table_entry這個宏定義主要是用來創(chuàng)建一個translation table的描述符,具體創(chuàng)建哪一個level的Translation table descriptor是由tbl參數(shù)指定的。怎么來創(chuàng)建描述符呢?如果是table descriptor,那么該描述符需要指向下一級頁表基地址,當(dāng)然,create_table_entry參數(shù)并沒有給出,是在程序中hardcode實現(xiàn):L(n)的translation table中的描述符指向的L(n+1) Translation table位于L(n)translation table所在page的下一個page(太拗口了,但是我也懶得畫圖了)。shift和ptrs這兩個參數(shù)用來計算頁表內(nèi)的index,具體算法可以參考下面的代碼:
.macro??? create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2?
lsr??? \tmp1, \virt, #\shift----------------------------(1)?
and??? \tmp1, \tmp1, #\ptrs - 1 -------------------------(2)?
add??? \tmp2, \tbl, #PAGE_SIZE------------------------(3)?
orr??? \tmp2, \tmp2, #PMD_TYPE_TABLE--------------------(4)?
str??? \tmp2, [\tbl, \tmp1, lsl #3]------------------------(5)?
add??? \tbl, \tbl, #PAGE_SIZE -------------------------(6)?
.endm
(1)如果是PGD,那么shift等于PGDIR_SHIFT,也就是39了。根據(jù)第二章的描述,我們知道L0 index(PGD index)使用虛擬地址的bit[47:39]。如果是PUD,那么shift等于PUD_SHIFT,也就是30了(注意:L1 index(PUD index)使用虛擬地址的bit[38:30])。要想找到virt這個地址(實際傳入的是物理地址,當(dāng)然,我們本來就是要建立和物理地址一樣的虛擬地址的mapping)在translation table中的index,當(dāng)然需要右移shift個bit了。
(2)除了右移操作,我們還需要mask操作(ptrs - 1實際上就是掩碼)。對于PGD,其index占據(jù)9個bit,因此mask是0x1ff。同樣的,對于PUD,其index占據(jù)9個bit,因此mask是0x1ff。至此,tmp1就是virt地址在translation table中對應(yīng)的index了。
(3)如果是table描述符,需要指向另外一個level的translation table,在哪里呢?答案就是next page,讀者可以自行回憶鏈接腳本中的3個連續(xù)的idmap_pg_dir的page定義。
(4)光有下一級translation table的地址不行,還要告知該描述符是否有效(set bit 0),該描述符的類型是哪一種類型(set bit 1表示是table descriptor),至此,描述符內(nèi)容準(zhǔn)備完畢,保存在tmp2中
(5)最關(guān)鍵的一步,將描述符寫入頁表中。之所以有“l(fā)sl #3”操作,是因為一個描述符占據(jù)8個Byte。
(6)將translation table的地址移到next level,以便進(jìn)行下一步設(shè)定。
如果你足夠細(xì)心,一定不會忽略這樣的一個細(xì)節(jié)。獲取KERNEL_START和KERNEL_END的代碼是不一樣的,對于KERNEL_START直接使用了adrp??? x3, KERNEL_START,而對于KERNEL_END使用了adr_l??? x6, KERNEL_END。具體使用哪一個是和該地址是否4K對齊相關(guān)的。KERNEL_START一定是4K對齊的,而KERNEL_END就不一定了,雖然在4.1.10中KERNEL_END也是4K對齊的,不過沒有任何協(xié)議保證這一點,為了保險起見,代碼使用了adr_l,確保獲取正確的KERNEL_END的物理地址。
回到create_pgd_entry函數(shù)中,這個函數(shù)填充了內(nèi)核image首地址對應(yīng)的1G memory range所需要的Translation table描述符,聽起來很嚇人,不過就是兩個描述符,一個是在PGD中,另外一個是在PUD中。雖然只有兩個描述符,可以可以支持1G虛擬地址的mapping了。當(dāng)然具體mapping多少(PMD中有多少entry),還是要看kernel image的size了。
OK,來到PMD部分的設(shè)定了,我們看看代碼:
??? .macro??? create_block_map, tbl, flags, phys, start, end?
??? lsr??? \phys, \phys, #BLOCK_SHIFT?
??? lsr??? \start, \start, #BLOCK_SHIFT?
??? and??? \start, \start, #PTRS_PER_PTE - 1??? // table index?
??? orr??? \phys, \flags, \phys, lsl #BLOCK_SHIFT??? // table entry?
??? lsr??? \end, \end, #BLOCK_SHIFT?
??? and??? \end, \end, #PTRS_PER_PTE - 1??????? // table end index?
9999:??? str??? \phys, [\tbl, \start, lsl #3]??????? // store the entry?
??? add??? \start, \start, #1??????????? // next entry?
??? add??? \phys, \phys, #BLOCK_SIZE??????? // next block?
??? cmp??? \start, \end?
??? b.ls??? 9999b?
??? .endm
create_block_map的名字起得不錯,該函數(shù)就是在tbl指定的Translation table中建立block descriptor以便完成address mapping。具體mapping的內(nèi)容是將start 到 end這一段VA mapping到phys開始的PA上去。其實這里的代碼邏輯和上面類似,我們這里就不詳述,需要提及的是PTE已經(jīng)進(jìn)入了最后一個level的mapping,因此描述符中除了地址信息之外(占據(jù)bit[47:21],還需要memory attribute和memory accesse的信息。對于這個場景,PMD中是block descriptor,因此描述符中還包括了block attribute域,分成upper block attribute[63:52]和lower block attribute[11:2]。對這些域的定義如下:
在代碼中,block attribute是通過flags參數(shù)傳遞的,MM_MMUFLAGS定義如下:
#define MM_MMUFLAGS??? PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS
#define PMD_FLAGS??? PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S
MT_NORMAL表示該段內(nèi)存的memory type是普通memory(對應(yīng)AttrIndx[2:0]),而不是device什么的。PMD_TYPE_SECT 說明該描述符是一個有效的(bit 0等于1)的block descriptor(bit 1等于0)。PMD_SECT_AF中的AF是access flag的意思,表示該memory block(或者page)是否被最近被訪問過。當(dāng)然,這需要軟件的協(xié)助。如果該bit被設(shè)置為0,當(dāng)程序第一次訪問的時候會產(chǎn)生異常,軟件需要將給bit設(shè)置為1,之后再訪問該page的時候,就不會產(chǎn)生異常了。不過當(dāng)軟件認(rèn)為該page已經(jīng)old enough的時候,也可以clear這個bit,表示最近都沒有訪問該page。這個flag是硬件對page reclaim算法的支持,找到最近不常訪問的那些page。當(dāng)然在這個場景下,我們沒有必要enable這個特性,因此將其設(shè)定為1。PMD_SECT_S對應(yīng)SH[1:0],描述memory的sharebility。這些內(nèi)容和memory attribute相關(guān),我們會在后續(xù)的文檔中描述,這里就不偏離主題了。
廣大人民群眾最關(guān)心的當(dāng)然也是最熟悉的是memory access control,這是通過AP[2:1]域來控制的。這里該域被設(shè)定為00b,表示EL1狀態(tài)下是RW,EL0狀態(tài)不可訪問。UXN和PXN是用來控制可執(zhí)行權(quán)限的,這里UXN和PXN都是0,表示EL1和EL0狀態(tài)下都是excutable的。
4、創(chuàng)建kernel space mapping
要創(chuàng)建kernel space的頁表了,遇到的第一個問題就是:mapping多少呢?kernel space辣么大,256T,不可能全部都mapping。OK,答案就是創(chuàng)建兩部分的頁表,一個從kernel image的開始地址(包括開始的那一段TEXT_OFFSET的保留區(qū)域)到kernel image的結(jié)束地址(內(nèi)核的正常運行需要這段mapping),這一段覆蓋了內(nèi)核的正文段、各種data段、bss段、各種奇奇怪怪段等。還以一個就是bootloader傳遞過來的blob memory對應(yīng)的頁表。我們先看第一段kernel image的mapping:
mov??? x0, x26-------------------------(1)?
mov??? x5, #PAGE_OFFSET-------------------(2)?
create_pgd_entry x0, x5, x3, x6-----------------(3)?
ldr??? x6, =KERNEL_END------end address?
mov??? x3, x24??????????????? // phys offset?
create_block_map x0, x7, x3, x5, x6---------------(4)
(1)swapper_pg_dir其實就是swapper進(jìn)程(pid等于0的那個,其實就是idle進(jìn)程)的地址空間,這時候,x0指向了內(nèi)核地址空間的PGD的基地址。
(2)PAGE_OFFSET是kernel image的首地址,對于48bit的VA而言,該地址是0xffff8000-00000000。
(3)創(chuàng)建PAGE_OFFSET(即kernel image首地址)對應(yīng)的PGD和PUD中的描述符。
(4)創(chuàng)建PMD中的描述符。x24保存了__PHYS_OFFSET,實際上也就是kernel image的首地址(物理地址)。
完成了kernel image的mapping,我們來看看blob mapping的建立。由于ARM64 boot protocol要求blob必須在內(nèi)核空間開始的512MB內(nèi)(同時要求2M對齊),因此實際上PGD和PUD都不需要建立了,只要建立PMD的描述符就OK了。對應(yīng)的PMD描述符的建立代碼如下:
mov??? x3, x21--------------FDT phys address?
and??? x3, x3, #~((1 << 21) - 1) ------2MB aligned?
mov??? x6, #PAGE_OFFSET-------kernel space start virtual address?
sub??? x5, x3, x24------------subtract kernel space start physical address
tst??? x5, #~((1 << 29) - 1) --------within 512MB??
csel??? x21, xzr, x21, ne ---------bad blob parameter and zero the FDT pointer?
b.ne??? 1f?
add??? x5, x5, x6 ------------x5 equal blob virtual address?
add??? x6, x5, #1 << 21 ---------mapping 2M size?
sub??? x6, x6, #1??
create_block_map x0, x7, x3, x5, x6---create blob block descriptor in PMD
5、收尾
??? mov??? x0, x25-------再次invalid上文中建立page table memory對應(yīng)的cache?
??? add??? x1, x26, #SWAPPER_DIR_SIZE?
??? dmb??? sy?
??? bl??? __inval_cache_range
??? mov??? lr, x27------恢復(fù)lr?
??? ret-----------返回?
ENDPROC(__create_page_tables)
由于頁表中寫了新的內(nèi)容,而且是在沒有打開cache的情況下寫的,這時候,cache line的數(shù)據(jù)有可能被speculatively load,因此再次invalid是一個比較保險的做法。
四、參考文獻(xiàn)
1、Documentation/arm64/memory.txt
2、ARM Architecture Reference Manual
change log:
1、2015-12-1,修正對PAGE_OFFSET的描述。
原創(chuàng)文章,轉(zhuǎn)發(fā)請注明出處。蝸窩科技
標(biāo)簽: __create_page_tables
?ARM64的啟動過程之(三):為打開MMU而進(jìn)行的CPU初始化|Linux PWM framework(1)_簡介和API描述?評論:
passerby?2015-10-22 15:23 謝謝指點,查了一下ARM32確實有micro tlb和main tlb。但是main tlb做同步用的,它們的作用與arm64的tlb0 tlb1不一樣。
第二個確實是這樣的 0^0,因為一直看到異常向量表是建立在0XFFFF 0000上的,就一直以為設(shè)置為兩個固定地址。 回復(fù) linuxer?
2015-10-22 18:25 @passerby:對于ARM64的EL1狀態(tài),有兩個Translation Table Base Register,叫做TTBR0_EL1和TTBR1_EL1,這兩個寄存器分別指向了用戶空間和內(nèi)核空間的Translation table。
具體TLB的組織是和具體的processor相關(guān),對于Cortex A72而言,其TLB包括兩個level,共計3個,分別是L1 instruction TLB,L1 data TLB和L2 TLB。
ARM32的micro tlb類似L1 instruction TLB和L1 data TLB,Main TLB類似A72中的L2 TLB,其功能是一樣的。 回復(fù) passerby?
2015-10-22 19:19 @linuxer:受教了,謝謝O_O 回復(fù) KO戶外?
2015-10-20 11:07 謝謝分享 回復(fù) 珠海影視制作?
2015-10-19 07:50 好吧, 表示這些我都不懂的 回復(fù) passerby?
2015-10-14 17:03 前段時間也在看aarch64,發(fā)現(xiàn)硬件的進(jìn)步確實給軟件帶來很多優(yōu)化。由于tbl有了兩個,所以kernel和user的頁表可以分離開了。并且arm32中的異常向量表只能放到0xffff 0000或者0x0000 0000,而aarch64有一個寄存器vbar_el1來指定來放異常向量表地址了。
另外我看的是高通的代碼,感覺swapper_pg_dir的建立過程和你上面說的有所不同呢。 回復(fù) linuxer?
2015-10-14 23:06 @passerby:我貼的代碼是標(biāo)準(zhǔn)linux kernel4.1.10版本的代碼,你可以貼出來高通的代碼大家一起研究一下怎么不一樣。 回復(fù) claud?
2015-10-22 11:55 @passerby:@passerby
糾正一下哦:
1.arm32 TLB也是2個, Micro TLB & Main TLB
2.arm32(armv-7)的vector也可以設(shè)置到32字節(jié)對齊的任意地址哦:) 放在CP15 VBAR寄存器中 回復(fù)
總結(jié)
以上是生活随笔為你收集整理的ARM64的启动过程之(二):创建启动阶段的页表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ARM64的启动过程之(一):内核第一个
- 下一篇: ARM64的启动过程之(三):为打开MM