| Home | | Developer Releases | | Stable Releases | | Documentation |

Technical README
DANG  - 0.98
Next Previous Contents

8. The CPU_Intel group of Modules

These files all relate to Intel-x86 specific code.

8.1 emu-i386/cpu.c Information

CPU/V86 support for dosemu

8.2 Functions in emu-i386/cpu.c

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


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.


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

8.3 emu-i386/ports.c Information

8.4 Functions in emu-i386/ports.c

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


INB is used to do controlled emulation of input from ports.

Arguments are:

  • port - port to input from.

8.5 emu-i386/do_vm86.c Information

8.6 Functions in emu-i386/do_vm86.c

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


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


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.7 Remarks in emu-i386/do_vm86.c

In a properly functioning emulator :-), sigsegv's will never come while in a non-reentrant system call (ioctl, select, etc). Therefore, there's really no reason to worry about them, so I say that I'm NOT in a signal handler (I might make this a little clearer later, to show that the purpose of in_sighandler is to stop non-reentrant system calls from being reentered. I reiterate: sigsegv's should only happen when I'm running the vm86 system call, so I really shouldn't be in a non-reentrant system call (except maybe vm86) - Robert Sanders


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.8 emu-i386/fake_cpu.c Information

8.9 emu-i386/n_ports.c Information

This is the code that allows and disallows port access within DOSEMU. The BOCHS port IO code was actually very cleverly done. So the idea was stolen from there.

This port I/O code (previously in portss.c, from Scott Bucholz) is based on a table access instead of a switch statement. This method is much more clean and easy to maintain, while not slower than a switch.

Remains of the old code are emerging here and there, they will hopefully be moved back to where they belong, mainly video code.

8.10 Functions in emu-i386/n_ports.c

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

port_inb(ioport_t port)

Handles/simulates an inb() port IO read

port_outb(ioport_t port, Bit8u byte)

Handles/simulates an outb() port IO write

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.

port_outw(ioport_t port, Bit16u word)

Handles/simulates an outw() port IO write

port_ind(ioport_t port)

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


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


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.


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


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



wrapper for the ioperm() syscall, returns -1 if port>=0x400

8.11 Remarks in emu-i386/n_ports.c

 PORT_DEBUG is to specify whether to record port writes to debug output.
   0 means disabled.
   1 means record all port accesses to 0x00 to 0xFF
   2 means record ANY port accesses!  (big fat debugfile!)
   3 means record all port accesses >= 0x100


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.


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.12 Items for Fixing in emu-i386/n_ports.c

This stuff should be moved to video code!!


this code needs to be removed - it collides with vgaemu


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

8.13 emu-i386/cputime.c Information


8.14 Functions in emu-i386/cputime.c

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


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


GETusTIME returns the DOS ('stretched') time with 1-usec resolution using GETcpuTIME to get the implementation-dependent CPU time. The 'sc' parameter controls the granularity of the stretching algorithm (not yet there, see the docs)


GETtickTIME returns the DOS (stretched) time with 838ns resolution using GETcpuTIME to get the implementation-dependent CPU time. The 'sc' parameter works like in GETusTIME.


GETusSYSTIME returns the real CPU time with 1-usec resolution

8.15 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.

Next Previous Contents
The DOSEMU team