驅動程式 - 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