最近被問到Linux的驅動如何寫,想起以前在樹莓派上安裝無線網卡驅動編譯了很久最後加載Module。NuttX也是支持Module加載的。這樣我就可以不用燒錄固件使它打開某個串口或者SPI啥的。
首先,example裏有模塊的例子。menuconfig中開啓:
> RTOS Features > [Y] Enable loadable OS modules
> File Systems > [Y] ROMFS file system
> Binary Loader > [Y] Enable the ELF Binary Format
> Application Configuration > Examples > [Y] Module Example
> Application Configuration > Examples > [Y] Built-in File System
編譯運行,發現報錯
chardev.c:40:26: fatal error: nuttx/config.h: No such file or directory
順便,報錯之後再用單線程編譯,這樣好找錯誤源頭。
make[5]: Entering directory ‘/home/godenfreemans/NuttX/apps/examples/module/drivers/chardev’
CC: chardev.c
chardev.c:40:26: fatal error: nuttx/config.h: No such file or directory
#include <nuttx/config.h>
^
compilation terminated.
這個文件就是Module例子中的。明顯是找不到配置文件。說明它的makefile裏沒有包含配置文件,設置-D後編譯依舊出錯。詢問了Nutt後,得到解決方法:
在apps/examples/module/drivers/chardev
下創建文件Make.defs 寫入內容:
# ELF kernael module definitions
CMODULEFLAGS = $(CFLAGS) -mlong-calls # --target1-abs
LDMODULEFLAGS = -r -e module_initialize
ifeq ($(WINTOOL),y)
LDMODULEFLAGS += -T "${shell cygpath -w
$(TOPDIR)/libs/libc/modlib/gnu-elf.ld}"
else
LDMODULEFLAGS += -T $(TOPDIR)/libs/libc/modlib/gnu-elf.ld
endif
在Make file開頭添加
include Make.defs
再編譯就通過了。
再次運行,出錯。
ERROR: insmod(/mnt/romfs/chardev, chardev) failed: 22
追溯一下,
apps\examples\module\module_main.c:295
handle = insmod(BINDIR "/chardev", "chardev");
是在調用這個函數的時候出現了問題,再往裏發現了一個類似調試輸出的東西
berr("ERROR: Failed to initialize to load module: %d\n", ret);
查找定義,發現是這麼個東西:
#ifdef CONFIG_DEBUG_BINFMT_ERROR
# define berr _err
#else
# define berr (void)
#endif
看起來需要我定義CONFIG_DEBUG_BINFMT_ERROR
了。
menuconfig中查找一下,按照順序開啓
> Build Setup > Debug Options > [Y] Enable Debug Features
> Build Setup > Debug Options > [Y] Enable Error Output
> Build Setup > Debug Options > [Y] Enable Warnings Output
> Build Setup > Debug Options > [Y] Enable Informational Debug Output
> Build Setup > Debug Options > [Y] Binary Loader Debug Features
> Build Setup > Debug Options > [Y] Binary Loader Error Output
> Build Setup > Debug Options > [Y] Binary Loader Warnings Output
再次編譯運行。依然是錯誤,不過這回顯示了最初生成錯誤的地方。對代碼分析半天無果。
感覺代碼有問題,git checkout .
後,居然正常了。。。
nsh>module
main: Registering romdisk at /dev/ram0
main: Mounting ROMFS filesystem at target=/mnt/romfs with source=/dev/ram0
insmod: Loading file: /mnt/romfs/chardev
modlib_initialize: filename: /mnt/romfs/chardev loadinfo: 200040ec
modlib_read: Read 52 bytes from offset 0
mod_dumploadinfo: LOAD_INFO:
mod_dumploadinfo: textalloc: 00000000
mod_dumploadinfo: datastart: 00000000
mod_dumploadinfo: textsize: 0
mod_dumploadinfo: datasize: 0
mod_dumploadinfo: filelen: 2204
mod_dumploadinfo: filfd: 3
mod_dumploadinfo: symtabidx: 0
mod_dumploadinfo: strtabidx: 0
mod_dumploadinfo: ELF Header:
mod_dumploadinfo: e_ident: 7f 45 4c 46
mod_dumploadinfo: e_type: 0001
mod_dumploadinfo: e_machine: 0028
mod_dumploadinfo: e_version: 00000001
mod_dumploadinfo: e_entry: 000000a9
mod_dumploadinfo: e_phoff: 0
mod_dumploadinfo: e_shoff: 1724
mod_dumploadinfo: e_flags: 05000000
mod_dumploadinfo: e_ehsize: 52
mod_dumploadinfo: e_phentsize: 0
mod_dumploadinfo: e_phnum: 0
mod_dumploadinfo: e_shentsize: 40
mod_dumploadinfo: e_shnum: 12
mod_dumploadinfo: e_shstrndx: 9
modlib_load: loadinfo: 200040ec
modlib_read: Read 480 bytes from offset 1724
modlib_loadfile: Loaded sections:
modlib_read: Read 236 bytes from offset 52
modlib_loadfile: 1. 00000000->20004570
modlib_read: Read 244 bytes from offset 288
modlib_loadfile: 3. 000000ec->2000465c
modlib_read: Read 0 bytes from offset 532
modlib_loadfile: 5. 000001e0->20004750
modlib_loadfile: 6. 000001e0->20004750
mod_dumploadinfo: LOAD_INFO:
mod_dumploadinfo: textalloc: 20004570
mod_dumploadinfo: datastart: 20004750
mod_dumploadinfo: textsize: 480
mod_dumploadinfo: datasize: 0
mod_dumploadinfo: filelen: 2204
mod_dumploadinfo: filfd: 3
mod_dumploadinfo: symtabidx: 0
mod_dumploadinfo: strtabidx: 0
mod_dumploadinfo: ELF Header:
mod_dumploadinfo: e_ident: 7f 45 4c 46
mod_dumploadinfo: e_type: 0001
mod_dumploadinfo: e_machine: 0028
mod_dumploadinfo: e_version: 00000001
mod_dumploadinfo: e_entry: 000000a9
mod_dumploadinfo: e_phoff: 0
mod_dumploadinfo: e_shoff: 1724
mod_dumploadinfo: e_flags: 05000000
mod_dumploadinfo: e_ehsize: 52
mod_dumploadinfo: e_phentsize: 0
mod_dumploadinfo: e_phnum: 0
mod_dumploadinfo: e_shentsize: 40
mod_dumploadinfo: e_shnum: 12
mod_dumploadinfo: e_shstrndx: 9
mod_dumploadinfo: Sections 0:
mod_dumploadinfo: sh_name: 00000000
mod_dumploadinfo: sh_type: 00000000
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 0
mod_dumploadinfo: sh_size: 0
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 0
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 1:
mod_dumploadinfo: sh_name: 0000001f
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000006
mod_dumploadinfo: sh_addr: 20004570
mod_dumploadinfo: sh_offset: 52
mod_dumploadinfo: sh_size: 236
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 2:
mod_dumploadinfo: sh_name: 0000001b
mod_dumploadinfo: sh_type: 00000009
mod_dumploadinfo: sh_flags: 00000040
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1452
mod_dumploadinfo: sh_size: 168
mod_dumploadinfo: sh_link: 10
mod_dumploadinfo: sh_info: 1
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 8
mod_dumploadinfo: Sections 3:
mod_dumploadinfo: sh_name: 00000029
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000002
mod_dumploadinfo: sh_addr: 2000465c
mod_dumploadinfo: sh_offset: 288
mod_dumploadinfo: sh_size: 244
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 4:
mod_dumploadinfo: sh_name: 00000025
mod_dumploadinfo: sh_type: 00000009
mod_dumploadinfo: sh_flags: 00000040
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1620
mod_dumploadinfo: sh_size: 16
mod_dumploadinfo: sh_link: 10
mod_dumploadinfo: sh_info: 3
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 8
mod_dumploadinfo: Sections 5:
mod_dumploadinfo: sh_name: 00000031
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000003
mod_dumploadinfo: sh_addr: 20004750
mod_dumploadinfo: sh_offset: 532
mod_dumploadinfo: sh_size: 0
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 6:
mod_dumploadinfo: sh_name: 00000037
mod_dumploadinfo: sh_type: 00000008
mod_dumploadinfo: sh_flags: 00000003
mod_dumploadinfo: sh_addr: 20004750
mod_dumploadinfo: sh_offset: 532
mod_dumploadinfo: sh_size: 0
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 7:
mod_dumploadinfo: sh_name: 0000003c
mod_dumploadinfo: sh_type: 00000001
mod_dumploadinfo: sh_flags: 00000030
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 532
mod_dumploadinfo: sh_size: 50
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 1
mod_dumploadinfo: Sections 8:
mod_dumploadinfo: sh_name: 00000045
mod_dumploadinfo: sh_type: 70000003
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 582
mod_dumploadinfo: sh_size: 57
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 9:
mod_dumploadinfo: sh_name: 00000011
mod_dumploadinfo: sh_type: 00000003
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1636
mod_dumploadinfo: sh_size: 85
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
mod_dumploadinfo: Sections 10:
mod_dumploadinfo: sh_name: 00000001
mod_dumploadinfo: sh_type: 00000002
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 640
mod_dumploadinfo: sh_size: 592
mod_dumploadinfo: sh_link: 11
mod_dumploadinfo: sh_info: 20
mod_dumploadinfo: sh_addralign: 4
mod_dumploadinfo: sh_entsize: 16
mod_dumploadinfo: Sections 11:
mod_dumploadinfo: sh_name: 00000009
mod_dumploadinfo: sh_type: 00000003
mod_dumploadinfo: sh_flags: 00000000
mod_dumploadinfo: sh_addr: 00000000
mod_dumploadinfo: sh_offset: 1232
mod_dumploadinfo: sh_size: 218
mod_dumploadinfo: sh_link: 0
mod_dumploadinfo: sh_info: 0
mod_dumploadinfo: sh_addralign: 1
mod_dumploadinfo: sh_entsize: 0
modlib_bind: INFO: modlib_relocate(modp, loadinfo, 2)
modlib_read: Read 8 bytes from offset 1452
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=2000458c [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1460
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004590 [00000044] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1468
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004594 [00000065] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1476
modlib_read: Read 16 bytes from offset 976
modlib_read: Read 128 bytes from offset 1286
modlib_symvalue: SHN_ABS: name=lib_dumpbuffer 00000000+0800f2b1=0800f2b1
up_relocate: Performing ABS32 link at addr=20004598 [00000000] to sym=200040b0 st_value=0800f2b1
modlib_read: Read 8 bytes from offset 1484
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=200045d4 [00000000] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1492
modlib_read: Read 16 bytes from offset 1200
modlib_read: Read 128 bytes from offset 1434
modlib_symvalue: SHN_ABS: name=strlen 00000000+080031cd=080031cd
up_relocate: Performing ABS32 link at addr=200045d8 [00000000] to sym=200040b0 st_value=080031cd
modlib_read: Read 8 bytes from offset 1500
modlib_read: Read 16 bytes from offset 1040
modlib_read: Read 128 bytes from offset 1330
modlib_symvalue: SHN_ABS: name=memcpy 00000000+080031dd=080031dd
up_relocate: Performing ABS32 link at addr=200045dc [00000000] to sym=200040b0 st_value=080031dd
modlib_read: Read 8 bytes from offset 1508
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=200045e0 [0000007c] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1516
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=200045e4 [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1524
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=200045e8 [0000009e] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1532
modlib_read: Read 16 bytes from offset 976
modlib_read: Read 128 bytes from offset 1286
modlib_symvalue: SHN_ABS: name=lib_dumpbuffer 00000000+0800f2b1=0800f2b1
up_relocate: Performing ABS32 link at addr=200045ec [00000000] to sym=200040b0 st_value=0800f2b1
modlib_read: Read 8 bytes from offset 1540
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=20004608 [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1548
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=2000460c [000000b6] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1556
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004610 [000000d3] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1564
modlib_read: Read 16 bytes from offset 1088
modlib_read: Read 128 bytes from offset 1353
modlib_symvalue: SHN_ABS: name=unregister_driver 00000000+08009363=08009363
up_relocate: Performing ABS32 link at addr=20004614 [00000000] to sym=200040b0 st_value=08009363
modlib_read: Read 8 bytes from offset 1572
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004644 [000000e0] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1580
modlib_read: Read 16 bytes from offset 1136
modlib_read: Read 128 bytes from offset 1395
modlib_symvalue: SHN_ABS: name=syslog 00000000+08003219=08003219
up_relocate: Performing ABS32 link at addr=20004648 [00000000] to sym=200040b0 st_value=08003219
modlib_read: Read 8 bytes from offset 1588
modlib_read: Read 16 bytes from offset 784
modlib_symvalue: Other: 00000081+20004570=200045f1
up_relocate: Performing ABS32 link at addr=2000464c [00000000] to sym=200040b0 st_value=200045f1
modlib_read: Read 8 bytes from offset 1596
modlib_read: Read 16 bytes from offset 960
modlib_read: Read 128 bytes from offset 1355
modlib_symvalue: SHN_ABS: name=register_driver 00000000+08009331=08009331
up_relocate: Performing ABS32 link at addr=20004650 [00000000] to sym=200040b0 st_value=08009331
modlib_read: Read 8 bytes from offset 1604
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004654 [00000028] to sym=200040b0 st_value=2000465c
modlib_read: Read 8 bytes from offset 1612
modlib_read: Read 16 bytes from offset 656
modlib_symvalue: Other: 00000000+2000465c=2000465c
up_relocate: Performing ABS32 link at addr=20004658 [000000d3] to sym=200040b0 st_value=2000465c
modlib_bind: INFO: modlib_relocate(modp, loadinfo, 4)
modlib_read: Read 8 bytes from offset 1620
modlib_read: Read 16 bytes from offset 736
modlib_symvalue: Other: 0000002d+20004570=2000459d
up_relocate: Performing ABS32 link at addr=2000468c [00000000] to sym=200040b0 st_value=2000459d
modlib_read: Read 8 bytes from offset 1628
modlib_read: Read 16 bytes from offset 688
modlib_symvalue: Other: 00000001+20004570=20004571
up_relocate: Performing ABS32 link at addr=20004690 [00000000] to sym=200040b0 st_value=20004571
module_initialize:
chardev_read: Returning 36 bytes
chardev_read: Returning (20004168):
0000: 48692074686572652c20617070732f65 78616d706c65732f6d6f64756c652074 Hi there, apps/e xamples/module t
0020: 6573740a est.
main: Read 36 bytes: 196
main: Bytes read (20004168):
0000: 48692074686572652c20617070732f65 78616d706c65732f6d6f64756c652074 Hi there, apps/e xamples/module t
0020: 6573740a est.
chardev_write: Writing 27 bytes
chardev_write: Writing (801400f):
0000: 48692074686572652c20696e7374616c 6c6564206472697665720a Hi there, instal led driver.
main: Wrote 27 bytes: 102
main: Bytes written (801400f):
0000: 48692074686572652c20696e7374616c 6c6564206472697665720a Hi there, instal led driver.
module_uninitialize: arg=0
可以看到,這個例子先掛載了一個ramdisk,這個ramdisk裏的內容就是chardev的模塊文件,接下來掛載了名爲chardev
的設備。但是在測試完成後居然卸載了模塊!這怎麼能行,我要用lsmod
查看模塊啊。下面手動掛載模塊。
insmod /mnt/romfs/chardev chardev
注意。這裏使用的是絕對路徑,如果使用相對路徑的話會出錯。或許是有什麼參數沒有開啓吧。
經過一長串的調試信息後,沒有報錯。應該是成功了。
nsh>ls /dev
/dev:
chardev
console
null
ram0
timer1
timer2
timer3
timer4
timer5
ttyS0
zero
nsh>lsmod
NAME INIT UNINIT ARG NEXPORTS TEXT SIZE DATA SIZE
chardev 200038c9 200038a1 0 0 20003820 480 20003a00 0
nsh>rmmod chardev
module_uninitialize: arg=0
nsh>ls /dev
/dev:
console
null
ram0
timer1
timer2
timer3
timer4
timer5
ttyS0
zero
nsh>lsmod
NAME INIT UNINIT ARG NEXPORTS TEXT SIZE DATA SIZE
nsh>
完全可以。沒有問題。
下來分析這個模塊的寫法。