Linux版本:v6.0
處理器架構:ARMv8
KVM品種:NVHE
前言
上一篇說明了KVM ARM EL2 per cpu變數如何宣告與使用。簡單複習一下,EL2 per cpu變數的存取方式是先取得被放在.hyp.data..percpu
section的基地址,然後加上存放在tpidr_el2
的offset算出最終的位址。經過這樣的講解,有兩個自然的問題:
EL2 per cpu變數使用的記憶體是如何分配的?
關鍵的
tpidr_el2
裡頭存的offset是如何計算並存進去的?
這就是本篇要解答的內容,start!
記憶體分配
KVM ARM初始化的重要函式init_hyp_mode
中會替EL2 per cpu變數分配記憶體:
1 | /* |
分配完記憶體之後就是要把那些空間map給EL2(一樣在init_hyp_mode
):
1 | // 對每一個可用的cpu: |
設定tpidr_el2
前面說明了如何分配EL2 per cpu變數使用的記憶體與替EL2建造page table的過程,接下來要做的就是計算各個cpu的offset還有實際安裝該值進tpidr_el2
。
計算per cpu offset
cpu_prepare_hyp_mode(cpu)
負責的工作在於填充一個struct kvm_nvhe_init_params
,這個結構存放初始化EL2各個系統暫存器的值,也就包含了tpidr_el2
該存的offset,列出目前關心的部份:
1 | static void cpu_prepare_hyp_mode(int cpu) |
安裝tpidr_el2
把offset存進params->tpidr_el2
之後,接著就是進入EL2並把該值存入tpidr_el2
系統暫存器,先來看一下KVM ARM初始化過程中和目前主題有關的call stack:
1 | kvm_init() |
hyp_install_host_vector
跑在EL1,會呼叫hypercall 同時傳入EL2初始化需要用到的struct kvm_nvhe_init_param
,接著進入EL2並執行___kvm_hyp_init
做EL2相關設定,其中就包含設定tpidr_el2
。
1 | static void hyp_install_host_vector(void) |
hvc那行如何進入EL2的細節先不討論,簡而言之x0
會放入__kvm_hyp_init
代表的數字(讓EL2的程式可以確認EL1為何呼叫hvc
),x1
會放入kvm_init_params
的物理位址,然後會跳到這邊:
1 | // arch/arm64/kvm/hyp/nvhe/hyp-init.S |
最後看一下___kvm_hyp_init
:
其實前兩行就是設定tpidr_el2
了,給你們揣摩它怎麼作到的吧,這裡也可以看到這個函式實際設定EL2執行環境的實作,至於講解細節的話…有空再說吧XD
這裡值得說明的是這邊EL2的MMU還沒開,所以都是直接使用實體位址進行操作
1 | SYM_CODE_START_LOCAL(___kvm_hyp_init) |