Subversion Repositories Kolibri OS

Rev

Rev 2644 | Details | Compare with Previous | Last modification | View Log | RSS feed

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