diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index 561e614505..4bc26b0d84 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -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")); @@ -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; @@ -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; @@ -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; @@ -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; } @@ -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") { @@ -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)) { @@ -3922,6 +3925,7 @@ class IMGMAKE : public Program { if (setdir) chdir(dirCur); return; } + spc_changed = true; } /* Root directory count, user choice. @@ -3935,12 +3939,13 @@ 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; @@ -3948,14 +3953,15 @@ class IMGMAKE : public Program { } /* 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; @@ -4096,11 +4102,10 @@ 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 @@ -4108,30 +4113,31 @@ class IMGMAKE : public Program { // 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) { @@ -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 @@ -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 @@ -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++;