91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是linux異常體系結構

發布時間:2021-10-22 10:36:58 來源:億速云 閱讀:138 作者:柒染 欄目:互聯網科技

這期內容當中小編將會給大家帶來有關什么是linux異常體系結構,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

以arm處理器為例, 外部中斷和處理器內核異常(soc內部)都屬于異常, 異常都是相對于主程序來講的, 當soc正常執行主程序時, 中斷和異常都可以打斷它, 依據異常對于主程序所體現出來的"中斷"性質可以區分出中斷和異常的區別:

異常: 由于soc本身的內核活動產生的, 如當執行主程序時候由于arm soc預取指令/數據而產生異常等, 這個異常來自soc的內核, 所以對于soc內核來說是"同步"的.

中斷: 當soc在執行主程序的時候, 各種片上外設和外部中斷引腳可以產生一個異常來中斷soc當前正在執行的程序, 這個異常信號來自soc的內核以外, 所以對于soc內核來說他是"異步"的

在arm架構的linux系統下, 共使用了5種異常: 1. 未定義指令異常 2. 指令預取中止異常 3. 數據訪問中止異常 4. 中斷異常 5. swi異常. 

(1) linux中斷體系結構

linux內核在(linux)/include/asm-arm/arch-s3c2410/irqs.h 中將所有的中斷統一編號, 另外 linux使用一個結構體數組來描述中斷, 并且這個數組的下標就是中斷號. 每個數組項對應一組中斷,

file: (linux)/include/linux/irq.h 
struct irq_desc {
	irq_flow_handler_t	handle_irq;     /* 當前中斷的處理函數入口 */
	struct irq_chip		*chip;          /* 底層的硬件訪問 */
        ...
	struct irqaction	*action;	/* 用戶提供的中斷處理函數鏈表 */
	unsigned int		status;		/* IRQ 狀態 */
        ...
	const char		*name;          /* cat /proc/interrupts 顯示的中斷名稱 */
} ____cacheline_internodealigned_in_smp;

其中的 chip 提供了底層的硬件訪問:

file: (linux)/include/linux/irq.h
struct irq_chip {
	const char	*name;	                            
	unsigned int	(*startup)(unsigned int irq);    /* 啟動中斷, 缺省為 "enable" */
	void		(*shutdown)(unsigned int irq);   /* 關閉中斷, 缺省為 "disable" */
	void		(*enable)(unsigned int irq);     /* 使能中斷, 缺省為 "unmask" */
	void		(*disable)(unsigned int irq);    /* 關閉中斷, 缺省為 "mask" */
	void		(*ack)(unsigned int irq);        /* 響應中斷, 通常為清除當前中斷使得可以接收下一個中斷 */
	void		(*mask)(unsigned int irq);       /* 屏蔽中斷源 */
	void		(*mask_ack)(unsigned int irq);   /* 屏蔽和響應中斷 */
	void		(*unmask)(unsigned int irq);     /* 開啟中斷源 */
	...
};

另外irqaction結構體為:

file: (linux)/include/linux/interrupt.h 
struct irqaction {
	irq_handler_t handler;    //用戶注冊的中斷處理函數
	unsigned long flags;	  //中斷標志
	cpumask_t mask;	          //用于smp
	const char *name;         //用戶注冊的名字 "cat /proc/interrupts" 可以看到
	void *dev_id;	          //用戶傳給上面的handler參數,還可以用來區分共享中斷
	struct irqaction *next;   //指向下一個irqaction結構
	int irq;                  //中斷號
	struct proc_dir_entry *dir;
};

中斷執行的流程是: 中斷到來時總中斷入口函數 asm_do_IRQ() 根據 中斷號 找到 irq_desc 結構體數組中的對應項, 并調用 irq_desc 結構體中的 handle_irq() 函數, handle_irq 函數使用 chip 結構體中的函數 清除/屏蔽/重新使能中斷, 最后一一調用 action 鏈表中注冊的中斷處理函數.

什么是linux異常體系結構

(2) 中斷體系結構初始化

在 (linux)/init/main.c 的 start_kernel() 函數中的 trap_init()  / init_IRQ()  來設置異常的處理函數. 

1. trap_init()  和 early_trap_init() 函數 通過下邊語句將異常向量復制到 0xffff0000 地址處, 將中斷服務函數復制到 0xffff0000 + 0x200地址處

file: (linux)/arch/arm/kernel 
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);

其中start和end如下:

.globl	__vectors_start
__vectors_start:
	swi	SYS_ERROR0
	b	vector_und + stubs_offset
	ldr	pc, .LCvswi + stubs_offset
	b	vector_pabt + stubs_offset
	b	vector_dabt + stubs_offset
	b	vector_addrexcptn + stubs_offset
	b	vector_irq + stubs_offset
	b	vector_fiq + stubs_offset

	.globl	__vectors_end
__vectors_end:

負責初始化的為 init_IRQ,因其與具體開發板密切相關,所以需要單獨列出來.  它用來初始化中斷的框架,設置各個中斷的默認處理函數. 當發生中斷時候進入中斷總入口 asm_do_IRQ()  調用init_IRQ()設置的函數

file: (linux)/arch/arm/kernel/irq.c
void __init init_IRQ(void)
{
	int irq;
	for (irq = 0; irq < NR_IRQS; irq++)
		irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;	
	init_arch_irq();
}

1 for循環中將 irq_desc[] 數組中每一項的狀態都設置為 IRQ_NOREQUEST | IRQ_NOPROBE (未請求 | 未探測)

2 init_arch_irq 其實是一個函數指針, 定義如下: 

file: (linux)/arch/arm/kernel/irq.c 
void (*init_arch_irq)(void) __initdata = NULL;

2440移植好的linux系統在啟動的時候通過(linux)/arch/arm/kernel/setup.c 的 setup_arch() 獲取到 machine_desc 結構體, 然后將 init_arch_irq 這個函數指針初始化為 s3c24xx_init_irq() . 

file: (linux/arch/plat-s3c24xx/irq.c 的 s3c24xx_init_irq)
void __init s3c24xx_init_irq(void)
{
    ...
    /* first, clear all interrupts pending... */
    ...
    /* register the main interrupts */
    ...
    /* setup the cascade irq handlers */
    set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
    set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
    ...
    /* external interrupts */
    //外部中斷 0 ~ 3
    for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
	irqdbf("registering irq %d (ext int)\n", irqno);
	set_irq_chip(irqno, &s3c_irq_eint0t4);
	set_irq_handler(irqno, handle_edge_irq);
	set_irq_flags(irqno, IRQF_VALID);
    }
    //外部中斷4 ~ 23
    for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
	irqdbf("registering irq %d (extended s3c irq)\n", irqno);
	set_irq_chip(irqno, &s3c_irqext_chip);
	set_irq_handler(irqno, handle_edge_irq);
	set_irq_flags(irqno, IRQF_VALID);
    }
    /* register the uart interrupts */
    ...
}

1. 清除所有中斷的 pending 位

2. 進一步設置 irq_desc[] 中元素的 chip , handle_irq字段.

set_irq_chip(irqno, &s3c_irqext_chip)  結果是: irq_desc[irqno]. chip = &s3c_irqext_chip; 之后就可以使用 irq_desc[irqno].chip 結構體的成員來設置觸發方式/使能中斷/禁止中斷等

set_irq_handler(irqno, handle_edge_irq) 結果是: irq_desc[irqno].handle_irq = handle_edge_irq; 這是該中斷號對應的中斷函數入口

set_irq_flags(irqno, IRQF_VALID) 結果是: 消除 irqno 對應的IRQ_NOREQUEST標志, 告訴系統該中斷被可申請使用了.中斷申請的時候會查看該標志如果設置了表示中斷尚不可用

執行完 init_IRQ之后 irq_desc[] 中各個數組項的chip, handle_irq字段都被設置好了.

(3) 用戶注冊中斷處理函數流程

驅動程序使用 request_irq 來向內核注冊中斷處理函數, request_irq 根據中斷號找到 irq_desc[] 數組項, 在數組項的 action 鏈表中添加一個表項.

file: (linux)/kernel/irq/manage.c
int request_irq(unsigned int irq, irq_handle_t handler, unsinged long irqflags, const char *devname, void *dev_id)
{
    struct irqaction *action;             //創建 irqaction 結構體指針   
    ...
    action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);//填充 irqaction 結構體各個元素
    action->handler = handler;    
    action->flags = irqflags;
    cpus_clear(action->mask);
    action->name = devname;
    action->next = NULL;
    action->dev_id = dev_id;
    
    retval = setup_irq(irq, action);      
    ...
}

setup_irq函數有幾個功能: 

1. 將 action 連接入 irq_desc[irq]的action鏈表中

2. irq_desc[].chip 結構體中沒有被 init_irq() 設置的元素設置為默認值

3. 使用傳入的 irqflags 作為參數 調用 chip->set_type來設置中斷: 設置為外部中斷, 設置觸發方式(高電平/低電平/上升沿/下降沿)

4. 啟動中斷, 調用chip->startup 或 chip->enable 使能中斷, 

總之, 調用了request_irq之后: irq_desc[]的action結構體已鏈入action鏈表, 中斷觸發方式也設置好了, 中斷已被使能. 現在中斷已經可以發生并處理了

(4) 中斷具體的執行流程

中斷的總入口是 asm_do_IRQ()

file: (linux)/arch/arm/kernel/irq.c 
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs){
        ...
	struct irq_desc *desc = irq_desc + irq;
        ...
        desc_handle_irq(irq, desc);
        ...
}

file: (linux)/include/asm-arm/mach/irq.h
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc){
	desc->handle_irq(irq, desc);
}

irq 取值范圍: IRQ0_EINT0~(IRQ_EINT0+31).  因為2440的INTPND共32bit, 但是irq_desc[]卻遠不止32個元素, 因為有些個中斷是共用同一個位, 如 EINT8~23. 所以當 asm_do_IRQ 的 irq 是對應于"一組"子中斷的時候, irq_desc[irq].handle_irq 函數還需要判斷出到底是哪個子中斷申請的中斷, 假設該子中斷號為irqno 那么繼續調用 irq_decs[irqno].handle_irq 來處理

  以外部中斷EINT8~23為例來講解中斷調用的詳細過程:

1 當EINT8~23 中任意一個中斷觸發的時候, INTOFFSET 寄存器的值都是 5.  asm_do_IRQ 的 irq 就是IRQ_EINT0+5 即 IRQ_EINT8t23, 然后調用 irq_desc[IRQ_EINT0t23].handle_irq 來處理

2 irq_desc[IRQ_EINT8t23].handle_irq 設置是在中斷初始化的時候完成的: init_IRQ -> init_arch_irq() 該函數指針在linux啟動的時候被賦值為 s3c24xx_init_irq ->

file: (linux)/arch/plat-s3c24xx/irq.c
    set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
    set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); //irq_desc[IRQ_EINT8t23].handle_irq 設置為 s3c_irq_demux_extint8
    set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
    set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
    set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
    set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);

接下來看看 s3c_irq_demux_extint8 做了些什么

static void s3c_irq_demux_extint8(unsigned int irq, struct irq_desc *desc){
	unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
	unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);

	eintpnd &= ~eintmsk;
	eintpnd &= ~0xff;	/* ignore lower irqs */

	/* we may as well handle all the pending IRQs here */
	while (eintpnd) {
		irq = __ffs(eintpnd);
		eintpnd &= ~(1<<irq);

		irq += (IRQ_EINT4 - 4);
		desc_handle_irq(irq, irq_desc + irq);
	}
}

他首先讀取了EINTPEND/EINTMASK寄存器, 查找出具體發生的中斷源, 然后重新計算中斷號, 最后使用新計算出的這個中斷號調用 irq_desc[新中斷號].handle_irq

 s3c_irq_demux_extint8 與 handle_edge_irq / handle_level_irq 是什么關系?

s3c_irq_demux_extint8最后調用 irq_desc[新中斷號].handle_irq 這個入口函數就是在 s3c24xx_init_irq 中定義的中斷入口函數 set_irq_handler(irqno, handle_edge_irq); 中的 handle_edge_irq 

上述就是小編為大家分享的什么是linux異常體系結構了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

莲花县| 紫金县| 贵定县| 兴仁县| 邮箱| 民丰县| 武冈市| 郑州市| 广灵县| 英超| 鹤壁市| 藁城市| 南溪县| 济宁市| 东丽区| 松溪县| 墨脱县| 鄂托克旗| 玛曲县| 江阴市| 淮滨县| 宣汉县| 博野县| 卓资县| 尉氏县| 海盐县| 安庆市| 定远县| 铅山县| 绥中县| 土默特右旗| 军事| 古浪县| 神木县| 全州县| 郧西县| 双鸭山市| 嵊泗县| 贡嘎县| 乐平市| 伽师县|