Newer
Older
AMI-Aptio-BIOS-Reversed / Nvme / Nvme.c
@Ajax Dong Ajax Dong 2 days ago 49 KB Init
/*
 * Nvme.c -- UEFI SMM NVMe Bus Driver
 * Source: FlashDriverSmm.efi (HR650X BIOS, AmiModulePkg)
 * Image: PE32+ x64, entry 0x3D4, image size 0x9880
 * Source path: e:\hs\AmiModulePkg\Nvme\NvmeBus.c
 *
 * This driver manages NVMe SSD detection, configuration, I/O queue setup,
 * BlockSID security, and legacy device installation over PCI(e) NVMe
 * controllers.
 *
 * Architecture:
 *   ModuleEntryPoint -> NvmeDriverEntry (UEFI driver init)
 *                    -> NvmeMainEntry (driver binding installation)
 *   Driver Binding Start -> NvmeDetectAndStart -> NvmeInitController
 *                        -> NvmeInstallBlockIo -> NvmeInstallProtocols
 *
 * Source path strings from debug info confirm file NvmeBus.c.
 */

#include "Nvme.h"

//
// ========================================================================
// Globals - populated at module entry
// ========================================================================
//
extern EFI_HANDLE         gImageHandle;
EFI_SYSTEM_TABLE          *gST;
EFI_BOOT_SERVICES         *gBS;
EFI_RUNTIME_SERVICES      *gRT;

UINT64                    gNvmeControllerBuffer;   // qword_9040 - 4920 bytes
UINT64                    gNvmeIdentifyBuffer;     // qword_9020 - 4096 bytes
UINT64                    gNvmeFeaturesBuffer;     // qword_9018 - 48 bytes
UINT64                    gNvmeProtocolBuffer;     // qword_9038 - protocol table
EFI_HANDLE                gNvmeImageHandle;        // ImageHandle_0 @ 0x8FA0
UINT8                     gNvmeLegacySmmIndex;     // byte_8FC0
UINT8                     gNvmeLegacyNsNext;       // byte_8FD8 - next free NS slot
EFI_HANDLE                gNvmeChildHandle;        // @ 0x8FF8
EFI_HANDLE                gNvmeBlockIoHandle;      // gBS->InstallProtocolInterface handle @ 0x9008
EFI_HANDLE                gNvmePassthruHandle;     // @ 0x9010
EFI_HANDLE                gNvmeDevicePathHandle;   // @ 0x9028
VOID                      *gNvmeSmmCommProtocol;  // @ 0x9030
EFI_HANDLE                gNvmeDriverBindingHandle;// @ 0x9000
VOID                      *gNvmeSmmIoProtocol;    // @ 0x9068 - located via LocateProtocol
UINT8                     gNvmeFeaturePresent;    // 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
NvmeDriverEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  gImageHandle = ImageHandle;

  if (ImageHandle == NULL) {
    DEBUG ((EFI_D_ERROR, "gImageHandle != NULL\n"));
  }
  gST = SystemTable;
  if (SystemTable == NULL) {
    DEBUG ((EFI_D_ERROR, "gST != NULL\n"));
  }
  gBS = SystemTable->BootServices;
  if (gBS == NULL) {
    DEBUG ((EFI_D_ERROR, "gBS != NULL\n"));
  }
  gRT = SystemTable->RuntimeServices;
  if (gRT == NULL) {
    DEBUG ((EFI_D_ERROR, "gRT != NULL\n"));
  }

  //
  // Initialize SMM I/O protocol and debug infrastructure
  //
  NvmeInitSmmIo ();
  gNvmeSmmIoProtocol = (VOID*)(*(UINT64*)(NvmeLocateProtocol (&gEfiSmmIoProtocolGuid) + 32))(5);

  //
  // Enable debug assertions and output for the driver
  //
  if ((INT8)*((UINT8*)NvmeGetCmosAddress (0xF9C4)) >= 0) {
    NvmeDebugPrint ((UINT64)NvmeGetCmosAddress (0xF9C0), L"Enabled");
    *((UINT8*)NvmeGetCmosAddress (0xF9C4)) |= 0x80;
  }

  //
  // Delay / stall for port initialization
  //
  UINT16 StallStatus = IoRead16 (0x80);
  UINT64 EndTime = (NvmeGetTsc () & 0xFFFFFF) + 357;
  while ((((UINT32)EndTime + 357 - (UINT32)NvmeGetTsc ()) & 0x800000) == 0) {
    CpuPause ();
  }

  if ((StallStatus & 0x200) != 0) {
    return NvmeDisableInterrupts ();
  } else {
    return NvmeEnableInterrupts ();
  }
}

//
// ========================================================================
// 0x544  NvmeMainEntry -- Install driver binding and protocol interfaces
// ========================================================================
//
EFI_STATUS
NvmeMainEntry (
  IN EFI_HANDLE  ImageHandle
  )
{
  EFI_STATUS  Status;
  UINTN       Size;

  //
  // 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);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Allocate 4096-byte identify buffer
  //
  Status = gBS->AllocatePool (EfiBootServicesData, 4096, &gNvmeIdentifyBuffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Allocate 48-byte features buffer
  //
  Status = gBS->AllocatePool (EfiBootServicesData, 48, &gNvmeFeaturesBuffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Allocate 0-sized protocol buffer (just handle table)
  //
  Status = gBS->AllocatePool (EfiBootServicesData, 0, &gNvmeProtocolBuffer);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Install timer callback for SMI watchdog (sub_494C)
  //
  Status = gBS->SetTimer (
                  gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NvmeTimerCallback1, NULL),
                  TimerPeriodic,
                  80000  // 8 * 10ms?
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Open the driver binding protocol on our image handles
  // (open protocol with BY_DRIVER)
  //
  Status = gBS->OpenProtocol (
                  &gEfiNvmeProtocolTable,
                  ImageHandle_0,
                  &gNvmeProtocolBuffer
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Install second timer callback (sub_4A40)
  //
  Status = gBS->SetTimer (
                  gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NvmeTimerCallback2, NULL),
                  TimerPeriodic,
                  80000
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Open protocol on second table (unk_8E60)
  //
  Status = gBS->OpenProtocol (
                  &gEfiNvmeProtocolTable2,
                  ImageHandle_0,
                  &gNvmeProtocolBuffer
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Install the component name / driver family protocol
  //
  gNvmeBlockIoHandle = NULL;
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &gNvmeBlockIoHandle,
                  &gEfiNvmeComponentNameProtocol,
                  gNvmeComponentName,
                  &gEfiNvmeComponentName2Protocol,
                  gNvmeComponentName2,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Register the legacy SMM NVMe handler
  //
  Status = gBS->RegisterProtocolNotify (
                  &gEfiNvmeLegacyProtocol,
                  TPL_CALLBACK,
                  NvmeLegacySmmHandler,
                  &gNvmeChildHandle
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Set MemoryOverwriteRequestControl variable
  //
  UINT16 MorData = 1;
  gRT->SetVariable (
        L"MemoryOverwriteRequestControl",
        &MorGuid,
        0,
        sizeof (MorData),
        &MorData
        );

  return Status;
}

//
// ========================================================================
// 0x494C  NvmeTimerCallback1 -- First periodic timer (8 sec)
//   Sends SMI/SW SMI to update controller context
// ========================================================================
//
EFI_STATUS
EFIAPI
NvmeTimerCallback1 (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS  Status;
  UINT64      SwSmiData = 0x494D535753LL;  // "SMI SW" signature
  UINT64      BufferSize = 32;
  VOID        *SmmCommunicationProtocol;

  //
  // Clear and set up the SW SMI data buffer (gNvmeControllerBuffer)
  //
  gBS->SetMem ((VOID*)gNvmeControllerBuffer, 32, 0);

  //
  // Locate the SMM communication protocol and trigger SMI
  //
  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, &SmmCommunicationProtocol);
  if (!EFI_ERROR (Status)) {
    Status = gBS->LocateProtocol (&gEfiSmmSwapProtocolGuid, NULL, &gNvmeSmmCommProtocol);
    if (!EFI_ERROR (Status)) {
      //
      // Prepare communication buffer
      //
      gBS->CopyMem ((VOID*)gNvmeControllerBuffer, &gEfiNvmeProtocolBufferGuid, 16);
      *(UINT64*)(gNvmeControllerBuffer + 16) = 8;
      gBS->CopyMem ((VOID*)(gNvmeControllerBuffer + 24), &SwSmiData, 8);

      //
      // Send the communication
      //
      ((EFI_SMM_COMMUNICATION_PROTOCOL*)gNvmeSmmCommProtocol)->Communicate (
          gNvmeSmmCommProtocol,
          (VOID*)gNvmeControllerBuffer,
          &BufferSize
          );
    }
  }

  //
  // Signal the timer event completion
  //
  gBS->SignalEvent (Event);
  return EFI_SUCCESS;
}

//
// ========================================================================
// 0x4A40  NvmeTimerCallback2 -- Second periodic timer (8 sec)
//   Iterates all NVME partitions and records legacy device info
// ========================================================================
//
EFI_STATUS
EFIAPI
NvmeTimerCallback2 (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  UINTN                   HandleCount;
  EFI_HANDLE              *HandleBuffer;
  EFI_STATUS              Status;
  UINTN                   Index;
  UINT64                  NvmeControllerData;
  NVME_CONTROLLER         *Controller;

  //
  // Get list of all handles with EFI_NVM_EXPRESS_PASS_THRU protocol
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiNvmeExpressPassThruProtocolGuid,
                  NULL,
                  &HandleCount,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status) || HandleCount == 0) {
    return Status;
  }

  //
  // Iterate up to 32 handles, for each
  //
  for (Index = 0; Index < HandleCount && Index < 32; Index++) {
    Status = gBS->OpenProtocol (
                    HandleBuffer[Index],
                    &gEfiNvmeExpressPassThruProtocolGuid,
                    &NvmeControllerData,
                    gImageHandle,
                    NULL,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR (Status)) {
      continue;
    }

    //
    // Prepare the name string for "AMI NVMe BUS Driver" component
    //
    gBS->SetMem ((VOID*)(gNvmeControllerBuffer + 24), 437, 0);
    *(UINT16*)(gNvmeControllerBuffer + 32) = (UINT16)Index;
    *(UINT64*)(gNvmeControllerBuffer + 24) = 0x4D4D534F54455844LL; // "DOTEXOSMM"

    //
    // Copy the NVME_CONTROLLER data (424 bytes @ 0x8D80 area)
    //
    gBS->CopyMem (
          (VOID*)(gNvmeControllerBuffer + 37),
          (VOID*)(NvmeControllerData),
          424
          );

    //
    // Copy the controller's namespace bitfield into identify buffer
    //
    Controller = (NVME_CONTROLLER*)NvmeControllerData;
    gBS->CopyMem (
          (VOID*)gNvmeIdentifyBuffer,
          (VOID*)(Controller->ControllerData + 360),
          4096
          );

    //
    // Enumerate namespace list
    //
    LIST_ENTRY *NamespaceList = &Controller->NamespaceList;
    LIST_ENTRY *Node = NamespaceList->ForwardLink;

    while (Node != NamespaceList) {
      NVME_NAMESPACE *Ns = CR (Node, NVME_NAMESPACE, ...);

      if (Ns->NsidExported) {
        //
        // Identify namespace data via protocol
        //
        NvmeIdentifyNamespace (Controller, Ns);
      }

      //
      // Copy namespace data into the scratch buffer
      //
      *(UINT16*)(gNvmeControllerBuffer + 34) = Ns->BlockSize;
      gBS->CopyMem (
            (VOID*)(gNvmeControllerBuffer + 37),
            (VOID*)Ns,
            NVME_NAMESPACE_ENTRY_SIZE
            );

      //
      // Copy media info from identify
      //
      gBS->CopyMem (
            (VOID*)gNvmeFeaturesBuffer,
            (VOID*)(Ns + 48),
            48
            );

      //
      // Mark if last node
      //
      if (Node->ForwardLink == NamespaceList) {
        *(UINT8*)(gNvmeControllerBuffer + 36) = 1;
      }

      NvmeLegacySmmProtocolInstall (437);

      Node = Node->ForwardLink;
    }

    gBS->FreePool (HandleBuffer);
  }
  return gBS->SignalEvent (Event);
}

//
// ========================================================================
// 0xA30   NvmeDetectAndStart -- Main NVMe detection and configuration flow
//   Called from DriverBinding.Start
//   Args: a1 = This (driver binding), a2 = ControllerHandle, a3 = RemainingDevicePath
// ========================================================================
//
EFI_STATUS
NvmeDetectAndStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  EFI_STATUS              Status;
  NVME_CONTROLLER         *Controller;
  VOID                    *PciIoInterface;
  VOID                    *DevicePathInterface;
  EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;

  Controller = NULL;

  //
  // Ensure device does not already have NvmePassThru installed
  //
  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiNvmExpressPassThruProtocolGuid,
                  &PciIoInterface,
                  This->DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (Status == EFI_ALREADY_STARTED) {
    //
    // Already has pass-thru protocol -- skip NVMe detection
    //
    goto SKIP_NVME;
  }
  if (Status != EFI_SUCCESS && Status != EFI_ALREADY_STARTED) {
    //
    // Open DevicePath protocol (required for NVMe)
    //
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiDevicePathProtocolGuid,
                    &DevicePathInterface,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_BY_DRIVER
                    );
    if (Status != EFI_SUCCESS && Status != EFI_ALREADY_STARTED) {
      return EFI_OUT_OF_RESOURCES;
    }

    //
    // Open PCI_IO protocol
    //
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiPciIoProtocolGuid,
                    &PciIoInterface,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_BY_DRIVER
                    );
    if (Status != EFI_SUCCESS && Status != EFI_ALREADY_STARTED) {
      return EFI_OUT_OF_RESOURCES;
    }
  }

SKK_NVME:
  NvmeDebugPrint (1, L"\nNVMe Driver Detection and Configuration starts\n");

  //
  // Detect the NVME device - open controller
  //
  if (Status != EFI_ALREADY_STARTED) {
    //
    // Initialize the controller structure
    //
    Status = NvmeInitController (ControllerHandle, This->DriverBindingHandle, &Controller);
    if (Status == EFI_OUT_OF_RESOURCES) {
      NvmeDebugPrint (2, L"\nNVMe Driver Detection and Configuration Ends with Status =  EFI_ALREADY_STARTED\n");
    }

    if (Status == EFI_SUCCESS) {
      //
      // Allocate namespace data buffer (4096 bytes)
      //
      UINT64  NamespaceBuffer;
      Status = gBS->AllocatePool (EfiBootServicesData, 4096, &NamespaceBuffer);
      if (Status == EFI_SUCCESS) {
        gBS->SetMem ((VOID*)NamespaceBuffer, 4096, 0);
        Controller->NamespaceData = NamespaceBuffer;

        //
        // Set up IO queues
        //
        Status = NvmeCreateIoSubmissionQueue (Controller, NamespaceBuffer, 1, 0);
        if (Status == EFI_SUCCESS) {
          //
          // Set up IO completion queues
          //
          NvmeSetQueueInterruptCoalescing (Controller);

          //
          // Set additional queue configuration
          //
          Status = gBS->AllocatePool (EfiBootServicesData, 0x8000, &Controller->IoCompletionQueue);
          if (Status == EFI_SUCCESS) {
            gBS->SetMem (Controller->IoCompletionQueue, 0x2000, 0);
            Controller->QueueCount = Controller->IoCompletionQueue;

            //
            // Set max queue entries
            //
            if (Controller->Version < 0x10100) {
              for (UINT32 i = 1; i < *(UINT32*)(Controller->NamespaceData + 516) + 1; i++) {
                *(UINT32*)(Controller->QueueCount + 4 * i) = i;
              }
            }

            Controller->QueueCountEnabled = 1;
            UINT32 QueueSize = Controller->MaxQueueEntries;
            if (QueueSize >= 256) QueueSize = 256;

            //
            // Create IO completion queue
            //
            Status = NvmeCreateIoCompletionQueue (Controller, Controller->AdminSubmissionQueue, 1, QueueSize);
            if (Status == EFI_SUCCESS) {
              //
              // Create child protocol handle
              //
              VOID *ChildBuffer;
              Status = gBS->AllocatePool (EfiBootServicesData, 56, &ChildBuffer);
              if (Status == EFI_SUCCESS) {
                Status = gBS->AllocatePool (EfiBootServicesData, 12, ChildBuffer);
                if (Status == EFI_SUCCESS) {
                  EFI_NVM_EXPRESS_PASS_THRU  *PassthruProtocol;

                  //
                  // Set up pass-through protocol instance
                  //
                  PassthruProtocol = (EFI_NVM_EXPRESS_PASS_THRU*)ChildBuffer;
                  PassthruProtocol->NamespaceCount = 9;
                  PassthruProtocol->NamespaceIdType = 4;
                  PassthruProtocol->Reserved = 0;

                  //
                  // Wire up protocol function pointers
                  //
                  PassthruProtocol->PassThru = NvmePassThru;
                  PassthruProtocol->GetNextNamespace = NvmeGetNextNamespace;
                  PassthruProtocol->GetNamespaceDevicePath = NvmeGetNamespaceDevicePath;
                  PassthruProtocol->BuildDevicePath = NvmeBuildDevicePath;

                  //
                  // Install the protocol
                  //
                  Status = gBS->InstallMultipleProtocolInterfaces (
                                  &PassthruProtocol->ControllerHandle,
                                  &gEfiNvmExpressPassThruProtocolGuid,
                                  PassthruProtocol,
                                  NULL
                                  );
                  if (EFI_ERROR (Status)) {
                    DEBUG ((EFI_D_ERROR, "!EFI_ERROR (Status)\n"));
                  }
                }
              }

              //
              // Initialize the namespace list (linked list head)
              //
              InitializeListHead (&Controller->NamespaceList);

              //
              // If RemainingDevicePath provided, process it
              //
              if (RemainingDevicePath != NULL) {
                if (RemainingDevicePath->Type != MESSAGING_DEVICE_PATH ||
                    RemainingDevicePath->SubType != MSG_NVME_NAMESPACE_DP ||
                    DevicePathNodeLength (RemainingDevicePath) != 16) {
                  return EFI_INVALID_PARAMETER;
                }
                NvmeCreateIoEventBuffer (Controller, *(UINT32*)(RemainingDevicePath + 4));
              }

              //
              // Process namespace list
              //
              while (TRUE) {
                if (IsListEmpty (&Controller->NamespaceList)) {
                  break;
                }
                //
                // Iterate to find all namespaces
                //
                LIST_ENTRY *FirstEntry = Controller->NamespaceList.ForwardLink;
                if (FirstEntry->BackLink == &Controller->NamespaceList) {
                  // only one entry
                  break;
                }
                //
                // Get the namespace node
                //
                NVME_NAMESPACE *EntryNs = (NVME_NAMESPACE*)((UINT8*)FirstEntry - OFFSET_OF_NS_ENTRY);
                NvmeCreateDeviceNode (This, ControllerHandle, Controller);

                if (FirstEntry == Controller->NamespaceList.ForwardLink) {
                  break;
                }
              }
            }
          }
        }
      }

      //
      // Try to locate and call external protocols for advanced features
      //
      if (gNvmeBlockIoHandle != NULL) {
        ((EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL*)gNvmeBlockIoHandle->)->GetVersion (Controller, 2);
        if (*(UINT8*)(gNvmeChildHandle + 24)) {
          ((EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL*)gNvmeBlockIoHandle)-> (Controller, 2);
        }
      }

      //
      // Block I/O installation
      //
      if (gNvmeBlockIoHandle == NULL) {
        gBS->LocateProtocol (&gEfiBlockIoProtocolGuid, NULL, &gNvmeBlockIoHandle);
      }

      //
      // Try SMM communication protocol for BlockIoSmm
      //
      if (gNvmeSmmCommProtocol == NULL || gNvmeSmmCommProtocol != NULL) {
        // fallback
      }

      if (gNvmeDevicePathHandle == NULL) {
        gBS->LocateProtocol (&gEfiDevicePathProtocolGuid, NULL, &gNvmeDevicePathHandle);
      }

      //
      // Install Block I/O and Disk I/O protocols
      //
      Status = NvmeInstallBlockIo (This, Controller);
      if (EFI_ERROR (Status)) {
        DEBUG ((EFI_D_ERROR, "!EFI_ERROR (Status)\n"));
      }

      //
      // Install driver diagnostic protocol
      //
      Status = gBS->OpenProtocol (
                      ControllerHandle,
                      &gEfiDriverDiagnosticsProtocolGuid,
                      &DevicePathNode,
                      This->DriverBindingHandle,
                      ControllerHandle,
                      EFI_OPEN_PROTOCOL_BY_DRIVER
                      );
      if (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND) {
        VOID *DiagBuffer;
        if (gBS->AllocatePool (EfiBootServicesData, 8, &DiagBuffer) == EFI_SUCCESS) {
          *(UINT64*)DiagBuffer = (UINT64)NvmeDiagnostics;
          Status = gBS->InstallMultipleProtocolInterfaces (
                          &ControllerHandle,
                          &gEfiDriverDiagnosticsProtocolGuid,
                          DiagBuffer,
                          NULL
                          );
        }
      }
    }

    //
    // Register for end of DXE notification
    //
    if (gNvmeDriverBindingHandle == NULL) {
      gBS->RegisterProtocolNotify (
            &gEfiEndOfDxeProtocolGuid,
            TPL_CALLBACK,
            NvmeEndOfDxeHandler,
            &gNvmeDriverBindingHandle
            );
    }

    NvmeDebugPrint (64, L"\nNVMe Driver Detection and Configuration Ends with Status =  EFI_SUCCESS\n");
    return EFI_SUCCESS;
  }

  //
  // If already started, just open pass-through on handle
  //
  {
    //
    // Set up I/O completion and SQs
    //
    NvmeSetQueueInterruptCoalescing (Controller);
    NvmeSetFeatures (Controller, NVME_FEATURE_NUMBER_OF_QUEUES, 1, Controller->MaxNamespaces);

    //
    // Register with SMM if needed
    //
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiSmmSwDispatch2ProtocolGuid,
                    &DevicePathInterface,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_BY_DRIVER
                    );
    if (Status == EFI_SUCCESS) {
      gBS->UninstallMultipleProtocolInterfaces (
            ControllerHandle,
            &gEfiSmmSwDispatch2ProtocolGuid,
            NULL
            );
    }

    Status = gBS->InstallMultipleProtocolInterfaces (
                    &ControllerHandle,
                    &gEfiSmmSwDispatch2ProtocolGuid,
                    NULL,
                    NULL
                    );
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_ERROR, "!EFI_ERROR (Status)\n"));
    }
  }

  //
  // Install Block I/O and Disk I/O protocols
  //
  {
    if (gNvmeBlockIoHandle == NULL) {
      // fallback
    }

    Status = NvmeInstallBlockIo (This, Controller);
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_ERROR, "!EFI_ERROR (Status)\n"));
    }
  }

  NvmeDebugPrint (64, L"\nNVMe Driver Detection and Configuration Ends with Status =  EFI_SUCCESS\n");
  return EFI_SUCCESS;
}

//
// ========================================================================
// 0x1D34  NvmeInitController -- Initialize the NVME controller structure
//   Parses PCI IO, identifies controller capabilities, allocates admin
//   queues, and prepares the controller for operation.
// ========================================================================
//
EFI_STATUS
NvmeInitController (
  IN  EFI_HANDLE        ControllerHandle,
  IN  EFI_HANDLE        DriverBindingHandle,
  OUT NVME_CONTROLLER   **Controller
  )
{
  EFI_PCI_IO_PROTOCOL  *PciIo;
  EFI_STATUS           Status;
  NVME_CONTROLLER      *Ctrl;

  *Controller = NULL;

  //
  // Allocate controller structure (424 bytes)
  //
  Status = gBS->AllocatePool (EfiBootServicesData, sizeof (NVME_CONTROLLER), (VOID**)&Ctrl);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  gBS->SetMem (Ctrl, sizeof (NVME_CONTROLLER), 0);
  *Controller = Ctrl;

  //
  // Allocate PCI IO structure (24 bytes)
  //
  Status = gBS->AllocatePool (EfiBootServicesData, 24, (VOID**)&Ctrl->PciIo);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  gBS->SetMem (Ctrl->PciIo, 24, 0);

  Ctrl->ControllerHandle = ControllerHandle;

  //
  // Initialize namespace linked list
  //
  InitializeListHead (&Ctrl->NamespaceList);

  //
  // Open PCI_IO protocol to access the NVMe BAR
  //
  {
    EFI_PCI_IO_PROTOCOL *TempPciIo;
    Status = gBS->OpenProtocol (
                    ControllerHandle,
                    &gEfiPciIoProtocolGuid,
                    (VOID**)&TempPciIo,
                    DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_BY_DRIVER
                    );
    if (EFI_ERROR (Status)) {
      return Status;
    }
    Ctrl->PciIo = TempPciIo;

    //
    // Read PCI config space for MMIO base address (BAR 0)
    //
    Status = TempPciIo->Pci.Read (TempPciIo, EfiPciIoWidthUint16, 0x24, 1, &Ctrl->MaxQueueEntries);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    //
    // Read capabilities (BAR size)
    //
    UINT32 BarValue;
    Status = TempPciIo->Pci.Read (TempPciIo, EfiPciIoWidthUint32, 0x10, 1, &BarValue);
    if (EFI_ERROR (Status)) {
      return Status;
    }
    Ctrl->MmioPhysBase = BarValue & 0xFFFFFFF8;
    Ctrl->MmioPhysBase |= ((UINT64)(*(UINT32*)((UINT8*)&BarValue + 4))) << 32;
  }

  //
  // Parse PCI IO BAR 0 to get MMIO base via GetBarAttributes
  //
  {
    UINT64  BarLength;
    UINTN   AddressSpaceCount;

    Ctrl->PciIo->GetBarAttributes (
                  Ctrl->PciIo,
                  0,
                  &AddressSpaceCount,
                  &Ctrl->MaxQueueEntries
                  );

    //
    // Read the NVMe controller registers from MMIO
    //
    UINT8  IdentifyBuffer[64];
    Status = TempPciIo->Mem.Read (
                          TempPciIo,
                          EfiPciIoWidthUint8,
                          0,  // BAR0
                          0,  // offset to NVMe regs
                          64,
                          IdentifyBuffer
                          );
    if (EFI_ERROR (Status)) {
      return Status;
    }

    //
    // Decode NVMe capability register (CAP)
    //
    Ctrl->Signature = *(UINT32*)IdentifyBuffer;                    // "RNTC"
    Ctrl->MaxQueueEntries = *(UINT32*)(IdentifyBuffer + 8)        // CAP.MQES
                            & 0xFFFFFFF8;
    Ctrl->PageSize = (*(UINT32*)(IdentifyBuffer + 8) >> 32);      // CAP high

    Ctrl->PciIo = Ctrl->PciIo;  // re-assign
    Ctrl->MaxQueueEntries = NvmeGetCapability (Ctrl, 4);
    Ctrl->MaxQueueEntries <<= 32;
    Ctrl->MaxQueueEntries |= NvmeGetCapability (Ctrl, 0);

    Ctrl->PciIo->Pci.Read (Ctrl->PciIo, EfiPciIoWidthUint8, 0, 64, IdentifyBuffer);

    Ctrl->Version = *(UINT32*)IdentifyBuffer;
    Ctrl->MaxQueueEntries = (UINT16)(Ctrl->MaxQueueEntries) + 1;
    Ctrl->PageMin = BYTE2 (Ctrl->MaxQueueEntries) & 1;
    Ctrl->PageMin |= (Ctrl->MaxQueueEntries >> 17) & 3;
    Ctrl->PageMin |= (Ctrl->MaxQueueEntries >> 24);
    Ctrl->PageMin |= (Ctrl->MaxQueueEntries >> 37) & 0xF;
    Ctrl->PageSize = (Ctrl->MaxQueueEntries & 0x1000000000LL) != 0;
    Ctrl->PageSize >>= 37;
  }

  //
  // Get max page entries and set namespace capacity
  //
  Ctrl->MaxNamespaces = NvmeGetCapability (Ctrl, 8);
  Ctrl->MaxNamespaces &= 0xFFFF;

  //
  // Check controller ready status
  //
  if ((Ctrl->PageSize & 1) == 0) {
    return EFI_UNSUPPORTED;
  }

  //
  // Clear CSTS.CFS if set
  //
  if ((NvmeGetCapability (Ctrl, 20) & 1) != 0) {
    UINT32 csts = NvmeGetCapability (Ctrl, 20);
    NvmeSetCapability (Ctrl, 20, csts & ~1);
  }

  //
  // Wait for controller ready (CSTS.RDY)
  //
  {
    UINT32 TimeoutMs = 500 * Ctrl->PageMin;
    while ((NvmeGetCapability (Ctrl, 28) & 1) == 0) {
      gBS->Stall (1000);
      if (--TimeoutMs == 0) {
        break;
      }
    }
    if (TimeoutMs == 0) {
      NvmeDebugPrint (0x80000000LL, L"Controller not ready     : %X\n", NvmeGetCapability (Ctrl, 28));
      return EFI_TIMEOUT;
    }
  }

  //
  // Configure the controller (CC register)
  //
  Ctrl->PageSize = Ctrl->MaxQueueEntries;
  if (Ctrl->PageSize > 0x10000) {
    Ctrl->PageSize = 0x10000;
  }

  UINT32 PageShift = 1;
  if ((Ctrl->PageSize & 0xFFFFFFFE) > 2) {
    do { ++PageShift; } while (Ctrl->PageSize >> PageShift > 1);
  }
  NvmeSetCapability (Ctrl, 20, ((PageShift - 12) | 0x8C00u) << 7);

  //
  // Allocate admin submission queue (ASQ) buffer
  //
  {
    UINT32 NumQueues = Ctrl->MaxQueueEntries;
    if (NumQueues >= 256) {
      NumQueues = 256;
    }

    Ctrl->AdminQueueSize = NumQueues;

    UINT64 AsqBufferSize = (UINT64)NumQueues << 6;
    UINT64 CompletionBufferSize = AsqBufferSize + Ctrl->PageSize;
    UINT32 NumPages = (UINT32)((CompletionBufferSize & 0xFFF) ? (CompletionBufferSize >> 12) + 1 : (CompletionBufferSize >> 12));

    //
    // Allocate physically contiguous pages for admin queues
    //
    Ctrl->PciIo->AllocateBuffer (
                  Ctrl->PciIo,
                  AllocateAnyPages,
                  EfiBootServicesData,
                  NumPages,
                  &Ctrl->AdminSubmissionQueuePhys,
                  2176
                  );
    Ctrl->AdminSubmissionQueue = (VOID*)(Ctrl->AdminSubmissionQueuePhys & ~(Ctrl->PageSize - 1));
    Ctrl->AdminQueueNumPages = NumPages;
    Ctrl->AdminCompletionQueuePhys = Ctrl->AdminSubmissionQueuePhys;

    //
    // Map the buffer
    //
    Ctrl->PciIo->Map (
                  Ctrl->PciIo,
                  EfiPciIoOperationBusMasterCommonBuffer,
                  Ctrl->AdminSubmissionQueuePhys,
                  &AsqBufferSize,
                  &Ctrl->AdminQueueMap,
                  &Ctrl->AdminQueueNumPages
                  );

    //
    // Allocate second buffer for admin completion queue
    //
    Ctrl->PciIo->AllocateBuffer (
                  Ctrl->PciIo,
                  AllocateAnyPages,
                  EfiBootServicesData,
                  NumPages,
                  &Ctrl->IoCompletionQueuePhys,
                  2176
                  );
    Ctrl->AdminCompletionQueueBuff = (VOID*)(Ctrl->IoCompletionQueuePhys & ~(Ctrl->PageSize - 1));
    Ctrl->IoQueueNumEntries = AsqBufferSize;
    Ctrl->PciIo->Map (
                  Ctrl->PciIo,
                  EfiPciIoOperationBusMasterCommonBuffer,
                  Ctrl->IoCompletionQueuePhys,
                  &AsqBufferSize,
                  &Ctrl->IoCompletionQueueMap,
                  &Ctrl->IoQueueNumPages
                  );

    //
    // Set admin queue sizes (ASQ and ACQ entries)
    //
    if (Ctrl->MaxQueueEntries < 0x100) {
      Ctrl->AdminQueueHead = Ctrl->MaxQueueEntries;
      Ctrl->AdminQueueTail = Ctrl->MaxQueueEntries;
    } else {
      Ctrl->AdminQueueHead = 256;
      Ctrl->AdminQueueTail = 256;
    }

    //
    // Zero the admin queues
    //
    gBS->SetMem (Ctrl->AdminSubmissionQueue, AsqBufferSize, 0);
    gBS->SetMem (Ctrl->AdminCompletionQueueBuff, AsqBufferSize, 0);

    //
    // Set AQA (Admin Queue Attributes) register
    //
    NvmeSetCapability (Ctrl, 36,
      Ctrl->AdminQueueHead - 65537 + (Ctrl->AdminQueueTail << 16));
    NvmeSetCapability (Ctrl, 40, (UINT32)(Ctrl->AdminSubmissionQueuePhys));
    NvmeSetCapability (Ctrl, 44, (UINT32)(Ctrl->AdminSubmissionQueuePhys >> 32));
    NvmeSetCapability (Ctrl, 48, (UINT32)(Ctrl->AdminCompletionQueuePhys));
    NvmeSetCapability (Ctrl, 52, (UINT32)(Ctrl->AdminCompletionQueuePhys >> 32));

    //
    // Enable the controller (CC.EN = 1)
    //
    Ctrl->Cc &= ~1;
    Ctrl->Cc |= 1;

    //
    // Allocate scratch buffer for admin commands (72 bytes)
    //
    Status = gBS->AllocatePool (EfiBootServicesData, 72, &Ctrl->AdminCmdBuf);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    //
    // Enable the controller with set features
    //
    {
      UINT32 CcValue = NvmeGetCapability (Ctrl, 20);
      NvmeSetCapability (Ctrl, 20, CcValue | 1);

      //
      // Wait for ready
      //
      Ctrl = (NVME_CONTROLLER*)Ctrl;  // keep consistent
      UINT32 WaitTime = 500 * Ctrl->PageMin;
      while ((NvmeGetCapability (Ctrl, 28) & 1) == 0) {
        gBS->Stall (1000);
        if (--WaitTime == 0) {
          break;
        }
      }
      if (WaitTime == 0) {
        NvmeDebugPrint (0x80000000LL, L"Controller not ready     : %X\n", NvmeGetCapability (Ctrl, 28));
        return EFI_TIMEOUT;
      }
    }

    //
    // Submit admin command to set features (number of queues)
    //
    Status = NvmeAdminSetFeatures (Ctrl, Ctrl->AdminCmdBuf);
    if (Status == EFI_SUCCESS) {
      //
      // Install the pass-through protocol on the controller handle
      //
      gBS->InstallMultipleProtocolInterfaces (
            &ControllerHandle,
            &gEfiNvmExpressPassThruProtocolGuid,
            Ctrl,
            NULL
            );
    }
  }

  return Status;
}

//
// ========================================================================
// 0x75C0  NvmeSubmitAdminCommand -- Submit an admin command to NVMe
//   Wraps the command into a submission queue entry, writes doorbell.
// ========================================================================
//
EFI_STATUS
NvmeSubmitAdminCommand (
  IN  NVME_CONTROLLER  *Controller,
  IN  NVME_ADMIN_CMD   *Cmd,
  OUT UINT32           *CplResult OPTIONAL
  )
{
  UINT16                *QueueInfo;
  CHAR8                 CmdType;
  UINT16                CmdId;
  UINT64                CompletionBase;
  UINT16                CompletionHead;
  UINT16                CompletionIndex;
  VOID                  *SubmissionEntry;

  QueueInfo = (UINT16*)Controller->ControllerData;

  //
  // The admin queue is now busy
  //
  if (Controller->AdminBusy) {
    return EFI_NOT_READY;
  }

  CmdType = Cmd->IsAdmin;
  if (CmdType) {
    CmdId = QueueInfo[0];
  } else {
    CmdId = QueueInfo[1];
  }

  if (CmdType) {
    CompletionBase = Controller->AdminDoorbell;
  } else {
    CompletionBase = Controller->IoSubmissionQueue2Db;
  }

  //
  // Get the current completion queue phase and index
  //
  if (CmdType) {
    CompletionHead = QueueInfo[2];
  } else {
    CompletionHead = QueueInfo[7];
  }

  if (CompletionHead == 0) {
    //
    // Flip the phase tag
    //
    if (CmdType) {
      QueueInfo[6] ^= 1;
    } else {
      QueueInfo[11] ^= 1;
    }
  }

  //
  // Get the submission entry
  //
  CompletionIndex = CompletionHead;
  SubmissionEntry = (VOID*)(CompletionBase + 16 * CompletionIndex);

  //
  // Wait for a free slot in the submission queue
  //
  UINT32 TimeoutMs = 100 * Cmd->TimeoutMs;
  while (TRUE) {
    //
    // Check if slot is available
    //
    if (((UINT16*)SubmissionEntry)[6] == CmdId &&
        ((UINT16*)SubmissionEntry)[5] == Cmd->QueueId) {
      //
      // Check phase tag
      //
      UINT8 PhaseTag = CmdType ? QueueInfo[6] : QueueInfo[11];
      if ((((UINT16*)SubmissionEntry)[7] & 1) == (PhaseTag & 1)) {
        break;
      }
    }

    //
    // Check for controller fatal error
    //
    if ((NvmeGetCapability (Controller, 28) & 2) != 0) {
      if (!Controller->Status) {
        NvmeDebugPrint (0x80000000LL, L"Nvme Fatal Error\n");
      }
      return EFI_DEVICE_ERROR;
    }

    NvmeMicrosecondDelay (35);
    if (--TimeoutMs == 0) {
      if (!Controller->Status) {
        NvmeDebugPrint (0x80000000LL, L"Nvme TimeOut\n");
      }
      return EFI_TIMEOUT;
    }
  }

  if (TimeoutMs == 0) {
    return EFI_TIMEOUT;
  }

  //
  // Set doorbell register
  //
  CompletionIndex = ((UINT16*)SubmissionEntry)[4];
  if (CmdType) {
    QueueInfo[4] = CompletionIndex;
    QueueInfo[2] = CompletionIndex;
  } else {
    QueueInfo[9] = CompletionIndex;
    QueueInfo[7] = CompletionIndex;
  }

  //
  // Write the submission queue tail doorbell
  //
  NvmeMmioWrite (
    Controller,
    (2 * Cmd->QueueId + 1) * (4 << Controller->PageMin) + 4096,
    CompletionIndex
    );

  //
  // Copy completion result
  //
  if (CplResult != NULL) {
    NvmeCopyMem (CplResult, SubmissionEntry, 64);
  }

  if ((*(UINT16*)((UINT8*)SubmissionEntry + 14) & 0x1FE) != 0 ||
      (*(UINT16*)((UINT8*)SubmissionEntry + 14) & 0xE00) != 0) {
    return EFI_WARN_BUFFER_TOO_SMALL;
  }

  //
  // Advance the submission queue tail
  //
  if (CmdType) {
    QueueInfo[0]++;
  } else {
    QueueInfo[1]++;
  }

  return EFI_SUCCESS;
}

//
// ========================================================================
// 0x5014  NvmePassThru -- EFI_NVM_EXPRESS_PASS_THRU.PassThru
//   Main command dispatch for read/write/admin commands.
// ========================================================================
//
EFI_STATUS
EFIAPI
NvmePassThru (
  IN     EFI_NVM_EXPRESS_PASS_THRU        *This,
  IN     UINT32                           NamespaceId,
  IN     EFI_NVM_EXPRESS_PASS_THRU_COMMAND *Command,
  IN     BOOLEAN                          NvmeCmd,
  IN OUT VOID                             *Buffer,
  IN     UINTN                            *TransferLength OPTIONAL
  )
{
  NVME_CONTROLLER  *Controller = (NVME_CONTROLLER*)This->ControllerData;
  EFI_STATUS       Status;

  //
  // Determine if admin or I/O command
  //
  if (Command->IsAdmin) {
    //
    // Admin command -> submit via admin submission queue
    //
    Status = NvmeSubmitAdminCommand (Controller, Command, NULL);
  } else {
    //
    // I/O command -> submit via I/O submission queue
    //
    switch (Command->Opcode) {
    case NVME_IO_CMD_READ:
      Status = NvmeReadSectors (Controller, Command->Lba, Command->TransferLength, Buffer);
      break;
    case NVME_IO_CMD_WRITE:
      Status = NvmeWriteSectors (Controller, Command->Lba, Command->TransferLength, Buffer);
      break;
    case NVME_IO_CMD_FLUSH:
      Status = NvmeFlushBlocks (Controller);
      break;
    default:
      Status = EFI_UNSUPPORTED;
      break;
    }
  }

  return Status;
}

//
// ========================================================================
// 0x6FC4  NvmeReadSectors -- Read sectors from a namespace
// ========================================================================
//
EFI_STATUS
NvmeReadSectors (
  IN  NVME_CONTROLLER  *Controller,
  IN  UINT64           StartLba,
  IN  UINTN            SectorCount,
  OUT VOID             *Buffer
  )
{
  EFI_STATUS       Status;
  NVME_ADMIN_CMD   Cmd;
  UINT16           CmdId;
  UINT64           Prp1, Prp2;
  UINT64           DataPhys;

  //
  // Prepare the command
  //
  NvmeZeroMem (&Cmd, sizeof (Cmd));

  Cmd.Opcode = NVME_IO_CMD_READ;
  Cmd.Nsid   = 0;  // namespace will be assigned
  Cmd.CmdId  = Controller->IoSubmissionTail;
  Cmd.Cdw10  = (UINT32)(StartLba & 0xFFFFFFFF);
  Cmd.Cdw11  = (UINT32)((StartLba >> 32) & 0xFFFFFFFF);
  Cmd.Cdw12  = (UINT32)(SectorCount - 1);
  Cmd.TimeoutMs = 1000;

  //
  // Map the buffer for DMA
  //
  DataPhys = (UINT64)Buffer;  // for simplicity, assume mapped

  Cmd.MpHost = DataPhys;
  if ((DataPhys & (Controller->PageSize - 1)) + SectorCount * 512 > Controller->PageSize) {
    //
    // PRP2 needed
    //
    Cmd.PrpHost = DataPhys;
    Cmd.PrpHost2 = DataPhys + Controller->PageSize;
  } else {
    Cmd.PrpHost = DataPhys;
    Cmd.PrpHost2 = 0;
  }

  Status = NvmeSubmitAdminCommand (Controller, &Cmd, NULL);
  return Status;
}

//
// ========================================================================
// 0x5E28  NvmeCopyUnicodeToAscii -- Unicode string to ascii conversion
// ========================================================================
//
VOID
NvmeCopyUnicodeToAscii (
  IN  UINT16  *UnicodeStr,
  OUT UINT8   *AsciiBuf
  )
{
  //
  // Basic ASCII-safe unicode copy
  //
  while (*UnicodeStr) {
    *AsciiBuf++ = (UINT8)(*UnicodeStr++ & 0xFF);
  }
  *AsciiBuf = 0;
}

//
// ========================================================================
// 0x7C88  NvmeMmioRead32 -- Read 32-bit MMIO register (via PciIo or memory)
// ========================================================================
//
UINT32
NvmeMmioRead32 (
  IN NVME_CONTROLLER  *Controller,
  IN UINTN            Offset
  )
{
  UINT32 Value = 0;

  if (Controller == NULL) {
    return 0;
  }

  if (Controller->MmioPhysBase == 0) {
    //
    // Fallback: read via PciIo.Mem.Read
    //
    if (Controller->PciIo != NULL) {
      Controller->PciIo->Mem.Read (
                            Controller->PciIo,
                            EfiPciIoWidthUint32,
                            0,
                            Offset,
                            1,
                            &Value
                            );
    } else {
      Value = *(UINT32*)(Offset + Controller->MmioPhysBase);
    }
  } else {
    if (Controller->PciIo != NULL) {
      Controller->PciIo->Mem.Read (
                            Controller->PciIo,
                            EfiPciIoWidthUint32,
                            0,
                            Offset,
                            1,
                            &Value
                            );
    } else {
      Value = *(UINT32*)(Offset + Controller->MmioPhysBase);
    }
  }

  return Value;
}

//
// ========================================================================
// 0x7CE4  NvmeMmioWrite32 -- Write 32-bit MMIO register
// ========================================================================
//
VOID
NvmeMmioWrite32 (
  IN NVME_CONTROLLER  *Controller,
  IN UINTN            Offset,
  IN UINT32           Value
  )
{
  if (Controller == NULL) {
    return;
  }

  if (Controller->PciIo != NULL && !Controller->MmioPhysBase) {
    Controller->PciIo->Mem.Write (
                          Controller->PciIo,
                          EfiPciIoWidthUint32,
                          0,
                          Offset,
                          1,
                          &Value
                          );
  } else {
    *(UINT32*)(Offset + (UINT64)Controller->PciIo) = Value;
  }

  return;
}

//
// ========================================================================
// 0x7BE8  NvmeAdminSetFeatures -- Set controller features (admin cmd 0x09)
//   Sets features and triggers admin queue doorbell (ASQ tail doorbell)
// ========================================================================
//
EFI_STATUS
NvmeAdminSetFeatures (
  IN NVME_CONTROLLER  *Controller,
  IN VOID             *CommandBuffer
  )
{
  NVME_ADMIN_CMD  *Cmd = (NVME_ADMIN_CMD*)CommandBuffer;

  if (Controller->AdminBusy == 1 && Controller->AdminDoorbell > 0) {
    return EFI_SUCCESS;  // already in progress
  }

  Controller->AdminCmdInProgress = 1;

  gBS->SetMem (Cmd, sizeof (NVME_ADMIN_CMD), 0);
  Cmd->Opcode = NVME_ADMIN_CMD_SET_FEATURES;
  Cmd->CmdId  = *((UINT16*)Controller->ControllerData);
  Cmd->Cdw10  = NVME_FEATURE_NUMBER_OF_QUEUES;
  Cmd->Cdw11  = 0x10001;  // NCQR = 1, NSQR = 1 (one IO CQ, one IO SQ)
  Cmd->TimeoutMs = 1000;
  Cmd->IsAdmin = 1;
  Cmd->QueueId = 0;

  EFI_STATUS Status = NvmeSubmitAdminCommand (Controller, Cmd, NULL);
  Controller->AdminCmdInProgress = 0;

  return Status;
}

//
// ========================================================================
// 0x406C  NvmeInstallBlockIo -- Install Block I/O protocol on namespaces
//   Called after NVMe detection completes.
// ========================================================================
//
EFI_STATUS
NvmeInstallBlockIo (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN NVME_CONTROLLER              *Controller
  )
{
  EFI_STATUS   Status;
  UINTN        HandleCount;
  EFI_HANDLE   *HandleBuffer;
  UINTN        Index;
  UINT64       NvmeProtocolData;
  EFI_HANDLE   NewHandle;

  //
  // Get list of handles with NVME pass-thru protocol
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiNvmExpressPassThruProtocolGuid,
                  NULL,
                  &HandleCount,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status) || HandleCount == 0) {
    return Status;
  }

  //
  // Allocate the Block IO protocol structure (72 bytes)
  //
  VOID *BlockIoBuffer;
  Status = gBS->AllocatePool (EfiBootServicesData, 72, &BlockIoBuffer);
  if (EFI_ERROR (Status)) {
    //
    // Error condition, already reported
    //
    NvmeDebugPrint (0x80000000LL, L"\nASSERT_EFI_ERROR (Status = %r)\n", Status);
    DEBUG ((EFI_D_ERROR, "!EFI_ERROR (Status)\n"));
    return Status;
  }

  //
  // Iterate over all handles to install block I/O for each namespace
  //
  for (Index = 0; Index < HandleCount; Index++) {
    Status = gBS->OpenProtocol (
                    HandleBuffer[Index],
                    &gEfiNvmExpressPassThruProtocolGuid,
                    &NvmeProtocolData,
                    This->DriverBindingHandle,
                    HandleBuffer[Index],
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR (Status)) {
      NvmeDebugPrint (0x80000000LL, L"\nASSERT_EFI_ERROR (Status = %r)\n", Status);
      continue;
    }

    //
    // Parse the namespace from the controller
    //
    NVME_CONTROLLER *Ctrl = (NVME_CONTROLLER*)NvmeProtocolData;
    UINT32          *NsInfo = (UINT32*)(Ctrl->ControllerData + 344);
    UINT16          NvmeVersion = *NsInfo;

    //
    // Prep the admin command for identify namespace
    //
    NvmeZeroMem (BlockIoBuffer, 72);

    //
    // Send IDENTIFY (ACTIVE) command (Opcode=6, CNS=2)
    //
    *(UINT8*)BlockIoBuffer = 0;
    *(UINT16*)(BlockIoBuffer + 2) = NvmeVersion;
    *(UINT32*)(BlockIoBuffer + 40) = *(UINT16*)(Ctrl->ControllerData + 164);
    *(UINT8*)(BlockIoBuffer + 64) = 1;
    *(UINT16*)(BlockIoBuffer + 66) = 0;
    *(UINT32*)(BlockIoBuffer + 68) = 1000;
    Status = NvmeSubmitAdminCommand (Ctrl, BlockIoBuffer, NULL);
    if (EFI_ERROR (Status)) {
      continue;
    }

    //
    // Send IDENTIFY (NS, CNS=0) to get namespace details
    //
    NvmeZeroMem (BlockIoBuffer, 72);
    *(UINT8*)BlockIoBuffer = 4;
    *(UINT16*)(BlockIoBuffer + 2) = NvmeVersion;
    *(UINT32*)(BlockIoBuffer + 40) = *(UINT16*)(Ctrl->ControllerData + 164);
    *(UINT8*)(BlockIoBuffer + 64) = 1;
    *(UINT16*)(BlockIoBuffer + 66) = 0;
    *(UINT32*)(BlockIoBuffer + 68) = 1000;
    Status = NvmeSubmitAdminCommand (Ctrl, BlockIoBuffer, NULL);
    if (EFI_ERROR (Status)) {
      continue;
    }

    //
    // Enable asynchronous event notification
    //
    {
      UINT32 Aen = (UINT32)NvmeMmioRead32 (Ctrl, 20);
      NvmeMmioWrite32 (Ctrl, 20, Aen | 0x4000);
    }

    //
    // Determine the controller timeout for completion
    //
    {
      UINT64 NsList = (UINT64)Ctrl->NamespaceData;
      UINT32 TimeoutMs;

      if (NsList != 0) {
        UINT32 Capability = *(UINT32*)(NsList + 88);
        TimeoutMs = Capability / 1000;
        UINT32 Remainder = Capability % 1000;
        if (TimeoutMs == 0) {
          TimeoutMs = 500 * Ctrl->PageMin;
        }
        if (Remainder != 0) {
          TimeoutMs++;
        }
      } else {
        TimeoutMs = 500 * Ctrl->PageMin;
      }

      //
      // Wait for command completion (CSTS phase bit)
      //
      while (((NvmeMmioRead32 (Ctrl, 28) & 0xC) != 8)) {
        gBS->Stall (1000);
        if (--TimeoutMs == 0) {
          break;
        }
      }

      if (TimeoutMs == 0) {
        DEBUG ((EFI_D_ERROR, "((BOOLEAN)(0==1))\n"));
      }
    }
  }

  gBS->FreePool (BlockIoBuffer);
  gBS->FreePool (HandleBuffer);

  return EFI_SUCCESS;
}

//
// ========================================================================
// 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.
// =