From 761292e9f159f6e83d2f05f722a8fde7a32997c5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 29 May 2017 06:17:13 +0200 Subject: [PATCH] Added sanity checks to SCSI hard disk emulation and made changes to the dynamic SCSI data buffer allocation, fixes problems when less data is requested for the INQUIRY command than it would actually need. --- src/WIN/win.c | 7 -- src/pc.c | 8 --- src/scsi_aha154x.c | 32 ++++----- src/scsi_buslogic.c | 28 ++++---- src/scsi_disk.c | 163 ++++++++++++++++++++++++-------------------- 5 files changed, 118 insertions(+), 120 deletions(-) diff --git a/src/WIN/win.c b/src/WIN/win.c index 0f1d77e99..3abbcf894 100644 --- a/src/WIN/win.c +++ b/src/WIN/win.c @@ -1442,26 +1442,19 @@ int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpsz ghwnd=hwnd; -printf("hwndRender;\n"); hwndRender = CreateWindow(L"STATIC", NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 0, 0, 1, 1, ghwnd, NULL, hinstance, NULL); -printf("initpc();\n"); initpc(argc, argv); -printf("init_cdrom_host_drives();\n"); init_cdrom_host_drives(); -printf("EmulatorStatusBar();\n"); hwndStatus = EmulatorStatusBar(hwnd, IDC_STATUS, hThisInstance); -printf("OriginalStatusBarProcedure;\n"); OriginalStatusBarProcedure = GetWindowLongPtr(hwndStatus, GWLP_WNDPROC); -printf("SetWindowLongPtr;\n"); SetWindowLongPtr(hwndStatus, GWL_WNDPROC, (LONG_PTR) &StatusBarProcedure); smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); -printf("initmodules();\n"); initmodules(); if (vid_apis[0][vid_api].init(hwndRender) == 0) diff --git a/src/pc.c b/src/pc.c index 2588eda45..6537c8733 100644 --- a/src/pc.c +++ b/src/pc.c @@ -506,14 +506,6 @@ void resetpchard(void) ide_qua_init(); } - for (i = 0; i < CDROM_NUM; i++) - { - if (cdrom_drives[i].bus_type == CDROM_BUS_SCSI) - { - SCSIReset(cdrom_drives[i].scsi_device_id, cdrom_drives[i].scsi_device_lun); - } - } - resetide(); scsi_card_init(); diff --git a/src/scsi_aha154x.c b/src/scsi_aha154x.c index 10e03cca6..2a80b626a 100644 --- a/src/scsi_aha154x.c +++ b/src/scsi_aha154x.c @@ -1090,6 +1090,7 @@ aha_buf_alloc(Req_t *req, int Is24bit) uint32_t sg_buffer_pos = 0; uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t Address; if (Is24bit) { DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); @@ -1106,8 +1107,6 @@ aha_buf_alloc(Req_t *req, int Is24bit) free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; } - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || @@ -1126,8 +1125,6 @@ aha_buf_alloc(Req_t *req, int Is24bit) aha_rd_sge(Is24bit, SGAddrCurrent, SGRead, SGBuffer); for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { - uint32_t Address; - pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); Address = SGBuffer[ScatterEntry].SegmentPointer; @@ -1143,6 +1140,10 @@ aha_buf_alloc(Req_t *req, int Is24bit) SCSIDevices[req->TargetID][req->LUN].InitLength = DataToTransfer; + pclog("Allocating buffer for Scatter/Gather (%i bytes)\n", DataToTransfer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both no read/write commands. */ if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || @@ -1158,8 +1159,6 @@ aha_buf_alloc(Req_t *req, int Is24bit) SGRead, SGBuffer); for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { - uint32_t Address; - pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); Address = SGBuffer[ScatterEntry].SegmentPointer; @@ -1176,9 +1175,14 @@ aha_buf_alloc(Req_t *req, int Is24bit) } } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - uint32_t Address = DataPointer; + Address = DataPointer; SCSIDevices[req->TargetID][req->LUN].InitLength = DataLength; + + pclog("Allocating buffer for direct transfer (%i bytes)\n", DataLength); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); + if (DataLength > 0) { DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, @@ -1203,6 +1207,7 @@ aha_buf_free(Req_t *req) uint32_t SGAddrCurrent; uint32_t Address; uint32_t Residual; + uint32_t DataToTransfer; if (req->Is24bit) { DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); @@ -1243,9 +1248,6 @@ aha_buf_free(Req_t *req) SGRead, SGBuffer); for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { - uint32_t Address; - uint32_t DataToTransfer; - pclog("BusLogic S/G: ScatterEntry=%u\n", ScatterEntry); Address = SGBuffer[ScatterEntry].SegmentPointer; @@ -2202,14 +2204,12 @@ aha_init(int chip, int has_bios) if (scsi_hard_disks[i][j] != 0xff) { SCSIDevices[i][j].LunType = SCSI_DISK; } - } - } - - for (i=0; i<16; i++) { - for (j=0; j<8; j++) { - if (find_cdrom_for_scsi_id(i, j) != 0xff) { + else if (find_cdrom_for_scsi_id(i, j) != 0xff) { SCSIDevices[i][j].LunType = SCSI_CDROM; } + else { + SCSIDevices[i][j].LunType = SCSI_NONE; + } } } diff --git a/src/scsi_buslogic.c b/src/scsi_buslogic.c index 5de27579b..a691fa699 100644 --- a/src/scsi_buslogic.c +++ b/src/scsi_buslogic.c @@ -762,8 +762,6 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; } - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || @@ -799,6 +797,9 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) SCSIDevices[req->TargetID][req->LUN].InitLength = DataToTransfer; + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both no read/write commands. */ if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || @@ -835,6 +836,10 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) uint32_t Address = DataPointer; SCSIDevices[req->TargetID][req->LUN].InitLength = DataLength; + + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); + if (DataLength > 0) { DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, @@ -2222,22 +2227,17 @@ BuslogicInit(int chip) pclog("Building SCSI CD-ROM map...\n"); build_scsi_cdrom_map(); - for (i=0; i<16; i++) { - for (j=0; j<8; j++) - { - if (scsi_hard_disks[i][j] != 0xff) - { - SCSIDevices[i][j].LunType = SCSI_DISK; - pclog("Found SCSI disk: %02i:%02i\n", i, j); - } - } - } - for (i=0; i<16; i++) { for (j=0; j<8; j++) { - if (find_cdrom_for_scsi_id(i, j) != 0xff) { + if (scsi_hard_disks[i][j] != 0xff) { + SCSIDevices[i][j].LunType = SCSI_DISK; + } + else if (find_cdrom_for_scsi_id(i, j) != 0xff) { SCSIDevices[i][j].LunType = SCSI_CDROM; } + else { + SCSIDevices[i][j].LunType = SCSI_NONE; + } } } diff --git a/src/scsi_disk.c b/src/scsi_disk.c index 268fba97f..369225f00 100644 --- a/src/scsi_disk.c +++ b/src/scsi_disk.c @@ -966,41 +966,6 @@ static void scsi_hd_data_phase_error(uint8_t id) scsi_hd_cmd_error(id); } -void scsi_hd_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) -{ - switch(cdb[0]) - { - case GPCMD_READ_6: - case GPCMD_WRITE_6: - cdb[1] = (lba_pos >> 16) & 0xff; - cdb[2] = (lba_pos >> 8) & 0xff; - cdb[3] = lba_pos & 0xff; - break; - - case GPCMD_READ_10: - case GPCMD_WRITE_10: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_12: - case GPCMD_WRITE_12: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 24) & 0xff; - cdb[7] = (number_of_blocks >> 16) & 0xff; - cdb[8] = (number_of_blocks >> 8) & 0xff; - cdb[9] = number_of_blocks & 0xff; - break; - } -} - /*SCSI Sense Initialization*/ void scsi_hd_sense_code_ok(uint8_t id) { @@ -1124,8 +1089,6 @@ void scsi_hd_reset(uint8_t id) void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) { - int is_ua = 0; - /*Will return 18 bytes of 0*/ if (alloc_length != 0) { @@ -1140,7 +1103,6 @@ void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) buffer[2]=SENSE_UNIT_ATTENTION; buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; buffer[13]=0x00; - is_ua = 1; } /* scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, hdbufferb[2], hdbufferb[12], hdbufferb[13]); */ @@ -1203,9 +1165,9 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) unsigned preamble_len; uint32_t alloc_length; uint64_t pos64; - uint64_t full_size = 0; char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + char *tempbuffer; #if 0 int CdbLength; @@ -1307,7 +1269,13 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) break; } - if (!shdc[id].sector_len) + if ((shdc[id].sector_pos > shdc[id].last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > shdc[id].last_sector)) + { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength == 0)) { /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ shdc[id].packet_status = CDROM_PHASE_COMPLETE; @@ -1320,16 +1288,23 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) pos64 = (uint64_t) shdc[id].sector_pos; - if (shdc[id].requested_blocks > 0) + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((shdc[id].requested_blocks > 0) && (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength > 0)) { shdf[id] = _wfopen(hdc[id].fn, L"rb+"); fseeko64(shdf[id], shdc[id].base + (pos64 << 9), SEEK_SET); - memset(hdbufferb, 0, shdc[id].sector_len << 9); - fread(hdbufferb, 1, (shdc[id].sector_len << 9), shdf[id]); + if (alloc_length > SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength) + { + fread(hdbufferb, 1, SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength, shdf[id]); + } + else + { + fread(hdbufferb, 1, alloc_length, shdf[id]); + } fclose(shdf[id]); } - alloc_length = shdc[id].packet_len = max_len << 9; if (shdc[id].requested_blocks > 1) { scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); @@ -1375,7 +1350,13 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) break; } - if (!shdc[id].sector_len) + if ((shdc[id].sector_pos > shdc[id].last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > shdc[id].last_sector)) + { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength == 0)) { /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ shdc[id].packet_status = CDROM_PHASE_COMPLETE; @@ -1388,15 +1369,23 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) pos64 = (uint64_t) shdc[id].sector_pos; - if (shdc[id].requested_blocks > 0) + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((shdc[id].requested_blocks > 0) && (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength > 0)) { shdf[id] = _wfopen(hdc[id].fn, L"rb+"); fseeko64(shdf[id], shdc[id].base + (pos64 << 9), SEEK_SET); - fwrite(hdbufferb, 1, (shdc[id].sector_len << 9), shdf[id]); + if (alloc_length > SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength) + { + fwrite(hdbufferb, 1, SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength, shdf[id]); + } + else + { + fwrite(hdbufferb, 1, alloc_length, shdf[id]); + } fclose(shdf[id]); } - alloc_length = shdc[id].packet_len = max_len << 9; if (shdc[id].requested_blocks > 1) { scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); @@ -1444,22 +1433,32 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) max_len <<= 8; max_len |= cdb[4]; + if ((!max_len) || (SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength == 0)) + { + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + tempbuffer = malloc(1024); + if (cdb[1] & 1) { preamble_len = 4; size_idx = 3; - hdbufferb[idx++] = 05; - hdbufferb[idx++] = cdb[2]; - hdbufferb[idx++] = 0; + tempbuffer[idx++] = 05; + tempbuffer[idx++] = cdb[2]; + tempbuffer[idx++] = 0; idx++; switch (cdb[2]) { case 0x00: - hdbufferb[idx++] = 0x00; - hdbufferb[idx++] = 0x83; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 0x83; break; case 0x83: if (idx + 24 > max_len) @@ -1468,10 +1467,10 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) return; } - hdbufferb[idx++] = 0x02; - hdbufferb[idx++] = 0x00; - hdbufferb[idx++] = 0x00; - hdbufferb[idx++] = 20; + tempbuffer[idx++] = 0x02; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 20; ide_padstr8(hdbufferb + idx, 20, "53R141"); /* Serial */ idx += 20; @@ -1479,15 +1478,15 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) { goto atapi_out; } - hdbufferb[idx++] = 0x02; - hdbufferb[idx++] = 0x01; - hdbufferb[idx++] = 0x00; - hdbufferb[idx++] = 68; - ide_padstr8(hdbufferb + idx, 8, "86Box"); /* Vendor */ + tempbuffer[idx++] = 0x02; + tempbuffer[idx++] = 0x01; + tempbuffer[idx++] = 0x00; + tempbuffer[idx++] = 68; + ide_padstr8(tempbuffer + idx, 8, "86Box"); /* Vendor */ idx += 8; - ide_padstr8(hdbufferb + idx, 40, device_identify_ex); /* Product */ + ide_padstr8(tempbuffer + idx, 40, device_identify_ex); /* Product */ idx += 40; - ide_padstr8(hdbufferb + idx, 20, "53R141"); /* Product */ + ide_padstr8(tempbuffer + idx, 20, "53R141"); /* Product */ idx += 20; break; default: @@ -1501,30 +1500,44 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) preamble_len = 5; size_idx = 4; - memset(hdbufferb, 0, 8); - hdbufferb[0] = 0; /*SCSI HD*/ + memset(tempbuffer, 0, 8); + tempbuffer[0] = 0; /*SCSI HD*/ if (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) { - hdbufferb[1] = 0x80; /*Removable*/ + tempbuffer[1] = 0x80; /*Removable*/ } else { - hdbufferb[1] = 0; /*Fixed*/ + tempbuffer[1] = 0; /*Fixed*/ } - hdbufferb[2] = 0x02; /*SCSI-2 compliant*/ - hdbufferb[3] = 0x02; - hdbufferb[4] = 31; + tempbuffer[2] = 0x02; /*SCSI-2 compliant*/ + tempbuffer[3] = 0x02; + tempbuffer[4] = 31; - ide_padstr8(hdbufferb + 8, 8, "86Box"); /* Vendor */ - ide_padstr8(hdbufferb + 16, 16, device_identify); /* Product */ - ide_padstr8(hdbufferb + 32, 4, emulator_version); /* Revision */ + ide_padstr8(tempbuffer + 8, 8, "86Box"); /* Vendor */ + ide_padstr8(tempbuffer + 16, 16, device_identify); /* Product */ + ide_padstr8(tempbuffer + 32, 4, emulator_version); /* Revision */ idx = 36; } atapi_out: - hdbufferb[size_idx] = idx - preamble_len; + tempbuffer[size_idx] = idx - preamble_len; len=idx; + if (len > max_len) + { + len = max_len; + } + + if (len > SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength) + { + len = SCSIDevices[hdc[id].scsi_id][hdc[id].scsi_lun].InitLength; + } + + memcpy(hdbufferb, tempbuffer, len); + + free(tempbuffer); + scsi_hd_data_command_finish(id, len, len, max_len, 0); break;