2
0
mirror of https://git.missingno.dev/kolibrios-nvme-driver/ synced 2024-12-22 22:08:47 +01:00

implement allocating and freeing PRP lists

This commit is contained in:
Abdur-Rahman Mansoor 2024-07-05 14:05:36 -04:00
parent d4bb46c00b
commit b6e6a69de7

View File

@ -450,27 +450,38 @@ proc get_log_page stdcall, pci:dword, dptr:dword, lid:byte
endp
proc free_prp_list stdcall, prp_list_ptr:dword, nprps:dword
proc free_prp_list stdcall, prp_list_ptr:dword, nprps:dword, recursive:byte
push ebx edi
push edi
mov edi, [prp_list_ptr]
xor ebx, ebx
mov ecx, [nprps]
cmp ecx, PAGE_SIZE / 8 - 1
jbe @f
mov eax, dword [edi + PAGE_SIZE - 8]
sub ecx, PAGE_SIZE / 8 - 1
stdcall free_prp_list, eax, ecx, TRUE
@@:
invoke KernelFree, dword [edi + ebx * 4]
inc ebx
cmp ebx, [nprps]
jb @b
pop edi ebx
cmp [recursive], 0
jz @f
invoke FreePage, edi
jmp .exit
@@:
invoke KernelFree, edi
.exit:
xor eax, eax
pop edi
ret
endp
proc build_prp_list stdcall, nprps:dword
push ebx edi
push esi ebx edi
xor edi, edi
xor esi, esi
mov ecx, [nprps]
mov ebx, ecx
shl ecx, 3
@ -478,34 +489,61 @@ proc build_prp_list stdcall, nprps:dword
test eax, eax
jz .err
mov edi, eax
mov ecx, [nprps]
mov ecx, ebx
imul ecx, PAGE_SIZE
invoke KernelAlloc, ecx
test eax, eax
jz .err
mov edx, eax
mov esi, eax
xor ecx, ecx
push esi
@@:
push edx ecx
invoke GetPhysAddr, edx
pop ecx edx
.loop:
; check if we need to build another PRP list
mov eax, ebx
sub eax, PAGE_SIZE
; is this the last entry in the list? If so, build yet another PRP list here
cmp ecx, PAGE_SIZE / 8 - 1
jne @f
push ecx
stdcall build_prp_list, eax
pop ecx
test eax, eax
jz .cleanup_prp_list
invoke GetPhysAddr
mov dword [edi + ecx * 4], eax
mov dword [edi + ecx * 4 + 4], 0
add edx, PAGE_SIZE
jmp .success
@@:
mov eax, esi
push ecx
invoke GetPhysAddr
pop ecx
mov dword [edi + ecx * 4], eax
mov dword [edi + ecx * 4 + 4], 0
add esi, PAGE_SIZE
inc ecx
cmp ecx, ebx
jb @b
pop edi ebx
jb .loop
.success:
mov eax, edi
pop esi
pop edi ebx esi
ret
.cleanup_prp_list:
pop esi
invoke KernelFree, esi
.err:
test edi, edi
jnz @f
jz @f
invoke KernelFree, edi
@@:
pop edi ebx
pop edi ebx esi
xor eax, eax
ret
@ -549,7 +587,7 @@ proc alloc_dptr stdcall, ns:dword, prps_ptr:dword, start_sector:qword, numsector
jmp .success
.free_prp_list:
invoke KernelFree, eax
stdcall free_prp_list, edi, eax
.err:
mov eax, dword [edi]
@ -574,7 +612,7 @@ proc nvme_read ns:dword, dst:dword, start_sector:qword, numsectors_ptr:dword
push ebx esi edi
sub esp, 8
stdcall alloc_dptr, [ns], dword [esp], dword [esp + 4], [start_sector], [numsectors_ptr]
stdcall alloc_dptr, [ns], esp, [start_sector], [numsectors_ptr]
test eax, eax
jz .end
mov edi, eax
@ -618,7 +656,7 @@ proc nvme_read ns:dword, dst:dword, start_sector:qword, numsectors_ptr:dword
endp
; See page 258-261 (read) and 269-271 (write) of the NVMe 1.4 specification for reference
proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, prp1:dword, prp2:dword, slba_lo:dword, slba_hi:dword, nlb:word, opcode:dword
proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, prps:qword, slba_lo:dword, slba_hi:dword, nlb:word, opcode:dword
; TODO: Use IDENTC.NOIOB to construct read/write commands that don't
; cross the I/O boundary to achieve optimal performance
@ -629,9 +667,9 @@ proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, prp1:dword, prp2:dword
movzx ecx, [qid]
stdcall set_cdw0, [pci], ecx, [opcode]
mov dword [esp + SQ_ENTRY.cdw0], eax ; CDW0
mov eax, [prp1]
mov eax, dword [prps]
mov dword [esp + SQ_ENTRY.dptr], eax
mov eax, [prp2]
mov eax, dword [prps + 4]
mov dword [esp + SQ_ENTRY.dptr + 8], eax
mov eax, [nsid]
mov dword [esp + SQ_ENTRY.nsid], eax