I have been thinking about interrupt handling in Wine because it needs some reworking in order to get DPMI32 programs to work. I have formed a proposal for refactoring current interrupt handling code and I would like to get some comments about this scheme before I decide whether I want to work on it or not.
So, my proposal is to move all interrupt handlers to winedos dll and have only single interrupt handler routine per interrupt, instead of having separate real and protected mode handlers. If an interrupt occurs in protected mode ntdll would just load winedos and call single function from winedos that simulates the interrupt.
A list of some things pro and con the proposal:
+ Win32 programs don't care about interrupt handlers. It would seem reasonable to think that many Win16 programs don't need them either. Also, architectures not supporting DOS/Win16 probably don't want to have any interrupt code. + Real and protected mode interrupt handlers are heavily interconnected. For example, protected mode handlers already serve both real mode and protected mode interrupts. MSDN documentation also says that nearly all interrupts under Win16 work just like they do under DOS real mode. + Differences in handling interrupts depend more on whether we are running DOS or Windows process than on whether the interrupt was called from real or protected mode. + We would only have one place that handles interrupts. This should make it easier to maintain interrupt code. + DLL separation would be easier because we would require far fewer calls between winedos and ntdll. - Win16 programs using interrupts take a bit longer to start and they get all kinds of unnecessary stuff into their address space from winedos. - Restructuring stuff means lots of work and possibility for regression bugs in Win16 support.
P.S. I have a good idea on what needs to be done to make Wine support DPMI32. I have actually got some 32-bit DOS extenders to almost work. However, this requires lots of interrupt related work and I would like to wait until I get enough feedback about this interrupt refactoring proposal in order to see whether to continue working using the current interrupt code.
Jukka Heinonen,
I have been thinking about interrupt handling in Wine because it needs some reworking in order to get DPMI32 programs to work. I have formed a proposal for refactoring current interrupt handling code and I would like to get some comments about this scheme before I decide whether I want to work on it or not.
As I understand this, what you are asking has been a design goal for some time now. Since the DOS section is where I stay when I submit patches, I would like to volunteer what limited assistence I can. This looks like something which would benefit wine. Making the whole system more modular allows for easier modification of the whole project and gives us a potential for special modules. This will also help developers to find the code that they are looking for. I had a horrid time adding the FPU interrupts because I couldn't track down where to attach the interrupts.
God Bless, --Robert 'Admiral' Coeyman
On Sun, Oct 13, admiral coeyman wrote:
As I understand this, what you are asking has been a design goal for some time now. Since the DOS section is where I stay when I submit patches, I would like to volunteer what limited assistence I can. This looks like something which would benefit wine. Making the whole system more modular allows for easier modification of the whole project and gives us a potential for special modules. This will also help developers to find the code that they are looking for. I had a horrid time adding the FPU interrupts because I couldn't track down where to attach the interrupts.
Okay, any assistance is welcome. Especially critic on my approach to interrupt handling would be welcome as well as auditing interrupt handling patches and testing interrupt code on Win16, DOS RM, DOS DPMI16 and DOS DPMI32.
Here is my plan for interrupt handling, please comment if this does not look reasonable:
1. Move interrupt handling code from INSTR_EmulateInstruction to winedos and convert INSTR_EmulateInstruction to do something like this when interrupt is to be emulated: if(!Dosvm.EmulateInterruptPM && !DPMI_LoadDosSystem()) ERR(...); else Dosvm.EmulateInterruptPM(context); 2. Move routines INT_GetPMHandler* and INT_SetPMHandler* to winedos. 3. Add interrupt handlers for all wine/msdos/*.c interrupts to winedos (these may just delegate handling by calling INT_Int*Handler). 4. Add 16-bit interrupt handler entry points to winedos (similar to wprocs.dll). Make routines INT_GetPMHandler* and INT_SetPMHandler* default to winedos handlers instead of wprocs.dll handlers. 5. Migrate the code of all handlers that can be easily migrated to winedos there (int21 handler might not be easy to migrate). 6. Refactor real mode interrupt handling code (for example, get default interrupt handlers using GetProcAddress from 32-bit winedos instead of using fixed list).
At this point, Wine functionality should not have changed but interrupt handlers have been migrated to winedos. Now it would be possible to really start improving Wine interrupt handling:
1. Fix interrupt handlers so that they support DPMI32. 2. Add support for asynchronous interrupts in PM when using DPMI16 or DPMI32 (IRQs, timer, keyboard). This probably requires some VIF/VIP magic to prevent nested interrupt handling and interrupt handling while in Wine code. 3. Add support for interrupt reflection (both DPMI16 and DPMI32 should reflect many interrupts from protected mode handlers to real mode handlers and in some cases from real mode handlers to protected mode handlers).
Finally, when interrupt code works fine, it can be checked if parts of DOSMEM could be moved to winedos, too. DOSMEM unfortunately has lots of intricate interactions with other parts of Wine which might make this too complicated.
-- Jukka Heinonen http://www.iki.fi/jhei/
Jukka Heinonen,
Okay, any assistance is welcome. Especially critic on my approach to interrupt handling would be welcome as well as auditing interrupt handling patches and testing interrupt code on Win16, DOS RM, DOS DPMI16 and DOS DPMI32.
My C is not as good as it should be, however, I will test anything that I get. (Does winehq have a paper on applying patches?)
Here is my plan for interrupt handling, please comment if this does not look reasonable:
- Move interrupt handling code from INSTR_EmulateInstruction to winedos and convert INSTR_EmulateInstruction to do something like this when interrupt is to be emulated: if(!Dosvm.EmulateInterruptPM && !DPMI_LoadDosSystem()) ERR(...); else Dosvm.EmulateInterruptPM(context);
And test to see if the Dos System has already been loaded. Is there a reason why you could not have more than one wine instance running, drawing on a single wine server which has a single winedos module loaded?
- Move routines INT_GetPMHandler* and INT_SetPMHandler* to winedos.
- Add interrupt handlers for all wine/msdos/*.c interrupts to winedos (these may just delegate handling by calling INT_Int*Handler).
That looks good to me. I had a hard time figuring out which of the two locations I was supposed to add code to.
- Add 16-bit interrupt handler entry points to winedos (similar to wprocs.dll). Make routines INT_GetPMHandler* and INT_SetPMHandler* default to winedos handlers instead of wprocs.dll handlers.
There may be a few interrupts, like those mentioned earlier, which should be left where they are.
- Migrate the code of all handlers that can be easily migrated to winedos there (int21 handler might not be easy to migrate).
A number of the handlers might not be easy to migrate. This is a good time to look over what we have and see if we can do better. This is something that only has to be done once.
- Refactor real mode interrupt handling code (for example, get default interrupt handlers using GetProcAddress from 32-bit winedos instead of using fixed list).
Will you have a hard time with programs that need interrupt vectors in seg:offset form? When I was doing self-modifying code for fpu emulation, I was told that there's no easy way to convert to seg:offset from linear addresses. Some software, like anti-debugger routines, will replace interrupt handlers in real mode. I'd like to see a way of converting linear addresses back to real. You also have to set up the dos environment so that the interrupt pointer list is at the bottom of the dos ram to avoid having trouble with software which calls the interrupt routines directly rather than through interrupt calls. And, we must account for intercepted hooks where a replaced handler calls the real handler. If you can do this with the dynamically loaded list, then I'm all for it.
At this point, Wine functionality should not have changed but interrupt handlers have been migrated to winedos. Now it would be possible to really start improving Wine interrupt handling:
That is reasonable.
- Fix interrupt handlers so that they support DPMI32.
- Add support for asynchronous interrupts in PM when using DPMI16 or DPMI32 (IRQs, timer, keyboard). This probably requires some VIF/VIP magic to prevent nested interrupt handling and interrupt handling while in Wine code.
- Add support for interrupt reflection (both DPMI16 and DPMI32 should reflect many interrupts from protected mode handlers to real mode handlers and in some cases from real mode handlers to protected mode handlers).
Maybe we can even clean the code a bit to make speed gains. Load time on some software is a nightmare.
Finally, when interrupt code works fine, it can be checked if parts of DOSMEM could be moved to winedos, too. DOSMEM unfortunately has lots of intricate interactions with other parts of Wine which might make this too complicated.
Possibly. We will run into this with some of the interrupts, like int 21h. God Bless, --Robert 'Admiral' Coeyman
Jukka Heinonen jhei@iki.fi writes:
So, my proposal is to move all interrupt handlers to winedos dll and have only single interrupt handler routine per interrupt, instead of having separate real and protected mode handlers. If an interrupt occurs in protected mode ntdll would just load winedos and call single function from winedos that simulates the interrupt.
Yes, that has always been the goal, so if you feel like working on that, great!
- Win16 programs using interrupts take a bit longer to start and they get all kinds of unnecessary stuff into their address space from winedos.
We may want to handle some interrupts internally in kernel, like int20 or int21/4c. For some Win16 apps that's the only interrupt they use, and it would be silly to load the full winedos just to terminate the app right away. But this can be added later on too.