linux 驅動程式___進階字元驅動程式___ioctl 方法解讀

來源:互聯網
上載者:User

 

~
ioctl方法

  • 概述

    • 目的: 通過裝置驅動程式執行各種類型的硬體控制
    • 使用者空間的調用原型:int ioctl(int fd, unsigned long cmd, ...);
      • fd 指的是 檔案描述符
      • ”…“ 代表選擇性參數,使用 ”…“ 可以關閉編譯時間的邏輯檢查
      • 習慣上使用 char *argp;
      • 選擇性參數可以為空白,可為整型,可以是指標;當使用指標時可以交換任意數量的資料。
    • 驅動程式的原型實現:int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
      • inode 和 filp兩個指標對應於使用者空間的 檔案描述符 fd
      • cmd 參數直接傳輸,不經任何修改
      • arg 接收的是選擇性參數,接收類型永遠是 unsigned long,參數類型檢查被關閉,如果有錯誤也不進行報告
      • 多數 ioctl 都是通過 switch 語句來完成的
  • ioctl 命令選擇
    • ioctl 命令結構

      • 參考檔案

        • include/asm/ioctl.h
        • Documentation/ioctl-number.txt
      • 位段結構
        • type

          • 幻數(類型),主要在Documentation/ioctl-number.txt 中定義
          • 位寬:8位 ( _IOC_TYPEBITS )
        • number
          • 序數(順序編號)
          • 位寬:8位 ( _IOC_NRBITS )
        • direction
          • 資料傳送的標誌,定義資料傳送的方向,該欄位是一個位元遮罩,可以通過邏輯運算分離
          • 可使用值
            • 沒有資料轉送 (_IOC_NONE)

              • #ifndef _IOC_NONE

                # define _IOC_NONE 0U

                #endif

            • _IOC_READ
              • #ifndef _IOC_READ

                # define _IOC_READ 2U

                #endif

            • _IOC_WRITE
              • #ifndef _IOC_WRITE

                # define _IOC_WRITE 1U

                #endif

            • 雙向資料轉送(_IOC_READ|_IOC_WRITE)
        • size
          • 指示使用者資料大小,與體繫結構有關,通常是13位或者14位
          • 宏定義:_IOC_SIZEBITS
          • 系統不對欄位進行檢查,使用者資料大時可以乎略
    • 構造命令編號的宏
      • 定義位置: <asm/ioctl.h>;type和number位欄位通過參數傳入,size位欄位通過對 datatype 參數取 sizeof 獲得。
      • _IO(type, nr)
        • 用於構造無參數的命令編號
      • _IOR(type, nr, datatype)
        • 用於構造從驅動程式中讀取資料的命令編號
      • _IOW(type, nr, datatype)
        • 用於寫入資料的命令
      • _IOWR(type, nr, datatype)
        • 用於雙向傳輸
    • 解開位段結構的宏
      • 定義位置 <asm/ioctl.h>
      • _IOC_DIR(nr)
      • _IOC_TYPE(nr)
      • _IOC_NR(nr)
      • _IOC_SIZE(nr)
  • ioctl 命令號不能匹配的預設的傳回值
    • 非法參數:-ENVAL
    • POSIX標準規定返回: -ENOTTY
  • ioctl 的預定義命令
    • 部分預定義命令可由核心識別,這些命令在使用時無法到達裝置,由核心運行,並且因為編號衝突,結果不可預期
    • 預定義命令分類
      • 可用於任何檔案(普通、裝置、FIFO和通訊端)的命令

        • 幻數是 ”T“
      • 只適用於普通檔案的命令
      • 特定於檔案系統類型的命令
        • 只能在宿主檔案系統上執行
    • 實際預定義命令
      • FIOCLEX

        • 設定執行時關閉標誌(File IOctl Close on EXec),設定後當調用進程執行一個新程式時,檔案描述符將被關閉
      • FIOUNCLEX
        • 清除執行時關閉標誌(File IOctl Not Close on EXec),恢複通常的檔案行為,撤銷 FIOCLEX 操作。
      • FIOASYNC
        • 設定或複位非同步通知
        • 修改 O_SYNC 標誌,同樣的工作可通過 fcntl 完成,因此 FIOASYNC 很少使用
      • FIOQSIZE
        • 返迴文件或目錄的大小。
        • 不可用於裝置檔案,否則導致 ENOTTY 錯誤
      • FIONBIO
        • File IOctl Non-Blocking I/O, 即檔案 ioctl 非阻塞型 I/O
        • 該調用修改 filp->f_flags 中的 O_NONBLOCK 標誌, 系統調用的第三個參數說明了是複位還是設定
        • filp->f_flags 中的 O_NONBLOCK 通常由 fcntl 系統調用使用命令 F_SETFL 命令完成
    • 使用 ioctl 參數
      • 當 ioctl 第三個參數是個指標時,會出現一些問題
      • 當指標指向使用者空間時,必須保證使用者空間合法,否則應返回錯誤
      • 地址驗證函式 access_ok
        • 函式宣告及原型

          • <asm/uaccess.h>
          • int access_ok(int type, const void *addr, unsigned long size);
        • 參數說明
          • type

            • VERIFY_READ

              • 從使用者空間讀出資料
            • VERIFY_WRITE
              • 往使用者空間寫入資料
              • 如果既要讀取又要寫入,則應該使用 VERIFY_WRITE,為超集
          • addr
            • 使用者空間地址
          • size
            • 資料的位元組數,如果為int,則是 sizeof(int)
        • 傳回值是 bool 量
          • 訪問成功返回 1
          • 訪問失敗返回 0,此時驅動程式應該返回 -EFAULT 給調用者
        • 使用注意事項
          • 沒有完成驗證記憶體的全部工作,只對進程對空間的存取權限進行驗證,尤其確保指標沒有指向核心空間
          • 大多數程式不需要直接調用該函數,大多數記憶體管理函數會處理它
      • 寫入/讀取資料函數(限於 1,2,4和8個位元組)
        • 寫入使用者空間

          • put_user(datum, ptr);

            • 進行地址檢查,成功時返回 0, 失敗時返回 -EFAULT
          • __put_user(datum, ptr);
            • 不進行地址檢查,使用時需要自行調用 access_ok

          讀取使用者空間

          • get_user(local, ptr)
          • __get_user(local, ptr)

          當指標類型與指定類型不相符時,編譯器返回 “conversion to non-scalar type requested"

          此時必須使用 copy_to_user 或者 copy_from_user

    • 權能與受限操作
      • 對權能檢查的說明

        • 對裝置的訪問一般由裝置檔案的許可權控制,驅動程式不進行檢查
        • 對於一些附加操作,驅動程式需要進行附加檢查以確認使用者是否有權進行
      • 權能(capability)
        • 權能把特權操作劃分為獨立的組,這樣某些特定使用者或程式可被授權執行指定操作,同時又沒有執行其它操作的許可權

          相關係統調用函數:capget 和 capset,因此可以在使用者空間管理權能

      • 定義檔案
        • <linux/capability.h>
      • 驅動程式關心的權能
        • CAP_DAC_OVERRIDE

          • 超越檔案或目錄的存取權限,資料存取控制或DAC)的能力
        • CAP_NET_ADMIN
          • 執行網路管理工作的能力,包括那些影響網路介面的任務
        • CAP_SYS_MODULE
          • 載入或刪除核心模組的能力
        • CAP_SYS_RAMIO
          • 執行”裸“ I/O操作的能力,例如訪問裝置連接埠或直接與 USB 通訊
        • CAP_SYS_ADMIN
          • 截獲的能力,它提供了訪問許多系統管理操作的途徑
        • CAP_SYS_TTY_CONFIG
          • 執行 tty 配置任務的能力
      • 權能檢查
        • 在執行一項特殊操作時,驅動程式應該檢查調用進程是否有相關權能
        • 函數實現
          • <sys/sched.h>
          • int capable(int capability);
  • ioctl 命令的實現
    • 利用 switch 語句實現命令控制,參考 scull 原始碼
    • 參數傳遞的一般途徑(六種)
      • int quantum;

         

        ioctl(fd,SCULL_IOCSQUANTUM, &quantum); /* Set by pointer */

        ioctl(fd,SCULL_IOCTQUANTUM, quantum); /* Set by value */

         

        ioctl(fd,SCULL_IOCGQUANTUM, &quantum); /* Get by pointer */

        quantum = ioctl(fd,SCULL_IOCQQUANTUM); /* Get by return value */

         

        ioctl(fd,SCULL_IOCXQUANTUM, &quantum); /* Exchange by pointer */

        quantum = ioctl(fd,SCULL_IOCHQUANTUM, quantum); /* Exchange by value *

         

  • 非 ioctl 的裝置控制——轉議序列
    • 適用於只執行命令,不需要資料轉送的裝置
    • 如果寫入資料種出現控制符時會產生誤會
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.