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:
parent
038e994d48
commit
06c0abac6a
@ -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]
|
||||
|
Loading…
x
Reference in New Issue
Block a user