Well, firstly, you need to make sure that the EIP you are at is a valid 16-bit EIP. You also must first drop down to 16-bit pmode before making the switch, then you also have to make sure you are at a legitemate physical address (paging not available in real-mode). So, to recap:
Must be <1mb (well, below 0x100FEFF), in 16-bit pmode, and at a valid physical page (not virtual). If all these are met, you now have to make sure the function knows where it's located, and it must support 16 and 32-bit relocations (well, unless you drop into 16-bit pmode on entry, then it must only support 16-bit relocations). The easiest method would be like this:
Memory map bottom 1mb (or however much you need, probably 4k is plenty), setup a 16-bit code and data segment, then reserve a block of memory below 1mb for your program (binary is nice, because elf, coff, etc don't support 16-bit relocations, and it'll have to be written in ASM). So, now we write the entry code similar to this:
Code: Select all
[bits 16]
[org 0x1000] ;Whatever you want here, 16-bit reserved location
Entry16:
cli ;Disable interrupts
mov eax, DATASEL16 ;16 bit data selector
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
;Disable paging, works because it's a 1:1 mapping!
mov eax, cr0
and eax, 0x7FFFFFFe ;Disable paging bit & enable 16-bit pmode
mov cr0, eax
jump 0x0000:GoRMode ;Perform Far jump to setup CS :)
GoRMode:
mov ax, 0x0000 ;Reset data selectors to 0x0000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
lidt 0x000 ;Real move IVT is @ 0x0000
sti ;Restore interrupts, be careful, unhandled int's will kill it
;And finally we are ready to play in real mode!
This code was written in this window, I may have missed a step or so, but should get you pointed in the right direction. Be careful enabling ints, you probably want to disable your PIC or APIC before entering real-mode so you don't have unhandled interrupts firing. You can go back into p-mode after this, just remember to reset the IDT, re-enable everything (paging, pmode bit), do a retf (far return, so it pops the Code segment back off as well, and when you call this you need to do a far call (callf CODESEL16:0x1000) to the function. So, basically it's not difficult, just have to remember that real-mode and p-mode are very different (16-bit, no virtual memory, IVT instead of IDT, cannot access > 1mb, etc, etc). If you run into more problems, let us know, that should get you started pretty nicely though. The other option (not sure how APM works exactly, so this may or may not be viable) is v86 mode.