LINUX驅動、系統底層


就業模擬測試題-LINUX驅動、系統底層工程師職位

本試卷從考試酷examcoo網站導出,文件格式為mht,請用WORD/WPS打開,並另存為doc/docx格式后再使用

試卷編號:143921
試卷錄入者:yisonghua(遠見)
試卷總分:80
出卷時間:2012-09-13 14:53
答題時間:150分鍾
姓名: 學號: 班級:

說明: 以下個體中的分數是說明題目的重要性而言的,並不是具體題目的考試分數,此試卷中的題目主要是出現在筆試之后的面試中,大部分題目要直接能說的出來,多去整理,完善自己的表達
1.你平常是怎么用C寫嵌入式系統的死循環的? [3分]

參考答案:
while(1)
{
//...
}
或者
for(;;)
{
//...
{

2.寫一條命令,實現在dir以及其子目錄下找出所有包含“hello world”字符串的文件[2分]

參考答案:
grep -r "hello world" ./dir
或者grep -rHn "hello world" ./

3.下面的兩段程序中,循環能否執行?為什么?
A:
unsigned short i;
unsigned short index = 0;
for(i = 0; i <index-1; i++){
printf(“a\n”);
}
不能,當執行到語句 i<index-1 時,由於類型不匹配,右邊的index和1相減時會發生隱式類型轉換 ,即index將被轉換成有符號整型 ,轉換之后的index還是0,因此程序片段A中的index-1的結果就是 -1 ,此時判斷 i<index-1,即 0<-1,顯然不成立。立即退出循環。

B:
unsigned short i;
unsigned long index = 0;
for(i = 0; i <index-1; i++){
printf(“b\n”);
}
能,index是unsigned long型,當執行到語句 i<index-1 時,由於類型不匹配,右邊的index和1相減時也會發生由低精度類型向高精度方向的隱式類型轉換 ,即1將被轉換成無符號長整型 ,因此程序片段B中的index-1的過程用十六進制數表示實際上就是0x00000-0x0001=0xffff,此時再把左邊的 i 隱式轉換成無符號長整型之后判斷 i<index-1,即 0<0xffff,顯然成立。立即進入循環。 [每空2分]
解析:
隱式類型轉換規則:

C語言自動轉換不同類型的行為稱之為隱式類型轉換 ,轉換的基本原則是:低精度類型向高精度類型轉換,具體是:

int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double

注意,上面的順序並不一定適用於你的機器,比如當int和long具有相同字長時,unsigned int的精度就會比long的精度高(事實上大多數針對32機的編譯器都是如此)。另外需要注意的一點是並沒有將char和short型寫入上式,原因是他們可以被提升到int也可能被提升到unsigned int。

提升數據的精度通常是一個平滑無損害的過程,但是降低數據的精度可能導致真正的問題。原因很簡單:一個較低精度的類型可能不夠大,不能存放一個具有更高精度的完整的數據。一個1字節的char變量可以存放整數101但不能存放整數12345。當把浮點類型數據轉換為整數類型時,他們被趨零截尾或舍入。

強制類型轉換:

通常我們應該避免自動類型轉換,當我們需要手動指定一個准確的數據類型時,我們可以用強制類型轉換機制來達到我們的目的,使用方法很簡單,在需要強制轉換類型的變量或常量前面加上(type),例如(double)i; 即把變量 i 強制轉換成double型。

4.一個計划跑LINUX系統的ARM系統把bootloader燒錄進去后,上電后串口上沒有任何輸出,硬件和軟件各應該去檢查什么?
提示: 1.跑LINUX的系統一般都需要外擴DRAM,一般的系統也經常有NOR或NAND FLASH
2.bootloader一般是由匯編和C編寫的裸奔程序[5分]

參考答案:
單片機系統:
硬件上:
1.確認電源電壓是否正常。用電壓表測量接地引腳跟電源引腳之間的電壓,看是否是電源電壓,例如常用的5V。
2.檢查復位引腳電壓是否正常。分別測量按下復位按鈕和放開復位按鈕的電壓值,看是否正確。
3.檢查晶振是否起振了,一般用示波器來看晶振引腳的波形,另一個辦法是測量復位狀態下的IO口電平,按住復位鍵不放,然后測量IO口(沒接外部上拉的IO口除外)的電壓,看是否是高電平,如果不是高電平,則多半是因為晶振沒有起振。
4.檢查基本的外擴設備(這里主要是DRAM,特別是DDR/DDR2/DDR3)的pcb layout的走線是否符合要求
軟件上:
如果軟件代碼中:
1.檢查CPU和DRAM是否正確初始化(CPU的初始化包括一些典型步驟如: 關閉看門狗,關鍵FIQ,IRQ中斷,關閉MMU和CACHE,調整CPU的頻率)
2.檢查堆棧指針是否正確設置了
2. 若如NAND FLASH做系統啟動部分,則需注意一般需要的從NAND FLASH中拷貝代碼到DRAM中的步驟是否能正常完成

5.列舉最少3種你所知道的嵌入式的體系結構,並請說明什么是ARM體系結構。[7分]

參考答案:
嵌入式的體系結構包括ARM,MIPS,POWERPC,X86,AVR32,SH等
這個沒有非常標准的答案,但由經常面試的時候會問到,關於什么是ARM體系結構主要請參考講義的ARM相關章節去總結,下面是我的總結,僅供參考:
什么是ARM體系結構?
答: 首先,ARM體系結構是ARM公司設計,並授權其合作伙伴生產的占嵌入式市場份額最大的一種RISC(精簡指令集)的CPU,它具有高性能、低功耗、低成本的特點。
ARM體系結構從工作模式、工作狀態,指令集幾個方面簡述以下ARM:
ARM體系支持7種工作模式,包括系統(Sys)、未定義指令(und)、數據存取異常(abt)、 管理(SVC)、中斷(IRQ)、快速中斷(FIQ)、用戶模式(usr).其中,除了用戶模式以外的其它模式,我們稱之為特權模式.它們之間的區別在於有些操作只能在特權模式下才被允許,如直接改變模式和中斷使能等. 除了用戶模式和系統模式以外的其它5種模式,我們又稱之為異常模式。當特定的異常出現的時候,程序就會進入到相應的異常模式中。
備注: 在LINUX系統中, Linux的應用程序工作在usr模式,而內核在正常情況下工作在svc模式,當中斷或異常時工作在異常模式
ARM體系結構中CPU有2種工作狀態,thumb(指令為16位)和ARM狀態(指令為32位),相對寄存器不多,總共37個,它包括通用寄存器r0~r12(FIQ 有自己的r8 ~ r12),棧指針寄存器SP(r13),鏈接寄存器lr(r14),PC指針寄存器PC(r15),程序狀態寄存器CPSR和保存程序狀態寄存器SPSR,在上面提到幾種異常中,用戶(usr)和系統模式(sys)使用相同寄存器, 而其他異常模式有自己獨立的SP,LR,SPSR寄存器。
當異常產生時, 硬件上(ARM core)會完成以下動作:
拷貝 CPSR 到 SPSR_<mode>
設置適當的 CPSR 位:
改變處理器狀態進入 ARM 態
改變處理器模式進入相應的異常模式
設置中斷禁止位禁止相應中斷 (如果需要)‏}保存返回地址到 LR_<mode>
設置 PC 為相應的異常向量
返回時, 軟件的異常處理程序需要:
從 SPSR_<mode>恢復CPSR
從LR_<mode>恢復PC
Note:這些操作只能在 ARM 態執行.
ARM處理器是基於精簡指令集計算機(RISC)原理設計的,發展過程中商用的指令集經過了v4,v5,v6,v7(cortex系列) 4個系列,ARM內核的通用處理器型號比較常見的有arm7tdmi(v4), arm920/arm920t/arm926ejs,arm10,arm11,cortex-a8。
為了提高指令執行效率,大部分的ARM指令為單周期指令,並從軟件設計角度看,ARM處理器的指令流水線采用3級流水線模型,並提供了LDM/STM類似的批量數據操作指令。
為了提高CPU訪問外部設備數據效率,ARM處理器除部分ARM7采用馮.洛伊曼結構外,其他得都采用
哈佛架構,從而實現了對指令和數據存儲器的同時訪問。並且,ARM CPU提供了現代操作系統所需的虛擬內存管理機制(MMU)和指令、數據cache,並提供了協議處理器(cp15)來協助管理CPU的MMU和CACHE。

擴展概念:以上敘述里面提及的概念也要稍微去總結一下,比如:
1.什么是RISC?
2.ARM中斷在ARM9,CORTEX-A8是怎么處理的?LINUX中為什么需要把中斷分為上半部分,下半部分
3.MMU和CACHE的一些基本原理和知識


6.請簡述下面這段代碼的功能
mov r12, #0x0
ldr r13, =0x30100000
mov r14, #4096
loop:
ldmia r12!, {r0-r11}
stmia r13!, {r0-r11}
cmp r12, r14
blo loop [2分]

參考答案:
借助r0~r11,將內存地址0x0開始的4KB數據拷貝到0x30100000

7.嵌入式中常用的文件系統有哪些?說出它們的主要特點和應用場合?[5分]

參考答案:
嵌入式相關的文件系統: 嵌入式文件系統包括只讀和可讀寫文件系統,一般情況下,只讀文件系統啟動速度快於可讀寫的文件系統
嵌入式相關的文件系統包括以下幾種:
只讀文件系統
cramfs: 壓縮的只讀文件系統
特點: 啟動快,文件最大支持256MB,單個文件最大16MB
squashfs: 只讀文件系統
特點: 壓縮比最大,啟動比cramfs慢
案例:路由器,ubuntu的發行光盤 可結合LZMA壓縮算法
可讀寫的文件系統:
JFFS2: 支持NOR 和NAND FLASH (對NAND的支持天生不足)
特點:
1.可讀寫
2. 掛載慢(特別是在小文件很多的文件系統中,就更慢)
3. 當數據占到JFFS2分區的75~80%左右時,性能會急劇下降
YAFFS2: 只支持NAND FLASH
特點: 1.可讀寫
2. 掛載快(特別是在小文件很多的文件系統中,優勢更明顯)
3.它不是標准內核中的,需通過補丁添加
ubifs:
起碼支持NAND FLASH
特點: 1.可讀寫
2. 掛載快
3.它的實現和其他的文件系統不一樣,引進了一個"卷"的概念
在內存中的文件系統:
ramdisk: 描述的是功能,不是格式
   啟動快,防止用戶修改
ramfs: 在內存中的文件系統
tmpfs: 臨時文件系統
實時反映系統狀態: procfs, sysfs
另外,一些支持SD卡,U盤功能的系統還需要支持
windows文件系統: fat: FAT32
另外,一些帶硬盤的嵌入式系統(比如DVR)還需要支持
硬盤的文件系統: EXT3/EXT4

另外,很重要很重要的一點,需要去總結文件過程中遇到的問題,總結比如文件體系掛不上的可能原因
(給個提示,可能有比如網卡或FLASH驅動沒加載,內核啟動參數傳的不對,文件系統制作的步驟不對等好像原因)

8.某外設寄存器rGpioBase的地址是0x56000000,寄存器的0~15位有效,請寫出給外設寄存器高八位(8~`15位)設置成0xc3的代碼[7分]

參考答案:
#define rGpioBase (*((volatile unsigned int *)0x56000000))
rGpioBase &= ~0xff00;
rGpioBase |= 0xc300;

9.根據時序圖和說明編寫程序:
 
GPIO已經設置好,只需要調用函數gpio_seet_level(int gpio, int level)即課使某個GPIO輸出高電平或者低電平。圖中用於產生時序的gpio已經分別定義為SSP_XCS,SSP_SCLK,SSP_DIN,level的定義分別為GPIO_LO和GPIO_HI,需要編寫函數的原型為:void ssp_io_write_word(u32 command),該函數用來輸出一個字(如上圖中的A0到C0一組9位),這9個位是在參數command中的低9位. [5分]

參考答案:
這道題立意非常好,做為一個底層工程師,看時序是必須的,相關的代碼寫法:
void ssp_io_wirte_word(u32 command)
{
int i;
//片選
gpio_set_level(SSP_XCS, GPIO_LO);
//送COMMAND
for (i=0; i++; i<9) { //依次送A0,C7~C0
gpio_set_level(SSP_SCLK,GPIO_LO);
gpio_set_level(SSP_DIN, (command >>(8-i))&0x1);
gpio_set_level(SSP_SCLK,GPIO_HI);
}
//結束片選
gpio_set_level(SSP_SCLK,GPIO_LO);
gpio_set_level(SSP_XCS, GPIO_HI);
return;
如果實際結果並沒有把數據正確的送出,那么就需用示波器或者邏輯分析儀看一下波形是否正確,再根據計算得到的CLK周期看一下CLK的延時是否合適,否則就加一定延遲處理
================================
另外,這道題還提醒我們,I2C的時序是要能記得的,如果不記得,再去復習I2C協議


10.簡述LINUX系統從上電開始到系統起來的主要流程?
提示: 1.可以uboot、內核和文件系統的主要功能去總結
2.這個題主要是在筆試之后的面試,需要在3~5分鍾之內表述清楚[8分]

參考答案:
系統啟動流程應該從4個方面去總結,bootloader,內核,文件系統掛載,應用程序運行4個方面去總結,先總結大功能,再總結小功能:下面的手繪稿中,先說第一層,再說分開說第二層,在說第二層的時候,可以三星的ARMCPU,以從NAND FLASH啟動為例,並在我們的圖上加上硬件的相應部分:CPU上電時,CPU里面的ROMCODE負責把booloader的前面部分代碼搬移到SRAM,並把SRAM映射成0x0地址,然后跳到0x0地址,另外,bootloader第二層里面,說完初始化CPU(可補充一下CPU的初始化包括進入到管理模式,關閉看門狗,中斷,MMU和CACHE)和DRAM后,省略號(...)的位置是在補充一行文字: 把bootloader完整代碼拷貝到DRAM中 
另外,很重要很重要的一點,需要去總結移植過程中遇到的典型問題和以及自己當時是怎么思考這個問題,並找到解決方法的過程(至少應該總結2~3個問題),也到網上去以比如(uboot, ARM 移植,問題)或(內核 移植 問題)和(文件 移植 問題)這樣的關鍵詞去搜看看別人經常遇到什么問題,總結一下!!
    

11.如何編寫一個LINUX驅動?
提示:主要說字符設備的編寫過程 [7分]

參考答案:
這個得對着自己相應模塊的驅動的找出其初始化部分並總結,下面是我總結的,僅僅供參考,不要照搬這些東西:切忌照搬,得自己去總結一下主要流程,
以字符設備為例,現在平台設備的驅動一般包括(注意,以下部分要結合一個具體的驅動去說):
一.在系統的資源文件代碼中定義platform_device,里面填寫對應設備的外設IO起始地址,地址長度,中斷,DMA資源等信息資源信息,並把資源信息添加到系統啟動初始化流程里面,比如:

/* LCD Controller */
static struct resource s3c_lcd_resource[] =
{
[0] = {
.start = S3C24XX_PA_LCD,
.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL }};
EXPORT_SYMBOL(s3c_device_lcd);

二. 通過module_init(xxx_init)和moule_exit(xxx_init)定義驅動入口和出口函數;
三.寫出模塊加載xxx_init()和退出的實際處理函數xxx_exit(),這里以xxx_init()為例:
在里面調用platform_driver_resigter()注冊一個platform_driver結構體,實現其中的probe()和remove()函數以及driver成員結構體中name和owner成員,比如:

static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.driver = {
.name = "s3c2410-lcd",
.owner = THIS_MODULE,
},
};
五、在xxx_probe()函數里面主要做一下事情:
1.獲取平台設備資源的外設IO地址,中斷,DMA資源等信息
2.映射外設控制寄存器的外設IO地址到內核的虛擬地址空間
3.使能外設時鍾,注冊外設中斷的處理函數(如果有中斷)
4.掃描和初始化硬件
5.最后向LINUX內核注冊相應設備並通知應用層的udev/mdev守護進程創建相應的設備節點,或者通過子系統(比如輸入子系統,I2C子系統等)注冊相應設備並創建設備節點
6.然后,根據字符設備相應的數據結構file_operations的實現里面的比如open,release,read,write,mmap等關鍵函數,或者通過子系統去注冊的話,按子系統要求去實現相應的代碼就行了



12.簡述LINUX驅動中字符設備和塊設備的區別?[5分]

參考答案:
字符設備的特點是數據以字符流的方式進行訪問,數據的順序不能錯序,亂序和隨機讀寫,字符設備內核中不需要讀寫的緩沖,其驅動不支持lseek()函數
塊設備的特點是數據是固定塊大小(典型值有512字節,2KB,4KB)進行讀寫,塊設備可以隨機讀寫,讀寫的時候內核中需要緩沖,驅動支持lseek()函數,塊設備中數據的訪問需要先mount到LINUX的目錄文件后才能訪問里面的數據
LINUX中字符設備架構相對簡單,應用編程的系統調用open,close,read,write和ioctl等函數驅動里面有相應的file_operations結構體里面的函數與之對應
LINUX中塊設備架構相對復雜,應用程序的讀寫會通過塊設備里面的文件系統轉化為讀寫的IO請求,塊設備驅動里面通過gendisk結構體抽象塊設備,並通過對請求隊列的處理來實現對塊設備的讀寫曹


13.試總結單片機底層開發與LINUX驅動開發有哪些異同?[4分]

參考答案:
相同點:
單片機開發和LINUX的驅動開發都有對硬件的操作,最底層對硬件的寄存器操作,對時序的理解是一致的。
不同點:
1.單片機是對外設的IO實地址進行直接操作,而LINUX里面,由於使能了MMU,所以對外設IO地址的操作必須先通過ioremap()或者通過靜態映射,把外設IO地址映射到內核的虛擬地址空間后才能正確操作
2.在單片機編寫對應設備的驅動不用考慮系統太多的系統分層問題,重用其他的代碼量比較小,而LINUX采用分層抽象的思想,在LINUX中編寫設備驅動,要按照LINUX已經搭建好的層次結構進行驅動編寫,經常調用LINUX提供的函數和機制,代碼重用性大
3.由於LINUX是一個多任務的系統,即使在單核CPU上也存在資源競爭的情況(思考一下,LINUX里面那些地方可能導致資源競爭),所以在對驅動的編寫的時候,對競爭資源需要采用一定的資源保護機制,比如原子變量,自旋鎖等
4.單片機中斷處理時,一般直接在產生中斷的進入到中斷處理函數里面在關中斷的情況下處理完中斷就可以。而LINUX里面把中斷分為2部分,上半部分和下班部分,在上半部分中,是在關中斷情況下,只做最基本和最核心的部分,然后在下半部分在開中斷情況下,通過LINUX提供的各種機制來處理(思考: LINUX中斷的底半部分有哪些模式)

14.請從網卡、USB HOST、LCD驅動器、NAND FLASH、WIFI 、音頻芯片中選擇一個或者2個(可以以具體的芯片為例),對下面的問題做答:
1.如果是外部擴展芯片,請說出你用的芯片的型號
請注意相應nand flash芯片型號,LCD屏廠家,型號;WIFI型號,音頻芯片型號 [每空5分]

15.畫出上題中你選定相應硬件模塊與CPU的主要引腳連線[5分]

參考答案:
請在紙上自己把自己項目中做的設備的CPU和引腳連線多畫幾次。

這個需要根據具體模塊,畫出主要引腳包括數據線,控制線(比如片選,讀寫控制,以及控制重要時序的引腳),地址線(如有地址的話)

16. 編寫上題中你選定相應硬件模塊相應LINUX驅動的流程?[6分]

參考答案:
這個對着自己相應模塊的驅動的初始化部分,總結一下主要流程,
現在平台設備的驅動一般包括(注意,以下部分要結合你自己的驅動去說):
1.獲取平台設備資源的外設IO地址,中斷,DMA資源等信息
2.映射外設控制寄存器的外設IO地址到內核的虛擬地址空間
3.使能外設時鍾,注冊外設中斷的處理函數(如果有中斷)
4.掃描和初始化硬件
5.最后向LINUX內核注冊相應設備
6.然后,根據對應設備是字符設備,塊設備,網絡設備還是各種子系統的不同
,再提供相應的數據結構里面的關鍵函數(比如字符設備里面file_operations,塊設備里面的gendisk,網絡設備里面的net_device)的實現

============ 本試卷共計16題,此處為結束標志。考試酷examcoo ============


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM