/hardfile.cpp
C++ | 3150 lines | 2862 code | 210 blank | 78 comment | 728 complexity | be09058b73539c5e8d2476c16ea564ac MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * UAE - The Un*x Amiga Emulator
- *
- * Hardfile emulation
- *
- * Copyright 1995 Bernd Schmidt
- * 2002 Toni Wilen (scsi emulation, 64-bit support)
- */
- #include "sysconfig.h"
- #include "sysdeps.h"
- #include "threaddep/thread.h"
- #include "options.h"
- #include "memory.h"
- #include "custom.h"
- #include "newcpu.h"
- #include "disk.h"
- #include "autoconf.h"
- #include "traps.h"
- #include "filesys.h"
- #include "execlib.h"
- #include "native2amiga.h"
- #include "gui.h"
- #include "uae.h"
- #include "scsi.h"
- #include "gayle.h"
- #include "execio.h"
- #include "zfile.h"
- #include "ide.h"
- #include "debug.h"
- #include "ini.h"
- #include "rommgr.h"
- #ifdef WITH_CHD
- #include "archivers/chd/chdtypes.h"
- #include "archivers/chd/chd.h"
- #include "archivers/chd/harddisk.h"
- #endif
- #define HDF_SUPPORT_NSD 1
- #define HDF_SUPPORT_TD64 1
- #define HDF_SUPPORT_DS 1
- #define HDF_SUPPORT_DS_PARTITION 0
- #undef DEBUGME
- #define hf_log(fmt, ...)
- #define hf_log2(fmt, ...)
- #define scsi_log(fmt, ...)
- #define hf_log3(fmt, ...)
- //#define DEBUGME
- #ifdef DEBUGME
- #undef hf_log
- #define hf_log write_log
- #undef hf_log2
- #define hf_log2 write_log
- #undef hf_log3
- #define hf_log3 write_log
- #undef scsi_log
- #define scsi_log write_log
- #endif
- extern int log_scsiemu;
- int enable_ds_partition_hdf;
- #define MAX_ASYNC_REQUESTS 50
- #define ASYNC_REQUEST_NONE 0
- #define ASYNC_REQUEST_TEMP 1
- #define ASYNC_REQUEST_CHANGEINT 10
- struct hardfileprivdata {
- uaecptr d_request[MAX_ASYNC_REQUESTS];
- uae_u8 *d_request_iobuf[MAX_ASYNC_REQUESTS];
- int d_request_type[MAX_ASYNC_REQUESTS];
- uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
- smp_comm_pipe requests;
- int thread_running;
- uae_sem_t sync_sem;
- uaecptr base;
- int changenum;
- uaecptr changeint;
- struct scsi_data *sd;
- bool directorydrive;
- };
- #define HFD_CHD_OTHER 5
- #define HFD_CHD_HD 4
- #define HFD_VHD_DYNAMIC 3
- #define HFD_VHD_FIXED 2
- STATIC_INLINE uae_u32 gl (uae_u8 *p)
- {
- return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
- }
- static uae_sem_t change_sem;
- static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS];
- static uae_u32 nscmd_cmd;
- static void wl (uae_u8 *p, uae_u32 v)
- {
- p[0] = v >> 24;
- p[1] = v >> 16;
- p[2] = v >> 8;
- p[3] = v;
- }
- static void ww (uae_u8 *p, uae_u16 v)
- {
- p[0] = v >> 8;
- p[1] = v;
- }
- static int rl (uae_u8 *p)
- {
- return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
- }
- static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
- {
- unsigned int total = (unsigned int)(hfd->virtsize / 1024);
- int heads;
- int sectors = 63;
- if (hfd->ci.physical_geometry) {
- *cyl = hfd->ci.pcyls;
- *tracksec = hfd->ci.psecs;
- *head = hfd->ci.pheads;
- *cylsec = (*head) * (*tracksec);
- return;
- }
- /* do we have RDB values? */
- if (hfd->rdbcylinders) {
- *cyl = hfd->rdbcylinders;
- *tracksec = hfd->rdbsectors;
- *head = hfd->rdbheads;
- *cylsec = hfd->rdbsectors * hfd->rdbheads;
- return;
- }
- /* what about HDF settings? */
- if (hfd->ci.surfaces && hfd->ci.sectors) {
- *head = hfd->ci.surfaces;
- *tracksec = hfd->ci.sectors;
- *cylsec = (*head) * (*tracksec);
- *cyl = (unsigned int)(hfd->virtsize / hfd->ci.blocksize) / ((*tracksec) * (*head));
- if (*cyl == 0)
- *cyl = (unsigned int)hfd->ci.max_lba / ((*tracksec) * (*head));
- return;
- }
- /* no, lets guess something.. */
- if (total <= 504 * 1024)
- heads = 16;
- else if (total <= 1008 * 1024)
- heads = 32;
- else if (total <= 2016 * 1024)
- heads = 64;
- else if (total <= 4032 * 1024)
- heads = 128;
- else
- heads = 255;
- *cyl = (unsigned int)(hfd->virtsize / hfd->ci.blocksize) / (sectors * heads);
- if (*cyl == 0)
- *cyl = (unsigned int)hfd->ci.max_lba / (sectors * heads);
- *cylsec = sectors * heads;
- *tracksec = sectors;
- *head = heads;
- }
- static void getchsx (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
- {
- getchs2 (hfd, cyl, cylsec, head, tracksec);
- hf_log (_T("CHS: %08X-%08X %d %d %d %d %d\n"),
- (uae_u32)(hfd->virtsize >> 32),(uae_u32)hfd->virtsize,
- *cyl, *cylsec, *head, *tracksec);
- }
- static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack, int mode)
- {
- int sptt[4];
- int i, spt, head, cyl;
- uae_u64 total = (unsigned int)(size / 512);
- if (mode == 1) {
- // old-style head=1, spt=32 always mode
- head = 1;
- spt = 32;
- cyl = total / (head * spt);
- } else {
- sptt[0] = 63;
- sptt[1] = 127;
- sptt[2] = 255;
- sptt[3] = -1;
- for (i = 0; sptt[i] >= 0; i++) {
- int maxhead = sptt[i] < 255 ? 16 : 255;
- spt = sptt[i];
- for (head = 4; head <= maxhead; head++) {
- cyl = total / (head * spt);
- if (size <= 512 * 1024 * 1024) {
- if (cyl <= 1023)
- break;
- } else {
- if (cyl < 16383)
- break;
- if (cyl < 32767 && head >= 5)
- break;
- if (cyl <= 65535)
- break;
- }
- if (maxhead > 16) {
- head *= 2;
- head--;
- }
- }
- if (head <= 16)
- break;
- }
- }
- if (head > 16)
- head--;
- *pcyl = cyl;
- *phead = head;
- *psectorspertrack = spt;
- }
- void getchsgeometry (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack)
- {
- getchsgeometry2 (size, pcyl, phead, psectorspertrack, 0);
- }
- void getchsgeometry_hdf (struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack)
- {
- uae_u8 block[512];
- int i;
- uae_u64 minsize = 512 * 1024 * 1024;
- if (size <= minsize) {
- *phead = 1;
- *psectorspertrack = 32;
- }
- memset (block, 0, sizeof block);
- if (hfd) {
- hdf_read(hfd, block, 0, 512);
- if (block[0] == 'D' && block[1] == 'O' && block[2] == 'S') {
- int mode;
- for (mode = 0; mode < 2; mode++) {
- uae_u32 rootblock;
- uae_u32 chk = 0;
- getchsgeometry2 (size, pcyl, phead, psectorspertrack, mode);
- rootblock = (2 + ((*pcyl) * (*phead) * (*psectorspertrack) - 1)) / 2;
- memset (block, 0, sizeof block);
- hdf_read(hfd, block, (uae_u64)rootblock * 512, 512);
- for (i = 0; i < 512; i += 4)
- chk += (block[i] << 24) | (block[i + 1] << 16) | (block[i + 2] << 8) | (block[i + 3] << 0);
- if (!chk && block[0] == 0 && block[1] == 0 && block[2] == 0 && block[3] == 2 &&
- block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 &&
- block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 &&
- block[508] == 0 && block[509] == 0 && block[510] == 0 && block[511] == 1) {
- return;
- }
- }
- }
- }
- getchsgeometry2 (size, pcyl, phead, psectorspertrack, size <= minsize ? 1 : 2);
- }
- // partition hdf default
- void gethdfgeometry(uae_u64 size, struct uaedev_config_info *ci)
- {
- int head = 1;
- int sectorspertrack = 32;
- if (size >= 1048576000) { // >=1000M
- head = 16;
- while ((size / 512) / ((uae_u64)head * sectorspertrack) >= 32768 && sectorspertrack < 32768) {
- sectorspertrack *= 2;
- }
- }
- ci->surfaces = head;
- ci->sectors = sectorspertrack;
- ci->reserved = 2;
- ci->blocksize = 512;
- }
- void getchspgeometry (uae_u64 total, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry)
- {
- uae_u64 blocks = total / 512;
- if (idegeometry) {
- *phead = 16;
- *psectorspertrack = 63;
- *pcyl = blocks / ((*psectorspertrack) * (*phead));
- if (blocks > 16515072) {
- /* >8G, CHS=16383/16/63 */
- *pcyl = 16383;
- *phead = 16;
- *psectorspertrack = 63;
- return;
- }
- return;
- }
- getchsgeometry (total, pcyl, phead, psectorspertrack);
- }
- static void getchshd (struct hardfiledata *hfd, int *pcyl, int *phead, int *psectorspertrack)
- {
- getchspgeometry (hfd->virtsize, pcyl, phead, psectorspertrack, false);
- }
- static void pl (uae_u8 *p, int off, uae_u32 v)
- {
- p += off * 4;
- p[0] = v >> 24;
- p[1] = v >> 16;
- p[2] = v >> 8;
- p[3] = v >> 0;
- }
- static void rdb_crc (uae_u8 *p)
- {
- uae_u32 sum;
- int i, blocksize;
- sum =0;
- blocksize = rl (p + 1 * 4);
- for (i = 0; i < blocksize; i++)
- sum += rl (p + i * 4);
- sum = -sum;
- pl (p, 2, sum);
- }
- static uae_u32 get_filesys_version(uae_u8 *fs, int size)
- {
- int ver = -1, rev = -1;
- for (int i = 0; i < size - 6; i++) {
- uae_u8 *p = fs + i;
- if (p[0] == 'V' && p[1] == 'E' && p[2] == 'R' && p[3] == ':' && p[4] == ' ') {
- uae_u8 *p2;
- p += 5;
- p2 = p;
- while (*p2 && p2 - fs < size)
- p2++;
- if (p2[0] == 0) {
- while (*p && (ver < 0 || rev < 0)) {
- if (*p == ' ') {
- p++;
- ver = atol((char*)p);
- if (ver < 0)
- ver = 0;
- while (*p) {
- if (*p == ' ')
- break;
- if (*p == '.') {
- p++;
- rev = atol((char*)p);
- if (rev < 0)
- rev = 0;
- }
- else {
- p++;
- }
- }
- break;
- }
- else {
- p++;
- }
- }
- }
- break;
- }
- }
- if (ver < 0)
- return 0xffffffff;
- if (rev < 0)
- rev = 0;
- return (ver << 16) | rev;
- }
- // hardware block size is always 256 or 512
- // filesystem block size can be 256, 512 or larger
- static void create_virtual_rdb (struct hardfiledata *hfd)
- {
- uae_u8 *rdb, *part, *denv, *fs;
- int fsblocksize = hfd->ci.blocksize;
- int hardblocksize = fsblocksize >= 512 ? 512 : 256;
- int cyl = hfd->ci.surfaces * hfd->ci.sectors;
- int cyls = (262144 + (cyl * fsblocksize) - 1) / (cyl * fsblocksize);
- int size = cyl * cyls * fsblocksize;
- int idx = 0;
- uae_u8 *filesys = NULL;
- int filesyslen = 0;
- uae_u32 fsver = 0;
- write_log(_T("Creating virtual RDB (RDB size=%d, %d blocks). H=%d S=%d HBS=%d FSBS=%d)\n"),
- size, size / hardblocksize, hfd->ci.surfaces, hfd->ci.sectors, hardblocksize, fsblocksize);
- if (hfd->ci.filesys[0]) {
- struct zfile *f = NULL;
- TCHAR fspath[MAX_DPATH];
- cfgfile_resolve_path_out_load(hfd->ci.filesys, fspath, MAX_DPATH, PATH_HDF);
- filesys = zfile_load_file(fspath, &filesyslen);
- if (filesys) {
- fsver = get_filesys_version(filesys, filesyslen);
- if (fsver == 0xffffffff)
- fsver = (99 << 16) | 99;
- if (filesyslen & 3) {
- xfree(filesys);
- filesys = NULL;
- filesyslen = 0;
- }
- }
- }
- int filesysblocks = (filesyslen + hardblocksize - 5 * 4 - 1) / (hardblocksize - 5 * 4);
- rdb = xcalloc (uae_u8, size);
- hfd->virtual_rdb = rdb;
- hfd->virtual_size = size;
- pl(rdb, 0, 0x5244534b); // "RDSK"
- pl(rdb, 1, 256 / 4);
- pl(rdb, 2, 0); // chksum
- pl(rdb, 3, 7); // hostid
- pl(rdb, 4, hardblocksize); // blockbytes
- pl(rdb, 5, 0); // flags
- pl(rdb, 6, -1); // badblock
- pl(rdb, 7, idx + 1); // part
- pl(rdb, 8, filesys ? idx + 2 : -1); // fs
- pl(rdb, 9, -1); // driveinit
- pl(rdb, 10, -1); // reserved
- pl(rdb, 11, -1); // reserved
- pl(rdb, 12, -1); // reserved
- pl(rdb, 13, -1); // reserved
- pl(rdb, 14, -1); // reserved
- pl(rdb, 15, -1); // reserved
- pl(rdb, 16, hfd->ci.highcyl + cyls - 1);
- pl(rdb, 17, hfd->ci.sectors);
- pl(rdb, 18, hfd->ci.surfaces * fsblocksize / hardblocksize);
- pl(rdb, 19, hfd->ci.interleave);
- pl(rdb, 20, 0); // park
- pl(rdb, 21, -1); // res
- pl(rdb, 22, -1); // res
- pl(rdb, 23, -1); // res
- pl(rdb, 24, 0); // writeprecomp
- pl(rdb, 25, 0); // reducedwrite
- pl(rdb, 26, 0); // steprate
- pl(rdb, 27, -1); // res
- pl(rdb, 28, -1); // res
- pl(rdb, 29, -1); // res
- pl(rdb, 30, -1); // res
- pl(rdb, 31, -1); // res
- pl(rdb, 32, 0); // rdbblockslo
- pl(rdb, 33, cyl * cyls * fsblocksize / hardblocksize - 1); // rdbblockshi
- pl(rdb, 34, cyls); // locyl
- pl(rdb, 35, hfd->ci.highcyl + cyls - 1); // hicyl
- pl(rdb, 36, cyl * fsblocksize / hardblocksize); // cylblocks
- pl(rdb, 37, 0); // autopark
- pl(rdb, 38, (1 + 1 + (filesysblocks ? 2 + filesysblocks : 0) - 1)); // highrdskblock
- pl(rdb, 39, -1); // res
- ua_copy ((char*)rdb + 40 * 4, 8, hfd->vendor_id);
- ua_copy ((char*)rdb + 42 * 4, 16, hfd->product_id);
- ua_copy ((char*)rdb + 46 * 4, 4, _T("UAE"));
- rdb_crc (rdb);
- idx++;
- part = rdb + hardblocksize * idx;
- pl(part, 0, 0x50415254); // "PART"
- pl(part, 1, 256 / 4);
- pl(part, 2, 0); // chksum
- pl(part, 3, 7); // hostid
- pl(part, 4, -1); // next
- pl(part, 5, hfd->ci.bootpri < -128 ? 2 : hfd->ci.bootpri == -128 ? 0 : 1); // bootable/nomount
- pl(part, 6, -1);
- pl(part, 7, -1);
- pl(part, 8, 0); // devflags
- part[9 * 4] = _tcslen (hfd->ci.devname);
- ua_copy ((char*)part + 9 * 4 + 1, 30, hfd->ci.devname);
- denv = part + 128;
- pl(denv, 0, 16);
- pl(denv, 1, fsblocksize / 4);
- pl(denv, 2, 0); // secorg
- pl(denv, 3, hfd->ci.surfaces);
- pl(denv, 4, 1);
- pl(denv, 5, hfd->ci.sectors);
- pl(denv, 6, hfd->ci.reserved);
- pl(denv, 7, 0); // prealloc
- pl(denv, 8, hfd->ci.interleave); // interleave
- pl(denv, 9, cyls); // lowcyl
- pl(denv, 10, hfd->ci.highcyl + cyls - 1);
- pl(denv, 11, hfd->ci.buffers);
- pl(denv, 12, hfd->ci.bufmemtype);
- pl(denv, 13, hfd->ci.maxtransfer);
- pl(denv, 14, hfd->ci.mask);
- pl(denv, 15, hfd->ci.bootpri);
- pl(denv, 16, hfd->ci.dostype);
- rdb_crc (part);
- idx++;
- if (filesys) {
- fs = rdb + hardblocksize * idx;
- pl(fs, 0, 0x46534844); // "FSHD"
- pl(fs, 1, 256 / 4);
- pl(fs, 2, 0); // chksum
- pl(fs, 3, 7); // hostid
- pl(fs, 4, -1); // next
- pl(fs, 5, 0); // flags
- pl(fs, 8, hfd->ci.dostype);
- pl(fs, 9, fsver); // version
- pl(fs, 10, 0x100 | 0x80 | 0x20 | 0x10); // patchflags: seglist + globvec + pri + stack
- pl(fs, 15, hfd->ci.stacksize); // stack
- pl(fs, 16, hfd->ci.priority); // priority
- pl(fs, 18, idx + 1); // first lseg
- pl(fs, 19, -1); // globvec
- rdb_crc(fs);
- idx++;
- int offset = 0;
- for (;;) {
- uae_u8 *lseg = rdb + hardblocksize * idx;
- int lsegdatasize = hardblocksize - 5 * 4;
- if (lseg + hardblocksize > rdb + size)
- break;
- pl(lseg, 0, 0x4c534547); // "LSEG"
- pl(lseg, 1, hardblocksize / 4);
- pl(lseg, 2, 0); // chksum
- pl(lseg, 3, 7); // hostid
- int v = filesyslen - offset;
- if (v <= lsegdatasize) {
- memcpy(lseg + 5 * 4, filesys + offset, v);
- pl(lseg, 4, -1);
- pl(lseg, 1, 5 + v / 4);
- rdb_crc(lseg);
- break;
- }
- memcpy(lseg + 5 * 4, filesys + offset, lsegdatasize);
- offset += lsegdatasize;
- idx++;
- pl(lseg, 4, idx); // next
- rdb_crc(lseg);
- }
- xfree(filesys);
- }
- hfd->virtsize += size;
- }
- void hdf_hd_close (struct hd_hardfiledata *hfd)
- {
- if (!hfd)
- return;
- hdf_close (&hfd->hfd);
- }
- int hdf_hd_open (struct hd_hardfiledata *hfd)
- {
- struct uaedev_config_info *ci = &hfd->hfd.ci;
- if (hdf_open (&hfd->hfd) <= 0)
- return 0;
- hfd->hfd.unitnum = ci->uae_unitnum;
- if (ci->physical_geometry) {
- hfd->cyls = ci->pcyls;
- hfd->heads = ci->pheads;
- hfd->secspertrack = ci->psecs;
- } else if (ci->highcyl && ci->surfaces && ci->sectors) {
- hfd->cyls = ci->highcyl;
- hfd->heads = ci->surfaces;
- hfd->secspertrack = ci->sectors;
- } else {
- getchshd (&hfd->hfd, &hfd->cyls, &hfd->heads, &hfd->secspertrack);
- }
- hfd->cyls_def = hfd->cyls;
- hfd->secspertrack_def = hfd->secspertrack;
- hfd->heads_def = hfd->heads;
- if (ci->surfaces && ci->sectors) {
- uae_u8 buf[512] = { 0 };
- hdf_read (&hfd->hfd, buf, 0, 512);
- if (buf[0] != 0 && memcmp (buf, _T("RDSK"), 4)) {
- ci->highcyl = (hfd->hfd.virtsize / ci->blocksize) / (ci->sectors * ci->surfaces);
- ci->dostype = rl (buf);
- create_virtual_rdb (&hfd->hfd);
- while (ci->highcyl * ci->surfaces * ci->sectors > hfd->cyls_def * hfd->secspertrack_def * hfd->heads_def) {
- hfd->cyls_def++;
- }
- }
- }
- hfd->size = hfd->hfd.virtsize;
- return 1;
- }
- static uae_u32 vhd_checksum (uae_u8 *p, int offset)
- {
- int i;
- uae_u32 sum;
- sum = 0;
- for (i = 0; i < 512; i++) {
- if (offset >= 0 && i >= offset && i < offset + 4)
- continue;
- sum += p[i];
- }
- return ~sum;
- }
- static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
- static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
- static void hdf_init_cache (struct hardfiledata *hfd)
- {
- }
- static void hdf_flush_cache (struct hardfiledata *hdf)
- {
- }
- static int hdf_cache_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- return hdf_read2 (hfd, buffer, offset, len);
- }
- static int hdf_cache_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- return hdf_write2 (hfd, buffer, offset, len);
- }
- int hdf_open (struct hardfiledata *hfd, const TCHAR *pname)
- {
- int ret;
- uae_u8 tmp[512], tmp2[512];
- uae_u32 v;
- TCHAR filepath[MAX_DPATH];
- if ((!pname || pname[0] == 0) && hfd->ci.rootdir[0] == 0)
- return 0;
- hfd->adide = 0;
- hfd->byteswap = 0;
- hfd->hfd_type = 0;
- hfd->virtual_size = 0;
- hfd->virtual_rdb = NULL;
- if (!pname)
- pname = hfd->ci.rootdir;
- cfgfile_resolve_path_out_load(pname, filepath, MAX_DPATH, PATH_HDF);
- #ifdef WITH_CHD
- TCHAR nametmp[MAX_DPATH];
- _tcscpy (nametmp, filepath);
- TCHAR *ext = _tcsrchr (nametmp, '.');
- if (ext && !_tcsicmp (ext, _T(".chd"))) {
- bool chd_readonly = false;
- struct zfile *zf = NULL;
- if (!hfd->ci.readonly)
- zf = zfile_fopen (nametmp, _T("rb+"));
- if (!zf) {
- chd_readonly = true;
- zf = zfile_fopen (nametmp, _T("rb"));
- }
- if (zf) {
- int err = CHDERR_FILE_NOT_WRITEABLE;
- hard_disk_file *chdf;
- chd_file *cf = new chd_file();
- if (!chd_readonly)
- err = cf->open(*zf, true, NULL);
- if (err == CHDERR_FILE_NOT_WRITEABLE) {
- chd_readonly = true;
- err = cf->open(*zf, false, NULL);
- }
- if (err != CHDERR_NONE) {
- zfile_fclose (zf);
- delete cf;
- goto end;
- }
- chdf = hard_disk_open(cf);
- if (!chdf) {
- hfd->ci.readonly = true;
- hfd->hfd_type = HFD_CHD_OTHER;
- hfd->chd_handle = cf;
- } else {
- hfd->hfd_type = HFD_CHD_HD;
- hfd->chd_handle = chdf;
- }
- if (chd_readonly)
- hfd->ci.readonly = true;
- hfd->virtsize = cf->logical_bytes();
- hfd->handle_valid = -1;
- write_log(_T("CHD '%s' mounted as %s, %s.\n"), filepath, chdf ? _T("HD") : _T("OTHER"), hfd->ci.readonly ? _T("read only") : _T("read/write"));
- return 1;
- }
- }
- #endif
- ret = hdf_open_target (hfd, filepath);
- if (ret <= 0)
- return ret;
- if (hdf_read_target (hfd, tmp, 0, 512) != 512)
- goto nonvhd;
- v = gl (tmp + 8); // features
- if ((v & 3) != 2)
- goto nonvhd;
- v = gl (tmp + 8 + 4); // version
- if ((v >> 16) != 1)
- goto nonvhd;
- hfd->hfd_type = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4);
- if (hfd->hfd_type != HFD_VHD_FIXED && hfd->hfd_type != HFD_VHD_DYNAMIC)
- goto nonvhd;
- v = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4);
- if (v == 0)
- goto nonvhd;
- if (vhd_checksum (tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v)
- goto nonvhd;
- if (hdf_read_target (hfd, tmp2, hfd->physsize - sizeof tmp2, 512) != 512)
- goto end;
- if (memcmp (tmp, tmp2, sizeof tmp))
- goto nonvhd;
- hfd->vhd_footerblock = hfd->physsize - 512;
- hfd->virtsize = (uae_u64)(gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8)) << 32;
- hfd->virtsize |= gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8 + 4);
- if (hfd->hfd_type == HFD_VHD_DYNAMIC) {
- uae_u32 size;
- hfd->vhd_bamoffset = gl (tmp + 8 + 4 + 4 + 4);
- if (hfd->vhd_bamoffset == 0 || hfd->vhd_bamoffset >= hfd->physsize)
- goto end;
- if (hdf_read_target (hfd, tmp, hfd->vhd_bamoffset, 512) != 512)
- goto end;
- v = gl (tmp + 8 + 8 + 8 + 4 + 4 + 4);
- if (vhd_checksum (tmp, 8 + 8 + 8 + 4 + 4 + 4) != v)
- goto end;
- v = gl (tmp + 8 + 8 + 8);
- if ((v >> 16) != 1)
- goto end;
- hfd->vhd_blocksize = gl (tmp + 8 + 8 + 8 + 4 + 4);
- hfd->vhd_bamoffset = gl (tmp + 8 + 8 + 4);
- hfd->vhd_bamsize = (((hfd->virtsize + hfd->vhd_blocksize - 1) / hfd->vhd_blocksize) * 4 + 511) & ~511;
- size = hfd->vhd_bamoffset + hfd->vhd_bamsize;
- hfd->vhd_header = xmalloc (uae_u8, size);
- if (hdf_read_target (hfd, hfd->vhd_header, 0, size) != size)
- goto end;
- hfd->vhd_sectormap = xmalloc (uae_u8, 512);
- hfd->vhd_sectormapblock = -1;
- hfd->vhd_bitmapsize = ((hfd->vhd_blocksize / (8 * 512)) + 511) & ~511;
- }
- write_log (_T("HDF is VHD %s image, virtual size=%lldK (%llx %lld)\n"),
- hfd->hfd_type == HFD_VHD_FIXED ? _T("fixed") : _T("dynamic"),
- hfd->virtsize / 1024, hfd->virtsize, hfd->virtsize);
- hdf_init_cache (hfd);
- return 1;
- nonvhd:
- hfd->hfd_type = 0;
- return 1;
- end:
- hdf_close_target (hfd);
- return 0;
- }
- int hdf_open (struct hardfiledata *hfd)
- {
- int v = hdf_open (hfd, NULL);
- if (!v)
- return v;
- get_hd_geometry(&hfd->ci);
- hfd->geometry = ini_load(hfd->ci.geometry, true);
- return v;
- }
- void hdf_close (struct hardfiledata *hfd)
- {
- hdf_flush_cache (hfd);
- hdf_close_target (hfd);
- #ifdef WITH_CHD
- if (hfd->hfd_type == HFD_CHD_OTHER) {
- chd_file *cf = (chd_file*)hfd->chd_handle;
- cf->close();
- delete cf;
- } else if (hfd->hfd_type == HFD_CHD_HD) {
- hard_disk_file *chdf = (hard_disk_file*)hfd->chd_handle;
- chd_file *cf = hard_disk_get_chd(chdf);
- hard_disk_close(chdf);
- cf->close();
- delete cf;
- }
- xfree(hfd->virtual_rdb);
- hfd->virtual_rdb = 0;
- hfd->virtual_size = 0;
- ini_free(hfd->geometry);
- hfd->geometry = NULL;
- hfd->chd_handle = NULL;
- #endif
- hfd->hfd_type = 0;
- xfree (hfd->vhd_header);
- hfd->vhd_header = NULL;
- xfree (hfd->vhd_sectormap);
- hfd->vhd_sectormap = NULL;
- }
- int hdf_dup (struct hardfiledata *dhfd, const struct hardfiledata *shfd)
- {
- return hdf_dup_target (dhfd, shfd);
- }
- static uae_u64 vhd_read (struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len)
- {
- uae_u64 read;
- uae_u8 *dataptr = (uae_u8*)v;
- //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
- read = 0;
- if (offset & 511)
- return read;
- if (len & 511)
- return read;
- while (len > 0) {
- uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset;
- uae_u32 sectoroffset = gl (hfd->vhd_header + bamoffset);
- if (sectoroffset == 0xffffffff) {
- memset (dataptr, 0, 512);
- read += 512;
- } else {
- int bitmapoffsetbits;
- int bitmapoffsetbytes;
- uae_u64 sectormapblock;
- bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512);
- bitmapoffsetbytes = bitmapoffsetbits / 8;
- sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511);
- if (hfd->vhd_sectormapblock != sectormapblock) {
- // read sector bitmap
- //write_log (_T("BM %08x\n"), sectormapblock);
- if (hdf_read_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
- write_log (_T("vhd_read: bitmap read error\n"));
- return read;
- }
- hfd->vhd_sectormapblock = sectormapblock;
- }
- // block allocated in bitmap?
- if (hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) {
- // read data block
- uae_u64 block = sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512;
- //write_log (_T("DB %08x\n"), block);
- if (hdf_read_target (hfd, dataptr, block, 512) != 512) {
- write_log (_T("vhd_read: data read error\n"));
- return read;
- }
- } else {
- memset (dataptr, 0, 512);
- }
- read += 512;
- }
- len -= 512;
- dataptr += 512;
- offset += 512;
- }
- return read;
- }
- static int vhd_write_enlarge (struct hardfiledata *hfd, uae_u32 bamoffset)
- {
- uae_u8 *buf, *p;
- int len;
- uae_u32 block;
- int v;
- len = hfd->vhd_blocksize + hfd->vhd_bitmapsize + 512;
- buf = xcalloc (uae_u8, len);
- if (!hdf_resize_target (hfd, hfd->physsize + len - 512)) {
- write_log (_T("vhd_enlarge: failure\n"));
- return 0;
- }
- // add footer (same as 512 byte header)
- memcpy (buf + len - 512, hfd->vhd_header, 512);
- v = hdf_write_target (hfd, buf, hfd->vhd_footerblock, len);
- xfree (buf);
- if (v != len) {
- write_log (_T("vhd_enlarge: footer write error\n"));
- return 0;
- }
- // write new offset to BAM
- p = hfd->vhd_header + bamoffset;
- block = hfd->vhd_footerblock / 512;
- p[0] = block >> 24;
- p[1] = block >> 16;
- p[2] = block >> 8;
- p[3] = block >> 0;
- // write to disk
- if (hdf_write_target (hfd, hfd->vhd_header + hfd->vhd_bamoffset, hfd->vhd_bamoffset, hfd->vhd_bamsize) != hfd->vhd_bamsize) {
- write_log (_T("vhd_enlarge: bam write error\n"));
- return 0;
- }
- hfd->vhd_footerblock += len - 512;
- return 1;
- }
- static uae_u64 vhd_write (struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len)
- {
- uae_u64 written;
- uae_u8 *dataptr = (uae_u8*)v;
- //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
- written = 0;
- if (offset & 511)
- return written;
- if (len & 511)
- return written;
- while (len > 0) {
- uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset;
- uae_u32 sectoroffset = gl (hfd->vhd_header + bamoffset);
- if (sectoroffset == 0xffffffff) {
- if (!vhd_write_enlarge (hfd, bamoffset))
- return written;
- continue;
- } else {
- int bitmapoffsetbits;
- int bitmapoffsetbytes;
- bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512);
- bitmapoffsetbytes = bitmapoffsetbits / 8;
- uae_u64 sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511);
- if (hfd->vhd_sectormapblock != sectormapblock) {
- // read sector bitmap
- if (hdf_read_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
- write_log (_T("vhd_write: bitmap read error\n"));
- return written;
- }
- hfd->vhd_sectormapblock = sectormapblock;
- }
- // write data
- if (hdf_write_target (hfd, dataptr, sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512, 512) != 512) {
- write_log (_T("vhd_write: data write error\n"));
- return written;
- }
- // block already allocated in bitmap?
- if (!(hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7))))) {
- // no, we need to mark it allocated and write the modified bitmap back to the disk
- hfd->vhd_sectormap[bitmapoffsetbytes & 511] |= (1 << (7 - (bitmapoffsetbits & 7)));
- if (hdf_write_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
- write_log (_T("vhd_write: bam write error\n"));
- return written;
- }
- }
- written += 512;
- }
- len -= 512;
- dataptr += 512;
- offset += 512;
- }
- return written;
- }
- int vhd_create (const TCHAR *name, uae_u64 size, uae_u32 dostype)
- {
- struct hardfiledata hfd;
- struct zfile *zf;
- uae_u8 *b;
- int cyl, cylsec, head, tracksec;
- uae_u32 crc, blocksize, batsize, batentrysize;
- int ret, i;
- time_t tm;
- if (size >= (uae_u64)10 * 1024 * 1024 * 1024)
- blocksize = 2 * 1024 * 1024;
- else
- blocksize = 512 * 1024;
- batsize = (size + blocksize - 1) / blocksize;
- batentrysize = batsize;
- batsize *= 4;
- batsize += 511;
- batsize &= ~511;
- ret = 0;
- b = NULL;
- zf = zfile_fopen (name, _T("wb"), 0);
- if (!zf)
- goto end;
- b = xcalloc (uae_u8, 512 + 1024 + batsize + 512);
- if (zfile_fwrite (b, 512 + 1024 + batsize + 512, 1, zf) != 1)
- goto end;
- memset (&hfd, 0, sizeof hfd);
- hfd.virtsize = hfd.physsize = size;
- hfd.ci.blocksize = 512;
- strcpy ((char*)b, "conectix"); // cookie
- b[0x0b] = 2; // features
- b[0x0d] = 1; // version
- b[0x10 + 6] = 2; // data offset
- // time stamp
- tm = time (NULL) - 946684800;
- b[0x18] = tm >> 24;
- b[0x19] = tm >> 16;
- b[0x1a] = tm >> 8;
- b[0x1b] = tm >> 0;
- strcpy ((char*)b + 0x1c, "vpc "); // creator application
- b[0x21] = 5; // creator version
- strcpy ((char*)b + 0x24, "Wi2k"); // creator host os
- // original and current size
- b[0x28] = b[0x30] = size >> 56;
- b[0x29] = b[0x31] = size >> 48;
- b[0x2a] = b[0x32] = size >> 40;
- b[0x2b] = b[0x33] = size >> 32;
- b[0x2c] = b[0x34] = size >> 24;
- b[0x2d] = b[0x35] = size >> 16;
- b[0x2e] = b[0x36] = size >> 8;
- b[0x2f] = b[0x37] = size >> 0;
- getchs2 (&hfd, &cyl, &cylsec, &head, &tracksec);
- // cylinders
- b[0x38] = cyl >> 8;
- b[0x39] = cyl;
- // heads
- b[0x3a] = head;
- // sectors per track
- b[0x3b] = tracksec;
- // disk type
- b[0x3c + 3] = HFD_VHD_DYNAMIC;
- get_guid_target (b + 0x44);
- crc = vhd_checksum (b, -1);
- b[0x40] = crc >> 24;
- b[0x41] = crc >> 16;
- b[0x42] = crc >> 8;
- b[0x43] = crc >> 0;
- // write header
- zfile_fseek (zf, 0, SEEK_SET);
- zfile_fwrite (b, 512, 1, zf);
- // write footer
- zfile_fseek (zf, 512 + 1024 + batsize, SEEK_SET);
- zfile_fwrite (b, 512, 1, zf);
- // dynamic disk header
- memset (b, 0, 1024);
- // cookie
- strcpy ((char*)b, "cxsparse");
- // data offset
- for (i = 0; i < 8; i++)
- b[0x08 + i] = 0xff;
- // table offset (bat)
- b[0x10 + 6] = 0x06;
- // version
- b[0x19] = 1;
- // max table entries
- b[0x1c] = batentrysize >> 24;
- b[0x1d] = batentrysize >> 16;
- b[0x1e] = batentrysize >> 8;
- b[0x1f] = batentrysize >> 0;
- b[0x20] = blocksize >> 24;
- b[0x21] = blocksize >> 16;
- b[0x22] = blocksize >> 8;
- b[0x23] = blocksize >> 0;
- crc = vhd_checksum (b, -1);
- b[0x24] = crc >> 24;
- b[0x25] = crc >> 16;
- b[0x26] = crc >> 8;
- b[0x27] = crc >> 0;
- // write dynamic header
- zfile_fseek (zf, 512, SEEK_SET);
- zfile_fwrite (b, 1024, 1, zf);
- // bat
- memset (b, 0, batsize);
- memset (b, 0xff, batentrysize * 4);
- zfile_fwrite (b, batsize, 1, zf);
- zfile_fclose (zf);
- zf = NULL;
- if (dostype) {
- uae_u8 bootblock[512] = { 0 };
- bootblock[0] = dostype >> 24;
- bootblock[1] = dostype >> 16;
- bootblock[2] = dostype >> 8;
- bootblock[3] = dostype >> 0;
- if (hdf_open (&hfd, name) > 0) {
- vhd_write (&hfd, bootblock, 0, 512);
- hdf_close (&hfd);
- }
- }
- ret = 1;
- end:
- xfree (b);
- zfile_fclose (zf);
- return ret;
- }
- static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- int ret = 0, extra = 0;
- if (offset < hfd->virtual_size) {
- uae_s64 len2 = offset + len <= hfd->virtual_size ? len : hfd->virtual_size - offset;
- if (!hfd->virtual_rdb)
- return 0;
- memcpy(buffer, hfd->virtual_rdb + offset, len2);
- len -= len2;
- if (len <= 0)
- return len2;
- offset += len2;
- buffer = (uae_u8*)buffer + len2;
- extra = len2;
- }
- offset -= hfd->virtual_size;
- if (hfd->hfd_type == HFD_VHD_DYNAMIC)
- ret = vhd_read (hfd, buffer, offset, len);
- else if (hfd->hfd_type == HFD_VHD_FIXED)
- ret = hdf_read_target (hfd, buffer, offset + 512, len);
- #ifdef WITH_CHD
- else if (hfd->hfd_type == HFD_CHD_OTHER) {
- chd_file *cf = (chd_file*)hfd->chd_handle;
- if (cf->read_bytes(offset, buffer, len) == CHDERR_NONE)
- ret = len;
- else
- return 0;
- } else if (hfd->hfd_type == HFD_CHD_HD) {
- hard_disk_file *chdf = (hard_disk_file*)hfd->chd_handle;
- hard_disk_info *chdi = hard_disk_get_info(chdf);
- chd_file *cf = hard_disk_get_chd(chdf);
- uae_u8 *buf = (uae_u8*)buffer;
- int got = 0;
- offset /= chdi->sectorbytes;
- while (len > 0) {
- if (cf->read_units(offset, buf) != CHDERR_NONE)
- break;
- got += chdi->sectorbytes;
- buf += chdi->sectorbytes;
- len -= chdi->sectorbytes;
- offset++;
- }
- ret = got;
- }
- #endif
- else
- ret = hdf_read_target (hfd, buffer, offset, len);
- if (ret <= 0)
- return ret;
- ret += extra;
- return ret;
- }
- static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- int ret = 0, extra = 0;
- // writes to virtual RDB are ignored
- if (offset < hfd->virtual_size) {
- uae_s64 len2 = offset + len <= hfd->virtual_size ? len : hfd->virtual_size - offset;
- len -= len2;
- if (len <= 0)
- return len2;
- offset += len2;
- buffer = (uae_u8*)buffer + len2;
- extra = len2;
- }
- offset -= hfd->virtual_size;
- if (hfd->hfd_type == HFD_VHD_DYNAMIC)
- ret = vhd_write (hfd, buffer, offset, len);
- else if (hfd->hfd_type == HFD_VHD_FIXED)
- ret = hdf_write_target (hfd, buffer, offset + 512, len);
- #ifdef WITH_CHD
- else if (hfd->hfd_type == HFD_CHD_OTHER)
- return 0;
- else if (hfd->hfd_type == HFD_CHD_HD) {
- if (hfd->ci.readonly)
- return 0;
- hard_disk_file *chdf = (hard_disk_file*)hfd->chd_handle;
- hard_disk_info *chdi = hard_disk_get_info(chdf);
- chd_file *cf = hard_disk_get_chd(chdf);
- uae_u8 *buf = (uae_u8*)buffer;
- int got = 0;
- offset /= chdi->sectorbytes;
- while (len > 0) {
- if (cf->write_units(offset, buf) != CHDERR_NONE)
- break;
- got += chdi->sectorbytes;
- buf += chdi->sectorbytes;
- len -= chdi->sectorbytes;
- offset++;
- }
- ret = got;
- }
- #endif
- else
- ret = hdf_write_target (hfd, buffer, offset, len);
- if (ret <= 0)
- return ret;
- ret += extra;
- return ret;
- }
- static void adide_decode (void *v, int len)
- {
- int i;
- uae_u8 *buffer = (uae_u8*)v;
- for (i = 0; i < len; i += 2) {
- uae_u8 *b = buffer + i;
- uae_u16 w = (b[0] << 8) | (b[1] << 0);
- uae_u16 o = adide_decode_word(w);
- b[0] = o >> 8;
- b[1] = o >> 0;
- }
- }
- static void adide_encode (void *v, int len)
- {
- int i;
- uae_u8 *buffer = (uae_u8*)v;
- for (i = 0; i < len; i += 2) {
- uae_u8 *b = buffer + i;
- uae_u16 w = (b[0] << 8) | (b[1] << 0);
- uae_u16 o = adide_encode_word(w);
- b[0] = o >> 8;
- b[1] = o >> 0;
- }
- }
- static void hdf_byteswap (void *v, int len)
- {
- int i;
- uae_u8 *b = (uae_u8*)v;
- for (i = 0; i < len; i += 2) {
- uae_u8 tmp = b[i];
- b[i] = b[i + 1];
- b[i + 1] = tmp;
- }
- }
- int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- int v;
- v = hdf_read (hfd, buffer, offset, len);
- if (v > 0 && offset < 16 * 512 && !hfd->byteswap && !hfd->adide) {
- uae_u8 *buf = (uae_u8*)buffer;
- bool changed = false;
- if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM"
- hfd->adide = 1;
- changed = true;
- write_log (_T("HDF: adide scrambling detected\n"));
- } else if (!memcmp (buf, "DRKS", 4)) {
- hfd->byteswap = 1;
- changed = true;
- write_log (_T("HDF: byteswapped RDB detected\n"));
- }
- if (changed)
- v = hdf_read (hfd, buffer, offset, len);
- }
- return v;
- }
- int hdf_read(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- int v;
- hf_log3 (_T("cmd_read: %p %04x-%08x (%d) %08x (%d)\n"),
- buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize));
- if (!hfd->adide) {
- v = hdf_cache_read (hfd, buffer, offset, len);
- } else {
- offset += 512;
- v = hdf_cache_read (hfd, buffer, offset, len);
- adide_decode (buffer, len);
- }
- if (hfd->byteswap)
- hdf_byteswap (buffer, len);
- return v;
- }
- int hdf_write(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
- {
- int v;
- hf_log3 (_T("cmd_write: %p %04x-%08x (%d) %08x (%d)\n"),
- buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize));
- if (hfd->byteswap)
- hdf_byteswap (buffer, len);
- if (!hfd->adide) {
- v = hdf_cache_write (hfd, buffer, offset, len);
- } else {
- offset += 512;
- adide_encode (buffer, len);
- v = hdf_cache_write (hfd, buffer, offset, len);
- adide_decode (buffer, len);
- }
- if (hfd->byteswap)
- hdf_byteswap (buffer, len);
- return v;
- }
- static uae_u64 cmd_readx(struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
- {
- m68k_cancel_idle();
- gui_flicker_led (LED_HD, hfd->unitnum, 1);
- return hdf_read (hfd, dataptr, offset, len);
- }
- static uae_u64 cmd_read(TrapContext *ctx, struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
- {
- if (!len)
- return 0;
- if (!ctx && real_address_allowed()) {
- addrbank *bank_data = &get_mem_bank (dataptr);
- if (!bank_data)
- return 0;
- if (bank_data->check(dataptr, len)) {
- uae_u8 *buffer = bank_data->xlateaddr(dataptr);
- return cmd_readx(hfd, buffer, offset, len);
- }
- }
- int total = 0;
- while (len > 0) {
- uae_u8 buf[RTAREA_TRAP_DATA_EXTRA_SIZE];
- int max = RTAREA_TRAP_DATA_EXTRA_SIZE & ~511;
- int size = len > max ? max : len;
- if (cmd_readx(hfd, buf, offset, size) != size)
- break;
- trap_put_bytes(ctx, buf, dataptr, size);
- offset += size;
- dataptr += size;
- len -= size;
- total += size;
- }
- return total;
- }
- static uae_u64 cmd_writex(struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
- {
- m68k_cancel_idle();
- gui_flicker_led (LED_HD, hfd->unitnum, 2);
- return hdf_write (hfd, dataptr, offset, len);
- }
- static uae_u64 cmd_write(TrapContext *ctx, struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
- {
- if (!len)
- return 0;
- if (!ctx && real_address_allowed()) {
- addrbank *bank_data = &get_mem_bank (dataptr);
- if (!bank_data)
- return 0;
- if (bank_data->check(dataptr, len)) {
- uae_u8 *buffer = bank_data->xlateaddr(dataptr);
- return cmd_writex(hfd, buffer, offset, len);
- }
- }
- int total = 0;
- while (len > 0) {
- uae_u8 buf[RTAREA_TRAP_DATA_EXTRA_SIZE];
- int max = RTAREA_TRAP_DATA_EXTRA_SIZE & ~511;
- int size = len > max ? max : len;
- trap_get_bytes(ctx, buf, dataptr, size);
- if (cmd_writex(hfd, buf, offset, size) != size)
- break;
- offset += size;
- dataptr += size;
- len -= size;
- total += size;
- }
- return total;
- }
- static int checkbounds (struct hardfiledata *hfd, uae_u64 offset, uae_u64 len, int mode)
- {
- uae_u64 max = hfd->virtsize;
- if (offset >= max || offset + len > max || (offset > 0xffffffff && (uae_s64)offset < 0)) {
- write_log (_T("UAEHF SCSI: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"),
- (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
- (uae_u32)(max >> 32),(uae_u32)max);
- return -1;
- }
- if (hfd->ci.max_lba) {
- max = hfd->ci.max_lba * hfd->ci.blocksize;
- if (offset >= max) {
- write_log (_T("UAEHF SCSI: forced last lba out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"),
- (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
- (uae_u32)(max >> 32),(uae_u32)max);
- return -1;
- }
- }
- if ((mode == 1 || mode == 2) && hfd->ci.badblock_num) {
- offset /= hfd->ci.blocksize;
- len /= hfd->ci.blocksize;
- for (int i = 0; i < hfd->ci.badblock_num; i++) {
- struct uaedev_badblock *bb = &hfd->ci.badblocks[i];
- if (offset + len >= bb->first && offset < bb->last)
- return 1;
- }
- }
- return 0;
- }
- static bool is_writeprotected(struct hardfiledata *hfd)
- {
- return hfd->ci.readonly || hfd->dangerous || currprefs.harddrive_read_only;
- }
- static int nodisk (struct hardfiledata *hfd)
- {
- if (hfd->drive_empty)
- return 1;
- return 0;
- }
- static void setdrivestring(const TCHAR *s, uae_u8 *d, int start, int length)
- {
- int i = 0;
- uae_char *ss = ua(s);
- while (i < length && ss[i]) {
- d[start + i] = ss[i];
- i++;
- }
- while (i > 0) {
- uae_char c = d[start + i - 1];
- if (c != '_')
- break;
- i--;
- }
- while (i < length) {
- d[start + i] = 32;
- i++;
- }
- xfree (ss);
- }
- static const uae_u8 sasi_commands[] =
- {
- 0x00, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x12,
- 0xe0, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
- 0xff
- };
- static const uae_u8 sasi_commands2[] =
- {
- 0x12,
- 0xff
- };
- static uae_u64 get_scsi_6_offset(struct hardfiledata *hfd, struct hd_hardfiledata *hdhfd, uae_u8 *cmdbuf, uae_u64 *lba)
- {
- bool chs = hfd->ci.unit_feature_level == HD_LEVEL_SASI_CHS;
- uae_u64 offset;
- if (chs) {
- int cyl, cylsec, head, tracksec;
- if (hdhfd) {
- cyl = hdhfd->cyls;
- head = hdhfd->heads;
- tracksec = hdhfd->secspertrack;
- cylsec = 0;
- } else {
- getchsx(hfd, &cyl, &cylsec, &head, &tracksec);
- }
- int d_head = cmdbuf[1] & 31;
- int d_cyl = cmdbuf[3] | ((cmdbuf[2] >> 6) << 8) | ((cmdbuf[1] >> 7) << 10);
- int d_sec = cmdbuf[2] & 63;
- *lba = ((cmdbuf[1] & (0x1f | 0x80 | 0x40)) << 16) | (cmdbuf[2] << 8) || cmdbuf[3];
- if (d_cyl >= cyl || d_head >= head || d_sec >= tracksec)
- return ~0;
- offset = d_cyl * head * tracksec + d_head * tracksec + d_sec;
- } else {
- offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
- }
- return offset;
- }
- int scsi_hd_emulate (struct hardfiledata *hfd, struct hd_hardfiledata *hdhfd, uae_u8 *cmdbuf, int scsi_cmd_len,
- uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
- {
- TrapContext *ctx = NULL;
- if (cmdbuf == NULL)
- return 0;
- uae_u64 len, offset;
- int lr = 0, ls = 0;
- int chkerr;
- int scsi_len = -1;
- int status = 0;
- int lun;
- uae_u8 cmd;
- bool sasi = hfd->ci.unit_feature_level >= HD_LEVEL_SASI && hfd->ci.unit_feature_level <= HD_LEVEL_SASI_ENHANCED;
- bool sasie = hfd->ci.unit_feature_level == HD_LEVEL_SASI_ENHANCED;
- bool omti = hfd->ci.unit_feature_level == HD_LEVEL_SASI_CHS;
- uae_u8 sasi_sense = 0;
- uae_u64 current_lba = ~0;
- cmd = cmdbuf[0];
- if (log_scsiemu) {
- write_log (_T("SCSIEMU HD %d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X CMDLEN=%d DATA=%p\n"), hfd->unitnum,
- cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5], cmdbuf[6],
- cmdbuf[7], cmdbuf[8], cmdbuf[9], cmdbuf[10], cmdbuf[11],
- scsi_cmd_len, scsi_data);
- }
- /* REQUEST SENSE */
- if (cmd == 0x03) {
- return 0;
- }
- *reply_len = *sense_len = 0;
- lun = cmdbuf[1] >> 5;
- if (sasi || omti) {
- lun = lun & 1;
- if (lun)
- goto nodisk;
- }
- if (cmd != 0x03 && cmd != 0x12 && lun) {
- status = 2; /* CHECK CONDITION */
- s[0] = 0x70;
- s[2] = 5; /* ILLEGAL REQUEST */
- s[12] = 0x25; /* INVALID LUN */
- ls = 0x12;
- write_log (_T("UAEHF: CMD=%02X LUN=%d ignored\n"), cmdbuf[0], lun);
- goto scsi_done;
- }
- if (sasi || omti) {
- int i;
- for (i = 0; sasi_commands[i] != 0xff; i++) {
- if (sasi_commands[i] == cmdbuf[0])
- break;
- }
- if (sasi_commands[i] == 0xff) {
- if (sasie) {
- for (i = 0; sasi_commands2[i] != 0xff; i++) {
- if (sasi_commands2[i] == cmdbuf[0])
- break;
- }
- if (sasi_commands2[i] == 0xff)
- goto errreq;
- } else {
- goto errreq;
- }
- }
- switch (cmdbuf[0])
- {
- case 0x05: /* READ VERIFY */
- if (nodisk(hfd))
- goto nodisk;
- offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, ¤t_lba);
- if (offset == ~0) {
- chkerr = 1;
- goto checkfail;
- }
- current_lba = offset;
- offset *= hfd->ci.blocksize;
- chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 1);
- if (chkerr) {
- current_lba = offset;
- goto checkfail;
- }
- scsi_len = 0;
- goto scsi_done;
- case 0x0c: /* INITIALIZE DRIVE CHARACTERISTICS */
- scsi_len = 8;
- write_log(_T("INITIALIZE DRIVE CHARACTERISTICS: "));
- write_log(_T("Heads: %d Cyls: %d Secs: %d\n"),
- (scsi_data[1] >> 4) | ((scsi_data[0] & 0xc0) << 4),
- ((scsi_data[1] & 15) << 8) | (scsi_data[2]),
- scsi_data[5]);
- for (int i = 0; i < 8; i++) {
- write_log(_T("%02X "), scsi_data[i]);
- }
- write_log(_T("\n"));
- goto scsi_done;
- case 0x11: // ASSIGN ALTERNATE TRACK
- if (nodisk(hfd))
- goto nodisk;
- // do nothing, swallow data
- scsi_len = 4;
- goto scsi_done;
- case 0x12: /* INQUIRY */
- {
- int cyl, cylsec, head, tracksec;
- int alen = cmdbuf[4];
- if (nodisk(hfd))
- goto nodisk;
- if (hdhfd) {
- cyl = hdhfd->cyls;
- head = hdhfd->heads;
- tracksec = hdhfd->secspertrack;
- cylsec = 0;
- } else {
- getchsx(hfd, &cyl, &cylsec, &head, &tracksec);
- }
- r[0] = 0;
- r[1] = 11;
- r[9] = cyl >> 8;
- r[10] = cyl;
- r[11] = head;
- scsi_len = lr = alen > 12 ? 12 : alen;
- goto scsi_done;
- }
- break;
- }
- }
- switch (cmdbuf[0])
- {
- case 0x12: /* INQUIRY */
- {
- if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
- goto err;
- int alen = (cmdbuf[3] << 8) | cmdbuf[4];
- if (lun != 0) {
- r[0] = 0x7f;
- } else {
- r[0] = 0;
- }
- r[2] = 2; /* supports SCSI-2 */
- r[3] = 2; /* response data format */
- r[4] = 32; /* additional length */
- r[7] = 0;
- lr = alen < 36 ? alen : 36;
- if (hdhfd) {
- r[2] = hdhfd->ansi_version;
- r[3] = hdhfd->ansi_version >= 2 ? 2 : 0;
- }
- setdrivestring(hfd->vendor_id, r, 8, 8);
- setdrivestring(hfd->product_id, r, 16, 16);
- setdrivestring(hfd->product_rev, r, 32, 4);
- uae_u8 *rr;
- if (ini_getdata(hfd->geometry, _T("INQUIRY"), _T("00"), &rr, &lr)) {
- if (lr > alen)
- lr = alen;
- memcpy(r, rr, lr);
- xfree(rr);
- }
- if (lun == 0 && hfd->drive_empty) {
- r[0] |= 0x20; // not present
- r[1] |= 0x80; // removable..
- }
- scsi_len = lr;
- }
- goto scsi_done;
- case 0x1b: /* START/STOP UNIT */
- scsi_len = 0;
- hfd->unit_stopped = (cmdbuf[4] & 1) == 0;
- goto scsi_done;
- }
- if (hfd->unit_stopped) {
- status = 2; /* CHECK CONDITION */
- s[0] = 0x70;
- s[2] = 2; /* NOT READY */
- s[12] = 4; /* not ready */
- s[13] = 2; /* need initialise command */
- ls = 0x12;
- goto scsi_done;
- }
- switch (cmdbuf[0])
- {
- case 0x00: /* TEST UNIT READY */
- if (nodisk (hfd))
- goto nodisk;
- scsi_len = 0;
- break;
- case 0x01: /* REZERO UNIT */
- if (nodisk (hfd))
- goto nodisk;
- scsi_len = 0;
- break;
- case 0x04: /* FORMAT UNIT */
- // do nothing
- if (nodisk (hfd))
- goto nodisk;
- if (is_writeprotected(hfd))
- goto readprot;
- scsi_len = 0;
- break;
- case 0x05: /* VERIFY TRACK */
- // do nothing
- if (nodisk (hfd))
- goto nodisk;
- scsi_len = 0;
- break;
- case 0x06: /* FORMAT TRACK */
- case 0x07: /* FORMAT BAD TRACK */
- if (nodisk (hfd))
- goto nodisk;
- if (is_writeprotected(hfd))
- goto readprot;
- // do nothing
- if (cmdbuf[5] & 0x40) {
- // data from sector buffer
- } else {
- // data is static 0x6c
- }
- scsi_len = 0;
- break;
- case 0x09: /* READ VERIFY */
- if (nodisk(hfd))
- goto nodisk;
- offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, ¤t_lba);
- if (offset == ~0) {
- chkerr = 1;
- goto checkfail;
- }
- current_lba = offset;
- offset *= hfd->ci.blocksize;
- chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 1);
- if (chkerr) {
- current_lba = offset;
- goto checkfail;
- }
- scsi_len = 0;
- break;
- case 0x0b: /* SEEK (6) */
- if (nodisk (hfd))
- goto nodisk;
- offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, ¤t_lba);
- if (offset == ~0) {
- chkerr = 1;
- goto checkfail;
- }
- current_lba = offset;
- offset *= hfd->ci.blocksize;
- chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 3);
- if (chkerr)
- goto checkfail;
- scsi_len = 0;
- break;
- case 0x08: /* READ (6) */
- if (nodisk (hfd))
- goto nodisk;
- offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, ¤t_lba);
- if (offset == ~0) {
- chkerr = 1;
- goto checkfail;
- }
- current_lba = offset;
- offset *= hfd->ci.blocksize;
- len = cmdbuf[4];
- if (!len)
- len = 256;
- len *= hfd->ci.blocksize;
- chkerr = checkbounds(hfd, offset, len, 1);
- if (chkerr)
- goto checkfail;
- scsi_len = (uae_u32)cmd_readx(hfd, scsi_data, offset, len);
- break;
- case 0x0e: /* READ SECTOR BUFFER */
- len = hfd->ci.blocksize;
- scsi_len = len;
- memset(scsi_data, 0, len);
- if (len > sizeof(hfd->sector_buffer))
- len = sizeof(hfd->sector_buffer);
- memcpy(scsi_data, hfd->sector_buffer, len);
- break;
- case 0x0f: /* WRITE SECTOR BUFFER */
- len = hfd->ci.blocksize;
- scsi_len = len;
- if (len > sizeof(hfd->sector_buffer))
- len = sizeof(hfd->sector_buffer);
- memcpy(hfd->sector_buffer, scsi_data, len);
- break;
- case 0x0a: /* WRITE (6) */
- if (nodisk (hfd))
- goto nodisk;
- if (is_writeprotected(hfd))
- goto readprot;
- offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, ¤t_lba);
- if (offset == ~0) {
- chkerr = 1;
- goto checkfail;
- }
- current_lba = offset;
- offset *= hfd->ci.blocksize;
- len = cmdbuf[4];
- if (!len)
- len = 256;
- len *= hfd->ci.blocksize;
- chkerr = checkbounds(hfd, offset, len, 2);
- if (chkerr)
- goto checkfail;
- scsi_len = (uae_u32)cmd_writex(hfd, scsi_data, offset, len);
- break;
- case 0x55: // MODE SELECT(10)
- case 0x15: // MODE SELECT(6)
- {
- bool select10 = cmdbuf[0] == 0x55;
- bool sp = (cmdbuf[1] & 1) != 0;
- bool pf = (cmdbuf[1] & 0x10) != 0;
- int plen;
- uae_u8 bd[8];
- if (nodisk (hfd))
- goto nodisk;
- // we don't support save pages
- if (pf)
- goto errreq;
- // assume error first
- status = 2; /* CHECK CONDITION */
- s[0] = 0x70;
- s[2] = 5; /* ILLEGAL REQUEST */
- s[12] = 0x26; /* INVALID FIELD IN PARAMETER LIST */
- ls = 0x12;
- memset(bd, 0, sizeof bd);
- uae_u8 *p = scsi_data;
- if (select10) {
- plen = (cmdbuf[7] << 8) | cmdbuf[8];
- memcpy(bd, p, plen > 8 ? 8 : plen);
- p += plen > 8 ? 8 : plen;
- } else {
- plen = cmdbuf[4];
- if (plen > 0)
- bd[0] = scsi_data[0];
- if (plen > 1)
- bd[2] = scsi_data[1]; // medium type
- if (plen > 2)
- bd[3] = scsi_data[2];
- if (plen > 3)
- bd[7] = scsi_data[3]; // bd len
- p += plen > 4 ? 4 : plen;
- }
- if (bd[0] != 0 || bd[1] != 0 || bd[2] != 0 || bd[3] != 0 || bd[4] != 0 || bd[5] != 0)
- goto scsi_done;
- int bdlen = (bd[6] << 8) | bd[7];
- if (bdlen != 0 && bdlen != 8)
- goto scsi_done;
- if (bdlen) {
- int block = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | (p[7] << 0);
- if (block != 512)
- goto scsi_done;
- p += bdlen;
- }
- for (;;) {
- int rem = plen - (p - scsi_data);
- if (!rem)
- break;
- if (rem < 2)
- goto scsi_done;
- uae_u8 pc = *p++;
- if (pc >= 0x40)
- goto scsi_done;
- uae_u8 pagelen = *p++;
- rem -= 2;
- if (!pagelen || pagelen > rem)
- goto scsi_done;
- if (pc != 0 && pc != 1 && pc != 3 && pc != 4)
- goto scsi_done;
- if (pc == 0)
- break;
- p += pagelen;
- }
- status = 0;
- ls = 0;
- scsi_len = 0;
- break;
- }
- case 0x5a: // MODE SENSE(10)
- case 0x1a: /* MODE SENSE(6) */
- {
- uae_u8 *p;
- bool pcodeloop = false;
- bool sense10 = cmdbuf[0] == 0x5a;
- int pc = cmdbuf[2] >> 6;
- int pcode = cmdbuf[2] & 0x3f;
- int dbd = cmdbuf[1] & 8;
- int cyl, head, tracksec;
- int totalsize, bdsize, alen;
- if (nodisk (hfd))
- goto nodisk;
- if (hdhfd) {
- cyl = hdhfd->cyls;
- head = hdhfd->heads;
- tracksec = hdhfd->secspertrack;
- } else {
- int cylsec;
- getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
- }
- //write_log (_T("MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
- p = r;
- if (sense10) {
- totalsize = 8 - 2;
- alen = (cmdbuf[7] << 8) | cmdbuf[8];
- p[2] = 0;
- p[3] = is_writeprotected(hfd) ? 0x80 : 0x00;
- p[4] = 0;
- p[5] = 0;
- p[6] = 0;
- p[7] = 0;
- p += 8;
- } else {
- totalsize = 4 - 1;
- alen = cmdbuf[4];
- p[1] = 0;
- p[2] = is_writeprotected(hfd) ? 0x80 : 0x00;
- p[3] = 0;
- p += 4;
- }
- bdsize = 0;
- if (!dbd) {
- uae_u32 blocks = (uae_u32)(hfd->virtsize / hfd->ci.blocksize);
- wl(p + 0, blocks >= 0x00ffffff ? 0x00ffffff : blocks);
- wl(p + 4, hfd->ci.blocksize);
- bdsize = 8;
- p += bdsize;
- }
- if (pcode == 0x3f) {
- pcode = 1; // page = 0 must be last
- pcodeloop = true;
- }
- for (;;) {
- int psize = 0;
- if (pcode == 0) {
- p[0] = 0;
- p[1] = 0;
- p[2] = 0x20;
- p[3] = 0;
- psize = 4;
- } else if (pcode == 1) {
- // error recovery page
- p[0] = 1;
- p[1] = 0x0a;
- psize = p[1] + 2;
- // return defaults (0)
- } else if (pcode == 3) {
- // format parameters
- p[0] = 3;
- p[1] = 22;
- p[3] = 1;
- p[10] = tracksec >> 8;
- p[11] = tracksec;
- p[12] = hfd->ci.blocksize >> 8;
- p[13] = hfd->ci.blocksize;
- p[15] = 1; // interleave
- p[20] = 0x80;
- psize = p[1] + 2;
- } else if (pcode == 4) {
- // rigid drive geometry
- p[0] = 4;
- wl(p + 1, cyl);
- p[1] = 22;
- p[5] = head;
- wl(p + 13, cyl);
- ww(p + 20, 5400);
- psize = p[1] + 2;
- } else {
- if (!pcodeloop)
- goto err;
- }
- totalsize += psize;
- p += psize;
- if (!pcodeloop)
- break;
- if (pcode == 0)
- break;
- pcode++;
- if (pcode == 0x3f)
- pcode = 0;
- }
- if (sense10) {
- totalsize += bdsize;
- r[6] = bdsi…
Large files files are truncated, but you can click here to view the full file