comcom64 icon indicating copy to clipboard operation
comcom64 copied to clipboard

r200fix doesn't work (with Jazz Jackrabbit)

Open jschwartzenberg opened this issue 9 months ago • 47 comments

See: https://github.com/dosemu2/dosemu2/issues/2303#issuecomment-2661575159 and the follow up.

Image

Download location for the game: https://www.dosgamesarchive.com/file/jazz-jackrabbit/jazz

jschwartzenberg avatar Feb 16 '25 19:02 jschwartzenberg

Do you happen to know a simple runtime 200 test-case?

stsp avatar Feb 20 '25 20:02 stsp

Also is this a problem with comcom32 too?

stsp avatar Feb 20 '25 20:02 stsp

Oh, I suspect r200fix works only with realmode progs, so perhaps the simpler test-case doesn't exist...

stsp avatar Feb 20 '25 20:02 stsp

Any program that relies on crt.asm would fail I guess? Maybe we could try to build a simple program. Here is more info: http://www.kennedysoftware.ie/patchcrt.htm

jschwartzenberg avatar Feb 20 '25 20:02 jschwartzenberg

Would be good if you try, as I think this will fix realmode program.

stsp avatar Feb 20 '25 20:02 stsp

I thought it might be good to create a minimal test for runtime error 200. I followed the link above and itself links to here which suggests that problem crt.asm is in versions <= 6. So I made a minimal pascal file as below

program Hello;
{ Minimal program }

begin
  WriteLn('Hello');
end.

and compiled as tpc hello.pas with turbo pascal 5.5, but it runs without error. I'm running FreeCOM with FDPP, is there any magic fixup going on?

andrewbird avatar Feb 21 '25 13:02 andrewbird

Note I also added uses crt; but it still runs okay.

andrewbird avatar Feb 21 '25 13:02 andrewbird

Maybe just uses crt is not enough - you need to use it? There seem to be the test-case from @stuaxo https://github.com/dosemu2/dosemu2/issues/808

stsp avatar Feb 21 '25 13:02 stsp

Yes that example you linked failed with runtime error 200.

I compiled my test program with TP5.5, TP6.0, and TP7.0, and only the TP7.0 version generated the error. Interestingly the TP7 came with patch files for the CRT unit. I'm not sure of the provenance of those disks as they came from Winworldpc and they may have been altered to include the patch files.

I will now test with Borland Pascal.

andrewbird avatar Feb 21 '25 16:02 andrewbird

So can the failed example be fixed with r200fix?

Пятница, 21 февраля 2025 г получено от Andrew Bird:

andrewbird left a comment (dosemu2/comcom64#105)

Yes that example you linked failed with runtime error 200.

I compiled my test program with TP5.5, TP6.0, and TP7.0, and only the TP7.0 version generated the error. Interestingly the TP7 came with patch files for the CRT unit. I'm not sure of the provenance of those disks as they came from Winworldpc and they may have been altered to include the patch files.

I will now test with Borland Pascal.

-- Reply to this email directly or view it on GitHub: https://github.com/dosemu2/comcom64/issues/105#issuecomment-2674930409 You are receiving this because you commented.

Message ID: @.***

stsp avatar Feb 21 '25 16:02 stsp

Yes (tp7.0), but I have to try the 7.01 version as according to the patch file a different patch is needed for that

andrewbird avatar Feb 21 '25 17:02 andrewbird

r200fix is also able to fix tp 7.01 executables. I did notice that the example from https://github.com/dosemu2/dosemu2/issues/808 seems to be packed somehow. Maybe that's defeating the fix?

andrewbird avatar Feb 21 '25 17:02 andrewbird

I think dpmi is defeating a fix. Try building for prot mode in BP7.

Пятница, 21 февраля 2025 г получено от Andrew Bird:

andrewbird left a comment (dosemu2/comcom64#105)

r200fix is also able to fix tp 7.01 executables. I did notice that the example from https://github.com/dosemu2/dosemu2/issues/808 seems to be packed somehow. Maybe that's defeating the fix?

-- Reply to this email directly or view it on GitHub: https://github.com/dosemu2/comcom64/issues/105#issuecomment-2675125394 You are receiving this because you commented.

Message ID: @.***

stsp avatar Feb 21 '25 17:02 stsp

I think dpmi is defeating a fix.

Yes same program compiled for 'dos protected mode' still fails with runtime 200 error even with r200fix.

BTW my pascal knowledge is very old/forgotten, do you know how to reference a 'define' inside the program? I want to compile each test program and pass in a string. I see that you can do tpc -Dsomething, but how to add that into a string constant defeats me. I want each test program to print a unique string for capture by the test suite.

andrewbird avatar Feb 21 '25 18:02 andrewbird

ooh, Claude showed me a way. Have to see if it's true now.

andrewbird avatar Feb 21 '25 18:02 andrewbird

Nope, wishful thinking.

andrewbird avatar Feb 21 '25 19:02 andrewbird

There's a nice write up of what the error + fixes here - https://retrocomputing.stackexchange.com/a/12112

stuaxo avatar Feb 21 '25 19:02 stuaxo

I think you can do:

{$ifdef something}
some code
{$endif}

I am not sure if strings are possible, but usually you can get away with ifdefs. Also of course you can just run cpp before bpc - then you can use Cish macros.

stsp avatar Feb 21 '25 19:02 stsp

https://www.freepascal.org/docs-html/prog/progse5.html#x136-1370002.2 Freepascal says you can just use the defined symbol as macro. Not sure if it works in BP but worth a try.

stsp avatar Feb 21 '25 19:02 stsp

Also of course you can just run cpp before bpc - then you can use Cish macros.

Yes, thanks! I'll probably do something similar to this using python and generate the build batch file at the same time.

andrewbird avatar Feb 21 '25 23:02 andrewbird

https://retrocomputing.stackexchange.com/a/12112

Thanks @stuaxo , that's a very good read.

andrewbird avatar Feb 21 '25 23:02 andrewbird

So they say there are some TSRs that still fix it even in prot mode? I wonder what technique do they use. Maybe they intercept loading, in which case they won't work with packed executables?

stsp avatar Feb 22 '25 07:02 stsp

I added a PR for comcom r200fix test, see https://github.com/dosemu2/dosemu2/pull/2402. Essentially the test just loads each executable and checks that it outputs a known string (the name/version of the compiler used). As you can see below the all are working except the protected mode versions.

Interactive Prompt!
C:\>testit.bat
testit.bat
C:\>tp40
Turbo Pascal 4.00
C:\>tp55
Turbo Pascal 5.50
C:\>tp60
Turbo Pascal 6.00
C:\>r200fix tp700
Turbo Pascal 7.00
C:\>r200fix tp701
Turbo Pascal 7.01
C:\>r200fix bp700_rm
Borland Pascal 7.00 Real Mode
C:\>r200fix bp701_rm
Borland Pascal 7.01 Real Mode
C:\>copy rtm700.exe rtm.exe
rtm700.exe copied to c:\rtm.exe
        1 file(s) copied
C:\>r200fix bp700_pm
Runtime error 200 at 0001:0120.
C:\>copy rtm701.exe rtm.exe
rtm701.exe copied to c:\rtm.exe
        1 file(s) copied
C:\>r200fix bp701_pm
Runtime error 200 at 0001:0120.
C:\>rem end

andrewbird avatar Feb 22 '25 18:02 andrewbird

Then we need to ask @skitt (author of the aforementioned text on stackexchange) what is the suggested fix for prot-mode part. In particular he notes some TSRs exist that handle PM. I am not quite sure what technique can that be.

stsp avatar Feb 22 '25 18:02 stsp

The new r200fix tests can be run as follows

test/test_dosemu.py PPDOSGITTestCase.test_comcom_r200fix_protected PPDOSGITTestCase.test_comcom_r200fix_real
 
Test PP-DOS-GIT  Comcom r200fix Protected Mode                                   ... expected failure
Test PP-DOS-GIT  Comcom r200fix Real Mode                                        ... ok (  2.30s)

----------------------------------------------------------------------
Ran 2 tests in 4.422s

OK (expected failures=1)

andrewbird avatar Feb 23 '25 19:02 andrewbird

Maybe @karcherm knows what is the recommended fix for the prot-mode part, as he is mentioned in the articlle above.

stsp avatar Feb 23 '25 19:02 stsp

I had some failed experiment trying to tie into the protected mode, by trying to hook the DPMI protected mode entry routine. That doesn't work, because most (all?) DPMI implementations return the address of the protected mode entry routine from their protected mode INT2F handler, so a hooked real-mode/V86 INT2F handler is not even reached on 1687h.

I did not try to write a DPMI TSR (which is not supported with all DPMI servers, as I understand it), which would hook some protected mode interrupt vector that is called from the protected mode initialization routine of CRT, but that approach might work. For now, an on-disk patch is the only way to fix runtime error 200 that I know of.

karcherm avatar Feb 23 '25 19:02 karcherm

So the above article is probably inaccurate and it should say there are no TSRs to solve the prot-mode part.

most (all?) DPMI implementations return the address of the protected mode entry routine from their protected mode INT2F handler

I am not sure I understand that part. 1687h is supposed to be called in real mode, and the returned entry is supposed to be called in real mode. In fact, the only DPMI server that support 1687h in prot mode... is dosemu2. I implemented that when gcc-ia16 didn't support 32bit mode natively, so the 16bit client could re-request the entry and become a 32bit one. No one else needs this (neither me, as gcc-ia16 now supports 32bits natively). So I am not quite sure what do you mean.

DPMI TSR (which is not supported with all DPMI servers, as I understand it),

In fact, they all do. But what you refer to here, is the RSP functionality (Resident Service Provider) - this one is usually not supported. The difference between TSR and RSP is that TSR works as a separate DPMI client, so it can provide its services to real-mode apps, but the next-loaded DPMI client will overtake everything. RSP, instead, allows to install the init and termination hooks for every new client, so in theory that way you can provide the services to DPMI apps as well. In practice, however, the RSP init hook is called only once, and if later the Borland runtime installs his own handler for exception 0 (divizion by zero), then you hook nothing. So I really don't think either TSR or RSP can help in this particular case.

stsp avatar Feb 23 '25 20:02 stsp

Of course this doesn't mean we are out of luck... This just means yet another DPMI extension, yet another hack. :( Not something I'd like to do today.

stsp avatar Feb 23 '25 20:02 stsp

most (all?) DPMI implementations return the address of the protected mode entry routine from their protected mode INT2F handler

I am not sure I understand that part. 1687h is supposed to be called in real mode, and the returned entry is supposed to be called in real mode.

Exactly. I tried to hook 1687 in real mode to provide a "wrapper" entry point in my runtime-200-fix tool, that tried to hook protected mode interrupts to detect when the CRT unit is initializing in protected mode. Alas, all DPMI implementations i tested (also dosemu, dosemu2 was not a thing at that time) caught the 1687 call in their "supervisor handler" for INT 2F, so a real-mode hook of INT 2F could not provide an alternate entry point.

DPMI TSR (which is not supported with all DPMI servers, as I understand it),

In fact, they all do. But what you refer to here, is the RSP functionality (Resident Service Provider) - this one is usually not supported. [...] RSP, instead, allows to install the init and termination hooks for every new client, so in theory that way you can provide the services to DPMI apps as well.

So, RSP is what I was thinking about. My real-mode Borland runtime-error-200 fix is triggered by the CRT unit initialization code hooking Interrupt 1B using by calling Int21, AX=251B. I started to port that over to protected mode, intending to hook the INT 31 entry that is used by protected mode CRT to catch the Ctrl-Break interrupt, and perform the anti-divide-by-zero patch at that point in time. This means I very much intended to "offer a service" to the Turbo Pascal progam, namely triggering the hot-patch as soon as I detect CRT initialization.

karcherm avatar Feb 23 '25 21:02 karcherm