2
0
mirror of https://git.missingno.dev/kolibrios-nvme-driver/ synced 2024-12-22 22:08:47 +01:00

fix lots of nasty bugs!

This commit is contained in:
Abdur-Rahman Mansoor 2024-05-25 18:56:58 -04:00
parent e2e1e50490
commit 78af4fb996
2 changed files with 77 additions and 100 deletions

View File

@ -42,13 +42,13 @@ proc START c, reason:dword
test eax, eax
jz .err
xor ecx, ecx
mov ebx, eax
.loop:
stdcall device_is_compat, dword [ebx + ecx * sizeof.pcidev]
mov ebx, dword [p_nvme_devices]
stdcall device_is_compat, ebx
test eax, eax
jz @f
stdcall nvme_init, dword [ebx + ecx * sizeof.pcidev]
stdcall nvme_init, ebx
@@:
inc ecx
@ -157,20 +157,23 @@ proc detect_nvme
mov ebx, dword [p_nvme_devices]
test ebx, ebx
jnz @f
invoke KernelAlloc, TOTAL_PCIDEVS_MALLOC_SZ
invoke KernelAlloc, sizeof.pcidev
test eax, eax
jz .err_no_mem
mov dword [p_nvme_devices], eax
DEBUGF DBG_INFO, "(NVMe) Allocated pcidev struct at 0x%x\n", [p_nvme_devices]
@@:
mov ebx, dword [p_nvme_devices]
mov ecx, dword [pcidevs_len]
dec ecx
pop eax
mov ebx, dword [p_nvme_devices]
movzx edx, byte [eax + PCIDEV.bus]
mov byte [ebx + ecx * sizeof.pcidev + pcidev.bus], dl
mov byte [ebx + pcidev.bus], dl
movzx edx, byte [eax + PCIDEV.devfn]
mov byte [ebx + ecx * sizeof.pcidev + pcidev.devfn], dl
mov byte [ebx + pcidev.devfn], dl
pop edx
jmp .next_dev
@ -188,44 +191,30 @@ endp
proc device_is_compat stdcall, pci:dword
push ebx
invoke PciRead32, dword [pci + pcidev.bus], dword [pci + pcidev.devfn], PCI_header00.base_addr_0
push ebx
mov ebx, [pci]
invoke PciRead32, dword [ebx + pcidev.bus], dword [ebx + pcidev.devfn], PCI_header00.base_addr_0
and eax, 0xfffffff0
test eax, eax
jz .failure
invoke MapIoMem, eax, sizeof.NVME_REG_MAP, PG_SW+PG_NOCACHE
invoke MapIoMem, eax, sizeof.NVME_MMIO, PG_SW+PG_NOCACHE
test eax, eax
jz .failure
mov dword [pci + pcidev.mmio_ptr], eax
mov ebx, dword [eax + NVME_REG_MAP.VS]
if __DEBUG__
push ecx
mov ecx, ebx
shr ecx, 16
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe controller version: %u.%u.%u\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn], ecx, bh, bl
pop ecx
end if
if 0
cmp ebx, NVM_SUPPORTED_CONTROLLER_VERSION
jne .unsupported
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe controller version is supported\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn]
end if
DEBUGF DBG_INFO, "(NVMe) MMIO allocated at: 0x%x\n", eax
mov ebx, [pci]
mov dword [ebx + pcidev.mmio_ptr], eax
mov eax, dword [eax + NVME_MMIO.VS]
DEBUGF DBG_INFO, "(NVMe) controller version: 0x%x\n", eax
pop ebx
xor eax, eax
inc eax
pop ebx
ret
.unsupported:
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): unsupported controller version\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn]
.failure:
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): something went wrong checking NVMe device compatibility\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn]
xor eax, eax
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): something went wrong checking NVMe device compatibility\n", byte [ebx + pcidev.bus], byte [ebx + pcidev.devfn]
pop ebx
xor eax, eax
ret
endp
@ -233,81 +222,69 @@ endp
; nvme_init: Initializes the NVMe controller
proc nvme_init stdcall, pci:dword
push ebx ecx
mov eax, dword [pci + pcidev.mmio_ptr]
mov bx, word [eax + NVME_REG_MAP.CAP]
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe maximum queue entries supported: %u\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn], bx
push ebx
mov eax, dword [pci]
mov eax, dword [eax + pcidev.mmio_ptr]
mov ebx, dword [eax + NVME_MMIO.CAP]
test ebx, CAP_CQR
jz .cqr_not_req
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe contiguous queues required\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn]
.cqr_not_req:
; For some reason, bit 7 (No I/O command set supported) is also set to 1 despite bit 0 (NVM command set)
; being set to 1.. so I am not sure if bit 7 should be checked at all.. investigate later.
mov ebx, dword [eax + NVME_REG_MAP.CAP + 4]
mov ebx, dword [eax + NVME_MMIO.CAP + 4]
test ebx, CAP_CSS_NVM_CMDSET
jz .exit_fail
if __DEBUG__
mov ecx, ebx
and ebx, CAP_MPSMIN
and ecx, CAP_MPSMAX
shr ebx, 16
shr ecx, 16
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe memory page size minimum: %u\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn], ebx
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe memory page size maximum: %u\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn], ecx
end if
; Reset controller
mov ebx, dword [eax + NVME_REG_MAP.CC]
stdcall nvme_controller_reset, [pci]
xor eax, eax
inc eax
pop ecx ebx
pop ebx
ret
.exit_fail:
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): failed to initialize NVMe controller\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn]
xor eax, eax
pop ecx ebx
pop ebx
ret
endp
proc nvme_controller_reset stdcall, pci:dword
DEBUGF DBG_INFO, "(NVMe) Resetting Controller...\n"
push ebx
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): Resetting NVMe controller\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn]
mov eax, dword [pci + pcidev.mmio_ptr]
mov ebx, dword [eax + NVME_REG_MAP.CSTS]
mov ebx, dword [pci]
mov ebx, dword [ebx + pcidev.mmio_ptr]
mov eax, dword [ebx + NVME_MMIO.CC]
and eax, 0xfffffffe ; CC.EN = 0
mov dword [ebx + NVME_MMIO.CC], eax
stdcall nvme_wait, [pci]
; Wait for controller to be brought to idle state, CSTS.RDY should be cleared to 0 when this happens
.wait:
test ebx, CSTS_RDY
mov eax, dword [ebx + NVME_MMIO.CSTS]
test eax, CSTS_RDY
jnz .wait
mov ebx, dword [eax + NVME_REG_MAP.CC]
PDEBUGF DBG_INFO, "PCI(%u.%u.%u): NVMe.CC = 0x%x\n", byte [pci + pcidev.bus], byte [pci + pcidev.devfn], ebx
and ebx, 0xfffffffe
mov dword [eax + NVME_REG_MAP.CC], ebx
stdcall nvme_wait, [pci]
DEBUGF DBG_INFO, "(NVMe) Successfully reset controller...\n"
pop ebx
ret
endp
; Should be called only after the value of CC.EN has changed
proc nvme_wait stdcall, pci:dword
push esi
mov eax, dword [pci + pcidev.mmio_ptr]
mov eax, dword [eax + NVME_REG_MAP.CAP]
mov eax, [pci]
mov eax, [eax + pcidev.mmio_ptr]
mov eax, dword [eax + NVME_MMIO.CAP]
and eax, CAP_TO
shr eax, 24
DEBUGF DBG_INFO, "CSTS.TO = %u\n", eax
mov esi, eax
;imul esi, 500
;invoke Sleep
pop esi
imul esi, 50
invoke Sleep
ret
endp
@ -316,17 +293,17 @@ proc nvme_cleanup
DEBUGF DBG_INFO, "(NVMe): Cleaning up...\n"
push ecx
xor ecx, ecx
mov eax, dword [p_nvme_devices]
mov ecx, eax
test eax, eax
jnz .loop
ret
.loop:
;invoke KernelFree, dword [p_nvme_devices + ecx * sizeof.pcidev + pcidev.ident_ptr]
inc ecx
cmp ecx, dword [pcidevs_len]
jne .loop
dec ecx
test ecx, ecx
jnz .loop
invoke KernelFree, dword [p_nvme_devices]
pop ecx
ret

View File

@ -163,41 +163,41 @@ CSTS_SHST = (1 shl 2) or (1 shl 3)
CSTS_NSSRO = 1 shl 4
CSTS_PP = 1 shl 5
struct NVME_REG_MAP
CAP rq 1 ; Controller Capabilities
VS rd 1 ; Version
INTMS rd 1 ; Interrupt Mask Set
INTMC rd 1 ; Interrupt Mask Clear
CC rd 1 ; Controller Configuration
rd 1 ; Reserved
CSTS rd 1 ; Controller Status
NSSR rd 1 ; NVM Subsystem Reset
AQA rd 1 ; Admin Queue Attributes
ASQ rq 1 ; Admin Submission Queue Base Address
ACQ rq 1 ; Admin Completion Queue Base Address
CMBLOC rd 1 ; Controller Memory Buffer Location
struct NVME_MMIO
CAP dq ? ; Controller Capabilities
VS dd ? ; Version
INTMS dd ? ; Interrupt Mask Set
INTMC dd ? ; Interrupt Mask Clear
CC dd ? ; Controller Configuration
dd ? ; Reserved
CSTS dd ? ; Controller Status
NSSR dd ? ; NVM Subsystem Reset
AQA dd ? ; Admin Queue Attributes
ASQ dq ? ; Admin Submission Queue Base Address
ACQ dq ? ; Admin Completion Queue Base Address
CMBLOC dd ? ; Controller Memory Buffer Location
ends
; Submission Queue Entry (64 bytes)
struct SQ_ENTRY
cdw0 rd 1
nsid rd 1
cdw2 rd 1
cdw3 rd 1
mptr rq 1
dptr rq 1
cdw10 rd 1
cdw11 rd 1
cdw12 rd 1
cdw13 rd 1
cdw14 rd 1
cdw15 rd 1
cdw0 dd ?
nsid dd ?
cdw2 dd ?
cdw3 dd ?
mptr dq ?
dptr dq ?
cdw10 dd ?
cdw11 dd ?
cdw12 dd ?
cdw13 dd ?
cdw14 dd ?
cdw15 dd ?
ends
; Completion Queue Entry (16 bytes)
struct CQ_ENTRY
cdw0 dd ?
dd ? ; reserved
rd 1 ; reserved
sqhd dw ?
sqid dw ?
cid dw ?
@ -207,7 +207,7 @@ ends
struct pcidev
bus db ?
devfn db ?
dw ?
rw 1
mmio_ptr dd ?
ends
TOTAL_PCIDEVS = 4