Subject: [Freedos-kernel] Analyzing Win386 compatibility
Date: Sun, 10 Oct 2004 20:17:56 +0200 (MEST)


Hi, I did some experiments with a MS DOS 6.20 system...

The DOS data segment is 10e, list of lists is at 26 there.
Int 2f.1603 is supported (get simple instance info), and the
returned data is:
word 70 (IO segment), 0 (no DOS 3.2 STACKS active), 6 (item count)
items (each segment, offset, size) are:
dosds:22,2 -> LoL[-4]
 -4     WORD    (DOS 3.0+) pointer in DOS data segment of unread CON input
                when CON is read via a handle, DOS reads an entire line,
                  and returns the requested portion, buffering the rest
                  for the next read.  0000h indicates no unread input
dosds:32,4 -> LoL[0c]
 0Ch    DWORD   pointer to active CON device's header (most recently loaded
                  driver with STDIN bit set)                           
dosds:1f9,106 -> looks like a buffer for int 21.0a (get string from stdin)
dosds:300,1 -> unknown, any idea? Value seems to change from time to time
 (contents of the other items were: 0, 70:23, and 0 1 "...", where "..." is
 the 0d terminated line of text which I typed in DEBUG before...)
dosds:fc0,22 -> unknown data structure, any ideas? Contents:
 fe ff 46 04 00 01 46 04 / e9 3b 46 17 22 e0 37 6b / 2c e4 2c ba 2d cf 2e 18
 2f ca 2f ee 2f e0 37 e0 / 37 ff (... but the two 46 04 change to e1 0f when
 no HIMEM is loaded ...)
70:0c,1 -> Unknown. First byte of the word right before the known LoL[-...]
 data items. Content: 0.

Int 2f.1607.15 is indeed supported by DOS kernel, at least partially! The
supported sub functions report:
0 query instance processing -> reports "instanced" (CX 1, common for DOS 5+),
  "default DOS driver segment 70" (DX 0), patch table in dosds, with contents:
  5 (version word), 5ec (saveds), 5ea (savebx), 321 (indos), 33e (userid),
  315 (critical section patch table), 8c (umb head).
 All values (except version) are pointers into dosds, and the contents
 are: saveds (PSP of DEBUG), savebx (inside DEBUG), indos (byte) 0,
 userid (word) 0, patchtable [d0c,d0c,d0c,d0c,0] (value at dosds:d0c is 80)
 and -1 (no UMB head segment).

1 request patching -> seems to support all 5 patch types, but did not figure
 out what exactly is done by the patches. Types are: 1 enable critical sect.,
 2 NOP out USERID set/check, 4 turn int 21.3f for STDIN into a polling loop
 (i.e. do not use int 16.00 without checking for keystroke with int 16.01 1st),
 8 "trap win386 sysinit stack fault" (???), 10 (hex) "trap DJ mechanism msg.".

2 undo patching -> according to RBIL 61, this is a dummy function in MS DOS...

3 get size info -> size of data item type 1, CurrentDirStructure, is 58 (hex).
 No other item types seem to be supported (reports 0 size for other types).

4 determine instanced data structures -> not supported, neither CDS nor SFT
 nor device list nor SDA are instanced, it seems.

5 driver info -> given a driver segment ES, this reports a magic DX AX if a
 driver is found there and a value BX CX which is the driver size in bytes.


Does anybody have an idea how to measure driver sizes? Any idea what the
FreeDOS equivalent of the dosds:1f9 buffer is? And the meaning of dosds:300
byte and dosds:fc0 data structure and 70:c byte? What would be the FreeDOS
equivalent of that?

All the instance stuff only makes sense if we get manipulation-proof SFT
processing: Each fnode has to contain a checksum for (part of) the SFT entry
to which it corresponds, and if the checksum checks wrong, the fnode has to
be regenerated. How complicated would it be to implement that?

Other comments:
Bitfields for DOSMGR patch requests:
Bit(s)  Description     (Table 02636)
 0      enable critical sections
   There is [386Enh] InDOSPolling=1 for system.ini, maybe an alternative...
 1      NOP setting/checking user ID
   What is using any user ID at all? The int 21.5d0x commit/close by PC,
   PSP, name functions???
 2      turn INT 21/AH=3Fh on STDIN into polling loop
   This probably has to happen in read_char_sft_dev (called by read_line etc.)
   which already does look like a polling loop!?
 3      trap stack fault in "SYSINIT" to WIN386
   Any idea WHAT causes a stack fault here and HOW and how to TRAP that???
 4      BIOS patch to trap "Insert disk X:" to WIN386
   This is probably not needed if we support int 2f.4a00.cx=0, the function
   to suppress DJ mechanism interaction: On call, DH=new drive number, DL=
   old drive number. On return, CX=-1 to skip BOTH the DJ message and the
   wait for key thing after it.


Finally I analyzed some of the sections which Win 3.x tries to patch when
you use 386 enhanced mode. Please comment.

One section which has to be present (the lines with *) is:
  cli / mov by [indos],0 / mov ss,ax / mov sp,ax
* sti
* push ds
* push si
* mov es,dx
* mov ds,dx
  mov ax,bx / retf
Which part of kernel could that be?

One section after which a breakpoint is inserted:
  mov [cs:57e],ds
  mov [cs:57c],dx
  mov bx,cs
  mov ds,bx
  inc by [2cf]
  xor ax,ax (breakpoint is inserted after this line)
In MS DOS, directly after this section, we have ANOTHER
section in which a breakpoint is inserted, at line *
  push ax
  mov ax,[ss:2ea] (which is 0)
* cmp ax,[es:di+disp8] (value of disp8 does not matter for Win3.x,
  but in my test it was 2F, and the next command was pop ax)
In MS DOS, directly after the pop ax, another required section is
found (Win 3.x insists that all this 3 sections are found in 70:xx!)...
  push es
  pop ds
* mov bx,di (Win inserts a breakpoint here)
  xor ax,ax
  mov dx,ax
  call ... (seems to point into the void! Win allows any value here...)
After this required area, the code continues, and Win reads out the disp16
value (here: 309) in the marked line for some reason, triggered by the
presence of the previous (push es...) section. The 3 sections do not have
to be consecutive, but in this DOS, they are:
  push ds / lds si,[ss:536] / call ... (nothing?) / mov dx,di / mov ah,86
* mov di,[ss:309]
  test di,8000 / jz PANIC / call ... (nothing?) / mov di,dx / or al,al
  jz PANIC / cmp al,3 / jz OTHER / pop ds / jmp "the mov bx,di line with
  the breakpoint above"
OTHER: pop di / les di,[ss:536] / jmp ... (the pointer seems to point to
  some MCB surfing function)
PANIC: pop di / mov di,dx
  ** Win 3.x inserts breakpoints at OTHER and PANIC, too, using a fixed
  offset from the "push es..." section again... **
PANICTXT: lodsb / cmp al,$ / jz HALT / mov bl,7 / mov ah,e / int 10
  jmp PANICTXT
HALT: jmp short HALT
  ** Win 3.x does not insist on finding this code pattern, but if it finds
  the PANICTXT ... HALT pattern, it inserts a breakpoint at HALT... **
The 6 breakpoints and 1 fetched value of the above 3 required and 1 optional
sections starting with mov [cs:57e],ds ... are hopefully all only important
to trap some kind of error handling. The first section (with SSSP=AXDI, as
I now see... I had written AXAX above...!!!) which starts with STI PUSH DS
seems to be more interesting. But what exactly does THAT section do when?

Another mysterious required section is:
  cmp al,7
  jb x
  cmp al,9
  jbe ... (disp8 is 1a here, but Win might expect 12 here?)
x mov si,dx
  mov bx,[si+12] (Win inserts a breakpoint after this line)
In this DOS, a test by [ss:1030],1 / jnz y / mov [ss:33e],bx / mov bx,[si+14]
y mov [ss:33c],bx
z ... follows. z is the target of the jbe here. No idea what this function
is supposed to do and why it treats AL values 7..9 specially. Any hints?

Finally we have an optional section (if Win finds it, it adds a breakpoint
at the start) is "xor ah,ah / int 16 / pop bx", with the "xor ah,ah" being
encoded as 32 e4 (FreeDOS DEBUG uses 30 e4, so be careful when you try to
simulate that...). I found out that this section is part of the DJ system:
push cx dx
mov dl,[es:di+5]
mov dh,dl
xor dh,1
sub cx,cx
mov ax,4a00
int 2f
inc cx
jz SKIPDJ (If a GUI has installed an int 2f.4a00 handler, it will return
  from the call after showing the DJ dialog (insert disk X: and press a key)
  and have CX set to -1. Without an handler, CX will still be 0.
add dl,41 (convert to ASCII)
mov [cs:17ec],dl
mov si,17d5 (DS seems to be 553 here, as the message is at 70:6605, right
  after this bit of code...)
push bx
lodsb cs
djloop: int 29
lodsb cs
or al,al
jnz djloop
call CLEARBUF (does: mov by [c],0 / do int 16.1 while NZ / clc / ret)
xor ah,ah
int 16
pop bx
SKIPDJ: pop dx
pop cx
ret



Phew. I hope I forgot no sections or other important details. Hopefully
this analysis can help to get FreeDOS closer to 386 enhanced mode Win 3.x
compatibility. Without int 2f.13 / 2f.1607.15 / 2f.1603 support, all Win 3.x
versions will refuse to enter 386 enhanced mode. For 3.1, that means that
you have to use /s explicitly if emm386 is loaded, and for WfW 3.11, you can
only use the "do not load any VXD" debugging mode which does not even offer
DOS boxes. Actually even without 386 enhanced mode our fnodes spoil our DOS
box compatibility. Opening a DOS box in Win 3.1 standard mode crashes - the
best which you can get is a crash after showing the "use EXIT to return to
Win..." message, or maybe a "drop to DOS, leave Win" style almost-crash right
now. Anyway, I hope that having int 2f.1607.15 / 2f.1603 support will already
give very interesting improvements (Win no longer refusing to load in 386
mode, and maybe even working as long as you use no DOS boxes, given that
you use those /D:FSVX options to avoid some compatibility endangering Win
activities...).


Cheers, Eric.

