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