1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
Description of Modules Used Within FreeCOM
-- 2000/07/15 ska
The information of this document is obsolte!
FreeCOM uses some kind of free-standing pieces of code that perform
some low-level functions and are shared among all copies of FreeCOM
currently loaded into memory. These modules are plain memory images
typically less than 64KB and are loaded into their own block of memory.
Because their useage is no furtherly predefined and they do not
necessarily hook any interrupts or such they are tagged by magic
number and actively searched by any program that needs to find them.
When loaded a module is just a block of memory, but owned by the system.
The tag is located within their MCB, within the lower eight bytes.
FreeCOM uses the tags "FCOM_###", where the "###" identifies the
module, e.g. ERR is the Critical Error handler.
To find such module a program must work the MCB chain and search the
lower part of the MCB for the tag. To do this, the mcb_forAll()
enumerator of the SUPPL library is used.
When a module is removed from memory, the underscore is changed into
a dash in order to leave the knowledge behind that the module existed
there some time, but invalidate it for module searches.
To load a module the DOS API is used in order to guarranty that really
a new MCB is created and the necessary changes to the MCB are made.
To unload a module the changes are reversed and the block memory
removed.
The communication between a module and the copies of FreeCOM sharing
the module among them will be accomplished by a far pointer that
points to the data required by the module, but generated by or for
a particular copy of FreeCOM. This pointer is located at the very
beginning of the module, thus, the four bytes at
MK_FP(segment_of_module, 0)
This pointer references a structure containing all necessary data fields.
In FreeCOM modules are stored as resources, appended to the executable
and, therefore, can be easily located and loaded into memory.
====
Example: The Critical Error handler
Its resource ID is major: 0x01.
The "structure" used to pass data between the module and the copy of FreeCOM
just contains a flag, whether or not AutoFail is active.
Because during the run of some programs new copies of FreeCOM could be spawned,
they search the MCB chain for the already loaded module and overwrite the
pointer with their own, then the current INT-24 handler is overwritten
by the address of the module. On termination they restore the previous pointer.
====
Problems with this implementation:
P1: Invalid pointers
This scenario assumes that no copy of FreeCOM dies before restoring the
previous pointer and that no third copy is spawned asynchroneously,
which does _not_ terminate before the second copy terminates.
I don't know if there is a solution for the second case in DOS at all,
but the first one can seriously trash the system and may come up especially
during the early implementation days quite often.
One possible solution is to rely on already available mechanism of DOS,
though, they might not exist for all specific modules.
The algorithm DOS handles the Critical Error handler is as follows:
On creation of a process the current INT-24 handler is saved into a
field of the PSP of the process. On run-time the process can overwrite
the INT-24 handler with its own, but is not required to restore the
previous handler, because on termination of the process the saved
copy of INT-24 is restored automatically.
This mechanism could be used to overcome above problem by this:
Each copy FreeCOM contains a stub that hooks INT-24, loads some registers
with a pointer to the module and jumps into the shared code.
That way the pointer that identifies which context to process is indirectly
part of the actual INT-24 pointer, which, as shown above, is stabilized by
DOS mechanisms. That way a valid INT-24 automatically implies a valid
context pointer.
|