驅動工程師

1.內核和用戶空間的通信?

2.、寫個字符設備需要什麼?

一句話,系統調用是內核給用戶空間提供的一個可以訪問內核資源的一個接口。

linux內核內存的分佈:

Linux簡化了分段機制,使得虛擬地址與線性地址總是一致,因此,Linux的虛擬地址空間也爲0~4G.Linux內核將這4G字節的空間分爲兩部分。將最高的1G字節(從虛擬地址0xC0000000到0xFFFFFFFF),供內核使用,稱爲"內核空間".而將較低的3G字節(從虛擬地址
0x00000000到0xBFFFFFFF),供各個進程使用,稱爲"用戶空間)。因爲每個進程可以通過系統調用進入內核,因此,Linux內核由系統內的所有進程共享。於是,從具體進程的角度來看,每個進程可以擁有4G字節的虛擬空間。

linux內核的保護機制

Linux使用兩級保護機制:0級供內核使用,3級供用戶程序使用。從圖中可以看出(這裏無法表示圖),每個進程有各自的私有用戶空間(0~3G),這個空間對系統中的其他進程是不可見的。最高的1GB字節虛擬內核空間則爲所有進程以及內核所共享。

內核空間中存放的是內核代碼和數據
進程的用戶空間中存放的是用戶程序的代碼和數據
不管是內核空間還是用戶空間,它們都處於虛擬空間中。
 雖然內核空間佔據了每個虛擬空間中的最高1GB字節,但映射到物理內存卻總是從最低地址(0x00000000)開始。對內核空間來說,其地址映射是很簡單的線性映射,0xC0000000就是物理地址與線性地址之間的位移量,在Linux代碼中就叫做PAGE_OFFSET.

內核空間和用戶空間之間如何進行通訊?

內核空間和用戶空間一般通過系統調用函數進行通信。

如何判斷一個驅動是用戶模式驅動還是內核模式驅動? 判斷的標準是什麼?

用戶空間模式的驅動一般通過系統調用來完成對硬件的訪問,如通過系統調用將驅動的io空間映射到用戶空間等。因此,主要的判斷依據就是系統調用。

內核空間和用戶空間的不同?

內核空間和用戶空間上不同太多了,說不完,比如用戶態的鏈表和內核鏈表不一樣;用戶態用printf,內核態用printk;用戶態每個應用程序空間是虛擬的,相對獨立的,內核態中卻不是獨立的,所以編程要非常小心。等等

還有用戶態和內核態程序通訊的方法很多,不單單是系統調用,實際上系統調用是個不好的選擇,因爲需要系統調用號,這個需要統一分配。

還有用戶態和內核態程序通訊的方法很多,不單單是系統調用,實際上系統調用是個不好的選擇,因爲需要系統調用號,這個需要統一分配。
  可以通過ioctl、sysfs、proc等來完成。

去/sys看一看,

localhost:/sys#ls /sys/

block/ bus/ class/ devices/ firmware/ kernel/ module/ power/

Block目錄:包含所有的塊設備

Devices目錄:包含系統所有的設備,並根據設備掛接的總線類型組織成層次結構

Bus目錄:包含系統中所有的總線類型

Drivers目錄:包括內核中所有已註冊的設備驅動程序

Class目錄:系統中的設備類型(如網卡設備,聲卡設備等)

sys下面的目錄和文件反映了整臺機器的系統狀況。比如bus,如查看USB鼠標信息等

去/proc看一看,

proc被稱爲虛擬文件系統,它是一個控制中心,可以通過更改其中某些文件改變內核運行狀態,
它也是內核提空給我們的查詢中心,用戶可以通過它查看系統硬件及當前運行的進程信息。
Linux中許多工具的數據來源正是proc目錄中的內容,比如lsmod的命令是cat /proc/modules的別名。

/proc目錄下常用文件介紹:

/proc/loadavg 前三列分別保存最近1分鐘,5分鐘,及15分鐘的平均負載。
/proc/meminfo 當前內存使用信息
/proc/diskstats 磁盤I/O統計信息列表
/proc/net/dev 網絡流入流出統計信息
/proc/filesystems 支持的文件系統
/proc/cpuinfo CPU的詳細信息
/proc/cmdline 啓動時傳遞至內核的啓動參數,通常由grub進行傳遞
/proc/mounts 系統當前掛在的文件系統
/proc/uptime 系統運行時間
/poc/version 當前運行的內核版本號等信息

爲什麼要分內核空間和用戶空間,其區別是什麼?

在我的理解裏,其實這樣分是一種保護機制,提供保護的目的。是要避免系統中的一個任務訪問屬於另外的或屬於其他的存儲區域,這樣的保護機制它能抵禦惡意用戶的窺探,也能防止質量低劣的用戶程序的侵害,從而使系統運行得更穩定可靠。

內核程序不能使用標準庫函數(strlen strcmp等fopen ),只能使用系統調用函數 如open
區別
內核空間中存放的是內核代碼和數據**
進程的用戶空間中存放的是用戶程序的代碼和數據

信息交互方法

信息交互按信息傳輸發起方可以分爲
用戶向內核傳送/提取數據

內核向用戶空間提交請求兩大類,先來說說:

字符設備和塊設備的區別,請分別列舉一些實際的設備說出它們是屬於哪一類設備

字符設備:/dev下的設備驅動文件,字符設備是個能夠像字節流(類似文件)一樣被訪問的設備,由字符設備驅動程序來實現這種特性。字符設備驅動程序通常至少實現open,close,read和write系統調用。字符終端、串口、鼠標、鍵盤、攝像頭、聲卡和顯卡等就是典型的字符設備。

塊設備:和字符設備類似,塊設備也是通過/dev目錄下的文件系統節點來訪問。塊設備上能夠容納文件系統,如:u盤,SD卡,磁盤等。

字符設備和塊設備的區別僅僅在於內核內部管理數據的方式,也就是內核及驅動程序之間的軟件接口,而這些不同對用戶來講是透明的。在內核中,和字符驅動程序相比,塊驅動程序具有完全不同的接口。

LINUX系統可以分爲四個部分

1、引導加載程序(BootLoader->uboot),
(1)初始化 RAM
因爲 Linux 內核一般都會在 RAM 中運行,所以在調用 Linux 內核之前 bootloader 必須設置和初始化 RAM,爲調用 Linux內核做好準備。
(2)初始化串口
(3)檢測處理器類型
Bootloader在調用 Linux內核前必須檢測系統的處理器類型,並將其保存到某個常量中提供給 Linux 內核。Linux 內核在啓動過程中會根據該處理器類型調用相應的初始化程序
(5)調用 Linux內核映像
Bootloader完成的最後一項工作便是調用 Linux內核。如果 Linux 內核存放在 Flash 中,並且可直接在上面運行(這裏的 Flash 指 Nor Flash),那麼可直接跳轉到內核中去執行。但由於在 Flash 中執行代碼會有種種限制,而且速度也遠不及 RAM 快,所以一般的嵌入式系統都是將 Linux內核拷貝到 RAM 中,然後跳轉到 RAM 中去執行
start_kernel-》跳到內核初始化的函數

2、linux內核,
3、文件系統,
4、應用程序。

Linux內核啓動過程概述**

(首先會執行彙編代碼,其目的是用來做一些內核啓動前的檢測(內核是否支持當前CPU),環境的建立(MMU))。
 
 1、首先看這段彙編代碼,它主要是用來做一些內核啓動前的檢測。
 
__lookup_processor_type 檢測內核是否支持當前CPU、__lookup_machine_type檢測是否支持當前單板,並且__create_page_tables創建頁表,__enable_mmu使能MMU。初始化中斷,IO的映射表,定時器,內存環境的初始化和建立。
後就跳到C語言部分。

2、接下來進入start_kernel啓動內核的C函數。上面是start_kernel的部分代碼。這部分代碼的主要作用是處理uboot傳遞來的參數,設置與體系結構相關的環境,初始化控制檯,最後執行應用程序,實現功能。這裏我把start_kernel函數的幾個主要功能的子函數逐層寫出,幫助大家理解start_kernel的功能結構。

linux設備驅動框架

一.Linux設備分類
字符設備: 以字節爲單位讀寫的設備。
例如:
字符設備驅動程序通常至少要實現open、close、read和write的系統調 用。字符終端(/dev/console)和串口(/dev/ttyS0以及類似設備)就是兩個字符設備,

塊設備 : 以塊爲單位(效率最高)讀寫的設備。
因此,塊設備和字符設備的 區別僅僅在於內核內部管理數據的方式

網絡設備 : 用於網絡通訊設備。
任何網絡事物都需要經過一個網絡接口形成。
如網絡接口的方法仍然是給它們分配一個唯一的名字(比如eth0)

二. 上層應用程序是如何訪問到底層驅動程序的呢?

在linux的世界裏一切皆文件,
在這裏我們拿字符設備爲例,來看一下應用程序如何和底層驅動程序關聯起來。
??????

1:應用層通過系統調用函數去訪問linux內核,首先會進入到VFS虛擬文件系統,因爲一切皆與文件,其中會有一個變量叫文件描述符,通過這個文件描述符就可以直接調用對應的文件驅動 從而跟內核通信,與硬件通信。
在這裏插入圖片描述

linux內核調度器 調度原理(2.6.24筆記整理)

Linux內核中,運行一個進程,會因爲各種因素,進程會處於何種狀態。

由調度器調度

有如下幾種狀態:

1.用戶運行態:用戶層面,由用戶執行程序,執行與等待結果過程。

2.運行態:CPU處理進程任務並返回運行結果

3.殭屍態:進程運行完,但是沒有進行資源回收,編程殭屍進程

4.可中斷睡眠:可中斷的睡眠狀態的進程會睡眠直到某個條件變爲真,如產生一個硬件中斷、釋放進程正在等待的系統資源或是傳遞一個信號都可以是喚醒進程的條件。

5.不可中斷睡眠:不可中斷睡眠狀態與可中斷睡眠狀態類似,但是它有一個例外,那就是把信號傳遞到這種睡眠狀態的進程不能改變它的狀態,也就是說它不響應信號的喚醒。

6.就緒態:多個進程在等待CPU的處理,隊列形式等待(調度優先級高的先執行)

7.暫停態:進程在CPU中,收到暫停信號,變成暫停態

(每個CPU都會有一個RQ運行隊列,將就緒態的進程組織在一起。其實是一個雙向鏈表,將相同優先等級的實時進程被組織在一個雙向鏈表中。)

在這裏插入圖片描述

  1. 查看驅動模塊中打印信息的命令:dmesg
    2)查看字符設備信息可以用lsmod
  2. 顯示當前使用的中斷號cat /proc/interrupt

copy_to_user()和copy_from_user()主要用於實現什麼功能?一般用於file_operations結構的哪些函數裏面?

由於內核空間和用戶空間是不能互相訪問的,如果需要訪問就必須藉助內核函數進行數據讀寫。copy_to_user():完成內核空間到用戶空間的複製,copy_from_user():是完成用戶空間到內核空間的複製。一般用於file_operations結構裏的read,write,ioctl等內存數據交換作用的函數。當然,如果ioctl沒有用到內存數據複製,那麼就不會用到這兩個函數。

請簡述主設備號和次設備號的用途。

在Linux內核看來,主設備號標識設備對應的驅動程序,告訴Linux內核使用哪一個驅動程序爲該設備(也就是/dev下的設備文件)服務;
而次設備號則用來標識具體且唯一的某個設備。

設備驅動程序中如何註冊一個字符設備?分別解釋一下它的幾個參數的含義。

註冊一個字符設備驅動有兩種方法:

1) void cdev_init(struct cdev *cdev, struct file_operations *fops)

該註冊函數可以將cdev結構嵌入到自己的設備特定的結構中。cdev是一個指向結構體cdev的指針,而fops是指向一個類似於f file_operations結構(可以是file_operations結構,但不限於該結構)的指針.

2) int register_chrdev(unsigned int major, const char *namem , struct file)operations *fopen);
該註冊函數是早期的註冊函數,major是設備的主設備號,name是驅動程序的名稱,而fops是默認的file_operations結構(這 是只限於file_operations結構)。對於register_chrdev的調用將爲給定的主設備號註冊0-255作爲次設備號,併爲每個 設備建 立一個對應的默認cdev結構。

linux中RCU原理?

從RCU(read-copy-update)的名稱上看,我們就能對他的實現機制有一個大概的瞭解,在修改數據的時候,首先需要讀取數據,然後生成一個副本,對副本進行修改,修改完成之後再將老數據update成新的數據,此所謂RCU。

  1. 對於讀操作,可以直接對共享資源進行訪問,但是前提是需要CPU支持訪存操作的原子化,現代CPU對這一點都做了保證。但是RCU的讀操作上下文是不可搶佔的(這一點在下面解釋),所以讀訪問共享資源時可以採用read_rcu_lock(),該函數的工作是停止搶佔。

2 . 對於寫操作,其需要將原來的老數據作一次備份(copy),然後對備份數據進行修改,修改完畢之後再用新數據更新老數據,更新老數據時採用了rcu_assign_pointer()宏,在該函數中首先屏障一下memory,然後修改老數據。

  1. 在RCU機制中存在一個垃圾回收的daemon,當共享資源被update之後,可以採用該daemon實現老數據資源的回收。

LINUX內存管理

在linux操作系統中,內存管理有2個概念,一個是虛擬內存與物理內存。

對應於虛擬內存,它實際上不佔用實際物理內存

Linux內核在用戶申請內存的時候,只是給它分配了一個線性區(也就是虛存),並沒有分配實際物理內存;只有當用戶使用這塊內存的時候,內核纔會分配具體的物理頁面給用戶,這時候才佔用寶貴的物理內存。內核釋放物理頁面是通過釋放線性區,找到其所對應的物理頁面,將其全部釋放的過程。

char *p=malloc(2048) //這裏只是分配了虛擬內存2048,並不佔用實際內存。
strcpy(p,”123”) //分配了物理頁面,雖然只是使用了3個字節,但內存還是爲它分配了2048字節的物理內存。
free§ //通過虛擬地址,找到其所對應的物理頁面,釋放物理頁面,釋放線性區。

進程內存空間

進程如何使用內存?

虛擬內存分爲以下幾個部分
BSS 數據段 代碼段 堆 棧
堆棧:
他們一個向下“長”(i386體系結構中棧向下、堆向上),一個向上“長”,相對而生。但你不必擔心他們會碰頭,因爲他們之間間隔很大(到底大到多少,你可以從下面的例子程序計算一下),絕少有機會能碰到一起。
在這裏插入圖片描述

因爲內存中的段機制可將虛擬地址轉換爲線性地址,
通過頁機制可將線性地址轉換爲物理地址,這之後虛擬地址才實實在在地映射到了系統的物理內存上

在這裏插入圖片描述
從用戶向內核看,所使用的內存表象形式會依次經歷“邏輯地址”——“線性地址”——“物理地址”

邏輯地址經段機制轉化成線性地址;線性地址又經過頁機制轉化爲物理地址。(但是我們要知道Linux系統雖然保留了段機制,但是將所有程序的段地址都定死爲0-4G,所以雖然邏輯地址和線性地址是兩種不同的地址空間,但在Linux中邏輯地址就等於線性地址,它們的值是一樣的)

而內核空間是由內核負責映射,它並不會跟着進程改變,是固定的。內核空間地址有自己對應的頁表

第一、4G的進程地址空間被人爲的分爲兩個部分——用戶空間與內核空間。用戶空間從0到3G(0xC0000000),內核空間佔據3G到4G。用戶進程通常情況下只能訪問用戶空間的虛擬地址,不能訪問內核空間虛擬地址。只有用戶進程進行系統調用(代表用戶進程在內核態執行)等時刻可以訪問到內核空間。

第二、用戶空間對應進程,所以每當進程切換,用戶空間就會跟着變化;而內核空間是由內核負責映射,它並不會跟着進程改變,是固定的。內核空間地址有自己對應的頁表(init_mm.pgd),用戶進程各自有不同的頁表。

insmod 一個驅動模塊,會執行模塊中的哪個函數?rmmod呢?這兩個函數在設計上要注意哪些?遇到過卸載驅動出現異常沒?是什麼問題引起的?

 答: insmod調用init函數,rmmod調用exit函數。這兩個函數在設計時要注意什麼?卸載模塊時曾出現卸載失敗的情形,原因是存在進程正在使用模塊,檢查代碼後發現產生了死鎖的問題。

  要注意在init函數中申請的資源在exit函數中要釋放,包括存儲,ioremap,定時器,工作隊列等等。也就是一個模塊註冊進內核,退出內核時要清理所帶來的影響,帶走一切不留下一點痕跡。

platform或設備驅動模型的組成三個成員

platform = platform bus + platform device + platform driver
設備驅動模型三個重要成員是 總線、設備、驅動;

platfoem總線的匹配規則是:要匹配的設備和驅動都要註冊,設備可以在設備樹裏註冊,也可以通過代碼註冊設備,匹配成功會去調用驅動程序裏的probe函數(probe函數在這個platform_driver結構體中註冊)。

在驅動調試過程中遇到過oops沒?你是怎麼處理的?

Oops 這個單詞含義爲“驚訝”
,當內核出錯時(比如訪問非法地址)打印出來的信息被
稱爲 Oops 信息。
分析 Oops 信息
(1)明確出錯原因。
由出錯信息“Unable to handle kernel NULL pointer dereference at virtual address 00000000”
可知內核是因爲非法地址訪問出錯,使用了空指針。
(2)根據棧回溯信息或報錯信息找出函數調用關係。
內核崩潰時,可以從 pc 寄存器得知崩潰發生時的函數、出錯指令。但是很多情況下,錯
誤有可能是它的調用者引入的,所以找出函數的調用關係也很重要。
實在不行就可以通過彙編
(3)結合內核源代碼和反彙編代碼定位問題。

Ioctl與unlocked_ioctl的區別

**而在驅動程序中這個指針函數變了之後最大的影響是參數中少了inode **

驅動中操作物理絕對地址爲什麼要先ioremap?

因爲內核沒有辦法直接訪問物理內存地址,必須先通過ioremap獲得對應的虛擬地址
Linux在io.h頭文件中聲明瞭函數ioremap(),用來將I/O內存資源的物理地址映射到核心虛地址空間(3GB-4GB)中(這裏是內核空間),

你平常是怎麼用C寫嵌入式系統的死循環的?

  for(;;){}  

  while(1){}

 一般for(;;)性能更優

for(;😉{}

 這兩個;; 空語句,編譯器一般會優掉的,直接進入死循環

while(1){}  

每循環一次都要判斷常量1是不是等於零,在這裏while比for多做了這點事

不過從彙編的角度來說,都是一樣的代碼。

kmalloc和vmalloc的區別

kmalloc()
用於申請較小的、連續的物理內存

  1. 以字節爲單位進行分配,在<linux/slab.h>中
  2. void *kmalloc(size_t size, int flags) 分配的內存物理地址上連續,虛擬地址上自然連續

vmalloc()
用於申請較大的內存空間,申請的物理內存是非連續內存區。虛擬內存是連續的

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

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

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

1.I2C協議

2條雙向串行線,一條數據線SDA,一條時鐘線SCL。
SDA傳輸數據是大端傳輸,每次傳輸8bit,即一字節。
支持多主控(multimastering),任何時間點只能有一個主控。
總線上每個設備都有自己的一個addr,共7個bit,廣播地址全0.
系統中可能有多個同種芯片,爲此addr分爲固定部分和可編程部份,細節視芯片而定,看datasheet。

Kernel Panic(內核崩潰)常見原因以及解決方法

出現原因 1. Linux在中斷處理程序中,它不處於任何一個進程上下文,如果使用可能睡眠的函數,則系統調度會被破壞,導致kernel panic。因此,在中斷處理程序中,是不能使用有可能導致睡眠的函數(例如信號量等)。

  1. 內核堆棧溢出,或者指針異常訪問時,會出現kernel panic。 堆棧溢出:程序循環或者多層嵌套的深度過多時,可能會導致棧溢出。參考Linux的內存模型

一、內核空間和用戶空間

Linux簡化了分段機制,使得虛擬地址與線性地址總是一致,因此,Linux的虛擬地址空間也爲0~ 4G。Linux內核將這4G字節的空間分爲兩部分。將最高的1G字節(從虛擬地址0xC0000000到0xFFFFFFFF),供內核使用,稱爲“內核空間”。而將較低的3G字節(從虛擬地址0x00000000到0xBFFFFFFF),供各個進程使用,稱爲“用戶空間“)。因爲每個進程可以通過系統調用進入內核,因此,Linux內核由系統內的所有進程共享。於是,從具體進程的角度來看,每個進程可以擁有4G字節的虛擬空間。
二、內核態和用戶態

當一個任務(進程)執行系統調用而陷入內核代碼中執行時,我們就稱進程處於內核運行態(或簡稱爲內核態)。此時處理器處於特權級最高的(0級)內核代碼中執行。當進程處於內核態時,執行的內核代碼會使用當前進程的內核棧。每個進程都有自己的內核棧。當進程在執行用戶自己的代碼時,則稱其處於用戶運行態(用戶態)。即此時處理器在特權級最低的(3級)用戶代碼中運行。當正在執行用戶程序而突然被中斷程序中斷時,此時用戶程序也可以象徵性地稱爲處於進程的內核態。因爲中斷處理程序將使用當前進程的內核棧。這與處於內核態的進程的狀態有些類似。

怎樣申請大塊內核內存?

   vmalloc

用戶進程間通信主要哪幾種方式?

無名管道(fork 父子進程能通信),有名管道FIFO,消息隊列,信號量,共享內存,網絡編程套接字,

framebuffer機制?

Linux抽象出FrameBuffer這個設備來供用戶態進程實現直接寫屏。Framebuffer機制模仿顯卡的功能,將顯卡硬件結構抽象掉,可以通過Framebuffer的讀寫直接對顯存進行操作。用戶可以將Framebuffer看成是顯示內存的一個映像,通過mmap將其映射到進程地址空間之後,就可以直接進行讀寫操作,而寫操作可以立即反應在屏幕上。這種操作是抽象的,統一的。用戶不必關心物理顯存的位置、換頁機制等等具體細節,這些都是由Framebuffer設備驅動來完成的。通過mmap調用把顯卡的物理內存空間映射到用戶空間

1. spinlock與信號量的區別?

雖然聽起來兩者之間的使用條件複雜,其實在實際使用中信號量和自旋鎖並不易混淆。
注意以下原則:

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

linux內核原子操作的實現

所謂原子操作,就是“不可中斷的一個或一系列操作”。

自旋鎖和信號量在互斥使用時需要注意哪些?在中斷服務程序裏面的互斥是使用自旋鎖還是信號量?還是兩者都能用?爲什麼(答案見1分析)?

答:使用自旋鎖的進程不能睡眠,使用執行時間短的任務。
使用信號量的進程可以睡眠,適合於執行時間較長的任務。
中斷服務例程中的互斥使用的是自旋鎖,原因是在中斷處理例程中,硬中斷是關閉的,這樣會丟失可能到來的中斷。

驅動裏面爲什麼要有併發、互斥的控制?如何實現?講個例子?

併發(concurrency)指的是多個執行單元同時、並行被執行,而併發的執行單元對共 享資源(硬件資源和軟件上的全局變量、靜態變量等)的訪問則很容易導致競態(race conditions)。
解決競態問題的途徑是保證對共享資源的互斥訪問,所謂互斥訪問就是指一個執行單元 在訪問共享資源的時候,其他的執行單元都被禁止訪問。

訪問共享資源的代碼區域被稱爲臨界區,臨界區需要以某種互斥機 制加以保護,中斷屏蔽,原子操作,自旋鎖,和信號量都是linux設備驅動中可採用的互斥途徑。

硬中斷與軟中斷的區別

硬中斷:

  1. 硬中斷是由硬件產生的,比如,像磁盤,網卡,鍵盤,時鐘等。每個設備或設備集都有它自己的IRQ(中斷請求)。基於IRQ,CPU可以將相應的請求分發到對應的硬件驅動上(注:硬件驅動通常是內核中的一個子程序,而不是一個獨立的進程)。
  2. 處理中斷的驅動是需要運行在CPU上的,因此,當中斷產生的時候,CPU會中斷當前正在運行的任務,來處理中斷。在有多核心的系統上,一箇中斷通常只能中斷一顆CPU(也有一種特殊的情況,就是在大型主機上是有硬件通道的,它可以在沒有主CPU的支持下,可以同時處理多箇中斷。)。
  3. 硬中斷可以直接中斷CPU。它會引起內核中相關的代碼被觸發。對於那些需要花費一些時間去處理的進程,中斷代碼本身也可以被其他的硬中斷中斷。
  4. 對於時鐘中斷,內核調度代碼會將當前正在運行的進程掛起,從而讓其他的進程來運行。它的存在是爲了讓調度代碼(或稱爲調度器)可以調度多任務。
    軟中斷:
  5. 軟中斷的處理非常像硬中斷。然而,它們僅僅是由當前正在運行的進程所產生的。
  6. 通常,軟中斷是一些對I/O的請求。這些請求會調用內核中可以調度I/O發生的程序。對於某些設備,I/O請求需要被立即處理,而磁盤I/O請求通常可以排隊並且可以稍後處理。根據I/O模型的不同,進程或許會被掛起直到I/O完成,此時內核調度器就會選擇另一個進程去運行。I/O可以在進程之間產生並且調度過程通常和磁盤I/O的方式是相同。
  7. 軟中斷僅與內核相聯繫。而內核主要負責對需要運行的任何其他的進程進行調度。一些內核允許設備驅動的一些部分存在於用戶空間,並且當需要的時候內核也會調度這個進程去運行。
  8. 軟中斷並不會直接中斷CPU。也只有當前正在運行的代碼(或進程)纔會產生軟中斷。這種中斷是一種需要內核爲正在運行的進程去做一些事情(通常爲I/O)的請求。有一個特殊的軟中斷是Yield調用,它的作用是請求內核調度器去查看是否有一些其他的進程可以運行。

問:軟中斷所經過的操作流程是比硬中斷的少嗎?換句話說,對於軟中斷就是:進程 ->內核中的設備驅動程序;對於硬中斷:硬件->CPU->內核中的設備驅動程序?

答:是的,軟中斷比硬中斷少了一個硬件發送信號的步驟。產生軟中斷的進程一定是當前正在運行的進程,因此它們不會中斷CPU。但是它們會中斷調用代碼的流程。

tasklet和workqueue區別?

tasklet運行於中斷上下文,不允許阻塞 、休眠,而workqueue運行與進程上下文,可以休眠和阻塞。

爲什麼要區分上半部和下半部?

中斷服務程序異步執行,可能會中斷其他的重要代碼,包括其他中斷服務程序。因此,爲了避免被中斷的代碼延遲太長的時間,中斷服務程序需要儘快運行,而且執行的時間越短越好,所以中斷程序只作必須的工作,其他工作推遲到以後處理。所以Linux把中斷處理切爲兩個部分:上半部和下半部。

4. 中斷的申請及何時執行(何時執行中斷處理函數)?

中斷的響應流程:cpu接受中斷->保存中斷上下文跳轉到中斷處理歷程->執行中斷上半部->執行中斷下半部->恢復中斷上下文。

中斷和輪詢哪個效率高?怎樣決定是採用中斷方式還是採用輪詢方式去實現驅動?

中斷是CPU處於被動狀態下來接受設備的信號,而輪詢是CPU主動去查詢該設備是否有請求。凡事都是兩面性,所以,看效率不能簡單的說那個效率高。
如果是請求設備是一個頻繁請求cpu的設備,或者有大量數據請求的網絡設備,那麼輪詢的效率是比中斷高。如果是一般設備,並且該設備請求cpu的頻率比較底,則用中斷效率要高一些。主要是看請求頻率

寫一箇中斷服務需要注意哪些?如果中斷產生之後要做比較多的事情你是怎麼做的?

第一: 中斷處理例程應該儘量短,把能放在後半段(tasklet,等待隊列等)的任務儘量放在後半段。
寫一箇中斷服務程序要注意快進快出,在中斷服務程序裏面儘量快速採集信息,包括硬件信息,然後退出中斷,要做其它事情可以使用工作隊列或者tasklet方式。也就是中斷上半部和下半部。

第二:中斷服務程序中不能有阻塞操作。應爲中斷期間是完全佔用CPU的(即不存在內核調度),中斷被阻塞住,其他進程將無法操作;

第三:中斷服務程序注意返回值,要用操作系統定義的宏做爲返回值,而不是自己定義的OK,FAIL之類的。

驅動中操作物理絕對地址爲什麼要先ioremap?

因爲內核沒有辦法直接訪問物理內存地址,必須先通過ioremap獲得對應的虛擬地址。

Linux軟中斷和工作隊列的作用是什麼?

  https://blog.csdn.net/godleading/article/details/52971179

什麼是設備驅動模型?

設備驅動模型其實是Linux內核爲了管理硬件上的設備和對應的驅動制定的一套軟件體系。那麼其實設備驅動模型是一個比較
抽象、比較廣的一個概念,一兩句話是很難說清楚的,類(class)、總線(bus)、設備(device)、驅動(driver)、mdev(自動創建設備節點和設備類)。??

停車場管理系統

V4L2是linux操作系統下用於採集圖片、視頻的API接口,可以實現圖片、視頻、音頻的採集。可以對免驅攝像頭進行數據採集。V4L2採集的方法是內存映射方式(mmap) 來採集數據,用於連續的視頻數據採集。步驟:1、打開視頻設備文件,進行視頻採集的參數初始化,2、申請若干視頻採集的幀緩衝區,便於應用程序讀取/處理視頻數據;3、將申請到的幀緩衝區在視頻採集輸入隊列排隊,並啓動視頻採集;
4、驅動開始視頻數據的採集,應用程序從視頻採集輸出隊列取出幀緩衝區,可抓幀顯示在LCD屏上。處理完後,將幀緩衝區重新放入視頻採集輸入隊列,循環往復採集連續的視頻數據;第五,停止視頻採集。

語音播報:
通過TCP 套接字與ubuntu進行通信,應用程序是科大訊飛的一個輸入一串字符串將其轉換成音頻文件的。這樣當開發板的程序要播放音頻的時候,首先傳字符串,科大訊飛合成音頻文件,將音頻文件通過套接字發送給開發板程序。最後通過alsa去播放wav文件的音頻。

然後也學習過alsa開源庫(ALSA 是Advanced Linux Sound Architecture,高級Linux 聲音架構的簡稱),在開發板上安裝配置alsa庫,利用代碼可以實現錄製(arecode)一段音頻,並且播放(aplay)一段音頻。音頻的格式爲WAV和PCM。

觸摸算法

觸摸部分:Rx去讀spi得到的數據,分爲2個數據一個數據是AD-X 另一個AD-Y然後開始去多次採樣、去頭掐尾求平均等簡單濾波算法最後通過tslib去計算出真正的xy的值,獲取到後通過input_report_abs上報這個點。 設置總線 設從機地址。 去寫

I2c 顯示

設置總線 設從機地址。
在這裏插入圖片描述在這裏插入圖片描述
去寫
在這裏插入圖片描述

input設備子系統

在這裏插入圖片描述

在這裏插入圖片描述

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