Dosbox-x: Define reasonable VESA mode settings to limit modelist for DOS applications that use a fixed size buffer.

Created on 25 Dec 2019  路  14Comments  路  Source: joncampbell123/dosbox-x

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:

  • The 16-color (4bpp) packed mode (Chips & Tech 655xx compatible) should be disabled by default. It's more of a novelty mode if you want to code for certain Chips & Tech SVGA BIOSes and chipsets made in the 1995-1996 timeframe.
  • Default video mode limit should be 1280x1024 to match a typical late 1990s VESA BIOS.
  • Perhaps another option should enable/disable SVGA modes (640x480 or higher) that do not have an aspect ratio of 4:3 or 5:4 so the modelist looks typical of a 1990s VESA BIOS. That means filtering out the 16:9 HD modes (1280x720 and 1920x1080) and "DVD-like" 720x480 mode.
  • Another option to enable/disable special S3 modes expected by some demoscene stuff i.e. 320x480 256-color.
  • Perhaps the extra 24bpp modes (beyond mode 0x11F) should be filtered out as an option. SVGA cards support 24bpp (older cards) or 32bpp (newer cards), but not both, as far as I know, and that is reflected in base modes 0x100-0x11F in which "truecolor" modes are either 24bpp or 32bpp, not both.
  • The lowres modes should be enabled to match mid 1990s BIOSes (or UNIVBE) that allowed modes like 320x200 16bpp or 400x300 32bpp.

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.

Ref: https://github.com/joncampbell123/dosbox-x/issues/1355

All 14 comments

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?

https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/vid_ext.c#L336

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.

https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/vid_dos.h#L22

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

https://bearwindows.zcm.com.au/vbe9x.htm

Testing with the Quake shareware demo (1.06):

  • Run with 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

https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/vid_ext.c#L450

and frees it here

https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/WinQuake/vid_ext.c#L576

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sduensin picture sduensin  路  7Comments

maximus105 picture maximus105  路  18Comments

forthrin picture forthrin  路  20Comments

joncampbell123 picture joncampbell123  路  7Comments

bob12111 picture bob12111  路  17Comments