Refactored ATAPI commands

READ (10) still doesn't work correctly with large transfers, but it's a huge step in the right direction
This commit is contained in:
StrikerX3 2018-12-10 13:33:03 -02:00
parent 8cf4830d0c
commit b68e17b1e9
37 changed files with 1554 additions and 555 deletions

View file

@ -3,6 +3,8 @@ file(GLOB DIR_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/ata/*.h
${CMAKE_CURRENT_SOURCE_DIR}/ata/cmds/*.h
${CMAKE_CURRENT_SOURCE_DIR}/ata/drvs/*.h
${CMAKE_CURRENT_SOURCE_DIR}/atapi/*.h
${CMAKE_CURRENT_SOURCE_DIR}/atapi/cmds/*.h
${CMAKE_CURRENT_SOURCE_DIR}/basic/*.h
${CMAKE_CURRENT_SOURCE_DIR}/bus/*.h
${CMAKE_CURRENT_SOURCE_DIR}/sm/*.h
@ -18,6 +20,8 @@ file(GLOB DIR_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/ata/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ata/cmds/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ata/drvs/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/atapi/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/atapi/cmds/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/basic/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/bus/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sm/*.cpp

View file

@ -246,9 +246,6 @@ DMATransferResult ATAChannel::ReadDMA(uint8_t *dstBuffer, uint32_t readLen) {
m_currentCommand->ReadData(dstBuffer, readLen);
if (m_currentCommand->IsFinished()) {
log_spew("ATAChannel::ReadDMA: Finished processing command for channel %d\n", m_channel);
if (m_currentCommand == nullptr) {
log_spew("This thing broke :(\n", m_channel);
}
delete m_currentCommand;
m_currentCommand = nullptr;
return DMATransferEnd;
@ -270,9 +267,6 @@ DMATransferResult ATAChannel::WriteDMA(uint8_t *srcBuffer, uint32_t writeLen) {
m_currentCommand->WriteData(srcBuffer, writeLen);
if (m_currentCommand->IsFinished()) {
log_spew("ATAChannel::WriteDMA: Finished processing command for channel %d\n", m_channel);
if (m_currentCommand == nullptr) {
log_spew("This thing broke :(\n", m_channel);
}
delete m_currentCommand;
m_currentCommand = nullptr;
return DMATransferEnd;

View file

@ -100,7 +100,7 @@ void DMAProtocolCommand::ReadData(uint8_t *value, uint32_t size) {
// If the device uses removable media, check if it has media
// TODO: implement removable media functions in the driver
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedia()) {
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedium()) {
// [8.23.6]: "NM shall be set to one if no media is present in a removable media device."
m_regs.error |= ErrDMANoMedia;
UnrecoverableError();
@ -151,7 +151,7 @@ void DMAProtocolCommand::WriteData(uint8_t *value, uint32_t size) {
// If the device uses removable media, check if it has media
// TODO: implement removable media functions in the driver
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedia()) {
/*if (m_driver->IsRemovableMedia() && !m_driver->HasMedium()) {
// [8.23.6]: "NM shall be set to one if no media is present in a removable media device."
m_regs.error |= ErrDMANoMedia;
UnrecoverableError();

View file

@ -12,13 +12,18 @@
#include "proto_packet.h"
#include "vixen/log.h"
#include "../atapi_defs.h"
#include "vixen/hw/atapi/atapi_defs.h"
#include "vixen/hw/atapi/atapi_xbox.h"
#include "vixen/hw/atapi/atapi_utils.h"
#include "vixen/hw/atapi/cmds/atapi_command.h"
namespace vixen {
namespace hw {
namespace ata {
namespace cmd {
using namespace vixen::hw::atapi;
// Notes regarding the protocol:
// - There are two fluxograms: PIO/non-data transfers and DMA transfers
// - They're largely the same, except for the actual data transfer and some register flag manipulations
@ -33,7 +38,7 @@ namespace cmd {
// bit 2 (REL) (Overlapped only) Indicates that the device is performing a bus release
// bit 1 (I/O) When set to 1, indicates a transfer to the host; 0 indicates transfer to the device
// bit 0 (C/D) When set to 1, indicates a command packet; 0 indicates a data packet
// - The Status register is largely the same, except for the following fields:
// - The Status register includes the following fields:
// bit 5 (DMRD) DMA ready
// bit 4 (SERV) (Overlapped only) Indicates that another command can be serviced
// bit 0 (CHK) Indicates an error; host should check the Error register sense key or code bit
@ -44,9 +49,7 @@ namespace cmd {
PacketProtocolCommand::PacketProtocolCommand(ATADevice& device)
: IATACommand(device)
, m_packetCmdBuffer(nullptr)
, m_packetDataBuffer(nullptr)
, m_packetDataPos(0)
, m_packetDataSize(0)
, m_command(nullptr)
{
}
@ -54,84 +57,72 @@ PacketProtocolCommand::~PacketProtocolCommand() {
if (m_packetCmdBuffer != nullptr) {
delete[] m_packetCmdBuffer;
}
if (m_packetDataBuffer != nullptr) {
delete[] m_packetDataBuffer;
if (m_command != nullptr) {
delete m_command;
}
}
void PacketProtocolCommand::Execute() {
if (ReadInput()) {
// Update Interrupt register
m_regs.sectorCount |= PkIntrCmdOrData;
m_regs.sectorCount &= ~PkIntrIODirection;
// On PIO and non-data transfers, Bus Release is cleared
if (!m_dmaTransfer) {
m_regs.sectorCount &= ~PkIntrBusRelease;
}
// Update Status register
m_regs.status |= StDataRequest;
m_regs.status &= ~StBusy;
// Allocate buffer for the packet
m_packetCmdBuffer = new uint8_t[m_driver->GetPacketCommandSize()];
m_packetCmdPos = 0;
// Follow (A) in the protocol fluxogram
}
else {
HandleProtocolTail(true);
}
}
bool PacketProtocolCommand::ReadInput() {
// Read input according to the protocol [8.21.4]
m_overlapped = !!(m_regs.features & PkFeatOverlapped);
m_dmaTransfer = !!(m_regs.features & PkFeatDMATransfer);
m_tag = (m_regs.sectorCount >> kPkTagShift) & kPkTagMask;
m_byteCountLimit = m_regs.cylinder;
m_selectedDevice = m_regs.GetSelectedDeviceIndex();
m_packetCmdState.input.overlapped = !!(m_regs.features & PkFeatOverlapped);
m_packetCmdState.input.dmaTransfer = !!(m_regs.features & PkFeatDMATransfer);
m_packetCmdState.input.tag = (m_regs.sectorCount >> kPkTagShift) & kPkTagMask;
m_packetCmdState.input.byteCountLimit = m_regs.cylinder;
m_packetCmdState.input.selectedDevice = m_regs.GetSelectedDeviceIndex();
// If the byte count limit is zero, set ABRT and stop command
if (m_packetCmdState.input.byteCountLimit == 0) {
m_regs.error |= ErrAbort;
HandleProtocolTail(true);
return;
}
return true;
// A byte count limit of 0xFFFF is interpreted by the device as though it were 0xFFFE
if (m_packetCmdState.input.byteCountLimit == 0xFFFF) {
m_packetCmdState.input.byteCountLimit = 0xFFFE;
}
// Update Interrupt register
m_regs.sectorCount |= PkIntrCmdOrData;
m_regs.sectorCount &= ~PkIntrIODirection;
// On PIO and non-data transfers, Bus Release is cleared
if (!m_packetCmdState.input.dmaTransfer) {
m_regs.sectorCount &= ~PkIntrBusRelease;
}
// Update Status register
m_regs.status |= StDataRequest;
m_regs.status &= ~StBusy;
// Allocate buffer for the packet
m_packetCmdBuffer = new uint8_t[m_driver->GetPacketCommandSize()];
m_packetCmdPos = 0;
// Follow (A) in the protocol fluxogram
}
void PacketProtocolCommand::ReadData(uint8_t *value, uint32_t size) {
// Host is reading the data requested by the Packet command
// If the packet data buffer is empty, ask driver to fill in a full block
// of data (up to the byte count limit) and tell us how many bytes it filled
if (m_packetDataSize == 0) {
// Let the driver fill in the data buffer
if (!m_driver->ProcessATAPIPacketDataRead(m_packetInfo, m_packetDataBuffer, m_byteCountLimit, &m_packetDataSize)) {
HandleProtocolTail(true);
return;
}
}
// Copy from buffer to value
// TODO: handle partial transfers
memcpy(value, m_packetDataBuffer + m_packetDataPos, size);
m_packetDataPos += size;
// Read from buffer
uint32_t sizeRead = m_packetCmdState.dataBuffer.Read(value, size);
// Done reading the packet data?
if (m_packetDataPos >= m_packetDataSize) {
if (m_packetCmdState.dataBuffer.IsReadFinished()) {
m_regs.status |= StBusy;
m_regs.status &= ~StDataRequest;
// Done transferring all the data needed by the packet?
m_packetDataTotal += m_packetDataPos;
if (m_packetDataTotal >= m_packetInfo.transferSize) {
if (m_command->IsTransferFinished()) {
HandleProtocolTail(false);
return;
}
// Let the driver fill in the data buffer again
if (!m_driver->ProcessATAPIPacketDataRead(m_packetInfo, m_packetDataBuffer, m_byteCountLimit, &m_packetDataSize)) {
// Read more data
if (!m_command->Execute()) {
HandleProtocolTail(true);
return;
}
m_packetDataPos = 0;
}
}
@ -149,29 +140,26 @@ void PacketProtocolCommand::WriteData(uint8_t *value, uint32_t size) {
}
else {
// Writing the data requested by the Packet command
// TODO: handle partial transfers
memcpy(m_packetDataBuffer + m_packetDataPos, value, size);
m_packetDataPos += size;
// Write to buffer
uint32_t sizeWritten = m_packetCmdState.dataBuffer.Write(value, size);
// Done writing the packet data?
if (m_packetDataPos >= m_byteCountLimit) {
if (m_packetCmdState.dataBuffer.IsWriteFinished()) {
m_regs.status |= StBusy;
m_regs.status &= ~StDataRequest;
// Let the driver process the data
if (!m_driver->ProcessATAPIPacketDataWrite(m_packetInfo, m_packetDataBuffer, m_byteCountLimit)) {
// Execute command with the current buffer
if (!m_command->Execute()) {
HandleProtocolTail(true);
return;
}
// Done transferring all the data needed by the packet?
m_packetDataTotal += m_packetDataPos;
if (m_packetDataTotal >= m_packetInfo.transferSize) {
if (m_command->IsTransferFinished()) {
HandleProtocolTail(false);
return;
}
m_packetDataPos = 0;
}
}
}
@ -181,63 +169,45 @@ void PacketProtocolCommand::ProcessPacket() {
m_regs.status |= StBusy;
m_regs.status &= ~StDataRequest;
// Identify packet
// Get the command descriptor block
atapi::CommandDescriptorBlock *cdb = reinterpret_cast<atapi::CommandDescriptorBlock *>(m_packetCmdBuffer);
// Check that there is an operation type for the operation code.
// Every command must have an operation type.
if (atapi::kOperationTypes.count(cdb->opCode.u8) == 0) {
// Get the command factory for the command's operation code
if (kCmdFactories.count(cdb->opCode.u8) == 0) {
log_warning("PacketProtocolCommand::ProcessPacket: Unimplemented command 0x%x!\n", cdb->opCode.u8);
HandleProtocolTail(true);
return;
}
// Prepare packet info data
m_packetInfo.cdb = *cdb;
m_packetInfo.opType = atapi::kOperationTypes.at(cdb->opCode.u8);
log_spew("PacketProtocolCommand::ProcessPacket: Processing command 0x%x\n", cdb->opCode.u8);
// Check if the device can process the packet
bool succeeded = m_driver->ValidateATAPIPacket(m_packetInfo);
// Instantiate the command.
// This will also allocate the data buffer if necessary.
m_packetCmdState.cdb = *cdb;
auto factory = kCmdFactories.at(cdb->opCode.u8);
m_command = factory(m_packetCmdState, m_driver);
// Handle error
if (!succeeded) {
// Validate parameters; return error immediately if invalid.
// Will also initialize the data buffer if a transfer is required.
if (!m_command->Prepare()) {
HandleProtocolTail(true);
return;
}
// If the byte count limit is zero, set ABRT and stop command
if (m_byteCountLimit == 0) {
m_regs.error |= ErrAbort;
HandleProtocolTail(true);
return;
}
// If the total requested data transfer length is greater than the byte count limit, then the byte count limit must be even
// If the total requested data transfer length is less than or equal to the byte count limit, then the byte count limit could be even or odd
if (m_packetInfo.transferSize > m_byteCountLimit && (m_byteCountLimit & 1)) {
m_regs.error |= ErrAbort;
HandleProtocolTail(true);
return;
}
// A byte count limit of 0xFFFF is interpreted by the device as though it were 0xFFFE
if (m_byteCountLimit == 0xFFFF) {
m_byteCountLimit = 0xFFFE;
}
if (m_packetInfo.opType == atapi::PktOpNonData) {
// Execute non-data command
bool succeeded = m_driver->ProcessATAPIPacketNonData(m_packetInfo);
if (m_command->GetOperationType() == PktOpNonData) {
// Execute non-data command immediately
bool succeeded = m_command->Execute();
HandleProtocolTail(!succeeded);
}
else {
// Prepare registers for a data transfer (in or out)
PrepareDataTransfer();
}
}
void PacketProtocolCommand::PrepareDataTransfer() {
// Check for overlapped execution (corresponds to (B) in the protocol fluxogram)
if (m_driver->SupportsOverlap() && m_driver->IsOverlapEnabled() && m_overlapped) {
if (m_driver->SupportsOverlap() && m_driver->IsOverlapEnabled() && m_packetCmdState.input.overlapped) {
ProcessPacketOverlapped();
}
else {
@ -246,7 +216,7 @@ void PacketProtocolCommand::PrepareDataTransfer() {
}
void PacketProtocolCommand::ProcessPacketImmediate() {
if (m_dmaTransfer) {
if (m_packetCmdState.input.dmaTransfer) {
m_regs.sectorCount &= ~PkIntrBusRelease;
m_regs.status &= ~StService;
m_regs.status |= StDMAReady;
@ -254,14 +224,14 @@ void PacketProtocolCommand::ProcessPacketImmediate() {
else {
// Set Tag
m_regs.sectorCount &= ~(kPkTagMask << kPkTagShift);
m_regs.sectorCount |= m_tag << kPkTagShift;
m_regs.sectorCount |= m_packetCmdState.input.tag << kPkTagShift;
// Set byte count
m_regs.cylinder = m_byteCountLimit;
m_regs.cylinder = m_packetCmdState.input.byteCountLimit;
}
// Set I/O
if (m_packetInfo.opType == atapi::PktOpDataOut) {
if (m_command->GetOperationType() == atapi::PktOpDataOut) {
m_regs.sectorCount |= PkIntrIODirection;
}
else {
@ -275,12 +245,6 @@ void PacketProtocolCommand::ProcessPacketImmediate() {
m_regs.status |= StDataRequest;
m_regs.status &= ~StBusy;
// Allocate buffer for the data transfer
m_packetDataBuffer = new uint8_t[m_byteCountLimit];
m_packetDataPos = 0;
m_packetDataTotal = 0;
m_packetDataSize = 0;
m_interrupt.Assert();
}
@ -298,13 +262,13 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
// Error register:
// "Sense Key is a command packet set specific error indication."
m_regs.error &= ~(kPkSenseMask << kPkSenseShift);
m_regs.error |= (m_packetInfo.result.senseKey & kPkSenseMask) << kPkSenseShift;
m_regs.error |= (m_packetCmdState.result.senseKey & kPkSenseMask) << kPkSenseShift;
// "ABRT shall be set to one if the requested command has been command
// [sic] aborted because the command code or a command parameter is
// invalid. ABRT may be set to one if the device is not able to
// complete the action requested by the command."
if (m_packetInfo.result.aborted) {
if (m_packetCmdState.result.aborted) {
m_regs.error |= ErrAbort;
}
else {
@ -313,7 +277,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
// "EOM - the meaning of this bit is command set specific. See the
// appropriate command set standard for its definition."
if (m_packetInfo.result.endOfMedium) {
if (m_packetCmdState.result.endOfMedium) {
m_regs.error |= PkErrEndOfMedium;
}
else {
@ -322,7 +286,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
// "ILI - the meaning of this bit is command set specific. See the
// appropriate command set standard for its definition."
if (m_packetInfo.result.incorrectLength) {
if (m_packetCmdState.result.incorrectLength) {
m_regs.error |= PkErrIncorrectLength;
}
else {
@ -336,7 +300,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
// disabled, this field is not applicable."
// We'll fill it in regardless of command queuing or overlap support
m_regs.sectorCount &= ~(kPkTagMask << kPkTagShift);
m_regs.sectorCount |= m_tag << kPkTagShift;
m_regs.sectorCount |= m_packetCmdState.input.tag << kPkTagShift;
// "REL - Shall be cleared to zero."
m_regs.sectorCount &= ~PkIntrBusRelease;
@ -361,7 +325,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
// TODO: support overlapped operations
// "DF(Device Fault) shall be set to one if a device fault has occurred."
if (m_packetInfo.result.deviceFault) {
if (m_packetCmdState.result.deviceFault) {
m_regs.status |= StDeviceFault;
}
@ -375,7 +339,7 @@ void PacketProtocolCommand::HandleProtocolTail(bool hasError) {
m_regs.sectorCount |= PkIntrIODirection | PkIntrCmdOrData;
m_regs.sectorCount &= ~PkIntrBusRelease;
if (m_dmaTransfer) {
if (m_packetCmdState.input.dmaTransfer) {
m_regs.status &= ~StDataRequest;
}
m_regs.status |= StReady;

View file

@ -14,6 +14,11 @@
#include <cstdint>
#include "ata_command.h"
#include "vixen/hw/atapi/cmds/cmd_mode_sense_10.h"
#include "vixen/hw/atapi/cmds/cmd_read_10.h"
#include "vixen/hw/atapi/cmds/cmd_read_capacity.h"
#include "vixen/hw/atapi/cmds/cmd_read_dvd_structure.h"
#include "vixen/hw/atapi/cmds/cmd_test_unit_ready.h"
namespace vixen {
namespace hw {
@ -37,9 +42,6 @@ public:
private:
// ----- Protocol operations ----------------------------------------------
// Parses the input registers and stores the values in the parameters.
bool ReadInput();
// Corresponds to the end of the protocol fluxogram starting from (C) when
// hasError is true, or (D) if false.
void HandleProtocolTail(bool hasError);
@ -51,28 +53,30 @@ private:
// Corresponds to the protocol fluxogram starting from (B).
void PrepareDataTransfer();
// Prepares registers for an immediate (non-overlapped) data transfer.
void ProcessPacketImmediate();
// Prepares registers for an overlapped data transfer.
void ProcessPacketOverlapped();
// ----- Parameters -------------------------------------------------------
bool m_overlapped;
bool m_dmaTransfer;
uint8_t m_tag;
uint16_t m_byteCountLimit;
uint8_t m_selectedDevice;
// ----- State ------------------------------------------------------------
uint8_t *m_packetCmdBuffer;
uint8_t m_packetCmdPos;
uint8_t *m_packetDataBuffer;
uint16_t m_packetDataPos;
uint32_t m_packetDataTotal;
uint32_t m_packetDataSize;
atapi::PacketCommandState m_packetCmdState;
atapi::PacketInformation m_packetInfo;
atapi::cmd::IATAPICommand *m_command;
};
// Map commands to their factories
const std::unordered_map<uint8_t, atapi::cmd::IATAPICommand::Factory, std::hash<uint8_t>> kCmdFactories = {
{ atapi::OpModeSense10, atapi::cmd::ModeSense10::Factory },
{ atapi::OpRead10, atapi::cmd::Read10::Factory },
{ atapi::OpReadCapacity, atapi::cmd::ReadCapacity::Factory },
{ atapi::OpReadDVDStructure, atapi::cmd::ReadDVDStructure::Factory },
//{ atapi::OpRequestSense, atapi::cmd::RequestSense::Factory },
{ atapi::OpTestUnitReady, atapi::cmd::TestUnitReady::Factory },
};
}

View file

@ -14,7 +14,7 @@
#include <cstdint>
#include "../../ata/ata_defs.h"
#include "../../ata/atapi_common.h"
#include "../../atapi/atapi_common.h"
#include "../ata_common.h"
#include "util.h"
@ -47,18 +47,17 @@ public:
virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) = 0;
virtual bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) = 0;
// ----- ATAPI ------------------------------------------------------------
virtual bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) = 0;
virtual bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) = 0;
virtual bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) = 0;
virtual bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) = 0;
// ----- Feature sets -----------------------------------------------------
virtual bool SupportsPacketCommands() = 0;
virtual bool SupportsOverlap() = 0;
virtual bool IsOverlapEnabled() = 0;
// ----- Medium -----------------------------------------------------------
virtual bool HasMedium() = 0;
virtual uint32_t GetMediumCapacitySectors() = 0;
virtual uint32_t GetSectorSize() = 0;
// ----- Utility functions ------------------------------------------------
@ -67,6 +66,7 @@ public:
virtual uint32_t CHSToLBA(uint32_t cylinder, uint8_t head, uint8_t sector) = 0;
virtual void LBAToCHS(uint32_t lbaAddress, uint16_t *cylinder, uint8_t *head, uint8_t *sector) = 0;
virtual uint8_t GetPacketCommandSize() = 0;
protected:
// ----- Common data ------------------------------------------------------

View file

@ -37,13 +37,6 @@ public:
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override { return false; }
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override { return false; }
// ----- ATAPI ------------------------------------------------------------
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override { return false; }
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override { return false; }
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override { return false; }
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override { return false; }
// ----- Feature sets -----------------------------------------------------
@ -51,6 +44,12 @@ public:
bool SupportsOverlap() override { return false; }
bool IsOverlapEnabled() override { return false; }
// ----- Medium -----------------------------------------------------------
bool HasMedium() override { return false; }
uint32_t GetMediumCapacitySectors() override { return 0; }
uint32_t GetSectorSize() override { return kSectorSize; }
// ----- Utility functions ------------------------------------------------
bool IsAttached() override { return true; }

View file

@ -13,8 +13,6 @@
#include "vixen/log.h"
#include "vixen/io.h"
#include "vixen/hw/ata/atapi_xbox.h"
#include "vixen/hw/ata/atapi_utils.h"
namespace vixen {
namespace hw {
@ -28,15 +26,9 @@ BaseDVDDriveATADeviceDriver::BaseDVDDriveATADeviceDriver() {
BaseDVDDriveATADeviceDriver::~BaseDVDDriveATADeviceDriver() {
}
bool BaseDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t * buffer, uint32_t size) {
// Always fail; this function should never be called on devices that support the PACKET Command feature set
log_warning("BaseDVDDriveATADeviceDriver::Read: Unexpected ATA read\n");
return false;
}
bool BaseDVDDriveATADeviceDriver::Write(uint64_t byteAddress, uint8_t * buffer, uint32_t size) {
// Always fail; this function should never be called on devices that support the PACKET Command feature set
log_warning("BaseDVDDriveATADeviceDriver::Write: Unexpected ATA write\n");
bool BaseDVDDriveATADeviceDriver::Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
// Always fail; the Xbox DVD drive doesn't support writes
log_warning("BaseDVDDriveATADeviceDriver::Write: Unexpected write\n");
return false;
}
@ -138,41 +130,6 @@ uint8_t BaseDVDDriveATADeviceDriver::GetPacketCommandSize() {
return 12;
}
bool BaseDVDDriveATADeviceDriver::ValidateCommand(PacketInformation& packetInfo) {
switch (packetInfo.cdb.opCode.u8) {
case OpModeSense10:
switch (packetInfo.cdb.modeSense10.pageCode) {
case kPageCodeAuthentication:
// TODO: is it correct to fail if the length is smaller than the page data?
if (B2L16(packetInfo.cdb.modeSense10.length) < sizeof(XboxDVDAuthentication)) {
packetInfo.result.aborted = true;
packetInfo.result.incorrectLength = true;
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKIllegalRequest;
packetInfo.result.additionalSenseCode = ASCInvalidFieldInCDB;
return false;
}
packetInfo.transferSize = sizeof(XboxDVDAuthentication);
return true;
}
return true;
case OpRequestSense:
packetInfo.transferSize = packetInfo.cdb.requestSense.length;
return true;
case OpReadCapacity:
packetInfo.transferSize = sizeof(ReadCapacityData);
return true;
case OpRead10:
packetInfo.transferSize = (uint32_t)B2L16(packetInfo.cdb.read10.length) * kDVDSectorSize;
return true;
case OpReadDVDStructure:
packetInfo.transferSize = kDVDSectorSize;
return true;
default:
return true;
}
}
}
}
}

View file

@ -33,26 +33,23 @@ public:
bool IdentifyPacketDevice(IdentifyPacketDeviceData *data) override;
bool SecurityUnlock(uint8_t unlockData[kSectorSize]) override;
bool SetDeviceParameters(uint8_t heads, uint8_t sectorsPerTrack) override;
// ----- Data access ------------------------------------------------------
virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0;
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
// ----- Feature sets -----------------------------------------------------
bool SupportsPacketCommands() override { return true; }
bool SupportsOverlap() override { return false; }
bool IsOverlapEnabled() override { return false; }
// ----- Data access ------------------------------------------------------
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
// ----- Medium -----------------------------------------------------------
// ----- ATAPI ------------------------------------------------------------
virtual bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override = 0;
virtual bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override = 0;
virtual bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override = 0;
virtual bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override = 0;
bool ValidateCommand(atapi::PacketInformation& packetInfo);
virtual bool HasMedium() override = 0;
virtual uint32_t GetMediumCapacitySectors() override = 0;
uint32_t GetSectorSize() override { return atapi::kDVDSectorSize; }
// ----- Utility functions ------------------------------------------------
@ -61,8 +58,6 @@ public:
uint32_t CHSToLBA(uint32_t cylinder, uint8_t head, uint8_t sector) override;
void LBAToCHS(uint32_t lbaAddress, uint16_t *cylinder, uint8_t *head, uint8_t *sector) override;
uint8_t GetPacketCommandSize() override;
protected:
};
}

View file

@ -13,108 +13,22 @@
#include "vixen/log.h"
#include "vixen/io.h"
#include "vixen/hw/ata/atapi_defs.h"
#include "vixen/hw/ata/atapi_xbox.h"
#include "vixen/hw/ata/atapi_utils.h"
namespace vixen {
namespace hw {
namespace ata {
using namespace atapi;
DummyDVDDriveATADeviceDriver::DummyDVDDriveATADeviceDriver() {
strcpy(m_serialNumber, "1234567890");
strcpy(m_firmwareRevision, "1.00");
strcpy(m_modelNumber, "DUMMY DVD 12345");
strcpy(m_serialNumber, "0123456789");
strcpy(m_firmwareRevision, "1.0.0");
strcpy(m_modelNumber, "vXn DDVDD0010000");
}
DummyDVDDriveATADeviceDriver::~DummyDVDDriveATADeviceDriver() {
}
bool DummyDVDDriveATADeviceDriver::ValidateATAPIPacket(PacketInformation& packetInfo) {
log_debug("DummyDVDDriveATADeviceDriver::ValidateATAPIPacket: Operation code 0x%x\n", packetInfo.cdb.opCode.u8, packetInfo.cdb.opCode.fields.commandCode, packetInfo.cdb.opCode.fields.groupCode);
// TODO: device-specific validation
// Check if the command is supported and has valid parameters.
return ValidateCommand(packetInfo);
}
bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketNonData(PacketInformation& packetInfo) {
switch (packetInfo.cdb.opCode.u8) {
case OpTestUnitReady:
// Say that there is no disc in the drive
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKNotReady;
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
return true;
default:
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketNonData: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
return false;
}
}
bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) {
switch (packetInfo.cdb.opCode.u8) {
case OpModeSense10:
switch (packetInfo.cdb.modeSense10.pageCode) {
case kPageCodeAuthentication:
{
// TODO: handle partial reads (if those ever happen here)
if (byteCountLimit < sizeof(XboxDVDAuthentication)) {
packetInfo.result.aborted = true;
packetInfo.result.deviceFault = true;
return false;
}
// Fill in just enough information to pass basic authentication checks on modified kernels
// TODO: Research Xbox DVD authentication
// https://multimedia.cx/eggs/xbox-sphinx-protocol/
XboxDVDAuthentication *dvdAuth = reinterpret_cast<XboxDVDAuthentication *>(packetDataBuffer);
dvdAuth->CDFValid = 1;
dvdAuth->PartitionArea = 1;
dvdAuth->Authentication = 1;
*packetDataSize = sizeof(XboxDVDAuthentication);
return true;
}
default:
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented page code 0x%x for MODE SENSE(10)\n", packetInfo.cdb.modeSense10.pageCode);
return false;
}
case OpRead10:
{
// Say that there is no disc in the drive
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKNotReady;
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
return true;
}
case OpReadCapacity:
{
// Say that there is no disc in the drive
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKNotReady;
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
ReadCapacityData *capData = reinterpret_cast<ReadCapacityData *>(packetDataBuffer);
L2B32(capData->lba, 0);
L2B32(capData->blockLength, 0);
*packetDataSize = sizeof(ReadCapacityData);
return true;
}
default:
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
return false;
}
}
bool DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit) {
log_debug("DummyDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
bool DummyDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
// Always fail; no media in drive
return false;
}

View file

@ -27,12 +27,14 @@ public:
DummyDVDDriveATADeviceDriver();
~DummyDVDDriveATADeviceDriver() override;
// ----- ATAPI ------------------------------------------------------------
// ----- Data access ------------------------------------------------------
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override;
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override;
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override;
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override;
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
// ----- Medium -----------------------------------------------------------
bool HasMedium() override { return false; }
uint32_t GetMediumCapacitySectors() override { return 0; }
};
}

View file

@ -13,9 +13,9 @@
#include "vixen/log.h"
#include "vixen/io.h"
#include "vixen/hw/ata/atapi_defs.h"
#include "vixen/hw/ata/atapi_xbox.h"
#include "vixen/hw/ata/atapi_utils.h"
#include "vixen/hw/atapi/atapi_defs.h"
#include "vixen/hw/atapi/atapi_xbox.h"
#include "vixen/hw/atapi/atapi_utils.h"
namespace vixen {
namespace hw {
@ -25,8 +25,8 @@ using namespace atapi;
ImageDVDDriveATADeviceDriver::ImageDVDDriveATADeviceDriver() {
strcpy(m_serialNumber, "9876543210");
strcpy(m_firmwareRevision, "1.00");
strcpy(m_modelNumber, "IMAGE DVD 12345");
strcpy(m_firmwareRevision, "1.0.0");
strcpy(m_modelNumber, "vXn VDVDD0010000");
}
ImageDVDDriveATADeviceDriver::~ImageDVDDriveATADeviceDriver() {
@ -63,178 +63,40 @@ bool ImageDVDDriveATADeviceDriver::LoadImageFile(const char *imagePath, bool cop
return true;
}
bool ImageDVDDriveATADeviceDriver::EjectMedia() {
bool ImageDVDDriveATADeviceDriver::EjectMedium() {
if (m_fpImage == NULL) {
log_warning("ImageDVDDriveATADeviceDriver::EjectMedia: No media to eject\n");
log_warning("ImageDVDDriveATADeviceDriver::EjectMedium: No medium to eject\n");
return false;
}
log_info("ImageDVDDriveATADeviceDriver::EjectMedia: Media ejected\n");
log_info("ImageDVDDriveATADeviceDriver::EjectMedium: Medium ejected\n");
fclose(m_fpImage);
m_fpImage = NULL;
// TODO: notify media removal
// TODO: should we notify media removal?
return true;
}
bool ImageDVDDriveATADeviceDriver::ValidateATAPIPacket(PacketInformation& packetInfo) {
log_debug("ImageDVDDriveATADeviceDriver::ValidateATAPIPacket: Operation code 0x%x\n", packetInfo.cdb.opCode.u8, packetInfo.cdb.opCode.fields.commandCode, packetInfo.cdb.opCode.fields.groupCode);
// TODO: device-specific validation
// Check if the command is supported and has valid parameters.
return ValidateCommand(packetInfo);
}
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketNonData(PacketInformation& packetInfo) {
switch (packetInfo.cdb.opCode.u8) {
case OpTestUnitReady:
// If there is no disc in the drive, return the expected sense key and parameters.
// The default values tell that there is media in the drive and the device is ready to accept commands.
if (!HasMedia()) {
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKNotReady;
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
}
return true;
default:
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketNonData: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
bool ImageDVDDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) {
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
// Should also honor the cache flags
// Image not loaded
if (m_fpImage == NULL) {
return false;
}
}
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) {
// TODO: refactor command handling
// - make a structure similar to ATA commands
switch (packetInfo.cdb.opCode.u8) {
case OpModeSense10:
switch (packetInfo.cdb.modeSense10.pageCode) {
case kPageCodeAuthentication:
{
// TODO: handle partial reads (if those ever happen here)
if (byteCountLimit < sizeof(XboxDVDAuthentication)) {
packetInfo.result.aborted = true;
packetInfo.result.deviceFault = true;
return false;
}
// Fill in just enough information to pass basic authentication checks on modified kernels
// TODO: Research Xbox DVD authentication
// https://multimedia.cx/eggs/xbox-sphinx-protocol/
XboxDVDAuthentication *dvdAuth = reinterpret_cast<XboxDVDAuthentication *>(packetDataBuffer);
dvdAuth->CDFValid = 1;
dvdAuth->PartitionArea = 1;
dvdAuth->Authentication = 1;
*packetDataSize = sizeof(XboxDVDAuthentication);
return true;
}
default:
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented page code 0x%x for MODE SENSE(10)\n", packetInfo.cdb.modeSense10.pageCode);
return false;
}
case OpRead10:
{
if (HasMedia()) {
uint32_t lba = B2L32(packetInfo.cdb.read10.lba);
uint16_t transferLength = B2L16(packetInfo.cdb.read10.length);
packetInfo.transferSize = transferLength * kDVDSectorSize;
// If this is the first read, fill in transfer data
if (!m_transfer) {
m_currentByte = lba * kDVDSectorSize;
m_lastByte = m_currentByte + transferLength * kDVDSectorSize;
m_transfer = true;
log_spew("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Starting transfer: 0x%llx to 0x%llx\n", m_currentByte, m_lastByte);
}
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
// Read from media
uint16_t readLen = (byteCountLimit < m_lastByte - m_currentByte)
? byteCountLimit
: m_lastByte - m_currentByte;
_fseeki64(m_fpImage, m_currentByte, SEEK_SET);
*packetDataSize = fread(packetDataBuffer, 1, readLen, m_fpImage);
// Update position
m_currentByte += *packetDataSize;
if (m_currentByte >= m_lastByte || *packetDataSize < readLen) {
log_spew("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Transfer finished\n");
m_transfer = false;
}
}
else {
// Say that there is no disc in the drive
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKNotReady;
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
}
return true;
}
case OpReadCapacity:
{
ReadCapacityData *capData = reinterpret_cast<ReadCapacityData *>(packetDataBuffer);
if (HasMedia()) {
L2B32(capData->lba, m_sectorCapacity);
L2B32(capData->blockLength, kDVDSectorSize);
}
else {
// Say that there is no disc in the drive
packetInfo.result.status = StCheckCondition;
packetInfo.result.senseKey = SKNotReady;
packetInfo.result.additionalSenseCode = ASCMediumNotPresent;
L2B32(capData->lba, 0);
L2B32(capData->blockLength, 0);
}
*packetDataSize = sizeof(ReadCapacityData);
return true;
}
case OpReadDVDStructure:
{
ReadDVDStructureData *dvdData = reinterpret_cast<ReadDVDStructureData *>(packetDataBuffer);
memset(dvdData, 0, kDVDSectorSize);
switch (packetInfo.cdb.readDVDStructure.format) {
case DVDFmtPhysical:
L2B16(dvdData->dataLength, (uint16_t)sizeof(ReadDVDStructureData::physicalFormatInformation));
// TODO: compute fields based on the image file
dvdData->physicalFormatInformation.partVersion = 1;
dvdData->physicalFormatInformation.bookType = BookTypeDVDROM;
dvdData->physicalFormatInformation.maxRate = MaxRate10_08Mbps;
dvdData->physicalFormatInformation.discSize = DiscSize120mm;
dvdData->physicalFormatInformation.layerType = 0;
dvdData->physicalFormatInformation.trackPath = TrackPathOTP;
dvdData->physicalFormatInformation.numLayers = NumLayers2;
dvdData->physicalFormatInformation.trackDensity = TrackDensity0_74umPerTrack;
dvdData->physicalFormatInformation.linearDensity = LinearDensity0_293umPerBit;
L2B24(dvdData->physicalFormatInformation.dataStartingSector, kStartingSectorNumberDVDROM);
L2B24(dvdData->physicalFormatInformation.dataEndingSector, m_sectorCapacity);
L2B24(dvdData->physicalFormatInformation.layer0EndingSector, 0);
dvdData->physicalFormatInformation.burstCuttingArea = 0;
*packetDataSize = kDVDSectorSize;
return true;
default:
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented format 0x%x for READ DVD STRUCTURE\n", packetInfo.cdb.readDVDStructure.format);
return false;
}
}
default:
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
// Seek address
if (_fseeki64(m_fpImage, byteAddress, SEEK_SET)) {
return false;
}
}
bool ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite(PacketInformation& packetInfo, uint8_t *packetDataBuffer, uint16_t byteCountLimit) {
// Read data from image
// TODO: handle copy-on-write
// If copy-on-write and the sector is copied, read from copy, otherwise read from image file
// If not copy-on-write, read from image file directly
int lenRead = fread(buffer, 1, size, m_fpImage);
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataWrite: Unimplemented operation code 0x%x\n", packetInfo.cdb.opCode.u8);
return false;
// Read is successful if the full size is read
return lenRead == size;
}
}

View file

@ -34,28 +34,22 @@ public:
// ----- Virtual DVD image management -------------------------------------
bool LoadImageFile(const char *imagePath, bool copyOnWrite);
bool EjectMedia();
bool EjectMedium();
// ----- ATAPI ------------------------------------------------------------
// ----- Data access ------------------------------------------------------
bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override;
// ----- Medium -----------------------------------------------------------
bool HasMedium() override { return m_fpImage != NULL; }
uint32_t GetMediumCapacitySectors() override { return m_sectorCapacity; }
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override;
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override;
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override;
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override;
private:
FILE *m_fpImage = NULL;
bool m_copyOnWrite;
inline bool HasMedia() { return m_fpImage != NULL; }
uint64_t m_sectorCapacity;
// ----- Transfer state ---------------------------------------------------
bool m_transfer = false;
uint64_t m_currentByte;
uint64_t m_lastByte;
};
}

View file

@ -33,24 +33,23 @@ public:
bool IdentifyPacketDevice(IdentifyPacketDeviceData *data) override;
bool SecurityUnlock(uint8_t unlockData[kSectorSize]) override;
bool SetDeviceParameters(uint8_t heads, uint8_t sectorsPerTrack) override;
// ----- Feature sets -----------------------------------------------------
bool SupportsPacketCommands() override { return false; }
bool SupportsOverlap() override { return false; }
bool IsOverlapEnabled() override { return false; }
// ----- Data access ------------------------------------------------------
virtual bool Read(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0;
virtual bool Write(uint64_t byteAddress, uint8_t *buffer, uint32_t size) override = 0;
// ----- ATAPI ------------------------------------------------------------
// ----- Feature sets -----------------------------------------------------
bool ValidateATAPIPacket(atapi::PacketInformation& packetInfo) override { return false; }
bool ProcessATAPIPacketNonData(atapi::PacketInformation& packetInfo) override { return false; }
bool ProcessATAPIPacketDataRead(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit, uint32_t *packetDataSize) override { return false; }
bool ProcessATAPIPacketDataWrite(atapi::PacketInformation& packetInfo, uint8_t* packetDataBuffer, uint16_t byteCountLimit) override { return false; }
bool SupportsPacketCommands() override { return false; }
bool SupportsOverlap() override { return false; }
bool IsOverlapEnabled() override { return false; }
// ----- Medium -----------------------------------------------------------
bool HasMedium() override { return true; }
virtual uint32_t GetMediumCapacitySectors() override { return m_sectorCapacity; }
uint32_t GetSectorSize() override { return kSectorSize; }
// ----- Utility functions ------------------------------------------------

View file

@ -30,9 +30,9 @@ static void padString(uint8_t *dest, const char *src, uint32_t length) {
}
DummyHardDriveATADeviceDriver::DummyHardDriveATADeviceDriver() {
strcpy(m_serialNumber, "1234567890");
strcpy(m_firmwareRevision, "1.00");
strcpy(m_modelNumber, "DUMMY HD 12345");
strcpy(m_serialNumber, "0123456789");
strcpy(m_firmwareRevision, "1.0.0");
strcpy(m_modelNumber, "vXn DHDD0010000");
// Initialize with parameters for a 10 GiB hard drive
m_numCylinders = 20480;

View file

@ -31,9 +31,9 @@ static void padString(uint8_t *dest, const char *src, uint32_t length) {
ImageHardDriveATADeviceDriver::ImageHardDriveATADeviceDriver() {
// TODO: fill in with appropriate data
strcpy(m_serialNumber, "1234567890");
strcpy(m_firmwareRevision, "1.00");
strcpy(m_modelNumber, "IMAGE HD 12345");
strcpy(m_serialNumber, "9876543210");
strcpy(m_firmwareRevision, "1.0.0");
strcpy(m_modelNumber, "vXn VHDD0010000");
// Initialize an empty (invalid) disk
m_numCylinders = 0;
@ -116,12 +116,6 @@ bool ImageHardDriveATADeviceDriver::Read(uint64_t byteAddress, uint8_t *buffer,
return false;
}
// Limit size to sector size
if (size > kSectorSize) {
log_warning("ImageHardDriveATADeviceDriver::ReadSector: Requested size (%d) truncated\n", size);
size = kSectorSize;
}
// Seek address
if (_fseeki64(m_fpImage, byteAddress, SEEK_SET)) {
return false;

View file

@ -0,0 +1,81 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "atapi_common.h"
namespace vixen {
namespace hw {
namespace atapi {
PacketCommandState::DataBuffer::~DataBuffer() {
if (m_buf != nullptr) {
delete[] m_buf;
}
}
bool PacketCommandState::DataBuffer::Allocate(uint32_t size) {
// Should allocate only once
assert(m_buf == nullptr);
m_buf = new uint8_t[size];
if (m_buf == nullptr) {
return false;
}
m_size = 0;
m_cap = size;
Clear();
return true;
}
uint32_t PacketCommandState::DataBuffer::Read(void *dst, uint32_t length) {
assert(m_buf != nullptr);
// Truncate to data length
if (length + m_readPos > m_size) {
length = m_size - m_readPos;
}
memcpy(dst, m_buf + m_readPos, length);
m_readPos += length;
return length;
}
uint32_t PacketCommandState::DataBuffer::Write(void *src, uint32_t length) {
assert(m_buf != nullptr);
// Truncate to allocation length
if (length + m_writePos > m_cap) {
length = m_cap - m_writePos;
}
memcpy(m_buf, src, length);
m_size = length;
return length;
}
}
}
}

View file

@ -1,7 +1,7 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement a subset of the ATAPI Command set used by the
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
@ -11,6 +11,9 @@
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
@ -33,18 +36,67 @@ namespace vixen {
namespace hw {
namespace atapi {
// ----- Packet Information ---------------------------------------------------
// ----- Packet Command State -------------------------------------------------
// Keeps the state of a packet command execution
struct PacketCommandState {
struct InputParameters {
// Whether the operation is to be overlapped
bool overlapped;
// Whether to execute a DMA (true) or PIO (false) transfer
bool dmaTransfer;
// The operation tag
uint8_t tag;
// The maximum number of bytes to transfer in a single DRQ block
uint16_t byteCountLimit;
// The selected device (DEV)
uint8_t selectedDevice;
} input;
// Information about a packet command
struct PacketInformation {
// The command descriptor block
CommandDescriptorBlock cdb;
// The operation type
PacketOperationType opType;
struct DataBuffer {
~DataBuffer();
// The size of the data to be transferred for this packet command
uint32_t transferSize;
// Allocates a buffer for data transfer
bool Allocate(uint32_t size);
// Copy data into the destination buffer, returning the number of bytes read
uint32_t Read(void *dst, uint32_t length);
// Copy data from the source buffer, returning the number of bytes written
uint32_t Write(void *src, uint32_t length);
// Clears the buffer, resetting the read and write pointers
void Clear() { m_readPos = m_writePos = m_size = 0; }
// Determines if the buffer's data has been fully read from
bool IsReadFinished() { return m_readPos >= m_size; }
// Determines if the buffer's data has been fully written to
bool IsWriteFinished() { return m_writePos >= m_cap; }
private:
// The data buffer to be used with transfer operations
uint8_t *m_buf = nullptr;
// The size of the data buffer, i.e. the number of valid bytes written to the buffer
uint32_t m_size;
// The capacity of the data buffer, i.e. the length of the buffer
uint32_t m_cap;
// The position of the writer
uint32_t m_writePos;
// The position of the reader
uint32_t m_readPos;
} dataBuffer;
// Execution result data, filled in by the driver once the command is processed
struct ExecutionResult {

View file

@ -1,7 +1,7 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement a subset of the ATAPI Command set used by the
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
@ -127,7 +127,7 @@ union CommandDescriptorBlock {
uint8_t pageControl : 2; // byte 2 [7:6] (PC) Page control
uint8_t subpageCode; // byte 3 Subpage code
uint8_t _reserved3[3]; // byte 4-6 Reserved
uint8_t length[2]; // byte 7-8 Allocation Length
uint8_t allocLength[2]; // byte 7-8 Allocation Length
uint8_t control; // byte 9 Control
} modeSense10;
@ -144,7 +144,7 @@ union CommandDescriptorBlock {
uint8_t lba[4]; // byte 2-5 Logical Block Address
uint8_t groupNumber : 5; // byte 6 [4:0] Group number
uint8_t _reserved2 : 3; // byte 6 [7:5] Reserved
uint8_t length[2]; // byte 7-8 Transfer length
uint8_t transferLength[2]; // byte 7-8 Transfer length
uint8_t control; // byte 9 Control
} read10;
@ -164,7 +164,7 @@ union CommandDescriptorBlock {
uint8_t address; // byte 2-5 Address
uint8_t layerNumber; // byte 6 Layer number
uint8_t format; // byte 7 Format
uint8_t length[2]; // byte 8-9 Allocation Length
uint8_t allocLength[2]; // byte 8-9 Allocation Length
uint8_t _reserved2 : 6; // byte 10 [5:0] Reserved
uint8_t authGrantID : 2; // byte 10 [7:6] (AGID) Authenticaton Grant ID (used with formats 2, 6 and 7 when address is 0)
uint8_t control; // byte 11 Control
@ -175,7 +175,7 @@ union CommandDescriptorBlock {
struct RequestSense {
OperationCode opCode; // byte 0 Operation Code (0x03)
uint8_t _reserved1[3]; // byte 1-3 Reserved
uint8_t length; // byte 4 Allocation Length
uint8_t allocLength; // byte 4 Allocation Length
uint8_t control; // byte 5 Control
} requestSense;
@ -420,6 +420,7 @@ enum AdditionalSenseCode : uint16_t {
ASCNone = 0x0000, // No additional sense information
ASCInvalidFieldInCDB = 0x2400, // Invalid field in CDB
ASCMediumNotPresent = 0x3A00, // Medium not present
ASCEndOfMediumReached = 0x3B0F, // End of medium reached
};
}

View file

@ -1,7 +1,31 @@
// ATA/ATAPI-4 emulation for the Original Xbox
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// Utility functions for dealing with ATAPI / SCSI data structures.
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
@ -39,42 +63,42 @@ inline uint64_t B2L64(uint8_t bytes[8]) {
// Converts a 16-bit unsigned integer from little-endian to big-endian.
inline void L2B16(uint8_t bytes[2], uint16_t val) {
bytes[0] = val >> 8;
bytes[1] = val;
bytes[0] = (uint8_t)(val >> 8);
bytes[1] = (uint8_t)val;
}
// Converts a 24-bit unsigned integer from little-endian to big-endian.
inline void L2B24(uint8_t bytes[3], uint32_t val) {
bytes[0] = val >> 16;
bytes[1] = val >> 8;
bytes[2] = val;
bytes[0] = (uint8_t)(val >> 16);
bytes[1] = (uint8_t)(val >> 8);
bytes[2] = (uint8_t)val;
}
// Converts a 24-bit unsigned integer split into low 16-bit and high 8-bit parts from little-endian to big-endian.
inline void L2B24S(uint8_t *high, uint8_t low[2], uint32_t val) {
*high = val >> 16;
low[0] = val >> 8;
low[1] = val;
*high = (uint8_t)(val >> 16);
low[0] = (uint8_t)(val >> 8);
low[1] = (uint8_t)val;
}
// Converts a 32-bit unsigned integer from little-endian to big-endian.
inline void L2B32(uint8_t bytes[4], uint32_t val) {
bytes[0] = val >> 24;
bytes[1] = val >> 16;
bytes[2] = val >> 8;
bytes[3] = val;
bytes[0] = (uint8_t)(val >> 24);
bytes[1] = (uint8_t)(val >> 16);
bytes[2] = (uint8_t)(val >> 8);
bytes[3] = (uint8_t)val;
}
// Converts a 64-bit unsigned integer from little-endian to big-endian.
inline void L2B64(uint8_t bytes[8], uint64_t val) {
bytes[0] = val >> 56L;
bytes[1] = val >> 48L;
bytes[2] = val >> 40L;
bytes[3] = val >> 32L;
bytes[4] = val >> 24L;
bytes[5] = val >> 16L;
bytes[6] = val >> 8L;
bytes[7] = val;
bytes[0] = (uint8_t)(val >> 56L);
bytes[1] = (uint8_t)(val >> 48L);
bytes[2] = (uint8_t)(val >> 40L);
bytes[3] = (uint8_t)(val >> 32L);
bytes[4] = (uint8_t)(val >> 24L);
bytes[5] = (uint8_t)(val >> 16L);
bytes[6] = (uint8_t)(val >> 8L);
bytes[7] = (uint8_t)val;
}
}

View file

@ -19,11 +19,11 @@ namespace atapi {
// SCSI MODE SENSE and MODE SELECT page code for the security data.
// Contains the XboxDVDAuthentication struct.
// http://xboxdevwiki.net/DVD_Drive
// [w] http://xboxdevwiki.net/DVD_Drive
const uint8_t kPageCodeAuthentication = 0x3E;
// The Xbox DVD authentication page data.
// https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/e452d56991c7dce655511c5529f4cf1a6fe98e42/import/OpenXDK/include/xboxkrnl/xboxkrnl.h#L2494
// [c] https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/e452d56991c7dce655511c5529f4cf1a6fe98e42/import/OpenXDK/include/xboxkrnl/xboxkrnl.h#L2494
struct XboxDVDAuthentication {
uint8_t Unknown[2];
uint8_t PartitionArea;

View file

@ -0,0 +1,50 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "atapi_command.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
IATAPICommand::IATAPICommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: m_packetCmdState(packetCmdState)
, m_driver(driver)
{
}
IATAPICommand::~IATAPICommand() {
}
}
}
}
}

View file

@ -0,0 +1,95 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "../atapi_common.h"
#include "../atapi_utils.h"
#include "../atapi_xbox.h"
#include "vixen/hw/ata/drvs/ata_device_driver.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Interface for ATAPI commands.
*
* Classes that derive this interface provide base implementations for ATAPI
* protocols, which handle the basic flow of the packet command execution.
*/
class IATAPICommand {
public:
IATAPICommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~IATAPICommand();
/*!
* Validates input parameters and allocates a data transfer buffer if
* required by the command. If the command transfers data to the host,
* the buffer is pre-filled with the necessary data.
*
* Status (including sense key and additional sense code) is updated in
* the packet command state.
*
* Returns true if the packet data has been successfully validated and
* the command is ready to be executed or to receive data.
*/
virtual bool Prepare() = 0;
/*!
* Executes the command with the provided state.
*/
virtual bool Execute() = 0;
/*!
* Determines if the data transfer has finished.
*/
virtual bool IsTransferFinished() = 0;
/*!
* Retrieves the operation type for this command.
*/
virtual PacketOperationType GetOperationType() = 0;
/*!
* Defines the factory function type used to build a factory table.
*/
typedef IATAPICommand* (*Factory)(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
protected:
PacketCommandState& m_packetCmdState;
ata::IATADeviceDriver *m_driver;
};
}
}
}
}

View file

@ -0,0 +1,77 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "cmd_mode_sense_10.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
ModeSense10::ModeSense10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: ATAPIDataInCommand(packetCmdState, driver)
{
}
ModeSense10::~ModeSense10() {
}
bool ModeSense10::BeginTransfer() {
auto& cdb = m_packetCmdState.cdb.modeSense10;
switch (cdb.pageCode) {
case kPageCodeAuthentication:
{
// Fill in just enough information to pass basic authentication checks on modified kernels
// TODO: Research Xbox DVD authentication
// https://multimedia.cx/eggs/xbox-sphinx-protocol/
XboxDVDAuthentication dvdAuth = { 0 };
dvdAuth.CDFValid = 1;
dvdAuth.PartitionArea = 1;
dvdAuth.Authentication = 1;
m_packetCmdState.dataBuffer.Write(&dvdAuth, sizeof(dvdAuth));
EndTransfer();
return true;
}
default:
log_warning("ModeSense10::Execute: Unimplemented page code 0x%x\n", cdb.pageCode);
return false;
}
}
uint32_t ModeSense10::GetAllocationLength(CommandDescriptorBlock *cdb) {
return B2L16(cdb->modeSense10.allocLength);
}
}
}
}
}

View file

@ -0,0 +1,62 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "proto_data_in.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Implements the MODE SENSE(10) command (0x5A) [p 6.10].
*/
class ModeSense10 : public ATAPIDataInCommand {
public:
ModeSense10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~ModeSense10();
bool BeginTransfer() override;
// This command only transfer one block; Execute() will never be invoked
bool Execute() override { return false; }
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ModeSense10(packetCmdState, driver); }
protected:
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
};
}
}
}
}

View file

@ -0,0 +1,132 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "cmd_read_10.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
Read10::Read10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: ATAPIDataInCommand(packetCmdState, driver)
{
}
Read10::~Read10() {
if (m_buffer != nullptr) {
delete[] m_buffer;
}
}
bool Read10::BeginTransfer() {
auto& cdb = m_packetCmdState.cdb.read10;
if (!m_driver->HasMedium()) {
// There is no medium in the drive
m_packetCmdState.result.status = StCheckCondition;
m_packetCmdState.result.senseKey = SKNotReady;
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
return true;
}
uint32_t lba = B2L32(cdb.lba);
uint16_t transferLength = B2L16(cdb.transferLength);
uint32_t transferLengthBytes = (uint32_t)transferLength * m_driver->GetSectorSize();
m_transferLength = transferLengthBytes;
if (m_transferLength > m_packetCmdState.input.byteCountLimit) {
m_transferLength = m_packetCmdState.input.byteCountLimit;
}
// Allocate buffer and setup transfer parameters
m_currentByte = lba * m_driver->GetSectorSize();
m_lastByte = m_currentByte + transferLengthBytes;
m_buffer = new uint8_t[m_transferLength];
log_spew("Read10::BeginTransfer: Starting transfer: 0x%llx to 0x%llx\n", m_currentByte, m_lastByte);
// Read from media
return Execute();
}
bool Read10::Execute() {
uint32_t readLen = m_lastByte - m_currentByte;
if (readLen > m_transferLength) {
readLen = m_transferLength;
}
if (!m_driver->HasMedium()) {
// No medium in drive
m_packetCmdState.result.status = StCheckCondition;
m_packetCmdState.result.senseKey = SKIllegalRequest;
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
log_spew("Read10::Execute: Medium not present\n");
EndTransfer();
return false;
}
// Read from the device
// TODO: maybe handle caching? Could improve performance if accessing real media on supported drives
// Should also honor the cache flags
bool successful = m_driver->Read(m_currentByte, m_buffer, readLen);
if (!successful) {
// Reached the end of the medium
m_packetCmdState.result.status = StCheckCondition;
m_packetCmdState.result.senseKey = SKNoSense;
m_packetCmdState.result.additionalSenseCode = ASCEndOfMediumReached;
m_packetCmdState.result.endOfMedium = true;
log_spew("Read10::Execute: Reached end of medium\n");
EndTransfer();
return false;
}
// Update position and check if the transfer ended
m_currentByte += readLen;
if (m_currentByte >= m_lastByte) {
log_spew("Read10::Execute: Transfer finished\n");
EndTransfer();
}
// Write to the transfer buffer
m_packetCmdState.dataBuffer.Clear();
m_packetCmdState.dataBuffer.Write(m_buffer, readLen);
return true;
}
uint32_t Read10::GetAllocationLength(CommandDescriptorBlock *cdb) {
return B2L16(cdb->read10.transferLength) * m_driver->GetSectorSize();
}
}
}
}
}

View file

@ -0,0 +1,73 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "proto_data_in.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Implements the READ(10) command (0x28) [b 5.11].
*/
class Read10 : public ATAPIDataInCommand {
public:
Read10(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~Read10();
bool BeginTransfer() override;
bool Execute() override;
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new Read10(packetCmdState, driver); }
protected:
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
private:
// Maximum number of bytes to transfer in a single read operation
uint32_t m_transferLength;
// Next starting byte to read
uint64_t m_currentByte;
// Last byte to read (exclusive)
uint64_t m_lastByte;
// Read buffer
uint8_t *m_buffer;
};
}
}
}
}

View file

@ -0,0 +1,76 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "cmd_read_capacity.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
ReadCapacity::ReadCapacity(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: ATAPIDataInCommand(packetCmdState, driver)
{
}
ReadCapacity::~ReadCapacity() {
}
bool ReadCapacity::BeginTransfer() {
auto& cdb = m_packetCmdState.cdb.readCapacity;
ReadCapacityData capData = { 0 };
if (m_driver->HasMedium()) {
L2B32(capData.lba, m_driver->GetMediumCapacitySectors());
L2B32(capData.blockLength, m_driver->GetSectorSize());
}
else {
// Say that there is no disc in the drive
m_packetCmdState.result.status = StCheckCondition;
m_packetCmdState.result.senseKey = SKNotReady;
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
L2B32(capData.lba, 0);
L2B32(capData.blockLength, 0);
}
m_packetCmdState.dataBuffer.Write(&capData, sizeof(capData));
EndTransfer();
return true;
}
uint32_t ReadCapacity::GetAllocationLength(CommandDescriptorBlock *cdb) {
return sizeof(ReadCapacityData);
}
}
}
}
}

View file

@ -0,0 +1,62 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "proto_data_in.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Implements the READ CAPACITY command (0x25) [m 5.16].
*/
class ReadCapacity : public ATAPIDataInCommand {
public:
ReadCapacity(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~ReadCapacity();
bool BeginTransfer() override;
// This command only transfer one block; Execute() will never be invoked
bool Execute() override { return false; }
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ReadCapacity(packetCmdState, driver); }
protected:
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
};
}
}
}
}

View file

@ -0,0 +1,86 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "cmd_read_dvd_structure.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
ReadDVDStructure::ReadDVDStructure(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: ATAPIDataInCommand(packetCmdState, driver)
{
}
ReadDVDStructure::~ReadDVDStructure() {
}
bool ReadDVDStructure::BeginTransfer() {
auto& cdb = m_packetCmdState.cdb.readDVDStructure;
ReadDVDStructureData dvdData = { 0 };
switch (cdb.format) {
case DVDFmtPhysical:
L2B16(dvdData.dataLength, (uint16_t)sizeof(ReadDVDStructureData::physicalFormatInformation));
// TODO: Compute fields based on the data reported by the driver
// Or perhaps let the driver fill it in?
dvdData.physicalFormatInformation.partVersion = 1;
dvdData.physicalFormatInformation.bookType = BookTypeDVDROM;
dvdData.physicalFormatInformation.maxRate = MaxRate10_08Mbps;
dvdData.physicalFormatInformation.discSize = DiscSize120mm;
dvdData.physicalFormatInformation.layerType = 0;
dvdData.physicalFormatInformation.trackPath = TrackPathOTP;
dvdData.physicalFormatInformation.numLayers = NumLayers2;
dvdData.physicalFormatInformation.trackDensity = TrackDensity0_74umPerTrack;
dvdData.physicalFormatInformation.linearDensity = LinearDensity0_293umPerBit;
L2B24(dvdData.physicalFormatInformation.dataStartingSector, kStartingSectorNumberDVDROM);
L2B24(dvdData.physicalFormatInformation.dataEndingSector, m_driver->GetMediumCapacitySectors());
L2B24(dvdData.physicalFormatInformation.layer0EndingSector, 0);
dvdData.physicalFormatInformation.burstCuttingArea = 0;
m_packetCmdState.dataBuffer.Write(&dvdData, sizeof(dvdData));
EndTransfer();
return true;
default:
log_debug("ImageDVDDriveATADeviceDriver::ProcessATAPIPacketDataRead: Unimplemented format 0x%x for READ DVD STRUCTURE\n", cdb.format);
return false;
}
}
uint32_t ReadDVDStructure::GetAllocationLength(CommandDescriptorBlock *cdb) {
return B2L16(cdb->readDVDStructure.allocLength);
}
}
}
}
}

View file

@ -0,0 +1,62 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "proto_data_in.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Implements the READ DVD STRUCTURE command (0xAD) [m 5.20].
*/
class ReadDVDStructure : public ATAPIDataInCommand {
public:
ReadDVDStructure(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~ReadDVDStructure();
bool BeginTransfer() override;
// This command only transfer one block; Execute() will never be invoked
bool Execute() override { return false; }
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new ReadDVDStructure(packetCmdState, driver); }
protected:
uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) override;
};
}
}
}
}

View file

@ -0,0 +1,65 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "cmd_test_unit_ready.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
TestUnitReady::TestUnitReady(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: ATAPINonDataCommand(packetCmdState, driver)
{
}
TestUnitReady::~TestUnitReady() {
}
bool TestUnitReady::Prepare() {
// Nothing to prepare or validate
return true;
}
bool TestUnitReady::Execute() {
// If there is no disc in the drive, return the expected sense key and parameters.
// The default values tell that there is media in the drive and the device is ready to accept commands.
if (!m_driver->HasMedium()) {
m_packetCmdState.result.status = StCheckCondition;
m_packetCmdState.result.senseKey = SKNotReady;
m_packetCmdState.result.additionalSenseCode = ASCMediumNotPresent;
}
return true;
}
}
}
}
}

View file

@ -0,0 +1,57 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "proto_nondata.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Implements the TEST UNIT READY command (0x00) [p 6.33].
*/
class TestUnitReady : public ATAPINonDataCommand {
public:
TestUnitReady(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~TestUnitReady();
bool Prepare() override;
bool Execute() override;
static IATAPICommand *Factory(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver) { return new TestUnitReady(packetCmdState, driver); }
};
}
}
}
}

View file

@ -0,0 +1,64 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "proto_data_in.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
ATAPIDataInCommand::ATAPIDataInCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: IATAPICommand(packetCmdState, driver)
{
}
ATAPIDataInCommand::~ATAPIDataInCommand() {
}
bool ATAPIDataInCommand::Prepare() {
// Get allocation length and allocate buffer
uint32_t allocLength = GetAllocationLength(&m_packetCmdState.cdb);
if (allocLength > m_packetCmdState.input.byteCountLimit) {
allocLength = m_packetCmdState.input.byteCountLimit;
}
if (!m_packetCmdState.dataBuffer.Allocate(allocLength)) {
return false;
}
// Initialize buffer with data.
// May access the device if needed.
return BeginTransfer();
}
}
}
}
}

View file

@ -0,0 +1,87 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "atapi_command.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Base class for all ATAPI commands that transfer data to the host.
*/
class ATAPIDataInCommand : public IATAPICommand {
public:
ATAPIDataInCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~ATAPIDataInCommand();
bool Prepare() override;
/*!
* Reads data into the buffer.
*
* Returns true if the data retrieval succeeded, or false if there was any error.
*/
virtual bool Execute() override = 0;
PacketOperationType GetOperationType() override { return PktOpDataIn; }
bool IsTransferFinished() override { return m_transferFinished; }
protected:
/*!
* Retrieves the allocation length from the CDB. Each command has its own
* CDB structure, and the allocation length is not necessarily in the same
* location or has the same size.
*/
virtual uint32_t GetAllocationLength(CommandDescriptorBlock *cdb) = 0;
/*!
* Initializes the data transfer.
*/
virtual bool BeginTransfer() = 0;
/*!
* Marks the end of a transfer.
*/
void EndTransfer() { m_transferFinished = true; }
private:
bool m_transferFinished = false;
};
}
}
}
}

View file

@ -0,0 +1,49 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#include "proto_nondata.h"
#include "vixen/log.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
ATAPINonDataCommand::ATAPINonDataCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver)
: IATAPICommand(packetCmdState, driver)
{
}
ATAPINonDataCommand::~ATAPINonDataCommand() {
}
}
}
}
}

View file

@ -0,0 +1,62 @@
// ATAPI Command set emulation for the Original Xbox
// (C) Ivan "StrikerX3" Oliveira
//
// This code aims to implement the subset of the ATAPI Command set used by the
// Original Xbox to access the DVD drive.
//
// Based on:
// [p] SCSI Primary Commands - 3 (SPC-3) Draft
// http://t10.org/ftp/t10/document.08/08-309r1.pdf
//
// [m] SCSI Multimedia Commands - 3 (MMC-3) Revision 10g
// https://www.rockbox.org/wiki/pub/Main/DataSheets/mmc2r11a.pdf
//
// [b] SCSI Block Commands - 3 (SBC-3) Revision 25
// http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
//
// [a] SCSI Architecture Model - 3 (SAM-3) Revision 13
// http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/sam3r13.pdf
//
// [c] ATA Packet Interface for CD-ROMs Revision 2.6 Proposed
// http://www.bswd.com/sff8020i.pdf
//
// [s] SCSI Commands Reference Manual 100293068, Rev. J
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
//
// References to particular items in the specification are denoted between brackets
// optionally followed by a quote from the specification. References are prefixed by
// the letter in brackets as listed above.
#pragma once
#include <cstdint>
#include "atapi_command.h"
namespace vixen {
namespace hw {
namespace atapi {
namespace cmd {
/*!
* Base class for all ATAPI commands that do not transfer data.
*/
class ATAPINonDataCommand : public IATAPICommand {
public:
ATAPINonDataCommand(PacketCommandState& packetCmdState, ata::IATADeviceDriver *driver);
virtual ~ATAPINonDataCommand();
virtual bool Prepare() override = 0;
virtual bool Execute() override = 0;
PacketOperationType GetOperationType() override { return PktOpNonData; }
// Technically, a non-data transfer doesn't transfer data.
// Technically, if no transfer is needed then the transfer is complete.
// So, technically, this should return true.
bool IsTransferFinished() override { return true; }
};
}
}
}
}