/* Should be compiled with 386 instructions enabled (-3 option) */ #include "x86.h" /*------------------------------------------------------------------------ INT instruction supports only immediate argument and to call indirect interrupt vector should be manually generated INT instruction opcode. For this, may be modified existing code (pre-compiled in code or data segment) or on the fly created new routine (code thunk) in byte array, which may reside in code or data segment or may be allocated in stack. Modifiyng existing code is most compact solution, but generating code thunk in stack allows reentrancy. How callint() function works: - prepared code thunk: - INT instruction opcode; - code to restore SP (MOV SP,xxxx) - workaround for bug with stack after INT25/26; - far jump back to code segment. - CPU flags and registers (EAX ECX EDX EBX EBP ESI EDI ES DS FS GS, but not ESP CS SS) are loaded from input structure. - code thunk called by placing its address in stack and then RETF. - after code thunk, all registers and flags are saved to output structure. ------------------------------------------------------------------------*/ unsigned long callint32 (int, const union REGS32*, union REGS32*); #if defined __COMPACT__ || defined __LARGE__ || defined __HUGE__ # pragma aux callint32 = \ "push bp" \ "push cs" "call prepare_code_thunk" "jmp save_registers" \ /* emulation for: push cs / mov bp,offset save_registers / push bp */ \ "prepare_code_thunk:" \ "sub sp,4" \ "mov al,0CDh" "push ax" /* int xx */ \ "mov bp,sp" /* start of code thunk */ \ "push ds" "push di" /* original DS:DI */ \ "mov byte ptr [bp+2],0BCh" /* mov sp,xxxx */ \ "mov [bp+3],sp" /* - fixup for int 25/26 */ \ "mov byte ptr [bp+5],0EAh" /* jmp far seg:ofs */ \ "push ss" "push bp" /* place address of code thunk */ \ "mov ds,cx" \ "mov ah,[bx+44]" "sahf" /* load flags and registers */ \ "mov eax,[bx ]" \ "mov ecx,[bx+1*4]" \ "mov edx,[bx+2*4]" \ "push dword ptr [bx+3*4]" \ "mov ebp,[bx+5*4]" \ "mov esi,[bx+6*4]" \ "les edi,[bx+7*4]" \ "mov fs,[bx+8*4+4*2]" \ "mov gs,[bx+8*4+5*2]" \ "mov ds,[bx+8*4+3*2]" \ "pop ebx" \ "retf" /* jump to code thunk */ \ "save_registers:" /* save flags and registers */ \ "push ds" "push edi" \ "mov di,sp" "lds di,ss:[di+6]" /* restore original DS:DI */ \ "mov [di ],eax" \ "mov [di+1*4],ecx" \ "mov [di+2*4],edx" \ "mov [di+3*4],ebx" \ "mov [di+4*4],esp" \ "mov [di+5*4],ebp" \ "mov [di+6*4],esi" \ "pop dword ptr [di+7*4]" \ "mov [di+8*4+0*2],es" \ "mov [di+8*4+1*2],cs" \ "mov [di+8*4+2*2],ss" \ "pop [di+8*4+3*2]" \ "mov [di+8*4+4*2],fs" \ "mov [di+8*4+5*2],gs" \ "pushf" "pop [di+44]" \ "sbb cx,cx" "neg cx" "mov [di+46],cx" \ "add sp,4+2+4+4" /* remove code thunk */ \ "pop bp" \ "mov dx,[di+2]" \ parm [ah] [cx bx] [ds di] value [dx ax] \ modify exact [cx bx si es]; #else # pragma aux callint32 = \ "push bp" \ "push cs" "call prepare_code_thunk" "jmp save_registers" \ /* emulation for: push cs / mov bp,offset save_registers / push bp */ \ "prepare_code_thunk:" \ "sub sp,4" \ "mov al,0CDh" "push ax" /* int xx */ \ "mov bp,sp" /* start of code thunk */ \ "push ds" "push bx" /* original DS:BX */ \ "mov byte ptr [bp+2],0BCh" /* mov sp,xxxx */ \ "mov [bp+3],sp" /* - fixup for int 25/26 */ \ "mov byte ptr [bp+5],0EAh" /* jmp far seg:ofs */ \ "push ss" "push bp" /* place address of code thunk */ \ "mov ah,[si+44]" "sahf" /* load flags and registers */ \ "mov eax,[si ]" \ "mov ecx,[si+1*4]" \ "mov edx,[si+2*4]" \ "mov ebx,[si+3*4]" \ "mov ebp,[si+5*4]" \ "push dword ptr [si+6*4]" \ "les edi,[si+7*4]" \ "mov fs,[si+8*4+4*2]" \ "mov gs,[si+8*4+5*2]" \ "mov ds,[si+8*4+3*2]" \ "pop esi" \ "retf" /* jump to code thunk */ \ "save_registers:" /* save flags and registers */ \ "push ds" "push ebx" \ "mov bx,sp" "lds bx,ss:[bx+6]" /* restore original DS:BX */ \ "mov [bx ],eax" \ "mov [bx+1*4],ecx" \ "mov [bx+2*4],edx" \ "pop dword ptr [bx+3*4]" \ "mov [bx+4*4],esp" \ "mov [bx+5*4],ebp" \ "mov [bx+6*4],esi" \ "mov [bx+7*4],edi" \ "mov [bx+8*4+0*2],es" \ "mov [bx+8*4+1*2],cs" \ "mov [bx+8*4+2*2],ss" \ "pop [bx+8*4+3*2]" \ "mov [bx+8*4+4*2],fs" \ "mov [bx+8*4+5*2],gs" \ "pushf" "pop [bx+44]" \ "sbb cx,cx" "neg cx" "mov [bx+46],cx" \ "add sp,4+2+4+4" /* remove code thunk */ \ "pop bp" \ "mov dx,[bx+2]" \ parm [ah] [si] [bx] value [dx ax] \ modify exact [cx si di es]; #endif /*----------------------------------------------------------------------*/ unsigned long _callint32 (int intno, const union REGS32 *inregs, union REGS32 *outregs) { return callint32 (intno, inregs, outregs); } /*----------------------------------------------------------------------*/ #ifdef TEST #include #include typedef unsigned char byte; typedef unsigned long dword; void main (void) { union REGS32 r; # define SMAP 0x534D4150ul /* ='SMAP' */ printf ("System memory map\n" " Type Base Length\n"); r.e.ebx = 0; /* continuation value */ do { struct { dword base [2], size [2], type; } map; /* sizeof (map) == 20 */ r.x.es = FP_SEG (&map), r.x.di = FP_OFF (&map), /* pointer to and */ r.e.ecx = sizeof map, /* buffer size */ r.e.edx = SMAP, r.e.eax = 0xE820; /* get system memory map */ if (_callint32 (0x15, &r, &r) != SMAP || r.x.cflag) break; /* CF -> fail or end of list */ if (map.type - 1 > 3) printf ("unknown (%3lu)", map.type); else if ((byte)map.type == 1) printf (" available"); else if ((byte)map.type == 2) printf (" reserved"); else if ((byte)map.type == 3) printf (" ACPI reclaim"); else if ((byte)map.type == 4) printf (" ACPI NVS"); if (map.base [1]) printf (" >4G "); else printf (" %08lX (%4luM)", map.base [0], map.base [0] >> 20); if (map.size [1]) printf (" >4G\n"); else printf (" %08lX (%luM, %luk, %lu)\n", map.size [0], map.size [0] >> 20, map.size [0] >> 10, map.size [0]); } while (r.e.ebx); } #endif