Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92bcb4a591 |
No files matched your search
@@ -593,7 +593,6 @@ tup.append_table(img_files, {
|
||||
{"DRIVERS/SIS.SYS", VAR_DRVS .. "/audio/sis.sys"},
|
||||
{"DRIVERS/SDHCI.SYS", "../drivers/sdhci/sdhci.sys"},
|
||||
{"DRIVERS/I2CHID.SYS", VAR_DRVS .. "/i2chid/i2chid.sys"},
|
||||
{"DRIVERS/NVME.SYS", VAR_DRVS .. "/nvme/nvme.sys"},
|
||||
})
|
||||
tup.append_table(extra_files, {
|
||||
{"HD_Load/9x2klbr/", VAR_PROGS .. "/hd_load/9x2klbr/9x2klbr.exe"},
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
/SYS/TMPDISK A0 0 # Add virtual RAM disk /tmp0/1
|
||||
/SYS/@RESHARE "" 0 # Shared resources
|
||||
/SYS/LOADDRV SDHCI 0 # Start SDHCI driver
|
||||
/SYS/LOADDRV NVME 0 # Start NVMe driver
|
||||
/SYS/@DOCKY "" 0 # Start docky
|
||||
/SYS/NETWORK/NETCFG A 0 # Init network driver
|
||||
/SYS/NETWORK/@ZEROCONF "" 0 # Network configuration
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
# NVMe driver
|
||||
|
||||
Driver for NVM Express controllers. Registers the first active namespace of every
|
||||
NVMe controller it finds as a KolibriOS disk named `nvme<controller>n<namespace>`, so
|
||||
that of the first controller usually shows up as `/nvme0n1/`.
|
||||
|
||||
## Origin
|
||||
|
||||
Written by Abdur-Rahman Mansoor for Google Summer of Code 2024, developed at
|
||||
<https://git.kolibrios.org/GSoC/kolibrios-nvme-driver> and proposed for the main tree
|
||||
as <https://git.kolibrios.org/KolibriOS/kolibrios/pulls/91>. Imported here from that
|
||||
repository's last commit (53c04b9, September 2024), which is newer than the pull
|
||||
request itself.
|
||||
|
||||
Licensed under the GNU General Public License, version 2.
|
||||
|
||||
## State
|
||||
|
||||
| Feature | Implemented | Notes |
|
||||
|------------------------------------|-------------|--------------------------------------------------------------------|
|
||||
| Mandatory administrator commands | Yes | |
|
||||
| Mandatory I/O commands | Yes | Reading and writing; requests are split to respect IDENTC.MDTS. |
|
||||
| Namespace identification | Yes | Across all controller versions. |
|
||||
| Multiple NVMe controllers | Yes | Up to `TOTAL_PCIDEVS`. |
|
||||
| Multiple namespaces per controller | No | Only the first active namespace is registered. |
|
||||
| Flush | Yes | Issued once the kernel has written out its own cache. |
|
||||
| Interrupts | No | Completions are polled; INTx, MSI and MSI-X are all disabled. |
|
||||
| Asynchronous API | No | Every command blocks the calling thread until it completes. |
|
||||
| SMART/health reporting | No | |
|
||||
|
||||
Sector sizes other than 512 bytes are rejected, because that is what KolibriOS
|
||||
supports, and so are LBA formats with metadata. The format checked is the one in use
|
||||
(FLBAS), not the first in the table.
|
||||
|
||||
## Interrupts
|
||||
|
||||
The driver does not use one. A thread that submits a command spins briefly on its
|
||||
completion and then reads the completion queues itself, using the phase tag; the
|
||||
controller's interrupt vectors are masked and INTx is disabled in the PCI command
|
||||
register, so the controller never signals anything. Since every command blocks its
|
||||
caller anyway, an interrupt would not make a completion arrive any sooner, while
|
||||
asking for one has real costs: many machines give an NVMe controller no usable INTx
|
||||
at all (MSI-X only, or firmware leaving the interrupt line at 0xFF), and the kernel's
|
||||
shared-IRQ heuristic can relink a handler onto the wrong line the first time an
|
||||
unrelated IRQ fires while a completion is pending - after which a level-triggered
|
||||
interrupt nobody services storms and freezes the machine. That last case was seen
|
||||
under QEMU while the driver still registered a handler.
|
||||
|
||||
Once the completion path becomes asynchronous, an MSI-X vector is the interrupt to
|
||||
add; there is nothing to gain from INTx before then.
|
||||
|
||||
Every wait on the controller (reset, enable, shutdown, command completion) is bounded,
|
||||
so a controller that never answers makes the driver give up rather than hang the boot.
|
||||
An I/O command that times out gets the controller reset and taken out of service, so
|
||||
that it cannot DMA into freed memory or complete a stale command later.
|
||||
Calls into the driver are serialised per controller, since the kernel may issue disk
|
||||
requests from several threads at once and the driver keeps one command in flight.
|
||||
|
||||
## Testing
|
||||
|
||||
Verified under QEMU (`-device nvme`) against controller version 1.4.0: driver load,
|
||||
partition detection, small and multi-megabyte file round trips, transfers from
|
||||
unaligned buffers checked against what actually landed on the disk image, and a boot
|
||||
of the same image with no NVMe controller present, where the driver has to back off
|
||||
without disturbing anything else.
|
||||
Also verified on VMware Workstation 17.6 (its controller reports firmware 1.3 and
|
||||
MDTS 8): the disk tests pass and the machine powers off cleanly, where the last
|
||||
upstream build faults during the 2 MB transfer and then hangs on shutdown. And on
|
||||
VirtualBox 7.2 (controller version 1.2.0, MDTS 0, i.e. no limit of its own): the same
|
||||
tests pass, the image is correct on the host, and the machine powers off. Real
|
||||
hardware is still untested.
|
||||
|
||||
Watch out when writing tests for this: a round trip done from inside KolibriOS can pass
|
||||
over corrupt data, because the kernel buffer the file was read back into may still hold
|
||||
the correct bytes from the write. What a transfer really left on the medium has to be
|
||||
checked from outside.
|
||||
|
||||
Two problems reported upstream are addressed here, both reproduced first and then
|
||||
confirmed fixed by running the last upstream build and this one against the same
|
||||
machine. The file corruption of
|
||||
[issue #7](https://git.kolibrios.org/GSoC/kolibrios-nvme-driver/issues/7) was PRP2
|
||||
being built as a list for transfers that fit in two memory pages, which the controller
|
||||
reads as a plain data pointer. The shutdown hang of
|
||||
[issue #5](https://git.kolibrios.org/GSoC/kolibrios-nvme-driver/issues/5) is visible on
|
||||
VMware Workstation, where the upstream build also faults inside the driver during a
|
||||
multi-megabyte transfer - VMware reports MDTS 8, so a 2 MB request is more than one
|
||||
command may carry, and the request was not being split.
|
||||
|
||||
## Building
|
||||
|
||||
The driver builds with the tree (`drivers/nvme/Tupfile.lua`) and is copied into the
|
||||
image as `DRIVERS/NVME.SYS`. To build it by hand:
|
||||
|
||||
fasm nvme.asm nvme.sys
|
||||
kpack nvme.sys
|
||||
@@ -1,3 +0,0 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
ROOT = "../.."
|
||||
tup.rule("nvme.asm", "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "%B.sys")
|
||||
@@ -1,243 +0,0 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; GNU GENERAL PUBLIC LICENSE ;;
|
||||
;; Version 2, June 1991 ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
proc set_cdw0 stdcall, pci:dword, y:dword, opcode:byte
|
||||
|
||||
stdcall get_new_cid, [pci], [y]
|
||||
shl eax, 16
|
||||
or al, [opcode]
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See pages 161-205 of the NVMe 1.4 specification for reference
|
||||
proc nvme_identify stdcall, pci:dword, nsid:dword, prp1:dword, cns:byte
|
||||
|
||||
push esi
|
||||
mov esi, [pci]
|
||||
mov dword [esi + pcidev.spinlock], 1
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
|
||||
mov eax, [nsid]
|
||||
mov dword [esp + SQ_ENTRY.nsid], eax
|
||||
mov eax, [prp1]
|
||||
mov dword [esp + SQ_ENTRY.prp1], eax
|
||||
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_IDENTIFY
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
mov al, [cns]
|
||||
mov byte [esp + SQ_ENTRY.cdw10], al
|
||||
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
|
||||
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
stdcall nvme_poll, esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See page 101 of the NVMe 1.4 specification for reference
|
||||
proc create_io_completion_queue stdcall, pci:dword, prp1:dword, qid:dword, ien:byte
|
||||
|
||||
push esi
|
||||
mov esi, [pci]
|
||||
mov dword [esi + pcidev.spinlock], 1
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_CRE_IO_COMPLETION_QUEUE
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
mov eax, [prp1]
|
||||
mov dword [esp + SQ_ENTRY.prp1], eax
|
||||
mov eax, (CQ_ENTRIES - 1) shl 16 ; CDW10.QSIZE (0's based)
|
||||
or eax, [qid] ; CDW10.QID
|
||||
mov dword [esp + SQ_ENTRY.cdw10], eax
|
||||
movzx eax, [ien] ; CDW11.IEN
|
||||
or eax, 0x1 ; CDW11.PC
|
||||
; Don't set CDW11.IV since we're not using MSI-X or MSI vector
|
||||
mov dword [esp + SQ_ENTRY.cdw11], eax
|
||||
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
stdcall nvme_poll, esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See page 103-104 of the NVMe 1.4 specification for reference
|
||||
proc create_io_submission_queue stdcall, pci:dword, prp1:dword, qid:dword, cqid:word
|
||||
|
||||
push esi
|
||||
mov esi, [pci]
|
||||
mov dword [esi + pcidev.spinlock], 1
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_CRE_IO_SUBMISSION_QUEUE
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
mov eax, [prp1]
|
||||
mov dword [esp + SQ_ENTRY.prp1], eax
|
||||
mov eax, (SQ_ENTRIES - 1) shl 16 ; CDW10.QSIZE (0's based)
|
||||
or eax, [qid]
|
||||
mov dword [esp + SQ_ENTRY.cdw10], eax
|
||||
movzx eax, [cqid]
|
||||
shl eax, 16 ; CDW11.CQID
|
||||
or eax, 0x1 ; CDW11.PC (always set this to 1 as some devices may not support non-contiguous pages)
|
||||
; TODO: Set CDW10.QPRIO
|
||||
mov dword [esp + SQ_ENTRY.cdw11], eax
|
||||
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
stdcall nvme_poll, esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See page 95-96 of the NVMe 1.4 specification for reference
|
||||
proc abort stdcall, pci:dword, cid:word, sqid:word
|
||||
|
||||
push esi
|
||||
mov esi, [pci]
|
||||
mov dword [esi + pcidev.spinlock], 1
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_ABORT
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
movzx eax, [cid]
|
||||
shl eax, 16
|
||||
mov ax, [sqid]
|
||||
mov dword [esp + SQ_ENTRY.cdw10], eax
|
||||
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
stdcall nvme_poll, esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
|
||||
; See page 205 of the NVMe 1.4 specification for reference
|
||||
proc set_features stdcall, pci:dword, prp1:dword, fid:byte, cdw11:dword
|
||||
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, [pci], ADMIN_QUEUE, ADM_CMD_SET_FEATURES
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
mov eax, [prp1]
|
||||
mov dword [esp + SQ_ENTRY.prp1], eax
|
||||
movzx eax, [fid]
|
||||
mov dword [esp + SQ_ENTRY.cdw10], eax
|
||||
mov eax, [cdw11]
|
||||
mov dword [esp + SQ_ENTRY.cdw11], eax
|
||||
stdcall sqytdbl_write, [pci], ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See page 105 of the NVMe 1.4 specification for reference
|
||||
proc delete_io_completion_queue stdcall, pci:dword, qid:word
|
||||
|
||||
push esi
|
||||
mov esi, [pci]
|
||||
mov dword [esi + pcidev.spinlock], 1
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_DEL_IO_COMPLETION_QUEUE
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
mov ax, [qid]
|
||||
mov word [esp + SQ_ENTRY.cdw10], ax
|
||||
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
stdcall nvme_poll, esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See page 114-116 of the NVMe 1.4 specification for reference
|
||||
proc get_features stdcall, pci:dword, prp1:dword, sel:byte, fid:byte
|
||||
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, [pci], ADMIN_QUEUE, ADM_CMD_GET_FEATURES
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
movzx eax, [sel]
|
||||
and eax, 111b
|
||||
shl eax, 8 ; CDW10.SEL
|
||||
mov al, [fid] ; CDW10.FID
|
||||
mov dword [esp + SQ_ENTRY.cdw10], eax
|
||||
mov eax, [prp1]
|
||||
mov dword [esp + SQ_ENTRY.prp1], eax
|
||||
; TODO: Implement CDW14.UUID?
|
||||
stdcall sqytdbl_write, [pci], ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
; See page 105-106 of the NVMe 1.4 specification for reference
|
||||
proc delete_io_submission_queue stdcall, pci:dword, qid:word
|
||||
|
||||
push esi
|
||||
mov esi, [pci]
|
||||
mov dword [esi + pcidev.spinlock], 1
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
stdcall set_cdw0, esi, ADMIN_QUEUE, ADM_CMD_DEL_IO_SUBMISSION_QUEUE
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax
|
||||
mov ax, [qid]
|
||||
mov word [esp + SQ_ENTRY.cdw10], ax
|
||||
stdcall sqytdbl_write, esi, ADMIN_QUEUE, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
stdcall nvme_poll, esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
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:qword, nlb:dword, opcode:dword
|
||||
|
||||
; TODO: Use IDENTC.NOIOB to construct read/write commands that don't
|
||||
; cross the I/O boundary to achieve optimal performance
|
||||
;
|
||||
; TODO: Read AWUN/NAWUN
|
||||
sub esp, sizeof.SQ_ENTRY
|
||||
mov eax, esp
|
||||
stdcall memsetdz, eax, sizeof.SQ_ENTRY / 4
|
||||
movzx ecx, [qid]
|
||||
stdcall set_cdw0, [pci], ecx, [opcode]
|
||||
mov dword [esp + SQ_ENTRY.cdw0], eax ; CDW0
|
||||
mov eax, dword [prps]
|
||||
mov dword [esp + SQ_ENTRY.prp1], eax
|
||||
mov eax, dword [prps + 4]
|
||||
mov dword [esp + SQ_ENTRY.prp2], eax
|
||||
mov eax, [nsid]
|
||||
mov dword [esp + SQ_ENTRY.nsid], eax
|
||||
mov eax, dword [slba] ; slba_lo
|
||||
mov dword [esp + SQ_ENTRY.cdw10], eax
|
||||
mov eax, dword [slba + 4] ; slba_hi
|
||||
mov dword [esp + SQ_ENTRY.cdw11], eax
|
||||
mov eax, [nlb]
|
||||
mov word [esp + SQ_ENTRY.cdw12], ax
|
||||
movzx ecx, [qid]
|
||||
stdcall sqytdbl_write, [pci], ecx, esp
|
||||
add esp, sizeof.SQ_ENTRY
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; GNU GENERAL PUBLIC LICENSE ;;
|
||||
;; Version 2, June 1991 ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
proc memsetdz stdcall, dest:dword, sz:dword
|
||||
|
||||
push edi
|
||||
mov edi, [dest]
|
||||
mov ecx, [sz]
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
pop edi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
proc memcpyd stdcall, dest:dword, src:dword, sz:dword
|
||||
|
||||
push esi edi
|
||||
mov esi, [src]
|
||||
mov edi, [dest]
|
||||
mov ecx, [sz]
|
||||
rep movsd
|
||||
pop edi esi
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,602 +0,0 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2024. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; GNU GENERAL PUBLIC LICENSE ;;
|
||||
;; Version 2, June 1991 ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
define LOG2 bsr
|
||||
|
||||
; NVMe Controller Versions
|
||||
VS100 = 0x00010000 ; (v1.0.0)
|
||||
VS110 = 0x00010100 ; (v1.1.0)
|
||||
VS120 = 0x00010200 ; (V1.2.0)
|
||||
VS121 = 0x00010201 ; (v1.2.1)
|
||||
VS130 = 0x00010300 ; (v1.3.0)
|
||||
VS140 = 0x00010400 ; (v1.4.0)
|
||||
|
||||
NVM_MPS = 0 ; Memory Page Size (2 ^ (12 + MPS))
|
||||
NVM_ASQS = 64 ; Admin Submission Queue Size
|
||||
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 ; Use 4KiB pages
|
||||
SUPPORTED_LBADS = 9 ; KolibriOS only supports LBADS of 512, later on we may remove this restriction
|
||||
SQ_ALLOC_SIZE = 0x1000
|
||||
CQ_ALLOC_SIZE = 0x1000
|
||||
QUEUE_ALLOC_SIZE = SQ_ALLOC_SIZE + CQ_ALLOC_SIZE
|
||||
|
||||
; Upper bound on the number of memory pages a single I/O command may span. A PRP
|
||||
; list holds PAGE_SIZE/8 entries, so staying well below that keeps every transfer
|
||||
; describable by one non-chained PRP list.
|
||||
MAX_PRP_PAGES = 256
|
||||
|
||||
PCI_MAX_CAPS = 48 ; a config space holds at most 48 capabilities
|
||||
|
||||
; Registers take the first page of the BAR, the doorbells start at 0x1000 with a
|
||||
; stride of 4 << CAP.DSTRD bytes; this much is mapped before CAP.DSTRD is known.
|
||||
MMIO_MIN_MAP_SIZE = 0x2000
|
||||
|
||||
; How long to wait on the controller, in milliseconds.
|
||||
CTRL_POLL_MS = 10
|
||||
SHUTDOWN_WAIT_MS = 5000
|
||||
IO_TIMEOUT_MS = 30000 ; how long a single I/O command may take
|
||||
POLL_SPINS = 64 ; lock checks between two looks at the completion queue
|
||||
IO_BUSY_ROUNDS = 20000 ; rounds to spend spinning before falling back to sleeping
|
||||
|
||||
MSIXCAP_CID = 0x11
|
||||
MSIXCAP_MXE = 1 shl 15 ; MSI-X Enable bit
|
||||
MSICAP_CID = 0x05
|
||||
MSICAP_MSIE = 1 ; MSI Enable bit
|
||||
|
||||
ADMIN_QUEUE = 0 ; Admin Queue ID
|
||||
|
||||
IEN_ON = 2
|
||||
IEN_OFF = 0
|
||||
|
||||
; Opcodes for NVM commands
|
||||
NVM_CMD_FLUSH = 0x00
|
||||
NVM_CMD_WRITE = 0x01
|
||||
NVM_CMD_READ = 0x02
|
||||
NVM_CMD_WRITE_UNCORRECTABLE = 0x04
|
||||
NVM_CMD_COMPARE = 0x05
|
||||
NVM_CMD_WRITE_ZEROES = 0x08
|
||||
NVM_CMD_DATASET_MANAGEMENT = 0x09
|
||||
NVM_CMD_VERIFY = 0x0C
|
||||
NVM_CMD_RESERVATION_REG = 0x0D
|
||||
NVM_CMD_RESERVATION_REPORT = 0x0E
|
||||
NVM_CMD_RESERVATION_ACQUIRE = 0x11
|
||||
NVM_CMD_RESERVATION_RELEASE = 0x15
|
||||
NVM_CMD_COPY = 0x19
|
||||
|
||||
; Opcodes for admin commands (Page 94 of NVMe 1.4 spec)
|
||||
ADM_CMD_DEL_IO_SUBMISSION_QUEUE = 0x00
|
||||
ADM_CMD_CRE_IO_SUBMISSION_QUEUE = 0x01
|
||||
ADM_CMD_GET_LOG_PAGE = 0x02
|
||||
ADM_CMD_DEL_IO_COMPLETION_QUEUE = 0x04
|
||||
ADM_CMD_CRE_IO_COMPLETION_QUEUE = 0x05
|
||||
ADM_CMD_IDENTIFY = 0x06
|
||||
ADM_CMD_ABORT = 0x08
|
||||
ADM_CMD_SET_FEATURES = 0x09
|
||||
ADM_CMD_GET_FEATURES = 0x0A
|
||||
|
||||
; fuse (fused operation): In a fused operation, a complex command is created by 'fusing' together
|
||||
; two simpler commands. This field specifies whether this command is part
|
||||
; of a fused operation, and if so, which command it is in the sequence:
|
||||
; 00b -> Normal operation
|
||||
; 01b -> Fused operation, first command
|
||||
; 10b -> Fused operation, second command
|
||||
; 11b -> Reserved
|
||||
NO_FUSE = 0
|
||||
FUSE_OP_FIRST_CMD = 1 shl 8
|
||||
FUSE_OP_SECOND_CMD = 2 shl 8
|
||||
|
||||
; sel (PRP or SGL for data transfer): This field specifies whether PRPs or SGLs are used for any
|
||||
; data transfer associated with the command. PRPs shall be
|
||||
; used for all Admin commands for NVMe over PCIe implementations.
|
||||
; SGLs shall be used for all Admin and I/O commands for NVMe over
|
||||
; Fabrics implementations (i.e., field set to 01b):
|
||||
; 00b -> PRPs are used for this transfer
|
||||
; 01b -> SGLs are used for this transfer, MPTR will contain address of
|
||||
; a single contiguous physical buffer that is byte aligned
|
||||
; 10b -> SGLs are used for this transfer. MPTR will contain address of
|
||||
; an SGL segment containing exactly one SGL descriptor that is
|
||||
; QWORD aligned
|
||||
; 11b -> Reserved
|
||||
SEL_PRP = 0
|
||||
SEL_SGL = 1 shl 14
|
||||
|
||||
; Controller or Namespace Structure (CNS) specifies the information to be returned to the host.
|
||||
CNS_IDNS = 0x0 ; Namespace data structure (NSID)
|
||||
CNS_IDCS = 0x1 ; Controller data structure
|
||||
CNS_ANIDL = 0x2 ; Active namespace ID list (NSID)
|
||||
CNS_NIDL = 0x3 ; Namespace identification descriptor list (NSID)
|
||||
CNS_NVM_SL = 0x4 ; NVM Set List
|
||||
|
||||
; Optional Admin Command Support (OACS) values
|
||||
OACS_SEC_SEN_RECV_SUPPORTED = 1 shl 0
|
||||
OACS_FMT_NVM_SUPPORTED = 1 shl 1
|
||||
OACS_FIRM_COMDL_SUPPORTED = 1 shl 2
|
||||
OACS_NSMAN_SUPPORTED = 1 shl 3
|
||||
|
||||
; scope is all attached namespaces or all namespaces in NVM subsystem
|
||||
NSID_BROADCAST = 0xFFFFFFFF
|
||||
|
||||
NSSRC_RESET = 0x4E564D65 ; "NVMe" (initiates a NVMe subsystem reset)
|
||||
|
||||
; NVMe Capabilities
|
||||
CAP_MQES = 0xffff
|
||||
CAP_CQR = 1 shl 16
|
||||
CAP_AMS = (1 shl 17) or (1 shl 18)
|
||||
CAP_TO = 0xff000000
|
||||
CAP_DSTRD = 1 or (1 shl 1) or (1 shl 2) or (1 shl 3)
|
||||
CAP_NSSRS = 1 shl 4
|
||||
CAP_CSS_NVM_CMDSET = 1 shl 5
|
||||
CAP_CSS_NOIO = 1 shl 12
|
||||
CAP_BPS = 1 shl 13
|
||||
CAP_CPS_COSCOP = 1 shl 15
|
||||
CAP_CPS_DOSCOP = 1 shl 16
|
||||
CAP_CPS_NVMSCOP = CAP_CPS_COSCOP or CAP_CPS_DOSCOP
|
||||
CAP_MPSMIN = 0xf shl 16 ; CAP bits 51:48
|
||||
CAP_MPSMAX = 0xf shl 20 ; CAP bits 55:52
|
||||
CAP_PMRS = 1 shl 24
|
||||
CAP_CMBS = 1 shl 25
|
||||
CAP_NSSS = 1 shl 27
|
||||
CAP_CRMS_CRWMS = 1 shl 28
|
||||
CAP_CRMS_CRIMS = 1 shl 29
|
||||
|
||||
; Controller Configuration Bits
|
||||
CC_EN = 1
|
||||
CC_CSS = (1 shl 4) or (1 shl 5) or (1 shl 6)
|
||||
CC_MPS = (1 shl 7) or (1 shl 8) or (1 shl 9) or (1 shl 10)
|
||||
CC_AMS = (1 shl 11) or (1 shl 12) or (1 shl 13)
|
||||
CC_SHN = (1 shl 14) or (1 shl 15)
|
||||
CC_IOSQES = (1 shl 16) or (1 shl 17) or (1 shl 18) or (1 shl 19)
|
||||
CC_IOCQES = (1 shl 20) or (1 shl 21) or (1 shl 22) or (1 shl 23)
|
||||
CC_CRIME = 1 shl 24
|
||||
|
||||
CC_SHN_NORMAL_SHUTDOWN = 1 shl 14
|
||||
CC_SHN_ABRUPT_SHUTDOWN = 1 shl 15
|
||||
|
||||
CC_DEFAULT_IOSQES = LOG2 sizeof.SQ_ENTRY shl 16
|
||||
CC_DEFAULT_IOCQES = LOG2 sizeof.CQ_ENTRY shl 20
|
||||
|
||||
; Completion Queue Entry Status Field Values
|
||||
CQ_PHASE_TAG = 1 shl 0
|
||||
CQ_STATUS_SC = 0xfe
|
||||
CQ_STATUS_SCT = (1 shl 9) or (1 shl 10) or (1 shl 11)
|
||||
CQ_STATUS_CRD = (1 shl 12) or (1 shl 13)
|
||||
CQ_STATUS_M = 1 shl 14
|
||||
CQ_STATUS_DNR = 1 shl 15
|
||||
|
||||
; Completion Queue Entry Status Field - Status Code Type Values
|
||||
CQ_STATUS_SCT_GCS = 0x0 ; Generic Command Status
|
||||
CQ_STATUS_SCT_CSS = 0x1 ; Command Specific Status
|
||||
CQ_STATUS_SCT_MADIE = 0x2 ; Media and Data Integrity Errors
|
||||
CQ_STATUS_SCT_PRS = 0x3 ; Path Related Status
|
||||
|
||||
; Completion Queue Entry Status Field - Status Code Generic Command Values
|
||||
CQ_STATUS_SC_GCS_SUCCESS = 0x00 ; Successful Completion
|
||||
CQ_STATUS_SC_GCS_ICOP = 0x01 ; Invalid Command Opcode
|
||||
CQ_STATUS_SC_GCS_IFIC = 0x02 ; Invalid Field in Command
|
||||
CQ_STATUS_SC_GCS_CIDC = 0x03 ; Command ID Conflict
|
||||
CQ_STATUS_SC_GCS_DTE = 0x04 ; Data Transfer Error
|
||||
CQ_STATUS_SC_GCS_CAPLN = 0x05 ; Commands Aborted due to Power Loss Notification
|
||||
CQ_STATUS_SC_GCS_INERR = 0x06 ; Internal Error
|
||||
CQ_STATUS_SC_GCS_CAR = 0x07 ; Command Abort Requested
|
||||
CQ_STATUS_SC_GCS_CASQD = 0x08 ; Command Aborted due to SQ Deletion
|
||||
CQ_STATUS_SC_GCS_CAFFC = 0x09 ; Command Aborted due to Failed Fused Command
|
||||
CQ_STATUS_SC_GCS_CAMFC = 0x0A ; Command Aborted due to Missing Fused Command
|
||||
CQ_STATUS_SC_GCS_INNOF = 0x0B ; Invalid Namespace or Format
|
||||
CQ_STATUS_SC_GCS_CSE = 0x0C ; Command Sequence Error
|
||||
CQ_STATUS_SC_GCS_INSGL = 0x0D ; Invalid SGL Segment Descriptor
|
||||
CQ_STATUS_SC_GCS_INNSGL = 0x0E ; Invalid Number of SGL Descriptors
|
||||
CQ_STATUS_SC_GCS_OPDEN = 0x15 ; Operation Denied
|
||||
CQ_STATUS_SC_GCS_NSIWP = 0x20 ; Namespace is Write Protected
|
||||
CQ_STATUS_SC_GCS_CINT = 0x21 ; Command Interrupted
|
||||
CQ_STATUS_SC_GCS_TTE = 0x22 ; Transient Transport Error
|
||||
|
||||
; Completion Queue Entry Status Field - Status Code Media and Data Integrity Errors
|
||||
CQ_STATUS_SC_MADIE_WF = 0x80 ; Write Fault
|
||||
CQ_STATUS_SC_MADIE_URE = 0x81 ; Unrecovered Read Error
|
||||
CQ_STATUS_SC_MADIE_ACDEN = 0x86 ; Access Denied
|
||||
CQ_STATUS_SC_MADIE_DOULB = 0x87 ; Deallocated or Unwritten Logical Block
|
||||
|
||||
; Controller Status (CSTS) Values
|
||||
CSTS_RDY = 1
|
||||
CSTS_CFS = 1 shl 1
|
||||
CSTS_SHST = (1 shl 2) or (1 shl 3)
|
||||
CSTS_NSSRO = 1 shl 4
|
||||
CSTS_PP = 1 shl 5
|
||||
CSTS_SHST_SHUTDOWN_OCCURRING = 1 shl 2
|
||||
CSTS_SHST_SHUTDOWN_COMPLETE = 1 shl 3
|
||||
|
||||
; Admin Queue Attributes (AQA) Values
|
||||
AQA_ASQS = 0xfff
|
||||
AQA_ACQS = 0xfff shl 16
|
||||
|
||||
; CDW10.SEL Values (Page 115 of NVMe 1.4 specification)
|
||||
CDW10_SEL_CURRENT = 000b
|
||||
CDW10_SEL_DEFAULT = 001b
|
||||
CDW10_SEL_SAVED = 010b
|
||||
CDW10_SEL_SUPPORTED_CAPABILITIES = 011b
|
||||
|
||||
; Feature Identifiers (FID) Values (Page 206 of NVMe 1.4 specification)
|
||||
; Used in Get/Set Features Commands
|
||||
FID_ARBITRATION = 0x01
|
||||
FID_POWER_MANAGEMENT = 0x02
|
||||
FID_LBA_RANGE_TYPE = 0x03
|
||||
FID_TEMPERATURE_THRESHOLD = 0x04
|
||||
FID_ERROR_RECOVERY = 0x05
|
||||
FID_VOLATILE_WRITE_CACHE = 0x06
|
||||
FID_NUMBER_OF_QUEUES = 0x07
|
||||
FID_INTERRUPT_COALESCING = 0x08
|
||||
FID_INTERRUPT_VECTOR_CONFIGURATION = 0x09
|
||||
FID_WRITE_ATOMICITY_NORMAL = 0x0A
|
||||
FID_ASYNCHRONOUS_EVENT_CONFIGURATION = 0x0B
|
||||
FID_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C
|
||||
FID_HOST_MEMORY_BUFFER = 0x0D
|
||||
FID_TIMESTAMP = 0x0E
|
||||
FID_KEEP_ALIVE_TIMER = 0x0F
|
||||
FID_HOST_CONTROLLED_THERMAL_MANAGEMENT = 0x10
|
||||
FID_NON_OPERATIONAL_POWER_STATE_CONFIG = 0x11
|
||||
FID_READ_RECOVERY_LEVEL_CONFIG = 0x12
|
||||
FID_PREDICTABLE_LATENCY_MODE_CONFIG = 0x13
|
||||
FID_PREDICTABLE_LATENCY_MODE_WINDOW = 0x14
|
||||
FID_LBA_STATUS_INFORMATION_REPORT_INTERVAL = 0x15
|
||||
FID_HOST_BEHAVIOR_SUPPORT = 0x16
|
||||
FID_SANITIZE_CONFIG = 0x17
|
||||
FID_ENDURANCE_GROUP_EVENT_CONFIGURATION = 0x18
|
||||
; NVM Command Set Specific - FID
|
||||
FID_SOFTWARE_PROGRESS_MARKER = 0x80
|
||||
FID_HOST_IDENTIFIER = 0x81
|
||||
FID_RESERVATION_NOTIFICATION_MASK = 0x82
|
||||
FID_RESERVATION_PERSISTENCE = 0x83
|
||||
FID_NAMESPACE_WRITE_PROTECTION_CONFIG = 0x84
|
||||
|
||||
; Get Log Page - Log Page Identifiers (Page 118-119 of NVMe 1.4 specification)
|
||||
LID_ERROR_INFORMATION = 0x01
|
||||
LID_SMARTHEALTH_INFORMATION = 0x02
|
||||
LID_FIRMWARE_SLOT_INFORMATION = 0x03
|
||||
LID_CHANGED_NAMESPACE_LIST = 0x04
|
||||
LID_COMMANDS_SUPPORTED_AND_EFFECTS = 0x05
|
||||
LID_DEVICE_SELF_TEST = 0x06
|
||||
LID_TELEMETRY_HOST_INITIATED = 0x07
|
||||
LID_TELEMETRY_CONTROLLER_INITIATED = 0x08
|
||||
LID_ENDURANCE_GROUP_INFORMATION = 0x09
|
||||
LID_PREDICTABLE_LATENCY_PER_NVM_SET = 0x0A
|
||||
LID_PREDICTABLE_LATENCY_EVENT_AGGREGATE = 0x0B
|
||||
LID_ASYMMETRIC_NAMESPACE_ACCESS = 0x0C
|
||||
LID_PERSISTENT_EVENT_LOG = 0x0D
|
||||
LID_LBA_STATUS_INFORMATION = 0x0E
|
||||
LID_ENDURANCE_GROUP_EVENT_AGGREGATE = 0x0F
|
||||
; I/O Command Set Specific - Log Page Identifiers
|
||||
LID_RESERVATION_NOTIFICATION = 0x80
|
||||
LID_SANITIZE_STATUS = 0x81
|
||||
|
||||
; Controller Type Values
|
||||
CNTRLTYPE_IO_CONTROLLER = 0x1
|
||||
CNTRLTYPE_DISCOVERY_CONTROLLER = 0x2
|
||||
CNTRLTYPE_ADMIN_CONTROLLER = 0x3
|
||||
|
||||
struct NVME_MMIO
|
||||
CAP dq ? ; Controller Capabilities
|
||||
VS dd ? ; Version
|
||||
INTMS dd ? ; Interrupt Mask Set
|
||||
INTMC dd ? ; Interrupt Mask Clear
|
||||
CC dd ? ; Controller Configuration
|
||||
rd 1 ; 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
|
||||
CMBSZ dd ? ; Controller Memory Buffer Size
|
||||
BPINFO dd ? ; Boot Partition Information
|
||||
BPRSEL dd ? ; Boot Partition Read Select
|
||||
BPMBL dq ? ; Boot Partition Memory Buffer Location
|
||||
CMBMSC dd ? ; Controller Memory Buffer Memory Space
|
||||
CMBSTS dd ? ; Controller Memory Buffer Status
|
||||
rb 3492 ; Reserved
|
||||
PMRCAP dd ? ; Persistent Memory Capabilities
|
||||
PMRCTL dd ? ; Persistent Memory Region Control
|
||||
PMRSTS dd ? ; Persistent Memory Region Status
|
||||
PMREBS dd ? ; Persistent Memory Region Elasticity Buffer Size
|
||||
PMRSWTP dd ? ; Persistent Memory Region Sustained Write Throughput
|
||||
PMRMSC dq ? ; Persistent Memory Region Controller Memory Space Control
|
||||
rb 484 ; Reserved
|
||||
SQ0TDBL dd ? ; Submission Queue 0 Tail Doorbell (Admin)
|
||||
ends
|
||||
|
||||
|
||||
; Submission Queue Entry (64 bytes)
|
||||
struct SQ_ENTRY
|
||||
cdw0 dd ?
|
||||
nsid dd ?
|
||||
cdw2 dd ?
|
||||
cdw3 dd ?
|
||||
mptr dq ?
|
||||
prp1 dq ?
|
||||
prp2 dq ?
|
||||
cdw10 dd ?
|
||||
cdw11 dd ?
|
||||
cdw12 dd ?
|
||||
cdw13 dd ?
|
||||
cdw14 dd ?
|
||||
cdw15 dd ?
|
||||
ends
|
||||
|
||||
; Completion Queue Entry (16 bytes) - See page 77 of the NVMe 1.4 spec
|
||||
struct CQ_ENTRY
|
||||
cdw0 dd ?
|
||||
rd 1 ; reserved
|
||||
sqhd dw ?
|
||||
sqid dw ?
|
||||
cid dw ?
|
||||
status dw ?
|
||||
ends
|
||||
|
||||
struct NSINFO
|
||||
capacity dq ?
|
||||
size dq ?
|
||||
nsid dd ?
|
||||
pci dd ?
|
||||
lbads db ?
|
||||
features db ?
|
||||
ends
|
||||
|
||||
struct pcidev
|
||||
bus db ?
|
||||
devfn db ?
|
||||
rb 2 ; align
|
||||
num dd ?
|
||||
io_addr dd ?
|
||||
queue_entries dd ?
|
||||
version dd ?
|
||||
nsid dd ?
|
||||
spinlock dd ?
|
||||
nsinfo dd ?
|
||||
last_status dd ? ; status field of the last completion, 0 when all went well
|
||||
nn dd ?
|
||||
last_cdw0 dd ? ; command specific result of the last completion
|
||||
max_sectors dd ? ; biggest transfer a single I/O command may carry
|
||||
disk dd ? ; handle from DiskAdd, 0 if none
|
||||
pcidev dd ? ; the kernel's PCIDEV, claimed through its owner field
|
||||
iolock MUTEX ; taken by whoever is using the I/O queue
|
||||
dstrd db ?
|
||||
mdts db ? ; Maximum Data Transfer Size, in 2^(12+MPSMIN) byte units
|
||||
ready db ? ; 1 while the controller serves I/O; 0 before, after cleanup or once it hung
|
||||
stuck db ? ; 1 if it hung and would not even go idle, so it may still DMA
|
||||
hung db ? ; 1 once any command timed out, init and cleanup included
|
||||
rb 3 ; align
|
||||
ends
|
||||
TOTAL_PCIDEVS = 4
|
||||
TOTAL_PCIDEVS_MALLOC_SZ = TOTAL_PCIDEVS * sizeof.pcidev
|
||||
|
||||
struct NVM_QUEUE_ENTRY
|
||||
tail dw ?
|
||||
head dw ?
|
||||
sq_ptr dd ?
|
||||
cq_ptr dd ?
|
||||
phase db ? ; phase tag the next completion of this queue will carry
|
||||
rb 19 ; pad to a power of two, the queue index is shifted by LOG2 of it
|
||||
ends
|
||||
|
||||
; Identify Controller Data Structure
|
||||
struct IDENTC
|
||||
|
||||
vid dw ?
|
||||
ssvid dw ?
|
||||
sn dt ?, ?
|
||||
mn rt 4
|
||||
fr dq ?
|
||||
rab db ?
|
||||
ieee db ?, ?, ?
|
||||
cmic db ?
|
||||
mdts db ?
|
||||
cntlid dw ?
|
||||
ver dd ?
|
||||
rtd3r dd ?
|
||||
rtd3e dd ?
|
||||
oaes dd ?
|
||||
ctratt dd ?
|
||||
rrls dw ?
|
||||
rb 9 ; reserved
|
||||
cntrltype db ?
|
||||
fguid dq ?, ?
|
||||
crdt1 dw ?
|
||||
crdt2 dw ?
|
||||
crdt3 dw ?
|
||||
rb 106 ; reserved
|
||||
rb 16 ; reserved (NVMMI)
|
||||
oacs dw ?
|
||||
acl db ?
|
||||
aerl db ?
|
||||
frmw db ?
|
||||
lpa db ?
|
||||
elpe db ?
|
||||
npss db ?
|
||||
avscc db ?
|
||||
apsta db ?
|
||||
wctemp dw ?
|
||||
cctemp dw ?
|
||||
mtfa dw ?
|
||||
hmpre dd ?
|
||||
hmmin dd ?
|
||||
tnvmcap dq ?, ?
|
||||
unvmcap dq ?, ?
|
||||
rpmbs dd ?
|
||||
edstt dw ?
|
||||
dsto db ?
|
||||
fwug db ?
|
||||
kas dw ?
|
||||
hctma dw ?
|
||||
mntmt dw ?
|
||||
mxtmt dw ?
|
||||
sanicap dd ?
|
||||
hmminds dd ?
|
||||
hmmaxd dw ?
|
||||
nsetidmax dw ?
|
||||
endgidmax dw ?
|
||||
anatt db ?
|
||||
anacap db ?
|
||||
anagrpmax dd ?
|
||||
nanagrpid dd ?
|
||||
pels dd ?
|
||||
rb 156
|
||||
sqes db ?
|
||||
cqes db ?
|
||||
maxcmd dw ?
|
||||
nn dd ?
|
||||
oncs dw ?
|
||||
fuses dw ?
|
||||
fna db ?
|
||||
vwc db ?
|
||||
awun dw ?
|
||||
awupf dw ?
|
||||
nvscc db ?
|
||||
nwpc db ?
|
||||
acwu dw ?
|
||||
rb 2
|
||||
sgls dd ?
|
||||
mnan dd ?
|
||||
rb 224
|
||||
subnqn rq 32
|
||||
rb 768
|
||||
rb 256
|
||||
psd0 rq 4
|
||||
psd1 rq 4
|
||||
psd2 rq 4
|
||||
psd3 rq 4
|
||||
psd4 rq 4
|
||||
psd5 rq 4
|
||||
psd6 rq 4
|
||||
psd7 rq 4
|
||||
psd8 rq 4
|
||||
psd9 rq 4
|
||||
psd10 rq 4
|
||||
psd11 rq 4
|
||||
psd12 rq 4
|
||||
psd13 rq 4
|
||||
psd14 rq 4
|
||||
psd15 rq 4
|
||||
psd16 rq 4
|
||||
psd17 rq 4
|
||||
psd18 rq 4
|
||||
psd19 rq 4
|
||||
psd20 rq 4
|
||||
psd21 rq 4
|
||||
psd22 rq 4
|
||||
psd23 rq 4
|
||||
psd24 rq 4
|
||||
psd25 rq 4
|
||||
psd26 rq 4
|
||||
psd27 rq 4
|
||||
psd28 rq 4
|
||||
psd29 rq 4
|
||||
psd30 rq 4
|
||||
psd31 rq 4
|
||||
rb 1024
|
||||
ends
|
||||
|
||||
; Identify Namespace Data Structure
|
||||
struct IDENTN
|
||||
nsze dq ?
|
||||
ncap dq ?
|
||||
nuse dq ?
|
||||
nsfeat db ?
|
||||
nlbaf db ?
|
||||
flbas db ?
|
||||
mc db ?
|
||||
dpc db ?
|
||||
dps db ?
|
||||
nmic db ?
|
||||
rescap db ?
|
||||
fpi db ?
|
||||
dlfeat db ?
|
||||
nawun dw ?
|
||||
nawupf dw ?
|
||||
nacwu dw ?
|
||||
nabsn dw ?
|
||||
nabo dw ?
|
||||
nabspf dw ?
|
||||
noiob dw ?
|
||||
nvmcap dq ?
|
||||
dq ?
|
||||
npwg dw ?
|
||||
npwa dw ?
|
||||
npdg dw ?
|
||||
npda dw ?
|
||||
nows dw ?
|
||||
rb 18
|
||||
anagrpid dd ?
|
||||
rb 3
|
||||
nsattr db ?
|
||||
nvmsetid dw ?
|
||||
endgid dw ?
|
||||
nguid dq ?
|
||||
dq ?
|
||||
eui64 dq ?
|
||||
lbaf0 dd ?
|
||||
lbaf1 dd ?
|
||||
lbaf2 dd ?
|
||||
lbaf3 dd ?
|
||||
lbaf4 dd ?
|
||||
lbaf5 dd ?
|
||||
lbaf6 dd ?
|
||||
lbaf7 dd ?
|
||||
lbaf8 dd ?
|
||||
lbaf9 dd ?
|
||||
lbaf10 dd ?
|
||||
lbaf11 dd ?
|
||||
lbaf12 dd ?
|
||||
lbaf13 dd ?
|
||||
lbaf14 dd ?
|
||||
lbaf15 dd ?
|
||||
rb 3904
|
||||
ends
|
||||
|
||||
; Namespace Granularity List (CNS 16h - Page 199 of NVMe specification 1.4)
|
||||
struct NSGRANLS
|
||||
|
||||
nga dd ?
|
||||
nod db ?
|
||||
rb 27 ; reserved
|
||||
ngd0 dq ?, ?
|
||||
ngd1 dq ?, ?
|
||||
ngd2 dq ?, ?
|
||||
ngd3 dq ?, ?
|
||||
ngd4 dq ?, ?
|
||||
ngd5 dq ?, ?
|
||||
ngd6 dq ?, ?
|
||||
ngd7 dq ?, ?
|
||||
ngd8 dq ?, ?
|
||||
ngd9 dq ?, ?
|
||||
ngd10 dq ?, ?
|
||||
ngd11 dq ?, ?
|
||||
ngd12 dq ?, ?
|
||||
ngd13 dq ?, ?
|
||||
ngd14 dq ?, ?
|
||||
ngd15 dq ?, ?
|
||||
|
||||
ends
|
||||
|
||||
assert NVM_ASQS = NVM_ACQS
|
||||
assert SQ_ENTRIES = NVM_ASQS
|
||||
assert CQ_ENTRIES = NVM_ACQS
|
||||
assert NVM_MPS = 0
|
||||
assert CTRL_POLL_MS mod 10 = 0 ; nvme_poll waits it out in 1/100 s ticks
|
||||
assert PAGE_SIZE = 0x1000
|
||||
assert sizeof.NVME_MMIO = 4096
|
||||
assert sizeof.SQ_ENTRY = 64
|
||||
assert sizeof.CQ_ENTRY = 16
|
||||
assert sizeof.IDENTC = 4096
|
||||
assert sizeof.IDENTN = 4096
|
||||
assert sizeof.NSGRANLS = 288
|
||||
assert sizeof.NVM_QUEUE_ENTRY = 32
|
||||
|
||||
@@ -1233,25 +1233,27 @@ f68:
|
||||
mov eax, [ecx + SRV.entry]
|
||||
test eax, eax
|
||||
jz .fail
|
||||
push ecx ;save handl
|
||||
mov eax, -2 ;error free RAM
|
||||
cmp [ecx + SRV.base], 0
|
||||
je .fail
|
||||
|
||||
push ecx ;save handl
|
||||
mov ebp, esp ;START may be cdecl or stdcall
|
||||
push edx ;cmdline
|
||||
push DRV_EXIT
|
||||
call eax ;the result is not checked
|
||||
lea esp, [esp+8]
|
||||
push ecx
|
||||
call [ecx + SRV.entry] ;the result is not checked
|
||||
mov esp, ebp
|
||||
pop esi
|
||||
|
||||
mov ebx, [ecx + SRV.base]
|
||||
mov eax, -2 ;error free RAM
|
||||
test ebx, ebx
|
||||
jz .fail
|
||||
stdcall kernel_free, ebx ;del driver
|
||||
|
||||
mov eax, [ecx + SRV.fd]
|
||||
mov edx, [ecx + SRV.bk]
|
||||
mov eax, [esi + SRV.fd]
|
||||
mov edx, [esi + SRV.bk]
|
||||
mov [edx + SRV.fd], eax
|
||||
mov [eax + SRV.bk], edx
|
||||
stdcall free, ecx
|
||||
push eax
|
||||
stdcall kernel_free, [esi + SRV.base] ;del driver
|
||||
mov eax, esi
|
||||
call free ;eax = mem
|
||||
pop eax
|
||||
;dec [count_services]
|
||||
|
||||
mov [esp + SYSCALL_STACK.eax], eax
|
||||
|
||||
Reference in new issue
Block a user