DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/cpu.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <assert.h>
00021 #include <sstream>
00022 #include <stddef.h>
00023 #include "dosbox.h"
00024 #include "cpu.h"
00025 #include "memory.h"
00026 #include "debug.h"
00027 #include "mapper.h"
00028 #include "setup.h"
00029 #include "programs.h"
00030 #include "paging.h"
00031 #include "callback.h"
00032 #include "lazyflags.h"
00033 #include "support.h"
00034 #include "control.h"
00035 #include "zipfile.h"
00036 
00037 #if defined(_MSC_VER)
00038 /* we don't care about switch statements with no case labels */
00039 #pragma warning(disable:4065)
00040 #endif
00041 
00042 extern ZIPFile savestate_zip;
00043 
00044 /* caution: do not uncomment unless you want a lot of spew */
00045 //#define CPU_DEBUG_SPEW
00046 
00047 #if defined(CPU_DEBUG_SPEW)
00048 # define _LOG LOG
00049 #else
00050 class _LOG : public LOG { // HACK
00051 public:
00052         _LOG(LOG_TYPES type , LOG_SEVERITIES severity) : LOG(type,severity) { }
00053 };
00054 # undef LOG
00055 # if defined (_MSC_VER)
00056 #  define LOG(X,Y)
00057 # else
00058 #  define LOG(X,Y) CPU_LOG
00059 # define CPU_LOG(...)
00060 # endif
00061 #endif
00062 
00063 bool enable_weitek = false;
00064 
00065 bool CPU_NMI_gate = true;
00066 bool CPU_NMI_active = false;
00067 bool CPU_NMI_pending = false;
00068 bool do_seg_limits = false;
00069 
00070 bool enable_fpu = true;
00071 bool enable_msr = true;
00072 bool enable_cmpxchg8b = true;
00073 bool ignore_undefined_msr = true;
00074 
00075 extern bool ignore_opcode_63;
00076 
00077 extern bool use_dynamic_core_with_paging;
00078 
00079 bool cpu_double_fault_enable;
00080 bool cpu_triple_fault_reset;
00081 
00082 int cpu_rep_max = 0;
00083 
00084 Bitu DEBUG_EnableDebugger(void);
00085 extern void GFX_SetTitle(Bit32s cycles, Bits frameskip, Bits timing, bool paused);
00086 
00087 CPU_Regs cpu_regs;
00088 CPUBlock cpu;
00089 Segments Segs;
00090 
00091 /* [cpu] setting realbig16.
00092  * If set, allow code to switch back to real mode with the B (big) set in the
00093  * code selector, and retain the state of the B bit while running in 16-bit
00094  * real mode. Needed for demos like Project Angel.
00095  *
00096  * Modifications are a derivative of this patch:
00097  *
00098  * cpu.diff from http://www.vogons.org/viewtopic.php?f=33&t=28226&start=5
00099  *
00100  * The main difference between that patch and the modifications derived is that
00101  * I modified additional points to keep the big bit set (the original cpu.diff
00102  * missed the CALL and JMP emulation that also reset the flag)
00103  *
00104  * It's well known that DOS programs can access all 4GB of addressable memory by
00105  * jumping into protected mode, loading segment registers with a 4GB limit, then
00106  * jumping back to real mode without reloading the segment registers, knowing
00107  * that Intel processors will not update the shadow part of the segment register
00108  * in real mode. I'm guessing that what Project Angel is doing, is using the same
00109  * abuse of protected mode to also set the B (big) bit in the code segment so that
00110  * it's code segment can extend past 64KB (huge unreal mode), which works until
00111  * something like an interrupt chops off the top 16 bits of the instruction pointer.
00112  *
00113  * I want to clarify that realbig16 is an OPTION that is off by default, because
00114  * I am uncertain at this time whether or not the patch breaks any DOS games or
00115  * OS emulation. It is rare for a DOS game or demo to actually abuse the CPU in
00116  * that way, so it is set up that you have to enable it if you need it. --J.C.
00117  *
00118  * J.C. TODO: Write a program that abuses the B (big) bit in real mode in the same
00119  *            way that Project Angel supposedly does, see if it works, then test it
00120  *            and Project Angel on some old 386/486/Pentium systems lying around to
00121  *            see how compatible such abuse is with PC hardware. That would make a
00122  *            good Hackipedia.org episode as well. --J.C.
00123  *
00124  * 2014/01/19: I can attest that this patch does indeed allow Project Angel to
00125  *             run when realbig16=true. And if GUS emulation is active, there is
00126  *             music as well. Now as for reliability... testing shows that one of
00127  *             three things can happen when you run the demo:
00128  *
00129  *             1) the demo hangs on startup, either right away or after it starts
00130  *                the ominous music (if you sit for 30 seconds waiting for the
00131  *                music to build up and nothing happens, consider closing the
00132  *                emulator and trying again).
00133  *
00134  *             2) the demo runs perfectly fine, but timing is slightly screwed up,
00135  *                and parts of the music sound badly out of sync with each other,
00136  *                or randomly slows to about 1/2 speed in some sections, animations
00137  *                run slow sometimes. If this happens, make sure you didn't set
00138  *                forcerate=ntsc.
00139  *
00140  *             3) the demo runs perfectly fine, with no timing issues, except that
00141  *                DOSBox's S3 emulation is not quite on-time and the bottom 1/4th
00142  *                of the screen flickers with the contents of the next frame that
00143  *                the demo is still drawing :(
00144  *
00145  *             --J.C. */
00146 bool cpu_allow_big16 = false;
00147 
00148 cpu_cycles_count_t CPU_Cycles = 0;
00149 cpu_cycles_count_t CPU_CycleLeft = 3000;
00150 cpu_cycles_count_t CPU_CycleMax = 3000;
00151 cpu_cycles_count_t CPU_OldCycleMax = 3000;
00152 cpu_cycles_count_t CPU_CyclePercUsed = 100;
00153 cpu_cycles_count_t CPU_CycleLimit = -1;
00154 cpu_cycles_count_t CPU_CycleUp = 0;
00155 cpu_cycles_count_t CPU_CycleDown = 0;
00156 cpu_cycles_count_t CPU_CyclesSet = 3000;
00157 cpu_cycles_count_t CPU_IODelayRemoved = 0;
00158 char core_mode[16];
00159 CPU_Decoder * cpudecoder;
00160 bool CPU_CycleAutoAdjust = false;
00161 bool CPU_SkipCycleAutoAdjust = false;
00162 unsigned char CPU_AutoDetermineMode = 0;
00163 
00164 unsigned char CPU_ArchitectureType = CPU_ARCHTYPE_MIXED;
00165 
00166 Bitu CPU_extflags_toggle=0;     // ID and AC flags may be toggled depending on emulated CPU architecture
00167 
00168 unsigned int CPU_PrefetchQueueSize=0;
00169 
00170 void CPU_Core_Full_Init(void);
00171 void CPU_Core_Normal_Init(void);
00172 void CPU_Core_Simple_Init(void);
00173 #if (C_DYNAMIC_X86)
00174 void CPU_Core_Dyn_X86_Init(void);
00175 void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache);
00176 void CPU_Core_Dyn_X86_Cache_Close(void);
00177 void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu);
00178 void CPU_Core_Dyn_X86_Cache_Reset(void);
00179 #endif
00180 
00181 void menu_update_cputype(void) {
00182         Section_prop * cpu_section = static_cast<Section_prop *>(control->GetSection("cpu"));
00183         const std::string cpu_sec_type = cpu_section->Get_string("cputype");
00184 
00185     bool is486 =
00186         (CPU_ArchitectureType == CPU_ARCHTYPE_486OLD) ||
00187         (CPU_ArchitectureType == CPU_ARCHTYPE_486NEW);
00188 
00189     mainMenu.get_item("cputype_auto").
00190         check(CPU_ArchitectureType == CPU_ARCHTYPE_MIXED).
00191         refresh_item(mainMenu);
00192     mainMenu.get_item("cputype_8086").
00193         check(CPU_ArchitectureType == CPU_ARCHTYPE_8086 && (cpudecoder != &CPU_Core_Prefetch_Run)).
00194         refresh_item(mainMenu);
00195     mainMenu.get_item("cputype_8086_prefetch").
00196         check(CPU_ArchitectureType == CPU_ARCHTYPE_8086 && (cpudecoder == &CPU_Core_Prefetch_Run)).
00197         enable(cpudecoder == &CPU_Core_Normal_Run || cpudecoder == &CPU_Core_Prefetch_Run).
00198         refresh_item(mainMenu);
00199     mainMenu.get_item("cputype_80186").
00200         check(CPU_ArchitectureType == CPU_ARCHTYPE_80186 && (cpudecoder != &CPU_Core_Prefetch_Run)).
00201         refresh_item(mainMenu);
00202     mainMenu.get_item("cputype_80186_prefetch").
00203         check(CPU_ArchitectureType == CPU_ARCHTYPE_80186 && (cpudecoder == &CPU_Core_Prefetch_Run)).
00204         enable(cpudecoder == &CPU_Core_Normal_Run || cpudecoder == &CPU_Core_Prefetch_Run).
00205         refresh_item(mainMenu);
00206     mainMenu.get_item("cputype_286").
00207         check(CPU_ArchitectureType == CPU_ARCHTYPE_286 && (cpudecoder != &CPU_Core_Prefetch_Run)).
00208         refresh_item(mainMenu);
00209     mainMenu.get_item("cputype_286_prefetch").
00210         check(CPU_ArchitectureType == CPU_ARCHTYPE_286 && (cpudecoder == &CPU_Core_Prefetch_Run)).
00211         enable(cpudecoder == &CPU_Core_Normal_Run || cpudecoder == &CPU_Core_Prefetch_Run).
00212         refresh_item(mainMenu);
00213     mainMenu.get_item("cputype_386").
00214         check(CPU_ArchitectureType == CPU_ARCHTYPE_386 && (cpudecoder != &CPU_Core_Prefetch_Run)).
00215         refresh_item(mainMenu);
00216     mainMenu.get_item("cputype_386_prefetch").
00217         check(CPU_ArchitectureType == CPU_ARCHTYPE_386 && (cpudecoder == &CPU_Core_Prefetch_Run)).
00218         enable(cpudecoder == &CPU_Core_Normal_Run || cpudecoder == &CPU_Core_Prefetch_Run).
00219         refresh_item(mainMenu);
00220     mainMenu.get_item("cputype_486").
00221         check(is486 && (cpudecoder != &CPU_Core_Prefetch_Run)).
00222         refresh_item(mainMenu);
00223     mainMenu.get_item("cputype_486_prefetch").
00224         check(is486 && (cpudecoder == &CPU_Core_Prefetch_Run)).
00225         enable(cpudecoder == &CPU_Core_Normal_Run || cpudecoder == &CPU_Core_Prefetch_Run).
00226         refresh_item(mainMenu);
00227     mainMenu.get_item("cputype_pentium").
00228         check(CPU_ArchitectureType == CPU_ARCHTYPE_PENTIUM).
00229         refresh_item(mainMenu);
00230     mainMenu.get_item("cputype_pentium_mmx").
00231         check(CPU_ArchitectureType == CPU_ARCHTYPE_P55CSLOW).
00232         refresh_item(mainMenu);
00233     mainMenu.get_item("cputype_ppro_slow").
00234         check(CPU_ArchitectureType == CPU_ARCHTYPE_PPROSLOW).
00235         refresh_item(mainMenu);
00236 }
00237 
00238 void menu_update_core(void) {
00239         Section_prop * cpu_section = static_cast<Section_prop *>(control->GetSection("cpu"));
00240         const std::string cpu_sec_type = cpu_section->Get_string("cputype");
00241     bool allow_dynamic = false;
00242 
00243     (void)cpu_section;
00244     (void)cpu_sec_type;
00245     (void)allow_dynamic;
00246 
00247     /* cannot select Dynamic core if prefetch cpu types are in use */
00248     allow_dynamic = (strstr(cpu_sec_type.c_str(),"_prefetch") == NULL);
00249 
00250     mainMenu.get_item("mapper_normal").
00251         check(cpudecoder == &CPU_Core_Normal_Run || cpudecoder == &CPU_Core_Prefetch_Run).
00252         refresh_item(mainMenu);
00253     mainMenu.get_item("mapper_simple").
00254         check(cpudecoder == &CPU_Core_Simple_Run).
00255         enable(cpudecoder != &CPU_Core_Prefetch_Run).
00256         refresh_item(mainMenu);
00257     mainMenu.get_item("mapper_full").
00258         check(cpudecoder == &CPU_Core_Full_Run).
00259         enable(cpudecoder != &CPU_Core_Prefetch_Run).
00260         refresh_item(mainMenu);
00261 #if (C_DYNAMIC_X86)
00262     mainMenu.get_item("mapper_dynamic").
00263         check(cpudecoder == &CPU_Core_Dyn_X86_Run).
00264         enable(allow_dynamic && (cpudecoder != &CPU_Core_Prefetch_Run)).
00265         refresh_item(mainMenu);
00266 #endif
00267 }
00268 
00269 void menu_update_autocycle(void) {
00270     DOSBoxMenu::item &item = mainMenu.get_item("mapper_cycauto");
00271     if (CPU_CycleAutoAdjust)
00272         item.set_text("Auto cycles [max]");
00273     else if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES)
00274         item.set_text("Auto cycles [auto]");
00275     else
00276         item.set_text("Auto cycles [off]");
00277 
00278     item.check(CPU_CycleAutoAdjust || (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES));
00279     item.refresh_item(mainMenu);
00280 }
00281 
00282 /* called to signal an NMI. */
00283 
00284 /* NTS: From the Intel 80386 programmer's reference manual:
00285  *
00286  * "
00287  *   9.2.1 NMI Masks Further NMIs
00288  *
00289  *   While an NMI handler is executing, the processor ignores further interrupt
00290  *   signals at the NMI pin until the next IRET instruction is executed.
00291  * "
00292  *
00293  * This is why, further down, CPU_IRET() clears the CPU_NMI_active flag.
00294  *
00295  *
00296  * And, in response to my father's incredulous response regarding the fact that
00297  * NMI is edge-triggered (from the Intel 386SX Microprocessor datasheet):
00298  *
00299  * "
00300  *   Non-Maskable Interrupt Request (NMI))
00301  *
00302  *   This input indicates a request for interrupt service
00303  *   which cannot be masked by software. The non-
00304  *   maskable interrupt request is always processed ac-
00305  *   cording to the pointer or gate in slot 2 of the interrupt
00306  *   table. Because of the fixed NMI slot assignment, no
00307  *   interrupt acknowledge cycles are performed when
00308  *   processing NMI.
00309  *
00310  *   NMI is an active HIGH, rising edge-sensitive asyn-
00311  *   chronous signal. Setup and hold times, t27 and and t28,
00312  *   relative to the CLK2 signal must be met to guarantee
00313  *   recognition at a particular clock edge. To assure rec-
00314  *   ognition of NMI, it must be inactive for at least eight
00315  *   CLK2 periods, and then be active for at least eight
00316  *   CLK2 periods before the beginning of the instruction
00317  *   boundary in the Intel386 SX Microprocessor's Exe-
00318  *   cution Unit.
00319  *
00320  *   Once NMI processing has begun, no additional
00321  *   NMI's are processed until after the next IRET in-
00322  *   struction, which is typically the end of the NMI serv-
00323  *   ice routine. If NMI is re-asserted prior to that time,
00324  *   however, one rising edge on NMI will be remem-
00325  *   bered for processing after executing the next IRET
00326  *   instruction
00327  * "
00328  *
00329  * From the Pentium Pro Processor datasheet:
00330  *
00331  * "
00332  *   A.38 NMI (I)
00333  *
00334  *   The NMI signal is the Non-maskable Interrupt signal.
00335  *   It is the state of the LINT1 signal when APIC is
00336  *   disabled. Asserting NMI causes an interrupt with an
00337  *   internally supplied vector value of 2. An external
00338  *   interrupt-acknowledge transaction is not generated. If
00339  *   NMI is asserted during the execution of an NMI
00340  *   service routine, it remains pending and is recognized
00341  *   after the IRET is executed by the NMI service
00342  *   routine. At most, one assertion of NMI is held
00343  *   pending.
00344  *
00345  *   NMI is rising-edge sensitive. Recognition of NMI is
00346  *   guaranteed in a specific clock if it is asserted
00347  *   synchronously and meets the setup and hold times. If
00348  *   asserted asynchronously, active and inactive pulse
00349  *   widths must be a minimum of two clocks. In FRC
00350  *   mode, NMI must be synchronous to BCLK.
00351  * "
00352  *
00353  * Similar references exist in the Pentium III and Pentium 4
00354  * datasheets, while later on in the Core 2 datasheets there
00355  * is no mention whatsoever to the NMI that I can find.
00356  */
00357 void CPU_NMI_Interrupt() {
00358         if (CPU_NMI_active) E_Exit("CPU_NMI_Interrupt() called while NMI already active");
00359         CPU_NMI_active = true;
00360         CPU_NMI_pending = false;
00361         CPU_Interrupt(2/*INT 2 = NMI*/,0,reg_eip);
00362 }
00363 
00364 void CPU_Raise_NMI() {
00365         CPU_NMI_pending = true;
00366         if (!CPU_NMI_active && CPU_NMI_gate) CPU_NMI_Interrupt();
00367 }
00368 
00369 void CPU_Check_NMI() {
00370         if (!CPU_NMI_active && CPU_NMI_gate && CPU_NMI_pending) CPU_NMI_Interrupt();
00371 }
00372 
00373 /* In debug mode exceptions are tested and dosbox exits when 
00374  * a unhandled exception state is detected. 
00375  * USE CHECK_EXCEPT to raise an exception in that case to see if that exception
00376  * solves the problem.
00377  * 
00378  * In non-debug mode dosbox doesn't do detection (and hence doesn't crash at
00379  * that point). (game might crash later due to the unhandled exception) */
00380 
00381 #define CPU_CHECK_EXCEPT 1
00382 // #define CPU_CHECK_IGNORE 1
00383 
00384 #if C_DEBUG
00385 // #define CPU_CHECK_EXCEPT 1
00386 // #define CPU_CHECK_IGNORE 1
00387  /* Use CHECK_EXCEPT when something doesn't work to see if a exception is 
00388  * needed that isn't enabled by default.*/
00389 #else
00390 /* NORMAL NO CHECKING => More Speed */
00391 //#define CPU_CHECK_IGNORE 1
00392 #endif /* C_DEBUG */
00393 
00394 #if defined(CPU_CHECK_IGNORE)
00395 #define CPU_CHECK_COND(cond,msg,exc,sel) {      \
00396         if (cond) do {} while (0);                              \
00397 }
00398 #elif defined(CPU_CHECK_EXCEPT)
00399 #define CPU_CHECK_COND(cond,msg,exc,sel) {      \
00400         if (cond) {                                     \
00401                 CPU_Exception(exc,sel);         \
00402                 return;                         \
00403         }                                       \
00404 }
00405 #else
00406 #define CPU_CHECK_COND(cond,msg,exc,sel) {      \
00407         if (cond) E_Exit(msg);                  \
00408 }
00409 #endif
00410 
00411 
00412 void Descriptor::Load(PhysPt address) {
00413         cpu.mpl=0;
00414         Bit32u* data = (Bit32u*)&saved;
00415         *data     = mem_readd(address);
00416         *(data+1) = mem_readd(address+4);
00417         cpu.mpl=3;
00418 }
00419 void Descriptor:: Save(PhysPt address) {
00420         cpu.mpl=0;
00421         Bit32u* data = (Bit32u*)&saved;
00422         mem_writed(address,*data);
00423         mem_writed(address+4,*(data+1));
00424         cpu.mpl=3;
00425 }
00426 
00427 
00428 void CPU_Push16(Bitu value) {
00429         Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask);
00430         mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
00431         reg_esp=new_esp;
00432 }
00433 
00434 void CPU_Push32(Bitu value) {
00435         Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask);
00436         mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
00437         reg_esp=new_esp;
00438 }
00439 
00440 Bitu CPU_Pop16(void) {
00441         Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
00442         reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
00443         return val;
00444 }
00445 
00446 Bitu CPU_Pop32(void) {
00447         Bitu val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
00448         reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
00449         return val;
00450 }
00451 
00452 PhysPt SelBase(Bitu sel) {
00453         if (cpu.cr0 & CR0_PROTECTION) {
00454                 Descriptor desc;
00455                 cpu.gdt.GetDescriptor(sel,desc);
00456                 return desc.GetBase();
00457         } else {
00458                 return sel<<4;
00459         }
00460 }
00461 
00462 void CPU_SetCPL(Bitu newcpl) {
00463         if (newcpl != cpu.cpl) {
00464                 if (paging.enabled) {
00465                         if ( ((cpu.cpl < 3) && (newcpl == 3)) || ((cpu.cpl == 3) && (newcpl < 3)) )
00466                         PAGING_SwitchCPL(newcpl == 3);
00467                 }
00468                 cpu.cpl = newcpl;
00469         }
00470 }
00471 
00472 void CPU_SetFlags(Bitu word,Bitu mask) {
00473         /* 8086/286 flags manipulation.
00474          * For more information read about the Intel CPU detection algorithm and other bits of info:
00475          * [http://www.rcollins.org/ddj/Sep96/Sep96.html] */
00476 
00477         /* 8086: bits 12-15 cannot be zeroed */
00478         if (CPU_ArchitectureType <= CPU_ARCHTYPE_80186) {
00479                 /* update mask and word to ensure bits 12-15 are set */
00480                 word |= 0xF000U;
00481                 mask |= 0xF000U;
00482         }
00483         /* 286 real mode: bits 12-15 bits cannot be set, always zero */
00484         else if (CPU_ArchitectureType <= CPU_ARCHTYPE_286) {
00485                 if (!(cpu.cr0 & CR0_PROTECTION)) {
00486                         /* update mask and word to ensure bits 12-15 are zero */
00487                         word &= ~0xF000U;
00488                         mask |= 0xF000U;
00489                 }
00490         }
00491         else {
00492                 mask |= CPU_extflags_toggle;    // ID-flag and AC-flag can be toggled on CPUID-supporting CPUs
00493         }
00494 
00495         reg_flags=(reg_flags & ~mask)|(word & mask)|2U;
00496         cpu.direction=1 - (int)((reg_flags & FLAG_DF) >> 9U);
00497         // ^ NTS: Notice the DF flag is bit 10. This code computes (reg_flags & FLAG_DF) >> 9 on purpose.
00498         //        It's not a typo (9 vs 10), it's done to set cpu.direction to either 1 or -1.
00499 }
00500 
00501 bool CPU_PrepareException(Bitu which,Bitu error) {
00502         cpu.exception.which=which;
00503         cpu.exception.error=error;
00504         return true;
00505 }
00506 
00507 bool CPU_CLI(void) {
00508         if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) || (GETFLAG(VM) && (GETFLAG_IOPL<3)))) {
00509                 return CPU_PrepareException(EXCEPTION_GP,0);
00510         } else {
00511                 SETFLAGBIT(IF,false);
00512                 return false;
00513         }
00514 }
00515 
00516 bool CPU_STI(void) {
00517         if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) || (GETFLAG(VM) && (GETFLAG_IOPL<3)))) {
00518                 return CPU_PrepareException(EXCEPTION_GP,0);
00519         } else {
00520                 SETFLAGBIT(IF,true);
00521                 return false;
00522         }
00523 }
00524 
00525 bool CPU_POPF(Bitu use32) {
00526         if (cpu.pmode && GETFLAG(VM) && (GETFLAG(IOPL)!=FLAG_IOPL)) {
00527                 /* Not enough privileges to execute POPF */
00528                 return CPU_PrepareException(EXCEPTION_GP,0);
00529         }
00530         Bitu mask=FMASK_ALL;
00531         /* IOPL field can only be modified when CPL=0 or in real mode: */
00532         if (cpu.pmode && (cpu.cpl>0)) mask &= (~FLAG_IOPL);
00533         if (cpu.pmode && !GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) mask &= (~FLAG_IF);
00534         if (use32)
00535                 CPU_SetFlags(CPU_Pop32(),mask);
00536         else CPU_SetFlags(CPU_Pop16(),mask & 0xffff);
00537         DestroyConditionFlags();
00538         return false;
00539 }
00540 
00541 bool CPU_PUSHF(Bitu use32) {
00542         if (cpu.pmode && GETFLAG(VM) && (GETFLAG(IOPL)!=FLAG_IOPL)) {
00543                 /* Not enough privileges to execute PUSHF */
00544                 return CPU_PrepareException(EXCEPTION_GP,0);
00545         }
00546         FillFlags();
00547         if (use32) 
00548                 CPU_Push32(reg_flags & 0xfcffff);
00549         else CPU_Push16(reg_flags);
00550         return false;
00551 }
00552 
00553 void CPU_CheckSegment(const enum SegNames segi) {
00554         bool needs_invalidation=false;
00555         Descriptor desc;
00556 
00557     if (!cpu.gdt.GetDescriptor(SegValue(segi),desc)) {
00558         needs_invalidation=true;
00559     }
00560     else {
00561         switch (desc.Type()) {
00562             case DESC_DATA_EU_RO_NA:    case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA:    case DESC_DATA_EU_RW_A:
00563             case DESC_DATA_ED_RO_NA:    case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA:    case DESC_DATA_ED_RW_A:
00564             case DESC_CODE_N_NC_A:      case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A:      case DESC_CODE_R_NC_NA:
00565                 if (cpu.cpl>desc.DPL()) needs_invalidation=true;
00566                 break;
00567             default:
00568                 break;
00569         }
00570     }
00571 
00572     if (needs_invalidation)
00573         CPU_SetSegGeneral(segi,0);
00574 }
00575 
00576 void CPU_CheckSegments(void) {
00577     CPU_CheckSegment(es);
00578     CPU_CheckSegment(ds);
00579     CPU_CheckSegment(fs);
00580     CPU_CheckSegment(gs);
00581 }
00582 
00583 class TaskStateSegment {
00584 public:
00585         TaskStateSegment() {
00586                 valid=false;
00587         }
00588         bool IsValid(void) {
00589                 return valid;
00590         }
00591         Bitu Get_back(void) {
00592                 cpu.mpl=0;
00593                 Bit16u backlink=mem_readw(base);
00594                 cpu.mpl=3;
00595                 return backlink;
00596         }
00597         void SaveSelector(void) {
00598                 cpu.gdt.SetDescriptor(selector,desc);
00599         }
00600         void Get_SSx_ESPx(Bitu level,Bitu & _ss,Bitu & _esp) {
00601                 cpu.mpl=0;
00602                 if (is386) {
00603                         PhysPt where=base+offsetof(TSS_32,esp0)+level*8;
00604                         _esp=mem_readd(where);
00605                         _ss=mem_readw(where+4);
00606                 } else {
00607                         PhysPt where=base+offsetof(TSS_16,sp0)+level*4;
00608                         _esp=mem_readw(where);
00609                         _ss=mem_readw(where+2);
00610                 }
00611                 cpu.mpl=3;
00612         }
00613         bool SetSelector(Bitu new_sel) {
00614                 valid=false;
00615                 if ((new_sel & 0xfffc)==0) {
00616                         selector=0;
00617                         base=0;
00618                         limit=0;
00619                         is386=1;
00620                         return true;
00621                 }
00622                 if (new_sel&4) return false;
00623                 if (!cpu.gdt.GetDescriptor(new_sel,desc)) return false;
00624                 switch (desc.Type()) {
00625                         case DESC_286_TSS_A:            case DESC_286_TSS_B:
00626                         case DESC_386_TSS_A:            case DESC_386_TSS_B:
00627                                 break;
00628                         default:
00629                                 return false;
00630                 }
00631                 if (!desc.saved.seg.p) return false;
00632                 selector=new_sel;
00633                 valid=true;
00634                 base=desc.GetBase();
00635                 limit=desc.GetLimit();
00636                 is386=desc.Is386();
00637                 return true;
00638         }
00639 
00640         void SaveState( std::ostream& stream );
00641         void LoadState( std::istream& stream );
00642 
00643         TSS_Descriptor desc;
00644         Bitu selector;
00645         PhysPt base;
00646         Bitu limit;
00647         Bitu is386;
00648         bool valid;
00649 };
00650 
00651 TaskStateSegment cpu_tss;
00652 
00653 enum TSwitchType {
00654         TSwitch_JMP,TSwitch_CALL_INT,TSwitch_IRET
00655 };
00656 
00657 bool CPU_SwitchTask(Bitu new_tss_selector,TSwitchType tstype,Bitu old_eip) {
00658         bool old_allow = dosbox_allow_nonrecursive_page_fault;
00659 
00660         /* this code isn't very easy to make interruptible. so temporarily revert to recursive PF handling method */
00661         dosbox_allow_nonrecursive_page_fault = false;
00662 
00663         FillFlags();
00664         TaskStateSegment new_tss;
00665         if (!new_tss.SetSelector(new_tss_selector)) 
00666                 E_Exit("Illegal TSS for switch, selector=%x, switchtype=%lx",(int)new_tss_selector,(unsigned long)tstype);
00667         if (tstype==TSwitch_IRET) {
00668                 if (!new_tss.desc.IsBusy())
00669                         E_Exit("TSS not busy for IRET");
00670         } else {
00671                 if (new_tss.desc.IsBusy())
00672                         E_Exit("TSS busy for JMP/CALL/INT");
00673         }
00674         Bitu new_cr3=0;
00675         Bitu new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi;
00676         Bitu new_es,new_cs,new_ss,new_ds,new_fs,new_gs;
00677         Bitu new_ldt,new_eip,new_eflags;
00678         /* Read new context from new TSS */
00679         if (new_tss.is386) {
00680                 new_cr3=mem_readd(new_tss.base+offsetof(TSS_32,cr3));
00681                 new_eip=mem_readd(new_tss.base+offsetof(TSS_32,eip));
00682                 new_eflags=mem_readd(new_tss.base+offsetof(TSS_32,eflags));
00683                 new_eax=mem_readd(new_tss.base+offsetof(TSS_32,eax));
00684                 new_ecx=mem_readd(new_tss.base+offsetof(TSS_32,ecx));
00685                 new_edx=mem_readd(new_tss.base+offsetof(TSS_32,edx));
00686                 new_ebx=mem_readd(new_tss.base+offsetof(TSS_32,ebx));
00687                 new_esp=mem_readd(new_tss.base+offsetof(TSS_32,esp));
00688                 new_ebp=mem_readd(new_tss.base+offsetof(TSS_32,ebp));
00689                 new_edi=mem_readd(new_tss.base+offsetof(TSS_32,edi));
00690                 new_esi=mem_readd(new_tss.base+offsetof(TSS_32,esi));
00691 
00692                 new_es=mem_readw(new_tss.base+offsetof(TSS_32,es));
00693                 new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs));
00694                 new_ss=mem_readw(new_tss.base+offsetof(TSS_32,ss));
00695                 new_ds=mem_readw(new_tss.base+offsetof(TSS_32,ds));
00696                 new_fs=mem_readw(new_tss.base+offsetof(TSS_32,fs));
00697                 new_gs=mem_readw(new_tss.base+offsetof(TSS_32,gs));
00698                 new_ldt=mem_readw(new_tss.base+offsetof(TSS_32,ldt));
00699         } else {
00700                 E_Exit("286 task switch");
00701                 new_cr3=0;
00702                 new_eip=0;
00703                 new_eflags=0;
00704                 new_eax=0;      new_ecx=0;      new_edx=0;      new_ebx=0;
00705                 new_esp=0;      new_ebp=0;      new_edi=0;      new_esi=0;
00706 
00707                 new_es=0;       new_cs=0;       new_ss=0;       new_ds=0;       new_fs=0;       new_gs=0;
00708                 new_ldt=0;
00709         }
00710 
00711         /* Check if we need to clear busy bit of old TASK */
00712         if (tstype==TSwitch_JMP || tstype==TSwitch_IRET) {
00713                 cpu_tss.desc.SetBusy(false);
00714                 cpu_tss.SaveSelector();
00715         }
00716         Bit32u old_flags = reg_flags;
00717         if (tstype==TSwitch_IRET) old_flags &= (~FLAG_NT);
00718 
00719         /* Save current context in current TSS */
00720         if (cpu_tss.is386) {
00721                 mem_writed(cpu_tss.base+offsetof(TSS_32,eflags),old_flags);
00722                 mem_writed(cpu_tss.base+offsetof(TSS_32,eip),old_eip);
00723 
00724                 mem_writed(cpu_tss.base+offsetof(TSS_32,eax),reg_eax);
00725                 mem_writed(cpu_tss.base+offsetof(TSS_32,ecx),reg_ecx);
00726                 mem_writed(cpu_tss.base+offsetof(TSS_32,edx),reg_edx);
00727                 mem_writed(cpu_tss.base+offsetof(TSS_32,ebx),reg_ebx);
00728                 mem_writed(cpu_tss.base+offsetof(TSS_32,esp),reg_esp);
00729                 mem_writed(cpu_tss.base+offsetof(TSS_32,ebp),reg_ebp);
00730                 mem_writed(cpu_tss.base+offsetof(TSS_32,esi),reg_esi);
00731                 mem_writed(cpu_tss.base+offsetof(TSS_32,edi),reg_edi);
00732 
00733                 mem_writed(cpu_tss.base+offsetof(TSS_32,es),SegValue(es));
00734                 mem_writed(cpu_tss.base+offsetof(TSS_32,cs),SegValue(cs));
00735                 mem_writed(cpu_tss.base+offsetof(TSS_32,ss),SegValue(ss));
00736                 mem_writed(cpu_tss.base+offsetof(TSS_32,ds),SegValue(ds));
00737                 mem_writed(cpu_tss.base+offsetof(TSS_32,fs),SegValue(fs));
00738                 mem_writed(cpu_tss.base+offsetof(TSS_32,gs),SegValue(gs));
00739         } else {
00740                 E_Exit("286 task switch");
00741         }
00742 
00743         /* Setup a back link to the old TSS in new TSS */
00744         if (tstype==TSwitch_CALL_INT) {
00745                 if (new_tss.is386) {
00746                         mem_writed(new_tss.base+offsetof(TSS_32,back),cpu_tss.selector);
00747                 } else {
00748                         mem_writew(new_tss.base+offsetof(TSS_16,back),cpu_tss.selector);
00749                 }
00750                 /* And make the new task's eflag have the nested task bit */
00751                 new_eflags|=FLAG_NT;
00752         }
00753         /* Set the busy bit in the new task */
00754         if (tstype==TSwitch_JMP || tstype==TSwitch_CALL_INT) {
00755                 new_tss.desc.SetBusy(true);
00756                 new_tss.SaveSelector();
00757         }
00758 
00759 //      cpu.cr0|=CR0_TASKSWITCHED;
00760         if (new_tss_selector == cpu_tss.selector) {
00761                 reg_eip = old_eip;
00762                 new_cs = SegValue(cs);
00763                 new_ss = SegValue(ss);
00764                 new_ds = SegValue(ds);
00765                 new_es = SegValue(es);
00766                 new_fs = SegValue(fs);
00767                 new_gs = SegValue(gs);
00768         } else {
00769         
00770                 /* Setup the new cr3 */
00771                 if (paging.cr3 != new_cr3)
00772                         // if they are the same it is not flushed
00773                         // according to the 386 manual
00774                 PAGING_SetDirBase(new_cr3);
00775 
00776                 /* Load new context */
00777                 if (new_tss.is386) {
00778                         reg_eip=new_eip;
00779                         CPU_SetFlags(new_eflags,FMASK_ALL | FLAG_VM);
00780                         reg_eax=new_eax;
00781                         reg_ecx=new_ecx;
00782                         reg_edx=new_edx;
00783                         reg_ebx=new_ebx;
00784                         reg_esp=new_esp;
00785                         reg_ebp=new_ebp;
00786                         reg_edi=new_edi;
00787                         reg_esi=new_esi;
00788 
00789 //                      new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs));
00790                 } else {
00791                         E_Exit("286 task switch");
00792                 }
00793         }
00794         /* Load the new selectors */
00795         if (reg_flags & FLAG_VM) {
00796                 SegSet16(cs,new_cs);
00797                 cpu.code.big=false;
00798                 CPU_SetCPL(3);                  //We don't have segment caches so this will do
00799         } else {
00800                 /* Protected mode task */
00801                 if (new_ldt!=0) CPU_LLDT(new_ldt);
00802                 /* Load the new CS*/
00803                 Descriptor cs_desc;
00804                 CPU_SetCPL(new_cs & 3);
00805                 if (!cpu.gdt.GetDescriptor(new_cs,cs_desc))
00806                         E_Exit("Task switch with CS beyond limits");
00807                 if (!cs_desc.saved.seg.p)
00808                         E_Exit("Task switch with non present code-segment");
00809                 switch (cs_desc.Type()) {
00810                 case DESC_CODE_N_NC_A:          case DESC_CODE_N_NC_NA:
00811                 case DESC_CODE_R_NC_A:          case DESC_CODE_R_NC_NA:
00812                         if (cpu.cpl != cs_desc.DPL()) E_Exit("Task CS RPL != DPL");
00813                         goto doconforming;
00814                 case DESC_CODE_N_C_A:           case DESC_CODE_N_C_NA:
00815                 case DESC_CODE_R_C_A:           case DESC_CODE_R_C_NA:
00816                         if (cpu.cpl < cs_desc.DPL()) E_Exit("Task CS RPL < DPL");
00817 doconforming:
00818                         Segs.expanddown[cs]=cs_desc.GetExpandDown();
00819                         Segs.limit[cs]=do_seg_limits?cs_desc.GetLimit():((PhysPt)(~0UL));
00820                         Segs.phys[cs]=cs_desc.GetBase();
00821                         cpu.code.big=cs_desc.Big()>0;
00822                         Segs.val[cs]=new_cs;
00823                         break;
00824                 default:
00825                         E_Exit("Task switch CS Type %d",(int)cs_desc.Type());
00826                 }
00827         }
00828         CPU_SetSegGeneral(es,new_es);
00829         CPU_SetSegGeneral(ss,new_ss);
00830         CPU_SetSegGeneral(ds,new_ds);
00831         CPU_SetSegGeneral(fs,new_fs);
00832         CPU_SetSegGeneral(gs,new_gs);
00833         if (!cpu_tss.SetSelector(new_tss_selector)) {
00834                 LOG(LOG_CPU,LOG_NORMAL)("TaskSwitch: set tss selector %X failed",new_tss_selector);
00835         }
00836 //      cpu_tss.desc.SetBusy(true);
00837 //      cpu_tss.SaveSelector();
00838 //      LOG_MSG("Task CPL %X CS:%X IP:%X SS:%X SP:%X eflags %x",cpu.cpl,SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags);
00839 
00840         dosbox_allow_nonrecursive_page_fault = old_allow;
00841         return true;
00842 }
00843 
00844 bool CPU_IO_Exception(Bitu port,Bitu size) {
00845         if (cpu.pmode && ((GETFLAG_IOPL<cpu.cpl) || GETFLAG(VM))) {
00846                 cpu.mpl=0;
00847                 if (!cpu_tss.is386) goto doexception;
00848                 PhysPt bwhere=cpu_tss.base+0x66;
00849                 Bitu ofs=mem_readw(bwhere);
00850                 if (ofs>cpu_tss.limit) goto doexception;
00851                 bwhere=cpu_tss.base+ofs+(port/8);
00852                 Bitu map=mem_readw(bwhere);
00853                 Bitu mask=(0xffffu >> (16u - size)) << (port & 7u);
00854                 if (map & mask) goto doexception;
00855                 cpu.mpl=3;
00856         }
00857         return false;
00858 doexception:
00859         cpu.mpl=3;
00860         LOG(LOG_CPU,LOG_NORMAL)("IO Exception port %X",port);
00861         return CPU_PrepareException(EXCEPTION_GP,0);
00862 }
00863 
00864 #include <stack>
00865 
00866 int CPU_Exception_Level[0x20] = {0};
00867 std::stack<int> CPU_Exception_In_Progress;
00868 
00869 void CPU_Exception_Level_Reset() {
00870         int i;
00871 
00872         for (i=0;i < 0x20;i++)
00873                 CPU_Exception_Level[i] = 0;
00874         while (!CPU_Exception_In_Progress.empty())
00875                 CPU_Exception_In_Progress.pop();
00876 }
00877 
00878 bool has_printed_double_fault = false;
00879 bool has_printed_triple_fault = false;
00880 bool always_report_double_fault = false;
00881 bool always_report_triple_fault = false;
00882 
00883 void On_Software_CPU_Reset();
00884 
00885 void CPU_Exception(Bitu which,Bitu error ) {
00886         assert(which < 0x20);
00887 //      LOG_MSG("Exception %d error %x",which,error);
00888         if (CPU_Exception_Level[which] != 0) {
00889                 if (CPU_Exception_Level[EXCEPTION_DF] != 0 && cpu_triple_fault_reset) {
00890                         if (always_report_triple_fault || !has_printed_triple_fault) {
00891                                 LOG_MSG("CPU_Exception: Double fault already in progress == Triple Fault. Resetting CPU.");
00892                                 has_printed_triple_fault = true;
00893                         }
00894 
00895                         // Triple fault -> special shutdown cycle -> reset signal -> reset.
00896                         // Sickening, I know, but that's how IBM wired things a long long time ago.
00897                         On_Software_CPU_Reset();
00898                         E_Exit("Triple fault reset call unexpectedly returned");
00899                 }
00900 
00901                 if (always_report_double_fault || !has_printed_double_fault) {
00902                         LOG_MSG("CPU_Exception: Exception %d already in progress, triggering double fault instead",(int)which);
00903                         has_printed_double_fault = true;
00904                 }
00905                 which = EXCEPTION_DF;
00906                 error = 0;
00907         }
00908 
00909         if (cpu_double_fault_enable) {
00910                 /* CPU_Interrupt() could cause another fault during memory access. This needs to happen here */
00911                 CPU_Exception_Level[which]++;
00912                 CPU_Exception_In_Progress.push(which);
00913         }
00914 
00915         cpu.exception.error=error;
00916         CPU_Interrupt(which,CPU_INT_EXCEPTION | ((which>=8) ? CPU_INT_HAS_ERROR : 0),reg_eip);
00917 
00918         /* allow recursive page faults. required for multitasking OSes like Windows 95.
00919          * we set this AFTER CPU_Interrupt so that if CPU_Interrupt faults while starting
00920          * a page fault we still trigger double fault. */
00921         if (which == EXCEPTION_PF || which == EXCEPTION_GP) {
00922                 if (CPU_Exception_Level[which] > 0)
00923                         CPU_Exception_Level[which]--;
00924 
00925                 if (!CPU_Exception_In_Progress.empty()) {
00926                         if ((Bitu)CPU_Exception_In_Progress.top() == which)
00927                                 CPU_Exception_In_Progress.pop();
00928                         else
00929                                 LOG_MSG("Top of fault stack not the same as what I'm handling");
00930                 }
00931         }
00932 }
00933 
00934 Bit8u lastint;
00935 void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) {
00936         lastint=num;
00937         FillFlags();
00938 #if C_DEBUG
00939 # if C_HEAVY_DEBUG
00940     bool DEBUG_IntBreakpoint(Bit8u intNum);
00941     Bitu DEBUG_EnableDebugger(void);
00942 
00943     if (type != CPU_INT_SOFTWARE) { /* CPU core already takes care of SW interrupts */
00944         if (DEBUG_IntBreakpoint(num))
00945             DEBUG_EnableDebugger();
00946     }
00947 # endif
00948 
00949         switch (num) {
00950         case 0xcd:
00951 #if C_HEAVY_DEBUG
00952                 LOG(LOG_CPU,LOG_ERROR)("Call to interrupt 0xCD this is BAD");
00953                 DEBUG_HeavyWriteLogInstruction();
00954                 E_Exit("Call to interrupt 0xCD this is BAD");
00955 #endif
00956                 break;
00957         case 0x03:
00958                 if (DEBUG_Breakpoint()) {
00959                         CPU_Cycles=0;
00960                         return;
00961                 }
00962         };
00963 #endif
00964         if (!cpu.pmode) {
00965                 /* Save everything on a 16-bit stack */
00966                 CPU_Push16(reg_flags & 0xffff);
00967                 CPU_Push16(SegValue(cs));
00968                 CPU_Push16(oldeip);
00969                 SETFLAGBIT(IF,false);
00970                 SETFLAGBIT(TF,false);
00971                 /* Get the new CS:IP from vector table */
00972                 PhysPt base=cpu.idt.GetBase();
00973                 reg_eip=mem_readw(base+(num << 2));
00974                 Segs.val[cs]=mem_readw(base+(num << 2)+2);
00975                 Segs.phys[cs]=Segs.val[cs]<<4;
00976                 if (!cpu_allow_big16) cpu.code.big=false;
00977                 return;
00978         } else {
00979                 /* Protected Mode Interrupt */
00980                 if ((reg_flags & FLAG_VM) && (type&CPU_INT_SOFTWARE) && !(type&CPU_INT_NOIOPLCHECK)) {
00981 //                      LOG_MSG("Software int in v86, AH %X IOPL %x",reg_ah,(reg_flags & FLAG_IOPL) >>12);
00982                         if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) {
00983                                 CPU_Exception(EXCEPTION_GP,0);
00984                                 return;
00985                         }
00986                 } 
00987 
00988                 Descriptor gate;
00989                 if (!cpu.idt.GetDescriptor(num<<3,gate)) {
00990                         // zone66
00991                         CPU_Exception(EXCEPTION_GP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1);
00992                         return;
00993                 }
00994 
00995                 if ((type&CPU_INT_SOFTWARE) && (gate.DPL()<cpu.cpl)) {
00996                         // zone66, win3.x e
00997                         CPU_Exception(EXCEPTION_GP,num*8+2);
00998                         return;
00999                 }
01000 
01001                 Bitu old_esp,old_ss,old_cpl;
01002 
01003                 old_esp = reg_esp;
01004                 old_ss = SegValue(ss);
01005                 old_cpl = cpu.cpl;
01006 
01007                 try {
01008                 switch (gate.Type()) {
01009                 case DESC_286_INT_GATE:         case DESC_386_INT_GATE:
01010                 case DESC_286_TRAP_GATE:        case DESC_386_TRAP_GATE:
01011                         {
01012                                 CPU_CHECK_COND(!gate.saved.seg.p,
01013                                         "INT:Gate segment not present",
01014                                         EXCEPTION_NP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1)
01015 
01016                                 Descriptor cs_desc;
01017                                 Bitu gate_sel=gate.GetSelector();
01018                                 Bitu gate_off=gate.GetOffset();
01019                                 CPU_CHECK_COND((gate_sel & 0xfffc)==0,
01020                                         "INT:Gate with CS zero selector",
01021                                         EXCEPTION_GP,(type&CPU_INT_SOFTWARE)?0:1)
01022                                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(gate_sel,cs_desc),
01023                                         "INT:Gate with CS beyond limit",
01024                                         EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01025 
01026                                 Bitu cs_dpl=cs_desc.DPL();
01027                                 CPU_CHECK_COND(cs_dpl>cpu.cpl,
01028                                         "Interrupt to higher privilege",
01029                                         EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01030                                 switch (cs_desc.Type()) {
01031                                 case DESC_CODE_N_NC_A:  case DESC_CODE_N_NC_NA:
01032                                 case DESC_CODE_R_NC_A:  case DESC_CODE_R_NC_NA:
01033                                         if (cs_dpl<cpu.cpl) {
01034                                                 /* Prepare for gate to inner level */
01035                                                 CPU_CHECK_COND(!cs_desc.saved.seg.p,
01036                                                         "INT:Inner level:CS segment not present",
01037                                                         EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01038                                                 CPU_CHECK_COND((reg_flags & FLAG_VM) && (cs_dpl!=0),
01039                                                         "V86 interrupt calling codesegment with DPL>0",
01040                                                         EXCEPTION_GP,gate_sel & 0xfffc)
01041 
01042                                                 Bitu n_ss,n_esp;
01043                                                 Bitu o_ss,o_esp;
01044                                                 o_ss=SegValue(ss);
01045                                                 o_esp=reg_esp;
01046                                                 cpu_tss.Get_SSx_ESPx(cs_dpl,n_ss,n_esp);
01047                                                 CPU_CHECK_COND((n_ss & 0xfffc)==0,
01048                                                         "INT:Gate with SS zero selector",
01049                                                         EXCEPTION_TS,(type&CPU_INT_SOFTWARE)?0:1)
01050                                                 Descriptor n_ss_desc;
01051                                                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
01052                                                         "INT:Gate with SS beyond limit",
01053                                                         EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01054                                                 CPU_CHECK_COND(((n_ss & 3)!=cs_dpl) || (n_ss_desc.DPL()!=cs_dpl),
01055                                                         "INT:Inner level with CS_DPL!=SS_DPL and SS_RPL",
01056                                                         EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01057 
01058                                                 // check if stack segment is a writable data segment
01059                                                 switch (n_ss_desc.Type()) {
01060                                                 case DESC_DATA_EU_RW_NA:                case DESC_DATA_EU_RW_A:
01061                                                 case DESC_DATA_ED_RW_NA:                case DESC_DATA_ED_RW_A:
01062                                                         break;
01063                                                 default:
01064                                                         E_Exit("INT:Inner level:Stack segment not writable.");          // or #TS(ss_sel+EXT)
01065                                                 }
01066                                                 CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
01067                                                         "INT:Inner level with nonpresent SS",
01068                                                         EXCEPTION_SS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01069 
01070                                                 // commit point
01071                                                 Segs.expanddown[ss]=n_ss_desc.GetExpandDown();
01072                                                 Segs.limit[ss]=do_seg_limits?n_ss_desc.GetLimit():((PhysPt)(~0UL));
01073                                                 Segs.phys[ss]=n_ss_desc.GetBase();
01074                                                 Segs.val[ss]=n_ss;
01075                                                 if (n_ss_desc.Big()) {
01076                                                         cpu.stack.big=true;
01077                                                         cpu.stack.mask=0xffffffff;
01078                                                         cpu.stack.notmask=0;
01079                                                         reg_esp=n_esp;
01080                                                 } else {
01081                                                         cpu.stack.big=false;
01082                                                         cpu.stack.mask=0xffff;
01083                                                         cpu.stack.notmask=0xffff0000;
01084                                                         reg_sp=n_esp & 0xffff;
01085                                                 }
01086 
01087                                                 CPU_SetCPL(cs_dpl);
01088                                                 if (gate.Type() & 0x8) {        /* 32-bit Gate */
01089                                                         if (reg_flags & FLAG_VM) {
01090                                                                 CPU_Push32(SegValue(gs));SegSet16(gs,0x0);
01091                                                                 CPU_Push32(SegValue(fs));SegSet16(fs,0x0);
01092                                                                 CPU_Push32(SegValue(ds));SegSet16(ds,0x0);
01093                                                                 CPU_Push32(SegValue(es));SegSet16(es,0x0);
01094                                                         }
01095                                                         CPU_Push32(o_ss);
01096                                                         CPU_Push32(o_esp);
01097                                                 } else {                                        /* 16-bit Gate */
01098                                                         if (reg_flags & FLAG_VM) E_Exit("V86 to 16-bit gate");
01099                                                         CPU_Push16(o_ss);
01100                                                         CPU_Push16(o_esp);
01101                                                 }
01102 //                                              LOG_MSG("INT:Gate to inner level SS:%X SP:%X",n_ss,n_esp);
01103                                                 goto do_interrupt;
01104                                         } 
01105                                         if (cs_dpl!=cpu.cpl)
01106                                                 E_Exit("Non-conforming intra privilege INT with DPL!=CPL");
01107                                 case DESC_CODE_N_C_A:   case DESC_CODE_N_C_NA:
01108                                 case DESC_CODE_R_C_A:   case DESC_CODE_R_C_NA:
01109                                         /* Prepare stack for gate to same priviledge */
01110                                         CPU_CHECK_COND(!cs_desc.saved.seg.p,
01111                                                         "INT:Same level:CS segment not present",
01112                                                 EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
01113                                         if ((reg_flags & FLAG_VM) && (cs_dpl<cpu.cpl))
01114                                                 E_Exit("V86 interrupt doesn't change to pl0");  // or #GP(cs_sel)
01115 
01116                                         // commit point
01117 do_interrupt:
01118                                         if (gate.Type() & 0x8) {        /* 32-bit Gate */
01119                                                 CPU_Push32(reg_flags);
01120                                                 CPU_Push32(SegValue(cs));
01121                                                 CPU_Push32(oldeip);
01122                                                 if (type & CPU_INT_HAS_ERROR) CPU_Push32(cpu.exception.error);
01123                                         } else {                                        /* 16-bit gate */
01124                                                 CPU_Push16(reg_flags & 0xffff);
01125                                                 CPU_Push16(SegValue(cs));
01126                                                 CPU_Push16(oldeip);
01127                                                 if (type & CPU_INT_HAS_ERROR) CPU_Push16(cpu.exception.error);
01128                                         }
01129                                         break;          
01130                                 default:
01131                                         E_Exit("INT:Gate Selector points to illegal descriptor with type %x",(int)cs_desc.Type());
01132                                 }
01133 
01134                                 Segs.val[cs]=(gate_sel&0xfffc) | cpu.cpl;
01135                                 Segs.phys[cs]=cs_desc.GetBase();
01136                                 Segs.limit[cs]=do_seg_limits?cs_desc.GetLimit():((PhysPt)(~0UL));
01137                                 Segs.expanddown[cs]=cs_desc.GetExpandDown();
01138                                 cpu.code.big=cs_desc.Big()>0;
01139                                 reg_eip=gate_off;
01140 
01141                                 if (!(gate.Type()&1)) {
01142                                         SETFLAGBIT(IF,false);
01143                                 }
01144                                 SETFLAGBIT(TF,false);
01145                                 SETFLAGBIT(NT,false);
01146                                 SETFLAGBIT(VM,false);
01147                                 LOG(LOG_CPU,LOG_NORMAL)("INT:Gate to %X:%X big %d %s",gate_sel,gate_off,cs_desc.Big(),gate.Type() & 0x8 ? "386" : "286");
01148                                 return;
01149                         }
01150                 case DESC_TASK_GATE:
01151                         CPU_CHECK_COND(!gate.saved.seg.p,
01152                                 "INT:Gate segment not present",
01153                                 EXCEPTION_NP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1)
01154 
01155                         CPU_SwitchTask(gate.GetSelector(),TSwitch_CALL_INT,oldeip);
01156                         if (type & CPU_INT_HAS_ERROR) {
01157                                 //TODO Be sure about this, seems somewhat unclear
01158                                 if (cpu_tss.is386) CPU_Push32(cpu.exception.error);
01159                                 else CPU_Push16(cpu.exception.error);
01160                         }
01161                         return;
01162                 default:
01163                         E_Exit("Illegal descriptor type %X for int %X",(int)gate.Type(),(int)num);
01164                 }
01165                 }
01166                 catch (GuestPageFaultException &pf) {
01167             (void)pf;//UNUSED
01168                         LOG_MSG("CPU_Interrupt() interrupted");
01169                         CPU_SetSegGeneral(ss,old_ss);
01170                         reg_esp = old_esp;
01171                         CPU_SetCPL(old_cpl);
01172                         throw;
01173                 }
01174         }
01175         assert(1);
01176         return ; // make compiler happy
01177 }
01178 
01179 
01180 void CPU_IRET(bool use32,Bitu oldeip) {
01181         Bitu orig_esp = reg_esp;
01182 
01183         /* x86 CPUs consider IRET the completion of an NMI, no matter where it happens */
01184         /* FIXME: If the IRET causes an exception, is it still considered the end of the NMI? */
01185         CPU_NMI_active = false;
01186 
01187         /* Fault emulation */
01188         if (!CPU_Exception_In_Progress.empty()) {
01189                 int which = CPU_Exception_In_Progress.top();
01190                 CPU_Exception_In_Progress.pop();
01191                 assert(which < 0x20);
01192 
01193                 if (CPU_Exception_Level[which] > 0)
01194                         CPU_Exception_Level[which]--;
01195 
01196 //              LOG_MSG("Leaving CPU exception %d",which);
01197         }
01198 
01199         if (!cpu.pmode) {                                       /* RealMode IRET */
01200                 if (use32) {
01201                         reg_eip=CPU_Pop32();
01202                         SegSet16(cs,CPU_Pop32());
01203                         CPU_SetFlags(CPU_Pop32(),FMASK_ALL);
01204                 } else {
01205                         reg_eip=CPU_Pop16();
01206                         SegSet16(cs,CPU_Pop16());
01207                         CPU_SetFlags(CPU_Pop16(),FMASK_ALL & 0xffff);
01208                 }
01209                 if (!cpu_allow_big16) cpu.code.big=false;
01210                 DestroyConditionFlags();
01211                 return;
01212         } else {        /* Protected mode IRET */
01213                 if (reg_flags & FLAG_VM) {
01214                         if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) {
01215                                 // win3.x e
01216                                 CPU_Exception(EXCEPTION_GP,0);
01217                                 return;
01218                         } else {
01219                                 try {
01220                                 if (use32) {
01221                                         Bit32u new_eip=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
01222                                         Bit32u tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
01223                                         Bit32u new_cs=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
01224                                         tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
01225                                         Bit32u new_flags=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
01226                                         reg_esp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
01227 
01228                                         reg_eip=new_eip;
01229                                         SegSet16(cs,(Bit16u)(new_cs&0xffff));
01230                                         /* IOPL can not be modified in v86 mode by IRET */
01231                                         CPU_SetFlags(new_flags,FMASK_NORMAL|FLAG_NT);
01232                                 } else {
01233                                         Bit16u new_eip=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
01234                                         Bit32u tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
01235                                         Bit16u new_cs=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
01236                                         tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
01237                                         Bit16u new_flags=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
01238                                         reg_esp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
01239 
01240                                         reg_eip=(Bit32u)new_eip;
01241                                         SegSet16(cs,new_cs);
01242                                         /* IOPL can not be modified in v86 mode by IRET */
01243                                         CPU_SetFlags(new_flags,FMASK_NORMAL|FLAG_NT);
01244                                 }
01245                                 }
01246                                 catch (GuestPageFaultException &pf) {
01247                     (void)pf;//UNUSED
01248                     LOG_MSG("CPU_IRET() interrupted prot vm86");
01249                                         reg_esp = orig_esp;
01250                                         throw;
01251                                 }
01252                                 cpu.code.big=false;
01253                                 DestroyConditionFlags();
01254                                 return;
01255                         }
01256                 }
01257                 /* Check if this is task IRET */        
01258                 if (GETFLAG(NT)) {
01259                         if (GETFLAG(VM)) E_Exit("Pmode IRET with VM bit set");
01260                         CPU_CHECK_COND(!cpu_tss.IsValid(),
01261                                 "TASK Iret without valid TSS",
01262                                 EXCEPTION_TS,cpu_tss.selector & 0xfffc)
01263                         if (!cpu_tss.desc.IsBusy()) {
01264                                 LOG(LOG_CPU,LOG_ERROR)("TASK Iret:TSS not busy");
01265                         }
01266                         Bitu back_link=cpu_tss.Get_back();
01267                         CPU_SwitchTask(back_link,TSwitch_IRET,oldeip);
01268                         return;
01269                 }
01270                 Bitu n_cs_sel,n_eip,n_flags;
01271                 Bit32u tempesp;
01272                 if (use32) {
01273                         n_eip=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
01274                         tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
01275                         n_cs_sel=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)) & 0xffff;
01276                         tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
01277                         n_flags=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
01278                         tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
01279 
01280                         if ((n_flags & FLAG_VM) && (cpu.cpl==0)) {
01281                                 // commit point
01282                                 try {
01283                                 reg_esp=tempesp;
01284                                 reg_eip=n_eip & 0xffff;
01285                                 Bitu n_ss,n_esp,n_es,n_ds,n_fs,n_gs;
01286                                 n_esp=CPU_Pop32();
01287                                 n_ss=CPU_Pop32() & 0xffff;
01288                                 n_es=CPU_Pop32() & 0xffff;
01289                                 n_ds=CPU_Pop32() & 0xffff;
01290                                 n_fs=CPU_Pop32() & 0xffff;
01291                                 n_gs=CPU_Pop32() & 0xffff;
01292 
01293                                 CPU_SetFlags(n_flags,FMASK_ALL | FLAG_VM);
01294                                 DestroyConditionFlags();
01295                                 CPU_SetCPL(3);
01296 
01297                                 CPU_SetSegGeneral(ss,n_ss);
01298                                 CPU_SetSegGeneral(es,n_es);
01299                                 CPU_SetSegGeneral(ds,n_ds);
01300                                 CPU_SetSegGeneral(fs,n_fs);
01301                                 CPU_SetSegGeneral(gs,n_gs);
01302                                 reg_esp=n_esp;
01303                                 cpu.code.big=false;
01304                                 SegSet16(cs,n_cs_sel);
01305                                 LOG(LOG_CPU,LOG_NORMAL)("IRET:Back to V86: CS:%X IP %X SS:%X SP %X FLAGS:%X",SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags);      
01306                                 return;
01307                                 }
01308                                 catch (GuestPageFaultException &pf) {
01309                     (void)pf;//UNUSED
01310                     LOG_MSG("CPU_IRET() interrupted prot use32");
01311                                         reg_esp = orig_esp;
01312                                         throw;
01313                                 }
01314                         }
01315                         if (n_flags & FLAG_VM) E_Exit("IRET from pmode to v86 with CPL!=0");
01316                 } else {
01317                         n_eip=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
01318                         tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
01319                         n_cs_sel=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
01320                         tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
01321                         n_flags=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
01322                         n_flags|=(reg_flags & 0xffff0000);
01323                         tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
01324 
01325                         if (n_flags & FLAG_VM) E_Exit("VM Flag in 16-bit iret");
01326                 }
01327                 CPU_CHECK_COND((n_cs_sel & 0xfffc)==0,
01328                         "IRET:CS selector zero",
01329                         EXCEPTION_GP,0)
01330                 Bitu n_cs_rpl=n_cs_sel & 3;
01331                 Descriptor n_cs_desc;
01332                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc),
01333                         "IRET:CS selector beyond limits",
01334                         EXCEPTION_GP,n_cs_sel & 0xfffc)
01335                 CPU_CHECK_COND(n_cs_rpl<cpu.cpl,
01336                         "IRET to lower privilege",
01337                         EXCEPTION_GP,n_cs_sel & 0xfffc)
01338 
01339                 switch (n_cs_desc.Type()) {
01340                 case DESC_CODE_N_NC_A:  case DESC_CODE_N_NC_NA:
01341                 case DESC_CODE_R_NC_A:  case DESC_CODE_R_NC_NA:
01342                         CPU_CHECK_COND(n_cs_rpl!=n_cs_desc.DPL(),
01343                                 "IRET:NC:DPL!=RPL",
01344                                 EXCEPTION_GP,n_cs_sel & 0xfffc)
01345                         break;
01346                 case DESC_CODE_N_C_A:   case DESC_CODE_N_C_NA:
01347                 case DESC_CODE_R_C_A:   case DESC_CODE_R_C_NA:
01348                         CPU_CHECK_COND(n_cs_desc.DPL()>n_cs_rpl,
01349                                 "IRET:C:DPL>RPL",
01350                                 EXCEPTION_GP,n_cs_sel & 0xfffc)
01351                         break;
01352                 default:
01353                         E_Exit("IRET:Illegal descriptor type %X",(int)n_cs_desc.Type());
01354                 }
01355                 CPU_CHECK_COND(!n_cs_desc.saved.seg.p,
01356                         "IRET with nonpresent code segment",
01357                         EXCEPTION_NP,n_cs_sel & 0xfffc)
01358 
01359                 if (n_cs_rpl==cpu.cpl) {        
01360                         /* Return to same level */
01361 
01362                         // commit point
01363                         reg_esp=tempesp;
01364                         Segs.expanddown[cs]=n_cs_desc.GetExpandDown();
01365                         Segs.limit[cs]=do_seg_limits?n_cs_desc.GetLimit():((PhysPt)(~0UL));
01366                         Segs.phys[cs]=n_cs_desc.GetBase();
01367                         cpu.code.big=n_cs_desc.Big()>0;
01368                         Segs.val[cs]=n_cs_sel;
01369                         reg_eip=n_eip;
01370 
01371                         Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL;
01372                         if (GETFLAG_IOPL<cpu.cpl) mask &= (~FLAG_IF);
01373                         CPU_SetFlags(n_flags,mask);
01374                         DestroyConditionFlags();
01375                         LOG(LOG_CPU,LOG_NORMAL)("IRET:Same level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big);
01376                 } else {
01377                         /* Return to outer level */
01378                         Bitu n_ss,n_esp;
01379                         if (use32) {
01380                                 n_esp=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
01381                                 tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
01382                                 n_ss=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)) & 0xffff;
01383                         } else {
01384                                 n_esp=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
01385                                 tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
01386                                 n_ss=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
01387                         }
01388                         CPU_CHECK_COND((n_ss & 0xfffc)==0,
01389                                 "IRET:Outer level:SS selector zero",
01390                                 EXCEPTION_GP,0)
01391                         CPU_CHECK_COND((n_ss & 3)!=n_cs_rpl,
01392                                 "IRET:Outer level:SS rpl!=CS rpl",
01393                                 EXCEPTION_GP,n_ss & 0xfffc)
01394                         Descriptor n_ss_desc;
01395                         CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
01396                                 "IRET:Outer level:SS beyond limit",
01397                                 EXCEPTION_GP,n_ss & 0xfffc)
01398                         CPU_CHECK_COND(n_ss_desc.DPL()!=n_cs_rpl,
01399                                 "IRET:Outer level:SS dpl!=CS rpl",
01400                                 EXCEPTION_GP,n_ss & 0xfffc)
01401 
01402                         // check if stack segment is a writable data segment
01403                         switch (n_ss_desc.Type()) {
01404                         case DESC_DATA_EU_RW_NA:                case DESC_DATA_EU_RW_A:
01405                         case DESC_DATA_ED_RW_NA:                case DESC_DATA_ED_RW_A:
01406                                 break;
01407                         default:
01408                                 E_Exit("IRET:Outer level:Stack segment not writable");          // or #GP(ss_sel)
01409                         }
01410                         CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
01411                                 "IRET:Outer level:Stack segment not present",
01412                                 EXCEPTION_NP,n_ss & 0xfffc)
01413 
01414                         // commit point
01415 
01416                         Segs.expanddown[cs]=n_cs_desc.GetExpandDown();
01417                         Segs.limit[cs]=do_seg_limits?n_cs_desc.GetLimit():((PhysPt)(~0UL));
01418                         Segs.phys[cs]=n_cs_desc.GetBase();
01419                         cpu.code.big=n_cs_desc.Big()>0;
01420                         Segs.val[cs]=n_cs_sel;
01421 
01422                         Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL;
01423                         if (GETFLAG_IOPL<cpu.cpl) mask &= (~FLAG_IF);
01424                         CPU_SetFlags(n_flags,mask);
01425                         DestroyConditionFlags();
01426 
01427                         CPU_SetCPL(n_cs_rpl);
01428                         reg_eip=n_eip;
01429 
01430                         Segs.val[ss]=n_ss;
01431                         Segs.phys[ss]=n_ss_desc.GetBase();
01432                         Segs.limit[ss]=do_seg_limits?n_ss_desc.GetLimit():((PhysPt)(~0UL));
01433                         Segs.expanddown[ss]=n_ss_desc.GetExpandDown();
01434                         if (n_ss_desc.Big()) {
01435                                 cpu.stack.big=true;
01436                                 cpu.stack.mask=0xffffffff;
01437                                 cpu.stack.notmask=0;
01438                                 reg_esp=n_esp;
01439                         } else {
01440                                 cpu.stack.big=false;
01441                                 cpu.stack.mask=0xffff;
01442                                 cpu.stack.notmask=0xffff0000;
01443                                 reg_sp=n_esp & 0xffff;
01444                         }
01445 
01446                         // borland extender, zrdx
01447                         CPU_CheckSegments();
01448 
01449                         LOG(LOG_CPU,LOG_NORMAL)("IRET:Outer level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big);
01450                 }
01451                 return;
01452         }
01453 }
01454 
01455 
01456 void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip) {
01457         if (!cpu.pmode || (reg_flags & FLAG_VM)) {
01458                 if (!use32) {
01459                         reg_eip=offset&0xffff;
01460                 } else {
01461                         reg_eip=offset;
01462                 }
01463                 SegSet16(cs,selector);
01464                 if (!cpu_allow_big16) cpu.code.big=false;
01465                 return;
01466         } else {
01467                 CPU_CHECK_COND((selector & 0xfffc)==0,
01468                         "JMP:CS selector zero",
01469                         EXCEPTION_GP,0)
01470                 Bitu rpl=selector & 3;
01471                 Descriptor desc;
01472                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc),
01473                         "JMP:CS beyond limits",
01474                         EXCEPTION_GP,selector & 0xfffc)
01475                 switch (desc.Type()) {
01476                 case DESC_CODE_N_NC_A:          case DESC_CODE_N_NC_NA:
01477                 case DESC_CODE_R_NC_A:          case DESC_CODE_R_NC_NA:
01478                         CPU_CHECK_COND(rpl>cpu.cpl,
01479                                 "JMP:NC:RPL>CPL",
01480                                 EXCEPTION_GP,selector & 0xfffc)
01481                         CPU_CHECK_COND(cpu.cpl!=desc.DPL(),
01482                                 "JMP:NC:RPL != DPL",
01483                                 EXCEPTION_GP,selector & 0xfffc)
01484                         LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:NC to %X:%X big %d",selector,offset,desc.Big());
01485                         goto CODE_jmp;
01486                 case DESC_CODE_N_C_A:           case DESC_CODE_N_C_NA:
01487                 case DESC_CODE_R_C_A:           case DESC_CODE_R_C_NA:
01488                         LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:C to %X:%X big %d",selector,offset,desc.Big());
01489                         CPU_CHECK_COND(cpu.cpl<desc.DPL(),
01490                                 "JMP:C:CPL < DPL",
01491                                 EXCEPTION_GP,selector & 0xfffc)
01492 CODE_jmp:
01493                         if (!desc.saved.seg.p) {
01494                                 // win
01495                                 CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
01496                                 return;
01497                         }
01498 
01499                         /* Normal jump to another selector:offset */
01500                         Segs.expanddown[cs]=desc.GetExpandDown();
01501                         Segs.limit[cs]=do_seg_limits?desc.GetLimit():((PhysPt)(~0UL));
01502                         Segs.phys[cs]=desc.GetBase();
01503                         cpu.code.big=desc.Big()>0;
01504                         Segs.val[cs]=(selector & 0xfffc) | cpu.cpl;
01505                         reg_eip=offset;
01506                         return;
01507                 case DESC_386_TSS_A:
01508                         CPU_CHECK_COND(desc.DPL()<cpu.cpl,
01509                                 "JMP:TSS:dpl<cpl",
01510                                 EXCEPTION_GP,selector & 0xfffc)
01511                         CPU_CHECK_COND(desc.DPL()<rpl,
01512                                 "JMP:TSS:dpl<rpl",
01513                                 EXCEPTION_GP,selector & 0xfffc)
01514                         LOG(LOG_CPU,LOG_NORMAL)("JMP:TSS to %X",selector);
01515                         CPU_SwitchTask(selector,TSwitch_JMP,oldeip);
01516                         break;
01517                 default:
01518                         E_Exit("JMP Illegal descriptor type %X",(int)desc.Type());
01519                 }
01520         }
01521         assert(1);
01522 }
01523 
01524 
01525 void CPU_CALL(bool use32,Bitu selector,Bitu offset,Bitu oldeip) {
01526         Bit32u old_esp = reg_esp;
01527         Bit32u old_eip = reg_eip;
01528 
01529         if (!cpu.pmode || (reg_flags & FLAG_VM)) {
01530                 try {
01531                 if (!use32) {
01532                         CPU_Push16(SegValue(cs));
01533                         CPU_Push16(oldeip);
01534                         reg_eip=offset&0xffff;
01535                 } else {
01536                         CPU_Push32(SegValue(cs));
01537                         CPU_Push32(oldeip);
01538                         reg_eip=offset;
01539                 }
01540                 }
01541                 catch (GuestPageFaultException &pf) {
01542             (void)pf;//UNUSED
01543                         reg_esp = old_esp;
01544                         reg_eip = old_eip;
01545                         throw;
01546                 }
01547                 if (!cpu_allow_big16) cpu.code.big=false;
01548                 SegSet16(cs,selector);
01549                 return;
01550         } else {
01551                 CPU_CHECK_COND((selector & 0xfffc)==0,
01552                         "CALL:CS selector zero",
01553                         EXCEPTION_GP,0)
01554                 Bitu rpl=selector & 3;
01555                 Descriptor call;
01556                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,call),
01557                         "CALL:CS beyond limits",
01558                         EXCEPTION_GP,selector & 0xfffc)
01559                 /* Check for type of far call */
01560                 switch (call.Type()) {
01561                 case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
01562                 case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
01563                         CPU_CHECK_COND(rpl>cpu.cpl,
01564                                 "CALL:CODE:NC:RPL>CPL",
01565                                 EXCEPTION_GP,selector & 0xfffc)
01566                         CPU_CHECK_COND(call.DPL()!=cpu.cpl,
01567                                 "CALL:CODE:NC:DPL!=CPL",
01568                                 EXCEPTION_GP,selector & 0xfffc)
01569                         LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:NC to %X:%X",selector,offset);
01570                         goto call_code; 
01571                 case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
01572                 case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
01573                         CPU_CHECK_COND(call.DPL()>cpu.cpl,
01574                                 "CALL:CODE:C:DPL>CPL",
01575                                 EXCEPTION_GP,selector & 0xfffc)
01576                         LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:C to %X:%X",selector,offset);
01577 call_code:
01578                         if (!call.saved.seg.p) {
01579                                 // borland extender (RTM)
01580                                 CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
01581                                 return;
01582                         }
01583                         // commit point
01584                         try {
01585                         if (!use32) {
01586                                 CPU_Push16(SegValue(cs));
01587                                 CPU_Push16(oldeip);
01588                                 reg_eip=offset & 0xffff;
01589                         } else {
01590                                 CPU_Push32(SegValue(cs));
01591                                 CPU_Push32(oldeip);
01592                                 reg_eip=offset;
01593                         }
01594                         }
01595                         catch (GuestPageFaultException &pf) {
01596                 (void)pf;//UNUSED
01597                 reg_esp = old_esp;
01598                                 reg_eip = old_eip;
01599                                 throw;
01600                         }
01601 
01602                         Segs.expanddown[cs]=call.GetExpandDown();
01603                         Segs.limit[cs]=do_seg_limits?call.GetLimit():((PhysPt)(~0UL));
01604                         Segs.phys[cs]=call.GetBase();
01605                         cpu.code.big=call.Big()>0;
01606                         Segs.val[cs]=(selector & 0xfffc) | cpu.cpl;
01607                         return;
01608                 case DESC_386_CALL_GATE: 
01609                 case DESC_286_CALL_GATE:
01610                         {
01611                                 CPU_CHECK_COND(call.DPL()<cpu.cpl,
01612                                         "CALL:Gate:Gate DPL<CPL",
01613                                         EXCEPTION_GP,selector & 0xfffc)
01614                                 CPU_CHECK_COND(call.DPL()<rpl,
01615                                         "CALL:Gate:Gate DPL<RPL",
01616                                         EXCEPTION_GP,selector & 0xfffc)
01617                                 CPU_CHECK_COND(!call.saved.seg.p,
01618                                         "CALL:Gate:Segment not present",
01619                                         EXCEPTION_NP,selector & 0xfffc)
01620                                 Descriptor n_cs_desc;
01621                                 Bitu n_cs_sel=call.GetSelector();
01622 
01623                                 CPU_CHECK_COND((n_cs_sel & 0xfffc)==0,
01624                                         "CALL:Gate:CS selector zero",
01625                                         EXCEPTION_GP,0)
01626                                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc),
01627                                         "CALL:Gate:CS beyond limits",
01628                                         EXCEPTION_GP,n_cs_sel & 0xfffc)
01629                                 Bitu n_cs_dpl   = n_cs_desc.DPL();
01630                                 CPU_CHECK_COND(n_cs_dpl>cpu.cpl,
01631                                         "CALL:Gate:CS DPL>CPL",
01632                                         EXCEPTION_GP,n_cs_sel & 0xfffc)
01633 
01634                                 CPU_CHECK_COND(!n_cs_desc.saved.seg.p,
01635                                         "CALL:Gate:CS not present",
01636                                         EXCEPTION_NP,n_cs_sel & 0xfffc)
01637 
01638                                 Bitu n_eip              = call.GetOffset();
01639                                 switch (n_cs_desc.Type()) {
01640                                 case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
01641                                 case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
01642                                         /* Check if we goto inner priviledge */
01643                                         if (n_cs_dpl < cpu.cpl) {
01644                                                 /* Get new SS:ESP out of TSS */
01645                                                 Bitu n_ss_sel,n_esp;
01646                                                 Descriptor n_ss_desc;
01647                                                 cpu_tss.Get_SSx_ESPx(n_cs_dpl,n_ss_sel,n_esp);
01648                                                 CPU_CHECK_COND((n_ss_sel & 0xfffc)==0,
01649                                                         "CALL:Gate:NC:SS selector zero",
01650                                                         EXCEPTION_TS,0)
01651                                                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss_sel,n_ss_desc),
01652                                                         "CALL:Gate:Invalid SS selector",
01653                                                         EXCEPTION_TS,n_ss_sel & 0xfffc)
01654                                                 CPU_CHECK_COND(((n_ss_sel & 3)!=n_cs_desc.DPL()) || (n_ss_desc.DPL()!=n_cs_desc.DPL()),
01655                                                         "CALL:Gate:Invalid SS selector privileges",
01656                                                         EXCEPTION_TS,n_ss_sel & 0xfffc)
01657 
01658                                                 switch (n_ss_desc.Type()) {
01659                                                 case DESC_DATA_EU_RW_NA:                case DESC_DATA_EU_RW_A:
01660                                                 case DESC_DATA_ED_RW_NA:                case DESC_DATA_ED_RW_A:
01661                                                         // writable data segment
01662                                                         break;
01663                                                 default:
01664                                                         E_Exit("Call:Gate:SS no writable data segment");        // or #TS(ss_sel)
01665                                                 }
01666                                                 CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
01667                                                         "CALL:Gate:Stack segment not present",
01668                                                         EXCEPTION_SS,n_ss_sel & 0xfffc)
01669 
01670                                                 /* Load the new SS:ESP and save data on it */
01671                                                 Bitu o_esp              = reg_esp;
01672                                                 Bitu o_ss               = SegValue(ss);
01673                                                 PhysPt o_stack  = SegPhys(ss)+(reg_esp & cpu.stack.mask);
01674 
01675 
01676                                                 // catch pagefaults
01677                                                 if (call.saved.gate.paramcount&31) {
01678                                                         if (call.Type()==DESC_386_CALL_GATE) {
01679                                                                 for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) 
01680                                                                         mem_readd(o_stack+i*4);
01681                                                         } else {
01682                                                                 for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--)
01683                                                                         mem_readw(o_stack+i*2);
01684                                                         }
01685                                                 }
01686 
01687                                                 bool old_allow = dosbox_allow_nonrecursive_page_fault;
01688 
01689                                                 /* this code isn't very easy to make interruptible. so temporarily revert to recursive PF handling method */
01690                                                 dosbox_allow_nonrecursive_page_fault = false;
01691 
01692                                                 // commit point
01693                                                 Segs.val[ss]=n_ss_sel;
01694                                                 Segs.phys[ss]=n_ss_desc.GetBase();
01695                                                 Segs.limit[ss]=do_seg_limits?n_ss_desc.GetLimit():((PhysPt)(~0UL));
01696                                                 Segs.expanddown[ss]=n_ss_desc.GetExpandDown();
01697                                                 if (n_ss_desc.Big()) {
01698                                                         cpu.stack.big=true;
01699                                                         cpu.stack.mask=0xffffffff;
01700                                                         cpu.stack.notmask=0;
01701                                                         reg_esp=n_esp;
01702                                                 } else {
01703                                                         cpu.stack.big=false;
01704                                                         cpu.stack.mask=0xffff;
01705                                                         cpu.stack.notmask=0xffff0000;
01706                                                         reg_sp=n_esp & 0xffff;
01707                                                 }
01708 
01709                                                 CPU_SetCPL(n_cs_desc.DPL());
01710                                                 Bit16u oldcs    = SegValue(cs);
01711                                                 /* Switch to new CS:EIP */
01712                                                 Segs.expanddown[cs]=n_cs_desc.GetExpandDown();
01713                                                 Segs.limit[cs]  = do_seg_limits?n_cs_desc.GetLimit():((PhysPt)(~0UL));
01714                                                 Segs.phys[cs]   = n_cs_desc.GetBase();
01715                                                 Segs.val[cs]    = (n_cs_sel & 0xfffc) | cpu.cpl;
01716                                                 cpu.code.big    = n_cs_desc.Big()>0;
01717                                                 reg_eip                 = n_eip;
01718                                                 if (!use32)     reg_eip&=0xffff;
01719 
01720                                                 if (call.Type()==DESC_386_CALL_GATE) {
01721                                                         CPU_Push32(o_ss);               //save old stack
01722                                                         CPU_Push32(o_esp);
01723                                                         if (call.saved.gate.paramcount&31)
01724                                                                 for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) 
01725                                                                         CPU_Push32(mem_readd(o_stack+i*4));
01726                                                         CPU_Push32(oldcs);
01727                                                         CPU_Push32(oldeip);
01728                                                 } else {
01729                                                         CPU_Push16(o_ss);               //save old stack
01730                                                         CPU_Push16(o_esp);
01731                                                         if (call.saved.gate.paramcount&31)
01732                                                                 for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--)
01733                                                                         CPU_Push16(mem_readw(o_stack+i*2));
01734                                                         CPU_Push16(oldcs);
01735                                                         CPU_Push16(oldeip);
01736                                                 }
01737 
01738                                                 dosbox_allow_nonrecursive_page_fault = old_allow;
01739                                                 break;          
01740                                         } else if (n_cs_dpl > cpu.cpl)
01741                                                 E_Exit("CALL:GATE:CS DPL>CPL");         // or #GP(sel)
01742                                 case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
01743                                 case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
01744                                         // zrdx extender
01745 
01746                                         try {
01747                                         if (call.Type()==DESC_386_CALL_GATE) {
01748                                                 CPU_Push32(SegValue(cs));
01749                                                 CPU_Push32(oldeip);
01750                                         } else {
01751                                                 CPU_Push16(SegValue(cs));
01752                                                 CPU_Push16(oldeip);
01753                                         }
01754                                         }
01755                                         catch (GuestPageFaultException &pf) {
01756                         (void)pf;//UNUSED
01757                         reg_esp = old_esp;
01758                                                 reg_eip = old_eip;
01759                                                 throw;
01760                                         }
01761 
01762                                         /* Switch to new CS:EIP */
01763                                         Segs.expanddown[cs]=n_cs_desc.GetExpandDown();
01764                                         Segs.limit[cs]  = do_seg_limits?n_cs_desc.GetLimit():((PhysPt)(~0UL));
01765                                         Segs.phys[cs]   = n_cs_desc.GetBase();
01766                                         Segs.val[cs]    = (n_cs_sel & 0xfffc) | cpu.cpl;
01767                                         cpu.code.big    = n_cs_desc.Big()>0;
01768                                         reg_eip                 = n_eip;
01769                                         if (!use32)     reg_eip&=0xffff;
01770                                         break;
01771                                 default:
01772                                         E_Exit("CALL:GATE:CS no executable segment");
01773                                 }
01774                         }                       /* Call Gates */
01775                         break;
01776                 case DESC_386_TSS_A:
01777                         CPU_CHECK_COND(call.DPL()<cpu.cpl,
01778                                 "CALL:TSS:dpl<cpl",
01779                                 EXCEPTION_GP,selector & 0xfffc)
01780                         CPU_CHECK_COND(call.DPL()<rpl,
01781                                 "CALL:TSS:dpl<rpl",
01782                                 EXCEPTION_GP,selector & 0xfffc)
01783 
01784                         CPU_CHECK_COND(!call.saved.seg.p,
01785                                 "CALL:TSS:Segment not present",
01786                                 EXCEPTION_NP,selector & 0xfffc)
01787 
01788                         LOG(LOG_CPU,LOG_NORMAL)("CALL:TSS to %X",selector);
01789                         CPU_SwitchTask(selector,TSwitch_CALL_INT,oldeip);
01790                         break;
01791                 case DESC_DATA_EU_RW_NA:        // vbdos
01792                 case DESC_INVALID:                      // used by some installers
01793                         CPU_Exception(EXCEPTION_GP,selector & 0xfffc);
01794                         return;
01795                 default:
01796                         E_Exit("CALL:Descriptor type %x unsupported",(int)call.Type());
01797                 }
01798         }
01799         assert(1);
01800 }
01801 
01802 
01803 void CPU_RET(bool use32,Bitu bytes,Bitu oldeip) {
01804     (void)oldeip;//UNUSED
01805 
01806         Bitu orig_esp = reg_esp;
01807 
01808         if (!cpu.pmode || (reg_flags & FLAG_VM)) {
01809                 try {
01810                 Bitu new_ip,new_cs;
01811                 if (!use32) {
01812                         new_ip=CPU_Pop16();
01813                         new_cs=CPU_Pop16();
01814                 } else {
01815                         new_ip=CPU_Pop32();
01816                         new_cs=CPU_Pop32() & 0xffff;
01817                 }
01818                 reg_esp+=bytes;
01819                 SegSet16(cs,new_cs);
01820                 reg_eip=new_ip;
01821                 if (!cpu_allow_big16) cpu.code.big=false;
01822                 return;
01823                 }
01824                 catch (GuestPageFaultException &pf) {
01825             (void)pf;//UNUSED
01826             LOG_MSG("CPU_RET() interrupted real/vm86");
01827                         reg_esp = orig_esp;
01828                         throw;
01829                 }
01830         } else {
01831                 Bitu offset,selector;
01832                 if (!use32) selector    = mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask) + 2);
01833                 else            selector        = mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask) + 4) & 0xffff;
01834 
01835                 Descriptor desc;
01836                 Bitu rpl=selector & 3;
01837                 if(rpl < cpu.cpl) {
01838                         // win setup
01839                         CPU_Exception(EXCEPTION_GP,selector & 0xfffc);
01840                         return;
01841                 }
01842 
01843                 CPU_CHECK_COND((selector & 0xfffc)==0,
01844                         "RET:CS selector zero",
01845                         EXCEPTION_GP,0)
01846                 CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc),
01847                         "RET:CS beyond limits",
01848                         EXCEPTION_GP,selector & 0xfffc)
01849 
01850                 if (cpu.cpl==rpl) {     
01851                         /* Return to same level */
01852                         switch (desc.Type()) {
01853                         case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
01854                         case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
01855                                 CPU_CHECK_COND(cpu.cpl!=desc.DPL(),
01856                                         "RET to NC segment of other privilege",
01857                                         EXCEPTION_GP,selector & 0xfffc)
01858                                 goto RET_same_level;
01859                         case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
01860                         case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
01861                                 CPU_CHECK_COND(desc.DPL()>cpu.cpl,
01862                                         "RET to C segment of higher privilege",
01863                                         EXCEPTION_GP,selector & 0xfffc)
01864                                 break;
01865                         default:
01866                                 E_Exit("RET from illegal descriptor type %X",(int)desc.Type());
01867                         }
01868 RET_same_level:
01869                         if (!desc.saved.seg.p) {
01870                                 // borland extender (RTM)
01871                                 CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
01872                                 return;
01873                         }
01874 
01875                         // commit point
01876                         try {
01877                         if (!use32) {
01878                                 offset=CPU_Pop16();
01879                                 selector=CPU_Pop16();
01880                         } else {
01881                                 offset=CPU_Pop32();
01882                                 selector=CPU_Pop32() & 0xffff;
01883                         }
01884                         }
01885                         catch (GuestPageFaultException &pf) {
01886                 (void)pf;//UNUSED
01887                 LOG_MSG("CPU_RET() interrupted prot rpl==cpl");
01888                                 reg_esp = orig_esp;
01889                                 throw;
01890                         }
01891 
01892                         Segs.expanddown[cs]=desc.GetExpandDown();
01893                         Segs.limit[cs]=do_seg_limits?desc.GetLimit():((PhysPt)(~0UL));
01894                         Segs.phys[cs]=desc.GetBase();
01895                         cpu.code.big=desc.Big()>0;
01896                         Segs.val[cs]=selector;
01897                         reg_eip=offset;
01898                         if (cpu.stack.big) {
01899                                 reg_esp+=bytes;
01900                         } else {
01901                                 reg_sp+=bytes;
01902                         }
01903                         LOG(LOG_CPU,LOG_NORMAL)("RET - Same level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL());
01904                         return;
01905                 } else {
01906                         /* Return to outer level */
01907                         switch (desc.Type()) {
01908                         case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
01909                         case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
01910                                 CPU_CHECK_COND(desc.DPL()!=rpl,
01911                                         "RET to outer NC segment with DPL!=RPL",
01912                                         EXCEPTION_GP,selector & 0xfffc)
01913                                 break;
01914                         case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
01915                         case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
01916                                 CPU_CHECK_COND(desc.DPL()>rpl,
01917                                         "RET to outer C segment with DPL>RPL",
01918                                         EXCEPTION_GP,selector & 0xfffc)
01919                                 break;
01920                         default:
01921                                 E_Exit("RET from illegal descriptor type %X",(int)desc.Type());         // or #GP(selector)
01922                         }
01923 
01924                         CPU_CHECK_COND(!desc.saved.seg.p,
01925                                 "RET:Outer level:CS not present",
01926                                 EXCEPTION_NP,selector & 0xfffc)
01927 
01928                         // commit point
01929                         Bitu n_esp,n_ss;
01930                         try {
01931                         if (use32) {
01932                                 offset=CPU_Pop32();
01933                                 selector=CPU_Pop32() & 0xffff;
01934                                 reg_esp+=bytes;
01935                                 n_esp = CPU_Pop32();
01936                                 n_ss = CPU_Pop32() & 0xffff;
01937                         } else {
01938                                 offset=CPU_Pop16();
01939                                 selector=CPU_Pop16();
01940                                 reg_esp+=bytes;
01941                                 n_esp = CPU_Pop16();
01942                                 n_ss = CPU_Pop16();
01943                         }
01944                         }
01945                         catch (GuestPageFaultException &pf) {
01946                 (void)pf;//UNUSED
01947                 LOG_MSG("CPU_RET() interrupted prot #2");
01948                                 reg_esp = orig_esp;
01949                                 throw;
01950                         }
01951 
01952                         CPU_CHECK_COND((n_ss & 0xfffc)==0,
01953                                 "RET to outer level with SS selector zero",
01954                                 EXCEPTION_GP,0)
01955 
01956                         Descriptor n_ss_desc;
01957                         CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
01958                                 "RET:SS beyond limits",
01959                                 EXCEPTION_GP,n_ss & 0xfffc)
01960 
01961                         CPU_CHECK_COND(((n_ss & 3)!=rpl) || (n_ss_desc.DPL()!=rpl),
01962                                 "RET to outer segment with invalid SS privileges",
01963                                 EXCEPTION_GP,n_ss & 0xfffc)
01964                         switch (n_ss_desc.Type()) {
01965                         case DESC_DATA_EU_RW_NA:                case DESC_DATA_EU_RW_A:
01966                         case DESC_DATA_ED_RW_NA:                case DESC_DATA_ED_RW_A:
01967                                 break;
01968                         default:
01969                                 E_Exit("RET:SS selector type no writable data segment");        // or #GP(selector)
01970                         }
01971                         CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
01972                                 "RET:Stack segment not present",
01973                                 EXCEPTION_SS,n_ss & 0xfffc)
01974 
01975                         CPU_SetCPL(rpl);
01976                         Segs.expanddown[cs]=desc.GetExpandDown();
01977                         Segs.limit[cs]=do_seg_limits?desc.GetLimit():((PhysPt)(~0UL));
01978                         Segs.phys[cs]=desc.GetBase();
01979                         cpu.code.big=desc.Big()>0;
01980                         Segs.val[cs]=(selector&0xfffc) | cpu.cpl;
01981                         reg_eip=offset;
01982 
01983                         Segs.val[ss]=n_ss;
01984                         Segs.phys[ss]=n_ss_desc.GetBase();
01985                         Segs.limit[ss]=do_seg_limits?n_ss_desc.GetLimit():((PhysPt)(~0UL));
01986                         Segs.expanddown[ss]=n_ss_desc.GetExpandDown();
01987                         if (n_ss_desc.Big()) {
01988                                 cpu.stack.big=true;
01989                                 cpu.stack.mask=0xffffffff;
01990                                 cpu.stack.notmask=0;
01991                                 reg_esp=n_esp+bytes;
01992                         } else {
01993                                 cpu.stack.big=false;
01994                                 cpu.stack.mask=0xffff;
01995                                 cpu.stack.notmask=0xffff0000;
01996                                 reg_sp=(n_esp & 0xffff)+bytes;
01997                         }
01998 
01999                         CPU_CheckSegments();
02000 
02001 //                      LOG(LOG_MISC,LOG_ERROR)("RET - Higher level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL());
02002                         return;
02003                 }
02004                 LOG(LOG_CPU,LOG_NORMAL)("Prot ret %lX:%lX",(unsigned long)selector,(unsigned long)offset);
02005                 return;
02006         }
02007         assert(1);
02008 }
02009 
02010 
02011 Bitu CPU_SLDT(void) {
02012         return cpu.gdt.SLDT();
02013 }
02014 
02015 bool CPU_LLDT(Bitu selector) {
02016         if (!cpu.gdt.LLDT(selector)) {
02017                 LOG(LOG_CPU,LOG_ERROR)("LLDT failed, selector=%X",selector);
02018                 return true;
02019         }
02020         LOG(LOG_CPU,LOG_NORMAL)("LDT Set to %X",selector);
02021         return false;
02022 }
02023 
02024 Bitu CPU_STR(void) {
02025         return cpu_tss.selector;
02026 }
02027 
02028 bool CPU_LTR(Bitu selector) {
02029         if ((selector & 0xfffc)==0) {
02030                 cpu_tss.SetSelector(selector);
02031                 return false;
02032         }
02033         TSS_Descriptor desc;
02034         if ((selector & 4) || (!cpu.gdt.GetDescriptor(selector,desc))) {
02035                 LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X",selector);
02036                 return CPU_PrepareException(EXCEPTION_GP,selector);
02037         }
02038 
02039         if ((desc.Type()==DESC_286_TSS_A) || (desc.Type()==DESC_386_TSS_A)) {
02040                 if (!desc.saved.seg.p) {
02041                         LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X (not present)",selector);
02042                         return CPU_PrepareException(EXCEPTION_NP,selector);
02043                 }
02044                 if (!cpu_tss.SetSelector(selector)) E_Exit("LTR failed, selector=%X",(int)selector);
02045                 cpu_tss.desc.SetBusy(true);
02046                 cpu_tss.SaveSelector();
02047         } else {
02048                 /* Descriptor was no available TSS descriptor */ 
02049                 LOG(LOG_CPU,LOG_NORMAL)("LTR failed, selector=%X (type=%X)",selector,desc.Type());
02050                 return CPU_PrepareException(EXCEPTION_GP,selector);
02051         }
02052         return false;
02053 }
02054 
02055 void CPU_LGDT(Bitu limit,Bitu base) {
02056         LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X",base,limit);
02057         cpu.gdt.SetLimit(limit);
02058         cpu.gdt.SetBase(base);
02059 }
02060 
02061 void CPU_LIDT(Bitu limit,Bitu base) {
02062         LOG(LOG_CPU,LOG_NORMAL)("IDT Set to base:%X limit:%X",base,limit);
02063         cpu.idt.SetLimit(limit);
02064         cpu.idt.SetBase(base);
02065 }
02066 
02067 Bitu CPU_SGDT_base(void) {
02068         return cpu.gdt.GetBase();
02069 }
02070 Bitu CPU_SGDT_limit(void) {
02071         return cpu.gdt.GetLimit();
02072 }
02073 
02074 Bitu CPU_SIDT_base(void) {
02075         return cpu.idt.GetBase();
02076 }
02077 Bitu CPU_SIDT_limit(void) {
02078         return cpu.idt.GetLimit();
02079 }
02080 
02081 static bool snap_cpu_snapped=false;
02082 static Bit32u snap_cpu_saved_cr0;
02083 static Bit32u snap_cpu_saved_cr2;
02084 static Bit32u snap_cpu_saved_cr3;
02085 
02086 /* On shutdown, DOSBox needs to snap back to real mode
02087  * so that it's shutdown code doesn't cause page faults
02088  * trying to clean up DOS structures when we've booted
02089  * a 32-bit OS. It shouldn't be cleaning up DOS structures
02090  * anyway in that case considering they're likely obliterated
02091  * by the guest OS, but that's something we'll clean up
02092  * later. */
02093 void CPU_Snap_Back_To_Real_Mode() {
02094     if (snap_cpu_snapped) return;
02095 
02096     SETFLAGBIT(IF,false);       /* forcibly clear interrupt flag */
02097 
02098     cpu.code.big = false;   /* force back to 16-bit */
02099     cpu.stack.big = false;
02100     cpu.stack.mask = 0xffff;
02101     cpu.stack.notmask = 0xffff0000;
02102 
02103     snap_cpu_saved_cr0 = cpu.cr0;
02104     snap_cpu_saved_cr2 = paging.cr2;
02105     snap_cpu_saved_cr3 = paging.cr3;
02106 
02107     CPU_SET_CRX(0,0);   /* force CPU to real mode */
02108     CPU_SET_CRX(2,0);   /* disable paging */
02109     CPU_SET_CRX(3,0);   /* clear the page table dir */
02110 
02111     cpu.idt.SetBase(0);         /* or ELSE weird things will happen when INTerrupts are run */
02112     cpu.idt.SetLimit(1023);
02113 
02114     snap_cpu_snapped = true;
02115 }
02116 
02117 void CPU_Snap_Back_Restore() {
02118         if (!snap_cpu_snapped) return;
02119 
02120         CPU_SET_CRX(0,snap_cpu_saved_cr0);
02121         CPU_SET_CRX(2,snap_cpu_saved_cr2);
02122         CPU_SET_CRX(3,snap_cpu_saved_cr3);
02123 
02124         snap_cpu_snapped = false;
02125 }
02126 
02127 void CPU_Snap_Back_Forget() {
02128         snap_cpu_snapped = false;
02129 }
02130 
02131 static bool printed_cycles_auto_info = false;
02132 void CPU_SET_CRX(Bitu cr,Bitu value) {
02133         switch (cr) {
02134         case 0:
02135                 {
02136                         value|=CR0_FPUPRESENT;
02137                         Bitu changed=cpu.cr0 ^ value;
02138                         if (!changed) return;
02139                         if (GCC_UNLIKELY(changed & CR0_WRITEPROTECT)) {
02140                                 if (CPU_ArchitectureType >= CPU_ARCHTYPE_486OLD)
02141                                         PAGING_SetWP((value&CR0_WRITEPROTECT)? true:false);
02142                         }
02143                         cpu.cr0=value;
02144                         if (value & CR0_PROTECTION) {
02145                                 cpu.pmode=true;
02146                                 LOG(LOG_CPU,LOG_NORMAL)("Protected mode");
02147                                 PAGING_Enable((value&CR0_PAGING)? true:false);
02148 
02149                                 if (!(CPU_AutoDetermineMode&CPU_AUTODETERMINE_MASK)) break;
02150 
02151                                 if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) {
02152                                         CPU_CycleAutoAdjust=true;
02153                                         CPU_CycleLeft=0;
02154                                         CPU_Cycles=0;
02155                                         CPU_OldCycleMax=CPU_CycleMax;
02156                                         GFX_SetTitle(CPU_CyclePercUsed,-1,-1,false);
02157                                         if(!printed_cycles_auto_info) {
02158                                                 printed_cycles_auto_info = true;
02159                                                 LOG_MSG("DOSBox switched to max cycles, because of the setting: cycles=auto. If the game runs too fast try a fixed cycles amount in DOSBox's options.");
02160                                         }
02161                     menu_update_autocycle();
02162                                 } else {
02163                                         GFX_SetTitle(-1,-1,-1,false);
02164                                 }
02165 #if (C_DYNAMIC_X86)
02166                                 if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) {
02167                                         CPU_Core_Dyn_X86_Cache_Init(true);
02168                                         cpudecoder=&CPU_Core_Dyn_X86_Run;
02169                                         strcpy(core_mode, "dynamic");
02170                                 }
02171 #endif
02172                                 CPU_AutoDetermineMode<<=CPU_AUTODETERMINE_SHIFT;
02173                         } else {
02174                                 cpu.pmode=false;
02175                                 if (value & CR0_PAGING) LOG_MSG("Paging requested without PE=1");
02176                                 PAGING_Enable(false);
02177                                 LOG(LOG_CPU,LOG_NORMAL)("Real mode");
02178                         }
02179                         break;
02180                 }
02181         case 2:
02182                 paging.cr2=value;
02183                 break;
02184         case 3:
02185                 PAGING_SetDirBase(value);
02186                 break;
02187         default:
02188                 LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV CR%d,%X",cr,value);
02189                 break;
02190         }
02191 }
02192 
02193 bool CPU_WRITE_CRX(Bitu cr,Bitu value) {
02194         /* Check if privileged to access control registers */
02195         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02196         if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0);
02197         if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLD) {
02198                 if (cr==4) return CPU_PrepareException(EXCEPTION_UD,0);
02199         }
02200         CPU_SET_CRX(cr,value);
02201         return false;
02202 }
02203 
02204 Bitu CPU_GET_CRX(Bitu cr) {
02205         switch (cr) {
02206         case 0:
02207                 if (CPU_ArchitectureType>=CPU_ARCHTYPE_PENTIUM) return cpu.cr0;
02208                 else if (CPU_ArchitectureType>=CPU_ARCHTYPE_486OLD) return (cpu.cr0 & 0xe005003f);
02209                 else return (cpu.cr0 | 0x7ffffff0);
02210         case 2:
02211                 return paging.cr2;
02212         case 3:
02213                 return PAGING_GetDirBase() & 0xfffff000;
02214         default:
02215                 LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, CR%d",cr);
02216                 break;
02217         }
02218         return 0;
02219 }
02220 
02221 bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue) {
02222         /* Check if privileged to access control registers */
02223         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02224         if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0);
02225         if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLD) {
02226                 if (cr==4) return CPU_PrepareException(EXCEPTION_UD,0);
02227         }
02228         retvalue=CPU_GET_CRX(cr);
02229         return false;
02230 }
02231 
02232 
02233 bool CPU_WRITE_DRX(Bitu dr,Bitu value) {
02234         /* Check if privileged to access control registers */
02235         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02236         switch (dr) {
02237         case 0:
02238         case 1:
02239         case 2:
02240         case 3:
02241                 cpu.drx[dr]=value;
02242                 break;
02243         case 4:
02244         case 6:
02245                 cpu.drx[6]=(value|0xffff0ff0) & 0xffffefff;
02246                 break;
02247         case 5:
02248         case 7:
02249                 if (CPU_ArchitectureType<CPU_ARCHTYPE_PENTIUM) {
02250                         cpu.drx[7]=(value|0x400) & 0xffff2fff;
02251                 } else {
02252                         cpu.drx[7]=(value|0x400);
02253                 }
02254                 break;
02255         default:
02256                 LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV DR%d,%X",dr,value);
02257                 break;
02258         }
02259         return false;
02260 }
02261 
02262 bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue) {
02263         /* Check if privileged to access control registers */
02264         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02265         switch (dr) {
02266         case 0:
02267         case 1:
02268         case 2:
02269         case 3:
02270         case 6:
02271         case 7:
02272                 retvalue=cpu.drx[dr];
02273                 break;
02274         case 4:
02275                 retvalue=cpu.drx[6];
02276                 break;
02277         case 5:
02278                 retvalue=cpu.drx[7];
02279                 break;
02280         default:
02281                 LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, DR%d",dr);
02282                 retvalue=0;
02283                 break;
02284         }
02285         return false;
02286 }
02287 
02288 bool CPU_WRITE_TRX(Bitu tr,Bitu value) {
02289         /* Check if privileged to access control registers */
02290         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02291         switch (tr) {
02292 //      case 3:
02293         case 6:
02294         case 7:
02295                 cpu.trx[tr]=value;
02296                 return false;
02297         default:
02298                 LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV TR%d,%X",tr,value);
02299                 break;
02300         }
02301         return CPU_PrepareException(EXCEPTION_UD,0);
02302 }
02303 
02304 bool CPU_READ_TRX(Bitu tr,Bit32u & retvalue) {
02305         /* Check if privileged to access control registers */
02306         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02307         switch (tr) {
02308 //      case 3:
02309         case 6:
02310         case 7:
02311                 retvalue=cpu.trx[tr];
02312                 return false;
02313         default:
02314                 LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, TR%d",tr);
02315                 break;
02316         }
02317         return CPU_PrepareException(EXCEPTION_UD,0);
02318 }
02319 
02320 
02321 Bitu CPU_SMSW(void) {
02322         return cpu.cr0;
02323 }
02324 
02325 bool CPU_LMSW(Bitu word) {
02326         if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
02327         word&=0xf;
02328         if (cpu.cr0 & 1) word|=1; 
02329         word|=(cpu.cr0&0xfffffff0);
02330         CPU_SET_CRX(0,word);
02331         return false;
02332 }
02333 
02334 void CPU_ARPL(Bitu & dest_sel,Bitu src_sel) {
02335         FillFlags();
02336         if ((dest_sel & 3) < (src_sel & 3)) {
02337                 dest_sel=(dest_sel & 0xfffc) + (src_sel & 3);
02338 //              dest_sel|=0xff3f0000;
02339                 SETFLAGBIT(ZF,true);
02340         } else {
02341                 SETFLAGBIT(ZF,false);
02342         } 
02343 }
02344         
02345 void CPU_LAR(Bitu selector,Bitu & ar) {
02346         FillFlags();
02347         if (selector == 0) {
02348                 SETFLAGBIT(ZF,false);
02349                 return;
02350         }
02351         Descriptor desc;Bitu rpl=selector & 3;
02352         if (!cpu.gdt.GetDescriptor(selector,desc)){
02353                 SETFLAGBIT(ZF,false);
02354                 return;
02355         }
02356         switch (desc.Type()){
02357         case DESC_CODE_N_C_A:   case DESC_CODE_N_C_NA:
02358         case DESC_CODE_R_C_A:   case DESC_CODE_R_C_NA:
02359                 break;
02360 
02361         case DESC_286_INT_GATE:         case DESC_286_TRAP_GATE:        {
02362         case DESC_386_INT_GATE:         case DESC_386_TRAP_GATE:
02363                 SETFLAGBIT(ZF,false);
02364                 return;
02365         }
02366 
02367         case DESC_LDT:
02368         case DESC_TASK_GATE:
02369 
02370         case DESC_286_TSS_A:            case DESC_286_TSS_B:
02371         case DESC_286_CALL_GATE:
02372 
02373         case DESC_386_TSS_A:            case DESC_386_TSS_B:
02374         case DESC_386_CALL_GATE:
02375         
02376 
02377         case DESC_DATA_EU_RO_NA:        case DESC_DATA_EU_RO_A:
02378         case DESC_DATA_EU_RW_NA:        case DESC_DATA_EU_RW_A:
02379         case DESC_DATA_ED_RO_NA:        case DESC_DATA_ED_RO_A:
02380         case DESC_DATA_ED_RW_NA:        case DESC_DATA_ED_RW_A:
02381         case DESC_CODE_N_NC_A:          case DESC_CODE_N_NC_NA:
02382         case DESC_CODE_R_NC_A:          case DESC_CODE_R_NC_NA:
02383                 if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
02384                         SETFLAGBIT(ZF,false);
02385                         return;
02386                 }
02387                 break;
02388         default:
02389                 SETFLAGBIT(ZF,false);
02390                 return;
02391         }
02392         /* Valid descriptor */
02393         ar=desc.saved.fill[1] & 0x00ffff00;
02394         SETFLAGBIT(ZF,true);
02395 }
02396 
02397 void CPU_LSL(Bitu selector,Bitu & limit) {
02398         FillFlags();
02399         if (selector == 0) {
02400                 SETFLAGBIT(ZF,false);
02401                 return;
02402         }
02403         Descriptor desc;Bitu rpl=selector & 3;
02404         if (!cpu.gdt.GetDescriptor(selector,desc)){
02405                 SETFLAGBIT(ZF,false);
02406                 return;
02407         }
02408         switch (desc.Type()){
02409         case DESC_CODE_N_C_A:   case DESC_CODE_N_C_NA:
02410         case DESC_CODE_R_C_A:   case DESC_CODE_R_C_NA:
02411                 break;
02412 
02413         case DESC_LDT:
02414         case DESC_286_TSS_A:
02415         case DESC_286_TSS_B:
02416         
02417         case DESC_386_TSS_A:
02418         case DESC_386_TSS_B:
02419 
02420         case DESC_DATA_EU_RO_NA:        case DESC_DATA_EU_RO_A:
02421         case DESC_DATA_EU_RW_NA:        case DESC_DATA_EU_RW_A:
02422         case DESC_DATA_ED_RO_NA:        case DESC_DATA_ED_RO_A:
02423         case DESC_DATA_ED_RW_NA:        case DESC_DATA_ED_RW_A:
02424         
02425         case DESC_CODE_N_NC_A:          case DESC_CODE_N_NC_NA:
02426         case DESC_CODE_R_NC_A:          case DESC_CODE_R_NC_NA:
02427                 if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
02428                         SETFLAGBIT(ZF,false);
02429                         return;
02430                 }
02431                 break;
02432         default:
02433                 SETFLAGBIT(ZF,false);
02434                 return;
02435         }
02436         limit=desc.GetLimit();
02437         SETFLAGBIT(ZF,true);
02438 }
02439 
02440 void CPU_VERR(Bitu selector) {
02441         FillFlags();
02442         if (selector == 0) {
02443                 SETFLAGBIT(ZF,false);
02444                 return;
02445         }
02446         Descriptor desc;Bitu rpl=selector & 3;
02447         if (!cpu.gdt.GetDescriptor(selector,desc)){
02448                 SETFLAGBIT(ZF,false);
02449                 return;
02450         }
02451         switch (desc.Type()){
02452         case DESC_CODE_R_C_A:           case DESC_CODE_R_C_NA:  
02453                 //Conforming readable code segments can be always read 
02454                 break;
02455         case DESC_DATA_EU_RO_NA:        case DESC_DATA_EU_RO_A:
02456         case DESC_DATA_EU_RW_NA:        case DESC_DATA_EU_RW_A:
02457         case DESC_DATA_ED_RO_NA:        case DESC_DATA_ED_RO_A:
02458         case DESC_DATA_ED_RW_NA:        case DESC_DATA_ED_RW_A:
02459 
02460         case DESC_CODE_R_NC_A:          case DESC_CODE_R_NC_NA:
02461                 if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
02462                         SETFLAGBIT(ZF,false);
02463                         return;
02464                 }
02465                 break;
02466         default:
02467                 SETFLAGBIT(ZF,false);
02468                 return;
02469         }
02470         SETFLAGBIT(ZF,true);
02471 }
02472 
02473 void CPU_VERW(Bitu selector) {
02474         FillFlags();
02475         if (selector == 0) {
02476                 SETFLAGBIT(ZF,false);
02477                 return;
02478         }
02479         Descriptor desc;Bitu rpl=selector & 3;
02480         if (!cpu.gdt.GetDescriptor(selector,desc)){
02481                 SETFLAGBIT(ZF,false);
02482                 return;
02483         }
02484         switch (desc.Type()){
02485         case DESC_DATA_EU_RW_NA:        case DESC_DATA_EU_RW_A:
02486         case DESC_DATA_ED_RW_NA:        case DESC_DATA_ED_RW_A:
02487                 if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
02488                         SETFLAGBIT(ZF,false);
02489                         return;
02490                 }
02491                 break;
02492         default:
02493                 SETFLAGBIT(ZF,false);
02494                 return;
02495         }
02496         SETFLAGBIT(ZF,true);
02497 }
02498 
02499 bool CPU_SetSegGeneral(SegNames seg,Bitu value) {
02500         value &= 0xffff;
02501         if (!cpu.pmode || (reg_flags & FLAG_VM)) {
02502                 Segs.val[seg]=value;
02503                 Segs.phys[seg]=value << 4;
02504                 if (seg==ss) {
02505                         cpu.stack.big=false;
02506                         cpu.stack.mask=0xffff;
02507                         cpu.stack.notmask=0xffff0000;
02508                 }
02509 
02510                 /* real mode: loads do not change the limit. "Flat real mode" would not be possible otherwise.
02511                  * vm86: loads are fixed at 64KB (right?) */
02512                 if (reg_flags & FLAG_VM)
02513                         Segs.limit[seg] = 0xFFFF;
02514 
02515                 return false;
02516         } else {
02517                 if (seg==ss) {
02518                         // Stack needs to be non-zero
02519                         if ((value & 0xfffc)==0) {
02520                                 E_Exit("CPU_SetSegGeneral: Stack segment zero");
02521 //                              return CPU_PrepareException(EXCEPTION_GP,0);
02522                         }
02523                         Descriptor desc;
02524                         if (!cpu.gdt.GetDescriptor(value,desc)) {
02525                                 E_Exit("CPU_SetSegGeneral: Stack segment beyond limits");
02526 //                              return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
02527                         }
02528                         if (((value & 3)!=cpu.cpl) || (desc.DPL()!=cpu.cpl)) {
02529                                 E_Exit("CPU_SetSegGeneral: Stack segment with invalid privileges");
02530 //                              return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
02531                         }
02532 
02533                         switch (desc.Type()) {
02534                         case DESC_DATA_EU_RW_NA:                case DESC_DATA_EU_RW_A:
02535                         case DESC_DATA_ED_RW_NA:                case DESC_DATA_ED_RW_A:
02536                                 break;
02537                         default:
02538                                 //Earth Siege 1
02539                                 return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
02540                         }
02541 
02542                         if (!desc.saved.seg.p) {
02543 //                              E_Exit("CPU_SetSegGeneral: Stack segment not present"); // or #SS(sel)
02544                                 return CPU_PrepareException(EXCEPTION_SS,value & 0xfffc);
02545                         }
02546 
02547                         Segs.val[seg]=value;
02548                         Segs.phys[seg]=desc.GetBase();
02549                         Segs.limit[seg]=do_seg_limits?desc.GetLimit():((PhysPt)(~0UL));
02550                         Segs.expanddown[seg]=desc.GetExpandDown();
02551                         if (desc.Big()) {
02552                                 cpu.stack.big=true;
02553                                 cpu.stack.mask=0xffffffff;
02554                                 cpu.stack.notmask=0;
02555                         } else {
02556                                 cpu.stack.big=false;
02557                                 cpu.stack.mask=0xffff;
02558                                 cpu.stack.notmask=0xffff0000;
02559                         }
02560                 } else {
02561                         if ((value & 0xfffc)==0) {
02562                                 Segs.val[seg]=value;
02563                                 Segs.phys[seg]=0;       // ??
02564                                 return false;
02565                         }
02566                         Descriptor desc;
02567                         if (!cpu.gdt.GetDescriptor(value,desc)) {
02568                                 return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
02569                         }
02570                         switch (desc.Type()) {
02571                         case DESC_DATA_EU_RO_NA:                case DESC_DATA_EU_RO_A:
02572                         case DESC_DATA_EU_RW_NA:                case DESC_DATA_EU_RW_A:
02573                         case DESC_DATA_ED_RO_NA:                case DESC_DATA_ED_RO_A:
02574                         case DESC_DATA_ED_RW_NA:                case DESC_DATA_ED_RW_A:
02575                         case DESC_CODE_R_NC_A:                  case DESC_CODE_R_NC_NA:
02576                                 if (((value & 3)>desc.DPL()) || (cpu.cpl>desc.DPL())) {
02577                                         // extreme pinball
02578                                         return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
02579                                 }
02580                                 break;
02581                         case DESC_CODE_R_C_A:                   case DESC_CODE_R_C_NA:
02582                                 break;
02583                         default:
02584                                 // gabriel knight
02585                                 return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
02586 
02587                         }
02588                         if (!desc.saved.seg.p) {
02589                                 // win
02590                                 return CPU_PrepareException(EXCEPTION_NP,value & 0xfffc);
02591                         }
02592 
02593                         Segs.val[seg]=value;
02594                         Segs.phys[seg]=desc.GetBase();
02595                         Segs.limit[seg]=do_seg_limits?desc.GetLimit():((PhysPt)(~0UL));
02596                         Segs.expanddown[seg]=desc.GetExpandDown();
02597                 }
02598 
02599                 return false;
02600         }
02601 }
02602 
02603 bool CPU_PopSeg(SegNames seg,bool use32) {
02604         Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
02605         if (CPU_SetSegGeneral(seg,val)) return true;
02606         Bitu addsp=use32?0x04:0x02;
02607         reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+addsp)&cpu.stack.mask);
02608         return false;
02609 }
02610 
02611 extern bool enable_fpu;
02612 
02613 bool CPU_CPUID(void) {
02614         if (CPU_ArchitectureType < CPU_ARCHTYPE_486NEW) return false;
02615         switch (reg_eax) {
02616         case 0: /* Vendor ID String and maximum level? */
02617                 reg_eax=1;  /* Maximum level */ 
02618                 reg_ebx='G' | ('e' << 8) | ('n' << 16) | ('u'<< 24); 
02619                 reg_edx='i' | ('n' << 8) | ('e' << 16) | ('I'<< 24); 
02620                 reg_ecx='n' | ('t' << 8) | ('e' << 16) | ('l'<< 24); 
02621                 break;
02622         case 1: /* get processor type/family/model/stepping and feature flags */
02623                 if ((CPU_ArchitectureType == CPU_ARCHTYPE_486NEW) ||
02624                         (CPU_ArchitectureType == CPU_ARCHTYPE_MIXED)) {
02625                         reg_eax=0x402;          /* intel 486dx */
02626                         reg_ebx=0;                      /* Not Supported */
02627                         reg_ecx=0;                      /* No features */
02628                         reg_edx=enable_fpu?1:0; /* FPU */
02629                 } else if (CPU_ArchitectureType == CPU_ARCHTYPE_PENTIUM) {
02630                         reg_eax=0x513;          /* intel pentium */
02631                         reg_ebx=0;                      /* Not Supported */
02632                         reg_ecx=0;                      /* No features */
02633                         reg_edx=0x00000010|(enable_fpu?1:0);    /* FPU+TimeStamp/RDTSC */
02634                         if (enable_msr) reg_edx |= 0x20; /* ModelSpecific/MSR */
02635             if (enable_cmpxchg8b) reg_edx |= 0x100; /* CMPXCHG8B */
02636                 } else if (CPU_ArchitectureType == CPU_ARCHTYPE_P55CSLOW) {
02637                         reg_eax=0x543;          /* intel pentium mmx (P55C) */
02638                         reg_ebx=0;                      /* Not Supported */
02639                         reg_ecx=0;                      /* No features */
02640                         reg_edx=0x00800010|(enable_fpu?1:0);    /* FPU+TimeStamp/RDTSC+MMX+ModelSpecific/MSR */
02641                         if (enable_msr) reg_edx |= 0x20; /* ModelSpecific/MSR */
02642             if (enable_cmpxchg8b) reg_edx |= 0x100; /* CMPXCHG8B */
02643                 } else if (CPU_ArchitectureType == CPU_ARCHTYPE_PPROSLOW) {
02644                         reg_eax=0x612;          /* intel pentium pro */
02645                         reg_ebx=0;                      /* Not Supported */
02646                         reg_ecx=0;                      /* No features */
02647                         reg_edx=0x00008011;     /* FPU+TimeStamp/RDTSC */
02648                 } else {
02649                         return false;
02650                 }
02651                 break;
02652         default:
02653                 LOG(LOG_CPU,LOG_ERROR)("Unhandled CPUID Function %x",reg_eax);
02654                 reg_eax=0;
02655                 reg_ebx=0;
02656                 reg_ecx=0;
02657                 reg_edx=0;
02658                 break;
02659         }
02660         return true;
02661 }
02662 
02663 Bits HLT_Decode(void) {
02664         /* Once an interrupt occurs, it should change cpu core */
02665         if (reg_eip!=cpu.hlt.eip || SegValue(cs) != cpu.hlt.cs) {
02666                 cpudecoder=cpu.hlt.old_decoder;
02667         } else {
02668                 CPU_IODelayRemoved += CPU_Cycles;
02669                 CPU_Cycles=0;
02670         }
02671         return 0;
02672 }
02673 
02674 void CPU_HLT(Bitu oldeip) {
02675         /* Since cpu.hlt.old_decoder assigns the current decoder to old, and relies on restoring
02676          * it back when finished, setting cpudecoder to HLT_Decode while already HLT_Decode effectively
02677          * hangs DOSBox and makes it complete unresponsive. Don't want that! */
02678         if (cpudecoder == &HLT_Decode) E_Exit("CPU_HLT attempted to set HLT_Decode while CPU decoder already HLT_Decode");
02679 
02680         reg_eip=oldeip;
02681         CPU_IODelayRemoved += CPU_Cycles;
02682         CPU_Cycles=0;
02683         cpu.hlt.cs=SegValue(cs);
02684         cpu.hlt.eip=reg_eip;
02685         cpu.hlt.old_decoder=cpudecoder;
02686         cpudecoder=&HLT_Decode;
02687 }
02688 
02689 void CPU_ENTER(bool use32,Bitu bytes,Bitu level) {
02690         level&=0x1f;
02691         Bitu sp_index=reg_esp&cpu.stack.mask;
02692         Bitu bp_index=reg_ebp&cpu.stack.mask;
02693         if (!use32) {
02694                 sp_index-=2;
02695                 mem_writew(SegPhys(ss)+sp_index,reg_bp);
02696                 reg_bp=(Bit16u)(reg_esp-2);
02697                 if (level) {
02698                         for (Bitu i=1;i<level;i++) {    
02699                                 sp_index-=2;bp_index-=2;
02700                                 mem_writew(SegPhys(ss)+sp_index,mem_readw(SegPhys(ss)+bp_index));
02701                         }
02702                         sp_index-=2;
02703                         mem_writew(SegPhys(ss)+sp_index,reg_bp);
02704                 }
02705         } else {
02706                 sp_index-=4;
02707         mem_writed(SegPhys(ss)+sp_index,reg_ebp);
02708                 reg_ebp=(reg_esp-4);
02709                 if (level) {
02710                         for (Bitu i=1;i<level;i++) {    
02711                                 sp_index-=4;bp_index-=4;
02712                                 mem_writed(SegPhys(ss)+sp_index,mem_readd(SegPhys(ss)+bp_index));
02713                         }
02714                         sp_index-=4;
02715                         mem_writed(SegPhys(ss)+sp_index,reg_ebp);
02716                 }
02717         }
02718         sp_index-=bytes;
02719         reg_esp=(reg_esp&cpu.stack.notmask)|((sp_index)&cpu.stack.mask);
02720 }
02721 
02722 void CPU_CycleIncrease(bool pressed) {
02723         if (!pressed) return;
02724         if (CPU_CycleAutoAdjust) {
02725                 CPU_CyclePercUsed+=5;
02726                 if (CPU_CyclePercUsed>105) CPU_CyclePercUsed=105;
02727                 LOG_MSG("CPU speed: max %ld percent.",CPU_CyclePercUsed);
02728                 GFX_SetTitle(CPU_CyclePercUsed,-1,-1,false);
02729         } else {
02730                 Bit32s old_cycles=CPU_CycleMax;
02731                 if (CPU_CycleUp < 100) {
02732                         CPU_CycleMax = (Bit32s)(CPU_CycleMax * (1 + (float)CPU_CycleUp / 100.0));
02733                 } else {
02734                         CPU_CycleMax = (Bit32s)(CPU_CycleMax + CPU_CycleUp);
02735                 }
02736             
02737                 CPU_CycleLeft=0;CPU_Cycles=0;
02738                 if (CPU_CycleMax==old_cycles) CPU_CycleMax++;
02739                 if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) {
02740                     LOG_MSG("CPU:%ld cycles (auto)",CPU_CycleMax);
02741                 } else {
02742                     CPU_CyclesSet=CPU_CycleMax;
02743 #if (C_DYNAMIC_X86)
02744             if (CPU_CycleMax > 15000 && cpudecoder != &CPU_Core_Dyn_X86_Run)
02745                 LOG_MSG("CPU speed: fixed %ld cycles. If you need more than 20000, try core=dynamic in DOSBox's options.",CPU_CycleMax);
02746             else
02747 #endif
02748                 LOG_MSG("CPU speed: fixed %ld cycles.",CPU_CycleMax);
02749         }
02750                 GFX_SetTitle(CPU_CycleMax,-1,-1,false);
02751         }
02752 }
02753 
02754 void CPU_CycleDecrease(bool pressed) {
02755         if (!pressed) return;
02756         if (CPU_CycleAutoAdjust) {
02757                 CPU_CyclePercUsed-=5;
02758                 if (CPU_CyclePercUsed<=0) CPU_CyclePercUsed=1;
02759                 if(CPU_CyclePercUsed <=70)
02760                         LOG_MSG("CPU speed: max %ld percent. If the game runs too fast, try a fixed cycles amount in DOSBox's options.",CPU_CyclePercUsed);
02761                 else
02762                         LOG_MSG("CPU speed: max %ld percent.",CPU_CyclePercUsed);
02763                 GFX_SetTitle(CPU_CyclePercUsed,-1,-1,false);
02764         } else {
02765                 if (CPU_CycleDown < 100) {
02766                         CPU_CycleMax = (Bit32s)(CPU_CycleMax / (1 + (float)CPU_CycleDown / 100.0));
02767                 } else {
02768                         CPU_CycleMax = (Bit32s)(CPU_CycleMax - CPU_CycleDown);
02769                 }
02770                 CPU_CycleLeft=0;CPU_Cycles=0;
02771                 if (CPU_CycleMax <= 0) CPU_CycleMax=1;
02772                 if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) {
02773                     LOG_MSG("CPU:%ld cycles (auto)",CPU_CycleMax);
02774                 } else {
02775                     CPU_CyclesSet=CPU_CycleMax;
02776                     LOG_MSG("CPU speed: fixed %ld cycles.",CPU_CycleMax);
02777                 }
02778                 GFX_SetTitle(CPU_CycleMax,-1,-1,false);
02779         }
02780 }
02781 
02782 static void CPU_ToggleAutoCycles(bool pressed) {
02783     if (!pressed)
02784         return;
02785 
02786     Section* sec=control->GetSection("cpu");
02787     if (sec) {
02788         std::string tmp("cycles=");
02789         if (CPU_CycleAutoAdjust) {
02790             std::ostringstream str;
02791             str << "fixed " << CPU_CyclesSet;
02792             tmp.append(str.str());
02793         } else if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) {
02794             tmp.append("max");
02795         } else {
02796             tmp.append("auto");
02797         }
02798 
02799         sec->HandleInputline(tmp);
02800     }
02801 }
02802 
02803 static void CPU_ToggleFullCore(bool pressed) {
02804     if (!pressed)
02805         return;
02806     Section* sec=control->GetSection("cpu");
02807     if(sec) {
02808         std::string tmp="core=full";
02809         sec->HandleInputline(tmp);
02810     }
02811 }
02812 
02813 static void CPU_ToggleNormalCore(bool pressed) {
02814     if (!pressed)
02815         return;
02816     Section* sec=control->GetSection("cpu");
02817     if(sec) {
02818         std::string tmp="core=normal";
02819         sec->HandleInputline(tmp);
02820     }
02821 }
02822 
02823 #if (C_DYNAMIC_X86)
02824 static void CPU_ToggleDynamicCore(bool pressed) {
02825     if (!pressed)
02826         return;
02827     Section* sec=control->GetSection("cpu");
02828     if(sec) {
02829         std::string tmp="core=dynamic";
02830         sec->HandleInputline(tmp);
02831     }
02832 }
02833 #endif
02834 
02835 static void CPU_ToggleSimpleCore(bool pressed) {
02836     if (!pressed)
02837         return;
02838     Section* sec=control->GetSection("cpu");
02839     std::string tmp="core=simple";
02840     if(sec) {
02841         sec->HandleInputline(tmp);
02842     }
02843 }
02844 
02845 void CPU_Enable_SkipAutoAdjust(void) {
02846         if (CPU_CycleAutoAdjust) {
02847                 CPU_CycleMax /= 2;
02848                 if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT)
02849                         CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT;
02850         }
02851         CPU_SkipCycleAutoAdjust=true;
02852 }
02853 
02854 void CPU_Disable_SkipAutoAdjust(void) {
02855         CPU_SkipCycleAutoAdjust=false;
02856 }
02857 
02858 
02859 extern Bit32s ticksDone;
02860 extern Bit32u ticksScheduled;
02861 extern int dynamic_core_cache_block_size;
02862 
02863 void CPU_Reset_AutoAdjust(void) {
02864         CPU_IODelayRemoved = 0;
02865         ticksDone = 0;
02866         ticksScheduled = 0;
02867 }
02868 
02869 class Weitek_PageHandler : public PageHandler {
02870 public:
02871         Weitek_PageHandler(HostPt /*addr*/){
02872                 flags=PFLAG_NOCODE;
02873         }
02874 
02875         ~Weitek_PageHandler() {
02876         }
02877 
02878         Bitu readb(PhysPt addr);
02879         void writeb(PhysPt addr,Bitu val);
02880         Bitu readw(PhysPt addr);
02881         void writew(PhysPt addr,Bitu val);
02882         Bitu readd(PhysPt addr);
02883         void writed(PhysPt addr,Bitu val);
02884 };
02885 
02886 Bitu Weitek_PageHandler::readb(PhysPt addr) {
02887     LOG_MSG("Weitek stub: readb at 0x%lx",(unsigned long)addr);
02888         return (Bitu)-1;
02889 }
02890 void Weitek_PageHandler::writeb(PhysPt addr,Bitu val) {
02891     LOG_MSG("Weitek stub: writeb at 0x%lx val=0x%lx",(unsigned long)addr,(unsigned long)val);
02892 }
02893 
02894 Bitu Weitek_PageHandler::readw(PhysPt addr) {
02895     LOG_MSG("Weitek stub: readw at 0x%lx",(unsigned long)addr);
02896         return (Bitu)-1;
02897 }
02898 
02899 void Weitek_PageHandler::writew(PhysPt addr,Bitu val) {
02900     LOG_MSG("Weitek stub: writew at 0x%lx val=0x%lx",(unsigned long)addr,(unsigned long)val);
02901 }
02902 
02903 Bitu Weitek_PageHandler::readd(PhysPt addr) {
02904     LOG_MSG("Weitek stub: readd at 0x%lx",(unsigned long)addr);
02905         return (Bitu)-1;
02906 }
02907 
02908 void Weitek_PageHandler::writed(PhysPt addr,Bitu val) {
02909     LOG_MSG("Weitek stub: writed at 0x%lx val=0x%lx",(unsigned long)addr,(unsigned long)val);
02910 }
02911 
02912 Weitek_PageHandler weitek_pagehandler(0);
02913 
02914 PageHandler* weitek_memio_cb(MEM_CalloutObject &co,Bitu phys_page) {
02915     (void)co; // UNUSED
02916     (void)phys_page; // UNUSED
02917     return &weitek_pagehandler;
02918 }
02919 
02920 bool CpuType_Auto(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
02921     (void)menu;//UNUSED
02922     (void)menuitem;//UNUSED
02923     Section* sec=control->GetSection("cpu");
02924     if (sec) sec->HandleInputline("cputype=auto");
02925     return true;
02926 }
02927 
02928 bool CpuType_ByName(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) {
02929     (void)menu;//UNUSED
02930 
02931     const char *name = menuitem->get_name().c_str();
02932 
02933     /* name should be cputype_... */
02934     if (!strncmp(name,"cputype_",8)) name += 8;
02935     else abort();
02936 
02937     Section* sec=control->GetSection("cpu");
02938     if (sec) sec->HandleInputline(std::string("cputype=")+name);
02939     return true;
02940 }
02941 
02942 class CPU: public Module_base {
02943 private:
02944         static bool inited;
02945 public:
02946         CPU(Section* configuration):Module_base(configuration) {
02947                 Section_prop * section=static_cast<Section_prop *>(configuration);
02948                 DOSBoxMenu::item *item;
02949 
02950                 if(inited) {
02951                         Change_Config(configuration);
02952                         return;
02953                 }
02954 //              Section_prop * section=static_cast<Section_prop *>(configuration);
02955                 inited=true;
02956                 reg_eax=0;
02957                 reg_ebx=0;
02958                 reg_ecx=0;
02959                 reg_edx=0;
02960                 reg_edi=0;
02961                 reg_esi=0;
02962                 reg_ebp=0;
02963                 reg_esp=0;
02964 
02965                 do_seg_limits = section->Get_bool("segment limits");
02966         
02967                 SegSet16(cs,0); Segs.limit[cs] = do_seg_limits ? 0xFFFF : ((PhysPt)(~0UL)); Segs.expanddown[cs] = false;
02968                 SegSet16(ds,0); Segs.limit[ds] = do_seg_limits ? 0xFFFF : ((PhysPt)(~0UL)); Segs.expanddown[ds] = false;
02969                 SegSet16(es,0); Segs.limit[es] = do_seg_limits ? 0xFFFF : ((PhysPt)(~0UL)); Segs.expanddown[es] = false;
02970                 SegSet16(fs,0); Segs.limit[fs] = do_seg_limits ? 0xFFFF : ((PhysPt)(~0UL)); Segs.expanddown[fs] = false;
02971                 SegSet16(gs,0); Segs.limit[gs] = do_seg_limits ? 0xFFFF : ((PhysPt)(~0UL)); Segs.expanddown[gs] = false;
02972                 SegSet16(ss,0); Segs.limit[ss] = do_seg_limits ? 0xFFFF : ((PhysPt)(~0UL)); Segs.expanddown[ss] = false;
02973         
02974                 CPU_SetFlags(FLAG_IF,FMASK_ALL);                //Enable interrupts
02975                 cpu.cr0=0xffffffff;
02976                 CPU_SET_CRX(0,0);                                               //Initialize
02977                 cpu.code.big=false;
02978                 cpu.stack.mask=0xffff;
02979                 cpu.stack.notmask=0xffff0000;
02980                 cpu.stack.big=false;
02981                 cpu.trap_skip=false;
02982                 cpu.idt.SetBase(0);
02983                 cpu.idt.SetLimit(1023);
02984 
02985                 for (Bitu i=0; i<7; i++) {
02986                         cpu.drx[i]=0;
02987                         cpu.trx[i]=0;
02988                 }
02989                 if (CPU_ArchitectureType>=CPU_ARCHTYPE_PENTIUM) {
02990                         cpu.drx[6]=0xffff0ff0;
02991                 } else {
02992                         cpu.drx[6]=0xffff1ff0;
02993                 }
02994                 cpu.drx[7]=0x00000400;
02995 
02996                 /* Init the cpu cores */
02997                 CPU_Core_Normal_Init();
02998                 CPU_Core_Simple_Init();
02999                 CPU_Core_Full_Init();
03000 #if (C_DYNAMIC_X86)
03001                 CPU_Core_Dyn_X86_Init();
03002 #endif
03003                 MAPPER_AddHandler(CPU_CycleDecrease,MK_minus,MMODHOST,"cycledown","Dec Cycles",&item);
03004                 item->set_text("Decrement cycles");
03005 
03006                 MAPPER_AddHandler(CPU_CycleIncrease,MK_equals,MMODHOST,"cycleup"  ,"Inc Cycles",&item);
03007                 item->set_text("Increment cycles");
03008 
03009                 MAPPER_AddHandler(CPU_ToggleAutoCycles,MK_nothing,0,"cycauto","AutoCycles",&item);
03010                 item->set_text("Auto cycles");
03011                 item->set_description("Enable automatic cycle count");
03012 
03013                 MAPPER_AddHandler(CPU_ToggleNormalCore,MK_nothing,0,"normal"  ,"NormalCore", &item);
03014                 item->set_text("Normal core");
03015 
03016                 MAPPER_AddHandler(CPU_ToggleFullCore,MK_nothing,0,"full","Full Core", &item);
03017                 item->set_text("Full core");
03018 
03019                 MAPPER_AddHandler(CPU_ToggleSimpleCore,MK_nothing,0,"simple","SimpleCore", &item);
03020                 item->set_text("Simple core");
03021 #if (C_DYNAMIC_X86)
03022                 MAPPER_AddHandler(CPU_ToggleDynamicCore,MK_nothing,0,"dynamic","DynCore",&item);
03023                 item->set_text("Dynamic core");
03024 #endif
03025 
03026         /* these are not mapper shortcuts, and probably should not be mapper shortcuts */
03027         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_auto").
03028             set_text("Auto").set_callback_function(CpuType_Auto);
03029         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_8086").
03030             set_text("8086").set_callback_function(CpuType_ByName);
03031         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_8086_prefetch").
03032             set_text("8086 with prefetch").set_callback_function(CpuType_ByName);
03033         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_80186").
03034             set_text("80186").set_callback_function(CpuType_ByName);
03035         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_80186_prefetch").
03036             set_text("80186 with prefetch").set_callback_function(CpuType_ByName);
03037         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_286").
03038             set_text("286").set_callback_function(CpuType_ByName);
03039         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_286_prefetch").
03040             set_text("286 with prefetch").set_callback_function(CpuType_ByName);
03041         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_386").
03042             set_text("386").set_callback_function(CpuType_ByName);
03043         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_386_prefetch").
03044             set_text("386 with prefetch").set_callback_function(CpuType_ByName);
03045         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_486").
03046             set_text("486").set_callback_function(CpuType_ByName);
03047         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_486_prefetch").
03048             set_text("486 with prefetch").set_callback_function(CpuType_ByName);
03049         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_pentium").
03050             set_text("Pentium").set_callback_function(CpuType_ByName);
03051         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_pentium_mmx").
03052             set_text("Pentium MMX").set_callback_function(CpuType_ByName);
03053         mainMenu.alloc_item(DOSBoxMenu::item_type_id,"cputype_ppro_slow").
03054             set_text("Pentium Pro").set_callback_function(CpuType_ByName);
03055 
03056                 Change_Config(configuration);   
03057                 CPU_JMP(false,0,0,0);                                   //Setup the first cpu core
03058         }
03059         bool Change_Config(Section* newconfig){
03060                 Section_prop * section=static_cast<Section_prop *>(newconfig);
03061                 CPU_AutoDetermineMode=CPU_AUTODETERMINE_NONE;
03062                 //CPU_CycleLeft=0;//needed ?
03063                 CPU_Cycles=0;
03064                 CPU_SkipCycleAutoAdjust=false;
03065 
03066                 ignore_opcode_63 = section->Get_bool("ignore opcode 63");
03067                 use_dynamic_core_with_paging = section->Get_bool("use dynamic core with paging on");
03068                 cpu_double_fault_enable = section->Get_bool("double fault");
03069                 cpu_triple_fault_reset = section->Get_bool("reset on triple fault");
03070                 cpu_allow_big16 = section->Get_bool("realbig16");
03071 
03072         if (cpu_allow_big16) {
03073             /* FIXME: GCC 4.8: How is this an empty body? Explain. */
03074             LOG(LOG_CPU,LOG_DEBUG)("Emulation of the B (big) bit in real mode enabled\n");
03075         }
03076 
03077                 always_report_double_fault = section->Get_bool("always report double fault");
03078                 always_report_triple_fault = section->Get_bool("always report triple fault");
03079 
03080                 dynamic_core_cache_block_size = section->Get_int("dynamic core cache block size");
03081                 if (dynamic_core_cache_block_size < 1 || dynamic_core_cache_block_size > 65536) dynamic_core_cache_block_size = 32;
03082 
03083                 Prop_multival* p = section->Get_multival("cycles");
03084                 std::string type = p->GetSection()->Get_string("type");
03085                 std::string str ;
03086                 CommandLine cmd(0,p->GetSection()->Get_string("parameters"));
03087                 if (type=="max") {
03088                         CPU_CycleMax=0;
03089                         CPU_CyclePercUsed=100;
03090                         CPU_CycleAutoAdjust=true;
03091                         CPU_CycleLimit=-1;
03092                         for (Bitu cmdnum=1; cmdnum<=cmd.GetCount(); cmdnum++) {
03093                                 if (cmd.FindCommand(cmdnum,str)) {
03094                                         if (str.find('%')==str.length()-1) {
03095                                                 str.erase(str.find('%'));
03096                                                 int percval=0;
03097                                                 std::istringstream stream(str);
03098                                                 stream >> percval;
03099                                                 if ((percval>0) && (percval<=105)) CPU_CyclePercUsed=(Bit32s)percval;
03100                                         } else if (str=="limit") {
03101                                                 cmdnum++;
03102                                                 if (cmd.FindCommand(cmdnum,str)) {
03103                                                         int cyclimit=0;
03104                                                         std::istringstream stream(str);
03105                                                         stream >> cyclimit;
03106                                                         if (cyclimit>0) CPU_CycleLimit=cyclimit;
03107                                                 }
03108                                         }
03109                                 }
03110                         }
03111                 } else {
03112                         if (type=="auto") {
03113                                 CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CYCLES;
03114                                 CPU_CycleMax=3000;
03115                                 CPU_OldCycleMax=3000;
03116                                 CPU_CyclePercUsed=100;
03117                                 for (Bitu cmdnum=0; cmdnum<=cmd.GetCount(); cmdnum++) {
03118                                         if (cmd.FindCommand(cmdnum,str)) {
03119                                                 if (str.find('%')==str.length()-1) {
03120                                                         str.erase(str.find('%'));
03121                                                         int percval=0;
03122                                                         std::istringstream stream(str);
03123                                                         stream >> percval;
03124                                                         if ((percval>0) && (percval<=105)) CPU_CyclePercUsed=(Bit32s)percval;
03125                                                 } else if (str=="limit") {
03126                                                         cmdnum++;
03127                                                         if (cmd.FindCommand(cmdnum,str)) {
03128                                                                 int cyclimit=0;
03129                                                                 std::istringstream stream(str);
03130                                                                 stream >> cyclimit;
03131                                                                 if (cyclimit>0) CPU_CycleLimit=cyclimit;
03132                                                         }
03133                                                 } else {
03134                                                         int rmdval=0;
03135                                                         std::istringstream stream(str);
03136                                                         stream >> rmdval;
03137                                                         if (rmdval>0) {
03138                                                                 CPU_CycleMax=(Bit32s)rmdval;
03139                                                                 CPU_OldCycleMax=(Bit32s)rmdval;
03140                                                         }
03141                                                 }
03142                                         }
03143                                 }
03144                         } else if(type =="fixed") {
03145                                 cmd.FindCommand(1,str);
03146                                 int rmdval=0;
03147                                 std::istringstream stream(str);
03148                                 stream >> rmdval;
03149                                 CPU_CycleMax=(Bit32s)rmdval;
03150                         } else {
03151                                 std::istringstream stream(type);
03152                                 int rmdval=0;
03153                                 stream >> rmdval;
03154                                 if(rmdval) CPU_CycleMax=(Bit32s)rmdval;
03155                                 if(rmdval) CPU_CyclesSet=(Bit32s)rmdval;
03156                         }
03157                         CPU_CycleAutoAdjust=false;
03158                 }
03159 
03160         menu_update_autocycle();
03161 
03162                 enable_fpu=section->Get_bool("fpu");
03163                 cpu_rep_max=section->Get_int("interruptible rep string op");
03164                 ignore_undefined_msr=section->Get_bool("ignore undefined msr");
03165                 enable_msr=section->Get_bool("enable msr");
03166         enable_cmpxchg8b=section->Get_bool("enable cmpxchg8b");
03167                 CPU_CycleUp=section->Get_int("cycleup");
03168                 CPU_CycleDown=section->Get_int("cycledown");
03169                 std::string core(section->Get_string("core"));
03170                 cpudecoder=&CPU_Core_Normal_Run;
03171                 safe_strncpy(core_mode,core.c_str(),15);
03172                 core_mode[15] = '\0';
03173                 if (core == "normal") {
03174                         cpudecoder=&CPU_Core_Normal_Run;
03175                 } else if (core =="simple") {
03176                         cpudecoder=&CPU_Core_Simple_Run;
03177                 } else if (core == "full") {
03178                         cpudecoder=&CPU_Core_Full_Run;
03179                 } else if (core == "auto") {
03180                         cpudecoder=&CPU_Core_Normal_Run;
03181                         CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CORE;
03182 #if (C_DYNAMIC_X86)
03183                 } else if (core == "dynamic") {
03184                         cpudecoder=&CPU_Core_Dyn_X86_Run;
03185                         CPU_Core_Dyn_X86_SetFPUMode(true);
03186                 } else if (core == "dynamic_nodhfpu") {
03187                         cpudecoder=&CPU_Core_Dyn_X86_Run;
03188                         CPU_Core_Dyn_X86_SetFPUMode(false);
03189 #endif
03190                 } else {
03191                         strcpy(core_mode,"normal");
03192                         cpudecoder=&CPU_Core_Normal_Run;
03193                         LOG_MSG("CPU:Unknown core type %s, switching back to normal.",core.c_str());
03194                 }
03195 
03196 #if (C_DYNAMIC_X86)
03197                 CPU_Core_Dyn_X86_Cache_Init((core == "dynamic") || (core == "dynamic_nodhfpu"));
03198 #endif
03199 
03200                 CPU_ArchitectureType = CPU_ARCHTYPE_MIXED;
03201                 std::string cputype(section->Get_string("cputype"));
03202                 if (cputype == "auto") {
03203                         CPU_ArchitectureType = CPU_ARCHTYPE_MIXED;
03204                 } else if (cputype == "8086") {
03205                         CPU_ArchitectureType = CPU_ARCHTYPE_8086;
03206                         cpudecoder=&CPU_Core8086_Normal_Run;
03207                 } else if (cputype == "8086_prefetch") { /* 6-byte prefetch queue ref [http://www.phatcode.net/res/224/files/html/ch11/11-02.html] */
03208                         CPU_ArchitectureType = CPU_ARCHTYPE_8086;
03209                         if (core == "normal") {
03210                                 cpudecoder=&CPU_Core_Prefetch_Run; /* TODO: Alternate 16-bit only decoder for 286 that does NOT include 386+ instructions */
03211                                 CPU_PrefetchQueueSize = 4; /* Emulate the 8088, which was more common in home PCs than having an 8086 */
03212                         } else if (core == "auto") {
03213                                 cpudecoder=&CPU_Core_Prefetch_Run; /* TODO: Alternate 16-bit only decoder for 286 that does NOT include 386+ instructions */
03214                                 CPU_PrefetchQueueSize = 4; /* Emulate the 8088, which was more common in home PCs than having an 8086 */
03215                                 CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
03216                         } else {
03217                                 E_Exit("prefetch queue emulation requires the normal core setting.");
03218                         }
03219                 } else if (cputype == "80186") {
03220                         CPU_ArchitectureType = CPU_ARCHTYPE_80186;
03221                         cpudecoder=&CPU_Core286_Normal_Run;
03222                 } else if (cputype == "80186_prefetch") { /* 6-byte prefetch queue ref [http://www.phatcode.net/res/224/files/html/ch11/11-02.html] */
03223                         CPU_ArchitectureType = CPU_ARCHTYPE_80186;
03224                         if (core == "normal") {
03225                                 cpudecoder=&CPU_Core_Prefetch_Run; /* TODO: Alternate 16-bit only decoder for 286 that does NOT include 386+ instructions */
03226                                 CPU_PrefetchQueueSize = 6;
03227                         } else if (core == "auto") {
03228                                 cpudecoder=&CPU_Core_Prefetch_Run; /* TODO: Alternate 16-bit only decoder for 286 that does NOT include 386+ instructions */
03229                                 CPU_PrefetchQueueSize = 6;
03230                                 CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
03231                         } else {
03232                                 E_Exit("prefetch queue emulation requires the normal core setting.");
03233                         }
03234                 } else if (cputype == "286") {
03235                         CPU_ArchitectureType = CPU_ARCHTYPE_286;
03236                         cpudecoder=&CPU_Core286_Normal_Run;
03237                 } else if (cputype == "286_prefetch") { /* 6-byte prefetch queue ref [http://www.phatcode.net/res/224/files/html/ch11/11-02.html] */
03238                         CPU_ArchitectureType = CPU_ARCHTYPE_286;
03239                         if (core == "normal") {
03240                                 cpudecoder=&CPU_Core_Prefetch_Run; /* TODO: Alternate 16-bit only decoder for 286 that does NOT include 386+ instructions */
03241                                 CPU_PrefetchQueueSize = 6;
03242                         } else if (core == "auto") {
03243                                 cpudecoder=&CPU_Core_Prefetch_Run; /* TODO: Alternate 16-bit only decoder for 286 that does NOT include 386+ instructions */
03244                                 CPU_PrefetchQueueSize = 6;
03245                                 CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
03246                         } else {
03247                                 E_Exit("prefetch queue emulation requires the normal core setting.");
03248                         }
03249                 } else if (cputype == "386") {
03250                         CPU_ArchitectureType = CPU_ARCHTYPE_386;
03251                 } else if (cputype == "386_prefetch") {
03252                         CPU_ArchitectureType = CPU_ARCHTYPE_386;
03253                         if (core == "normal") {
03254                                 cpudecoder=&CPU_Core_Prefetch_Run;
03255                                 CPU_PrefetchQueueSize = 16;
03256                         } else if (core == "auto") {
03257                                 cpudecoder=&CPU_Core_Prefetch_Run;
03258                                 CPU_PrefetchQueueSize = 16;
03259                                 CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
03260                         } else {
03261                                 E_Exit("prefetch queue emulation requires the normal core setting.");
03262                         }
03263                 } else if (cputype == "486") {
03264                         CPU_ArchitectureType = CPU_ARCHTYPE_486NEW;
03265                 } else if (cputype == "486_prefetch") {
03266                         CPU_ArchitectureType = CPU_ARCHTYPE_486NEW;
03267                         if (core == "normal") {
03268                                 cpudecoder=&CPU_Core_Prefetch_Run;
03269                                 CPU_PrefetchQueueSize = 32;
03270                         } else if (core == "auto") {
03271                                 cpudecoder=&CPU_Core_Prefetch_Run;
03272                                 CPU_PrefetchQueueSize = 32;
03273                                 CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
03274                         } else {
03275                                 E_Exit("prefetch queue emulation requires the normal core setting.");
03276                         }
03277                 } else if (cputype == "pentium") {
03278                         CPU_ArchitectureType = CPU_ARCHTYPE_PENTIUM;
03279                 } else if (cputype == "pentium_mmx") {
03280                         CPU_ArchitectureType = CPU_ARCHTYPE_P55CSLOW;
03281                 } else if (cputype == "ppro_slow") {
03282                         CPU_ArchitectureType = CPU_ARCHTYPE_PPROSLOW;
03283                 }
03284 
03285                 /* WARNING */
03286                 if (CPU_ArchitectureType == CPU_ARCHTYPE_8086) {
03287                         LOG_MSG("CPU warning: 8086 cpu type is experimental at this time");
03288                 }
03289                 else if (CPU_ArchitectureType == CPU_ARCHTYPE_80186) {
03290                         LOG_MSG("CPU warning: 80186 cpu type is experimental at this time");
03291                 }
03292 
03293                 if (CPU_ArchitectureType>=CPU_ARCHTYPE_486NEW) CPU_extflags_toggle=(FLAG_ID|FLAG_AC);
03294                 else if (CPU_ArchitectureType>=CPU_ARCHTYPE_486OLD) CPU_extflags_toggle=(FLAG_AC);
03295                 else CPU_extflags_toggle=0;
03296 
03297     // weitek coprocessor emulation?
03298         if (CPU_ArchitectureType == CPU_ARCHTYPE_386 || CPU_ArchitectureType == CPU_ARCHTYPE_486OLD || CPU_ArchitectureType == CPU_ARCHTYPE_486NEW) {
03299                 Section_prop *dsection = static_cast<Section_prop *>(control->GetSection("dosbox"));
03300 
03301             enable_weitek = dsection->Get_bool("weitek");
03302             if (enable_weitek) {
03303                 LOG_MSG("Weitek coprocessor emulation enabled");
03304 
03305                 static Bitu weitek_lfb = 0xC0000000UL;
03306                 static Bitu weitek_lfb_pages = 0x2000000UL >> 12UL; /* "The coprocessor will respond to memory addresses 0xC0000000-0xC1FFFFFF" */
03307                 static MEM_Callout_t weitek_lfb_cb = MEM_Callout_t_none;
03308 
03309                 if (weitek_lfb_cb == MEM_Callout_t_none) {
03310                     weitek_lfb_cb = MEM_AllocateCallout(MEM_TYPE_MB);
03311                     if (weitek_lfb_cb == MEM_Callout_t_none) E_Exit("Unable to allocate weitek cb for LFB");
03312                 }
03313 
03314                 {
03315                     MEM_CalloutObject *cb = MEM_GetCallout(weitek_lfb_cb);
03316 
03317                     assert(cb != NULL);
03318 
03319                     cb->Uninstall();
03320 
03321                     cb->Install(weitek_lfb>>12UL,MEMMASK_Combine(MEMMASK_FULL,MEMMASK_Range(weitek_lfb_pages)),weitek_memio_cb);
03322 
03323                     MEM_PutCallout(cb);
03324                 }
03325             }
03326         }
03327         else {
03328             enable_weitek = false;
03329         }
03330 
03331                 if (cpu_rep_max < 0) cpu_rep_max = 4;   /* compromise to help emulation speed without too much loss of accuracy */
03332 
03333                 if(CPU_CycleMax <= 0) CPU_CycleMax = 3000;
03334                 if(CPU_CycleUp <= 0)   CPU_CycleUp = 500;
03335                 if(CPU_CycleDown <= 0) CPU_CycleDown = 20;
03336 
03337         if (enable_cmpxchg8b && CPU_ArchitectureType >= CPU_ARCHTYPE_PENTIUM) LOG_MSG("Pentium CMPXCHG8B emulation is enabled");
03338 
03339                 menu_update_core();
03340                 menu_update_cputype();
03341 
03342         void CPU_Core_Prefetch_reset(void);
03343         CPU_Core_Prefetch_reset();
03344 
03345                 if (CPU_CycleAutoAdjust) GFX_SetTitle(CPU_CyclePercUsed,-1,-1,false);
03346                 else GFX_SetTitle(CPU_CycleMax,-1,-1,false);
03347                 return true;
03348         }
03349         ~CPU(){ /* empty */};
03350 };
03351         
03352 static CPU * test;
03353 
03354 void CPU_ShutDown(Section* sec) {
03355     (void)sec;//UNUSED
03356 
03357 #if (C_DYNAMIC_X86)
03358         CPU_Core_Dyn_X86_Cache_Close();
03359 #endif
03360         delete test;
03361 }
03362 
03363 void CPU_OnReset(Section* sec) {
03364     (void)sec;//UNUSED
03365 
03366         LOG(LOG_CPU,LOG_DEBUG)("CPU reset");
03367 
03368         CPU_Snap_Back_To_Real_Mode();
03369         CPU_Snap_Back_Forget();
03370         CPU_SetFlags(0,~0UL);
03371 
03372         Segs.limit[cs]=0xFFFF;
03373         Segs.expanddown[cs]=false;
03374         if (CPU_ArchitectureType >= CPU_ARCHTYPE_386) {
03375                 /* 386 and later start at F000:FFF0 with CS base set to FFFF0000 (really?) */
03376                 SegSet16(cs,0xF000);
03377                 reg_eip=0xFFF0;
03378                 Segs.phys[cs]=0xFFFF0000;
03379         }
03380         else if (CPU_ArchitectureType >= CPU_ARCHTYPE_286) {
03381                 /* 286 start at F000:FFF0 (FFFF0) */
03382                 SegSet16(cs,0xF000);
03383                 reg_eip=0xFFF0;
03384         }
03385         else {
03386                 /* 8086 start at FFFF:0000 (FFFF0) */
03387                 SegSet16(cs,0xFFFF);
03388                 reg_eip=0x0000;
03389         }
03390 }
03391 
03392 void CPU_OnSectionPropChange(Section *x) {
03393         if (test != NULL) test->Change_Config(x);
03394 }
03395 
03396 void CPU_LoadState(Section *sec) {
03397     (void)sec;//UNUSED
03398 
03399     /* STOP THE CPU */
03400         CPU_Cycles = CPU_CycleLeft = 0;
03401 
03402     {
03403         ZIPFileEntry *ent = savestate_zip.get_entry("cpureg.txt");
03404         if (ent != NULL) {
03405             zip_nv_pair_map nv(*ent);
03406             reg_eax =       nv.get_ulong("eax");
03407             reg_ebx =       nv.get_ulong("ebx");
03408             reg_ecx =       nv.get_ulong("ecx");
03409             reg_edx =       nv.get_ulong("edx");
03410             reg_esi =       nv.get_ulong("esi");
03411             reg_edi =       nv.get_ulong("edi");
03412             reg_ebp =       nv.get_ulong("ebp");
03413             reg_esp =       nv.get_ulong("esp");
03414             reg_eip =       nv.get_ulong("eip");
03415             reg_flags =     nv.get_ulong("eflags");
03416 
03417             Segs.val[es] =          nv.get_ulong("es.val");
03418             Segs.phys[es] =         nv.get_ulong("es.phys");
03419             Segs.limit[es] =        nv.get_ulong("es.limit");
03420             Segs.expanddown[es] =   nv.get_bool("es.expanddown");
03421 
03422             Segs.val[cs] =          nv.get_ulong("cs.val");
03423             Segs.phys[cs] =         nv.get_ulong("cs.phys");
03424             Segs.limit[cs] =        nv.get_ulong("cs.limit");
03425             Segs.expanddown[cs] =   nv.get_bool("cs.expanddown");
03426 
03427             Segs.val[ss] =          nv.get_ulong("ss.val");
03428             Segs.phys[ss] =         nv.get_ulong("ss.phys");
03429             Segs.limit[ss] =        nv.get_ulong("ss.limit");
03430             Segs.expanddown[ss] =   nv.get_bool("ss.expanddown");
03431 
03432             Segs.val[ds] =          nv.get_ulong("ds.val");
03433             Segs.phys[ds] =         nv.get_ulong("ds.phys");
03434             Segs.limit[ds] =        nv.get_ulong("ds.limit");
03435             Segs.expanddown[ds] =   nv.get_bool("ds.expanddown");
03436 
03437             Segs.val[fs] =          nv.get_ulong("fs.val");
03438             Segs.phys[fs] =         nv.get_ulong("fs.phys");
03439             Segs.limit[fs] =        nv.get_ulong("fs.limit");
03440             Segs.expanddown[fs] =   nv.get_bool("fs.expanddown");
03441 
03442             Segs.val[gs] =          nv.get_ulong("gs.val");
03443             Segs.phys[gs] =         nv.get_ulong("gs.phys");
03444             Segs.limit[gs] =        nv.get_ulong("gs.limit");
03445             Segs.expanddown[gs] =   nv.get_bool("gs.expanddown");
03446 
03447             /* CPU state includes other variables based on flags, update them */
03448             CPU_SetFlags(reg_flags, FMASK_ALL);
03449         }
03450     }
03451 }
03452 
03453 void CPU_SaveState(Section *sec) {
03454     (void)sec;//UNUSED
03455 
03456     {
03457         ZIPFileEntry *ent = savestate_zip.new_entry("cpureg.txt");
03458         if (ent != NULL) {
03459             zip_nv_write_hex(*ent,"eax",        reg_eax);
03460             zip_nv_write_hex(*ent,"ebx",        reg_ebx);
03461             zip_nv_write_hex(*ent,"ecx",        reg_ecx);
03462             zip_nv_write_hex(*ent,"edx",        reg_edx);
03463             zip_nv_write_hex(*ent,"esi",        reg_esi);
03464             zip_nv_write_hex(*ent,"edi",        reg_edi);
03465             zip_nv_write_hex(*ent,"ebp",        reg_ebp);
03466             zip_nv_write_hex(*ent,"esp",        reg_esp);
03467             zip_nv_write_hex(*ent,"eip",        reg_eip);
03468             zip_nv_write_hex(*ent,"eflags",     reg_flags);
03469 
03470             zip_nv_write_hex(*ent,"es.val",         Segs.val[es]);
03471             zip_nv_write_hex(*ent,"es.phys",        Segs.phys[es]);
03472             zip_nv_write_hex(*ent,"es.limit",       Segs.limit[es]);
03473             zip_nv_write(*ent,"es.expanddown",      Segs.expanddown[es]);
03474 
03475             zip_nv_write_hex(*ent,"cs.val",         Segs.val[cs]);
03476             zip_nv_write_hex(*ent,"cs.phys",        Segs.phys[cs]);
03477             zip_nv_write_hex(*ent,"cs.limit",       Segs.limit[cs]);
03478             zip_nv_write(*ent,"cs.expanddown",      Segs.expanddown[cs]);
03479 
03480             zip_nv_write_hex(*ent,"ss.val",         Segs.val[ss]);
03481             zip_nv_write_hex(*ent,"ss.phys",        Segs.phys[ss]);
03482             zip_nv_write_hex(*ent,"ss.limit",       Segs.limit[ss]);
03483             zip_nv_write(*ent,"ss.expanddown",      Segs.expanddown[ss]);
03484 
03485             zip_nv_write_hex(*ent,"ds.val",         Segs.val[ds]);
03486             zip_nv_write_hex(*ent,"ds.phys",        Segs.phys[ds]);
03487             zip_nv_write_hex(*ent,"ds.limit",       Segs.limit[ds]);
03488             zip_nv_write(*ent,"ds.expanddown",      Segs.expanddown[ds]);
03489 
03490             zip_nv_write_hex(*ent,"fs.val",         Segs.val[fs]);
03491             zip_nv_write_hex(*ent,"fs.phys",        Segs.phys[fs]);
03492             zip_nv_write_hex(*ent,"fs.limit",       Segs.limit[fs]);
03493             zip_nv_write(*ent,"fs.expanddown",      Segs.expanddown[fs]);
03494 
03495             zip_nv_write_hex(*ent,"gs.val",         Segs.val[gs]);
03496             zip_nv_write_hex(*ent,"gs.phys",        Segs.phys[gs]);
03497             zip_nv_write_hex(*ent,"gs.limit",       Segs.limit[gs]);
03498             zip_nv_write(*ent,"gs.expanddown",      Segs.expanddown[gs]);
03499         }
03500     }
03501 }
03502 
03503 void CPU_Init() {
03504         LOG(LOG_MISC,LOG_DEBUG)("Initializing CPU");
03505 
03506         control->GetSection("cpu")->onpropchange.push_back(&CPU_OnSectionPropChange);
03507 
03508         test = new CPU(control->GetSection("cpu"));
03509         AddExitFunction(AddExitFunctionFuncPair(CPU_ShutDown),true);
03510         AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(CPU_OnReset));
03511 
03512     AddVMEventFunction(VM_EVENT_LOAD_STATE,AddVMEventFunctionFuncPair(CPU_LoadState));
03513     AddVMEventFunction(VM_EVENT_SAVE_STATE,AddVMEventFunctionFuncPair(CPU_SaveState));
03514 }
03515 //initialize static members
03516 bool CPU::inited=false;
03517 
03518 
03519 Bit16u CPU_FindDecoderType( CPU_Decoder *decoder )
03520 {
03521     (void)decoder;//UNUSED
03522 
03523         Bit16u decoder_idx;
03524 
03525         decoder_idx = 0xffff;
03526 
03527 
03528         if(0) {}
03529         else if( cpudecoder == &CPU_Core_Normal_Run ) decoder_idx = 0;
03530         else if( cpudecoder == &CPU_Core_Prefetch_Run ) decoder_idx = 1;
03531         else if( cpudecoder == &CPU_Core_Simple_Run ) decoder_idx = 2;
03532         else if( cpudecoder == &CPU_Core_Full_Run ) decoder_idx = 3;
03533 #if C_DYNAMIC_X86
03534         else if( cpudecoder == &CPU_Core_Dyn_X86_Run ) decoder_idx = 4;
03535 #endif
03536         else if( cpudecoder == &CPU_Core_Normal_Trap_Run ) decoder_idx = 100;
03537 #if C_DYNAMIC_X86
03538         else if( cpudecoder == &CPU_Core_Dyn_X86_Trap_Run ) decoder_idx = 101;
03539 #endif
03540         else if( cpudecoder == &HLT_Decode ) decoder_idx = 200;
03541 
03542 
03543         return decoder_idx;
03544 }
03545 
03546 
03547 CPU_Decoder *CPU_IndexDecoderType( Bit16u decoder_idx )
03548 {
03549         CPU_Decoder *cpudecoder;
03550 
03551 
03552         cpudecoder = 0;
03553         switch( decoder_idx ) {
03554                 case 0: cpudecoder = &CPU_Core_Normal_Run; break;
03555                 case 1: cpudecoder = &CPU_Core_Prefetch_Run; break;
03556                 case 2: cpudecoder = &CPU_Core_Simple_Run; break;
03557                 case 3: cpudecoder = &CPU_Core_Full_Run; break;
03558 #if C_DYNAMIC_X86
03559                 case 4: cpudecoder = &CPU_Core_Dyn_X86_Run; break;
03560 #endif
03561                 case 100: cpudecoder = &CPU_Core_Normal_Trap_Run; break;
03562 #if C_DYNAMIC_X86
03563                 case 101: cpudecoder = &CPU_Core_Dyn_X86_Trap_Run; break;
03564 #endif
03565                 case 200: cpudecoder = &HLT_Decode; break;
03566         }
03567 
03568 
03569         return cpudecoder;
03570 }
03571 
03572 Bitu vm86_fake_io_seg = 0xF000; /* unused area in BIOS for IO instruction */
03573 Bitu vm86_fake_io_off = 0x0700;
03574 Bitu vm86_fake_io_offs[3*2]={0};        /* offsets from base off because of dynamic core cache */
03575 
03576 void init_vm86_fake_io() {
03577         Bitu phys = (vm86_fake_io_seg << 4) + vm86_fake_io_off;
03578         Bitu wo = 0;
03579 
03580         if (vm86_fake_io_offs[0] != 0)
03581                 return;
03582 
03583         /* read */
03584         vm86_fake_io_offs[0] = vm86_fake_io_off + wo;
03585         phys_writeb(phys+wo+0x00,(Bit8u)0xEC);  /* IN AL,DX */
03586         phys_writeb(phys+wo+0x01,(Bit8u)0xCB);  /* RETF */
03587         wo += 2;
03588 
03589         vm86_fake_io_offs[1] = vm86_fake_io_off + wo;
03590         phys_writeb(phys+wo+0x00,(Bit8u)0xED);  /* IN AX,DX */
03591         phys_writeb(phys+wo+0x01,(Bit8u)0xCB);  /* RETF */
03592         wo += 2;
03593 
03594         vm86_fake_io_offs[2] = vm86_fake_io_off + wo;
03595         phys_writeb(phys+wo+0x00,(Bit8u)0x66);  /* IN EAX,DX */
03596         phys_writeb(phys+wo+0x01,(Bit8u)0xED);
03597         phys_writeb(phys+wo+0x02,(Bit8u)0xCB);  /* RETF */
03598         wo += 3;
03599 
03600         /* write */
03601         vm86_fake_io_offs[3] = vm86_fake_io_off + wo;
03602         phys_writeb(phys+wo+0x00,(Bit8u)0xEE);  /* OUT DX,AL */
03603         phys_writeb(phys+wo+0x01,(Bit8u)0xCB);  /* RETF */
03604         wo += 2;
03605 
03606         vm86_fake_io_offs[4] = vm86_fake_io_off + wo;
03607         phys_writeb(phys+wo+0x00,(Bit8u)0xEF);  /* OUT DX,AX */
03608         phys_writeb(phys+wo+0x01,(Bit8u)0xCB);  /* RETF */
03609         wo += 2;
03610 
03611         vm86_fake_io_offs[5] = vm86_fake_io_off + wo;
03612         phys_writeb(phys+wo+0x00,(Bit8u)0x66);  /* OUT DX,EAX */
03613         phys_writeb(phys+wo+0x01,(Bit8u)0xEF);
03614         phys_writeb(phys+wo+0x02,(Bit8u)0xCB);  /* RETF */
03615         wo += 3;
03616 }
03617 
03618 Bitu CPU_ForceV86FakeIO_In(Bitu port,Bitu len) {
03619         Bitu old_ax,old_dx,ret;
03620 
03621         /* save EAX:EDX and setup DX for IN instruction */
03622         old_ax = reg_eax;
03623         old_dx = reg_edx;
03624 
03625         reg_edx = port;
03626 
03627         /* make the CPU execute that instruction */
03628         CALLBACK_RunRealFar(vm86_fake_io_seg,vm86_fake_io_offs[(len==4?2:(len-1))+0]);
03629 
03630         /* take whatever the CPU or OS v86 trap left in EAX and return it */
03631         ret = reg_eax;
03632         if (len == 1) ret &= 0xFF;
03633         else if (len == 2) ret &= 0xFFFF;
03634 
03635         /* then restore EAX:EDX */
03636         reg_eax = old_ax;
03637         reg_edx = old_dx;
03638 
03639         return ret;
03640 }
03641 
03642 void CPU_ForceV86FakeIO_Out(Bitu port,Bitu val,Bitu len) {
03643         Bitu old_ax,old_dx;
03644 
03645         /* save EAX:EDX and setup DX/AX for OUT instruction */
03646         old_ax = reg_eax;
03647         old_dx = reg_edx;
03648 
03649         reg_edx = port;
03650         reg_eax = val;
03651 
03652         /* make the CPU execute that instruction */
03653         CALLBACK_RunRealFar(vm86_fake_io_seg,vm86_fake_io_offs[(len==4?2:(len-1))+3]);
03654 
03655         /* then restore EAX:EDX */
03656         reg_eax = old_ax;
03657         reg_edx = old_dx;
03658 }
03659 
03660 /* pentium machine-specific registers */
03661 bool CPU_RDMSR() {
03662         if (!enable_msr) return false;
03663 
03664         switch (reg_ecx) {
03665                 default:
03666                         LOG(LOG_CPU,LOG_NORMAL)("RDMSR: Unknown register 0x%08lx",(unsigned long)reg_ecx);
03667                         break;
03668         }
03669 
03670         if (ignore_undefined_msr) {
03671                 /* wing it and hope nobody notices */
03672                 reg_edx = reg_eax = 0;
03673                 return true;
03674         }
03675 
03676         return false; /* unknown reg, signal illegal opcode */
03677 }
03678 
03679 bool CPU_WRMSR() {
03680         if (!enable_msr) return false;
03681 
03682         switch (reg_ecx) {
03683                 default:
03684                         LOG(LOG_CPU,LOG_NORMAL)("WRMSR: Unknown register 0x%08lx (write 0x%08lx:0x%08lx)",(unsigned long)reg_ecx,(unsigned long)reg_edx,(unsigned long)reg_eax);
03685                         break;
03686         }
03687 
03688         if (ignore_undefined_msr) return true; /* ignore */
03689         return false; /* unknown reg, signal illegal opcode */
03690 }
03691 
03692 /* NTS: Hopefully by implementing this Windows ME can stop randomly crashing when cputype=pentium */
03693 void CPU_CMPXCHG8B(PhysPt eaa) {
03694     uint32_t hi,lo;
03695 
03696     /* NTS: We assume that, if reading doesn't cause a page fault, writing won't either */
03697     hi = (uint32_t)mem_readd(eaa+(PhysPt)4);
03698     lo = (uint32_t)mem_readd(eaa);
03699 
03700     LOG_MSG("Experimental CMPXCHG8B implementation executed. EDX:EAX=0x%08lx%08lx ECX:EBX=0x%08lx%08lx EA=0x%08lx MEM64=0x%08lx%08lx",
03701         (unsigned long)reg_edx,
03702         (unsigned long)reg_eax,
03703         (unsigned long)reg_ecx,
03704         (unsigned long)reg_ebx,
03705         (unsigned long)eaa,
03706         (unsigned long)hi,
03707         (unsigned long)lo);
03708 
03709     /* Compare EDX:EAX with 64-bit DWORD at memaddr 'eaa'.
03710      * if they match, ZF=1 and write ECX:EBX to memaddr 'eaa'.
03711      * else, ZF=0 and load memaddr 'eaa' into EDX:EAX */
03712     if (reg_edx == hi && reg_eax == lo) {
03713         mem_writed(eaa+(PhysPt)4,reg_ecx);
03714         mem_writed(eaa,          reg_ebx);
03715                 SETFLAGBIT(ZF,true);
03716     }
03717     else {
03718                 SETFLAGBIT(ZF,false);
03719         reg_edx = hi;
03720         reg_eax = lo;
03721     }
03722 }
03723