| 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