Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions devices/common/ata/atabasedevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,17 +198,22 @@ int AtaBaseDevice::pull_data(uint8_t *buf, int len) {

int xfer_size = std::min(this->xfer_cnt, len);

if (this->xfer_cnt != len)
LOG_F(WARNING, "%s: xfer_cnt != len", this->name.c_str());
if (this->xfer_cnt != len) {
LOG_F(9, "%s: DMA pull size differs from descriptor, remaining=%d requested=%d",
this->name.c_str(), this->xfer_cnt, len);
}

//for (int i = 0; i < xfer_size >> 1; i++)
// this->data_ptr[i] = BYTESWAP_16(this->data_ptr[i]);

std::memcpy(buf, this->data_ptr, xfer_size);
this->data_ptr = (uint16_t *)((uint8_t *)this->data_ptr + xfer_size);

this->xfer_cnt -= xfer_size;
if (!this->xfer_cnt) {
TimerManager::get_instance()->add_oneshot_timer(500, [this]() {
this->is_dma_xfer = false;
this->data_ptr = nullptr;
TimerManager::get_instance()->add_immediate_timer([this]() {
this->r_status &= ~(BSY | DRQ);
this->update_intrq(1);
});
Expand Down
58 changes: 58 additions & 0 deletions devices/common/ata/atahd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
/** @file ATA hard disk emulation. */

#include <core/memaccess.h>
#include <core/timermanager.h>
#include <devices/common/ata/atahd.h>
#include <devices/deviceregistry.h>
#include <devices/common/ata/idechannel.h>
#include <loguru.hpp>
#include <machines/machinebase.h>

#include <algorithm>
#include <bitset>
#include <cstring>
#include <fstream>
Expand Down Expand Up @@ -120,6 +122,38 @@ int AtaHardDisk::perform_command() {
this->signal_data_ready();
}
break;
case READ_DMA:
case READ_DMA_NR: {
uint16_t sec_count = this->r_sect_count ? this->r_sect_count : 256;
int xfer_size = sec_count * ATA_HD_SEC_SIZE;
uint64_t offset = this->get_lba() * ATA_HD_SEC_SIZE;

hdd_img.read(buffer, offset, xfer_size);
this->data_ptr = (uint16_t *)this->buffer;
this->is_dma_xfer = true;
this->prepare_xfer(xfer_size, xfer_size);
this->r_status &= ~(BSY | DRQ | ERR);
this->r_status |= DRDY | DSC;
// TODO: Model ATA DMAREQ as a latched signal instead of relying
// on this delay to avoid racing DBDMA command startup.
this->host_obj->assert_dmareq(500);
}
break;
case WRITE_DMA:
case WRITE_DMA_NR: {
uint16_t sec_count = this->r_sect_count ? this->r_sect_count : 256;
int xfer_size = sec_count * ATA_HD_SEC_SIZE;

this->cur_fpos = this->get_lba() * ATA_HD_SEC_SIZE;
this->is_dma_xfer = true;
this->prepare_xfer(xfer_size, xfer_size);
this->r_status &= ~(BSY | DRQ | ERR);
this->r_status |= DRDY | DSC;
// TODO: Model ATA DMAREQ as a latched signal instead of relying
// on this delay to avoid racing DBDMA command startup.
this->host_obj->assert_dmareq(500);
}
break;
case WRITE_MULTIPLE:
case WRITE_SECTOR:
case WRITE_SECTOR_NR: {
Expand Down Expand Up @@ -256,6 +290,30 @@ int AtaHardDisk::perform_command() {
return 0;
}

int AtaHardDisk::push_data(uint8_t *buf, int len) {
if (!this->xfer_cnt || !this->is_dma_xfer)
return 0;

int xfer_size = std::min(this->xfer_cnt, len);
this->hdd_img.write(buf, this->cur_fpos, xfer_size);
this->cur_fpos += xfer_size;
this->xfer_cnt -= xfer_size;

if (!this->xfer_cnt) {
this->is_dma_xfer = false;
TimerManager::get_instance()->add_immediate_timer([this]() {
this->r_status &= ~(BSY | DRQ | ERR);
this->r_status |= DRDY | DSC;
this->update_intrq(1);
});
} else {
this->r_status &= ~BSY;
this->r_status |= DRQ;
}

return xfer_size;
}

void AtaHardDisk::prepare_identify_info() {
uint16_t *buf_ptr = (uint16_t *)this->data_buf;

Expand Down
1 change: 1 addition & 0 deletions devices/common/ata/atahd.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class AtaHardDisk : public AtaBaseDevice

void insert_image(std::string filename);
int perform_command() override;
int push_data(uint8_t *buf, int len) override;

protected:
void prepare_identify_info();
Expand Down
14 changes: 8 additions & 6 deletions devices/common/dbdma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ uint8_t DMAChannel::interpret_cmd() {
if (cmd_struct.req_count) {
res = mmu_map_dma_mem(cmd_struct.address, cmd_struct.req_count, false);
this->queue_data = res.host_va;
this->res_count = 0;
this->res_count = cmd_struct.req_count;
this->queue_len = cmd_struct.req_count; // don't set queue_len until all the other fields are set
this->cmd_in_progress = true;
switch (this->cur_cmd) {
Expand Down Expand Up @@ -468,7 +468,8 @@ void DMAChannel::xfer_from_device() {
this->xfer_dir = DMA_DIR_FROM_DEV;

int got_bytes = this->dev_obj->xfer_from(this, this->queue_data, this->queue_len);
this->res_count += got_bytes;
this->queue_data += got_bytes;
this->res_count -= got_bytes;
this->queue_len -= got_bytes;
if (!this->queue_len) {
this->finish_cmd();
Expand All @@ -487,7 +488,8 @@ void DMAChannel::xfer_to_device() {
this->xfer_dir = DMA_DIR_TO_DEV;

int got_bytes = this->dev_obj->xfer_to(this, this->queue_data, this->queue_len);
this->res_count += got_bytes;
this->queue_data += got_bytes;
this->res_count -= got_bytes;
this->queue_len -= got_bytes;
if (!this->queue_len) {
this->finish_cmd();
Expand Down Expand Up @@ -536,14 +538,14 @@ DmaPullResult DMAChannel::pull_data(uint32_t req_len, uint32_t *avail_len, uint8
*p_data = this->queue_data;
*avail_len = req_len;
this->queue_len -= req_len;
this->res_count += req_len;
this->res_count -= req_len;
this->queue_data += req_len;
} else { // return less data than req_len
LOG_F(9, "%s: Return queue_len = %d data", this->get_name().c_str(),
this->queue_len);
*p_data = this->queue_data;
*avail_len = this->queue_len;
this->res_count += this->queue_len;
this->res_count -= this->queue_len;
this->queue_len = 0;
}
return DmaPullResult::MoreData; // tell the caller there is more data
Expand All @@ -568,7 +570,7 @@ DmaPushResult DMAChannel::push_data(const char* src_ptr, int len) {
len = std::min((int)this->queue_len, len);
std::memcpy(this->queue_data, src_ptr, len);
this->queue_data += len;
this->res_count += len;
this->res_count -= len;
this->queue_len -= len;
}

Expand Down
Loading