顯示具有 kernel 標籤的文章。 顯示所有文章
顯示具有 kernel 標籤的文章。 顯示所有文章

2011年8月7日 星期日

linux nfc kernel driver pn544

讀 linux kernel "Documentation/nfc/nfc-pn544.txt"

感謝作者: Jari Vanhala
聯絡方式: Matti Aaltonen (matti.j.aaltonen at nokia.com)

兩個可參考的驅動程式: "drivers/nfc/pn533.c", "drivers/nfc/pn544.c" 感謝 Nokia 的愛心。

使用 linux kernel 的 misc device, device name /dev/pn544
其中 pn544 有 I2C, SPI, HSU 三種介面但驅動程式只提供 I2C 介面實作

對 user space 介面有 sysfs 的硬體測試與 IOCTL 切換 HCI, firmware update 兩種工作模式,傳輸訊息的方式有三種:read, write, poll

由 user space 傳訊息到 PN544  晶片進行控制,驅動程式目前只傳遞訊息不瞭解訊息內容

溝通協定

正常的 HCI 模式與 firmware update 模式的 read/write 行為不太一樣,因為兩種模式的訊息格式與溝通協定都不同。

HCI模式的溝通協定採用 ETSI 的 HCI spec,firmware update 則另有特殊協定。

HCI 訊息有 8 bit header 跟訊息內容。header 包括訊息長度,最大 33 bytes。傳送出去的訊息需要經過 checksum 驗證。

Firmware update 訊息長度存在第二(MSB)跟第三(LSB)位元組,最大值 1024 bytes.

sysfs 的硬體測試指的是讀取 sysfs 檔案後能將 pn544 轉為 firmware update mode,如果未提供測試則不需要建立此 sysfs 檔案。

使用範例:

 60 Example:
 61 > cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test
 62 1

正常運作流程:
device 檔案 open 後 pn544 就給電,未開啟前斷電,一次只能有單一使用者。user space 應用程式使用 HCI 訊息控制。 當有資料可讀時就發出一次中斷,當 user space 下 read 時才從 pn544 實際讀取資料,poll() 檢查 read interrupt state。設定與單元測試都由 user space 的 read/write 完成。

範例 platform data:


78 static int rx71_pn544_nfc_request_resources(struct i2c_client *client)
79 {
80 /* Get and setup the HW resources for the device */
81 }
82
83 static void rx71_pn544_nfc_free_resources(void)
84 {
85 /* Release the HW resources */
86 }
87
88 static void rx71_pn544_nfc_enable(int fw)
89 {
90 /* Turn the device on */
91 }
92
93 static int rx71_pn544_nfc_test(void)
94 {
95 /*
96 * Put the device into the FW update mode
97 * and then back to the normal mode.
98 * Check the behavior and return one on success,
99 * zero on failure.
100 */
101 }
102
103 static void rx71_pn544_nfc_disable(void)
104 {
105 /* turn the power off */
106 }
107
108 static struct pn544_nfc_platform_data rx71_nfc_data = {
109 .request_resources = rx71_pn544_nfc_request_resources,
110 .free_resources = rx71_pn544_nfc_free_resources,
111 .enable = rx71_pn544_nfc_enable,
112 .test = rx71_pn544_nfc_test,
113 .disable = rx71_pn544_nfc_disable,
114 };


NXP pn544 introduction pdf
including: contact less procotols, host interfaces, power cosumption

NXP NFC 的 peer to peer, card emulation, Reader三種模式與使用的溝同協定說明

值得注意的是,就專利版圖來看,目前 NFC 市場並沒有真正的大廠,前六強分別是 Sony, Broadcom, IBM, Nokia, Panasonic, NXP

2011年7月27日 星期三

Linux kernel spinlock 使用方式與時機

由 Linus 親自整理的 Linux kernel spinlock 文件

~linux/Documentation/spinlocks.txt
            多核心處理 critical section 的方式,safe but slow(disable interrupts)
 67 See . The basic version is:
 68
 69    spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
 70
 71
 72     unsigned long flags;
 73
 74     spin_lock_irqsave(&xxx_lock, flags);
 75     ... critical section here ..
 76     spin_unlock_irqrestore(&xxx_lock, flags);

            單核心處理 critical section 的方式:
115
116     spin_lock_irqsave(flags);
117     .. critical section ..
118     spin_unlock_irqrestore(flags);
119

        reader/writer 處理 shared data 的鎖定方式:
149    rwlock_t xxx_lock = RW_LOCK_UNLOCKED;
150
151
152     unsigned long flags;
153
154     read_lock_irqsave(&xxx_lock, flags);
155     .. critical section that only reads the info ...
156     read_unlock_irqrestore(&xxx_lock, flags);
157
158     write_lock_irqsave(&xxx_lock, flags);
159     .. read and write exclusive access to the info ...
160     write_unlock_irqrestore(&xxx_lock, flags);

        如果確定不會跑在 interrupt handler 中(否則會重複鎖定造成 dead lock),
        可以用簡化的 spin_lock API 較快
192     spin_lock(&lock);
193     ...
194     spin_unlock(&lock);

        因此 read lock 等可以用簡化的非 irq safe spinlock,但 write lock 則必須
        使用 irq safe 的 spin lock

Linux kernel and user space interfaces

1. /dev/  character device ioctl control code read/write interface
2. /sys sysfs  show/store read/write interface
3. /proc procfs  read/write interface
4. event: input events (for example key events)

2011年6月26日 星期日

DISCONTIGMEM on PXA270

Russell King在回覆給 dera 的 DISCONTIGMEM on PXA270 一文中,提到 PXA270 平台設定
多個 DRAM memory bank 在 Linux kernel 的設計方式:

1. PHYS_OFFSET 從最小的 SDRAM 開始,在該文中是以 0x8000,0000
2. 因為 memory bank 之間有太大的漏洞,必須修改  __virt_to_phys/__phys_to_virt 將你的實體
記憶體壓縮排列到虛擬記憶體中。
3. 因為實體與虛擬記憶體非 1:1 對應,因此不能定義 NODE_MEM_SIZE_BITS, 而是要以單一
bank (該文是 128MB) 設定 NODE_MEM_SIZE_MASK (128MB -1)
4. 定義 KVADDR_TO_NID(vaddr) 將虛擬記憶體轉為 node number
5. 定義 PFN_TO_NID(pfn)轉 page frame number (phys >> PAGE_SHIFT) 到同一
node number (memory bank)
6. 公式就是以下列式必須符合 SDRAM 每一個位址:
KVADDR(vaddr) == PFN_TO_NID(phys_to_pfn(virt_to_phys(vaddr)))
7. Vernon Sauder 在回文中提到 必須考慮到 arch/arm/mach-pxa/Makefile.boot
中定義的 linux kernel start address zreladdr, 有修改為 0x8000,8000.

但實務上現在 arm linux 不應該再使用 DISCONTIGMEM ,而該使用 SPARSEMEM
1. mach/memory.h 定義 MAX_PHYSMEM_BITS 跟 SECTION_SIZE_BITS
可以在 arch/arm/include/asm/sparsemem.h 找到這兩個參數的定義

2.  config 中加入 ARCH_SPARSEMEM_ENABLE 移除 ARCH_DISCONTIGMEM_ENABLE
3. 仍需要修改  __virt_to_phys/__phys_to_virt 將你的實體記憶體壓縮排列到虛擬記憶體中。
4. 確定 sparse memory 的 patch 有上, finish of sparse memory patch

2011年6月19日 星期日

ARM Linux kernel 記憶體配置

摘譯這篇由 Russell King 在 2005 年 11 月 17 日針對 2.6.15 Linux kernel 撰寫的 ARM Linux kernel 記憶體配置

裡面指的是 linux kernel 使用 arm cpu 的虛擬記憶體的位址配置與排列方式

arm cpu 的虛擬記憶體定址空間: 4GB (32 位元的定址空間, 0000,0000 ~ FFFF,FFFF)

沒有遵循這個記憶體配置的 kernel 可能無法開機或發生隨機當機


===========開始=========針對 user space 的加入內容==========================

針對每個 user space 程式而言,其實都跟硬體裝置的記憶體映射空間, kernel 使用的記憶體空間,三者共用整個 4GB 的虛擬記憶體。

user space 程式這個區塊內部的記憶體配置如下:
   +----------------------+---------------------+-----------+------------+------------+
    | Code segment(r+x) | Data segment(r+w) | BSS(r+w)  | Heap(r+w) | Stack(r+w) |
   +-------------------------------------------------------------------------------------+

Code segment 是 instruction memory,儲存程式碼
Data segment 是 data memory,使用 brk(), sbrk() system call 改變或查詢 Program break 大小
BSS segment 是未初始化的 global 變數存放位置
Heap segment 儲存程式執行期產生的動態變數、記憶體區塊由 malloc() 取用,free()  釋放
Stack segment 使用 SP stack pointer 暫存器輔助 IP instrcution pointer 指定,由 function call, 與其 local 變數使用 

註:參考 Memory Management for System Programmers (pdf)

在 Linux 系統底下我們可以藉由 /proc/some_pid/maps 看到執行檔與 library memory map,另外 smaps 則詳列各區段 memory map 的使用狀態。其中可以看到從  0x0000,1000~0xBF00,0000 的載入函式庫與 heap, stack, 其中 stack 與 TASK_SIZE 相鄰

舉某個 android process 為例:
其中

    0xBEBE,9000- 0xBEBF,E00 是 stack 使用
    0xB000,0000 ~ 0xB001,0000 是 linker 載入位置, Thread 0 Stack
    0x8000,0000 ~ 0xAFE46000  是 Non-prelinked libraries
    0x4154,C000 ~ 0x8000,0000 是 mmap'd 記譯體,Java jar library, apk 檔案
    0x4000,0000 ~ 0x4154,C000 是 mmaped open file
    0x0000,A000 ~ 0x003C,4000 用在 heap
    0x0000,1000~0x0000, A000 佔用 .text (code segment) / .data 

Android 2.3 以前的 prelink library build/core/prelink-linux-arm.map 裡面除了重述 Russel King 的 ARM Linux kernel memory 的記憶體配置,Android 的記憶體配置中,包含兩塊系統預設的 library memory mapping:

    其中 Android prelink 定義了以下兩大塊記憶體對應:

    # 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
    # 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
    可以在 prelink-linux-arm.map 中找到或新增你要加入的 library 記憶體對應。

    # 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
    0xAEF00000  - 0xAFF00000 # core system libraries
    0xAE700000 - 0xAEE00000 # bluetooth libraries
    0xAE300000 - 0xAE600000 # extended system libraries
    0xACA00000 - 0xAE200000 # core dalvik runtime support
    0xA9C00000 - 0xAC900000 # graphics
    0xA8D00000 - 0xA9B00000 # audio
    0xA7000000 - 0xA8B00000 # assorted system libraries
    0xA4800000 - 0xA6F00000 # pv libraries
    0xA4000000 - 0xA4700000 # opencore hardware support
    0xA3800000 - 0xA3900000 # pv libraries
    0xA2F00000 - 0xA3700000 # stagefright libraries
    0xA2A00000 - 0xA2E00000 # libraries for specific hardware

    # 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
    0x9CA00000 - 0x9F000000 # libraries for specific apps or temporary libraries

# 0xC0000000 - 0xFFFFFFFF Kernel
# 0xB0100000 - 0xBFFFFFFF Thread 0 Stack
# 0xB0000000 - 0xB00FFFFF Linker
# 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
# 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
# 0x80000000 - 0x8FFFFFFF Non-prelinked Libraries
# 0x40000000 - 0x7FFFFFFF mmap'd stuff
# 0x10000000 - 0x3FFFFFFF Thread Stacks
# 0x00000000 - 0x0FFFFFFF .text / .data / heap

====================針對 user space 的加入內容==========結束================

因為 cpu 架構的發展變化可能影響 kernel 記憶體位置的配置,user space 程式應該只使用到 0000,1000 ~ TASK_SIZE -1 這段記憶體。請使用 open(), mmap() 系統呼叫使用這段記憶體。

    FFFF,8000 ~ FFFF,FFFF           copy_user_page/clear_user_page 使用
    SA11xx 跟 Xscale cpu 建立 minicache 的記憶體位址

    FFFF,1000 ~ FFFF,7FFF           保留
    各平台禁止使用這塊記憶體配置

    FFFF,0000 ~ FFFF,0FFF           cpu vector page
    如果 cpu 支援改變中斷向量位址 (control register V bit), 會把中斷向量映射到這
    4K bytes 區塊

    FFC0,0000 ~ fffe,ffff           DMA 記憶體映射區塊,由 dma_alloc_xxx 的
    函式呼叫都使用這塊記憶體動態配置,總共 0x003F,0000 佔 4MB

    FF00,0000 ~ FFBFF,FFFF          保留給 DMA 記憶體映射擴充使用 佔 12MB

    VMALLOC_END ~ feff,ffff         平台自由運用的記憶體區塊都建議用這段
    VMALLOC_END 必須對齊 2MB 的記憶體區塊
    在 arch/arm/mach-pxa/include/mach/memory.h 中定義

    #define ARM_DMA_ZONE_SIZE SZ_64M 除了以上 16MB 保留給 DMA 另外用了 48 MB
    使用 FBC0,0000~fffe,ffff
    在 arch/arm/mach-pxa/include/mach/vmalloc.h 定義
    #define VMALLOC_END       (0xE8000000UL)

    VMALLOC_START ~ VMALLOC_END - 1 vmalloc() / ioremap() space
    由 vmalloc() 及 ioremap() 取得的記憶體會動態配置在這區塊,VMALLOC_START 相依
    於 high_memory(不能有重疊)
    在 arch/arm/include/asm/pgtable.h 中註解有說明留 8MB 給誤動作的記憶體錯誤緩衝空間,
    定義如下:
    #ifndef VMALLOC_START
    #define VMALLOC_OFFSET      (8*1024*1024)
    #define VMALLOC_START       (((unsigned long)high_memory + VMALLOC_OFFSET) &
                                                      ~(VMALLOC_OFFSET-1))
    #endif

其中 high_memory 在 arch/arm/mm/init.c 的 void __init bootmem_init(void) 計算:
    high_memory = __va(((phys_addr_t)max_low << PAGE_SHIFT) - 1) + 1;

    PAGE_OFFSET ~ high_memory - 1   Kernel direct-mapped RAM region
    這段記憶體對應到平台上的實體記憶體,通常跟系統記憶體是 1:1 的對應
    (direct addressing) 在 arch/arm/include/asm/memory.h 看到 PAGE_OFFSET 定義為
    UL(CONFIG_PAGE_OFFSET)
    也因此我們可以在 arch/arm/include/asm/memory.h 看到以下 virtual, physical 記憶體互轉的
    巨集定義:
    #define __virt_to_phys(x)   ((x) - PAGE_OFFSET + PHYS_OFFSET)
    #define __phys_to_virt(x)   ((x) - PHYS_OFFSET + PAGE_OFFSET)

    其中的 PHYS_OFFSET 實體記憶體在 cpu 定址的記憶體初始(start of bank 0 dram)位址
    ,是定義在同檔案的以下巨集:
    #define PHYS_OFFSET UL(CONFIG_DRAM_BASE) 與
    #define PHYS_OFFSET PLAT_PHYS_OFFSET
    CONFIG_DRAM_BASE 是實體記憶體起始的 offset 值,在 pxa 平台可以
    在 arch/arm/mach-pxa/include/mach/memory.h 中看到定義為:
    #define PLAT_PHYS_OFFSET    UL(0xa0000000)
    我們可以對照 pxa270 spec memory map 章節的 dram map 起始位址
    0xa000,0000 作為實體記憶體的起始位址得到驗證。
    再配合 arch/arm/Makefile 定義的 Linux kernel image text area 值
    TEXT_OFFSET := $(textofs-y)
    而 textofs-y   := 0x00008000 是預設值。
    arch/arm/boot/Makefile 告訴我們 zImage 等 target 就是
     21 #   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
    因此可以算出:ZRELADDR = PHYS_OFFSET + TEXT_OFFSET = 0xA000,8000 (physical)
    而虛擬位置是 0xC000,8000(virtual),這個計算結果可以跟 Makefile include 的
    include $(srctree)/$(MACHINE)/Makefile.boot 檔案,在 pxa 平台就是
    arch/arm/mach-pxa/Makefile.boot 檔案裡面定義的 zreladdr-y
    zreladdr-y   := 0xa0008000
    在實務上我們也可以修改 zreladdr-y 定義的實體記憶體位址,來改成我們想要把 linux kernel
    起始點放在 physical memory 的哪一個位置上。這也就是為何我們從 boot loader 載入 linux
    kernel 都要指定到某個固定實體記憶體位址的原因,因為在 make kernel 時就決定了這個位址。

    PAGE_OFFSET 也就是 linux kernel image 的虛擬位址起始點, 0xC000,0000 3GB 的 user address
    space

    TASK_SIZE ~ PAGE_OFFSET - 1     Kernel module space
    使用 insmod 動態載入的 kernel modules 會在這段記憶體使用動態配置
    arch/arm/include/asm/memory.h 定義
    #define PAGE_OFFSET     UL(CONFIG_PAGE_OFFSET)

    0000,1000 ~ TASK_SIZE - 1       User space mapping
    每個 thread 使用 mmap 對應到這段位置
    arch/arm/include/asm/memory.h 定義
    #define TASK_SIZE         (UL(CONFIG_PAGE_OFFSET) - UL(0x01000000))
    如果 PAGE_OFFSET = 0xC000,0000,則 TASK_SIZE = 0xBF00,0000 (3GB - 16MB)

    0000,0000 ~ 0000,0FFF           cpu vector page, null pointer trap
    不支援中斷向量重新映射的 cpu 會把中斷向量 page 放在這 4K bytes

關於以上作業系統的 Virtual address map 我們可以使用 arch/arm/mach-pxa/generic.c 與 arch/arm/mach-pxa/include/mach/hardware.h 的建立 memory mapped device 跟 chip select memory mapped device 的 Virtual -> Physical mapping

arm 因為使用到 co processor 15,controller register(1th), v bit (13th), 因此用到 vector page relocate 功能,原本會到 0x0000, 0000 找 vector table 的動作改為到 0xffff, 0000 找 vector table,而我們在 mmu 啟動後使用的 0xffff,0000 Virtual address 就是在 arch/arm/mm/mmu.c 的 devicemaps_init() 中將 Linux kernel 開機時在 arch/arm/kernel/entry-armv.S 建立的 vector table 存在 SDRAM 後,建立一組 0xffff, 0000 high vector page 對映到實體記憶體的 vector table,因此 Linux kernel 開機啟動 mmu 進入 virtual address mode 後才能在硬體發出 exception 中斷時,找到 vector table 處理中斷。

2010年5月28日 星期五

linux kernel read_proc() in procfs

在 ~linux/fs/proc/generic.c 中找 __proc_file_read() 的實作可以看到相關說明:
/*
* How to be a proc read function
* ------------------------------
* Prototype:
* int f(char *buffer, char **start, off_t offset,
* int count, int *peof, void *dat)
*
* Assume that the buffer is "count" bytes in size.
*
裡面有三種讀 read_proc 的方式說明,底下就是說明的程式碼,
也可以搜尋其他 driver使用 read_proc 的範例。
比如 ~linux/drivers/char/efirtc.c。
*/
n = dp->read_proc(page, &start, *ppos,
count, &eof, dp->data);
...
這邊是當 kernel 讀取 proc 檔呼叫 driver read_proc callback 的地方,也就是用法。因此可以倒推回去我們的 callback function 如何實作:

第一種是 driver 要回傳的資料量小於 read_proc 中的 buffer size(PAGE_SIZE)。
此時不管 *start,將 driver 要傳給 filesystem 的資料擺在 buffer 的 offset 位置,我們只看 offset 跟上次 callback 讀到的 buffer size, n 的差值,在接到的 offset 跟剩餘要傳的 n 差值(n - offset) 為零時,告知 filesystem 我們的 driver 已經傳完資料,才設定 *peof = 1; 否則繼續 callback。

第二種是當你有大量資料要傳輸時使用。
將 *start 設定為介於 buffer 跟零 之間的值,資料是從 buffer 起始位址開始填,return 每次要填的資料長度,如果你的資料還沒填完,第二次進入 read_proc 時 offset 值會增加 *start 的長度,直到你填完資料後再設定 *peof = 1; 就可以完成傳輸大量資料了。

第三種跟第一種一樣,只是把 offset 代換成 *start

參考文獻:
  1. procfs-guide.pdf 3.1 Reading data
  2. linux kernel source: ~linux/fs/proc/generic.c, ~linux/drivers/char/efirtc.c
  3. Linux Modules (3) - procfs

2010年5月27日 星期四

boot code, bootloader, and Linux Kernel entry points

菠蘿麵包整理了 Android 開機流程 boot sequence
給個 boot rom, bootloader, Linux kernel, Android Init, Zygote, Dalvik,, System Server, 最後發出
ACTION_BOOT_COMPLETED 的 braodcast intent 觸發需要知道開機啟動的服務,其中從
硬體到使用者接觸到的應用程式的完整流程。

我們關注的是前面這段觀念:
硬體平台上的 boot ROM 儲存了 boot code,boot rom 本身也是在記憶體上執行,arm cpu
藉由 reset 0x0000, 0000 由 chip select 線路連結的開機媒介決定到哪一種 storage (Nor flash,
 Nand flash) 去讀取 boot loader。 將 boot loader 載入到實體記憶體後開始執行 boot loader ...

booting sequence documentation 則提到在 bootloader 到 linux kernel 端的開機介面
與流程:

ARM Linux kernel 對 bootloader 所需要的,就是藉由 bootloader 將 Linux kernel 從
storage 讀出載入到記憶體,設定某些暫存器,並呼叫 Linux kernel entry point,此
時還不需要啟動 MMU。

 Linux kernel 的 zImage 壓縮檔,就必須要跳到 arch/arm/boot/compressed/head.S
會使用  arch/arm/boot/compressed/misc.c (抄自 gzip 的某些函式介面) 裡面的
decompress_kernel() 其中會呼叫 arch_decomp_setup() 設定 debug FF/ST uart port,
或特殊的 Chip Select memory mapping,接著在開機印出 "Uncompressing Linux..."
字串後進行解壓縮。

ARM Linux boot sequence

另外關於 arm linux 的開機流程也有人寫了程式碼分析文:
ARM Linux boot sequence

zImage 解壓縮階段:
從跟 boot loader 串接,關閉 cpu cache, MMU, 設定 stack, kernel entry point 在實體
記憶體位置,設定 cpu 型號辨識,啟用 cpu cache, MMU, 設定 MMU page table
將 kernel zImage 解壓縮並載入到 RAM,進入 kernel start...

ARM 相關的 kernel code:
查詢 cpu 型號,啟用多核心支援,查詢(主機)板子的 machine 型號,MACHINE_DESC
macro 的定義。建立 MMU 的 page table,enable MMU,初始化 cache, write buffer。
繼續 enable MMU,設定 page table pointer (TTB),找到 page table 起始點,切換
MMU 進入 virtual address space, 回到已經過 mmap 過的 switch data。

複製 data segment 到 RAM
清空 BSS(寫零)
跳到 start_kernel 開始執行 Linux kernel 開機程序。也就是接 Intel 文件中的 C 程式碼
起始點。 

Linux kernel entry points

Intel 的 device driver debugging 可以找到幾個 Linux kernel source entry point。

開發新平台(OS Adaptation, OS bring up, customize core components)
其中一項重要的工作就是寫驅動程式,有些多媒體編解碼的最佳化,
也是在驅動程式端實作。

一些有用的 kernel 資訊如:active kernel threads, loaded kernel modules

x86 開機流程中 BIOS->OS boot loader --start_kernel()-->OS

sched_init() 是 scheduler initialization

mwait_idle() 是 OS 主要的迴圈(就像 micro controller 的 main loop)


相關連結:

Device Driver Debugging on Intel Atom processor based devices (pdf)

2010年5月8日 星期六

從 gpio & I2C 硬體線路對應到檔案讀寫

0. 硬體電路的 schema
找到電路圖上的 gpio, i2c 線路圖上的 block 是接到 datasheet 上哪一個 slot

1. datasheet 中的 gpio chapter
針對 gpio controller 的 register 值依照 in/out, pull up/down, data 值設定

2. board initial entry point,比如 Samsung s3c6410
~linux/arch/arm/mach-s3c64xx/mach-smdk6410.c
MACHINE_START macro 定義 board information
可以看到註冊的 .init_machine 進入點 function 是 smdk6410_machine_init

Qualcomm 的 arm board initial 檔案則是在
~linux/arch/arm/mach-msm/board-msm7x27.c
定義了 QCT MSM7x2x (7225)
~linux/arch/arm/mach-msm/board-msm7x30.c
定義了 QCT MSM7x30
~linux/arch/arm/mach-msm/board-qsd8x50.c
定義了 QCT QSD8X50 (8250)

3. i2c
關於 i2c 參考 Documentation/i2c/instantiating-devices,可以看到 mach-smdk6410.c 定義兩個 i2c slot 0, 1 為 struct i2c_board_info,裡面定義這個 bus 上接的 i2c slave device(s) 名稱與 slave address 資訊,透過 S3C_EINT 對應到外部中斷 12,然後在 smdk6410_machine_init():

i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

註冊兩個 i2c bus,0 跟 1。接下來 i2c device 的具體化由 i2c core 完成。

kernel driver 可以在 ~linux/drivers/i2c 目錄找到,可以使用 i2c-dev,直接 sudo modprobe -a i2c-dev,就可以在 /dev/i2c-0 存取 i2c bus。

參考 ~linux/Documentation/i2c/dev-interface 可以針對 /dev/i2c-0[1] 的 device file 使用 user space driver 的 ioctl 控制 i2c 設定與傳輸。

最簡單的動作是 ioctl(file, I2C_SLAVE, addr),就直接對 file read(), write() 就可以讀寫 i2c device 資料。

4. gpio
關於取得需要使用的 gpio 方式如下:

gpio_request(S3C64XX_GPN(5), "LCD power");
gpio_request(S3C64XX_GPF(13), "LCD power");
gpio_request(S3C64XX_GPF(15), "LCD power");

這是指取用 GPN pin 5 跟 GPF pin 13, pin 15 操作 LCD power

~linux/Documentation/gpio.txt 可以用 /sys/class/gpio/ 底下針對 gpiochip (controller) 或是 gpioXX (pin) 進行 user driver 的控制 in/out, high/low, trigger mode /sys/class/gpio/gpiochip0/ 中的 label 可以對應到 datasheet 的 controller 名稱,參考 arch/arm/mach-s3c64xx/include/mach/gpio.h 可以找到 S3C64XX_GPA, S3C64XX_GPB 等 gpio controller

S3C64XX_GPIO_A_NR (8) 定義 Bank A 有 8 根 gpio 腳位,依此類推對於 /sys/class/gpio/gpioXX/value read/write 就可以讀取 gpio 腳位high/low 或設定 high/low


2008年2月16日 星期六

linux kernel vmsplice bugs to local root exploit

CVE-2008-0009
CVE-2008-0010
CVE-2008-0600

許久沒看 kernel trap 新聞,結果一翻開就是
bull's eye ,linux kernel local root exploit @@

0009 是 fs/splice.c 中 vmsplice_to_user() 並
未檢查 user space pointer 指向的資料,使用
者可能被用來存取 kernel space 的任意記憶體
位置。

0010 是 位於 fs/splice.c 的
copy_from_user_mmap_sem() 未檢查 user
space pointer 指向的資料,使用者程式可能
被用來取得 root 權限。

0600 是 vmsplice_to_pipe() 未檢查 user space
pointer 指向的資料,使用者程式可能被用
來取得 root 權限。