I'm not that much of a fan of V86 mode, so I've decided that in my kernel when I need to do a real mode interrupt (which is rare) I'll just switch to real mode; do the interrupt and jump back to protected mode.
The implementation is pretty simple, I keep a relocateable piece of real mode code that I can properly patch (the relative or absolute offsets) and relocate to any real mode memory address.
This works, mostly

Since I can control the place of relocation and it's the first thing I use in the low memory area (<1mb) I have noticed that calling the BIOS (int 0x15) for extended memory information can sometimes hang if the routine is located in certain memory areas: since I know the free low memory theoretically start at 0x500 and end at 0xA0000, I should have it free, everything works fine if the routine runs from 0x500, but hangs if the routine runs for example from 0x800 - which should be fine since this is a free memory area.
This made me think if perhaps the bios interrupts expects certain things which I am maybe not setting correctly, I have loaded all the segments with valid 16bit descriptors, set a real mode IDT, a real mode stack (which is derived from the location the routine is located and is around 1k) patched all the correct addresses, reampped the PIC back to normal, even with interrupts disabled it hangs..
Furthermore, if I force the INT 0x15 to be my own real mode interrupt vector it always works, no matter where it's located, and I have also debugged that the registers are transfered correctly to-and-from protected mode to real mode.
[IE the real mode stack does its' job]
I know this is a longshot, but if anyone have any idea what may be preventing the bios from functioning correctly when I use certain addresses it would be much helpful.
Thanks in advance,
Daniel.
* I use Microsoft Virtual PC 2004 [which emulates BIOS].
* PS: This might be lame of me but I was pretty surprised to find out that you must set CS to something different than 0 in real mode in order to run code. Since you can describe the address 0x500 with either: CS:0 and offset 0x500 or CS:50 and offset 0.