A METHOD AND SYSTEM FOR DEVICE VIRTUALIZATION BASED ON AN INTERRUPT REQUEST IN A DOS-BASED ENVIRONMENT

Abstract: A technique for providing device virtualization in an MS-DOS based operating environment (212), using an interrupt request (e.g., a non-maskable interrupt), is described. The technique includes executing an application on a processor within the MS-DOS based operating environment (212), and, when the application attempts to address the device to be emulated, causing a processor interrupt to occur. In response to the interrupt, the processor executes code representing the virtualization of a device. The code for servicing the interrupt and emulating the device are written in protected mode-code stored in the extended memory area (314), and made available by making appropriate entries into the interrup descriptor tables (318) for the protected-mode context established for the DOS extender (410). The entries made into IDT (318) for the protected-mode context established for the DOS extender are accomplished by intercepting communications between the DOS extender and the virtual control program interface (314).

Description: A METHOD AND SYSTEM FOR DEVICE VIRTUALIZATION BASED ON AN INTERRUPT REQUEST IN A DOS-BASED ENVIRONMENT A portion of the disclosure of this patent document contains material which is subject to copyright protection, particularly Appendices A, B and C. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or d e patent disclosure, as it appears in the Patent and Trademark Office patent file or records, but otherwise reserves all copyright rights whatsoever. FIELD OF THE INVENTION This invention generally relates to computer software and, more particularly, it relates to the use of an interrupt request for triggering device virtualization services in a DOS-based operating system environment. BACKGROUND OF THE INVENTION MS-DOS is Microsoft's 16-bit operating system which runs on PC-XT- and PC-AT-type personal computers (PCs). This operating system (OS) was originally developed for the Intel 8086 and 8088 microprocessors which operates in what is generally referred to as "real-mode." Real-mode refers to the way the microprocessor handles memory (i.e., providing the user with a single-tasking working environment in which programs can freely access system memory and input/output devices). It is noted that real-mode, by itself, does not include features such as memory management or protection. Today's personal computers are equipped with more advanced processors from Intel, specifically the 80386, 80486, and Pentium, all of which are capable of running 8086-compatible code (real-mode). These processors, however, have a more advanced 32-bit protected-mode which provides hardware support for multitasking, data security and virtual memory. Among other things, protected-mode allows access to more random access memory (RAM) than the 1 megabyte (MB) that the standard real-mode MS-DOS operating system permits (additional details described in King, A., "Inside Windows 95", Microsoft Press, pp. 33-43, 1994, which is herein incorporated by reference). A typical memory configuration of a personal computer is shown in Figure 1. The memory configuration of Figure 1 shows a memory area 110 containing 640 kilobytes (K) of conventional memory. Because MS-DOS is designed for managing this conventional memory, an additional memory manager is not required. All MS-DOS based programs require conventional memory. The remainder of the standard 1 MB is referred to as the upper memory area 112 which comprises 384K of memory above the 640K of conventional memory. The upper memory area 112 is generally used by system hardware, such as a display adapter. Unused parts of the upper memory area 112 are called upper memory blocks (UMBs). On any PC, UMBs can be used for running device drivers and memory-resident programs as described below. An extended memory (XMS) area 114 is memory located beyond the 1 MB boundary on computers with 80286, 80386 or 80486 processors. Extended memory requires an extended-memory manager, such as HIMEM. A high memory area (HMA) 116 is approximately the first 64K of the extended memory area 114. The HMA 116 is a small address region, slightly less than 64K, above the 1 MB boundary that can be accessed by real-mode code. The address region of the HMA is from lOOOOOh through lOffefh. On a computer with extended memory, the setup program can install MS-DOS to run in the HMA 116. This provides more conventional memory to be available for other software programs. Another type of memory available, as shown in Figure 1 , is known as expanded memory. An expanded memory board (EMS) 118 contains additional memory that some MS-DOS based applications can use. Most personal computers accommodate expanded memory. Expanded memory is installed on an expanded memory board 118 and requires an associated expanded memory manager. Computer software programs use expanded memory 64K at a time by addressing a part of the upper memory area 112 known as the EMS page frame. Because an expanded memory manager gives access to a limited amount of expanded memory at a time, using expanded memory is slower than using extended memory. A conventional software program such as EMM386 can simulate expanded memory using extended memory for programs that require it. As MS-DOS matured through the 1980s, much of its functionality was added in the form of device drivers. As set forth in the Encyclopedia of Computer Science, Third Edition, IEEE Press (1993), which is hereby incorporated by reference, a device driver is a program or subprogram that is written to control either a particular hardware device or anomer software routine. This low-level software program is loaded into memory after the operating system boots and remains in memory for the duration of the operating session. As mentioned, the device driver can deal directly with the hardware of a particular device. The device driver is capable of responding to hardware and software interrupts and interfacing to the operating system through an established MS-DOS device driver protocol in order to serve as an interface between such hardware or software and the operating system (described in "Microsoft MS-DOS 6 User's Guide", Microsoft Corporation, pp. 87-89, 1993 and which is also hereby incorporated by reference). It should be noted that device drivers are generally limited in size to 64K bytes. In addition to device drivers, MS-DOS also uses memory- resident software programs, often referred to as terminate-and-stay-resident programs (TSRs). These programs are executed like normal software programs, but after termination, a portion of the program remains installed in memory in order to monitor and/or service hardware or software interrupts. TSRs can also interface with the operating system in a limited sense, but they do not use the MS-DOS device driver protocol. Both device drivers and TSRs are typically real-mode code and reside in memory below the MS-DOS 1 MB limit. In many cases, these resident software programs reside within the conventional 640K of memory which is normally used by MS-DOS to load and execute programs. As mentioned above, they may reside above the conventional 640K in the upper memory area 112 when, for example, a memory optimizing routine is executed such as MemMaker (additional details are provided in MS-DOS User's Guide, beginning on page 131). In this case, the driver or TSR would be placed into the upper memory area 112 with a link to its location placed in the 640K conventional memory 110 to indicate its memory location in the upper memory area 112. Even so, as more and more device drivers and TSRs are loaded into a system, the maximum allowable memory area for MS-DOS programs, drivers and TSRs is rapidly reduced. To further illustrate the functional interrelationships of MS- DOS, device drivers, hardware, etc., Figures 2 through 4 illustrate the evolution, from a functional perspective, beginning with the original MS- DOS real-mode environment up to present day environments allowing for protected-mode and DOS extenders. It is noted that the functional interrelationships shown in Figures 2 through 4 are well known to those of ordinary skill in the art and well documented as well, therefore, each figure is only briefly described. A more comprehensive treatment of DOS extenders and their evolution is provided in Duncan et al., EXTENDING DOS. A Programmer's Guide to Protected-Mode DOS. 2nd Edition, Addison- Wesley (1992), which is herein incorporated by reference for its teaching of DOS extenders and associated aspects relevant herein. Turning to the figures, Figure 2 shows a block diagram of a conventional DOS operating environment with no memory management services. This operating environment is similar to that used in the 8086- and 8088-based PCs. The hardware 210 sends an interrupt request, represented by the dotted line 211, to the DOS operating system 212 which is initially serviced by the DOS Interrupt Vector Table 213. Based on the entries in Interrupt Vector Table 213, the interrupt request can be directed to the DOS OS 212, device drivers 214, TSRs 216, etc. As mentioned above, with the release of more powerful Intel processors in the late 1980s, special "extensions" to the standard MS-DOS operating system were developed to allow MS-DOS programs to easily access computer memory that would not otherwise be addressable using real-mode code. These extensions (i.e., device drivers) to the operating system take advantage of the protected-mode features of the 80X86 processors while allowing MS-DOS to continue executing in real-mode. These device drivers implement, as a minimum, memory management services referred to as EMS and XMS services. These services allow software programs to store and retrieve large amounts of data from the memory pool above the 1 MB boundary. However, they do not allow software programs to occupy this memory for execution purposes. The well known programs provided by Microsoft to implement this functionality are called HIMEM. SYS and EMM386.EXE. Continuing with the figures, Figure 3 shows a block diagram of a conventional DOS operating environment with conventional memory management services 312 installed for managing the extended memory area 114. This operating environment is similar to that used in 80286-based PCs through Pentium-based PCs. As shown in Figure 3, a protected-mode OS 310 executes above the DOS OS 212. An interrupt request 311 generated in this environment passes first into the protected-mode OS 310 allowing for higher level management. As shown, the interrupt request 311, based on entries in an Interrupt Descriptor Table (IDT, described in more detail below), may be directed to memory management services 312, a virtual control program interface (VCPI) 314, the DOS Interrupt Vector Table 213, etc. As shown, the protected-mode OS includes the IDT 318 as well as a GDT 320. Additional details of the operation of the VCPI are described in the Virtual Control Program Interface specification, Version 1.0, (1989), which is herein incorporated by reference for its teachings regarding d e operation of a VCPI. Concurrent with the development of these memory extensions was the development of DOS extenders. Figure 4 shows a block diagram of a conventional DOS operating environment with memory management services 312 installed and a DOS extender 410 running. DOS extenders are low-level software components that allow programs to be executed in protected-mode under MS-DOS. The DOS extender 410 allows protected- mode applications 412 to communicate with hardware and the OS and vice versa. These programs can use the vast amount of memory above 1 MB to execute code as well as store and retrieve data. However, the extenders do not allow executable code to permanently reside in memory above the 1 MB boundary; rather, upon switching into protected-mode, the DOS extenders can temporarily copy executable code into the extended memory area for purposes of execution, but upon termination, it no longer exists in extended memory. Even so, the extenders allow programs to apply a much simpler and much more powerful programming model. DOS extenders achieve their task by switching the processor into protected-mode while running the program, and switching the processor back to real-mode when the program completes. The DOS extenders also switch the processor in and out of real- mode during the program execution when MS-DOS functions need to be called, or when device drivers or TSRs need to run. To do this, the DOS extender must be in complete control of the system. Thus, a protected-mode operating system is created under which MS-DOS runs as a (virtual 8086) real-mode task. As shown in Figure 4, the newly created protected-mode operating environment created for the DOS extender 410 includes its own IDT 418 and GDT 420. It is noted, however, that when the DOS extender switches back to real mode it then uses IDT 318 and GDT 320. In systems with memory management enabled, as shown in Figures 3 and 4, the device drivers that provide these services create their own protected-mode environment and already have MS-DOS running as a real-mode task. Therefore, they provide contention management services to negotiate memory allocation and mode switching between themselves and DOS extenders. This contention management is implemented by all memory managers today via me VCPI 314. If a DOS extender 410 determines that a VCPI 314 is present in a system, it uses this interface to acquire its protected- mode context and to perform its mode switching (real versus protected). In most cases, the extender 410 also allocates all of its required program memory through the VCPI 314. With this evolution in mind, as available memory, as well as processing power, continue to increase, it is desirable to make efficient use of these computing resources such as having the capability of providing device virtualization, thereby, reducing the amount of hardware necessary to provide desirable features. The 80386 and later processors do generally provide for hardware virtualization by allowing certain instructions to be "trapped. " Specifically, if a program executes an "IN" or "OUT" (I/O) instruction, a General Protection Fault handler can be invoked to decide whether or not to let the IN/OUT execute and/or whether or not to emulate the presence of some hardware. This "I/O Trapping" can be applied to any process running below processor privilege level (or ring) 0. Unfortunately, most DOS extenders (Rational Systems' DOS4GW for example) run at ring 0, thus they are not subject to the 80386 I/O trapping mechanism. In addition to the 80386 I/O trapping mechanism, at least one hardware manufacmre has used a combination of external hardware interrupts and software to replace the functions of more costly hardware. Specifically, Advanced Gravis has used a technique which combines a Non-Maskable Interrupt (NMI) and a DOS TSR to virtualize hardware. Although this technique provides hardware virtualization for applications executing in real- mode, it does not provide virtualization for applications executing under a DOS extender, since there is no predetermined method for the OS to direct the interrupt services of the DOS extender. There is, therefore, a real need to provide an efficient way of performing device virtualization which is also accessible by DOS extenders. SUMMARY OF THE INVENTION The present invention involves a technique for providing device virtualization in a DOS based operating environment including the steps of executing an application, under a DOS extender, on a processor within the DOS-based operating environment, where the application executes within a protected-mode context created for the DOS extender and the protected-mode context includes an interrupt descriptor table (IDT). Additionally, a processor interrupt is caused when the application addresses a predetermined address related to the device to be emulated and, responsive to the processor interrupt, an appropriate entry in the IDT associated with the protected-mode context of the DOS extender is processed, thereby, causing the processor to execute computer code designed to emulate the device. BRIEF DESCRIPTION OF THE FIGURES Figure 1 is a block diagram of a conventional memory configuration of a personal computer. Figure 2 is a high-level functional block diagram of a conventional DOS operating environment. Figure 3 is a high-level functional block diagram of a conventional DOS operating environment with memory management services installed. Figure 4 is a high-level functional block diagram of a conventional DOS operating environment illustrating the functional relationships of DOS with memory management services and DOS extenders. Figure 5 is a high-level functional block diagram of a DOS operating environment as it relates to an exemplary embodiment of the present invention. Figure 6 is a flow diagram of the initialization operation, at boot time, of an exemplary embodiment of the present invention. Figure 7 is a flow diagram of the operation of an exemplary embodiment of the present invention, at run time, to provide compatibility with DOS extenders. DETAILED DESCRIPTION OF THE EXEMPLARY EMBODIMENTS Overview As mentioned in the BACKGROUND section, device virtualization, in general, is known. Unfortunately, when running in the context of DOS extenders (e.g., Rational Systems' DOS4GW), device drivers cannot take advantage of the I/O trapping mechanism; nor can they take advantage of Advanced Gravis technique mentioned above in the Background section. Because many present day applications use DOS extenders for various reasons, a device virtualization technique should be accessible by applications running with or without DOS extenders. Generally, the present invention provides device virtualization, in an MS-DOS based operating environment, by way of an interrupt request (e.g. non-maskable interrupt) for applications running with or without a DOS extender. The present invention dynamically extends its device virtualization capabilities to applications running under DOS extenders by intercepting communications between the DOS extender and the VCPI at run time. In particular, when an executing application requests the use of a particular device (e.g., requesting a predetermined address), a processor interrupt request is generated. In response to the interrupt request, the device virtualization code for that particular device can be accessed and executed even for applications running under DOS extenders. It is noted that, in the exemplary embodiment, the present invention relies on the presence of a memory manager, or an equivalent thereof, to provide for a protected-mode operating environment. Figure 5 is a block diagram illustrating the functional relationship between conventional operating system components in a typical MS-DOS environment as described in the BACKGROUND section with reference to Figures 2 through 4 and an exemplary embodiment of the present invention. As shown in Figure 5, the present invention functionally represents a new functional layer working in conjunction with the protected- mode OS 310. This new layer is referred to, for purposes of this specification, as VIVO driver 510. Essentially, the VIVO driver 510 becomes an extension of the protected-mode operating system that supervises MS-DOS and DOS extenders instead of simply becoming an extension of MS-DOS itself, as is the case with standard device drivers and TSRs. In the exemplary embodiment of the present invention, in addition to VIVO driver 510 which represents a driver designed to provide the device virtualization services, a VIVO TSR 520 is provided to aid in the dynamic extension of the services by the VIVO driver 510 for use with DOS extenders 410. The present invention includes loading protected-mode executable code, including an interrupt service routine and device virtualization code, into memory, and entering the associated interrupt service vector directly into the protected-mode operating system's interrupt descriptor table (IDT) 318. The use of IDT's is well known and additional details of descriptor addressing are described beginning on page 41 of the Windows '95 reference incorporated herein. Additional teachings on IDT's can be found in Microprocessors. Intel (1989), which is also herein incorporated by reference. Briefly, the protected-mode IDT 318 determines interrupt vectoring instead of the DOS Interrupt Vector Table 213 even when the protected-mode OS 310 is running real-mode code. In many cases, such as MS-DOS OS calls, the services indicated by the IDT entries simply pass control to the real-mode services in the DOS interrupt vector table that were installed by MS-DOS. As well as being faster and more efficient than real- mode interrupt handlers, using the protected-mode IDT makes the services of the present invention unconditionally available to the system whether it is running in real- or protected-mode. Continuing, the present invention, by way of the VIVO TSR 520, uses the VCPI 'Get Protected-mode Interface' real-mode call (Int 67, function deOlh) to force all of the DOS extender's 410 subsequent VCPI 314 protected-mode "far calls" to "pass through" the VIVO driver 510. It is noted that the 'Get Protected-mode Interface' is used by a DOS extender at startup to acquire a protected-mode context. When the VIVO driver 510 receives these far calls, it is running under the context of the DOS extender's protected-mode OS. At this point, the VIVO driver 510 installs its interrupt service vector into the DOS extender's IDT 418 making the VIVO driver's device virtualization service available to the DOS extender (and its applications) until it terminates. Although the present invention is designed to operate using most any interrupt request, the exemplary embodiment of the present invention uses the non-maskable interrupt (NMI) as the interrupt request for triggering the device virtualization routine. It is noted that, historically, the NMI has been used by system motherboard logic to notify the operating system of a RAM (memory) parity error, or by I/O devices to notify the operating system of some "unrecoverable" error. Today, however, the RAM parity no longer exists and I/O devices do not implement NMI generation. A typical DOS extender's NMI handler, however, not knowing specifically how to handle such an event, simply re-boots the system rather than "passing- down" the interrupt to the currently installed DOS handler as it would do with a normal interrupt. Therefore, unlike other interrupt services, an NMI interrupt service routine installed under DOS would most likely be ignored by an application running under a DOS extender. Description of Exemplary Embodiment Although illustrated and described below with reference to certain specific embodiments, the present invention is nevertheless not intended to be limited to the details shown. Rather, various modifications may be made in the details within the scope and range of equivalents of the claims and without departing from the spirit of the invention. Referring back to Figure 5, in operation, when an interrupt request 211 (e.g., NMI) occurs, the protected-mode IDT 318 directs the flow of operation to the appropriate service routine based on the entries therein. If the interrupt is not intended for the VIVO driver 510, then the interrupt is passed on to the normal flow of operation. When the VIVO driver 510 of the present invention is present with a DOS extender 410 running, the interrupt request is not passed directly to the DOS extender 410. Rather, if the interrupt request is intended for the VIVO driver 510, the VIVO driver 510 acts on the request directly. If the request is not for the VIVO driver 510, then control is passed to the DOS extender 410, and the DOS extender 410 handles it in its normal way. It is noted that, in the exemplary embodiment of the present invention, because the NMI is used, the device virtualization can be performed immediately following the "faulting" instruction (i.e., the instruction which caused the NMI). Turning to the generation and installation of the present invention, after the computer code embodying the present invention is written, it is compiled/assembled and linked, in the exemplary embodiment, as zero address-based, non-relocatable, flat-model, 32-bit protected-mode code. The present invention is then saved as a standalone binary file. It is noted that, in preparing the computer code embodying the present invention, protected-mode code is required (at least at the NMI service entry point) since the protected mode IDT's vectoring mechanism does not allow vectoring to real-mode (or virtual 8086) code. It is also noted that, although some protected-mode code is required, the exemplary embodiment of the present invention is implemented using almost all protected-mode code since it is more efficient for vectoring and execution and can be completely located in extended memory, thereby, avoiding memory-hungry DOS real-mode applications. Basically, the VIVO driver 510 includes the device virtualization code for emulating the particular device and it includes the code necessary to receive, at run time, the re-directed "far calls" from the DOS extender 410, make the appropriate entries in the IDT 418, and pass control onto the VCPI 314. It also includes the Int 67 handler which is used to reflect the VCPI Get Protected-Mode Interface call return into the VIVO TSR 520. An exemplary implementation of VTVO driver 510 suitable for use with the present invention is included as Appendix A. The installation and operation of the present invention is described with reference to the flowcharts in Figures 6 and 7. Referring to Figure 6, at boot-time, in the exemplary embodiment of the present invention, an MS-DOS initialization program (e.g., ssinit.com) allocates a predetermined amount of the extended memory area 114 above the HMA 116 using an extended memory (XMS) interface reference, step 610. An exemplary implemenation of ssinit.com suitable for use with the present invention is included as Appendix B. The predetermined amount of memory, in the exemplary embodiment of the present invention, is the size of the 32- bit protected-mode code file. Additionally, in the exemplary embodiment, the allocated memory is below the 4 Megabyte boundary. Then, the allocated memory, using the XMS interface, is locked and the physical address is saved. Subsequently, the code embodying the present invention is copied into the allocated portion of extended memory, step 612. Appropriate entries are made into the protected-mode IDT 318 and GDT 320 to allow the associated hardware interrupt to vector directly to the 32-bit service entry point(s) in extended memory, step 614. It is noted that since the interrupt vectoring is done at the protected-mode level, the 32-bit services are always available and can be initiated by the protected-mode OS 310 without explicitly performing any time-consuming mode switching. More specifically, steps 612 and 614 are accomplished as follows: The protected-mode code file embodying the present invention is opened and a 1 kbyte portion of the code is loaded into local memory. In the exemplary embodiment of the present invention, this first portion of the code is loaded because it has variables that need to be initialized at pre- determined offsets which can only be determined at this stage of loading the program (e.g., configuration parameters). Next, the VCPI "Get Protected-mode Interface" call (Int 67h, function deOlh) is invoked and three selectors and an entry point offset are returned. The three selectors and the entry point offset are copied into a predetermined offset in the first portion of the protected-mode code. Also, the segment and offset of a portion of the MS-DOS initialization code is copied into a pre-determined offset in the first portion of the protected-mode code. This referenced portion of the MS-DOS initialization code remains resident after the MS-DOS inititialization code terminates and me protected- mode code, in the exemplary embodiment, will need to know where it is because it is essentially a shared dataspace used by the VIVO TSR 520 and the VIVO driver 510 to communicate. Next, the first portion of the protected-mode code is copied into the allocated extended memory (e.g., using an XMS interface) and then the rest of the protected-mode code embodying the present invention is copied into extended memory in the same manner. Next, the linear addresses for the protected-mode IDT and GDT and d e physical address for the Page Directory (using standard 386 instructions) are obtained and saved. A protected-mode initialization program (e.g., a DOS4GW executable) is spawned and the physical address of die allocated Extended Memory, GDT and IDT linear addresses, as well as the Page Directory physical address, are passed thereto. An exemplary implemenation of the DOS4GW executable suitable for use with the present invention is included as Appendix C. The functions of the protected-mode initialization program, in the exemplary embodiment of loading the present invention,, are to: 1) Make three entries at the top of the protected mode OS's GDT 320. The first entry is a 32-bit code selector with a linear address based at the beginning of the allocated Extended Memory. The second entry is a data selector to alias d e first entry. The third entry is a 32-bit data selector that is based at linear address 0 and has a maximum size (or limit). 2) Save the selector base of the entries made in step 1). 3) Make an entry into me protected mode OS's IDT 318 for vector 02h (the NMI vector). This vector uses the selector base saved above with an offset of zero (in the exemplary embodiment, me NMI entry point in the 32-bit code). 4) Save d e original Int 67h vector. 5) Make an entry into me protected mode OS's IDT 318 for vector 67h (me Int 67 vector). This vector uses the selector base saved above widi an offset of eight (the Int 67h intercept entry point in the 32-bit code). 6) Then, return control to the MS-DOS initialization program. Finally, the MS-DOS initialization program terminates, leaving a relatively small program in memory ~ referred to above as the VIVO TSR 520. The general technique of leaving a TSR in memory upon initialization program termination is a well known technique to those of ordinary skill in the art. By way of the Int 67h entry, the VIVO driver 510 is linked into die the VCPI service/control chain via the IDT 318 for Interrupt 67h so that the hooks are present for the present invention to extend its functionality to DOS extenders 410 when they initialize. It is noted that Interrupt 67h is a control function interface to die EMS 118 and VCPI 314. This Interrupt 67h handler (VTVO driver 510) acts upon VCPI functions, and d en passes control to the normal Interrupt 67h handler installed by me protected-mode OS. At diis point, the protected-mode OS 310 is configured such d at hardware virtualization is available to all real-mode programs and drivers. There are also now hooks in place to allow for the extension of the device virtualization service to applications running under DOS extenders. It is noted mat, in the exemplary embodiment of me present invention, although the hooks are put in place during boot time, the extension of the device virtualization services to applications running under DOS extenders is completed at run-time. This is an important aspect of the present invention becomes it allows the present invention to avoid many of the drawbacks of the prior art techniques. It is noted mat, although the above-described initialization process is performed using a combination of the MS DOS initialization program and me protected-mode initialization program, in an alternate embodiment, all of me initialization functions performed by me MS DOS initialization program can be performed by me protected-mode initialization program. To do so, die MS DOS initialization program needs to pass an extra parameter to me protected-mode initialization program. The extra parameter is the real-mode offset of the shared data space widi the DOS initialization program. Continuing, the way in which the VIVO code of d e present invention extends its functionality to DOS extenders via die Interrupt 67h handler is described widi reference to the flowchart of Figure 7. As shown in Figure 7, after having establishing the VIVO TSR 520, it is triggered when, at run time, the DOS extender 410 calls the VCPI "Get Protected-Mode Interface" function, step 712, via Int 67h. At diis point, the DOS extender 410, initially in real-mode, expects to acquire the protected-mode far-call entry point to the VCPI 314. This entry point is used by the protected-mode OS created by die DOS extender 410 to communicate directly widi the VCPI 314 without invoking software interrupts and wid oui switching to real mode. However, me VIVO TSR 520 of the present invention, at this point, gives the DOS extender 410 an entry point to the VIVO driver 510, step 714. It is noted diat, in the exemplary embodiment of me present invention, the VIVO TSR 520 relies on the presence of a VCPI 314, or equivalent diereof, for cooperation widi DOS extenders 410. By providing DOS extender 410 wi i an entry point into d e VIVO driver 510 rather dian the actual VCPI entry point, me DOS extender 410 will now pass through the VIVO driver 510 on subsequent far calls. As such, when die VIVO driver 510 intercepts the VCPI far-calls, it makes its own interrupt vector entries into the DOS extender's protected-mode OS vector tables 418/420, step 716, similar to that which was done for die native protected-mode OS 310. After making the appropriate entries, die VIVO driver 510 then passes control to the actual VCPI 314 via the previously saved VCPI protected-mode far-call entry point, step 718. More specifically, steps 714, 716 and 718 are accomplished as follows: The VIVO driver 510 intercepts the Get Protected-Mode Interface call at the Int 67h entry point (all other Int 67h calls are passed dirough to the default handler). The VIVO driver 510 saves die real-mode return address for the DOS extender 410 into d e shared data space. It dien changes the real-mode return address (stored on the processor stack) so that, when the actual VCPI service completes, control will pass to e VIVO TSR 520. So, essentially, all Int67h calls still get processed by die default handler except a Get Protected-Mode Interface call causes die change of the real- mode return address, by die VIVO driver 510, prior to being processed by die default handler. It is noted that, in an alternate embodiment, the function of intercepting the initial Int 67h call from the DOS extender 410 may be performed by VIVO TSR 520. This may be problematic, however, because when me present invention runs under a memory manager, such as QEMM by Quarterdeck Office Systems, the memory manager does not pass die VCPI Int 67h calls dirough the DOS Interrupt Vector Table, but rather, fields all VCPI Int 67h calls in protected mode via the IDT. Continuing with the exemplary embodiment, in d e case of the Get Protected-Mode Interface call, control is ien passed to die VCPI 314 which performs its service. The VCPI 314 returns control, via the new return address, to die VIVO TSR 520. At this point, a page table context has been setup in the DOS extender's data space. The VIVO TSR 520 then makes additional page entries so that die VIVO driver 510 is valid widiin the DOS extender's protected-mode context. The VIVO TSR 520 dien copies the diree selectors being passed back to die DOS extender 410 into the shared data space as well as die VCPI far call entry offset. Next, die VIVO TSR 520 copies its own diree selectors (described above) into the DOS extender's return data space. It dien alters d e VCPI entry offset (in register ebx) to 16, which is the offset into the VIVO driver for the VCPI far call intercept. Finally, it returns control to the original real-mode remm address (die DOS extender 410) saved above in me shared data space. At diis point, all VCPI far calls made by the DOS extender 410 now pass control to the VIVO driver 510 widiin die context of die DOS extender's new protected-mode OS. These calls include allocating extended memory for the DOS extender application and (temporarily) switching back to real-mode to service DOS interrupts. Whenever a VCPI far call is made, an interrupt entry is made in IDT 418 by VIVO driver 510. Widi diis completed, device virtualization (e.g., hardware virtualization) services are available to the DOS extender's protected-mode application program as well as to me normal DOS real-mode programs (i.e. , VIVO driver 510 is accessible by programs running under DOS extender), step 720. The VIVO driver of d e present invention, like other device drivers and TSRs, implements software services for hardware interrupt events. However, the VIVO driver in accordance wid die present invention is different than standard MS-DOS device drivers and TSRs. For example, the memory-resident, executable code of d e VIVO driver of die present invention can permanently reside above die 1 MB memory boundary and above die HMA 116. As such, die VIVO driver does not compete for valuable memory space with standard MS-DOS programs and odier device drivers and TSRs. Moreover, the VIVO driver is not limited to me 64K restriction of a typical device driver allowing for applications significantly larger than 64K which is particularly useful when, for example, one desires to emulate hardware wid software. Commercial Embodiment A commercial embodiment in accordance wid die present invention is me Ensoniq SoundScape™ sound card VIVO drivers. In diis commercial embodiment, a VIVO driver is used to perform the function of hardware which previously existed on a sound card. By replacing die hardware wid a VIVO driver, d e space consumed and cost of die sound card are significantly reduced. In operation, when an application requests access to die sound card, d e request is directly processed by d e VIVO driver and die functionality of that hardware element is performed in software rather dian hardware. This is possible, in part, because present generation microprocessors (e.g., Pentium) are so powerful ttiat diey typically have considerable idle time which can be used to execute die VIVO driver, which appears like an application, without a noticeable delay in other necessary processing. This is only one example of how the use of a VIVO driver provides substantial advantages to not only optimizing conventional memory space but also optimizing the size and cost of an auxiliary computer card. In particular, in the commercial embodiment, if an application attempts to address die sound card in the processor I/O address space, normally 220h tiirough 22fh, an NMI is generated. As a result, the VIVO driver performs functional emulation of various hardware previously residing on die card (e.g., die Sound Blaster) in response to I/O writes and, during certain I/O reads, die handler alters die hardware I/O return value (in me Intel 386, register EAX) in order to emulate or virtualize die presence of d e hardware in the system. Since d e commercial embodiment of d e present invention optionally alters the processor register state, it is necessary diat the NMI service routine execute immediately following the faulting I/O instruction. Although illustrated and described above wid reference to certain specific embodiments, the present invention is nevertheless not intended to be limited to die details shown. Rather, various modifications may be made in me details widiin the scope and range of equivalents of the claims and witiiout departing from the spirit of the invention. APPENDIX A The port mapping for the I/O handlers is as follows BasePort+OOh ioMpuOata BasePort+Olh ioMpuCstat wavePort+OOh Iowss avePort+Olh io ss wavePort+02h iowss WavePort+03h iowss avePort+04h ioCdAddr wavePort+05h ioCdData wavePort+06h ioPass wavePort+07h loPass 220h IoPass 221h IoPass 222h IoPass 223h IoPass 224h IoPass 225h oPass 226h ioSblReset 227h ioPass 228h ioFmAstat 229h ioFmData 22ah ioSbloata 22bh ioPass 22ch ioSblCstat 22dh ioPass 22eh ioSblRxrdy 22fh ioPass 388h IoFmAstat 389h IoFmData 38ah ioPass 38bh ioPass The I/O handlers are 32-bit NEAR procedures that are called from the stub code. They will all assume the following register conventions. Entry: cs - I/O handlers' code selector ds - I/O handlers' data selector ah - xOxxxxxxb if the "faulting" I/O cycle was a read, xlxxxxxxb if it was a write al - the write value if the "faulting" I/O cycle was a write, otherwise undefined esi - offset to the SoundScape hardware structure Exit: al - set to the prescribed return value if the faulting I/O cycle was a read, otherwise preserved All other registers will be preserved by the I/O handlers. .386p IF WIN_CODE include vmm.inc include debug. inc include sndscape.inc .xlist .list EXTRN gpSSI: DWORD ELSE .MODEL flat ENDIF INCLUDE vivo. inc EXTRN _synth_i ni t : NEAR EXTRN _synth_process_MIDI : NEAR EXTRN _synth_all_notes_off : NEAR IF WIN_CODE VXD_L0CKED_CODE_SEG PUBLIC _Nmiιsr _Nmilsr LABEL NEAR ELSE _TEXT SEGMENT ; NMI entry point here - jump over the hardware config and stub data jmp Nmi Service ALIGN 4 ; IRQ entry point here skip to its service jmp irqService ALIGN 4 ; Int 67h entry point here skip to its service jmp lnt67Service ALIGN 4 ; VCPI entry poi nt here - ski p to its service jmp vcpi Service al l other data at end , 330h , 534h , 2180h , 5 , 9 , 1 > mov esi .gpssi setup HW config ptr push edx —edx— push eax —eax— eld push edx mov dx, [esi .ssi_wiθAddressGA] add dl,NMISTAT_OFF in al ,dx mov ah.al inc dl in al.dx pop edx ah:al is NMISTAT:NMIDATA test ah,80h 3 'z . SHORT nmiex push eax and ah,30h z SHORT nmisb emp ah,30h je SHORT nmiad pop eax push edx and dl.Ofeh emp dx, [es .ssi_wIOAddressGA] SHORT nmimp a j< n\dι dl.Ofβh push eax mov ax , [esi . ssi_wlθAddresscθDEC] sub al,4 mp dx.ax pop eax je SHORT nmicd pop edx jmp SHORT nmiex n isb: pop eax mov dl.ah and edx.OOOOOOOfh call Sblτable[4*edx] call the SoundBlaster service jmp SHORT reack nmiad: pop eax mov dl.ah and edx,00000003h call Adlτablef4*edx] call the AdLib service jmp SHORT nmiex nrmmp: pop edx and edx.OOOOOOOlh call MpuTable[;4*edx] call the MPU-401 service jmp SHORT nmiex nmicd: pop edx and edx,00000007h call Cdτable[4*edx] call the CoDec service jmp SHORT reack nop reack: mov dx, [esi .ssi_wlθAddressGA] add dl,NMISTAT_OFF ack agai n i n case we touched CoDec in al ,dx nmiex: in al ,61h re-arm NMI edge detection and al .Ofh or al ,08h out βlh . al and al ,07h out 61h ,al pop eax pop edx IrqProcess PROC iptsbt: ipeoi ipnosl : IrqProcess ENDP handle goto vββ mode separately save minimum regs no ints! switch to local stack setup global data selector patch client IDT find a GDT patch entry note GDT entry for call point into client table save current client entries ; copy-in the real VCPI GDT entries make the real VCPI call ; restore client GDT entries restore working regs restore global selector lss esp.spsave ; restore stack popfd pop ds pop ecx ; restore regs retf registers sidt ClientTab ; patch the client IDT mov ebx,CTladdr add ebx.lOh mov eax.cs shl eax ,16 mov ecx,00008e00h mov es: [ebx] , eax mov es: [ebx+4] ,ecx mov al.04h add ebx.MidivectOff mov es: [ebx] ,eax mov es: [ebx+4] ,ecx mov al,80h out 70h,al xor al ,al out 70h,al mov eax , [esp+10] ; save client v86 destination mov ax, [esp+8] mov ebx.sharedDataP mov es: [ebx+4] ,eax mov eax.VFoffset ; setup our v86 destination mov [esp+8] ,eax mov eax , VFsegment mov [esp+12] ,eax mov eax.cs mov VEselector.ax ; note selector for far call sgdt Cl i entTab mov ebx, CTladdr ; point to client GDT patch entry add ebx, eax sub ebx, 4 mov ecx, 6 clfixlp mov eax, vcpi Gentri es-4 [4*ecx] ; copy-in the real VCPI GDT entries mov es: [ebx+4*ecx] ,eax loop clfixlp mov CTladdr, ebx ; save GDT entry laddr for fixup mov eax,cr3 ; save client's cr3 mov ClientCr3,eax mov ecx, [esp+4] mov ebx, [esp] mov eax.gs mov ds.eax mov eax.OdeOch ; re-init function arg jmp es: vcpi Entry Int67Service: emp ax.OdeOlh VCPI GetPMi call? jne SHORT i67tfix push eax mov eax.cs push edx add eax , lOh setup ds:[edx] for shared data save init di to shared space save v86 return to shared space force v86 ret to vivo gpmi code link to normal PM handler ; save regs need client's page context don't use stack until restored client GDT entries ENDIF ; handle otto timer int - assumes local stack, sels set, esi->HW; OttoTi er PROC push eax push ecx push edx emp Activecount.O SHORT otupd dec Activecount jnz SHORT otupd clc call Timerctl otupd: push 1000 mov eax.SystemTime add eax,16 mov Systemτ me,eax push eax call _synth_uρdate add esp,8 pop edx pop ecx pop eax ret OttoTimer ENDP ; handle otto SB int - assumes local stack, sels set, esi->HW; PUBLIC OttoSbint OttoSbint PROC push eax push ecx push edx push leh freq page call _otto_io_page add esp,4 xor eax,eax zero freq push eax push 04h call _otto_io_write add esp,8 » push 3eh addr page call _otto_io_page add esp, . pushd SOOOOOOOh open loop push 08h call _otto_io_write add esp,8 r xor eax,eax zero accum push eax push Och call _otto_io_jam add esp, 8 pushd 0ff04h idle mode push OOh call _otto_io_jam add esp, 8 bts sbFlags,ITEST_SBFLAG ; note forced-int mov dx, [es .ssi_wlOAddressGA] add dl,NMlCTL_OFF ; kill CoDec virtualization in al ,dx push eax and al.OcOh out dx,al push edx ; force int mov dx, [esi .ssi.wIOAddressCODEC] sub dx,4 mov al ,40h out dx.al pop edx pop eax out dx .al ; re-enable CoDec vi rtualization push 38h call _otto_i o_read add esp , 4 pop edx pop ecx pop eax ret OttoSbint ENDP PUBLIC Ti erCtl Ti erCtl PROC push eax push ecx push edx pushfd push lfh cal 1 _otto_i o_page add esp , 4 popfd + 2*(80*24 + 79) ENDIF in al ,dx -36- pop edx ret cdRead ENDP Cdctrl PROC ; a function to set the CoDec freq corresponding to a SB TConst SetRate PROC pop edx pop ecx pop eax ret SetRate ENDP ; a function to mute/unmute the AD- 1848 DAC MuteCtl PROC At this point we have accumulated a full MIDI message put it in eax and pass it to the synth. The format will be EAX: D31-D24 D23-D16 D15-D8 D7-D0 MIDI: ZERO DATAl DATAO STATUS make sure timer is on mi deal1 : mov eax.MidiMessage IF WIN_CODE τrace_Out "IoMpuData: MIDI Message Dump #EAX", DeblevelMax ENDIF mp one: ret mduart: duwtx : IoMpuData ENDP ALIGN 4 PUBLIC IOMpuCStat ioMpuCstat PROC test ah,40h jnz SHORT mcout ret mcout : emp al.Offh IOMpuCStat ENDP GetMscStat PROC push edx mov dx , [esi . ssi_wlθAddressGA] add dl ,MSCWBAK_OFF in al .dx pop edx ret GetMscStat ENDP SetMscStat PROC SetMSCStat ENDP SblPutData PROC SblPutData ENDP MpuPutData PROC MpuPutData ENDP iosblReset ENDP HwCleanup PROC push eax push edx mov dx, [esi .ssi_wlOAddressCODEC] sub dl,4 xor al ,al out dx.al mov ax , (CD_CONFIG SHL 8) OR OOh call Cdwrite mov ah,CD_TINIT call CdRead test al.lOh jz SHORT drqok in al ,dx or al,04h inc dl in al ,dx out dx.al drqok: mov dx, [esi .ssi_wIOAddressGA] add dl,3 in al ,dx out dx.al dec dl out dx,al mov dx, [esi .ssi_wlOAddressCODEC] add dl ,2 in al ,dx pop edx pop eax ret HwCleanup ENDP ALIGN 4 PUBLIC iosblData iosblData PROC test ah ,40h ; data write? jnz SHORT sdout Btr sbFlags ,DPEND_SBFLAG ; got a pending byte? jc SHORT dpend call GetMscStat and al , NOT SB_RXRDY cal l setMscStat ret dpend: -42- xor al ,al call SblPutData ret sdout: ret Iosbloata ENDP ALIGN 4 PUBLIC IoSblCstat iosblCstat PROC test ah,40h jnz SHORT SCOUt call GetMscStat bt sbFlags ,CODECON_SBFLAG jne SHORT txnorm inc Toggle ; if the DAC is on, we need to toggle test Toggle,04h z SHORT txnorm or al,SB_TXRDY call setMscStat ret txnorm: ; pass normal TxRdy and al ,NOT SB_TXRDY call SetMscStat ret scout: jmp [CmdProc] ; go to current command process parsecmd LABEL NEAR ; parse for a new command emp al ,DACDMA_CMD jne SHORT pcsetTc dacdma: mov [CmdProc],OFFSET GetDacCl ret pcSetTc: emp al,SETTC_CMD jne SHORT pcDacio mov [CmdProc],OFFSET GetTc ret pcDacio: emp al,DACIO_CMD jne SHORT pCAdClO bts SbFlags,DACIO_SBFLAG jc dioset mov ax,C(CD_CONFIG OR 40h) SHL 8) OR 4Sh call CdCtrl mov dx , [esi . ssi_wlθAddressCOOEC] xor al ,al out dx.al mov ax , (CD_PINCTL SHL 8) OR OcOh call Cdwrite mov ax,(CD_UFREQ SHL 8) OR 0c3h call cdwrite inc ah call Cdwrite mov Tconst.O fh dioset: mov [CmdProc],OFFSET GetDaclo ret pcAdclo: emp al,DACIO_CMD jne SHORT pcDacAon bts SbFl ags , ADCIO_SBFLAG aioset mov ax , ((CD_CONFIG OR 40h) SHL 8) OR 86h PCNone: ret GetAdcCl : mov ah,CD_CCOUNTL call Cdwrite mov [CmdProc],OFFSET GetAdcCu ret GetAdcCu : ; this process starts the ADC mov ah,CD_CCOUNTU call Cdwrite bts SbFlags ,CODECON_SBFLAG c adcson mov ax,((CD_CONFIG OR 20h) SHL 8) OR 02h call CdCtrl adcson : mov CmdProc,OFFSET ParseCmd ret GetDaclo: push edx mov dx, [esi .ssi_wIOAddressCODEC] add dl,3 out dx.al pop edx mov CmdProc,OFFSET ParseCmd ret GetSilCl: mov DmaCountL.al mov CmdProc,OFFSET GetSilCu ret GetSilCu: mov DmaCountU.al xor ecx, ecx derive otto sample count mov cx.DmaCount inc ecx mov eax, 31250 xor edx, edx mul ecx xor ecx,ecx mov cx.sbSrate xor edx,edx div ecx inc eax shl eax ,11 ; create a loop-end value push eax push 3eh ; addr page call _otto_io_page add esp,4 push 08h ; set loop-end (eax pre-pushed) call _otto_io_write add esp,8 push leh ; freq page call _otto_io_page add esp, pushd 0ff20h ; non- loopi ng , i nt enable push OOh call _otto_io_jam add esp,8 pushd 0800h ; frequency i s 1 push 04h call _otto_io_write add esp,8 mov CmdProc,OFFSET ParseCmd ret GetDacCl : mov ah,CD_PCOUNTL call Cdwrite mov [CmdProc],OFFSET GetDacCu ret GetDacCu: this process starts the OAC mov ah,CD_PCOUNTU call Cdwrite bts SbFlags,CODECON_SBFLAG jne dacst mov dx, [esi .ssi.wlOAddressCODEC] add dl,2 in al.dx test al.Olh jz SHORT dacex mov ax,(CD_CONFIG SHL 8) OR OOh call Cdwrite out dx.al dacst: mov ax,((CD_CONFIG OR 20h) SHL 8) OR Olh call CdCtrl dacex : mov CmdProc,OFFSET ParseCmd ret GetAbL: mov AutoBlkL.al mov [CmdProc] .OFFSET GetAbU ret GetAbu: mov AutoBlkU.al mov CmdProc,OFFSET ParseCmd ret GetTc: call SetRate mov CmdProc,OFFSET ParseCmd ret GetScram: xor al.SbXorPat add al ,SbAccum mov dx, [esi .ssi_wIOAddressGA] add dl , 3AMDATA_0FF out dx.al mov SbAccum,al ror Sbxor at,2 dec dl in al ,dx or al,02h out dx.al mov CmdProc,OFFSET ParseCmd ret Getlnv: not al call sblPutData mov CmdProc,OFFSET ParseCmd ret GetTag: mov Tagβyte . al mov CmdProc , OFFSET ParseCmd ret iosbl Cstat ENDP ALIGN 4 PUBLIC Iosbl xrdy iosblRxrdy PROC test ah,40h jnz srxout mov dx, [esi .ssi_wlθAddressCODEC] add dl,2 in al ,dx test al.Olh jz SHORT noted R OOh clear CoDec int did we fire-off a test int? kill forced IRQ srxout: ret iosbl xrdy ENDP ALIGN 4 PUBLIC IoFmAstat IoFmAstat PROC test ah,40h inz SHORT faout btr VFl agS , FMOET_FLAG jne SHORT farex pushd Offffffffh call _synth_all_notes_off add esp,4 mov _num_actιve_voιces,12 farex: ret faout: mov FmAddr.al FM address reg write ret IoFmAstat ENDP ALIGN 4 PUBLIC IoFmData IoFmData PROC test ah ,40h writing fm data port? ; FM data reg wri te ; fill-in FM data array ; need to process FM notes? ; make sure timer i s on test for timer detection ALIGN 4 -50- PUBLIC iocdData locdσata PROC test ah,40h jnz SHORT cdout mov ah.CdAddr and ah.lfh emp ah ,CD_MISC jne SHORT cdrex mov BYTE PTR [esp+4],0ah emp wssSwtch.O jne SHORT cdrex mov BYTE PTR [esp+4],0ffh cdrex: ret cdout : mov ah.CdAddr and ah , Ifh emp ah,CD_PFORM jne SHORT cdtpi n xor edx,edx mov dl.al and dl.Ofh mov dx,Freqτable[2*edx] mov ah , CD_UFREQ mov al.dh call Cdwrite inc ah mov al.dl call Cdwrite ret cdtpin : emp ah ,CD_PINCTL jne SHORT cdtmsc or al ,0c0h call Cdwrite ret cdtmsc: emp ah ,CD_MISC jne SHORT cdtl cc mov al . 50h call Cdwrite ret cdtlcc: emp ah ,CD_CCOUNTL jne SHORT cdtucc mov ah ,CD_PCOUNTL call Cdwrite ret cdtucc: emp ah,CD_CCOUNTU jne SHORT cdwex mov ah,CD_PCOUNTU call Cdwrite cdwex : ret IocdData ENDP ALIGN 4 PUBLIC IOWSS iowss PROC test ah , 40h jnz SHORT wsout emp wssSwtch .O j ne SHORT wiwss mov BYTE PTR [esp+4] ,0ffh wiwss : ret wsout : emp wssSwtch . O jne SHORT wopass xor al , al out dx . al wopass : ret iowss ENDP ALIGN 4 PUBLIC ioPass ioPass PROC ret IOPass ENDP IF WIN_CODE VxD_LOCKED_CODE_ENDS VXD_L0CKED_DATA_SEG ENDIF ALIGN 4 IFE WIN_CODE PUBLIC gpssi gpSS DD OFFSET HwCoπfig IFDEF DOS_DEBUG DebugPtr DD (ObOOOOh + 2*80*8) E ENDIF E ENDIF MpuTable LABEL DWORD DD IoMpuData, ioMpuCstat SblTable LABEL DWORD DD oPass, ioPass, ioPass, iopass DD oPass, IoPass , iosbl eset, ioPass DD IoFmAstat, IoFmData, ioSblData, ioPass DD ioSblCstat, IoPass, ioSblRxRdy, ioPass AdlTable LABEL DWORD DD IoFmAstat IoFmData, IoPass, ioPass cdTable LABEL DWORD DD IOWSS, iowss, iowss , iowss DD IoCdAddr, IocdData, ioPass, iopass SystemTime DD 0 ClientCr3 DD ? ClientTab LABEL FWORD CTlimit DW ? CTladdr DD ? RegSave DD ? PmDest LABEL FWORD PDoffset DD ? PDselector DW ? SaveGentr es DD 6 DUP(?) CmdProc DD OFFSET ParseCmd MidiMessage LABEL DWORD MidiStat DB 80h MidiData DB OOh, OOh, OOh FreqTable LABEL WORD DW 8000, 5513 , 16000 , 11025 IF WIN_CODE PUBLIC EXtMidi ExtMidi OB 0 PUBLIC _SynthvolL _SynthVolL DB 7fh PUBLIC _SyπthVθlR _SynthvolR DB 7fh ENDIF IFDEF DOS.DEBUG DebugByte DB '0' ENDIF IF WIN.CODE VxD_LOCKED_DATA_ENDS ELSE _TEXT ENDS ENDIF END APPENDIX B .386p INCLUDE vivo. inc NUM_CODEPAGES EQU 25 NMI_INT EQU 02h TIMER_INT EQU 08h DOS_SETVECT EQU 25h DOS_TSR EQU 31h DOS_GETVECT EQU 35h DOS_FREE EQU 49h DOS_MODIFY EQU 4ah _TEXT SEGMENT DWORD PUBLIC USE16 'CODE' ASSUME cs:_τ__xτ, ds:_TEXT ORG OlOOh Start: jmp Entry ; Resident Data (non-discardable) starts here 0) ; Resident Code (non-discardable) starts here IFDEF DOS_DEBUG DbPUtCh PROC push es push di mov di.ObOOOh ; apw mov es ,di mov di ,cs:DebugPtr mov es:[di],al add cs:DebugPtr,4 pop di pop es ret DbPutCh ENDP DbPutByte PROC β@3: πba: loop mov BYTE PTR es:[di] add di,2 emp di, 2*80*24 jb nbb xor di ,di nbb: mov BYTE PTR es:[di] mov es:DebugPtr,di DbPutByte ENDP DbPutword PROC push ex push dx push di push es mov di ,cs:DebugPtr mov dx.ObOOOh mov es.dx mov ex, 4 rol ax,4 mov dl.al and dl.Ofh emp dl.Oah jb add dl.'A' - Oah jmp SHORT 993 add dl.'O' mov es:[di],dl add di,2 emp di,2*80*24 jb nwa xor di ,di nwa: loop 991 mov BYTE PTR es:[di] add di,2 emp di, 2*80*24 jb nwb xor di ,di nwb: mov BYTE PTR es : [di ] mov es:DebugPtr,di pop es pop di pop dx pop ex ret DbPutword ENDP ENDIF NmiISr PROC FAR push ax push dx Midilsr PROC FAR MUXisr PROC FAR ushf mi link: wstrt: Timerlsr PROC FAR bt cs:Flags,FLAG_WIN jne tidoit jmp cs:τimerLink tidoit: push ax push dx mov dx.es: M di Pic in al ,dx and al ,cs: Midi unmask out dx.al in al.βlh and al ,07h out 61h,al xor al ,al out 70h,al pop dx pop ax jmp cs:TimerLink Timerlsr ENDP Init Data (discardable) starts here ALIGN 2 xmsEntry XMS far-call entry point XEoffset XEsegment xmsHandle our XMS chunk handle ToScope discardable data sent to SCOPE.EXE EmmCr3 EmmGdt Emmldt ; param struct for .EXE spawning ParamBlock PARMBLK < ?, OFFSET Param, ?, 5ch, ?, 6ch, ? > FileHandle DW 0 SsPath DB 65 DUP(?) vscape32 DB '\VSCAPE32.BIN',0 SsConfig DB '\SSCONFIG.EXE\0 Scope DB '\SCOPE.EXE',0 D0S4GW DB '\DOS4GW.EXE',0 Quiet DB 'DOS4G=QUIET',0 Param DB 127 DUP(" ') TmpBuff DB 128 DUP(?) ; init Code (discardable) starts here PrintChar ENDP Printword PROC 991: ah 993: printword ENDP PrintRet PROC PrintRet ENDP -61- mov BYTE PTR es:[di],0 inc di Pop dx pop ex ret wordToStr ENDP StrCpy Inputs : ds:si source string es:di destination string Return: Nothing. All regs are left unaffected except di - tfiis will point to the byte immediately fol lowing the last destination byte that was copied to. StrCpy PROC push ax save regs push si 991 : mov al, copy the string mov es ;[di],al inc si inc di emp al,0 jne 991 pop si restore regs and exit pop ax ret StrCpy ENDP Entry: ; string ops forward always eld ; print a hello dorks message call PrintMsg DB Odh.Oah,' SoundscapeVϊVO(TM) initialization Driver. Version 3.22. ',Odh,Oah DB ' Copyright(c) 1995-1996, ENSONIQ Cor . , All Rights Reserved. ',Odh,Oah.0 ; if we need to, free all but our 64k so we can spawn later csizok: if not, assume .co and resize psizok: get the int 67 vector, make sure we got a memory manager mov ax , (DOS.GETVECT SHL 8) OR 67h int 21h mov ax.es or ax,ax jnz emvok call PrintMsg DB 0dh,0ah,07h, error: Memory Manager not detected. ' .Odh.Oah DB ' Soundscapevivo requires EMM386 or similar. ',Odh,Oah,0 jmp exit emvok: ; see if we're already loaded mov ax.Odeelh mov bx,Ob55h int 67h emp bl.Oaah jne ssnpres call PrintMsg DB Odh.Oah,' ... Soundscapevivo driver is currently loaded ... ' ,Odh,Oah, 0 jmp exit ssnpres: envlp: ; set the local quiet environment var for 4GW spawn mov di , bx mov es.es: [002ch] mov si .OFFSET Quiet call strcpy mov BYTE PTR es:[di],0 ; build the parameter line for config spawn mov di .OFFSET Param+2 mov ax,ds mov es.ax mov ax,OFFSET HwConfig call wordToStr setup config offset arg mov BYTE PTR [di-1], ' ' mov ax.ds call wordToStr setup segment arg mov BYTE PTR [di-1],Odh sub di,OFFSET Param+2 add length mov ax.di mov Param,a1 ; build the filename for the config code mov si .OFFSET ssPath mov di .OFFSET T pBuff mov dx ,ds mov es.dx ; first copy path call Strcpy dec di mov si .OFFSET SsCoπfig ; append f lename call StrCpy mov bx,OFFSET Paramβlock setup param block mov ax.es: [002ch] mov (PARMBLK PTR [bxl) .envseg,ax mov (PARMBLK PTR r bx , ).c—md- ■ s-e-g-,d- ■ s- mov (PARMBLK PTR bx J.fcblseg.ds mov (PARMBLK PTR bx ).fcb2seg,ds mov dx,OFFSET τmpβuf ,: mov ax.ds mov es.ax mov ax,4b00h and spawn the .exe int 21h jne cfgran call PrintMsg DB 0dh,0ah,07h, error: Could not execute SSCONFiG.EXE. ',Odh,Oah,0 jmp exit cfgran: emp BasePort.O jne cfgok mp exit cf ok: see if we have to bail now mov di,0080h xor ex,ex mov cl.[di] look for /N cmd line arg or cl.cl i z nokill dec ex inc di mov ax.ds mov es.ax mov al.'/' repne scasb jnz nokill mov al,[di] and al.OdfFF emp al.'N' jne nokill call PrintMsg DB Odh.Oah,' nitialization Complete, DOS drivers NOT loaded. ',Odh,Oah,Odh,Oah,0 jmp exit nokill: - ent vars f w hav an XMS driver . . error : XMS services were not detected . ' , Odh , Oah , 0 jmp exit xmspr : ; get the XMS control function entry point mov ax ,4310h int 2fh mov XEoffset . bx mov XEsegment . es ; get enough XMS for our 32-bit code mov dx,(4 * NUM.CODEPAGES) mov ah,09h call xmsEntry or ax,ax jnz xmsok call priπtMsα DB 0dh,0ah,07h, r error: Could not allocate required Extended Memory. ',Odh,Oah,0 jmp exit x sok : ; lock the XMS block (handle in dx) , save phys addr mov an.Och call xmsEπtry or ax,ax jnz xmok call PrintMsg DB 0dh,0ah,07h. error: Could not lock Extended Memory. ',Odh,Oah,0 jmp xfexit xnilok : mov XPlower.bx mov xpupper.dx ; make sure we're below 4M mov eax.xmsPaddr add eax,((NUM_CODEPAGES SHL 12) - 1) emp eax,400000h jb xm4ok call PrintMsg DB 0dh,0ah,07h, error: Could not allocate Extended Memory below 4 Mbyte boundary. ,Odh,Oah DB ' Try loading SSINIT.COM before SMARTDRV.EXE' ,Odh,Oah,0 fxexit jmp xuexit xm4ok : ; get the EMM386 environment and data for scope.exe mov eax,cr3 mov EmmCr3,eax sgdt EmmGdt sidt Emmldt ; build the parameter line for scope spawn mov di,OFFSET Param+2 mov ax.ds mov es.ax mov si,OFFSET SsPath setup fpath and fname for D0S4GW call strcpy dec di mov si,OFFSET Scope call Strcpy mov BYTE PTR [di -1] , ' ' mov BYTE PTR [di],0 mov ax,OFFSET Toscope call wordToStr setup data-out offset arg mov BYTE PTR [di-1],' ' mov ax.ds call wordToStr setup segment arg mov BYTE PTR [di-1],Odh sub di .OFFSET param+2 add length mov ax , di mov Pa ram, a 1 bui ld the fi lename for the scope (D0S4GW) code fi rst copy path append fi lename setup param block and spawn the . exe , , , not execute SCOPE.EXE. ', Odh, Oah,0 jmp fxexit scpran: emp NumCodePages.O jne scpok jmp fxexit scpok: mov dx.OFFSET Nmilsr j install NMI service mov ax , (D0S_SETVECT SHL 8) OR 02h int 21h mov dx,OFFSET Midilsr ; install MIDI IRQ service mov al.Midivect int 21h mov ax , (DOS_GETVECT SHL 8) OR 21h int 21h ; save DOS vector mov DLoffset.bx mov DLsegment.es mov dx,OFFSET DOSlSr install our DOS service mov ah,DOS_SETVECT int 21h mov ax , (DOS_GETVECT SHL 8) OR 2fh int 21h ; save Mux vector mov MLoffset.bx mov MLsegment.es mov dx,OFFSET Muxisr ; install our Mux service mov ah,DOS_SETVECT int 21h mov ax , (DOS_GETVECT SHL 8) OR TIMER_INT int 21h ; save timer vector mov TLoffset.bx mov TLsegment.es mov dx , OFFSET Timerlsr ; install our timer service mov ah,DOS_SETVECT int 21h ; call synth-init and enable otto ints mov ax.Odeelh mov bh.Olh int 67h mov dx.βasePort add dl,CONTROL_OFF mov al,08h out dx.a ; wait, then un-mute the synth mov dx.BasePort add dl,ODADDR_OFF mov cx.OOOfh u wtlpo: push ex mov ex,Offffh umwtlpi pi po Type .OOh r mov dx . es :wavePort s on: out dx.al TandSR: call PrintMsg DB Odh.Oah,' initialization Complete. ' .Odh.Oah,Odh,Oah,0 mov es.es: [002ch] free our local environment seg mov ah,DOS_FREE int 21h mov dx, (OFFSET TsrEnd π OOOfh) terminate / stay resident shr dx,4 mov ax,(DOS_TSR SHL 8) int 21h xuexit: ; unlock XMS memory block mov dx.xmsHandle mov ah,Odh call xmsεntry xfexit: ; free XMS memory block mov dx.xmsHandle mov ah,Oah cal l xms Entry exi t : ; get outta here ret _TEXT ENDS END start APPEND1X C #i ncl ude <stdi o . h> #i ncl ude <stdl i b . h> #i ncl ude <i 86. h> #defi ne NUM_CODEPAGES 25 /* number of 4k pages occupied by v32 code */ //#defi ne DEBUG /* Some standard typedefs ... */ typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; /* The following structure is the data passed in from SSINIT */ typedef struct { DWORD CR3 ; /* EMM'S CR3 */ WORD GdtLimit; /* EMM's GDT limit, linear address */ DWORD GdtLaddr; WORD idtLimit; /* EMM's IDT limit, linear address */ DWORD idtLaddr; WORD Dooffset ; /* output data offset */ WORD HwOffset ; /* HW config data offset */ WORD GetPmioff; /* offset of v86 get PMI return handler */ WORD FixupOff; /* offset of v86 switch return handler */ WORD SharedOff; /* offset to V86/V32 shared data area */ } DATA_IN; /* The following structure points to SSINIT'S resident data area */ typedef struct DWORD vivoGentries[6] /* vivo GDT entries for VCPI get MI */ DWORD xmsPaddr; /* phys addr of Extended Mem */ WORD NumCodePages ; /* number of 4k v32 code pages */ } DATA_RES; /* The following structure i s SSINIT ' s HW confi g data * 7 typedef struct { WORD BasePort; /* Gate Array base port 7 WORD wavePort ; /* CoDec base port */ WORD SynthPort; /* Otto base port */ BYTE Wavelrq; /* CoDec/SB IRQ */ BYTE Midilrq; /* Synth IRQ BYTE DmaChan ; /* CoDec/SB DMA channel V BYTE ExtMidi ; /* External MIDI enable V BYTE SbEnable; /* SB emulation enable */ BYTE Synthvol ; Synth volume */ BYTE wavevol : /* Wave volume */ BYTE cdAuxvol ; /* CD/Aux volume */ BYTE BoardType; /* vivo rev number */ } HW_CONFIG; /* The following structure is the config data at the top of the v32 code */ typedef struct { BYTE Jumpτable[Oxlc /* jump instr's for multiple entry pts */ DWORD vivoGentries[6 /* the vivo VCPI Get PMI GDT entries */ DWORD vcpiGentries[6! /* the real VCPI Get PMI GDT entries */ DWORD SharedDatap; /* linear addr of v86/v32 shared data */ DWORD M divectOff; /* IDT MIDI vect offset from NMI */ DWORD GetPmioff; /* QWORD far ptr to v86 Get PMI handler */ DWORD GetPm Seg; DWORD FixupOff; /* QWORD far ptr to v86 switch fixup handler */ DWORD FixupSeg; DWORD l67Linkθff; /* PM link to the real Int 67 handler */ WORD l67LinkSel; DWORD vcpiEntryOff; /* PM entry point to the real VCPI handler */ WORD vcpiEntrySel ; WORD HardwareOptions ; /* bit field for board type */ WORD BasePort; /* duplication of hardware config for V32 */ WORD wavePort; WORD SynthPort; BYTE wavelrq; BYTE Midilrq; BYTE DmaChan ; BYTE ExtMidi ; BYTE SynthvolL; BYTE SyπthvolR; } V32_CONFIG; /* The following structure is the DOS mem used in the VCPI Get PMI call */ typedef struct { DWORD PageTable[0x0400] ; DWORD vcpiGentries[6] ; BYTE Dosstack[0x0400 - 4*6]; } DOS_MEM; DWORD DosMalloc(DWORD size) ; void DosFree(WORD selector); DWORD GetGDT() ; DWORD Getvcpi (WORD dmseg) ; DWORD GetCR3(); /* This function returns the 386 CR3 value */ #pragma aux GetCR3 = \ mov eax,cr3" \ value [eax]; void FlushTLB(void); /* This function flushes the page table TLB */ #praqma aux FlushTLB - \ mov eax,cr3" \ "mov cr3,eax" \ modify [eax]; void Setl(void); /* This function disables interrupts */ #pragma aux Setl - \ sti"; void Clrl(void); /* This function enables interrupts */ #pragma aux Cl rl - \ B cli"; void main(int argc, char *argv[]) { #ifdef DEBUG fd - fopenC'SCOPE.DBG", "w") ; #endi f /* make sure we got the right arg count, make pointers and midivect */ if( argc < 3 ) return; di offset = (WORD) strtoul(argv[l], NULL, 16); dsegment = (WORD) strtoul(argv[2] , NULL, 16); pdi » (DATA_IN *) (((DWORD) dsegment « 4) + dioffset); pdr - (DATA_RES *) (((DWORD) dsegment « 4) + pdi->DoOffset); phw = (HW_CONFIG *) (((DWORD) dsegment « 4) + pdi ->HwOf f set) ; midivect = (phw->Midilrq < 8 ? 0x08 : 0x68) + phw->Midilrq; #ifdef DEBUG fprintf(fd, "\npoiπters ...\n"); fprintf(fd, "P v86 non-res %081x\n", pdi); fprintf(fd, "P v86 res %081x\n", pdr) ; fprintf(fd, "P v86 HW%081x\n", phw); fprintf(fd, "\nEMM context ...\n ); fpriπtf(fd, "CR3 X081x\π", pdi->CR3); fprintf(fd, "GDT %081x %04x\n" , pdi->GdtLaddr, pdi->GdtLimit) ; fprintf(fd, "IDT X081x %04x\n" , pdi->ldtLaddr, pdi->ldtLimit) ; #endif /* setup the DOS4GW page table-zero-pointer */ pd4g0 - (DWORD *) (GetCR3() & OxfffffOOOUL) ; pd4g0 = (DWORD *) (*pd4gO & OxfffffOOOUL); /* setup laddr 0x180000 for EMM page dir, 0x181000 for var page tab ptr */ *(pd4g0 + 0x0180) = (pdi->CR3 & OxfffffOOOUL) I 0x67u; ppdir = (DWORD *) OxlβOOOOUL; pptab = (DWORD volatile *) 0X181000UL; /* point pptab at EMM's page table for the GDT, create a ptr */ *(pd4gO + 0x0181) = *(ppdir + (pdi->GdtLaddr » 22)); FlushTLB(); /* setup page table and pointer for EMM'S GDT */ *(pd4g0 + 0x0182) = *(pptab + ((pdi->GdtLaddr » 12) & Ox000003ffUL)) | 0x67U; *(pd4g0 + 0x0183) = *(pd4g0 + 0x0182) -t- OxlOOOU; pgdt = (DWORD *) (OX182000UL I (pdi->GdtLaddr & OxOOOOOfffUL)); /* point pptab at EMM's page table for the IDT, create a ptr */ *(pd4g0 + 0x0181) = *(ppdir + (pdi->IdtLaddr » 22)); FlushTLB(); /* setup page table and pointer for EMM'S IDT */ *(pd4g0 + 0x0184) = *(pptab + ((pdi->ldtLaddr » 12) & 0x000003ffuD) | 0x67u; *(pd4g0 + 0x0185) - *(pd4g0 + 0x0184) + OxlOOOU; pidt = (DWORD *) (Oxl84000UL | (pdi->ldtLaddr & OxOOOOOfffUL)); /* open the code file in current .exe's directory */ fname) ; /* get the DOS memory for the GetPMl call, setup far ptr */ if( Ktrnp = DosMalloc(5*1024UL)) ) { printf("\007 error: could not alocate DOS memory.\n"); goto exit; dmsel = (WORD) (tmp » 16); dmseg = (WORD) tmp; * (DWORD *) &pdm - OUL; * ((WORD *) &pdm + 2) ■ dmsel; /* get the first chunk of our file */ fread(TmpBuff, 1, 1024, fp) ; /* setup v32 confi g data pointer */ pv32 - (V32_C0NFIG *) ΛT pBuff ; /* make the Get PMI call , copy VCPI data i nto V32 config */ pv32->vcpi EntryOff - GetVcpi (dmseg) ; for( i = 0 ; i < 6 ; ++i ) pv32->vcpiGentri es [i ] « pdm->vcpiGentri es [i] ; /* setup the ivo GDT entri es i n v32 and data-out mem */ pv32->vivoGentri es f0] - pdr->vivoGentri es [0] » pv32->vivoGentri es [2] - pdr->vivoGentπes[2] - (pdr->xmsPaddr « 16) | Oxffffu; tmp = (pdr->xmsPaddr & OxffOOOOOOUL) I ((pdr->XmsPaddr » 16) & OxOOOOOOffUL) I 0x004f9300UL ; pv32->vivoGentries 1] * pdr->vivoGentries tmp OxOOOOOβOOU ; pv32->vi voGentri es ' 31 ■ pdr->vivoGentries tmp; pv32->vivoGentries 4] ■ pdr->vi voGentri es OxOOOOffffUL; pv32->vi voGentri es 5] - pdr->vivoGentries 0x00cf9300UL; #i #e I* make entries in page table at 0x200000+ for our code, make pointer */ for( i -= 0, tmp - (pdr->xmsPaddr & OxfffffOOOUL) I 0x67; i < NUM_COOEPAGES + 1; ++i , tmp +- OxlOOOU ) *(pd4g0 + 0x0200 + i) - tmp; pxms - (DWORD *) (Ox200000UL | (pdr->xmsPaddr & OxOOOOOfffUL)); /* copy first file chunk up to Extended Memory */ for( i - 0; i < 256; - -i ) *pxms++ ■ TmpBuff[i]; /* now copy the rest of the code file up */ while( Ifeof(fp) ) { ι «= (fread(τmpBuff, 1, 1024, fp) + 3) » 2; for( i - 0; i < j; ++i ) *pxms++ ■ Tmpβuff[i]; } /* The next section will fill-in unused entries in the DOS4GW */ /* page table at lin-addr OxlβOOOO-- and setup some pointers to allow */ /* us to access the page table, GDT, and IDT of the EMM. */ /* fill in the EMM'S page-table-zero with our XMS entries */ *(pd4g0 ■«• 0x0181) « *ppdir; FlushT BO; for( i ■ (WORD) (pdr->xmsPaddr » 12), tmp = pdr->xmsPaddr | 0x67U; i < (WORD) (pdr->xmsPaddr » 12) + 25; ++i , tmp +- OxlOOOu ) * (pptab + i) - tmp; /* find a GDT space to patch starting from top */ fifdef DEBUG fpri ntf(fd , "\nβase Sel ector X04x\n" , i « 2) ; fendi f /* patch the GDT with our three servi ce entri es */ *(pgdt + i ) = *(pgdt + i + 2) ■ pdr->vivoGentri es [0] ; * (pgdt + i + 1) - ρdr->vi voGentri es [11 *(pgdt + i + 3) - pdr->vivoGentries [3j * (pgdt + i + 4) = pdr->VivoGentri es [4] * (pgdt + i + 5) - ρdr->vivoGentri es [5] /* initi al i ze some hardware i np(phw->BasePort + 0x08) ; // NMI clr outp(phw->BasePort + 0x02, 0x03); // UART reset outp(phw->βasePort + 0x02, 0x00); outp(phw->βasePort + 0x06, 0x00); // no Otto ints yet outp(phw->BasePort + 0x08, Oxfe); outp(phw->BasePort + 0x09, Oxaa); outp(phw->βasePorτ + 0x0a. 0x08); outp(phw->βasePort + 0x04, 0x03); outp(phw->βasePort + 0x05, 0x80 I (phw->DmaChan « 4)) ; outp(phw->βasePort + 0x04, 0x04); outp(phw->βasePort + 0x05, (phw->wavelrq == 9 ? 0x00 : phw->wavelrq -= 5 0x04 0x08) I (phw->Mid lrq «« 9 ? 0x00 : phw->Midilrq -= 7 0x02 0x03)) ; outp(phw->βasePort + 0x04, 0x06); outp(phw->βasePort + 0x05, 0x00); outp(phw->wavePort, OxOc) ; outp(phw->wavePort + 1, 0x50); outp(phw->wavePort, 0x49); outp(phw->wavePort + 1, 0x04); outp(phw->wavePort, 0x48) ; outp(phw->wavePort + 1, 0x00); outp(phw->wavePort, 0x0a) ; outp(phw->wavePort + 1, 0x80); outp(phw->wavePort, Oxlb) ; outp(phw->wavePort + 1, 0x08); outp(phw->wavePort, 0x10); outp(phw->wavePort + 1, 0x80); outp(phw->wavePort, Oxll); outp(phw->wavβPort + 1, OxeO) ; outp(phw->wavePort, 0x00); outp(phw->wavePort + 1, 0x8c) ; outp(phw->wavePort, 0x01); outp(phw->wavePort + 1, 0x8c); outp(phw->wavePort , 0x06) ; outp(phw->wavePort + 1, (phw->wavevol A 0x7f) » 1); outp(phw->wavePort , 0x07 ; outp(phw->wavePort + 1, (phw->waveVol A 0x7f) » 1); outp(phw->wavePort, 0x02); outp(phw->wavePort + 1, (phw->CdAuxvol A 0x7f) » 2); outp(phw->wavePort, 0x03); outp(phw->WavePort + 1, (phw->CdAuxvol A 0x7f) » 2); /* now create the IDT entries for our NMI, MIDI, DOS and lnt67 services ClrlO; tmp = (DWORD) i « 18; *(pidt + (0x02u « 1)) = tmp; * (pi dt + (0x02u « 1) -r 1) - OxOOOOβeOOUL ; *(pidt + ((WORD) midivect « 1)) - tmp I 0x0O04u; * (pidt + ( (WORD) mi divect « 1) + 1) - OxOOOOβeOOUL ; *(pi dt + (0x67u « 1)) = tmp | OxOOOcU ; *(pi t + (Ox67u « 1) + 1) OxOOOOeeOOuL ; setlϋ; #ifdef DEBUG fprintf(fd, "\nv86 Resident Data ...\π"); fprintf(fd, "VIVO GDT 0 XOβlx X081x\n", pdr->vivoGentries[01 , pdr->vivoGentries fprintf(fd, "VIVO GDT 1 XOβlx X081x\n", pdr->VivoGentries 2 , pdr->vivoGentri es ; fprintf(fd, "VIVO GDT 2 XOβlx X081x\n", pdr->vivoGentries[4] , pdr->vivoGentr es fprintf(fd, "XMS Paddr X081x\n", pdr->xmsPaddr) ; cl .! fprintf(fd, "Nu Code Pages X04x\n", pdr->NumcodePages) ; #endif /* fill-out the rest of the resident data struct */ pdr->NumCodePages - NUM.CODEPAGES; exit: if( dmsel ) DosFree(dmsel) ; if( fp ) fclose(fp); #ifdef DEBUG fclose(fd); #endif return; } /* This function invokes the DPMI lNT-31h call for allocating DOS memory. */ DWORD DosMalloc(DWORD size) { union REGS r; r.w.bx » (WORD) ((size + 15) » 4); r.w.ax - 0x0100; int386(0x31, 4r. 4r); if( r.w.cflag ) return OUL; return (r.x.edx « 16) | r.w.ax; /* This function invokes the DPMI lNT-31h call for freeing DOS memory. */ void DosFree(WORD selector) { union REGS r; r.w.dx ■ selector; r.w.ax » 0x0101; int386(0x31, &r. 4r) ; return; /* Thi s function i nvokes the DOS-mode VCPI lNT-67h cal l for acqui ri ng the */ /* protected-mode i nterface. */ DWORD Getvcpi (W0RD dmseg) { segread(As); r.w.ax » 0x0300; r.w.bx » 0x0067; r.w.ex « 0; r.x.edi «= (DWORD) &RmRegs; s.es - s.ds; int386x(0x31, 4r, 4r, 4s); return RmRegs.ebx;

Claims: What is Claimed: 1. A method for providing device virtualization in an DOS-based operating environment comprising the steps of: executing an application, under a DOS extender, on a processor within the DOS-based operating environment, said application executes within a protected-mode context created for the DOS extender, said protected-mode context includes an interrupt descriptor table (IDT); causing a processor interrupt when the application addresses a predetermined address related to the device to be emulated; and responsive to the processor interrupt, processing an entry in the IDT associated with the protected-mode context of the DOS extender and causing the processor to execute computer code designed to emulate the device. 2. The method of claim 1 , the entry in the IDT being made at run- time. 3. The method of claim 1, wherein the MS-DOS based operating environment includes an extended memory area, further comprising the step of, prior to executing the application, storing the computer code designed to emulate the device in the extended memory area. 4. The method of claim 1 , wherein the processor interrupt is a non- maskable interrupt. 5. A system for providing device virtualization in an DOS based operating environment, wherein an application executes, under a DOS extender, on a processor within the DOS-based operating environment, said application executes within a protected-mode context created for the DOS extender, said protected-mode context includes an interrupt descriptor table (IDT), said system comprising: means for emulating the device; means for causing a processor interrupt when the application addresses a predetermined address related to the device to be emulated; and means, responsive to the processor interrupt, for processing an entry in die IDT associated with the protected-mode context of the DOS extender which causes the means for emulating the device to be executed. 6. The system of claim 5, the entry in the IDT being made at run- time. 7. The system of claim 5, wherein the DOS-based operating environment includes extended memory, wherein the means for emulating the device is computer code which resides in extended memory. 8. The system of claim 5, wherein the processor interrupt is a non- maskable interrupt. 9. A method for providing device virtualization to an application executing, under a DOS extender, on a processor in a DOS-based operating environment, said application executes within a protected-mode context created for the DOS extender, said protected-mode context includes an interrupt descriptor table (IDT), said operating environment including an extended memory area having a high memory area, said method comprising the steps of: allocating a portion of the extended memory area beyond the high memory area; storing executable protected-mode code, including code representing the device to be emulated, into the allocated portion of the extended memory; and making an entry into the protected-mode IDT at run-time such that the stored protected-mode code responds to an interrupt request, representing an attempted access of the device to be emulated, caused by an executing application. 10. The method of claim 9, wherein the interrupt request is based on a non-maskable interrupt. 11. In an MS-DOS based operating environment including a DOS extender, a method for installing a protected-mode driver to be operational with the DOS extender, said operating environment including an extended memory area having a high memory area, a memory management means and a virtual control program interface (VCPI) to provide a protected-mode operating system (OS), the method comprising the steps of: allocating a portion of memory; loading executable code, including executable code representing the device to be emulated, into the allocated portion of the memory; making an entry in a protected-mode OS interrupt descriptor table (IDT) such that the executable code responds to an interrupt request, representing an attempted access of the device to be emulated, caused by an executing application; providing a first means for intercepting communications to the VCPI by the DOS extender in order to establish a protected-mode context, when the protected-mode context is established, an interrupt descriptor table for that protected-mode is created; establishing, by way of the first means, a communication link to a second means for intercepting VCPI far-calls by the DOS extender; and making, by way of the second means, an appropriate entry in the IDT such that the protected-mode executable code is accessible by an application executing under the DOS extender in order to provide device virtualization to the application executing under the DOS extender. 12. The method of claim 11, wherein the second means functions at run-time. 13. The method of claim 11 , wherein the step of allocating a portion of memory allocates a portion of extended memory . 14. The method of claim 13, wherein the second means is a protected- mode driver. 15. The method of claim 11 , wherein the interrupt request is based on a non-maskable interrupt (NMI). 16. In an MS-DOS based operating environment including a DOS extender, a method for causing a protected-mode driver to be operational with the DOS extender, a memory management means and a virtual control program interface (VCPI) to provide a protected-mode operating system (OS), the method comprising the steps of: providing a first means for intercepting communications to the VCPI by the DOS extender in order to establish a protected-mode context, when the protected-mode context is established, an interrupt descriptor table (IDT) for that protected-mode exists; establishing, by way of the first means, a communication link to a second means for intercepting VCPI far-calls by the DOS extender; and making, by way of the second means, an appropriate entry in the IDT such that the protected-mode driver is accessible by an application executing under the DOS extender. 17. The method of claim 16, wherein the second means functions at run-time. 18. The method of claim 16, wherein the first means is a real-mode terminate and stay resident program (TSR). 19. The method of claim 16, wherein the interrupt request is based on a non-maskable interrupt (NMI). 20. A method for providing device virtualization to an application executing, under a DOS extender, on a processor in a DOS-based operating environment, said application executes within a protected-mode context created for the DOS extender, said protected-mode context includes an interrupt descriptor table (IDT), said method comprising the steps of: storing code representing the device to be emulated; and making an entry into the protected-mode IDT at run-time such that the stored protected-mode code responds to an interrupt request, representing an attempted access of the device to be emulated, caused by an executing application.

Inventors: FRIEL JOSEPH T, WEIR ANDREW P, FRIEL, JOSEPH, T., WEIR, ANDREW, P.
Applicants: ENSONIC CORP, FRIEL JOSEPH T, WEIR ANDREW P, ENSONIQ CORPORATION, FRIEL, JOSEPH, T., WEIR, ANDREW, P.
Application year: 1997
Main classification: G06F13
IPC codes: G06F9, G06F13