Skip to content

Commit

Permalink
Merge pull request joncampbell123#5172 from maron2000/fix_imgmake_option
Browse files Browse the repository at this point in the history
Fix regression -spc, -rootdir options were ignored for floppy image made by IMGMAKE command
  • Loading branch information
joncampbell123 authored Aug 14, 2024
2 parents d37f4c6 + f0315d7 commit 23be2fb
Showing 1 changed file with 60 additions and 72 deletions.
132 changes: 60 additions & 72 deletions src/dos/dos_programs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3522,8 +3522,8 @@ class IMGMAKE : public Program {
std::string tmp;

int lbamode = -1;
unsigned int c, h, s, sectors;
uint64_t size = 0;
uint32_t c, h, s;
uint64_t size = 0, sectors;

if(control->SecureMode()) {
WriteOut(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW"));
Expand Down Expand Up @@ -3639,37 +3639,39 @@ class IMGMAKE : public Program {

uint8_t mediadesc = 0xF8; // media descriptor byte; also used to differ fd and hd
uint16_t root_ent = 512; // FAT root directory entries: 512 is for harddisks
uint16_t disksize = 0;
uint16_t disksize = 0; // disk size of floppy images
uint32_t sect_per_fat=0; // allowable range: FAT12 1-12, FAT16 16-256, FAT32 512-2,097,152 sectors
uint16_t sectors_per_cluster = 0; // max limit: 128
bool is_fd = false;
if(disktype=="fd_160") {
c = 40; h = 1; s = 8; mediadesc = 0xFE; root_ent = 64;
c = 40; h = 1; s = 8; mediadesc = 0xFE; root_ent = 64; sect_per_fat = 1; sectors_per_cluster = 1;
disksize = 160; is_fd = true;
} else if(disktype=="fd_180") {
c = 40; h = 1; s = 9; mediadesc = 0xFC; root_ent = 64;
c = 40; h = 1; s = 9; mediadesc = 0xFC; root_ent = 64; sect_per_fat = 2; sectors_per_cluster = 1;
disksize = 180; is_fd = true;
} else if(disktype=="fd_200") {
c = 40; h = 1; s = 10; mediadesc = 0xFC; root_ent = 64; // root_ent?
c = 40; h = 1; s = 10; mediadesc = 0xFC; root_ent = 64; sect_per_fat = 2; sectors_per_cluster = 2;// root_ent?
disksize = 200; is_fd = true;
} else if(disktype=="fd_320") {
c = 40; h = 2; s = 8; mediadesc = 0xFF; root_ent = 112;
c = 40; h = 2; s = 8; mediadesc = 0xFF; root_ent = 112; sect_per_fat = 1; sectors_per_cluster = 2;
disksize = 320; is_fd = true;
} else if(disktype=="fd_360") {
c = 40; h = 2; s = 9; mediadesc = 0xFD; root_ent = 112;
c = 40; h = 2; s = 9; mediadesc = 0xFD; root_ent = 112; sect_per_fat = 2; sectors_per_cluster = 2;
disksize = 360; is_fd = true;
} else if(disktype=="fd_400") {
c = 40; h = 2; s = 10; mediadesc = 0xFD; root_ent = 112;
c = 40; h = 2; s = 10; mediadesc = 0xFD; root_ent = 112; sect_per_fat = 2; sectors_per_cluster = 2;
disksize = 400; is_fd = true;
} else if(disktype=="fd_720") {
c = 80; h = 2; s = 9; mediadesc = 0xF9; root_ent = 112;
c = 80; h = 2; s = 9; mediadesc = 0xF9; root_ent = 112; sect_per_fat = 3; sectors_per_cluster = 2;
disksize = 720; is_fd = true;
} else if(disktype=="fd_1200") {
c = 80; h = 2; s = 15; mediadesc = 0xF9; root_ent = 224;
c = 80; h = 2; s = 15; mediadesc = 0xF9; root_ent = 224; sect_per_fat = 7; sectors_per_cluster = 1;
disksize = 1200; is_fd = true;
} else if(disktype=="fd_1440"||disktype=="fd"||disktype=="floppy") {
c = 80; h = 2; s = 18; mediadesc = 0xF0; root_ent = 224;
c = 80; h = 2; s = 18; mediadesc = 0xF0; root_ent = 224; sect_per_fat = 9; sectors_per_cluster = 1;
disksize = 1440; is_fd = true;
} else if(disktype=="fd_2880") {
c = 80; h = 2; s = 36; mediadesc = 0xF0; root_ent = 240;
c = 80; h = 2; s = 36; mediadesc = 0xF0; root_ent = 240; sect_per_fat = 9; sectors_per_cluster = 2;
disksize = 2880; is_fd = true;
} else if(disktype=="hd_250") {
c = 489; h = 16; s = 63;
Expand Down Expand Up @@ -3708,8 +3710,8 @@ class IMGMAKE : public Program {
printHelp();
return;
}
size = (unsigned long long)c * (unsigned long long)h * (unsigned long long)s * 512ULL;
if((size < 3u*1024u*1024u) || (size > 0x1FFFFFFFFLL)/*8GB*/) {
size = (uint64_t)c * (uint64_t)h * (uint64_t)s * 512ULL;
if((size < 3*1024*1024ull) || (size > 0x1FFFFFFFFull)/*8GB*/) {
// user picked geometry resulting in wrong size
WriteOut(MSG_Get("PROGRAM_IMGMAKE_BADSIZE"));
return;
Expand All @@ -3722,20 +3724,20 @@ class IMGMAKE : public Program {
size *= 1024*1024LL; // size in megabytes
// low limit: 3 megs, high limit: 2 terabytes
// Int13 limit would be 8 gigs
if((size < 3*1024*1024LL) || (size > 0x1FFFFFFFFFFLL)/*2TB*/) {
if((size < 3*1024*1024ull) || (size > 0x1FFFFFFFFFFull)/*2TB*/) {
// wrong size
WriteOut(MSG_Get("PROGRAM_IMGMAKE_BADSIZE"));
return;
}
if(disktype == "vhd" && size > 2190433320960) {/*2040GB*/
if(disktype == "vhd" && size > 2040*1024*1024*1024ull) {/*2040GB*/
// wrong size
WriteOut(MSG_Get("PROGRAM_IMGMAKE_BADSIZE"));
return;
}
sectors = (unsigned int)(size / 512);
sectors = size / 512;

// Now that we finally have the proper size, figure out good CHS values
if (size > 0xFFFFFFFFLL/*4GB*/) {
if (size > 0xFFFFFFFFull/*4GB*/) {
/* beyond that point it's easier to just map like LBA and be done with it */
h=255;
s=63;
Expand Down Expand Up @@ -3763,8 +3765,8 @@ class IMGMAKE : public Program {
t2 = "-bat";
}

size = (unsigned long long)c * (unsigned long long)h * (unsigned long long)s * 512ULL;
Bits bootsect_pos = 0; // offset of the boot sector in clusters
size = (uint64_t)c * (uint64_t)h * (uint64_t)s * 512ULL;
int64_t bootsect_pos = 0; // offset of the boot sector in clusters
if(cmd->FindExist("-nofs",true)) {
bootsect_pos = -1;
}
Expand Down Expand Up @@ -3825,7 +3827,7 @@ class IMGMAKE : public Program {
LOG_MSG(MSG_Get("PROGRAM_IMGMAKE_PRINT_CHS"),temp_line.c_str(),c,h,s);

// do it again for fixed chs values
sectors = (unsigned int)(size / 512);
sectors = size / 512;

// create the image file
if(disktype == "vhd") {
Expand Down Expand Up @@ -3873,13 +3875,14 @@ class IMGMAKE : public Program {
}
// Format the image if not unrequested (and image size<2GB)
if(bootsect_pos > -1) {
unsigned int reserved_sectors = 1; /* 1 for the boot sector + BPB. FAT32 will require more */
unsigned int sectors_per_cluster = 0;
unsigned int vol_sectors = 0;
unsigned int fat_copies = 2; /* number of copies of the FAT. always 2. TODO: Allow the user to specify */
uint32_t reserved_sectors = 1; /* 1 for the boot sector + BPB. FAT32 will require more */
uint64_t vol_sectors = 0;
uint8_t fat_copies = 2; /* number of copies of the FAT */
uint32_t fatlimitmin;
uint32_t fatlimit;
int FAT = -1;
int8_t FAT = -1;
bool spc_changed = false;
bool rootent_changed = false;

/* FAT filesystem, user choice */
if (cmd->FindString("-fat",tmp,true)) {
Expand Down Expand Up @@ -3922,6 +3925,7 @@ class IMGMAKE : public Program {
if (setdir) chdir(dirCur);
return;
}
spc_changed = true;
}

/* Root directory count, user choice.
Expand All @@ -3935,27 +3939,29 @@ class IMGMAKE : public Program {
if (setdir) chdir(dirCur);
return;
}
rootent_changed = true;
}

/* decide partition placement */
if (mediadesc == 0xF8) {
bootsect_pos = (Bits)s;
vol_sectors = sectors - (unsigned int)bootsect_pos;
bootsect_pos = (int64_t)s;
vol_sectors = sectors - bootsect_pos;
}
else {
bootsect_pos = 0;
vol_sectors = sectors;
}

/* auto-decide FAT system */
if (FAT < 0) {
if (is_fd) FAT = 12;
else if (FAT < 0) {
bool dosver_fat32 = (dos.version.major >= 8) || (dos.version.major == 7 && dos.version.minor >= 10);

if (vol_sectors >= 4194304 && !dosver_fat32) /* 2GB or larger */
if (vol_sectors >= 2*1024*1024*1024ull/512ull && !dosver_fat32) /* 2GB or larger */
FAT = 32;
else if (vol_sectors >= 1048576 && dosver_fat32) /* 512MB or larger */
else if (vol_sectors >= 512*1024*1024ull/512ull && dosver_fat32) /* 512MB or larger */
FAT = 32;
else if (vol_sectors >= 24576) /* 12MB or larger */
else if (vol_sectors >= 12*1024*1024ull/512ull) /* 12MB or larger */
FAT = 16;
else
FAT = 12;
Expand Down Expand Up @@ -4096,42 +4102,42 @@ class IMGMAKE : public Program {
while ((vol_sectors/sectors_per_cluster) >= (tmp_fatlimit - 2u) && sectors_per_cluster < 0x80u) sectors_per_cluster <<= 1;
}
}
while ((vol_sectors/sectors_per_cluster) >= (fatlimit - 2u) && sectors_per_cluster < 0x80u) sectors_per_cluster <<= 1;
while (!is_fd && (vol_sectors/sectors_per_cluster) >= (fatlimit - 2u) && sectors_per_cluster < 0x80u) sectors_per_cluster <<= 1;
sbuf[SecPerClus]=(uint8_t)sectors_per_cluster;
// TODO small floppies have 2 sectors per cluster?
// reserved sectors
host_writew(&sbuf[0x0e],reserved_sectors);
host_writew(&sbuf[RsvdSecCnt],reserved_sectors);
// Number of FATs
sbuf[NumFATs] = fat_copies;
// Root entries if not FAT32
if (FAT < 32) host_writew(&sbuf[RootEntCnt],root_ent);
// sectors (under 32MB) if not FAT32 and less than 65536
if (FAT < 32 && vol_sectors < 65536ul) host_writew(&sbuf[TotSec16],vol_sectors);
// sectors (32MB or larger or FAT32)
if (FAT >= 32 || vol_sectors >= 65536ul) host_writed(&sbuf[0x20],vol_sectors);
if (FAT >= 32 || vol_sectors >= 65536ul) host_writed(&sbuf[TotSec32],vol_sectors);
else host_writed(&sbuf[TotSec32],0);
// media descriptor
sbuf[Media]=mediadesc;
// sectors per FAT
// needed entries: (sectors per cluster)
Bitu sect_per_fat=0;
Bitu clusters = vol_sectors / sectors_per_cluster; // initial estimate
uint64_t clusters = vol_sectors / sectors_per_cluster; // initial estimate

// sectors per FAT
if (FAT >= 32) sect_per_fat = ((clusters*4u)+511u)/512u;
else if (FAT >= 16) sect_per_fat = ((clusters*2u)+511u)/512u;
else sect_per_fat = ((((clusters+1u)/2u)*3u)+511u)/512u;
// Use standard sect_per_fat values for standard floppy images, otherwise it may required to be adjusted
else if (!is_fd || (is_fd && (rootent_changed || (fat_copies != 2)))) sect_per_fat = ((((clusters+1u)/2u)*3u)+511u)/512u;

if (FAT < 32 && sect_per_fat >= 65536u) {
WriteOut("Error: Generated filesystem has more than 64KB sectors per FAT and is not FAT32\n");
if (FAT < 32 && sect_per_fat > 256u) {
WriteOut("Error: Generated filesystem has more than 256 sectors per FAT and is not FAT32\n");
fclose(f);
unlink(temp_line.c_str());
if (setdir) chdir(dirCur);
return;
}

Bitu data_area = vol_sectors - reserved_sectors - (sect_per_fat * fat_copies);
uint64_t data_area = vol_sectors - reserved_sectors - (sect_per_fat * fat_copies);
if (FAT < 32) data_area -= ((root_ent * 32u) + 511u) / 512u;
clusters = data_area / sectors_per_cluster;
if (FAT < 32) host_writew(&sbuf[0x16],(uint16_t)sect_per_fat);
if (FAT < 32) host_writew(&sbuf[FATSz16],(uint16_t)sect_per_fat);

/* Too many or to few clusters can foul up FAT12/FAT16/FAT32 detection and cause corruption! */
if ((clusters+2u) < fatlimitmin) {
Expand All @@ -4146,14 +4152,15 @@ class IMGMAKE : public Program {
WriteOut("Warning: Cluster count is too high given the volume size. Reporting a\n");
WriteOut(" smaller sector count.\n");
/* Well, if the user wants an oversized partition, hack the total sectors fields to make it work */
unsigned int adj_vol_sectors =
(unsigned int)(reserved_sectors + (sect_per_fat * fat_copies) +
uint32_t adj_vol_sectors =
(uint32_t)(reserved_sectors + (sect_per_fat * fat_copies) +
(((root_ent * 32u) + 511u) / 512u) + (clusters * sectors_per_cluster));

// sectors (under 32MB) if not FAT32 and less than 65536
if (adj_vol_sectors < 65536ul) host_writew(&sbuf[0x13],adj_vol_sectors);
if (adj_vol_sectors < 65536ul) host_writew(&sbuf[TotSec16],(uint16_t)adj_vol_sectors);
// sectors (32MB or larger or FAT32)
if (adj_vol_sectors >= 65536ul) host_writed(&sbuf[0x20],adj_vol_sectors);
if (adj_vol_sectors >= 65536ul) host_writed(&sbuf[TotSec32],adj_vol_sectors);
else host_writed(&sbuf[TotSec32],0);
}

// sectors per track
Expand All @@ -4164,7 +4171,7 @@ class IMGMAKE : public Program {
host_writed(&sbuf[HiddSec],(uint32_t)bootsect_pos);
/* after 0x24, FAT12/FAT16 and FAT32 diverge in structure */
if (FAT >= 32) {
host_writed(&sbuf[FATSz32],(uint32_t)sect_per_fat);
host_writed(&sbuf[FATSz32],sect_per_fat);
sbuf[0x28] = 0x00; // FAT is mirrored at runtime because that is what DOSBox-X's FAT driver does
host_writew(&sbuf[0x2A],0x0000); // FAT32 version 0.0
host_writed(&sbuf[0x2C],2); // root directory starting cluster
Expand Down Expand Up @@ -4199,28 +4206,9 @@ class IMGMAKE : public Program {
host_writew(&sbuf[SecPerTrk],DiskGeometryList[index].secttrack);
host_writew(&sbuf[NumHeads], DiskGeometryList[index].headscyl);
host_writew(&sbuf[BytsPerSec], DiskGeometryList[index].bytespersect);
sbuf[SecPerClus] = DiskGeometryList[index].sectcluster;
host_writew(&sbuf[RootEntCnt], DiskGeometryList[index].rootentries);
/* FATSz16 to match FreeDOS FORMAT command https://github.com/FDOS/format/blob/master/floppy.h */
if(disksize == 160 || disksize == 320) {
host_writew(&sbuf[FATSz16],1);
sect_per_fat = 1;
}
else if(disksize == 180 || disksize == 200 || disksize == 360 || disksize == 400) {
host_writew(&sbuf[FATSz16],2);
sect_per_fat = 2;
}
else if(disksize == 720) {
host_writew(&sbuf[FATSz16],3);
sect_per_fat = 3;
}
else if(disksize == 1200) {
host_writew(&sbuf[FATSz16],7);
sect_per_fat = 7;
} else { // Explicitly set to 9 for disksize == 1400 || disksize == 2880
host_writew(&sbuf[FATSz16],9);
sect_per_fat = 9;
}
sbuf[SecPerClus] = spc_changed ? sectors_per_cluster : DiskGeometryList[index].sectcluster;
host_writew(&sbuf[RootEntCnt], rootent_changed ? root_ent : DiskGeometryList[index].rootentries);
host_writew(&sbuf[FATSz16],sect_per_fat);
break;
}
index++;
Expand Down

0 comments on commit 23be2fb

Please sign in to comment.