2
0
mirror of https://git.missingno.dev/kolibrios-nvme-driver/ synced 2025-01-31 09:40:10 +01:00

wip: implement code for allocating PRP entries and lists

This commit is contained in:
Abdur-Rahman Mansoor 2024-07-03 15:53:32 -04:00
parent 038e994d48
commit 06c0abac6a

View File

@ -19,6 +19,12 @@ DRIVER_VERSION = 1
DBG_INFO = 1
NULLPTR = 0
; flags for alloc_dptr
PRP1_ENTRY_ALLOCATED = 1
PRP1_LIST_ALLOCATED = 2
PRP2_ENTRY_ALLOCATED = 4
PRP2_LIST_ALLOCATED = 8
section ".flat" code readable writable executable
include "../proc32.inc"
include "../struct.inc"
@ -445,18 +451,125 @@ proc get_log_page stdcall, pci:dword, dptr:dword, lid:byte
endp
; Returns a PRP/PRP List
proc alloc_dptr stdcall, start_sector:qword, numsectors_ptr:dword
; ----------------------------------------------------------------------------------------------------
; flags (used for identifying how to free the memory used by the PRPs after the command is completed):
; BIT 1 SET: allocated PRP1 entry
; BIT 2 SET: allocated PRP1 list
; BIT 3 SET: allocated PRP2 entry
; BIT 4 SET: allocated PRP2 list
proc alloc_dptr stdcall, ns:dword, prps_ptr:dword, start_sector:qword, numsectors:dword, flags_ptr:dword
; WIP: Todo
push esi edi ebx
mov esi, [ns]
mov edi, [flags_ptr]
mov ebx, dword [esi + NSINFO.pg_sectors]
mov esi, [prps_ptr]
mov dword [esi + 4], 0 ; set PRP #2 to reserved by default
cmp ebx, dword [edi]
ja .numsectors_over_1pg
.alloc_prp1_entry:
invoke KernelAlloc, 0x1000
test eax, eax
jz .err
or byte [edi], PRP1_ENTRY_ALLOCATED
mov dword [esi], eax
pop ebx edi esi
ret
.numsectors_over_1pg:
; check if offset portion of PRP1 is 0
mov eax, dword [esi]
and eax, (PAGE_SIZE shl NVM_MPS) - 1
test eax, eax
jz .check_prp2_cond_bii
; check PRP2 condition b) i.
cmp ebx, [numsectors]
jne .check_prp2_cond_cici
invoke KernelAlloc, 0x1000
test eax, eax
jz .err
mov dword [esi + 4], eax
or byte [edi], PRP2_ENTRY_ALLOCATED
jmp .alloc_prp1_entry
.check_prp2_cond_bii:
mov eax, ebx
shl eax, 1
cmp eax, [numsectors]
ja .check_prp2_cond_c
invoke KernelAlloc, 0x1000
test eax, eax
jz .err
mov dword [esi + 4], eax
or byte [edi], PRP2_ENTRY_ALLOCATED
jmp .alloc_prp1_entry
.check_prp2_cond_c:
; is the command data transfer length greater or equal to two memory pages?
mov eax, ebx
shl eax, 1
cmp eax, [numsectors_ptr]
jb .alloc_prp1_entry
mov ecx, 4
; note that ECX should be set to the offset (0 for PRP1, 4 for PRP2) before
; jumping here
; TODO: Move to separate function
.build_prp_list:
or byte [edi], PRP2_LIST_ALLOCATED
; insert number of PRPS to build in edx later
mov edx, 4
shl edx, 2
push edx
invoke KernelAlloc, edx
pop edx
test eax, eax
jz .err
push edi ecx
mov edi, eax
xor ecx, ecx
.build_prp_list.loop:
; TODO: handle cleaning up if an error occurs later
invoke KernelAlloc, 0x1000
test eax, eax
jz .build_prp_list.loop.cleanup
mov dword [edi + ecx], eax
add ecx, 4
cmp ecx, edx
jne .build_prp_list.loop
pop ecx
mov dword [esi + ecx], edi
pop edi
;ret
.build_prp_list.loop.cleanup:
push ecx ebx
xor ecx, ecx
@@:
invoke KernelFree, dword [edi + ecx]
add ecx, 4
cmp ecx, edx
jne @b
pop ebx ecx
pop ecx edi
.err:
xor eax, eax
pop ebx edi esi
ret
endp
proc nvme_read stdcall, ns:dword, dst:dword, start_sector:qword, numsectors_ptr:dword
proc nvme_read ns:dword, dst:dword, start_sector:qword, numsectors_ptr:dword
push ebx esi edi
stdcall alloc_dptr, [start_sector], [numsectors_ptr]
sub esp, 8
stdcall alloc_dptr, [ns], dword [esp], dword [esp + 4], [start_sector], [numsectors_ptr]
test eax, eax
jz .end
mov edi, eax
@ -484,12 +597,15 @@ proc nvme_read stdcall, ns:dword, dst:dword, start_sector:qword, numsectors_ptr:
mov esi, edi
mov edi, [dst]
rep movsd
add esp, 8
pop edi esi ebx
xor eax, eax ; TODO: add proper return value later
ret
.is_prp_list:
.end:
add esp, 8
pop edi esi ebx
xor eax, eax
ret
@ -497,7 +613,7 @@ proc nvme_read stdcall, ns:dword, dst:dword, start_sector:qword, numsectors_ptr:
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, dptr:dword, slba_lo:dword, slba_hi:dword, nlb:word, opcode:dword
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
; TODO: Use IDENTC.NOIOB to construct read/write commands that don't
; cross the I/O boundary to achieve optimal performance
@ -508,8 +624,10 @@ proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, dptr:dword, slba_lo:dw
movzx ecx, [qid]
stdcall set_cdw0, [pci], ecx, [opcode]
mov dword [esp + SQ_ENTRY.cdw0], eax ; CDW0
mov eax, [dptr]
mov eax, [prp1]
mov dword [esp + SQ_ENTRY.dptr], eax
mov eax, [prp2]
mov dword [esp + SQ_ENTRY.dptr + 8], eax
mov eax, [nsid]
mov dword [esp + SQ_ENTRY.nsid], eax
mov eax, [slba_lo]