home *** CD-ROM | disk | FTP | other *** search
- /* History:390,1 */
- This is the file internals.doc
-
- Contents:
-
- * Methods that go32 uses to perform the DOS extender function.
-
- * How to add new graphics card support.
-
-
-
- Note: This file includes PC graphics characters in some illustrations.
- It is intended to be viewed via PC or PC compatible printer. If you are
- viewing it from Unix and the illustrations look strange, this is why.
-
-
-
-
-
-
-
-
-
- Methods:
-
- Go32 contains three basic parts:
-
- * a real-mode control program (code/data segments)
- * a 16-bit protected mode interface section
- * a 32-bit flat program arena, loaded from a.out file
-
- The interface section provides Turbo-C routines that acces memory in the
- 32-bit arena, as well as a method for executing code in protected mode.
-
-
-
-
- Initialization:
-
- Control.c is the starting point for the extender. main() is here. This
- is where all the system tables are created, like the GDT and TSSs.
-
- TABLES.ASM contains the stubs for the exception handlers, and the
- exception tasks. The IDT is mass-loaded by main() to point to these
- stubs, then the oddball exceptions are moved (ivec7, page fault handler, etc).
-
-
-
- control assist functions:
-
- utils.c, doutils.asm
-
- All control assist functions use linear/physical addresses, not segment
- addresses!
-
- The control assist functions allow the controller to read/write memory
- from real mode into the 32-bit arena. The available functions are:
-
- word32 peek32(vaddr)
- poke32(vaddr, word32)
- word16 peek16(vaddr)
- poke16(vaddr, word16)
- word8 peek8(vaddr)
- poke8(vaddr, word8)
- memget(vaddr, void *, length)
- memput(vaddr, void *, length)
- zero32(vaddr) /* always 4K regions */
-
-
-
-
-
- The main focal point for process control is a TSS structure with some
- additional fields at the end. These additional fields record information
- such as CR2, the exception number, a temporary stack, and other
- information deduced by the extender. There are many TSSs used:
-
- * c_tss is the control tasks. This is the "real mode" task that is
- initially switched to as part of entering protected mode. A switch to
- this task returns you to real mode.
-
- * a_tss is the arena's task state. By using the fields in this
- structure, the extender can get or change register contents. When the
- arena task causes an exception, the state of the task is recorded here
- for the extender to use in servicing the exception.
-
- * o_tss is the task structure used by the utilities ("other" routines).
-
- * p_tss is the task switched to when a page fault occurs.
-
- * f_tss is the task used by the page fault handler when it calls the
- utilities. This is in case the utilites cause a page fault.
-
- * i_tss is the task most exceptions switch to. Exception 7 is
- redirected to a protected mode handler if a 387 is present. Each
- exception has a stub (in tables.asm) that saves the exception number
- and jumps to this task. This task just un-does the effects of the
- interrupt, so the TSS points to the exception and not the exception
- handler, and then returns to real mode.
-
- The variable tss_ptr points to the currently active TSS. This is the one
- the debugger uses when exceptions happen.
-
-
-
-
-
- Running protected mode code:
-
- MSWITCH.ASM is the gateway into the protected mode arena. *ALL* accesses
- to protected mode go into go32() and come out through it. A20 switching
- is also handled here.
-
- go32() does a number of functions:
-
- * Set the active task gate in the GDT to refer to tss_ptr.
- * Disable interrupts for all tasks except a_tss.
- * Clear all the TaskBusy bits for all tasks, to prevent exceptions.
- * Clear the exception flag (set when an exception occurs).
- * save the real mode stack state.
- * Disable sensitive interrupts (like the hard drive). IRQ0-7 remain
- enabled.
- * Make sure A20 is enabled (a20gate was a stupid idea).
- * Set up the GDT and IDT registers.
- * Go into protected mode.
- * Load the debug registers from _dr[].
- * Enable the paging hardware
- * Load the 387 state from the structure "npx", if the state had been
- stored there (by an exception handler or the "npx" instruction).
- * Load the task register to point to c_tss
- * Switch to tss_ptr's task
-
- . . . wait for switch back to c_tss . . .
-
- * Save DR6 in _dr6 (debug status).
- * Reset IDT and stack
- * Re-enable interrupts
- * Handle certain time-critical exceptions, like timer tick and COM ports.
- Keyboard and NPX interrupts, as well as all other exceptions, are
- handled by exception_handler().
- * return to caller.
-
-
- The basic flow of control looks like this (in to top, out from bottom):
-
- ╔═══════════════════════╗
- ║ Start - Real Mode ║
- ╚═══════════╤═══════════╝
- │ ┌───────────────────────────────────────┐
- ╔═══════════╧═══╧═══════╗ │
- ║ Protected Mode, c_tss ║ │
- ╚═══════════╤═══════╤═══╝ │
- │ └────────┐ │
- ╔═══════════╧═══════════╗ ╔═╧═════════════════════╗ │
- ║ tss_ptr, a_tss ║ ║ tss_ptr, o_tss/f_tss ║ │
- ╚═══╤═══════════════╤═══╝ ╚═╤═════════════════════╝ │
- │ │ │ │
- ╔═══════════════════╧═══╗ ╔═══╧════════╧══════════╗ │
- ║ Exception ║ ║ Page Fault, p_tss ║ │
- ╚═══════════╤═══════════╝ ╚═══════╤═══════╤═══════╝ │
- ╔═══════════╧═══════════╗ │ ╔══╧═════════════════╗ │
- ║ i_tss* ║ │ ║ Graphics handler ║ │
- ╚═══════════╤═══════════╝ │ ╚══════════════════╤═╝ │
- └──────────┐ ┌───────┘ └───────┘
- ╔══════╧════════╧═══════╗
- ║ Back to Real Mode ║
- ╚═══════════════════════╝
-
-
- * some hardware interrupts have their own tss's
-
-
-
-
- GDT entries:
-
- * mandatory zero entry
- * GDT
- * IDT
- * real-mode code segment (for utilities)
- * real-mode data segment (for utilities)
- * real-mode code, but 32-bit (unused)
- * real-mode data, but 32-bit (unused)
- * core. 32-bits, mapped 1:1 with first 1M of memory. Used to access screen.
- * arena code. 32-bit, starts at 0x10000000.
- * arena data. 32-bit, starts at 0x10000000.
- * c_tss task segment
- * a_tss task segment - changes to reflect what tss_ptr points to
- * p_tss task segment
- * i_tss task segment
- * graphics driver routines
- * real code 32-bits, was used for NPX routines (unused)
- * VCPI entries
- * TSS's for some hardware interrupts
-
-
-
-
-
- Mappings:
-
- * First 1M mapped 1:1 to linear address 0x0000000
- * Arena segments start at 0x10000000. All utilities must be
- adjusted to reflect this by adding the constant ARENA to addresses.
- * Symbol space is at 0xa000000 (used by debug32)
- * Core (0-1M) remapped to 0xF0000000 (0xE0000000 to arena)
- * VGA 256c paging at 0xE0000000 (0xD0000000 to arena)
- Three 1M pages:
- 0xD0000000 - 0xD00FFFFF - read/write
- 0xD0100000 - 0xD01FFFFF - read only
- 0xD0200000 - 0xD02FFFFF - write only
-
-
-
-
-
- Page management:
-
- Valloc.c keeps track of what physical pages are available. Pages are
- accessed via valloc() and vfree(), which use page *numbers* (not addresses).
- Up to 128M of RAM can be managed by this routine. If valloc() is called
- and there aren't any free pages, page_out() is called to free one up.
- The application has the option of choosing memory from the lower 640K or
- above 1M. The page directory and page tables are kept in low memory so
- the real mode functions can access them without going into protected mode.
-
- The page table entries include extra information about the status of a
- given page, whether it is swappable, swapped, or uninitialized.
-
- Paging.c keeps track of the page tables and directory. It reads the
- a.out file and sets up various areas of memory (text, data, stack, etc).
- When page faults occur, page_in() pages in memory from disk, swap, or
- available memory (for bss and sbrk()). It detects accesses outside the
- designated areas to flag a protection violation. Page_out() selects a
- present page and swaps it to the swap file, to make space for an incoming
- page.
-
- Dalloc.c keeps track of the disk-based swap space, through dalloc() and
- dfree(). Up to 128M of swap space can be used.
-
-
-
-
-
- A20:
-
- A20 is enabled if it was disabled, and never disabled by the extender.
- If VCPI is running, then VCPI is used to enable and disable A20 as
- appropriate. To determine if it is disabled, the extender compares 0:0
- with FFFF:0010 to see if they map to the same physical memory.
-
-
-
-
-
- Exceptions:
-
- All exceptions are handled by exception_handler() in expnhdlr.c. This
- function returns 1 if a fault happens, or 0 if it handles the exception.
- Control returns to the arena after an exception is handled. Unhandled
- exceptions return you to the debugger or to DOS.
-
-
- Changes to the DOS INT 21H calls:
-
- brk() and sbrk() replace the DOS memory management vector:
- int 21,AH=4A (change memory allocation)
- AL=0 brk(ebx) returns old brk in eax
- AL=1 sbrk(ebx) returns old brk in eax
-
- Some system calls are handled by the extender directly, instead of through
- DOS interrupts:
- int 21,AH=FF - turbo assist. Func in AL, parms (ebx,ecx,edx) ret eax
- 1: creat
- 2: open
- 3: fstat
- 4: gettimeofday
- 5: settimeofdat
- 6: stat
- 7: system
-
-
- int 10, AH=FF - set video mode
- 0: 80x25 text
- 1: default text
- 2: text CX cols by DX rows
- 3: biggest text
- 4: 320x200 graphics
- 5: default graphics
- 6: graphics CX width by DX height
- 7: biggest non-interlaced graphics
- 8: biggest graphics
-
-
-
-
- 80387:
-
- NPX.ASM has all the NPX code (except displaying it, that's in debug.c).
- When a numeric exception happens, the 387 state is stored in [_npx], and
- _npx_stored is set to 1. go32() will restore the 387 from [_npx] if it
- is going to run a_tss (and if the state is stored there). Most of the
- time, the 387 state remains in the 387 and _npx_stored remains 0. The
- debugger can also move the 387 state from the 387 to [_npx] through
- save_npx() if it needs to look at it's state (or fix it, which it doesn't
- yet do).
-
- Exception 7 (device not available) occurs the first time you use the 387
- after a task switch. It just resets the task switch flag in CR0 and resumes.
- This vector points to the real mode handler if the 387 is not installed,
- to detect attempts to use the 387.
-
- Exception 0x75 (IRQ13) is the numeric exception vector. Currently, only
- divide-by-zero and invalid operation are unmasked. This includes
- sqrt(-1), ln(-1), npx stack faults, acos(2), etc.
-
-
-
-
-
- Debugging:
-
- There are seven debug registers, and seven variables (_dr0.._dr7, or
- _dr[0..7]) that control them. go32() loads the debug registers from
- these variables going into protected mode, and clears them coming out.
- Debug registers point to linear, not segment, addresses, so ad 0x10000000
- to them for arena addresses.
-
- syms.c handles all symbol management, including register names and
- expression parsing. Symbols are stored in virtual memory beginning
- at 0xa0000000.
-
- unassmble.c handles unassembling machine instructions. It's very table
- driven, and handles all known (I hope) 386/387 instructions and address
- modes.
-
- debug.c is the central point for debuggin instructions. The main loop
- for the debugger is here. The utility function will longjump() to the
- beginning of the debugger() loop (if available) if they detect an exception.
-
-
-
-
-
-
-
-
-
-
-
- Graphics Card support:
-
- The files graphics.c and grprot.asm control the graphics handling.
- The system allows an external graphics driver to be loaded and used
- instead of the built-in VGA graphics driver.
-
- The Graphics Driver:
-
- Go32 includes the standard VGA driver built-in, as well as in an external
- driver. To select an external driver, enter a DOS command like:
-
- C> set go32=driver c:\go32\drivers\tseng4k.grd tw 132 th 43 gw 800 gh 600
-
- This says that the driver is "c:\go32\drivers\tseng4k.grd", that the
- default text mode is 132x43, and that the default graphics mode is
- 800x600. The driver defines the resolutions for all the other modes.
- The parameters may be listed in any order, or omitted:
-
- C> set go32=driver c:\go32\drivers\tseng4k.grd gh 600 gw 800
-
- There is also an "ansi" parameter that may be added to use an ansi
- screen driver to use colors while debugging.
-
- For a listing of what the various modes are, see any of the following:
- * listing earlier in this document
- * code for the drivers
- * include/graphics.h
-
- Example drivers are in vga.asm, tseng4k.asm, and tseng3k.asm.
-
- The first two words point to the two routines a driver provides.
- The next word indicates if "split page" is available (see below).
- The next four words are the default text and graphics sizes.
-
- The "split page" feature of some vga's (like the TSENG, unlike PS/2)
- allow one bank to be used for reading and another for writing, so
- reading 0xa000:0x0400 talks to one byte in VRAM, and writing
- 0xa000:0x0400 talks to a different byte. If your card supports this,
- set the split-bank word to 1. If not, set it to 0. You can return
- anything for PS/2's because they don't have enough memory to need page
- swapping, so can't really tell that you don't have that feature.
-
- GRAPHICS.C installs and calls the graphics driver for mode changes.
- The mode change function is pointed to by the first pointer (note: the
- pointers are only read when the file is installed). It takes the mode
- in AX, and the size (when required) in CX and DX. It should return
- the new size in CX and DX.
-
- GRPROT.ASM handles the actual page faults. It uses a page table's
- PRESENT bits to determine where the application can read/write to
- without having to reconfigure the graphics card. There are two states
- the graphics system can be in:
-
- 1: rw
- Access to 0xd0000000 - 0xd00fffff are allowed. Reads and writes
- to the same address refer to the same physical byte of video memory
- ┌───R───┐ 0xD00xxxxx
- ────────┼───────┼────────────────────────────────────── video ram
- └───W───┘ 0xD00xxxxx
-
- 2: r_w
- Reads to 0xd0100000 - 0xd01fffff and writes to 0xd0200000 - 0xd02fffff
- are allowed. The card is configured to read from one bank and
- write to another. This is "split bank" mode, and is used for fast
- blits across the screen.
- ┌───R───┐ 0xD01xxxxxx
- ────────┴───────┴───────┬───────┬────────────────────── video ram
- └───W───┘ 0xD02xxxxxx
-
-
- When grprot determines that the VGA has to be reprogrammed, it calls the
- function pointed to by the second pointer (in protected mode), passing
- the read page in AH and the write page in AL.
-
- That's it! All knowlegde of card specifics are contained in the drivers,
- so libgr.a and your programs don't have to be recompiled!
-
- If you can't manage to get your card to work, I may be persuaded to add
- it for you (as long as you provide technical manuals!). If you add a
- card, please send me the sources for the driver so I can integrate it
- into future releases!
-
-