From a189c949803a4ab0302f98bcdbf05613ba5d28a7 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Wed, 14 Dec 2022 16:14:37 +0100 Subject: [PATCH] scsihd: fix READ_CAPACITY_10 command. Also bump internal buffer size to 2 MB to temporarily fix buffer overflows. --- devices/common/ata/atahd.cpp | 4 +- devices/common/scsi/scsicdrom.h | 2 +- devices/common/scsi/scsidevice.cpp | 1 + .../common/scsi/{scsi_hd.cpp => scsihd.cpp} | 37 ++++++++++++++----- devices/common/scsi/{scsi_hd.h => scsihd.h} | 3 +- machines/machinepdm.cpp | 2 +- 6 files changed, 35 insertions(+), 14 deletions(-) rename devices/common/scsi/{scsi_hd.cpp => scsihd.cpp} (89%) rename devices/common/scsi/{scsi_hd.h => scsihd.h} (96%) diff --git a/devices/common/ata/atahd.cpp b/devices/common/ata/atahd.cpp index 6c89ded..3c519c3 100644 --- a/devices/common/ata/atahd.cpp +++ b/devices/common/ata/atahd.cpp @@ -22,6 +22,8 @@ along with this program. If not, see . /** @file ATA hard disk emulation. */ #include + +#include #include #include #include @@ -99,7 +101,7 @@ int AtaHardDisk::perform_command() } case IDENTIFY_DEVICE: { this->r_status |= DRQ; - memcpy(buffer, ide_hd_id, 512); + std::memcpy(buffer, ide_hd_id, 512); this->r_status &= ~(DRQ); break; } diff --git a/devices/common/scsi/scsicdrom.h b/devices/common/scsi/scsicdrom.h index a4a8674..bae5834 100644 --- a/devices/common/scsi/scsicdrom.h +++ b/devices/common/scsi/scsicdrom.h @@ -83,7 +83,7 @@ private: int bytes_out = 0; TrackDescriptor tracks[CDROM_MAX_TRACKS]; - char data_buf[1 << 16]; // TODO: proper buffer management + char data_buf[1 << 18]; // TODO: proper buffer management }; #endif // SCSI_CDROM_H diff --git a/devices/common/scsi/scsidevice.cpp b/devices/common/scsi/scsidevice.cpp index 352d817..5fcb002 100644 --- a/devices/common/scsi/scsidevice.cpp +++ b/devices/common/scsi/scsidevice.cpp @@ -24,6 +24,7 @@ along with this program. If not, see . #include #include +#include void ScsiDevice::notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param) { diff --git a/devices/common/scsi/scsi_hd.cpp b/devices/common/scsi/scsihd.cpp similarity index 89% rename from devices/common/scsi/scsi_hd.cpp rename to devices/common/scsi/scsihd.cpp index e62ce11..146fa54 100644 --- a/devices/common/scsi/scsi_hd.cpp +++ b/devices/common/scsi/scsihd.cpp @@ -22,11 +22,12 @@ along with this program. If not, see . /** @file Generic SCSI Hard Disk emulation. */ #include -#include +#include #include +#include #include #include -#include +#include #include #include @@ -50,6 +51,7 @@ void ScsiHardDisk::insert_image(std::string filename) { int rc = stat(filename.c_str(), &stat_buf); if (!rc) { this->img_size = stat_buf.st_size; + this->total_blocks = (this->img_size + HDD_SECTOR_SIZE - 1) / HDD_SECTOR_SIZE; } else { ABORT_F("ScsiHardDisk: could not determine file size using stat()"); } @@ -73,7 +75,8 @@ void ScsiHardDisk::process_command() { uint8_t* cmd = this->cmd_buf; - if (cmd[0] != 0 && cmd[0] != 8 && cmd[0] != 0xA && cmd[0] != 0x28 && cmd[0] != 0x2A) { + if (cmd[0] != 0 && cmd[0] != 8 && cmd[0] != 0xA && cmd[0] != 0x28 + && cmd[0] != 0x2A && cmd[0] != 0x25) { ABORT_F("SCSI-HD: untested command 0x%X", cmd[0]); } @@ -214,16 +217,30 @@ void ScsiHardDisk::mode_sense_6(uint8_t page_code, uint8_t subpage_code, uint8_t } void ScsiHardDisk::read_capacity_10() { - uint32_t sec_limit = (this->img_size >> 9); + uint32_t lba = READ_DWORD_BE_U(&this->cmd_buf[2]); - std::memset(img_buffer, 0, sizeof(img_buffer)); + if (this->cmd_buf[1] & 1) { + ABORT_F("SCSI-HD: RelAdr bit set in READ_CAPACITY_10"); + } - img_buffer[0] = (sec_limit >> 24) & 0xFF; - img_buffer[1] = (sec_limit >> 16) & 0xFF; - img_buffer[2] = (sec_limit >> 8) & 0xFF; - img_buffer[3] = sec_limit & 0xFF; + if (!(this->cmd_buf[8] & 1) && lba) { + LOG_F(ERROR, "SCSI-HD: non-zero LBA for PMI=0"); + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = ScsiSense::ILLEGAL_REQ; + this->switch_phase(ScsiPhase::STATUS); + return; + } - img_buffer[6] = 2; + uint32_t last_lba = this->total_blocks - 1; + uint32_t blk_len = HDD_SECTOR_SIZE; + + WRITE_DWORD_BE_A(&img_buffer[0], last_lba); + WRITE_DWORD_BE_A(&img_buffer[4], blk_len); + + this->cur_buf_cnt = 8; + this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE; + + this->switch_phase(ScsiPhase::DATA_IN); } diff --git a/devices/common/scsi/scsi_hd.h b/devices/common/scsi/scsihd.h similarity index 96% rename from devices/common/scsi/scsi_hd.h rename to devices/common/scsi/scsihd.h index 14dc93e..99e39b1 100644 --- a/devices/common/scsi/scsi_hd.h +++ b/devices/common/scsi/scsihd.h @@ -63,9 +63,10 @@ protected: private: std::fstream hdd_img; uint64_t img_size; + int total_blocks; uint64_t file_offset = 0; - char img_buffer[1 << 17]; // TODO: add proper buffer management! + char img_buffer[1 << 21]; // TODO: add proper buffer management! uint32_t cur_buf_cnt = 0; uint8_t error = ScsiError::NO_ERROR; diff --git a/machines/machinepdm.cpp b/machines/machinepdm.cpp index ca90200..a49ee32 100644 --- a/machines/machinepdm.cpp +++ b/machines/machinepdm.cpp @@ -28,7 +28,7 @@ along with this program. If not, see . #include #include #include -#include +#include #include #include #include