#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 (AX CX DX BX BP SI DI ES DS, but not SP 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 callint (int, const union REGS16*, union REGS16*); #if defined __COMPACT__ || defined __LARGE__ || defined __HUGE__ # pragma aux callint = \ "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+24]" "sahf" /* load flags and registers */ \ "mov ax,[bx ]" \ "mov cx,[bx+1*2]" \ "mov dx,[bx+2*2]" \ "push [bx+3*2]" \ "mov bp,[bx+5*2]" \ "mov si,[bx+6*2]" \ "les di,[bx+7*2]" \ "mov ds,[bx+8*2+3*2]" \ "pop bx" \ "retf" /* jump to code thunk */ \ "save_registers:" /* save flags and registers */ \ "push ds" "push di" \ "mov di,sp" "lds di,ss:[di+4]" /* restore original DS:DI */ \ "mov [di ],ax" \ "mov [di+1*2],cx" \ "mov [di+2*2],dx" \ "mov [di+3*2],bx" \ "mov [di+4*2],sp" \ "mov [di+5*2],bp" \ "mov [di+6*2],si" \ "pop [di+7*2]" \ "mov [di+8*2+0*2],es" \ "mov [di+8*2+1*2],cs" \ "mov [di+8*2+2*2],ss" \ "pop [di+8*2+3*2]" \ "pushf" "pop [di+24]" \ "sbb cx,cx" "neg cx" "mov [di+26],cx" \ "add sp,4+2+4+4" /* remove code thunk */ \ "pop bp" \ parm [ah] [cx bx] [ds di] value [ax] \ modify exact [cx dx bx si es]; #else # pragma aux callint = \ "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+24]" "sahf" /* load flags and registers */ \ "mov ax,[si ]" \ "mov cx,[si+1*2]" \ "mov dx,[si+2*2]" \ "mov bx,[si+3*2]" \ "mov bp,[si+5*2]" \ "push [si+6*2]" \ "les di,[si+7*2]" \ "mov ds,[si+8*2+3*2]" \ "pop si" \ "retf" /* jump to code thunk */ \ "save_registers:" /* save flags and registers */ \ "push ds" "push bx" \ "mov bx,sp" "lds bx,ss:[bx+4]" /* restore original DS:BX */ \ "mov [bx ],ax" \ "mov [bx+1*2],cx" \ "mov [bx+2*2],dx" \ "pop [bx+3*2]" \ "mov [bx+4*2],sp" \ "mov [bx+5*2],bp" \ "mov [bx+6*2],si" \ "mov [bx+7*2],di" \ "mov [bx+8*2+0*2],es" \ "mov [bx+8*2+1*2],cs" \ "mov [bx+8*2+2*2],ss" \ "pop [bx+8*2+3*2]" \ "pushf" "pop [bx+24]" \ "sbb cx,cx" "neg cx" "mov [bx+26],cx" \ "add sp,4+2+4+4" /* remove code thunk */ \ "pop bp" \ parm [ah] [si] [bx] value [ax] \ modify exact [cx dx si di es]; #endif /*----------------------------------------------------------------------*/ unsigned _callint (int intno, const union REGS16 *inregs, union REGS16 *outregs) { return callint (intno, inregs, outregs); } /*----------------------------------------------------------------------*/ #ifdef TEST #include #include void main (void) { union REGS16 r; /* char name [] = ".", buffer [128]; r.x.es = FP_SEG (buffer); r.x.di = FP_OFF (buffer); r.x.ds = FP_SEG (name); r.x.si = FP_OFF (name); r.h.ah = 0x60; / * truename: canonize filename/path * / _callint (0x21, &r, &r); if (r.x.cflag) printf ("Error: code=%u (%Xh)\n", r.x.ax, r.x.ax); else printf ("Done: AH=%02Xh, buffer=\"%s\"\n", r.h.ah, buffer); */ r.h.dl = 1; /* A: */ r.h.ah = 0x1C; /* get allocation information for drive */ _callint (0x21, &r, &r); if (r.h.al != 0xff) printf (" media ID: %02Xh (at %04X:%04X)\n" " bytes per sector: %u\n" "sectors per clusters: %u\n" " total clusters: %u\n" " size: %lu\n", *(unsigned char far*)MK_FP (r.x.ds, r.x.bx), r.x.ds, r.x.bx, r.x.cx, r.h.al, r.x.dx, (unsigned long)(r.x.cx * r.h.al) * r.x.dx); } #endif