Merge pull request #2705 from cimarronm/dos_execute-umb-fix

Fix with how DOS_Execute allocates memory to comply with the memory a…
This commit is contained in:
Jonathan Campbell
2021-07-22 09:39:04 -06:00
committed by GitHub
3 changed files with 43 additions and 17 deletions

View File

@@ -233,6 +233,7 @@ void DOS_Terminate(uint16_t pspseg,bool tsr,uint8_t exitcode);
/* Memory Handling Routines */
void DOS_SetupMemory(void);
uint16_t DOS_GetMaximumFreeSize(uint16_t minBlocks);
bool DOS_AllocateMemory(uint16_t * segment,uint16_t * blocks);
bool DOS_ResizeMemory(uint16_t segment,uint16_t * blocks);
bool DOS_FreeMemory(uint16_t segment);
@@ -670,6 +671,11 @@ public:
uint8_t GetType(void) { return (uint8_t)sGet(sMCB,type);}
uint16_t GetSize(void) { return (uint16_t)sGet(sMCB,size);}
uint16_t GetPSPSeg(void) { return (uint16_t)sGet(sMCB,psp_segment);}
enum class MCBType : uint8_t
{
ValidBlock = 'M',
LastBlock = 'Z'
};
private:
#ifdef _MSC_VER
#pragma pack (1)

View File

@@ -366,6 +366,10 @@ bool DOS_Execute(const char* name, PhysPt block_pt, uint8_t flags) {
DOS_AllocateMemory(&pspseg,&maxfree);
if (iscom) {
minsize=0x1000;maxsize=0xffff;
pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
uint16_t dataread=0xf800;
DOS_ReadFile(fhandle,loadbuf,&dataread);
if (dataread<0xf800) minsize=((dataread+0x10)>>4)+0x20;
if (machine==MCH_PCJR) {
/* try to load file into memory below 96k */
pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
@@ -386,24 +390,15 @@ bool DOS_Execute(const char* name, PhysPt block_pt, uint8_t flags) {
* This allows it to run without the SS:IP out of range error below. */
if (maxsize < minsize) maxsize = minsize;
}
maxfree = DOS_GetMaximumFreeSize(minsize);
if (maxfree<minsize) {
if (iscom) {
/* Reduce minimum of needed memory size to filesize */
pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
uint16_t dataread=0xf800;
DOS_ReadFile(fhandle,loadbuf,&dataread);
if (dataread<0xf800) minsize=((dataread+0x10)>>4)+0x20;
}
if (maxfree<minsize) {
DOS_CloseFile(fhandle);
delete[] loadbuf;
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
DOS_CloseFile(fhandle);
delete[] loadbuf;
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
if (maxfree<maxsize) memsize=maxfree;
else memsize=maxsize;
memsize = (maxfree<maxsize) ? maxfree : maxsize;
if (!DOS_AllocateMemory(&pspseg,&memsize)) E_Exit("DOS:Exec error in memory");
if (iscom && (machine==MCH_PCJR) && (pspseg<0x2000)) {
maxsize=0xffff;

View File

@@ -16,8 +16,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <algorithm>
#include "dosbox.h"
#include "dosbox.h"
#include "logging.h"
#include "mem.h"
#include "bios.h"
@@ -153,6 +154,30 @@ void DOS_zeromem(uint16_t seg,uint16_t para) {
}
}
static uint16_t GetMaximumMCBFreeSize(uint16_t mcb_segment)
{
uint16_t largestSize = 0;
DOS_MCB mcb(mcb_segment);
for (bool endOfChain = false; !endOfChain; mcb.SetPt(mcb_segment))
{
auto size = mcb.GetSize();
if (mcb.GetPSPSeg()==MCB_FREE) largestSize = (std::max)(largestSize, size);
endOfChain = DOS_MCB::MCBType(mcb.GetType())==DOS_MCB::MCBType::LastBlock;
mcb_segment += size+1;
}
return largestSize;
}
uint16_t DOS_GetMaximumFreeSize(uint16_t minBlocks)
{
if (memAllocStrategy & 0xc0)
{
auto umbFreeSize = GetMaximumMCBFreeSize(dos_infoblock.GetStartOfUMBChain());
if (memAllocStrategy & 0x40 || umbFreeSize >= minBlocks) return umbFreeSize;
}
return GetMaximumMCBFreeSize(dos.firstMCB);
}
bool DOS_AllocateMemory(uint16_t * segment,uint16_t * blocks) {
DOS_CompressMemory();
uint16_t bigsize=0;