51 lines
1.2 KiB
C
51 lines
1.2 KiB
C
#include <sys/types.h>
|
|
#include <i86.h>
|
|
#include <dos.h>
|
|
|
|
#include "dpmi.h"
|
|
|
|
static uint16_t vbeDOSBufferDPMISelector = 0;
|
|
|
|
/**
|
|
* This is memory accessible to real-mode x86, so that
|
|
* interrupts can access the data.
|
|
*/
|
|
void *dpmiAllocateDOSMemory(int size) {
|
|
union REGS regs;
|
|
|
|
// a paragraph is 16 bytes because why not
|
|
unsigned short sizeParagraphs = (size + 15) >> 4UL;
|
|
|
|
regs.w.ax = 0x0100;
|
|
regs.w.bx = sizeParagraphs;
|
|
int386(0x31, ®s, ®s);
|
|
|
|
vbeDOSBufferDPMISelector = regs.w.dx;
|
|
return (void *)(((unsigned long)regs.w.ax) << 4UL);
|
|
}
|
|
|
|
void dpmiDeallocateDOSMemory() {
|
|
union REGS regs;
|
|
|
|
regs.w.ax = 0x0101;
|
|
regs.w.dx = vbeDOSBufferDPMISelector;
|
|
int386(0x31, ®s, ®s);
|
|
}
|
|
|
|
/**
|
|
* You only need to use this if you're passing a DPMI-allocated
|
|
* memory struture to an interrupt via ES:DI. Otherwise, a
|
|
* regular int386 call is sufficient.
|
|
*/
|
|
void dpmiInt(int interruptNo, struct dpmiRealModeRegs *rc) {
|
|
union REGS regs;
|
|
|
|
// call the DPMI real mode interrupt handler
|
|
regs.w.ax = 0x0300;
|
|
regs.w.bx = interruptNo; // real mode interrupt
|
|
regs.w.cx = 0; // don't mess with our stack
|
|
regs.x.edi = (unsigned int)rc;
|
|
|
|
int386(0x31, ®s, ®s);
|
|
}
|