Hello, world!是一個相當經典的入門教學範例,從這個範例的框架,使用者可以一探Linux Kernel的精簡之美,當然,它主要表達的目的,更多是對於操作環境的熟悉
ldd.S
.set noreorder .global init_module .global cleanup_module .macro push arg:req addiu $sp, -4 sw \arg, 0($sp) .endm .macro pop arg:req lw \arg, 0($sp) addiu $sp, 4 .endm .section .modinfo, "ae" __UNIQUE_ID_0: .asciz "license=GPL" __UNIQUE_ID_1: .asciz "author=Steward Fu" __UNIQUE_ID_2: .asciz "description=Linux Driver" .section .text msg_load: .asciz "Hello, world!\n" msg_unload: .asciz "Unload it\n" .align 2 .section .text init_module: push $ra la $a0, msg_load jal printk nop pop $ra jr $ra move $v0, $0 cleanup_module: push $ra la $a0, msg_unload jal printk nop pop $ra jr $ra move $v0, $0
init_module: 系統載入驅動程式時,第一時間呼叫使用
cleanup_module: 卸載驅動程式時,最後時間被系統呼叫使用
MIPS Assembly最擾人的地方就屬Branch Delay Slot,意思就是,執行Branch指令後,它的下一個指令會先被執行,然後才執行Branch指令(延遲一個指令),這也是為何jal printk後面要有一個nop,如果沒有加這個nop,pop $ra就會被執行,導致呼叫printk後,無法回到正常的位置,而jr $ra指令後面的move $v0, $0也是這樣的意思,這是由於MIPS架構因素所致,剛接觸MIPS Assembly的使用者需要特別注意這個問題
Makefile
export ARCH=mips export CROSS_COMPILE=/opt/gcc-8.30/bin/mipsel-linux- export AS=${CROSS_COMPILE}as KERNEL=$(HOME)/kernel obj-m += main.o main-objs:= ldd.o all: $(AS) -o ldd.o ldd.S -msoft-float make -C $(KERNEL) M=$(PWD) modules clean: make -C $(KERNEL) M=$(PWD) clean
編譯
$ make mipsel-linux-as -o ldd.o ldd.S make -C kernel M=hello modules make[1]: Entering directory 'kernel' AS [M] hello/ldd.o LD [M] hello/main.o Building modules, stage 2. MODPOST 1 modules CC hello/main.mod.o LD [M] hello/main.ko make[1]: Leaving directory 'kernel'
接著複製main.ko到USB隨身碟,將USB插入開發板,開機進入系統後,執行如下指令掛載驅動程式
# insmod /mnt/main.ko Hello, world!
卸載驅動程式
# rmmod main Unload it