For BGii users, this doc file is superseded by Appendix I in the BGii Manual (12/22/86) 1/14/85 Plu*Perfect Systems Resident System Extension Modules Resident system extensions provide a standardized method of adding semi-permanent features to the basic CP/M operating environment. PluPerfect Systems has developed a uniform specification for extension modules that provides these key features: - mutual compatability of several modules - removability of modules (in reverse order of loading) - standardized loading of modules This method of extending basic operating system functions is used extensively in Plu*Perfect products -- The Backgrounder, its major resident utilities (SPOOL, SNAPPY[snapshot,notepad,snapfile],LINEDIT, XSNAPPY[snapshot,notepad,snapfile,printpad],BGCALC, BGPRINT, SNAPGRAF), and the DateStamper (which is not, however, removable). The Backgrounder Accessory disk contains source code for BGPRINT, a relatively simple system extension. It can be used as is, enhanced, or used as a model for customized system extensions. MODULE FUNCTIONS Each module consists of an 18-byte header in a standard format, several standard functions, and custom routines that perform the module's particular functions. The header includes the following information: 1. at its lowest address, a jump to the BDOS entry point 2. a jump to the module's warm-boot routine 3. a jump to the module's remove routine 4. the address of the bios warmboot entry point 5. the address of the first byte of the module that must be protected 6. the address of the module's name 7. a jump to the warmboot routine of the next (higher) module The required module functions are module_warmboot, module_remove, and module_name_string. Module_warmboot must: - restore the bios warmboot address at 0001 - if there is no lower resident system extension module, install the module's protect address at 0006 - jump to the next warmboot routine Module_remove must: - restore all addresses in the operating system that were patched when the module was loaded - set the carry flag Module_name_string: - a nul or hi-bit terminated module name and version string The remaining module code performs the custom functions of the module. It helps to understand the relationship of different modules by referring to the memory maps, shown below. LOADER FUNCTIONS In outline, the loader must: 1. Announce itself 2. Check the system environment to be sure that: a. no non-permanent (non-resident-system-extension) module is in memory b. that The Backgrounder is in memory, if required. c. that the module to be loaded is not already in memory 3. Install standard module parameters a. calculate system addresses b. relocate and move the resident module code to its high location c. install header addresses d. install warmboot and remove addresses 4. Install module-specific parameters a. divert module-supplied bios functions b. other parameters 5. Install module data from the loader configuration area (if any) 6. Announce a successful installation of the named module 7. Jump to a warmboot The loader must know the relevant addresses in the system extension module in order to patch the module into the control chain. In the example this communication is acomplished by an inelegant, but workable device -- a parameter record that is shared by both the loader and the overlaying module code. By assembling each with the same labels at the addresses in that record, the module is able to pass its needed address offsets to the loader. Our convention is that the module area 0000H - 00ffH is reserved for parameters, followed by the module code beginning at 0100H. A debugger (DDT) is used to overlay the module and its bitmap onto the end of the loader. The layout of the loader is: 0100 Loader code ... ... 0700 relocation routine 0701-0702 length of module code 0800 parameter record 0900 Module code (0000 origin) ... ... 0900+length module relocation bit map The EX batch-processing script BGPRINT.SUB will automatically make a new BGPRINT.COM from the source files. PRODUCING A RESIDENT SYSTEM EXTENSION Code for a resident system extension consists of the high module, which will remain resident until removed (or cold-boot), and the module loader. The module itself is most conveniently written for a relocating assembler; the assembled code is then relocated by the loader, which also patches the module's linkages into the bios chain. The Accessory disk includes a complete example, BGPRINT. We have written it for the Digital Research RMAC assembler and LINK-80 linker (although for production we more often use a more powerful assembler/linker). LINK-80 produces page-relocatable (PRL) files which contain the code relative to an origin of 0000 and a bitmap of the code bytes that are relocatable. BGPRINT.ASM is the source file for the relocatable high module; LOADBGPR.ASM is the source for the loader. Each can serve as a prototype for developing custom system extensions, and only sections of the loader will need customization for another application. MEMORY MAPS Fig 0. Before modules are loaded: {bios jmp vector} WBOOT: jmp BIOSWB CONST: jmp BIOSCS CONIN: jmp BIOSCI ... LIST: jmp BIOSLIST ... Fig 1. After Module 1 is loaded: {bios jmp vector} {module header:} prot1: jmp BDOSENTRY WBOOT: jmp wbent1 wbent1: jmp wb1 CONST: jmp BIOSCS jmp remove1 CONIN: jmp BIOSCI wbaddr1 ... protadd1 LIST: JMP list1 nameadd1 ... uwboot1: jmp BIOSWB {module code} wb1: restore 0001h if bottom module, restore 0006 jmp uwboot1 remove1: restore WBOOT+1 restore LIST+1 set carry list1: (custom code) jmp BIOSLIST name1: nul-terminated mod. name Fig 2. After Module 2 is loaded: {bios jmp vector} {module1 header:} {module2 header:} prot1: jmp BDOSENTRY prot2: jmp BDOSENTRY WBOOT: jmp wbent2 wbent1: jmp wb1 wbent2: jmp wb2 CONST: jmp BIOSCS jmp remove1 jmp remove2 CONIN: jmp BIOSCI WBOOT WBOOT ... prot1 prot2 LIST: JMP list2 name1 name2 ... uwboot1: jmp BIOSWB uwboot2: jmp wbent1 wb1: restore 0001h wb2: restore 0001h {if bottom module, if bottom module, restore 0006} restore 0006 jmp uwboot1 jmp uwboot2 remove1: remove2: restore WBOOT+1 restore WBOOT+1 restore LIST+1 restore LIST+1 set carry set carry list1: list2: (custom code) (custom code) jmp BIOSLIST jmp list1 name1: name2: module1. name module2. name There are several key point to observe here. As each module is loaded, it is patched into the bios vector/module chain to become the lowest link. Control flows from the bios jump vector to Module n, the last-loaded module, then n-1, ... and finally to the internal bios routine. This linkage is required for the warmboot function. Other bios functions may appear in just a single module, or in several, as illustrated for LIST. High memory is protected by the page-0 address at 0006H. On a warm-boot, each module's warmboot routine is traversed. The lowest module's warmboot routine detects that it is indeed at the bottom of the chain, and has the responsibty for re-setting location 6 to point to its protective jump vector; the higher modules must leave this address intact, but can take other action appropriate to their function. The warm-boot routines also restore the warmboot address at 0001H, in case an errant program has changed it. Note well that the restore routine in each module restores all patches that were made when it was loaded. Thus, if Module 2 is removed, the memory map will again be that of Fig 1. AN EXAMPLE: BGPRINT BGPRINT is a fairly basic resident system extension that adds two new capabilities to the standard bios LIST function. 1. printer pause when a PAUSE_CHARACTER is sent 2. string substitution for specified special characters These features are handy for several types of applications. When embedded in a text document, the pause character halts printing to allow the operator to change printwheels, ribbon, or sheet paper at an exact point in the text. String substitution permits access to special printwheel or dotmatrix characters that cannot be sent by the preferred wordprocessing software. It can also be used to send the printer's escape sequence to activate a different font or spacing. As assembled, BGPRINT and LOADBGPR provide a simple demonstration of the pause and control strings for an OKIDATA 82/83 printer. We placed the printer-specific data at 103H in LOADBGPR, and you can readily patch in your own codes without reassembling and linking the package. However, the supplied configuration program provides a mush simpler method of setting up your strings. Embellishment of the basic BGPRINT is left as a useful exercise to the interested reader. If you make some improvements, please keep us informed and we'll try to include them in future releases. Although we called it BGPRINT, because the module was developed for use with The Backgrounder, this particular system extension does not require The Backgrounder for its operation; it should work with any standard CP/M 2.2 system. When used with The Backgrounder, The Backgrounder should be loaded first.