Ch9 Communicating with Hardware

Slides:



Advertisements
Similar presentations
第一單元 建立java 程式.
Advertisements

现代电子技术实验 ——综合实验之单片机部分
LinkIt ONE開發板的簡介.
第一章 C语言概述 计算机公共教学部.
编译原理上机实习
Chapter 6 時序.
Project 2 JMVC code tracing
Hardware Chen Ching-Jung
主讲教师:唐大仕 第5讲 计算机硬件 主讲教师:唐大仕
第一章 C语言概述.
CH2 開發環境介紹 最簡單的互動設計 – Arduino一試就上手 孫駿榮、吳明展、盧聰勇.
第1章 認識Arduino.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
101北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
第十一章 文件 文件概述 文件操作 文件操作实例 本章小结 作业: 练习:
2-1 接腳說明 2018/11/30 第2章 系統分析.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
C語言簡介 日期 : 2018/12/2.
類別(class) 類別class與物件object.
CH.8 硬體管理.
在專用的嵌入式板子運行 GNU/Linux 系統已經變得越來越流行。一個嵌入式 Linux 系統從軟體的角度看通常可以分為四個層次:
Echo Server/Client Speaker:Fang.
TCP/IP介紹 講師:陳育良 2018/12/28.
2017 Operating Systems 作業系統實習 助教:陳主恩、林欣穎 實驗室:720A.
Ch9 Communicating with Hardware
Chap3 Linked List 鏈結串列.
组员:吴迪&王柳杨&金虎&陈武荣&谭金柏
網路安全技術 OSI七層 學生:A 郭瀝婷 指導教授:梁明章.
程式設計實習課(四) ----C 函數運用----
編譯程式設計 期末專題說明 V1.1 May 2004.
第一單元 建立java 程式.
PLC-GPPW軟體使用教學 授課教師:張祖烈
Ch20. 計算器 (Mac 版本).
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
(第2版).
第 19 章 XML記憶體執行模式.
8051單晶片 蘇恆生 老師.
網路安全管理報告 緩衝區溢位攻擊 學生:吳忠祐 指導教授:梁明章.
Chapter 7 掌控記憶體.
CH05. 選擇敘述.
緩衝區溢位攻擊 學生:A 羅以豪 教授:梁明章
基本IO.
SOCKET( ).
C qsort.
4.19 Fsys _ SLOW MODE HT66F70A.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
Chapter 7 掌控記憶體.
第二章 类型、对象、运算符和表达式.
流程控制:Switch-Case 94學年度第一學期‧資訊教育 東海大學物理系.
陣列與結構.
Chapter 15 檔案存取 LabVIEW中的檔案存取函數也可將程式中的資料儲存成Excel或Word檔。只要將欲存取的檔案路徑位址透過LabVIEW中的路徑元件告訴檔案存取函數後,LabVIEW便可將資料存成Excel或Word檔;當然也可以將Excel或Word檔的資料讀入LabVIEW的程式中。
北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
一、簡介 電腦硬體設計:純硬體電路(hardware)及韌體電 路(firmware)兩種方式。
2018 Operating Systems 作業系統實習 助教:林欣穎 實驗室:720A.
資料表示方法 資料儲存單位.
第十二章 位运算.
MultiThread Introduction
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
作業系統實習課(二) -Scheduler-Related System Calls-
LED Pili LED 中州技術學院 電子系 副教授 余文俊.
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
Array(陣列) Anny
Chapter 4 Multi-Threads (多執行緒).
快取映射 之直接對映 計算整理.
Unix指令4-文字編輯與程式撰寫.
JUDGE GIRL 使用介紹 & 常見問題 TAs :
ABAP Basic Concept (2) 運算子 控制式與迴圈 Subroutines Event Block
InputStreamReader Console Scanner
Presentation transcript:

Ch9 Communicating with Hardware Linux Device Driver Ch9 Communicating with Hardware Nickle @ CCU CSIE

Content I/O 埠 與 I/O 記憶體 使用 I/O 埠 使用數位 I/O 埠 I/O 暫存器與傳統記憶體 字串操作 暫停 I/O 平台相依性 使用數位 I/O 埠 並列埠的基本概念 short驅動程式

Content -cont. 使用 I/O 記憶體 直接映射記憶體 使用short 測試 I/O 記憶體 軟體映射的 I/O 記憶體 位於1MB以下的 ISA記憶體 isa_readb()與相關函式

I/O 埠 與 I/O 記憶體 幾乎每一種周邊裝置的控制,都是藉由 register 來達成的,這些暫存器,可能在記憶體空間,也可能在 I/O 空間。 目前流行的周邊匯流排是以PC架構為模型;因此,即使沒將 I/O 位址空間獨立出來的處理器,在存取這些週邊裝置時,也必須”假裝”讀寫 I/O 埠。因此,Linux 虛構一組 I/O 埠存取架構。 一般認為,I/O 記憶區是比較適當的形式,他有下列優點: 不需要用到特殊用途的 CPU 指令。 CPU core 對記憶體的存取效率相對於專用 I/O 指令而言較高。 在暫存器的分配及定址模式上,由編輯器產生存取記憶體的程式碼有較自由的選擇。

I/O 埠 與 I/O 記憶體 直接映射記憶體 I/O 暫存器和RAM最大的差異,在於 I/O 操作有”副作用”: 存取記憶體只是改變目標的儲存值。 存取 I/O,目的不在於儲存值,許多控制是藉由”讀取”和“寫入”的動作來改變裝置的狀態。 將原本施加於記憶體最佳化技術施(cache)加於 I/O 暫存器身上,則無法產生 I/O 暫存器操作想要的“副作用”。 解決方法:在必須以原貌出現在硬體上的程式之間,加上記憶屏障(memory barrier)。

I/O 埠 與 I/O 記憶體 memory barrier #include <linux/kernel.h> void barrier(void) 要求編譯器編譯出來的程式碼,被修改存在CPU占存器的值,會確實寫回記憶體: #include <asm/system.h> void rmb(void); void read_barrier_depends(void); void wmb(void); void mb(void); rmb()保證出現在barrier之前的讀取動作,都會在後續的任何讀取動作之前如實完成。 wmb()保證寫出動作會被依序徹底完成。 mb() 保證 讀、寫動作都會落實執行。

I/O 埠 與 I/O 記憶體 void smp_rmb(void); void smp_read_barrier_depends(void); void smp_wmb(void); void smp_mb(void); 同前述函式,但只在支援SMP的system有作用 使用barrier的例子: writel(dev->registers.addr, io_destination_address); writel(dev->registers.size, io_size); writel(dev->registers.operation, DEV_READ); wmb( ); writel(dev->registers.control, DEV_GO); 前面三個writel都完成後,才會進行writel(dev-> …….)的動作。

I/O 埠 與 I/O 記憶體 某些平台容許「一次設值(atomic_t)」和「一個記憶體屏障」組成比較有效率的執行單位,提供以下巨集: #define set_mb(var, value) do {var = value; mb( );} while 0 #define set_wmb(var, value) do {var = value; wmb( );} while 0 #define set_rmb(var, value) do {var = value; rmb( );} while 0

使用 I/O 埠 在驅動程式真正使用I/O埠之前,必須先配置: #include <linux/ioport.h> int check_region(unsigned long first, unsigned long n); struct resource *request_region(unsigned long first, unsigned long n,const char *name); void release_region(unsigned long start, unsigned long n); 大部分的硬體會區分 8-bit 16-bit 32-bit埠,因此不能像平常存許系統記憶體那樣混用。

使用 I/O 埠 Linux核心中的<asm/io.h>定義以下用來存取I/O埠的內插函式: unsigned inb(unsigned port); void outb(unsigned char byte, unsigned port); 讀寫1-byte埠,某些平台上port定義成unsigned long,回傳值也因平台而易。 unsigned inw(unsigned port); void outw(unsigned short word, unsigned port); 存取16-bits埠,在只支援byte I/O的平台不存在。 unsigned inl(unsigned port); void outl(unsigned longword, unsigned port); 存取32-bits埠,longword有可能被宣告成unsigned long或是unsigned int 64-bits port I/O 並不存在。

使用 I/O 埠 前述 I/O 函式也可以在user space使用,GUN定義在<sys/io.h>,但必須遵守以下條件: 必須先使用ioperm() 或iopl()取得目標I/O埠的存取權,這兩個函式只能用在Intel系統上。 程式本身要以root的身分呼叫ioerm()或iopl(),或是他的父行程之一必須已經用root取得I/O埠的存取權。 範例程式:misc-progs/inp.c、misc-progs/outp.c

使用 I/O 埠 字串操作(string intructions):某些處理器提供特殊指令能夠將依連串同等大小的bytes、word、longs讀入、寫出到一個I/O埠。 字串操作的巨集原型: void insb(unsigned port, void *addr, unsigned long count); void outsb(unsigned port, void *addr, unsigned long count); 前者從port讀取count個位元組存入addr位址上的記憶體,後者將addr位址上的count個位元組寫入port void insw(unsigned port, void *addr, unsigned long count); void outsw(unsigned port, void *addr, unsigned long count); 同上面的函式,以16-bits word為單位。 void insl(unsigned port, void *addr, unsigned long count); void outsl(unsigned port, void *addr, unsigned long count); 同上面的函式,以32-bits long word為單位。

使用 I/O 埠 暫停 I/O:當處理器與匯流排之間的傳輸率過快,導致裝置漏失一些資料。 改採一些會暫停的函式來代替正常函式,其作用和用法與之前那些正常I/O相同,只在名稱末端多了 _p字樣(e.g. inb_p() 、outb_p())

使用 I/O 埠 平台相依性 I/O 指令天生和處理器之間有著高度的相依性,因為他們控制著資料如何進出處理器的細節;因此,程式中涉及I/O埠的部份,幾乎都必須針對特定平台來設計,而沒有一體性的寫法。 各平台差異請詳見課本 p.243 ~ p.244

使用數位 I/O 埠 數位I/O埠最平常的具體形式,是一個單位元組寬的I/O位置,該位址可能映射到記憶空間,但也可能有專屬的I/O空間。 並列埠的基本概念 依照PC標準規格每台可以配置兩個並列埠介面,第一個介面起始位置是0x378,第二個是0x278。並列埠的基本模式是由三個8-bit埠構成;第一個埠是雙向的資料暫存器,直接連到實體街頭的pin2 ~ pin9;第二埠是一個唯讀的暫存器;第三埠是控制暫存器(能寫不能讀)。

使用數位 I/O 埠 並列埠各個位元的規格

使用數位 I/O 埠 short(Simple Hardware Operations and Raw Tests)驅動程式 short只能讀、寫在載入期指定的少數幾個 8-bits埠。 short驅動程式不會做任何有用的事情,只讓我們將I/O指令作用到指定的埠。 不能用short存取已被其他驅動程式佔用的裝置。 short宗旨:在任何Linux平台測試任何可透過outb()和inb()來存取數位I/O介面。

使用數位 I/O 埠 short本身操作- /dev/short0 是 I/O的基底位址8-bits管道,能夠一次寫出或讀入8-bits資料。/dev/short1對應到base + 1,以此類推到short7。 輸出動作 while (count--) { outb(*(ptr++), port); wmb( ); } #echo –n “any string” > /dev/short0 點亮LED燈,只有最後一個字元能夠被看到,因此加上-n選項,在字串末端加上‘\n’。 讀入動作 outb()換成inb()。 讀出port 0x378的值: #dd if=/dev/short0 bs=1 count=1 | od –t x1 Memory barrier 確保動作不會被最佳化處理掉

使用數位 I/O 埠 short三種變形 /dev/short0 用前述的緊密迴圈 /dev/short0p使用outb_p() 和 inb_p() /dev/short0s使用字串函式

使用 I/O 記憶體 I/O 記憶體是性質類似於RAM的特殊區域,處理器可直接從其匯流排存取特定的硬體裝置,意即,讀寫這些區域會產生“副作用”。 本章只討論如何存取PCI和ISA記憶體。 基於8.1.1強調的額外顧慮,應避免使用直接指向I/O記憶體的指標 裝置記憶體需要先配置才能使用(linux/ioport.h): struct resource *request_mem_region(unsigned long start, unsigned long len,char *name); 配置的記憶體列表於 /proc/iomem. void release_mem_region(unsigned long start, unsigned long len); int check_mem_region(unsigned long start, unsigned long len);

使用 I/O 記憶體 直接映射記憶體 保留部位記憶位址空間給I/O專用,這些I/O專區不受記憶體管理系統的管制,也沒有任何虛擬位址會落在I/O專區的範圍內。 存取直接映射的I/O記憶區:用指標存取 unsigned int ioread8(void *addr); unsigned int ioread16(void *addr); unsigned int ioread32(void *addr); void iowrite8(u8 value, void *addr); void iowrite16(u16 value, void *addr); void iowrite32(u32 value, void *addr); 如果要存取一序列的資料(repeat): void ioread8_rep(void *addr, void *buf, unsigned long count); void ioread16_rep(void *addr, void *buf, unsigned long count); void ioread32_rep(void *addr, void *buf, unsigned long count); void iowrite8_rep(void *addr, const void *buf, unsigned long count); void iowrite16_rep(void *addr, const void *buf, unsigned long count); void iowrite32_rep(void *addr, const void *buf, unsigned long count);

使用 I/O 記憶體 讀寫一個block,用: unsigned readb(address); unsigned readw(address); unsigned readl(address); 這些巨集分別從I/O記憶體擷取8-bits、16-bits、32-bits資料值。 void writeb(unsigned value, address); void writew(unsigned value, address); void writel(unsigned value, address); 用於寫出8-bits、16-bits、32-bits資料值。 void memset_io(void *addr, u8 value, unsigned int count); void memcpy_fromio(void *dest, void *source, unsigned int count); void memcpy_toio(void *dest, void *source, unsigned int count); 這些函式將資料塊搬出、搬入I/O記憶體,類似C函式庫中的memcpy()一樣。

使用 I/O 記憶體 使用short 測試 I/O 記憶體 Ports as I/O Memory 於載入期告訴它使用I/O記憶體,並將I/O region的起始位置告訴它。 對short,存取I/O埠和I/O記憶體一樣,不過I/O記憶體沒有字串操作;因此/dev/short0p /dev/short0s和/dev/short0操作是一樣的。 Ports as I/O Memory 有些裝置使用I/O port,有些使用I/O Memory;兩者access的方法不同,2.6版本提供: void *ioport_map(unsigned long port, unsigned int count); void ioport_unmap(void *addr); 使得作法更為簡便。

使用 I/O 記憶體 軟體映射的 I/O 記憶體 對於要存取I/O記憶體的軟體,必須要有一種辦法將虛擬位址指向裝置:ioremap() #include <asm/io.h> void *ioremap(unsigned long phys_addr, unsigned long size); void *ioremap_nocache(unsigned long phys_addr, unsigned long size); 大多數平台上,其實做和ioremap()完全一樣。 void iounmap(void * addr); 如果使用的是完全映射的I/O位址,則ioremap()沒有作用。

使用 I/O 記憶體 位於1MB以下的 ISA記憶體 指位於640KB ~ 1024KB範圍的的記憶體位址。 Silly模組(Simple Tool for Unloading and Printing ISA Data)。 Silly的任務是存取ISA記憶體,他必須把ISA的實體位址映射到核心的虛擬位址(使用ioremap() )。 #define ISA_BASE 0xA0000 #define ISA_MAX 0x100000 /* for general memory access */ /* this line appears in silly_init */ io_base = ioremap(ISA_BASE, ISA_MAX - ISA_BASE);

使用 I/O 記憶體 Silly的作業方法: 存取/dev/sillyb (8-bits存取模式) case M_8: while (count) { *ptr = ioread8(add); add++; count--; ptr++; } break;

使用 I/O 記憶體 最後使用iounmap(io_base)恢復原狀。 存取/dev/sillyw和/dev/sillyl case M_32: while (count >= 4) { iowrite8(*(u32 *)ptr, add); add += 4; count -= 4; ptr += 4; } break; 存取/dev/sillycp,使用memcpy_*io() case M_memcpy: memcpy_fromio(ptr, add, count); 最後使用iounmap(io_base)恢復原狀。

使用 I/O 記憶體 isa_readb()與相關函式 先前介紹的每個函式,都有各自對等的isa_*()函式,讓我們可以存取ISA記憶體而不必是先呼叫ioremap()。 不過這些函式將來可能會消失,盡量避免不用。

THE END~ Any question?