linux驅動面試題目彙總

http://blog.163.com/dasifly@126/blog/static/5256264320129168146332/

1、linux驅動分類

2、信號量與自旋鎖

3、platform總線設備及總線設備如何編寫

4、kmalloc和vmalloc的區別

5、module_init的級別

6、添加驅動

7、IIC原理,總線框架,設備編寫方法,i2c_msg

8、kernel panic

9、USB總線,USB傳輸種類,urb等

10、android boot 流程

11、android init解析init.rc

12、同步和互斥


答案:

1、http://baike.baidu.com/view/5363967.htm

Linux設備驅動的分類

  (1)字符設備。
  (2) 塊設備。
  (3) 網絡設備。
  字符設備指那些必須以串行順序依次進行訪問的設備,如觸摸屏、磁帶驅動器、鼠標等。塊設備可以用任意順序進行訪問,以塊爲單位進行操作,如硬盤、軟驅等。字符設備不經過系統的快速緩衝,而塊設備經過系統的快速緩衝。但是,字符設備和塊設備並沒有明顯的界限,如對於Flash設備,符合塊設備的特點,但是我們仍然可以把它作爲一個字符設備來訪問。網絡設備在Linux裏做專門的處理。Linux的網絡系統主要是基於BSD unix的socket 機制。在系統和驅動程序之間定義有專門的數據結構(sk_buff)進行數據的傳遞。系 統裏支持對發送數據和接收數據的緩存,提供流量控制機制,提供對多協議的支持。



2、http://www.cnblogs.com/linxinshuo/archive/2009/12/08/1619771.html

自旋鎖

  自旋鎖是專爲防止多處理器併發而引入的一種鎖,它應用於中斷處理等部分。對於單處理器來說,防止中斷處理中的併發可簡單採用關閉中斷的方式,不需要自旋鎖。

  自旋鎖最多隻能被一個內核任務持有,如果一個內核任務試圖請求一個已被爭用(已經被持有)的自旋鎖,那麼這個任務就會一直進行忙循環——旋轉——等待鎖重新可用。要是鎖未被爭用,請求它的內核任務便能立刻得到它並且繼續進行。自旋鎖可以在任何時刻防止多於一個的內核任務同時進入臨界區,因此這種鎖可有效地避免多處理器上併發運行的內核任務競爭共享資源。

  事實上,自旋鎖的初衷就是:在短期間內進行輕量級的鎖定。一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用的期間進行自旋(特別浪費處理器時間),所以自旋鎖不應該被持有時間過長。如果需要長時間鎖定的話, 最好使用信號量。但是自旋鎖節省了上下文切換的開銷。

自旋鎖的基本形式如下:

  spin_lock(&mr_lock);

  //臨界區

  spin_unlock(&mr_lock);

  因爲自旋鎖在同一時刻只能被最多一個內核任務持有,所以一個時刻只有一個線程允許存在於臨界區中。這點很好地滿足了對稱多處理機器需要的鎖定服務。在單處理器上,自旋鎖僅僅當作一個設置內核搶佔的開關。如果內核搶佔也不存在,那麼自旋鎖會在編譯時被完全剔除出內核。

  簡單的說,自旋鎖在內核中主要用來防止多處理器中併發訪問臨界區,防止內核搶佔造成的競爭。另外自旋鎖不允許任務睡眠(持有自旋鎖的任務睡眠會造成自死鎖——因爲睡眠有可能造成持有鎖的內核任務被重新調度,而再次申請自己已持有的鎖),它能夠在中斷上下文中使用。

死鎖:假設有一個或多個內核任務和一個或多個資源,每個內核都在等待其中的一個資源,但所有的資源都已經被佔用了。這便會發生所有內核任務都在相互等待,但它們永遠不會釋放已經佔有的資源,於是任何內核任務都無法獲得所需要的資源,無法繼續運行,這便意味着死鎖發生了。自死瑣是說自己佔有了某個資源,然後自己又申請自己已佔有的資源,顯然不可能再獲得該資源,因此就自縛手腳了。遞歸使用一個自旋鎖就會出現這種情況。

 

信號量

信號量是一種睡眠鎖。如果有一個任務試圖獲得一個已被持有的信號量時,信號量會將其推入等待隊列,然後讓其睡眠。這時處理器獲得自由去執行其它代碼。當持有信號量的進程將信號量釋放後,在等待隊列中的一個任務將被喚醒,從而便可以獲得這個信號量。

  信號量的睡眠特性,使得信號量適用於鎖會被長時間持有的情況;只能在進程上下文中使用,因爲中斷上下文中是不能被調度的;另外當代碼持有信號量時,不可以再持有自旋鎖。

信號量基本使用形式爲:

  static DECLARE_MUTEX(mr_sem);//聲明互斥信號量

  if(down_interruptible(&mr_sem))

           //可被中斷的睡眠,當信號來到,睡眠的任務被喚醒

           //臨界區

       up(&mr_sem);  

 

信號量和自旋鎖區別

  從嚴格意義上講,信號量和自旋鎖屬於不同層次的互斥手段,前者的實現有賴於後者。

注意以下原則:

       如果代碼需要睡眠——這往往是發生在和用戶空間同步時——使用信號量是唯一的選擇。由於不受睡眠的限制,使用信號量通常來說更加簡單一些。如果需要在自旋鎖和信號量中作選擇,應該取決於鎖被持有的時間長短。理想情況是所有的鎖都應該儘可能短的被持有,但是如果鎖的持有時間較長的話,使用信號量是更好的選擇。另外,信號量不同於自旋鎖,它不會關閉內核搶佔,所以持有信號量的代碼可以被搶佔。這意味者信號量不會對影響調度反應時間帶來負面影響。

 

自旋鎖對信號量

需求              建議的加鎖方法

低開銷加鎖           優先使用自旋鎖

短期鎖定            優先使用自旋鎖

長期加鎖            優先使用信號量

中斷上下文中加鎖        使用自旋鎖

持有鎖是需要睡眠、調度     使用信號量 


3、http://www.cnblogs.com/noaming1900/archive/2010/10/26/1861177.html

     http://blog.chinaunix.net/space.php?uid=11909535&do=blog&id=2801676

     http://slhieanng.blog.163.com/blog/static/1932833562011731982291/


4、http://blog.163.com/liuqiang_mail@126/blog/static/109968875201241961116110/


kmalloc()和vmalloc()介紹
kmalloc()
用於申請較小的、連續的物理內存
1. 以字節爲單位進行分配,在<linux/slab.h>中
2. void *kmalloc(size_t size, int flags) 分配的內存物理地址上連續,虛擬地址上自然連續
3. gfp_mask標誌
:什麼時候使用哪種標誌?如下:
———————————————————————————————-
情形 相應標誌
———————————————————————————————-
進程上下文,可以睡眠 GFP_KERNEL
進程上下文,不可以睡眠 GFP_ATOMIC
中斷處理程序 GFP_ATOMIC
軟中斷 GFP_ATOMIC
Tasklet GFP_ATOMIC
用於DMA的內存,可以睡眠 GFP_DMA | GFP_KERNEL
用於DMA的內存,不可以睡眠 GFP_DMA | GFP_ATOMIC
———————————————————————————————-
4. void kfree(const void *ptr)
釋放由kmalloc()分配出來的內存塊


vmalloc()
用於申請較大的內存空間,虛擬內存是連續的
1. 以字節爲單位進行分配,在<linux/vmalloc.h>中
2. void *vmalloc(unsigned long size) 分配的內存虛擬地址上連續,物理地址不連續
3. 一般情況下,只有硬件設備才需要物理地址連續的內存,因爲硬件設備往往存在於MMU之外,根本不瞭解虛擬地址;但爲了性能上的考慮,內核中一般使用 kmalloc(),而只有在需要獲得大塊內存時才使用vmalloc(),例如當模塊被動態加載到內核當中時,就把模塊裝載到由vmalloc()分配 的內存上。
4.void vfree(void *addr),這個函數可以睡眠,因此不能從中斷上下文調用。


malloc(), vmalloc()和kmalloc()區別
[*]kmalloc和vmalloc是分配的是內核的內存,malloc分配的是用戶的內存
[*]kmalloc保證分配的內存在物理上是連續的,vmalloc保證的是在虛擬地址空間上的連續,malloc不保證任何東西(這點是自己猜測的,不一定正確)
[*]kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大
[*]內存只有在要被DMA訪問的時候才需要物理上連續
[*]vmalloc比kmalloc要慢

    

5、http://blog.163.com/xinbuqianjin@126/blog/static/167563447201010221231507/

#define module_init(x) __initcall(x);
#define __initcall(fn)    device_initcall(fn)

#define device_initcall(fn) __define_initcall("6",fn,6)  

可知module_init()的級別爲6

在vmlinux.lds中的
.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
   __initcall_start = .;
   *(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
   __initcall_end = .;
   }

可以看出initcall總共分爲0~7八個級別,表示系統在啓動過程中調用do_initcalls()時,會根據它們的級別順序調用。可知模塊中的module_init中的初始化函數何時被調用了:在系統啓動過程中start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()。


6、

就靜態加載和動態加載:
靜態加載是系統啓動的時候由內核自動加載的,這個要事先將驅動編譯進內核才行;
動態加載,也就是模塊加載方式,這種方式下驅動以模塊的形式存放在文件系統中,需要時動態載入內核,這種主要用在調試的時候,比較方便靈活。insmod module.ko


7、

http://liu1227787871.blog.163.com/blog/static/2053631972012521191287/                        IIC 總線基礎知識

http://blog.163.com/liuqiang_mail@126/blog/static/109968875201243094211492/   IIC總線驅動程序架構分析

http://liu1227787871.blog.163.com/blog/static/20536319720125333531134/           IIC驅動程序分析

http://liu1227787871.blog.163.com/blog/static/2053631972012539436224/

http://liu1227787871.blog.163.com/blog/static/2053631972012531048573/

http://liu1227787871.blog.163.com/blog/static/2053631972012531620760/


8、

http://blog.51osos.com/linux/linux-kernel-panic/

有兩種主要類型kernel panic:

1.hard panic(也就是Aieee信息輸出)
2.soft panic (也就是Oops信息輸出)



9、

USB總線:

USB總線屬於一種輪詢式總線,主機控制端口初始化所有的數據傳輸。每一總線動作最多傳送三個數據包,包括令牌(Token)、數據(Data)、聯絡(HandShake)。按照傳輸前制定好的原則,在每次傳送開始時,主機送一個描述傳輸動作的種類、方向、USB設備地址和終端號的USB數據包,這個數據包通常被稱爲令牌包(TokenPacket)。USB設備從解碼後的數據包的適當位置取出屬於自己的數據。數據傳輸方向不是從主機到設備就是從設備到主機。在傳輸開始時,由標誌包來標誌數據的傳輸方向,然後發送端開始發送包含信息的數據包或表明沒有數據傳送。接收端也要相應發送一個握手的數據包表明是否傳送成功。發送端和接收端之間的USB數據傳輸,在主機和設備的端口之間,可視爲一個通道。USB中有一個特殊的通道一缺省控制通道,它屬於消息通道,設備一啓動即存在,從而爲設備的設置、狀態查詢和輸入控制信息提供一個入口。


USB總線的四種傳輸類型:

1、中斷傳輸:由OUT事務和IN事務構成,用於鍵盤、鼠標等HID設備的數據傳輸中 2、批量傳輸:由OUT事務和IN事務構成,用於大容量數據傳輸,沒有固定的傳輸速率,也不佔用帶寬,當總線忙時,USB會優先進行其他類型的數據傳輸,而暫時停止批量轉輸。 3、同步傳輸:由OUT事務和IN事務構成,有兩個特別地方,第一,在同步傳輸的IN和OUT事務中是沒有返回包階段的;第二,在數據包階段任何的數據包都爲DATA0 4、控制傳輸:最重要的也是最複雜的傳輸,控制傳輸由三個階段構成(初始配置階段、可選數據階段、狀態信息步驟),每一個階段能夠看成一個的傳輸,也就是說控制傳輸其實是由三個傳輸構成的,用來於USB設備初次加接到主機之後,主機通過控制傳輸來交換信息,設備地址和讀取設備的描述符,使得主機識別設備,並安裝相應的驅動程式,這是每一個USB研發者都要關心的問題。
URB:
USB請求塊(USB request block,urb)是USB設備驅動中用來描述與USB設備通信所用的基本載體和核心數據結構,非常類似於網絡設備驅動中的sk_buff結構體,是USB主機與設備通信的“電波”。
http://book.51cto.com/art/200803/66930.htm



10、  

http://www.cnblogs.com/idiottiger/archive/2012/05/22/2513001.html   android boot process from power on

http://www.cnblogs.com/idiottiger/archive/2012/05/23/2513494.html   android boot 代碼流程 1

http://www.cnblogs.com/idiottiger/archive/2012/05/25/2516295.html  android boot 代碼流程 2


11、

http://ytydyd.blog.sohu.com/136255592.html

Android初始化語言(Android Init Language

Android初始化腳本語言包含四種類型的語句:

  • 動作(Actions)
  • 指令(Commands)
  • 服務(Services)
  • 選項(Options)

該語言的語法包括下列約定:

  • 所有類型的語句都是基於行(line-oriented)的, 一個語句包含若干個tokens,token之間通過空格字符分隔. 如果一個token中需要包含空格字符,則需要通過C語言風格的反斜線('\')來轉義,或者使用雙引號把整個token引起來。反斜線還可以出現在一行的末尾,表示下一行的內容仍然屬於當前語句。
  • 以'#'開始的行是註釋行。
  • 動作(Actions)和服務(Services)語句隱含表示一個新的段落(section)的開始。 所有的指令(commands)和選項(options)歸屬於上方最近的一個段落。在第一個段落之前的指令(commands)和選項(options)是無效的。
  • 動作(Actions)和服務(Services)擁有唯一性的名字。如果出現重名,那麼後出現的定義將被作爲錯誤忽略掉。
動作(Actions)

動作(Actions)是一個有名字的指令(commands)序列。每個動作(Actions)都定義一個觸發條件(trigger),用於指示什麼時候執行這個動作。當與動作的觸發器匹配的事件發生時,該動作將被添加到一個即將被執行的隊列的隊尾(除非它已經在隊列中)。

隊列中的每一個動作被依次取出執行,動作中的每一個指令也將依次執行。初始化程序(Init)在執行一個動作的各項指令的期間,還需要處理其它操作(比如,設備創建/銷燬,屬性設置,進程重啓)。

一個動作定義的形式如下:

on <trigger>
  <command>
  <command>
  <command>

服務(Services)

服務是初始化程序需要啓動的一些程序,初始化程序還有可能會在這些程序退出之後重啓它們。Services take 一個服務定義的形式如下:
  service <name> <pathname> [ <argument> ]*
  <option>
  <option>
  ...

選項(Options)

選項將影響控制初始化程序運行服務的時機和方法。可能的選項如下表。

選項 說明
disabled This service will not automatically start with its class. It must be explicitly started by name.
socket <name> <type>  <perm> [ <user> [ <group> ] ] Create a unix domain socket named /dev/socket/<name> and pass its fd to the launched process. Valid <type> values include dgram and streamuser and groupdefault to 0.
user <username> Change to username before exec'ing this service. Currently defaults to root.
group <groupname> [ <groupname> ]* Change to groupname before exec'ing this service.  Additional  groupnames beyond the first, which is required, are used to set additional groups of the process (withsetgroups()). Currently defaults to root.
capability [ <capability> ]+ Set linux capability before exec'ing this service
oneshot Do not restart the service when it exits.
class <name> Specify a class name for the service.  All services in a named class must start and stop together. A service is considered of class "default" if one is not specified via the class option.


觸發器(Triggers)

觸發器是一個字符串,用於匹配特定的事件,這些事件將觸發觸發器所屬動作(Actions)的執行。

觸發器 說明
boot This is the first trigger that occurs when init starts (after /init.conf is loaded).
<name>=<value> Triggers of this form occur when the property <name> is set to the specific value<value>.
device-added-<path>
device-removed-<path>
Triggers of these forms occur when a device node is added or removed.
service-exited-<name> Triggers of this form occur when the specified service exits.


指令(Commands)

Command Description
exec <path> [ <argument> ]* Fork and execute a program (<path>). This will block until the program completes execution. Try to avoid exec. Unlike the builtin commands, it runs the risk of getting init "stuck".
export <name> <value> Set the environment variable <name> equal to <value> in the global environment (which will be inherited by all processes started after this command is executed).
ifup <interface> Bring the network interface <interface> online.
import <filename> Parse an init config file, extending the current configuration.
hostname <name> Set the host name.
class_start <serviceclass> Start all services of the specified class if they are not already running.
class_stop <serviceclass> Stop all services of the specified class if they are currently running.
domainname <name> Set the domain name.
insmod <path> Install the module at <path>.
mkdir <path> Make a directory at <path>.
mount <type> <device> <dir> [ <mountoption> ]* Attempt to mount the named device at the directory <dir> <device>. This may be of the form mtd@name to specify a mtd block device by name.
setkey - currenlty undefined -
setprop <name> <value> Set system property <name> to <value>.
setrlimit <resource> <cur> <max> Set the rlimit for a resource.
start <service> Start a service running if it is not already running.
stop <service> Stop a service from running if it is currently running.
symlink <target> <path> Create a symbolic link at <path> with the value <target>.
write <path> <string> [ <string> ]* Open the file at <path> and write one or more strings to it with write(2).


屬性(Properties)

初始化程序(Init)可以根據需要修改一些系統的屬性。 

屬性 說明
init.action Equal to the name of the action currently being executed or "" if none.
init.command Equal to the command being executed or "" if none.
init.svc.<name> State of a named service ("stopped", "running", or "restarting").


init.rc文件示例

on boot
  export PATH /sbin:/system/sbin:/system/bin
  export LD_LIBRARY_PATH /system/lib

  mkdir /dev
  mkdir /proc
  mkdir /sys


  mount tmpfs tmpfs /dev
  mkdir /dev/pts
  mkdir /dev/socket
  mount devpts devpts /dev/pts
  mount proc proc /proc
  mount sysfs sysfs /sys


  write /proc/cpu/alignment 4


  ifup lo


  hostname localhost
  domainname localhost


  mount yaffs2 mtd@system /system
  mount yaffs2 mtd@userdata /data


  import /system/etc/init.conf


  class_start default


service adbd /sbin/adbd
  user adb
  group adb


service usbd /system/bin/usbd -r
  user usbd
  group usbd
  socket usbd 666


service zygote /system/bin/app_process -Xzygote /system/bin --zygote
  socket zygote 666


service runtime /system/bin/runtime
  user system
  group system


on device-added-/dev/compass
  start akmd


on device-removed-/dev/compass
  stop akmd


service akmd /sbin/akmd
  disabled
  user akmd
  group akmd


12、http://www.cnblogs.com/linxinshuo/archive/2009/12/09/1620413.html

同步和互斥

  相交進程之間的關係主要有兩種,同步與互斥。所謂互斥,是指散步在不同進程之間的若干程序片斷,當某個進程運行其中一個程序片段時,其它進程就不能運行它們之中的任一程序片段,只能等到該進程運行完這個程序片段後纔可以運行。所謂同步,是指散步在不同進程之間的若干程序片斷,它們的運行必須嚴格按照規定的某種先後次序來運行,這種先後次序依賴於要完成的特定的任務。

 

  顯然,同步是一種更爲複雜的互斥,而互斥是一種特殊的同步。 

  也就是說互斥是兩個線程之間不可以同時運行,他們會相互排斥,必須等待一個線程運行完畢,另一個才能運行,而同步也是不能同時運行,但他是必須要安照某種次序來運行相應的線程(也是一種互斥)!

  總結:

  互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。

  同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章