A lot of complaints have been made about DOSBox-X breaking DOS games and applications simply because the VESA modelist is too long.
So let's discuss the default settings for VESA BIOS modes, meaning the settings in dosbox.conf that define what modes are and aren't allowed and the maximum video resolution to provide in order to trim the modelist down.
Here's what I think would be a good start:
If possible, debugging or examination of the source should be done to figure out the typical fixed size buffer DOS games use and therefore the maximum number of modes DOSBox-X can safely report.
Perhaps a first good example would be the Quake source code, since Quake is also prone to crash if too many VESA BIOS modes are listed.
If possible, debugging or examination of the source should be done to figure out the typical fixed size buffer DOS games use and therefore the maximum number of modes DOSBox-X can safely report.
Perhaps a first good example would be the Quake source code, since Quake is also prone to crash if too many VESA BIOS modes are listed.
I guess (maybe) this:
https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/vid_ext.c#L47
Edit: Trying the Quake demo, it successfully started for vesa modelist cap values I tested up until 106 for me. From 107 onward it doesn't start.
Interesting... see the bug in the code here?
The loop does terminate if nummodes == MAX_VESA_MODES, but the array is exactly MAX_VESA_MODES large. The next pointer in that case points to whatever happens to follow in memory, which may or may not be vesa_extra[0], but is probably uninitialized and probably nonzero. That's a POINTER that it follows later on like a linked list.
It probably takes 106/107 entries to trigger in order to come up with at least 30 256-color modes for Quake to hit this limit.
However that might not be the exact bug since the mode count does affect it even though VID_ExtraGetModeInfo() only returns true if it find a mode that is 8bpp and to Quake's satisfaction.
It's not a problem with translation of the VBE information to protected mode either, I see Quake getting the actual memory address in ROM of the modelist. Some implementations and/or DOS extenders like to get the VBE BIOS information and then translate the memory addresses which includes copying the modelist into the VBE info struct itself (obviously over-running the buffer doing that).
The VESA BIOS can return the modelist pointing into the struct itself, that is what more modern BIOSes do. They can put the modelist in the info struct given by the application and then point at that.
EDIT: Ok, I see what they did, they do update the last pointer.
Hold on...Quake seems to be enumerating VESA modes twice.
I'm happy to report that whatever is crashing Quake does not cause VBEMP 9x any problems. In fact the latest driver allows me to set Windows 95 up to 1920x1080 given DOSBox-X's default modelist.
I can also go all the way down to 320x200 256-color XD
Testing with the Quake shareware demo (1.06):
vesa modelist cap = 30 and in the in-game console type VID_NUMMODES to get the number of video modes. The game console returns 16 VIDEO MODES ARE AVAILABLE.In the in-game console type VID_DESCRIBEMODES. The game console returns:
**** STANDARD VGA MODES ****
0: 320x200
**** MODE X-STYLE MODES ****
1: 320x200
2: 360x200
3: 320x240
4: 360x240
5: 320x350
6: 360x350
7: 320x400
8: 360x400
9: 320x480
10: 360x480
********* VESA MODES *********
11: 640x400
12: 640x480
13: 800x600
14: 1024x768
15: 1280x1024
Doing the same as above with vesa modelist cap = 31 increments the list of supported modes by 1, to 17, adding
16: 640x350
to the VESA MODES list.
Additional test results:
vesa modelist cap = 40=22 video modes
vesa modelist cap = 70=29 video modes
vesa modelist cap = 90 & vesa modelist cap = 95 =33 video modes
vesa modelist cap = 96 through vesa modelist cap = 106 (the maximum with which QUAKE.EXE will successfully start)=34 modes
The VESA modes that get added to fill out the list to 34 modes are:
17: 320x480
18: 320x240
19: 320x400
20: 320x200
21: 512x384
22: 400x300
23: 320x480
24: 640x480
25: 800x600
26: 1024x768
27: 1152x864
28: 720x480
29: 848x480
30: 1280x800
31: 1280x960
32: 1280x720
33: 960x720
When starting Quake, the DOSBox-X log has a list of memory allocations, with the number of allocations depending on how big the vesa modelist cap value is. At 106, the biggest value with which QUAKE.EXE will start, it looks like
134248061 DEBUG MISC:DOS_AllocateMemory(blocks=0x0020) = 0x7fee-0x800d
134253728 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x800f-0x801e
134255143 DEBUG MISC:DOS_FreeMemory(seg=0x800f)
134483012 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x800f-0x801e
134484427 DEBUG MISC:DOS_FreeMemory(seg=0x800f)
134703022 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x800f-0x801e
134704338 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8020-0x802f
134705784 DEBUG MISC:DOS_FreeMemory(seg=0x8020)
134924379 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8020-0x802f
134925719 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8031-0x8040
134927197 DEBUG MISC:DOS_FreeMemory(seg=0x8031)
135145804 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8031-0x8040
135147168 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8042-0x8051
135148675 DEBUG MISC:DOS_FreeMemory(seg=0x8042)
135367291 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8042-0x8051
135368679 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8053-0x8062
135370091 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8064-0x8073
(omitting middle, which are all DOS_AllocateMemory(blocks=0x0010))
139513703 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8691-0x86a0
139516835 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x86a2-0x86b1
139519985 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x86b3-0x86c2
139523152 DEBUG MISC:DOS_AllocateMemory(blocks=0x0040) = 0x86c4-0x8703
139525586 DEBUG MISC:DOS_FreeMemory(seg=0x7fee)
With vesa modelist cap at 107, where QUAKE.EXE starts failing, this looks the same until the end, where instead of allocating 0x0040 blocks and then freeing memory, it allocates 0x0010 again and then starts hitting errors.
149097206 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x8691-0x86a0
149100338 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x86a2-0x86b1
149103488 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x86b3-0x86c2
149106656 DEBUG MISC:DOS_AllocateMemory(blocks=0x0010) = 0x86c4-0x86d3
154434695 DEBUG MISC:IO write slow path port=262a data=1bf iolen=2: device matches=0
154434695 DEBUG MISC:IO write slow path port=262a data=bf iolen=1: device matches=0
154434695 DEBUG MISC:IO write slow path port=262b data=1 iolen=1: device matches=0
154434703 DEBUG MISC:IO read slow path port=262a iolen=2: device matches=0
154434703 DEBUG MISC:IO read slow path port=262b iolen=1: device matches=0
154434703 DEBUG MISC:IO read slow path port=262a iolen=1: device matches=0
154553787 CPU:Illegal/Unhandled opcode FFFF
154657800 CPU:Illegal/Unhandled opcode FFFF
154801334 CPU:Illegal/Unhandled opcode 0FE0
154873266 DEBUG MISC:IO read slow path port=ca00 iolen=2: device matches=0
154873266 DEBUG MISC:IO read slow path port=ca01 iolen=1: device matches=0
154873266 DEBUG MISC:IO read slow path port=ca00 iolen=1: device matches=0
154904956 DEBUG MISC:IO write slow path port=ca00 data=0 iolen=2: device matches=0
154904956 DEBUG MISC:IO write slow path port=ca00 data=0 iolen=1: device matches=0
154904956 DEBUG MISC:IO write slow path port=ca01 data=0 iolen=1: device matches=0
154909033 CPU:Illegal/Unhandled opcode FFFF
154974107 WARN FPU:ESC 2:Unhandled group 7 subfunction 7
154982126 WARN FPU:ESC 2:Unhandled group 7 subfunction 7
154990145 WARN FPU:ESC 2:Unhandled group 7 subfunction 7
154998164 WARN FPU:ESC 2:Unhandled group 7 subfunction 7
Dynamic core will hang here, Normal core will restart DOSBox-X.
Just a guess, but could the problem be Quake allocating memory while checking the VESA mode list and not freeing it?
In Vid_ExtraGetModeInfo it allocates memory here
and frees it here
but can exit the function early at a few places and not reach the dos_freememory(infobuf); line.
I never thought to look at DOS memory allocation. I was focused on whether or not there was any way a modelist could overrun buffers somewhere. Good analysis @Allofich !
The memory leak makes sense... The full modelist has lots of modes that don't fit Quake's criteria of a usable mode.
From my experience most VESA BIOSes at the time didn't list a lot of modes anyway, so it's understandable the iD team would miss that bug.
Even in the late 1990s VESA BIOSes tended to list only 640x400, 640x480, 800x600, 1024x768, 256-color, 16bpp and 32bpp. Maybe 1280x1024. Maybe the doublescanned 320x200 and 320x240 modes (or else you'd need UNIVBE). Maybe 400x300.
You know the leak could be avoided entirely if you just turn off all but the 8bpp (256-color) VESA modes. :)
The latest commit adds additional options for VESA modes and sets the defaults to produce a modelist more like your typical late 1990s VESA BIOS instead of the entire list DOSBox-X used to offer. Of course dosbox.conf can be used to lift all limits again.
The default modelist is now quite a bit smaller and Quake no longer crashes.
Any suggestions?
Any suggestions?
I'll check later whether Warcraft II and Nesticle run with the default setting (if you haven't already). If they do, then it all seems good to me!
Warcraft II and Nesticle both run fine with default settings now.
I do have a suggestion, though. This description for vesa modelist cap in the .conf file needs to be updated now:
# vesa modelist cap: IF nonzero, the VESA modelist is capped so that it contains no more than the specified number of video modes.
# Set this option to a value between 8 to 32 if the DOS application has problems with long modelists or a fixed
# buffer for querying modes. Such programs may crash if given the entire modelist supported by DOSBox-X.
# Warcraft II by Blizzard ................ Set to a value between 8 and 16. This game has a fixed buffer that it
# reads the modelist into. DOSBox-X's normal modelist is too long and
# the game will overrun the buffer and crash without this setting.
Updated.