參考資訊:
https://www.aps-web.jp/en/ca-en/21578/#anchor2
User Application可以透過read()、write()傳送資料給驅動程式,但是需要注意的地方是,在Linux Kernel中,如果要存取User Application傳送過來的資料時,必須使用copy_to_user()、copy_from_user(),而不是一般的memcpy()或者直接指標操作,否則會導致驅動程式崩潰,這是因為Linux Kernel和User Application是位於不同保護空間,因此,在存取User Application資料時,必須確保該資料已經被Map且位於記憶體
使用方式:
1. arm_copy_to_user() 2. arm_copy_from_user()
在做arm_copy_to_user()、arm_copy_from_user()之前,必須先設定Domain Access Control Register
ldd.S
.global init_module
.global cleanup_module
.section .modinfo, "ae"
__UNIQUE_ID_0: .asciz "license=GPL"
__UNIQUE_ID_1: .asciz "author=Steward Fu"
__UNIQUE_ID_2: .asciz "description=Linux Driver"
.equ cdev.kobj, 0
.equ cdev.owner, 36
.equ cdev.ops, 40
.equ cdev.list, 44
.equ cdev.dev, 52
.equ cdev.count, 56
.struct 0
cdev_s:
c0: .struct . + 36
c1: .struct . + 4
c2: .struct . + 4
c3: .struct . + 8
c4: .struct . + 4
c5: .struct . + 4
cdev_e:
cdev_l = cdev_e - cdev_s
.equ file_operations.owner, 0
.equ file_operations.llseek, 4
.equ file_operations.read, 8
.equ file_operations.write, 12
.equ file_operations.read_iter, 16
.equ file_operations.write_iter, 20
.equ file_operations.iterate, 24
.equ file_operations.iterate_shared, 28
.equ file_operations.poll, 32
.equ file_operations.unlocked_ioctl, 36
.equ file_operations.compat_ioctl, 40
.equ file_operations.mmap, 44
.equ file_operations.open, 48
.equ file_operations.flush, 52
.equ file_operations.release, 56
.equ file_operations.fsync, 60
.equ file_operations.fasync, 64
.equ file_operations.lock, 68
.equ file_operations.sendpage, 72
.equ file_operations.get_unmapped_area, 76
.equ file_operations.check_flags, 80
.equ file_operations.setfl, 84
.equ file_operations.flock, 88
.equ file_operations.splice_write, 92
.equ file_operations.splice_read, 96
.equ file_operations.setlease, 100
.equ file_operations.fallocate, 104
.equ file_operations.show_fdinfo, 108
.equ file_operations.mmap_capabilities, 112
.equ file_operations.copy_file_range, 116
.equ file_operations.clone_file_range, 120
.equ file_operations.dedupe_file_range, 124
.struct 0
file_operations_s:
i0: .struct . + 4
i1: .struct . + 4
i2: .struct . + 4
i3: .struct . + 4
i4: .struct . + 4
i5: .struct . + 4
i6: .struct . + 4
i7: .struct . + 4
i8: .struct . + 4
i9: .struct . + 4
i10: .struct . + 4
i11: .struct . + 4
i12: .struct . + 4
i13: .struct . + 4
i14: .struct . + 4
i15: .struct . + 4
i16: .struct . + 4
i17: .struct . + 4
i18: .struct . + 4
i19: .struct . + 4
i20: .struct . + 4
i21: .struct . + 4
i22: .struct . + 4
i23: .struct . + 4
i24: .struct . + 4
i25: .struct . + 4
i26: .struct . + 4
i27: .struct . + 4
i28: .struct . + 4
i29: .struct . + 4
i30: .struct . + 4
i31: .struct . + 4
file_operations_e:
file_operations_l = file_operations_e - file_operations_s
.section .data
base: .dcb 4
mycdev: .space cdev_l
myfops: .space file_operations_l
chr_name: .asciz "myfile"
open_msg: .asciz "myopen\n"
write_msg: .asciz "mywrite, %s\n"
read_msg: .asciz "myread, %s\n"
close_msg: .asciz "myclose\n"
myclass: .dcb 4
mybuf: .dcb 255
.align 2
.section .text
myopen:
push {lr}
ldr r0, =open_msg
bl printk
mov r0, #0
pop {pc}
myread:
push {r4, lr}
mov r4, r1
ldr r0, =mybuf
bl strlen
mov r2, r0
ldr r0, =0x55555555
mcr p15, 0, r0, c3, c0, 0
isb sy
mov r0, r4
ldr r1, =mybuf
bl arm_copy_to_user
mov r4, r0
ldr r0, =read_msg
ldr r1, =mybuf
bl printk
mov r0, r4
pop {r4, pc}
mywrite:
push {r4, lr}
ldr r0, =0x55555555
mcr p15, 0, r0, c3, c0, 0
isb sy
ldr r0, =mybuf
bl arm_copy_from_user
mov r4, r0
ldr r0, =write_msg
ldr r1, =mybuf
bl printk
mov r0, r4
pop {r4, pc}
myclose:
push {lr}
ldr r0, =close_msg
bl printk
mov r0, #0
pop {pc}
init_module:
push {r4, r5, lr}
ldr r0, =myfops
add r1, r0, #file_operations.open
ldr r2, =myopen
str r2, [r1]
add r1, r0, #file_operations.release
ldr r2, =myclose
str r2, [r1]
add r1, r0, #file_operations.read
ldr r2, =myread
str r2, [r1]
add r1, r0, #file_operations.write
ldr r2, =mywrite
str r2, [r1]
ldr r0, =base
mov r1, #0
mov r2, #1
ldr r3, =chr_name
bl alloc_chrdev_region
ldr r4, =base
mov r0, #0
ldr r1, =chr_name
ldr r2, =myclass
bl __class_create
ldr r1, =myclass
str r0, [r1]
mov r1, #0
ldr r2, [r4]
mov r3, #0
ldr r5, =chr_name
push {r5}
bl device_create
pop {r5}
ldr r0, =mycdev
ldr r1, =myfops
bl cdev_init
ldr r0, =mycdev
ldr r1, [r4]
mov r2, #1
bl cdev_add
mov r0, #0
pop {r4, r5, pc}
cleanup_module:
push {lr}
ldr r0, =myclass
ldr r0, [r0]
ldr r1, =base
ldr r1, [r1]
bl device_destroy
ldr r0, =mycdev
bl cdev_del
ldr r0, =myclass
ldr r0, [r0]
bl class_destroy
ldr r0, =base
ldr r0, [r0]
mov r1, #1
bl unregister_chrdev_region
pop {pc}
.end
init_module: 建立字元驅動程式
myopen: 僅列印字串
mywrite: 儲存並且列印User Application傳送的字串
myread: 複製儲存的字串給User Application並且列印出來
myclose: 僅列印字串
cleanup_module: 刪除字元驅動程式
寫入字串
# echo "test" > /dev/myfile
mywrite, test
P.S. 按下Ctrl+C停止
讀取字串
# cat /dev/myfile
myopen
myread, test
myclose