mirror of
https://github.com/aaru-dps/aaruremote.git
synced 2025-12-16 19:24:37 +00:00
361 lines
14 KiB
C
361 lines
14 KiB
C
/*
|
|
* This file is part of the Aaru Remote Server.
|
|
* Copyright (c) 2019-2020 Natalia Portillo.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "../dicmote.h"
|
|
#include "ntioctl.h"
|
|
#include "win32.h"
|
|
|
|
#include <stdint.h>
|
|
#include <windows.h>
|
|
|
|
// TODO: Check if we can live without copying buffer in and out
|
|
int32_t Win32SendAtaChsCommand(void* device_ctx,
|
|
AtaRegistersChs registers,
|
|
AtaErrorRegistersChs* error_registers,
|
|
uint8_t protocol,
|
|
uint8_t transfer_register,
|
|
char* buffer,
|
|
uint32_t timeout,
|
|
uint8_t transfer_blocks,
|
|
uint32_t* duration,
|
|
uint32_t* sense,
|
|
uint32_t* buf_len)
|
|
{
|
|
Win32DeviceContext* ctx = device_ctx;
|
|
PATA_PASS_THROUGH_EX apte;
|
|
PVOID apte_and_buffer;
|
|
ULONG_PTR offsetForBuffer;
|
|
PCHAR data_buffer;
|
|
DWORD k = 0;
|
|
DWORD error = 0;
|
|
LARGE_INTEGER frequency;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER end;
|
|
DOUBLE interval;
|
|
DWORD apte_and_buffer_len;
|
|
|
|
*duration = 0;
|
|
*sense = FALSE;
|
|
offsetForBuffer = sizeof(ATA_PASS_THROUGH_EX) + sizeof(uint32_t);
|
|
apte_and_buffer_len = sizeof(ATA_PASS_THROUGH_EX) + sizeof(uint32_t) + 64 * 512;
|
|
|
|
if(!ctx) return -1;
|
|
if(!buffer) return -1;
|
|
if(*buf_len > 64 * 512) return -1;
|
|
|
|
apte_and_buffer = malloc(apte_and_buffer_len);
|
|
|
|
if(!apte_and_buffer) return -1;
|
|
|
|
memset(apte_and_buffer, 0, apte_and_buffer_len);
|
|
data_buffer = (PCHAR)apte_and_buffer + offsetForBuffer;
|
|
apte = (PATA_PASS_THROUGH_EX)apte_and_buffer;
|
|
|
|
apte->TimeOutValue = timeout;
|
|
apte->DataBufferOffset = offsetForBuffer;
|
|
apte->Length = sizeof(ATA_PASS_THROUGH_EX);
|
|
apte->CurrentTaskFile[0] = registers.feature;
|
|
apte->CurrentTaskFile[1] = registers.sector_count;
|
|
apte->CurrentTaskFile[2] = registers.sector;
|
|
apte->CurrentTaskFile[3] = registers.cylinder_low;
|
|
apte->CurrentTaskFile[4] = registers.cylinder_high;
|
|
apte->CurrentTaskFile[5] = registers.device_head;
|
|
apte->CurrentTaskFile[6] = registers.command;
|
|
|
|
switch(protocol)
|
|
{
|
|
case DICMOTE_ATA_PROTOCOL_PIO_IN:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_IN:
|
|
case DICMOTE_ATA_PROTOCOL_DMA: apte->AtaFlags = ATA_FLAGS_DATA_IN; break;
|
|
case DICMOTE_ATA_PROTOCOL_PIO_OUT:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_OUT: apte->AtaFlags = ATA_FLAGS_DATA_OUT; break;
|
|
}
|
|
|
|
switch(protocol)
|
|
{
|
|
case DICMOTE_ATA_PROTOCOL_DMA:
|
|
case DICMOTE_ATA_PROTOCOL_DMA_QUEUED:
|
|
case DICMOTE_ATA_PROTOCOL_FPDMA:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_IN:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_OUT: apte->AtaFlags |= ATA_FLAGS_USE_DMA; break;
|
|
}
|
|
|
|
// Unknown if needed
|
|
apte->AtaFlags |= ATA_FLAGS_DRDY_REQUIRED;
|
|
|
|
QueryPerformanceFrequency(&frequency);
|
|
|
|
memcpy(data_buffer, buffer, *buf_len);
|
|
|
|
QueryPerformanceCounter(&start);
|
|
*sense = !DeviceIoControl(ctx->handle,
|
|
IOCTL_ATA_PASS_THROUGH,
|
|
apte_and_buffer,
|
|
apte_and_buffer_len,
|
|
apte_and_buffer,
|
|
apte_and_buffer_len,
|
|
&k,
|
|
NULL);
|
|
QueryPerformanceCounter(&end);
|
|
|
|
interval = (DOUBLE)(end.QuadPart - start.QuadPart) / frequency.QuadPart;
|
|
*duration = interval * 1000;
|
|
|
|
if(*sense) error = GetLastError();
|
|
|
|
memcpy(buffer, data_buffer, *buf_len);
|
|
|
|
error_registers->error = apte->CurrentTaskFile[0];
|
|
error_registers->sector_count = apte->CurrentTaskFile[1];
|
|
error_registers->sector = apte->CurrentTaskFile[2];
|
|
error_registers->cylinder_low = apte->CurrentTaskFile[3];
|
|
error_registers->cylinder_high = apte->CurrentTaskFile[4];
|
|
error_registers->device_head = apte->CurrentTaskFile[5];
|
|
error_registers->status = apte->CurrentTaskFile[6];
|
|
|
|
*sense = error_registers->error != 0 || (error_registers->status & 0xA5) != 0;
|
|
|
|
free(apte_and_buffer);
|
|
return error;
|
|
}
|
|
|
|
int32_t Win32SendAtaLba28Command(void* device_ctx,
|
|
AtaRegistersLba28 registers,
|
|
AtaErrorRegistersLba28* error_registers,
|
|
uint8_t protocol,
|
|
uint8_t transfer_register,
|
|
char* buffer,
|
|
uint32_t timeout,
|
|
uint8_t transfer_blocks,
|
|
uint32_t* duration,
|
|
uint32_t* sense,
|
|
uint32_t* buf_len)
|
|
{
|
|
Win32DeviceContext* ctx = device_ctx;
|
|
PATA_PASS_THROUGH_EX apte;
|
|
PVOID apte_and_buffer;
|
|
ULONG_PTR offsetForBuffer;
|
|
PCHAR data_buffer;
|
|
DWORD k = 0;
|
|
DWORD error = 0;
|
|
LARGE_INTEGER frequency;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER end;
|
|
DOUBLE interval;
|
|
DWORD apte_and_buffer_len;
|
|
|
|
*duration = 0;
|
|
*sense = FALSE;
|
|
offsetForBuffer = sizeof(ATA_PASS_THROUGH_EX) + sizeof(uint32_t);
|
|
apte_and_buffer_len = sizeof(ATA_PASS_THROUGH_EX) + sizeof(uint32_t) + 64 * 512;
|
|
|
|
if(!ctx) return -1;
|
|
if(!buffer) return -1;
|
|
if(*buf_len > 64 * 512) return -1;
|
|
|
|
apte_and_buffer = malloc(apte_and_buffer_len);
|
|
|
|
if(!apte_and_buffer) return -1;
|
|
|
|
memset(apte_and_buffer, 0, apte_and_buffer_len);
|
|
data_buffer = (PCHAR)apte_and_buffer + offsetForBuffer;
|
|
apte = (PATA_PASS_THROUGH_EX)apte_and_buffer;
|
|
|
|
apte->TimeOutValue = timeout;
|
|
apte->DataBufferOffset = offsetForBuffer;
|
|
apte->Length = sizeof(ATA_PASS_THROUGH_EX);
|
|
apte->CurrentTaskFile[0] = registers.feature;
|
|
apte->CurrentTaskFile[1] = registers.sector_count;
|
|
apte->CurrentTaskFile[2] = registers.lba_low;
|
|
apte->CurrentTaskFile[3] = registers.lba_mid;
|
|
apte->CurrentTaskFile[4] = registers.lba_high;
|
|
apte->CurrentTaskFile[5] = registers.device_head;
|
|
apte->CurrentTaskFile[6] = registers.command;
|
|
|
|
switch(protocol)
|
|
{
|
|
case DICMOTE_ATA_PROTOCOL_PIO_IN:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_IN:
|
|
case DICMOTE_ATA_PROTOCOL_DMA: apte->AtaFlags = ATA_FLAGS_DATA_IN; break;
|
|
case DICMOTE_ATA_PROTOCOL_PIO_OUT:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_OUT: apte->AtaFlags = ATA_FLAGS_DATA_OUT; break;
|
|
}
|
|
|
|
switch(protocol)
|
|
{
|
|
case DICMOTE_ATA_PROTOCOL_DMA:
|
|
case DICMOTE_ATA_PROTOCOL_DMA_QUEUED:
|
|
case DICMOTE_ATA_PROTOCOL_FPDMA:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_IN:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_OUT: apte->AtaFlags |= ATA_FLAGS_USE_DMA; break;
|
|
}
|
|
|
|
// Unknown if needed
|
|
apte->AtaFlags |= ATA_FLAGS_DRDY_REQUIRED;
|
|
|
|
QueryPerformanceFrequency(&frequency);
|
|
|
|
memcpy(data_buffer, buffer, *buf_len);
|
|
|
|
QueryPerformanceCounter(&start);
|
|
*sense = !DeviceIoControl(ctx->handle,
|
|
IOCTL_ATA_PASS_THROUGH,
|
|
apte_and_buffer,
|
|
apte_and_buffer_len,
|
|
apte_and_buffer,
|
|
apte_and_buffer_len,
|
|
&k,
|
|
NULL);
|
|
QueryPerformanceCounter(&end);
|
|
|
|
interval = (DOUBLE)(end.QuadPart - start.QuadPart) / frequency.QuadPart;
|
|
*duration = interval * 1000;
|
|
|
|
if(*sense) error = GetLastError();
|
|
|
|
memcpy(buffer, data_buffer, *buf_len);
|
|
|
|
error_registers->error = apte->CurrentTaskFile[0];
|
|
error_registers->sector_count = apte->CurrentTaskFile[1];
|
|
error_registers->lba_low = apte->CurrentTaskFile[2];
|
|
error_registers->lba_mid = apte->CurrentTaskFile[3];
|
|
error_registers->lba_high = apte->CurrentTaskFile[4];
|
|
error_registers->device_head = apte->CurrentTaskFile[5];
|
|
error_registers->status = apte->CurrentTaskFile[6];
|
|
|
|
*sense = error_registers->error != 0 || (error_registers->status & 0xA5) != 0;
|
|
|
|
free(apte_and_buffer);
|
|
return error;
|
|
}
|
|
|
|
int32_t Win32SendAtaLba48Command(void* device_ctx,
|
|
AtaRegistersLba48 registers,
|
|
AtaErrorRegistersLba48* error_registers,
|
|
uint8_t protocol,
|
|
uint8_t transfer_register,
|
|
char* buffer,
|
|
uint32_t timeout,
|
|
uint8_t transfer_blocks,
|
|
uint32_t* duration,
|
|
uint32_t* sense,
|
|
uint32_t* buf_len)
|
|
{
|
|
Win32DeviceContext* ctx = device_ctx;
|
|
PATA_PASS_THROUGH_EX apte;
|
|
PVOID apte_and_buffer;
|
|
ULONG_PTR offsetForBuffer;
|
|
PCHAR data_buffer;
|
|
DWORD k = 0;
|
|
DWORD error = 0;
|
|
LARGE_INTEGER frequency;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER end;
|
|
DOUBLE interval;
|
|
DWORD apte_and_buffer_len;
|
|
|
|
*duration = 0;
|
|
*sense = FALSE;
|
|
offsetForBuffer = sizeof(ATA_PASS_THROUGH_EX) + sizeof(uint32_t);
|
|
apte_and_buffer_len = sizeof(ATA_PASS_THROUGH_EX) + sizeof(uint32_t) + 64 * 512;
|
|
|
|
if(!ctx) return -1;
|
|
if(!buffer) return -1;
|
|
if(*buf_len > 64 * 512) return -1;
|
|
|
|
apte_and_buffer = malloc(apte_and_buffer_len);
|
|
|
|
if(!apte_and_buffer) return -1;
|
|
|
|
memset(apte_and_buffer, 0, apte_and_buffer_len);
|
|
data_buffer = (PCHAR)apte_and_buffer + offsetForBuffer;
|
|
apte = (PATA_PASS_THROUGH_EX)apte_and_buffer;
|
|
|
|
apte->TimeOutValue = timeout;
|
|
apte->DataBufferOffset = offsetForBuffer;
|
|
apte->Length = sizeof(ATA_PASS_THROUGH_EX);
|
|
apte->PreviousTaskFile[0] = ((registers.feature & 0xFF00) >> 8);
|
|
apte->PreviousTaskFile[1] = ((registers.sector_count & 0xFF00) >> 8);
|
|
apte->PreviousTaskFile[2] = ((registers.lba_low & 0xFF00) >> 8);
|
|
apte->PreviousTaskFile[3] = ((registers.lba_mid & 0xFF00) >> 8);
|
|
apte->PreviousTaskFile[4] = ((registers.lba_high & 0xFF00) >> 8);
|
|
apte->CurrentTaskFile[0] = registers.feature & 0xFF;
|
|
apte->CurrentTaskFile[1] = registers.sector_count & 0xFF;
|
|
apte->CurrentTaskFile[2] = registers.lba_low & 0xFF;
|
|
apte->CurrentTaskFile[3] = registers.lba_mid & 0xFF;
|
|
apte->CurrentTaskFile[4] = registers.lba_mid & 0xFF;
|
|
apte->CurrentTaskFile[5] = registers.device_head;
|
|
apte->CurrentTaskFile[6] = registers.command;
|
|
|
|
switch(protocol)
|
|
{
|
|
case DICMOTE_ATA_PROTOCOL_PIO_IN:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_IN:
|
|
case DICMOTE_ATA_PROTOCOL_DMA: apte->AtaFlags = ATA_FLAGS_DATA_IN; break;
|
|
case DICMOTE_ATA_PROTOCOL_PIO_OUT:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_OUT: apte->AtaFlags = ATA_FLAGS_DATA_OUT; break;
|
|
}
|
|
|
|
switch(protocol)
|
|
{
|
|
case DICMOTE_ATA_PROTOCOL_DMA:
|
|
case DICMOTE_ATA_PROTOCOL_DMA_QUEUED:
|
|
case DICMOTE_ATA_PROTOCOL_FPDMA:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_IN:
|
|
case DICMOTE_ATA_PROTOCOL_UDMA_OUT: apte->AtaFlags |= ATA_FLAGS_USE_DMA; break;
|
|
}
|
|
|
|
apte->AtaFlags |= ATA_FLAGS_48BIT_COMMAND;
|
|
|
|
// Unknown if needed
|
|
apte->AtaFlags |= ATA_FLAGS_DRDY_REQUIRED;
|
|
|
|
QueryPerformanceFrequency(&frequency);
|
|
|
|
memcpy(data_buffer, buffer, *buf_len);
|
|
|
|
QueryPerformanceCounter(&start);
|
|
*sense = !DeviceIoControl(ctx->handle,
|
|
IOCTL_ATA_PASS_THROUGH,
|
|
apte_and_buffer,
|
|
apte_and_buffer_len,
|
|
apte_and_buffer,
|
|
apte_and_buffer_len,
|
|
&k,
|
|
NULL);
|
|
QueryPerformanceCounter(&end);
|
|
|
|
interval = (DOUBLE)(end.QuadPart - start.QuadPart) / frequency.QuadPart;
|
|
*duration = interval * 1000;
|
|
|
|
if(*sense) error = GetLastError();
|
|
|
|
memcpy(buffer, data_buffer, *buf_len);
|
|
|
|
error_registers->error = apte->CurrentTaskFile[0];
|
|
error_registers->sector_count = (apte->PreviousTaskFile[1] << 8) + apte->CurrentTaskFile[1];
|
|
error_registers->lba_low = (apte->PreviousTaskFile[2] << 8) + apte->CurrentTaskFile[2];
|
|
error_registers->lba_mid = (apte->PreviousTaskFile[3] << 8) + apte->CurrentTaskFile[3];
|
|
error_registers->lba_high = (apte->PreviousTaskFile[4] << 8) + apte->CurrentTaskFile[4];
|
|
error_registers->device_head = apte->CurrentTaskFile[5];
|
|
error_registers->status = apte->CurrentTaskFile[6];
|
|
|
|
*sense = error_registers->error != 0 || (error_registers->status & 0xA5) != 0;
|
|
|
|
free(apte_and_buffer);
|
|
return error;
|
|
} |