home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / SOUND / PLAY_SRC.ZIP / PMODE.DOC < prev    next >
Encoding:
Text File  |  1994-09-09  |  30.0 KB  |  649 lines

  1.  
  2.   Greetings... This is the documentation for PMODE v2.5 assembly protected
  3. mode header by Tran (a.k.a. Thomas Pytel). It is intended for assembly
  4. programmers with a good deal of knowlege of the 386. In this doc is explained
  5. the workings and usage of PMODE.ASM. This doc was originally written for an
  6. earlier version of PMODE, but it is suitable (with minor adjustments) for
  7. PMODE v2.5.
  8.  
  9. ------------------------------------------------------------------------------
  10. Contents:
  11. ---------
  12.  
  13.   0 - Overview
  14.       0.0 - What it does
  15.       0.1 - Your code
  16.   1 - Memory, segments, and selectors
  17.       1.0 - Memory structure
  18.       1.1 - Usage and DOS
  19.       1.2 - Selectors
  20.   2 - The stack and calling across modes
  21.       2.0 - The stack
  22.       2.1 - Calling real mode
  23.       2.2 - Calling protected mode
  24.   3 - IRQs and exceptions
  25.       3.0 - IRQs
  26.       3.1 - DPMI and the stack
  27.       3.2 - Chaining to real mode
  28.       3.3 - The IF flag
  29.       3.4 - Exceptions
  30.   4 - Functions and data
  31.       4.0 - Variables
  32.       4.1 - Memory functions
  33.       4.2 - IRQ functions
  34.       4.3 - Selector functions
  35.       4.4 - Other functions
  36.   5 - Notes
  37.       5.0 - DMA problems
  38.       5.1 - Misc notes
  39.       5.2 - Final word
  40.  
  41. ------------------------------------------------------------------------------
  42. 0 - Overview:
  43. -------------
  44.  
  45.   PMODE.ASM is a small piece of assembly code which is intended to allow for
  46. easy 32bit flat protected mode coding in assembly. I wrote it for myself, and
  47. it was designed for exactly what I need. But since it is so useful, and there
  48. are not too many other alternatives for protected mode ASM coding, I am
  49. putting it out for public distribution. The current version of PMODE has
  50. been evolving for a while. There has been plenty of time to refine and debug
  51. it. It is at this point, from my own and friends experiences, totally stable
  52. and bug-free. I do not make this statement lightly. But I do not guarantee it
  53. either.
  54.  
  55.   PMODE v2.5 is a touched up version of PMODE v2.4. Most (I think all) of the
  56. dead code has been removed from previous versions of PMODE. One minor DPMI bug
  57. has been fixed and the DPMI memory block allocation had been changed to
  58. compensate for a QDPMI bug (QEMM DPMI host). The previous allocation scheme
  59. may also have been the cause of memory allocation failure under OS/2. PMODE is
  60. a dedicated ASM extender. So far it has proven very stable and pretty clean
  61. over all. If you have been looking for something like this, feel free to use
  62. it. Or examine the source code if you just want to learn (though the code is a
  63. bit messy). All I ask if you use this code is credits.
  64.  
  65. 0.0 - What it does:
  66. -------------------
  67.  
  68.   PMODE provides a flat 32bit protected mode environment for assembly code to
  69. run in. No matter what kind of 386 protection control is already in place. It
  70. will run under VCPI, DPMI, or in raw mode with no 386 control system in place.
  71. This includes all the popular memory managers, Windows the virus, OS/2, etc...
  72. PMODE will take care of detecting a 386+ processor, making sure there is
  73. enough memory and allocating it. It will handle all the minor details of 386
  74. protected mode. Send IRQs that occur in protected mode to their real mode
  75. handlers, or allow you to intercept them. And, ofcourse, allow your protected
  76. mode code to call real mode interrupts and routines. PMODE will also take care
  77. of allocating and maintaining the stack across mode calls.
  78.  
  79.   When a PMODE program starts up, PMODE will do all of its necessary starup
  80. tasks. Then, if no error was detected (not enough mem, no 386+, etc...), it
  81. will jump to a label in your code called _main. Your program takes over from
  82. there with all interrupts disabled since real mode. You must do a STI to
  83. enable them. Don't forget this like I have so many times. When your program is
  84. done and wants to exit to DOS, simply jump to a label called _exit, defined
  85. in PMODE. You can pass back an error code to DOS. There is a variable called
  86. _exitcode which contains the byte to pass back to DOS (AL in INT 21h AH=4c).
  87.  
  88. 0.1 - Your code:
  89. ----------------
  90.  
  91.   All your 32bit code goes into one large CODE32 segment. It runs in 32bit
  92. protected mode from start to finish. All your code and data reside in this
  93. one large segment. Though you can read or write stuff below the beginning of
  94. CODE32. Within your code you will hardly ever have to worry about segment
  95. overrides or stuff like that. Its just pretty much straight flat assembly with
  96. full 32bit linear addresses for all your code and data. You can do most of the
  97. stuff you do in real mode. I would not suggest trying to go TSR or running
  98. external programs from your PMODE code though. It is doable, and will probably
  99. work, but PMODE was not designed for that. You would have to free up low
  100. memory yourself, and you can't free up high memory. There may be other minor
  101. problems uncompensated for. PMODE is meant for standalone ASM programs like
  102. games or demos, and does very well for that.
  103.  
  104. ------------------------------------------------------------------------------
  105. 1 - Memory, segments, and selectors:
  106. ------------------------------------
  107.  
  108.   In protected mode, your program has access to all free low and high memory
  109. that could be allocated. Low memory is all memory visible to DOS below 1M.
  110. High memory is all extended memory that could be allocated through VCPI, DPMI,
  111. XMS, or INT 15 AH=88h of raw mode. All this memory can be accessed directly
  112. realative to the beginning of the 32bit protected mode segment (CODE32). You
  113. can also access memory realative to the absolute beginning of memory. Three
  114. main selectors are set up by PMODE. One for the code segment starting at
  115. CODE32, its limit is set to 4G. One for a data segment alias for the code
  116. segment (same memory space), also at 4G. And one for a data segment beginning
  117. at the absolute beginning of memory. In fact, all selectors allocated by PMODE
  118. are set to a limit of 4G.
  119.  
  120. 1.0 - Memory structure:
  121. -----------------------
  122.  
  123.   The structure of memory when your code begins executing is as follows:
  124.  
  125. +-------------------------------------------------------------+
  126. | Normal crap (real mode int vector table, DOS, TSRs, etc...) |
  127. +-------------------------------------------------------------+
  128. | PSP                                                         |
  129. +-------------------------------------------------------------+
  130. | Beginning of CODE16 - PMODE 16bit code and data             |
  131. +-------------------------------------------------------------+
  132. | Beginning of CODE32 - PMODE 32bit code and data             |
  133. +-------------------------------------------------------------+
  134. | Your 32bit code and data                                    |
  135. +-------------------------------------------------------------+
  136. | The stack                                                   |
  137. +-------------------------------------------------------------+
  138. | PMODE data allocated at run-time (IDT, TSS, etc...)         |
  139. +-------------------------------------------------------------+
  140. | Free low memory (_lomembase to _lomemtop)                   |
  141. +-------------------------------------------------------------+
  142. | Video buffer, ROMS, also possibly hiram                     |
  143. +-------------------------------------------------------------+
  144. | Used extended memory (if any)                               |
  145. +-------------------------------------------------------------+
  146. | Free extended memory (if any, _himembase to _himemtop)      |
  147. +-------------------------------------------------------------+
  148. | Used extended memory (if any)                               |
  149. +-------------------------------------------------------------+
  150.  
  151.   When your code begins execution at _main, you can be sure there is a minimum
  152. of low memory available. This number is specified at the top of PMODE.ASM as
  153. LOWMIN. There is also a minimum of high memory specified in PMODE.ASM as
  154. EXTMIN. The beginning and ending addresses of these memory spaces, realative
  155. to the beginning of CODE32, are defined in four variables made available to
  156. your code. _lomembase is the linear address of the beginning of free low
  157. memory. _lomemtop is the linear address of the top of low memory (last
  158. possible byte+1). _himembase is the beginning of extended memory, and
  159. _himemtop is the end of it. All of these vars can be modified by your program.
  160. They will also be modified by PMODE memory functions. See section 4 for a
  161. description of these functions. Basically all that they do is see if there is
  162. enough memory available for a block you request. If there is, they pass back
  163. a pointer to the base of free memory of the type you requested, then adjust
  164. that base by the amount you requested.
  165.  
  166.   The functions (just tiny stubs of code really) provided for memory are just
  167. straight linear functions. No management of blocks of memory is done. I
  168. personally don't like fragmentations of memory, and can work fine without the
  169. need for blocks. If you want, write yourself a little malloc library if that
  170. is what you need.
  171.  
  172. 1.1 - Usage and DOS:
  173. --------------------
  174.  
  175.   When you call real mode DOS interrupts, or any real mode procedure that
  176. expects a buffer, you will have to make sure that buffer is in low memory.
  177. Remember that real mode DOS and code can only see low memory. Your code and
  178. data and the stack always reside in low memory. If you want to pass something
  179. that is in high memory however, you will have to copy it to somewhere in low
  180. memory. Once in low memory, you will have to get the real mode segment:offset
  181. pair for your linear address. Figuring this out is very easy. All linear
  182. addresses in PMODE are realative to the beginning of the CODE32 segment. To
  183. convert to an absolute address, all you have to do is add the offset of the
  184. CODE32 segment from absolute 0. And just this value is available in a variable
  185. called _code32a. All this really is, is the real mode segment value of CODE32
  186. shifted left 4 bits. So for example, _lomembase+_code32a is the linear address
  187. of the beginning of free low memory from absolute 0. And if you don't know how
  188. to convert this type of address to a seg:off pair, you should probably not be
  189. reading this doc just yet.
  190.  
  191. 1.2 - Selectors:
  192. ----------------
  193.  
  194.   As you know (and if you don't, get some books and learn more about protected
  195. mode), in protected mode the segment registers don't work with segment
  196. addresses, but with selectors. Selectors are indexes into tables describing
  197. segments. Appropriately enough these tables are called descriptor tables. And
  198. you do not have to worry about them, PMODE takes care of all the crap
  199. associated with them.
  200.  
  201.   The three main selectors you need (the code, data, and zero selectors) are
  202. set up by PMODE. Their numerical values are stored in three variables made
  203. available to your program. _selcode, _seldata, and _selzero are these
  204. variables. When your program begins execution at _main, CS is obviously set
  205. to _selcode, DS, ES, FS, and SS to _seldata, and GS is set to _selzero. With
  206. the exception of FS and SS, this is the state PMODE expects the segment regs
  207. to be whenever you call one of its functions or interrupts.
  208.  
  209.   PMODE also allows you to allocate extra data selectors and to set their base
  210. addresses to anything you want. This could be useful for tight routines where
  211. you want to conserve register space and use 16bit register addressing. You
  212. can specify the maximum number of selectors you will need to have allocated
  213. at any one time at the top of PMODE.ASM in the SELECTORS equate.
  214.  
  215.   During the execution of your code, you can modify DS, ES, FS, and GS to
  216. whatever selector you wish. Just remember to set the appropriate values for
  217. DS, ES, and GS before calling and PMODE functions or interrupts. Throughout
  218. the execution of your program you can assume SS to be _seldata. Except in the
  219. special case of IRQ handlers, explained in section 3.
  220.  
  221. ------------------------------------------------------------------------------
  222. 2 - The stack and calling across modes:
  223. ---------------------------------------
  224.  
  225.   The stack and calling across modes are closely tied together. Multiple
  226. nested calls from protected to real mode and back are supported. DPMI also
  227. feels the need to complicate the situation a little in dealing with IRQs, but
  228. more on that later. You do not have to worry about the stack in calling across
  229. modes, PMODE will take care of it.
  230.  
  231. 2.0 - The stack:
  232. ----------------
  233.  
  234.   PMODE sets up and maintains the stack for your program. In fact, your code
  235. should not attempt to set up its own stack. Both because its not necessary,
  236. and because of some other stupid historical reasons that I have forgotten by
  237. now. There are four equates at the top of PMODE.ASM that determine the final
  238. size and allocation of the stack. STAKMAIN sets the size of your main program
  239. stack. The stack that will be used in your main stream of execution. STAKRMODE
  240. is the size of the stack that will be given to any real mode code that is
  241. called from protected mode. STAKPMODE is the size of the stack given to any
  242. protected mode routines called from real mode. MODENESTING is the maximum
  243. number of nested cross-mode calls supported. The final size of the master
  244. stack is determined from all of these variables, and it cannot exceed 64k.
  245.  
  246. 2.1 - Calling real mode:
  247. ------------------------
  248.  
  249.   From your protected mode code you can call real mode interrupts and routines
  250. using protected mode interrupts set up by PMODE for this purpose. You pass
  251. registers to the real mode interrupt or routine through the use of virtual
  252. registers, which are just memory images of the values to be set for those
  253. registers in real mode. There are virtual registers for EAX, EBX, ECX, EDX,
  254. ESI, EDI, EBP, DS, ES, FS, and GS. The virtual registers for AL, AH, and AX
  255. share the appropriate memory space within the virtual EAX reg. Notice that
  256. there are no SS, ESP, CS, and EIP registers. CS:EIP is taken from the real
  257. mode interrupt vektor table for interrupt calls, and passed in the real CX:DX
  258. registers for a procedure call. SS:ESP is set up by PMODE.
  259.  
  260.   An INT 32h instruction in protected mode calls a real mode procedure. The
  261. real CX:DX registers are the seg:off of the real mode procedure. The real mode
  262. procedure must return with a RETF. The interrupt enable flag is preserved
  263. across the call to real mode, but not back. After the INT 32h the IF flag will
  264. be the same as before. The real carry, zero, aux, parity, sign, and overflow
  265. flags will be passed back from the real mode routine unchanged. The real CPU
  266. registers will be set to the values of the virtual registers for the real mode
  267. routine. The return values of the routine will be stored back into the virtual
  268. registers. The actual CPU registers will be unchanged in protected mode.
  269.  
  270.   An INT 33h in protected mode will call a real mode interrupt handler. AL is
  271. the interrupt number you want to call. The interrupt flag is disabled for the
  272. real mode interrupt handler just as it is in real mode. Other than this, INT
  273. 33h works just like INT 32h with respect to virtual registers and the real
  274. flags passed back from the handler.
  275.  
  276.   One minor thing I must point out. INT 32h and INT 33h do not preserve FS. It
  277. is returned as _seldata.
  278.  
  279. 2.2 - Calling protected mode:
  280. -----------------------------
  281.  
  282.   You can also call a protected mode routine from real mode. The virtual
  283. registers are used again to pass register values. With the exception of the
  284. segment registers. For the protected mode routine, CS will obviously be
  285. _selcode. DS, ES, FS, and SS will be _seldata. GS will be _selzero. Also, the
  286. direction flag will be cleared for the protected mode routine. The virtual
  287. DS, ES, FS, and GS registers are untouched by a call to a protected mode
  288. routine. The interrupt enable flag is preserved across the call, but not back,
  289. just like a protected mode call to INT 32h. The carry, zero, aux, parity,
  290. sign, and overflow flags are also passed back real mode from the protected
  291. mode routine. To call a protected mode routine from real mode, do an INT 32h
  292. in real mode. That's right, another INT 32h. But its a different handler from
  293. the protected mode version of the int. The offset of the protected mode
  294. routine you want to call should be in EDX. And that routine must return with
  295. a regular RET.
  296.  
  297. ------------------------------------------------------------------------------
  298. 3 - IRQs and exceptions:
  299. ------------------------
  300.  
  301.   First thing, let me just say that many DPMI drivers are very buggy in the
  302. area of IRQs. They may not reflect them properly to real mode. Or they may
  303. screw up if you try to do a call to real mode from a protected mode IRQ
  304. handler. Keep this is mind if you are testing your code under a DPMI system.
  305.  
  306. 3.0 - IRQs:
  307. -----------
  308.  
  309.   By default, IRQs that occur in protected mode are sent on to their real mode
  310. handlers (this counts as a mode switch to the PMODE master stack). PMODE
  311. allows you to install your own protected mode IRQ handlers. There are two
  312. functions for getting and setting protected mode IRQ vectors in PMODE (see
  313. section 4). Once set with these functions, your protected mode IRQ handler
  314. will be active, but only in protected mode. If an IRQ you have hooked occurs
  315. while processing a call to real mode (INT 32h or 33h or an IRQ that is being
  316. processed by its real mode handler), it will go to the handler specified in
  317. the real mode interrupt vector table. PMODE provides another set of functions
  318. to create real mode callbacks to protected mode IRQ handlers, so that your
  319. handler will get control no matter where the IRQ occurred. These callbacks,
  320. however, modify the real mode interrupt vector table. Making chaining to the
  321. real mode handler not as easy as using INT 33h with the appropriate interrupt
  322. number.
  323.  
  324.   You should terminate any protected mode IRQs with an IRETD (notice the D).
  325. DPMI dox also say that this may not restore the interrupt enable flag, so
  326. you should do a STI just before. However, all DPMIs I have tested seem to
  327. restore the flag correctly without the STI.
  328.  
  329. 3.1 - DPMI, and the stack:
  330. --------------------------
  331.  
  332.   The one anomaly to PMODEs stack with IRQs is DPMI. It sees fit to switch
  333. onto its own stack whenever an IRQ goes off. And if you try to switch off that
  334. stack, you will be severely punished by DPMI. For this reason, calls to real
  335. mode (INT 32h, 33h) from IRQs under DPMI may or may not work depending on what
  336. DPMI you're running under and how buggy it is. I have had no problems with
  337. Windows DPMI driver in these situations, but you have been warned. Because
  338. DPMI switches onto its own stack, you can not assume anything about SS in IRQ
  339. handlers, and should definately not mess with it.
  340.  
  341. 3.2 - Chaining to real mode:
  342. ----------------------------
  343.  
  344.   If you don't set the real mode IRQ callback for a particular IRQ, chaining
  345. to that IRQs real mode handler is as easy as using INT 33h with the
  346. appropriate interrupt number. But you probably will set the callbacks. In
  347. which case, if you use INT 33h, it will just go to the protected mode IRQ
  348. handler. And if this INT 33h call was from the protected mode IRQ handler,
  349. well, lets just say infinite loop. If you have the callback set, and you wish
  350. to chain (why bother?), you must make the address of the real mode IRQ handler
  351. available to a real mode far routine that will call that handler as an
  352. interrupt routine. You should call this real mode routine with INT 32h from
  353. protected mode to do the IRQ chaining.
  354.  
  355. 3.3 - The IF flag:
  356. ------------------
  357.  
  358.   DPMI may need to virtualize the real system interrupt flag in protected
  359. mode. For this reason you may not assume anything about the IF flag and
  360. instructions which usually modify it. For example, PUSHF(D) may not store the
  361. actual IF flag on the stack, and POPF(D) may not change either the real IF
  362. flag or the virtual one. You can however be sure that CLI and STI will carry
  363. out their functions correctly. Also, PMODE will replicate DPMIs native
  364. interrupt flag functions if DPMI is not present. They are on INT 31h in
  365. protected mode and are as follows:
  366.  
  367.   AX=900h: Get state of IF then disable it. Returns AL set to the IF flag.
  368.   AX=901h: Get state of IF then enable it. Returns AL set to the IF flag.
  369.   AX=902h: Only returns AL set to the IF flag (0=disabled, 1=enabled).
  370.  
  371. 3.4 - Exceptions:
  372. -----------------
  373.  
  374.   Under DPMI, exceptions are handled by the DPMI driver, which will usually
  375. just terminate your program. Otherwise PMODE will automatically exit to DOS
  376. on any exception not overridden by the low 8 IRQs. Any exception that is, will
  377. erroneously be sent to that IRQ handler, be it a protected mode handler or
  378. a real mode handler. Hey, you should not be getting exceptions in the first
  379. place.
  380.  
  381. ------------------------------------------------------------------------------
  382. 4 - Functions and data:
  383. -----------------------
  384.  
  385.   PMODE makes some variables available to your program concerning the state of
  386. the system and memory. It also provides some functions for dealing with IRQs,
  387. memory, and selectors. These functions and vars are defined in PMODE.INC. Just
  388. include that somewhere in your code. Some of the functions are actually
  389. defined as dwords, not as near lables. This is because their address may be
  390. modified at startup to point to appropriate functions for the system type.
  391. Don't worry about this. Just call them as you would call normal functions. So
  392. here is a summary of all data and functions you can use. The functions
  393. definitions are pretty self-explanatory. Except maybe that CF=0 means carry
  394. flag clear, and CF=1 means a cheeseburger, hold the mayo.
  395.  
  396. 4.0 - Variables:
  397. ----------------
  398.  
  399. _selcode:word - The 32bit code selector.
  400.  
  401. _seldata:word - The 32bit data selector (alias for the code).
  402.  
  403. _selzero:word - The 32bit data selector starting at absolute 0.
  404.  
  405. _lomembase:dword - The linear address of the current base of low memory.
  406.  
  407. _lomemtop:dword - The linear address of the current top of low memory.
  408.  
  409. _himembase:dword - The linear address of the current base of high memory.
  410.  
  411. _himemtop:dword - The linear address of the current top of high memory.
  412.  
  413. _pspa:dword - The linear address of the PSP from absolute 0.
  414.  
  415. _code16a:dword - The linear address of the CODE16 segment from absolute 0.
  416.  
  417. _code32a:dword - The linear address of the CODE32 segment from absolute 0.
  418.  
  419. _sysbyte0:byte - The low 2 bits are the system type, 0=raw, 1=XMS, 2=VCPI,
  420.   3=DPMI. The high 6 bits are undefined.
  421.  
  422. _exitcode:byte - The exit code you want to pass to DOS, 0 by default.
  423.  
  424. Here are the virtual registers for cross-mode calls:
  425.  
  426.   v86r_eax:dword, v86r_ebx:dword, v86r_ecx:dword, v86r_edx:dword
  427.   v86r_esi:dword, v86r_edi:dword, v86r_ebp:dword
  428.   v86r_ah:byte, v86r_al:byte, v86r_bh:byte, v86r_bl:byte
  429.   v86r_ch:byte, v86r_cl:byte, v86r_dh:byte, v86r_dl:byte
  430.   v86r_ax:word, v86r_bx:word, v86r_cx:word, v86r_dx:word
  431.   v86r_si:word, v86r_di:word, v86r_bp:word
  432.   v86r_ds:word, v86r_es:word, v86r_fs:word, v86r_gs:word
  433.  
  434. 4.1 - Memory functions:
  435. -----------------------
  436.  
  437. _getlomem - Allocate some low mem
  438.   In:
  439.     EAX - size requested
  440.   Out:
  441.     CF=0 - memory allocated
  442.     CF=1 - not enough mem
  443.     EAX - linear pointer to mem or ?
  444.  
  445. _gethimem - Allocate some high mem
  446.   In:
  447.     EAX - size requested
  448.   Out:
  449.     CF=0 - memory allocated
  450.     CF=1 - not enough mem
  451.     EAX - linear pointer to mem or ?
  452.  
  453. _getmem - Allocate any mem, (first cheks low, then high)
  454.   In:
  455.     EAX - size requested
  456.   Out:
  457.     CF=0 - memory allocated
  458.     CF=1 - not enough mem
  459.     EAX - linear pointer to mem or ?
  460.  
  461. _lomemsize - Get amount of free low mem
  462.   Out:
  463.     EAX - number of bytes free
  464.  
  465. _himemsize - Get amount of free high mem
  466.   Out:
  467.     EAX - number of bytes free
  468.  
  469. 4.2 - IRQ functions:
  470. --------------------
  471.  
  472. _getirqvect - Get protected mode IRQ handler offset
  473.   In:
  474.     BL - IRQ num (0-0fh)
  475.   Out:
  476.     EDX - offset of IRQ handler
  477.  
  478. _setirqvect - Set protected mode IRQ handler offset
  479.   In:
  480.     BL - IRQ num (0-0fh)
  481.     EDX - offset of IRQ handler
  482.  
  483. _getirqmask - Get status of IRQ mask bit
  484.   In:
  485.     BL - IRQ num (0-15)
  486.   Out:
  487.     AL - status: 0=enabled, 1=disabled
  488.  
  489. _setirqmask - Set status of IRQ mask bit
  490.   In:
  491.     BL - IRQ num (0-15)
  492.     AL - status: 0=enabled, 1=disabled
  493.  
  494. _rmpmirqset - Set a real mode IRQ vect to redirect to pmode
  495.   In:
  496.     BL - IRQ number
  497.     EDX - offset of IRQ handler
  498.     EDI -> 21 byte buffer for code stub created
  499.   Out:
  500.     EAX - old seg:off of real mode IRQ handler
  501.  
  502. _rmpmirqfree - Reset a real more IRQ vect back to normal
  503.   In:
  504.     BL - IRQ number
  505.     EAX - seg:off of real mode IRQ handler
  506.  
  507. 4.3 - Selector functions:
  508. -------------------------
  509.  
  510. _getselector - Allocate a selector
  511.   Out:
  512.     CF=1 - selector not allocated
  513.     CF=0 - selector allocated
  514.     AX - 4G data selector or ?
  515.  
  516. _freeselector - Free an allocated selector
  517.   In:
  518.     AX - selector
  519.  
  520. _setselector - Set the base addx for a selector
  521.   In:
  522.     AX - selector
  523.     EDX - linear base addx for selector
  524.  
  525. 4.4 - Other functions:
  526. ----------------------
  527.  
  528. _exit - Exit to real mode
  529.  
  530. _ret - Absolutely nothing, just a RET instruction
  531.  
  532. ------------------------------------------------------------------------------
  533. 5 - Notes:
  534. ----------
  535.  
  536.   In this section is a whole bunch of info that didn't really fit into the
  537. other sections, or that I want to emphasize. If you run into a weird bug,
  538. check here to for some possibilities. It is easy to forget enable interrupts
  539. when your program gains control. Or to forget theres a limit to the stack
  540. since control of it is taken away from your program.
  541.  
  542. 5.0 - DMA Problems:
  543. -------------------
  544.  
  545.   As you know, the DMA controllers in the PC use all physical addresses.
  546. Nothing but the processor itself knows how linear memory is arranged in the
  547. physical memory banks. When paging is disabled, the relationship is very
  548. simple. The linear address is always the same as the physical address. But
  549. when you enable paging, that could get all screwed up. In raw mode and XMS,
  550. you don't have to worry about this since paging is disabled. But under VCPI
  551. and DPMI things are different. You can almost definately count on extended
  552. memory addresses not being consistent with their physical addresses. Low
  553. memory however, will usually map perfectly to its physical addresses. Unless
  554. the program is running in some sort of multitasking system. Then the chances
  555. are slim. The point is that you can't trust DMA much under VCPI and DPMI.
  556.  
  557.   Ive seen the specs for VDS, and its useless for the type of DMA I need to
  558. do. So there is no support for it in PMODE. If you feel like it, use it
  559. yourself if you detect it.
  560.  
  561. 5.1 - Misc notes:
  562. -----------------
  563.  
  564. ) No, you can't link PMODE with any high level languages.
  565.  
  566. ) When linking, PMODE must be the first object in the link list.
  567.  
  568. ) PMODE functions and INTs expect the direction flag to be clear.
  569.  
  570. ) In IRQ handlers, you should not assume anything about the stack.
  571.  
  572. ) Under VCPI, PMODE will allocate a maximum of 60M extended memory.
  573.  
  574. ) You do not have to free any selectors you allocate before exiting.
  575.  
  576. ) Remember to use 'IRETD' not 'IRET' at the end of protected mode IRQs.
  577.  
  578. ) Due to all of its 'evolving', PMODE.ASM is now very very very very messy.
  579.  
  580. ) I would REALLY suggest not ever switching your stack in protected mode
  581. yourself.
  582.  
  583. ) Remember that upon reaching '_main', interrupts are still disabled. Don't
  584. forget to do the STI.
  585.  
  586. ) You can't write to memory with a CS: override in protected mode, but you can
  587. read with a CS: override.
  588.  
  589. ) This thing was tested under TASM 4.0. So if you have something different,
  590. don't blame me if it doesnt compile.
  591.  
  592. ) Yeah, theres no debugger. Quit whining, don't you realize it runs under
  593. DPMI? So you can use any old DPMI debugger.
  594.  
  595. ) When doing multiple nested cross-mode calls, keep in mind that the same
  596. virtual regs are used to pass register values.
  597.  
  598. ) Division faults, single step interrupts, the NMI, INT3, INTO, and BOUND
  599. faults are sent to real mode handlers for the appropriate int number.
  600.  
  601. ) If you modify the base address of a selector you allocated, make sure to
  602. reload any segment registers containing that selector before using them.
  603.  
  604. ) I hope you realize that in PMODE IRQ handlers, you don't have the BIOS to
  605. redirect IRQ9 to IRQ2. So any device that uses IRQ2 will actually be using 9.
  606.  
  607. ) If you're getting problems that smell of stack trouble, try increasing the
  608. stack size vars at the top of PMODE.ASM and the maximum nesting level if
  609. you're doing many calls across modes.
  610.  
  611. ) Upon entry to a protected mode IRQ handler, remember that all segregs are
  612. in an unknown state, including DS. Don't forget the 'mov ds,cs:_seldata'. Also
  613. ofcourse preserve the previous value of all the regs.
  614.  
  615. ) Remember that the INT31 AX=9?? flag functions are only available in pmode.
  616. Go ahead, use the PUSHFs and POPFs in real mode to alter the IF flag... And
  617. any DPMI host that can't handle that properly deserves to crash.
  618.  
  619. ) There may be weird problems under some DPMIs. Many DPMI drivers out there
  620. are anywhere from a little to extremely buggy. If you suspect your DPMI
  621. driver, try running without it, or under a different DPMI driver.
  622.  
  623. ) If you're gonna add other segments, put them between CODE16 and CODE32 only
  624. if theyre small enough to still allow access to CODE32 data from CODE16.
  625. Otherwise put them between CODE32 and CODEEND. You can also just stick your
  626. 16bit code in the CODE16 segment.
  627.  
  628. ) Before exiting your program, you do not need to restore any protected mode
  629. IRQ vectors. If you modified the real mode vector table, you gotta restore
  630. those. And you do not have to restore the IRQ masks at 21h and A1h, PMODE
  631. stores them before jumping to _main, and restores them before exiting.
  632.  
  633. ) PMODE does not handle the VDISK low to high extended memory allocation
  634. scheme because it is just plain stupid (and does not seem to be used outside
  635. of XMS where its not a problem since the XMS driver is used to allocate mem).
  636. If you wanna take precautions for this type of allocation, make yourself a
  637. little macro to check for it and adjust _himembase accordingly.
  638.  
  639. 5.2 - Final word:
  640. -----------------
  641.  
  642.   Well thats that... If you have a problem with something in PMODE, code your
  643. own. Use this code, or don't, its your choice. Or just use it to learn if you
  644. wish. Oh well...
  645.  
  646.                                                 L8r...
  647.                                                 Tran...
  648.  
  649.