Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  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.  
  28.  
  29. API_VERSION             equ 1
  30. ; Input structures:
  31. struc add_disk_struc
  32. {
  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. .sizeof:
  38. }
  39. virtual at 0
  40. add_disk_struc  add_disk_struc
  41. end virtual
  42. struc del_disk_struc
  43. {
  44. .DiskId         db      ? ; from 0 to 9
  45. .sizeof:
  46. }
  47. virtual at 0
  48. del_disk_struc del_disk_struc
  49. end virtual
  50.  
  51. max_num_disks   equ     10
  52.  
  53. ; standard driver stuff
  54. format MS COFF
  55.  
  56. DEBUG equ 0
  57. include 'proc32.inc'
  58. include 'imports.inc'
  59.  
  60. public START
  61. public version
  62.  
  63. struc IOCTL
  64. {
  65.         .handle         dd ?
  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
  75. end virtual
  76.  
  77. section '.flat' code readable align 16
  78. ; the start procedure (see the description above)
  79. proc START
  80. ; This procedure is called in two situations:
  81. ; when the driver is loading and when the system is shutting down.
  82. ; 1. Check that the driver is loading; do nothing unless so.
  83.         xor     eax, eax ; set return value in case we will do nothing
  84.         cmp     dword [esp+4], 1
  85.         jne     .nothing
  86. ; 2. Register the driver in the system.
  87.         stdcall RegService, my_service, service_proc
  88. ; 3. Return the value returned by RegService back to the system.
  89. .nothing:
  90.         retn    4
  91. endp
  92.  
  93. ; 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.
  95. proc service_proc
  96. ; 1. Save used registers to be stdcall.
  97. ; 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.
  99.         push    ebx esi edi
  100. ; 2. Get parameter from the stack: [esp+16] is the first parameter,
  101. ;    pointer to IOCTL structure.
  102.         mov     edx, [esp+16]    ; edx -> IOCTL
  103. ; 3. Set the return value to 'invalid IOCTL'.
  104. ; Now, if one of conditions for IOCTL does not met, the code
  105. ; can simply return the value already loaded.
  106.         mov     al, ERROR_INVALID_IOCTL
  107. ; 4. Get request code and select a handler for the code.
  108.         mov     ecx, [edx+IOCTL.io_code]
  109.         test    ecx, ecx        ; check for SRV_GETVERSION
  110.         jnz     .no.srv_getversion
  111. ; 4. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION.
  112. ; 4a. Output size must be at least 4 bytes.
  113.         cmp     [edx+IOCTL.out_size], 4
  114.         jl      .return
  115. ; 4b. Write result to the output buffer.
  116.         mov     eax, [edx+IOCTL.output]
  117.         mov     dword [eax], API_VERSION
  118. ; 4c. Return success.
  119.         xor     eax, eax
  120.         jmp     .return
  121. .no.srv_getversion:
  122.         dec     ecx     ; check for DEV_ADD_DISK
  123.         jnz     .no.dev_add_disk
  124. ; 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.
  126.         cmp     [edx+IOCTL.inp_size], add_disk_struc.sizeof
  127.         jnz     .return
  128. ; 5b. Load input parameters and call the worker procedure.
  129.         mov     eax, [edx+IOCTL.input]
  130.         movzx   ebx, [eax+add_disk_struc.DiskId]
  131.         mov     esi, [eax+add_disk_struc.DiskSize]
  132.         call    add_disk
  133. ; 5c. Return back to the caller the value from the worker procedure.
  134.         jmp     .return
  135. .no.dev_add_disk:
  136.         dec     ecx     ; check for DEV_DEL_DISK
  137.         jnz     .return
  138. ; 6. This is DEV_DEL_DISK request, input is del_disk_struc
  139. ; 6a. Input size must be exactly del_disk_struc.sizeof bytes.
  140.         cmp     [edx+IOCTL.inp_size], del_disk_struc.sizeof
  141.         jnz     .return
  142. ; 6b. Load input parameters and call the worker procedure.
  143.         mov     eax, [edx+IOCTL.input]
  144.         movzx   ebx, [eax+del_disk_struc.DiskId]
  145.         call    del_disk
  146. ; 6c. Return back to the caller the value from the worker procedure.
  147. .return:
  148. ; 7. Exit.
  149. ; 7a. The code above returns a value in al for efficiency,
  150. ; propagate it to eax.
  151.         movzx   eax, al
  152. ; 7b. Restore used registers to be stdcall.
  153.         pop     edi esi ebx
  154. ; 7c. Return, popping one argument.
  155.         retn    4
  156. endp
  157.  
  158. ; The worker procedure for DEV_ADD_DISK request.
  159. ; Creates a memory-based disk of given size and formats it in FAT16/32.
  160. ; Called with ebx = disk id, esi = disk size,
  161. ; returns error code in al.
  162. proc add_disk
  163. ; 1. Check that disk id is correct and free.
  164. ; Otherwise, return the corresponding error code.
  165.         mov     al, ERROR_INVALID_ID
  166.         cmp     ebx, max_num_disks
  167.         jae     .return
  168.         cmp     [disk_pointers+ebx*4], 0
  169.         jnz     .return
  170. ; 2. Check that the size is reasonable.
  171. ; Otherwise, return the corresponding error code.
  172.         mov     al, ERROR_SIZE_TOO_LARGE
  173.         cmp     esi, MAX_SIZE
  174.         ja      .return
  175.         mov     al, ERROR_SIZE_TOO_SMALL
  176.         cmp     esi, MIN_FAT16_SIZE
  177.         jb      .return
  178. ; 3. Allocate memory for the disk, store the pointer in edi.
  179. ; If failed, return the corresponding error code.
  180.         mov     eax, esi
  181.         shl     eax, 9
  182.         stdcall KernelAlloc, eax
  183.         mov     edi, eax
  184.         test    eax, eax
  185.         mov     al, ERROR_NO_MEMORY
  186.         jz      .return
  187. ; 4. Store the pointer and the size in the global variables.
  188. ; It is possible, though very unlikely, that two threads
  189. ; have called this function in parallel with the same id,
  190. ; 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.
  192.         xor     eax, eax
  193.         lock cmpxchg [disk_pointers+ebx*4], edi
  194.         jz      @f
  195. ; Otherwise, free the allocated memory and return the corresponding error code.
  196.         stdcall KernelFree, edi
  197.         mov     al, ERROR_INVALID_ID
  198.         jmp     .return
  199. @@:
  200.         mov     [disk_sizes+ebx*4], esi
  201. ; 5. Call the worker procedure for formatting this disk.
  202. ; It should not fail.
  203.         call    format_disk
  204. ; 6. Register the disk in the system.
  205. ; 6a. Generate name as /tmp#, where # = ebx + '0'. Use two dwords in the stack.
  206.         push    0
  207.         push    'tmp'
  208.         mov     eax, esp ; eax points to 'tmp' + zero byte + zero dword
  209.         lea     ecx, [ebx+'0'] ; ecx = digit
  210.         mov     [eax+3], cl ; eax points to 'tmp#' + zero dword
  211. ; 6b. Call the kernel API. Use disk id as 'userdata' parameter for callbacks.
  212.         stdcall DiskAdd, disk_functions, eax, ebx, 0
  213. ; 6c. Restore the stack after 6a.
  214.         pop     ecx ecx
  215. ; 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.
  217.         test    eax, eax
  218.         jnz     @f
  219.         mov     [disk_sizes+ebx*4], 0
  220.         mov     [disk_pointers+ebx*4], 0
  221.         stdcall KernelFree, edi
  222.         mov     al, ERROR_NO_MEMORY
  223.         jmp     .return
  224. @@:
  225.         push    eax
  226. ; 6d. Notify the kernel that media is inserted.
  227.         stdcall DiskMediaChanged, eax, 1
  228. ; 6e. Disk is fully configured; store its handle in the global variable
  229. ; and return success.
  230.         pop     [disk_handles+ebx*4]
  231.         xor     eax, eax
  232. ; 7. Return.
  233. .return:
  234.         retn
  235. endp
  236.  
  237. ; The worker procedure for DEV_DEL_DISK request.
  238. ; Deletes a previously created memory-based disk.
  239. ; Called with ebx = disk id,
  240. ; returns error code in al.
  241. proc del_disk
  242. ; 1. Check that disk id is correct.
  243. ; Otherwise, return the corresponding error code.
  244.         mov     al, ERROR_INVALID_ID
  245.         cmp     ebx, max_num_disks
  246.         jae     .return
  247. ; 2. Get the disk handle, simultaneously clearing the global variable.
  248.         xor     edx, edx
  249.         xchg    edx, [disk_handles+ebx*4]
  250. ; 3. Check that the handle is non-zero.
  251. ; Otherwise, return the corresponding error code.
  252.         test    edx, edx
  253.         jz      .return
  254. ; 4. Delete the disk from the system.
  255.         stdcall DiskDel, edx
  256. ; 5. Return success.
  257. ; Note that we can't free memory yet; it will be done in tmpdisk_close.
  258.         xor     eax, eax
  259. .return:
  260.         retn
  261. endp
  262.  
  263. ; Include implementation of tmpdisk_* callbacks.
  264. include 'tmpdisk_work.inc'
  265. ; Include FAT-specific code.
  266. include 'tmpdisk_fat.inc'
  267.  
  268. ; initialized data
  269. align 4
  270. disk_functions:
  271.         dd      disk_functions_end - disk_functions
  272.         dd      tmpdisk_close
  273.         dd      0 ; no need in .closemedia
  274.         dd      tmpdisk_querymedia
  275.         dd      tmpdisk_read
  276.         dd      tmpdisk_write
  277.         dd      0 ; no need in .flush
  278.         dd      tmpdisk_adjust_cache_size
  279. disk_functions_end:
  280. ; disk_handles = array of values for Disk* kernel functions
  281. label disk_handles dword
  282. times max_num_disks dd 0
  283. ; disk_pointers = array of pointers to disk data
  284. label disk_pointers dword
  285. times max_num_disks dd 0
  286. ; disk_sizes = array of disk sizes
  287. label disk_sizes dword
  288. times max_num_disks dd 0
  289.  
  290. version         dd      0x00060006
  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
  296.