# Nvme

## Function Table

| Address | Name | Description |
|---------|------|-------------|
|  | **NvmeDriverEntryPoint** |  |
|  | **NvmeMainEntry** |  |
|  | **NvmeTimerCallback1** |  |
|  | **NvmeTimerCallback2** |  |
|  | **NvmeDetectAndStart** |  |
|  | **NvmeInitController** |  |
|  | **NvmeSubmitAdminCommand** |  |
|  | **NvmePassThru** |  |
|  | **NvmeReadSectors** |  |
|  | **NvmeCopyUnicodeToAscii** |  |
|  | **NvmeMmioRead32** |  |
|  | **NvmeMmioWrite32** |  |
|  | **NvmeAdminSetFeatures** |  |
|  | **NvmeInstallBlockIo** |  |
| Globals | **- populated at module entry** |  |
| extern | **EFI_HANDLE         gImageHandle;** |  |
| qword_9040 | **- 4920 bytes** |  |
| qword_9020 | **- 4096 bytes** |  |
| qword_9018 | **- 48 bytes** |  |
| qword_9038 | **- protocol table** |  |
| ImageHandle_0 | **@ 0x8FA0** |  |
| byte_8FC0 | **UINT8                     gNvmeLegacyNsNext;       // byte_8FD8 - next free NS slot** |  |
| byte_8FC0 | **bit 0** |  |
| Protocol | **GUIDs stored in .rdata / known from table at 0x8D80** |  |
| EFI_GUID | **gEfiSmmIoProtocolGuid        = {0x8E,0xC6,0x9D,0xBD,0x4C,0x9D,0x94,0xDB,0x65,0xAC,0xC5,0xC3,0x32,0x28,0xB8,0xB2};** |  |
| 0x3D4 | **ModuleEntryPoint (NVMe Driver Entry Point)** |  |
| EFI_STATUS | **EFIAPI** |  |
| Initialize | **SMM I/O protocol and debug infrastructure** |  |
| NvmeInitSmmIo | **();** |  |
| Enable | **debug assertions and output for the driver** |  |
| if | **((INT8)*((UINT8*)NvmeGetCmosAddress (0xF9C4)) >= 0) {** |  |
| Delay | **/ stall for port initialization** |  |
| UINT16 | **StallStatus = IoRead16 (0x80);** |  |
| EFI_STATUS | **NvmeMainEntry (** |  |
| GUID | **for MemoryOverwriteRequestControl variable (MorControl)** |  |
| EFI_GUID | **MorGuid = {0xE20939BE, 0x7AD8, 0x4D6F, {0xA0, 0xE1, 0x3A, 0xF5, 0x6E, 0xE0, 0xE1, 0xA4}};** |  |
| Allocate | **4920 bytes for NVME_CONTROLLER** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 4920, &gNvmeControllerBuffer);** |  |
| Allocate | **4096-byte identify buffer** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 4096, &gNvmeIdentifyBuffer);** |  |
| Allocate | **48-byte features buffer** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 48, &gNvmeFeaturesBuffer);** |  |
| Allocate | **0-sized protocol buffer (just handle table)** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 0, &gNvmeProtocolBuffer);** |  |
| Install | **timer callback for SMI watchdog (sub_494C)** |  |
| Status | **= gBS->SetTimer (** |  |
| 8 | *** 10ms?** |  |
| Open | **the driver binding protocol on our image handles** |  |
| Status | **= gBS->OpenProtocol (** |  |
| Install | **second timer callback (sub_4A40)** |  |
| Open | **protocol on second table (unk_8E60)** |  |
| Install | **the component name / driver family protocol** |  |
| gNvmeBlockIoHandle | **= NULL;** |  |
| Register | **the legacy SMM NVMe handler** |  |
| Status | **= gBS->RegisterProtocolNotify (** |  |
| Set | **MemoryOverwriteRequestControl variable** |  |
| UINT16 | **MorData = 1;** |  |
| Sends | **SMI/SW SMI to update controller context** |  |
| Clear | **and set up the SW SMI data buffer (gNvmeControllerBuffer)** |  |
| Locate | **the SMM communication protocol and trigger SMI** |  |
| Status | **= gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, &SmmCommunicationProtocol);** |  |
| Prepare | **communication buffer** |  |
| Send | **the communication** |  |
| Signal | **the timer event completion** |  |
| Iterates | **all NVME partitions and records legacy device info** |  |
| Get | **list of all handles with EFI_NVM_EXPRESS_PASS_THRU protocol** |  |
| Status | **= gBS->LocateHandleBuffer (** |  |
| Iterate | **up to 32 handles, for each** |  |
| for | **(Index = 0; Index < HandleCount && Index < 32; Index++) {** |  |
| Prepare | **the name string for "AMI NVMe BUS Driver" component** |  |
| Copy | **the NVME_CONTROLLER data (424 bytes @ 0x8D80 area)** |  |
| Copy | **the controller's namespace bitfield into identify buffer** |  |
| Controller | **= (NVME_CONTROLLER*)NvmeControllerData;** |  |
| Enumerate | **namespace list** |  |
| LIST_ENTRY | ***NamespaceList = &Controller->NamespaceList;** |  |
| Identify | **namespace data via protocol** |  |
| NvmeIdentifyNamespace | **(Controller, Ns);** |  |
| Copy | **namespace data into the scratch buffer** |  |
| Copy | **media info from identify** |  |
| Mark | **if last node** |  |
| if | **(Node->ForwardLink == NamespaceList) {** |  |
| Called | **from DriverBinding.Start** |  |
| EFI_STATUS | **NvmeDetectAndStart (** |  |
| Ensure | **device does not already have NvmePassThru installed** |  |
| Already | **has pass-thru protocol** | skip NVMe detection |
| goto | **SKIP_NVME;** |  |
| Open | **DevicePath protocol (required for NVMe)** |  |
| Open | **PCI_IO protocol** |  |
| Detect | **the NVME device - open controller** |  |
| if | **(Status != EFI_ALREADY_STARTED) {** |  |
| Initialize | **the controller structure** |  |
| Status | **= NvmeInitController (ControllerHandle, This->DriverBindingHandle, &Controller);** |  |
| Allocate | **namespace data buffer (4096 bytes)** |  |
| UINT64 | **NamespaceBuffer;** |  |
| Set | **up IO queues** |  |
| Status | **= NvmeCreateIoSubmissionQueue (Controller, NamespaceBuffer, 1, 0);** |  |
| Set | **up IO completion queues** |  |
| NvmeSetQueueInterruptCoalescing | **(Controller);** |  |
| Set | **additional queue configuration** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 0x8000, &Controller->IoCompletionQueue);** |  |
| Set | **max queue entries** |  |
| if | **(Controller->Version < 0x10100) {** |  |
| Create | **IO completion queue** |  |
| Status | **= NvmeCreateIoCompletionQueue (Controller, Controller->AdminSubmissionQueue, 1, QueueSize);** |  |
| Create | **child protocol handle** |  |
| VOID | ***ChildBuffer;** |  |
| Set | **up pass-through protocol instance** |  |
| PassthruProtocol | **= (EFI_NVM_EXPRESS_PASS_THRU*)ChildBuffer;** |  |
| Wire | **up protocol function pointers** |  |
| Install | **the protocol** |  |
| Status | **= gBS->InstallMultipleProtocolInterfaces (** |  |
| Initialize | **the namespace list (linked list head)** |  |
| InitializeListHead | **(&Controller->NamespaceList);** |  |
| If | **RemainingDevicePath provided, process it** |  |
| if | **(RemainingDevicePath != NULL) {** |  |
| while | **(TRUE) {** |  |
| Iterate | **to find all namespaces** |  |
| LIST_ENTRY | ***FirstEntry = Controller->NamespaceList.ForwardLink;** |  |
| only | **one entry** |  |
| Get | **the namespace node** |  |
| NVME_NAMESPACE | ***EntryNs = (NVME_NAMESPACE*)((UINT8*)FirstEntry - OFFSET_OF_NS_ENTRY);** |  |
| Try | **to locate and call external protocols for advanced features** |  |
| if | **(gNvmeBlockIoHandle != NULL) {** |  |
| Block | **I/O installation** |  |
| if | **(gNvmeBlockIoHandle == NULL) {** |  |
| Try | **SMM communication protocol for BlockIoSmm** |  |
| if | **(gNvmeSmmCommProtocol == NULL || gNvmeSmmCommProtocol != NULL) {** |  |
| fallback | **}** |  |
| Install | **Block I/O and Disk I/O protocols** |  |
| Status | **= NvmeInstallBlockIo (This, Controller);** |  |
| Install | **driver diagnostic protocol** |  |
| Register | **for end of DXE notification** |  |
| if | **(gNvmeDriverBindingHandle == NULL) {** |  |
| If | **already started, just open pass-through on handle** |  |
| Set | **up I/O completion and SQs** |  |
| Register | **with SMM if needed** |  |
| Parses | **PCI IO, identifies controller capabilities, allocates admin** |  |
| EFI_STATUS | **NvmeInitController (** |  |
| Allocate | **controller structure (424 bytes)** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, sizeof (NVME_CONTROLLER), (VOID**)&Ctrl);** |  |
| Allocate | **PCI IO structure (24 bytes)** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 24, (VOID**)&Ctrl->PciIo);** |  |
| Initialize | **namespace linked list** |  |
| InitializeListHead | **(&Ctrl->NamespaceList);** |  |
| Open | **PCI_IO protocol to access the NVMe BAR** |  |
| Read | **PCI config space for MMIO base address (BAR 0)** |  |
| Status | **= TempPciIo->Pci.Read (TempPciIo, EfiPciIoWidthUint16, 0x24, 1, &Ctrl->MaxQueueEntries);** |  |
| Read | **capabilities (BAR size)** |  |
| UINT32 | **BarValue;** |  |
| Parse | **PCI IO BAR 0 to get MMIO base via GetBarAttributes** |  |
| Read | **the NVMe controller registers from MMIO** |  |
| UINT8 | **IdentifyBuffer[64];** |  |
| BAR0 | **0,  // offset to NVMe regs** |  |
| Decode | **NVMe capability register (CAP)** |  |
| CAP | **high** |  |
| Get | **max page entries and set namespace capacity** |  |
| Check | **controller ready status** |  |
| if | **((Ctrl->PageSize & 1) == 0) {** |  |
| Clear | **CSTS.CFS if set** |  |
| if | **((NvmeGetCapability (Ctrl, 20) & 1) != 0) {** |  |
| Wait | **for controller ready (CSTS.RDY)** |  |
| Configure | **the controller (CC register)** |  |
| Allocate | **admin submission queue (ASQ) buffer** |  |
| Allocate | **physically contiguous pages for admin queues** |  |
| Map | **the buffer** |  |
| Allocate | **second buffer for admin completion queue** |  |
| Set | **admin queue sizes (ASQ and ACQ entries)** |  |
| if | **(Ctrl->MaxQueueEntries < 0x100) {** |  |
| Zero | **the admin queues** |  |
| Set | **AQA (Admin Queue Attributes) register** |  |
| NvmeSetCapability | **(Ctrl, 36** |  |
| Enable | **the controller (CC.EN = 1)** |  |
| Allocate | **scratch buffer for admin commands (72 bytes)** |  |
| Status | **= gBS->AllocatePool (EfiBootServicesData, 72, &Ctrl->AdminCmdBuf);** |  |
| Enable | **the controller with set features** |  |
| Wait | **for ready** |  |
| Ctrl | **= (NVME_CONTROLLER*)Ctrl;  // keep consistent** |  |
| Submit | **admin command to set features (number of queues)** |  |
| Status | **= NvmeAdminSetFeatures (Ctrl, Ctrl->AdminCmdBuf);** |  |
| Install | **the pass-through protocol on the controller handle** |  |
| Wraps | **the command into a submission queue entry, writes doorbell.** |  |
| EFI_STATUS | **NvmeSubmitAdminCommand (** |  |
| The | **admin queue is now busy** |  |
| if | **(Controller->AdminBusy) {** |  |
| Get | **the current completion queue phase and index** |  |
| if | **(CmdType) {** |  |
| Flip | **the phase tag** |  |
| Get | **the submission entry** |  |
| CompletionIndex | **= CompletionHead;** |  |
| Wait | **for a free slot in the submission queue** |  |
| UINT32 | **TimeoutMs = 100 * Cmd->TimeoutMs;** |  |
| Check | **if slot is available** |  |
| if | **(((UINT16*)SubmissionEntry)[6] == CmdId &&** |  |
| Check | **phase tag** |  |
| UINT8 | **PhaseTag = CmdType ? QueueInfo[6] : QueueInfo[11];** |  |
| Check | **for controller fatal error** |  |
| if | **((NvmeGetCapability (Controller, 28) & 2) != 0) {** |  |
| Set | **doorbell register** |  |
| CompletionIndex | **= ((UINT16*)SubmissionEntry)[4];** |  |
| Write | **the submission queue tail doorbell** |  |
| NvmeMmioWrite | **(** |  |
| Copy | **completion result** |  |
| if | **(CplResult != NULL) {** |  |
| Advance | **the submission queue tail** |  |
| Main | **command dispatch for read/write/admin commands.** |  |
| Determine | **if admin or I/O command** |  |
| if | **(Command->IsAdmin) {** |  |
| Admin | **command -> submit via admin submission queue** |  |
| Status | **= NvmeSubmitAdminCommand (Controller, Command, NULL);** |  |
| switch | **(Command->Opcode) {** |  |
| EFI_STATUS | **NvmeReadSectors (** |  |
| Prepare | **the command** |  |
| NvmeZeroMem | **(&Cmd, sizeof (Cmd));** |  |
| namespace | **will be assigned** |  |
| Map | **the buffer for DMA** |  |
| DataPhys | **= (UINT64)Buffer;  // for simplicity, assume mapped** |  |
| PRP2 | **needed** |  |
| VOID | **NvmeCopyUnicodeToAscii (** |  |
| Basic | **ASCII-safe unicode copy** |  |
| while | **(*UnicodeStr) {** |  |
| UINT32 | **NvmeMmioRead32 (** |  |
| if | **(Controller->PciIo != NULL) {** |  |
| VOID | **NvmeMmioWrite32 (** |  |
| Sets | **features and triggers admin queue doorbell (ASQ tail doorbell)** |  |
| EFI_STATUS | **NvmeAdminSetFeatures (** |  |
| already | **in progress** |  |
| NCQR | **= 1, NSQR = 1 (one IO CQ, one IO SQ)** |  |
| Called | **after NVMe detection completes.** |  |
| EFI_STATUS | **NvmeInstallBlockIo (** |  |
| Get | **list of handles with NVME pass-thru protocol** |  |
| Allocate | **the Block IO protocol structure (72 bytes)** |  |
| VOID | ***BlockIoBuffer;** |  |
| Error | **condition, already reported** |  |
| NvmeDebugPrint | **(0x80000000LL, L"\nASSERT_EFI_ERROR (Status = %r)\n", Status);** |  |
| Iterate | **over all handles to install block I/O for each namespace** |  |
| for | **(Index = 0; Index < HandleCount; Index++) {** |  |
| Parse | **the namespace from the controller** |  |
| NVME_CONTROLLER | ***Ctrl = (NVME_CONTROLLER*)NvmeProtocolData;** |  |
| Prep | **the admin command for identify namespace** |  |
| NvmeZeroMem | **(BlockIoBuffer, 72);** |  |
| Send | **IDENTIFY (ACTIVE) command (Opcode=6, CNS=2)** |  |
| Send | **IDENTIFY (NS, CNS=0) to get namespace details** |  |
| Enable | **asynchronous event notification** |  |
| Determine | **the controller timeout for completion** |  |
| Wait | **for command completion (CSTS phase bit)** |  |
| while | **(((NvmeMmioRead32 (Ctrl, 28) & 0xC) != 8)) {** |  |
| 0x77F0 | **NvmeSubmitIoCommand** | Submit an I/O command to the SQ |
| Handles | **command slot allocation, doorbell registration.** |  |
| 0x79EC | **NvmeProcessCompletionQueue** | Process I/O completion queue |
| Reaps | **completions, re-arms the CQ doorbell, re-submits if needed.** |  |
| 0x2834 | **NvmeCreateDeviceNode** | Create a namespace device node |
| Walks | **the namespace list, allocates BlockIO/DevicePath protocols.** |  |
| 0x14A8 | **NvmeFreeDeviceMemory** | Free all allocated controller resources |
| Uninstalls | **protocols, frees buffers, maps, and the controller itself.** |  |
| 0x3120 | **NvmeSetQueueInterruptCoalescing** | Set IO queue interrupt |
| Configures | **the controller's interrupt coalescing registers.** |  |
| 0x244C | **NvmeCreateIoSubmissionQueue** | Create IO Submission Queue |
| Allocates | **the queue, maps to physical address, sends admin command.** |  |
| 0x6A1C | **NvmeCreateIoCompletionQueue** | Create IO Completion Queue |
| Allocates | **and maps the completion queue, enables controller.** |  |
| 0x3304 | **NvmeSecurityInit** | Security initialization (BlockSID) |
| Issues | **SAT3 Freeze Lock and BlockSID commands over pass-through.** |  |
| 0x4E80 | **NvmeLegacySmmHandler** | Handle legacy SMM event |
| Triggered | **at end of DXE to install legacy device protocols.** |  |
| 0x4C80 | **NvmeLegacyDeviceInstall** | Install NVMe legacy device protocol |
| Sends | **AQ commands for namespace flush then configures legacy path.** |  |
| 0x43F4 | **NvmeIdentifyNamespace** | Identify and record namespace info |
| Performs | **IDENTIFY command on a namespace via SMM communication.** |  |
| 0x467C | **NvmeLegacySmmProtocolInstall** | Install legacy SMM protocol |
| Adds | **the legacy NVMe device protocol to the SMM communication.** |  |

---
*Generated by HR650X BIOS Decompilation Project*