FDOS/kernel

Dosemu2 test suite test `test_create_new_psp` still failing on current git master

andrewbird opened this issue · 9 comments

Since you seem to be chasing down a few FreeDOS kernel bugs, you might be interested in this? I have a test in Dosemu2 that creates a new PSP. Historically the test has always passed on MS-DOS 6.22 and DR-DOS 7.01, FDPP was subsequently fixed, and FreeDOS is currently still broken. Here is a test run

ajb@polly:/clients/common/dosemu2.git$ test/test_dos.py test_create_new_psp
Test DR-DOS-7.01 Create New PSP                                                  ... ok (  2.53s)
Test FR-DOS-1.20 Create New PSP                                                  ... skipped 'known failure'
Test FR-DOS-GIT  Create New PSP                                                  ... FAIL
Test MS-DOS-6.22 Create New PSP                                                  ... ok (  2.20s)
Test PP-DOS-GIT  Create New PSP                                                  ... ok (  1.93s)

The test does this

"""
.text                                                                           
.code16                                                                         
                                                                                
    .globl  _start16                                                            
_start16:                                                                       
                                                                                
# designate target segment                                                      
    push    %%cs                                                                
    pop     %%ax                                                                
    addw    $0x0200, %%ax                                                       
    movw    %%ax, %%es                                                          
                                                                                
# create PSP in memory                                                          
    movw    %%es, %%dx                                                          
    movw    $0x2600, %%ax                                                       
    int     $0x21                                                               
                                                                                
# see if the exit field is set                                                  
    cmpw    $0x20cd, %%es:(0x0000)                                              
    jne     extfail                                                             
                                                                                
# see if the parent PSP is zero                                                 
    cmpw    $0x0000, %%es:(0x0016)                                              
    je      pntzero                                                             
                                                                                
# see if the parent PSP points to a PSP                                         
    push    %%es                                                                
    pushw   %%es:(0x0016)                                                       
    pop     %%es                                                                
    cmpw    $0x20cd, %%es:(0x0000)                                              
    pop     %%es                                                                
    jne     pntnpsp                                                             
                                                                                
# see if the 'INT 21,RETF' is there                                             
    cmpw    $0x21cd, %%es:(0x0050)                                              
    jne     int21ms                                                             
    cmpb    $0xcb, %%es:(0x0052)                                                
    jne     int21ms                                                             
                                                                                
# see if the cmdtail is there                                                   
    movzx   %%es:(0x0080), %%cx                                                 
    cmpw    $%d, %%cx                                                           
    jne     cmdlngth                                                            
                                                                                
    inc     %%cx                                                                
    mov     $cmdline, %%si                                                      
    mov     $0x0081, %%di                                                       
    cld                                                                         
    repe    cmpsb                                                               
    jne     cmdtail                                                             
                                                                                
success:                                                                        
    movw    $successmsg, %%dx                                                   
    jmp     exit                                                                
                                                                                
extfail:                                                                        
    movw    $extfailmsg, %%dx                                                   
    jmp     exit                                                                
                                                                                
pntzero:                                                                        
    movw    $pntzeromsg, %%dx                                                   
    jmp     exit                                                                
                                                                                
pntnpsp:                                                                        
    movw    $pntnpspmsg, %%dx                                                   
    jmp     exit                                                                
                                                                                
int21ms:                                                                        
    movw    $int21msmsg, %%dx                                                   
    jmp     exit                                                                
                                                                                
cmdlngth:                                                                       
    movw    $cmdlngthmsg, %%dx                                                  
    jmp     exit                                                                
                                                                                
cmdtail:                                                                        
    movw    $cmdtailmsg, %%dx                                                   
    jmp     exit                                                                
                                                                                
exit:                                                                           
    movb    $0x9, %%ah                                                          
    int     $0x21                                                               
                                                                                
    movb    $0x4c, %%ah                                                         
    int     $0x21                                                               

extfailmsg:                                                                     
    .ascii  "PSP exit field not set to CD20\r\n$"                               
                                                                                
pntzeromsg:                                                                     
    .ascii  "PSP parent is zero\r\n$"                                           
                                                                                
pntnpspmsg:                                                                     
    .ascii  "PSP parent doesn't point to a PSP\r\n$"                            
                                                                                
int21msmsg:                                                                     
    .ascii  "PSP is missing INT21, RETF\r\n$"                                   
                                                                                
cmdlngthmsg:                                                                    
    .ascii  "PSP has incorrect command length\r\n$"                             
                                                                                
cmdtailmsg:                                                                     
    .ascii  "PSP has incorrect command tail\r\n$"                               
                                                                                
successmsg:                                                                     
    .ascii  "PSP structure okay\r\n$"                                           
                                                                                
# 05 20 54 45 53 54 0d                                                          
cmdline:                                                                        
    .ascii " %s\r"                                                              
                                                                                
""" % (1 + len(cmdline), cmdline))

I've added the prebuilt binary and its gnu assembler source here create_new_psp.zip. You can run it with the testit.bat file

As you will see the error is PSP parent is zero

C:\>testit.bat
testit.bat

C:\>c:\getnwpsp COMMAND TAIL TEST
PSP parent is zero

Note: FreeDOS is tested here built using the gcc-elf-ia16 compiler, though I'm not sure if that is significant,

Hello @andrewbird,

Hmm... this is one area where Ralf Brown's Interrupt List turns out to be wrong. (It says "the parent PSP field is set to 0", but that is only the case for MS-DOS 1.x.)

Thank you!

@tkchia , I can't claim to understand the full significance of the parent PSP field, as I remember @stsp was looking for a problem with the PSP on FDPP and asked me to write a test to establish the values on several flavours / versions of DOS. This test was the result of that investigation and has remained within the test suite since. I have some other failing tests with FreeDOS GIT around FCB file functions when using wildcards, but I'll wait until later to see how easy it is to document those in a manner that doesn't require people to run dosemu and the test suite itself.

Thank you!

stsp commented

Please refer to this comment:
dosemu2/fdpp#112 (comment)
But I don't think it is possible to
get this game to work on freedos.
The problem with zeroed out PSP
is just one of many tricks it does
to detect the DOS clones. I think
me and Andrew spent many months
on reverse-engineering the full scheme.

Hello @andrewbird, hello @stsp,

@tkchia , I can't claim to understand the full significance of the parent PSP field, as I remember @stsp was looking for a problem with the PSP on FDPP and asked me to write a test to establish the values on several flavours / versions of DOS.

Hmm... I decided to look at the open-sourced MS-DOS 1.x and 2.x code a bit.

It seems that DOS 1's command.com uses the int 0x21, ah = 0x26 syscall to create a new PSP when running a child program.

  • (Yes — in DOS 1, the code to start a new child process is in the interpreter, not the kernel.)
  • Basically the call just copies whatever is in the current process's PSP (which cs is assumed to point to...).
  • I do not think any DOS 1.x programs actually depend on their PSP's "parent PSP" field being any particular value.

As for MS-DOS 2.x, its exec syscall (int 0x21, ah = 0x4b) is actually internally implemented in terms of several other syscalls, one of them being int 0x21, ah = 0x55.

  • Unlike 0x26, this will specifically create a child PSP, whose "parent PSP" field points back to the current process's PSP.
  • (In addition, RBIL says that "the reference count for each inherited file is incremented".)

So — on second thought — my current guess is, in terms of documented behaviour, there is no actual guarantee that the parent PSP that comes out of ah = 0x26 should be any particular value. It will probably be a "good-to-have feature", but not super-essential, to make FreeDOS's behaviour match that of MS-DOS in this case.

But I don't think it is possible to get this game to work on freedos.

Well, games that do anti-debugging tricks to try to detect emulators are always interesting... :-)

Thank you!

stsp commented

Our ticket ends on anti-debugger tricks,
but elsewhere we analyzed lots of tricks
to detect dos clones (like resizing psp
to 0 and many more).
DOS is full of undocumented behaviour,
so I do not support your judgement
based on that, but unless you can make
the whole game to work, this is indeed
absolutely unimportant to support.

Hello @stsp,

Well, important or not, I have submitted a pull request... :-) Thank you!

The test case passes now, which pleases me greatly!

ajb@polly:/clients/common/dosemu2.git$ test/test_dos.py FRDOSGITTestCase.test_create_new_psp
Test FR-DOS-GIT  Create New PSP                                                  ... ok (  3.11s)

----------------------------------------------------------------------
Ran 1 test in 3.137s

OK

Thank you!

stsp commented

Then you may as well dig the rest of
the changes to get the aforementioned
game working. Which would be an
interesting quest, as there were lots of
false-starts, reverted changes etc.
That game was a real pita.
Lets see if you can. :)

The patch is now applied.

Thank you!