8. The CPU_Intel group of Modules

These files all relate to Intel-x86 specific code.

8.1. Functions in emu-i386/cpu.c

These are the functions defined in emu-i386/cpu.c.

8.1.1. cpu_trap_0f

process opcodes 0F xx xx trapped by GP_fault returns 1 if handled, 0 otherwise Main difference with previous version: bits in our pseudo-control regs can now be written. This should make CPU detection pgms happy.

8.1.2. cpu_setup

Setup initial interrupts which can be revectored so that the kernel does not need to return to DOSEMU if such an interrupt occurs.

8.2. Functions in emu-i386/ports.c

These are the functions defined in emu-i386/ports.c.

8.2.1. port_inb(ioport_t port)

Handles/simulates an inb() port IO read

8.2.2. port_outb(ioport_t port, Bit8u byte)

Handles/simulates an outb() port IO write

8.2.3. port_inw(ioport_t port)

Handles/simulates an inw() port IO read. Usually this invokes port_inb() twice, but it may be necessary to do full word i/o for some video boards.

8.2.4. port_outw(ioport_t port, Bit16u word)

Handles/simulates an outw() port IO write

8.2.5. port_ind(ioport_t port)

Handles/simulates an ind()/outd() port IO read/write.

8.2.6. special_port_inb,special_port_outb

I don't know what to do of this stuff... it was added incrementally to port.c and has mainly to do with video code. This is not the right place for it... Anyway, this implements some HGC stuff for X and the emuretrace port access for 0x3c0/0x3da

8.2.7. port_init()

Resets all the port port_handler information. This must be called before parsing the config file - This must NOT be called again when warm booting! Can't use debug logging, it is called too early.

8.2.8. extra_port_init()

Catch all the special cases previously defined in ports.c mainly video stuff that should be moved away from here This must be called at the end of initialization phase

NOTE: the order in which these inits are done could be significant! I tried to keep it the same it was in ports.c but this code surely can still have bugs

8.2.9. port_register_handler

Assigns a handle in the port table to a range of ports with or without a device, and registers the ports

8.2.10. set_ioperm

wrapper for the ioperm() syscall, returns -1 if not successful.

8.3. Remarks in emu-i386/ports.c

The following port_{in|out}{bwd} functions are the main entry points to the port code. They look into the port_handle_table and call the appropriate code, usually the std_port_ functions, but each device is free to register its own functions which in turn will call std_port or directly access I/O (like video code does), or emulate it - AV


optimized versions for rep - basically we avoid changing privileges and iopl on and off lots of times. We are safe letting iopl=3 here since we don't exit from this code until finished. This code is shared between VM86 and DPMI.


This is the core of the new emuretrace algorithm: If a read of port 0x3da is performed we just set it as pending and set ioperm OFF for port 0x3c0 When a write to port 0x3c0 is then trapped, we perform any pending read to 0x3da and reset the ioperm for 0x3c0 in the default ON state. This way we avoid extra port accesses when the program is only looking for the sync bits, and we don't miss the case where the read to 0x3da is used to reset the index/data flipflop for port 0x3c0. Futher accesses to port 0x3c0 are handled at full speed.


find out whether the port address request is available; this way, try to deny uncoordinated access

If it is not listed in /proc/ioports, register them (we need some syscall to do so bo 960609)... (we have a module to do so AV 970813) if it is registered, we need the name of a device to open if we can't open it, we disallow access to that port


We need to check if our required port range is in use by some device. So we look into proc/ioports to check the addresses. Fine, but at this point we must supply a device name ourselves, and we can't check from here if it's the right one. The device is then open and left open until dosemu ends; for the rest, in the original code the device wasn't used, just locked, and only then port access was granted.

8.4. Items for Fixing in emu-i386/ports.c

This stuff should be moved to video code!!


we should free the name but we are going to exit anyway

8.5. Functions in emu-i386/do_vm86.c

These are the functions defined in emu-i386/do_vm86.c.

8.5.1. vm86_GP_fault

All from the kernel unhandled general protection faults from V86 mode are handled here. This are mainly port IO and the HLT instruction.

8.5.2. run_vm86

Here is where DOSEMU runs VM86 mode with the vm86() call which also has the registers that it will be called with. It will stop vm86 mode for many reasons, like trying to execute an interrupt, doing port I/O to ports not opened for I/O, etc ...

8.5.3. loopstep_run_vm86

Here we collect all stuff, that has to be executed within _one_ pass (step) of a loop containing run_vm86().

8.6. Remarks in emu-i386/do_vm86.c

Here we handle all prefixes prior switching to the appropriate routines The exception CS:EIP will point to the first prefix that effects the faulting instruction, hence, 0x65 0x66 is same as 0x66 0x65. So we collect all prefixes and remember them. - Hans Lermen

8.7. Functions in emu-i386/cputime.c

These are the functions defined in emu-i386/cputime.c.

8.7.1. GETcpuTIME

GETcpuTIME is a pointer to a function which returns the relative CPU time. Different methods of getting the time can then be implemented, currently there are two using gettimeofday() for 486 and TSC for pentium

8.7.2. GETusTIME(sc)

GETusTIME returns the DOS time with 1-usec resolution using GETcpuTIME to get the implementation-dependent CPU time. The 'sc' parameter is unused.

8.7.3. GETtickTIME(sc)

GETtickTIME returns the DOS time with 838ns resolution using GETcpuTIME to get the implementation-dependent CPU time. The 'sc' parameter is unused.

8.7.4. GETusSYSTIME()

GETusSYSTIME returns the real CPU time with 1-usec resolution

8.8. Remarks in emu-i386/cputime.c

At the heart of the timing system in dosemu >= 0.67.11 is the availability of the system time as a 64-bit [type hitimer_t] monoton value. (a 64-bit timer on a 200MHz CPU increments by 2^48 a day).

Dosemu needs this time under two resolutions:

       - a MICROSECOND resolution for general timing purposes
       - a TICK(838ns) resolution for PIT

On non-pentium machines, only the first one is available via the kernel call gettimeofday(). On the pentium and up, the situation is better since we have a cheap hi-res timer on-chip, and worse since this timer runs at a speed depending from the CPU clock (which we need to know/measure, and could be not 100% accurate esp. if the speed is a non-integer multiple of 33.3333).

dosemu >= 0.67.11 can use both timing methods (call them 486 and pentium), and switch between them in a dynamic way when configuring.

At the first level (local to the file cputime.c) there are the RAW timer functions, addressed by RAWcpuTIME(). These get the actual absolute CPU time in usecs.

At the second level, GETcpuTIME() returns the relative, zero-based system time. This is where the 486/pentium switch happens.

The third level is the actual timer interface for dosemu and is made of two functions:

      - GETusTIME(s)   gives the time in usecs
      - GETtickTIME(s) gives the time in ticks

The 's' parameter can be used to control secondary time functions like 'time stretching' (see the READMEs). The function GETusSYSTIME() never activates this stretching, and is used only by the realtime thread-based 1-sec timer in rtc.c.

All timing are RELATIVE to a base. The use of a based time allows us to play more freely with time, e.g. stop and restart it during debugging, stretch it, make it go at different speeds between real-time and CPU emulation, etc. The base has been chosen to be zero, because it will avoid overflows in calculations, produce more readable and more easily comparable debug log files, and also because only int0x1a and BIOS timer require knowledge of the actual time, PIT and PIC are not sensitive.

8.9. Functions in emu-i386/simx86/sigsegv.c

These are the functions defined in emu-i386/simx86/sigsegv.c.

8.9.1. dosemu_fault(int, struct sigcontext_struct);

All CPU exceptions (except 13=general_protection from V86 mode, which is directly scanned by the kernel) are handled here.