Steward
分享是一種喜悅、更是一種幸福
驅動程式 - Linux Device Driver (LDD) - 使用範例 - Assembly (ARM) - Char Device - File Read/Write
參考資訊:
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | . 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