ARM64的启动过程之(四):打开MMU
原文地址:http://www.wowotech.net/linux_kenrel/turn-on-mmu.html
一、前言
經(jīng)過(guò)漫長(zhǎng)的前戲,我們終于迎來(lái)了打開(kāi)MMU的時(shí)刻,本文主要描述打開(kāi)MMU以及跳轉(zhuǎn)到start_kernel之前的代碼邏輯。這一節(jié)完成之后,我們就會(huì)離開(kāi)痛苦的匯編,進(jìn)入人民群眾喜聞樂(lè)見(jiàn)的c代碼了。
二、打開(kāi)MMU前后的概述
對(duì)CPU以及其執(zhí)行的程序而言,打開(kāi)MMU是一件很有意思的事情,好象從現(xiàn)實(shí)世界一下子走進(jìn)了奇妙的虛幻世界,本節(jié),我們一起來(lái)看看內(nèi)核是如何“穿越”的。下面這張圖描述了兩個(gè)不同的世界:
當(dāng)沒(méi)有打開(kāi)MMU的時(shí)候,cpu在進(jìn)行取指以及數(shù)據(jù)訪問(wèn)的時(shí)候是直接訪問(wèn)物理內(nèi)存或者IO memory。雖然64bit的CPU理論上擁有非常大的address space,但是實(shí)際上用于存儲(chǔ)kernel image的物理main memory并沒(méi)有那么大,一般而言,系統(tǒng)的main memory在低端的一小段物理地址空間中,如上圖右側(cè)的圖片所示。當(dāng)打開(kāi)MMU的時(shí)候,cpu對(duì)memory系統(tǒng)的訪問(wèn)不能直接觸及物理空間,而是需要通過(guò)一系列的Translation table進(jìn)行翻譯。虛擬地址空間分成三段,低端是0x00000000_00000000~0x0000FFFF_FFFFFFFF,用于user space。高端是0xFFFF0000_00000000~0xFFFFFFFF_FFFFFFFF,用于kernel space。中間的一段地址是無(wú)效地址,對(duì)其訪問(wèn)會(huì)產(chǎn)生MMU fault。虛擬地址空間如上圖右側(cè)的圖片所示。
Linker感知的是虛擬地址,在將內(nèi)核的各個(gè)object文件鏈接成一個(gè)kernel image的時(shí)候,kernel image binary code中訪問(wèn)的都是虛擬地址,也就是說(shuō)kernel image應(yīng)該運(yùn)行在Linker指定的虛擬地址空間上。問(wèn)題來(lái)了,kernel image運(yùn)行在那個(gè)地址上呢?實(shí)際上,將kernel image放到kernel space的首地址運(yùn)行是一個(gè)最直觀的想法,不過(guò)由于各種原因,具體的arch在編譯內(nèi)核的時(shí)候,可以指定一個(gè)offset(TEXT_OFFSET),對(duì)于ARM64而言是512KB(0x00080000),因此,編譯后的內(nèi)核運(yùn)行在0xFFFF8000_00080000的地址上。系統(tǒng)啟動(dòng)后,bootloader會(huì)將kernel image copy到main memory,當(dāng)然,和虛擬地址空間類似,kernel image并沒(méi)有copy到main memory的首地址,也保持了一個(gè)同樣size的offset。現(xiàn)在,問(wèn)題又來(lái)了:在kernel的開(kāi)始運(yùn)行階段,MMU是OFF的,也就是說(shuō)kernel image是直接運(yùn)行在物理地址上的,但是實(shí)際上kernel是被linker鏈接到了虛擬地址上去的,在這種情況下,在沒(méi)有turn on MMU之前,kernel能正常運(yùn)行嗎?可以的,如果kernel在turn on MMU之前的代碼都是PIC的,那么代碼實(shí)際上是可以在任意地址上運(yùn)行的。你可以仔細(xì)觀察turn on MMU之前的代碼,都是位置無(wú)關(guān)的代碼。
OK,解決了MMU turn on之前的問(wèn)題,現(xiàn)在我們可以準(zhǔn)備“穿越”了。真正打開(kāi)MMU就是一條指令而已,就是將某個(gè)system register的某個(gè)bit設(shè)定為1之類的操作。這樣我們可以把相關(guān)指令分成兩組,turn on mmu之前的綠色指令和之后的橘色指令,如下圖所示:
由于現(xiàn)代CPU的設(shè)計(jì)引入了pipe, super scalar,out-of-order execution,分支預(yù)測(cè)等等特性,實(shí)際上在turn on MMU的指令執(zhí)行的那個(gè)時(shí)刻,該指令附近的指令的具體狀態(tài)有些混亂,可能綠色指令執(zhí)行的數(shù)據(jù)加載在實(shí)際在總線上發(fā)起bus transaction的時(shí)候已經(jīng)啟動(dòng)了MMU,本來(lái)它是應(yīng)該訪問(wèn)physical address space的。而也有可能橘色的指令提前執(zhí)行,導(dǎo)致其發(fā)起的memory操作在MMU turn on之前就完成。為了解決這些混亂,可以采取一種投機(jī)取巧的辦法,就是建立一致性映射:假設(shè)kernel image對(duì)應(yīng)的物理地址段是A~B這一段,那么在建立頁(yè)表的時(shí)候就把A~B這段虛擬地址段映射到A~B這一段的物理地址。這樣,在turn on MMU附近的指令是毫無(wú)壓力的,無(wú)論你是通過(guò)虛擬地址還是物理地址,訪問(wèn)的都是同樣的物理memory。
還有一種方法,就是清楚的隔離turn on MMU前后的指令,那就是使用指令同步工具,如下:
指令屏障可以清清楚楚的把指令的執(zhí)行劃分成三段,第一段是綠色指令,在執(zhí)行turn on mmu指令執(zhí)行之前全部完成,隨后啟動(dòng)turn on MMU的指令,隨后的指令屏障可以確保turn on MMU的指令完全執(zhí)行完畢(整個(gè)計(jì)算機(jī)系統(tǒng)的視圖切換到了虛擬世界),這時(shí)候才啟動(dòng)橘色指令的取指、譯碼、執(zhí)行等操作。
三、打開(kāi)MMU的代碼
具體打開(kāi)MMU的代碼在__enable_mmu函數(shù)中如下:
__enable_mmu:?
??? ldr??? x5, =vectors?
??? msr??? vbar_el1, x5 ---------------------------(1)?
??? msr??? ttbr0_el1, x25??????????? // load TTBR0 -----------------(2)?
??? msr??? ttbr1_el1, x26??????????? // load TTBR1?
??? isb?
??? msr??? sctlr_el1, x0 ---------------------------(3)?
??? isb?
??? br??? x27 -------------跳轉(zhuǎn)到__mmap_switched執(zhí)行,不設(shè)定lr寄存器?
ENDPROC(__enable_mmu)
傳入該函數(shù)的參數(shù)有四個(gè),一個(gè)是x0寄存器,該寄存器中保存了打開(kāi)MMU時(shí)候要設(shè)定的SCTLR_EL1的值(在__cpu_setup函數(shù)中設(shè)定),第二個(gè)是個(gè)是x25寄存器,保存了idmap_pg_dir的值。第三個(gè)參數(shù)是x26寄存器,保存了swapper_pg_dir的值。最后一個(gè)參數(shù)是x27,是執(zhí)行完畢該函數(shù)之后,跳轉(zhuǎn)到哪里去執(zhí)行(__mmap_switched)。
(1)VBAR_EL1, Vector Base Address Register (EL1),該寄存器保存了EL1狀態(tài)的異常向量表。在ARMv8中,發(fā)生了一個(gè)exception,首先需要確定的是該異常將送達(dá)哪一個(gè)exception level。如果一個(gè)exception最終送達(dá)EL1,那么cpu會(huì)跳轉(zhuǎn)到這里向量表來(lái)執(zhí)行。具體異常的處理過(guò)程由其他文檔描述,這里就不說(shuō)了。
(2)idmap_pg_dir是為turn on MMU準(zhǔn)備的一致性映射,未來(lái)將會(huì)用于用戶空間的進(jìn)程,在進(jìn)程切換的時(shí)候,其地址空間的切換實(shí)際就是修改TTBR0的值。TTBR1用于kernel space,所有的內(nèi)核線程都是共享一個(gè)空間就是swapper_pg_dir。
(3)打開(kāi)MMU。實(shí)際上在這條指令的上下都有isb指令,理論上已經(jīng)可以turn on MMU之前之后的代碼執(zhí)行順序嚴(yán)格的定義下來(lái),其實(shí)我感覺(jué)不必要再啟用idmap_pg_dir的那些頁(yè)表了,當(dāng)然,這只是猜測(cè)。
四、通向start_kernel
我痛恨匯編,如果能不使用匯編那絕對(duì)不要使用匯編,還好我們馬上就要投奔start_kernel:
__mmap_switched:?
??? adr_l??? x6, __bss_start?
??? adr_l??? x7, __bss_stop
1:??? cmp??? x6, x7?
??? b.hs??? 2f?
??? str??? xzr, [x6], #8 ---------------clear BSS?
??? b??? 1b?
2:?
??? adr_l??? sp, initial_sp, x4 -----------建立和swapper進(jìn)程的鏈接?
??? str_l??? x21, __fdt_pointer, x5??????? // Save FDT pointer?
??? str_l??? x24, memstart_addr, x6??????? // Save PHYS_OFFSET?
??? mov??? x29, #0?
??? b??? start_kernel?
ENDPROC(__mmap_switched)
這段代碼分成兩個(gè)部分,一部分是清BSS,另外一部分是為進(jìn)入c代碼做準(zhǔn)備(主要是stack)。clear BSS段就是把未初始化的全局變量設(shè)定為0的初值,沒(méi)有什么可說(shuō)的。要進(jìn)入start_kernel這樣的c代碼,沒(méi)有stack可不行,那么如何設(shè)定stack呢?熟悉kernel的人都知道,用戶空間的進(jìn)程當(dāng)陷入內(nèi)核態(tài)的時(shí)候,stack切換到內(nèi)核棧,實(shí)際上就是該進(jìn)程的thread info內(nèi)存段(4K或者8K)的頂部。對(duì)于swapper進(jìn)程,原理是類似的:
.set??? initial_sp, init_thread_union + THREAD_START_SP
如果說(shuō)之前的代碼執(zhí)行都處于一個(gè)孤魂野鬼的狀態(tài),“adr_l??? sp, initial_sp, x4”指令執(zhí)行之后,初始化代碼終于找到了歸宿,初始化代碼有了自己的thread info,有了自己的task struct,有了自己的pid,有了進(jìn)程(內(nèi)核線程)應(yīng)該擁有的一切,從此之后的代碼歸屬idle進(jìn)程,pid等于0的那個(gè)進(jìn)程。
為了方便后面的代碼的訪問(wèn),這里還初始化了兩個(gè)變量,分別是__fdt_pointer(設(shè)備樹(shù)信息,物理地址)和memstart_addr(kernel image所在的物理地址,一般而言是main memory的首地址)。 memstart_addr主要用于main memory中物理地址和虛擬地址的轉(zhuǎn)換,具體可以參考__virt_to_phys和__phys_to_virt的實(shí)現(xiàn)。
五、參考文獻(xiàn)
1、ARM Architecture Reference Manual
change log:
1、2015-11-30,強(qiáng)調(diào)了初始化代碼和idle進(jìn)程的連接
2、2015-12-2,修改了物理空間和虛擬空間的視圖
原創(chuàng)文章,轉(zhuǎn)發(fā)請(qǐng)注明出處。蝸窩科技
標(biāo)簽: 打開(kāi)MMU
?作業(yè)系統(tǒng)之前的程式 for rpi2 (1) - mmu (0) : 位址轉(zhuǎn)換|ARM64的啟動(dòng)過(guò)程之(三):為打開(kāi)MMU而進(jìn)行的CPU初始化?評(píng)論:
amusion?2015-10-28 11:25 無(wú)意中看到了這個(gè)網(wǎng)站,拜讀了幾篇文章后,真是很欽佩啊,文章分析的很深入,不知能否寫些和SMP先關(guān)的分析 回復(fù) linuxer?
2015-10-29 08:59 @amusion:這位客官,本站暫時(shí)不接受“點(diǎn)菜”,呵呵~~~開(kāi)玩笑的,大家工作都很忙,業(yè)余時(shí)間寫寫文章,讓自己爽一下,所以,想到哪里寫到哪里,SMP的代碼分布在各個(gè)內(nèi)核的子系統(tǒng)中,其實(shí)不是很好寫的。 回復(fù) kitty?
2015-10-27 17:31 博主真的是辛苦了,像博主這樣靜下心搞鉆研,如此認(rèn)真隱忍的,太少了。 回復(fù) linuxer?
2015-10-27 18:30 @kitty:不辛苦,如果真心熱愛(ài)的話就不辛苦,^_^
喜歡鉆研的人很多,只是沒(méi)有聚合在一起,蝸窩這個(gè)網(wǎng)站就是因此而設(shè)立的,歡迎每一個(gè)沉醉于技術(shù)的人。 回復(fù) kitty?
2015-10-30 10:38 @linuxer:hi linuxer,看你寫的power相關(guān)文章,寫的非常詳細(xì)。但power相關(guān)架構(gòu),很多要進(jìn)行調(diào)整了,在今年年底,linuro要發(fā)布一個(gè)新的調(diào)度器架構(gòu)EAS,會(huì)把DVFS和cpu idle添加CFS調(diào)度器中,而themal也會(huì)被IPA機(jī)制取代,這是新的研究方向,感興趣的話,可以一起學(xué)習(xí)。 回復(fù) mobz?
2015-10-27 14:16 Hi linuxer,看到你最近有對(duì)系統(tǒng)啟動(dòng)做詳細(xì)的分析,正好遇到個(gè)問(wèn)題,想請(qǐng)教你下,就是在內(nèi)核里的函數(shù)kernel_execve,有下面這樣一段匯編代碼,最終將調(diào)用到ret_to_user嗎?是個(gè)什么流程?
????asm(????"add????r0, %0, %1\n\t"
????????"mov????r1, %2\n\t"
????????"mov????r2, %3\n\t"
????????"bl memmove\n\t"????/* copy regs to top of stack */
????????"mov????r8, #0\n\t" /* not a syscall */
????????"mov????r9, %0\n\t" /* thread structure */
????????"mov????sp, r0\n\t" /* reposition stack pointer */
????????"b??ret_to_user"
????????:
????????: "r" (current_thread_info()),
??????????"Ir" (THREAD_START_SP - sizeof(regs)),
??????????"r" (®s),
??????????"Ir" (sizeof(regs))
????????: "r0", "r1", "r2", "r3", "r8", "r9", "ip", "lr", "memory"); 回復(fù) linuxer?
2015-10-27 17:47 @mobz:無(wú)論是userspace還是kernel space,都有執(zhí)行程序的需求。例如在內(nèi)核空間,當(dāng)把控制權(quán)轉(zhuǎn)交給userspace的時(shí)候,需要執(zhí)行/sbin/init(也有可能是其他程序)。用戶空間的使用場(chǎng)景更多,你在terminal上輸入某一個(gè)程序的命令行的時(shí)候,shell程序會(huì)fork,然后調(diào)用execve來(lái)執(zhí)行程序。
所謂執(zhí)行某一個(gè)二進(jìn)制程序其實(shí)就是內(nèi)核態(tài)的loader將當(dāng)前進(jìn)程的地址空間(text,data,bss和stack)銷毀,使用新的可執(zhí)行程序的image來(lái)創(chuàng)建新的進(jìn)程的過(guò)程,因此返回調(diào)用函數(shù)是沒(méi)有任何意義的(實(shí)際上也不存在了)。但是,內(nèi)核的loader總是要把控制權(quán)交給這個(gè)新創(chuàng)建的進(jìn)程,因此,loader在這個(gè)新進(jìn)程的內(nèi)核棧上模擬了一次陷入內(nèi)核的過(guò)程,在內(nèi)核棧上構(gòu)建了一個(gè)“現(xiàn)場(chǎng)”,然后調(diào)用ret_to_user返回userspace,開(kāi)始新的進(jìn)程的執(zhí)行,當(dāng)然,CPU的PC值會(huì)設(shè)定為二進(jìn)制程序image的入口函數(shù)。 回復(fù) mobz?
2015-10-27 20:03 @linuxer:ret_to_user會(huì)調(diào)用到arch_ret_to_user r1, lr 這里,可是我還是沒(méi)搞懂這個(gè)arch_ret_to_user又是如何實(shí)現(xiàn)的?代碼中怎么也搜索不到??還是我沒(méi)看懂。
因?yàn)槲医?jīng)常遇到內(nèi)核啟動(dòng)到Freeing init memory后就卡住的問(wèn)題.定位發(fā)現(xiàn)應(yīng)該就是卡在返回用戶空間來(lái)是執(zhí)行init進(jìn)程的時(shí)候出現(xiàn)的問(wèn)題,就像類是bootargs設(shè)置錯(cuò)誤導(dǎo)致
ENTRY(ret_to_user)
ret_slow_syscall:
????disable_irq???????????? @ disable interrupts
ENTRY(ret_to_user_from_irq)
????ldr r1, [tsk, #TI_FLAGS]
????tst r1, #_TIF_WORK_MASK
????bne work_pending
no_work_pending:
#if defined(CONFIG_IRQSOFF_TRACER)
????asm_trace_hardirqs_on
#endif
????/* perform architecture specific actions before user return */
????arch_ret_to_user r1, lr
????restore_user_regs fast = 0, offset = 0
ENDPROC(ret_to_user_from_irq)
ENDPROC(ret_to_user) 回復(fù) linuxer?
2015-10-28 08:58 @mobz:我正在讀的是4.1.10版本中的ARM64的代碼,其中其實(shí)都沒(méi)有kernel_execve這個(gè)函數(shù),也沒(méi)有arch_ret_to_user。
看起來(lái)arm平臺(tái)有arch_ret_to_user的定義,在linux/arch/arm/kernel/entry-common.S文件中:
#ifdef CONFIG_NEED_RET_TO_USER
#include <mach/entry-macro.S>
#else
????.macro??arch_ret_to_user, tmp1, tmp2
????.endm
#endif 回復(fù) mobz?
2015-10-28 09:49 @linuxer:恩,是的,但是這個(gè)是怎么實(shí)現(xiàn)從return to userspace的?沒(méi)看懂只有定義,實(shí)現(xiàn)呢?不理解這里 回復(fù) linuxer?
2015-10-28 12:28 @mobz:與其說(shuō)arch_ret_to_user是architecture specific,不如說(shuō)是ARM arch下,machine specific。對(duì)于有些特殊的arm machine(例如ARCH_IOP13XX),在返回用戶空間的時(shí)候需要特別的操作,但是對(duì)于大部分的ARM處理器,arch_ret_to_user是空的。 回復(fù) mobz?
2015-10-28 13:39 @linuxer:那這么說(shuō)來(lái),其實(shí)從內(nèi)核到用戶空間就是:下面這三條語(yǔ)句(指令)了咯???
????disable_irq
????ldr r1, [tsk, #TI_FLAGS]
????tst r1, #_TIF_WORK_MASK linuxer?
2015-10-28 14:41 @linuxer:后面不是有一個(gè)restore_user_regs嘛,用于從內(nèi)核棧恢復(fù)userspace的上下文 mobz?
2015-10-28 18:46 @linuxer:在你最新的答復(fù)上回復(fù)不了,就回復(fù)在這里吧,restore_user_regs 這個(gè)和arch_ret_to_user在ARM平臺(tái)上也是一樣的,都是空,我并沒(méi)在代碼中找到相關(guān)的內(nèi)容,倒是在FRV平臺(tái)里找到有 linuxer?
2015-10-29 08:35 @linuxer:在arch/arm/kernel/entry-head.S中有定義(我的內(nèi)核版本是4.1.10,其他版本應(yīng)該類似吧)。 passerby?
2015-10-27 09:10 我在paging_init中的map_mem
for_each_memblock(memory, reg) {
????????phys_addr_t start = reg->base;
????????phys_addr_t end = start + reg->size;
????????if (start >= end)
????????????break;
????????????????create_mapping(start, __phys_to_virt(start), end - start,
????????????????????false);
????}
對(duì)所有的memblock進(jìn)行映射,這里就包括了在匯編中映射好的kernel image。 回復(fù) linuxer?
2015-10-27 15:30 @passerby:要回答這個(gè)問(wèn)題,需要理解memory blocks模塊(mm/memblock.c文件)。
該模塊定義了一個(gè)全局變量:
struct memblock memblock;
這個(gè)全局變量用來(lái)管理系統(tǒng)中的所有的memory blocks。這些blocks分成兩種:
1、reserved
2、memory
從邏輯上講,無(wú)論那種類型的block,其address region不能是overlap的(因此會(huì)有memory region的分裂和合并的操作)。
在函數(shù)arm64_memblock_init函數(shù)中會(huì)調(diào)用memblock_reserve(__pa(_text), _end - _text)將kernel image的這段memory region加入“reserved”那種類型的memory blocks。
而你說(shuō)的for_each_memblock(memory, reg) ,僅僅是遍歷“memory”那種類型的memroy blocks。而一旦你reserved了kernel image對(duì)應(yīng)的那一段memory region,它是不會(huì)出現(xiàn)在memory類型的blocks中,因此不會(huì)再次mapping。
BTW,我非常簡(jiǎn)單的過(guò)了一下memblock.c的代碼,很多是從邏輯上推導(dǎo)的,可能有誤。 回復(fù) passerby?
2015-10-27 16:52 @linuxer:對(duì)于不做mapping有點(diǎn)疑問(wèn),因?yàn)槠渌膔eserved的內(nèi)存也需要被做映射啊。比如
91???????? cont_splash_mem: splash_region@83000000 {
??92???????????? linux,reserve-contiguous-region;
??93???????????? linux,reserve-region;
??94???????????? reg = <0x0 0x83000000 0x0 0x2000000>;
??95???????????? label = "cont_splash_mem";
??96???????? };
kernel image可以不做,但是其他的reserved空間并沒(méi)有做mapping。在其他地方我并沒(méi)有看到對(duì)reserverd做mapping的地方,只有在這里有看到。 回復(fù) linuxer?
2015-10-27 18:26 @passerby:通過(guò)device tree中的reserved-memory節(jié)點(diǎn)可以定義若干的reserved memory block,這些保留的memory region基本上被認(rèn)為是for特定驅(qū)動(dòng)使用的,因此,我的觀點(diǎn)是:內(nèi)核不會(huì)進(jìn)行mapping,使用這些memory的driver應(yīng)該負(fù)責(zé)進(jìn)行mapping。 回復(fù) passerby?
2015-10-26 11:18 @linuxer,有個(gè)小問(wèn)題,在匯編中建立的頁(yè)表是將整個(gè)內(nèi)核都做了映射嗎? 回復(fù) linuxer?
2015-10-26 12:14 @passerby:是的,是將整個(gè)kernel image進(jìn)行了映射,開(kāi)始和結(jié)束的定義是:
#define KERNEL_START????_text
#define KERNEL_END????_end
當(dāng)然,和整個(gè)內(nèi)核空間比,這一段實(shí)際上也不大的。 回復(fù) passerby?
2015-10-26 13:05 @linuxer:那映射完了,在start_kernel又會(huì)做一次page_init映射。這個(gè)時(shí)候匯編中做的映射會(huì)被拋棄掉重新做?不過(guò)不是,那這部分page怎么告訴伙伴系統(tǒng)這部分空間已經(jīng)被占用的? 回復(fù) linuxer?
2015-10-26 19:02 @passerby:那映射完了,在start_kernel又會(huì)做一次page_init映射。這個(gè)時(shí)候匯編中做的映射會(huì)被拋棄掉重新做?
------------------------------------
在start_kernel中不會(huì)拋棄”匯編時(shí)代“的映射,因?yàn)闆](méi)有必要,都已經(jīng)建立了又何必毀掉呢。
那這部分page怎么告訴伙伴系統(tǒng)這部分空間已經(jīng)被占用的?
------------------------------
伙伴系統(tǒng)其實(shí)不需要管理kernel image占用的內(nèi)存,這是通過(guò)arm64_memblock_init函數(shù)中的下面代碼實(shí)現(xiàn):
memblock_reserve(__pa(_text), _end - _text); 回復(fù) donkey?
2015-12-30 17:05 @linuxer:有個(gè)問(wèn)題想請(qǐng)教一下,我最近在看ARM64啟動(dòng)的代碼,現(xiàn)在正在研究跳到內(nèi)核后正式頁(yè)表的創(chuàng)建流程。在paging_init函數(shù)的map_mem函數(shù)中會(huì)對(duì)memory類型的內(nèi)存創(chuàng)建頁(yè)表,但是我怎么都找不到memory類型的內(nèi)存是怎么加到memblock中的。只是在arm64_memblock_init中看到把一些內(nèi)存區(qū)域加到了reserved類型的memblock中,但并沒(méi)有什么代碼把內(nèi)存加到memory類型的memblock中啊? 回復(fù) linuxer?
2015-12-30 17:59 @donkey:我沒(méi)有看代碼,不過(guò)推測(cè)是在device tree相關(guān)的代碼中。 回復(fù) donkey?
2015-12-31 11:19 @linuxer:果然是高手,按照你的提示,我又仔細(xì)研究了一下代碼流程,發(fā)現(xiàn)了這樣一條函數(shù)調(diào)用流程:
setup_arch-->setup_machine_fdt-->early_init_dt_scan-->early_init_dt_scan_nodes-->early_init_dt_add_memory_arch-->memblock_add
經(jīng)過(guò)這個(gè)流程,感覺(jué)memory類型的內(nèi)存區(qū)域就有著落了,呵呵!再次感謝! donkey?
2015-12-31 11:23 @linuxer:剛才那個(gè)流程不知道為什么沒(méi)顯示完全,再補(bǔ)充一下:
...->early_init_dt_add_memory_arch-->memblock_add
總結(jié)
以上是生活随笔為你收集整理的ARM64的启动过程之(四):打开MMU的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ARM64的启动过程之(三):为打开MM
- 下一篇: ARM64的启动过程之(五):UEFI