DISK: Add support for arbitrary sector sizes in all container formats

This commit is contained in:
Mark Pizzolato 2020-04-29 12:21:08 -07:00
parent 3c081a80c1
commit aa380517fa

View file

@ -334,7 +334,6 @@ static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD);
static int sim_vhd_disk_close (FILE *f);
static void sim_vhd_disk_flush (FILE *f);
static t_offset sim_vhd_disk_size (FILE *f);
static t_stat sim_vhd_disk_info (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom);
static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
static t_stat sim_vhd_disk_clearerr (UNIT *uptr);
@ -644,6 +643,7 @@ t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread,
{
t_stat r;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
uint32 f = DK_GET_FMT (uptr);
t_seccnt sread = 0;
sim_debug_unit (ctx->dbit, uptr, "sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr - ctx->dptr->units), lba, sects);
@ -658,8 +658,9 @@ if ((sects == 1) && /* Single sector reads *
if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Aligned & whole sector transfers */
((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
(0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {
switch (DK_GET_FMT (uptr)) { /* case on format */
(0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1)))) ||
(f == DKUF_F_STD) || (f == DKUF_F_VHD)) { /* or SIMH or VHD formats */
switch (f) { /* case on format */
case DKUF_F_STD: /* SIMH format */
r = _sim_disk_rdsect (uptr, lba, buf, &sread, sects);
break;
@ -677,35 +678,22 @@ if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Al
sim_buf_swap_data (buf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size);
return r;
}
else { /* Unaligned and/or partial sector transfers */
uint8 *tbuf = (uint8*) malloc (sects * ctx->sector_size + 2 * ctx->storage_sector_size);
t_lba sspsts = ctx->storage_sector_size / ctx->sector_size; /* sim sectors in a storage sector */
t_lba tlba = lba & ~(sspsts - 1);
t_seccnt tsects = sects + (lba - tlba);
else { /* Unaligned and/or partial sector transfers in RAW mode */
size_t tbufsize = sects * ctx->sector_size + 2 * ctx->storage_sector_size;
uint8 *tbuf = (uint8*) malloc (tbufsize);
t_offset ssaddr = (lba * (t_offset)ctx->sector_size) & ~(t_offset)(ctx->storage_sector_size -1);
uint32 soffset = (uint32)((lba * (t_offset)ctx->sector_size) - ssaddr);
uint32 bytesread;
tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1);
if (sectsread)
*sectsread = 0;
if (tbuf == NULL)
return SCPE_MEM;
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_STD: /* SIMH format */
r = _sim_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
break;
case DKUF_F_VHD: /* VHD format */
r = sim_vhd_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
r = sim_os_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
break;
default:
free (tbuf);
return SCPE_NOFNC;
}
sim_buf_swap_data (tbuf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size);
memcpy (buf, tbuf + ((lba - tlba) * ctx->sector_size), sects * ctx->sector_size);
r = sim_os_disk_read (uptr, ssaddr, tbuf, &bytesread, tbufsize & ~(ctx->storage_sector_size - 1));
sim_buf_swap_data (tbuf + soffset, ctx->xfer_element_size, (bytesread - soffset) / ctx->xfer_element_size);
memcpy (buf, tbuf + soffset, sects * ctx->sector_size);
if (sectsread) {
*sectsread = sread - (lba - tlba);
*sectsread = (bytesread - soffset) / ctx->sector_size;
if (*sectsread > sects)
*sectsread = sects;
}
@ -788,96 +776,60 @@ if (uptr->dynflags & UNIT_DISK_CHK) {
}
}
}
if (f == DKUF_F_STD)
switch (f) { /* case on format */
case DKUF_F_STD: /* SIMH format */
return _sim_disk_wrsect (uptr, lba, buf, sectswritten, sects);
if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Aligned & whole sector transfers */
((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
(0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {
if (sim_end || (ctx->xfer_element_size == sizeof (char)))
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */
return sim_vhd_disk_wrsect (uptr, lba, buf, sectswritten, sects);
case DKUF_F_RAW: /* Raw Physical Disk Access */
return sim_os_disk_wrsect (uptr, lba, buf, sectswritten, sects);
default:
return SCPE_NOFNC;
}
if (!sim_end && (ctx->xfer_element_size != sizeof (char))) {
tbuf = (uint8*) malloc (sects * ctx->sector_size);
if (NULL == tbuf)
return SCPE_MEM;
sim_buf_copy_swapped (tbuf, buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */
r = sim_vhd_disk_wrsect (uptr, lba, tbuf, sectswritten, sects);
break;
buf = tbuf;
}
r = sim_vhd_disk_wrsect (uptr, lba, buf, sectswritten, sects);
free (tbuf);
return r;
case DKUF_F_RAW: /* Raw Physical Disk Access */
r = sim_os_disk_wrsect (uptr, lba, tbuf, sectswritten, sects);
break;
break; /* handle below */
default:
r = SCPE_NOFNC;
break;
return SCPE_NOFNC;
}
}
else { /* Unaligned and/or partial sector transfers */
t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */
t_lba tlba = lba & ~(sspsts - 1);
t_seccnt tsects = sects + (lba - tlba);
if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Aligned & whole sector transfers */
((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
(0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {
tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size);
tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1);
if (!sim_end && (ctx->xfer_element_size != sizeof (char))) {
tbuf = (uint8*) malloc (sects * ctx->sector_size);
if (NULL == tbuf)
return SCPE_MEM;
sim_buf_copy_swapped (tbuf, buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
buf = tbuf;
}
r = sim_os_disk_wrsect (uptr, lba, buf, sectswritten, sects);
}
else { /* Unaligned and/or partial sector transfers in RAW mode */
size_t tbufsize = sects * ctx->sector_size + 2 * ctx->storage_sector_size;
t_offset ssaddr = (lba * (t_offset)ctx->sector_size) & ~(t_offset)(ctx->storage_sector_size -1);
t_offset sladdr = ((lba + sects) * (t_offset)ctx->sector_size) & ~(t_offset)(ctx->storage_sector_size -1);
uint32 soffset = (uint32)((lba * (t_offset)ctx->sector_size) - ssaddr);
uint32 byteswritten;
tbuf = (uint8*) malloc (tbufsize);
if (sectswritten)
*sectswritten = 0;
if (tbuf == NULL)
return SCPE_MEM;
/* Partial Sector writes require a read-modify-write sequence for the partial sectors */
if ((lba & (sspsts - 1)) ||
(sects < sspsts))
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */
sim_vhd_disk_rdsect (uptr, tlba, tbuf, NULL, sspsts);
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
sim_os_disk_rdsect (uptr, tlba, tbuf, NULL, sspsts);
break;
default:
r = SCPE_NOFNC;
break;
}
if ((tsects > sspsts) &&
((sects + lba - tlba) & (sspsts - 1)))
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */
sim_vhd_disk_rdsect (uptr, tlba + tsects - sspsts,
tbuf + (tsects - sspsts) * ctx->sector_size,
NULL, sspsts);
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
sim_os_disk_rdsect (uptr, tlba + tsects - sspsts,
tbuf + (tsects - sspsts) * ctx->sector_size,
NULL, sspsts);
break;
default:
r = SCPE_NOFNC;
break;
}
sim_buf_copy_swapped (tbuf + (lba & (sspsts - 1)) * ctx->sector_size,
if (soffset)
sim_os_disk_read (uptr, ssaddr, tbuf, NULL, ctx->storage_sector_size);
sim_os_disk_read (uptr, sladdr, tbuf + (size_t)(sladdr - ssaddr), NULL, ctx->storage_sector_size);
sim_buf_copy_swapped (tbuf + soffset,
buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_VHD: /* VHD format */
r = sim_vhd_disk_wrsect (uptr, tlba, tbuf, sectswritten, tsects);
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
r = sim_os_disk_wrsect (uptr, tlba, tbuf, sectswritten, tsects);
break;
default:
r = SCPE_NOFNC;
break;
}
if ((r == SCPE_OK) && sectswritten) {
*sectswritten -= (lba - tlba);
r = sim_os_disk_write (uptr, ssaddr, tbuf, &byteswritten, (soffset + (sects * ctx->sector_size) + ctx->storage_sector_size - 1) & ~(ctx->storage_sector_size - 1));
if (sectswritten) {
*sectswritten = byteswritten / ctx->sector_size;
if (*sectswritten > sects)
*sectswritten = sects;
}
@ -2238,7 +2190,7 @@ t_stat (*storage_function)(FILE *file, uint32 *sector_size, uint32 *removable, u
t_bool created = FALSE, copied = FALSE;
t_bool auto_format = FALSE;
t_offset container_size, filesystem_size, current_unit_size;
size_t size_tmp;
size_t tmp_size = 1;
if (uptr->flags & UNIT_DIS) /* disabled? */
return SCPE_UDIS;
@ -2252,11 +2204,8 @@ switch (xfer_element_size) {
case 1: case 2: case 4: case 8:
break;
}
size_tmp = 64;
while ((size_tmp != sector_size) && (size_tmp < 4096))
size_tmp = size_tmp << 1;
if (sector_size != size_tmp)
return sim_messagef (SCPE_ARG, "Invalid sector size: %u - must be a power of 2 between 64 and 4096\n", (uint32)sector_size);
if ((sector_size % xfer_element_size) != 0)
return sim_messagef (SCPE_ARG, "Invalid sector size: %u - must be a multiple of the transfer element size %u\n", (uint32)sector_size, (uint32)xfer_element_size);
if (sim_switches & SWMASK ('F')) { /* format spec? */
char gbuf[CBUFSIZE];
cptr = get_glyph (cptr, gbuf, 0); /* get spec */
@ -2464,9 +2413,11 @@ switch (DK_GET_FMT (uptr)) { /* case on format */
uptr->fileref = NULL;
open_function = sim_vhd_disk_open;
size_function = sim_vhd_disk_size;
storage_function = sim_vhd_disk_info;
break;
}
while (tmp_size < sector_size)
tmp_size <<= 1;
if (tmp_size == sector_size) { /* Power of 2 sector size can do RAW */
if (NULL != (uptr->fileref = sim_os_disk_open_raw (cptr, "rb"))) {
sim_disk_set_fmt (uptr, 0, "RAW", NULL); /* set file format to RAW */
sim_os_disk_close_raw (uptr->fileref); /* close raw file*/
@ -2476,6 +2427,7 @@ switch (DK_GET_FMT (uptr)) { /* case on format */
uptr->fileref = NULL;
break;
}
}
sim_disk_set_fmt (uptr, 0, "SIMH", NULL); /* set file format to SIMH */
open_function = sim_fopen;
size_function = sim_fsize_ex;
@ -2487,7 +2439,6 @@ switch (DK_GET_FMT (uptr)) { /* case on format */
uptr->fileref = NULL;
open_function = sim_vhd_disk_open;
size_function = sim_vhd_disk_size;
storage_function = sim_vhd_disk_info;
auto_format = TRUE;
break;
}
@ -2507,7 +2458,6 @@ switch (DK_GET_FMT (uptr)) { /* case on format */
uptr->fileref = NULL;
open_function = sim_vhd_disk_open;
size_function = sim_vhd_disk_size;
storage_function = sim_vhd_disk_info;
auto_format = TRUE;
break;
}
@ -4111,11 +4061,6 @@ static t_offset sim_vhd_disk_size (FILE *f)
return (t_offset)-1;
}
static t_stat sim_vhd_disk_info (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom)
{
return SCPE_NOFNC;
}
static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
return SCPE_IOERR;
@ -5074,17 +5019,6 @@ VHDHANDLE hVHD = (VHDHANDLE)f;
return (t_offset)(NtoHll (hVHD->Footer.CurrentSize));
}
static t_stat sim_vhd_disk_info (FILE *f, uint32 *sector_size, uint32 *removable, uint32 *is_cdrom)
{
if (sector_size)
*sector_size = 512;
if (removable)
*removable = FALSE;
if (is_cdrom)
*is_cdrom = FALSE;
return SCPE_OK;
}
#include <stdlib.h>
#include <time.h>
@ -5599,6 +5533,83 @@ static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szPare
return (FILE *)CreateDifferencingVirtualDisk (szVHDPath, szParentVHDPath);
}
static t_stat
ReadVirtualDisk(VHDHANDLE hVHD,
uint8 *buf,
uint32 BytesToRead,
uint32 *BytesRead,
uint64 Offset)
{
uint32 TotalBytesRead = 0;
uint32 BitMapBytes;
uint32 BitMapSectors;
t_stat r = SCPE_OK;
if (BytesRead)
*BytesRead = 0;
if (!hVHD || (hVHD->File == NULL)) {
errno = EBADF;
return SCPE_IOERR;
}
if (BytesToRead == 0)
return SCPE_OK;
if (Offset >= (uint64)NtoHll (hVHD->Footer.CurrentSize)) {
errno = ERANGE;
return SCPE_IOERR;
}
if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Fixed) {
if (ReadFilePosition(hVHD->File,
buf,
BytesToRead,
BytesRead,
Offset))
r = SCPE_IOERR;
return r;
}
/* We are now dealing with a Dynamically expanding or differencing disk */
BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/VHD_Internal_SectorSize))/8;
BitMapSectors = (BitMapBytes+VHD_Internal_SectorSize-1)/VHD_Internal_SectorSize;
while (BytesToRead && (r == SCPE_OK)) {
uint32 BlockNumber = (uint32)(Offset / NtoHl (hVHD->Dynamic.BlockSize));
uint32 BytesInRead = BytesToRead;
uint32 BytesThisRead = 0;
if (BlockNumber != (Offset + BytesToRead) / NtoHl (hVHD->Dynamic.BlockSize))
BytesInRead = (uint32)(((BlockNumber + 1) * NtoHl (hVHD->Dynamic.BlockSize)) - Offset);
if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) {
if (!hVHD->Parent) {
memset (buf, 0, BytesInRead);
BytesThisRead = BytesInRead;
}
else {
if (ReadVirtualDisk(hVHD->Parent,
buf,
BytesInRead,
&BytesThisRead,
Offset))
r = SCPE_IOERR;
}
}
else {
uint64 BlockOffset = VHD_Internal_SectorSize * ((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + BitMapSectors)) + (Offset % NtoHl (hVHD->Dynamic.BlockSize));
if (ReadFilePosition(hVHD->File,
buf,
BytesInRead,
&BytesThisRead,
BlockOffset))
r = SCPE_IOERR;
}
BytesToRead -= BytesThisRead;
buf = (uint8 *)(((char *)buf) + BytesThisRead);
Offset += BytesThisRead;
TotalBytesRead += BytesThisRead;
}
if (BytesRead)
*BytesRead = TotalBytesRead;
return SCPE_OK;
}
static t_stat
ReadVirtualDiskSectors(VHDHANDLE hVHD,
uint8 *buf,
@ -5607,81 +5618,15 @@ ReadVirtualDiskSectors(VHDHANDLE hVHD,
uint32 SectorSize,
t_lba lba)
{
uint64 BlockOffset = ((uint64)lba)*SectorSize;
uint32 SectorsRead = 0;
uint32 SectorsInRead;
size_t BytesRead = 0;
if (!hVHD || (hVHD->File == NULL)) {
errno = EBADF;
return SCPE_IOERR;
}
if ((BlockOffset + sects*SectorSize) > (uint64)NtoHll (hVHD->Footer.CurrentSize)) {
errno = ERANGE;
return SCPE_IOERR;
}
if (sectsread)
*sectsread = 0;
if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Fixed) {
if (ReadFilePosition(hVHD->File,
uint32 BytesRead;
t_stat r = ReadVirtualDisk(hVHD,
buf,
sects * SectorSize,
&BytesRead,
BlockOffset)) {
SectorSize * (uint64)lba);
if (sectsread)
*sectsread = (t_seccnt)(BytesRead/SectorSize);
return SCPE_IOERR;
}
if (sectsread)
*sectsread = (t_seccnt)(BytesRead/SectorSize);
return SCPE_OK;
}
/* We are now dealing with a Dynamically expanding or differencing disk */
while (sects) {
uint32 SectorsPerBlock = NtoHl (hVHD->Dynamic.BlockSize)/SectorSize;
uint64 BlockNumber = lba/SectorsPerBlock;
uint32 BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/VHD_Internal_SectorSize))/8;
uint32 BitMapSectors = (BitMapBytes+VHD_Internal_SectorSize-1)/VHD_Internal_SectorSize;
SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock;
if (SectorsInRead > sects)
SectorsInRead = sects;
if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) {
if (!hVHD->Parent)
memset (buf, 0, SectorSize*SectorsInRead);
else {
if (ReadVirtualDiskSectors(hVHD->Parent,
buf,
SectorsInRead,
NULL,
SectorSize,
lba)) {
if (sectsread)
*sectsread = SectorsRead;
return FALSE;
}
}
}
else {
BlockOffset = VHD_Internal_SectorSize * ((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + BitMapSectors))+ (SectorSize * (lba % SectorsPerBlock));
if (ReadFilePosition(hVHD->File,
buf,
SectorsInRead * SectorSize,
NULL,
BlockOffset)) {
if (sectsread)
*sectsread = SectorsRead;
return SCPE_IOERR;
}
}
sects -= SectorsInRead;
buf = (uint8 *)(((char *)buf) + SectorSize * SectorsInRead);
lba += SectorsInRead;
SectorsRead += SectorsInRead;
}
if (sectsread)
*sectsread = SectorsRead;
return SCPE_OK;
*sectsread = BytesRead / SectorSize;
return r;
}
static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
@ -5713,61 +5658,51 @@ return TRUE;
}
static t_stat
WriteVirtualDiskSectors(VHDHANDLE hVHD,
WriteVirtualDisk(VHDHANDLE hVHD,
uint8 *buf,
t_seccnt sects,
t_seccnt *sectswritten,
uint32 SectorSize,
t_lba lba)
uint32 BytesToWrite,
uint32 *BytesWritten,
uint64 Offset)
{
uint64 BlockOffset = ((uint64)lba)*SectorSize;
uint32 SectorsWritten = 0;
uint32 SectorsInWrite;
size_t BytesWritten = 0;
uint32 SectorsPerBlock;
uint64 BlockNumber;
uint32 TotalBytesWritten = 0;
uint32 BitMapBytes;
uint32 BitMapSectors;
t_stat r = SCPE_OK;
if (BytesWritten)
*BytesWritten = 0;
if (!hVHD || !hVHD->File) {
errno = EBADF;
return SCPE_IOERR;
}
if ((BlockOffset + sects * SectorSize) > (uint64)NtoHll(hVHD->Footer.CurrentSize)) {
sects = (t_seccnt)(((uint64)NtoHll(hVHD->Footer.CurrentSize) - BlockOffset) / SectorSize);
if (BytesToWrite == 0)
return SCPE_OK;
if (Offset >= (uint64)NtoHll(hVHD->Footer.CurrentSize)) {
errno = ERANGE;
r = SCPE_IOERR;
return SCPE_IOERR;
}
if (sectswritten)
*sectswritten = 0;
if (NtoHl(hVHD->Footer.DiskType) == VHD_DT_Fixed) {
if (WriteFilePosition(hVHD->File,
buf,
sects * SectorSize,
&BytesWritten,
BlockOffset)) {
if (sectswritten)
*sectswritten = (t_seccnt)(BytesWritten / SectorSize);
return SCPE_IOERR;
}
if (sectswritten)
*sectswritten = (t_seccnt)(BytesWritten/SectorSize);
BytesToWrite,
BytesWritten,
Offset))
r = SCPE_IOERR;
return r;
}
/* We are now dealing with a Dynamically expanding or differencing disk */
SectorsPerBlock = NtoHl(hVHD->Dynamic.BlockSize) / SectorSize;
BitMapBytes = (7 + (NtoHl(hVHD->Dynamic.BlockSize) / VHD_Internal_SectorSize)) / 8;
BitMapSectors = (BitMapBytes + VHD_Internal_SectorSize - 1) / VHD_Internal_SectorSize;
while (sects) {
BlockNumber = lba / SectorsPerBlock;
while (BytesToWrite && (r == SCPE_OK)) {
uint32 BlockNumber = (uint32)(Offset / NtoHl(hVHD->Dynamic.BlockSize));
uint32 BytesInWrite = BytesToWrite;
uint32 BytesThisWrite = 0;
if (BlockNumber >= NtoHl(hVHD->Dynamic.MaxTableEntries)) {
if (sectswritten)
*sectswritten = SectorsWritten;
return SCPE_EOF;
}
SectorsInWrite = 1;
if (BlockNumber != (Offset + BytesToWrite) / NtoHl (hVHD->Dynamic.BlockSize))
BytesInWrite = (uint32)(((BlockNumber + 1) * NtoHl(hVHD->Dynamic.BlockSize)) - Offset);
if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) {
uint8 *BitMap = NULL;
uint32 BitMapBufferSize = VHD_DATA_BLOCK_ALIGNMENT;
@ -5776,16 +5711,19 @@ while (sects) {
uint8 *BATUpdateBufferAddress;
uint32 BATUpdateBufferSize;
uint64 BATUpdateStorageAddress;
uint64 BlockOffset;
if (!hVHD->Parent && BufferIsZeros(buf, SectorsInWrite * SectorSize))
if (!hVHD->Parent && BufferIsZeros(buf, BytesInWrite)) {
BytesThisWrite = BytesInWrite;
goto IO_Done;
}
/* Need to allocate a new Data Block. */
BlockOffset = sim_fsize_ex (hVHD->File);
if (((int64)BlockOffset) == -1)
return SCPE_IOERR;
if (BitMapSectors*VHD_Internal_SectorSize > BitMapBufferSize)
if ((BitMapSectors * VHD_Internal_SectorSize) > BitMapBufferSize)
BitMapBufferSize = BitMapSectors * VHD_Internal_SectorSize;
BitMapBuffer = (uint8 *)calloc(1, BitMapBufferSize + SectorSize * SectorsPerBlock);
BitMapBuffer = (uint8 *)calloc(1, BitMapBufferSize + NtoHl(hVHD->Dynamic.BlockSize));
if (BitMapBufferSize > BitMapSectors * VHD_Internal_SectorSize)
BitMap = BitMapBuffer + BitMapBufferSize - BitMapBytes;
else
@ -5796,7 +5734,7 @@ while (sects) {
{ // Already aligned, so use padded BitMapBuffer
if (WriteFilePosition(hVHD->File,
BitMapBuffer,
BitMapBufferSize + SectorSize * SectorsPerBlock,
BitMapBufferSize + NtoHl(hVHD->Dynamic.BlockSize),
NULL,
BlockOffset)) {
free (BitMapBuffer);
@ -5815,7 +5753,7 @@ while (sects) {
BlockOffset -= BitMapSectors * VHD_Internal_SectorSize;
if (WriteFilePosition(hVHD->File,
BitMap,
(BitMapSectors * VHD_Internal_SectorSize) + (SectorSize * SectorsPerBlock),
(BitMapSectors * VHD_Internal_SectorSize) + NtoHl(hVHD->Dynamic.BlockSize),
NULL,
BlockOffset)) {
free (BitMapBuffer);
@ -5828,7 +5766,7 @@ while (sects) {
/* the BAT block address is the beginning of the block bitmap */
BlockOffset -= BitMapSectors * VHD_Internal_SectorSize;
hVHD->BAT[BlockNumber] = NtoHl((uint32)(BlockOffset / VHD_Internal_SectorSize));
BlockOffset += (BitMapSectors * VHD_Internal_SectorSize) + (SectorSize * SectorsPerBlock);
BlockOffset += (BitMapSectors * VHD_Internal_SectorSize) + NtoHl(hVHD->Dynamic.BlockSize);
if (WriteFilePosition(hVHD->File,
&hVHD->Footer,
sizeof(hVHD->Footer),
@ -5862,25 +5800,19 @@ while (sects) {
goto Fatal_IO_Error;
if (hVHD->Parent)
{ /* Need to populate data block contents from parent VHD */
uint32 BlockSectors = SectorsPerBlock;
BlockData = malloc (NtoHl (hVHD->Dynamic.BlockSize));
BlockData = malloc(SectorsPerBlock * SectorSize);
if (((lba / SectorsPerBlock) * SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize)) / SectorSize)
BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize)) / SectorSize - (lba / SectorsPerBlock) * SectorsPerBlock);
if (ReadVirtualDiskSectors(hVHD->Parent,
if (ReadVirtualDisk(hVHD->Parent,
(uint8*) BlockData,
BlockSectors,
NtoHl (hVHD->Dynamic.BlockSize),
NULL,
SectorSize,
(lba / SectorsPerBlock) * SectorsPerBlock))
(Offset / NtoHl (hVHD->Dynamic.BlockSize)) * NtoHl (hVHD->Dynamic.BlockSize)))
goto Fatal_IO_Error;
if (WriteVirtualDiskSectors(hVHD,
if (WriteVirtualDisk(hVHD,
(uint8*) BlockData,
BlockSectors,
NtoHl (hVHD->Dynamic.BlockSize),
NULL,
SectorSize,
(lba / SectorsPerBlock) * SectorsPerBlock))
(Offset / NtoHl (hVHD->Dynamic.BlockSize)) * NtoHl (hVHD->Dynamic.BlockSize)))
goto Fatal_IO_Error;
free(BlockData);
}
@ -5888,33 +5820,46 @@ while (sects) {
Fatal_IO_Error:
free (BitMap);
free (BlockData);
fclose (hVHD->File);
hVHD->File = NULL;
return SCPE_IOERR;
r = SCPE_IOERR;
}
else {
BlockOffset = VHD_Internal_SectorSize * ((uint64)(NtoHl(hVHD->BAT[BlockNumber]) + BitMapSectors)) + (SectorSize * (lba % SectorsPerBlock));
SectorsInWrite = SectorsPerBlock - lba % SectorsPerBlock;
if (SectorsInWrite > sects)
SectorsInWrite = sects;
uint64 BlockOffset = VHD_Internal_SectorSize * ((uint64)(NtoHl(hVHD->BAT[BlockNumber]) + BitMapSectors)) + (Offset % NtoHl(hVHD->Dynamic.BlockSize));
if (WriteFilePosition(hVHD->File,
buf,
SectorsInWrite * SectorSize,
&BytesWritten,
BlockOffset)) {
if (sectswritten)
*sectswritten = SectorsWritten + BytesWritten / SectorSize;
return SCPE_IOERR;
}
BytesInWrite,
&BytesThisWrite,
BlockOffset))
r = SCPE_IOERR;
}
IO_Done:
sects -= SectorsInWrite;
buf = (uint8 *)(((char *)buf) + SectorsInWrite * SectorSize);
lba += SectorsInWrite;
SectorsWritten += SectorsInWrite;
BytesToWrite -= BytesThisWrite;
buf = (uint8 *)(((char *)buf) + BytesThisWrite);
Offset += BytesThisWrite;
TotalBytesWritten += BytesThisWrite;
}
if (BytesWritten)
*BytesWritten = TotalBytesWritten;
return r;
}
static t_stat
WriteVirtualDiskSectors(VHDHANDLE hVHD,
uint8 *buf,
t_seccnt sects,
t_seccnt *sectswritten,
uint32 SectorSize,
t_lba lba)
{
uint32 BytesWritten;
t_stat r = WriteVirtualDisk(hVHD,
buf,
sects * SectorSize,
&BytesWritten,
SectorSize * (uint64)lba);
if (sectswritten)
*sectswritten = SectorsWritten;
*sectswritten = BytesWritten / SectorSize;
return r;
}
@ -6052,8 +5997,8 @@ return r;
t_stat sim_disk_test (DEVICE *dptr)
{
const char *fmt[] = {"VHD", "VHD", "SIMH", "RAW", NULL};
uint32 sect_size[] = {4096, 1024, 512, 256, 128, 64, 0};
const char *fmt[] = {"RAW", "VHD", "VHD", "SIMH", NULL};
uint32 sect_size[] = {576, 4096, 1024, 512, 256, 128, 64, 0};
uint32 xfr_size[] = {1, 2, 4, 8, 0};
int x, s, f;
UNIT *uptr = &dptr->units[0];