8. The Misc group of Modules

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

8.1. Functions in base/async/int.c

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

8.1.1. DEFAULT_INTERRUPT

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

8.1.2. ms_dos

int0x21 call

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

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

8.1.3. run_caller_func(i, from_int)

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

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

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

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

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

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

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

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

8.1.4. DO_INT

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

8.1.5. setup_interrupts

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

8.1.6. int_vector_setup

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

8.2. Remarks in base/async/int.c

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

-----

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

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

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

8.3.1. dosemu_fault(int, struct sigcontext_struct);

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

8.3.2. print_exception_info

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

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

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

8.4.1. SIG_init

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

8.4.2. signal_init

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

8.4.3. cli

Stop additional signals from interrupting DOSEMU.

8.4.4. sti

Allow all signals to interrupt DOSEMU.

8.4.5. handle_signals

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

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

8.4.6. SIGNAL_save

Arguments are:

  • context - signal context to save.

  • signal_call - signal handling routine to be called.

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

8.4.7. SIGIO_call

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

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

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

8.6. Functions in base/misc/disks.c

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

8.6.1. disk_init

Test by opening all floppies/hardrives configured.

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

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

8.7.1. initialize_timers

ensure the 0x40 port timer is initially set correctly

8.7.2. timer_tick

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

8.7.3. do_sound

do_sound handles the _emulated_ mode pc-speaker emulation.

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

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

Major Changes from version written by Rainter Zimmerman.

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

o Added a generic interface to allow multiple speaker backends.

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

--EB 21 September 1997

8.7.4. timer_int_engine

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

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

PLEASE NOTE

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

8.8. Functions in base/misc/shared.c

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

8.8.1. shared_qf_memory_init

Setup all memory areas to be shared with clients.

8.9. Remarks in base/misc/shared.c

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

8.10. Functions in base/misc/dos2linux.c

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

8.10.1. run_unix_command

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

Return values mean:

Arguments are:

  • buffer - string with command to execute

8.11. Functions in base/misc/ioctl.c

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

8.11.1. io_select_init

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

8.11.2. add_to_io_select

Arguments are:

  • fd - File handle to add to select statment

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

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

8.11.3. remove_from_io_select

Arguments are:

  • fd - File handle to remove from select statment.

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

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

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

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

8.12.1. printer_init

Initialize printer control structures

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

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

8.13.1. pci_read_header

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

8.13.2. pci_read_header

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

8.13.3. pci_read_header

Register standard PCI ports 0xcf8-0xcff

8.14. Functions in base/dev/misc/joystick.c

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

8.14.1. joy_reader_set

Assigns the Linux joystick reader to the one specified. Sets the Linux axis ranges based on what joystick API is being used.

8.14.2. joy_emu_button_set

Update the button status for each joystick.

We must perform "button mapping" if only the first joystick is enabled ie. we are required to map the "excessive" buttons (>2) from the first joystick onto the second: -- 3rd button of 1st joy --> 1st button of 2nd joy -- 4th button of 1st joy --> 2nd button of 2nd joy

8.14.3. joy_emu_axis_set

Update the axis status for each joystick.

We must perform "axis mapping" if only the first joystick is enabled ie. we are required to map the "excessive" axes (>2) from the first joystick onto the second: -- 3rd axis of 1st joy --> 2st axis of 2nd joy -- 4th axis of 1st joy --> 1st axis of 2nd joy (yes, these are reversed deliberately because it's what happens in DOS)

8.14.4. joy_emu_axis_conv

Convert a Linux joystick reading to a DOS one by making use of the differences in the allowable ranges of joystick readings.

NOTE: I don't know whether or not Linux returns exponential readings for the joystick but (apparently) DOS programs expect the reading to be exponential and so if this is to be fixed, it should probably be done in this function.

8.14.5. joy_linux_process_event

Update global joystick status variables given a Linux joystick event.

8.14.6. joy_linux_read_events

Process the event queue for _both_ linux joysticks using nonblocking reads with the new joystick API (joy_reader_new).

This must be done before any joystick status is given to DOS as all events are queued until they are processed and we want to return the current state of the joystick -- not what it was some time ago. _Both_ joysticks are processed here because of axis/button mapping affecting the status of the emulated joysticks (what DOS sees).

8.14.7. joy_linux_read_buttons_(family)

Eventually called from DOS to get the button status of joysticks. The threaded version will simply get the readings from global variables. The unthreaded versions will perform non-blocking reads using the old joystick API.

8.14.8. joy_linux_read_axis_(family)

Eventually called from DOS to get the axis status of joysticks. The threaded version will simply get the readings from global variables. The unthreaded versions will perform non-blocking reads using the old joystick API.

The @param invalid_val is the value to return to signify a non-existent axis.

8.14.9. joy_bios_read

This is the int15 function 0x84 handler (ie. BIOS joystick emulation), called from src/base/async/int.c.

The real BIOS actually reads its values straight from the joystick port (0x201) but we don't bother because we can read it from globals faster :)

Because of this, it returns the joystick axis readings with the same range as port 0x201 BUT for some reason, a real BIOS has a different range of joystick readings than direct port access (anyone know why?). No programs seem to expect a certain range of values except for Alley Cat which seems to want a range of about 1-50 but only from port 0x201.

8.14.10. joy_port_inb

This function emulates reads from the joystick port (0x201) -- this is the most common way of detecting and reading the joystick.

The real implementation of this port actually times out and resets the equivalent of the joy_port_x and joy_port_y axis counters if the time between 2 reads is too great (how great?) but no programs, I have seen, make use of this behaviour.

8.15. Remarks in base/dev/misc/joystick.c

Linux joystick readers:

We make a runtime decision based on the detected joystick API version (and #ifdef USE_PTHREADS) on which reader to use. We can select from the following readers:

1. joy_reader_nojoy: simply tells DOS programs that you have no joystick 2. joy_reader_old: uses old, non-blocking joystick API (<1.0.0); limited to 2 axes 3. joy_reader_new: uses new, non-blocking joystick API (>=1.0.0); a (little) slower than joy_reader_new_threaded 4. joy_reader_new_threaded: uses new, BLOCKING joystick API (>=1.0.0); efficient but requires pthreads

-----

Register the joystick ports so that correct port values are returned for programs that try to detect the joystick (or the lack of one).

-----

if the 2nd joystick is enabled, we ignore any button >= 2 regardless of which joystick it is (if it's the 1st, the 2nd joystick would overwrite its buttons; if it's the 2nd, it would be out of range)

-----

if the 2nd joystick is enabled, we ignore any axis >= 2 regardless of which joystick it is (if it's the 1st, the 2nd joystick would overwrite its axes; if it's the 2nd, it would be out of range)

-----

Here we set the range of possible axis readings for Linux. You should _not_ change these values unless you know what you are doing.

They are later used in joy_emu_axis_conv() as part of a calculation to compress axis readings to an acceptable range for DOS programs (usually somewhere between 5 and 150).

-----

Apparently, the Carry Flag is cleared if int15 function 0x84 exists and it is set if it doesn't exist.

But what does this mean? Does the existence of such a BIOS function depend on the existence of a Game Card/SoundBlaster, or does it just mean that there is such an implemented BIOS function, regardless of whether or not you have a joystick?

I have never seen a real BIOS set the Carry Flag on this call, even on a computer without a joystick -- so to mimick what happens in the real world, I just clear the Carry Flag regardless of whether the user has a joystick or not. This could be incorrect behaviour so it may have to be changed in the future.

-----

Here we set bits based on joystick axis counters. The code here is particularly tricky and if you try to change it, you will probably break it :)

-----

Here we read the button status from Linux (programs can read the button status from the port, _without_ making a dummy write to the port first so the Linux read must be done _here_) and return it.

8.16. Items for Fixing in base/dev/misc/joystick.c

does this code work for ports other than 0x201? */

-----

joy_reset() is called immediately after joy_init(), which is rather inconvenient (anyone heard of a port_unregister_handler()?) so we don't bother resetting at all but in the future this could cause problems */

-----

I've lost my joystick Y-cable (lets you connect two joysticks to one gameport) so the code to handle two joysticks is totally untested! */

-----

What happens if you read a word from the joystick port? Analysis of a real DOS system shows that it reads a byte and doubles it up but I don't know if this is the correct behaviour... */

-----

joy_port_outw is not exactly correct at all but what would you do? */

8.17. Remarks in include/doshelpers.h

The Helper Interrupt uses the following groups:

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

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