1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-05-05 23:45:14 +00:00

SCP: Updated to current version

This commit is contained in:
Richard Cornwell
2017-03-12 11:02:04 -04:00
parent 719c19c660
commit 7b42641606
23 changed files with 6164 additions and 2149 deletions

View File

@@ -162,16 +162,12 @@ static void *
_disk_io(void *arg)
{
UNIT* volatile uptr = (UNIT*)arg;
int sched_policy;
struct sched_param sched_priority;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
/* Boost Priority for this I/O thread vs the CPU instruction execution
thread which in general won't be readily yielding the processor when
this thread needs to run */
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) starting\n", (int)(uptr-ctx->dptr->units));
@@ -243,7 +239,7 @@ if (ctx) {
return FALSE;
}
static void _disk_cancel (UNIT *uptr)
static t_bool _disk_cancel (UNIT *uptr)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
@@ -256,6 +252,7 @@ if (ctx) {
pthread_mutex_unlock (&ctx->io_lock);
}
}
return FALSE;
}
#else
#define AIO_CALLSETUP
@@ -289,9 +286,9 @@ static t_bool sim_os_disk_isavailable_raw (FILE *f);
static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable);
static t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec);
static char *HostPathToVhdPath (const char *szHostPath, char *szVhdPath, size_t VhdPathSize);
static char *VhdPathToHostPath (const char *szVhdPath, char *szHostPath, size_t HostPathSize);
static t_offset get_filesystem_size (UNIT *uptr);
struct sim_disk_fmt {
const char *name; /* name */
@@ -425,18 +422,29 @@ return (uptr->flags & DKUF_WRP)? TRUE: FALSE;
t_offset sim_disk_size (UNIT *uptr)
{
t_offset physical_size, filesystem_size;
t_bool saved_quiet = sim_quiet;
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_STD: /* SIMH format */
return sim_fsize_ex (uptr->fileref);
physical_size = sim_fsize_ex (uptr->fileref);
break;
case DKUF_F_VHD: /* VHD format */
return sim_vhd_disk_size (uptr->fileref);
physical_size = sim_vhd_disk_size (uptr->fileref);
break;
case DKUF_F_RAW: /* Raw Physical Disk Access */
return sim_os_disk_size_raw (uptr->fileref);
physical_size = sim_os_disk_size_raw (uptr->fileref);
break;
default:
return (t_offset)-1;
}
sim_quiet = TRUE;
filesystem_size = get_filesystem_size (uptr);
sim_quiet = saved_quiet;
if ((filesystem_size == (t_offset)-1) ||
(filesystem_size < physical_size))
return physical_size;
return filesystem_size;
}
/* Enable asynchronous operation */
@@ -471,7 +479,7 @@ if (ctx->asynch_io) {
}
uptr->a_check_completion = _disk_completion_dispatch;
uptr->a_is_active = _disk_is_active;
uptr->a_cancel = _disk_cancel;
uptr->cancel = _disk_cancel;
return SCPE_OK;
#endif
}
@@ -841,6 +849,452 @@ uptr->disk_ctx = NULL;
return stat;
}
#pragma pack(push,1)
typedef struct _ODS1_HomeBlock
{
uint16 hm1_w_ibmapsize;
uint32 hm1_l_ibmaplbn;
uint16 hm1_w_maxfiles;
uint16 hm1_w_cluster;
uint16 hm1_w_devtype;
uint16 hm1_w_structlev;
#define HM1_C_LEVEL1 0401
#define HM1_C_LEVEL2 0402
uint8 hm1_t_volname[12];
uint8 hm1_b_fill_1[4];
uint16 hm1_w_volowner;
uint16 hm1_w_protect;
uint16 hm1_w_volchar;
uint16 hm1_w_fileprot;
uint8 hm1_b_fill_2[6];
uint8 hm1_b_window;
uint8 hm1_b_extend;
uint8 hm1_b_lru_lim;
uint8 hm1_b_fill_3[11];
uint16 hm1_w_checksum1;
uint8 hm1_t_credate[14];
uint8 hm1_b_fill_4[382];
uint32 hm1_l_serialnum;
uint8 hm1_b_fill_5[12];
uint8 hm1_t_volname2[12];
uint8 hm1_t_ownername[12];
uint8 hm1_t_format[12];
uint8 hm1_t_fill_6[2];
uint16 hm1_w_checksum2;
} ODS1_HomeBlock;
typedef struct _ODS2_HomeBlock
{
uint32 hm2_l_homelbn;
uint32 hm2_l_alhomelbn;
uint32 hm2_l_altidxlbn;
uint8 hm2_b_strucver;
uint8 hm2_b_struclev;
uint16 hm2_w_cluster;
uint16 hm2_w_homevbn;
uint16 hm2_w_alhomevbn;
uint16 hm2_w_altidxvbn;
uint16 hm2_w_ibmapvbn;
uint32 hm2_l_ibmaplbn;
uint32 hm2_l_maxfiles;
uint16 hm2_w_ibmapsize;
uint16 hm2_w_resfiles;
uint16 hm2_w_devtype;
uint16 hm2_w_rvn;
uint16 hm2_w_setcount;
uint16 hm2_w_volchar;
uint32 hm2_l_volowner;
uint32 hm2_l_reserved;
uint16 hm2_w_protect;
uint16 hm2_w_fileprot;
uint16 hm2_w_reserved;
uint16 hm2_w_checksum1;
uint32 hm2_q_credate[2];
uint8 hm2_b_window;
uint8 hm2_b_lru_lim;
uint16 hm2_w_extend;
uint32 hm2_q_retainmin[2];
uint32 hm2_q_retainmax[2];
uint32 hm2_q_revdate[2];
uint8 hm2_r_min_class[20];
uint8 hm2_r_max_class[20];
uint8 hm2_r_reserved[320];
uint32 hm2_l_serialnum;
uint8 hm2_t_strucname[12];
uint8 hm2_t_volname[12];
uint8 hm2_t_ownername[12];
uint8 hm2_t_format[12];
uint16 hm2_w_reserved2;
uint16 hm2_w_checksum2;
} ODS2_HomeBlock;
typedef struct _ODS1_FileHeader
{
uint8 fh1_b_idoffset;
uint8 fh1_b_mpoffset;
uint16 fh1_w_fid_num;
uint16 fh1_w_fid_seq;
uint16 fh1_w_struclev;
uint16 fh1_w_fileowner;
uint16 fh1_w_fileprot;
uint16 fh1_w_filechar;
uint16 fh1_w_recattr;
uint8 fh1_b_fill_1[494];
uint16 fh1_w_checksum;
} ODS1_FileHeader;
typedef struct _ODS2_FileHeader
{
uint8 fh2_b_idoffset;
uint8 fh2_b_mpoffset;
uint8 fh2_b_acoffset;
uint8 fh2_b_rsoffset;
uint16 fh2_w_seg_num;
uint16 fh2_w_structlev;
uint16 fh2_w_fid[3];
uint16 fh2_w_ext_fid[3];
uint16 fh2_w_recattr[16];
uint32 fh2_l_filechar;
uint16 fh2_w_remaining[228];
} ODS2_FileHeader;
typedef union _ODS2_Retreval
{
struct
{
unsigned fm2___fill : 14; /* type specific data */
unsigned fm2_v_format : 2; /* format type code */
} fm2_r_word0_bits;
struct
{
unsigned fm2_v_exact : 1; /* exact placement specified */
unsigned fm2_v_oncyl : 1; /* on cylinder allocation desired */
unsigned fm2___fill : 10;
unsigned fm2_v_lbn : 1; /* use LBN of next map pointer */
unsigned fm2_v_rvn : 1; /* place on specified RVN */
unsigned fm2_v_format0 : 2;
} fm2_r_map_bits0;
struct
{
unsigned fm2_b_count1 : 8; /* low byte described below */
unsigned fm2_v_highlbn1 : 6; /* high order LBN */
unsigned fm2_v_format1 : 2;
unsigned fm2_w_lowlbn1 : 16; /* low order LBN */
} fm2_r_map_bits1;
struct
{
struct
{
unsigned fm2_v_count2 : 14; /* count field */
unsigned fm2_v_format2 : 2;
unsigned fm2_l_lowlbn2 : 16; /* low order LBN */
} fm2_r_map2_long0;
uint16 fm2_l_highlbn2; /* high order LBN */
} fm2_r_map_bits2;
struct
{
struct
{
unsigned fm2_v_highcount3 : 14; /* low order count field */
unsigned fm2_v_format3 : 2;
unsigned fm2_w_lowcount3 : 16; /* high order count field */
} fm2_r_map3_long0;
uint32 fm2_l_lbn3;
} fm2_r_map_bits3;
} ODS2_Retreval;
typedef struct _ODS1_Retreval
{
uint8 fm1_b_ex_segnum;
uint8 fm1_b_ex_rvn;
uint16 fm1_w_ex_filnum;
uint16 fm1_w_ex_filseq;
uint8 fm1_b_countsize;
uint8 fm1_b_lbnsize;
uint8 fm1_b_inuse;
uint8 fm1_b_avail;
union {
struct {
uint8 fm1_b_highlbn;
uint8 fm1_b_count;
uint16 fm1_w_lowlbn;
} fm1_s_fm1def1;
struct {
uint8 fm1_b_highlbn;
uint8 fm1_b_count;
uint16 fm1_w_lowlbn;
} fm1_s_fm1def2;
} fm1_pointers[4];
} ODS1_Retreval;
typedef struct _ODS1_StorageControlBlock
{
uint8 scb_b_unused[3];
uint8 scb_b_bitmapblks;
struct _bitmapblk {
uint16 scb_w_freeblks;
uint16 scb_w_freeptr;
} scb_r_blocks[1];
} ODS1_SCB;
typedef struct _ODS2_StorageControlBlock
{
uint8 scb_b_strucver; /* 1 */
uint8 scb_b_struclev; /* 2 */
uint16 scb_w_cluster;
uint32 scb_l_volsize;
uint32 scb_l_blksize;
uint32 scb_l_sectors;
uint32 scb_l_tracks;
uint32 scb_l_cylinder;
uint32 scb_l_status;
uint32 scb_l_status2;
uint16 scb_w_writecnt;
uint8 scb_t_volockname[12];
uint32 scb_q_mounttime[2];
uint16 scb_w_backrev;
uint32 scb_q_genernum[2];
uint8 scb_b_reserved[446];
uint16 scb_w_checksum;
} ODS2_SCB;
#pragma pack(pop)
static uint16
ODSChecksum (void *Buffer, uint16 WordCount)
{
int i;
uint16 Sum = 0;
uint16 CheckSum = 0;
uint16 *Buf = (uint16 *)Buffer;
for (i=0; i<WordCount; i++)
CheckSum += Buf[i];
return CheckSum;
}
static t_offset get_ods2_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu; /* Make sure we can access the largest sector */
uint32 capac_factor;
ODS2_HomeBlock Home;
ODS2_FileHeader Header;
ODS2_Retreval *Retr;
ODS2_SCB Scb;
uint16 CheckSum1, CheckSum2;
uint32 ScbLbn;
t_offset ret_val = (t_offset)-1;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
return ret_val;
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
saved_capac = uptr->capac;
uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if (sim_disk_rdsect (uptr, 512 / ctx->sector_size, (uint8 *)&Home, NULL, sizeof (Home) / ctx->sector_size))
goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum1)-((char *)&Home.hm2_l_homelbn))/2));
CheckSum2 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum2)-((char *)&Home.hm2_l_homelbn))/2));
if ((Home.hm2_l_homelbn == 0) ||
(Home.hm2_l_alhomelbn == 0) ||
(Home.hm2_l_altidxlbn == 0) ||
((Home.hm2_b_struclev != 2) && (Home.hm2_b_struclev != 5)) ||
(Home.hm2_b_strucver == 0) ||
(Home.hm2_w_cluster == 0) ||
(Home.hm2_w_homevbn == 0) ||
(Home.hm2_w_alhomevbn == 0) ||
(Home.hm2_w_ibmapvbn == 0) ||
(Home.hm2_l_ibmaplbn == 0) ||
(Home.hm2_w_resfiles >= Home.hm2_l_maxfiles) ||
(Home.hm2_w_ibmapsize == 0) ||
(Home.hm2_w_resfiles < 5) ||
(Home.hm2_w_checksum1 != CheckSum1) ||
(Home.hm2_w_checksum2 != CheckSum2))
goto Return_Cleanup;
if (sim_disk_rdsect (uptr, (Home.hm2_l_ibmaplbn+Home.hm2_w_ibmapsize+1) * (512 / ctx->sector_size),
(uint8 *)&Header, NULL, sizeof (Header) / ctx->sector_size))
goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Header, 255);
if (CheckSum1 != *(((uint16 *)&Header)+255)) /* Verify Checksum on BITMAP.SYS file header */
goto Return_Cleanup;
Retr = (ODS2_Retreval *)(((uint16*)(&Header))+Header.fh2_b_mpoffset);
/* The BitMap File has a single extent, which may be preceeded by a placement descriptor */
if (Retr->fm2_r_word0_bits.fm2_v_format == 0)
Retr = (ODS2_Retreval *)(((uint16 *)Retr)+1); /* skip placement descriptor */
switch (Retr->fm2_r_word0_bits.fm2_v_format)
{
case 1:
ScbLbn = (Retr->fm2_r_map_bits1.fm2_v_highlbn1<<16)+Retr->fm2_r_map_bits1.fm2_w_lowlbn1;
break;
case 2:
ScbLbn = (Retr->fm2_r_map_bits2.fm2_l_highlbn2<<16)+Retr->fm2_r_map_bits2.fm2_r_map2_long0.fm2_l_lowlbn2;
break;
case 3:
ScbLbn = Retr->fm2_r_map_bits3.fm2_l_lbn3;
break;
}
Retr = (ODS2_Retreval *)(((uint16 *)Retr)+Retr->fm2_r_word0_bits.fm2_v_format+1);
if (sim_disk_rdsect (uptr, ScbLbn * (512 / ctx->sector_size), (uint8 *)&Scb, NULL, sizeof (Scb) / ctx->sector_size))
goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Scb, 255);
if (CheckSum1 != *(((uint16 *)&Scb)+255)) /* Verify Checksum on Storage Control Block */
goto Return_Cleanup;
if ((Scb.scb_w_cluster != Home.hm2_w_cluster) ||
(Scb.scb_b_strucver != Home.hm2_b_strucver) ||
(Scb.scb_b_struclev != Home.hm2_b_struclev))
goto Return_Cleanup;
if (!sim_quiet) {
sim_printf ("%s%d: '%s' Contains ODS%d File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename, Home.hm2_b_struclev);
sim_printf ("%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm2_t_volname);
sim_printf ("Format: %12.12s ", Home.hm2_t_format);
sim_printf ("Sectors In Volume: %u\n", Scb.scb_l_volsize);
}
ret_val = ((t_offset)Scb.scb_l_volsize) * 512;
Return_Cleanup:
uptr->capac = saved_capac;
return ret_val;
}
static t_offset get_ods1_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu; /* Make sure we can access the largest sector */
uint32 capac_factor;
ODS1_HomeBlock Home;
ODS1_FileHeader Header;
ODS1_Retreval *Retr;
uint8 scb_buf[512];
ODS1_SCB *Scb = (ODS1_SCB *)scb_buf;
uint16 CheckSum1, CheckSum2;
uint32 ScbLbn;
t_offset ret_val = (t_offset)-1;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
return ret_val;
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
saved_capac = uptr->capac;
uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if (sim_disk_rdsect (uptr, 512 / ctx->sector_size, (uint8 *)&Home, NULL, sizeof (Home) / ctx->sector_size))
goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm1_w_checksum1)-((char *)&Home.hm1_w_ibmapsize))/2));
CheckSum2 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm1_w_checksum2)-((char *)&Home.hm1_w_ibmapsize))/2));
if ((Home.hm1_w_ibmapsize == 0) ||
(Home.hm1_l_ibmaplbn == 0) ||
(Home.hm1_w_maxfiles == 0) ||
(Home.hm1_w_cluster != 1) ||
((Home.hm1_w_structlev != HM1_C_LEVEL1) && (Home.hm1_w_structlev != HM1_C_LEVEL2)) ||
(Home.hm1_l_ibmaplbn == 0) ||
(Home.hm1_w_checksum1 != CheckSum1) ||
(Home.hm1_w_checksum2 != CheckSum2))
goto Return_Cleanup;
if (sim_disk_rdsect (uptr, (((Home.hm1_l_ibmaplbn << 16) + ((Home.hm1_l_ibmaplbn >> 16) & 0xFFFF)) + Home.hm1_w_ibmapsize + 1) * (512 / ctx->sector_size),
(uint8 *)&Header, NULL, sizeof (Header) / ctx->sector_size))
goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Header, 255);
if (CheckSum1 != *(((uint16 *)&Header)+255)) /* Verify Checksum on BITMAP.SYS file header */
goto Return_Cleanup;
Retr = (ODS1_Retreval *)(((uint16*)(&Header))+Header.fh1_b_mpoffset);
ScbLbn = (Retr->fm1_pointers[0].fm1_s_fm1def1.fm1_b_highlbn<<16)+Retr->fm1_pointers[0].fm1_s_fm1def1.fm1_w_lowlbn;
if (sim_disk_rdsect (uptr, ScbLbn * (512 / ctx->sector_size), (uint8 *)Scb, NULL, 512 / ctx->sector_size))
goto Return_Cleanup;
if (Scb->scb_b_bitmapblks < 127)
ret_val = (((t_offset)Scb->scb_r_blocks[Scb->scb_b_bitmapblks].scb_w_freeblks << 16) + Scb->scb_r_blocks[Scb->scb_b_bitmapblks].scb_w_freeptr) * 512;
else
ret_val = (((t_offset)Scb->scb_r_blocks[0].scb_w_freeblks << 16) + Scb->scb_r_blocks[0].scb_w_freeptr) * 512;
if (!sim_quiet) {
sim_printf ("%s%d: '%s' Contains an ODS1 File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_printf ("%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm1_t_volname);
sim_printf ("Format: %12.12s ", Home.hm1_t_format);
sim_printf ("Sectors In Volume: %u\n", (uint32)(ret_val / 512));
}
Return_Cleanup:
uptr->capac = saved_capac;
return ret_val;
}
typedef struct ultrix_disklabel {
uint32 pt_magic; /* magic no. indicating part. info exits */
uint32 pt_valid; /* set by driver if pt is current */
struct pt_info {
uint32 pi_nblocks; /* no. of sectors */
uint32 pi_blkoff; /* block offset for start */
} pt_part[8];
} ultrix_disklabel;
#define PT_MAGIC 0x032957 /* Partition magic number */
#define PT_VALID 1 /* Indicates if struct is valid */
static t_offset get_ultrix_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu; /* Make sure we can access the largest sector */
uint32 capac_factor;
uint8 sector_buf[512];
ultrix_disklabel *Label = (ultrix_disklabel *)(sector_buf + sizeof (sector_buf) - sizeof (ultrix_disklabel));
t_offset ret_val = (t_offset)-1;
int i;
uint32 max_lbn = 0, max_lbn_partnum = 0;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
return ret_val;
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
saved_capac = uptr->capac;
uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if (sim_disk_rdsect (uptr, 31 * (512 / ctx->sector_size), sector_buf, NULL, 512 / ctx->sector_size))
goto Return_Cleanup;
if ((Label->pt_magic != PT_MAGIC) ||
(Label->pt_valid != PT_VALID))
goto Return_Cleanup;
for (i = 0; i < 8; i++) {
uint32 end_lbn = Label->pt_part[i].pi_blkoff + Label->pt_part[i].pi_nblocks;
if (end_lbn > max_lbn) {
max_lbn = end_lbn;
max_lbn_partnum = i;
}
}
if (!sim_quiet) {
sim_printf ("%s%d: '%s' Contains Ultrix partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_printf ("Partition with highest sector: %c, Sectors On Disk: %u\n", 'a' + max_lbn_partnum, max_lbn);
}
ret_val = ((t_offset)max_lbn) * 512;
Return_Cleanup:
uptr->capac = saved_capac;
return ret_val;
}
typedef t_offset (*FILESYSTEM_CHECK)(UNIT *uptr);
static t_offset get_filesystem_size (UNIT *uptr)
{
static FILESYSTEM_CHECK checks[] = {
&get_ods2_filesystem_size,
&get_ods1_filesystem_size,
&get_ultrix_filesystem_size,
NULL
};
t_offset ret_val;
int i;
for (i = 0; checks[i] != NULL; i++) {
ret_val = checks[i] (uptr);
if (ret_val != (t_offset)-1)
break;
}
return ret_val;
}
t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize,
uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay)
@@ -854,7 +1308,7 @@ t_offset (*size_function)(FILE *file);
t_stat (*storage_function)(FILE *file, uint32 *sector_size, uint32 *removable) = NULL;
t_bool created = FALSE, copied = FALSE;
t_bool auto_format = FALSE;
t_offset capac;
t_offset capac, filesystem_capac;
if (uptr->flags & UNIT_DIS) /* disabled? */
return SCPE_UDIS;
@@ -1044,6 +1498,8 @@ else
switch (DK_GET_FMT (uptr)) { /* case on format */
case DKUF_F_STD: /* SIMH format */
if (NULL == (uptr->fileref = sim_vhd_disk_open (cptr, "rb"))) {
if (errno == EBADF) /* VHD but broken */
return SCPE_OPENERR;
open_function = sim_fopen;
size_function = sim_fsize_ex;
break;
@@ -1139,7 +1595,7 @@ if (storage_function)
if ((created) && (!copied)) {
t_stat r = SCPE_OK;
uint8 *secbuf = (uint8 *)calloc (1, ctx->sector_size); /* alloc temp sector buf */
uint8 *secbuf = (uint8 *)calloc (128, ctx->sector_size); /* alloc temp sector buf */
/*
On a newly created disk, we write a zero sector to the last and the
@@ -1154,10 +1610,16 @@ if ((created) && (!copied)) {
*/
if (secbuf == NULL)
r = SCPE_MEM;
if (r == SCPE_OK)
r = sim_disk_wrsect (uptr, (t_lba)(((((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)) - ctx->sector_size)/ctx->sector_size), secbuf, NULL, 1); /* Write Last Sector */
if (r == SCPE_OK)
r = sim_disk_wrsect (uptr, (t_lba)(0), secbuf, NULL, 1); /* Write First Sector */
if (r == SCPE_OK) { /* Write all blocks */
t_lba lba;
t_lba total_lbas = (t_lba)((((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))/ctx->sector_size);
for (lba = 0; (r == SCPE_OK) && (lba < total_lbas); lba += 128) {
t_seccnt sectors = ((lba + 128) <= total_lbas) ? 128 : total_lbas - lba;
r = sim_disk_wrsect (uptr, lba, secbuf, NULL, sectors);
}
}
free (secbuf);
if (r != SCPE_OK) {
sim_disk_detach (uptr); /* report error now */
@@ -1198,9 +1660,10 @@ if ((created) && (!copied)) {
}
if (!sim_quiet)
sim_printf ("%s%d: Initialized To Sector Address %dMB. 100%% complete.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000));
free (init_buf);
}
if (pdp11tracksize)
sim_disk_pdp11_bad_block (uptr, pdp11tracksize);
sim_disk_pdp11_bad_block (uptr, pdp11tracksize, sector_size/sizeof(uint16));
}
if (sim_switches & SWMASK ('K')) {
@@ -1254,22 +1717,42 @@ if (sim_switches & SWMASK ('K')) {
uptr->dynflags |= UNIT_DISK_CHK;
}
filesystem_capac = get_filesystem_size (uptr);
capac = size_function (uptr->fileref);
if (capac && (capac != (t_offset)-1)) {
if (dontautosize) {
t_addr saved_capac = uptr->capac;
if ((filesystem_capac != (t_offset)-1) &&
(filesystem_capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)))) {
if (!sim_quiet) {
uptr->capac = (t_addr)(filesystem_capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
sim_printf ("%s%d: The file system on the disk %s is larger than simulated device (%s > ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr));
uptr->capac = saved_capac;
sim_printf ("%s)\n", sprint_capac (dptr, uptr));
}
sim_disk_detach (uptr);
return SCPE_OPENERR;
}
if ((capac < (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) && (DKUF_F_STD != DK_GET_FMT (uptr))) {
if (!sim_quiet) {
sim_printf ("%s%d: non expandable disk %s is smaller than simulated device (", sim_dname (dptr), (int)(uptr-dptr->units), cptr);
sim_print_val ((t_addr)(capac/ctx->capac_factor), 10, T_ADDR_W, PV_LEFT);
sim_printf ("%s < ", (ctx->capac_factor == 2) ? "W" : "");
sim_print_val (uptr->capac*((dptr->flags & DEV_SECTORS) ? 512 : 1), 10, T_ADDR_W, PV_LEFT);
sim_printf ("%s)\n", (ctx->capac_factor == 2) ? "W" : "");
uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
sim_printf ("%s%d: non expandable disk %s is smaller than simulated device (%s < ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr));
uptr->capac = saved_capac;
sim_printf ("%s)\n", sprint_capac (dptr, uptr));
}
sim_disk_detach (uptr);
return SCPE_OPENERR;
}
}
else
if ((capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) || (DKUF_F_STD != DK_GET_FMT (uptr)))
else {
if ((filesystem_capac != (t_offset)-1) &&
(filesystem_capac > capac))
capac = filesystem_capac;
if ((capac != (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) ||
(DKUF_F_STD != DK_GET_FMT (uptr)))
uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
}
}
#if defined (SIM_ASYNCH_IO)
@@ -1396,6 +1879,7 @@ fprintf (st, " disk)\n");
fprintf (st, " -M Merge a Differencing VHD into its parent VHD disk\n");
fprintf (st, " -O Override consistency checks when attaching differencing disks\n");
fprintf (st, " which have unexpected parent disk GUID or timestamps\n\n");
fprintf (st, " -U Fix inconsistencies which are overridden by the -O switch\n");
fprintf (st, " -Y Answer Yes to prompt to overwrite last track (on disk create)\n");
fprintf (st, " -N Answer No to prompt to overwrite last track (on disk create)\n");
fprintf (st, "Examples:\n");
@@ -1528,20 +2012,21 @@ return SCPE_OK;
Inputs:
uptr = pointer to unit
sec = number of sectors per surface
wds = number of words per sector
Outputs:
sta = status code
*/
static t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec)
t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
int32 i;
t_addr da;
int32 wds = ctx->sector_size/sizeof (uint16);
uint16 *buf;
DEVICE *dptr;
char *namebuf, *c;
uint32 packid;
t_stat stat = SCPE_OK;
if ((sec < 2) || (wds < 16))
return SCPE_ARG;
@@ -1551,8 +2036,6 @@ if ((dptr = find_dev_from_unit (uptr)) == NULL)
return SCPE_NOATT;
if (uptr->flags & UNIT_RO)
return SCPE_RO;
if (ctx->capac_factor != 2) /* Must be Word oriented Capacity */
return SCPE_IERR;
if (!get_yn ("Overwrite last track? [N]", FALSE))
return SCPE_OK;
if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL)
@@ -1571,24 +2054,30 @@ buf[2] = buf[3] = 0;
for (i = 4; i < wds; i++)
buf[i] = 0177777u;
da = (uptr->capac*((dptr->flags & DEV_SECTORS) ? 512 : 1)) - (sec * wds);
for (i = 0; (i < sec) && (i < 10); i++, da += wds)
if (sim_disk_wrsect (uptr, (t_lba)(da/wds), (uint8 *)buf, NULL, 1)) {
free (buf);
return SCPE_IOERR;
for (i = 0; (stat == SCPE_OK) && (i < sec) && (i < 10); i++, da += wds)
if (ctx)
stat = sim_disk_wrsect (uptr, (t_lba)(da/wds), (uint8 *)buf, NULL, 1);
else {
if (sim_fseek (uptr->fileref, da, SEEK_SET)) {
stat = SCPE_IOERR;
break;
}
if (wds != sim_fwrite (buf, sizeof (uint16), wds, uptr->fileref))
stat = SCPE_IOERR;
}
free (buf);
return SCPE_OK;
return stat;
}
void sim_disk_data_trace(UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
DEVICE *dptr = find_dev_from_unit (uptr);
if (sim_deb && (ctx->dptr->dctrl & reason)) {
if (sim_deb && (dptr->dctrl & reason)) {
char pos[32];
sprintf (pos, "lbn: %08X ", (unsigned int)lba);
sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), pos, len, txt, reason);
sim_data_trace(dptr, uptr, (detail ? data : NULL), pos, len, txt, reason);
}
}
@@ -1674,9 +2163,18 @@ errno = EINVAL;
#else
#include <winioctl.h>
#endif
#if defined(__cplusplus)
extern "C" {
#endif
WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize);
#if defined(__cplusplus)
}
#endif
struct _device_type {
int32 Type;
char *desc;
const char *desc;
} DeviceTypes[] = {
{FILE_DEVICE_8042_PORT, "8042_PORT"},
{FILE_DEVICE_ACPI, "ACPI"},
@@ -1821,7 +2319,6 @@ static t_offset sim_os_disk_size_raw (FILE *Disk)
{
DWORD IoctlReturnSize;
LARGE_INTEGER Size;
WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize);
if (GetFileSizeEx((HANDLE)Disk, &Size))
return (t_offset)(Size.QuadPart);
@@ -2872,29 +3369,47 @@ if ((sDynamic) &&
if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ru", 4)) {
const char *c;
if ((c = strrchr (szVHDPath, '\\')))
memcpy (CheckPath, szVHDPath, c-szVHDPath+1);
strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1));
if ((c = strrchr (szVHDPath, '\\'))) {
memcpy (CheckPath, szVHDPath, c-szVHDPath+1);
strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1));
}
}
VhdPathToHostPath (CheckPath, CheckPath, sizeof (CheckPath));
if ((0 == GetVHDFooter(CheckPath,
&sParentFooter,
NULL,
NULL,
&ParentModificationTime,
NULL,
0)) &&
(0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) &&
((sDynamic->ParentTimeStamp == ParentModificationTime) ||
((NtoHl(sDynamic->ParentTimeStamp)-NtoHl(ParentModificationTime)) == 3600) ||
(sim_switches & SWMASK ('O')))) {
strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize);
if (0 == GetVHDFooter(CheckPath,
&sParentFooter,
NULL,
NULL,
&ParentModificationTime,
NULL,
0)) {
if ((0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) &&
((sDynamic->ParentTimeStamp == ParentModificationTime) ||
((NtoHl(sDynamic->ParentTimeStamp)-NtoHl(ParentModificationTime)) == 3600) ||
(sim_switches & SWMASK ('O'))))
strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize);
else {
if (0 != memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID)))
sim_printf ("Error Invalid Parent VHD '%s' for Differencing VHD: %s\n", CheckPath, szVHDPath);
else
sim_printf ("Error Parent VHD '%s' has been modified since Differencing VHD: %s was created\n", CheckPath, szVHDPath);
Return = EINVAL; /* File Corrupt/Invalid */
}
break;
}
else {
struct stat statb;
if (0 == stat (CheckPath, &statb)) {
sim_printf ("Parent VHD '%s' corrupt for Differencing VHD: %s\n", CheckPath, szVHDPath);
Return = EBADF; /* File Corrupt/Invalid */
break;
}
}
}
if (!*szParentVHDPath) {
Return = EINVAL; /* File Corrupt */
sim_printf ("Error Invalid Parent VHD for Differencing VHD\n");
if (Return != EINVAL) /* File Not Corrupt? */
sim_printf ("Missing Parent VHD for Differencing VHD: %s\n", szVHDPath);
Return = EBADF;
}
}
}
@@ -2985,6 +3500,7 @@ return (char *)(&hVHD->Footer.DriveType[0]);
static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess)
{
VHDHANDLE hVHD = (VHDHANDLE) calloc (1, sizeof(*hVHD));
int NeedUpdate = FALSE;
int Status;
if (!hVHD)
@@ -3017,9 +3533,22 @@ static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess
0);
if (Status)
goto Cleanup_Return;
if (ParentModifiedTimeStamp != hVHD->Dynamic.ParentTimeStamp) {
Status = EBADF;
goto Cleanup_Return;
if ((0 != memcmp (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (ParentFooter.UniqueID))) ||
(ParentModifiedTimeStamp != hVHD->Dynamic.ParentTimeStamp)) {
if (sim_switches & SWMASK ('O')) { /* OVERRIDE consistency checks? */
if ((sim_switches & SWMASK ('U')) && /* FIX (UPDATE) consistency checks AND */
(strchr (DesiredAccess, '+'))) { /* open for write/update? */
memcpy (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (ParentFooter.UniqueID));
hVHD->Dynamic.ParentTimeStamp = ParentModifiedTimeStamp;
hVHD->Dynamic.Checksum = 0;
hVHD->Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Dynamic, sizeof(hVHD->Dynamic)));
NeedUpdate = TRUE;
}
}
else {
Status = EBADF;
goto Cleanup_Return;
}
}
}
if (hVHD->Footer.SavedState) {
@@ -3036,6 +3565,18 @@ Cleanup_Return:
sim_vhd_disk_close ((FILE *)hVHD);
hVHD = NULL;
}
else {
if (NeedUpdate) { /* Update Differencing Disk Header? */
if (WriteFilePosition(hVHD->File,
&hVHD->Dynamic,
sizeof (hVHD->Dynamic),
NULL,
NtoHll (hVHD->Footer.DataOffset))) {
sim_vhd_disk_close ((FILE *)hVHD);
hVHD = NULL;
}
}
}
errno = Status;
return (FILE *)hVHD;
}
@@ -3452,7 +3993,7 @@ if ((szFileSpec[0] != '/') || (strchr (szFileSpec, ':')))
else
strncpy (szFullFileSpecBuffer, szFileSpec, BufferSize);
if ((c = strstr (szFullFileSpecBuffer, "]/")))
memcpy (c+1, c+2, strlen(c+2)+1);
memmove (c+1, c+2, strlen(c+2)+1);
memset (szFullFileSpecBuffer + strlen (szFullFileSpecBuffer), 0, BufferSize - strlen (szFullFileSpecBuffer));
#endif
}
@@ -3480,14 +4021,14 @@ if ((c = strrchr (szVhdPath, ']'))) {
while ((c = strchr (szVhdPath, '/')))
*c = '\\';
for (c = strstr (szVhdPath, "\\.\\"); c; c = strstr (szVhdPath, "\\.\\"))
memcpy (c, c+2, strlen(c+2)+1);
memmove (c, c+2, strlen(c+2)+1);
for (c = strstr (szVhdPath, "\\\\"); c; c = strstr (szVhdPath, "\\\\"))
memcpy (c, c+1, strlen(c+1)+1);
memmove (c, c+1, strlen(c+1)+1);
while ((c = strstr (szVhdPath, "\\..\\"))) {
*c = '\0';
d = strrchr (szVhdPath, '\\');
if (d)
memcpy (d, c+3, strlen(c+3)+1);
memmove (d, c+3, strlen(c+3)+1);
else
return d;
}