Linux 驅動程式的 I/O, #3: kernel-space 與 user-space 的「I/O」

jollen 發表於 December 26, 2006 11:40 PM

重要觀念

任何作業系統底下的「驅動程式」,都需要分二個層面來討論所謂的「I/O 處理」:

1. 實體層:驅動程式 v.s. 硬體。

2. 虛擬層:驅動程式 v.s. user process

在前一篇日記「Linux 驅動程式的 I/O, #2: I/O 存取相關函數」中所提到的 I/O 函數是處理「實體層」的 I/O;本日記所要介紹的 copy_to_user()copy_from_user() 則是在處理「虛擬層」的 I/O。另外,在繼續往下讀之前,您必須了解以下的觀念都是「等價」的:

1. 驅動程式與 user process 的 I/O;等於

2. 驅動程式與 user process 間的 data communication;等於

3. kernel-space 與 user-space 間的 data communication。

此外,還要了解:

1. user-space 無法「直接」存取 kernel-space 的記憶體。

2. 「Linux device driver」與「user-space」間的 I/O 會與 fops->readfops->writefops->ioctl 共三個 system call 有關。

copy_to_user() 與 copy_from_user()

了解以上的觀念後,再來「直接殺進重點」就很容易懂了:從 user-space 讀取資料至 kernel-space,或是將 kernel-space 的資料寫至 user-space,「必須」透過 kernel 提供的 2 個 API 來進行。這二個 API 如下:

˙ long copy_to_user(void *to, const void *from, long n);
˙ long copy_from_user(void *to, const void *from, long n);

參數說明,以 copy_to_user() 來說:

˙ to:資料的目的位址,此參數為一個指向 user-space 記憶體的指標。
˙ from:資料的來源位址,此參數為一個指向 kernel-space 記憶體的指標。
˙ 口訣:copy data to user-space from kernel-space

copy_from_user() 來說:

˙ to:資料的目的位址,此參數為一個指向 kernel-space 記憶體的指標。
˙ from:資料的來源位址,此參數為一個指向 user-space 記憶體的指標。
˙ 口訣:copy data from user-space to kernel-space

由 user-space 讀取資料,或是寫入資料給 user-space 的 3 個 driver method 為:read、write與ioctl。

另外,指向 user-space 的指標是 kernel 回呼 driver method 時所傳遞進來的,可由 read、write 與 ioctl driver function 的函數原型宣告來觀察(紅色部份):

˙ int card_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
˙ ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp);
˙ ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp);

fops->ioctl 的參數 arg、fops->write 與 fops->read 的參數 buff 是指向 user-space 資料的指標。撰寫程式時,要注意資料型別上的不同。

下一篇日記再寫一個範例來配合著研究,大家應該會更清楚。

Also See

Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue

您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw