mengmeng
mengmeng

Reputation: 1

How to low-level format NVMe SSD in WindowsPE

How to perform a low-level format on an NVMe disk using C++ in Windows or Windows PE, similar to the command nvme format /dev/nvme1n1 -f in Linux. Note: This is not a quick format or overwrite.

First, I tried this C++ code in WindowsPE, but no use.

#include <Windows.h>
#include <iostream>
#include <winioctl.h>
#include <memory>
#include <nvme.h>

/*
 * A demo for NVMe SSD format command
 * Adopt NVMe protocol Secure Erase in WindowsPE environment, by WindowsAPI
 * There are three steps
 * step 1:
 *      Get NVMe SSD device handle
 * step 2:
 *      Send the NVMe format command to device by DeviceIoControl
 * step 3:
 *      Check success or fail
 * */

void *getNVMeSSDDeviceHandle() {
    unsigned int diskNumber{};
    std::cout << "Input disk number please" << std::endl;
    std::cin >> diskNumber;
    char driveName[MAX_PATH]{};
    sprintf_s(driveName, R"(\\.\physicalDrive%d)", diskNumber);
//    sprintf_s(driveName, R"(\\.\physicalDrive1)");
    void *diskDevice = CreateFileA(driveName, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
                                   OPEN_EXISTING, 0, nullptr);

    if (INVALID_HANDLE_VALUE == diskDevice) {
        std::cerr << "CreatFile driveName: " << driveName << " failed"
                  << " and error no is " << GetLastError() << std::endl;
        return nullptr;
    }

    return diskDevice;
}

// send nvme command via handle
unsigned long sendNVMeSSDCommand(void *handle, PSTORAGE_PROTOCOL_COMMAND protocolCommand) {
    unsigned long errorNo{0};
    unsigned long returnedBytes{0};
    bool devIoCtlRes = DeviceIoControl(handle, IOCTL_STORAGE_PROTOCOL_COMMAND,
                                       protocolCommand, sizeof(STORAGE_PROTOCOL_COMMAND),
                                       nullptr, 0, &returnedBytes, nullptr);
    if (devIoCtlRes) {
        std::cout << "NVMe command send successfully" << std::endl;
    } else {
        errorNo = GetLastError();
        std::cerr << "NVMe command send failed, error no is: " << errorNo << ", and line NO. is " << __LINE__
                  << std::endl;
    }
    return errorNo;
}

PSTORAGE_PROTOCOL_COMMAND getFormatForNVMeSSDCommand() {
    auto protocolCommand(new STORAGE_PROTOCOL_COMMAND);
    ZeroMemory(protocolCommand, sizeof(STORAGE_PROTOCOL_COMMAND));

    // set STORAGE_PROTOCOL_COMMAND structure
    protocolCommand->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION;
    protocolCommand->Length = sizeof(STORAGE_PROTOCOL_COMMAND);
    protocolCommand->ProtocolType = ProtocolTypeNvme;
    protocolCommand->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST;
    protocolCommand->CommandLength = STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
    protocolCommand->TimeOutValue = 10;
    protocolCommand->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND;

    auto nvmeCommand = reinterpret_cast<PNVME_COMMAND>(protocolCommand->Command);
    ZeroMemory(nvmeCommand, sizeof(NVME_COMMAND));
    nvmeCommand->CDW0.OPC = NVME_ADMIN_COMMAND_FORMAT_NVM;
    nvmeCommand->NSID = 0xFFFFFFFF;
    nvmeCommand->u.FORMATNVM.CDW10.LBAF = 0;
    nvmeCommand->u.FORMATNVM.CDW10.SES = 1;

    return protocolCommand;
}

int main() {
    // get NVMe SSD disk device handle
    void *diskHandle = getNVMeSSDDeviceHandle();
    if (!diskHandle) {
        std::cerr << "getNvmeSSDeviceHandle failed" << std::endl;
        return -1;
    }

    PSTORAGE_PROTOCOL_COMMAND formatNVMeCommandVal = getFormatForNVMeSSDCommand();
    std::cout << "After set the format NVMe command" << std::endl;

    unsigned long sendRes = sendNVMeSSDCommand(diskHandle, formatNVMeCommandVal);
    if (sendRes) {
        std::cerr << "NVMe command send failed, error no is: " << sendRes << ", and line NO. is " << __LINE__ << std::endl;
        return -1;
    }
    CloseHandle(diskHandle);

    return 0;
}

In Windows11 those code GetLastError return 317.

second, I guess My SSD not support low-level format.However I tried in Linux succeed by use nvme format /dev/nvmeOn1 -f.

I think that both Linux and Windows essentially run as software on hardware. Therefore, if something is feasible in Linux, it's likely that a similar operation can be implemented in Windows as well, since the underlying hardware remains unchanged.

I don't know if Windows PE supports low-level formatting functions for NVMe SSDs or if there is an error in the code. I would greatly appreciate it if someone could answer this. Thank you very much.

Upvotes: 0

Views: 63

Answers (0)

Related Questions