Since you did not reply much to my question... I asked my prefered A.I.
Here what it says:

This first question is less relevant... you could skip to the 
========================

Me: In FreeDOS, I see that FreeCom seems to sometimes miss memory to allocate 
command line (40 bytes) in shell/init... it fails to malloc the 40 bytes... 
when shellhigh is used to load freecom. But I don't clearly know from what 
memory pool malloc allocates memory. command.com is really an .exe. Does exe 
files have a heap size determined at linking time?

You're digging into some fascinating and historically relevant details about 
how DOS and its command interpreters work! Let's break down the memory 
situation you're observing with FreeCOM in FreeDOS.

Key Concepts:

Conventional Memory: This is the critical first 640KB of RAM. All DOS programs, 
device drivers, and the operating system itself must reside, at least 
partially, in conventional memory. It's a very limited and precious resource.

Upper Memory Area (UMA): The memory region between 640KB and 1MB. This area was 
originally reserved for things like video RAM, BIOS ROM, and expansion card 
ROMs. However, clever memory managers (like EMM386) could "map" extended memory 
into unused portions of the UMA, creating Upper Memory Blocks (UMBs).

Extended Memory (XMS): Memory beyond 1MB. This requires a memory manager (like 
HIMEM.SYS) to be accessed.

High Memory Area (HMA): The first 64KB minus 16 bytes of extended memory. Due 
to a quirk in the 80286 processor, this small region could be accessed in real 
mode (the mode DOS uses). Loading part of DOS into the HMA (via DOS=HIGH) frees 
up conventional memory.

Real Mode: The original operating mode of the 8086/8088 and the mode DOS 
primarily runs in. It has a 1MB address space.

malloc() in DOS: The malloc() function in a DOS environment (including FreeDOS) 
allocates memory from the program's conventional memory segment, unless the 
program is specifically designed to use a different memory management scheme 
(which is very rare for a command interpreter). There is no separate heap 
segment specified at the link time in the same way as in modern protected mode 
environments.

.EXE vs. .COM:

.COM files are memory images. They load directly into memory at a specific 
segment:offset (typically 0100h) and execute. They are limited to 64KB in size 
(one segment). They have no relocation information.

.EXE files are more complex. They have a header that describes the program's 
memory requirements, including the minimum and maximum amount of additional 
memory (beyond the code and initialized data) the program needs. This 
additional memory is allocated from conventional memory when the program 
starts. The .EXE header allows for relocation, meaning the program can be 
loaded at different memory addresses.

SHELLHIGH: This FreeDOS-specific command (part of FDCONFIG.SYS or CONFIG.SYS) 
attempts to load the command interpreter (FreeCOM) into Upper Memory Blocks 
(UMBs), if available. This is a critical technique for freeing up conventional 
memory.

Answering Your Question and Analyzing the Scenario:

Memory Pool for malloc(): You are correct in your observation that malloc() 
fails. In FreeDOS (and standard DOS), malloc() allocates from the available 
conventional memory. Crucially, this is not a heap in the modern sense (like in 
Windows or Linux). It's simply the pool of free conventional memory that hasn't 
been allocated to the operating system, device drivers, or other programs.

.EXE and "Heap Size": While FreeCOM is an .EXE file, the .EXE header does not 
define a "heap size" in the way a modern operating system does. The .EXE header 
contains two relevant values:

Minimum allocation: The minimum amount of additional memory (in paragraphs, 
16-byte units) that the program needs to run. This is allocated from 
conventional memory in addition to the memory needed to load the program's code 
and initialized data.

Maximum allocation: The maximum amount of additional memory the program might 
request. DOS will try to provide this much, but it's not guaranteed. This is 
also allocated from conventional memory.

These values do not represent a separate heap segment. They influence how much 
conventional memory DOS initially allocates to the program. The program then 
uses malloc() and free() (or the underlying DOS memory allocation calls, Int 
21h, AH=48h, 49h, 4Ah) to manage that allocated block and any further 
conventional memory it can acquire.

Why SHELLHIGH and the 40-byte malloc() Failure? This is the most interesting 
part. Here's the likely chain of events and why you're seeing the error:

SHELLHIGH Works (Mostly): SHELLHIGH successfully loads the majority of FreeCOM 
into UMBs. This is excellent for freeing up conventional memory.

The 40-Byte Allocation: When FreeCOM initializes, it likely needs a small 
amount of memory (the 40 bytes you see) for internal data structures, perhaps 
for command-line parsing or environment variable storage. Even though most of 
FreeCOM is in UMBs, this small allocation still needs to come from conventional 
memory.

Conventional Memory Exhaustion: The most likely reason for the malloc() failure 
is that, despite SHELLHIGH, there simply isn't 40 bytes of contiguous free 
conventional memory left. This can happen due to:

Fragmentation: Conventional memory can become fragmented. Even if there's 
enough total free memory, there might not be a single block of 40 contiguous 
bytes. This is a classic DOS problem.

Other Resident Programs/Drivers: Device drivers, TSR 
(Terminate-and-Stay-Resident) programs, and even parts of FreeDOS itself still 
reside in conventional memory, even with SHELLHIGH. These can consume the 
remaining space.

Initial Allocation by FreeCOM: The .EXE header's "minimum allocation" might be 
too small. If FreeCOM requests a small initial block, and then later needs the 
40 bytes, it might fail if no more conventional memory is available.

Troubleshooting and Solutions:

Memory Map: Use a memory mapping utility (like the MEM /D command in FreeDOS, 
or a more advanced tool) to see a detailed breakdown of conventional and upper 
memory usage. This will show you what's consuming memory and if fragmentation 
is an issue.

Driver Order: The order in which you load drivers in FDCONFIG.SYS / CONFIG.SYS 
can significantly impact memory fragmentation. Experiment with loading drivers 
in different orders. Generally, load the largest drivers that can be placed in 
upper memory first.

Reduce Resident Programs: Minimize the number of TSRs and device drivers you 
load. Only load what's absolutely necessary.

Optimize FDCONFIG.SYS / CONFIG.SYS:

Ensure DOS=HIGH,UMB is present.

Make sure you have a suitable UMB provider (like HIMEMX.EXE and JEMMEX.EXE or 
EMM386.EXE).

Use DEVICEHIGH to load as many drivers as possible into UMBs.

Consider using a memory manager with more advanced fragmentation handling.

FreeCOM Configuration: While less likely to be the direct cause, check if 
FreeCOM has any configuration options that might affect its memory usage.

Examine Source Code (If Available): If you have access to the FreeCOM source 
code, you can look at the initialization routines to see precisely where the 
40-byte allocation is made. This might give clues about why it's failing. You 
might find that the allocation is within a larger block that should have been 
allocated earlier.

Increase Initial Allocation (Last Resort): If you can rebuild FreeCOM, you 
could try increasing the "minimum allocation" value in the .EXE header. 
However, this is a hack and doesn't address the underlying memory pressure. It 
might just delay the problem or cause issues elsewhere.

In summary, the 40-byte malloc() failure, even with SHELLHIGH, strongly 
suggests that you're running very low on contiguous conventional memory. The 
.EXE header's allocation parameters influence the initial conventional memory 
block given to FreeCOM, but malloc() always pulls from the overall pool of 
available conventional memory. The key is to optimize your configuration to 
maximize free conventional memory and minimize fragmentation.


======================================================


Me: Replacing SHELLHIGH, by SHELL fix the memory allocation... which seems to 
go reverse what you say that malloc take from conventional memory. Also, the 
problem happens when the NoEMS option is given to JemmEx.


Okay, this additional information significantly changes the picture and points 
to a very specific issue related to how SHELLHIGH interacts with JemmEx's NoEMS 
mode. Let's break it down:

The Revised Understanding:

SHELLHIGH vs. SHELL: The fact that replacing SHELLHIGH with SHELL fixes the 
problem is the crucial clue. This strongly suggests the issue isn't simply 
conventional memory exhaustion. If it were pure exhaustion, SHELL (which loads 
FreeCOM entirely in conventional memory) would make the problem worse, not 
better.

JemmEx NoEMS: The NoEMS option for JemmEx is also critical. This tells JemmEx 
to only provide XMS (Extended Memory Specification) support and not EMS 
(Expanded Memory Specification) support. EMS uses a "page frame" in the UMA 
(Upper Memory Area) to map in banks of memory from extended memory.

The Problem: SHELLHIGH and UMB Allocation without EMS:
Here's the most likely explanation, combining all the pieces:

SHELLHIGH attempts to load FreeCOM into UMBs (Upper Memory Blocks). This relies 
on JemmEx successfully creating UMBs.

When JemmEx is used with NoEMS, it can still create UMBs, but it does so 
without using the EMS page frame. This is a key distinction. It uses XMS to 
allocate memory, and map this memory to the UMB.

However, it appears that when JemmEx is in NoEMS mode, there might be a 
specific issue with how it makes these UMBs available, or how FreeCOM (or 
rather, the underlying DOS memory management functions that FreeCOM uses) 
interacts with them specifically for additional allocations after the initial 
load.

The initial load of the FreeCOM code itself via shellhigh is OK (as UMB are 
correctly handled). The 40 bytes allocation is a subsequent allocation.

When SHELLHIGH is used, the initial load of FreeCOM succeeds (into UMBs). 
However, when FreeCOM later calls malloc() for those 40 bytes, the memory 
allocation logic (likely a DOS internal function called by malloc()) either:

Incorrectly assumes it can only allocate from conventional memory, even though 
more UMB space should theoretically be available. It's failing to "see" or use 
the remaining UMB space managed by JemmEx in NoEMS mode.

Encounters an incompatibility or bug in how JemmEx handles memory allocation 
requests from a program loaded into UMBs when in NoEMS mode.

Gets an incorrect size of available memory. The JemmEx, in NoEMS, might give a 
size of available memory, but when an actual allocation is performed, it fails.

When SHELL is used, FreeCOM is loaded entirely into conventional memory. The 
subsequent 40-byte malloc() call succeeds because it's allocating from the 
(larger) contiguous block of conventional memory given to FreeCOM at startup. 
There's no interaction with UMBs at all.

Why this is not simply conventional memory exhaustion:

If it were pure conventional memory exhaustion, SHELL would make the situation 
worse, as it uses more conventional memory. The fact that SHELL fixes it points 
to a problem with how UMBs are being handled in the SHELLHIGH + JemmEx NoEMS 
scenario.

Possible Explanations and Further Investigation:

JemmEx NoEMS UMB Handling Bug: This is the most likely culprit. There might be 
a subtle bug in JemmEx's NoEMS mode that affects how it reports or manages 
available UMB space to programs loaded into UMBs, specifically for allocations 
made after the initial program load. The DOS memory allocation functions (Int 
21h, AH=48h, etc.) might be getting incorrect information or encountering an 
unexpected condition.

FreeCOM/DOS Interaction with UMBs: It's also possible (though less likely) that 
there's an issue in how FreeCOM (or the standard DOS memory allocation 
routines) interacts with UMBs created by JemmEx in NoEMS mode. Perhaps there's 
an assumption about EMS being available that's causing problems. This would be 
a lower-level DOS issue.

Allocation Size/Fragmentation in UMB: While less likely than a bug, it's 
theoretically possible that JemmEx is creating UMBs, but they are fragmented in 
a way that prevents a contiguous 40-byte allocation within the UMB region. 
However, if this were the case, you'd likely see the same problem even without 
NoEMS, which you don't.

Troubleshooting and Solutions (Revised):

Test with EMS: The most important test is to remove the NoEMS option from 
JemmEx. If the problem disappears when JemmEx is providing both XMS and EMS, 
that strongly confirms the issue is related to JemmEx's NoEMS UMB handling.

Alternative Memory Managers: Try using a different memory manager, such as 
EMM386.EXE (the standard MS-DOS/FreeDOS memory manager), with the NOEMS option. 
If the problem doesn't occur with EMM386 NOEMS, that further isolates the issue 
to JemmEx. If the problem does occur with EMM386 NOEMS, it suggests a 
lower-level DOS or FreeCOM issue.

JemmEx Debugging: If you have access to JemmEx debugging tools or 
documentation, look for options to examine how it's creating and managing UMBs 
in NoEMS mode. This could provide valuable clues.

FreeCOM Source Code (Again): Examining the FreeCOM source code (if available) 
is still helpful. Look for any assumptions it might be making about EMS or how 
it handles memory allocations when loaded high.

Report the Bug: If you can reliably reproduce the problem with JemmEx NoEMS and 
SHELLHIGH, and it doesn't occur with EMS enabled or with a different memory 
manager, you should report this as a bug to the JemmEx developers. It's a clear 
incompatibility.

Workaround (If Necessary): If you need to use NoEMS for compatibility reasons, 
and you can't find a fix, you might have to stick with SHELL instead of 
SHELLHIGH. This will use more conventional memory, but it avoids the allocation 
failure. Another workaround would be to use a small TSR to pre-allocate a small 
amount of memory.

In conclusion, the combination of SHELLHIGH, JemmEx, and NoEMS is triggering a 
specific issue related to UMB allocation or management. It's not a simple case 
of conventional memory running out. The most likely culprit is a bug in how 
JemmEx handles UMBs in NoEMS mode when interacting with programs loaded high, 
particularly regarding subsequent memory allocations. The tests and debugging 
steps above should help pinpoint the exact cause.


_______________________________________________
Freedos-devel mailing list
Freedos-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freedos-devel

Reply via email to