Hi,
I got this feeling that I'm absolutly wrong in this but here goes...
The way that I see Interrupt handling in wine is that when a real-mode dos executable is loaded, the processor (or the os mabe?) is forced into v86 were the int xx intruction is not privilaged. In this mode an exception is issued when an int xx is encountered and is then handeld by the exception handler is dosvm.c. Which in turn checks if the we have a builtin handler for the interrupt and if so then we simply call its handler as defined in real_mode_handlers. But when the app switches to protected mode, the int xx instuction becomes privilaged and gets handeld by EmulateInstruction. In this function the 32-bit version is not implemented but the 16-bit version is (Is this correct (the one is 16-bit the other 32-bit)? If not then what does long_op symbolise?) Is it likley that this piece of code will ever get called? And if so then why does it assume that the insterrupt it is emulating is not builtin?
What all of this probable garbage came from is: What will it take to emulate int xx from 32-bit code?
nog.
On Sat, 16 Feb 2002, Nog wrote:
The way that I see Interrupt handling in wine is that when a real-mode dos executable is loaded, the processor (or the os mabe?) is forced into v86 were the int xx intruction is not privilaged.
Well, int is sorta privileged in vm86 mode, otherwise an exception wouldn't be raised...
In this mode an exception is issued when an int xx is encountered and is then handeld by the exception handler is dosvm.c. Which in turn checks if the we have a builtin handler for the interrupt and if so then we simply call its handler as defined in real_mode_handlers. But when the app switches to protected mode, the int xx instuction becomes privilaged and gets handeld by EmulateInstruction. In this function the 32-bit version is not implemented but the 16-bit version is (Is this correct (the one is 16-bit the other 32-bit)?
That's correct.
If not then what does long_op symbolise?) Is it likley that this piece of code will ever get called?
It should never be called by Win32 apps, which is why 32-bit ints aren't implemented. It's probably different for DOS apps that use 32-bit DPMI, though, but those apps were never Wine's primary goal...
And if so then why does it assume that the insterrupt it is emulating is not builtin?
The table of 16-bit interrupt entry points is initialized from wprocs.dll (dlls/kernel/wprocs.spec), so it doesn't need to assume anything.
What all of this probable garbage came from is: What will it take to emulate int xx from 32-bit code?
A sane mechanism to handle those interrupt vectors, probably.
Ove Kaaven wrote:
On Sat, 16 Feb 2002, Nog wrote:
[SNIP]
And if so then why does it assume that the insterrupt it is emulating is not builtin?
The table of 16-bit interrupt entry points is initialized from wprocs.dll (dlls/kernel/wprocs.spec), so it doesn't need to assume anything.
This was my point. When emulating these interrupts it pushes the values of Eflags, Cs and Eip onto the stack but none of the interrupt handlers call the iret instruction or pop anything off the stack. What have I missed?
What all of this probable garbage came from is: What will it take to emulate int xx from 32-bit code?
A sane mechanism to handle those interrupt vectors, probably.
I assume that the Would this be somthing like the code in msdos/interrupts.c? But then why do we need to have 2 tables for interrupts (one in msdos/interrupts.c, the other in dlls/winedos/dosvm.c)? The only explanation I can come up with is that mabe, just mabe, the interrupts in wproc.spec get called from 16-bit windows.
Back to implementing int xx from 32-bit code, are all of the interrupts availible in real mode availible in protected mode?
nog.
On Sat, 16 Feb 2002, Nog wrote:
Ove Kaaven wrote:
On Sat, 16 Feb 2002, Nog wrote:
[SNIP]
And if so then why does it assume that the insterrupt it is emulating is not builtin?
The table of 16-bit interrupt entry points is initialized from wprocs.dll (dlls/kernel/wprocs.spec), so it doesn't need to assume anything.
This was my point. When emulating these interrupts it pushes the values of Eflags, Cs and Eip onto the stack but none of the interrupt handlers call the iret instruction or pop anything off the stack. What have I missed?
They can't do that, of course, as they're 32-bit code, and the caller (and the stack) is 16-bit. So it's all taken care of by the 16/32 relay thunks generated by winebuild from the .spec file.
What all of this probable garbage came from is: What will it take to emulate int xx from 32-bit code?
A sane mechanism to handle those interrupt vectors, probably.
I assume that the Would this be somthing like the code in msdos/interrupts.c?
Perhaps.
But then why do we need to have 2 tables for interrupts (one in msdos/interrupts.c, the other in dlls/winedos/dosvm.c)? The only explanation I can come up with is that mabe, just mabe, the interrupts in wproc.spec get called from 16-bit windows.
From 16-bit protected mode, which typically means Win16, yes.
The winedos tables are for 16-bit real mode (v86 mode).
Back to implementing int xx from 32-bit code, are all of the interrupts availible in real mode availible in protected mode?
No. Almost no interrupts are available. Calling DOS interrupts from protected mode requires explicit thunking, and apps typically requests such services from DPMI. Some thunks are provided by Windows (for compatibility) in 16-bit mode, but AFAIK none are provided in 32-bit.
If an app does use DPMI in Wine, then the request will be properly routed to winedos and its interrupt tables, so you don't have to do anything for this to work (except make int31 (DPMI call) work in 32-bit, of course)
Ove Kaaven wrote:
On Sat, 16 Feb 2002, Nog wrote:
Ove Kaaven wrote:
On Sat, 16 Feb 2002, Nog wrote:
[SNIP]
And if so then why does it assume that the insterrupt it is emulating is not builtin?
The table of 16-bit interrupt entry points is initialized from wprocs.dll (dlls/kernel/wprocs.spec), so it doesn't need to assume anything.
This was my point. When emulating these interrupts it pushes the values of Eflags, Cs and Eip onto the stack but none of the interrupt handlers call the iret instruction or pop anything off the stack. What have I missed?
They can't do that, of course, as they're 32-bit code, and the caller (and the stack) is 16-bit. So it's all taken care of by the 16/32 relay thunks generated by winebuild from the .spec file.
What all of this probable garbage came from is: What will it take to emulate int xx from 32-bit code?
A sane mechanism to handle those interrupt vectors, probably.
I assume that the Would this be somthing like the code in msdos/interrupts.c?
Perhaps.
But then why do we need to have 2 tables for interrupts (one in msdos/interrupts.c, the other in dlls/winedos/dosvm.c)? The only explanation I can come up with is that mabe, just mabe, the interrupts in wproc.spec get called from 16-bit windows.
From 16-bit protected mode, which typically means Win16, yes.
The winedos tables are for 16-bit real mode (v86 mode).
Back to implementing int xx from 32-bit code, are all of the interrupts availible in real mode availible in protected mode?
No. Almost no interrupts are available. Calling DOS interrupts from protected mode requires explicit thunking, and apps typically requests such services from DPMI. Some thunks are provided by Windows (for compatibility) in 16-bit mode, but AFAIK none are provided in 32-bit.
If an app does use DPMI in Wine, then the request will be properly routed to winedos and its interrupt tables, so you don't have to do anything for this to work (except make int31 (DPMI call) work in 32-bit, of course)
Ok, I have hacked togher something, but there is still something that I'm not sure about: What to add to Eip? This seems to be 2, looking at how other istructions are emulated. If this is so then there is something else wrong because all dpmi programs that I have come up to emulate a couple 32-bit instructions and then simply chocke when they execute another one with privileged instruction. Anyway here's the first draft of this code...
Index: include/miscemu.h =================================================================== RCS file: /home/wine/wine/include/miscemu.h,v retrieving revision 1.45 diff -u -r1.45 miscemu.h --- include/miscemu.h 2002/01/31 23:22:07 1.45 +++ include/miscemu.h 2002/02/17 14:55:30 @@ -157,8 +157,10 @@
/* msdos/interrupts.c */ typedef void (WINAPI *INTPROC)(CONTEXT86*); -extern FARPROC16 INT_GetPMHandler( BYTE intnum ); -extern void INT_SetPMHandler( BYTE intnum, FARPROC16 handler ); +extern FARPROC16 INT_Get16PMHandler( BYTE intnum ); +extern void INT_Set16PMHandler( BYTE intnum, FARPROC16 handler ); +extern INTPROC INT_Get32PMHandler( BYTE intnum ); +extern void INT_Set32PMHandler( BYTE intnum, INTPROC handler );
/* msdos/ioports.c */ extern DWORD IO_inport( int port, int count ); Index: loader/task.c =================================================================== RCS file: /home/wine/wine/loader/task.c,v retrieving revision 1.115 diff -u -r1.115 task.c --- loader/task.c 2001/08/28 18:39:04 1.115 +++ loader/task.c 2002/02/17 14:55:42 @@ -297,9 +297,9 @@ pTask->pdb.dispatcher[0] = 0x9a; /* ljmp */ PUT_UA_DWORD(&pTask->pdb.dispatcher[1], (DWORD)GetProcAddress16( GetModuleHandle16("KERNEL"), "DOS3Call" )); - pTask->pdb.savedint22 = INT_GetPMHandler( 0x22 ); - pTask->pdb.savedint23 = INT_GetPMHandler( 0x23 ); - pTask->pdb.savedint24 = INT_GetPMHandler( 0x24 ); + pTask->pdb.savedint22 = INT_Get16PMHandler( 0x22 ); + pTask->pdb.savedint23 = INT_Get16PMHandler( 0x23 ); + pTask->pdb.savedint24 = INT_Get16PMHandler( 0x24 ); pTask->pdb.fileHandlesPtr = MAKESEGPTR( GlobalHandleToSel16(pTask->hPDB), (int)&((PDB16 *)0)->fileHandles ); pTask->pdb.hFileHandles = 0; cvs server: Diffing loader/ne cvs server: Diffing memory Index: memory/instr.c =================================================================== RCS file: /home/wine/wine/memory/instr.c,v retrieving revision 1.13 diff -u -r1.13 instr.c --- memory/instr.c 2001/10/21 15:18:15 1.13 +++ memory/instr.c 2002/02/17 14:55:51 @@ -672,12 +672,15 @@ case 0xcd: /* int <XX> */ if (long_op) { - ERR("int xx from 32-bit code is not supported.\n"); - break; /* Unable to emulate it */ + FARPROC addr = INT_Get32PMHandler( instr[1] ); + (*addr)(context); + context->Eip += prefixlen + 2; } else { - FARPROC16 addr = INT_GetPMHandler( instr[1] ); + FARPROC16 addr = INT_Get16PMHandler( instr[1] ); WORD *stack = get_stack( context ); if (!addr) { Index: msdos/dpmi.c =================================================================== RCS file: /home/wine/wine/msdos/dpmi.c,v retrieving revision 1.60 diff -u -r1.60 dpmi.c --- msdos/dpmi.c 2001/12/17 22:12:26 1.60 +++ msdos/dpmi.c 2002/02/17 14:55:55 @@ -365,7 +365,7 @@ break; case 0x0204: /* Get protected mode interrupt vector */ TRACE("get protected mode interrupt handler (0x%02x), stub!\n",BL_reg(context)); - dw = (DWORD)INT_GetPMHandler( BL_reg(context) ); + dw = (DWORD)INT_Get16PMHandler( BL_reg(context) ); CX_reg(context) = HIWORD(dw); DX_reg(context) = LOWORD(dw); break; @@ -373,7 +373,7 @@ case 0x0205: /* Set protected mode interrupt vector */ TRACE("set protected mode interrupt handler (0x%02x,%p), stub!\n", BL_reg(context),MapSL(MAKESEGPTR(CX_reg(context),DX_reg(context)))); - INT_SetPMHandler( BL_reg(context), + INT_Set16PMHandler( BL_reg(context), (FARPROC16)MAKESEGPTR( CX_reg(context), DX_reg(context) )); break;
Index: msdos/int21.c =================================================================== RCS file: /home/wine/wine/msdos/int21.c,v retrieving revision 1.67 diff -u -r1.67 int21.c --- msdos/int21.c 2001/12/26 23:08:33 1.67 +++ msdos/int21.c 2002/02/17 14:56:08 @@ -1252,7 +1252,7 @@ break; case 0x25: /* SET INTERRUPT VECTOR */ - INT_SetPMHandler( AL_reg(context), (FARPROC16)MAKESEGPTR( context->SegDs, DX_reg(context))); + INT_Set16PMHandler( AL_reg(context), (FARPROC16)MAKESEGPTR( context->SegDs, DX_reg(context))); break;
case 0x29: /* PARSE FILENAME INTO FCB */ @@ -1373,7 +1373,7 @@ case 0x35: /* GET INTERRUPT VECTOR */ TRACE("GET INTERRUPT VECTOR 0x%02x\n",AL_reg(context)); { - FARPROC16 addr = INT_GetPMHandler( AL_reg(context) ); + FARPROC16 addr = INT_Get16PMHandler( AL_reg(context) ); context->SegEs = SELECTOROF(addr); BX_reg(context) = OFFSETOF(addr); } Index: msdos/int2f.c =================================================================== RCS file: /home/wine/wine/msdos/int2f.c,v retrieving revision 1.39 diff -u -r1.39 int2f.c --- msdos/int2f.c 2002/01/13 01:46:12 1.39 +++ msdos/int2f.c 2002/02/17 14:56:12 @@ -343,7 +343,7 @@
case 0x87: /* DPMI installation check */ #if 1 /* DPMI still breaks pkunzip */ - if (ISV86(context)) break; /* so bail out for now if in v86 mode */ +/* if (ISV86(context)) break; /* so bail out for now if in v86 mode */ #endif { SYSTEM_INFO si; Index: msdos/interrupts.c =================================================================== RCS file: /home/wine/wine/msdos/interrupts.c,v retrieving revision 1.21 diff -u -r1.21 interrupts.c --- msdos/interrupts.c 2001/12/04 19:54:49 1.21 +++ msdos/interrupts.c 2002/02/17 14:56:12 @@ -14,20 +14,33 @@
DEFAULT_DEBUG_CHANNEL(int);
-static FARPROC16 INT_Vectors[256]; +/* 16-bit protected mode vector table */ +static FARPROC16 INT_Vectors16[256]; +/* 32-bit protected mode vector table */ +static INTPROC INT_Vectors32[256] = +{ + /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 08 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 18 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 28 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 30 */ 0, INT_Int31Handler +}; +
/* Ordinal number for interrupt 0 handler in WPROCS.DLL */ #define FIRST_INTERRUPT 100
/********************************************************************** - * INT_GetPMHandler + * INT_Get16PMHandler * - * Return the protected mode interrupt vector for a given interrupt. + * Return the 16-bit protected mode interrupt vector for a given interrupt. */ -FARPROC16 INT_GetPMHandler( BYTE intnum ) +FARPROC16 INT_Get16PMHandler( BYTE intnum ) { - if (!INT_Vectors[intnum]) + if (!INT_Vectors16[intnum]) { static HMODULE16 wprocs; if (!wprocs) @@ -39,26 +52,26 @@ return 0; } } - if (!(INT_Vectors[intnum] = GetProcAddress16( wprocs, (LPCSTR)(FIRST_INTERRUPT + intnum)))) + if (!(INT_Vectors16[intnum] = GetProcAddress16( wprocs, (LPCSTR)(FIRST_INTERRUPT + intnum)))) { - WARN("int%x not implemented, returning dummy handler\n", intnum ); - INT_Vectors[intnum] = GetProcAddress16( wprocs, (LPCSTR)(FIRST_INTERRUPT + 256) ); + WARN("int%x in 16-bit mode not implemented, returning dummy handler\n", intnum ); + INT_Vectors16[intnum] = GetProcAddress16( wprocs, (LPCSTR)(FIRST_INTERRUPT + 256) ); } } - return INT_Vectors[intnum]; + return INT_Vectors16[intnum]; }
/********************************************************************** - * INT_SetPMHandler + * INT_Set16PMHandler * - * Set the protected mode interrupt handler for a given interrupt. + * Set the 16-bit protected mode interrupt handler for a given interrupt. */ -void INT_SetPMHandler( BYTE intnum, FARPROC16 handler ) +void INT_Set16PMHandler( BYTE intnum, FARPROC16 handler ) { - TRACE("Set protected mode interrupt vector %02x <- %04x:%04x\n", + TRACE("Set 16-bit protected mode interrupt vector %02x <- %04x:%04x\n", intnum, HIWORD(handler), LOWORD(handler) ); - INT_Vectors[intnum] = handler; + INT_Vectors16[intnum] = handler; }
@@ -69,4 +82,33 @@ */ void WINAPI INT_DefaultHandler( CONTEXT86 *context ) { +} + + +/********************************************************************** + * INT_Get32PMHandler + * + * Return the 32-bit protected mode interrupt vector for a given interrupt. + */ +INTPROC INT_Get32PMHandler( BYTE intnum ) +{ + if(!INT_Vectors32[intnum]) + { + WARN("int%x in 32-bit mode not implemented, returning dummy handler\n", intnum ); + INT_Vectors32[intnum] = INT_DefaultHandler; + } + return INT_Vectors32[intnum]; +} + + +/********************************************************************** + * INT_Set32PMHandler + * + * Set the 32-bit protected mode interrupt handler for a given interrupt. + */ +void INT_Set32PMHandler( BYTE intnum, INTPROC handler ) +{ + INT_Vectors32[intnum] = handler; } Index: windows/user.c =================================================================== RCS file: /home/wine/wine/windows/user.c,v retrieving revision 1.84 diff -u -r1.84 user.c --- windows/user.c 2002/01/01 00:24:35 1.84 +++ windows/user.c 2002/02/17 14:56:22 @@ -82,7 +82,7 @@ { /* Hack: restore the divide-by-zero handler */ /* FIXME: should set a USER-specific handler that displays a msg box */ - INT_SetPMHandler( 0, INT_GetPMHandler( 0xff ) ); + INT_Set16PMHandler( 0, INT_Get16PMHandler( 0xff ) );
/* Create task message queue */ if ( !InitThreadInput16( 0, 0 ) ) return 0;
Nog wrote:
Ove Kaaven wrote:
On Sat, 16 Feb 2002, Nog wrote:
Ove Kaaven wrote:
On Sat, 16 Feb 2002, Nog wrote:
[SNIP]
And if so then why does it assume that the insterrupt it is emulating is not builtin?
The table of 16-bit interrupt entry points is initialized from wprocs.dll (dlls/kernel/wprocs.spec), so it doesn't need to assume anything.
This was my point. When emulating these interrupts it pushes the values of Eflags, Cs and Eip onto the stack but none of the interrupt handlers call the iret instruction or pop anything off the stack. What have I missed?
They can't do that, of course, as they're 32-bit code, and the caller (and the stack) is 16-bit. So it's all taken care of by the 16/32 relay thunks generated by winebuild from the .spec file.
What all of this probable garbage came from is: What will it take to emulate int xx from 32-bit code?
A sane mechanism to handle those interrupt vectors, probably.
I assume that the Would this be somthing like the code in msdos/interrupts.c?
Perhaps.
But then why do we need to have 2 tables for interrupts (one in msdos/interrupts.c, the other in dlls/winedos/dosvm.c)? The only explanation I can come up with is that mabe, just mabe, the interrupts in wproc.spec get called from 16-bit windows.
From 16-bit protected mode, which typically means Win16, yes.
The winedos tables are for 16-bit real mode (v86 mode).
Back to implementing int xx from 32-bit code, are all of the interrupts availible in real mode availible in protected mode?
No. Almost no interrupts are available. Calling DOS interrupts from protected mode requires explicit thunking, and apps typically requests such services from DPMI. Some thunks are provided by Windows (for compatibility) in 16-bit mode, but AFAIK none are provided in 32-bit.
If an app does use DPMI in Wine, then the request will be properly routed to winedos and its interrupt tables, so you don't have to do anything for this to work (except make int31 (DPMI call) work in 32-bit, of course)
Ok, I have hacked togher something, but there is still something that I'm not sure about: What to add to Eip? This seems to be 2, looking at how other istructions are emulated. If this is so then there is something else wrong because all dpmi programs that I have come up to emulate a couple 32-bit instructions and then simply chocke when they execute another one with privileged instruction. Anyway here's the first draft of this code...
Ok, I have made some headway in this. I have confirmed that we have to add on 2 to Eip. What that exception realy is, is that the program does an LEA (Load Effective Address), and this aborts with a General Protection fault probably because the address to the lea instruction is invalid. How would one debug this?
nog.
On Tue, 19 Feb 2002, Nog wrote:
Ok, I have made some headway in this. I have confirmed that we have to add on 2 to Eip. What that exception realy is, is that the program does an LEA (Load Effective Address), and this aborts with a General Protection fault probably because the address to the lea instruction is invalid. How would one debug this?
This can't be, the processor doesn't validate the 'address' computed by LEA. In fact, compilers frequently use LEA as a fast, purely mathematical, integer multiply-accumulate instruction, for values that have no relation to addresses at all...