
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??
在持續探索開源鴻蒙操作系統內核的過程中有必要從LINUX,AOSP或其他小型操作系統中先深入分析汲取基礎知識經驗,進而對照分析學習進而更深入學習理論和進行實踐。
接下來從操作系統的基礎知識按照常規劃分結構,從硬件基礎結構,操作系統結構,內存管理,進程線程,操作系統調度,同步原語,文件系統與存儲,設備管理,系統虛擬化,網絡協議,安全,調試,幾個部分來進行基礎知識的梳理。深入了解操作系統的內核,補全基礎知識。
操作系統運行機制(中斷與異常)
中斷和異常基礎知識
操作系統中斷和異常是計算機系統中重要的概念,它們可以幫助操作系統處理各種事件和錯誤
中斷(Interrupt)
中斷是指在計算機執行程序時,突然發生的一些事件,例如輸入輸出操作完成、定時器超時、硬件錯誤等等。當發生中斷時,操作系統會停止當前進程的執行,并處理中斷事件。處理完畢后,操作系統會回到原來的進程并繼續執行。
- 外部硬件設備產生的信號如鍵盤按鍵響應,鼠標響應
- 異步:產生原因和當前的執行指令無關,如程序被磁盤的讀寫打斷
異常(Execption)
異常是指在程序執行過程中出現的錯誤或非正常情況。例如,除以零、訪問不存在的內存地址等等。當發生異常時,操作系統會停止當前進程的執行,并處理異常。處理完畢后,操作系統會終止當前進程并回收資源。
- 軟件的程序執行而產生的事件
- 包括系統調用(System Call)-用戶程序請求操作系統提供服務
- 同步:產生和當前執行或試圖執行的指令相關的
在不同的處理器架構上定義有所不同實現方式也有所不同
主要在主流處理器架構AArch64和x86-64上進行探討。
- 在中斷處理方面,AArch64和x86-64的處理方式比較相似,都有中斷向量表和中斷處理程序。當中斷發生時,處理器會根據中斷向量表中的入口地址跳轉到對應的中斷處理程序。不過,在中斷優先級方面,AArch64使用的是基于中斷源編號的優先級,而x86-64使用的是基于中斷向量號的優先級。
- 在異常處理方面,AArch64和x86-64的處理方式有一些區別。AArch64定義了3種不同的異常:同步異常、異步異常和中斷。同步異常是由當前指令在執行過程中發生的異常,而異步異常則是由硬件或軟件事件觸發的異常。中斷則是一種特殊的異常,它由外部設備觸發,與異步異常的處理方式相似。在AArch64中,異常處理程序被稱為異常向量表,其中包含了不同類型異常的入口地址。而在x86-64中,異常被稱為中斷,異常處理程序被稱為中斷處理程序,它們的處理方式和中斷處理方式相同。
此外,AArch64和x86-64在異常處理的寄存器保存和恢復方面也有一些不同。在AArch64中,異常處理程序會保存通用寄存器、程序狀態寄存器以及特定的系統控制寄存器。而在x86-64中,中斷處理程序會保存通用寄存器、標志寄存器、指令指針以及特定的中斷控制寄存器。
AArch64
中斷
- 重置 (RESET) -最高級別的異常,但是由芯片內部電器信號觸發,(嚴格劃分不屬于外部中斷)。
- 中斷(Interrupt) -CPU外部信號觸發,打斷執行 ,如計時器中斷,串口終端,空閑中斷。
異常
- 中止(Abort) - 失敗的指令獲取或數據訪問,訪問到不可讀地址。
- 異常產生指令
- SVC : 用戶程序 -》 操作系統
- HVC : 客戶系統 -》 虛擬機管理器
- SMC :Normal -> Secure World
X86-64
中斷(設備產生,異步)
- 可屏蔽 - 設備產生的信號,通過中斷控制器與處理器項鏈,能夠被暫時屏蔽。
- 不可屏蔽:一些關鍵硬件的崩潰錯誤。
異常
三大類分類 :
- 錯誤 (Fault)可恢復(缺頁異常),段錯誤(不可恢復)。
- 陷阱 (Trap)無需回復。
- 中止 (Abort)嚴重錯誤,不可恢復,需要進行機器檢查。
中斷和異常的產生機制
中斷

如圖所示當發生異常 (如除以零錯誤) 時,CPU 會向操作系統異常處理程序發出信號,以便其接管并處理異常。操作系統異常處理程序隨后確定異常的原因,并決定是否可以恢復。如果可以恢復,處理程序將嘗試從異常中恢復。如果無法恢復,系統將崩潰.
當發生中斷 (如設備請求) 時,CPU 會向中斷處理程序發出信號,以便其接管并處理中斷。中斷處理程序隨后確定中斷的原因,并決定是系統調用還是設備中斷。如果是系統調用,處理程序將執行請求的系統調用。如果是設備中斷,處理程序將處理設備中斷 (如通過讀取設備數據)。
在ARM架構內核和X86架構內核當中,有如下所示的SOC連接方式。

當中連線最多的部分是GIC。
也就是(General interrupt controller)部分有多根總線連接到不同的設備上。
- 硬件層:最下層為硬件連接層,對應的是具體的外設與SoC的物理連接,中斷信號是從外設到中斷控制器,由中斷控制器統一管理,再路由到處理器上;
- 硬件相關層:這個層包括兩部分代碼,一部分是架構相關的,比如ARM64處理器處理中斷相關,另一部分是中斷控制器的驅動代碼。
- 通用層:這部分也可以認為是框架層,是硬件無關層,這部分代碼在所有硬件平臺上是通用的。
- 用戶層:這部分也就是中斷的使用者了,主要是各類設備驅動,通過中斷相關接口來進行申請和注冊,最終在外設觸發中斷時,進行相應的回調處理。
中斷控制器GIC需要考慮的問題
- 如何指定不同中斷的優先級。
- 低優先級的終端處理中,出現高優先級的中斷如何響應。
- 嵌套中斷。
- 誰來處理中斷。
- 和中斷控制器協同的軟件怎么編寫。
在aarch64架構中,GIC支持不同的中斷優先級,這樣可以確保重要的中斷可以優先處理。中斷優先級由中斷號和中斷類型確定,每個中斷都有一個唯一的中斷號,它是一個32位的整數,同時,每個中斷也有一個對應的中斷類型,可以是中斷或異常。
中斷優先級是通過GIC中的中斷控制器寄存器來實現的。GIC提供了四個中斷優先級寄存器,分別為CPU Interface控制器寄存器的ICC_PMR、Distributor控制器寄存器的ICDIPR、ICDIPTR和ICDIPRn(其中n是從0開始的中斷號)。這些寄存器用于設置中斷優先級和掩碼。ICC_PMR是CPU Interface控制器的一個寄存器,它用于指定中斷的優先級閾值。當中斷的優先級高于這個閾值時,中斷將被立即處理,否則將被掛起。這個閾值可以是0到255之間的任何值。ICDIPR是Distributor控制器的一個寄存器,它用于設置每個中斷的優先級。每個中斷都有一個對應的ICDIPR寄存器,它是一個8位的寄存器,用于指定中斷的優先級。值越大,優先級越高。ICDIPTR是Distributor控制器的一個寄存器,它用于將中斷連接到處理器。每個中斷都有一個對應的ICDIPTR寄存器,它是一個8位的寄存器,用于指定中斷連接到哪個處理器。ICDIPRn是Distributor控制器的一組寄存器,用于設置和查詢每個中斷的優先級和掩碼。每個中斷都有一個對應的ICDIPRn寄存器,它是一個32位的寄存器,其中包含了中斷的優先級和掩碼信息。通過這些寄存器,我們可以靈活地配置中斷的優先級,從而確保系統能夠高效地處理各種中斷信號。

除了中斷控制器寄存器控制中斷號其次還對中斷進行了劃分 ,VFIQ,VIRQ,IRQ ,FIQ,SError。IRQ是指普通中斷,優先級低,處理緩慢,FIQ是快速中斷,常常為可信任的中斷源預留,SError是原因難以定位的異常,通常由異步中止Abort導致。,VIRQ和VFIQ是針對虛擬化的。
ARM GIC V2.0中給出的GIC模型如下:

在上圖中可以看到中斷路由功能的實現。
以及GIC主要包含三個重要部分。
Distributor、CPU interfaces 和 Virtual CPU interfaces。Virtual CPU interfaces 包含 Virtual interface control 和 Virtual CPU interface。
圖中Distributor部分的主要作用為檢測中斷源,控制中斷源行為和將中斷源分發到指定CPU的指定接口上。
具體功能包括:
- 全局啟用中斷轉發到 CPU 接口。
- 開啟或關閉每一個中斷。
- 為每個中斷設置優先級。
- 為每個中斷設置目標處理器列表。
- 設置每個外設中斷觸發方式(電平觸發、邊緣觸發)。
- 為每個中斷設置組。
- 將 SGI 轉發到一個或多個處理器。
- 每個中斷狀態可見。
- 提供軟件設置或清除外設中斷的掛起狀態的一種機制。
在早期的中斷控制器中并不是這種架構,在我們常規使用的Contex M2-M3系列芯片中如今仍然使用的是內嵌式中斷向量控制器NVIC,在NVIC中會維護一張表,中斷向量表是一個表,這個表里面存放的是中斷向量。中斷服務程序的入口地址或存放中斷服務程序的首地址成為中斷向量,因此中斷向量表是一系列中斷服務程序入口地址組成的表。這些中斷服務程序(函數)在中斷向量表中的位置是由半導體廠商定好的,當某個中斷被觸發以后就會自動跳轉到中斷向量表中對應的中斷服務程序(函數)入口地址處。
中斷被劃分為三種類型:
SGI(Software Generated Interrupt) - 軟件觸發中斷:通常用于多核間通訊,最多支持 16 個 SGI 中斷,硬件中斷號從 ID0~ID15。
PPI(Private Peripheral Interrupt) - 私有外設中斷:是每個 CPU 私有的中斷。最多支持 16 個 PPI 中斷,硬件中斷號從 ID16~ID31。可以處理指定核心的中斷任務
SPI(Shared Peripheral Interrupt)- 公用外設中斷:最多可以支持 988 個外設中斷,硬件中斷號從 ID32~ID1019,可以處理按鍵中斷,串口中斷等。
中斷源有很多,為了區分這些不同的中斷源肯定要給他們分配一個唯一 ID,這些 ID 就是中斷 ID。每一個 CPU 最多支持 1020 個中斷 ID,中斷 ID 號為 ID0~ID1019。這 1020個 ID 包含了 PPI、SPI 和 SGI,那么這三類中斷是如何分配這 1020 個中斷 ID 的呢?這 1020 個 ID 分配如下:
ID0~ID15:這 16 個 ID 分配給 SGI。
ID16~ID31:這 16 個 ID 分配給 PPI。
ID32~ID1019:這 988 個 ID 分配給 SPI,像 GPIO 中斷、串口中斷等這些外部中斷 ,至于具體到某個 ID 對應哪個中斷那就由半導體廠商根據實際情況去定義了。比如 I.MX6U的總共使用了 128 個中斷 ID,加上前面屬于 PPI 和 SGI 的 32 個 ID, I.MX6U 的中斷源共有 128+32=160個,這 128 個中斷 ID 對應的中斷在《I.MX6ULL 參考手冊》的“3.2 Cortex A7 interrupts”小節NXP 官方 SDK中的文件 MCIMX6Y2C.h,在此文件中定義了一個枚舉類型 IRQn_Type,此枚舉類型就枚舉出了 I.MX6U 的所有中斷,代碼如下所示:
/** Interrupt Number Definitions */
#define NUMBER_OF_INT_VECTORS 160 /**< Number of interrupts in the Vector table */
typedef enum IRQn {
/* Auxiliary constants */
NotAvail_IRQn = -128, /**< Not available device specific interrupt */
/* Core interrupts */
Software0_IRQn = 0, /**< Cortex-A7 Software Generated Interrupt 0 */
Software1_IRQn = 1, /**< Cortex-A7 Software Generated Interrupt 1 */
Software2_IRQn = 2, /**< Cortex-A7 Software Generated Interrupt 2 */
Software3_IRQn = 3, /**< Cortex-A7 Software Generated Interrupt 3 */
Software4_IRQn = 4, /**< Cortex-A7 Software Generated Interrupt 4 */
Software5_IRQn = 5, /**< Cortex-A7 Software Generated Interrupt 5 */
Software6_IRQn = 6, /**< Cortex-A7 Software Generated Interrupt 6 */
Software7_IRQn = 7, /**< Cortex-A7 Software Generated Interrupt 7 */
Software8_IRQn = 8, /**< Cortex-A7 Software Generated Interrupt 8 */
Software9_IRQn = 9, /**< Cortex-A7 Software Generated Interrupt 9 */
Software10_IRQn = 10, /**< Cortex-A7 Software Generated Interrupt 10 */
Software11_IRQn = 11, /**< Cortex-A7 Software Generated Interrupt 11 */
Software12_IRQn = 12, /**< Cortex-A7 Software Generated Interrupt 12 */
Software13_IRQn = 13, /**< Cortex-A7 Software Generated Interrupt 13 */
Software14_IRQn = 14, /**< Cortex-A7 Software Generated Interrupt 14 */
Software15_IRQn = 15, /**< Cortex-A7 Software Generated Interrupt 15 */
VirtualMaintenance_IRQn = 25, /**< Cortex-A7 Virtual Maintenance Interrupt */
HypervisorTimer_IRQn = 26, /**< Cortex-A7 Hypervisor Timer Interrupt */
VirtualTimer_IRQn = 27, /**< Cortex-A7 Virtual Timer Interrupt */
LegacyFastInt_IRQn = 28, /**< Cortex-A7 Legacy nFIQ signal Interrupt */
SecurePhyTimer_IRQn = 29, /**< Cortex-A7 Secure Physical Timer Interrupt */
NonSecurePhyTimer_IRQn = 30, /**< Cortex-A7 Non-secure Physical Timer Interrupt */
LegacyIRQ_IRQn = 31, /**< Cortex-A7 Legacy nIRQ Interrupt */
/* Device specific interrupts */
IOMUXC_IRQn = 32, /**< General Purpose Register 1 from IOMUXC. Used to notify cores on exception condition while boot. */
DAP_IRQn = 33, /**< Debug Access Port interrupt request. */
SDMA_IRQn = 34, /**< SDMA interrupt request from all channels. */
TSC_IRQn = 35, /**< TSC interrupt. */
SNVS_IRQn = 36, /**< Logic OR of SNVS_LP and SNVS_HP interrupts. */
LCDIF_IRQn = 37, /**< LCDIF sync interrupt. */
RNGB_IRQn = 38, /**< RNGB interrupt. */
CSI_IRQn = 39, /**< CMOS Sensor Interface interrupt request. */
PXP_IRQ0_IRQn = 40, /**< PXP interrupt pxp_irq_0. */
SCTR_IRQ0_IRQn = 41, /**< SCTR compare interrupt ipi_int[0]. */
SCTR_IRQ1_IRQn = 42, /**< SCTR compare interrupt ipi_int[1]. */
WDOG3_IRQn = 43, /**< WDOG3 timer reset interrupt request. */
Reserved44_IRQn = 44, /**< Reserved */
APBH_IRQn = 45, /**< DMA Logical OR of APBH DMA channels 0-3 completion and error interrupts. */
WEIM_IRQn = 46, /**< WEIM interrupt request. */
RAWNAND_BCH_IRQn = 47, /**< BCH operation complete interrupt. */
RAWNAND_GPMI_IRQn = 48, /**< GPMI operation timeout error interrupt. */
UART6_IRQn = 49, /**< UART6 interrupt request. */
PXP_IRQ1_IRQn = 50, /**< PXP interrupt pxp_irq_1. */
SNVS_Consolidated_IRQn = 51, /**< SNVS consolidated interrupt. */
SNVS_Security_IRQn = 52, /**< SNVS security interrupt. */
CSU_IRQn = 53, /**< CSU interrupt request 1. Indicates to the processor that one or more alarm inputs were asserted. */
USDHC1_IRQn = 54, /**< USDHC1 (Enhanced SDHC) interrupt request. */
USDHC2_IRQn = 55, /**< USDHC2 (Enhanced SDHC) interrupt request. */
SAI3_RX_IRQn = 56, /**< SAI3 interrupt ipi_int_sai_rx. */
SAI3_TX_IRQn = 57, /**< SAI3 interrupt ipi_int_sai_tx. */
UART1_IRQn = 58, /**< UART1 interrupt request. */
UART2_IRQn = 59, /**< UART2 interrupt request. */
UART3_IRQn = 60, /**< UART3 interrupt request. */
UART4_IRQn = 61, /**< UART4 interrupt request. */
UART5_IRQn = 62, /**< UART5 interrupt request. */
eCSPI1_IRQn = 63, /**< eCSPI1 interrupt request. */
eCSPI2_IRQn = 64, /**< eCSPI2 interrupt request. */
eCSPI3_IRQn = 65, /**< eCSPI3 interrupt request. */
eCSPI4_IRQn = 66, /**< eCSPI4 interrupt request. */
I2C4_IRQn = 67, /**< I2C4 interrupt request. */
I2C1_IRQn = 68, /**< I2C1 interrupt request. */
I2C2_IRQn = 69, /**< I2C2 interrupt request. */
I2C3_IRQn = 70, /**< I2C3 interrupt request. */
UART7_IRQn = 71, /**< UART-7 ORed interrupt. */
UART8_IRQn = 72, /**< UART-8 ORed interrupt. */
Reserved73_IRQn = 73, /**< Reserved */
USB_OTG2_IRQn = 74, /**< USBO2 USB OTG2 */
USB_OTG1_IRQn = 75, /**< USBO2 USB OTG1 */
USB_PHY1_IRQn = 76, /**< UTMI0 interrupt request. */
USB_PHY2_IRQn = 77, /**< UTMI1 interrupt request. */
DCP_IRQ_IRQn = 78, /**< DCP interrupt request dcp_irq. */
DCP_VMI_IRQ_IRQn = 79, /**< DCP interrupt request dcp_vmi_irq. */
DCP_SEC_IRQ_IRQn = 80, /**< DCP interrupt request secure_irq. */
TEMPMON_IRQn = 81, /**< Temperature Monitor Temperature Sensor (temperature greater than threshold) interrupt request. */
ASRC_IRQn = 82, /**< ASRC interrupt request. */
ESAI_IRQn = 83, /**< ESAI interrupt request. */
SPDIF_IRQn = 84, /**< SPDIF interrupt. */
Reserved85_IRQn = 85, /**< Reserved */
PMU_IRQ1_IRQn = 86, /**< Brown-out event on either the 1.1, 2.5 or 3.0 regulators. */
GPT1_IRQn = 87, /**< Logical OR of GPT1 rollover interrupt line, input capture 1 and 2 lines, output compare 1, 2, and 3 interrupt lines. */
EPIT1_IRQn = 88, /**< EPIT1 output compare interrupt. */
EPIT2_IRQn = 89, /**< EPIT2 output compare interrupt. */
GPIO1_INT7_IRQn = 90, /**< INT7 interrupt request. */
GPIO1_INT6_IRQn = 91, /**< INT6 interrupt request. */
GPIO1_INT5_IRQn = 92, /**< INT5 interrupt request. */
GPIO1_INT4_IRQn = 93, /**< INT4 interrupt request. */
GPIO1_INT3_IRQn = 94, /**< INT3 interrupt request. */
GPIO1_INT2_IRQn = 95, /**< INT2 interrupt request. */
GPIO1_INT1_IRQn = 96, /**< INT1 interrupt request. */
GPIO1_INT0_IRQn = 97, /**< INT0 interrupt request. */
GPIO1_Combined_0_15_IRQn = 98, /**< Combined interrupt indication for GPIO1 signals 0 - 15. */
GPIO1_Combined_16_31_IRQn = 99, /**< Combined interrupt indication for GPIO1 signals 16 - 31. */
GPIO2_Combined_0_15_IRQn = 100, /**< Combined interrupt indication for GPIO2 signals 0 - 15. */
GPIO2_Combined_16_31_IRQn = 101, /**< Combined interrupt indication for GPIO2 signals 16 - 31. */
GPIO3_Combined_0_15_IRQn = 102, /**< Combined interrupt indication for GPIO3 signals 0 - 15. */
GPIO3_Combined_16_31_IRQn = 103, /**< Combined interrupt indication for GPIO3 signals 16 - 31. */
GPIO4_Combined_0_15_IRQn = 104, /**< Combined interrupt indication for GPIO4 signals 0 - 15. */
GPIO4_Combined_16_31_IRQn = 105, /**< Combined interrupt indication for GPIO4 signals 16 - 31. */
GPIO5_Combined_0_15_IRQn = 106, /**< Combined interrupt indication for GPIO5 signals 0 - 15. */
GPIO5_Combined_16_31_IRQn = 107, /**< Combined interrupt indication for GPIO5 signals 16 - 31. */
Reserved108_IRQn = 108, /**< Reserved */
Reserved109_IRQn = 109, /**< Reserved */
Reserved110_IRQn = 110, /**< Reserved */
Reserved111_IRQn = 111, /**< Reserved */
WDOG1_IRQn = 112, /**< WDOG1 timer reset interrupt request. */
WDOG2_IRQn = 113, /**< WDOG2 timer reset interrupt request. */
KPP_IRQn = 114, /**< Key Pad interrupt request. */
PWM1_IRQn = 115, /**< hasRegInstance(`PWM1`)?`Cumulative interrupt line for PWM1. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */
PWM2_IRQn = 116, /**< hasRegInstance(`PWM2`)?`Cumulative interrupt line for PWM2. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */
PWM3_IRQn = 117, /**< hasRegInstance(`PWM3`)?`Cumulative interrupt line for PWM3. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */
PWM4_IRQn = 118, /**< hasRegInstance(`PWM4`)?`Cumulative interrupt line for PWM4. Logical OR of rollover, compare, and FIFO waterlevel crossing interrupts.`:`Reserved`) */
CCM_IRQ1_IRQn = 119, /**< CCM interrupt request ipi_int_1. */
CCM_IRQ2_IRQn = 120, /**< CCM interrupt request ipi_int_2. */
GPC_IRQn = 121, /**< GPC interrupt request 1. */
Reserved122_IRQn = 122, /**< Reserved */
SRC_IRQn = 123, /**< SRC interrupt request src_ipi_int_1. */
Reserved124_IRQn = 124, /**< Reserved */
Reserved125_IRQn = 125, /**< Reserved */
CPU_PerformanceUnit_IRQn = 126, /**< Performance Unit interrupt ~ipi_pmu_irq_b. */
CPU_CTI_Trigger_IRQn = 127, /**< CTI trigger outputs interrupt ~ipi_cti_irq_b. */
SRC_Combined_IRQn = 128, /**< Combined CPU wdog interrupts (4x) out of SRC. */
SAI1_IRQn = 129, /**< SAI1 interrupt request. */
SAI2_IRQn = 130, /**< SAI2 interrupt request. */
Reserved131_IRQn = 131, /**< Reserved */
ADC1_IRQn = 132, /**< ADC1 interrupt request. */
ADC_5HC_IRQn = 133, /**< ADC_5HC interrupt request. */
Reserved134_IRQn = 134, /**< Reserved */
Reserved135_IRQn = 135, /**< Reserved */
SJC_IRQn = 136, /**< SJC interrupt from General Purpose register. */
CAAM_Job_Ring0_IRQn = 137, /**< CAAM job ring 0 interrupt ipi_caam_irq0. */
CAAM_Job_Ring1_IRQn = 138, /**< CAAM job ring 1 interrupt ipi_caam_irq1. */
QSPI_IRQn = 139, /**< QSPI1 interrupt request ipi_int_ored. */
TZASC_IRQn = 140, /**< TZASC (PL380) interrupt request. */
GPT2_IRQn = 141, /**< Logical OR of GPT2 rollover interrupt line, input capture 1 and 2 lines, output compare 1, 2 and 3 interrupt lines. */
CAN1_IRQn = 142, /**< Combined interrupt of ini_int_busoff,ini_int_error,ipi_int_mbor,ipi_int_txwarning and ipi_int_waken */
CAN2_IRQn = 143, /**< Combined interrupt of ini_int_busoff,ini_int_error,ipi_int_mbor,ipi_int_txwarning and ipi_int_waken */
Reserved144_IRQn = 144, /**< Reserved */
Reserved145_IRQn = 145, /**< Reserved */
PWM5_IRQn = 146, /**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */
PWM6_IRQn = 147, /**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */
PWM7_IRQn = 148, /**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */
PWM8_IRQn = 149, /**< Cumulative interrupt line. OR of Rollover Interrupt line, Compare Interrupt line and FIFO Waterlevel crossing interrupt line */
ENET1_IRQn = 150, /**< ENET1 interrupt */
ENET1_1588_IRQn = 151, /**< ENET1 1588 Timer interrupt [synchronous] request. */
ENET2_IRQn = 152, /**< ENET2 interrupt */
ENET2_1588_IRQn = 153, /**< MAC 0 1588 Timer interrupt [synchronous] request. */
Reserved154_IRQn = 154, /**< Reserved */
Reserved155_IRQn = 155, /**< Reserved */
Reserved156_IRQn = 156, /**< Reserved */
Reserved157_IRQn = 157, /**< Reserved */
Reserved158_IRQn = 158, /**< Reserved */
PMU_IRQ2_IRQn = 159 /**< Brown-out event on either core, gpu or soc regulators. */
} IRQn_Type;
GIC中斷搶占
GIC中斷控制器支持中斷優先級搶占,一個高優先級中斷可以搶占一個低優先級且處于active狀態的中斷,即GIC仲裁單元會記錄和比較當前優先級最高的pending狀態,然后去搶占當前中斷,并且發送這個最高優先級的中斷請求給CPU,CPU應答了高優先級中斷,暫停低優先級中斷服務,進而去處理高優先級中斷。
GIC會將pending狀態優先級最高的中斷請求發送給CPU。
在這里我們就必須要重新回顧剛才提到的圖片中的CPU interface部分的更詳細的信息。
??GIC?? 為每個 ??CPU?? 接口上每個受支持的中斷維護一個狀態機。下圖顯示了此狀態機的實例,以及可能的狀態轉換。

在這個單元中包含了 Inactive ,Pending,Active and Pending以及Active四種狀態,和操作系統進程的狀態類似,我們重點關注轉換過程而不是狀態本身。
(1) 當GIC檢測到一個中斷發生時,會將該中斷標記為pending狀態(A1)。
(2) 對處于pending狀態的中斷,仲裁單元回確定目標CPU,將中斷請求發送到這個CPU上。
(3) 對于每個CPU,仲裁單元會從眾多pending狀態的中斷中選擇一個優先級最高的中斷,發送到目標CPU的CPU Interface模塊上。
(4) CPU Interface會決定這個中斷是否可以發送給CPU。如果該終端優先級滿足要求,GIC會發生一個中斷信號給該CPU。
(5) 當一個CPU進入中斷異常后,會去讀取GICC_IAR寄存器來響應該中斷(一般是Linux內核的中斷處理程序來讀寄存器)。寄存器會返回硬件中斷號(hardware interrupt ID),對于SGI中斷來說是返回源CPU的ID。
總結整理為 添加新的掛起狀態(A1,A2),刪除掛起狀態(B1,B2),掛起到激活狀態(C),掛起到激活和掛起(D),刪除激活狀態。
從GIC角度看,GIC會發送高優先級中斷請求給CPU。
但是目前CPU處于關中斷狀態,需要等低優先級中斷處理完畢,直到發送EOI給GIC。
然后CPU才會響應pending狀態中優先級最高的中斷進行處理。
所以Linux下:
- 高優先級中斷無法搶占正在執行的低優先級中斷。
- 同處于pending狀態的中斷,優先響應高優先級中斷進行處理。
對于ARM體系的處理器,通過判斷CPSR寄存器中的I位或F位的值確定處理器是否通過啟動中斷確認過程來響應中斷信號,處理搶占中斷是,處理器必須保存并稍后恢復為剛剛活動的ISR的上下文,
優先級下降意味著中斷的優先級不再影響 CPU 接口上的運行優先級,因此不會阻止中斷搶占。在 GICv1 實現中,僅當中斷停用時才會發生優先級下降,但在 GICv2 實現中,優先級下降和中斷停用可以分開。這也就解決了剛剛提出的具有沖突可能的問題。
在虛擬機中如何支持IRQ和FIQ中斷




該用例來自于GICV2.0的說明文檔,指出,在CPU需要進行虛擬化時,GIC的響應方式。
安全軟件分配:
對組 0 的安全中斷,作為 FIQ 信號發送到處理器。
對組 1 的非安全中斷,作為 IRQ 向處理器發出信號。
虛擬機管理程序:
使用 GIC 上的虛擬化擴展的功能實現虛擬分發服務器。此虛擬分發服務器可以將來自 GIC 的 IRQ 中斷虛擬化為虛擬 IRQ 和虛擬 FIQ 中斷,并將其路由到相應的虛擬機。
將物理 IRQ 路由到 Hyp 模式,以便虛擬分發服務器可以為其提供服務。當虛擬化方案使用基于虛擬化擴展(Virtualization Extensions,簡稱VE)的虛擬化方式時,物理中斷控制器(Physical GIC,簡稱PGIC)會將物理IRQ路由到Hyp模式,Hypervisor進行處理。硬件會根據中斷的優先級和路由信息將中斷發送到正確的處理器模式中(如Hyp模式、Guest模式等)。
在虛擬機上運行的客戶機操作系統將中斷分配給組 0 或組 1,以將其分配為 FIQ 或 IRQ。對 GIC 分發服務器寄存器的訪問將捕獲到虛擬機管理程序,因此可以訪問虛擬分發服務器。
虛擬 CPU 接口將這些中斷作為虛擬 FIQ 或虛擬 IRQ 發出信號。此虛擬化受虛擬機管理程序控制,對來賓操作系統不可見。
當 GIC 向處理器發送 IRQ 信號時,中斷將路由到 Hyp 模式。虛擬機管理程序確定中斷是針對自身還是針對來賓操作系統。如果是針對來賓操作系統,它將確定:
哪個客戶機操作系統必須處理中斷。
該來賓操作系統是否已將中斷配置為 FIQ 或 IRQ。
中斷優先級,基于目標來賓操作系統的優先級配置。
綜合而言可以理解為虛擬機的中斷是通過虛擬中斷控制器(VGIC)轉發給物理中斷控制器(PGIC)來實現的。當虛擬機需要處理中斷時,VGIC會將中斷發送給PGIC,PGIC會根據中斷的優先級和路由信息將中斷發送給相應的虛擬機。
系統調用
系統調用是指運行在用戶空間的程序向操作系統內核請求需要更高權限運行的服務。
系統提供用戶程序與操作系統之間的接口
- 用戶調用系統調用API,傳遞參數給應用程序。
- 應用程序進入內核空間,調用系統調用處理程序。
- 內核進行權限檢查和參數驗證,準備系統調用參數。
- 內核執行系統調用指令,將處理器從用戶模式切換到內核模式,進入內核態。
- 處理器在內核模式下,保存現場,即保存用戶態的寄存器狀態等信息,以備將來返回用戶空間時使用。
- 處理器執行系統調用處理程序,內核根據系統調用類型進行相應的處理,可能會訪問設備或文件系統等。
- 處理完系統調用后,內核恢復現場,即恢復之前保存的寄存器狀態等信息。
- 處理器退出內核模式,返回用戶模式,即返回應用程序。
- 應用程序得到系統調用結果,進行后續處理。

例如我們運行庫函數 getchar() ,會在庫函數中找到其函數實體,并調用內核API接口使用匯編指令 SVC #0.
那么以下是從硬件視角進行分析的一張圖。

以下是Linux系統常見的系統調用:

當發生系統調用時可以用ptrace()進行追蹤系統調用的情況,strace追蹤系統調用,ltrace追蹤庫函數的調用。
系統調用由于用戶直接操作到了內核,所以其中的寄存器傳參,以及具體的指針訪問們必須經過嚴格的檢驗。但是如果進行完備的指針檢測十分耗時,所以需要進行非全面檢查。Linux非全面檢查的房房是,初步檢測用戶指針是否屬于對應進程 的用戶內存區域最大可能邊界,通過了初步檢測,用戶指針可能仍然非法。
文章相關附件可以點擊下面的原文鏈接前往下載:
https://ost.51cto.com/resource/2616
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??