kolibrios/drivers/disk/virt_disk.asm

725 lines
18 KiB
NASM
Raw Permalink Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2023. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Virtual disk driver for KolibriOS ;;
;; ;;
;; Written by Mikhail Frolov aka Doczom ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DISK_STATUS_OK = 0 ; success
DISK_STATUS_GENERAL_ERROR = -1; if no other code is suitable
DISK_STATUS_INVALID_CALL = 1 ; invalid input parameters
DISK_STATUS_NO_MEDIA = 2 ; no media present
DISK_STATUS_END_OF_MEDIA = 3 ; end of media while reading/writing data
; For all IOCTLs the driver returns one of the following error codes:
NO_ERROR equ 0
ERROR_INVALID_IOCTL equ 1 ; unknown IOCTL code
maxPathLength = 1000h
include '../struct.inc'
; TODO list:
; add support VDI image
; Input structures:
Flag:
.Ro = 1b
.Wo = 10b
.RW = 11b
struct DISK_DEV
next rd 1
pref rd 1
SectorCount rd 2
DiskHandle rd 1
DiskNumber rd 1
Flags rd 1 ; 1-ro 2-wo 3-rw
TypeImage rd 1 ; 0-raw 1-vhd 2-vdi 3-imd
SectorSize rd 1
DiskPath rb maxPathLength
ends
struct IMAGE_ADD_STRUCT
Flags rd 1 ; 1-ro 2-wo 3-rw
TypeImage rd 1 ; 0-raw 1-vhd 2-vdi 3-imd
SectorSize rd 1
DiskPath rb maxPathLength
ends
struct DISKMEDIAINFO
Flags dd ?
SectorSize dd ?
Capacity dq ?
ends
DEBUG = 1
__DEBUG__ = 1
__DEBUG_LEVEL__ = 1 ; 1 = verbose, 2 = errors only
format PE DLL native 0.05
entry START
section '.flat' code readable writable executable
include '../proc32.inc'
include '../peimport.inc'
include '../macros.inc'
include '../fdo.inc'
proc START c, state:dword, cmdline:dword
xor eax, eax ; set return value in case we will do nothing
cmp dword [state], 1
jne .nothing
mov ecx, disk_list_lock
invoke MutexInit
DEBUGF 1, "VIRT_DISK: driver loaded\n"
invoke RegService, my_service, service_proc
ret
.nothing:
ret
endp
; get version
; add disk
; del disk
; get list disks
; get disk info
proc service_proc
push ebx esi edi
; 2. Get parameter from the stack: [esp+16] is the first parameter,
; pointer to IOCTL structure.
mov ebx, [esp + 16] ; edx -> IOCTL
mov ecx, [ebx + IOCTL.io_code]
test ecx, ecx ; check for SRV_GETVERSION
jnz .add_disk
cmp [ebx + IOCTL.out_size], 4
jb .error_ret
mov eax, [ebx + IOCTL.output]
mov dword [eax], 1 ;API_VERSION
xor eax, eax
jmp .return
.add_disk:
dec ecx ; check for DEV_ADD_DISK
jnz .del_disk
cmp [ebx + IOCTL.inp_size], sizeof.IMAGE_ADD_STRUCT
jb .error_ret
cmp [ebx + IOCTL.out_size], 4
jb .error_ret
invoke KernelAlloc, sizeof.DISK_DEV
test eax, eax
jz .error_ret
push eax
mov edi, eax
mov ecx, sizeof.DISK_DEV/4
xor eax, eax
rep stosd
pop eax
mov edi, eax
add edi, DISK_DEV.Flags
mov esi, [ebx + IOCTL.input]
mov ecx, sizeof.IMAGE_ADD_STRUCT/4
rep movsd
mov esi, eax ;save
cmp byte[esi + DISK_DEV.DiskPath], '/'
jnz .add_disk.error
mov ecx, disk_list_lock
invoke MutexLock
call get_free_num
jnz .add_disk.error2
mov [esi + DISK_DEV.DiskNumber], eax
mov ecx,[ebx + IOCTL.output]
mov [ecx], eax
; init image
mov eax, [esi + DISK_DEV.TypeImage]
cmp eax, image_type.max_num
ja .add_disk.error2
call dword[image_type + eax*8] ;esi - DISK_DEV*
test eax, eax
jnz .add_disk.error2
; creating name
push ebp
mov ebp, esp
mov eax, [esi + DISK_DEV.DiskNumber]
mov edi, esp
dec edi
mov byte[edi], 0
mov ecx, 10
@@:
xor edx, edx
div ecx
add edx,'0'
dec edi
mov byte[edi], dl
test eax, eax
jnz @b
mov esp, edi
push word 'vd'
sub edi, 2
; add disk
mov eax, [esi + DISK_DEV.TypeImage]
invoke DiskAdd, dword[image_type + eax*8 + 4] , \
edi, esi, 0
mov [esi + DISK_DEV.DiskHandle], eax
mov esp, ebp
pop ebp
test eax, eax
jz .add_disk.error2
invoke DiskMediaChanged, eax, 1
; add in list
mov dword[esi], disk_root_list
mov eax, [disk_root_list + 4]
mov [esi + 4], eax
mov [eax], esi
mov [disk_root_list + 4], esi
inc dword[disk_count]
mov ecx, disk_list_lock
invoke MutexUnlock
xor eax, eax
jmp .return
.add_disk.error2:
mov ecx, disk_list_lock
invoke MutexUnlock
.add_disk.error:
invoke KernelFree, esi
jmp .error_ret
.del_disk:
dec ecx ; check for DEV_DEL_DISK
jnz .get_root_list
cmp [ebx + IOCTL.inp_size], 4
jb .error_ret
mov ecx, [ebx + IOCTL.input]
mov ecx, [ecx]
call get_disk
test eax, eax
jz .error_ret
cmp [eax + DISK_DEV.DiskHandle], 0
jz .error_ret
mov ecx, [eax + DISK_DEV.DiskHandle]
mov [eax + DISK_DEV.DiskHandle], 0
invoke DiskDel, ecx
xor eax, eax
jmp .return
.get_root_list:
dec ecx ; check for DEV_DEL_DISK
jnz .get_disk_info
cmp [ebx + IOCTL.inp_size], 4*2 ; offset + count
jb .error_ret
mov ecx, [ebx + IOCTL.input]
mov edx, [ecx] ; offset
mov eax, [ecx + 4] ; count
add edx, eax
cmp edx, [disk_count]
ja .error_ret
xor edx, edx
imul eax, sizeof.DISK_DEV - 8
add eax, 4
cmp [ebx + IOCTL.out_size], eax
jb .error_ret
mov edi, [ebx + IOCTL.output]
mov eax, [disk_count]
stosd
mov edx, [ecx]
mov eax, [disk_root_list]
@@:
test edx, edx
jz @f
mov eax, [eax]
dec edx
jmp @b
@@:
mov edx, [ecx + 4]
@@:
test edx, edx
jz @f
mov esi, eax
add esi, 8
mov ecx, (sizeof.DISK_DEV - 8)/4
rep movsd
mov eax, [eax]
dec edx
jmp @b
@@:
xor eax, eax
jmp .return
.get_disk_info:
dec ecx
jnz .error_ret
cmp [ebx + IOCTL.inp_size], 4
jb .error_ret
cmp [ebx + IOCTL.out_size], sizeof.DISK_DEV - 8
jb .error_ret
mov ecx, [ebx + IOCTL.input]
mov ecx, [ecx]
call get_disk
test eax, eax
jz .error_ret
mov esi, eax
add esi, 4*2
mov edi, [ebx + IOCTL.output]
mov ecx, (sizeof.DISK_DEV - 8)/4
rep movsd
xor eax, eax
jmp .return
.error_ret:
mov eax, ERROR_INVALID_IOCTL
.return:
pop edi esi ebx
retn 4
endp
; IN: ecx - ptr DISK_DEV
; OUT: ZF - found zF - not found
proc disk_dev_check
push eax
mov eax, disk_root_list
@@:
mov eax, [eax]
cmp eax, disk_root_list
jz .nf
cmp eax, ecx
jnz @b
pop eax
ret
.nf:
test eax, eax
pop eax
ret
endp
; IN: ecx - disk number
; OUT: eax - ptr DISK_DEV
proc get_disk
push ecx
mov ecx, disk_list_lock
invoke MutexLock
pop ecx
mov eax, disk_root_list
@@:
mov eax, [eax]
cmp eax, disk_root_list
jz .nf
cmp ecx, [eax + DISK_DEV.DiskNumber]
jnz @b
push eax
mov ecx, disk_list_lock
invoke MutexUnlock
pop eax
ret
.nf:
mov ecx, disk_list_lock
invoke MutexUnlock
xor eax, eax
ret
endp
; OUT: eax - number free disk
; Zf - good zf - not found
proc get_free_num
xor eax, eax
mov edx, disk_root_list
@@:
mov edx, [edx]
cmp edx, disk_root_list
jz @f
cmp eax, [edx + DISK_DEV.DiskNumber]
jnz @b
inc eax
jnz @b
test edx, edx ; random :)
@@:
ret
endp
;; IN: ecx - number disk
;; OUT: eax - ptr to DISK_DEV or zero
;proc get_link_disk
;
; push ecx
; mov ecx, disk_list_lock
; invoke MutexLock
; pop ecx
;
; xor eax, eax
; cmp ecx, [disk_array.len]
; jae .end
;
; mov eax, [disk_array]
; mov eax, [edx + ecx*4]
;
;.end:
; push eax
; ; unlock disk list
; mov ecx, disk_list_lock
; invoke MutexUnlock
; pop eax
; ret
;endp
;; IN: esi - ptr to DISK_DEV
;; OUT: eax - offset in array or -1
;proc add_link_disk
; ; find free item
; mov ecx, [disk_array]
; xor eax, eax
; dec eax
;@@:
; inc eax
; cmp eax, [disk_array.len]
; jae .not_found
;
; cmp dword[ecx + eax*4], 0
; jnz @b
;
; mov [ecx + eax*4], esi
; ret
;
;.not_found:
; inc dword[disk_array.len]
; ;get new memory
; mov eax,[disk_array.len]
; shl eax, 2 ;*4
; invoke Kmalloc
; test eax, eax
; jz .err
; ; copy data
; push edi esi
; mov ecx, [disk_array.len]
; mov edi, eax
; mov esi, [disk_array]
; rep movsd
; pop esi edi
; ; del old array
; xchg [disk_array], eax
; invoke Kfree
; mov eax, [disk_array.len]
; ret
;.err:
; dec dword[disk_array.len]
; mov eax, -1
; ret
;endp
;
;; IN: ecx - offset in array
;proc del_link_disk
; mov edx, ecx
; dec edx
; cmp edx,[disk_array.len]
; jz .last_item
;
; mov edx,[disk_array]
; mov [edx + ecx*4], 0
; ret
;.last_item:
; dec dword[disk_array.len]
; ;get new memory
; mov eax,[disk_array.len]
; shl eax, 2 ;*4
; invoke Kmalloc
; test eax, eax
; jz .err
; ; copy data
; push edi esi
; mov ecx, [disk_array.len]
; mov edi, eax
; mov esi, [disk_array]
; rep movsd
; pop esi edi
; ; del old array
; xchg [disk_array], eax
; invoke Kfree
; ret
;.err:
; inc dword[disk_array.len]
; mov eax, -1
; ret
;endp
; RAW IMAGE DISK FUNCTIONS
proc raw_disk_close stdcall, pdata
; del item list
mov ecx, disk_list_lock
invoke MutexLock
mov ecx, [pdata]
mov eax, [ecx] ; eax = next
mov edx, [ecx + 4] ; edx = prev
mov [eax + 4], edx ; [next.prev] = prev
mov [edx], eax ; [prev.next] = next
dec dword[disk_count]
mov ecx, disk_list_lock
invoke MutexUnlock
invoke KernelFree, [pdata]
DEBUGF 1, "VIRT_DISK: disk deleted\n"
ret
endp
proc disk_querymedia stdcall, pdata, mediainfo
mov eax, [mediainfo]
mov edx, [pdata]
mov [eax + DISKMEDIAINFO.Flags], 0
mov ecx, [edx + DISK_DEV.SectorSize]
mov [eax + DISKMEDIAINFO.SectorSize], ecx
mov ecx, [edx + DISK_DEV.SectorCount]
mov dword[eax + DISKMEDIAINFO.Capacity], ecx
mov ecx, [edx + DISK_DEV.SectorCount + 4]
mov dword[eax + DISKMEDIAINFO.Capacity + 4], ecx
xor eax, eax
ret
endp
proc raw_disk_rd stdcall pdata: dword,\
buffer: dword,\
startsector: qword,\
numsectors_ptr:dword
mov ecx, [pdata]
test [ecx + DISK_DEV.Flags], Flag.Ro
jz .no_support
pusha
lea eax,[ecx + DISK_DEV.DiskPath]
push eax
dec esp
mov byte[esp], 0
push dword[buffer]
mov eax, [numsectors_ptr]
mov eax, [eax]
mul dword[ecx + DISK_DEV.SectorSize]
push eax
; get offset for startsector
mov eax, dword[startsector]
xor edx, edx
mul dword[ecx + DISK_DEV.SectorSize]
push edx
push eax
mov eax, dword[startsector + 4]
mul dword[ecx + DISK_DEV.SectorSize]
add [esp + 4], eax
push dword 0 ;read file
mov ebx, esp
invoke FS_Service
push eax
mov ecx, [pdata]
mov eax, ebx
xor edx, edx
div dword[ecx + DISK_DEV.SectorSize]
mov edx, [numsectors_ptr]
mov [edx], eax
pop eax
add esp, 6*4+1 ; size FS struct
test eax, eax
popa
jz @f
mov eax, 1
ret
@@:
xor eax, eax
ret
.no_support:
mov eax, DISK_STATUS_GENERAL_ERROR
ret
endp
proc raw_disk_wr stdcall pdata: dword,\
buffer: dword,\
startsector: qword,\
numsectors_ptr:dword
mov ecx, [pdata]
test [ecx + DISK_DEV.Flags], Flag.Wo
jz .no_support
pusha
lea eax,[ecx + DISK_DEV.DiskPath]
push eax
dec esp
mov byte[esp],0
push dword[buffer]
mov eax, [numsectors_ptr]
mov eax, [eax]
mul dword[ecx + DISK_DEV.SectorSize]
push eax
; get offset for startsector
mov eax, dword[startsector]
xor edx, edx
mul dword[ecx + DISK_DEV.SectorSize]
push edx
push eax
xor edx, edx
mov eax, dword[startsector + 4]
mul dword[ecx + DISK_DEV.SectorSize]
add [esp + 4], eax
push dword 3 ; write file
mov ebx, esp
invoke FS_Service
push eax
mov ecx, [pdata]
mov eax, ebx
xor edx, edx
div dword[ecx + DISK_DEV.SectorSize]
mov edx, [numsectors_ptr]
mov [edx], eax
pop eax
add esp, 6*4+1 ; size FS struct
test eax, eax
popa
jz @f
mov eax, 1
ret
@@:
xor eax, eax
ret
.no_support:
mov eax, DISK_STATUS_GENERAL_ERROR
ret
endp
disk_root_list:
dd disk_root_list
dd disk_root_list
disk_count: dd 0
disk_list_lock: MUTEX
image_type:
; init function, table disk function
dd raw_image_init, raw_disk_functions
; vdi
.max_num = ($ - image_type - 8) / 8; 8 - item size
align 4
; esi - ptr to DISK_DEV
;WARNING: raw image size >=2tb not supported.
proc raw_image_init
sub esp, 40 ; for file_info
mov ecx, esp
pusha
lea eax,[esi + DISK_DEV.DiskPath]
push eax
dec esp
mov byte[esp],0
push ecx
xor eax, eax
push eax eax eax
push dword 5
mov ebx, esp
invoke FS_Service
add esp, 6*4+1
test eax, eax
popa
lea esp,[esp + 40]
jnz .err
; WARNING: Not working with stack, destroys the structure!
mov eax, [ecx + 32]
mov edx, [ecx + 36]
test eax, eax
jz .err
div dword[esi + DISK_DEV.SectorSize] ; undefined exeption
mov [esi + DISK_DEV.SectorCount], eax
mov [esi + DISK_DEV.SectorCount + 4], 0
; END WARNING
xor eax, eax
ret
.err:
or eax, -1
ret
endp
align 4
raw_disk_functions:
dd .size
dd raw_disk_close
dd 0 ; no need in .closemedia
dd disk_querymedia
dd raw_disk_rd
dd raw_disk_wr
dd 0 ; no need in .flush
dd disk_adjust_cache_size
.size = $ - raw_disk_functions
proc disk_adjust_cache_size
virtual at esp+4
.userdata dd ?
.suggested_size dd ?
end virtual
xor eax, eax
retn 8
endp
my_service db 'VIRT_DISK',0
data fixups
end data
include_debug_strings