diff --git a/drivers/nvme/nvme.asm b/drivers/nvme/nvme.asm index 9ca7838..27bc115 100644 --- a/drivers/nvme/nvme.asm +++ b/drivers/nvme/nvme.asm @@ -551,26 +551,32 @@ proc build_prp_list stdcall, nprps:dword endp -proc alloc_dptr stdcall, ns:dword, prps_ptr:dword, start_sector:qword, numsectors:dword +proc alloc_dptr stdcall, ns:dword, prps_ptr:dword, numsectors:dword push esi edi - mov esi, [ns] mov edi, [prps_ptr] - mov dword [esi], 0 - mov dword [esi + 4], 0 - invoke KernelAlloc, PAGE_SIZE + mov dword [edi], 0 + mov dword [edi + 4], 0 + invoke AllocPage test eax, eax jz .err mov dword [edi], eax - ; is the number of sectors equal to two memory pages in size? + mov esi, [ns] + mov edx, [numsectors] mov eax, dword [esi + NSINFO.pg_sectors] + + ; is the number of sectors less than or equal to one memory page? + cmp eax, edx + jbe .success + + ; is the number of sectors equal to two memory pages in size? (todo: fix???) shl eax, 1 - cmp eax, [numsectors] + cmp eax, edx jne @f ; allocate a single PRP entry for PRP2 - invoke KernelAlloc, PAGE_SIZE + invoke AllocPage test eax, eax jz .err mov dword [edi + 4], eax @@ -596,7 +602,7 @@ proc alloc_dptr stdcall, ns:dword, prps_ptr:dword, start_sector:qword, numsector mov eax, dword [edi] test eax, eax jz @f - invoke KernelFree, eax + invoke FreePage, eax @@: xor eax, eax @@ -720,65 +726,67 @@ proc nvme_readwrite stdcall, ns:dword, dst:dword, start_sector:qword, numsectors push ebx esi edi sub esp, 16 - mov ebx, [numsectors_ptr] - mov ebx, [ebx] + mov ebx, esp + mov eax, [numsectors_ptr] + mov eax, dword [eax] mov dword [esp + 8], edx ; command type (read or write) - mov dword [esp + 12], ebx ; save original numsectors value + mov dword [esp + 12], eax ; save original numsectors value + mov esi, [ns] + mov edi, [dst] + mov edx, [numsectors_ptr] + mov edx, [edx] ; Note that [esp] will contain the value of PRP1 and [esp + 4] will ; contain the value of PRP2 (after this call, if it completes successfully) - stdcall alloc_dptr, [ns], esp, dword [start_sector], dword [start_sector + 4], ebx + stdcall alloc_dptr, esi, ebx, edx test eax, eax jz .end - invoke GetPhysAddr - mov esi, [ns] stdcall nvme_io_rw, [esi + NSINFO.pci], \ - 1, \ - [esi + NSINFO.nsid], \ - dword [esp], \ - dword [esp + 4], \ - dword [start_sector], \ - dword [start_sector + 4], \ - ebx, \ - dword [esp + 8] + 1, \ + [esi + NSINFO.nsid], \ + dword [ebx], \ + dword [ebx + 4], \ + dword [start_sector], \ + dword [start_sector + 4], \ + dword [ebx + 12], \ + dword [ebx + 8] ; assume command completes successfully for now ; Write PRP1 - stdcall write_prp_buf, [ns], dword [esp], [dst], [numsectors_ptr] + stdcall write_prp_buf, esi, dword [ebx], edi, [numsectors_ptr] test eax, eax jz .end ; check if PRP2 is needed at all mov ecx, dword [esi + NSINFO.pg_sectors] - cmp ecx, ebx + mov edx, dword [ebx + 8] + cmp edx, ecx jbe .end ; check if PRP2 should be a PRP list or a regular entry shl ecx, 1 - cmp ecx, ebx + cmp ecx, edx ja .is_prp_list ; PRP2 is a PRP entry - mov edi, [dst] - mov eax, dword [esp + 12] - mov edx, [ns] - imul eax, dword [edx + NSINFO.lbads] - mov ebx, [numsectors_ptr] - sub eax, dword [ebx] + mov eax, dword [ebx + 12] + imul eax, dword [esi + NSINFO.lbads] + mov edx, [numsectors_ptr] + sub eax, dword [edx] add edi, eax - stdcall write_prp_buf, [ns], dword [esp + 4], edi, [numsectors_ptr] + stdcall write_prp_buf, esi, dword [ebx + 4], edi, [numsectors_ptr] jmp .end .is_prp_list: - mov esi, [ns] + ; TODO: Fix this mov eax, ebx xor edx, edx mov ecx, dword [esi + NSINFO.lbads] div ecx mov ebx, eax - stdcall write_prp_list_buf, dword [esp + 4], [dst], ebx - stdcall free_prp_list, dword [esp + 4], ebx, FALSE + stdcall write_prp_list_buf, dword [ebx + 4], [dst], ebx + stdcall free_prp_list, dword [ebx + 4], ebx, FALSE .end: add esp, 16 @@ -788,7 +796,7 @@ proc nvme_readwrite stdcall, ns:dword, dst:dword, start_sector:qword, numsectors 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, prps:qword, slba_lo:dword, slba_hi:dword, nlb:word, opcode:dword +proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, prps:qword, slba:qword, 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 @@ -805,9 +813,9 @@ proc nvme_io_rw stdcall, pci:dword, qid:word, nsid:dword, prps:qword, slba_lo:dw mov dword [esp + SQ_ENTRY.dptr + 8], eax mov eax, [nsid] mov dword [esp + SQ_ENTRY.nsid], eax - mov eax, [slba_lo] + mov eax, dword [slba] ; slba_lo mov dword [esp + SQ_ENTRY.cdw10], eax - mov eax, [slba_hi] + mov eax, dword [slba + 4] ; slba_hi mov dword [esp + SQ_ENTRY.cdw11], eax movzx eax, [nlb] mov word [esp + SQ_ENTRY.cdw12], ax @@ -1171,12 +1179,12 @@ proc nvme_init stdcall, pci:dword test eax, eax jz .exit_fail mov edi, eax - invoke KernelAlloc, 0x4 + invoke KernelAlloc, 0x8 test eax, eax jz .exit_fail mov edx, NVM_CMD_READ mov dword [eax], 0x1 - stdcall nvme_readwrite, [esi + pcidev.nsinfo], edi, 1, eax + stdcall nvme_readwrite, [esi + pcidev.nsinfo], edi, 1, 0, eax test eax, eax jz .exit_fail DEBUGF DBG_INFO, "nvme%u: Successfully initialized driver\n", [esi + pcidev.num]