<!doctype linuxdoc system>
<article>

<title> The DOSEMU Alterer Novices Guide
<author> Author: Alistair MacDonald, <tt/alistair\@slitesys.demon.co.uk/
<date> version dosemu-0.97.10.5
<abstract>
This Document is the DOSEMU Alterer Novices Guide. It is known as the DANG.
</abstract>

<toc>

<sect>Introduction

<p>
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 &dquot;Corey Sweeney&dquot;
&lt;corey@interaccess.com&gt;. It has been completely revised. It is now
generated automatically directly from the source code. Special thanks to
&dquot;James B. MacLean&dquot; &lt;macleajb@ednet.ns.ca&gt; for supplying the original
information. (It was mostly ripped out of a mail message.) &dquot;Jochen Hein&dquot;
has made many useful comments &amp; 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!




<sect>The Main group of Modules

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


<sect1>dos.c Information

<p>
 Initial program executed to run DOSEMU. Gets access to libdosemu
 and sets international character parms. Finally calls entry
 point of DOSEMU emulate() function which is loaded above the
 usual DOS memory area from 0 - 1meg. Emulate() is in emu.c.
 
<sect1>Functions in dos.c

<p>
These are the functions defined in dos.c.

<sect2>dosemu


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  argc - Count of argumnents.
<ITEM>  argc - Actual arguments.
</itemize>
  Function created by entry point into libdosemu. Called to
  jump into the emulate function of DOSEMU.

 


<sect1>emu.c Information

<p>
 Here is where DOSEMU gets booted. From emu.c external calls are made to
 the specific I/O systems (video/keyboard/serial/etc...) to initialize
 them. Memory is cleared/set up and the boot sector is read from the
 boot drive. Many SIGNALS are set so that DOSEMU can exploit things like
 timers, I/O signals, illegal instructions, etc... When every system
 gives the green light, vm86() is called to switch into vm86 mode and
 start executing i86 code.
 
 The vm86() function will return to DOSEMU when certain `exceptions` occur
 as when some interrupt instructions occur (0xcd).
 
 The top level function emulate() is called from dos.c by way of a dll
 entry point.
 
<sect1>Functions in emu.c

<p>
These are the functions defined in emu.c.

<sect2>jmp_emulate


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


<sect2>SIG_int


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


<sect2>emulate


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  argc - Argument count. 
<ITEM>  argv - Arguments.
</itemize>
 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().
 
 


<sect1>Remarks in emu.c

<p>
 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. 
 
<sect1>include/emu.h Information

<p>
<sect1>Functions in include/emu.h

<p>
These are the functions defined in include/emu.h.

<sect2>NEWSETQSIG


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  sig - the signal to have a handler installed to.
<ITEM>  fun - the signal handler function to install
</itemize>
  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.

 


<sect1>Remarks in include/emu.h

<p>
 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.
 
<sect>The Init group of Modules

<p>
These files are used for initialization and runtime configuration of DOSEMU


<sect1>base/init/init.c Information

<p>
<sect1>Functions in base/init/init.c

<p>
These are the functions defined in base/init/init.c.

<sect2>dosemu_banner


<p>
 
  Setup the call stack to draw the dosemu banner
 
 


<sect2>stdio_init


<p>
 
  Initialize stdio, open debugging output file if user specified one
 
 


<sect2>time_setting_init


<p>
 
  Beats me
 
 


<sect2>timer_interrupt_init


<p>
 
  Tells the OS to send us periodic timer messages
 
 


<sect2>hardware_setup


<p>
 
  Initialize any leftover hardware. 
 
 


<sect2>map_video_bios


<p>
 
  Map the video bios into main memory
 
 


<sect2>map_hardware_ram


<p>
 
  Initialize the hardware direct-mapped pages
 
 


<sect2>map_custom_bios


<p>
 
  Setup the dosemu amazing custom BIOS
 
 


<sect2>bios_mem_setup


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


<sect2>memory_init


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


<sect2>device_init


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


<sect2>low_mem_init


<p>
 
  Initializes the lower 1Meg via mmap &amp; sets up the HMA region
 
 


<sect2>version_init


<p>
 
  Find version of OS running and set necessary global parms.
 
 


<sect1>Items for Fixing in base/init/init.c

<p>
 config.timer is undocumented and probably obsolete

<sect1>base/init/config.c Information

<p>
<sect1>Functions in base/init/config.c

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

<sect2>cpu_override


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


<sect2>config_defaults


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


<sect2>config_init


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


<sect2>parse_debugflags


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  s - string of options.
</itemize>
 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) &num;   where &num; 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 &dquot;01-a-1+0vk&dquot; 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.
 
 


<sect1>Remarks in base/init/config.c

<p>
 For simpler support of X, DOSEMU can be started
 by a symbolic link called `xdos` which DOSEMU will use to switch
 into X-mode. 
<sect1>base/init/dev_list.c Information

<p>
 Description:
  Manages a list of the available I/O devices.  It will automatically
  call their initialization and termination routines.
  The current I/O device list includes:
<p><verb>
     Fully emulated:      pit, pic, cmos, serial
     Partially emulated:  rtc, keyb, lpt
     Unemulated:          dma, hdisk, floppy, pos
</verb>
<sect>The DPMI group of Modules

<p>
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 .... &dquot;Away you Go!&dquot; (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 ...)


<sect1>dosext/dpmi/dpmi.c Information

<p>
 DOS Protected Mode Interface allows DOS programs to run in the
 protected mode of &lsqb;2345..&rsqb;86 processors

<sect1>Functions in dosext/dpmi/dpmi.c

<p>
These are the functions defined in dosext/dpmi/dpmi.c.

<sect2>dpmi_control


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

 


<sect2>run_pm_int


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

 


<sect2>do_default_cpu_exception


<p>
 
 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 :-)).

 


<sect2>do_cpu_exception


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

 


<sect2>dpmi_fault


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

 


<sect1>Remarks in dosext/dpmi/dpmi.c

<p>
 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
 
<sect1>Items for Fixing in dosext/dpmi/dpmi.c

<p>
 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 */

<sect1>New Ideas for dosext/dpmi/dpmi.c

<p>
 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
 
<sect1>dosext/dpmi/msdos.h Information

<p>
 MS-DOS API translator allows DPMI programs to call DOS service directly
 in protected mode.

<sect1>Functions in dosext/dpmi/msdos.h

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

<sect2>msdos_pre_extender


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

 


<sect2>msdos_post_extender


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

 


<sect>The Video group of Modules

<p>
All of the Video handling code is in the &dquot;video&dquot; 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 &amp; restore routines putting in a file
here.


<sect1>env/video/vc.c Information

<p>
 Here's all the calls to the code to try and properly save &amp; restore
 the video state between VC's and the attempts to control updates to
 the VC whilst the user is using another. We map between the real
 screen address and that used by DOSEMU here too.
 
 Attempts to use a cards own bios require the addition of the parameter
 &dquot;graphics&dquot; to the video statement in &dquot;/etc/dosemu.conf&dquot;. This will make
 the emulator try to execute the card's initialization routine which is
 normally located at address c000:0003. This can now be changed as an
 option.
<sect1>env/video/video.c Information

<p>
<sect1>Functions in env/video/video.c

<p>
These are the functions defined in env/video/video.c.

<sect2>video_init


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

 


<sect1>Remarks in env/video/video.c

<p>
 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-&gt;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.
 
<sect1>env/video/X.c Information

<p>
 This module contains the video interface for the X Window 
 System. It has mouse and selection 'cut' support.
 
<sect1>Functions in env/video/X.c

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

<sect2>vga256_cmap_init


<p>
 
 Allocates a colormap for 256 color modes and initializes it.

 


<sect2>X_close


<p>
 
  Destroys the window, unloads font, pixmap and colormap.

 


<sect2>X_setmode


<p>
 
  Resizes the window, also the graphical sizes/video modes.
  remember the dos videomodi

 


<sect2>X_change_mouse_cursor(void)


<p>
   
 This function seems to be called each screen_update :(
 It is called in base/mouse/mouse.c:mouse_cursor(int) a lot for show and 
 hide.
 


<sect2>X_redraw_screen


<p>
 
  Redraws the entire screen, also in graphics mode
  Used for expose events etc.

 returns: 
  nothing

<p>Arguments are:&nl;
<itemize>
<ITEM>   none
</itemize>


<sect2>X_update_screen


<p>
 
 Updates the X screen, in text mode and in graphics mode.
 Both text and graphics in X have to be smarter and improved.
  
 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 end 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.
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  none
</itemize>


<sect2>set_mouse_position


<p>
 
  places the mouse on the right position
 Not tested in X with graphics
 
 returns: 
  nothing

<p>Arguments are:&nl;
<itemize>
<ITEM>  x,y - coordinates
</itemize>


<sect1>Remarks in env/video/X.c

<p>
 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
 
<sect1>env/video/vgaemu.c Information

<p>
 The VGA emulator for DOSEmu.
 
 Emulated are the video memory and the VGA register set (CRTC, DAC, etc.).
 Parts of the hardware emulation is done in separate files (attremu.c,
 crtcemu.c, dacemu.c and seqemu.c).

 VGAEmu uses the video BIOS code in base/bios/int10.c and env/video/vesa.c.

 For an excellent reference to programming SVGA cards see Finn Thøgersen's
 VGADOC4, available at http://www.datashopper.dk/~finth

<sect1>Functions in env/video/vgaemu.c

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

<sect2>VGA_emulate_outb


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  port  - The port being written to.
<ITEM>  value - The value written,
</itemize>


<sect2>VGA_emulate_inb


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  port  - The port being read from.
</itemize>


<sect2>vga_emu_fault


<p>
 
 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-&gt;cr2),
 but what are those changes?
 An other problem is, it could eat a lot of time, but it does now also.

<p>Arguments are:&nl;
<itemize>
<ITEM>  scp - A pointer to a struct sigcontext_struct holding some relevant data.
</itemize>


<sect2>vga_emu_init


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  vedt - Pointer to struct describing the type of display we are actually
<ITEM>         attached to.
</itemize>


<sect2>vga_emu_update


<p>
 
 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-&gt;max_max_len' and `veut-&gt;max_len'.
 See the example in env/video/X.c how this works.
 
 If the return value of vga_emu_update() is &gt;= 0, it is the number of changed
 pages, -1 means there are still changed pages but the maximum update chunk size
 (`veut-&gt;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.

<p>Arguments are:&nl;
<itemize>
<ITEM>  veut - A pointer to a vga_emu_update_type object holding all relevant info.
</itemize>


<sect2>vga_emu_switch_bank


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  bank - The bank to switch to.
</itemize>


<sect2>vga_emu_find_mode


<p>
 
 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 (&gt;= 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.

<p>Arguments are:&nl;
<itemize>
<ITEM>  mode   - video mode.
<ITEM>  vmi    - pointer into internal mode list
</itemize>


<sect2>vga_emu_setmode


<p>
 
 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'.

<p>Arguments are:&nl;
<itemize>
<ITEM>  mode   - The new video mode.
<ITEM>  width  - Number of text columns.
<ITEM>  height - Number of text rows.
</itemize>


<sect2>dirty_all_video_pages


<p>
 
 Marks the whole VGA memory as modified.

 


<sect2>vga_emu_set_text_page


<p>
 
 Set visible text page.

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

<p>Arguments are:&nl;
<itemize>
<ITEM>  page      - Number of the text page.
<ITEM>  page_size - Size of one text page.
</itemize>


<sect1>env/video/vesa.c Information

<p>
 VESA BIOS Extensions for VGAEmu.
 
 Supported are VBE version 2.0, including a linear frame buffer
 and display power management support.

<sect1>Functions in env/video/vesa.c

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

<sect2>vbe_init


<p>
 
 Initializes the VGA/VBE BIOS and the VBE support.

<p>Arguments are:&nl;
<itemize>
<ITEM>  vedt - Pointer to struct describing the type of display we are actually
<ITEM>         attached to.
</itemize>


<sect2>vesa_emu_fault


<p>
 
 vesa_emu_fault() is used to handle video ROM accesses.
 This function is called from env/video/vgaemu.c:vga_emu_fault().
 The sigcontext_struct is defined in include/cpu.h
 It just jumps over the instruction (LWORD (eip) += instr-len)
 which caused the write exception to the video ROM. It is needed for
 some dirty programs that try to write to a ROM (dos=high,umb seems
 to do this, but not on all PC's). We're sure now, nobody can write to
 the ROM and we don't crash on it, just ignore as it should be!

<p>Arguments are:&nl;
<itemize>
<ITEM>  scp - A pointer to a struct sigcontext_struct holding some relevant data.
</itemize>


<sect2>do_vesa_int


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

 


<sect1>env/video/vesabios.S Information

<p>
 The VGA/VESA BIOS for VGAEmu.
 
 This is what DOS applications see as their video BIOS. It will be
 mapped at 0xc000:0x0000 and typically be less than one page in size.
 This video BIOS is write-protected, write accesses to this memory
 are emulated by vesa_emu_fault() in env/video/vesa.c.

 It doesn't have much functionality, just stores the VESA mode table
 and the protected mode interface necessary for VESA BIOS Extension (VBE)
 support.

 Note that some parts of the video BIOS are added by vbe_init()
 in env/video/vesa.c.

<sect1>env/video/vesabios_pm.S Information

<p>
<sect1>env/video/attremu.c Information

<p>
 The protected mode code for the VESA BIOS Extensions.
 
 We define some functions here that are required to support the
 VBE 2.0 protected mode interface.

 The whole code _must_ be fully relocatable. It will be copied into
 the video BIOS during VBE initialization (cf. vbe_init()).

 The Attribute Controller emulator for VGAemu.
<sect1>Functions in env/video/attremu.c

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

<sect2>Attr_init


<p>
 
 Initializes the attribute controller.

 


<sect2>Attr_write_value


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

 


<sect2>Attr_read_value


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

 


<sect2>Attr_get_index


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

 


<sect2>Attr_get_input_status_1


<p>
 
 


<sect1>env/video/dacemu.c Information

<p>
 The DAC emulator for DOSemu.
<sect1>Functions in env/video/dacemu.c

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

<sect2>DAC_init


<p>
 
 Initializes the DAC.

 


<sect2>DAC_dirty_all


<p>
 
 Dirty all DAC entries.  Usefull for a mode set.

 


<sect2>DAC_set_read_index


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

 


<sect2>DAC_set_write_index


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

 


<sect2>DAC_read_value


<p>
 
 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 vgadoc3 if you want to know more about the DAC.
 This is a hardware emulation function.

 


<sect2>DAC_write_value


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

 


<sect2>DAC_set_pel_mask


<p>
 
 Sets the pel mask and marks all DAC entries as dirty.
 This is a hardware emulation function.

 


<sect2>DAC_get_entry


<p>
 
 Returns a complete DAC entry (r,g,b). Color values are AND-ed with the
 pel mask.
 This is an interface function.

 


<sect2>DAC_read_entry


<p>
 
 Returns a complete DAC entry (r,g,b), doesn't un-dirty it.
 Color values are _not_ maked.
 This is an interface function.

 


<sect2>DAC_get_dirty_entry


<p>
 
 Searches the DAC_dirty list for the first dirty entry. Returns the 
 changed entrynumber and fills in the entry if a dirty entry is found or
 returns -1 otherwise.
 This is an interface function.

 


<sect2>DAC_set_entry


<p>
 
 Sets a complete DAC entry (r,g,b).
 This is an interface function for the int 10 handler.

 


<sect2>DAC_get_pel_mask


<p>
 
 Returns the current pel mask. Drawing functions should get the pel
 mask and AND it with the pixel values to get the correct pixel value.
 This is *very* slow to implement and fortunately this register is used
 very rare. Maybe the implementation should be in vgaemu, maybe in the
 vgaemu client...
 This is an interface function. 

 


<sect2>DAC_get_state


<p>
 
 Returns the current state of the DAC
 This is an interface function.

 


<sect1>env/video/seqemu.c Information

<p>
<sect1>env/video/crtcemu.c Information

<p>
 The VGA sequencer for VGAemu.
 The VGA CRT controller emulator for VGAEmu.

 This emulates a very basic CRT controller. Just
 the start address registers (0xc, 0xd).

<sect1>env/video/remap.c Information

<p>
 Transform a 2D image (rescale and color space conversion).
 
 Here are functions to adapt the VGA graphics to various
 X displays.

<sect1>env/video/remap_asm.S Information

<p>
 Low-level assembler functions for remapping 2D images.
 
 Note that these functions mostly call other functions that
 have been calculated in remap.c.

<sect1>env/video/console.c Information

<p>
<sect1>env/video/dualmon.c Information

<p>
<sect1>Functions in env/video/dualmon.c

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

<sect2>MDA_init


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

<p>Arguments are:&nl;
<itemize>
<ITEM>   none
</itemize>


<sect1>Remarks in env/video/dualmon.c

<p>
 After MDA_init() the VGA is configured, something in video.c 
 or console.c &dquot;reprograms&dquot; 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)

 
<sect1>env/video/et4000.c Information

<p>
<sect1>env/video/hgc.c Information

<p>
<sect1>base/bios/int10.c Information

<p>
 Video BIOS implementation.
 
 This module handles the int10 video functions.
 Most functions here change only the video memory and status 
 variables; the actual screen is then rendered asynchronously 
 after these by Video-&gt;update_screen.

<sect1>env/video/s3.c Information

<p>
<sect1>env/video/terminal.c Information

<p>
<sect1>env/video/trident.c Information

<p>
<sect1>env/video/vga.c Information

<p>
<sect1>env/video/vgaemu.c Information

<p>
 The VGA emulator for DOSEmu.
 
 Emulated are the video memory and the VGA register set (CRTC, DAC, etc.).
 Parts of the hardware emulation is done in separate files (attremu.c,
 crtcemu.c, dacemu.c and seqemu.c).

 VGAEmu uses the video BIOS code in base/bios/int10.c and env/video/vesa.c.

 For an excellent reference to programming SVGA cards see Finn Thøgersen's
 VGADOC4, available at http://www.datashopper.dk/~finth

<sect1>Functions in env/video/vgaemu.c

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

<sect2>VGA_emulate_outb


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  port  - The port being written to.
<ITEM>  value - The value written,
</itemize>


<sect2>VGA_emulate_inb


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  port  - The port being read from.
</itemize>


<sect2>vga_emu_fault


<p>
 
 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-&gt;cr2),
 but what are those changes?
 An other problem is, it could eat a lot of time, but it does now also.

<p>Arguments are:&nl;
<itemize>
<ITEM>  scp - A pointer to a struct sigcontext_struct holding some relevant data.
</itemize>


<sect2>vga_emu_init


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  vedt - Pointer to struct describing the type of display we are actually
<ITEM>         attached to.
</itemize>


<sect2>vga_emu_update


<p>
 
 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-&gt;max_max_len' and `veut-&gt;max_len'.
 See the example in env/video/X.c how this works.
 
 If the return value of vga_emu_update() is &gt;= 0, it is the number of changed
 pages, -1 means there are still changed pages but the maximum update chunk size
 (`veut-&gt;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.

<p>Arguments are:&nl;
<itemize>
<ITEM>  veut - A pointer to a vga_emu_update_type object holding all relevant info.
</itemize>


<sect2>vga_emu_switch_bank


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

<p>Arguments are:&nl;
<itemize>
<ITEM>  bank - The bank to switch to.
</itemize>


<sect2>vga_emu_find_mode


<p>
 
 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 (&gt;= 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.

<p>Arguments are:&nl;
<itemize>
<ITEM>  mode   - video mode.
<ITEM>  vmi    - pointer into internal mode list
</itemize>


<sect2>vga_emu_setmode


<p>
 
 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'.

<p>Arguments are:&nl;
<itemize>
<ITEM>  mode   - The new video mode.
<ITEM>  width  - Number of text columns.
<ITEM>  height - Number of text rows.
</itemize>


<sect2>dirty_all_video_pages


<p>
 
 Marks the whole VGA memory as modified.

 


<sect2>vga_emu_set_text_page


<p>
 
 Set visible text page.

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

<p>Arguments are:&nl;
<itemize>
<ITEM>  page      - Number of the text page.
<ITEM>  page_size - Size of one text page.
</itemize>


<sect1>include/vgaemu.h Information

<p>
 Header file for the VGA emulator for DOSEmu.
 
 This file describes the interface to the VGA emulator.
 Have a look at env/video/vgaemu.c and env/video/vesa.c for details.

<sect>The Keyboard group of Modules

<p>
All of the Keyboard handling code is in the &dquot;keyboard&dquot; subdirectory.

Latest addition is SLANG.


<sect1>base/keyboard/keymaps.c Information

<p>
 These are definitions, giving which key is related to which scancode in
 raw keyboard mode. Basically, the code of 'x' on a US keyboard may be that
 of a 'Y' on a German keyboard. This way, all types of keyboard can be
 represented under DOSEMU. Also, the right ALT-key is often a function
 key in it's own right.
 
<sect1>Remarks in base/keyboard/keymaps.c

<p>
 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
 
 
<sect1>base/keyboard/serv_xlat.c Information

<p>
 This module contains the the translation part of the keyboard 'server',
 which translates keysyms into the form in which they can be sent do DOS.
 
 The frontends will call one of the following functions to send
 keyboard events to DOS:

<p><verb>
     putrawkey(t_rawkeycode code);
     putkey(Boolean make, t_keysym key)
     set_shiftstate(t_shiftstate s);
</verb>

 Interface to serv_backend.c is through write_queue(bios_key, shift, raw).

 More information about this module is in doc/README.newkbd

<P>Maintainers:
<p>
Rainer Zimmermann  <htmlurl url="mailto:zimmerm@mathematik.uni-marburg.de" name="&lt;zimmerm@mathematik.uni-marburg.de&gt;">&nl;
<sect1>Functions in base/keyboard/serv_xlat.c

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

<sect2>putrawkey


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

 


<sect2>putkey


<p>
 
 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-&gt;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).

 


<sect2>set_shiftstate


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

 


<sect1>base/keyboard/serv_backend.c Information

<p>
 This module handles interfacing to the DOS side both on int9/port60h level
 (if keybint=on), or on the bios buffer level.
 Keycodes are buffered in a queue, which, however, has limited depth, so it
 shouldn't be used for pasting.
 
 More information about this module is in doc/README.newkbd

<P>Maintainers:
<p>
Rainer Zimmermann  <htmlurl url="mailto:zimmerm@mathematik.uni-marburg.de" name="&lt;zimmerm@mathematik.uni-marburg.de&gt;">&nl;
<sect1>base/keyboard/serv_8042.c Information

<p>
 This code provides truly rudimentary 8042 controller emulation.
 Not having any documentation on the 8042 makes it hard to improve. :)

<sect1>base/keyboard/keyb_raw.c Information

<p>
<sect1>Functions in base/keyboard/keyb_raw.c

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

<sect2>raw_keyboard_init


<p>
 
 Initialize the keyboard for RAW mode.
 
 


<sect1>base/keyboard/keyb_slang.c Information

<p>
<sect1>Functions in base/keyboard/keyb_slang.c

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

<sect2>slang_keyb_init()


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


<sect>The Misc group of Modules

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


<sect1>dosext/misc/emm.c Information

<p>
 This provides the EMM Memory Management for DOSEMU. It was originally part
 of the Mach Dos Emulator. 
 
 Recent work in this area has involved a patch to the Kernel. If this is used
 and the DEFINE MMAP_EMS line used, a faster form of EMS memory support is
 included, using the /proc filesystem.
 
 In contrast to some of the comments (Yes, _I_ know the adage about that...)
 we appear to be supporting EMS 4.0, not 3.2.  The following EMS 4.0
 functions are not supported (yet): 0x4f (partial page map functions),
 0x55 (map pages and jump), and 0x56 (map pages and call).  OS handle
 support is missing, and raw page size is 16k (instead of 4k).  Other than
 that, EMS 4.0 support appears complete.

<sect1>dosext/misc/xms.c Information

<p>
 Currently the XMS 3.0 spec is covered in this file. XMS is fairly simple
 as it only deals with allocating extended memory and then moving it 
 around in specific calls. This spec also includes the allocation of UMB's,
 so they are also included as part of this file. The amount of xms memory
 returned to DOS programs via the XMS requests, or int15 fnc88 is set in
 &dquot;/etc/dosemu.conf&dquot; via the XMS paramter.
 
<sect1>base/async/int.c Information

<p>
<sect1>Functions in base/async/int.c

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

<sect2>DEFAULT_INTERRUPT 


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

 


<sect2>ms_dos


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

 


<sect2>run_caller_func(i, from_int)


<p>
 
 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&num;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

 


<sect2>DO_INT 


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

 


<sect2>setup_interrupts


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

 


<sect2>int_vector_setup


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

 


<sect1>Remarks in base/async/int.c

<p>
 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 &lt; 0xe0 (0:380-0:3ff area)
 - change anything in the vector area _after_ installation - AV
 
<sect1>include/int.h Information

<p>
<sect1>arch/linux/async/sigsegv.c Information

<p>
<sect1>Functions in arch/linux/async/sigsegv.c

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

<sect2>dosemu_fault(int, struct sigcontext_struct);


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

 


<sect2>print_exception_info


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

 


<sect1>arch/linux/async/signal.c Information

<p>
<sect1>Functions in arch/linux/async/signal.c

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

<sect2>signal_init


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

 


<sect2>cli


<p>
 
  Stop additional signals from interrupting DOSEMU.

 


<sect2>sti


<p>
 
  Allow all signals to interrupt DOSEMU.

 


<sect2>handle_signals


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

 


<sect2>SIGNAL_save


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  context     - signal context to save.
<ITEM>  signal_call - signal handling routine to be called.
</itemize>
  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.

 


<sect2>SIGIO_call


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

 


<sect1>Remarks in arch/linux/async/signal.c

<p>
 Check for keyboard coming from client
  For now, first byte is interrupt requests from Client 
 
<sect1>include/ports.h Information

<p>
<sect1>base/misc/dosio.c Information

<p>
<sect1>base/misc/disks.c Information

<p>
<sect1>Functions in base/misc/disks.c

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

<sect2>disk_init


<p>
 
  Test by opening all floppies/hardrives configured.

 


<sect1>dev/misc/lpt.c Information

<p>
<sect1>base/dev/misc/timers.c Information

<p>
 This is the timer emulation for DOSEMU.  It emulates the Programmable
 Interval Timer (PIT), and also handles IRQ0 interrupt events.
 A lot of animation and video game software are dependant on this module
 for high frequency timer interrupts (IRQ0).

 This code will actually generate 18.2 DOS interrupts/second (the code
 here itself will be triggered about 100 times per second). It will even
 happily attempt to generate faster clocks, right up to the point where
 it chokes.  Since the absolute best case timing we can get out of Linux
 is 100Hz, figure that anything approaching or exceeding that isn't going
 to work well.  (The code will attempt to generate up to 10Khz interrupts
 per second at the moment.  Too bad that would probably overflow all
 internal queues really fast. :)

 Speaker emulation, now including port 61h, is also in here. &lsqb;rz&rsqb;

<sect1>Functions in base/dev/misc/timers.c

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

<sect2>initialize_timers


<p>
 
 ensure the 0x40 port timer is initially set correctly

 


<sect2>timer_tick


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

 


<sect2>do_sound


<p>
 
 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&lsqb;2&rsqb;.mode == 2) || (pit&lsqb;2&rsqb;.mode == 3) test in the original
 implementation, it doesn't seem to cause problems though.

 The implementation of speaker_on &amp; 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
 


<sect2>timer_int_engine


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

 


<sect1>base/speaker/speaker.c Information

<p>
 
 The pc-speaker emulator for Dosemu.

 This file contains functions to make a pc speaker beep for dosemu.  

 Actuall emulation is done in src/base/dev/misc/timers.c in do_sound.

 Currenly emulation is only done when the new keyboard is enabled but with a
 little extra work it should be possible to enable it for the old keyboard
 code if necessary. 

 For parts of dosemu that want to beep the pc-speaker (say the video bios)
 &num;include &dquot;speaker.h&dquot;
 Use 'speaker_on(ms, period)'
 to turn the pc-speaker on for 'ms' milliseconds with period 'period'.
 The function returns immediately.

 Use 'speaker_off()'
 To turn the pc-speaker definentily off.  This is mostly useful when exiting
 the program to ensure you aren't killy someones ears :)

 'speaker_on' always overrides whatever previous speaker sound was previously
 given.  No mixing happens.

 For code that wants to implement speaker emulation.  The recommeded method
 is to add a file in src/base/speaker with the necessary code.  Declare it's
 methods in speaker.h (or somewhere accessible to your code).  And call

 'register_speaker(gp, on, off)'
 when your speaker code is ready to function.

  gp may be any void pointer value.

  gp is passed as the first argument to the functions arguments 'on'
  and 'off' when global functions 'speaker_on' and 'speaker_off' are called.
  This allows important state information to be passed to the functions.  And
  reduces reliance on global variables.  

 The functions 'on' and 'off' besides the extra parameter are called just as
 the global functions 'speaker_on' and 'speaker_off' are called respectively.
 
 Before the registered function is no longer valid call 
 'register_speaker(NULL, NULL, NULL)' this will reset the speaker code
 to it's default speaker functions, which will always work.

 --EB 20 Sept 1997

<P>Maintainers:
<p>
Eric W. Biederman  <htmlurl url="mailto:ebiederm+eric@npwt.net" name="&lt;ebiederm+eric@npwt.net&gt;">&nl;
<sect1>base/misc/shared.c Information

<p>
	Memory areas needed to be shared between the DOSEMU process
	and other clients.
<sect1>Functions in base/misc/shared.c

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

<sect2>shared_qf_memory_init


<p>
 
 Setup all memory areas to be shared with clients.

 


<sect1>Remarks in base/misc/shared.c

<p>
 Set to 0 all client request area
 
-----

 Output info required for client activity
 
<sect1>base/misc/dos2linux.c Information

<p>
 
 This file contains a simple system for passing information through to
 DOSEMU from the Linux side. It does not allow dynamic message passing,
 but it intended to provide useful information for the DOS user.
 
 As such, the current set of implemented commands are :
 GET_USER_ENVVAR and GET_COMMAND

 These are made available to the DOSEMU by using the DOS_HELPER interrupt
 (Currently 0xE6) and writing a string into a location passed to this 
 interrupt handler using the registers. In the case of GET_USER_ENVVAR the
 string also contains the name of the environment variable to interrogate.
 (The string is overwritten with the reply).

<sect1>Functions in base/misc/dos2linux.c

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

<sect2>run_unix_command


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

<p>Return values mean:&nl;
<p>Arguments are:&nl;
<itemize>
<ITEM>    buffer - string with command to execute
</itemize>


<sect1>base/misc/ioctl.c Information

<p>
<sect1>Functions in base/misc/ioctl.c

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

<sect2>io_select_init


<p>
 
 Initialize fd_sets to NULL for both SIGIO and NON-SIGIO.
 
 


<sect2>add_to_io_select


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  fd - File handle to add to select statment
<ITEM>  want_sigio - want SIGIO (1) if it's available, or not (0).
</itemize>
 Add file handle to one of 2 select FDS_SET's depending on
 whether the kernel can handle SIGIO.
 
 


<sect2>remove_from_io_select


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  fd - File handle to remove from select statment. 
<ITEM>  used_sigio - used SIGIO (1) if it's available, or not (0).
</itemize>
 Remove a file handle from one of 2 select FDS_SET's depending
 on whether the kernel can handle SIGIO.
 
 


<sect1>base/dev/misc/cmos.c Information

<p>
<sect1>base/dev/misc/lpt.c Information

<p>
<sect1>Functions in base/dev/misc/lpt.c

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

<sect2>printer_init


<p>
 
  Initialize printer control structures

 


<sect1>base/dev/misc/pci.c Information

<p>
<sect1>Functions in base/dev/misc/pci.c

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

<sect2>pci_read_header


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

 


<sect2>pci_read_header


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

 


<sect2>pci_read_header


<p>
 
 Register standard PCI ports 0xcf8-0xcff

 


<sect1>include/doshelpers.h Information

<p>
<sect1>Remarks in include/doshelpers.h

<p>
 The Helper Interrupt uses the following groups:
 
 0x00      - Check for DOSEMU
 0x01-0x11 - Initialisation functions &amp; 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-0x52 - DOSEMU/Linux communications
      50 -- run unix command in ES:DX
      51,52?
      53 -- do system(ES:DX)
 0x7a      - IPX functions
 0x8x   -- utility functions
	0x80 -- getcwd(ES:DX, size AX)
	0x81 -- chdir(ES:DX)
 0xfe      - called from our MBR, emulate MBR-code.
 0xff      - Terminate DOSEMU
 
 There are (as yet) no guidelines on choosing areas for new functions.
 
<sect>The CPU_Intel group of Modules

<p>
These files all relate to Intel-x86 specific code.


<sect1>emu-i386/cpu.c Information

<p>
 CPU/V86 support for dosemu
<sect1>Functions in emu-i386/cpu.c

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

<sect2>cpu_trap_0f


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

 


<sect2>cpu_setup


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

 


<sect1>emu-i386/ports.c Information

<p>
<sect1>Functions in emu-i386/ports.c

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

<sect2>inb


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

<p>Arguments are:&nl;
<itemize>
<ITEM>   port - port to input from.
</itemize>


<sect1>emu-i386/do_vm86.c Information

<p>
<sect1>Functions in emu-i386/do_vm86.c

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

<sect2>vm86_GP_fault


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

 


<sect2>run_vm86


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


<sect1>Remarks in emu-i386/do_vm86.c

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

<p>
<sect1>emu-i386/n_ports.c Information

<p>
 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.
<sect1>Functions in emu-i386/n_ports.c

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

<sect2>port_inb(ioport_t port)


<p>
 
 Handles/simulates an inb() port IO read

 


<sect2>port_outb(ioport_t port, Bit8u byte)


<p>
 
 Handles/simulates an outb() port IO write

 


<sect2>port_inw(ioport_t port)


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

 


<sect2>port_outw(ioport_t port, Bit16u word)


<p>
 
 Handles/simulates an outw() port IO write

 


<sect2>port_ind(ioport_t port)


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

 


<sect2>special_port_inb,special_port_outb


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

 


<sect2>port_init()


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

 


<sect2>extra_port_init()


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

 


<sect2>port_register_handler


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

 


<sect2>port_allow_io


<p>
 

 


<sect2>set_ioperm


<p>
 
 wrapper for the ioperm() syscall, returns -1 if port&gt;=0x400

 


<sect1>Remarks in emu-i386/n_ports.c

<p>
<p><verb>
 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
</verb>
 
-----

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

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

<sect1>emu-i386/cputime.c Information

<p>
<P>Maintainers:
<p>
<sect1>Functions in emu-i386/cputime.c

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

<sect2>GETcpuTIME


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

 


<sect2>GETusTIME(sc)


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

 


<sect2>GETtickTIME(sc)


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

 


<sect2>GETusSYSTIME()


<p>
 
 GETusSYSTIME returns the real CPU time with 1-usec resolution

 


<sect1>Remarks in emu-i386/cputime.c

<p>
 At the heart of the timing system in dosemu &gt;= 0.67.11 is the availability
 of the system time as a 64-bit &lsqb;type hitimer_t&rsqb; monoton value.
 (a 64-bit timer on a 200MHz CPU increments by 2^48 a day).
 
 Dosemu needs this time under two resolutions:
<p><verb>
   - a MICROSECOND resolution for general timing purposes
   - a TICK(838ns) resolution for PIT
</verb>
 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&percnt; accurate esp. if the speed is
 a non-integer multiple of 33.3333).

 dosemu &gt;= 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:
<p><verb>
  - GETusTIME(s)   gives the time in usecs
  - GETtickTIME(s) gives the time in ticks
</verb>
 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.

 
<sect>The Serial group of Modules

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


<sect1>base/serial/ser_defs.h Information

<p>
 ser_defs.h: Include file for all files in the 'serial' subdirectory.
 Please send bug reports and bugfixes to marky@magmacom.com
 Please read the files in this 'serial' subdirectory for more info.
 
<sect1>Remarks in base/serial/ser_defs.h

<p>
 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&lsqb;&rsqb; variable array structure used in serial.c
 
 Most of the serial variables are stored in the com&lsqb;&rsqb; array.
 The com&lsqb;&rsqb; 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&lsqb;x&rsqb;.base_port       The base port address of emulated serial port.
   com&lsqb;x&rsqb;.real_comport    The COM port number.
   com&lsqb;x&rsqb;.interrupt       The PIC interrupt level (based on IRQ number)
   com&lsqb;x&rsqb;.mouse           Flag  mouse (to enable extended features)
   com&lsqb;x&rsqb;.fd              File descriptor for port device 
   com&lsqb;x&rsqb;.dev&lsqb;&rsqb;           Filename of port port device
   com&lsqb;x&rsqb;.dev_locked      Flag whether device has been locked

 The arbritary example variable 'x' in com&lsqb;x&rsqb; 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&lsqb;&rsqb; array works:

   for (i = 0; i &lt; config.numser; i++)
     s_printf(&dquot;COM port number &percnt;d has a base address of &percnt;x&dquot;, 
              com&lsqb;i&rsqb;.real_comport, com&lsqb;i&rsqb;.base_port);

 
<sect1>base/serial/ser_init.c Information

<p>
 ser_init.c: Serial ports initialization for DOSEMU
 Please read the README.serial file in this directory for more info!
 
 Lock file stuff was derived from Taylor UUCP with these copyrights:
 Copyright (C) 1991, 1992 Ian Lance Taylor
 Uri Blumenthal &lt;uri@watson.ibm.com&gt; (C) 1994
 Paul Cadach, &lt;paul@paul.east.alma-ata.su&gt; (C) 1994
 
 Rest of serial code Copyright (C) 1995 by Mark Rejhon

 The code in this module is free software; you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2 of 
 the License, or (at your option) any later version.

 This module is maintained by Mark Rejhon at these Email addresses:
      marky@magmacom.com
      ag115@freenet.carleton.ca
<P>Maintainers:
<p>
Mark Rejhon  <htmlurl url="mailto:marky@ottawa.com" name="&lt;marky@ottawa.com&gt;">&nl;
<sect1>Functions in base/serial/ser_init.c

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

<sect2>serial_init


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

 


<sect1>Items for Fixing in base/serial/ser_init.c

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

<sect1>base/serial/ser_ports.c Information

<p>
 ser_ports.c: Serial ports for DOSEMU: Software emulated 16550 UART!
 Please read the README.serial file in this directory for more info!
 
 Copyright (C) 1995 by Mark Rejhon
 
 The code in this module is free software; you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2 of 
 the License, or (at your option) any later version.

 This module is maintained by Mark Rejhon at these Email addresses:
      marky@magmacom.com
      ag115@freenet.carleton.ca

<sect1>Functions in base/serial/ser_ports.c

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

<sect2>do_serial_in


<p>
 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).
 &lsqb;num = abritary port number for serial line, address = I/O port address&rsqb;
 


<sect2>do_serial_out 


<p>
 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). 
 &lsqb;num = abritary port number for serial line, address = I/O port address,
 val = value to write to I/O port address&rsqb;
 


<sect1>Items for Fixing in base/serial/ser_ports.c

<p>
 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? */

<sect1>base/serial/ser_irq.c Information

<p>
 ser_irq.c: Serial interrupt services for DOSEMU
 Please read the README.serial file in this directory for more info!
 
 Copyright (C) 1995 by Mark Rejhon
 
 The code in this module is free software; you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2 of 
 the License, or (at your option) any later version.

<sect1>Functions in base/serial/ser_irq.c

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

<sect2>serial_int_engine


<p>
 
 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.
 &lsqb;num = port, int_requested = the requested serial interrupt&rsqb;
 
 


<sect2>pic_serial_run 


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

 


<sect2>serial_run 


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

 


<sect1>Remarks in base/serial/ser_irq.c

<p>
 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()?
 
<sect1>Items for Fixing in base/serial/ser_irq.c

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

-----

 Perhaps this can be modified to limit max chain length?

<sect1>base/serial/int14.c Information

<p>
 int14.c: Serial BIOS services for DOSEMU.
 Please read the README.serial file in this directory for more info!
 
 Copyright (C) 1995 by Mark Rejhon
 
 The code in this module is free software; you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2 of 
 the License, or (at your option) any later version.

 This module is maintained by Mark Rejhon at these Email addresses:
      marky@magmacom.com
      ag115@freenet.carleton.ca

<sect1>Functions in base/serial/int14.c

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

<sect2>int14


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


<sect1>New Ideas for base/serial/int14.c

<p>
 If any of you coders are ambitious, try thinking of the following:
 - Converting this into inline assembler and use direct port access 
 
<sect1>base/serial/fossil.c Information

<p>
 fossil.c: FOSSIL serial driver emulator for dosemu.
 
 Copyright (C) 1995 by Pasi Eronen.
 Portions Copyright (C) 1995 by Mark Rejhon
 
 The code in this module is free software; you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2 of 
 the License, or (at your option) any later version.

<sect1>Items for Fixing in base/serial/fossil.c

<p>
 This really should be write-with-wait. */

<sect1>include/serial.h Information

<p>
 serial.h: Include file for port data array for DOSEMU serial.
 Please send bug reports and bugfixes to marky@magmacom.com
 Please read the files in the 'serial' subdirectory for more info.
<sect1>Items for Fixing in include/serial.h

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

<sect>The Mouse group of Modules

<p>
  All of the Mouse handling code is in the &dquot;mouse&dquot; subdirectory.

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


<sect1>base/mouse/mouse.c Information

<p>
<sect1>Functions in base/mouse/mouse.c

<p>
These are the functions defined in base/mouse/mouse.c.

<sect2>mouse_init


<p>
 
  Initialize internal mouse.

 


<sect1>Remarks in base/mouse/mouse.c

<p>
 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 &amp; 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 &amp; 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 by 1.

 -- Eric Biederman 19 August 1998
 
<sect>The Bios group of Modules

<p>
  All of the Bios code is in the &dquot;bios&dquot; 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.


<sect1>base/bios/bios.S Information

<p>
<sect1>base/bios/hlt.c Information

<p>
<sect1>Functions in base/bios/hlt.c

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

<sect2>hlt_init(void)


<p>
 
   Resets all the HLT handlers

 


<sect2>hlt_handle()


<p>
 
 Handles a HLT instruction reached inside the dos emulator.

 


<sect>The PIC group of Modules

<p>
  All of the PIC handling code is in the &dquot;PIC&dquot; subdirectory.


<sect1>base/dev/pic/pic.c Information

<p>
  pic.c is a fairly complete emulation of both 8259 Priority Interrupt 
  Controllers.  It also includes provision for 16 lower level interrupts.
  This implementation supports the following i/o commands:
 
<p><verb>
      ICW1    bits 0 and 1     number of ICWs to expect
      ICW2    bits 3 - 7       base address of IRQs
      ICW3    no bits          accepted but ignored
      ICW4    no bits          accepted but ignored

      OCW1    all bits         sets interrupt mask
      OCW2    bits 7,5-0       EOI commands only
      OCW3    bits 0,1,5,6     select read register, 
                               select special mask mode

     Reads of both pic ports are supported completely.
</verb>

  An important concept to understand in pic is the interrupt level.
  This is a value which represents the priority of the current interrupt.  
  It is used to identify interrupts, and IRQs can be mapped to these 
  levels(see pic.h~). The currently active interrupt level is maintained 
  in pic_ilevel, which is globally available,   A pic_ilevel of 32 means
  no interrupts are active; 0, the highest priority, represents the NMI.
  IRQs 0 through 15 are mapped, in priority order, to values of 1-15
  (there is no IRQ2 in an AT). Values of 16 - 31 represent additional
  interrupt levels available for internal dosemu usage.

     More detail is available in the file README.pic

  Debug information:

  A debug flag of +r or 1r will generate debug messages concerning
  reads and writes to pic ports.  Many of these messages are not yet
  implemented.  A debug flag of 2r will generate messages concerning
  activation, nesting, and completion of interrupts.  A flag of -r
  or 0r will turn off debugging messages.  Flags may be combined:
  to get both 1r and 2r, use a value of 3r.

<sect1>Functions in base/dev/pic/pic.c

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

<sect2>pic_print


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

 


<sect2>write_pic0,write_pic1


<p>
 
 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
<p>Arguments are:&nl;


<sect2>read_pic0,read_pic1


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

 


<sect2>pic_mask,pic_unmask


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

 


<sect2>pic_seti


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

 


<sect2>run_irqs


<p>
 
 run_irqs, which is initiated via the macro pic_run, is the &dquot;brains&dquot; 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.

 


<sect2>do_irq


<p>
 
  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 &gt;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 &dquot;bios&dquot;   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_&lsqb;SEG,OFF&rsqb;, 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

 


<sect2>pic_request


<p>
 
 pic_request triggers an interrupt.  There is presently no way to
 &dquot;un-trigger&dquot; 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.

 


<sect2>pic_iret


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

 


<sect2>pic_watch


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

 


<sect2>pic_pending


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


<sect2>pic_activate


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


<sect2>pic_sched


<p>
 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).
 


<sect1>Remarks in base/dev/pic/pic.c

<p>
 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.
 
<sect1>include/pic.h Information

<p>
<sect>The Sound group of Modules

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



<sect1>dosext/sound/sound.c Information

<p>
<P>Maintainers:
<p>
Alistair MacDonald  <htmlurl url="mailto:alistair@slitesys.demon.co.uk" name="&lt;alistair@slitesys.demon.co.uk&gt;">&nl;
David Brauman  <htmlurl url="mailto:crisk@netvision.net.il" name="&lt;crisk@netvision.net.il&gt;">&nl;
Rutger Nijlunsing  <htmlurl url="mailto:rutger@null.net" name="&lt;rutger@null.net&gt;">&nl;
Michael Karcher  <htmlurl url="mailto:Michael.Karcher@writeme.com" name="&lt;Michael.Karcher@writeme.com&gt;">&nl;
<sect1>Functions in dosext/sound/sound.c

<p>
These are the functions defined in dosext/sound/sound.c.

<sect2>sb_io_read


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  port - The I/O port being read from.
</itemize>
 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.)

 


<sect2>adlib_io_read


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  port - The I/O port being read from.
</itemize>
 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.

 


<sect2>mpu401_io_read


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  port - The I/O port being read from.
</itemize>
 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.

 


<sect2>sb_io_write


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  port - The I/O port being written to.
<ITEM>  value - The value being output.
</itemize>
 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.

 


<sect2>sb_dsp_write


<p>
 
<p>Arguments are:&nl;
<itemize>
<ITEM>  value - The value being written to the DSP.
</itemize>
 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.

 


<sect1>Remarks in dosext/sound/sound.c

<p>
 Write silence could probably be implemented by setting up a
 &dquot;DMA&dquot; transfer from /dev/null - AM
 
<sect1>Items for Fixing in dosext/sound/sound.c

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

<sect1>arch/linux/dosext/sound/linux_sound.c Information

<p>
<P>Maintainers:
<p>
Alistair MacDonald  <htmlurl url="mailto:alistair@slitesys.demon.co.uk" name="&lt;alistair@slitesys.demon.co.uk&gt;">&nl;
David Brauman  <htmlurl url="mailto:crisk@netvision.net.il" name="&lt;crisk@netvision.net.il&gt;">&nl;
Michael Karcher  <htmlurl url="mailto:Michael.Karcher@writeme.com" name="&lt;Michael.Karcher@writeme.com&gt;">&nl;
<sect1>base/dev/dma/dma.c Information

<p>
<P>Maintainers:
<p>
Alistair MacDonald  <htmlurl url="mailto:alistair@slitesys.demon.co.uk" name="&lt;alistair@slitesys.demon.co.uk&gt;">&nl;
David Brauman  <htmlurl url="mailto:crisk@netvision.net.il" name="&lt;crisk@netvision.net.il&gt;">&nl;
<sect1>Remarks in base/dev/dma/dma.c

<p>
 **** 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.
 
<sect1>Items for Fixing in base/dev/dma/dma.c

<p>
 : 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 (!) 

<sect>The FileAccess group of Modules

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


<sect1>dosext/mfs/mfs.c Information

<p>
 This is the file redirector code for DOSEMU. It was built on the Mach
 DOS redirector and as such continues that copyright as well in 
 addition the GNU copyright. This redirector uses the 
 DOS int2f fnx 11 calls to give running DOS programs access to any 
 Unix mounted drives that permissions exist for.
 
<sect1>Remarks in dosext/mfs/mfs.c

<p>
 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.
 
 
<sect1>Items for Fixing in dosext/mfs/mfs.c

<p>
 We probably should use llseek here for file &gt; 2 GBytes

-----

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

<sect>The Threads group of Modules

<p>
This is the (non-POSIX) threads package, that uses the basic clone interface
of the Linux-kernel.

Now, what is the difference between threads and
processes? A process runs totaly isolated from the other processes in the
Unix system, it concurrently request resources and is controled by the
operating system such that it does no harm to the other processes.
Interfaceing between processes is cost intensive performance wise.

A thread, on the other hand, is scheduled within the context of _one_ process,
shares most (if not all) of its resources, and has to cooperate with the
other threads in order to do no harm to whole thread group. Interfaceing
between threads is very cheap performance wise, hence, using threads is what
You should do when having _one_ application that needs to do work in
parallel.


<sect1>arch/linux/threads/lt-threads.c Information

<p>
 This thread package does _NOT_  POSIX compatible threading.
 As its name says: it is a tiny fast alternative using Linux cloning.
 The aim was to avoid as much unnecessary sys_calls as possible.
 Locking is _NOT_ done via IPC semaphores, instead we use a user level
 atomic technique, when the resource is free, there will be no sys_call atall.
 
 Each thread has its own 'Thread Control Block' (TCB) at the bottom of its
 stack. Hence to identify itself it doesn't need to go over getpid().

 However, there are restrictions given by the technique used:

<p><verb>
   - The total maximum number of threads is 27.
   - The size of the stack must be at power of 2 and is equal
     for all threads. It is not a problem to make the stack area huge,
     because only those pages actually used will be allocated (paged in)
     by the system. Though you will be estonished what /proc/<pid>/status
     is telling you about stack consumption, ... just ignore it;-)
   - You have to lock/unlock resource_libc when using non-reentrant parts
     of libc (malloc _is_ no-reentrant).
   - You must not use atexit, exit, _exit atall. instead use the techniques
     and functions supplied by lt-threads.
</verb>

<P>Maintainers:
<p>
Hans Lermen  <htmlurl url="mailto:lermen@fgan.de" name="&lt;lermen@fgan.de&gt;">&nl;
<sect1>Functions in arch/linux/threads/lt-threads.c

<p>
These are the functions defined in arch/linux/threads/lt-threads.c.

<sect2>Making room on the stack


<p>
<p><verb>
static char *force_stack_expand(unsigned long address)
</verb>
 The kernel has a feature, such that it doesn't
 allow grow down the stack below the current stack pointer.
 This makes sense in single threaded applications,
 but is bad for threading purposes:
<p><verb>
   1.	You are forced to put the stacks into the heap (below 1st giga)
	hence it is less protected against overwriting then normally.
   2.	The 1 giga stack address space isn't used any more, and
	you may have problems with address space, on huge programs
	that use huge arrays (data bases, matrices).
</verb>
 We trick out the kernel by expanding the stack vma to a given
 value (setting ESP to the bottom and thouching it).
 ( look at do_page_fault in arch/i386/mm/fault.c how it
   treats growing down of stack )
 


<sect2>Setting User Space Stack limits


<p>
<p><verb>
int make_stack_unlimited(int drop_privs)
</verb>
 When running as user, current Linux has a stacklimit of 8Mb.
 ( no way to change that via bash ulimit )
 This is enough for normal stacksizes, however, if you need more
 You need some way to set it to 'unlimited'. This only can be done
 as root, hence setting the suid bit is needed.
 The below function sets the limit high, and (in case drop_privs)
 will drop root priviledges before return.
 


<sect2>Queuing tools


<p>
 These two functions have to be used when maintaining queues of various
 sorts. You may cast to your private queue entry structure as long as
 the top of this structure fits `struct queue_entry':
<p><verb>
	struct queue_entry {
		struct queue_entry *next;
		struct queue_entry *last;
	};
</verb>
<p><verb>
void append_to_queue(struct queue_entry *existing, struct queue_entry *new)
</verb>
<p><verb>
void remove_from_queue(struct queue_entry *entry)
</verb>
 Note: An existing entry _must_ have valid pointers in `next', `last'.
 We build the head of a queue with an empty queue_entry haveing
 `next', `last' poining to itself.
 
 


<sect2>Avoiding Libc reentrancy Problems


<p>
 Because all threads share the same VM, libc needs to be reentrant.
 This isn't the case for a lot of functions ( malloc() is one on them).
 Though newer libc can be made reentrant (needs the -D_REENTRANT on compilation
 of _each_ object file), this feature has a performance lost due to the
 overhead that applies to evry libc call. As we exactly know _when_ we
 come into trouble with libc, the faster (and IMHO) better solution is to
 to take care of this at application level.
 
 For this to accomplish we have to put a (un)lock_resource(resource_libc)
 bracket around those involved libc functions. The most frequently used ones
 are offered by the threads package, including such locking.
 Some of those are:
<p><verb>
void *locked_malloc(size_t size)
</verb>
<p><verb>
void locked_free(void *p)
</verb>
 The prototype is exactly as you expect it from the libc functions.
 


<sect2>getting page aligned memory from the heap


<p>
 If you need a page aligned piece of memory, you usualy would use valloc().
 However, you can't free that memory later. For this purpose you may use the
 below functions, which are put on top of malloc()/free().
<p><verb>
void *page_malloc(size_t size)
</verb>
<p><verb>
void page_free(void *ptr)
</verb>


<sect2>Name List Tools


<p>
 The below functions are used for handling small name lists (you may call
 it directories). All major resources in lt-threads are accessable also by
 their names, as they are defined on creation time. Especially when it comes
 to link between different processes (thread cores) and different maschines,
 we look up the resources (such as mailboxes, threads, services) via name lists.
 
 The global structures used for building namelists (as defined in lt-threads.h)
 are:
<p><verb>
struct name_list_entry {
	char *name;
	union {
		void *p;
		struct tcb *tcb;
		struct lock_struct *lock;
		struct mbox *mbox;
		int idata;
	} u;
};

struct name_list {
	int size;
	int count;
	struct name_list_entry list[0];
};
</verb>
 The follow functions are available:
<p><verb>
struct name_list *create_namelist(int numentries)
</verb>
<p><verb>
int lookup_name_list(struct name_list *list, char *name)
</verb>
<p><verb>
void * get_name_list_value(struct name_list *list, char *name)
</verb>
<p><verb>
int set_name_list_value(struct name_list *list, char *name, void *value)
</verb>
<p><verb>
int insert_name_list_entry(struct name_list *list, char *name, void *value)
</verb>
<p><verb>
int delete_name_list_entry(struct name_list *list, char *name)
</verb>


<sect2>Exiting a thread


<p>
 Once the threading system is setup, you never should use exit() or
 _exit(). Instead use exit_thread(0) to exit the running thread,
 exit_thread(tcb) to kill an other thread and exit_all() to terminate
 all threads.
<p><verb>
void exit_thread(struct tcb *tcb)
</verb>
<p><verb>
void exit_all(int exit_code)
</verb>


<sect2>Suspending / resuming a thread


<p>
 When a thread has nothing valuable to do (e.g. it is waiting for
 some event to happen), it should go asleep. The following function
 supends the current running thread:
<p><verb>
void suspend_thread()
</verb>
 With the follow function a thread can awake a sleeping thread.
 This may (but need not) happen imediately such that the calling thread
 has been sleeping before retuning from resume_thread()
<p><verb>
void resume_thread(struct tcb *tcb)
</verb>
 To suspend a thread for a given time interval (not resume_thread() needed
 to awaken it later) the function thread_usleep can be used.
<p><verb>
 Note: we use our own usleep to avoid
  A) problems with signal stuff
  B) problems with libc
</verb>
<p><verb>
void thread_usleep(int useconds)
</verb>


<sect2>Locking Resources


<p>
 
 The below locking scheme implements userspace semaphores,
 that in the most frequent cases do _not_ enter the kernel.
 ( doesn't use IPC or kernel semphores )
 It depends on the atomic_reserv/free() algorithme defined above
 and won't work with other locking strategies, that cannot
 `reserve and queue' with _one_ atomic operation.

 The win of this algorithme is _much_ more speed,
 the disadvantage is that you can't have more then 27 threads.
 (though, on 64-bit machines it could be 58 threads)

 All locking function rely on the following structure
<p><verb>
struct lock_struct {
	int used;
	int id;
	int owner_count;
	struct tcb *owner;
	int successor_id;
};
</verb>
 However, you should not manipulate them manually.
<p><verb>
struct lock_struct *create_resource(char *name)
</verb>
 create_resource returns a pointer to a newly created resource.
 This one also is then added to the resources namelist so you may
 look up for then `name'. If there are too many resources NULL will
 be returned.
 The following two functions are used to lock and unlock a previosly
 created resource. A call to lock_resource() will put the thread into
 sleep state, when the resource is already locked by an other thread.
 A call to unlock_resource() will awake a thread, that has been waiting on
 the resource.
<p><verb>
void lock_resource(struct lock_struct *lock)
</verb>
<p><verb>
void unlock_resource(struct lock_struct *lock)
</verb>
 The below function is a special one: The owner of a lock may dedicate
 the lock to a given other thread instead of just releasing it.
 This will change the normal scheduling of locks.
 (for example, this is used by the message routines)
<p><verb>
void transfer_resource(struct lock_struct *lock, int successor_id)
</verb>


<sect2>Sending and receiving messages


<p>
 A threading system without message transfer would be worthless.
 We have it ;-)
 
 All messages can be send to `mailboxes', that were created before.
 The size of the message queue within a mailbox can be defined at
 creation time. When a sending thread hits a queue overflow in the mailbox,
 the sending thread is put asleep and queued for later to be awaken.
 When a receiving thread hits an empty mailbox, it also gets asleep.
 A sending thread on an empty mailbox awakens a sleeping receiver,
 A receiving thread on a full mailbox awakens a sleeping sender.
<p><verb>
mbox_handle create_local_mailbox(char *name, int numentries)
</verb>
<p><verb>
mbox_handle get_mailbox(char *name)
</verb>
<p><verb>
mbox_handle get_mailbox_wait(char *name)
</verb>
<p><verb>
void sendmessage(mbox_handle mbx, struct msg *msg)
</verb>
<p><verb>
struct msg *receivemessage(mbox_handle mbx)
</verb>
<p><verb>
int mailbox_is_empty(mbox_handle mbx)
</verb>


<sect2>Creating (starting) a thread


<p>
 Any thread can create child threads. You must pass the address of
 the function, that contains the thread's code and (optionaly)
 pass the thread a private parameter pointer.
<p><verb>
struct tcb *create_thread(thread_function_type *thread_code, void *params)
</verb>
 A little bit different is the creation of the `father of all threads',
 the original Unix process itself. In order to let it also use the
 threads related functions, it must be converted into a thread.

 `init_zero_thread()' makes the starting parent process behave
 as a normal thread and threfore this function call must come before
 any other thread related call. It initializes the thrreads system.
<p><verb>
struct tcb *init_zero_thread(int stacksize)
</verb>
 To obtain the pid of any thread please use the threads_getpid() instead
 of the system call getpid(). It may be called any time and returns the
 pid of the current process, when no threading is active (before init_thread0())
 If `tcb' is NULL, it returns the pid of the current thread,
 if -1 or THREAD0_TCB it returns the pid of `the father of all threads'
 (thread0).
<p><verb>
pid_t threads_getpid(struct tcb *tcb)
</verb>


<sect2>Some debugging aids


<p>
 
 To make your life a bit easier (and because GDB has problems
 debugging a thread group), here some usefull functions

<p><verb>
int locked_printf( const char *fmt, ...)
</verb>
<p><verb>
void print_tcb(struct tcb *tcb)
</verb>
<p><verb>
void print_resource(struct lock_struct *lock)
</verb>
<p><verb>
void print_mbox(mbox_handle mbx)
</verb>


<sect1>include/lt-threads.h Information

<p>
<sect1>Functions in include/lt-threads.h

<p>
These are the functions defined in include/lt-threads.h.

<sect2>The thread itself


<p>
<p><verb>
typedef void thread_function_type(void *params);
</verb>
 All treads are functions of this type, when control reaches end of
 this function, the thread exits the same as with exit_threads(0).
 The 'params' pointer can be passed on create_tread().
 


<sect2>A thread's exit function


<p>
<p><verb>
typedef void thread_exit_function_type(void);
</verb>
 A thread must _not_ use atexit() to register a exit-function
 (problems with non reentrancy of libc).
 Instead, it may use the tcb-&gt;exit_func pointer point to a function
 of below type. However, the old value of tcb-&gt;exit_func must
 be saved on a _static_ place and restored within the exit function.
 This way a a chain of exit functions will be called on a
 `last-in first-out' policy.
 


<sect2>Accessing a thread's TCB


<p>
 All thread private data is on the stack, there may be private data
 allocated on the heap, but the pointers to those areas should be itself
 on the stack. As long as access happens within scope of the thread function
 itself (or within local functions within function) this needs no extra
 handling. However, calling an other function that needs to access thread
 private data may be a problem. This problem can be solved by putting all
 this data into a private structure and starting the thread by passing
 it a pointer to this structure. Now, within scope of the thread one has
 access to this pointer via.
<p><verb>
 OWN_TCB->params;
</verb>
 The TCB itself always is on bottom of the stack, hence it is also
 available within a signal handler.
 


<sect2>Looping through all TCBs


<p>
 It may be necessary to scan data of all running threads or
 doing something special like notifying e.t.c. To acomplish this you
 should use the macro FOR_ALL_TCB such as
<p><verb>
 struct tcb *tcb;
 int id;
 FOR_ALL_TCB(id,tcb) {
    locked_printf("thread %d tcb is at address %p\n", id, tcb);
 }
</verb>
 


<sect2>Atomic inline Functions


<p>
 This set of functions is mainly used within the threads package itself,
 however, you may find them usefull for your stuff too.
 
 Below function atomically reserves 'resource' and queues ID.
 When the reservation was successfull (i.e. if 'resource' was -1 before)
 the function returns -1, otherwise '0'.
 Id must be a number in the range 0..27.
 In any case bit 'idnum' is set in resource. Due to the technique used
 for being atomic, only 27 of 32 bits in the integer can be used.
<p><verb>
static __inline__ int atomic_reserv(int *resource, int id)
</verb>
 Below function frees a previously with atomic_reserv reserved resource
 If there are still IDs queued, the function returns with 0, otherwise -1.
<p><verb>
static __inline__ int atomic_free(int *resource, int id)
</verb>
 Below function return the highest priority queued ID in the resource
 or -1, if none is queued.
 Format of 'resource' is as in atomic_reserv and atomic_free.
<p><verb>
static __inline__ int get_lowest_waiting_id_from_resource(int resource)
</verb>
 Below function increases `flag' atomically and returns -1 if increasing
 did result in transition from negativ to positive, else returns 0.
<p><verb>
static __inline__ int lt_atomic_inc(int *flag, int increment)
</verb>
 Below function decreases `flag' atomically and returns -1 if decreasing
 did result in transition from positive to negative, else returns 0.
<p><verb>
static __inline__ int lt_atomic_dec(int *flag, int decrement)
</verb>
 Below function atomicaly tests and sets bit `bitnum' in the bitfield
 pointed to by `addr'. It returns 0 if the bit was 0 before, else -1.
<p><verb>
static __inline__ int atomic_bitset(void *addr, int bitnum)
</verb>
 Below function atomicaly tests and clears bit `bitnum' in the bitfield
 pointed to by `addr'. It returns 0 if the bit was 0 before, else -1.
<p><verb>
static __inline__ int atomic_bitclear(void *addr, int bitnum)
</verb>


<sect2>Misc inline Functions


<p>
 This set of functions is mainly used within the threads package itself,
 however, you may find them usefull for your stuff too.
 
 search_lowest_bit
 returns the index of lowest bit set or -1, if not found
 `fieldsize' must be multiple of 32
<p><verb>
static __inline__ int search_lowest_bit(void *addr, int fieldsize)
</verb>
 As its name says: roundup_to_power_of_2
<p><verb>
static __inline__ int roundup_to_power_of_2(int val)
</verb>


<sect1>Data Definitions in include/lt-threads.h

<p>
These are the structures and/or data defined in include/lt-threads.h.

<sect2>TCB  (Thread Control Block)


<p>
 The TCB is the main data structure, that is unic to each thread.
 It alway is at bottom of the thread's stack and can be accessed
 using the OWN_TCB macro. This also is valid while in signal handlers.
<p>Elements are:&nl;
<itemize>
<ITEM> 	struct queue_entry link;
<ITEM> 	pid_t pid;
<ITEM> 	int tcb_id;
<ITEM> 	int threadflags;
<ITEM> 	struct tcb *parent;
<ITEM> 	thread_function_type *thread_code;
<ITEM> 	void *params;
<ITEM> 	unsigned long stack_size;
<ITEM> 	int suspend_count;
<ITEM> 	char owning_locks&lsqb;MAX_RESOURCES&gt;&gt;3&rsqb;;
<ITEM> 	jmp_buf exit_jmpbuf;
<ITEM> 	thread_exit_function_type *exit_func;
<ITEM> 	int exit_code;
<ITEM> 	uid_t uid, euid;
<ITEM> 	gid_t gid, egid;
</itemize>


<sect>And Finally ...

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




</article>
