Linux Device Driver >> Assembly (ARM) >> chrdev
read、write
參考資訊:
1. ldd
2. 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()
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: 刪除字元驅動程式
在做arm_copy_to_user()、arm_copy_from_user()之前,必須先設定Domain Access Control Register
寫入字串
# echo "test" > /dev/myfile mywrite, test
P.S. 按下Ctrl+C停止
讀取字串
# cat /dev/myfile myopen myread, test myclose