Reputation: 1
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