diff --git a/README.md b/README.md index af1a664f..a987d397 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,8 @@ Host platforms which have libSDL available can leverage this functionality. #### Disk Extensions RAW Disk Access (including CDROM) Virtual Disk Container files, including differencing disks + File System type detection to accurately autosize disks. + Recognized file systems are: DEC ODS1, DEC ODS2, DEC RT11, Ultrix Partitions #### Tape Extensions AWS format tape support diff --git a/sim_disk.c b/sim_disk.c index 069e218b..3b022685 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -1304,6 +1304,204 @@ uptr->capac = saved_capac; return ret_val; } +#pragma pack(push,1) +typedef struct _RT11_HomeBlock { + uint8 hb_b_bbtable[130]; + uint8 hb_b_unused1[2]; + uint8 hb_b_initrestore[38]; + uint8 hb_b_bup[18]; + uint8 hb_b_unused2[260]; + uint16 hb_w_reserved1; + uint16 hb_w_reserved2; + uint8 hb_b_unused3[14]; + uint16 hb_w_clustersize; + uint16 hb_w_firstdir; + uint16 hb_w_sysver; +#define HB_C_SYSVER_V3A 36521 +#define HB_C_SYSVER_V04 36434 +#define HB_C_SYSVER_V05 36435 + uint8 hb_b_volid[12]; + uint8 hb_b_owner[12]; + uint8 hb_b_sysid[12]; +#define HB_C_SYSID "DECRT11A " + uint8 hb_b_unused4[2]; + uint16 hb_w_checksum; + } RT11_HomeBlock; + +typedef struct _RT11_DirHeader { + uint16 dh_w_count; + uint16 dh_w_next; + uint16 dh_w_highest; +#define DH_C_MAXSEG 31 + uint16 dh_w_extra; + uint16 dh_w_start; + } RT11_DirHeader; + +typedef struct _RT11_DirEntry { + uint16 de_w_status; +#define DE_C_PRE 0000020 +#define DE_C_TENT 0000400 +#define DE_C_EMPTY 0001000 +#define DE_C_PERM 0002000 +#define DE_C_EOS 0004000 +#define DE_C_READ 0040000 +#define DE_C_PROT 0100000 + uint16 de_w_fname1; + uint16 de_w_fname2; + uint16 de_w_ftype; + uint16 de_w_length; + uint16 de_w_jobchannel; + uint16 de_w_creationdate; + } RT11_DirEntry; +#pragma pack(pop) + +#define RT11_MAXPARTITIONS 256 /* Max partitions supported */ +#define RT11_HOME 1 /* Home block # */ + +#define RT11_NOPART 0 +#define RT11_SINGLEPART 1 +#define RT11_MULTIPART 2 + +static int rt11_get_partition_type(RT11_HomeBlock *home, int part) +{ +if (strncmp((char *)&home->hb_b_sysid, HB_C_SYSID, strlen(HB_C_SYSID)) == 0) { + uint16 type = home->hb_w_sysver; + + if (part == 0) { + if ((type == HB_C_SYSVER_V3A) || (type == HB_C_SYSVER_V04)) + return RT11_SINGLEPART; + } + + if (type == HB_C_SYSVER_V05) + return RT11_MULTIPART; + } +return RT11_NOPART; +} + +static t_offset get_rt11_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; +uint32 capac_factor; +uint8 sector_buf[1024]; +RT11_HomeBlock Home; +RT11_DirHeader *dir_hdr = (RT11_DirHeader *)sector_buf; +int partitions = 0; +int part; +uint32 base; +uint32 dir_sec; +uint16 dir_seg; +uint16 version; +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; +saved_capac = uptr->capac; +uptr->capac = (t_addr)(temp_capac / (capac_factor * ((dptr->flags & DEV_SECTORS) ? 512 : 1))); + +for (part = 0; part < RT11_MAXPARTITIONS; part++) { + uint16 seg_highest; + int type; + + base = part << 16; + + if (sim_disk_rdsect(uptr, (base + RT11_HOME) * (512 / ctx->sector_size), (uint8 *)&Home, NULL, 512 / ctx->sector_size)) + goto Return_Cleanup; + + type = rt11_get_partition_type(&Home, part); + + if (type != RT11_NOPART) { + uint16 highest = 0; + uint8 seg_seen[DH_C_MAXSEG + 1]; + + memset(seg_seen, 0, sizeof(seg_seen)); + + partitions++; + + dir_seg = 1; + do { + int offset = sizeof(RT11_DirHeader); + int dir_size = sizeof(RT11_DirEntry); + uint16 cur_blk; + + if (seg_seen[dir_seg]++ != 0) + goto Next_Partition; + + dir_sec = Home.hb_w_firstdir + ((dir_seg - 1) * 2); + + if (sim_disk_rdsect(uptr, (base + dir_sec) * (512 / ctx->sector_size), sector_buf, NULL, 1024 / ctx->sector_size)) + goto Return_Cleanup; + + if (dir_seg == 1) { + seg_highest = dir_hdr->dh_w_highest; + if (seg_highest > DH_C_MAXSEG) + goto Next_Partition; + } + dir_size += dir_hdr->dh_w_extra; + cur_blk = dir_hdr->dh_w_start; + + while ((1024 - offset) >= dir_size) { + RT11_DirEntry *dir_entry = (RT11_DirEntry *)§or_buf[offset]; + + if (dir_entry->de_w_status & DE_C_EOS) + break; + + /* + * Within each directory segment the bas address should never + * decrease. + */ + if (((cur_blk + dir_entry->de_w_length) & 0xFFFF) < cur_blk) + goto Next_Partition; + + cur_blk += dir_entry->de_w_length; + offset += dir_size; + } + if (cur_blk > highest) + highest = cur_blk; + dir_seg = dir_hdr->dh_w_next; + + if (dir_seg > seg_highest) + goto Next_Partition; + } while (dir_seg != 0); + + ret_val = (t_offset)((base + highest) * 512); + version = Home.hb_w_sysver; + + if (type == RT11_SINGLEPART) + break; + } +Next_Partition: + } + +Return_Cleanup: +if (partitions) { + if (!sim_quiet) { + char *parttype = "???"; + + switch (version) { + case HB_C_SYSVER_V3A: + parttype = "V3A"; + break; + + case HB_C_SYSVER_V04: + parttype = "V04"; + break; + + case HB_C_SYSVER_V05: + parttype = "V05"; + break; + } + sim_printf ("%s%d: '%s' Contains RT11 partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename); + sim_printf ("%d valid partition%s, Type: %s, Sectors On Disk: %u\n", partitions, partitions == 1 ? "" : "s", parttype, (uint32)(ret_val / 512)); + } + } +uptr->capac = saved_capac; +return ret_val; +}; + typedef t_offset (*FILESYSTEM_CHECK)(UNIT *uptr); static t_offset get_filesystem_size (UNIT *uptr) @@ -1312,6 +1510,11 @@ static FILESYSTEM_CHECK checks[] = { &get_ods2_filesystem_size, &get_ods1_filesystem_size, &get_ultrix_filesystem_size, + &get_rt11_filesystem_size, /* This should be the last entry + in the table to reduce the + possibility of matching an RT-11 + container file stored in another + filesystem */ NULL }; t_offset ret_val;