在proc目錄下有iomem和ioports文件,其主要描述了系統的io內存和io端口資源分布。
對於外設的訪問,最終都是通過讀寫設備上的寄存器實現的,寄存器不外乎:控制寄存器、狀態寄存器和數據寄存器,這些外設寄存器也稱為“IO端口”,並且一個外設的寄存器通常是連續編址的。
不同的CPU體系對外設IO端口物理地址的編址方式也不同,分為I/O映射方式(I/O-mapped)和內存映射方式(Memory-mapped)。
對X86熟悉點,以它為例:X86為外設專門實現有單獨的地址空間,可以稱為“I/O地址空間”或“I/O端口空間”,這個是獨立與CPU和RAM物理地址空間,它將所有外設的IO端口均在這一空間進行編址。CPU通過設立專門的IN和OUT指令來訪問這一空間中的地址單元(即I/O端口),這就是所謂的“I/O映射方式”(I/O-mapped)。和RAM物理地址空間相比,I/O地址空間通常都比較小,如x86 CPU的I/O空間就只有64KB(0-0xffff)。這是“I/O映射方式”的一個主要缺點,你可以通過cat /proc/ioports去查看,IO port空間的地址資源分配情況是以樹狀結構顯示。這個源於x86平台的設計思想,目前基本不用了,獲取這些資源的函數接口如request_region和ioremap。
Linux設計了一個通用的數據結構resource來描述各種I/O資源(如:I/O端口、外設內存、DMA和IRQ等)。該結構定義在include/linux/ioport.h頭文件中。Linux是以一種倒置的樹形結構來管理每一類I/O資源。每一類I/O資源都對應有一顆倒置的資源樹,樹中的每一個節點都是個resource結構。基於上述這個思想,Linux將基於I/O映射方式的I/O端口和基於內存映射方式的I/O端口資源統稱為“I/O區域”(I/O Region)。
/proc/iomem這個文件記錄的是物理地址的分配情況,也是以樹狀結構顯示,對其使用也是request_mem_region和ioremap,空間大小為16EB,遠大於io port的64K。
ioport和iomem地址空間分別編制,均是從地址0開始,如果硬件支持MMIO,port地址也可以映射到memory空間去。
這里以pci設備為例,硬件的拓撲結構就決定了硬件在內存映射到CPU的物理地址,由於內存訪問都是虛擬地址,所有就需要ioremap,此時物理內存是存在的,所以不用再分配內存,只需要做映射即可
應用總結:使用I/O內存首先要申請,然后才能映射,使用I/O端口首先要申請,對I/O端口的請求是讓內核知道你要訪問該端口,內核並讓你獨占該端口.
申請I/O端口的函數是request_region, 申請I/O內存的函數是request_mem_region。request_mem_region函數並沒有做實際性的映射工作,只是告訴內核要使用一塊內存地址,聲明占有,也方便內核管理這些資源。重要的還是ioremap函數,ioremap主要是檢查傳入地址的合法性,建立頁表(包括訪問權限),完成物理地址到虛擬地址的轉換。
在intel的X86平台,GPIO資源也是類似應用,如果IO配置為SCI或者SMI中斷,SCI可以產生GPE,然后經歷acpi子系統,不過GPE中斷號默認是0x10+GPIO端口號。
如果request_mem_region和ioremap返回失敗,那很可能是地址已經被占用,使用cat /proc/iomem查看物理地址的占用情況。
樹莓派手冊中GPIO地址為總線地址,物理地址可以通過源碼mach/platform.h中的GPIO_BASE變量得知