日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Mips TLB miss实现in Linux

發(fā)布時(shí)間:2025/3/15 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mips TLB miss实现in Linux 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

TLB miss是Mips中內(nèi)存管理的核心流程。上一篇寫(xiě)了關(guān)于Mips中,TLB miss的相關(guān)原理,本文關(guān)注在Linux kernel中的代碼實(shí)現(xiàn)。

TLB Refill初始化

內(nèi)核啟動(dòng)過(guò)程中,會(huì)對(duì)TLB Refill異常進(jìn)行初始化,設(shè)置相應(yīng)的處理接口。主要流程如下(以R3k為例):

start_secondaryper_cpu_trap_inittlb_initbuild_tlb_refill_handlerbuild_r3000_tlb_refill_handler

具體設(shè)置處理函數(shù)的操作在build_r3000_tlb_refill_handler進(jìn)行,代碼如下:

/** The R3000 TLB handler is simple.*/ /** 標(biāo)準(zhǔn)的TLB Refill代碼,相對(duì)比較簡(jiǎn)單,只用一級(jí)頁(yè)表,跟Mips手冊(cè)中的基本一致。*/ static void build_r3000_tlb_refill_handler(void) {/* 頁(yè)目錄 */long pgdc = (long)pgd_current;u32 *p;/* 初始化tlb處理接口 */memset(tlb_handler, 0, sizeof(tlb_handler));p = tlb_handler;/* 讀取產(chǎn)生異常的虛擬地址 */uasm_i_mfc0(&p, K0, C0_BADVADDR);uasm_i_lui(&p, K1, uasm_rel_hi(pgdc)); /* cp0 delay */uasm_i_lw(&p, K1, uasm_rel_lo(pgdc), K1);uasm_i_srl(&p, K0, K0, 22); /* load delay */uasm_i_sll(&p, K0, K0, 2);uasm_i_addu(&p, K1, K1, K0);/* 從CONTEXT寄存器中讀取信息 */uasm_i_mfc0(&p, K0, C0_CONTEXT);uasm_i_lw(&p, K1, 0, K1); /* cp0 delay */uasm_i_andi(&p, K0, K0, 0xffc); /* load delay */uasm_i_addu(&p, K1, K1, K0);uasm_i_lw(&p, K0, 0, K1);uasm_i_nop(&p); /* load delay *//* 寫(xiě)ENTRYLO0寄存器,供后面的tlbwr指令使用,將其寫(xiě)入TLB */uasm_i_mtc0(&p, K0, C0_ENTRYLO0);/* 讀取EPC寄存器,其中保存了異常返回地址 */uasm_i_mfc0(&p, K1, C0_EPC); /* cp0 delay *//* tlbwr指令,根據(jù)ENTRYLO0寄存器內(nèi)容(來(lái)源于頁(yè)表,通過(guò)Context寄存器索引),寫(xiě)TLB */uasm_i_tlbwr(&p); /* cp0 delay *//* 跳轉(zhuǎn)到異常返回地址,退出異常 */uasm_i_jr(&p, K1);uasm_i_rfe(&p); /* branch delay */.../** 關(guān)鍵點(diǎn):將tlb_handler(也就是前面設(shè)置的TLB refill異常處理函數(shù))內(nèi)容拷貝到ebase* (Mips為異常分配的物理地址空間(大小為0x80),用ebase寄存器指向,簡(jiǎn)單情況下,就是* 物理地址0x0),當(dāng)TLB Refill異常發(fā)生時(shí),硬件會(huì)自動(dòng)跳轉(zhuǎn)到ebase對(duì)應(yīng)的地址執(zhí)行。*/memcpy((void *)ebase, tlb_handler, 0x80);... }

可以看出,TLB refill異常的處理函數(shù)代碼,是內(nèi)核動(dòng)態(tài)設(shè)置的,而不是匯編?kù)o態(tài)代碼,由于Mips硬件型號(hào)比較多,如此操作更具靈活性。

同時(shí),請(qǐng)注意TLB refill異常處理函數(shù)入口位于固定物理地址:0x0。

General Exception初始化

內(nèi)核啟動(dòng)過(guò)程中,會(huì)對(duì)General Exception相應(yīng)的異常處理接口進(jìn)行初始化,主要流程如下:

start_kerneltrap_init

trap_init完成異常相關(guān)初始化操作,主要代碼如下:

void __init trap_init(void) {// General Exception處理接口extern char except_vec3_generic;.../** Copy the generic exception handlers to their final destination.* This will be overriden later as suitable for a particular* configuration.*//** 將General Exception的處理函數(shù)(指令)拷貝到0x180(物理地址)中,0x180是r4000以上* 的Mips CPU中General Exception默認(rèn)入口地址,該段物理地址空間大小為0x80,專門(mén)* 預(yù)留出來(lái)用于General Exception的處理。*/set_handler(0x180, &except_vec3_generic, 0x80);/** Setup default vectors*//×* 為0-31號(hào)異常設(shè)置默認(rèn)的處理接口,General Exception對(duì)應(yīng)編號(hào)為3,TLB refill異常* 對(duì)應(yīng)編號(hào)為1。*/for (i = 0; i <= 31; i++)set_except_vector(i, handle_reserved);.../** General Exception是所有普通優(yōu)先級(jí)異常的總?cè)肟?#xff0c;其中會(huì)根據(jù)異常碼調(diào)用不同的處理* 接口,這里就是設(shè)置不同的異常嗎對(duì)應(yīng)的處理接口。* 注意:2號(hào)異常碼對(duì)應(yīng)為**page fault**異常,即TLB Load異常,處理接口為handle_tlbl*/set_except_vector(0, using_rollback_handler() ? rollback_handle_int: handle_int);set_except_vector(1, handle_tlbm);set_except_vector(2, handle_tlbl);set_except_vector(3, handle_tlbs);set_except_vector(4, handle_adel);set_except_vector(5, handle_ades);set_except_vector(6, handle_ibe);set_except_vector(7, handle_dbe);/* 設(shè)置系統(tǒng)調(diào)用處理接口 */set_except_vector(8, handle_sys);/** 根據(jù)不同的CPU類型,設(shè)置相應(yīng)的General Exception的處理接口地址,對(duì)應(yīng)R4,地址為* 0x180,其它(更老的)為0x80.*/if (cpu_has_vce)/* Special exception: R4[04]00 uses also the divec space. */set_handler(0x180, &except_vec3_r4000, 0x100);else if (cpu_has_4kex)set_handler(0x180, &except_vec3_generic, 0x80);elseset_handler(0x080, &except_vec3_generic, 0x80);... }

General Exception處理

General Exception處理在except_vec3_generic函數(shù)中,以匯編實(shí)現(xiàn),其中主要工作是:讀取異常類型碼ExcCode,然后調(diào)用相應(yīng)的處理接口。主要代碼如下(genex.S文件中):

/** General exception vector for all other CPUs.** Be careful when changing this, it has to be at most 128 bytes* to fit into space reserved for the exception handler.*/ /** 匯編代碼,最終被拷貝到0x180的物理地址中,注意這段物理地址空間是有大小限制的,最大為128* 字節(jié)(0x80),所以處理不能太復(fù)雜。*/ NESTED(except_vec3_generic, 0, sp).set push.set noat #if R5432_CP0_INTERRUPT_WARmfc0 k0, CP0_INDEX #endifmfc0 k1, CP0_CAUSE //從CP0_CAUSE寄存器中讀取異常類型碼ExcCodeandi k1, k1, 0x7c #ifdef CONFIG_64BITdsll k1, k1, 1 #endif/** 根據(jù)類型碼,條用exception_handlers中對(duì)應(yīng)的接口,exception_handlers中的處理接口* 是在trap_init初始化時(shí)設(shè)置的。*/PTR_L k0, exception_handlers(k1)jr k0.set popEND(except_vec3_generic)

TLB Load異常處理初始化

前面的General Exception初始化流程中,僅設(shè)置了General Exception的處理入口和不同的異常碼對(duì)應(yīng)的處理接口,但是并設(shè)置具體的異常處理函數(shù)內(nèi)容,即異常發(fā)生后具體執(zhí)行的代碼,其初始化是在另外的流程中:

start_secondaryper_cpu_trap_inittlb_initbuild_tlb_refill_handlerbuild_r3000_tlb_load_handler

具體實(shí)現(xiàn)在build_r3000_tlb_load_handler函數(shù)中,關(guān)鍵代碼如下:

static void build_r3000_tlb_load_handler(void) {u32 *p = handle_tlbl;const int handle_tlbl_size = handle_tlbl_end - handle_tlbl;.../* 初始化 */memset(handle_tlbl, 0, handle_tlbl_size * sizeof(handle_tlbl[0]));.../** 寫(xiě)匯編代碼,相當(dāng)于j tlb_do_page_fault_0,即直接跳轉(zhuǎn)到tlb_do_page_fault_0處* 執(zhí)行,即調(diào)用tlb_do_page_fault_0函數(shù)*/uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);uasm_i_nop(&p);... }

TLB Load異常處理(Page Fault)

如前面的代碼分析,tlb load異常的處理接口中,其實(shí)就是調(diào)用tlb_do_page_fault_0函數(shù),再看看這個(gè)函數(shù)實(shí)現(xiàn)(匯編代碼,在tlbex-fault.S文件中):

/* tlb_do_page_fault_0和tlb_do_page_fault_1一起實(shí)現(xiàn),通過(guò)宏控制 */ .macro tlb_do_page_fault, write NESTED(tlb_do_page_fault_\write, PT_SIZE, sp) /* 保存上下文 */ SAVE_ALL /* 讀取發(fā)送異常的虛擬地址 */ MFC0 a2, CP0_BADVADDR KMODE move a0, sp REG_S a2, PT_BVADDR(sp) li a1, \write PTR_LA ra, ret_from_exception /* 關(guān)鍵點(diǎn):調(diào)用do_page_fault函數(shù) */ j do_page_fault END(tlb_do_page_fault_\write) .endm

代碼很簡(jiǎn)單,除保存上下文之類的操作外,就是調(diào)用do_page_fault函數(shù)了,這個(gè)就是我們很熟悉的page fault的標(biāo)準(zhǔn)接口了,其中會(huì)分配內(nèi)存,并新增頁(yè)表項(xiàng),建立虛擬地址和物理地址的映射關(guān)系。這里就不說(shuō)的,以前寫(xiě)過(guò)分析文檔。


原文地址:?http://happyseeker.github.io/kernel/2016/12/28/mips-TLB-miss-implemented-in-linux.html

與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的Mips TLB miss实现in Linux的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。