diff --git a/scp.c b/scp.c index b012726c..3b831c07 100644 --- a/scp.c +++ b/scp.c @@ -4420,12 +4420,13 @@ if (toks || (flag < 0) || (flag > 1)) return SCPE_OK; } -void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr) +const char *sprint_capac (DEVICE *dptr, UNIT *uptr) { +static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8]; t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000; t_addr mval; t_addr psize = uptr->capac; -char scale, width; +char *scale, *width; if (sim_switches & SWMASK ('B')) kval = 1024; @@ -4435,23 +4436,27 @@ if (dptr->flags & DEV_SECTORS) { mval = mval / 512; } if ((dptr->dwidth / dptr->aincr) > 8) - width = 'W'; -else width = 'B'; + width = "W"; +else + width = "B"; if (uptr->capac < (kval * 10)) - scale = 0; + scale = ""; else if (uptr->capac < (mval * 10)) { - scale = 'K'; + scale = "K"; psize = psize / kval; } else { - scale = 'M'; + scale = "M"; psize = psize / mval; } -fprint_val (st, (t_value) psize, 10, T_ADDR_W, PV_LEFT); -if (scale) - fputc (scale, st); -fputc (width, st); -return; +sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT); +sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width); +return capac_buf; +} + +void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr) +{ +fprintf (st, "%s", sprint_capac (dptr, uptr)); } /* Show processors */ diff --git a/scp.h b/scp.h index 3d0b1850..2a914446 100644 --- a/scp.h +++ b/scp.h @@ -169,6 +169,7 @@ t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt t_stat sprint_val (char *buf, t_value val, uint32 rdx, uint32 wid, uint32 fmt); t_stat sim_print_val (t_value val, uint32 radix, uint32 width, uint32 format); const char *sim_fmt_secs (double seconds); +const char *sprint_capac (DEVICE *dptr, UNIT *uptr); char *read_line (char *cptr, int32 size, FILE *stream); void fprint_reg_help (FILE *st, DEVICE *dptr); void fprint_set_help (FILE *st, DEVICE *dptr); diff --git a/sim_disk.c b/sim_disk.c index a4c7e09a..6c3e67ee 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -837,6 +837,230 @@ uptr->disk_ctx = NULL; return stat; } +#pragma pack(push,1) +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 _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 _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 +ODS2Checksum (void *Buffer, uint16 WordCount) + { + int i; + uint16 Sum = 0; + uint16 CheckSum = 0; + uint16 *Buf = (uint16 *)Buffer; + + for (i=0; idwidth / 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, 1, (uint8 *)&Home, NULL, 1)) + goto Return_Cleanup; +CheckSum1 = ODS2Checksum (&Home, (uint16)((((char *)&Home.hm2$w_checksum1)-((char *)&Home.hm2$l_homelbn))/2)); +CheckSum2 = ODS2Checksum (&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, (uint8 *)&Header, NULL, 1)) + goto Return_Cleanup; +CheckSum1 = ODS2Checksum (&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, (uint8 *)&Scb, NULL, 1)) + goto Return_Cleanup; +CheckSum1 = ODS2Checksum (&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' Found containing 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 ("SectorsInVolume: %d\n", Scb.scb$l_volsize); + } +ret_val = ((t_offset)Scb.scb$l_volsize) * 512; + +Return_Cleanup: +uptr->capac = saved_capac; +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) @@ -850,7 +1074,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; @@ -1252,22 +1476,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)