DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/callback.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include <stdlib.h>
00021 #include <string.h>
00022 
00023 #include "dosbox.h"
00024 #include "callback.h"
00025 #include "logging.h"
00026 #include "bios.h"
00027 #include "mem.h"
00028 #include "cpu.h"
00029 
00030 #if C_EMSCRIPTEN
00031 # include <emscripten.h>
00032 #endif
00033 
00034 Bit16u CB_SEG=0,CB_SOFFSET=0;
00035 extern Bitu vm86_fake_io_seg;
00036 extern Bitu vm86_fake_io_off;
00037 
00038 unsigned int last_callback = 0;
00039 
00040 /* CallBack are located at 0xF000:0x1000  (see CB_SEG and CB_SOFFSET in callback.h)
00041    And they are 16 bytes each and you can define them to behave in certain ways like a
00042    far return or and IRET
00043 */
00044 
00045 CallBack_Handler CallBack_Handlers[CB_MAX] = {NULL};
00046 char* CallBack_Description[CB_MAX] = {NULL};
00047 
00048 Bitu call_stop,call_default;
00049 Bit8u call_idle;
00050 Bitu call_priv_io;
00051 
00052 static Bitu illegal_handler(void) {
00053         E_Exit("Illegal CallBack #%u Called",last_callback);
00054         return 1;
00055 }
00056 
00057 void DBG_CALLBACK_Dump(void) {
00058         LOG_MSG("Callbacks");
00059     for (Bitu i=0;i < CB_MAX;i++) {
00060         if (CallBack_Handlers[i] == &illegal_handler)
00061             continue;
00062 
00063         LOG_MSG("  [%u] func=%p desc='%s'",
00064             (unsigned int)i,
00065             (void*)((uintptr_t)CallBack_Handlers[i]), /* shut the compiler up by func -> uintptr_t -> void* conversion */
00066             CallBack_Description[i] != NULL ? CallBack_Description[i] : "");
00067     }
00068         LOG_MSG("--------------");
00069 }
00070 
00071 void CALLBACK_Dump(void) {
00072         LOG(LOG_CPU,LOG_DEBUG)("Callback dump");
00073     for (Bitu i=0;i < CB_MAX;i++) {
00074         if (CallBack_Handlers[i] == &illegal_handler)
00075             continue;
00076 
00077         LOG(LOG_CPU,LOG_DEBUG)("  [%u] func=%p desc='%s'",
00078             (unsigned int)i,
00079             (void*)((uintptr_t)CallBack_Handlers[i]), /* shut the compiler up by func -> uintptr_t -> void* conversion */
00080             CallBack_Description[i] != NULL ? CallBack_Description[i] : "");
00081     }
00082         LOG(LOG_CPU,LOG_DEBUG)("--------------");
00083 }
00084 
00085 void CALLBACK_Shutdown(void) {
00086         for (Bitu i=0;(i<CB_MAX);i++) {
00087                 CallBack_Handlers[i] = &illegal_handler;
00088                 CALLBACK_SetDescription(i,NULL);
00089         }
00090 }
00091 
00092 Bit8u CALLBACK_Allocate(void) {
00093         for (Bit8u i=1;(i<CB_MAX);i++) {
00094                 if (CallBack_Handlers[i]==&illegal_handler) {
00095                         if (CallBack_Description[i] != NULL) LOG_MSG("CALLBACK_Allocate() warning: empty slot still has description string!\n");
00096                         CallBack_Handlers[i]=0;
00097                         return i;
00098                 }
00099         }
00100         E_Exit("CALLBACK:Can't allocate handler.");
00101         return 0;
00102 }
00103 
00104 void CALLBACK_DeAllocate(Bitu in) {
00105     assert(in != 0);
00106     assert(in < CB_MAX);
00107 
00108         CallBack_Handlers[in]=&illegal_handler;
00109         CALLBACK_SetDescription(in,NULL);
00110 }
00111 
00112 
00113 void CALLBACK_Idle(void) {
00114 #if C_EMSCRIPTEN
00115     void GFX_Events();
00116     GFX_Events();
00117 #endif
00118 
00119 /* this makes the cpu execute instructions to handle irq's and then come back */
00120         Bitu oldIF=GETFLAG(IF);
00121         SETFLAGBIT(IF,true);
00122         Bit16u oldcs=SegValue(cs);
00123         Bit32u oldeip=reg_eip;
00124         SegSet16(cs,CB_SEG);
00125         reg_eip=CB_SOFFSET+call_idle*CB_SIZE;
00126         DOSBOX_RunMachine();
00127         reg_eip=oldeip;
00128         SegSet16(cs,oldcs);
00129         SETFLAGBIT(IF,oldIF);
00130         if (!CPU_CycleAutoAdjust && CPU_Cycles>0)
00131                 CPU_Cycles=0;
00132 }
00133 
00134 void CALLBACK_IdleNoInts(void) {
00135 #if C_EMSCRIPTEN
00136     void GFX_Events();
00137     GFX_Events();
00138 #endif
00139 
00140 /* this makes the cpu execute instructions to handle irq's and then come back */
00141 //      Bitu oldIF=GETFLAG(IF);
00142 //      SETFLAGBIT(IF,true);
00143         Bit16u oldcs=SegValue(cs);
00144         Bit32u oldeip=reg_eip;
00145         SegSet16(cs,CB_SEG);
00146         reg_eip=CB_SOFFSET+call_idle*CB_SIZE;
00147         DOSBOX_RunMachine();
00148         reg_eip=oldeip;
00149         SegSet16(cs,oldcs);
00150 //      SETFLAGBIT(IF,oldIF);
00151         if (!CPU_CycleAutoAdjust && CPU_Cycles>0)
00152                 CPU_Cycles=0;
00153 }
00154 
00155 static Bitu default_handler(void) {
00156         LOG(LOG_CPU,LOG_ERROR)("Illegal Unhandled Interrupt Called %X",lastint);
00157         return CBRET_NONE;
00158 }
00159 
00160 static Bitu stop_handler(void) {
00161         return CBRET_STOP;
00162 }
00163 
00164 Bitu FillFlags(void);
00165 
00166 void CALLBACK_RunRealFarInt(Bit16u seg,Bit16u off) {
00167         FillFlags();
00168 
00169         reg_sp-=6;
00170         mem_writew(SegPhys(ss)+reg_sp,RealOff(CALLBACK_RealPointer(call_stop)));
00171         mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(CALLBACK_RealPointer(call_stop)));
00172         mem_writew(SegPhys(ss)+reg_sp+4,(Bit16u)reg_flags);
00173         Bit32u oldeip=reg_eip;
00174         Bit16u oldcs=SegValue(cs);
00175         reg_eip=off;
00176         SegSet16(cs,seg);
00177         DOSBOX_RunMachine();
00178         reg_eip=oldeip;
00179         SegSet16(cs,oldcs);
00180 }
00181 
00182 void CALLBACK_RunRealFar(Bit16u seg,Bit16u off) {
00183         reg_sp-=4;
00184         mem_writew(SegPhys(ss)+reg_sp,RealOff(CALLBACK_RealPointer(call_stop)));
00185         mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(CALLBACK_RealPointer(call_stop)));
00186         Bit32u oldeip=reg_eip;
00187         Bit16u oldcs=SegValue(cs);
00188         reg_eip=off;
00189         SegSet16(cs,seg);
00190         DOSBOX_RunMachine();
00191         reg_eip=oldeip;
00192         SegSet16(cs,oldcs);
00193 }
00194 
00195 void CALLBACK_RunRealInt_retcsip(Bit8u intnum,Bitu &rcs,Bitu &rip) {
00196         Bit32u oldeip=reg_eip;
00197         Bit16u oldcs=SegValue(cs);
00198         reg_eip=CB_SOFFSET+(CB_MAX*CB_SIZE)+(intnum*6U);
00199         SegSet16(cs,CB_SEG);
00200         DOSBOX_RunMachine();
00201         rcs = SegValue(cs);
00202         rip = reg_ip;
00203         reg_eip=oldeip;
00204         SegSet16(cs,oldcs);
00205 }
00206 
00207 void CALLBACK_RunRealInt(Bit8u intnum) {
00208         Bit32u oldeip=reg_eip;
00209         Bit16u oldcs=SegValue(cs);
00210         reg_eip=CB_SOFFSET+(CB_MAX*CB_SIZE)+(intnum*6U);
00211         SegSet16(cs,CB_SEG);
00212         DOSBOX_RunMachine();
00213         reg_eip=oldeip;
00214         SegSet16(cs,oldcs);
00215 }
00216 
00217 void CALLBACK_SZF(bool val) {
00218     Bit32u tempf;
00219 
00220     if (cpu.stack.big)
00221         tempf = mem_readd(SegPhys(ss)+reg_esp+8); // first word past FAR 32:32
00222     else
00223         tempf = mem_readw(SegPhys(ss)+reg_sp+4); // first word past FAR 16:16
00224 
00225     if (val) tempf |= FLAG_ZF;
00226     else tempf &= ~FLAG_ZF;
00227 
00228     if (cpu.stack.big)
00229         mem_writed(SegPhys(ss)+reg_esp+8,tempf);
00230     else
00231         mem_writew(SegPhys(ss)+reg_sp+4,(Bit16u)tempf);
00232 }
00233 
00234 void CALLBACK_SCF(bool val) {
00235     Bit32u tempf;
00236 
00237     if (cpu.stack.big)
00238         tempf = mem_readd(SegPhys(ss)+reg_esp+8); // first word past FAR 32:32
00239     else
00240         tempf = mem_readw(SegPhys(ss)+reg_sp+4); // first word past FAR 16:16
00241 
00242     if (val) tempf |= FLAG_CF;
00243     else tempf &= ~FLAG_CF;
00244 
00245     if (cpu.stack.big)
00246         mem_writed(SegPhys(ss)+reg_esp+8,tempf);
00247     else
00248         mem_writew(SegPhys(ss)+reg_sp+4,(Bit16u)tempf);
00249 }
00250 
00251 void CALLBACK_SIF(bool val) {
00252     Bit32u tempf;
00253 
00254     if (cpu.stack.big)
00255         tempf = mem_readd(SegPhys(ss)+reg_esp+8); // first word past FAR 32:32
00256     else
00257         tempf = mem_readw(SegPhys(ss)+reg_sp+4); // first word past FAR 16:16
00258 
00259     if (val) tempf |= FLAG_IF;
00260     else tempf &= ~FLAG_IF;
00261 
00262     if (cpu.stack.big)
00263         mem_writed(SegPhys(ss)+reg_esp+8,tempf);
00264     else
00265         mem_writew(SegPhys(ss)+reg_sp+4,(Bit16u)tempf);
00266 }
00267 
00268 void CALLBACK_SetDescription(Bitu nr, const char* descr) {
00269         if (CallBack_Description[nr]) delete[] CallBack_Description[nr];
00270         CallBack_Description[nr] = 0;
00271 
00272         if (descr != NULL) {
00273                 CallBack_Description[nr] = new char[strlen(descr)+1];
00274                 strcpy(CallBack_Description[nr],descr);
00275         }
00276 }
00277 
00278 const char* CALLBACK_GetDescription(Bitu nr) {
00279         if (nr>=CB_MAX) return 0;
00280         return CallBack_Description[nr];
00281 }
00282 
00283 Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_cb=true) {
00284         if (callback>=CB_MAX)
00285                 return 0;
00286         switch (type) {
00287         case CB_RETN:
00288                 if (use_cb) {
00289                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00290                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00291                         phys_writew(physAddress+0x02,(Bit16u)callback); //The immediate word
00292                         physAddress+=4;
00293                 }
00294                 phys_writeb(physAddress+0x00,(Bit8u)0xC3);              //A RETN Instruction
00295                 return (use_cb?5:1);
00296         case CB_RETF:
00297                 if (use_cb) {
00298                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00299                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00300                         phys_writew(physAddress+0x02,(Bit16u)callback); //The immediate word
00301                         physAddress+=4;
00302                 }
00303                 phys_writeb(physAddress+0x00,(Bit8u)0xCB);              //A RETF Instruction
00304                 return (use_cb?5:1);
00305         case CB_RETF8:
00306                 if (use_cb) {
00307                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00308                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00309                         phys_writew(physAddress+0x02,(Bit16u)callback); //The immediate word
00310                         physAddress+=4;
00311                 }
00312                 phys_writeb(physAddress+0x00,(Bit8u)0xCA);              //A RETF 8 Instruction
00313                 phys_writew(physAddress+0x01,(Bit16u)0x0008);
00314                 return (use_cb?7:3);
00315         case CB_RETF_STI:
00316                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              //STI
00317                 if (use_cb) {
00318                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00319                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00320                         phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word
00321                         physAddress+=4;
00322                 }
00323                 phys_writeb(physAddress+0x01,(Bit8u)0xCB);              //A RETF Instruction
00324                 return (use_cb?6:2);
00325         case CB_RETF_CLI:
00326                 phys_writeb(physAddress+0x00,(Bit8u)0xFA);              //CLI
00327                 if (use_cb) {
00328                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00329                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00330                         phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word
00331                         physAddress+=4;
00332                 }
00333                 phys_writeb(physAddress+0x01,(Bit8u)0xCB);              //A RETF Instruction
00334                 return (use_cb?6:2);
00335         case CB_IRET:
00336                 if (use_cb) {
00337                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00338                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00339                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00340                         physAddress+=4;
00341                 }
00342                 phys_writeb(physAddress+0x00,(Bit8u)0xCF);              //An IRET Instruction
00343                 return (use_cb?5:1);
00344         case CB_IRETD:
00345                 if (use_cb) {
00346                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00347                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00348                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00349                         physAddress+=4;
00350                 }
00351                 phys_writeb(physAddress+0x00,(Bit8u)0x66);              //An IRETD Instruction
00352                 phys_writeb(physAddress+0x01,(Bit8u)0xCF);
00353                 return (use_cb?6:2);
00354         case CB_IRET_STI:
00355                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              //STI
00356                 if (use_cb) {
00357                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00358                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00359                         phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word
00360                         physAddress+=4;
00361                 }
00362                 phys_writeb(physAddress+0x01,(Bit8u)0xCF);              //An IRET Instruction
00363                 return (use_cb?6:2);
00364         case CB_IRET_EOI_PIC1:
00365                 if (use_cb) {
00366                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00367                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00368                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00369                         physAddress+=4;
00370                 }
00371                 phys_writeb(physAddress+0x00,(Bit8u)0x50);              // push ax
00372                 phys_writeb(physAddress+0x01,(Bit8u)0xb0);              // mov al, 0x20
00373                 phys_writeb(physAddress+0x02,(Bit8u)0x20);
00374                 phys_writeb(physAddress+0x03,(Bit8u)0xe6);              // out 0x20, al (IBM) / out 0x00, al (PC-98)
00375                 phys_writeb(physAddress+0x04,(Bit8u)(IS_PC98_ARCH ? 0x00 : 0x20));
00376                 phys_writeb(physAddress+0x05,(Bit8u)0x58);              // pop ax
00377                 phys_writeb(physAddress+0x06,(Bit8u)0xcf);              //An IRET Instruction
00378                 return (use_cb?0x0b:0x07);
00379         case CB_IRQ0:   // timer int8
00380                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              //STI
00381                 if (use_cb) {
00382                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00383                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00384                         phys_writew(physAddress+0x03,(Bit16u)callback);         //The immediate word
00385                         physAddress+=4;
00386                 }
00387                 phys_writeb(physAddress+0x01,(Bit8u)0x1e);              // push ds
00388                 phys_writeb(physAddress+0x02,(Bit8u)0x50);              // push ax
00389                 phys_writeb(physAddress+0x03,(Bit8u)0x52);              // push dx
00390                 phys_writew(physAddress+0x04,(Bit16u)0x1ccd);   // int 1c
00391                 phys_writeb(physAddress+0x06,(Bit8u)0xfa);              // cli
00392                 phys_writew(physAddress+0x07,(Bit16u)0x20b0);   // mov al, 0x20
00393                 phys_writew(physAddress+0x09,(Bit16u)(IS_PC98_ARCH ? 0x00e6 : 0x20e6)); // out 0x20, al / out 0x00, al (PC-98) (FIXME: PC-98 does not have INT 1Ch)
00394                 phys_writeb(physAddress+0x0b,(Bit8u)0x5a);              // pop dx
00395                 phys_writeb(physAddress+0x0c,(Bit8u)0x58);              // pop ax
00396                 phys_writeb(physAddress+0x0d,(Bit8u)0x1f);              // pop ds
00397                 phys_writeb(physAddress+0x0e,(Bit8u)0xcf);              //An IRET Instruction
00398                 return (use_cb?0x13:0x0f);
00399         case CB_IRQ1:   // keyboard int9
00400                 phys_writeb(physAddress+0x00,(Bit8u)0x50);                      // push ax
00401         if (machine == MCH_PCJR || IS_PC98_ARCH) {
00402             /* NTS: NEC PC-98 does not have keyboard input on port 60h, it's a 8251 UART elsewhere.
00403              *
00404              *      IBM PCjr reads the infared input on NMI interrupt, which then calls INT 48h to
00405              *      translate to IBM PC/XT scan codes before passing AL directly to IRQ1 (INT 9).
00406              *      PCjr keyboard handlers, including games made for the PCjr, assume the scan code
00407              *      is in AL and do not read the I/O port */
00408             phys_writew(physAddress+0x01,(Bit16u)0x9090);               // nop, nop
00409         }
00410         else {
00411             phys_writew(physAddress+0x01,(Bit16u)0x60e4);               // in al, 0x60
00412         }
00413         if (IS_PC98_ARCH || IS_TANDY_ARCH) {
00414             phys_writew(physAddress+0x03,(Bit16u)0x9090);               // nop, nop
00415             phys_writeb(physAddress+0x05,(Bit8u)0x90);                  // nop
00416             phys_writew(physAddress+0x06,(Bit16u)0x9090);               // nop, nop (PC-98 does not have INT 15h keyboard hook)
00417         }
00418         else {
00419             phys_writew(physAddress+0x03,(Bit16u)0x4fb4);               // mov ah, 0x4f
00420             phys_writeb(physAddress+0x05,(Bit8u)0xf9);                  // stc
00421             phys_writew(physAddress+0x06,(Bit16u)0x15cd);               // int 15
00422         }
00423 
00424                 if (use_cb) {
00425             if (IS_PC98_ARCH || IS_TANDY_ARCH)
00426                 phys_writew(physAddress+0x08,(Bit16u)0x9090);   // nop nop
00427             else
00428                 phys_writew(physAddress+0x08,(Bit16u)0x0473);   // jc skip
00429 
00430                         phys_writeb(physAddress+0x0a,(Bit8u)0xFE);              //GRP 4
00431                         phys_writeb(physAddress+0x0b,(Bit8u)0x38);              //Extra Callback instruction
00432                         phys_writew(physAddress+0x0c,(Bit16u)callback);                 //The immediate word
00433                         // jump here to (skip):
00434                         physAddress+=6;
00435                 }
00436                 phys_writeb(physAddress+0x08,(Bit8u)0xfa);                      // cli
00437                 phys_writew(physAddress+0x09,(Bit16u)0x20b0);           // mov al, 0x20
00438                 phys_writew(physAddress+0x0b,(Bit16u)(IS_PC98_ARCH ? 0x00e6 : 0x20e6));         // out 0x20, al
00439                 phys_writeb(physAddress+0x0d,(Bit8u)0x58);                      // pop ax
00440                 phys_writeb(physAddress+0x0e,(Bit8u)0xcf);                      //An IRET Instruction
00441         phys_writeb(physAddress+0x0f,(Bit8u)0xfa);                      // cli
00442         phys_writew(physAddress+0x10,(Bit16u)0x20b0);           // mov al, 0x20
00443         phys_writew(physAddress+0x12,(Bit16u)0x20e6);           // out 0x20, al
00444         phys_writeb(physAddress+0x14,(Bit8u)0x55);                      // push bp
00445         phys_writew(physAddress+0x15,(Bit16u)0x05cd);           // int 5
00446         phys_writeb(physAddress+0x17,(Bit8u)0x5d);                      // pop bp
00447         phys_writeb(physAddress+0x18,(Bit8u)0x58);                      // pop ax
00448         phys_writeb(physAddress+0x19,(Bit8u)0xcf);                      //An IRET Instruction
00449         return (use_cb ?0x20:0x1a);
00450         case CB_IRQ1_BREAK:     // return from int9, when Ctrl-Break is detected; invokes int 1b
00451                 phys_writew(physAddress+0x00,(Bit16u)0x1bcd);           // int 1b
00452                 phys_writeb(physAddress+0x02,(Bit8u)0xfa);              // cli
00453                 if (use_cb) {
00454                         phys_writeb(physAddress+0x03,(Bit8u)0xFE);      //GRP 4
00455                         phys_writeb(physAddress+0x04,(Bit8u)0x38);      //Extra Callback instruction
00456                         phys_writew(physAddress+0x05,(Bit16u)callback);         //The immediate word
00457                         physAddress+=4;
00458                 }
00459                 phys_writew(physAddress+0x03,(Bit16u)0x20b0);           // mov al, 0x20
00460                 phys_writew(physAddress+0x05,(Bit16u)(IS_PC98_ARCH ? 0x00e6 : 0x20e6));         // out 0x20, al
00461                 phys_writeb(physAddress+0x07,(Bit8u)0x58);                      // pop ax
00462                 phys_writeb(physAddress+0x08,(Bit8u)0xcf);                      //An IRET Instruction
00463                 return (use_cb?0x0d:0x09);
00464         case CB_IRQ9:   // pic cascade interrupt
00465                 if (use_cb) {
00466                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00467                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00468                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00469                         physAddress+=4;
00470                 }
00471                 phys_writeb(physAddress+0x00,(Bit8u)0x50);              // push ax
00472                 phys_writew(physAddress+0x01,(Bit16u)0x61b0);   // mov al, 0x61
00473                 phys_writew(physAddress+0x03,(Bit16u)0xa0e6);   // out 0xa0, al
00474                 phys_writew(physAddress+0x05,(Bit16u)0x0acd);   // int a
00475                 phys_writeb(physAddress+0x07,(Bit8u)0xfa);              // cli
00476                 phys_writeb(physAddress+0x08,(Bit8u)0x58);              // pop ax
00477                 phys_writeb(physAddress+0x09,(Bit8u)0xcf);              //An IRET Instruction
00478                 return (use_cb?0x0e:0x0a);
00479         case CB_IRQ12:  // ps2 mouse int74
00480                 if (!use_cb) E_Exit("int74 callback must implement a callback handler!");
00481                 phys_writeb(physAddress++,(Bit8u)0xfb);         // sti
00482                 phys_writeb(physAddress++,(Bit8u)0x1e);         // push ds
00483                 phys_writeb(physAddress++,(Bit8u)0x06);         // push es
00484                 if (CPU_ArchitectureType>=CPU_ARCHTYPE_386) {
00485                         phys_writew(physAddress,(Bit16u)0x6066);// pushad
00486                         physAddress += 2;
00487                 }
00488                 else if (CPU_ArchitectureType>=CPU_ARCHTYPE_80186) {
00489                         phys_writeb(physAddress++,(Bit8u)0x60); // pusha
00490                 }
00491                 else {
00492                         // 8086-level tedium, PUSHA not available
00493                         phys_writeb(physAddress++,(Bit8u)0x50); // push ax
00494                         phys_writeb(physAddress++,(Bit8u)0x51); // push cx
00495                         phys_writeb(physAddress++,(Bit8u)0x52); // push dx
00496                         phys_writeb(physAddress++,(Bit8u)0x53); // push bx
00497                         phys_writeb(physAddress++,(Bit8u)0x55); // push bp
00498                         phys_writeb(physAddress++,(Bit8u)0x56); // push si
00499                         phys_writeb(physAddress++,(Bit8u)0x57); // push di
00500                 }
00501                 phys_writeb(physAddress++,(Bit8u)0xFE);         //GRP 4
00502                 phys_writeb(physAddress++,(Bit8u)0x38);         //Extra Callback instruction
00503                 phys_writew(physAddress,(Bit16u)callback);                      //The immediate word
00504                 physAddress += 2;
00505                 phys_writeb(physAddress++,(Bit8u)0x50);         // push ax
00506                 phys_writew(physAddress,(Bit16u)0x20b0);        // mov al, 0x20
00507                 physAddress += 2;
00508                 phys_writew(physAddress,(Bit16u)0xa0e6);        // out 0xa0, al
00509                 physAddress += 2;
00510                 phys_writew(physAddress,(Bit16u)0x20e6);        // out 0x20, al
00511                 physAddress += 2;
00512                 phys_writeb(physAddress++,(Bit8u)0x58);         // pop ax
00513                 phys_writeb(physAddress++,(Bit8u)0xfc);         // cld
00514                 phys_writeb(physAddress++,(Bit8u)0xCB);         //A RETF Instruction
00515                 return 0x13;
00516         case CB_IRQ12_RET:      // ps2 mouse int74 return
00517                 phys_writeb(physAddress++,(Bit8u)0xfa);         // cli
00518                 phys_writew(physAddress,(Bit16u)0x20b0);        // mov al, 0x20
00519                 physAddress += 2;
00520                 phys_writew(physAddress,(Bit16u)0xa0e6);        // out 0xa0, al
00521                 physAddress += 2;
00522                 phys_writew(physAddress,(Bit16u)0x20e6);        // out 0x20, al
00523                 physAddress += 2;
00524                 if (use_cb) {
00525                         phys_writeb(physAddress++,(Bit8u)0xFE); //GRP 4
00526                         phys_writeb(physAddress++,(Bit8u)0x38); //Extra Callback instruction
00527                         phys_writew(physAddress,(Bit16u)callback);              //The immediate word
00528                         physAddress+=2;
00529                 }
00530                 if (CPU_ArchitectureType>=CPU_ARCHTYPE_386) {
00531                         phys_writew(physAddress,(Bit16u)0x6166);// popad
00532                         physAddress += 2;
00533                 }
00534                 else if (CPU_ArchitectureType>=CPU_ARCHTYPE_80186) {
00535                         phys_writeb(physAddress++,(Bit8u)0x61); // popa
00536                 }
00537                 else {
00538                         // 8086-level tedium, POPA not available
00539                         phys_writeb(physAddress++,(Bit8u)0x5F); // pop di
00540                         phys_writeb(physAddress++,(Bit8u)0x5E); // pop si
00541                         phys_writeb(physAddress++,(Bit8u)0x5D); // pop bp
00542                         phys_writeb(physAddress++,(Bit8u)0x5B); // pop bx
00543                         phys_writeb(physAddress++,(Bit8u)0x5A); // pop dx
00544                         phys_writeb(physAddress++,(Bit8u)0x59); // pop cx
00545                         phys_writeb(physAddress++,(Bit8u)0x58); // pop ax
00546                 }
00547                 phys_writeb(physAddress++,(Bit8u)0x07);         // pop es
00548                 phys_writeb(physAddress++,(Bit8u)0x1f);         // pop ds
00549                 phys_writeb(physAddress++,(Bit8u)0xcf);         //An IRET Instruction
00550                 return (use_cb?0x10:0x0c);
00551         case CB_IRQ6_PCJR:      // pcjr keyboard interrupt
00552                 phys_writeb(physAddress+0x00,(Bit8u)0x50);                      // push ax
00553                 phys_writew(physAddress+0x01,(Bit16u)0x60e4);           // in al, 0x60
00554                 phys_writew(physAddress+0x03,(Bit16u)0xe03c);           // cmp al, 0xe0
00555                 if (use_cb) {
00556                         phys_writew(physAddress+0x05,(Bit16u)0x0b74);   // je skip
00557                         phys_writeb(physAddress+0x07,(Bit8u)0xFE);              //GRP 4
00558                         phys_writeb(physAddress+0x08,(Bit8u)0x38);              //Extra Callback instruction
00559                         phys_writew(physAddress+0x09,(Bit16u)callback);                 //The immediate word
00560                         physAddress+=4;
00561                 } else {
00562                         phys_writew(physAddress+0x05,(Bit16u)0x0774);   // je skip
00563                 }
00564                 phys_writeb(physAddress+0x07,(Bit8u)0x1e);                      // push ds
00565                 phys_writew(physAddress+0x08,(Bit16u)0x406a);           // push 0x0040
00566                 phys_writeb(physAddress+0x0a,(Bit8u)0x1f);                      // pop ds
00567                 phys_writew(physAddress+0x0b,(Bit16u)0x09cd);           // int 9
00568                 phys_writeb(physAddress+0x0d,(Bit8u)0x1f);                      // pop ds
00569                 // jump here to (skip):
00570                 phys_writeb(physAddress+0x0e,(Bit8u)0xfa);                      // cli
00571                 phys_writew(physAddress+0x0f,(Bit16u)0x20b0);           // mov al, 0x20
00572                 phys_writew(physAddress+0x11,(Bit16u)0x20e6);           // out 0x20, al
00573                 phys_writeb(physAddress+0x13,(Bit8u)0x58);                      // pop ax
00574                 phys_writeb(physAddress+0x14,(Bit8u)0xcf);                      //An IRET Instruction
00575                 return (use_cb?0x19:0x15);
00576         case CB_MOUSE:
00577                 phys_writew(physAddress+0x00,(Bit16u)0x07eb);           // jmp i33hd
00578                 physAddress+=9;
00579                 // jump here to (i33hd):
00580                 if (use_cb) {
00581                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00582                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00583                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00584                         physAddress+=4;
00585                 }
00586                 phys_writeb(physAddress+0x00,(Bit8u)0xCF);              //An IRET Instruction
00587                 return (use_cb?0x0e:0x0a);
00588         case CB_INT16:
00589                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              //STI
00590                 if (use_cb) {
00591                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00592                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00593                         phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word
00594                         physAddress+=4;
00595                 }
00596                 phys_writeb(physAddress+0x01,(Bit8u)0xCF);              //An IRET Instruction
00597                 for (Bit8u i=0;i<=0x0b;i++) phys_writeb(physAddress+0x02+i,0x90);
00598                 phys_writew(physAddress+0x0e,(Bit16u)0xedeb);   //jmp callback
00599                 return (use_cb?0x10:0x0c);
00600         /*case CB_INT28:        // DOS idle
00601                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              // STI
00602                 phys_writeb(physAddress+0x01,(Bit8u)0xF4);              // HLT
00603                 phys_writeb(physAddress+0x02,(Bit8u)0xcf);              // An IRET Instruction
00604                 return (0x04);*/
00605         case CB_INT29:  // fast console output
00606         if (IS_PC98_ARCH) LOG_MSG("WARNING: CB_INT29 callback setup not appropriate for PC-98 mode (INT 10h no longer BIOS call)");
00607                 if (use_cb) {
00608                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00609                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00610                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00611                         physAddress+=4;
00612                 }
00613                 phys_writeb(physAddress+0x00,(Bit8u)0x50);      // push ax
00614                 phys_writeb(physAddress+0x01,(Bit8u)0x53);      // push bx
00615                 phys_writew(physAddress+0x02,(Bit16u)0x0eb4);   // mov ah, 0x0e
00616                 phys_writeb(physAddress+0x04,(Bit8u)0xbb);      // mov bx,
00617                 phys_writew(physAddress+0x05,(Bit16u)0x0007);   // 0x0007
00618                 phys_writew(physAddress+0x07,(Bit16u)0x10cd);   // int 10
00619                 phys_writeb(physAddress+0x09,(Bit8u)0x5b);      // pop bx
00620                 phys_writeb(physAddress+0x0a,(Bit8u)0x58);      // pop ax
00621                 phys_writeb(physAddress+0x0b,(Bit8u)0xcf);      //An IRET Instruction
00622                 return (use_cb?0x10:0x0c);
00623         case CB_HOOKABLE:
00624                 phys_writeb(physAddress+0x00,(Bit8u)0xEB);              //jump near
00625                 phys_writeb(physAddress+0x01,(Bit8u)0x03);              //offset
00626                 phys_writeb(physAddress+0x02,(Bit8u)0x90);              //NOP
00627                 phys_writeb(physAddress+0x03,(Bit8u)0x90);              //NOP
00628                 phys_writeb(physAddress+0x04,(Bit8u)0x90);              //NOP
00629                 if (use_cb) {
00630                         phys_writeb(physAddress+0x05,(Bit8u)0xFE);      //GRP 4
00631                         phys_writeb(physAddress+0x06,(Bit8u)0x38);      //Extra Callback instruction
00632                         phys_writew(physAddress+0x07,(Bit16u)callback);         //The immediate word
00633                         physAddress+=4;
00634                 }
00635                 phys_writeb(physAddress+0x05,(Bit8u)0xCB);              //A RETF Instruction
00636                 return (use_cb?0x0a:0x06);
00637         case CB_TDE_IRET:       // TandyDAC end transfer
00638                 if (use_cb) {
00639                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00640                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00641                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00642                         physAddress+=4;
00643                 }
00644                 phys_writeb(physAddress+0x00,(Bit8u)0x50);              // push ax
00645                 phys_writeb(physAddress+0x01,(Bit8u)0xb8);              // mov ax, 0x91fb
00646                 phys_writew(physAddress+0x02,(Bit16u)0x91fb);
00647                 phys_writew(physAddress+0x04,(Bit16u)0x15cd);   // int 15
00648                 phys_writeb(physAddress+0x06,(Bit8u)0xfa);              // cli
00649                 phys_writew(physAddress+0x07,(Bit16u)0x20b0);   // mov al, 0x20
00650                 phys_writew(physAddress+0x09,(Bit16u)0x20e6);   // out 0x20, al
00651                 phys_writeb(physAddress+0x0b,(Bit8u)0x58);              // pop ax
00652                 phys_writeb(physAddress+0x0c,(Bit8u)0xcf);              //An IRET Instruction
00653                 return (use_cb?0x11:0x0d);
00654 /*      case CB_IPXESR:         // IPX ESR
00655                 if (!use_cb) E_Exit("ipx esr must implement a callback handler!");
00656                 phys_writeb(physAddress+0x00,(Bit8u)0x1e);              // push ds
00657                 phys_writeb(physAddress+0x01,(Bit8u)0x06);              // push es
00658                 phys_writew(physAddress+0x02,(Bit16u)0xa00f);   // push fs
00659                 phys_writew(physAddress+0x04,(Bit16u)0xa80f);   // push gs
00660                 phys_writeb(physAddress+0x06,(Bit8u)0x60);              // pusha
00661                 phys_writeb(physAddress+0x07,(Bit8u)0xFE);              //GRP 4
00662                 phys_writeb(physAddress+0x08,(Bit8u)0x38);              //Extra Callback instruction
00663                 phys_writew(physAddress+0x09,(Bit16u)callback); //The immediate word
00664                 phys_writeb(physAddress+0x0b,(Bit8u)0xCB);              //A RETF Instruction
00665                 return 0x0c;
00666         case CB_IPXESR_RET:             // IPX ESR return
00667                 if (use_cb) E_Exit("ipx esr return must not implement a callback handler!");
00668                 phys_writeb(physAddress+0x00,(Bit8u)0xfa);              // cli
00669                 phys_writew(physAddress+0x01,(Bit16u)0x20b0);   // mov al, 0x20
00670                 phys_writew(physAddress+0x03,(Bit16u)0xa0e6);   // out 0xa0, al
00671                 phys_writew(physAddress+0x05,(Bit16u)0x20e6);   // out 0x20, al
00672                 phys_writeb(physAddress+0x07,(Bit8u)0x61);              // popa
00673                 phys_writew(physAddress+0x08,(Bit16u)0xA90F);   // pop gs
00674                 phys_writew(physAddress+0x0a,(Bit16u)0xA10F);   // pop fs
00675                 phys_writeb(physAddress+0x0c,(Bit8u)0x07);              // pop es
00676                 phys_writeb(physAddress+0x0d,(Bit8u)0x1f);              // pop ds
00677                 phys_writeb(physAddress+0x0e,(Bit8u)0xcf);              //An IRET Instruction
00678                 return 0x0f; */
00679         case CB_INT21:
00680                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              //STI
00681                 if (use_cb) {
00682                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00683                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00684                         phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word
00685                         physAddress+=4;
00686                 }
00687                 phys_writeb(physAddress+0x01,(Bit8u)0xCF);              //An IRET Instruction
00688                 phys_writeb(physAddress+0x02,(Bit8u)0xCB);              //A RETF Instruction
00689                 phys_writeb(physAddress+0x03,(Bit8u)0x51);              // push cx
00690                 phys_writeb(physAddress+0x04,(Bit8u)0xB9);              // mov cx,
00691                 phys_writew(physAddress+0x05,(Bit16u)0x0140);           // 0x140
00692                 phys_writew(physAddress+0x07,(Bit16u)0xFEE2);           // loop $-2
00693                 phys_writeb(physAddress+0x09,(Bit8u)0x59);              // pop cx
00694                 phys_writeb(physAddress+0x0A,(Bit8u)0xCF);              //An IRET Instruction
00695                 return (use_cb?15:11);
00696         case CB_INT13:
00697                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              //STI
00698                 if (use_cb) {
00699                         phys_writeb(physAddress+0x01,(Bit8u)0xFE);      //GRP 4
00700                         phys_writeb(physAddress+0x02,(Bit8u)0x38);      //Extra Callback instruction
00701                         phys_writew(physAddress+0x03,(Bit16u)callback); //The immediate word
00702                         physAddress+=4;
00703                 }
00704                 phys_writeb(physAddress+0x01,(Bit8u)0xCF);              //An IRET Instruction
00705                 phys_writew(physAddress+0x02,(Bit16u)0x0ECD);           // int 0e
00706                 phys_writeb(physAddress+0x04,(Bit8u)0xCF);              //An IRET Instruction
00707                 return (use_cb?9:5);
00708         case CB_VESA_WAIT:
00709                 if (use_cb) E_Exit("VESA wait must not implement a callback handler!");
00710                 phys_writeb(physAddress+0x00,(Bit8u)0xFB);              // sti
00711                 phys_writeb(physAddress+0x01,(Bit8u)0x50);              // push ax
00712                 phys_writeb(physAddress+0x02,(Bit8u)0x52);              // push dx
00713                 phys_writeb(physAddress+0x03,(Bit8u)0xBA);              // mov dx,
00714                 phys_writew(physAddress+0x04,(Bit16u)0x03DA);   // 0x3da
00715                 phys_writeb(physAddress+0x06,(Bit8u)0xEC);              // in al,dx
00716                 phys_writew(physAddress+0x07,(Bit16u)0x08A8);   // test al,8
00717                 phys_writew(physAddress+0x09,(Bit16u)0xFB75);   // jne $-5
00718                 phys_writeb(physAddress+0x0B,(Bit8u)0xEC);              // in al,dx
00719                 phys_writew(physAddress+0x0C,(Bit16u)0x08A8);   // test al,8
00720                 phys_writew(physAddress+0x0E,(Bit16u)0xFB74);   // je $-5
00721                 phys_writeb(physAddress+0x10,(Bit8u)0x5A);              // pop dx
00722                 phys_writeb(physAddress+0x11,(Bit8u)0x58);              // pop ax
00723                 phys_writeb(physAddress+0x12,(Bit8u)0xCB);              //A RETF Instruction
00724                 return 19;
00725         case CB_VESA_PM:
00726                 if (use_cb) {
00727                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00728                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00729                         phys_writew(physAddress+0x02,(Bit16u)callback); //The immediate word
00730                         physAddress+=4;
00731                 }
00732                 phys_writew(physAddress+0x00,(Bit16u)0xC3F6);   // test bl,
00733                 phys_writeb(physAddress+0x02,(Bit8u)0x80);              // 0x80
00734                 phys_writew(physAddress+0x03,(Bit16u)0x1674);   // je $+22
00735                 phys_writew(physAddress+0x05,(Bit16u)0x5066);   // push ax
00736                 phys_writew(physAddress+0x07,(Bit16u)0x5266);   // push dx
00737                 phys_writew(physAddress+0x09,(Bit16u)0xBA66);   // mov dx,
00738                 phys_writew(physAddress+0x0B,(Bit16u)0x03DA);   // 0x3da
00739                 phys_writeb(physAddress+0x0D,(Bit8u)0xEC);              // in al,dx
00740                 phys_writew(physAddress+0x0E,(Bit16u)0x08A8);   // test al,8
00741                 phys_writew(physAddress+0x10,(Bit16u)0xFB75);   // jne $-5
00742                 phys_writeb(physAddress+0x12,(Bit8u)0xEC);              // in al,dx
00743                 phys_writew(physAddress+0x13,(Bit16u)0x08A8);   // test al,8
00744                 phys_writew(physAddress+0x15,(Bit16u)0xFB74);   // je $-5
00745                 phys_writew(physAddress+0x17,(Bit16u)0x5A66);   // pop dx
00746                 phys_writew(physAddress+0x19,(Bit16u)0x5866);   // pop ax
00747                 if (use_cb)
00748                         phys_writeb(physAddress+0x1B,(Bit8u)0xC3);      //A RETN Instruction
00749                 return (use_cb?32:27);
00750         case CB_IRET_EOI_PIC2:
00751                 if (use_cb) {
00752                         phys_writeb(physAddress+0x00,(Bit8u)0xFE);      //GRP 4
00753                         phys_writeb(physAddress+0x01,(Bit8u)0x38);      //Extra Callback instruction
00754                         phys_writew(physAddress+0x02,(Bit16u)callback);         //The immediate word
00755                         physAddress+=4;
00756                 }
00757                 phys_writeb(physAddress+0x00,(Bit8u)0x50);              // push ax
00758                 phys_writeb(physAddress+0x01,(Bit8u)0xb0);              // mov al, 0x20
00759                 phys_writeb(physAddress+0x02,(Bit8u)0x20);
00760                 phys_writeb(physAddress+0x03,(Bit8u)0xe6);              // out 0xA0, al (IBM) / out 0x08, al (PC-98)
00761                 phys_writeb(physAddress+0x04,(Bit8u)(IS_PC98_ARCH ? 0x08 : 0xA0));
00762                 phys_writeb(physAddress+0x05,(Bit8u)0xe6);              // out 0x20, al (IBM) / out 0x00, al (PC-98)
00763                 phys_writeb(physAddress+0x06,(Bit8u)(IS_PC98_ARCH ? 0x00 : 0x20));
00764                 phys_writeb(physAddress+0x07,(Bit8u)0x58);              // pop ax
00765                 phys_writeb(physAddress+0x08,(Bit8u)0xcf);              //An IRET Instruction
00766                 return (use_cb?0x0d:0x09);
00767         case CB_CPM:
00768                 phys_writeb(physAddress+0x00,(Bit8u)0x9C);              //PUSHF
00769                 return CALLBACK_SetupExtra(callback,CB_INT21,physAddress+1,use_cb)+1;
00770         default:
00771                 E_Exit("CALLBACK:Setup:Illegal type %u",(unsigned int)type);
00772         }
00773         return 0;
00774 }
00775 
00776 bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* descr) {
00777         if (callback>=CB_MAX) return false;
00778         CALLBACK_SetupExtra(callback,type,CALLBACK_PhysPointer(callback)+0,(handler!=NULL));
00779         CallBack_Handlers[callback]=handler;
00780         CALLBACK_SetDescription(callback,descr);
00781         return true;
00782 }
00783 
00784 Bitu CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,PhysPt addr,const char* descr) {
00785         if (callback>=CB_MAX) return 0;
00786         Bitu csize=CALLBACK_SetupExtra(callback,type,addr,(handler!=NULL));
00787         if (csize>0) {
00788                 CallBack_Handlers[callback]=handler;
00789                 CALLBACK_SetDescription(callback,descr);
00790         }
00791         return csize;
00792 }
00793 
00794 void CALLBACK_RemoveSetup(Bitu callback) {
00795         if (MemBase == NULL) {
00796                 /* avoid crash */
00797                 return;
00798         }
00799 
00800         for (Bit8u i = 0;i < CB_SIZE;i++) {
00801                 phys_writeb(CALLBACK_PhysPointer(callback)+i ,(Bit8u) 0x00);
00802         }
00803 }
00804 
00805 void CALLBACK_HandlerObject::Uninstall(){
00806         if(!installed) return;
00807         if(m_type == CALLBACK_HandlerObject::SETUP) {
00808                 if(vectorhandler.installed && MemBase != NULL){
00809                         //See if we are the current handler. if so restore the old one
00810                         if(RealGetVec(vectorhandler.interrupt) == Get_RealPointer()) {
00811                                 RealSetVec(vectorhandler.interrupt,vectorhandler.old_vector);
00812                         } else
00813                                 LOG(LOG_MISC,LOG_WARN)("Interrupt vector changed on %X %s",vectorhandler.interrupt,CALLBACK_GetDescription(m_callback));
00814                 }
00815                 CALLBACK_RemoveSetup(m_callback);
00816         } else if(m_type == CALLBACK_HandlerObject::SETUPAT){
00817                 E_Exit("Callback:SETUP at not handled yet.");
00818         } else if(m_type == CALLBACK_HandlerObject::NONE){
00819                 //Do nothing. Merely DeAllocate the callback
00820         } else E_Exit("what kind of callback is this!");
00821         if(CallBack_Description[m_callback]) delete [] CallBack_Description[m_callback];
00822         CallBack_Description[m_callback] = 0;
00823         CALLBACK_DeAllocate(m_callback);
00824         installed=false;
00825 }
00826 
00827 CALLBACK_HandlerObject::~CALLBACK_HandlerObject(){
00828         Uninstall();
00829 }
00830 
00831 void CALLBACK_HandlerObject::Install(CallBack_Handler handler,Bitu type,const char* description){
00832         if(!installed) {
00833                 installed=true;
00834                 m_type=SETUP;
00835                 m_callback=CALLBACK_Allocate();
00836                 CALLBACK_Setup(m_callback,handler,type,description);
00837         } else E_Exit("Callback handler object already installed");
00838 }
00839 void CALLBACK_HandlerObject::Install(CallBack_Handler handler,Bitu type,PhysPt addr,const char* description){
00840         if(!installed) {
00841                 installed=true;
00842                 m_type=SETUP;
00843                 m_callback=CALLBACK_Allocate();
00844                 CALLBACK_Setup(m_callback,handler,type,addr,description);
00845         } else E_Exit("Callback handler object already installed");
00846 }
00847 
00848 void CALLBACK_HandlerObject::Allocate(CallBack_Handler handler,const char* description) {
00849         if(!installed) {
00850                 installed=true;
00851                 m_type=NONE;
00852                 m_callback=CALLBACK_Allocate();
00853                 CALLBACK_SetDescription(m_callback,description);
00854                 CallBack_Handlers[m_callback]=handler;
00855         } else E_Exit("Callback handler object already installed");
00856 }
00857 
00858 void CALLBACK_HandlerObject::Set_RealVec(Bit8u vec,bool reinstall){
00859         if(!vectorhandler.installed || reinstall) {
00860                 vectorhandler.installed=true;
00861                 vectorhandler.interrupt=vec;
00862                 RealSetVec(vec,Get_RealPointer(),vectorhandler.old_vector);
00863         } else E_Exit ("double usage of vector handler");
00864 }
00865 
00866 extern bool custom_bios;
00867 
00868 void CALLBACK_Init() {
00869         {
00870                 /* NTS: Layout of the callback area:
00871                  *
00872                  * CB_MAX entries CB_SIZE each, where executable x86 code is written per callback,
00873                  * followed by 256 entries 6 bytes each corresponding to an interrupt call */
00874                 Bitu o;
00875 
00876                 LOG(LOG_MISC,LOG_DEBUG)("Initializing DOSBox callback instruction system");
00877 
00878                 o = ROMBIOS_GetMemory((CB_MAX*CB_SIZE)+(256*6),"DOSBox callback area",/*align*/4);
00879                 if (o == 0) E_Exit("Cannot allocate callback area");
00880                 CB_SOFFSET = o&0xFFFF;
00881                 CB_SEG = (o>>4)&0xF000;
00882                 if (((Bitu)CB_SOFFSET + (CB_MAX*CB_SIZE) + (256*6)) > 0x10000) E_Exit("Callback area spans 64KB segment");
00883 
00884                 o = ROMBIOS_GetMemory(14/*2+2+3+2+2+3*/,"DOSBox vm86 hack",/*align*/4);
00885                 if (o == 0) E_Exit("Cannot allocate vm86 hack");
00886                 vm86_fake_io_off = o&0xFFFF;
00887                 vm86_fake_io_seg = (o>>4)&0xF000;
00888                 if ((vm86_fake_io_off+14) > 0x1000000) E_Exit("vm86 area spans 64KB segment");
00889         }
00890 
00891         LOG(LOG_CPU,LOG_DEBUG)("Callback area starts at %04x:%04x",CB_SEG,CB_SOFFSET);
00892 
00893         Bit16u i;
00894         for (i=0;i<CB_MAX;i++) {
00895                 CallBack_Handlers[i]=&illegal_handler;
00896                 CallBack_Description[i]=NULL;
00897         }
00898 
00899         /* Setup the Stop Handler */
00900         call_stop=CALLBACK_Allocate();
00901         CallBack_Handlers[call_stop]=stop_handler;
00902         CALLBACK_SetDescription(call_stop,"stop");
00903         phys_writeb(CALLBACK_PhysPointer(call_stop)+0,0xFE);
00904         phys_writeb(CALLBACK_PhysPointer(call_stop)+1,0x38);
00905         phys_writew(CALLBACK_PhysPointer(call_stop)+2,(Bit16u)call_stop);
00906 
00907         /* Setup the idle handler */
00908         call_idle=CALLBACK_Allocate();
00909         CallBack_Handlers[call_idle]=stop_handler;
00910         CALLBACK_SetDescription(call_idle,"idle");
00911         for (i=0;i<=11;i++) phys_writeb(CALLBACK_PhysPointer(call_idle)+i,0x90);
00912         phys_writeb(CALLBACK_PhysPointer(call_idle)+12,0xFE);
00913         phys_writeb(CALLBACK_PhysPointer(call_idle)+13,0x38);
00914         phys_writew(CALLBACK_PhysPointer(call_idle)+14,(Bit16u)call_idle);
00915 
00916         /* Default handlers for unhandled interrupts that have to be non-null */
00917         call_default=CALLBACK_Allocate();
00918         CALLBACK_Setup(call_default,&default_handler,CB_IRET,"default");
00919 
00920         /* Setup block of 0xCD 0xxx instructions */
00921         PhysPt rint_base=CALLBACK_GetBase()+CB_MAX*CB_SIZE;
00922         for (i=0;i<=0xff;i++) {
00923                 phys_writeb(rint_base,0xCD);
00924                 phys_writeb(rint_base+1,(Bit8u)i);
00925                 phys_writeb(rint_base+2,0xFE);
00926                 phys_writeb(rint_base+3,0x38);
00927                 phys_writew(rint_base+4,(Bit16u)call_stop);
00928                 rint_base+=6;
00929 
00930         }
00931 
00932         call_priv_io=CALLBACK_Allocate();
00933 
00934         // virtualizable in-out opcodes
00935         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x00,(Bit8u)0xec);       // in al, dx
00936         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x01,(Bit8u)0xcb);       // retf
00937         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x02,(Bit8u)0xed);       // in ax, dx
00938         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x03,(Bit8u)0xcb);       // retf
00939         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x04,(Bit8u)0x66);       // in eax, dx
00940         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x05,(Bit8u)0xed);
00941         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x06,(Bit8u)0xcb);       // retf
00942 
00943         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x08,(Bit8u)0xee);       // out dx, al
00944         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x09,(Bit8u)0xcb);       // retf
00945         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0a,(Bit8u)0xef);       // out dx, ax
00946         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0b,(Bit8u)0xcb);       // retf
00947         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0c,(Bit8u)0x66);       // out dx, eax
00948         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0d,(Bit8u)0xef);
00949         phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0e,(Bit8u)0xcb);       // retf
00950 }