我试图在Windows中将ATA命令发送到物理磁盘,并从设备获取响应。

Note: In this case I want to send the 07000 (0xEC)
command. The device will respond with
a 512-byte block of data. (In
particular I’m interested in bit 0 of
word 119 – the device’s 07001).

我知道我需要使用CreateFile打开设备:

handle = CreateFile(
    "\\.\PhysicalDrive0",GENERIC_READ,FILE_SHARE_READ,nil,// no security attributes
    OPEN_EXISTING,// flags and attributes
    nil             // no template file
);

但是之后我被阻止怎么办

我想到使用[DeviceIoControl] [4]发送0xEC:

// const ATACommand_IdentifyDevice = 0xEC;
uint bytesReturned = 0;

DeviceIoControl(handle,0xEC,// IO Control Code
    nil,// input buffer not needed
    0,// input buffer is zero bytes
    @buffer,// output buffer to store the returned 512-bytes
    512,// output buffer is 512 bytes long
    out bytesReturned,nil                 // not an overlapped operation
);

但这是完全错误的。发送到DeviceIoControl的IoControlCode必须是有效的IO_CTL,它们是built using the macro:

#define CTL_CODE(DeviceType,Function,Method,Access) (
   ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)
)

看看SDK,有一些有效的Disk Management Control Codes,如:

> IOCTL_disK_CREATE_disK
> IOCTL_disK_GET_DRIVE_GEOMETRY
> IOCTL_disK_GET_DRIVE_GEOMETRY_EX
> IOCTL_disK_GET_PARTITION_INFO
> IOCTL_STORAGE_QUERY_PROPERTY

但是没有一个是IDENTIFY DEVICE命令,或返回任何返回的东西。

所以我相信我必须使用一些“原始”的发送命令的方法。

搜索到的时候,我遇到了IOCTL的无证件

#define  DFP_RECEIVE_DRIVE_DATA   0x0007c088

当您分解IOCTL片段时,意味着:

Custom: (0)
Device Type: (7) FILE_DEVICE_disK
required Access: (3) METHOD_NEITHER
Custom: (0)
Function Code: (34)
Transfer Type: (0)

但是,inputBuffer必须包含哪些内容,其大小以及outputBuffer将包含哪些内容或其所需的任何文档。我也不能弄清楚functionCode 34(0x22)是什么。

我的问题:如何将原始ATA命令(例如0xEC)发送到ATA设备,并读取其响应?

也可以看看

> IOCTL_ATA_PASS_THROUGH Control Code
> IOCTL_ATA_PASS_THROUGH_DIRECT Control Code
> ATA_PASS_THROUGH_EX Structure

回答片断

用ReadWrite访问打开驱动器:

handle = CreateFile(
    "\\.\PhysicalDrive0",GENERIC_READ or GENERIC_WRITE,// IOCTL_ATA_PASS_THROUGH requires read-write
    FILE_SHARE_READ,// flags and attributes
    nil             // no template file
);

设置一个ATA_PASS_THROUGH_EX结构作为IOCTL_ATA_PASS_THROUGH IO控制代码使用的输入缓冲区:

ATA_PASS_THROUGH_EX inputBuffer;
inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
inputBuffer.DataTransferLength = 0;
inputBuffer.DataBufferOffset = 0;
// todo: put the ATA command (e.g. 0xEC) somewhere

uint inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);

设置一个输出缓冲区来保存驱动器中预期的512字节响应:

Byte[] outputBuffer = new Byte[512];
uint outputBufferSize = 512;

调用DeviceIoControl:

int ioControlCode = IOCTL_ATA_PASS_THROUGH; // or maybe IOCTL_ATA_PASS_THROUGH_DIRECT
uint bytesReturned = 0;

DeviceIoControl(handle,ioControlCode,inputBuffer,inputBufferSize,outputBuffer,outputBufferSize,out bytesReturned,nil      // not an overlapped operation    
);

关闭文件句柄:

handle.Close();
您需要使用IOCTL_ATA_PASS_THROUGH / IOCTL_ATA_PASS_THROUGH_DIRECT,这些都有很好的记录。此外,您需要CreateFile的GENERIC_READ | GENERIC_WRITE访问。

请注意,pre XP SP2不正确支持这些。另外,如果您有一个基于nForce的MB与nvidia驱动程序,您的SATA驱动器将显示为SCSI,您不能使用此通过。

在某些情况下,SMART IOCTL(例如SMART_RCV_DRIVE_DATA)将适用于nForce驱动程序。您可以使用这些来获取IDENTIFY和SMART数据,但不能太多。

开源smartmontools是开始寻找示例代码的好地方。

编辑:来自与ATA设备交谈的应用程序的示例。

EResult DeviceOperationManagerWin::executeATACommandindirect(ATACommand & Cmd) {
    const uint32 FillerSize = 0;
    Utils::ByteBuffer B;
    B.reserve(sizeof(ATA_PASS_THROUGH_EX) + 4 + Cmd.bufferSize());
    ATA_PASS_THROUGH_EX & PTE = * (ATA_PASS_THROUGH_EX *) B.appendPointer(sizeof(ATA_PASS_THROUGH_EX) + FillerSize + Cmd.bufferSize());
    uint8 * DataPtr = ((uint8 *) &PTE) + sizeof(ATA_PASS_THROUGH_EX) + FillerSize;

    memset(&PTE,sizeof(ATA_PASS_THROUGH_EX) + FillerSize);
    PTE.Length = sizeof(PTE);
    PTE.AtaFlags = 0;
    PTE.AtaFlags |= Cmd.requiresDRDY() ? ATA_FLAGS_DRDY_required : 0;
    switch (Cmd.dataDirection()) {
    case ddFromDevice: 
        PTE.AtaFlags |= ATA_FLAGS_DATA_IN; 
        break;
    case ddToDevice:
        PTE.AtaFlags |= ATA_FLAGS_DATA_OUT;
        memcpy(DataPtr,Cmd.buffer(),Cmd.bufferSize());
        break;
    default:
        break;
    }
    PTE.AtaFlags |= Cmd.is48Bit() ? ATA_FLAGS_48BIT_COMMAND : 0;
    PTE.AtaFlags |= Cmd.isDMA() ? ATA_FLAGS_USE_DMA : 0;
    PTE.DataTransferLength = Cmd.bufferSize();
    PTE.TimeOutValue = Cmd.timeout();
    PTE.DataBufferOffset = sizeof(PTE) + FillerSize;
    PTE.DataTransferLength = Cmd.bufferSize();
    PTE.CurrentTaskFile[0] = Cmd.taskFileIn0().Features;
    PTE.CurrentTaskFile[1] = Cmd.taskFileIn0().Count;
    PTE.CurrentTaskFile[2] = Cmd.taskFileIn0().LBALow;
    PTE.CurrentTaskFile[3] = Cmd.taskFileIn0().LBAMid;
    PTE.CurrentTaskFile[4] = Cmd.taskFileIn0().LBAHigh;
    PTE.CurrentTaskFile[5] = Cmd.taskFileIn0().Device;
    PTE.CurrentTaskFile[6] = Cmd.taskFileIn0().Command;
    PTE.CurrentTaskFile[7] = 0;
    if (Cmd.is48Bit()) {
        PTE.PrevIoUsTaskFile[0] = Cmd.taskFileIn1().Features;
        PTE.PrevIoUsTaskFile[1] = Cmd.taskFileIn1().Count;
        PTE.PrevIoUsTaskFile[2] = Cmd.taskFileIn1().LBALow;
        PTE.PrevIoUsTaskFile[3] = Cmd.taskFileIn1().LBAMid;
        PTE.PrevIoUsTaskFile[4] = Cmd.taskFileIn1().LBAHigh;
        PTE.PrevIoUsTaskFile[5] = Cmd.taskFileIn1().Device;
        PTE.PrevIoUsTaskFile[6] = 0;
        PTE.PrevIoUsTaskFile[7] = 0;
    }

    DWORD BR; 
    if (!DeviceIoControl(FHandle,IOCTL_ATA_PASS_THROUGH,&PTE,B.size(),&BR,0)) {
        FLastOSError = GetLastError();
        LOG_W << "ioctl ATA_PT Failed for " << Cmd << ": " << FLastOSError << " (" << Utils::describeOSError(FLastOSError) << ")";
        return Utils::mapOSError(FLastOSError);
    }
    Cmd.taskFileOut0().Error = PTE.CurrentTaskFile[0];
    Cmd.taskFileOut0().Count = PTE.CurrentTaskFile[1];
    Cmd.taskFileOut0().LBALow = PTE.CurrentTaskFile[2];
    Cmd.taskFileOut0().LBAMid = PTE.CurrentTaskFile[3];
    Cmd.taskFileOut0().LBAHigh = PTE.CurrentTaskFile[4];
    Cmd.taskFileOut0().Device = PTE.CurrentTaskFile[5];
    Cmd.taskFileOut0().Status = PTE.CurrentTaskFile[6];
    Cmd.taskFileOut1().Error = PTE.PrevIoUsTaskFile[0];
    Cmd.taskFileOut1().Count = PTE.PrevIoUsTaskFile[1];
    Cmd.taskFileOut1().LBALow = PTE.PrevIoUsTaskFile[2];
    Cmd.taskFileOut1().LBAMid = PTE.PrevIoUsTaskFile[3];
    Cmd.taskFileOut1().LBAHigh = PTE.PrevIoUsTaskFile[4];
    Cmd.taskFileOut1().Device = PTE.PrevIoUsTaskFile[5];
    Cmd.taskFileOut1().Status = PTE.PrevIoUsTaskFile[6];
    if (Cmd.dataDirection() == ddFromDevice) {
        memcpy(Cmd.buffer(),DataPtr,Cmd.bufferSize());
    }
    return resOK;
    }

编辑:没有外部依赖关系的示例。

IDENTIFY需要一个512字节的数据缓冲区:

unsigned char Buffer[512 + sizeof(ATA_PASS_THROUGH_EX)] = { 0 };
ATA_PASS_THROUGH_EX & PTE = *(ATA_PASS_THROUGH_EX *) Buffer;
PTE.Length = sizeof(PTE);
PTE.TimeOutValue = 10;
PTE.DataTransferLength = 512;
PTE.DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);

根据ATA规范设置IDE寄存器。

IDEREGS * ir = (IDEREGS *) PTE.CurrentTaskFile;
ir->bCommandReg = 0xEC;
ir->bSectorCountReg = 1;

IDENTIFY既不是48位也不是DMA,它从设备读取:

PTE.AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_required;

做ioctl:

DeviceIOControl(Handle,sizeof(Buffer),0);

在这里,您应该插入错误检查,两者都来自DeviceIOControl,并通过查看IDEREGS来查看设备报告的错误。

假设您已经定义了一个struct IdentifyData,获取IDENTIFY数据

IdentifyData * IDData = (IdentifyData *) (Buffer + sizeof(ATA_PASS_THROUGH_EX));

在Windows中直接发送ATA命令到设备?的更多相关文章

  1. ios – 确定核心音频AudioBuffer中的帧数

    我正在尝试访问iPhone/iPad上的音频文件的原始数据.我有以下代码,这是我需要的路径的基本开始.但是,一旦我有了一个AudioBuffer,我就不知道该怎么做了.基本上我不知道如何判断每个缓冲区包含多少帧,因此我无法从它们中可靠地提取数据.我是处理原始音频数据的新手,所以我对如何最好地读取AudioBuffer结构的mData属性有任何建议.我在过去也没有做过很多关于void指针的事情,所以在这种情况下对它的帮助也会很棒!

  2. iOS – 生成并播放无限简单的音频(正弦波)

    我正在寻找一个非常简单的iOS应用程序,它带有一个启动和停止音频信号的按钮.信号只是一个正弦波,它将在整个播放过程中检查我的模型,并相应地改变音量.我的困难与任务的不确定性有关.我理解如何构建表格,填充数据,响应按钮按下等等;然而,当谈到只是无限期地继续时,我有点卡住了!任何指针都会很棒!

  3. ios – 核心音频离线渲染GenericOutput

    等正在产生这些问题.尝试努力,它会工作.不要放弃:-).核心音频在处理低级音频时非常强大和有用.这是我从最近几周学到的东西.享受:-D…

  4. 如何正确使用iOS(Swift)SceneKit SCNSceneRenderer unprojectPoint

    那么,如果那架飞机与摄像机是正交的–那就是你的帮助.那么你需要做的就是在那架飞机上投射一点:现在,您可以在三维视图中拥有世界起源的位置归一化深度空间.要将2D视图空间中的其他点映射到此平面上,请使用此矢量中的z坐标:这让您在世界空间中将点击/分接位置映射到z=0平面,适合用作节点的位置,如果要向用户显示该位置.

  5. Swift:如何使用sizeof?

    为了在使用Swift时与CAPI集成,我需要使用sizeof函数。在C,这很容易。在Swift,我在一个迷宫式的错误。为什么是这个,我如何解决它?如果你想要anInt变量的大小,你可以将dynamicType字段传递给sizeof。

  6. Swift是否保证类和结构中字段的存储顺序?

    在C中,您在结构中定义字段的顺序是它们将在内存中实例化的顺序.考虑到内存对齐,下面的结构在内存中的大小为8字节,如图所示,但如果字段反转则只有6个字节,因为不需要任何对齐填充.这种排序保证存在于C结构,C类(和结构)和Objective-C类中.对于Swift类和结构中的字段,存储顺序是否同样有保证?或者,编译器是否在编译时为您重新安排它们?

  7. 泛型 – 如何为所有Integer类型创建一个通用的整数到十六进制函数?

    非常简单的解决方案是将输入值合并到.toIntMax()中的IntMax中:注意:这仅适用于0…UInt32.max值.已添加:这适用于所有可用的整数类型/值.>.toIntMax()将T转换为具体的整数类型.>/16而不是>>4.

  8. swift – SceneKit – 自定义几何体不显示

    我应该看到2个黄色三角形,但我什么也看不见.我用它如下:我看到其他节点具有非自定义几何体.怎么了?

  9. Win32 C/C++从内存缓冲区加载图像

    这是初始化代码:

  10. Windows – ConnectEx要求套接字“最初绑定”,但是要什么?

    ConnectEx功能需要“未连接的,先前绑定的套接字”.实际上,如果我省略了我的示例中的bind步骤(见下文),则ConnectEx在WSAEINVAL失败.这是我目前的理解:在调用ConnectEx之前,bind将套接字调用到INADDR_ANY和端口0:或者对于IPv6套接字:这允许操作系统为我们的套接字分配本地地址.connect自动执行此步骤,但ConnectEx不会.我的问题是:>我的评估是否正确?>有没有办法对地址族进行无关的自动绑定,还是我必须手动处理AF_INET,AF_INET6,AF

随机推荐

  1. static – 在页面之间共享数据的最佳实践

    我想知道在UWP的页面之间发送像’selectedItem’等变量的最佳做法是什么?创建一个每个页面都知道的静态全局变量类是一个好主意吗?

  2. .net – 为Windows窗体控件提供百分比宽度/高度

    WindowsForm开发的新手,但在Web开发方面经验丰富.有没有办法为Windows窗体控件指定百分比宽度/高度,以便在用户调整窗口大小时扩展/缩小?当窗口调整大小时,可以编写代码来改变控件的宽度/高度,但我希望有更好的方法,比如在HTML/CSS中.在那儿?

  3. 使用Windows Azure查询表存储数据

    我需要使用特定帐户吗?>将应用程序部署到Azure服务后,如何查询数据?GoogleAppEngine有一个数据查看器/查询工具,Azure有类似的东西吗?>您可以看到的sqlExpressintance仅在开发结构中,并且一旦您表示没有等效,所以请小心使用它.>您可以尝试使用Linqpad查询表格.看看JamieThomson的thispost.

  4. windows – SetupDiGetClassDevs是否与文档中的设备实例ID一起使用?

    有没有更好的方法可以使用DBT_DEVICEARRIVAL事件中的数据获取设备的更多信息?您似乎必须指定DIGCF_ALLCLASSES标志以查找与给定设备实例ID匹配的所有类,或者指定ClassGuid并使用DIGCF_DEFAULT标志.这对我有用:带输出:

  5. Windows Live ID是OpenID提供商吗?

    不,WindowsLiveID不是OpenID提供商.他们使用专有协议.自从他们的“测试版”期结束以来,他们从未宣布计划继续它.

  6. 如果我在代码中进行了更改,是否需要重新安装Windows服务?

    我写了一个Windows服务并安装它.现在我对代码进行了一些更改并重新构建了解决方案.我还应该重新安装服务吗?不,只需停止它,替换文件,然后重新启动它.

  7. 带有双引号的字符串回显使用Windows批处理输出文件

    我正在尝试使用Windows批处理文件重写配置文件.我循环遍历文件的行并查找我想要用指定的新行替换的行.我有一个’函数’将行写入文件问题是%Text%是一个嵌入双引号的字符串.然后失败了.可能还有其他角色也会导致失败.如何才能使用配置文件中的所有文本?尝试将所有“在文本中替换为^”.^是转义字符,因此“将被视为常规字符你可以尝试以下方法:其他可能导致错误的字符是:

  8. .net – 将控制台应用程序转换为服务?

    我正在寻找不同的优势/劣势,将我们长期使用的控制台应用程序转换为Windows服务.我们为ActiveMQ使用了一个叫做java服务包装器的东西,我相信人们告诉我你可以用它包装任何东西.这并不是说你应该用它包装任何东西;我们遇到了这个问题.控制台应用程序是一个.NET控制台应用程序,默认情况下会将大量信息记录到控制台,尽管这是可配置的.任何推荐?我们应该在VisualStudio中将其重建为服务吗?我使用“-install”/“-uninstall”开关执行此操作.例如,seehere.

  9. windows – 捕获外部程序的STDOUT和STDERR *同时*它正在执行(Ruby)

    哦,我在Windows上:-(实际上,它比我想象的要简单,这看起来很完美:…是的,它适用于Windows!

  10. windows – 当我试图批量打印变量时,为什么我得到“Echo is on”

    我想要执行一个简单的批处理文件脚本:当我在XP中运行时,它给了我预期的输出,但是当我在Vista或Windows7中运行它时,我在尝试打印值时得到“EchoisOn”.以下是程序的输出:摆脱集合表达式中的空格.等号(=)的两侧可以并且应该没有空格BTW:我通常在@echo关闭的情况下启动所有批处理文件,并以@echo结束它们,所以我可以避免将代码与批处理文件的输出混合.它只是使您的批处理文件输出更好,更清洁.

返回
顶部