Apps: fixed 3 programs for using a long path in parameters
[kolibrios.git] / drivers / disk / tmpdisk.asm
blob414c62c2e2b7faaa643520fdf2dc3aa46e635b9f
1 ; Disk driver to create FAT16/FAT32 memory-based temporary disk aka RAM disk.
2 ; (c) CleverMouse
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.
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
28 include '../struct.inc'
30 API_VERSION equ 1
31 ; Input structures:
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.
35 ; Size for useful data is slightly less than this number.
36 DiskId db ? ; from 0 to 9
37 ends
38 struct del_disk_struc
39 DiskId db ? ; from 0 to 9
40 ends
42 max_num_disks equ 10
44 ; standard driver stuff; version of driver model = 5
45 format PE DLL native 0.05
47 DEBUG equ 0
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'
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.
65 invoke RegService, my_service, service_proc
66 ; 3. Return the value returned by RegService back to the system.
67 .nothing:
68 retn
69 endp
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
103 ; 5a. Input size must be exactly sizeof.add_disk_struc bytes.
104 cmp [edx+IOCTL.inp_size], sizeof.add_disk_struc
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
117 ; 6a. Input size must be exactly sizeof.del_disk_struc bytes.
118 cmp [edx+IOCTL.inp_size], sizeof.del_disk_struc
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
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
160 invoke KernelAlloc, eax
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.
174 invoke KernelFree, edi
175 mov al, ERROR_INVALID_ID
176 jmp .return
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.
190 invoke DiskAdd, disk_functions, eax, ebx, 0
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
199 invoke KernelFree, edi
200 mov al, ERROR_NO_MEMORY
201 jmp .return
203 push eax
204 ; 6d. Notify the kernel that media is inserted.
205 invoke DiskMediaChanged, eax, 1
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
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.
233 invoke DiskDel, edx
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
241 ; Include implementation of tmpdisk_* callbacks.
242 include 'tmpdisk_work.inc'
243 ; Include FAT-specific code.
244 include 'tmpdisk_fat.inc'
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
268 my_service db 'tmpdisk',0