嵌入式30dvd30盤3linux-mipsMIPSCPU體系結(jié)構(gòu)概述Linux MIPS內(nèi)核_第1頁
嵌入式30dvd30盤3linux-mipsMIPSCPU體系結(jié)構(gòu)概述Linux MIPS內(nèi)核_第2頁
嵌入式30dvd30盤3linux-mipsMIPSCPU體系結(jié)構(gòu)概述Linux MIPS內(nèi)核_第3頁
嵌入式30dvd30盤3linux-mipsMIPSCPU體系結(jié)構(gòu)概述Linux MIPS內(nèi)核_第4頁
嵌入式30dvd30盤3linux-mipsMIPSCPU體系結(jié)構(gòu)概述Linux MIPS內(nèi)核_第5頁
已閱讀5頁,還剩29頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、MIPS CPU 體系結(jié)構(gòu)概述,Linux/MIPS內(nèi)核(下),彎曲評(píng)論、中國計(jì)算所第二部分 Linux/MIPS剖析1.硬件知識(shí)CPU 手冊(cè): h主板資料:相應(yīng)的廠商.背景知識(shí):如PCI協(xié)議,中斷概念等.2.資源/linux , h*ing lists:linu debia* kernel cvssgi:cvs -d :pserv (Only needed the cvs -d :pserv:/cvs logintime you use anonymous CVS, the password is cvs):/cvs co linux另外sourcef* 經(jīng)典書籍:也有另一個(gè)內(nèi)核樹,似乎不如

2、sgi的版本有影響.* Mips R4000 Microprosor Users Manual,by Joe Heinrich* See Mips Run,by Dominic Stman* See Mips Run(中文版)mJun Suns mips porting guide:交叉編譯指南: /brad/mips/mips-cross-toolchain.htmlDebian Mips port:* 系統(tǒng)計(jì)算:3. mips kernel的一般介紹(下面一些具體代碼基于2.4.8的內(nèi)核)來跟隨內(nèi)核啟動(dòng)運(yùn)行的過程看看mips內(nèi)核特別之處.加電后,mips kernel從系統(tǒng)固件程序(類似b

3、ios,可能燒在eprom,flash中)得到控制之后(head.S),初始化內(nèi)核棧,調(diào)用init_arch初始化硬件相關(guān)的代碼.init_arch(setup.c)首先監(jiān)測(cè)使用的CPU(通過MIPS CPU的CP0控制寄存器PRID)確定使用的指令集和一些CPU參數(shù),如TLB大小等.然后調(diào)用prom_init做一些底層參數(shù)初始化. prom_init是和具體的硬件相關(guān)的.使用MIPS CPU的多如牛毛, 所以大家在arips下面可以看到很多的子目錄,每個(gè)子目錄是一個(gè)或者一系列相似的.這里的差不多可以理解成一塊主板加上它的系統(tǒng)固件,其中很多還包括一些這些目錄的主要任務(wù)是:的顯卡什么的硬件(比如

4、一些工作站).1. 提供底層板子上的一些重要信息,包括系統(tǒng)固件傳遞的參數(shù),io的址,內(nèi)存的大小的分布等.多數(shù)還包括提供早期的信息輸入輸出接口(通常是一個(gè)簡(jiǎn)單的串口驅(qū)動(dòng))以方便調(diào)試,因?yàn)閜mon往往不提供鍵盤和顯示卡的支持.?2. 底層中碼,包括中斷控制器編程和中斷的分派,應(yīng)答等3. pci子系統(tǒng)底層代碼. 實(shí)現(xiàn)pci配置空間的讀寫,以及pci設(shè)備的中斷,IO/Mem空間的分配4. 其它,特定的硬件.常見的有實(shí)時(shí)時(shí)鐘等這里關(guān)鍵是要理解這些硬件和熟悉的x86不同之處.筆者印象較深的有幾個(gè):* item MIPS不象X86有很標(biāo)準(zhǔn)的硬件接口,而是五花八門,每個(gè)廠家有一套,因?yàn)樗鼈兒芏嗍窍到y(tǒng)或者專門的

5、工作站.不象PC中,有了BIOS后用同一套的程序,就可以使用很多不同的主板和CPU.MIPS中的bios常用的有pmon和yamon,都是開放源代碼的。很多開發(fā)板帶的固件功能和PC BIOS很不一樣,它們多數(shù)支持串口顯示,或者網(wǎng)絡(luò)和啟動(dòng),以及類DEBUG的調(diào)試界面,但可能根本不支持顯卡和硬盤,沒有一般的基本輸入輸出功能.* PCI系統(tǒng)和地址空間,總線等問題.在x86中,IO空間用專門的指令,而PCI設(shè)備的內(nèi)存空間和物理內(nèi)存空間是相同的,也就是說,在CPU看來物理內(nèi)存從地址0開始的話,在PCI設(shè)備看來也是一樣的.反之,PCI設(shè)備的相同的物理地址就行了.址寄存器設(shè)定的PCI地址,CPU用而在MIP

6、S中就很不一樣了,IO一般是memory map的,map到哪里就倚賴具體了.而PCI設(shè)備的地址空間和CPU所見的物理內(nèi)存地址空間往往也不一樣(bus address & physical address).所以mips kernel的iob/outb,以及 bus_to_virt/virt_to_bus,phys_to_virt/virt_to_phys,ioremap等就要考慮.這些問題有時(shí)間筆者會(huì)對(duì)這些問題做專門的說明.PCI配置空間的讀寫和地址空間的處理通常都是每個(gè)不一樣的.因?yàn)槿狈涌诘腂IOS,內(nèi)核經(jīng)常要自己做PCI設(shè)備的枚舉,空間分配,中斷分配.* 中斷系統(tǒng).PC斷控制器先是有8

7、259,后來是apic,而cpu的中斷處理386之后好像也變化不大,相對(duì).mips CPU的中斷處理方式倒是比較一致,但是主板上的控制器就亂七八糟了怎么鑒別中斷源,怎么編程控制器等任務(wù)就得各自實(shí)現(xiàn)了.總的說來,MIPS CPU的中斷處理方式體現(xiàn)了RISC的特點(diǎn):做事多,硬件盡量精簡(jiǎn). 編程控制器,提供中斷控制接口,dispatch中系?這一部分原來很,大家各寫各的,現(xiàn)在有人試圖寫一些比較用的controller/handler 抽象).的代碼(實(shí)際上就是原來x86上*管理.MIPS 是典型的RISC結(jié)構(gòu),它的管理單元做的事情比象x86這種機(jī)器少得多.例如,它的tlb是管理的,cache常常是需

8、要系統(tǒng)程序干預(yù)的.而且,過多的CPU和主板變種使得這一部分非常復(fù)雜,容易出錯(cuò).管理的代碼主要在include/asm-mips和ar* 其它.ips/mm/目錄下.如時(shí)間處理,r4k以上的MIPSpare寄存器,每隔幾拍count增加,提供到和compare相等時(shí)發(fā)生時(shí)鐘中斷,這可以用來提供系統(tǒng)的時(shí)鐘中斷.但很多板子自己也提供其它的可編程時(shí)鐘源.具體用什么就取決于開發(fā)者了.init_arch后是loadmmu,初始化cache/tlb.代碼在ar在cache和tlb之前CPU怎么工作的?ips/mm里.有人可能會(huì)問,在x86里有實(shí)模式,而MIPS沒有,但它的地址空間是特殊的,分成幾個(gè)不同的區(qū)域

9、, 每個(gè)區(qū)域中的地址在CPU里的待遇是不一樣的,系統(tǒng)剛上電時(shí)CPU從地址bfc00000開始,那里的地址既不用tlb也不用cache,所以CPU能工作而不管cache和tlb是什么樣子.當(dāng)然,這樣子效率是很低的,所以CPU很快就開始進(jìn)行l(wèi)oadmmu. 因?yàn)镸IPS CPU變種繁多,所以代碼又臭又長(zhǎng). 主要不外是檢測(cè)cache大小,選擇相應(yīng)的cache/tlb flush過程,還有一些memcpy/memset等的高效實(shí)現(xiàn).這里還很容易出微妙的錯(cuò)誤,管理tlb或者cache都不簡(jiǎn)單,要保證效率又要保證正確.在開發(fā)初期常常先關(guān)掉CPU的cache以便排除cache問題.MMU初始化后,系統(tǒng)就直接

10、跳轉(zhuǎn)到init/main.c中的start_kernel,很快吧?不過別高興,start_kernel槍,又回到arips/kernel/setup.c,調(diào)用setup_arch,這回就是完成上面說的各相關(guān)的初始化了.相關(guān)的初始化完成之后,mips內(nèi)核和其它的內(nèi)核區(qū)別就不大了,但也還有不少問題需要關(guān)注.如許多驅(qū)動(dòng)程序可能因?yàn)橐匈噚86的特殊屬性(如IO端口,自動(dòng)的cache一致性,顯卡初始化等)而不能直接在MIPS下工作.例如,能直接(用現(xiàn)有的內(nèi)核驅(qū)動(dòng))在MIPS下工作的網(wǎng)卡不是很多,筆者知道的有eleepro100,AMD pcnet32 ,Tulip. 3com的網(wǎng)卡好像大多不能用.顯卡則

11、由于vga bios,很少能直接使用.(常見的顯卡都是為x86做的,它們常常帶著一塊rom,里面含有vga bios,PC的BIOS的初始化過程中發(fā)現(xiàn)它們的化就會(huì)先去執(zhí)行它們以初始化顯卡,然后才能很早地在屏幕上輸出信息).而vga bios里面的代碼一般是for x86,不能直接在mips CPU上運(yùn)行.而且這些代碼里常常有一些廠家相關(guān)的特定初始化,沒有一個(gè)通用的代碼可以替換.數(shù)比較開放的廠家提供足夠的資料使得內(nèi)核開發(fā)能夠跳過vga bios的執(zhí)行直接初始化他的顯卡,如matrox.除此之外,也可能有其它的內(nèi)核代碼由于種種原因(不對(duì)齊等)不能使用,如一些文件系統(tǒng)(xfs?).,unsigned

12、/signed關(guān)于linux-mips內(nèi)核,在sgi的ing list搜索或者提問比較有希望獲得解決.如果你足夠有錢,可以montivista的服務(wù).htt.4.mips的異常處理硬件mips CPU的異常處理中,硬件做的事情很少,這也是RISC的特點(diǎn). 和x86系統(tǒng)相比,有兩點(diǎn)大不一樣:硬件不負(fù)責(zé)具體鑒別異常,CPU響應(yīng)異常之后需要根據(jù)狀態(tài)寄存器等來確定究竟發(fā)生哪個(gè)異常.有時(shí)候硬件會(huì)做一點(diǎn)簡(jiǎn)單分類,CPU能直接到某一類異常的處理 .硬件通常不負(fù)責(zé)保存上下文.例如系統(tǒng)調(diào)用,所有的寄存器內(nèi)容都要由進(jìn)行必要的保存.各種主板的中斷控制種類很多,需要根據(jù)中斷控制器和連線情況來編程.2.kernel實(shí)現(xiàn)

13、* 處理程序什么時(shí)候安裝?traps_init(ar./* Copy tips/kernel/traps.c,setup_arch之后start_kernel調(diào)用)eric exception handler code to its final destination. */memcpy(void *)(KSEG0 + 0 x80), &except_vec1_generic, 0 x80);memcpy(void *)(KSEG0 + 0 x100), &except_vec2_generic, 0 x80);memcpy(void *)(KSEG0 + 0 x180), &except_v

14、ec3_generic, 0 x80); flush_icache_range(KSEG0 + 0 x80, KSEG0 + 0 x200);/* Setup default vectors*/for (i = 0; i = 31; i+)set_except_vector(i, handle_.);* 裝的什么?except_vec3_generic(head.S) (除了TLB refill例外都用這個(gè)):/* General exception vector R4000 ver NESTED(except_vec3_r4000, 0, sp).setnoatmfc0k1, CP_CAUS

15、E. */andik1, k1, 0 x7c /* 從cause寄存器取出異常號(hào) */lilik0, 31init_IRQ中調(diào)用set_except_vector(0,p6032IRQ)填表(所有的中斷都cause寄存器中設(shè)置具體中斷原因).異常0,并在下面列出這兩個(gè)文件以便解說: p6032IRQ.salgor p6032(筆者用的開發(fā)板)中斷安排如下:MIPS IRQSource*0123456Software (ignored) Software (ignored)bonitoerrupt (hw0)i8259Aerrupt (hw1)Hardware (ignored) Debug S

16、witchHardware (ignored)*7R4k timer (what we use).text.set.setnoreordernoat.align 5NESTED(p6032IRQ, PT_SIZE, sp)SAVE_ALL /* 保存現(xiàn)場(chǎng),切換堆棧(if usermode - kernel mode)*/CLI/* 關(guān)中斷,mips有多種方法響應(yīng)中斷,CLI用清s的方法,如下:us相應(yīng)位Move to kernel mode and disableerrupts.Set cp0 enabit as signt were runningon the kernel stack */

17、#define CLImfc0t0,CP0_SUS;li or xorimtc0t1,ST0_CU0|0 x1f; t0,t1;t0,0 x1f;t0,CP0_SUS.semfc0s0, CP0_CAUSE/* get irq mask,中斷響應(yīng)時(shí)cause寄存器指示哪類中斷發(fā)生注意,MIPS CPU只區(qū)分8個(gè)中斷源,并沒有象PC中從總線中斷向量號(hào),所以每類中斷的代碼要自己設(shè)法定位中斷*/* 挨個(gè)檢查可能的中斷原因 */* andibeqwe check for r4k counter/timer IRQ. */ a0, s0, CAUSEF_IP7a0, zero, 1fandi a0, s

18、0, CAUSEF_IP3# delay slot, check 8259errupt/* Wheee, a timererrupt. */lijala0, 63do_IRQmovea1, spjnopret_from_irq# delay slot1:beqza0,1fandi a0, s0, CAUSEF_IP2/* Wheee, i8259Aerrupt. */* p6032也使用8259來處理一些pc style的設(shè)備*/jali8259A_irqdispatch/* 調(diào)用8259控制器的中斷分派代碼*/move a0, sp# delay slotjnopret_from_irq#

19、delay slot1:beqa0, zero, 1fandi a0, s0, CAUSEF_IP5/* Wheee, bonitoerrupt. */* bonito是6032板的北橋,它提供了一個(gè)中斷控制器*/jalbonito_irqdispatchmove a0, sp# delay slotjnopret_from_irq# delay slot1:nopbeqza0,1f/* Wheee, a debugerrupt. */ errupt# delay slotjalp6032_debug_move a0, spjret_from_irqnop# delay slot1:/* He

20、re by mistake? This issible, what can happen* is*/t by the time we take the exception the IRQoes low, so just leave if this is the case.jret_from_irq nopEND(p6032IRQ)irq.c部分代碼如下:p6032中斷共有四類: beginenumerateitem timer中斷,單獨(dú)處理 item debug中斷,單獨(dú)處理item 8259中斷,由8259控制器代碼處理 item bonito中斷由bonito控制器代碼處理 endenum

21、erate/* now mips kernel is using the same abstraction as x86 kernel,t is, all irqhe system are described in an structarray: irq_desc. Each item of a specific item recordsall the information about this irq,including suion,and the controllerndle it etc. Below is the controllerstructure for bonito irqs

22、,we can easily guess its functionalityfrom its names.*/hw_irq_controller bonito_irq_controller = bonito_irq,bonito_irq_startup,bonito_irq_shutdown, bonito_irq_enable, bonito_irq_disable, bonito_irq_ack,bonito_irq_end,NULL/* no affinity stuor UP */;voidbonito_irq_init(u32 irq_base)extern irq_desc_t i

23、rq_desc; u32 i;for (i= irq_base; i P6032_END; i+) irq_desci.sus = IRQ_DISABLED; irq_desci.action = NULL; irq_desci.depth = 1;irq_desci.handler = &bonito_irq_controller;bonito_irq_base = irq_base;/* 中斷初始化,的數(shù)據(jù)結(jié)構(gòu)就是irq_desc數(shù)組它的每個(gè)元素對(duì)應(yīng)一個(gè)中斷,該中斷的控制器類型,處理函數(shù),狀態(tài)等關(guān)于這些可以參見對(duì)x86中斷的分析*/void init init_IRQ(void)Bonit

24、o;/* Mask out allerrupt by writing 1 to all bitition in* theerrupt reset reg.*/BONITO_EDGE = BONITO_ICU_SYSTEMERR | BONITO_ICU_MASTERERR| BONITO_ICU_RETRYERR | BONITO_ICU_MBOXES;BONITO_POL = (1 (P6032_UART1-16)| (1 (P6032| (1 (P6032| (1 (P6032_ISANMI-16)_ISAIRQ-16)_UART0-16);BONITO_BONITO_STEER = 0;

25、ENCLR = 0;/* init all controllers */ init_generic_irq(); init_i8259_irqs();bonito_irq_init(16);BONITO_BONITO_STEER |= 1 (P6032ENSET = 1 (P6032_ISAIRQ-16);_ISAIRQ-16);/* hook up the-levelerrupndler */set_except_vector(0, p6032IRQ);./*p6032IRQ發(fā)現(xiàn)一個(gè)bonito中斷后調(diào)用這個(gè)*/ asmlinkage voidbonito_irqdispatch(struc

26、t pt_regs *regs)Bonito;irq; unsigned longi;_sus;/* Get pending sour, masked by current enables */* 到底是哪個(gè)中斷呢?從主板寄存器讀*/_sus = BONITO_;ISR & BONITO_EN & (1 (P6032_ISAIRQ-16)/* Scl pendingerrupt bits and execute appropriate actions */for (i=0; i32 &_sus; i+) if (_sus & 1i) irq = i + 16; /* 0-15 assigned

27、 to 8259,16-48 bonito*/* Clear bit to optimise loop exit */_sus &= (1normal,1-errorEXL: exception level,0-normal,1-exception,異常發(fā)生是EXL自動(dòng)置1IE:errupt Enable, 0 - disableerrupt,1-enableerrupt(IM位則可以用于enbale/disable具體某個(gè)中斷,ERL|EXL=1 也使得中斷不能響應(yīng))系統(tǒng)所處的模式由KSU,ERL,EXL決定:User mode: KSU = 10 & EXL=0 & ERL=0Superv

28、isor mode(never used): KSU=01 & EXL=0 & ERL=0 Kernel mode: KSU=00 | EXL=1 | ERL=12.cause寄存器31 30 29 28 2716 158 7 62 1 0|BD|0 | CE |0| IP7 - IP0|0|Exc code| 0 |異常發(fā)生時(shí)cause被自動(dòng)設(shè)置其中:BD指示最近發(fā)生的異常指令是否在delay slot中CE發(fā)生coprosor unusable異常時(shí)的coprosor(mips有4個(gè)cp)IP:errupt pending, 1-pending,0-noerrupt,CPU有6個(gè)中斷引腳,

29、加上兩個(gè)中斷(最高兩個(gè))Exc code:異常類型,所有的外設(shè)中斷為0,系統(tǒng)調(diào)用為8,. 3.EPC對(duì)一般的異常,EPC包含:. 導(dǎo)致異常的指令地址(virtual)or. if 異常在delay slot指令發(fā)生,該指令前面那個(gè)跳轉(zhuǎn)指令的地址當(dāng)EXL=1時(shí),處理器不寫EPC4.和相關(guān)的:context,BadVaddr,Xcontext,ECC,CacheErr,ErrorEPC以后再說一般異常處理程序都是先保存一些寄存器,然后清除EXL以便嵌套異常,清除KSU保持態(tài),IE位看情況而定;處理完后恢復(fù)一些保存內(nèi)容以及CPU狀態(tài)*/* SAVE_ALL 保存所有的寄存器,分成幾個(gè)部分,方便不同的

30、需求選用*/*保存AT寄存器,sp是棧頂PT_R1是at寄存器在pt_regs結(jié)構(gòu)的偏移量.set*/是匯編指示,告訴匯編器要干什么,不要干什么,或改變狀態(tài)#define SAVE_AT.set.set sw.setpush; noat;$1, PT_R1(sp);pop/*保存臨時(shí)寄存器,以及hi,lo寄存器(用于乘法保存64位結(jié)果)可以看到mfhi(取hi寄存器的值)后并沒有立即保存,這是因?yàn)榱魉€中,mfhi的結(jié)果一般一拍不能出來,如果下一條指令就想用v1則會(huì)導(dǎo)致硬件停一拍,這種情況下讓無關(guān)的指令先做可以提高效率.下面還有許多類似的例子*/#define SAVE_TEMPmfhi sw

31、 sw sw mflo sw sw sw sw sw sw swswv1;$8, PT_R8(sp);$9, PT_R9(sp);v1, PT_HI(sp); v1;$10,PT_R10(sp);$11, PT_R11(sp);v1, PT_LO(sp);$12, PT_R12(sp);$13, PT_R13(sp);$14, PT_R14(sp);$15, PT_R15(sp);$24, PT_R24(sp)/* s0-s8 */#define SAVE_SICsw sw sw sw sw sw sw swsw$16, PT_R16(sp);$17, PT_R17(sp);$18, PT_R

32、18(sp);$19, PT_R19(sp);$20, PT_R20(sp);$21, PT_R21(sp);$22, PT_R22(sp);$23, PT_R23(sp);$30, PT_R30(sp)#define str2(x) #x#define str(x) str2(x)/*ok,下面對(duì)這個(gè)宏有冗長(zhǎng)的注解*/ #define save_sic_function(symbol) asm (.globlt #symbol nt .alignt2nt.typet #symbol , functionnt .entt #symbol , 0n #symbol:nt.framet$29, 0

33、, $31nt ic_functionntswt$16, str(PT_R16)($29)ttt# save_s swt$17, str(PT_R17)($29)nt swt$18, str(PT_R18)($29)nt swt$19, str(PT_R19)($29)nt swt$20, str(PT_R20)($29)nt swt$21, str(PT_R21)($29)nt swt$22, str(PT_R22)($29)nt swt$23, str(PT_R23)($29)nt swt$30, str(PT_R30)($29)nt.endt #symbol nt.sizet #symb

34、ol,. - #symbol)/* Used in declaration of save_sic functions. */#define sic_unused sic attribute (unused)/*以下這一段涉及比較微妙,沒有可以跳過*/* save_sic_function宏是一個(gè)令人迷惑的東西,它定義了一個(gè)匯編函數(shù),保存s0-s8這個(gè)函數(shù)沒有返回!實(shí)際上,它只是一個(gè)函數(shù)的一部分:在arips/kernel/signal.c中有:save_sic_function(sys_rt_sigsuspend); sic_unused_sys_rt_sigsuspend(struct p

35、t_regs regs)sigset_t *unewset, saveset, newset; size_t sigsetsize;這里用save_sic_function定義了sys_rt_sigsuspend,而實(shí)際上如果你調(diào)用sys_rt_sigsuspend的話,它保存完s0-s8后,接著就調(diào)用_sys_rt_sigsuspend!看它后的反匯編片段:80108cc8 :80108cc8:80108ccc: 80108cd0:80108cd4:80108cd8:80108cdc: 80108ce0:80108ce4:80108ce8:afb00058 afb1005c afb20060

36、 afb30064 afb40068 afb5006c afb60070 afb70074afbe0090sw sw sw sw sw sw sw swsw$s0,88($sp)$s1,92($sp)$s2,96($sp)$s3,100($sp)$s4,104($sp)$s5,108($sp)$s6,112($sp)$s7,116($sp)$s8,144($sp)80108cec :80108cec: 80108cf0:80108cf4:80108cf8:80108cfc:27bdffc8 8fa8006424030010afbf0034 afb00030addiu lwli swsw$sp,

37、$sp,-56$t0,100($sp)$v1,16$ra,52($sp)$s0,48($sp) notice80108d00:80108d04:80108d08:.afa40038 afa5003cafa60040sw swsw$a0,56($sp)$a1,60($sp)$a2,64($sp)用到save_sic_function的地方共有4處:signal.c:save_s signal.c:save_s syscall.c:save_ssyscall.c:save_sic_function(sys_sigsuspend); ic_function(sys_rt_sigsuspend); i

38、c_function(sys_fork);ic_function(sys_clone);知道s0-s8如果在子過程用到,編譯器本來就會(huì)保存/恢復(fù)它的(如上面的s0),那為何要搞這個(gè)花招呢?筆者分析之后得出如下結(jié)論:(警告:以下某些內(nèi)容是筆者的推測(cè),可能不完全正確)先看看syscall的處理,syscall也是mips的一種異常,異常號(hào)為8.上次說了一般異常是如何工作的,但在handle_sys并非用BUILD_HANDLER生成,而是在scall_o23.S中定義,因?yàn)樗钟衅涮厥庵?缺省情況它只用了SAVE_SOME,并沒有保存at,t*,s*等寄存器,因?yàn)閟yscall 是由應(yīng)用程序調(diào)用

39、的,不象中斷,任何時(shí)候都可以發(fā)生,所以一般編譯器就可以保證不會(huì)丟數(shù)據(jù)了(at,t*的值應(yīng)該已經(jīng)無效,s*的值會(huì)被函數(shù)保存恢復(fù)).這樣可以提高系統(tǒng)調(diào)用的效率它還得和用戶空間打交道(取參數(shù),送數(shù)據(jù))還有個(gè)別系統(tǒng)調(diào)用需要在特定的時(shí)候手工保存s*寄存器,如上面的幾個(gè).為什么呢?對(duì)sigsuspend來說,它將使進(jìn)程在內(nèi)核中睡眠等待信號(hào)到來,信號(hào)來了之后將直接 先回到進(jìn)程的信號(hào)處理代碼,而信號(hào)處理代碼可能希望看到當(dāng)前進(jìn)程的寄存器 (sigcontext),這是通過內(nèi)核棧中的pt_regs結(jié)構(gòu)獲得的,所以內(nèi)核必需把s*寄存器保存到pt_regs中.對(duì)于fork的情況,則似乎是為了滿足vfork的要求.(v

40、fork時(shí),子進(jìn)程不拷貝頁表(即和父進(jìn)程完全共享內(nèi)存),注意,連copy-on-write都沒有!父進(jìn)程掛起一直到子進(jìn)程不再使用它的資源(exec或者exit).fork 系統(tǒng)調(diào)用使用ret_from_fork返回,其中調(diào)用到了RESTORE_ALL_AND_RET(entry.S),需要恢復(fù)s*.這里還有一個(gè)很容易的地方: 在scall_o32.S和entry.S中有幾個(gè)函數(shù)(匯編)是同名的,如restore_all,sig_return等.總體來說scall_o32.S中是對(duì)滿足o32(old 32bit)匯編約定的系統(tǒng)調(diào)用處理,可以避免保存s*,而entry.S中是通用的,保存/恢復(fù)所由

41、寄存器scall_o32.S中也有一些情況需要保存靜態(tài)寄存器s*,此時(shí)它就會(huì)到ret_from_syscall而不是本文件中的o32_ret_from_syscall返回了,兩者的差別就是恢復(fù)的寄存器數(shù)目不同.scall_o32.S中一些錯(cuò)誤處理直接用ret_from_syscall返回,筆者懷疑會(huì)導(dǎo)致s*寄存器被破壞,有機(jī)會(huì)請(qǐng)各路高手指教.好了,說了一通系統(tǒng)調(diào)用,無非是想讓大家明白內(nèi)核中寄存器的保存恢復(fù)過程,以及為了少做些無用功所做的努力.下面看為什么要save_sic_function:為了避免s0寄存器的破壞.如果使用sys_rt_sigsuspend() .save_sic;.問題呢,

42、請(qǐng)看,會(huì)Nasty degree - 3 days of tracking.The symptom was pthread cannot be created.get a BUS error.he end the caller willWhat exactly happened has to do with how registers are saved. Belowattached is the beginning part of sys_sigsuspend() function. It is easyto seewhen prot s0 is savedo stack frame AFT

43、ER its modified. Next times returns to userland, the s0 reg will be wrong!So the bug is either1)t we need to save s0 register in SAVE_SOME and not save it insave_sic; ort2) we fix compiler sot it does not use s0 registerhat case (itdoes the same thing for sys_rt_sigsuspend)I am sure Ralf will have s

44、omething to say about it. :-) In any case, Iattached a patch for 1) fix.sys_sigsuspend(struct pt_regs regs)8008e280: 27bdffc08008e284: afb00030addiu $sp,$sp,-64sw$s0,48($sp)sigset_t *uset, saveset, newset;save_sic(®s);8008e288:27b00040addiu $s0,$sp,64 /* save_ss0已經(jīng)破壞*/ic時(shí)8008e28c:8008e290:8008e29

45、4:8008e298:8008e29c:8008e2a0:8008e2a4:8008e2a8:8008e2ac:afbf003c afb20038 afb10034 afa40040 afa50044 afa60048 afa7004c ae100058ae11005csw sw sw sw sw sw sw swsw$ra,60($sp)$s2,56($sp)$s1,52($sp)$a0,64($sp)$a1,68($sp)$a2,72($sp)$a3,76($sp)$s0,88($s0)$s1,92($s0)#ifdef CONFIG_SMP# define GET_SAVED_SPmfc

46、0k0, CP0_CONTEXT;lui srlsllk1, %hi(kernelsp); k0, k0, 23;k0, k0, 2;adduk1, k0;lwk1, %lo(kernelsp)(k1);#else# define GET_SAVED_SP/*實(shí)際上就是k1 = kernelsp, kernelsp保存當(dāng)前進(jìn)程的內(nèi)核棧指針 */luilwk1, %hi(kernelsp);k1, %lo(kernelsp)(k1);#endif/*判斷當(dāng)前運(yùn)行態(tài),設(shè)置棧頂sp保存寄存器-參數(shù)a0-a3:4-7,返回值v0-v1:2-3,25,28,31以及一些控制寄存器,*/#define S

47、AVE_SOME.setpush;.setreorder; mfc0k0, CP0_SUS;sll.set bltzk0, 3;/* extract cu0 bit */ noreorder;k0, 8f;move k1, sp;.setreorder;/* Called from user mode, new stack. */GET_SAVED_SP8:movek0, sp;subu sw sw sw mfc0 sw sw sw mfc0 sw sw sw mfc0 sw sw sw swswsp, k1, PT_SIZE; k0, PT_R29(sp);$3, PT_R3(sp);$0,

48、 PT_R0(sp);v1, CP0_S$2, PT_R2(sp);US;v1, PT_SUS(sp);$4, PT_R4(sp);v1, CP0_CAUSE;$5, PT_R5(sp);v1, PT_CAUSE(sp);$6, PT_R6(sp); v1, CP0_EPC;$7, PT_R7(sp); v1, PT_EPC(sp);$25, PT_R25(sp);$28, PT_R28(sp);$31, PT_R31(sp);ori xori.set$28, sp, 0 x1;$28, 0 x1pop;#define SAVE_ALLSAVE_SOME; SAVE_AT; SAVE_TEMP

49、;SAVE_SIC#define RESTORE_AT.set.set lw.setpush; noat;$1, PT_R1(sp);pop;#define RESTORE_TEMPlw lw lw mtlo lw lw lw mthi lw lw lw lwlw$24, PT_LO(sp);$8, PT_R8(sp);$9, PT_R9(sp);$24;$24, PT_HI(sp);$10,PT_R10(sp);$11, PT_R11(sp);$24;$12, PT_R12(sp);$13, PT_R13(sp);$14, PT_R14(sp);$15, PT_R15(sp);$24, PT

50、_R24(sp)#define RESTORE_SIClw lw lwlw$16, PT_R16(sp);$17, PT_R17(sp);$18, PT_R18(sp);$19, PT_R19(sp);lw lw lw lwlw$20, PT_R20(sp);$21, PT_R21(sp);$22, PT_R22(sp);$23, PT_R23(sp);$30, PT_R30(sp)#if defined(CONFIG_CPU_R3000) | defined(CONFIG_CPU_TX39XX)#define RESTORE_SOME.setpush;.setreorder; mfc0t0,

51、 CP0_SUS;.set orixoripop;t0, 0 x1f; t0, 0 x1f;mtc0t0, CP0_SUS;li and lw nor and or mtc0 lw lw lw lw lw lw lw lwlwv1, 0 xff00; t0, v1; v0, PT_Sv1, $0, v1; v0, v1;v0, t0;v0, CP0_SUS(sp);US;$31, PT_R31(sp);$28, PT_R28(sp);$25, PT_R25(sp);$7,$6,$5,$4,$3,$2,PT_R7(sp); PT_R6(sp); PT_R5(sp); PT_R4(sp); PT_

52、R3(sp);PT_R2(sp)#define RESTORE_SP_AND_RET.setpush;.setnoreorder;lw lw jrrfe;k0, PT_EPC(sp);sp,k0;PT_R29(sp);/* 異常返回時(shí),把控制轉(zhuǎn)移到用戶代碼和把模式從內(nèi)核態(tài)改為用戶態(tài)要同時(shí)完成如果前者先完成,用戶態(tài)指令有機(jī)會(huì)以內(nèi)核態(tài)運(yùn)行導(dǎo)致安全;反之則會(huì)由于用戶態(tài)下不能修改狀態(tài)而導(dǎo)致異常r3000以前使用rfe(restore from exception)指令,這個(gè)指令把sus寄存器狀態(tài)位修改回異常發(fā)生前的狀態(tài)(利用硬件的一個(gè)小堆棧),但不做跳轉(zhuǎn). 技巧來完成要求:在一個(gè)跳轉(zhuǎn)指令的delay

53、slot中放rte.因?yàn)閐elay slot的指令是一定會(huì)做的,跳轉(zhuǎn)完成時(shí),sus也恢復(fù)了.MIPS III(r4000)以上的指令集則增加了eret指令來完成整個(gè)工作: 它清除sus寄存器的EXL位并跳轉(zhuǎn)到epc指定的位置.使用一個(gè)*/.setpop#else#define RESTORE_SOME.setpush;.setreorder; mfc0t0, CP0_SUS;.setori xoripop;t0, 0 x1f; t0, 0 x1f;mtc0t0, CP0_SUS;li and lw nor andorv1, 0 xff00; t0, v1; v0, PT_Sv1, $0, v1

54、; v0, v1;v0, t0;US(sp);mtc0v0, CP0_SUS;lw mtc0 lw lw lw lw lw lw lw lwlwv1, PT_EPC(sp); v1, CP0_EPC;$31, PT_R31(sp);$28, PT_R28(sp);$25, PT_R25(sp);$7,$6,$5,$4,$3,$2,PT_R7(sp); PT_R6(sp); PT_R5(sp); PT_R4(sp); PT_R3(sp);PT_R2(sp)#define RESTORE_SP_AND_RETlw.set eret;.setsp, PT_R29(sp);mips3;mips0#en

55、dif#define RESTORE_SPlwsp, PT_R29(sp);#define RESTORE_ALLRESTORE_SOME; RESTORE_AT; RESTORE_TEMP;RESTORE_SRESTORE_SPIC;#define RESTORE_ALL_AND_RET RESTORE_SOME; RESTORE_AT;RESTORE_TEMP;RESTORE_SIC;RESTORE_SP_AND_RET/* Move to kernel mode and disableerrupts.* Set cp0 enab*/#define CLImfc0it as signt w

56、ere running on the kernel stackt0,CP0_SUS;li orxorit1,ST0_CU0|0 x1f; t0,t1;t0,0 x1f;mtc0t0,CP0_SUS/* Move to kernel mode and enableerrupts.* Set cp0 enab*/#define STImfc0it as signt were running on the kernel stackt0,CP0_SUS;li orxorit1,ST0_CU0|0 x1f; t0,t1;t0,0 x1e;mtc0t0,CP0_SUS/* Just move to ker

57、nel mode and leaveerrupts as they are.* Set cp0 enabit as sign*/#define KMODEmfc0t0,CP0_St were running on the kernel stackUS;li orxorit1,ST0_CU0|0 x1e; t0,t1;t0,0 x1e;mtc0t0,CP0_SUS#endif /* ASM_STACKFRAME_H */下面是筆者在為godson CPU的頁面可執(zhí)行保護(hù)功能增加內(nèi)核支持時(shí)分析linux-mips mmu實(shí)現(xiàn)的一些筆記。也許第5節(jié)對(duì)整個(gè)工作過程的分析會(huì)有些用,其它語焉不詳?shù)臇|西多數(shù)

58、只是對(duì)筆者本人有點(diǎn)用.首先的,關(guān)鍵的,要明白MIPS CPU的tlb是參見它們的用戶手冊(cè).(for sgi-cvs kernel 2.4.17)1. mmu context管理的,cache也不是透明的,具體的cpu用8位asid來區(qū)分tlb表項(xiàng)所屬的進(jìn)程,但是進(jìn)程超過256個(gè)怎么辦?linux實(shí)現(xiàn)的是擴(kuò)展,每256個(gè)一組,TLB任何時(shí)候只存放同一組的asid因此不會(huì). 從一組的某個(gè)進(jìn)程切換到另一組時(shí),把tlb刷新ASID switch include/asm/mmu_context.h:asid_cache:8bit physical asid + software exten, the s

59、oftware extenbitsare used as a ver; this records the newest asid allocated,whilepros-mm-context records its own ver.get_new_mmu_context:asid_cache+, if increasement lead to change of software extenpartthen flush icache & tlb to avoiding with old vers.asid_cache = 0asid_cache ver switch_mm:to represe

60、nt no valid mmu context case,so thestart from 0 x100.if asid verof new pros differs from current pros,get a newcontext for it.( its safe even if it gets same 8bit asid as previousbecause this pros tlb entries musve been flushed at the timeof verincreasement)set entryhi,install pgd activate_mm:get ne

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論