# The DOSEMU Alterer Novices Guide

Alistair MacDonald, <alistair@slitesys.demon.co.uk>

version dosemu-1.0.0.9

This Document is the DOSEMU Alterer Novices Guide. It is known as the DANG.

## Introduction

This document is the preliminary draft of a manual to help people understand the inner workings of dosemu. It is the goal of this document to create new dosemu hackers. This concept was inspired by the linux kernel hackers guide.

This Guide was concieved and originally written by "Corey Sweeney" <corey@interaccess.com>. It has been completely revised. It is now generated automatically directly from the source code. Special thanks to "James B. MacLean" <macleajb@ednet.ns.ca> for supplying the original information. (It was mostly ripped out of a mail message.) "Jochen Hein" has made many useful comments & suggestions.

At the end if this document is a section detailing how this guide is put together. This may help you when trying to locate the relevant pieces of code. If you add new code, it would be useful if the relevant markers are added where appropriate.

This file is a collective effort. If you don't like one of the explanations, or want to add anything, please send me something!

## The Main group of Modules

These files are used to start DOSEMU as well as hold globally called functions and global vars.

### Functions in dos.c

These are the functions defined in dos.c.

#### dosemu

Arguments are:

- argc - Count of argumnents.

- argc - Actual arguments.

Function created by entry point into libdosemu. Called to jump into the emulate function of DOSEMU.

### Functions in emu.c

These are the functions defined in emu.c.

#### jmp_emulate

call the emulate function by way of the dll headers. Always make sure that this line is the first of emu.c and link emu.o as the first object file to the lib

#### SIG_int

The IRQ numbers to monitor are taken from config.sillyint, each bit corresponding to one IRQ. The higher 16 bit are defining the use of SIGIO

#### emulate

Arguments are:

- argc - Argument count.

- argv - Arguments.

Emulate gets called from dos.c. It initializes DOSEMU to prepare it for running in vm86 mode. This involves catching signals, preparing memory, calling all the initialization functions for the I/O subsystems (video/serial/etc...), getting the boot sector instructions and calling vm86().

### Remarks in emu.c

DOSEMU must not work within the 1 meg DOS limit, so start of code is loaded at a higher address, at some time this could conflict with other shared libs. If DOSEMU is compiled statically (without shared libs), and org instruction is used to provide the jump above 1 meg.

### Functions in include/emu.h

These are the functions defined in include/emu.h.

#### NEWSETQSIG

Arguments are:

- sig - the signal to have a handler installed to.

- fun - the signal handler function to install

All signals that wish to be handled properly in context with the execution of vm86() mode, and signals that wish to use non-reentrant functions should add themselves to the ADDSET_SIGNALS_THAT_QUEUE define and use SETQSIG(). To that end they will also need to be set up in an order such as SIGIO.

### Remarks in include/emu.h

The `vm86_struct` is used to pass all the necessary status/registers to DOSEMU when running in vm86 mode.

-----

We assume system call restarting... under linux 0.99pl8 and earlier, this was the default. SA_RESTART was defined in 0.99pl8 to explicitly request restarting (and thus does nothing). However, if this ever changes, I want to be safe

-----

DOSEMU keeps system wide configuration status in a structure called config.

-----

The var `fatalerr` can be given a true value at any time to have DOSEMU exit on the next return from vm86 mode.

-----

The var 'running_DosC' is set by the DosC kernel and is used to handle some things differently, e.g. the redirector. It interfaces via INTe6,0xDC (DOS_HELPER_DOSC), but only if running_DosC is !=0. At the very startup DosC issues a INTe6,0xdcDC to set running_DosC with the contents of BX (which is the internal DosC version).

## The Init group of Modules

These files are used for initialization and runtime configuration of DOSEMU

### Functions in base/init/init.c

These are the functions defined in base/init/init.c.

#### dosemu_banner

Setup the call stack to draw the dosemu banner

#### stdio_init

Initialize stdio, open debugging output file if user specified one

#### time_setting_init

Beats me

#### timer_interrupt_init

Tells the OS to send us periodic timer messages

#### hardware_setup

Initialize any leftover hardware.

#### map_video_bios

Map the video bios into main memory

#### map_hardware_ram

Initialize the hardware direct-mapped pages

#### map_custom_bios

Setup the dosemu amazing custom BIOS, quietly overwriting anything was copied there before. Do not overwrite graphic fonts!

#### bios_mem_setup

Set up all memory areas as would be present on a typical i86 during the boot phase.

#### memory_init

Set up all memory areas as would be present on a typical i86 during the boot phase.

#### device_init

Calls all initialization routines for devices (keyboard, video, serial, disks, etc.)

#### low_mem_init

Initializes the lower 1Meg via mmap & sets up the HMA region

#### version_init

Find version of OS running and set necessary global parms.

### Items for Fixing in base/init/init.c

config.timer is undocumented and probably obsolete

### Functions in base/init/config.c

These are the functions defined in base/init/config.c.

#### cpu_override

Process user CPU override from the config file ('cpu xxx') or from the command line. Returns the selected CPU identifier or -1 on error. 'config.realcpu' should have already been defined.

#### config_defaults

Set all values in the `config` structure to their default value. These will be modified by the config parser.

#### config_init

This is called to parse the command-line arguments and config files.

#### parse_debugflags

Arguments are:

- s - string of options.

This part is fairly flexible...you specify the debugging flags you wish with -D string. The string consists of the following characters: + turns the following options on (initial state) - turns the following options off a turns all the options on/off, depending on whether +/- is set 0-9 sets debug levels (0 is off, 9 is most verbose) # where # is a letter from the valid option list (see docs), turns that option off/on depending on the +/- state.

Any option letter can occur in any place. Even meaningless combinations, such as "01-a-1+0vk" will be parsed without error, so be careful. Some options are set by default, some are clear. This is subject to my whim. You can ensure which are set by explicitly specifying.

### Remarks in base/init/config.c

For simpler support of X, DOSEMU can be started by a symbolic link called `xdos` which DOSEMU will use to switch into X-mode.

## The DPMI group of Modules

DPMI is Lutz's Baby. It's a really important part of the Emulator as far as we are concerned, since it will allow us to run so many more programs and, most importantly, bcc. This is the one thing that the WINE developers want that we haven't been able to give them.

If you think you can help .... "Away you Go!" (Sorry to those non-UK folks ... Thats a reference to a UK kids sports programme from my youth ... anyway ... enough of this banter. You'll be wanting to know that this is all about DPMI ...)

### Functions in dosext/dpmi/dpmi.c

These are the functions defined in dosext/dpmi/dpmi.c.

#### dpmi_control

This function is similar to the vm86() syscall in the kernel and switches to dpmi code.

#### run_pm_int

This routine is used for running protected mode hardware interrupts and software interrupts 0x1c, 0x23 and 0x24. run_pm_int() switches to the locked protected mode stack and calls the handler. If no handler is installed the real mode interrupt routine is called.

#### do_default_cpu_exception

This is the default CPU exception handler. Exceptions 0, 1, 2, 3, 4, 5 and 7 are reflected to real mode. All other exceptions are terminating the client (and may be dosemu too :-)).

#### do_cpu_exception

This routine switches to the locked protected mode stack, disables interrupts and calls the DPMI client exception handler. If no handler is installed the default handler is called.

#### dpmi_fault

This is the brain of DPMI. All CPU exceptions are first reflected (from the signal handlers) to this code.

Exception from nonprivileged instructions INT XX, STI, CLI, HLT and from WINDOWS 3.1 are handled here.

All here unhandled exceptions are reflected to do_cpu_exception()

### Remarks in dosext/dpmi/dpmi.c

We are caching ldt here for speed reasons and for Windows 3.1. I would love to have an readonly ldt-alias (located in the first 16MByte for use with 16-Bit descriptors (WIN-LDT)). This is on my wish list for the kernel hackers (Linus mainly) :-))))))).

-----

DPMI is designed such that the stack change needs a task switch. We are doing it via an SIGSEGV - instead of one task switch we have now four :-(. Arrgh this is the point where I should start to include DPMI stuff in the kernel, but then we could include the rest of dosemu too. Would Linus love this? I don't :-((((. Anyway I would love to see first a working DPMI port, maybe we will later (with version 0.9 or similar :-)) start with it to get a really fast dos emulator...............

NOTE: Using DIRECT_DPMI_CONTEXT_SWITCH we avoid these 4 taskswitches actually doing 0. We don't need a 'physical' taskswitch (not having different TSS for us and DPMI), we only need a complete register (context) replacement. For back-switching, however, we need the sigcontext technique, so we build a proper sigcontext structure even for 'hand made taskswitch'. (Hans Lermen, June 1996)

dpmi_control is called only from dpmi_run when in_dpmi_dos_int==0

-----

Hopefully the below LAR can serve as a replacement for the KERNEL_LDT, which we are abandoning now. Especially the 'accessed-bit' will get updated in the ldt-cache with the code below. Most DPMI-clients fortunately _are_ using LAR also to get this info, however, some do not. Some of those which do _not_, atleast use the DPMI-GetDescriptor function, so this may solve the problem. (Hans Lermen, July 1996)

-----

Handling of the virtual interrupt flag is still not correct and there are many open questions since DPMI specifications are unclear in this point. An example: If IF=1 in protected mode and real mode code is called which is disabling interrupts via cli and returning to protected mode, is IF then still one or zero? I guess I have to think a lot about this and to write a small dpmi client running under a commercial dpmi server :-).

-----

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

### Items for Fixing in dosext/dpmi/dpmi.c

Should we really care for the Memory info?

-----

We shouldn't return to dosemu code if IF=0, but it helps - WHY? */

-----

we should not change registers for hardware interrupts */

### New Ideas for dosext/dpmi/dpmi.c

Simulate Local Descriptor Table for MS-Windows 3.1 must be read only, so if krnl386.exe/krnl286.exe try to write to this table, we will bomb into sigsegv() and and emulate direct ldt access

### Functions in dosext/dpmi/msdos.h

These are the functions defined in dosext/dpmi/msdos.h.

#### msdos_pre_extender

This function is called before a protected mode client goes to real mode for DOS service. All protected mode selector is changed to real mode segment register. And if client\'s data buffer is above 1MB, necessary buffer copying is performed. This function returns 1 if it does not need to go to real mode, otherwise returns 0.

#### msdos_post_extender

This function is called after return from real mode DOS service All real mode segment registers are changed to protected mode selectors And if client\'s data buffer is above 1MB, necessary buffer copying is performed.

## The Video group of Modules

All of the Video handling code is in the "video" subdirectory.

There is one file for each video card or chipset and the master file. To Add a new card, it needs a set of save & restore routines putting in a file here.

### Functions in env/video/video.c

These are the functions defined in env/video/video.c.

#### video_init

Set pointer to correct structure of functions to initialize, close, etc... video routines.

### Remarks in env/video/video.c

Here the sleeping lion will be awoken and eat much of CPU time !!!

The result of setting VM86_SCREEN_BITMAP (at state of Linux 1.1.56): Each vm86 call will set 32 pages of video mem RD-only (there may be 1000000 per second) Write access to RD-only page results in page-fault (mm/memory.c), which will set a bit in current->screen_bitmap and calls do_wp_page() which does __get_free_page(GFP_KERNEL) but frees it immediatly, because copy-on-write is not neccessary and sets RD/WR for the page. (this could happen 32000000 per second, if the CPU were fast enough) It would be better to get the DIRTY-bit directly from the page table, isn't it? A special syscall in emumodule could do this.

-----

reserve_video_memory()

This procedure is trying to eke out all the UMB blocks possible to maximize your memory under DOSEMU. If you know about dual monitor setups, you can contribute by putting in the correct graphics page address values.

### Functions in env/video/X.c

These are the functions defined in env/video/X.c.

#### X_close

Initialize everything X-related.

#### X_close

Destroy the window, unload font, pixmap and colormap.

#### X_shm_init

Check availability of the MIT-SHM shared memory extension.

#### X_shm_init

Turn off usage of the MIT-SHM shared memory extension.

#### X_set_mouse_cursor

called by mouse.c to hide/display the mouse and set it's position. This is currently the only callback from mouse.c to X.

#### X_handle_events

Handle pending X events (called from SIGALRM handler).

#### graphics_cmap_init

Allocate a colormap for graphics modes and initialize it. Do mostly nothing on true color displays. Otherwise, do: - if colormaps have less than 256 entries (notably 16 or 2 colors), don't use a private colormap - if a shared map is requested and there are less than 36 colors (3/4/3) available, use a private colormap

Note: Text modes always use the screen's default colormap.

#### X_set_videomode

This is the interface function called by the video subsystem to set a video mode.

NOTE: The actual mode is taken from the global variable "video_mode".

#### X_setmode

Set the video mode. If init_vga is zero, this will only reinitialize the current mode. The other arguments are ignored in this case.

#### X_update_screen

Update the part of the screen which has changed, in text mode and in graphics mode. Usually called from the SIGALRM handler.

X_update_screen returns 0 if nothing was updated, 1 if the whole screen was updated, and 2 for a partial update.

It is called in arch/linux/async/signal.c::SIGALRM_call() as part of a struct video_system (see top of X.c) every 50 ms or every 10 ms if 2 was returned, depending somewhat on various config options as e.g. config.X_updatefreq and VIDEO_CHECK_DIRTY. At least it is supposed to do that.

#### set_mouse_position

Place the mouse on the right position.

### Remarks in env/video/X.c

DO NOT REMOVE THIS TEST!!! It is magic, without it EMS fails on my machine under X. Perhaps someday when we don't use a buggy /proc/self/mem.. -- EB 18 May 1998 A slightly further look says it's not the test so much as suppressing noop resize events... -- EB 1 June 1998

### Functions in env/video/vgaemu.c

These are the functions defined in env/video/vgaemu.c.

#### VGA_emulate_outb

Emulates writes to VGA ports. This is a hardware emulation function.

Arguments are:

- port - The port being written to.

- value - The value written,

#### VGA_emulate_inb

Emulates reads from VGA ports. This is a hardware emulation function.

Arguments are:

- port - The port being read from.

#### vga_emu_fault

vga_emu_fault() is used to catch video access, and handle it. This function is called from arch/linux/async/sigsegv.c::dosemu_fault1(). The sigcontext_struct is defined in include/cpu.h. Now it catches only changes in a 4K page, but maybe it is useful to catch each video access. The problem when you do that is, you have to simulate each instruction which could write to the video memory. It is easy to get the place where the exception happens (scp->cr2), but what are those changes? An other problem is, it could eat a lot of time, but it does now also.

MODIFICATION: VGA mode 12h under X is supported in exactly the way that was suggested above. Not every instruction needs to be simulated in order to make this feature useful, just the ones used to access video RAM by key applications (Borland BGI, Protel, etc.).

MODIFICATION: all VGA modes now work and almost all instructions are simulated.

Arguments are:

- scp - A pointer to a struct sigcontext_struct holding some relevant data.

#### vga_emu_init

vga_emu_init() must be called before using the VGAEmu functions. It is only called from env/video/X.c::X_init() at the moment. This function basically initializes the global variable `vga' and allocates the VGA memory.

It does in particular *not* map any memory into the range 0xa0000 - 0xc0000, this is done as part of a VGA mode switch.

There should be an accompanying vga_emu_done().

Arguments are:

- vedt - Pointer to struct describing the type of display we are actually

- attached to.

#### vga_emu_update

vga_emu_update() scans the VGA memory for dirty (= written to since last update) pages and returns the changed area in *veut. See the definition of vga_emu_update_type in env/video/vgaemu_inside.h for details.

You will need to call this function repeatedly until it returns 0 to grab all changes. You can specify an upper limit for the size of the area that will be returned using `veut->max_max_len' and `veut->max_len'. See the example in env/video/X.c how this works.

If the return value of vga_emu_update() is >= 0, it is the number of changed pages, -1 means there are still changed pages but the maximum update chunk size (`veut->max_max_len') was exceeded.

This function does in its current form not work for Hercules modes; it does, however work for text modes, although this feature is currently not used.

Arguments are:

- veut - A pointer to a vga_emu_update_type object holding all relevant info.

#### vgaemu_switch_plane

vgaemu_switch_plane() maps the specified plane.

This function returns True on success and False on error, usually indicating an invalid bank number.

Arguments are:

- plane (0..3) - The plane to map.

#### vga_emu_switch_bank

vga_emu_switch_bank() is used to emulate video-bankswitching.

This function returns True on success and False on error, usually indicating an invalid bank number.

Arguments are:

- bank - The bank to switch to.

#### vga_emu_find_mode

Searches a video mode with the requested mode number.

The search starts with the mode *after* the mode `vmi' points to. If `vmi' == NULL, starts at the beginning of the internal mode table. `mode' may be a standard VGA mode number (0 ... 0x7f) or a VESA mode number (>= 0x100). The mode number may have its don't-clear-bit (bit 7 or bit 15) or its use-lfb-bit (bit 14) set. The special mode number -1 will match any mode and may be used to scan through the whole table.

Returns NULL if no mode was found and a pointer into the mode table otherwise. The returned pointer is a suitable argument for subsequent calls to this function.

You should (and can) access the mode table only through this function.

Arguments are:

- mode - video mode.

- vmi - pointer into internal mode list

#### vga_emu_setmode

Set a video mode.

Switches to `mode' with text sizes `width' and `height' or (if no such mode was found) at least `width' and `height'.

Arguments are:

- mode - The new video mode.

- width - Number of text columns.

- height - Number of text rows.

#### vga_emu_set_textsize

Sets the text mode resolution. Typically called after a font change.

Arguments are:

- width - Number of text columns.

- height - Number of text rows.

#### dirty_all_video_pages

Marks the whole VGA memory as modified.

#### vga_emu_set_text_page

Set visible text page.

`vga.display_start' is set to `page' * `page_size'. This function works only in text modes.

Arguments are:

- page - Number of the text page.

- page_size - Size of one text page.

#### dirty_all_vga_colors

Marks all colors as changed.

#### changed_vga_colors

Checks DAC and Attribute Controller to find all colors with changed RGB-values. Returns number of changed colors. Note: the list _must_ be large enough, that is, have at least min(256, (1 << vga.pixel_size)) entries!

Arguments are:

- de - list of DAC entries to store changed colors in

#### vgaemu_adj_cfg

Adjust VGAEmu according to VGA register changes.

### Functions in env/video/vesa.c

These are the functions defined in env/video/vesa.c.

#### vbe_init

Initializes the VGA/VBE BIOS and the VBE support.

Arguments are:

- vedt - Pointer to struct describing the type of display we are actually

- attached to.

#### do_vesa_int

This is the VESA interrupt handler.

It is called from base/bios/int10.c::int10(). The VESA interrupt is called with 0x4f in AH and the function number (0x00 ... 0x10) in AL.

### Functions in env/video/attremu.c

These are the functions defined in env/video/attremu.c.

#### Attr_init

Initializes the attribute controller. This is an interface function.

#### Attr_get_entry

Directly reads the Attribute Controller's registers. This is an interface function.

#### Attr_set_entry

Directly sets the Attribute Controller's registers. This is an interface function.

#### Attr_read_value

Emulates reads from the attribute controller. This is a hardware emulation function.

#### Attr_write_value

Emulates writes to attribute controller combined index and data register. Read VGADOC for details. This is a hardware emulation function.

#### Attr_get_index

Returns the current index of the attribute controller. This is a hardware emulation function, though in fact this function is undefined in a real attribute controller. Well, it is exactly what my VGA board (S3) does. -- sw This is a hardware emulation function.

### Functions in env/video/dacemu.c

These are the functions defined in env/video/dacemu.c.

#### DAC_init

Initializes the DAC. It depends on a correct value in vga.pixel_size. This function should be called during VGA mode initialization. This is an interface function.

#### DAC_set_width

Sets the DAC width. Typical values are 6 or 8 bits. In theory, we support other values as well (untested). This is an interface function.

#### DAC_get_entry

Returns a complete DAC entry (r, g, b). Don't forget to set DAC_entry.index first! This is an interface function.

#### DAC_set_entry

Sets a complete DAC entry (r,g,b). This is an interface function.

#### DAC_rgb2gray

Converts a DAC register's RGB values to gray scale. This is an interface function.

#### DAC_set_read_index

Specifies which palette entry is read. This is a hardware emulation function.

#### DAC_set_write_index

Specifies which palette entry is written. This is a hardware emulation function.

#### DAC_read_value

Read a value from the DAC. Each read will cycle through the registers for red, green and blue. After a ``blue read'' the read index will be incremented. Read VGADOC4 if you want to know more about the DAC. This is a hardware emulation function.

#### DAC_write_value

Write a value to the DAC. Each write will cycle through the registers for red, green and blue. After a ``blue write'' the write index will be incremented. This is a hardware emulation function.

#### DAC_get_pel_mask

Returns the current PEL mask. Note that changed_vga_colors() already applies the PEL mask; so applications should not worry too much about it. This is a hardware emulation function.

#### DAC_set_pel_mask

Sets the PEL mask and marks all DAC entries as dirty. This is a hardware emulation function.

#### DAC_get_state

Returns the current state of the DAC. This is a hardware emulation function.

### Functions in env/video/crtcemu.c

These are the functions defined in env/video/crtcemu.c.

#### CRTC_init

Initializes the CRT Controller. This is an interface function.

### Functions in env/video/dualmon.c

These are the functions defined in env/video/dualmon.c.

#### MDA_init

Initializes the monochrome card. First detects which monochrome card is used, because the Hercules RamFont and the Hercules InColor need one more register to be initialized. If there is no monochrome card at all, we just think there is one and poke an peek in the void. After the detection the card is initialized.

returns: nothing

Arguments are:

- none

### Remarks in env/video/dualmon.c

After MDA_init() the VGA is configured, something in video.c or console.c "reprograms" the monochrome card again in such a way that I always have to run hgc.com before I can use any program that uses the monochrome card. I've spent a day trying to find it, but I can't figure out. Something is writing to one of the following ports: 0x3b4, 0x3b5, 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bf. The problem occurs at (at least) the following 2 systems:

- AMD 386DX40, Trident 9000/512Kb ISA, Hercules Graphics Card Plus - Intel 486DX2/66, Cirrus Logic 5426/1Mb VLB, Hercules clone

The problem doesn't occur when I start dosemu from a telnet connection or from a VT100 terminal. (Erik Mouw, jakmouw@et.tudelft.nl)

### Functions in env/video/vgaemu.c

These are the functions defined in env/video/vgaemu.c.

#### VGA_emulate_outb

Emulates writes to VGA ports. This is a hardware emulation function.

Arguments are:

- port - The port being written to.

- value - The value written,

#### VGA_emulate_inb

Emulates reads from VGA ports. This is a hardware emulation function.

Arguments are:

- port - The port being read from.

#### vga_emu_fault

vga_emu_fault() is used to catch video access, and handle it. This function is called from arch/linux/async/sigsegv.c::dosemu_fault1(). The sigcontext_struct is defined in include/cpu.h. Now it catches only changes in a 4K page, but maybe it is useful to catch each video access. The problem when you do that is, you have to simulate each instruction which could write to the video memory. It is easy to get the place where the exception happens (scp->cr2), but what are those changes? An other problem is, it could eat a lot of time, but it does now also.

MODIFICATION: VGA mode 12h under X is supported in exactly the way that was suggested above. Not every instruction needs to be simulated in order to make this feature useful, just the ones used to access video RAM by key applications (Borland BGI, Protel, etc.).

MODIFICATION: all VGA modes now work and almost all instructions are simulated.

Arguments are:

- scp - A pointer to a struct sigcontext_struct holding some relevant data.

#### vga_emu_init

vga_emu_init() must be called before using the VGAEmu functions. It is only called from env/video/X.c::X_init() at the moment. This function basically initializes the global variable `vga' and allocates the VGA memory.

It does in particular *not* map any memory into the range 0xa0000 - 0xc0000, this is done as part of a VGA mode switch.

There should be an accompanying vga_emu_done().

Arguments are:

- vedt - Pointer to struct describing the type of display we are actually

- attached to.

#### vga_emu_update

vga_emu_update() scans the VGA memory for dirty (= written to since last update) pages and returns the changed area in *veut. See the definition of vga_emu_update_type in env/video/vgaemu_inside.h for details.

You will need to call this function repeatedly until it returns 0 to grab all changes. You can specify an upper limit for the size of the area that will be returned using `veut->max_max_len' and `veut->max_len'. See the example in env/video/X.c how this works.

If the return value of vga_emu_update() is >= 0, it is the number of changed pages, -1 means there are still changed pages but the maximum update chunk size (`veut->max_max_len') was exceeded.

This function does in its current form not work for Hercules modes; it does, however work for text modes, although this feature is currently not used.

Arguments are:

- veut - A pointer to a vga_emu_update_type object holding all relevant info.

#### vgaemu_switch_plane

vgaemu_switch_plane() maps the specified plane.

This function returns True on success and False on error, usually indicating an invalid bank number.

Arguments are:

- plane (0..3) - The plane to map.

#### vga_emu_switch_bank

vga_emu_switch_bank() is used to emulate video-bankswitching.

This function returns True on success and False on error, usually indicating an invalid bank number.

Arguments are:

- bank - The bank to switch to.

#### vga_emu_find_mode

Searches a video mode with the requested mode number.

The search starts with the mode *after* the mode `vmi' points to. If `vmi' == NULL, starts at the beginning of the internal mode table. `mode' may be a standard VGA mode number (0 ... 0x7f) or a VESA mode number (>= 0x100). The mode number may have its don't-clear-bit (bit 7 or bit 15) or its use-lfb-bit (bit 14) set. The special mode number -1 will match any mode and may be used to scan through the whole table.

Returns NULL if no mode was found and a pointer into the mode table otherwise. The returned pointer is a suitable argument for subsequent calls to this function.

You should (and can) access the mode table only through this function.

Arguments are:

- mode - video mode.

- vmi - pointer into internal mode list

#### vga_emu_setmode

Set a video mode.

Switches to `mode' with text sizes `width' and `height' or (if no such mode was found) at least `width' and `height'.

Arguments are:

- mode - The new video mode.

- width - Number of text columns.

- height - Number of text rows.

#### vga_emu_set_textsize

Sets the text mode resolution. Typically called after a font change.

Arguments are:

- width - Number of text columns.

- height - Number of text rows.

#### dirty_all_video_pages

Marks the whole VGA memory as modified.

#### vga_emu_set_text_page

Set visible text page.

`vga.display_start' is set to `page' * `page_size'. This function works only in text modes.

Arguments are:

- page - Number of the text page.

- page_size - Size of one text page.

#### dirty_all_vga_colors

Marks all colors as changed.

#### changed_vga_colors

Checks DAC and Attribute Controller to find all colors with changed RGB-values. Returns number of changed colors. Note: the list _must_ be large enough, that is, have at least min(256, (1 << vga.pixel_size)) entries!

Arguments are:

- de - list of DAC entries to store changed colors in

#### vgaemu_adj_cfg

Adjust VGAEmu according to VGA register changes.

### Functions in env/video/instremu.c

These are the functions defined in env/video/instremu.c.

#### instr_len

Returns the length of an instruction; 0 if it could not be determined.

#### instr_sim

instr_sim is used to simulate instructions that access the VGA video memory in planar modes when using X as the video output device.

It is necessary to do this in order to simulate the effects of the hardware VGA controller in X mode.

If the return value is 0, it means the instruction was not one that for which a simulation is provided. The return value is 1 for success, but the function exits because we need to go back to the DOSEMU's main loop or count runs out.

Arguments are:

- x86: the structure holding everything about the cpu-state we need.

#### instr_emu

instr_emu is the main interface to instr_sim. It puts the processor state in the x86 structure.

Arguments are:

- scp - A pointer to a struct sigcontext_struct holding some relevant data.

- cp - A pointer to the instruction to be simulated

## The Keyboard group of Modules

All of the Keyboard handling code is in the "keyboard" subdirectory.

Latest addition is SLANG.

### Remarks in base/keyboard/keymaps.c

The DEAD codes must refer to keys that don't exist on any language keyboard. I hope nobody has a smily face key :-) dead_key_table is a list of the dead keys supported. They must be placed on the correct key in the keymaps above. See key_map_es_latin1.

-----

dos850_dead_map consists of the triple, {deadkey, letter, result}. It should be correct for all the code page 850 users (Western Europe). If you uses a different code page, please create a map! Jon Tombs jon@gtex02.us.es

### Functions in base/keyboard/serv_xlat.c

These are the functions defined in base/keyboard/serv_xlat.c.

#### putrawkey

This function sends a raw keycode byte, e.g. read directly from the hardware, to DOS. It is both queued for the port60h emulation and processed for the BIOS keyboard buffer, using the national translation tables etc.

For DOS applications using int16h we will therefore not have to load KEYB.EXE, others (e.g. games) need their own drivers anyway.

This function is used if we are at the console and config.rawkeyboard=on.

#### putkey

This does all the work of sending a key event to DOS. scan - the keycode, one of the KEY_ constants from new-kbd.h make - TRUE for key press, FALSE for release ascii - the key's ascii value, or 0 for none.

Applications using int16h will always see the ASCII code passed here independently of the scancode, so no character translation needs/should be done. As DOS expects characters in IBM Extended ASCII, the keyboard clients may have to do ISO->IBM character translation or similar!

An emulated hardware scancode is also sent to port60h.

Note that you have to send both MAKE (press) and BREAK (release) events. If no BREAK codes are available (e.g. terminal mode), send them immediately after the MAKE codes. Also, shift keys should be sent (with ascii = 0).

#### set_shiftstate

This simply sets the keyboard server's shift state.

USE WITH CAUTION: this changes the keyboard flags without generating the appropriate shift key make/break codes that normally come along with such changes. This function is mostly intended for start-up shiftstate synchronisation.

Note also that you can't simply write to the shiftstate variable instead of using this function.

### Functions in base/keyboard/keyb_raw.c

These are the functions defined in base/keyboard/keyb_raw.c.

#### raw_keyboard_init

Initialize the keyboard for RAW mode.

### Functions in base/keyboard/keyb_slang.c

These are the functions defined in base/keyboard/keyb_slang.c.

#### slang_keyb_init()

Code is called at start up to set up the terminal line for non-raw mode.

## The Misc group of Modules

These are the remaining important files, that do not really fit into another group. These should not be dismissed as unimportant - rather, they are often amongst the most important.

### Functions in base/async/int.c

These are the functions defined in base/async/int.c.

#### DEFAULT_INTERRUPT

DEFAULT_INTERRUPT is the default interrupt service routine called when DOSEMU initializes.

#### ms_dos

int0x21 call

we trap this for two functions: simulating the EMMXXXX0 device and fudging the CONFIG.XXX and AUTOEXEC.XXX bootup files.

note that the emulation herein may cause problems with programs that like to take control of certain int 21h functions, or that change functions that the true int 21h functions use. An example of the latter is ANSI.SYS, which changes int 10h, and int 21h uses int 10h. for the moment, ANSI.SYS won't work anyway, so it's no problem.

#### run_caller_func(i, from_int)

This function runs the specified caller function in response to an int instruction. Where i is the interrupt function to execute and from_int specifies if we are comming directly from an int instruction.

This function runs the instruction with the following model _CS:_IP is the address to start executing at after the caller function terminates, and _EFLAGS are the flags to use after termination. For the simple case of an int instruction this is easy. _CS:_IP = retCS:retIP and _FLAGS = retFLAGS as well equally the current values (retIP = curIP +2 technically).

However if the function is called (from dos) by simulating an int instruction (something that is common with chained interrupt vectors) _CS:_IP = BIOS_SEG:HLT_OFF(i) and _FLAGS = curFLAGS while retCS, retIP, and retFlags are on the stack. These I pop and place in the appropriate registers.

This functions actions certainly correct for functions executing an int/iret discipline. And almost certianly correct for functions executing an int/retf#2 discipline (with flag changes), as an iret is always possilbe. However functions like dos int 0x25 and 0x26 executing with a int/retf will not be handled correctlty by this function and if you need to handle them inside dosemu use a halt handler instead.

Finally there is a possible trouble spot lurking in this code. Interrupts are only implicitly disabled when it calls the caller function, so if for some reason the main loop would be entered before the caller function returns wrong code may execute if the retFLAGS have interrupts enabled!

This is only a real handicap for sequences of dosemu code execute for long periods of time as we try to improve timer response and prevent signal queue overflows! -- EB 10 March 1997

Grumble do to code that executes before interrupts, and the semantics of default_interupt, I can't implement this function as I would like. In the tricky case of being called from dos by simulating an int instruction, I must leave retCS, retIP, on the stack. But I can safely read retFlags so I do. I pop retCS, and retIP just before returning to dos, as well as dropping the stack slot that held retFlags.

This improves consistency of interrupt handling, but not quite as much as if I could handle it the way I would like. -- EB 30 Nov 1997

#### DO_INT

DO_INT is used to deal with interrupts returned to DOSEMU by the kernel.

#### setup_interrupts

SETUP_INTERRUPTS is used to initialize the interrupt_function array which directs handling of interrupts in protected mode and also initializes the base vector for interrupts in real mode.

#### int_vector_setup

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

### Remarks in base/async/int.c

Some video BIOSes need access to the PIT timer 2, and some (e.g. Matrox) directly read the timer output on port 0x61. If we don't allow video port access, this will be totally emulated; else, we give temporary access to the needed ports (timer at 0x42, timer config at 0x43 and timer out/speaker at 0x61), provided they were not previously enabled by SPKR_NATIVE - AV

-----

Many video BIOSes use hi interrupt vector locations as scratchpad area - this is because they come before DOS and feel safe to do it. But we are initializing vectors before video, so this only causes trouble. I assume no video BIOS will ever: - change vectors < 0xe0 (0:380-0:3ff area) - change anything in the vector area _after_ installation - AV

### Functions in arch/linux/async/sigsegv.c

These are the functions defined in arch/linux/async/sigsegv.c.

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

#### print_exception_info

Prints information about an exception: exception number, error code, address, reason, etc.

### Functions in arch/linux/async/signal.c

These are the functions defined in arch/linux/async/signal.c.

#### signal_init

Initialize the signals to have NONE being blocked. Currently this is NOT of much use to DOSEMU.

#### cli

Stop additional signals from interrupting DOSEMU.

#### sti

Allow all signals to interrupt DOSEMU.

#### handle_signals

Due to signals happening at any time, the actual work to be done because a signal occurs is done here in a serial fashion.

The concept, should this eventualy work, is that a signal should only flag that it has occurred and let DOSEMU deal with it in an orderly fashion as it executes the rest of it's code.

#### SIGNAL_save

Arguments are:

- context - signal context to save.

- signal_call - signal handling routine to be called.

Save into an array structure queue the signal context of the current signal as well as the function to call for dealing with this signal. This is a queue because any signal may occur multiple times before DOSEMU deals with it down the road.

#### SIGIO_call

Whenever I/O occurs on devices allowing SIGIO to occur, DOSEMU will be flagged to run this call which inturn checks which fd(s) was set and execute the proper routine to get the I/O from that device.

### Remarks in arch/linux/async/signal.c

Check for keyboard coming from client For now, first byte is interrupt requests from Client

### Functions in base/misc/disks.c

These are the functions defined in base/misc/disks.c.

#### disk_init

Test by opening all floppies/hardrives configured.

### Functions in base/dev/misc/timers.c

These are the functions defined in base/dev/misc/timers.c.

#### initialize_timers

ensure the 0x40 port timer is initially set correctly

#### timer_tick

Every time we get a TIMER signal from Linux, this procedure is called. It checks to see if we should queue a timer interrupt based on the current values.

#### do_sound

do_sound handles the _emulated_ mode pc-speaker emulation.

As far as I can determine all cases of the pc-speaker are now emulated. But I am not sure where Rainer Zimmerman got his (pit[2].mode == 2) || (pit[2].mode == 3) test in the original implementation, it doesn't seem to cause problems though.

The implementation of speaker_on & speaker_off can be found in src/base/speaker.c

Major Changes from version written by Rainter Zimmerman.

o Added support for programs that control the directly through bit 1 of port61.

o Added a generic interface to allow multiple speaker backends.

o Implemented X speaker code so the emulated speaker now works in X.

--EB 21 September 1997

#### timer_int_engine

This is experimental TIMER-IRQ CHAIN code! This is a function to determine whether it is time to invoke a new timer irq 0 event. Normally it is 18 times a second, but many video games set it to 100 times per second or more. Since the kernel cannot keep an accurate timer interrupt, the job of this routine is to perform a chained timer irq 0 right after the previous timer irq 0. This routine should, ideally, be called right after the end of a timer irq, if possible.

This would speed up high frequency timer interrupts if this code can be converted into an assembly macro equivalent!

PLEASE NOTE

This code has been replaced by interrupt scheduling code in pic. The result is that we simply call pic_sched and run the dos interrupt. If the new code causes no problems, I'll revise this section permanently.

### Functions in base/misc/shared.c

These are the functions defined in base/misc/shared.c.

#### shared_qf_memory_init

Setup all memory areas to be shared with clients.

### Remarks in base/misc/shared.c

Output info required for client activity (NOTE: 'client activity' as of 2000/02/02 totally disabled, but left file structure compatible, --Hans)

### Functions in base/misc/dos2linux.c

These are the functions defined in base/misc/dos2linux.c.

#### run_unix_command

Runs a command and prints the (stdout and stderr) output on the dosemu screen.

Return values mean:

Arguments are:

- buffer - string with command to execute

### Functions in base/misc/ioctl.c

These are the functions defined in base/misc/ioctl.c.

#### io_select_init

Initialize fd_sets to NULL for both SIGIO and NON-SIGIO.

#### add_to_io_select

Arguments are:

- fd - File handle to add to select statment

- want_sigio - want SIGIO (1) if it's available, or not (0).

Add file handle to one of 2 select FDS_SET's depending on whether the kernel can handle SIGIO.

#### remove_from_io_select

Arguments are:

- fd - File handle to remove from select statment.

- used_sigio - used SIGIO (1) if it's available, or not (0).

Remove a file handle from one of 2 select FDS_SET's depending on whether the kernel can handle SIGIO.

### Functions in base/dev/misc/lpt.c

These are the functions defined in base/dev/misc/lpt.c.

#### printer_init

Initialize printer control structures

### Functions in base/dev/misc/pci.c

These are the functions defined in base/dev/misc/pci.c.

#### pci_read_header

Use standard 32-bit (type 1) access method to read PCI configuration space data

#### pci_read_header

32-bit I/O port output on PCI ports (0xcf8=addr,0xcfc=data) Optimization: trap the config writes (outd 0xcf8 with bit31=1). Since this kind of access is always followed by another R/W access to port 0xcfc, we can just set it as pending and merge it with the following operation, saving two calls to priv_iopl().

#### pci_read_header

Register standard PCI ports 0xcf8-0xcff

### Remarks in include/doshelpers.h

The Helper Interrupt uses the following groups:

0x00 - Check for DOSEMU 0x01-0x11 - Initialisation functions & Debugging 0x12 - Set hogthreshold (aka garrot?) 0x20 - MFS functions 0x21-0x22 - EMS functions 0x28 - Garrot Functions for use with the mouse 0x29 - Serial functions 0x30 - Whether to use the BOOTDISK predicate 0x33 - Mouse Functions 0x40 - CD-ROM functions 0x50-0x5f - DOSEMU/Linux communications 50 -- run unix command in ES:DX 51,52? 53 -- do system(ES:DX) 54 -- get CPU speed 55 -- get terminal type 0x60-0x6f - reserved for plug-ins 0x7a - IPX functions 0x8x -- utility functions 0x80 -- getcwd(ES:DX, size AX) 0x81 -- chdir(ES:DX) 0xdc - helper for DosC kernel 0xfe - called from our MBR, emulate MBR-code. 0xff - Terminate DOSEMU

There are (as yet) no guidelines on choosing areas for new functions.

## The CPU_Intel group of Modules

These files all relate to Intel-x86 specific code.

### Functions in emu-i386/cpu.c

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

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

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

### Functions in emu-i386/ports.c

These are the functions defined in emu-i386/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.

#### 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

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

#### 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

#### port_register_handler

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

#### set_ioperm

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

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

### Items for Fixing in emu-i386/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

### Functions in emu-i386/do_vm86.c

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

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

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

### 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

### Functions in emu-i386/cputime.c

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

#### 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

#### GETusTIME(sc)

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(sc)

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()

GETusSYSTIME returns the real CPU time with 1-usec resolution

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

## The Serial group of Modules

This is the code that works our serial emulation. This needs to be very fast if we are to convince DOS that we have a very fast serial port.

### Remarks in base/serial/ser_defs.h

Extensions to serial debugging.

SER_DEBUG_MAIN (0 or 1) - extra debug output on the most critical information.

SER_DEBUG_HEAVY (0 or 1) - super-heavy extra debug output, including all ports reads and writes, and every character received and transmitted!

SER_DEBUG_INTERRUPT (0 or 1) - additional debug output related to serial interrupt code, including flagging serial interrupts, or PIC-driven code.

SER_DEBUG_FOSSIL_RW (0 or 1) - heavy FOSSIL debug output, including all reads and writes.

SER_DEBUG_FOSSIL_STATUS (0 or 1) - super-heavy FOSSIL debug output, including all status checks.

You must recompile dosemu everytime one of these constants are modified. Just type 'make' in the dosemu dir and it will recompile the changes only.

-----

IMPORTANT INFO about com[] variable array structure used in serial.c

Most of the serial variables are stored in the com[] array. The com[] array is a structure in itself. Take a look at the 'serial_t' struct declaration in the serial.h module for more info about this. Only the most commonly referenced global variables are listed here:

config.num_ser Number of serial ports active. com[x].base_port The base port address of emulated serial port. com[x].real_comport The COM port number. com[x].interrupt The PIC interrupt level (based on IRQ number) com[x].mouse Flag mouse (to enable extended features) com[x].fd File descriptor for port device com[x].dev[] Filename of port port device com[x].dev_locked Flag whether device has been locked

The arbritary example variable 'x' in com[x] can have a minimum value of 0 and a maximum value of (config.numser - 1). There can be no gaps for the value 'x', even though gaps between actual COM ports are permitted. It is strongly noted that the 'x' does not equal the COM port number. This example code illustrates the fact, and how the com[] array works:

for (i = 0; i < config.numser; i++) s_printf("COM port number %d has a base address of %x", com[i].real_comport, com[i].base_port);

### Functions in base/serial/ser_init.c

These are the functions defined in base/serial/ser_init.c.

#### serial_init

This is the master serial initialization function that is called upon startup of DOSEMU to initialize ALL the emulated UARTs for all configured serial ports. The UART is initialized via the initialize_uart function, which opens the serial ports and defines variables for the specific UART.

If the port is a mouse, the port is only initialized when i

### Items for Fixing in base/serial/ser_init.c

This needs more work before it is implemented into /etc/dosemu.conf as an 'rtscts' option.

### Functions in base/serial/ser_ports.c

These are the functions defined in base/serial/ser_ports.c.

#### do_serial_in

The following function returns a value from an I/O port. The port is an I/O address such as 0x3F8 (the base port address of COM1). There are 8 I/O addresses for each serial port which ranges from the base port (ie 0x3F8) to the base port plus seven (ie 0x3FF). [num = abritary port number for serial line, address = I/O port address]

#### do_serial_out

The following function writes a value to an I/O port. The port is an I/O address such as 0x3F8 (the base port address of COM1). [num = abritary port number for serial line, address = I/O port address, val = value to write to I/O port address]

### Items for Fixing in base/serial/ser_ports.c

Should clearing UART cause THRE int if it's enabled? */

-----

Fix the calculation assumption

-----

Is this safe to put this here? */

-----

Is this safe to put this here? */

### Functions in base/serial/ser_irq.c

These are the functions defined in base/serial/ser_irq.c.

#### serial_int_engine

This function is the serial interrupts scheduler. Its purpose is to update interrupt status and/or invoke a requested serial interrupt. If interrupts are not enabled, the Interrupt Identification Register is still updated and the function returns. See pic_serial_run() below it is executed right at the instant the interrupt is actually invoked.

Since it is not possible to run the interrupt on the spot, it triggers the interrupt via the pic_request() function (which is in pic.c) and sets a flag that an interrupt is going to be occur soon.

Please read pic_serial_run() for more information about interrupts. [num = port, int_requested = the requested serial interrupt]

#### pic_serial_run

This function is called by the priority iunterrupt controller when a serial interrupt occurs. It executes the highest priority serial interrupt for that port. (Priority order is: RLSI, RDI, THRI, MSI)

Because it is theoretically possible for things to change between the interrupt trigger and the actual interrupt, some checks must be repeated.

#### serial_run

This is the main housekeeping function, which should be called about 20 to 100 times per second. The more frequent, the better, up to a certain point. However, it should be self-compensating if it executes 10 times or even 1000 times per second. Serial performance increases with frequency of execution of serial_run.

Serial mouse performance becomes more smooth if the time between calls to serial_run are smaller.

### Remarks in base/serial/ser_irq.c

Linux code hackers: How do I detect a break signal without having to rely on Linux signals? Can I peek a 'break state bit'? Also, how do I 'turn on' and 'turn off' the break state, via an ioctl() or tcsetattr(), rather than using POSIX tcsendbrk()?

### Items for Fixing in base/serial/ser_irq.c

how do we cancel a PIC interrupt, when we have come this far?

-----

Perhaps this can be modified to limit max chain length?

### Functions in base/serial/int14.c

These are the functions defined in base/serial/int14.c.

#### int14

The following function executes a BIOS interrupt 0x14 function. This code by Mark Rejhon replaced some very buggy, old int14 interface a while back. These routines are not flawless since it does not wait for a character during receive, and this may confuse some programs.

### New Ideas for base/serial/int14.c

If any of you coders are ambitious, try thinking of the following: - Converting this into inline assembler and use direct port access

### Items for Fixing in base/serial/fossil.c

This really should be write-with-wait. */

### Items for Fixing in include/serial.h

Why does a RX_BUFFER_SIZE of 256 cause slower performance than a size of 128?

## The Mouse group of Modules

All of the Mouse handling code is in the "mouse" subdirectory.

There are only 2 main files, mouse.c and mouseint.c.

### Functions in base/mouse/mouse.c

These are the functions defined in base/mouse/mouse.c.

#### mouse_init

Initialize internal mouse.

### Remarks in base/mouse/mouse.c

I have not properly tested this INT74 - JES 96/10/20 I have removed it. INT74 is irq 12. Which I suppose is the proper irq for a ps2 mouse. It appears initial support was planned to support irq 12 and at Mouse_ROUTINE_OFF is a routine that acknowledges an irq. That routine is probably what should be acknowledging irq12, and what int 0x74 should point to. I have disabled int0x74 support for now. --EB 29 Oct 1997

-----

Whoever wrote the dos mouse driver spec was brain dead... For some video modes the mouse driver appears to randomly pick a shift factor, possibly to keep at least a 640x200 resolution.

The general programming documentation doesn't make this clear. And says that in text modes it is safe to divide the resolution by 8 to get the coordinates in characters.

The only safe way to handle the mouse driver is to call function 0x26 Get max x & max y coordinates and scale whatever the driver returns yourself.

To handle programs written by programmers who weren't so cautious a doctrine of least suprise has been implemented.

As much as possible do the same as a standard dos mouse driver in the original vga modes 0,1,2,3,4,5,6,7,13,14,15,16,17,18,19.

For other text modes allow the divide by 8 technique to work. For other graphics modes return x & y in screen coordinates. Except when those modes are either 40x?? or 320x??? and then handle the x resolution as in 40x25 and 320x200 modes.

320x200 modes are slightly controversial as I have indications that not all mouse drivers do the same thing. So I have taken the simplest, and most common route, which is also long standing dosemu practice of always shifting the xaxis by 1. When I researched this I could find no examples that did otherwise.

-- Eric Biederman 19 August 1998

This code has now been updated so it defaults as above but allows work arounds if necessary. Because tweaking dosemu is easier than fixing applications without source.

-- Eric Biederman 29 May 2000

## The Bios group of Modules

All of the Bios code is in the "bios" subdirectory.

DOSEMU requires certain code to be coded in assembler and also code to be located in the F000 segment. This is where all such code should be put.

### Functions in base/bios/hlt.c

These are the functions defined in base/bios/hlt.c.

#### hlt_init(void)

Resets all the HLT handlers

#### hlt_handle()

Handles a HLT instruction reached inside the dos emulator.

## The PIC group of Modules

All of the PIC handling code is in the "PIC" subdirectory.

### Functions in base/dev/pic/pic.c

These are the functions defined in base/dev/pic/pic.c.

#### pic_print

This is the pic debug message printer. It writes out some basic information, followed by an informative message. The basic information consists of: interrupt nesting counter change flag (+, -, or blank) interrupt nesting count (pic_icount) interrupt level change flag (+, -, or blank) current interrupt level interrupt in-service register interrupt mask register interrupt request register message part one decimal data value message part two

If the message part 2 pointer is a null pointer, then only message part one (without the data value) is printed.

The change flags are there to facilitate grepping for changes in pic_ilevel and pic_icount

To avoid line wrap, the first seven values are printed without labels. Instead, a header line is printed every 15 messages.

#### write_pic0,write_pic1

write_pic_0() and write_pic1() implement dos writes to the pic ports. They are called by the code that emulates inb and outb instructions. Each function implements both ports for the pic: pic0 is on ports 0x20 and 0x21; pic1 is on ports 0xa0 and 0xa1. These functions take

Arguments are:

#### read_pic0,read_pic1

read_pic0 and read_pic1 return the values for the interrupt mask register (port 1), or either the in service register or interrupt request register, as determined by the last OCW3 command (port 0). These functions take a single parameter, which is a port number (0 or 1). They are called by code that emulates the inb instruction.

#### pic_mask,pic_unmask

The pic maintains an additional interrupt mask which is not visible to the DOS process. This is normally cleared (enabling an interrupt) when an interrupt is initialized, but dosemu code may choose to use this mask internally. One possible use is to implement the interrupt gate controlled by the OUT2 bit of the 16550A UART's Modem Control Register. This mask is cleared by pic_unmaski() and set by pic_maski()

#### pic_seti

pic_seti is used to initialize an interrupt for dosemu. It requires three parameters. The first parameter is the interrupt level, which man select the NMI, any of the IRQs, or any of the 16 extra levels (16 - 31). The second parameter is the dosemu function to be called when the interrupt is activated. This function should call do_irq() if the DOS interruptis really to be activated. If there is no special dosemu code to call, the second parameter can specify do_irq(), but see that description for some special considerations.

#### run_irqs

run_irqs, which is initiated via the macro pic_run, is the "brains" of the pic. It is called from the vm86() loop, checks for the highest priority interrupt requested, and executes it. This function is written in assembly language in order to take advantage of atomic (indivisible) instructions, so that it should be safe for a two process model, even in a multiple CPU machine. A c language version was started, but it became impossible, even with in-line assembly macros, because such macros can only return a single result. If I find a way to do it in c, I will, but don't hold your breath.

#### do_irq

do_irq() calls the correct do_int(). It then executes a vm86 loop until an outb( end-of-interrupt) is found. For priority levels 0 and >15 (not real IRQs), vm86 executes once, then returns, since no outb20 will come. Returns: 0 = complete, 1 = interrupt not run because it directly calls our "bios" See run_timer_tick() in timer.c for an example To assure notification when the irq completes, we push flags, ip, and cs here and fake cs:ip to PIC_[SEG,OFF], where there is a hlt. This makes the irq generate a sigsegv, which calls pic_iret when it completes. pic_iret then pops the real cs:ip from the stack. This routine is RE-ENTRANT - it calls run_irqs, which may call an interrupt routine, which may call do_irq(). Be Careful! !!!!!!!!!!!!!!!!!! No single interrupt is ever re-entered.

Callers: base/misc/ioctl.c base/keyboard/serv_8042.c base/keyboard/keyboard-server.c base/serial/ser_irq.c dosext/sound/sound.c dosext/net/net/pktnew.c

#### pic_request

pic_request triggers an interrupt. There is presently no way to "un-trigger" an interrupt. The interrupt will be initiated the next time pic_run is called, unless masked or superceded by a higher priority interrupt. pic_request takes one argument, an interrupt level, which specifies the interrupt to be triggered. If that interrupt is already active, the request will be queued until all active interrupts have been completed. The queue is only one request deep for each interrupt, so it is the responsibility of the interrupt code to retrigger itself if more interrupts are needed.

#### pic_iret

pic_iret is used to sense that all active interrupts are really complete, so that interrupts queued by pic_request can be triggered. Interrupts end when they issue an outb 0x20 to the pic, however it is not yet safe at that time to retrigger interrupts, since the stack has not been restored to its initial state by an iret. pic_iret is called whenever interrupts have been enabled by a popf, sti, or iret. It determines if an iret was the cause by comparing stack contents with cs and ip. If so, it decrements a count of interrupts on the stack (set by do_irq()). If the count is then zero, pic_iret moves all queued interrupts to the interrupt request register. It is possible for pic_iret to be fooled by dos code; for this reason active interrupts are checked, any queued interrupts that are also active will remain queued. Also, some programs fake an iret, so that it is possible for pic_iret to fail. See pic_watch for the watchdog timer that catches and fixes this event.

#### pic_watch

pic_watch is a watchdog timer for pending interrupts. If pic_iret somehow fails to activate a pending interrupt request for 2 consecutive timer ticks, pic_watch will activate them anyway. pic_watch is called ONLY by timer_tick, the interval timer signal handler, so the two functions will probably be merged.

#### pic_pending

This function returns a non-zero value if the designated interrupt has been requested and is not masked. In these circumstances, it is important for a hardware emulation to return a status which does *not* reflect the event(s) which caused the request, until the interrupt actually gets processed. This, in turn, hides the interrupt latency of pic from the dos software.

The single parameter ilevel is the interrupt level (see pic.h) of the interrupt of interest.

If the requested interrupt level is currently active, the returned status will depend upon whether the interrupt code has re-requested itself. If no re-request has occurred, a value of false (zero) will be returned.

#### pic_activate

pic_activate requests any interrupts whose scheduled time has arrived. anything after pic_dos_time and before pic_sys_time is activated. pic_dos_time is advanced to the earliest time scheduled.

#### pic_sched

pic_sched schedules an interrupt for activation after a designated time interval. The time measurement is in unis of 1193047/second, ( or if using MONOTON_MICRO_TIMING in units of PIT_TICK_RATE/second ) the same rate as the pit counters. This is convenient for timer emulation, but can also be used for pacing other functions, such as serial emulation, incoming keystrokes, or video updates. Some sample intervals:

rate/sec: 5 7.5 11 13.45 15 30 60 interval: 238608 159072 108459 88702 79536 39768 19884

rate/sec: 120 180 200 240 360 480 720 interval: 9942 6628 5965 4971 3314 2485 1657

rate/sec: 960 1440 1920 2880 3840 5760 11520 interval: 1243 829 621 414 311 207 103

pic_sched expects two parameters: an interrupt level and an interval. To assure proper repeat scheduling, pic_sched should be called from within the interrupt handler for the same interrupt. The maximum interval is 15 minutes (0x3fffffff).

### Remarks in base/dev/pic/pic.c

pic_push,pic_pop

Pic maintains two stacks of the current interrupt level. an internal one is maintained by run_irqs, and is valid whenever the emulator code for an interrupt is active. These functions maintain an external stack, which is valid from the time the dos interrupt code is called until the code has issued all necessary EOIs. Because pic will not necessarily get control immediately after an EOI, another EOI (for another interrupt) could occur. This external stack is kept strictly synchronized with the actions of the dos code to avoid any problems. pic_push and pic_pop maintain the external stack.

## The Sound group of Modules

The sound code provides emulation of the SB. The actual emulation provided depends upon the support available from the kernel sound driver. Because this is very OS dependant the driver code itself is kept in architecture specifc files under src/arch/osname/dosext/sound/. Communication is via a set of interface functions and the device independant structures.

### Functions in dosext/sound/sound.c

These are the functions defined in dosext/sound/sound.c.

#### sb_io_read

Arguments are:

- port - The I/O port being read from.

This handles all of the reads for the SB emulation. The value read is returned. The value of 0xFF indicates an invalid read. (assumes the ports float high when not pulled low by the hardware.)

#### adlib_io_read

Arguments are:

- port - The I/O port being read from.

This handles all of the reads for the adlib (FM) emulation. The value read is returned. The value of 0xFF indicates an invalid read. (assumes the ports float high when not pulled low by the hardware.) The FM emulation is not written yet. The current plan is to use the midi emulation where available as this is the most common use for the FM sound.

#### mpu401_io_read

Arguments are:

- port - The I/O port being read from.

The MPU-401 functionality is primarily provided by 'midid' - a standalone program. This makes most of the MPU-401 code simply a pass-through driver.

#### sb_io_write

Arguments are:

- port - The I/O port being written to.

- value - The value being output.

This handles the writes for the SB emulation. Very little of the processing is performed in this function as it basically consists of a very large switch() statement. The processing here is limited to trivial (1 line) items and distinguishing between the different actions and responses that the different revisions of the SB series give.

#### sb_dsp_write

Arguments are:

- value - The value being written to the DSP.

The SB DSP is a complete I/O system in itself controlled via a number of data bytes. The number of bytes depends upon the function. The function to be executed is determined by the first byte. If there is no existing command then the command is stored. This then used in the switch to identify the action to be taken. When the command has supplied all of its arguments, or failed, then the command storage is cleared. Each DSP function is responsible for clearing this itself. Again, this function relies on other functions to do the real work, and apart from storing details of the command and parameters is basically a large switch statement.

### Remarks in dosext/sound/sound.c

Write silence could probably be implemented by setting up a "DMA" transfer from /dev/null - AM

### Items for Fixing in dosext/sound/sound.c

The file header needs tidying up a _LOT_ ! */

-----

Adlib status reads are unimplemented */

-----

Advanced adlib reads are unimplemented */

-----

CMS Writes are unimplemented.

-----

DSP Status is unimplemented

-----

Adlib Waveform tests are unimplemented */

-----

Advanced Adlib register writes are unimplemented */

-----

Advanced Adlib data writes are unimplemented */

-----

SB Midi is Unimplemented

-----

Sine Generation is unimplemented

-----

AUX Status is Unimplemented

-----

Stero Input is no implemented

-----

ADC is Unimplemented

-----

Stopping Auto-Init DMA is not implemented

### Remarks in base/dev/dma/dma.c

**** WARNING **** This Code _HAS_ changed.

-----

The Emulated DMA channels are provided by using files and writes. This means that they are easy to track. It might cause problems when attempting to interface to the REAL DMA controller. (Necessary to talk to hardware which uses DMA.)

Note that DMA controller 2 uses word granular addressing and controller 1 uses byte granular address ... this simplifies the code !

-----

I think that DREQ should only be set on auto-init if we are the reading portion.

### Items for Fixing in base/dev/dma/dma.c

: Pipe Creation failed. Lets hope that it times out !

-----

: Cascade Mode Reads are not supported

-----

: The Verify Mode is not supported

-----

: The Invalid Mode is not supported (!)

## The FileAccess group of Modules

This hold all kind of accessing files on a Unix filesysten from DOS.

### Remarks in dosext/mfs/mfs.c

The msdos_dir_ent structure has much more than 28 bytes. Is this significant?

-----

Added compares to NUL so that newer versions of Foxpro which test directories using xx\yy\nul perform closer to whats DOS does.

### Items for Fixing in dosext/mfs/mfs.c

We probably should use llseek here for file > 2 GBytes

-----

returned size of struct dir_ent seems wrong at 28 bytes. */

## And Finally ...

The Following items are used to delimit the text used to create this file. Whilst it is not necessary to know this, they are included because they may be useful for searching, as they are (at least at the moment) reasonably unique.

DANG_BEGIN_MODULE / DANG_END_MODULE This will bracket a description of the file (normally at the start). Within this you may have the keyword 'Maintainer:' followed by a list (one line each) of maintainers for this packet. These will be turned into URLs.

DANG_BEGIN_FUNCTION / DANG_END_FUNCTION This brackets a description of functions (good this, isn't it!) Not every function needs to be described in this way - just the major ones. Within this you may have the keywords: `arguments:', `return:' and `description:', which will sort out the information following it to build proper lists.

DANG_BEGIN_STRUCT / DANG_END_STRUCT This brackets a description of structures and data definitions Not every structure needs to be described in this way - just the major ones. Within this you may have the keywords: `elements:', and `description:', which will sort out the information following it to build proper lists. Also, you may bracket the structur definition of real C-code, given you have one element per line. In this case comments (/*...*/) behind the element will be inserted properly into the formatted list while the C-code itself is still compilable.

DANG_BEGIN_REMARK / DANG_END_REMARK This brackets descriptions of obscure items, like data structures and architecture.

DANG_FIXTHIS This is a one line item, indicating a an area requiring a fix, or redesign.

DANG_BEGIN_NEWIDEA / DANG_END_NEWIDEA New Ideas Start Here! As Ideas are proposed, that get added with their description, so that future generations can laugh at or code the ideas ..... These bracket the idea description.

DANG_BEGIN_CHANGELOG / DANG_END_CHANGELOG Changelogs - very useful for bug fixing, and avvailable for use with DPR (or that's the theory)

In addition there are some keywords, that are recognized within a bracket.

VERB ... /VERB This formats the enclosed text verbatim. This is valid within *_MODULE, *_REMARK, *_STRUCT, *_FUNCTION

REMARK ... /REMARK This is only valid within *_MODULE and also can contain VERB brakets. Its usefull to when you want to have a global modul description

PROTO ... /PROTO This is only valid within *_FUNCTION and takes a C-function prototype as `verbatim' until either a `{' or a /PROTO is seen. After this all input is `skipped' until the next PROTO or a /SKIP.

SKIP ... /SKIP This is only valid within *_FUNCTION and skips formatting until either PROTO or /SKIP is seen.