Subversion Repositories Kolibri OS

Rev

Rev 2644 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2644 Rev 5044
1
; Disk driver to create FAT16/FAT32 memory-based temporary disk aka RAM disk.
1
; Disk driver to create FAT16/FAT32 memory-based temporary disk aka RAM disk.
2
; (c) CleverMouse
2
; (c) CleverMouse
3
 
3
 
4
; Note: in the ideal world, a disk driver should not care about a file system
4
; Note: in the ideal world, a disk driver should not care about a file system
5
; on it. In the current world, however, there is no way to format a disk in
5
; on it. In the current world, however, there is no way to format a disk in
6
; FAT, so this part of file-system-specific operations is included in the
6
; FAT, so this part of file-system-specific operations is included in the
7
; driver.
7
; driver.
8
 
8
 
9
; When this driver is loading, it registers itself in the system and does
9
; When this driver is loading, it registers itself in the system and does
10
; nothing more. When loaded, this driver controls pseudo-disk devices
10
; nothing more. When loaded, this driver controls pseudo-disk devices
11
; named /tmp#/, where # is a digit from 0 to 9. The driver does not create
11
; named /tmp#/, where # is a digit from 0 to 9. The driver does not create
12
; any device by itself, waiting for instructions from an application.
12
; any device by itself, waiting for instructions from an application.
13
; The driver responds to the following IOCTLs from a control application:
13
; The driver responds to the following IOCTLs from a control application:
14
SRV_GETVERSION          equ 0 ; input ignored,
14
SRV_GETVERSION          equ 0 ; input ignored,
15
                              ; output = dword API_VERSION
15
                              ; output = dword API_VERSION
16
DEV_ADD_DISK            equ 1 ; input = structure add_disk_struc,
16
DEV_ADD_DISK            equ 1 ; input = structure add_disk_struc,
17
                              ; no output
17
                              ; no output
18
DEV_DEL_DISK            equ 2 ; input = structure del_disk_struc,
18
DEV_DEL_DISK            equ 2 ; input = structure del_disk_struc,
19
                              ; no output
19
                              ; no output
20
; For all IOCTLs the driver returns one of the following error codes:
20
; For all IOCTLs the driver returns one of the following error codes:
21
NO_ERROR                equ 0
21
NO_ERROR                equ 0
22
ERROR_INVALID_IOCTL     equ 1 ; unknown IOCTL code, wrong input/output size...
22
ERROR_INVALID_IOCTL     equ 1 ; unknown IOCTL code, wrong input/output size...
23
ERROR_INVALID_ID        equ 2 ; .DiskId must be from 0 to 9
23
ERROR_INVALID_ID        equ 2 ; .DiskId must be from 0 to 9
24
ERROR_SIZE_TOO_LARGE    equ 3 ; .DiskSize is too large
24
ERROR_SIZE_TOO_LARGE    equ 3 ; .DiskSize is too large
25
ERROR_SIZE_TOO_SMALL    equ 4 ; .DiskSize is too small
25
ERROR_SIZE_TOO_SMALL    equ 4 ; .DiskSize is too small
26
ERROR_NO_MEMORY         equ 5 ; memory allocation failed
26
ERROR_NO_MEMORY         equ 5 ; memory allocation failed
-
 
27
 
27
 
28
include '../struct.inc'
28
 
29
 
29
API_VERSION             equ 1
30
API_VERSION             equ 1
30
; Input structures:
31
; Input structures:
31
struc add_disk_struc
32
struct add_disk_struc
32
{
-
 
33
.DiskSize       dd      ? ; disk size in sectors, 1 sector = 512 bytes
33
DiskSize        dd      ? ; disk size in sectors, 1 sector = 512 bytes
34
; Note: .DiskSize is the full size, including FAT service data.
34
; Note: DiskSize is the full size, including FAT service data.
35
; Size for useful data is slightly less than this number.
35
; Size for useful data is slightly less than this number.
36
.DiskId         db      ? ; from 0 to 9
36
DiskId          db      ? ; from 0 to 9
37
.sizeof:
-
 
38
}
-
 
39
virtual at 0
-
 
40
add_disk_struc  add_disk_struc
-
 
41
end virtual
37
ends
42
struc del_disk_struc
38
struct del_disk_struc
43
{
-
 
44
.DiskId         db      ? ; from 0 to 9
39
DiskId          db      ? ; from 0 to 9
45
.sizeof:
-
 
46
}
-
 
47
virtual at 0
-
 
48
del_disk_struc del_disk_struc
-
 
49
end virtual
40
ends
50
 
41
 
51
max_num_disks   equ     10
42
max_num_disks   equ     10
52
 
43
 
53
; standard driver stuff
44
; standard driver stuff; version of driver model = 5
54
format MS COFF
45
format PE DLL native 0.05
55
 
-
 
56
DEBUG equ 0
-
 
-
 
46
 
57
include 'proc32.inc'
47
DEBUG equ 0
58
include 'imports.inc'
48
 
59
 
-
 
60
public START
49
section '.flat' code readable writable executable
61
public version
-
 
62
 
-
 
63
struc IOCTL
-
 
64
{
50
data fixups
65
        .handle         dd ?
51
end data
66
        .io_code        dd ?
-
 
67
        .input          dd ?
-
 
68
        .inp_size       dd ?
-
 
69
        .output         dd ?
-
 
70
        .out_size       dd ?
-
 
71
}
-
 
72
 
-
 
73
virtual at 0
-
 
74
IOCTL IOCTL
52
entry START
75
end virtual
53
include '../proc32.inc'
76
 
54
include '../peimport.inc'
77
section '.flat' code readable align 16
55
include '../macros.inc'
78
; the start procedure (see the description above)
56
; the start procedure (see the description above)
79
proc START
57
proc START
80
; This procedure is called in two situations:
58
; This procedure is called in two situations:
81
; when the driver is loading and when the system is shutting down.
59
; when the driver is loading and when the system is shutting down.
82
; 1. Check that the driver is loading; do nothing unless so.
60
; 1. Check that the driver is loading; do nothing unless so.
83
        xor     eax, eax ; set return value in case we will do nothing
61
        xor     eax, eax ; set return value in case we will do nothing
84
        cmp     dword [esp+4], 1
62
        cmp     dword [esp+4], 1
85
        jne     .nothing
63
        jne     .nothing
86
; 2. Register the driver in the system.
64
; 2. Register the driver in the system.
87
        stdcall RegService, my_service, service_proc
65
        invoke  RegService, my_service, service_proc
88
; 3. Return the value returned by RegService back to the system.
66
; 3. Return the value returned by RegService back to the system.
89
.nothing:
67
.nothing:
90
        retn    4
68
        retn
91
endp
69
endp
92
 
70
 
93
; Service procedure for the driver - handle all IOCTL requests for the driver.
71
; Service procedure for the driver - handle all IOCTL requests for the driver.
94
; The description of handled IOCTLs is located in the start of this file.
72
; The description of handled IOCTLs is located in the start of this file.
95
proc service_proc
73
proc service_proc
96
; 1. Save used registers to be stdcall.
74
; 1. Save used registers to be stdcall.
97
; Note: this shifts esp, so the first parameter [esp+4] becomes [esp+16].
75
; Note: this shifts esp, so the first parameter [esp+4] becomes [esp+16].
98
; Note: edi is used not by this procedure itself, but by worker procedures.
76
; Note: edi is used not by this procedure itself, but by worker procedures.
99
        push    ebx esi edi
77
        push    ebx esi edi
100
; 2. Get parameter from the stack: [esp+16] is the first parameter,
78
; 2. Get parameter from the stack: [esp+16] is the first parameter,
101
;    pointer to IOCTL structure.
79
;    pointer to IOCTL structure.
102
        mov     edx, [esp+16]    ; edx -> IOCTL
80
        mov     edx, [esp+16]    ; edx -> IOCTL
103
; 3. Set the return value to 'invalid IOCTL'.
81
; 3. Set the return value to 'invalid IOCTL'.
104
; Now, if one of conditions for IOCTL does not met, the code
82
; Now, if one of conditions for IOCTL does not met, the code
105
; can simply return the value already loaded.
83
; can simply return the value already loaded.
106
        mov     al, ERROR_INVALID_IOCTL
84
        mov     al, ERROR_INVALID_IOCTL
107
; 4. Get request code and select a handler for the code.
85
; 4. Get request code and select a handler for the code.
108
        mov     ecx, [edx+IOCTL.io_code]
86
        mov     ecx, [edx+IOCTL.io_code]
109
        test    ecx, ecx        ; check for SRV_GETVERSION
87
        test    ecx, ecx        ; check for SRV_GETVERSION
110
        jnz     .no.srv_getversion
88
        jnz     .no.srv_getversion
111
; 4. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION.
89
; 4. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION.
112
; 4a. Output size must be at least 4 bytes.
90
; 4a. Output size must be at least 4 bytes.
113
        cmp     [edx+IOCTL.out_size], 4
91
        cmp     [edx+IOCTL.out_size], 4
114
        jl      .return
92
        jl      .return
115
; 4b. Write result to the output buffer.
93
; 4b. Write result to the output buffer.
116
        mov     eax, [edx+IOCTL.output]
94
        mov     eax, [edx+IOCTL.output]
117
        mov     dword [eax], API_VERSION
95
        mov     dword [eax], API_VERSION
118
; 4c. Return success.
96
; 4c. Return success.
119
        xor     eax, eax
97
        xor     eax, eax
120
        jmp     .return
98
        jmp     .return
121
.no.srv_getversion:
99
.no.srv_getversion:
122
        dec     ecx     ; check for DEV_ADD_DISK
100
        dec     ecx     ; check for DEV_ADD_DISK
123
        jnz     .no.dev_add_disk
101
        jnz     .no.dev_add_disk
124
; 5. This is DEV_ADD_DISK request, input is add_disk_struc, output is 1 byte
102
; 5. This is DEV_ADD_DISK request, input is add_disk_struc, output is 1 byte
125
; 5a. Input size must be exactly add_disk_struc.sizeof bytes.
103
; 5a. Input size must be exactly sizeof.add_disk_struc bytes.
126
        cmp     [edx+IOCTL.inp_size], add_disk_struc.sizeof
104
        cmp     [edx+IOCTL.inp_size], sizeof.add_disk_struc
127
        jnz     .return
105
        jnz     .return
128
; 5b. Load input parameters and call the worker procedure.
106
; 5b. Load input parameters and call the worker procedure.
129
        mov     eax, [edx+IOCTL.input]
107
        mov     eax, [edx+IOCTL.input]
130
        movzx   ebx, [eax+add_disk_struc.DiskId]
108
        movzx   ebx, [eax+add_disk_struc.DiskId]
131
        mov     esi, [eax+add_disk_struc.DiskSize]
109
        mov     esi, [eax+add_disk_struc.DiskSize]
132
        call    add_disk
110
        call    add_disk
133
; 5c. Return back to the caller the value from the worker procedure.
111
; 5c. Return back to the caller the value from the worker procedure.
134
        jmp     .return
112
        jmp     .return
135
.no.dev_add_disk:
113
.no.dev_add_disk:
136
        dec     ecx     ; check for DEV_DEL_DISK
114
        dec     ecx     ; check for DEV_DEL_DISK
137
        jnz     .return
115
        jnz     .return
138
; 6. This is DEV_DEL_DISK request, input is del_disk_struc
116
; 6. This is DEV_DEL_DISK request, input is del_disk_struc
139
; 6a. Input size must be exactly del_disk_struc.sizeof bytes.
117
; 6a. Input size must be exactly sizeof.del_disk_struc bytes.
140
        cmp     [edx+IOCTL.inp_size], del_disk_struc.sizeof
118
        cmp     [edx+IOCTL.inp_size], sizeof.del_disk_struc
141
        jnz     .return
119
        jnz     .return
142
; 6b. Load input parameters and call the worker procedure.
120
; 6b. Load input parameters and call the worker procedure.
143
        mov     eax, [edx+IOCTL.input]
121
        mov     eax, [edx+IOCTL.input]
144
        movzx   ebx, [eax+del_disk_struc.DiskId]
122
        movzx   ebx, [eax+del_disk_struc.DiskId]
145
        call    del_disk
123
        call    del_disk
146
; 6c. Return back to the caller the value from the worker procedure.
124
; 6c. Return back to the caller the value from the worker procedure.
147
.return:
125
.return:
148
; 7. Exit.
126
; 7. Exit.
149
; 7a. The code above returns a value in al for efficiency,
127
; 7a. The code above returns a value in al for efficiency,
150
; propagate it to eax.
128
; propagate it to eax.
151
        movzx   eax, al
129
        movzx   eax, al
152
; 7b. Restore used registers to be stdcall.
130
; 7b. Restore used registers to be stdcall.
153
        pop     edi esi ebx
131
        pop     edi esi ebx
154
; 7c. Return, popping one argument.
132
; 7c. Return, popping one argument.
155
        retn    4
133
        retn    4
156
endp
134
endp
157
 
135
 
158
; The worker procedure for DEV_ADD_DISK request.
136
; The worker procedure for DEV_ADD_DISK request.
159
; Creates a memory-based disk of given size and formats it in FAT16/32.
137
; Creates a memory-based disk of given size and formats it in FAT16/32.
160
; Called with ebx = disk id, esi = disk size,
138
; Called with ebx = disk id, esi = disk size,
161
; returns error code in al.
139
; returns error code in al.
162
proc add_disk
140
proc add_disk
163
; 1. Check that disk id is correct and free.
141
; 1. Check that disk id is correct and free.
164
; Otherwise, return the corresponding error code.
142
; Otherwise, return the corresponding error code.
165
        mov     al, ERROR_INVALID_ID
143
        mov     al, ERROR_INVALID_ID
166
        cmp     ebx, max_num_disks
144
        cmp     ebx, max_num_disks
167
        jae     .return
145
        jae     .return
168
        cmp     [disk_pointers+ebx*4], 0
146
        cmp     [disk_pointers+ebx*4], 0
169
        jnz     .return
147
        jnz     .return
170
; 2. Check that the size is reasonable.
148
; 2. Check that the size is reasonable.
171
; Otherwise, return the corresponding error code.
149
; Otherwise, return the corresponding error code.
172
        mov     al, ERROR_SIZE_TOO_LARGE
150
        mov     al, ERROR_SIZE_TOO_LARGE
173
        cmp     esi, MAX_SIZE
151
        cmp     esi, MAX_SIZE
174
        ja      .return
152
        ja      .return
175
        mov     al, ERROR_SIZE_TOO_SMALL
153
        mov     al, ERROR_SIZE_TOO_SMALL
176
        cmp     esi, MIN_FAT16_SIZE
154
        cmp     esi, MIN_FAT16_SIZE
177
        jb      .return
155
        jb      .return
178
; 3. Allocate memory for the disk, store the pointer in edi.
156
; 3. Allocate memory for the disk, store the pointer in edi.
179
; If failed, return the corresponding error code.
157
; If failed, return the corresponding error code.
180
        mov     eax, esi
158
        mov     eax, esi
181
        shl     eax, 9
159
        shl     eax, 9
182
        stdcall KernelAlloc, eax
160
        invoke  KernelAlloc, eax
183
        mov     edi, eax
161
        mov     edi, eax
184
        test    eax, eax
162
        test    eax, eax
185
        mov     al, ERROR_NO_MEMORY
163
        mov     al, ERROR_NO_MEMORY
186
        jz      .return
164
        jz      .return
187
; 4. Store the pointer and the size in the global variables.
165
; 4. Store the pointer and the size in the global variables.
188
; It is possible, though very unlikely, that two threads
166
; It is possible, though very unlikely, that two threads
189
; have called this function in parallel with the same id,
167
; have called this function in parallel with the same id,
190
; so [disk_pointers+ebx*4] could be filled by another thread.
168
; so [disk_pointers+ebx*4] could be filled by another thread.
191
; Play extra safe and store new value only if old value is zero.
169
; Play extra safe and store new value only if old value is zero.
192
        xor     eax, eax
170
        xor     eax, eax
193
        lock cmpxchg [disk_pointers+ebx*4], edi
171
        lock cmpxchg [disk_pointers+ebx*4], edi
194
        jz      @f
172
        jz      @f
195
; Otherwise, free the allocated memory and return the corresponding error code.
173
; Otherwise, free the allocated memory and return the corresponding error code.
196
        stdcall KernelFree, edi
174
        invoke  KernelFree, edi
197
        mov     al, ERROR_INVALID_ID
175
        mov     al, ERROR_INVALID_ID
198
        jmp     .return
176
        jmp     .return
199
@@:
177
@@:
200
        mov     [disk_sizes+ebx*4], esi
178
        mov     [disk_sizes+ebx*4], esi
201
; 5. Call the worker procedure for formatting this disk.
179
; 5. Call the worker procedure for formatting this disk.
202
; It should not fail.
180
; It should not fail.
203
        call    format_disk
181
        call    format_disk
204
; 6. Register the disk in the system.
182
; 6. Register the disk in the system.
205
; 6a. Generate name as /tmp#, where # = ebx + '0'. Use two dwords in the stack.
183
; 6a. Generate name as /tmp#, where # = ebx + '0'. Use two dwords in the stack.
206
        push    0
184
        push    0
207
        push    'tmp'
185
        push    'tmp'
208
        mov     eax, esp ; eax points to 'tmp' + zero byte + zero dword
186
        mov     eax, esp ; eax points to 'tmp' + zero byte + zero dword
209
        lea     ecx, [ebx+'0'] ; ecx = digit
187
        lea     ecx, [ebx+'0'] ; ecx = digit
210
        mov     [eax+3], cl ; eax points to 'tmp#' + zero dword
188
        mov     [eax+3], cl ; eax points to 'tmp#' + zero dword
211
; 6b. Call the kernel API. Use disk id as 'userdata' parameter for callbacks.
189
; 6b. Call the kernel API. Use disk id as 'userdata' parameter for callbacks.
212
        stdcall DiskAdd, disk_functions, eax, ebx, 0
190
        invoke  DiskAdd, disk_functions, eax, ebx, 0
213
; 6c. Restore the stack after 6a.
191
; 6c. Restore the stack after 6a.
214
        pop     ecx ecx
192
        pop     ecx ecx
215
; 6c. Check the result. If DiskAdd has failed, cleanup and return
193
; 6c. Check the result. If DiskAdd has failed, cleanup and return
216
; ERROR_NO_MEMORY, this is the most probable or even the only reason to fail.
194
; ERROR_NO_MEMORY, this is the most probable or even the only reason to fail.
217
        test    eax, eax
195
        test    eax, eax
218
        jnz     @f
196
        jnz     @f
219
        mov     [disk_sizes+ebx*4], 0
197
        mov     [disk_sizes+ebx*4], 0
220
        mov     [disk_pointers+ebx*4], 0
198
        mov     [disk_pointers+ebx*4], 0
221
        stdcall KernelFree, edi
199
        invoke  KernelFree, edi
222
        mov     al, ERROR_NO_MEMORY
200
        mov     al, ERROR_NO_MEMORY
223
        jmp     .return
201
        jmp     .return
224
@@:
202
@@:
225
        push    eax
203
        push    eax
226
; 6d. Notify the kernel that media is inserted.
204
; 6d. Notify the kernel that media is inserted.
227
        stdcall DiskMediaChanged, eax, 1
205
        invoke  DiskMediaChanged, eax, 1
228
; 6e. Disk is fully configured; store its handle in the global variable
206
; 6e. Disk is fully configured; store its handle in the global variable
229
; and return success.
207
; and return success.
230
        pop     [disk_handles+ebx*4]
208
        pop     [disk_handles+ebx*4]
231
        xor     eax, eax
209
        xor     eax, eax
232
; 7. Return.
210
; 7. Return.
233
.return:
211
.return:
234
        retn
212
        retn
235
endp
213
endp
236
 
214
 
237
; The worker procedure for DEV_DEL_DISK request.
215
; The worker procedure for DEV_DEL_DISK request.
238
; Deletes a previously created memory-based disk.
216
; Deletes a previously created memory-based disk.
239
; Called with ebx = disk id,
217
; Called with ebx = disk id,
240
; returns error code in al.
218
; returns error code in al.
241
proc del_disk
219
proc del_disk
242
; 1. Check that disk id is correct.
220
; 1. Check that disk id is correct.
243
; Otherwise, return the corresponding error code.
221
; Otherwise, return the corresponding error code.
244
        mov     al, ERROR_INVALID_ID
222
        mov     al, ERROR_INVALID_ID
245
        cmp     ebx, max_num_disks
223
        cmp     ebx, max_num_disks
246
        jae     .return
224
        jae     .return
247
; 2. Get the disk handle, simultaneously clearing the global variable.
225
; 2. Get the disk handle, simultaneously clearing the global variable.
248
        xor     edx, edx
226
        xor     edx, edx
249
        xchg    edx, [disk_handles+ebx*4]
227
        xchg    edx, [disk_handles+ebx*4]
250
; 3. Check that the handle is non-zero.
228
; 3. Check that the handle is non-zero.
251
; Otherwise, return the corresponding error code.
229
; Otherwise, return the corresponding error code.
252
        test    edx, edx
230
        test    edx, edx
253
        jz      .return
231
        jz      .return
254
; 4. Delete the disk from the system.
232
; 4. Delete the disk from the system.
255
        stdcall DiskDel, edx
233
        invoke  DiskDel, edx
256
; 5. Return success.
234
; 5. Return success.
257
; Note that we can't free memory yet; it will be done in tmpdisk_close.
235
; Note that we can't free memory yet; it will be done in tmpdisk_close.
258
        xor     eax, eax
236
        xor     eax, eax
259
.return:
237
.return:
260
        retn
238
        retn
261
endp
239
endp
262
 
240
 
263
; Include implementation of tmpdisk_* callbacks.
241
; Include implementation of tmpdisk_* callbacks.
264
include 'tmpdisk_work.inc'
242
include 'tmpdisk_work.inc'
265
; Include FAT-specific code.
243
; Include FAT-specific code.
266
include 'tmpdisk_fat.inc'
244
include 'tmpdisk_fat.inc'
267
 
245
 
268
; initialized data
246
; initialized data
269
align 4
247
align 4
270
disk_functions:
248
disk_functions:
271
        dd      disk_functions_end - disk_functions
249
        dd      disk_functions_end - disk_functions
272
        dd      tmpdisk_close
250
        dd      tmpdisk_close
273
        dd      0 ; no need in .closemedia
251
        dd      0 ; no need in .closemedia
274
        dd      tmpdisk_querymedia
252
        dd      tmpdisk_querymedia
275
        dd      tmpdisk_read
253
        dd      tmpdisk_read
276
        dd      tmpdisk_write
254
        dd      tmpdisk_write
277
        dd      0 ; no need in .flush
255
        dd      0 ; no need in .flush
278
        dd      tmpdisk_adjust_cache_size
256
        dd      tmpdisk_adjust_cache_size
279
disk_functions_end:
257
disk_functions_end:
280
; disk_handles = array of values for Disk* kernel functions
258
; disk_handles = array of values for Disk* kernel functions
281
label disk_handles dword
259
label disk_handles dword
282
times max_num_disks dd 0
260
times max_num_disks dd 0
283
; disk_pointers = array of pointers to disk data
261
; disk_pointers = array of pointers to disk data
284
label disk_pointers dword
262
label disk_pointers dword
285
times max_num_disks dd 0
263
times max_num_disks dd 0
286
; disk_sizes = array of disk sizes
264
; disk_sizes = array of disk sizes
287
label disk_sizes dword
265
label disk_sizes dword
288
times max_num_disks dd 0
266
times max_num_disks dd 0
289
 
-
 
290
version         dd      0x00060006
267
 
291
my_service      db      'tmpdisk',0
-
 
292
 
-
 
293
; uninitialized data
-
 
294
; actually, not used here
-
 
295
;section '.data' data readable writable align 16 ; standard driver stuff
268
my_service      db      'tmpdisk',0