initial windows 3 enhanced support based on unstable kernel branch

This commit is contained in:
Kenneth J Davis 2021-08-19 11:46:10 -04:00
parent 292f3079be
commit 9186e6c5ed
5 changed files with 332 additions and 17 deletions

View File

@ -41,6 +41,7 @@ segment HMA_TEXT
extern _user_r
extern _ErrorMode
extern _InDOS
extern _winInstanced
extern _cu_psp
extern _MachineId
extern critical_sp
@ -276,7 +277,9 @@ int21_reentry:
jne int21_1
int21_user:
call dos_crit_sect
%IFNDEF WIN31SUPPORT
call end_dos_crit_sect
%ENDIF ; NOT WIN31SUPPORT
push ss
push bp
@ -362,15 +365,27 @@ int21_onerrorstack:
jmp short int21_exit_nodec
int21_2: inc byte [_InDOS]
int21_2:
%IFDEF WIN31SUPPORT ; begin critical section
; should be called as needed, but we just
; mark the whole int21 api as critical
call begin_dos_crit_sect
%ENDIF ; WIN31SUPPORT
inc byte [_InDOS]
mov cx,_char_api_tos
or ah,ah
jz int21_3
%IFDEF WIN31SUPPORT ; testing, this function call crashes
cmp ah,06h
je int21_3
%ENDIF ; WIN31SUPPORT
cmp ah,0ch
jbe int21_normalentry
int21_3:
call dos_crit_sect
%IFNDEF WIN31SUPPORT
call end_dos_crit_sect
%ENDIF ; NOT WIN31SUPPORT
mov cx,_disk_api_tos
int21_normalentry:
@ -390,6 +405,15 @@ int21_normalentry:
call _int21_service
int21_exit: dec byte [_InDOS]
%IFDEF WIN31SUPPORT
call end_dos_crit_sect ; release all critical sections
%if 0
push ax
mov ax, 8101h ; Leave Critical Section
int 2ah
pop ax
%endif
%ENDIF ; WIN31SUPPORT
;
; Recover registers from system call. Registers and flags
@ -415,11 +439,28 @@ int21_ret:
; ... and return.
;
iret
%IFDEF WIN31SUPPORT
;
; begin DOS Critical Section 1
;
;
begin_dos_crit_sect:
; we only enable critical sections if Windows is active
; we currently use winInstanced, but may need to use separate patchable location
cmp word [_winInstanced], 0
jz skip_crit_sect
push ax
mov ax, 8001h ; Enter Critical Section
int 2ah
pop ax
skip_crit_sect:
ret
%ENDIF ; WIN31SUPPORT
;
; end Dos Critical Section 0 thur 7
;
;
dos_crit_sect:
end_dos_crit_sect:
mov [_Int21AX],ax ; needed!
push ax ; This must be here!!!
mov ah,82h ; re-enrty sake before disk stack

View File

@ -122,10 +122,14 @@ WinIdle: ; only HLT if at haltlevel 2+
Int2f3: cmp ax,1680h ; Win "release time slice"
je WinIdle
cmp ah,16h
je FarTabRetn ; other Win Hook return fast
cmp ah,12h
je IntDosCal ; Dos Internal calls
cmp ah,13h
je IntDosCal ; Install Int13h Hook
cmp ah,16h
je IntDosCal ; Win (Multitasking) Hook
cmp ah,46h
je IntDosCal ; Win Hook to avoid MCB corruption
cmp ax,4a01h
je IntDosCal ; Dos Internal calls
@ -135,6 +139,9 @@ Int2f3: cmp ax,1680h ; Win "release time slice"
cmp ax,4a33h ; Check DOS version 7
jne Check4Share
xor ax,ax ; no undocumented shell strings
xor bx,bx ; RBIL undoc BX = ?? (0h)
; " DS:DX ASCIIZ shell exe name
; " DS:SI SHELL= line
iret
Check4Share:
%endif

View File

@ -31,6 +31,8 @@
#include "portab.h"
#include "globals.h"
#include "nls.h"
#include "win.h"
#include "debug.h"
#ifdef VERSION_STRINGS
BYTE *RcsId =
@ -1901,7 +1903,12 @@ struct int2f12regs {
UWORD callerARG1; /* used if called from INT2F/12 */
};
/* On input pr->AX==0x12xx, 0x4A01 or 0x4A02
extern intvec BIOSInt13, UserInt13, BIOSInt19;
/* WARNING: modifications in `r' are used outside of int2F_12_handler()
* On input r.AX==0x12xx, 0x4A01 or 0x4A02
* also handle Windows' DOS notification hooks, r.AH==0x16 and r.AH==0x13
*/
VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr)
{
@ -1931,6 +1938,252 @@ VOID ASMCFUNC int2F_12_handler(struct int2f12regs FAR *pr)
r.BX = size;
return;
}
else if (r.AH == 0x13) /* set disk interrupt (13h) handler */
{
/* set new values for int13h calls, and must return old values */
register intvec tmp = UserInt13;
UserInt13 = MK_FP(r.ds, r.DX); /* int13h handler to use */
r.ds = FP_SEG(tmp); r.DX = FP_OFF(tmp);
tmp = BIOSInt13;
BIOSInt13 = MK_FP(r.es, r.BX); /* int13h handler to restore on reboot */
r.es = FP_SEG(tmp); r.BX = FP_OFF(tmp);
return;
}
else if (r.AH == 0x16) /* Window/Multitasking hooks */
{
#ifdef WIN31SUPPORT /* See "DOS Internals" or RBIL under DOSMGR for details */
switch (r.AL)
{
/* default: unhandled requests pass through unchanged */
case 0x0: /* is Windows active */
case 0x0A: /* identify Windows version */
{
/* return AX unchanged if Windows not active */
break;
} /* 0x0, 0x0A */
case 0x03: /* Windows Get Instance Data */
{
/* This should only be called if AX=1607h/BX=15h is not supported. */
/* The data returned here corresponds directly with text entries that
can also be in INSTANCE.386 [which in theory means Windows could
be updated to support FD kernel without responding to these?].
*/
DebugPrintf(("get instance data\n"));
break;
} /* 0x03 */
case 0x05: /* Windows Startup Broadcast */
{
/* After receiving this call we activate compatibility changes
as DOS 5 does, though can wait until 0x07 subfunc 0x01
*/
/* on entry:
DX flags, bit 0 is set(=1) for standard mode
DI Windows version#, major# in high byte
CX 0, set on exit to nonzero to fail load request
DS:SI is 0000:0000, for enhanced mode, at most 1 program can
set to memory manager calling point to disable V86
ES:BX is 0000:0000, set to startup structure
*/
r.CX = 0x0; /* it is ok to load Windows, give it a shot anyway :-) */
r.es = FP_SEG(&winStartupInfo);
r.BX = FP_OFF(&winStartupInfo);
winStartupInfo.winver = r.di; /* match what caller says it is */
winInstanced = 1; /* internal flag marking Windows is active */
DebugPrintf(("Win startup\n"));
break;
} /* 0x05 */
case 0x06: /* Windows Exit Broadcast */
{
/* can do nothing or can remove any changes made
specifically for Windows, must preserve DS.
Note: If Windows fatally exits then may not be called.
*/
winInstanced = 0; /* internal flag marking Windows is NOT active */
DebugPrintf(("Win exit\n"));
break;
} /* 0x06 */
case 0x07: /* DOSMGR Virtual Device API */
{
DebugPrintf(("Vxd:DOSMGR:%x:%x:%x:%x\n",r.AX,r.BX,r.CX,r.DX));
if (r.BX == 0x15) /* VxD id of "DOSMGR" */
{
switch (r.CX)
{
/* default: unhandled requests pass through unchanged */
case 0x00: /* query if supported */
{
r.CX = winInstanced; /* should always be nonzero if Win is active */
r.DX = FP_SEG(&nul_dev); /* data segment / segment of DOS drivers */
r.es = FP_SEG(&winPatchTable); /* es:bx points to table of offsets */
r.BX = FP_OFF(&winPatchTable);
break;
}
case 0x01: /* enable Win support, ie patch DOS */
{
/* DOS 5+ return with bitflags unchanged, Windows critical section
needs are handled without need to patch. If this
function does not return successfully windows will
attempt to do the patching itself (very bad idea).
On entry BX is bitflags describing support requested,
and on return DX is set to which we can support.
Note: any we report as unhandled Windows will attempt
to patch kernel to handle, probably not a good idea.
0001h: enable critical section signals (int 2Ah functions
80h/81h) to allow re-entering DOS while InDOS.
0002h: allow nonzero local machine ID, ie different VMs
report different values.
FIXME: does this mean we need to set this or does Windows?
0004h: split up binary reads to increase int 2Ah function 84h scheduling
/ turn Int 21h function 3Fh on STDIN into polling loop
0008h: notify Windows of halting due to internal stack errors
0010h: notify Windows of logical drive map change ("Insert disk X:")
*/
r.BX = r.DX; /* sure we support everything asked for, ;-) */
r.DX = 0xA2AB; /* on succes DX:AX set to A2AB:B97Ch */
r.AX = 0xB97C;
/* FIXME: do we need to do anything special for FD kernel? */
break;
}
case 0x02: /* disable Win support, ie remove patches */
{
/* Note: if we do anything special in 'patch DOS', undo it here.
This is only called when Windows exits, can be ignored.
*/
r.CX = 0; /* for compatibility with MS-DOS 5/6 */
break;
}
case 0x03: /* get internal structure sizes */
{
if (r.CX & 0x01) /* size of Current Directory Structure in bytes */
{
r.DX = 0xA2AB; /* on succes DS:AX set to A2AB:B97Ch */
r.AX = 0xB97C;
r.CX = sizeof(struct cds);
}
else
r.CX = 0; /* unknown or unsupported structure requested */
break;
}
case 0x04: /* Get Instancing Exemptions */
{
/* On exit BX is bit flags denoting data that is instanced
so Windows need not instance it. DOS 5&6 fail with DX=CX=0.
0001h: Current Directory Structure
0002h: System File Table and device status of STDOUT
0004h: device driver chain
0008h: Swappable Data Area
*/
r.DX = 0xA2AB; /* on succes DX:AX set to A2AB:B97Ch */
r.AX = 0xB97C;
r.BX = 0; /* a zero here tells Windows to instance everything */
break;
}
case 0x05: /* get device driver size */
{
/* On entry ES:DI points to possible device driver
if is not one return with AX=BX=CX=DX=0
else return BX:CX size in bytes allocated to driver
and DX:AX set to A2AB:B97Ch */
mcb FAR *smcb = MK_PTR(mcb, (r.ES-1), 0); /* para before is possibly submcb segment */
/* drivers always start a seg:0 (DI==0), so if not then either
not device driver or duplicate (ie device driver file loaded
is of multi-driver variety; multiple device drivers in same file,
whose memory was allocated as a single chunk)
Drivers don't really have a MCB, instead the DOS MCB is broken
up into submcbs, which will have a type of 'D' (or 'E')
So we check that this is primary segment, a device driver, and owner.
*/
if (!r.DI && (smcb->m_type == 'D') && (smcb->m_psp == r.ES))
{
ULONG size = smcb->m_size * 16ul;
r.BX = hiword(size);
r.CX = loword(size);
r.DX = 0xA2AB; /* on succes DX:AX set to A2AB:B97Ch */
r.AX = 0xB97C;
break;
}
r.DX = 0; /* we aren't one so return unsupported */
r.AX = 0;
r.BX = 0;
r.CX = 0;
break;
}
}
}
DebugPrintf(("Vxd:DOSMGR:%x:%x:%x:%x\n",r.AX,r.BX,r.CX,r.DX));
break;
} /* 0x07 */
case 0x08: /* Windows Init Complete Broadcast */
{
DebugPrintf(("Init complete\n"));
break;
} /* 0x08 */
case 0x09: /* Windows Begin Exit Broadcast */
{
DebugPrintf(("Exit initiated\n"));
break;
} /* 0x09 */
case 0x0B: /* Win TSR Identify */
{
DebugPrintf(("TSR identify request.\n"));
break;
} /* 0x0B */
case 0x80: /* Win Release Time-slice */
{
/* This function is generally only called in idle loops */
DosIdle_hlt();
r.AX = 0;
/* DebugPrintf(("Release Time Slice\n")); */
break;
} /* 0x80 */
case 0x81: /* Win3 Begin Critical Section */
{
DebugPrintf(("Begin CritSect\n"));
break;
} /* 0x81 */
case 0x82: /* Win3 End Critical Section */
{
DebugPrintf(("End CritSect\n"));
break;
} /* 0x82 */
case 0x8F: /* Win4 Close Awareness */
{
if (r.DH != 0x01) /* query close */
r.AX = 0x0;
/* else r.AX = 0x168F; don't close -- continue execution */
break;
} /* 0x8F */
default:
DebugPrintf(("Win call (int 2Fh/16h): %04x %04x %04x %04x\n", r.AX, r.BX, r.CX, r.DX));
break;
}
#endif
return;
}
else if (r.AH == 0x46) /* MS Windows WinOLDAP switching */
{
#ifdef WIN31SUPPORT /* See "DOS Internals" under DOSMGR or RBIL for details */
if (r.AL == 0x01) /* save MCB */
{
/* To prevent corruption when dos=umb where Windows 3.0 standard
writes a sentinel at 9FFEh, DOS 5 will save the MCB marking
end of conventional memory (ie MCB following caller's PSP memory
block [which I assume occupies all of conventional memory] into
the DOS data segment.
Note: presumably Win3.1 uses the WinPatchTable.OffLastMCBSeg
when DOS ver > 5 to do this itself.
*/
/* FIXME: Implement this! */
}
else if (r.AL == 0x02) /* restore MCB */
{
/* Copy the MCB we previously saved back. */
/* FIXME: Implement this! */
}
#endif
return;
}
/* else (r.AH == 0x12) */
switch (r.AL)
{

View File

@ -320,14 +320,22 @@ segment _LOWTEXT
global _intvec_table
_intvec_table: db 10h
dd 0
; used by int13 handler and get/set via int 2f/13h
global _BIOSInt13 ; BIOS provided disk handler
global _UserInt13 ; actual disk handler used by kernel
db 13h
dd 0
_BIOSInt13: dd 0
db 15h
dd 0
; used for cleanup on reboot
global _BIOSInt19
db 19h
dd 0
_BIOSInt19: dd 0
db 1Bh
dd 0
; default to using BIOS provided disk handler
db 13h
_UserInt13: dd 0
; floppy parameter table
global _int1e_table
@ -480,7 +488,7 @@ _winStartupInfo:
dw instance_table,seg instance_table ; array of instance data
instance_table: ; should include stacks, Win may auto determine SDA region
; we simply include whole DOS data segment
dw 0, seg _DATASTART ; [SEG:OFF] address of region's base
dw seg _DATASTART, 0 ; [SEG:OFF] address of region's base
dw markEndInstanceData wrt seg _DATASTART ; size in bytes
dd 0 ; 0 marks end of table
dw 0 ; and 0 length for end of instance_table entry
@ -508,7 +516,9 @@ _winPatchTable: ; returns offsets to various internal variables
_firstsftt:
dd -1 ; link to next
dw 5 ; count
times 5*59 db 0 ; reserve space for the 5 sft entries
db 0 ; pad byte so next value on even boundary
; Some references seem to indicate that this data should start at 01fbh in
; order to maintain 100% MS-DOS compatibility.
times (01fbh - ($ - DATASTART)) db 0

View File

@ -112,6 +112,7 @@ VOID ASMCFUNC FreeDOSmain(void)
/* install DOS API and other interrupt service routines, basic kernel functionality works */
setup_int_vectors();
/* check if booting from floppy/CD */
CheckContinueBootFromHarddisk();
/* display copyright info and kernel emulation status */
@ -247,24 +248,27 @@ STATIC void setup_int_vectors(void)
{ 0x1, FP_OFF(empty_handler) }, /* single step */
{ 0x3, FP_OFF(empty_handler) }, /* debug breakpoint */
{ 0x6, FP_OFF(int6_handler) }, /* invalid opcode */
{ 0x19, FP_OFF(int19_handler) },
{ 0x19, FP_OFF(int19_handler) }, /* BIOS bootstrap loader, vdisk */
{ 0x20, FP_OFF(int20_handler) },
{ 0x21, FP_OFF(int21_handler) },
{ 0x21, FP_OFF(int21_handler) }, /* primary DOS API */
{ 0x22, FP_OFF(int22_handler) },
{ 0x24, FP_OFF(int24_handler) },
{ 0x25, FP_OFF(low_int25_handler) },
{ 0x25, FP_OFF(low_int25_handler) }, /* DOS abs read/write calls */
{ 0x26, FP_OFF(low_int26_handler) },
{ 0x27, FP_OFF(int27_handler) },
{ 0x28, FP_OFF(int28_handler) },
{ 0x2a, FP_OFF(int2a_handler) },
{ 0x2f, FP_OFF(int2f_handler) }
{ 0x2f, FP_OFF(int2f_handler) } /* multiplex int */
};
struct vec *pvec;
struct lowvec FAR *plvec;
int i;
for (plvec = intvec_table; plvec < intvec_table + 5; plvec++)
/* save current int vectors so can restore on reboot and call original directly */
for (plvec = intvec_table; plvec < intvec_table + 6; plvec++)
plvec->isv = getvec(plvec->intno);
/* install default handlers */
for (i = 0x23; i <= 0x3f; i++)
setvec(i, empty_handler);
HaltCpuWhileIdle = 0;
@ -273,7 +277,7 @@ STATIC void setup_int_vectors(void)
pokeb(0, 0x30 * 4, 0xea);
pokel(0, 0x30 * 4 + 1, (ULONG)cpm_entry);
/* these two are in the device driver area LOWTEXT (0x70) */
/* handlers for int 0x1b and 0x29 are in the device driver area LOWTEXT (0x70) */
setvec(0x1b, got_cbreak);
setvec(0x29, int29_handler); /* required for printf! */
}