首頁>技術>

百萬漢字註解 >> 精讀核心原始碼,中文註解分析, 深挖地基工程,大腦永久記憶,四大碼倉每日同步更新< Gitee | Github | CSDN | Coding >

百篇部落格分析 >> 故事說核心,問答式導讀,生活式比喻,表格化說明,圖形化展示,多站點每日同步更新< OSCHINA | CSDN | WeHarmony >

系列篇硬體部分說明基於ARM720T.pdf文件.

正如一個網際網路專案的後臺管理系統有許可權管理一樣,CPU工作是否也有許可權(模式)? 一個成熟的軟硬體架構,肯定會有這些設計,只是大部分人不知道,也不需要知道,老百姓就幹好老百姓的活就行了,有工作能吃飽飯就知足了,宮的事你管那麼多幹嘛,你也管不了.

應用程式就只關注應用功能,業務邏輯相關的部分就行了,底層實現對應用層遮蔽得越乾淨系統設計的就越優良.

使用者模式(usr):屬於正常的使用者模式,ARM處理器正常的程式執行狀態。快速中斷模式(fiq):用於處理快速中斷,對高速資料傳輸或通道處理外部中斷模式(irq):對一般情況下的中斷進行處理。管理模式(svc):屬於作業系統使用的保護模式,處理軟體中斷swi reset。資料訪問終止模式(abt):當資料或指令預取終止時進入該模式,可用於處理儲存器故障、實現虛擬儲存器和儲存器保護。系統模式(sys):執行具有特權的作業系統任務。未定義指令中止模式(und):處理未定義的指令陷阱,當未定義的指令執行時進入該模式,可用於支援硬體協處理器的軟體模擬。

除了使用者模式外,其它六種均為特權模式或者叫異常模式。每種模式都有自己獨立的入口和獨立的執行棧空間.系列篇之CPU篇已介紹過只要提供了入口函式和執行空間,CPU就可以幹活了.入口函式解決了指令來源問題,執行空間解決了指令的執行問題.而且在多核情況下,每個CPU核的每種異常模式都有自己獨立的棧空間.注意是異常模式下的棧空間,使用者模式的棧空間是由使用者(應用)程式提供的.

如何讓這七種模式能流暢地跑起來呢? 至少需要以下解決三個基本問題.

棧空間是怎麼申請的?申請了多大?被切換中的模式程式碼放在哪裡?誰來安排它們放在哪裡?模式之間是怎麼切換的?狀態怎麼儲存?

本篇程式碼來源於鴻蒙核心原始碼之reset_vector_mp.S,點選檢視這個彙編檔案大概 500多行,非常重要,本篇受限於篇幅只列出一小部分,說清楚以上三個問題.系列其餘篇中將詳細說明每段彙編程式碼的作用和實現,可前往查閱.

1.異常模式棧空間怎麼申請?

鴻蒙是如何給異常模式申請棧空間的

#define CORE_NUM                 LOSCFG_KERNEL_SMP_CORE_NUM //CPU 核數#ifdef LOSCFG_GDB#define OS_EXC_UNDEF_STACK_SIZE  512#define OS_EXC_ABT_STACK_SIZE    512#else#define OS_EXC_UNDEF_STACK_SIZE  40#define OS_EXC_ABT_STACK_SIZE    40#endif#define OS_EXC_FIQ_STACK_SIZE    64#define OS_EXC_IRQ_STACK_SIZE    64#define OS_EXC_SVC_STACK_SIZE    0x2000 //8K#define OS_EXC_STACK_SIZE        0x1000 //4K@六種特權模式申請對應的棧執行空間__undef_stack:    .space OS_EXC_UNDEF_STACK_SIZE * CORE_NUM __undef_stack_top:__abt_stack:    .space OS_EXC_ABT_STACK_SIZE * CORE_NUM__abt_stack_top:__irq_stack:    .space OS_EXC_IRQ_STACK_SIZE * CORE_NUM __irq_stack_top:__fiq_stack:    .space OS_EXC_FIQ_STACK_SIZE * CORE_NUM__fiq_stack_top:__svc_stack:    .space OS_EXC_SVC_STACK_SIZE * CORE_NUM__svc_stack_top:__exc_stack:    .space OS_EXC_STACK_SIZE * CORE_NUM__exc_stack_top:

程式碼解讀

六種異常模式都有自己獨立的棧空間每種模式的OS_EXC_***_STACK_SIZE棧大小都不一樣,最大是管理模式(svc)8K,最小的只有40個位元組. svc模式為什麼要這麼大呢?因為開機程式碼和系統呼叫程式碼的執行都在管理模式,系統呼叫的函式實現往往較複雜,最大不能超過8K.例如:某個系統呼叫中定義一個8K的區域性變數,核心肯定立馬閃蹦.因為棧將溢位,處理異常的程式出現了異常,後面就再也沒人兜底了,只能是死局.鴻蒙是支援多核處理的,CORE_NUM表明,每個CPU核的每種異常模式都有自己的獨立棧空間.注意理解這個是理解核心程式碼的基礎.否則會一頭霧水.2.異常模式入口地址在哪?

再看一張圖,圖來源於 ARM720T.pdf 第56頁

這就是一切一切的開始,指定所有異常模式的入口地址表,這就是規定,沒得商量的.在低地址情況下.開機程式碼就是放在 0x00000000的位置, 觸發開機鍵後,硬體將PC暫存器置為0x00000000,開始了萬里長征的第一步.在系統執行過程中就這麼來回跳.

    b   reset_vector            @開機程式碼    b   _osExceptUndefInstrHdl 	@異常處理之CPU碰到不認識的指令    b   _osExceptSwiHdl			@異常處理之:軟中斷    b   _osExceptPrefetchAbortHdl	@異常處理之:取指異常    b   _osExceptDataAbortHdl		@異常處理之:資料異常    b   _osExceptAddrAbortHdl		@異常處理之:地址異常    b   OsIrqHandler				@異常處理之:硬中斷    b   _osExceptFiqHdl				@異常處理之:快中斷

以上是各個異常情況下的入口地址,在reset_vector_mp.S中都能找到,經過編譯連結後就會變成

    b   0x00000000      @開機程式碼    b   0x00000004 	    @異常處理之CPU碰到不認識的指令    b   0x00000008		@異常處理之:軟中斷    b   0x0000000C	    @異常處理之:取指異常    b   0x00000010		@異常處理之:資料異常    b   0x00000014		@異常處理之:地址異常    b   0x00000018		@異常處理之:硬中斷    b   0x0000001C		@異常處理之:快中斷

不管是主動切換的異常,還是被動切換的異常,都會先跳到對應的入口去處理.每個異常的程式碼都起始於彙編,處理完了再切回去.舉個例子:某個應用程式呼叫了系統呼叫(比如建立定時器),會經過以下大致過程:

swi指令將使用者模式切換到管理模式(svc)在管理模式中先儲存使用者模式的現場資訊(R0-R15暫存器值入棧)獲取系統呼叫號,知道是呼叫了哪個系統呼叫查詢系統呼叫對應的註冊函式執行真正的建立定時器函式執行完成後,恢復使用者模式的現場資訊(R0-R15暫存器值出棧)跳回使用者模式繼續執行

各異常處理程式碼很多,不一一列出,本篇只列出開機程式碼,請嘗試讀懂鴻蒙核心開機程式碼,後續講詳細說明每行程式碼的用處.

開機程式碼
    reset_vector:   //開機程式碼    /* clear register TPIDRPRW */    mov     r0, #0					@r0 = 0    mcr     p15, 0, r0, c13, c0, 4 	@c0,c13 = 0, C13為程序識別符號 含義見 ARM720T.PDF 第64頁    /* do some early cpu setup: i/d cache disable, mmu disabled */ @禁用MMU, i/d快取    mrc     p15, 0, r0, c1, c0, 0  	@r0 = c1 ,c1暫存器詳細解釋見第64頁    bic     r0, #(1<<12) 			@位清除指令,清除r0的第11位    bic     r0, #(1<<2 | 1<<0)		@清除第0和2位 ,禁止 MMU和快取 0位:MMU enable/disable 2位:Cache enable/disable    mcr     p15, 0, r0, c1, c0, 0 	@c1=r0     /* r11: delta of physical address and virtual address */@物理地址和虛擬地址的增量    adr     r11, pa_va_offset @將基於PC相對偏移的地址pa_va_offset值讀取到暫存器R11中    ldr     r0, [r11]		  @將R11的值給r0    sub     r11, r11, r0	  @r11 = r11 - r0	    mrc     p15, 0, r12, c0, c0, 5              /* r12: get cpuid */ @獲取CPUID    and     r12, r12, #MPIDR_CPUID_MASK @r12經過掩碼過濾    cmp     r12, #0	@當前是否為0號CPU    bne     secondary_cpu_init @不是0號主CPU則呼叫secondary_cpu_init    /* if we need to relocate to proper location or not */    adr     r4, __exception_handlers            /* r4: base of load address */ @r4獲得載入基地址    ldr     r5, =SYS_MEM_BASE                   /* r5: base of physical address */@r5獲得物理基地址    subs    r12, r4, r5                         /* r12: delta of load address and physical address */ @r12=r4-r5 載入地址和物理地址的增量    beq     reloc_img_to_bottom_done            /* if we load image at the bottom of physical address */    /* we need to relocate image at the bottom of physical address */    ldr     r7, =__exception_handlers           /* r7: base of linked address (or vm address) */    ldr     r6, =__bss_start                    /* r6: end of linked address (or vm address) */    sub     r6, r7                              /* r6: delta of linked address (or vm address) */    add     r6, r4                              /* r6: end of load address */
異常的許可權

當同時出現多個異常時,該響應哪一個呢?就涉及到了異常的許可權,如下

Reset (highest priority).Data Abort.FIQ.IRQ.Prefetch Abort.Undefined Instruction, SWI (lowest priority).

可以看出swi的許可權最低,swi就是軟體中斷,系統呼叫就是透過它來實現的.

3.異常模式怎麼切換?

寫應用程式經常會用到狀態,來記錄各種分支邏輯,傳遞引數.這麼多異常模式,相互切換,中間肯定會有很多的狀態需要儲存.比如:如何能知道當前執行在哪種模式下?怎麼查?去哪裡查呢?答案是: CPSR 和 SPSRCPSR:程式狀態暫存器(current program status register) (當前程式狀態暫存器),在任何處理器模式下被訪問。SPSR:程式狀態儲存暫存器(saved program status register),每一種處理器模式下都有一個狀態暫存器SPSR,SPSR用於儲存CPSR的狀態,以便異常返回後恢復異常發生時的工作狀態。當特定 的異常中斷髮生時,這個暫存器用於存放當前程式狀態暫存器的內容。在異常中斷退出時,可以用SPSR來恢復CPSR。

這些暫存器:

儲存有關最近執行的ALU操作的資訊控制中斷的啟用和禁用設定處理器操作模式

百萬漢字註解 >> 精讀核心原始碼,中文註解分析, 深挖地基工程,大腦永久記憶,四大碼倉每日同步更新< Gitee | Github | CSDN | Coding >

百篇部落格分析 >> 故事說核心,問答式導讀,生活式比喻,表格化說明,圖形化展示,多站點每日同步更新< OSCHINA | CSDN | WeHarmony >

3
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 視覺化程式設計工具blockly——工具箱