diff --git a/drivers/nvme/nvme.asm b/drivers/nvme/nvme.asm index 5336f0a..8245d37 100644 --- a/drivers/nvme/nvme.asm +++ b/drivers/nvme/nvme.asm @@ -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