From d4bb46c00b73705f0f2eaf98ad9e68a691977129 Mon Sep 17 00:00:00 2001 From: Abdur-Rahman Mansoor Date: Thu, 4 Jul 2024 14:42:06 -0400 Subject: [PATCH] some refactoring and fixes --- drivers/nvme/nvme.asm | 174 +++++++++++++++++++++--------------------- drivers/nvme/nvme.inc | 2 +- 2 files changed, 90 insertions(+), 86 deletions(-) diff --git a/drivers/nvme/nvme.asm b/drivers/nvme/nvme.asm index 05a7002..5336f0a 100644 --- a/drivers/nvme/nvme.asm +++ b/drivers/nvme/nvme.asm @@ -450,120 +450,122 @@ proc get_log_page stdcall, pci:dword, dptr:dword, lid:byte endp +proc free_prp_list stdcall, prp_list_ptr:dword, nprps:dword + + push ebx edi + mov edi, [prp_list_ptr] + xor ebx, ebx + +@@: + invoke KernelFree, dword [edi + ebx * 4] + inc ebx + cmp ebx, [nprps] + jb @b + pop edi ebx + xor eax, eax + ret + +endp + proc build_prp_list stdcall, nprps:dword push ebx edi - mov ebx, [nprps] - push ebx - shl ebx, 2 - invoke KernelAlloc, ebx - pop ebx + xor edi, edi + mov ecx, [nprps] + mov ebx, ecx + shl ecx, 3 + invoke KernelAlloc, ecx ; store pointers to the PRP entries here test eax, eax jz .err mov edi, eax - xor ecx, ecx - -@@: - invoke KernelAlloc, 0x1000 + mov ecx, [nprps] + imul ecx, PAGE_SIZE + invoke KernelAlloc, ecx test eax, eax - jz .cleanup - mov dword [edi + ecx], eax + jz .err + mov edx, eax + xor ecx, ecx + +@@: + push edx ecx + invoke GetPhysAddr, edx + pop ecx edx + mov dword [edi + ecx * 4], eax + mov dword [edi + ecx * 4 + 4], 0 + add edx, PAGE_SIZE inc ecx cmp ecx, ebx jb @b - mov dword [esi + ecx], edi - mov eax, edi pop edi ebx ret - -.cleanup: - xor ecx, ecx + +.err: + test edi, edi + jnz @f + invoke KernelFree, edi @@: - invoke KernelFree, dword [edi + ecx] - inc ecx - cmp ecx, edx - jb @b - -.err: - xor eax, eax pop edi ebx + xor eax, eax ret endp -; Returns a PRP/PRP List -; ---------------------------------------------------------------------------------------------------- -; 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 +proc alloc_dptr stdcall, ns:dword, prps_ptr:dword, start_sector:qword, numsectors:dword - push esi edi ebx + push esi edi 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 + mov edi, [prps_ptr] + mov qword [esi], 0 + invoke KernelAlloc, PAGE_SIZE test eax, eax jz .err - or byte [edi], PRP1_ENTRY_ALLOCATED - mov dword [esi], eax - pop ebx edi esi - ret + mov dword [edi], eax -.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 + ; is the number of sectors equal to two memory pages in size? + mov eax, dword [esi + NSINFO.pg_sectors] 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 - stdcall build_prp_list, 4 ; TODO: replace 4 with proper number of PRPs later - test eax, eax - jz .err - mov dword [esi + 4], eax - jmp .alloc_prp1_entry + jne @f + ; allocate a single PRP entry for PRP2 + invoke KernelAlloc, PAGE_SIZE + test eax, eax + jz .err + mov dword [edi + 4], eax + jmp .success + +@@: + ; allocate PRP list for PRP2 + shr eax, 1 + mov ecx, [numsectors] + xchg eax, ecx + xor edx, edx + div ecx + stdcall build_prp_list, eax + test eax, eax + jz .free_prp_list + mov dword [edi + 4], eax + jmp .success + +.free_prp_list: + invoke KernelFree, eax + .err: + mov eax, dword [edi] + test eax, eax + jz @f + invoke KernelFree, eax + +@@: xor eax, eax - pop ebx edi esi + pop edi esi + ret + +.success: + xor eax, eax + inc eax + pop edi esi ret endp @@ -830,6 +832,7 @@ proc nvme_init stdcall, pci:dword stdcall memset, eax, 0, sizeof.NVM_QUEUE_ENTRY * (LAST_QUEUE_ID + 1) ; Allocate submission/completion queue pointers + ; TODO: Make these queues physically contiguous xor ecx, ecx @@: push ecx @@ -907,6 +910,7 @@ proc nvme_init stdcall, pci:dword DEBUGF DBG_INFO, "nvme%u: I/O controller detected...\n", [esi + pcidev.num] @@: + ; TODO: check IDENTC.AVSCC mov al, byte [edi + IDENTC.sqes] and al, 11110000b cmp al, 0x60 ; maximum submission queue size should at least be 64 bytes diff --git a/drivers/nvme/nvme.inc b/drivers/nvme/nvme.inc index 45e7f7c..1c16782 100644 --- a/drivers/nvme/nvme.inc +++ b/drivers/nvme/nvme.inc @@ -16,7 +16,6 @@ VS121 = 0x00010201 ; (v1.2.1) VS130 = 0x00010300 ; (v1.3.0) VS140 = 0x00010400 ; (v1.4.0) -PAGE_SIZE = 4096 NVM_CMDS = 64 ; Number of Commands NVM_MPS = 0 ; Memory Page Size (2 ^ (12 + MPS)) NVM_ASQS = 63 ; Admin Submission Queue Size @@ -24,6 +23,7 @@ NVM_ACQS = NVM_ASQS ; Admin Completion Queue Size LAST_QUEUE_ID = 1 ; Index of the last queue SQ_ENTRIES = NVM_ASQS ; I/O and Admin Submission Queue Size CQ_ENTRIES = NVM_ACQS ; I/O and Admin Completion Queue Size +PAGE_SIZE = 4096 shl NVM_MPS ADMIN_QUEUE = 0 ; Admin Queue ID