Further ATA cmd work

This commit is contained in:
dingusdev 2022-12-11 16:08:43 -07:00
parent 86b0174b13
commit 0dd9a3d9b1
5 changed files with 82 additions and 41 deletions

View File

@ -50,30 +50,30 @@ void AtaBaseDevice::device_reset()
this->r_cylinder_lo = 0;
this->r_cylinder_hi = 0;
this->r_dev_head = 0; // TODO: ATAPI devices shouldn't change this reg!
this->r_status = IDE_Status::DRDY | IDE_Status::DSC;
this->r_status = DRDY | DSC;
}
uint16_t AtaBaseDevice::read(const uint8_t reg_addr) {
switch (reg_addr) {
case IDE_Reg::DATA:
case ATA_Reg::DATA:
LOG_F(WARNING, "Retrieving data from %s", this->name.c_str());
return 0xFFFFU;
case IDE_Reg::ERROR:
case ATA_Reg::ERROR:
return this->r_error;
case IDE_Reg::SEC_COUNT:
case ATA_Reg::SEC_COUNT:
return this->r_sect_count;
case IDE_Reg::SEC_NUM:
case ATA_Reg::SEC_NUM:
return this->r_sect_num;
case IDE_Reg::CYL_LOW:
case ATA_Reg::CYL_LOW:
return this->r_cylinder_lo;
case IDE_Reg::CYL_HIGH:
case ATA_Reg::CYL_HIGH:
return this->r_cylinder_hi;
case IDE_Reg::DEVICE_HEAD:
case ATA_Reg::DEVICE_HEAD:
return this->r_dev_head;
case IDE_Reg::STATUS:
case ATA_Reg::STATUS:
// TODO: clear pending interrupt
return this->r_status;
case IDE_Reg::ALT_STATUS:
case ATA_Reg::ALT_STATUS:
return this->r_status;
default:
LOG_F(WARNING, "Attempted to read unknown IDE register: %x", reg_addr);
@ -83,37 +83,37 @@ uint16_t AtaBaseDevice::read(const uint8_t reg_addr) {
void AtaBaseDevice::write(const uint8_t reg_addr, const uint16_t value) {
switch (reg_addr) {
case IDE_Reg::DATA:
case ATA_Reg::DATA:
LOG_F(WARNING, "Pushing data to %s", this->name.c_str());
break;
case IDE_Reg::FEATURES:
case ATA_Reg::FEATURES:
this->r_features = value;
break;
case IDE_Reg::SEC_COUNT:
case ATA_Reg::SEC_COUNT:
this->r_sect_count = value;
break;
case IDE_Reg::SEC_NUM:
case ATA_Reg::SEC_NUM:
this->r_sect_num = value;
break;
case IDE_Reg::CYL_LOW:
case ATA_Reg::CYL_LOW:
this->r_cylinder_lo = value;
break;
case IDE_Reg::CYL_HIGH:
case ATA_Reg::CYL_HIGH:
this->r_cylinder_hi = value;
break;
case IDE_Reg::DEVICE_HEAD:
case ATA_Reg::DEVICE_HEAD:
this->r_dev_head = value;
break;
case IDE_Reg::COMMAND:
case ATA_Reg::COMMAND:
this->r_command = value;
if (is_selected() || this->r_command == IDE_Cmd::DIAGNOSTICS) {
if (is_selected() || this->r_command == DIAGNOSTICS) {
perform_command();
}
break;
case IDE_Reg::DEV_CTRL:
if (!(this->r_dev_ctrl & ATA_CTRL_SRST) && (value & ATA_CTRL_SRST)) {
case ATA_Reg::DEV_CTRL:
if (!(this->r_dev_ctrl & SRST) && (value & SRST)) {
LOG_F(INFO, "%s: soft reset triggered", this->name.c_str());
this->r_status |= IDE_Status::BSY;
this->r_status |= BSY;
}
this->r_dev_ctrl = value;
break;

View File

@ -29,7 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
namespace ata_interface {
/** ATA register offsets. */
enum IDE_Reg : int {
enum ATA_Reg : int {
DATA = 0x0,
ERROR = 0x1, // error (read)
FEATURES = 0x1, // features (write)
@ -46,7 +46,7 @@ enum IDE_Reg : int {
};
/** Status register bits. */
enum IDE_Status : int {
enum ATA_Status : int {
ERR = 0x1,
IDX = 0x2,
CORR = 0x4,
@ -58,25 +58,26 @@ enum IDE_Status : int {
};
/** Error register bits. */
enum IDE_Error : int {
ANMF = 0x1,
TK0NF = 0x2,
ABRT = 0x4,
enum ATA_Error : int {
ANMF = 0x1, //no address mark
TK0NF = 0x2, //track 0 not found
ABRT = 0x4, //abort command
MCR = 0x8,
IDNF = 0x10,
MC = 0x20,
IDNF = 0x10, //id mark not found
MC = 0x20, //media change request
UNC = 0x40,
BBK = 0x80
BBK = 0x80 //bad block
};
/** Bit definition for the device control register. */
enum {
ATA_CTRL_nIEN = 1 << 1,
ATA_CTRL_SRST = 1 << 2,
enum ATA_CTRL : int{
IEN = 0x2,
SRST = 0x4,
HOB = 0x80,
};
/* ATA commands. */
enum IDE_Cmd : int {
enum ATA_Cmd : int {
NOP = 0x00,
RESET_ATAPI = 0x08,
RECALIBRATE = 0x10,
@ -85,7 +86,7 @@ enum IDE_Cmd : int {
READ_LONG = 0x22,
READ_SECTOR_EXT = 0x24,
WRITE_SECTOR = 0x30,
WRITE_SECTOR_NR = 0x21,
WRITE_SECTOR_NR = 0x31,
WRITE_LONG = 0x32,
READ_VERIFY = 0x40,
FORMAT_TRACKS = 0x50,

View File

@ -50,6 +50,7 @@ int AtaHardDisk::perform_command()
{
LOG_F(INFO, "%s: command 0x%x requested", this->name.c_str(), this->r_command);
this->r_status |= BSY;
this->r_status &= ~(DRDY);
switch (this->r_command) {
case NOP:
break;
@ -57,23 +58,58 @@ int AtaHardDisk::perform_command()
device_reset();
break;
}
case RECALIBRATE:
hdd_img.seekg(0, std::ios::beg);
this->r_error = 0;
this->r_cylinder_lo = 0;
this->r_cylinder_hi = 0;
break;
case READ_SECTOR:
case READ_SECTOR_NR: {
this->r_status |= DRQ;
uint16_t sec_count = (this->r_sect_count == 0) ? 256 : this->r_sect_count;
uint32_t sector = (r_sect_num << 16);
sector |= ((this->r_cylinder_lo) << 8) + (this->r_cylinder_hi);
uint64_t offset = sector * 512;
hdd_img.seekg(offset, std::ios::beg);
hdd_img.read(buffer, sec_count * 512);
this->r_status &= ~(DRQ);
break;
}
case DIAGNOSTICS:
case WRITE_SECTOR:
case WRITE_SECTOR_NR: {
this->r_status |= DRQ;
uint16_t sec_count = (this->r_sect_count == 0) ? 256 : this->r_sect_count;
uint32_t sector = (r_sect_num << 16);
sector |= ((this->r_cylinder_lo) << 8) + (this->r_cylinder_hi);
uint64_t offset = sector * 512;
hdd_img.seekg(offset, std::ios::beg);
hdd_img.write(buffer, sec_count * 512);
this->r_status &= ~(DRQ);
break;
}
case INIT_DEV_PARAM:
break;
case DIAGNOSTICS: {
this->r_status |= DRQ;
int ret_code = this->r_error;
this->r_status &= ~(DRQ);
return ret_code;
break;
}
case IDENTIFY_DEVICE: {
this->r_status |= DRQ;
memcpy(buffer, ide_hd_id, 512);
this->r_status &= ~(DRQ);
break;
}
default:
LOG_F(INFO, "Unknown ATA command 0x%x", this->r_command);
this->r_status &= ~(BSY);
this->r_status |= ERR;
return -1;
}
this->r_status &= ~(BSY);
this->r_status |= DRDY;
return -1;
return 0;
}

View File

@ -41,6 +41,10 @@ private:
std::fstream hdd_img;
uint64_t img_size;
char * buffer = new char[1 <<17];
char* ide_hd_id = {
0x0
};
};
#endif // ATA_HARD_DISK_H

View File

@ -48,7 +48,7 @@ IdeChannel::IdeChannel(const std::string name)
uint32_t IdeChannel::read(const uint8_t reg_addr, const int size)
{
if (reg_addr == IDE_Reg::TIME_CONFIG) {
if (reg_addr == TIME_CONFIG) {
if (size != 4) {
LOG_F(WARNING, "%s: non-DWORD read from the channel config", this->name.c_str());
}
@ -60,14 +60,14 @@ uint32_t IdeChannel::read(const uint8_t reg_addr, const int size)
void IdeChannel::write(const uint8_t reg_addr, const uint32_t val, const int size)
{
if (reg_addr == IDE_Reg::TIME_CONFIG) {
if (reg_addr == TIME_CONFIG) {
if (size != 4) {
LOG_F(WARNING, "%s: non-DWORD write to the channel config", this->name.c_str());
}
this->ch_config = val;
} else {
// keep track of the currently selected device
if (reg_addr == IDE_Reg::DEVICE_HEAD) {
if (reg_addr == DEVICE_HEAD) {
this->cur_dev = (val >> 4) & 1;
}