home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / smp.zip / smp.inf (.txt)
OS/2 Help File  |  1996-06-10  |  111KB  |  4,595 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Notices ΓòÉΓòÉΓòÉ
  3.  
  4. First Edition (June 1994) 
  5.  
  6. The following paragraph does not apply to the United Kingdom or any country 
  7. where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS 
  8. MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY 
  9. KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  10. WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states 
  11. do not allow disclaimer of express or implied warranties in certain 
  12. transactions, therefore, this statement may not apply to you. 
  13.  
  14. This publication could include technical inaccuracies or typographical errors. 
  15. Changes are periodically made to the information herein; these changes will be 
  16. incorporated in new editions of the publication. IBM may make improvements 
  17. and/or changes in the product(s) and/or the program(s) described in this 
  18. publication at any time. 
  19.  
  20. It is possible that this publication may contain reference to, or information 
  21. about, IBM products (machines and programs), programming, or services that are 
  22. not announced in your country.  Such references or information must not be 
  23. construed to mean that IBM intends to announce such IBM products, programming, 
  24. or services in your country. 
  25.  
  26. Requests for technical information about IBM products should be made to your 
  27. IBM authorized reseller or IBM marketing representative. 
  28.  
  29.  
  30. ΓòÉΓòÉΓòÉ 1.1. Copyright Notices ΓòÉΓòÉΓòÉ
  31.  
  32. COPYRIGHT LICENSE: This publication contains printed sample application 
  33. programs in source language, which illustrate OS/2 programming techniques. You 
  34. may copy, modify, and distribute these sample programs in any form without 
  35. payment to IBM, for the purposes of developing, using, marketing or 
  36. distributing application programs conforming to the OS/2 application 
  37. programming interface. 
  38.  
  39. Each copy of any portion of these sample programs or any derivative work, which 
  40. is distributed to others, must include a copyright notice as follows: "(C) 
  41. (your company name) (year).  All rights reserved." 
  42.  
  43. (C) Copyright International Business Machines Corporation 1994. All rights 
  44. reserved. Note to U.S. Government Users - Documentation related to restricted 
  45. rights - Use, duplication, or disclosure is subject to restrictions set forth 
  46. in GSA ADP Schedule Contract with IBM Corp. 
  47.  
  48.  
  49. ΓòÉΓòÉΓòÉ 1.2. Disclaimers ΓòÉΓòÉΓòÉ
  50.  
  51. References in this publication to IBM products, programs, or services do not 
  52. imply that IBM intends to make these available in all countries in which IBM 
  53. operates. Any reference to an IBM product, program or service is not intended 
  54. to state or imply that only IBM's product, program, or service may be used. Any 
  55. functionally equivalent product, program, or service that does not infringe any 
  56. of IBM's intellectual property rights or other legally protectable rights may 
  57. be used instead of the IBM product, program, or service. Evaluation and 
  58. verification of operation in conjunction with other products, programs, or 
  59. services, except those expressly designated by IBM, are the user's 
  60. responsibility. 
  61.  
  62. IBM may have patents or pending patent applications covering subject matter in 
  63. this document. The furnishing of this document does not give you any license to 
  64. these patents. You can send license inquiries, in writing, to the IBM Director 
  65. of Licensing, IBM Corporation, 208 Harbor Drive, Stamford, Connecticut 
  66. 06904-2501, U.S.A. 
  67.  
  68.  
  69. ΓòÉΓòÉΓòÉ 1.3. Trademarks ΓòÉΓòÉΓòÉ
  70.  
  71. The following terms found in this publication, are trademarks of the IBM 
  72. Corporation in the United States or other countries: 
  73.  
  74. OS/2 
  75. DB2/2 
  76. CICS 
  77. IBM 
  78. NetView 
  79. Presentation Manager 
  80.  
  81. The following terms found in this publication, are trademarks of other 
  82. companies as follows. Other trademarks are trademarks of their respective 
  83. companies. 
  84.  
  85. Intel          Intel Corporation 
  86. Lotus Notes    Lotus Development Corporation 
  87. Novell         Novell, Inc. 
  88. Compaq         Compaq Computer Corporation 
  89. Windows NT     Microsoft Corporation 
  90. Windows        Microsoft Corporation 
  91. ALR            Advanced Logic Research, Inc. 
  92.  
  93.  
  94. ΓòÉΓòÉΓòÉ 2. Overview of OS/2 for SMP Version 2.11 ΓòÉΓòÉΓòÉ
  95.  
  96. This document provides a guide for developers writing applications and device 
  97. drivers for OS/2 for Symmetrical Multiprocessing (SMP) V2.11. 
  98.  
  99. OS/2 for SMP V2.11 was developed to satisfy the need to run OS/2 on 
  100. multiprocessor based CISC processors, namely the Intel x86 compatible family. 
  101. The requirements for OS/2 for SMP V2.11 were that it run all existing 
  102. applications, device drivers and subsystems, as well as take advantage of new 
  103. multiprocessor (MP) exploitive applications and device drivers. 
  104.  
  105. The emergence of low-cost MP hardware based on the 486 and Pentium processors 
  106. makes OS/2 for SMP V2.11 an attractive desktop operating environment. Server 
  107. and workstation environments using the x86 architecture are moving toward the 
  108. more powerful emerging RISC based chip sets. These new RISC processors lack the 
  109. full range of programming tools available for the x86 chip set. OS/2 for SMP 
  110. V2.11 attempts to solve the problems of insufficient processor bandwidth by 
  111. supporting multiple x86 processors in a single computer. 
  112.  
  113. To provide increased performance, OS/2 for SMP V2.11 allows applications, file 
  114. system, mass storage and network drivers to execute on any processor at any 
  115. time. A number of databases and applications have been converted to run OS/2 
  116. for SMP V2.11. DB2/2 and CICS are two databases that IBM has converted to run 
  117. under OS/2 for SMP V2.11. These application can benefit greatly from OS/2 for 
  118. SMP V2.11 because they are CPU-intensive. Other applications which can also 
  119. benefit from OS/2 for SMP V2.11 are: 
  120.  
  121. o Lotus Notes & cc-Mail 
  122. o NetView Series 
  123. o Novell Netware 
  124. o Scientific Applications 
  125. o MultiMedia Applications 
  126. o OS/2 Lan Server 
  127.  
  128.  
  129. ΓòÉΓòÉΓòÉ 2.1. Architectural Design Objectives ΓòÉΓòÉΓòÉ
  130.  
  131. The architectural design objectives for a multiprocessor (MP) version of OS/2 
  132. were as follows: 
  133.  
  134.  1. Transparent support for two or more CPUs (16 CPUs max). 
  135.  
  136.  2. Support for applications and device drivers which are not MP safe and 
  137.     aware. 
  138.  
  139.  3. Support for various MP hardware platforms (eg.  Compaq, APIC, EBI2, 
  140.     Corollary, etc) via a Platform Specific Driver (PSD) layer. 
  141.  
  142.  4. Small footprint - 4MB for OS/2 and DOS applications; 6MB for WINOS2 
  143.  
  144.  5. Performance equal to or better than Windows NT. 
  145.  
  146.  6. 100% application compatible for existing OS/2 DOS and Windows applications. 
  147.  
  148.  7. Honor priority preemption across all processors. 
  149.  
  150. Transforming the OS/2 2.x uniprocessor (UP) code base into OS/2 for SMP V2.11 
  151. was mostly a matter of copying the vital system data structures for the number 
  152. of processors. Only ONE copy of OS/2 is running at one time, no matter how many 
  153. processors are present. System initialization automatically determines the 
  154. number of processors and generates the appropriate number of data structures, 
  155. including new control blocks and per-processor data structures. one 
  156. process/thread running 
  157.  
  158.  
  159. ΓòÉΓòÉΓòÉ 3. Platform Specific Drivers (PSDs) ΓòÉΓòÉΓòÉ
  160.  
  161. In OS/2 for SMP V2.11, all of the platform specific code has been removed from 
  162. the operating system, and placed into a Platform Specific Driver. These drivers 
  163. provide an abstraction layer for the underlying hardware by allowing the 
  164. operating system to call generic functions to perform platform-specific 
  165. operations without worrying about the actual hardware implementation. This 
  166. allows OS/2 for SMP V2.11 to support new MP hardware platforms without 
  167. modifying the operating system. 
  168.  
  169. PSDs are 32-bit flat DLLs specified in CONFIG.SYS by using the PSD= keyword, 
  170. and must conform to the 8.3 file naming convention (e.g. PSD=BELIZE.PSD). They 
  171. cannot contain either drive or path information because OS/2 cannot process 
  172. such information at the stage of the startup sequence when the PSD statements 
  173. are processed. The root directory of the startup partition is first searched 
  174. for the specified file name, followed by the \OS2 directory of the startup 
  175. partition. If drive or path information is included in a PSD statement, an 
  176. error is generated. 
  177.  
  178. PSD parameters may be specified after the PSD's name, and may be a maximum of 
  179. 1024 characters long. The parameter string is not interpreted or parsed by 
  180. OS/2, but is passed verbatim as an ASCIIZ string when the PSD's Install 
  181. function is invoked. 
  182.  
  183. If multiple PSD statements are encountered, OS/2 will load each PSD in the 
  184. order listed in CONFIG.SYS, and call the PSD's install function. The first PSD 
  185. which successfully installs will be the one OS/2 uses. 
  186.  
  187. PSD statements are processed before BASEDEV, IFS, and DEVICE statements. 
  188.  
  189.  
  190. ΓòÉΓòÉΓòÉ 3.1. Platform Specific Driver Architecture and Structure ΓòÉΓòÉΓòÉ
  191.  
  192. The PSD operates in three contexts (modes): Kernel, Interrupt, and Init. 
  193.  
  194. o Kernel Mode 
  195.  
  196.   The OS/2 kernel calls the PSD for task-time operations, that is, it will 
  197.   execute as a thread within a process. Kernel mode is also referred to as the 
  198.   task context. 
  199.  
  200. o Interrupt Mode 
  201.  
  202.   The OS/2 kernel calls the PSD for interrupt-time operations. Interrupt time 
  203.   is a generic term that refers to executing code as a result of a hardware 
  204.   interrupt. The code does not execute as a thread belonging to a process. 
  205.  
  206. o Init Mode 
  207.  
  208.   The PSD is currently being used for system initialization. A limited set of 
  209.   PSD helps are available for use. 
  210.  
  211. PSDs may contain multiple code and data objects. All objects will be fixed 
  212. (not-swappable or movable) in low physical memory, with virtual addresses in 
  213. the system arena. Objects are loaded in low physical memory to facilitate the 
  214. use of real mode or bi-modal code. All objects default to permanent, which 
  215. means that they remain in the system after initialization is completed. The 
  216. SEGMENTS directive and the IOPL option in the linker DEF file should be used to 
  217. mark those objects that are not to be kept after initialization. 
  218.  
  219. The multitasking/multiprocessing environment of OS/2 for SMP V2.11 dictates 
  220. that the PSD must be capable of handling multiple requests simultaneously. This 
  221. means that global variables should be used sparingly. Upon PSD installation, 
  222. the kernel passes a pointer to a small area of processor local memory (PLMA) 
  223. which the PSD developer can use to store variables. PSD developers must be 
  224. aware of the effects of the calls they make, because there is no guarantee that 
  225. if an operation is started on a processor, and execution blocks, that the 
  226. operation will continue on the same processor. OS/2 does not preempt a thread 
  227. in the PSD, but it may block as a result of using a PSD help, or it may be 
  228. interrupted by a hardware interrupt. 
  229.  
  230. PSDs can register an interrupt handler for any given IRQ level using the 
  231. SET_IRQ PSD help. These interrupt handlers are guaranteed to be called before 
  232. any device driver's interrupt handler. If the PSD's interrupt handler returns 
  233. NO_ERROR, the interrupt manager will assume the interrupt has been handled, it 
  234. will end the interrupt. If a -1 is returned, the interrupt manager will assume 
  235. that the interrupt has not been handled, and will call each device driver which 
  236. has a registered interrupt handler for that particular level until one claims 
  237. the interrupt. If the interrupt is unclaimed, the IRQ level will be masked off. 
  238.  
  239. All PSDs must use the SET_IRQ PSD help to indicate which IRQ level they will be 
  240. using for inter-processor interrupts (IPI). If the PSD's IPI IRQ level is 
  241. shared, it must register a handler which detects if the IRQ is an IPI or 
  242. another interrupt. The handler must return NO_ERROR if the interrupt was caused 
  243. by an IPI, otherwise it returns a -1. If the IPI IRQ level is unique, an 
  244. interrupt handler need not be installed but SET_IRQ must still be used to 
  245. indicate which is the IPI IRQ level. 
  246.  
  247. The kernel will save the state of all the registers (except EAX) around calls 
  248. to the PSD functions. All the functions will run at Ring 0. Upon invocation, 
  249. SS, DS, and ES will be flat. The PSD functions must conform to the C calling 
  250. convention. They receive parameters on the stack (4 bytes per parameter), and 
  251. must return a return code in EAX. 
  252.  
  253. The PSD functions have been split into three categories: 
  254.  
  255. o Functions that the PSD must have for OS/2 to operate (required functions) 
  256. o Functions that the PSD does not need to have (optional functions) 
  257. o Functions that the PSD must have for OS/2 to use multiple processors (MP 
  258.   functions). 
  259.  
  260. The kernel provides default handling for some of the PSD functions. PSD 
  261. functions can also chain to a kernel default handler by returning a -1 return 
  262. code. If a return code other than -1 is returned by a PSD function, the default 
  263. handler will not get called. The PSD function glossary later in this chapter 
  264. details the categories of all the functions, as well as any default handlers 
  265. they may have. 
  266.  
  267. The PSD developer makes functions available to OS/2 by using the EXPORTS 
  268. statement in the module definition (DEF) file. All functions should be exported 
  269. using upper case with no leading underscores (_). An example is shown below. 
  270.  
  271.  
  272.   LIBRARY TESTPSD
  273.  
  274.   EXPORTS
  275.  
  276.      PSD_INSTALL   = _Install
  277.      PSD_DEINSTALL = _DeInstall
  278.  
  279. The initial CS and EIP in the PSD's executable image is ignored. The image 
  280. should also not contain a stack object. OS/2 allocates a per-processor PSD 
  281. stack and sets SS and ESP correctly before invoking any of the PSD functions. 
  282.  
  283. PSDs should be written in flat 32-bit code, using C, and must be linked as a 
  284. LIBRARY. 
  285.  
  286. OS/2 invokes all PSD functions in protect mode, but there is also a PSD help 
  287. which allows the PSD developer to call a PSD function in real mode. 
  288.  
  289. OS/2 services are provided through the PSD help interface. Access to these 
  290. services are obtained upon PSD installation. PSD helpers preserve all registers 
  291. except EAX. 
  292.  
  293. All the definitions (e.g. defines, structures, etc.) that are required for 
  294. building a PSD are in the header file PSD.H. 
  295.  
  296.  
  297. ΓòÉΓòÉΓòÉ 3.2. OS/2 Initialization ΓòÉΓòÉΓòÉ
  298.  
  299. OS/2 requires a PSD for system initialization. The system will display an error 
  300. message if a valid PSD for the current platform cannot be installed. 
  301.  
  302. The following is a list of steps, in the order in which they occur, that are 
  303. executed after a PSD is installed. If any step does not complete successfully, 
  304. the system initialization process will stop, and a fatal error message will be 
  305. displayed. 
  306.  
  307.  1. After a PSD is successfully installed, its Init function is invoked. This 
  308.     function is used to allocate and initialize any resources that the PSD may 
  309.     require, as well as initializing the state of the hardware. 
  310.  
  311.  2. The kernel determines the number of usable processors on the current 
  312.     platform by using the PSD_GET_NUM_OF_PROCS function. 
  313.  
  314.  3. The kernel allocates all resources required to support the additional 
  315.     processors. This step determines what to allocate based on the results of 
  316.     the previous step. 
  317.  
  318.  4. The PSD's processor initialization function is invoked on the current 
  319.     processor (CPU0). 
  320.  
  321.  5. An MP daemon is created for CPU0. An MP daemon is a thread that never goes 
  322.     away, which is used for MP operations by a specific processor. 
  323.  
  324.  6. An MP daemon is created for the next logical processor. 
  325.  
  326.  7. The PSD's start processor call is invoked to start the next logical 
  327.     processor. The PSD should only start the specified processor, and then 
  328.     return (see the PSD_START_PROC function for more detail). The started 
  329.     processor will spin in a tight loop waiting for a variable to be cleared. 
  330.     This variable is referred to as the processor initialization real mode 
  331.     spinlock. 
  332.  
  333.  8. Upon return from the PSD's start processor call, the processor 
  334.     initialization real mode spinlock is cleared. 
  335.  
  336.  9. CPU0 will spin in a tight loop waiting for a variable to be cleared. This 
  337.     variable is referred to as the CPU0 spinlock. 
  338.  
  339. 10. The started processor continues execution of the kernel's real mode 
  340.     processor initialization code now that processor's initialization real mode 
  341.     spinlock has been cleared. 
  342.  
  343. 11. The started processor sets up all protect mode and paging information, and 
  344.     switches into protect mode with paging enabled. 
  345.  
  346. 12. Up to this point, the started processor has been running on a small 
  347.     processor initialization stack (It has not been running as an OS/2 thread). 
  348.     The current context is switched to that of this processors MP daemon. 
  349.  
  350. 13. OS/2 calls the PSD's processor initialization function for the current 
  351.     processor. 
  352.  
  353. 14. The PSD indicates that the processor has been initialized. 
  354.  
  355. 15. The started processor will spin in a tight loop waiting for a variable to 
  356.     be cleared. This variable is referred to as the processor initialization 
  357.     protect mode spinlock. 
  358.  
  359. 16. The CPU0 spinlock is cleared. 
  360.  
  361. 17. System initialization continues on CPU0 now that its spinlock has been 
  362.     cleared. 
  363.  
  364. 18. Steps 6, through 17 are repeated until all processors have been started. 
  365.  
  366. 19. The rest of system initialization continues normally, on CPU0. 
  367.  
  368. 20. After the system is fully initialized, the processor initialization protect 
  369.     mode spinlock is cleared. This allows CPU1 through CPU-N to start executing 
  370.     code. 
  371.  
  372.  
  373. ΓòÉΓòÉΓòÉ 3.3. PSD Function Glossary ΓòÉΓòÉΓòÉ
  374.  
  375. In the functions listed below all pointers must be flat 32-bit linear 
  376. addresses. 
  377.  
  378. The following keywords indicate: 
  379.  
  380. Required          Indicates that the function is required for OS/2 to operate 
  381.                   properly, so the function can not be omitted. 
  382.  
  383.  
  384. Optional          Indicates that the function is not required. 
  385.  
  386.  
  387. MP                Indicates that the function is not required for OS/2 to 
  388.                   execute with one processor, but it is required for OS/2 to 
  389.                   use multiple processors. 
  390.  
  391.  
  392. Default           Indicates that the OS/2 kernel provides default handling for 
  393.                   that specific function. 
  394.  
  395.  
  396. Can Block         Indicates that the function can call a PSD help that may 
  397.                   block. 
  398.  
  399.  
  400. Can't Block       Indicates that the function can not call a PSD help that may 
  401.                   block. 
  402.  
  403.  
  404. Input             Indicates that the kernel fills the field with input values 
  405.                   before calling the function. 
  406.  
  407.  
  408. Output            Indicates that the PSD should return values in the specified 
  409.                   field. 
  410.  
  411.  
  412. 0-based           Indicates that a zero denotes the first value. 
  413.  
  414.  
  415. 1-based           Indicates that a one denotes the first value. 
  416.  
  417.  
  418. ΓòÉΓòÉΓòÉ 3.4. PSD Functions ΓòÉΓòÉΓòÉ
  419.  
  420. Following are the PSD functions. 
  421.  
  422.  
  423. ΓòÉΓòÉΓòÉ 3.4.1. PSD_INSTALL ΓòÉΓòÉΓòÉ
  424.  
  425. PSD_INSTALL keywords 
  426.      Required, Can Block 
  427.  
  428.  
  429. Description 
  430.      Determine if the PSD supports the current platform. 
  431.  
  432.      This function probes the hardware to see if the PSD supports the current 
  433.      platform. No other operations should be executed in this function. It is 
  434.      merely a presence check. This function is the first function called upon 
  435.      loading a PSD. It must store away all the information passed to it in the 
  436.      install structure. 
  437.  
  438.  
  439. Mode 
  440.      Called in Init Mode; may be called in Kernel Mode. 
  441.  
  442.  
  443. Entry 
  444.      Pointer to an INSTALL structure. 
  445.  
  446.  
  447. Exit 
  448.  
  449.    NO_ERROR     if the PSD installed successfully. 
  450.    -1           if the PSD does not support the current platform. 
  451.  
  452.  
  453. Structures 
  454.  
  455.           typedef struct install_s
  456.           {
  457.              P_F_2   pPSDHlpRouter;  (Input)
  458.              char   *pParmString;    (Input)
  459.              void   *pPSDPLMA;       (Input)
  460.              ulong_t sizePLMA;       (Input)
  461.           } INSTALL;
  462.  
  463.    pPSDHlpRouter       points to the PSD help router. Use the PSDHelp macro in 
  464.                        PSD.H to access the PSD helps. 
  465.    pParmString         points to any parameters specified in CONFIG.SYS after 
  466.                        the PSD's name. If no parameters were specified this 
  467.                        field is NULL. 
  468.    pPSDPLMA            points to the PSD's processor local memory area. This 
  469.                        area contains different physical memory at the same 
  470.                        linear address across all processors. You can use the 
  471.                        area to store variables such that each processor 
  472.                        accesses unique values, but all the code references the 
  473.                        same variables. 
  474.    sizePLMA            is the total size of the PSD's PLMA in bytes. 
  475.  
  476.  
  477. Notes 
  478.      This function may be called after OS/2 is finished with initialization by 
  479.      the Dos32TestPSD API; therefore, the PSD developer must be careful not to 
  480.      use any Init mode only PSD help's in this function. 
  481.  
  482.  
  483. ΓòÉΓòÉΓòÉ 3.4.2. PSD_DEINSTALL ΓòÉΓòÉΓòÉ
  484.  
  485. PSD_DEINSTALL keywords 
  486.      Required, Can Block 
  487.  
  488.  
  489. Description 
  490.      DeInstall the PSD. 
  491.  
  492.      This function is called to release any resources that may have been 
  493.      allocated by the PSD_INSTALL function. A PSD is never de-installed after 
  494.      its Init routine is called. 
  495.  
  496.  
  497. Mode 
  498.      Called in Init Mode; may be called in Kernel Mode. 
  499.  
  500.  
  501. Entry 
  502.      None. 
  503.  
  504.  
  505. Exit 
  506.  
  507.    NO_ERROR     if the PSD DeInstalled succesfully. 
  508.    -1           if the PSD didn't DeInstall. 
  509.  
  510.  
  511. Notes 
  512.      This function may be called after OS/2 is finished with initialization by 
  513.      the Dos32TestPSD API; therefore, the PSD developer must be careful not to 
  514.      use any init mode only PSDHelp's in this function. 
  515.  
  516.  
  517. ΓòÉΓòÉΓòÉ 3.4.3. PSD_INIT ΓòÉΓòÉΓòÉ
  518.  
  519. PSD_INIT keywords 
  520.      Required, Can Block 
  521.  
  522.  
  523. Description 
  524.      Initialize the PSD. 
  525.  
  526.      This function is called to initialize the PSD. It is used to allocate and 
  527.      initialize any resources that the PSD may require, as well as initializing 
  528.      the state of the hardware. This function should only initialize the state 
  529.      of the hardware in general. Initialization of CPUs should be done in 
  530.      ProcInit. It must fill in the INIT structure passed to it by OS/2. This 
  531.      function is only called once on CPU0. 
  532.  
  533.  
  534. Mode 
  535.      Called in Init Mode only. 
  536.  
  537.  
  538. Entry 
  539.      Pointer to INIT structure 
  540.  
  541.  
  542. Exit 
  543.  
  544.    NO_ERROR     if the PSD initialized successfully. 
  545.    -1           if the PSD didn't initialize. 
  546.  
  547.  
  548. Structures 
  549.  
  550.           typedef struct init_s
  551.           {
  552.              ulong_t flags;    (Output)
  553.              ulong_t version;  (Output)
  554.           } INIT;
  555.  
  556.    flags     in the INIT structure indicate any special features or requirement 
  557.              that the PSD may have. 
  558.  
  559.       INIT_GLOBAL_IRQ_ACCESS            indicates that the platform can perform 
  560.                                         IRQ operations (e.g. PIC masking) on 
  561.                                         any processor. If this flag is omitted, 
  562.                                         the IRQ functions are guaranteed to 
  563.                                         only get called on CPU0, otherwise they 
  564.                                         may get called on any processor. If the 
  565.                                         flag is omitted and an IRQ operation is 
  566.                                         initiated on a processor other then 
  567.                                         CPU0, the OS/2 kernel will route the 
  568.                                         request to CPU0. 
  569.       INIT_USE_FPERR_TRAP               indicates that Trap 16 will be used to 
  570.                                         report floating point errors, instead 
  571.                                         of IRQ 13. If this flag is set, the 
  572.                                         kernel sets the NE flag in CR0 for all 
  573.                                         processors. The PSD is responsible for 
  574.                                         doing any additional work for making 
  575.                                         the transition. 
  576.       INIT_EOI_IRQ13_ON_CPU0            indicates that an EOI for a floating 
  577.                                         point error using IRQ13 should only be 
  578.                                         performed from CPU0. On CPU1-N, the 
  579.                                         hardware is responsible for clearing 
  580.                                         the interrupt. 
  581.  
  582.  
  583.    version   indicates the version number of this PSD. It should be updated 
  584.              appropriately as this will help with service. 
  585.  
  586.  
  587. Notes 
  588.      None. 
  589.  
  590.  
  591. ΓòÉΓòÉΓòÉ 3.4.4. PSD_PROC_INIT ΓòÉΓòÉΓòÉ
  592.  
  593. PSD_PROC_INIT keywords 
  594.      MP, Can Block 
  595.  
  596.  
  597. Description 
  598.      Initialize the current processor. 
  599.  
  600.      This function is called to initialize the current processor. It is called 
  601.      in protect mode, once on a per-processor basis. It should initialize 
  602.      variables in the PSD's PLMA, along with initialization of the hardware 
  603.      state for that specific processor. 
  604.  
  605.  
  606. Mode 
  607.      Called in Init Mode only. 
  608.  
  609.  
  610. Entry 
  611.      None. 
  612.  
  613.  
  614. Exit 
  615.  
  616.    NO_ERROR     if the processor initialized successfully. 
  617.    -1           if the processor didn't initialize. 
  618.  
  619.  
  620. Structures 
  621.      None 
  622.  
  623.  
  624. Notes 
  625.      None 
  626.  
  627.  
  628. ΓòÉΓòÉΓòÉ 3.4.5. PSD_START_PROC ΓòÉΓòÉΓòÉ
  629.  
  630. PSD_START_PROC keywords 
  631.      MP, Can Block 
  632.  
  633.  
  634. Description 
  635.      Start a processor. 
  636.  
  637.      This function is used to start a specified processor. The PSD may only 
  638.      start the processor that was specified. 
  639.  
  640.      OS/2 fills in the address of a started processors initial real mode CS:IP 
  641.      in the warm reboot vector of the BIOS data area (0x40:0x67). 
  642.  
  643.      OS/2 provides serialization such that another processor will not be 
  644.      started until the previous processor has finished its real mode 
  645.      initialization, gone into protect mode, and finished calling the ProcInit 
  646.      function. The processor which is started will be held in real mode until 
  647.      the StartProc function has been completed, and will then be allowed to 
  648.      initialize. 
  649.  
  650.      All processors are started before the first device driver is loaded. 
  651.  
  652.  
  653. Mode 
  654.      Called in Init Mode only. 
  655.  
  656.  
  657. Entry 
  658.      Processor number (0-based). 
  659.  
  660.  
  661. Exit 
  662.  
  663.    NO_ERROR     if the processor started successfully. 
  664.    -1           if the processor didn't start. 
  665.  
  666.  
  667. Structures 
  668.      None. 
  669.  
  670.  
  671. Notes 
  672.      If the hardware implementation uses some other mechanism to indicate a 
  673.      started processors initial CS:IP the value specified in the warm reboot 
  674.      vector should be used. 
  675.  
  676.      If the hardware implementation requires some other real mode operation to 
  677.      be completed before the processor can continue to execute, the PSD 
  678.      developer must be certain to chain to the address specified in the warm 
  679.      reboot vector. 
  680.  
  681.  
  682. ΓòÉΓòÉΓòÉ 3.4.6. PSD_GET_NUM_OF_PROCS ΓòÉΓòÉΓòÉ
  683.  
  684. PSD_GET_NUM_OF_PROCS keywords 
  685.      Required, Can Block 
  686.  
  687.  
  688. Description 
  689.      Return number of processors. 
  690.  
  691.      This function must detect and return the number of usable x86 based 
  692.      processors that exist on the current platform. If the PSD detects that any 
  693.      of the processors are defective or non x86-based, it is the PSD's 
  694.      responsibility to setup the state of the PSD and hardware, such that all 
  695.      usable processors are logically ordered. For example, if there are 4 
  696.      processors and CPU2 is defective, the CPU's should be ordered as follows: 
  697.      CPU0 = 0, CPU1 = 1, CPU2 (Defective), CPU3 = 2). 
  698.  
  699.  
  700. Mode 
  701.      Called in Init Mode only. 
  702.  
  703.  
  704. Entry 
  705.      None. 
  706.  
  707.  
  708. Exit 
  709.      Number of processors (1-based). 
  710.  
  711.  
  712. Structures 
  713.      None. 
  714.  
  715.  
  716. Notes 
  717.      OS/2 for SMP V2.11 only supports processors that are compatible with the 
  718.      architecture of the Intel 386 and above. 
  719.  
  720.  
  721. ΓòÉΓòÉΓòÉ 3.4.7. PSD_GEN_IPI ΓòÉΓòÉΓòÉ
  722.  
  723. PSD_GEN_IPI keywords 
  724.      MP, Can't Block 
  725.  
  726.  
  727. Description 
  728.      Generate an inter-processor interrupt. 
  729.  
  730.      This function is used to generate an inter-processor interrupt. All 
  731.      inter-processor hardware dependencies should be fully initialized before 
  732.      the first GenIPI is called. 
  733.  
  734.  
  735. Mode 
  736.      Called in Kernel, and Interrupt Mode. 
  737.  
  738.  
  739. Entry 
  740.      Processor number to interrupt (0-based). 
  741.  
  742.  
  743. Exit 
  744.  
  745.    NO_ERROR     if the IPI was generated. 
  746.    -1           if the IPI was not generated. 
  747.  
  748.  
  749. Structures 
  750.      None. 
  751.  
  752.  
  753. Notes 
  754.      OS/2 guarantees that the GenIPI function will not be called to interrupt a 
  755.      processor that has not finished processing any previous IPIs. 
  756.  
  757.  
  758. ΓòÉΓòÉΓòÉ 3.4.8. PSD_END_IPI ΓòÉΓòÉΓòÉ
  759.  
  760. PSD_END_IPI keywords 
  761.      MP, Can't Block 
  762.  
  763.  
  764. Description 
  765.      End an inter-processor interrupt. 
  766.  
  767.      This function is used to end an inter-processor interrupt, that was 
  768.      generated by GenIPI. 
  769.  
  770.  
  771. Mode 
  772.      Called in Kernel, and Interrupt Mode. 
  773.  
  774.  
  775. Entry 
  776.      Processor number to end interrupt on (0-based). 
  777.  
  778.  
  779. Exit 
  780.  
  781.    NO_ERROR     if the IPI was ended successfully. 
  782.    -1           if the IPI didn't end successfully. 
  783.  
  784.  
  785. Structures 
  786.      None. 
  787.  
  788.  
  789. Notes 
  790.      The processor number specified and the current processor number should be 
  791.      identical. 
  792.  
  793.  
  794. ΓòÉΓòÉΓòÉ 3.4.9. PSD_PORT_IO ΓòÉΓòÉΓòÉ
  795.  
  796. PSD_PORT_IO keywords 
  797.      Optional, Default, Can't Block 
  798.  
  799.  
  800. Description 
  801.      Perform local port I/O. 
  802.  
  803.      Some platforms have some non MP specific system ports localized on a 
  804.      per-processor basis. If a local I/O operation may block before completion, 
  805.      I/O can be routed to a specific CPU for processing. This should be done, 
  806.      because an operation which started on one processor is not guaranteed to 
  807.      complete on that processor if execution is blocked. This function gets 
  808.      invoked as the result of a device driver calling DevHelp_Port_IO. 
  809.  
  810.  
  811. Mode 
  812.      Called in Kernel, and Interrupt Mode. 
  813.  
  814.  
  815. Entry 
  816.      Pointer to a PORT_IO structure. 
  817.  
  818.  
  819. Exit 
  820.  
  821.    NO_ERROR     if the I/O was successful. 
  822.    -1           if the I/O wasn't successful. 
  823.  
  824.  
  825. Structures 
  826.  
  827.           typedef struct port_io_s
  828.           {
  829.              ulong_t port;   (Input)
  830.              ulong_t data;   (Input/Output)
  831.              ulong_t flags;  (Input)
  832.           } PORT_IO;
  833.  
  834.    port      indicates which port to read to, or write from. 
  835.    data      contains the data read from a read request, or the data to write 
  836.              if a write request. If the request uses less the 4 bytes the least 
  837.              significant portion of the data variable is used. 
  838.    flags     indicate what operation to perform. 
  839.  
  840.       IO_READ_BYTE          Read a byte from the port 
  841.       IO_READ_WORD          Read a word from the port 
  842.       IO_READ_DWORD         Read a dword from the port 
  843.       IO_WRITE_BYTE         Write a byte to the port 
  844.       IO_WRITE_WORD         Write a word to the port 
  845.       IO_WRITE_DWORD        Write a dword to the port 
  846.  
  847.  
  848. Notes 
  849.      If the I/O performed is to a non-local port, the I/O should be handled as 
  850.      a regular I/O request. 
  851.  
  852.      If device drivers or applications access the local ports directly, instead 
  853.      of using the documented interfaces problems may occur. 
  854.  
  855.  
  856. ΓòÉΓòÉΓòÉ 3.4.10. PSD_IRQ_MASK ΓòÉΓòÉΓòÉ
  857.  
  858. PSD_IRQ_MASK keywords 
  859.      Optional, Default, Can't Block 
  860.  
  861.  
  862. Description 
  863.      Mask/Unmask IRQ levels 
  864.  
  865.      This function allows masking (disabling), or un-masking (enabling) of IRQ 
  866.      levels. When this function is invoked it should save the state of the 
  867.      interrupt flag, and disable interrupts before performing the mask 
  868.      operation. It should then restore the state of the interrupt flag. 
  869.  
  870.  
  871. Mode 
  872.      Called in Kernel, and Interrupt Mode. 
  873.  
  874.  
  875. Entry 
  876.      Pointer to PSD_IRQ structure. 
  877.  
  878.  
  879. Exit 
  880.  
  881.    NO_ERROR     operation completed successfully. 
  882.    -1           operation failed. 
  883.  
  884.  
  885. Structures 
  886.  
  887.           typedef struct psd_irq_s
  888.           {
  889.              ulong_t flags;    (Input)
  890.              ulong_t data;     (Input/Output)
  891.              ulong_t procnum;  (Input)
  892.           } PSD_IRQ;
  893.  
  894.    data      is the logical IRQ levels to mask, or un-mask. 
  895.    flags     indicate which type of operation is to be performed. 
  896.  
  897.       IRQ_MASK         mask (disable) IRQ levels 
  898.       IRQ_UNMASK       unmask (enable) IRQ levels 
  899.       IRQ_GETMASK      retrieves the masks for all IRQ levels 
  900.       IRQ_NEWMASK      indicates that all the IRQ levels should reflect the 
  901.                        state of the specified mask. 
  902.  
  903.  
  904.    procnum   is the processor number of where the operation should take place. 
  905.  
  906.  
  907. Notes 
  908.      If this function is omitted, OS/2 will perform all mask operations for an 
  909.      8259 Master/Slave based PIC system. The requests will be sent to CPU0 
  910.      depending on the state of the INIT_GLOBAL_IRQ_ACCESS flag. 
  911.  
  912.  
  913. ΓòÉΓòÉΓòÉ 3.4.11. PSD_IRQ_REG ΓòÉΓòÉΓòÉ
  914.  
  915. PSD_IRQ_REG keywords 
  916.      Optional, Default, Can't Block 
  917.  
  918.  
  919. Description 
  920.      Access IRQ related registers. 
  921.  
  922.      This function permits access to the IRQ related registers. 
  923.  
  924.  
  925. Mode 
  926.      Called in Kernel, and Interrupt Mode. 
  927.  
  928.  
  929. Entry 
  930.      Pointer to PSD_IRQ structure. 
  931.  
  932.  
  933. Exit 
  934.  
  935.    NO_ERROR     operation completed successfully. 
  936.    -1           operation failed. 
  937.  
  938.  
  939. Structures 
  940.  
  941.           typedef struct psd_irq_s
  942.           {
  943.              ulong_t flags;    (Input)
  944.              ulong_t data;     (Input/Output)
  945.              ulong_t procnum;  (Input)
  946.           } PSD_IRQ;
  947.  
  948.    flags     indicate which type of operation is to be performed. 
  949.  
  950.       IRQ_READ_IRR     read the interrupt request register. 
  951.       IRQ_READ_ISR     read the in service register. 
  952.  
  953.  
  954.    data      contains the data read from a read request, or the data to write 
  955.              if a write request. 
  956.    procnum   is the processor number of where the operation should take place. 
  957.  
  958.  
  959. Notes 
  960.      If this function is omitted, OS/2 will perform all register operations for 
  961.      an 8259 Master/Slave based PIC system. The requests will be sent to CPU0 
  962.      depending on the state of the INIT_GLOBAL_IRQ_ACCESS flag. 
  963.  
  964.  
  965. ΓòÉΓòÉΓòÉ 3.4.12. PSD_IRQ_EOI ΓòÉΓòÉΓòÉ
  966.  
  967. PSD_IRQ_EOI keywords 
  968.      Optional, Default, Can't Block 
  969.  
  970.  
  971. Description 
  972.      Issue an EOI. 
  973.  
  974.      This function is used to issue an End-Of-Interrupt. 
  975.  
  976.  
  977. Mode 
  978.      Called in Kernel, and Interrupt mode. 
  979.  
  980.  
  981. Entry 
  982.      Pointer to PSD_IRQ structure. 
  983.  
  984.  
  985. Exit 
  986.  
  987.    NO_ERROR     operation completed successfully. 
  988.    -1           operation failed. 
  989.  
  990.  
  991. Structures 
  992.  
  993.           typedef struct psd_irq_s
  994.           {
  995.              ulong_t flags;    (Input)
  996.              ulong_t data;     (Input/Output)
  997.              ulong_t procnum;  (Input)
  998.           } PSD_IRQ;
  999.  
  1000.    data      is the interrupt level to end. 
  1001.    flags     is not used in this operation. 
  1002.    procnum   is the processor number of where the operation should take place. 
  1003.  
  1004.  
  1005. Notes 
  1006.      If this function is omitted, OS/2 will perform all EOI operations for an 
  1007.      8259 Master/Slave based PIC system. The requests will be sent to CPU0 
  1008.      depending on the state of the INIT_GLOBAL_IRQ_ACCESS flag. 
  1009.  
  1010.  
  1011. ΓòÉΓòÉΓòÉ 3.4.13. PSD_APP_COMM ΓòÉΓòÉΓòÉ
  1012.  
  1013. PSD_APP_COMM keywords 
  1014.      Optional, Can Block 
  1015.  
  1016.  
  1017. Description 
  1018.      Perform generic APP/PSD communication. 
  1019.  
  1020.      This function performs generic application/PSD communication. The entry 
  1021.      arguments, and return codes are not interpreted by OS/2, it is passed 
  1022.      verbatim to and from the PSD. 
  1023.  
  1024.  
  1025. Mode 
  1026.      Called in Kernel mode. 
  1027.  
  1028.  
  1029. Entry 
  1030.      Function number, Argument. 
  1031.  
  1032.  
  1033. Exit 
  1034.      Return code. 
  1035.  
  1036.  
  1037. Structures 
  1038.      None. 
  1039.  
  1040.  
  1041. Notes 
  1042.      None. 
  1043.  
  1044.  
  1045. ΓòÉΓòÉΓòÉ 3.4.14. PSD_SET_ADV_INT_MODE ΓòÉΓòÉΓòÉ
  1046.  
  1047. PSD_SET_ADV_INT_MODE keywords 
  1048.      Optional, Can't Block 
  1049.  
  1050.  
  1051. Description 
  1052.      TBD 
  1053.  
  1054.  
  1055. Mode 
  1056.      Called in Init Mode only. 
  1057.  
  1058.  
  1059. Entry 
  1060.      None. 
  1061.  
  1062.  
  1063. Exit 
  1064.      Return code. 
  1065.  
  1066.  
  1067. Structures 
  1068.      None. 
  1069.  
  1070.  
  1071. Notes 
  1072.      The kernel initially provides default handling/detection for spurious 
  1073.      interrupts. This is done for the last IRQ line of every PIC. It does this 
  1074.      by checking the PIC's ISR register, and if the IRQ is not in service, it 
  1075.      does not pass the interrupt request to the interrupt manager (i.e. a 
  1076.      spurious interrupt). 
  1077.  
  1078.      If a PSD switches into advanced interrupt mode; the kernel will no longer 
  1079.      provide default handling/detection of spurious interrupts. It becomes the 
  1080.      PSD's responsibility. 
  1081.  
  1082.      One way a PSD could provide handling/detection of a spurious interrupt is 
  1083.      to register a PSD handler for an IRQ level which may be spurious. As soon 
  1084.      as the interrupt is detected the handler should insure that it is valid. 
  1085.      If it is not (i.e. a spurious interrupt), it should dismiss the interrupt, 
  1086.      and return NO_ERROR to the interrupt manager. The NO_ERROR return code 
  1087.      informs the interrupt manager that the interrupt has been handled by the 
  1088.      PSD. If the interrupt is valid the PSD should return a -1, as this informs 
  1089.      the interrupt manager that the interrupt should be passed on to any device 
  1090.      drivers registered to receive that interrupt. 
  1091.  
  1092.  
  1093. ΓòÉΓòÉΓòÉ 3.5. PSD Helps ΓòÉΓòÉΓòÉ
  1094.  
  1095. OS/2 provides system services to the PSD developer via PSD helps. 
  1096.  
  1097. The address of the PSD help router is passed in the INSTALL structure when a 
  1098. PSD's install function is called. All PSD helps destroy the contents of the EAX 
  1099. register (used for a return code). All other registers, including the flags, 
  1100. are preserved. 
  1101.  
  1102. To invoke a PSD help, set up the appropriate parameters and call the PSD help 
  1103. router. For an example, refer to Appendix A. Some prototypes and macros are 
  1104. defined in PSD.H to simplify their usage. 
  1105.  
  1106. The following keywords indicate: 
  1107.  
  1108. May Block      Indicates that the help may block. 
  1109. Won't Block    Indicates that the help won't block. 
  1110.  
  1111.  
  1112. ΓòÉΓòÉΓòÉ 3.5.1. PSDHLP_VMALLOC ΓòÉΓòÉΓòÉ
  1113.  
  1114. PSDHLP_VMALLOC keywords 
  1115.      May Block 
  1116.  
  1117.  
  1118. Description 
  1119.      Allocate memory. 
  1120.  
  1121.      This function is used to allocate virtual memory, or map virtual memory to 
  1122.      physical memory, depending on the value of the flags. All virtual 
  1123.      addresses are allocated from the system arena (i.e. global address space). 
  1124.  
  1125.  
  1126. Mode 
  1127.      Callable in Init and Kernel mode. 
  1128.  
  1129.  
  1130. Parameters 
  1131.      Pointer to a VMALLOC structure. 
  1132.  
  1133.  
  1134. Exit 
  1135.      Return code. 
  1136.  
  1137.  
  1138. Structures 
  1139.  
  1140.           typedef struct vmalloc_s
  1141.           {
  1142.              ulong_t addr;    (Input/Output)
  1143.              ulong_t cbsize;  (Input)
  1144.              ulong_t flags;   (Input)
  1145.           } VMALLOC;
  1146.  
  1147.    addr      is filled with the linear address of the allocated or mapped 
  1148.              memory on return from the help. 
  1149.  
  1150.              If VMALLOC_LOCSPECIFIC is specified, this field must contain the 
  1151.              virtual address to map before calling the help. 
  1152.  
  1153.              If VMALLOC_PHYS is specified, this field must contain the physical 
  1154.              address to map before calling the help. 
  1155.    cbsize    is the size of the allocation, or mapping in bytes. 
  1156.    flags     indicate which type of operation is to be performed. 
  1157.  
  1158.       VMALLOC_FIXED         indicates that the allocated memory is to be fixed 
  1159.                             in memory (not-swappable or movable). If this flag 
  1160.                             is omitted, the allocated memory will be swappable 
  1161.                             by default. 
  1162.       VMALLOC_CONTIG        indicates that the allocation must use contigous 
  1163.                             physical memory. If this flag is specified 
  1164.                             VMALLOC_FIXED must also be used. 
  1165.       VMALLOC_LOCSPECIFIC   indicates a request for a memory allocation at a 
  1166.                             specific virtual address. If this flag is 
  1167.                             specified, the addr field must contain the virtual 
  1168.                             address to map. 
  1169.  
  1170.                             Note:  This flag can be used with the VMALLOC_PHYS 
  1171.                                    flag to allocate memory where linear = 
  1172.                                    physical. 
  1173.  
  1174.  
  1175.       VMALLOC_PHYS          indicates a request for a virtual mapping of 
  1176.                             physical memory. If this flag is specified, the 
  1177.                             addr field must contain the physical address to 
  1178.                             map. 
  1179.  
  1180.                             Note:  This flag can be used with the 
  1181.                                    VMALLOC_LOCSPECIFIC flag to allocate memory 
  1182.                                    where linear = physical. 
  1183.  
  1184.  
  1185.       VMALLOC_1M            indicates a request for a memory allocation below 
  1186.                             the 1MB boundary. 
  1187.  
  1188.  
  1189. Notes 
  1190.      None. 
  1191.  
  1192.  
  1193. ΓòÉΓòÉΓòÉ 3.5.2. PSDHLP_VMFREE ΓòÉΓòÉΓòÉ
  1194.  
  1195. PSDHLP_VMFREE keywords 
  1196.      May Block 
  1197.  
  1198.  
  1199. Description 
  1200.      Free allocation created by PSDHLP_VMALLOC. 
  1201.  
  1202.      This function frees memory or destroys a physical mapping created by the 
  1203.      PSDHLP_VMALLOC help. 
  1204.  
  1205.  
  1206. Mode 
  1207.      Callable in Init and Kernel Mode. 
  1208.  
  1209.  
  1210. Parameters 
  1211.      Linear address to free. 
  1212.  
  1213.  
  1214. Exit 
  1215.      Return code. 
  1216.  
  1217.  
  1218. Structures 
  1219.      None. 
  1220.  
  1221.  
  1222. Notes 
  1223.      All memory or mappings allocated by a PSD must be released if the PSD is 
  1224.      DeInstalled. 
  1225.  
  1226.  
  1227. ΓòÉΓòÉΓòÉ 3.5.3. PSDHLP_SET_IRQ ΓòÉΓòÉΓòÉ
  1228.  
  1229. PSDHLP_SET_IRQ keywords 
  1230.      Won't Block 
  1231.  
  1232.  
  1233. Description 
  1234.      Setup IRQ information. 
  1235.  
  1236.      This function is used to setup IRQ information. 
  1237.  
  1238.      The PSD can use this help to register an interrupt handler at any given 
  1239.      IRQ level between IRQ 0-IRQ 1F. These interrupt handler's are guaranteed 
  1240.      to be called before any device driver's interrupt handler. If the PSD's 
  1241.      interrupt handler returns NO_ERROR, the interrupt manager will assume the 
  1242.      interrupt has been handled, and it will end the interrupt. If a -1 is 
  1243.      returned, the interrupt manager will assume that the interrupt has not 
  1244.      been handled, and will call each device driver which has a registered 
  1245.      interrupt handler for that particular level, until one claims the 
  1246.      interrupt. If the interrupt is unclaimed, the IRQ level will be masked 
  1247.      off. 
  1248.  
  1249.      All PSDs must use the SET_IRQ PSD help to indicate which IRQ level it will 
  1250.      be using for its inter-processor interrupts (IPI). If the PSD's IPI IRQ 
  1251.      level is shared, it must register a handler which detects if the IRQ is an 
  1252.      IPI or another interrupt. The handler must return NO_ERROR if the 
  1253.      interrupt was caused by an IPI, otherwise, it returns a -1. If the IPI IRQ 
  1254.      level is unique, an interrupt handler need not be installed, but SET_IRQ 
  1255.      must still be used to indicate the IPI IRQ level. 
  1256.  
  1257.      This function can also be used to set, or remap what interrupt vector a 
  1258.      particular IRQ level will use. 
  1259.  
  1260.  
  1261. Mode 
  1262.      Callable in Init mode only. 
  1263.  
  1264.  
  1265. Parameters 
  1266.      Pointer to a SET_IRQ structure. 
  1267.  
  1268.  
  1269. Exit 
  1270.      Return code. 
  1271.  
  1272.  
  1273. Structures 
  1274.  
  1275.           typedef struct set_irq_s
  1276.           {
  1277.              ushort_t irq;
  1278.              ushort_t flags;
  1279.              ulong_t  vector;
  1280.              P_F_2    handler;
  1281.           } SET_IRQ;
  1282.  
  1283.    irq       specifies which IRQ level this operation is to be performed on. 
  1284.    flags     indicate what is the type of the specified IRQ. If no flag is 
  1285.              used, a regular IRQ level is assumed. 
  1286.  
  1287.       IRQf_IPI       indicates that the specified IRQ level is to be used for 
  1288.                      inter-processor interrupts. 
  1289.       IRQf_LSI       indicates that the specified IRQ level is to be used as a 
  1290.                      local software interrupt. 
  1291.       IRQf_SPI       indicates that the specfied IRQ level is to be used as a 
  1292.                      system priority interrupt. 
  1293.  
  1294.  
  1295.    vector    is used to specify what interrupt vector the IRQ level will use. 
  1296.    handler   contains the address of an interrupt handler. If the PSD is just 
  1297.              specifying that a specific IRQ level is of a special type (e.g. 
  1298.              IPI IRQ), it does not need a handler (the handler variable must be 
  1299.              NULL). 
  1300.  
  1301.  
  1302. Notes 
  1303.      IRQf_LSI, and IRQf_SPI, are currently not being used. 
  1304.  
  1305.  
  1306. ΓòÉΓòÉΓòÉ 3.5.4. PSDHLP_CALL_REAL_MODE ΓòÉΓòÉΓòÉ
  1307.  
  1308. PSDHLP_CALL_REAL_MODE keywords 
  1309.      Won't Block 
  1310.  
  1311.  
  1312. Description 
  1313.      Call a PSD function in real mode. 
  1314.  
  1315.      This function is used by the PSD developer to call one of his PSD 
  1316.      functions in real mode. 
  1317.  
  1318.  
  1319. Mode 
  1320.      Callable in Init mode only. 
  1321.  
  1322.  
  1323. Parameters 
  1324.      Pointer to a CALL_REAL_MODE structure. 
  1325.  
  1326.  
  1327. Exit 
  1328.      Called functions return code. 
  1329.  
  1330.  
  1331. Structures 
  1332.  
  1333.           typedef struct call_real_mode_s
  1334.           {
  1335.              ulong_t function;
  1336.              ulong_t pdata;
  1337.           } CALL_REAL_MODE;
  1338.  
  1339.    function  contains the linear address of the function to be called in real 
  1340.              mode. 
  1341.    pdata     contains the linear address of a parameter to be passed to the 
  1342.              real mode function. The parameter is pointed to by DS:SI on entry 
  1343.              to the called function. 
  1344.  
  1345.      A return code may be returned by the real mode function in EAX. 
  1346.  
  1347.  
  1348. Notes 
  1349.      No PSD helps may be used in real mode. 
  1350.  
  1351.  
  1352. ΓòÉΓòÉΓòÉ 3.5.5. PSDHLP_VMLINTOPHYS ΓòÉΓòÉΓòÉ
  1353.  
  1354. PSDHLP_VMLINTOPHYS keywords 
  1355.      Won't Block 
  1356.  
  1357.  
  1358. Description 
  1359.      Convert linear address to physical 
  1360.  
  1361.      This function converts the specified linear address to physical. 
  1362.  
  1363.  
  1364. Mode 
  1365.      Callable in Init, Kernel, and Interrupt Mode. 
  1366.  
  1367.  
  1368. Parameters 
  1369.      Linear address to convert. 
  1370.  
  1371.  
  1372. Exit 
  1373.      Physical address if successful, -1 otherwise. 
  1374.  
  1375.  
  1376. Structures 
  1377.      None. 
  1378.  
  1379.  
  1380. Notes 
  1381.      None. 
  1382.  
  1383.  
  1384. ΓòÉΓòÉΓòÉ 3.6. Application Programming Interface ΓòÉΓòÉΓòÉ
  1385.  
  1386. The OS/2 kernel will provide new support APIs for PSDs. 
  1387.  
  1388.  
  1389. ΓòÉΓòÉΓòÉ 3.6.1. DosCallPSD ΓòÉΓòÉΓòÉ
  1390.  
  1391. Description 
  1392.      Perform generic APP/PSD communication. 
  1393.  
  1394.      This function performs generic application/PSD communication. The entry 
  1395.      arguments, and return codes are not interpreted by OS/2, it is passed 
  1396.      verbatim to, and from the PSD. 
  1397.  
  1398.  
  1399. Parameters 
  1400.      Function number, Argument. 
  1401.  
  1402.  
  1403. Exit 
  1404.      Return code. 
  1405.  
  1406.  
  1407. Notes 
  1408.      This function can only be called from protect mode applications. There is 
  1409.      currently no plan to provide a DOS mode equivalent. 
  1410.  
  1411.      If the PSD does not export the PSD_APP_COMM function, and the DosCallPSD 
  1412.      API is invoked, ERROR_INVALID_FUNCTION is returned. 
  1413.  
  1414.  
  1415. ΓòÉΓòÉΓòÉ 3.6.2. Dos32TestPSD ΓòÉΓòÉΓòÉ
  1416.  
  1417. Description 
  1418.      Determine if the PSD is valid for the current platform. 
  1419.  
  1420.      This function will load the specified PSD, call its Install, and DeInstall 
  1421.      routine, and unload the PSD. It returns the return code from the PSD's 
  1422.      Install routine, or any error code it might have received while attempting 
  1423.      to do the above operation. 
  1424.  
  1425.  
  1426. Parameters 
  1427.      Pointer to a fully qualified PSD path and name. 
  1428.  
  1429.  
  1430. Exit 
  1431.      Return Code. 
  1432.  
  1433.  
  1434. Notes 
  1435.      This function will mainly be used by OS/2's install, to test the validity 
  1436.      of a PSD that will be installed. 
  1437.  
  1438.  
  1439. ΓòÉΓòÉΓòÉ 4. Understanding Spinlocks ΓòÉΓòÉΓòÉ
  1440.  
  1441. OS/2 for SMP V2.11 provides synchronization and serialization using spinlocks. 
  1442. A spinlock is simply a section of code that executes in a tight loop waiting 
  1443. for a variable to be cleared. 
  1444.  
  1445.  
  1446. ΓòÉΓòÉΓòÉ 4.1. Spinlocks ΓòÉΓòÉΓòÉ
  1447.  
  1448. The defined mechanism for protection of critical resources in OS/2 MP is a 
  1449. spinlock.  A spinlock is a serialization mechanism that is used to restrict 
  1450. access to a critical resource to the owner of the spinlock.  Spinlocks are 
  1451. implemented in the LockManager, which is part of the kernel, and are 
  1452. manipulated by using the new MPHelper services.  The act of acquiring a 
  1453. spinlock can be thought of as locking the spinlock. 
  1454.  
  1455. The reason spinlocks are used for critical resource protection instead of 
  1456. disabling interrupts, is disabling interrupts no longer works in an MP 
  1457. environment. CLI and STI will only work on the processor on which the 
  1458. instruction is executing. It will not prevent another processor from executing 
  1459. task time or interrupt code from the same device driver. Even though the kernel 
  1460. is non-preemptive, another processor can enter the kernel, and hence a device 
  1461. driver at any time. That means that CLI will not provide the same protection as 
  1462. on a single processor system. CLI/STI must be avoided. 
  1463.  
  1464. MP aware device drivers will use spinlocks to protect critical resources. A 
  1465. spinlock must be allocated for each critical resource. Spinlock allocation 
  1466. should be done during initialization. When access to the resource is required, 
  1467. the device driver will try to lock the spinlock for the resource. If the 
  1468. spinlock is already locked then the processor will "spin" waiting for the lock 
  1469. to become available. Once the spinlock is acquired (locked) the device driver 
  1470. has exclusive access to the critical resource. The spinlock should remain 
  1471. locked for a VERY short time. When done with the resource the spinlock is 
  1472. released (unlocked). 
  1473.  
  1474. Because spinlocks are for VERY SHORT durations, interrupts must be disabled 
  1475. while a spinlock is locked. If interrupts were enabled the path of execution 
  1476. could be expanded indefinitely by interrupt handlers. To enforce this rule, the 
  1477. LockManager will save the state of the interrupt flag and disable interrupts 
  1478. when a spinlock is locked. When the spinlock is unlocked, the LockManager will 
  1479. restore the interrupt flag to his original state. This allows device drivers to 
  1480. be unaware of the interrupt flag state while locking and unlocking spinlocks. 
  1481. The device driver, however, must not enable interrupts while owning a spinlock. 
  1482. If interrupts were enabled there are two possible effects. First is the 
  1483. uncontrolled expansion of the time a spinlock is owned. Second is the 
  1484. possibility of deadlock. 
  1485.  
  1486. A spinlock is defined such that an attempt to acquire a spinlock which is 
  1487. currently owned by another processor, makes you spin (i.e. a tight loop of code 
  1488. which waits for the spinlock to be released). Spinlocks should be used 
  1489. sparingly, and should only be owned for very short periods of time, as spinning 
  1490. prevents the processor from doing any additional work. Spinlocks have different 
  1491. properties depending on whether it is a kernel or device driver spinlock. 
  1492. Spinlocks have been used because it is more expensive to reschedule a thread 
  1493. that is trying to acquire a spinlock than it would be waiting for the lock to 
  1494. clear. 
  1495.  
  1496.  
  1497. ΓòÉΓòÉΓòÉ 4.2. Properties of Spinlocks ΓòÉΓòÉΓòÉ
  1498.  
  1499. It is important to note the differences in the various types of spinlocks. 
  1500.  
  1501. Properties of kernel spinlocks: 
  1502.  
  1503. o can have nested ownership. 
  1504. o can use a level to enforce a lock hierarchy. 
  1505. o can not be owned while outside of the kernel. 
  1506. o can only be owned for very short periods of time. 
  1507. o can not block while owning a spinlock. 
  1508.  
  1509. Properties of device driver spinlocks: 
  1510.  
  1511. o can't have nested ownership. 
  1512. o can't use a level to enforce a lock hierarchy. 
  1513. o can be held outside of the kernel. 
  1514. o can only be owned for very short periods of time. 
  1515.  
  1516. There is a different type of spinlock which is exported to subsystems. These 
  1517. locks are used to provide an efficient MP safe CLI/STI substitute for 
  1518. protecting data structures that are shared between task-time and interrupt-time 
  1519. code. 
  1520.  
  1521. Properties of subsystem spinlocks: 
  1522.  
  1523. o can't have nested ownership. 
  1524. o can't use a level to enforce a lock hierarchy. 
  1525. o can be held outside of the kernel. 
  1526. o can only be used for very short periods of time. 
  1527. o each processor can hold only one subsystem spinlock at a time. 
  1528.  
  1529. A suspend lock, is defined such that an attempt to acquire a suspend lock which 
  1530. is currently owned by another processor places the current thread into a 
  1531. blocked state, and causes a reschedule. The thread's which are blocked on 
  1532. suspend locks will awaken when the lock is released. Suspend locks are only 
  1533. used inside the kernel. 
  1534.  
  1535. Properties of a kernel suspend lock: 
  1536.  
  1537. o can have nested ownership. 
  1538. o can use a level to enforce a lock hierarchy. 
  1539. o can not be owned while outside of the kernel. 
  1540. o can be owned for long periods of time. 
  1541. o can not block while owning a suspend lock. 
  1542.  
  1543. When a spinlock is acquired, the lock manager automatically saves the state of 
  1544. the interrupt flag, then disables interrupts before returning to the caller. It 
  1545. restores the state of the interrupt flag when the lock is released. The kernel 
  1546. will panic if an interrupt is taken while owning a spinlock. 
  1547.  
  1548.  
  1549. ΓòÉΓòÉΓòÉ 4.3. Spinlock Use Guidelines ΓòÉΓòÉΓòÉ
  1550.  
  1551. Here are some guidelines on using spinlocks to protect critical resources. 
  1552.  
  1553. o Define spinlocks only for critical resources. A read only I/O port is not a 
  1554.   critical resource. A set of read only I/O ports that must all be read before 
  1555.   a decision is made IS a critical resource. 
  1556.  
  1557. o Do not define too many spinlocks. 
  1558.  
  1559. o Use spinlocks for VERY SHORT durations only. As a general rule, calls should 
  1560.   be avoided while owning a spinlock. 
  1561.  
  1562. o Leave interrupts disabled after locking a spinlock. This prevents interrupts 
  1563.   on the same processor and possible deadlock. 
  1564.  
  1565. o Be careful to not make any calls that may try to lock a spinlock that is 
  1566.   already locked. ADDs, when making asynchronous callbacks, can be reentered at 
  1567.   their IORB entry point. 
  1568.  
  1569. o Be aware that DevHelp_Block called with spinlocks locked will unlock them. 
  1570.   When the block wakes up spinlocks must be reacquired. 
  1571.  
  1572. o Never make a call that could block while owning a spinlock. For example, some 
  1573.   DevHelp calls can block. 
  1574.  
  1575.  
  1576. ΓòÉΓòÉΓòÉ 5. Device Drivers In OS/2 for SMP V2.11 ΓòÉΓòÉΓòÉ
  1577.  
  1578. This chapter describes the impacts to driver writers when writing device 
  1579. drivers for OS/2 for SMP V2.11. 
  1580.  
  1581. Existing device drivers should run on OS/2 for SMP V2.11 without modifications 
  1582. providing two simple rules are followed: 
  1583.  
  1584. o The driver must call DevHlp EOI to perform an EOI. 
  1585. o The driver must not mask or unmask interrupts directly. 
  1586.  
  1587. OS/2 2.x device drivers were written with only 8259 architecture in mind. The 
  1588. code that is most commonly executed in a device driver is to send the End Of 
  1589. Interrupt (EOI) command to the 8259. There is a system interface for do this, 
  1590. however, for performance reasons some device drivers have decided to implement 
  1591. this function directly. Additionally, some device drivers may MASK or UNMASK 
  1592. interrupts or read the 8259 registers to determine the interrupt state. 
  1593.  
  1594.  
  1595. ΓòÉΓòÉΓòÉ 5.1. Device Driver Spinlocks ΓòÉΓòÉΓòÉ
  1596.  
  1597. The device driver should protect access to critical resources using spinlocks. 
  1598. The device driver allocates spinlocks in the Init routine by calling 
  1599. DevHlp_CreateSpinLock. CreateSpinLock returns a handle for use by the device 
  1600. driver. This handle is passed to DevHlp_AcquireSpinLock and 
  1601. DevHlp_ReleaseSpinLock. The spinlock is freed by calling DevHlp_FreeSpinLock. 
  1602. The driver may request any number of spinlocks, as the spinlocks are 
  1603. represented by a very small data structure. Once created, the spinlocks never 
  1604. go away. 
  1605.  
  1606. As was outlined previously, OS/2 for SMP V2.11 contains a layer of abstraction 
  1607. for any functions that are deemed platform specific. These functions are placed 
  1608. inside the Platform Specific Driver (PSD) and isolate device drivers from the 
  1609. particular hardware platform that they are running on. At boot time, OS/2 
  1610. determines and loads the appropriate PSD for the MP system hardware it is 
  1611. currently running on. 
  1612.  
  1613. All device drivers that are MP-safe must use the appropriate kernel services to 
  1614. do hardware specific functions. The kernel will route these requests to the PSD 
  1615. for processing. 
  1616.  
  1617. Device drivers in OS/2 2.x were written with the concept that only one 
  1618. processor can generate interrupts. But with OS/2 for SMP V2.11 other processors 
  1619. can now generate interrupts, so device drivers should account for re-entrance 
  1620. and parallel execution of task-time and interrupt-time code. 
  1621.  
  1622.  
  1623. ΓòÉΓòÉΓòÉ 6. Application Considerations ΓòÉΓòÉΓòÉ
  1624.  
  1625. The following sections discuss application considerations of OS/2 for SMP 
  1626. V2.11. 
  1627.  
  1628.  
  1629. ΓòÉΓòÉΓòÉ 6.1. Application Compatibility Requirements ΓòÉΓòÉΓòÉ
  1630.  
  1631. o An Application or associated subsystem must not use the 'INC' instruction as 
  1632.   a semaphore without prepending a 'LOCK' prefix. On a UniProcessor (UP) system 
  1633.   this instruction can be used as high performance semaphore without calling 
  1634.   any other OS service if the semaphore is free and when the semaphore is clear 
  1635.   and there are no waiters for the semaphore. Because the INC instruction can 
  1636.   not be interrupted once started and because the results would be stored in 
  1637.   the flags register which are per thread then it could be used safely as 
  1638.   semaphore. 
  1639.  
  1640.   In an OS/2 for SMP V2.11 environment this technique will not work because it 
  1641.   is possible that two or more threads could be executing the same 'INC' 
  1642.   instruction receiving the same results in each processor's/thread's flag 
  1643.   register thinking that they each have the semaphore. 
  1644.  
  1645. o Similarly a 486 or greater instruction such as the CMPXCHG has the same 
  1646.   problem above if a 'LOCK' prefix is not prepended before the instruction. 
  1647.  
  1648. o An Application or associated subsystem which relies on priorities to 
  1649.   guarantee execution of its threads within a process will not work in OS/2 for 
  1650.   SMP V2.11. For example an application may have a time-critical and an idle 
  1651.   thread and may assume that while the time-critical thread is executing that 
  1652.   the idle thread will not get any execution time unless the time-critical 
  1653.   thread explicitly yields the CPU. In an OS/2 for SMP V2.11 environment it is 
  1654.   possible that both the time-critical and idle threads are executing 
  1655.   simultaneously on different processors. 
  1656.  
  1657. The above compatibility requirements apply only to multithreaded applications, 
  1658. and therefore do not apply to DOS and WINOS2 applications. However, you are 
  1659. strongly encouraged to write 32-bit multithreaded applications for better 
  1660. performance and portability on OS/2 for SMP V2.11. 
  1661.  
  1662. Given that there is the possibility of some set of applications which may use 
  1663. one of these techniques, OS/2 for SMP V2.11 provides a mechanism whereby these 
  1664. multithreaded applications can execute in UP mode. Only one thread of that 
  1665. process would be allowed to execute at any given time. That thread could 
  1666. execute on any one of the processors. A utility is used to mark the EXE file as 
  1667. uniprocessor only. OS/2 forces the process to run in the uniprocessor mode when 
  1668. the loader detects that the EXE file has been marked as uniprocessor only. See 
  1669. "The Single Processor Utility Program" section. 
  1670.  
  1671.  
  1672. ΓòÉΓòÉΓòÉ 6.2. Application Exploitation ΓòÉΓòÉΓòÉ
  1673.  
  1674. There are some very attractive benefits of OS/2 for SMP V2.11 beyond the 
  1675. increased raw CPU power. Caching is a technique that is employed in both 
  1676. hardware and software to increase performance. SMPs increase the effectiveness 
  1677. of the various caches dramatically. An application that can divide its work 
  1678. into separate executing units such as threads will see performance increases 
  1679. across the hardware and software. 
  1680.  
  1681. Each x86 processor (assuming 386 or higher) has a translation lookaside buffer 
  1682. (TLB) that keeps the most recent page translation addresses in a cache, so that 
  1683. every time the processor needs to translate a linear address into a physical 
  1684. address it does not have access the Page Directory and Page Table which reside 
  1685. in much slower memory. This cache is very limited in size. The more unique 
  1686. entries it encounters the less its effectiveness. An application which is 
  1687. single threaded makes use of only one TLB and probably causes thrashing within 
  1688. the TLB because of branching. However, with multiple processors, multithreaded 
  1689. applications will make use of N TLBs (where N is the number of threads and 
  1690. processors available). Thus the performance increase is more than just raw CPU 
  1691. power. 
  1692.  
  1693. Beyond the TLB cache, these processors also contain Level 1 (L1) caches and 
  1694. OEMs will sometimes add Level 2 (L2) caches to their systems. The same 
  1695. advantages are applicable here but to a further degree. 
  1696.  
  1697. There are also some advantages for software caches as well. Consider a file 
  1698. system cache where the effectiveness of the cache is largely determined by the 
  1699. hit ratio. If the cache receives large number of hits compared to misses, it is 
  1700. effective. The best way to achieve this is to keep the Most Recently Used (MRU) 
  1701. data in the cache. The best way to achieve this is to keep referencing the same 
  1702. data. A multithreaded application running on OS/2 for SMP V2.11 will cause this 
  1703. behavior to exist because the file system cache is being accessed in a shorter 
  1704. period of time by the same application. A single-threaded application with 
  1705. longer periods of access could allow for the cache to be flushed. 
  1706.  
  1707. Secondly, an important aspect of a demand paged OS is its ability to keep the 
  1708. right set of pages in memory at the right times. With OS/2 for SMP V2.11 and a 
  1709. multithreaded application, the Page Manager can make a better decision because 
  1710. pages for this application are being accessed more frequently than before. 
  1711.  
  1712.  
  1713. ΓòÉΓòÉΓòÉ 6.3. New OS/2 for SMP V2.11 APIs ΓòÉΓòÉΓòÉ
  1714.  
  1715. The new OS/2 for SMP V2.11 APIs are described in the following text. 
  1716.  
  1717. This section defines the new spinlock APIs that have been added for 
  1718. multiprocessor support. 
  1719.  
  1720.  
  1721. ΓòÉΓòÉΓòÉ 6.3.1. DosCreateSpinLock ΓòÉΓòÉΓòÉ
  1722.  
  1723. Description 
  1724.      Create a spinlock for multiprocessor serialization 
  1725.  
  1726.  
  1727. Calling Sequence 
  1728.      APIRET DosCreateSpinLock (PHSPINLOCK pHandle) 
  1729.  
  1730.  
  1731. Parameters 
  1732.      pHandle (PHSPINLOCK) - output 
  1733.      A pointer to the spinlock handle. This handle can be passed to 
  1734.      DosAcquireSpinLock to acquire a spinlock and to DosReleaseSpinLock to 
  1735.      release the spinlock. 
  1736.  
  1737.  
  1738. Returns 
  1739.      ulrc (APIRET) 
  1740.      DosCreateSpinLock returns the following values: 
  1741.  
  1742.    0       NO_ERROR 
  1743.    32804   ERROR_NO_MORE_HANDLES 
  1744.  
  1745.  
  1746. Remarks 
  1747.      DosCreateSpinLock returns a handle to a spin lock that is allocated in 
  1748.      kernel data space. The handle is to be used on subsequent spin lock 
  1749.      function calls and DevHlps. 
  1750.  
  1751.  
  1752. Related Functions 
  1753.  
  1754.    o DosAcquireSpinLock 
  1755.    o DosReleaseSpinLock 
  1756.  
  1757.  
  1758. Example Code 
  1759.      The following code example shows the use of DosCreateSpinLock: 
  1760.  
  1761.  
  1762.             #define INCL_BASE
  1763.             #define OS2_API16
  1764.             #define INCL_DOSSPINLOCK
  1765.             #include <os2.h>
  1766.             #include <stdio.h>
  1767.             #include <string.h>
  1768.  
  1769.             main()
  1770.             {
  1771.                 APIRET      rc;                 /* Return code */
  1772.                 HSPINLOCK   Handle;             /* Handle to spin lock */
  1773.                 PHSPINLOCK  pHandle = &Handle;  /* pointer to spin lock handle */
  1774.  
  1775.                 /* Create a spin lock */
  1776.  
  1777.                 rc = DosCreateSpinLock(pHandle);
  1778.  
  1779.                 if (rc !=0)
  1780.                   {
  1781.                     printf("DosCreateSpinLock failed -- rc = %1d",rc);
  1782.                     DosExit(0,1);
  1783.                   }
  1784.  
  1785.                 /* Acquire spin lock */
  1786.  
  1787.                 rc = DosAcquireSpinLock(Handle);
  1788.  
  1789.                 if (rc !=0)
  1790.                   {
  1791.                     printf("DosAcquireSpinLock failed -- rc = %1d",rc);
  1792.                     DosExit(0,1);
  1793.                   }
  1794.  
  1795.                 /* Code that needs serialization */
  1796.  
  1797.                 /* Release spin lock */
  1798.  
  1799.                 rc = DosReleaseSpinLock(Handle);
  1800.  
  1801.                 if (rc !=0)
  1802.                   {
  1803.                     printf("DosReleaseSpinLock failed -- rc = %1d",rc);
  1804.                     DosExit(0,1);
  1805.                   }
  1806.             }
  1807.  
  1808.  
  1809. ΓòÉΓòÉΓòÉ 6.3.2. DosAcquireSpinLock ΓòÉΓòÉΓòÉ
  1810.  
  1811. Description 
  1812.      Acquire a spinlock for multiprocessor serialization 
  1813.  
  1814.  
  1815. Calling Sequence 
  1816.      APIRET DosAcquireSpinLock (HSPINLOCK Handle) 
  1817.  
  1818.  
  1819. Parameters 
  1820.      Handle (HSPINLOCK) - input 
  1821.      A handle to a spinlock. This handle was returned on the DosCreateSpinLock 
  1822.      api call. 
  1823.  
  1824.  
  1825. Returns 
  1826.      ulrc (APIRET) 
  1827.      DosAcquireSpinLock returns one of the following values: 
  1828.  
  1829.    0    NO_ERROR 
  1830.    6    ERROR_INVALID_HANDLE 
  1831.  
  1832.  
  1833. Remarks 
  1834.      DosAcquireSpinLock is passed a handle which was returned by 
  1835.      DosCreateSpinLock When control is returned to the requester, the spin lock 
  1836.      has been acquired and interrupts are disabled. A call to 
  1837.      DosReleaseSpinLock must follow very shortly. Spin locks can be nested. 
  1838.  
  1839.  
  1840. Related Functions 
  1841.  
  1842.    o DosCreateSpinLock 
  1843.    o DosReleaseSpinLock 
  1844.  
  1845.  
  1846. Example Code 
  1847.      The following code example shows the use of DosAcquireSpinLock 
  1848.  
  1849.  
  1850.           #define INCL_BASE
  1851.           #define OS2_API16
  1852.           #define INCL_DOSSPINLOCK
  1853.           #include <os2.h>
  1854.           #include <stdio.h>
  1855.           #include <string.h>
  1856.  
  1857.           main()
  1858.           {
  1859.               APIRET      rc;                     /* Return code */
  1860.               HSPINLOCK   Handle;                 /* Handle to spin lock */
  1861.               PHSPINLOCK  pHandle = &Handle;  /* pointer to spin lock handle */
  1862.  
  1863.               /* Create a spin lock */
  1864.  
  1865.               rc = DosCreateSpinLock(pHandle);
  1866.  
  1867.               if (rc !=0)
  1868.                 {
  1869.                   printf("DosCreateSpinLock failed -- rc = %1d",rc);
  1870.                   DosExit(0,1);
  1871.                 }
  1872.  
  1873.               /* Acquire spin lock */
  1874.  
  1875.               rc = DosAcquireSpinLock(Handle);
  1876.  
  1877.               if (rc !=0)
  1878.                 {
  1879.                   printf("DosAcquireSpinLock failed -- rc = %1d",rc);
  1880.                   DosExit(0,1);
  1881.                 }
  1882.  
  1883.               /* Code that needs serialization */
  1884.  
  1885.               /* Release spin lock */
  1886.  
  1887.               rc = DosReleaseSpinLock(Handle);
  1888.  
  1889.               if (rc !=0)
  1890.                 {
  1891.                   printf("DosReleaseSpinLock failed -- rc = %1d",rc);
  1892.                   DosExit(0,1);
  1893.                 }
  1894.           }
  1895.  
  1896.  
  1897. ΓòÉΓòÉΓòÉ 6.3.3. DosReleaseSpinLock ΓòÉΓòÉΓòÉ
  1898.  
  1899. Description 
  1900.      Release a spinlock for multiprocessor serialization 
  1901.  
  1902.  
  1903. Calling Sequence 
  1904.      APIRET DosReleaseSpinLock (HSPINLOCK Handle) 
  1905.  
  1906.  
  1907. Parameters 
  1908.      Handle (HSPINLOCK) - input 
  1909.      A handle to a spinlock. This handle was returned by DosCreateSpinLock. 
  1910.  
  1911.  
  1912. Returns 
  1913.      ulrc (APIRET) 
  1914.      DosReleaseSpinLock returns the following values: 
  1915.  
  1916.    0    NO_ERROR 
  1917.    6    ERROR_INVALID_HANDLE 
  1918.  
  1919.  
  1920. Remarks 
  1921.      DosReleaseSpinLock is passed a handle which was returned by 
  1922.      DosCreateSpinLock When control is returned to the requester, the spin lock 
  1923.      is released and interrupts are enabled. A DosAcquireSpinLock must have 
  1924.      been previously issued. 
  1925.  
  1926.  
  1927. Related Functions 
  1928.  
  1929.    o DosAcquireSpinLock 
  1930.    o DosCreateSpinLock 
  1931.  
  1932.  
  1933. Example Code 
  1934.      The following code example shows the use of DosReleaseSpinLock: 
  1935.  
  1936.  
  1937.           #define INCL_BASE
  1938.           #define OS2_API16
  1939.           #define INCL_DOSSPINLOCK
  1940.           #include <os2.h>
  1941.           #include <stdio.h>
  1942.           #include <string.h>
  1943.  
  1944.           main()
  1945.           {
  1946.               APIRET      rc;                     /* Return code */
  1947.               HSPINLOCK   Handle;                 /* Handle to spin lock */
  1948.               PHSPINLOCK  pHandle = &Handle;  /* pointer to spin lock handle */
  1949.  
  1950.               /* Create a spin lock */
  1951.  
  1952.               rc = DosCreateSpinLock(pHandle);
  1953.  
  1954.               if (rc !=0)
  1955.                 {
  1956.                   printf("DosCreateSpinLock failed -- rc = %1d",rc);
  1957.                   DosExit(0,1);
  1958.                 }
  1959.  
  1960.               /* Acquire spin lock */
  1961.  
  1962.               rc = DosAcquireSpinLock(Handle);
  1963.  
  1964.               if (rc !=0)
  1965.                 {
  1966.                   printf("DosAcquireSpinLock failed -- rc = %1d",rc);
  1967.                   DosExit(0,1);
  1968.                 }
  1969.  
  1970.               /* Code that needs serialization */
  1971.  
  1972.               /* Release spin lock */
  1973.  
  1974.               rc = DosReleaseSpinLock(Handle);
  1975.  
  1976.               if (rc !=0)
  1977.                 {
  1978.                   printf("DosReleaseSpinLock failed -- rc = %1d",rc);
  1979.                   DosExit(0,1);
  1980.                 }
  1981.           }
  1982.  
  1983.  
  1984. ΓòÉΓòÉΓòÉ 6.3.4. DosFreeSpinLock ΓòÉΓòÉΓòÉ
  1985.  
  1986. Description 
  1987.      Free a spinlock for multiprocessor serialization. 
  1988.  
  1989.  
  1990. Calling Sequence 
  1991.      APIRET DosFreeSpinLock (HSPINLOCK Handle) 
  1992.  
  1993.  
  1994. Parameters 
  1995.      Handle (HSPINLOCK) - input 
  1996.      A handle to a spinlock. This handle was returned on the DosCreateSpinLock 
  1997.      api call. 
  1998.  
  1999.  
  2000. Returns 
  2001.      ulrc (APIRET) 
  2002.      DosFreeSpinLock returns the following values: 
  2003.  
  2004.    0    NO_ERROR 
  2005.    6    ERROR_INVALID_HANDLE 
  2006.  
  2007.  
  2008. Remarks 
  2009.      DosFreeSpinLock is passed the handle which was returned by 
  2010.      DosCreateSpinLock 
  2011.  
  2012.  
  2013. Related Functions 
  2014.  
  2015.    o DosCreateSpinLock 
  2016.    o DosAcquireSpinLock 
  2017.    o DosReleaseSpinLock 
  2018.  
  2019.  
  2020. Example Code 
  2021.      The following code example shows the use of DosFreeSpinLock: 
  2022.  
  2023.  
  2024.           #define INCL_BASE
  2025.           #define OS2_API16
  2026.           #define INCL_DOSSPINLOCK
  2027.           #include <os2.h>
  2028.           #include <stdio.h>
  2029.           #include <string.h>
  2030.  
  2031.           main()
  2032.           {
  2033.               APIRET      rc;                     /* Return code */
  2034.               HSPINLOCK   Handle;                 /* Handle to spin lock */
  2035.               PHSPINLOCK  pHandle = &Handle;  /* pointer to spin lock handle */
  2036.  
  2037.               /* Create a spin lock */
  2038.  
  2039.               rc = DosCreateSpinLock(pHandle);
  2040.               if (rc !=0)
  2041.                 {
  2042.                   printf("DosCreateSpinLock failed -- rc = %1d",rc);
  2043.                   DosExit(0,1);
  2044.                 }
  2045.  
  2046.               /* Acquire spin lock */
  2047.  
  2048.               rc = DosAcquireSpinLock(Handle);
  2049.               if (rc !=0)
  2050.                 {
  2051.                   printf("DosAcquireSpinLock failed -- rc = %1d",rc);
  2052.                   DosExit(0,1);
  2053.                 }
  2054.  
  2055.               /* Code that needs serialization */
  2056.               /* Release spin lock */
  2057.  
  2058.               rc = DosReleaseSpinLock(Handle);
  2059.               if (rc !=0)
  2060.                 {
  2061.                   printf("DosReleaseSpinLock failed -- rc = %1d",rc);
  2062.                   DosExit(0,1);
  2063.                 }
  2064.  
  2065.               /* Free spin lock */
  2066.  
  2067.               rc = DosFreeSpinLock(Handle);
  2068.               if (rc !=0)
  2069.                 {
  2070.                   printf("DosFreeSpinLock failed -- rc = %1d",rc);
  2071.                   DosExit(0,1);
  2072.                 }
  2073.           }
  2074.  
  2075.  
  2076. New APIs are being introduced to provide support for the OS/2 SMP V2.11 
  2077. performance monitor. 
  2078.  
  2079.  
  2080. ΓòÉΓòÉΓòÉ 6.3.5. DosGetProcessorCount ΓòÉΓòÉΓòÉ
  2081.  
  2082. Description 
  2083.      Get the count of usable processors 
  2084.  
  2085.  
  2086. Calling Sequence 
  2087.      APIRET DosGetProcessorCount (PULONG pCount) 
  2088.  
  2089.  
  2090. Parameters 
  2091.      pCount (PULONG) - output 
  2092.      A pointer to the count of usable processors. 
  2093.  
  2094.  
  2095. Returns 
  2096.      DosGetProcessorCount returns the following values: 
  2097.  
  2098.    0    NO_ERROR 
  2099.    87   ERROR_INVALID_PARAMETER 
  2100.  
  2101.  
  2102. Remarks 
  2103.      DosGetProcessorCount returns the number of usable processors. 
  2104.  
  2105.  
  2106. Related Functions 
  2107.  
  2108.    o DosGetProcessorIdleTime 
  2109.    o DosGetProcessorStatus 
  2110.    o DosSetProcessorStatus 
  2111.  
  2112.  
  2113. ΓòÉΓòÉΓòÉ 6.3.6. DosGetProcessorIdleTime ΓòÉΓòÉΓòÉ
  2114.  
  2115. Description 
  2116.      Get the idle time for the specified processor. 
  2117.  
  2118.  
  2119. Calling Sequence 
  2120.      APIRET DosGetProcessorIdleTime (ULONG ProcNum, PULONG pIdleTime) 
  2121.  
  2122.  
  2123. Parameters 
  2124.      ProcNum (ULONG) - input 
  2125.         The processor number for which the idle time is to be gotten. 
  2126.      pIdleTime (PULONG) - output 
  2127.         A pointer to the idle time for the specified processor. 
  2128.  
  2129.  
  2130. Returns 
  2131.      DosGetProcessorIdleTime returns the following values: 
  2132.  
  2133.    0    NO_ERROR 
  2134.    87   ERROR_INVALID_PARAMETER 
  2135.  
  2136.  
  2137. Remarks 
  2138.      DosGetProcessorIdleTime returns the idle time for the specified processor 
  2139.  
  2140.  
  2141. Related Functions 
  2142.  
  2143.    o DosGetProcessorCount 
  2144.    o DosGetProcessorStatus 
  2145.    o DosSetProcessorStatus 
  2146.  
  2147.  
  2148. ΓòÉΓòÉΓòÉ 6.3.7. DosGetProcessorStatus ΓòÉΓòÉΓòÉ
  2149.  
  2150. Description 
  2151.      Get the status for the specified processor. 
  2152.  
  2153.  
  2154. Calling Sequence 
  2155.      APIRET DosGetProcessorStatus (ULONG ProcNum, PULONG pStatus) 
  2156.  
  2157.  
  2158. Parameters 
  2159.      ProcNum (ULONG) - input 
  2160.         The processor number for which the status is to be gotten. 
  2161.      pStatus (PULONG) - output 
  2162.         A pointer to the status for the specified processor. 
  2163.  
  2164.  
  2165. Returns 
  2166.      DosGetProcessorStatus returns the following values: 
  2167.  
  2168.    0    NO_ERROR 
  2169.    87   ERROR_INVALID_PARAMETER 
  2170.  
  2171.  
  2172. Remarks 
  2173.      DosGetProcessorStatus returns the status for the specified processor. A 0 
  2174.      indicates OFFLINE and a 1 indicates ONLINE. All other values are reserved. 
  2175.  
  2176.  
  2177. Related Functions 
  2178.  
  2179.    o DosGetProcessorCount 
  2180.    o DosGetProcessorIdleTime 
  2181.    o DosSetProcessorStatus 
  2182.  
  2183.  
  2184. ΓòÉΓòÉΓòÉ 6.3.8. DosSetProcessorStatus ΓòÉΓòÉΓòÉ
  2185.  
  2186. Description 
  2187.      Set the status for the specified processor. 
  2188.  
  2189.  
  2190. Calling Sequence 
  2191.      APIRET DosSetProcessorStatus (ULONG ProcNum, PULONG pStatus) 
  2192.  
  2193.  
  2194. Parameters 
  2195.      ProcNum (ULONG) - input 
  2196.         The processor number for which the status is to be set. 
  2197.      pStatus (PULONG) - input 
  2198.         A pointer to the status for the specified processor. 
  2199.  
  2200.  
  2201. Returns 
  2202.      DosSetProcessorStatus returns the following values: 
  2203.  
  2204.    0    NO_ERROR 
  2205.    87   ERROR_INVALID_PARAMETER 
  2206.  
  2207.  
  2208. Remarks 
  2209.      DosSetProcessorStatus sets the status for the specified processor. A 0 
  2210.      indicates OFFLINE and a 1 indicates ONLINE. All other values are reserved. 
  2211.  
  2212.  
  2213. Related Functions 
  2214.  
  2215.    o DosGetProcessorCount 
  2216.    o DosGetProcessorIdleTime 
  2217.    o DosGetProcessorStatus 
  2218.  
  2219.  
  2220. ΓòÉΓòÉΓòÉ 6.3.9. DosAllocThreadLocalMemory ΓòÉΓòÉΓòÉ
  2221.  
  2222. Description 
  2223.      Allocates a block of memory that is local to a thread. 
  2224.  
  2225.  
  2226. Calling Sequence 
  2227.      APIRET DosAllocThreadLocalMemory (ULONG Lwords, PPVOID pMemBlock) 
  2228.  
  2229.  
  2230. Parameters 
  2231.      Lwords (ULONG) - input 
  2232.         The number of 32-bit dwords to allocate. 
  2233.      pMemBlock (PPVOID) - input 
  2234.         A pointer to the memory block allocated. 
  2235.  
  2236.  
  2237. Returns 
  2238.      DosAllocThreadLocalMemory returns the following values: 
  2239.  
  2240.    0    NO_ERROR 
  2241.    8    ERROR_NOT_ENOUGH_MEMORY 
  2242.    87   ERROR_INVALID_PATAMETER 
  2243.  
  2244.  
  2245. Remarks 
  2246.      When a process is started, a small block of memory is set aside to be used 
  2247.      as a thread-local memory area. This memory is at the same virtual address 
  2248.      for each thread, but is backed by different physical memory. This permits 
  2249.      each thread to have a small block of memory that is unique, or local, to 
  2250.      that thread. 
  2251.  
  2252.      The thread-local memory area consists of 32 DWORDs (128 bytes), each DWORD 
  2253.      being 32-bits in size. Up to 8 DWORDs (32 bytes) can be requested each 
  2254.      time this function is called. If you want to allocate more than 8 DWORDs, 
  2255.      you must call this function more than once. 
  2256.  
  2257.      Allocation is by DWORD only. If you want to store a BYTE in the 
  2258.      thread-local memory area, you would still allocate a DWORD, then store the 
  2259.      BYTE in it. 
  2260.  
  2261.  
  2262. Related Functions 
  2263.  
  2264.    o DosFreeThreadLocalMemory 
  2265.  
  2266.  
  2267. Example Code 
  2268.      The following code example allocates a thread-local memory block of 6 
  2269.      DWORDs, then frees it. 
  2270.  
  2271.  
  2272.             #define  INCL_DOSPROCESS  /* Memory Manager values */
  2273.             #include <os2.h>
  2274.  
  2275.             #include <stdio.h>  /* For printf */
  2276.  
  2277.             PVOID    pMemBlock;     /* Pointer to the memory block returned */
  2278.             APIRET   rc;            /* Return code */
  2279.  
  2280.                rc = DosAllocThreadLocalMemory(6, &pMemBlock);   /* Allocate 6 DWORDs */
  2281.  
  2282.                if (rc != NO_ERROR)
  2283.                {
  2284.                    printf("DosAllocThreadLocalMemory error: return code = %ld", rc);
  2285.                    return 1;
  2286.                }
  2287.  
  2288.  
  2289.                /* ... Use the thread-local memory block ... */
  2290.  
  2291.  
  2292.                rc = DosFreeThreadLocalMemory(pMemBlock);     /* Free the memory block */
  2293.  
  2294.                if (rc != NO_ERROR)
  2295.                {
  2296.                    printf("DosFreeThreadLocalMemory error: return code = %ld", rc);
  2297.                    return 1;
  2298.                }
  2299.  
  2300.                return 0;
  2301.  
  2302.  
  2303. ΓòÉΓòÉΓòÉ 6.3.10. DosFreeThreadLocalMemory ΓòÉΓòÉΓòÉ
  2304.  
  2305. Description 
  2306.      Free memory allocated by DosAllocThreadLocalMemory. 
  2307.  
  2308.  
  2309. Calling Sequence 
  2310.      APIRET DosFreeThreadLocalMemory (ULONG ProcNum, PULONG pStatus) 
  2311.  
  2312.  
  2313. Parameters 
  2314.      ProcNum (ULONG) - input 
  2315.         The processor number for which the status is to be set. 
  2316.      pStatus (PULONG) - input 
  2317.         A pointer to the status for the specified processor. 
  2318.  
  2319.  
  2320. Returns 
  2321.      DosFreeThreadLocalMemory returns the following values: 
  2322.  
  2323.    0    NO_ERROR 
  2324.    87   ERROR_INVALID_PARAMETER 
  2325.  
  2326.  
  2327. Remarks 
  2328.      When a process is started, a small block of memory is set aside to be used 
  2329.      as a thread-local memory area. This memory is at the same virtual address 
  2330.      for each thread, but is backed by different physical memory. This permits 
  2331.      each thread to have a small block of memory that is unique, or local, to 
  2332.      that thread. 
  2333.  
  2334.      The thread-local memory area consists of 32 DWORDs (128 bytes), each DWORD 
  2335.      being 32-bits in size. 
  2336.  
  2337.  
  2338. Related Functions 
  2339.  
  2340.    o DosAllocThreadLocalMemory 
  2341.  
  2342.  
  2343. Example Code 
  2344.      The following code example allocates a thread-local memory block of 6 
  2345.      DWORDs, then frees it. 
  2346.  
  2347.  
  2348.            #define  INCL_DOSPROCESS  /* Memory Manager values */
  2349.            #include <os2.h>
  2350.  
  2351.            #include <stdio.h>  /* For printf */
  2352.  
  2353.            PVOID    pMemBlock;  /* Pointer to the memory block returned */
  2354.            APIRET   rc;         /* Return code */
  2355.  
  2356.               rc = DosAllocThreadLocalMemory(6, &pMemBlock); /* Allocate 6 DWORDs */
  2357.  
  2358.               if (rc != NO_ERROR)
  2359.               {
  2360.                   printf("DosAllocThreadLocalMemory error: return code = %ld", rc);
  2361.                   return 1;
  2362.               }
  2363.  
  2364.  
  2365.               /* ... Use the thread-local memory block ... */
  2366.  
  2367.               rc = DosFreeThreadLocalMemory(pMemBlock); /* Free the memory block */
  2368.  
  2369.               if (rc != NO_ERROR)
  2370.               {
  2371.                   printf("DosFreeThreadLocalMemory error: return code = %ld", rc);
  2372.                   return 1;
  2373.               }
  2374.  
  2375.               return 0;
  2376.  
  2377.  
  2378. ΓòÉΓòÉΓòÉ 6.3.11. DosQuerySysInfo ΓòÉΓòÉΓòÉ
  2379.  
  2380. DosQuerySysInfo now returns three new system variables. These variables are in 
  2381. the following list. 
  2382.  
  2383. VALUE     MNEMONIC CONSTANT AND DESCRIPTION 
  2384. 24        QSV_FOREGROUND_FS_SESSION 
  2385.           Session ID of the current foreground full-screen session. Note that 
  2386.           this only applies to full-screen sessions. The Presentation Manager 
  2387.           session (which displays VIO-windowed, PM, and windowed DOS Sessions) 
  2388.           is full-screen session ID 1. 
  2389. 25        QSV_FOREGROUND_PROCESS 
  2390.           Process ID of the current foreground process. 
  2391. 26        QSV_NUMPROCESSORS 
  2392.           Number of processors in the machine. 
  2393.  
  2394.  
  2395. ΓòÉΓòÉΓòÉ 7. Avoiding Device Driver Deadlocks ΓòÉΓòÉΓòÉ
  2396.  
  2397. Deadlock can be defined as an unresolved contention for use of a resource. 
  2398. Whenever any mutual exclusion primitive is used, the possibility of deadlock is 
  2399. introduced. This is evident even in uniprocessor system such as OS/2 with the 
  2400. use of semaphores. The possibilities of deadlock are greater in a 
  2401. multiprocessor environment because of the large requirement for mutual 
  2402. exclusion. The method of mutual exclusion for device drivers and the OS/2 SMP 
  2403. kernel is the spinlock. Using spinlocks incorrectly can result in deadlock 
  2404. conditions where an application or device driver will become hung. In the case 
  2405. of a device driver, no more activity will take place on that processor if the 
  2406. device driver enters a deadlock state. Writing device drivers and code for OS/2 
  2407. for SMP V2.11 requires the programmer to think about the conditions in the code 
  2408. which might cause a deadlock condition, and then use spinlocks to protect those 
  2409. resources. 
  2410.  
  2411. While it would be impossible to list every cause of deadlock, a few of the most 
  2412. common code examples are given below in pseudo-code that can result in 
  2413. deadlock. These examples are not exhaustive, but represent the majority of 
  2414. situations that will probably be encountered. Being aware of these types of 
  2415. conditions can help you reduce the chances of deadlock within your device 
  2416. driver or applications. 
  2417.  
  2418.  
  2419. ΓòÉΓòÉΓòÉ 7.1. Use of CLI/STI ΓòÉΓòÉΓòÉ
  2420.  
  2421. As stated above, CLI/STI will only work on the processor on which they execute. 
  2422. Therefore, only the same processor will be protected from "stepping" on a 
  2423. protected resource. For example, assume the application maintains a linked list 
  2424. of I/O packets for a device. Whenever packets are inserted or removed, the list 
  2425. must be protected as a critical resource. Under the uniprocessor model, a 
  2426. CLI/STI around the manipulation of the list would be sufficient protection. 
  2427. However, in an MP environment, the CLI/STI would only protect the resource on 
  2428. the same processor. Another processor could enter a section of code that 
  2429. attempted to manipulate the linked list. The results would be unpredictable. 
  2430. Possibilities would range from no effect to deadlock. Code that uses CLI/STI is 
  2431. not reliable and should be eliminated. 
  2432.  
  2433. The solution is to replace CLI/STIs with spinlocks. Each critical resource will 
  2434. have associated with it a spinlock. Before accessing the resource the spinlock 
  2435. must be acquired, and when complete, the spinlock is released. 
  2436.  
  2437.  
  2438. ΓòÉΓòÉΓòÉ 7.2. Spinlocks Taken Out of Order ΓòÉΓòÉΓòÉ
  2439.  
  2440. One possible cause of deadlock stems from taking spinlocks in different orders 
  2441. in different sections of code. Consider the following two sections of code, 
  2442. each executing on a separate processor at the same time. For both examples all 
  2443. locks are available when the code begins execution. 
  2444.  
  2445.  
  2446.         Code section 1              Code section 2
  2447.  
  2448.  
  2449.      1  Lock spinlock1           1  Lock spinlock2
  2450.      2  Do some processing       2  Do some processing
  2451.      3  Lock spinlock2           3  Lock spinlock1
  2452.      4  More processing          4  More processing
  2453.      5  Unlock spinlock2         5  Unlock spinlock1
  2454.      6  Unlock spinlock1         6  Unlock spinlock2
  2455.  
  2456. In section 1 line 1 locks spinlock1.  In section 2 line 1 locks spinlock2. Both 
  2457. sections will successfully lock their respective locks and continue normally. 
  2458. Now section 1 on line 3 tries to lock spinlock2, which is already locked by 
  2459. section 2, so section 1 spins. Now section 2 tries to lock spinlock1 (line 3), 
  2460. which is already locked by section 1, so section 2 now spins. Now each section 
  2461. of code is spinning waiting for a lock that the other owns. The result is 
  2462. deadlock. Neither section of code will ever continue executing and will 
  2463. therefore never release the spinlock that the other needs. This kind of 
  2464. deadlock is very common, but can be avoided by always taking spinlocks that are 
  2465. related in the same order. 
  2466.  
  2467. To fix the above code, code section 2 would be recoded to the following: 
  2468.  
  2469.  
  2470.        Code section 2
  2471.  
  2472.  
  2473.     1  Lock spinlock1
  2474.     2  Lock spinlock2
  2475.     3  Do some processing
  2476.     4  More processing
  2477.     5  Unlock spinlock2
  2478.     6  Unlock spinlock1
  2479.  
  2480. By taking the locks in the same order as code section 1 the deadlock potential 
  2481. is eliminated. Both sections can no longer be waiting on a resource the other 
  2482. owns at the same time. It should be noted that spinlocks should be released in 
  2483. the reverse order that they are locked. 
  2484.  
  2485.  
  2486. ΓòÉΓòÉΓòÉ 7.3. Blocking With Spinlocks Locked ΓòÉΓòÉΓòÉ
  2487.  
  2488. Another cause of deadlock is blocking with locked spinlocks. Consider the 
  2489. following two sections of code. Section 1 is a task time operation that needs 
  2490. an interrupt to complete. Section 2 is the interrupt code that will execute and 
  2491. unblock section 1. 
  2492.  
  2493.  
  2494.       Code section 1                  Code section 2
  2495.       (Task time)                     (Interrupt time)
  2496.  
  2497.       Lock spinlock1                  interrupt received
  2498.       start I/O                       lock spinlock1
  2499.       block (ProcBlock)               unblock (ProcRun)
  2500.                                       release spinlock1
  2501.       return from block
  2502.       some processing
  2503.          (may include a re-block)
  2504.       release spinlock1
  2505.  
  2506. In the above example code section 1 locks spinlock1 and then blocks (with the 
  2507. spinlock still locked). Code section 2 will then execute when the I/O 
  2508. completes. The interrupt code first tries to lock spinlock1. Because spinlock1 
  2509. is already locked, the interrupt code will spin waiting for the lock. The lock 
  2510. will never become available, however, because the only way for the spinlock to 
  2511. be unlocked is for section 1 to be unblocked. But the interrupt code, which is 
  2512. responsible for the unblock, can't continue until it acquires the spinlock. The 
  2513. result is deadlock. 
  2514.  
  2515. Now the first attempt to solve this problem may be to recode section 1 with the 
  2516. following: 
  2517.  
  2518.  
  2519.      Lock spinlock1
  2520.      start I/O
  2521.      release spinlock1
  2522.      block (ProcBlock)
  2523.  
  2524.      return from block
  2525.      lock spinlock1
  2526.      some processing
  2527.      release spinlock1
  2528.  
  2529. The above code sequence appears to correct the problem. It does not, however, 
  2530. and can also result in a deadlock. The reason is that there exists a window 
  2531. between where the code releases the spinlock and the thread is blocked in which 
  2532. an interrupt can occur. Remember that disabling interrupts no longer prevents 
  2533. interrupts from happening. If an interrupt fires in this window, the interrupt 
  2534. handler (section 2 above) will run. It will acquire the spinlock and attempt to 
  2535. unblock the thread. The thread, however, has not actually blocked yet. When the 
  2536. thread finally does block, the wakeup event has already occurred. The result 
  2537. once again is deadlock. 
  2538.  
  2539. To solve this particular problem, DevHelp_Block has been modified to release 
  2540. ALL spinlocks that are owned on the current processor. The device driver should 
  2541. call DevHelp_Block with spinlocks locked. The kernel will first put the thread 
  2542. of execution in the blocked state. Then, before dispatching the next thread, it 
  2543. will release all locked spinlocks for the current processor. Because the thread 
  2544. is in the blocked state, it is valid for another processor to execute interrupt 
  2545. code that will do the DevHelp_Run. The result is no deadlock. The code 
  2546. sequences from above should be re-coded to the following to avoid the deadlock: 
  2547.  
  2548.  
  2549.       Code section 1                  Code section 2
  2550.  
  2551.       Lock spinlock1                  interrupt received
  2552.       start I/O                       lock spinlock1
  2553.       While(block required)           unblock (ProcRun)
  2554.          Block                        release spinlock1
  2555.          return from block
  2556.          Lock spinlock1
  2557.       EndWhile
  2558.       some processing
  2559.       release spinlock1
  2560.  
  2561. The above example has been expanded to include the steps required to insure 
  2562. that when the thread is woken up, that the blocking condition is satisfied 
  2563. before execution continues. This code sequence is analogous to that listed in 
  2564. the description for DevHlp_Block in the Device Helper Services chapter of the 
  2565. Physical Device Driver Reference. It has been modified to use spinlocks instead 
  2566. of disabling interrupts (which will not work). 
  2567.  
  2568. Once again this list is not exhaustive, but is a representation of the majority 
  2569. of cases that can cause deadlock. By avoiding these situations the chances of 
  2570. deadlock are reduced considerably. In addition, there are certain system level 
  2571. checks performed to help insure that deadlock is avoided. If the system detects 
  2572. a situation that could cause deadlock, such as attempting to block while owing 
  2573. a spinlock, it will panic the system and print an internal processing error 
  2574. message. 
  2575.  
  2576.  
  2577. ΓòÉΓòÉΓòÉ 7.4. Blocking ΓòÉΓòÉΓòÉ
  2578.  
  2579. As shown in the last example, there are special considerations that must be 
  2580. followed when blocking in an MP aware device driver. Because blocking with a 
  2581. spinlock owned can cause deadlock, the DevHelp_Block service will unlock 
  2582. spinlocks as part of the blocking sequence. When the run is done and the 
  2583. blocked thread begins execution again, it must again lock any required 
  2584. spinlocks. 
  2585.  
  2586. All system components that use spinlocks must be aware of calls that may block. 
  2587. For example, the file system, which calls a device driver to perform I/O, will 
  2588. almost always block in the device driver. The file system therefore should 
  2589. release all spinlocks before calling the device driver. In general, release all 
  2590. spinlocks before making a call that could block. 
  2591.  
  2592.  
  2593. ΓòÉΓòÉΓòÉ 7.5. Interrupt Processing ΓòÉΓòÉΓòÉ
  2594.  
  2595. Interrupt processing should not be affected, except by the need to lock 
  2596. spinlocks for critical resources. When a spinlock is locked, the LockManger 
  2597. will disable interrupts before returning to the device driver. This insures 
  2598. that no interrupt will occur, on the same processor, between when the spinlock 
  2599. is requested and when the kernel returns to the device driver with the spinlock 
  2600. locked. (The same level of function accomplished by a CLI on a single processor 
  2601. system). The device driver MUST leave interrupts disabled while owning the 
  2602. spinlock. If interrupts were enabled a deadlock could occur.  Consider the 
  2603. following: 
  2604.  
  2605.  
  2606.  
  2607.       Task Time                           Int Time
  2608.  
  2609.    (ints enabled)
  2610.    Lock spinlock1
  2611.    STI
  2612.                    ---Interrupt--->     Lock spinlock1
  2613.                                         some processing
  2614.                                         Unlock spinlock1
  2615.                                         EOI
  2616.                    <-- Return from Int
  2617.    Some processing
  2618.    Unlock spinlock1
  2619.  
  2620. In the above example the the task time and interrupt code are running on the 
  2621. same processor. When the task time code locks spinlock1 with interrupts enabled 
  2622. the LockManager will return with interrupts disabled. If interrupts were 
  2623. enabled after the lock with the STI instruction, then the interrupt code on the 
  2624. right could run. The first thing the interrupt handler does is try to grab 
  2625. spinlock1. Because spinlock1 is already locked, the interrupt handler will 
  2626. spin. The lock, however, will never become available. The task time code will 
  2627. not run until the interrupt code completes. The result is deadlock. This is why 
  2628. it is important to leave interrupts disabled while owning a spinlock. 
  2629.  
  2630. Consider the same code above, but with the task time code running on processor 
  2631. A and the interrupt code running on processor B. For this example, however, 
  2632. interrupts remain disabled (remove the STI). Because the LockManager disables 
  2633. interrupts, processor B will run the interrupt code. When the interrupt code 
  2634. attempts to get the spinlock, it will spin. Because processor A continues 
  2635. executing, the spinlock will be released, thereby allowing the interrupt code 
  2636. on processor B to acquire the spinlock and continue execution.  Deadlock is 
  2637. avoided. When processor A returns from the unlock the state of the interrupt 
  2638. flag will be restored by the LockManager to its state before the lock was done. 
  2639.  
  2640. Another action the device driver must avoid is issuing its own EOI. All EOIs 
  2641. must use the DevHelp_EOI device helper service. The reason for this is that 
  2642. different multiprocessor platforms have defined their own advanced interrupt 
  2643. controllers. Without detailed knowledge of the controller and how it operates, 
  2644. and knowledge of how the kernel is using the controller, the device driver can 
  2645. cause unpredictable results, including deadlock. All MP-aware device drivers 
  2646. must use the EOI service. 
  2647.  
  2648.  
  2649. ΓòÉΓòÉΓòÉ 8. New Device Helper (DevHlp) Routines ΓòÉΓòÉΓòÉ
  2650.  
  2651. Following are the new physical and virtual DevHlp routines. 
  2652.  
  2653.  
  2654. ΓòÉΓòÉΓòÉ 8.1. Physical DevHlps ΓòÉΓòÉΓòÉ
  2655.  
  2656. The OS/2 kernel will provide new DevHlps for OS/2 for SMP V2.11 as follows. 
  2657.  
  2658. DevHlp_CreateSpinLock         EQU    111     ; 6F Create a spinlock - SMP
  2659. DevHlp_FreeSpinLock           EQU    112     ; 70 Free a spinlock - SMP
  2660. DevHlp_AcquireSpinLock        EQU    113     ; 71 Acquire a spinlock - SMP
  2661. DevHlp_ReleaseSpinLock        EQU    114     ; 72 Release a spinlock - SMP
  2662. DevHlp_PortIO                 EQU    118     ; 76 Port I/O
  2663. DevHlp_SetIRQMask             EQU    119     ; 77 Set/Unset an IRQ mask
  2664. DevHlp_GetIRQMask             EQU    120     ; 78 Get an IRQ mask
  2665.  
  2666.  
  2667. ΓòÉΓòÉΓòÉ 8.1.1. DevHlp_CreateSpinLock ΓòÉΓòÉΓòÉ
  2668.  
  2669. Description 
  2670.      Create a subsystem spinlock. 
  2671.  
  2672.      This function creates a subsystem spinlock. 
  2673.  
  2674.  
  2675. Parameters 
  2676.      Pointer to spinlock handle. 
  2677.  
  2678.  
  2679. Exit 
  2680.      Return code. 
  2681.  
  2682.  
  2683. Assembly language 
  2684.  
  2685.            ;       dh_CreateSpinLock - Create a spinlock
  2686.            ;
  2687.            ;       This routine creats a subsystem spinlock.
  2688.            ;
  2689.            ;       ENTRY:  AX:BX = pointer to store spinlock handle
  2690.            ;
  2691.            ;       EXIT:   None
  2692.            ;
  2693.            ;       USES:   EAX, Flags
  2694.            ;
  2695.  
  2696.              MOV     AX,AddressHigh               ; high word of address
  2697.              MOV     BX,AddressLow                ; low word of address
  2698.              MOV     DL,DevHlp_CreateSpinLock     ;
  2699.              CALL    DevHlp
  2700.              JC      Error
  2701.  
  2702.  
  2703. ΓòÉΓòÉΓòÉ 8.1.2. DevHlp_FreeSpinLock ΓòÉΓòÉΓòÉ
  2704.  
  2705. Description 
  2706.      Free a subsystem spinlock. 
  2707.  
  2708.      This function frees a subsystem spinlock. 
  2709.  
  2710.  
  2711. Parameters 
  2712.      Spinlock handle. 
  2713.  
  2714.  
  2715. Exit 
  2716.      Return code. 
  2717.  
  2718.  
  2719. Assembly language 
  2720.  
  2721.            ;       dh_FreeSpinLock - Free a subsystem spinlock
  2722.            ;
  2723.            ;       This routine frees a subsystem spinlock.
  2724.            ;
  2725.            ;       ENTRY:  AX:BX = spinlock handle
  2726.            ;
  2727.            ;       EXIT:   None
  2728.            ;
  2729.            ;       USES:   Flags
  2730.            ;
  2731.  
  2732.              hSpinLock       dd      ?            ; 16:16
  2733.  
  2734.              MOV     AX,hSpinLockHighWord         ; high word of handle
  2735.              MOV     BX,hSpinLockLowWord          ; low word of handle
  2736.              MOV     DL,DevHlp_FreeSpinLock       ;
  2737.              CALL    DevHlp
  2738.              JC      Error
  2739.  
  2740.  
  2741. ΓòÉΓòÉΓòÉ 8.1.3. DevHlp_AcquireSpinLock ΓòÉΓòÉΓòÉ
  2742.  
  2743. Description 
  2744.      Acquire a subsystem spinlock. 
  2745.  
  2746.      This function obtains ownership of a subsystem spinlock. 
  2747.  
  2748.  
  2749. Parameters 
  2750.      Spinlock handle. 
  2751.  
  2752.  
  2753. Exit 
  2754.      Return code. 
  2755.  
  2756.  
  2757. Assembly language 
  2758.  
  2759.            ;       dh_AcquireSpinLock - Acquire a subsystem spinlock
  2760.            ;
  2761.            ;       Obtains ownership of a subsystem spinlock. Used by device drivers.
  2762.            ;
  2763.            ;       ENTRY:  AX:BX = spinlock handle
  2764.            ;
  2765.            ;       EXIT:   None
  2766.            ;
  2767.            ;       USES:   Flags
  2768.            ;
  2769.  
  2770.              hSpinLock       dd      ?            ; 16:16
  2771.  
  2772.              MOV     AX,hSpinLockHighWord         ; high word of handle
  2773.              MOV     BX,hSpinLockLowWord          ; low word of handle
  2774.              MOV     DL,DevHlp_AcquireSpinLock    ;
  2775.              CALL    DevHlp
  2776.              JC      Error
  2777.  
  2778.  
  2779. ΓòÉΓòÉΓòÉ 8.1.4. DevHlp_ReleaseSpinLock ΓòÉΓòÉΓòÉ
  2780.  
  2781. Description 
  2782.      Release a subsystem spinlock. 
  2783.  
  2784.      This function releases ownership of a subsystem spinlock. 
  2785.  
  2786.  
  2787. Parameters 
  2788.      Spinlock handle. 
  2789.  
  2790.  
  2791. Exit 
  2792.      Return code. 
  2793.  
  2794.  
  2795. Assembly language 
  2796.  
  2797.            ;       dh_ReleaseSpinLock - Release a subsystem spinlock.
  2798.            ;
  2799.            ;       Releases ownership of a subsystem spinlock. Used by device drivers.
  2800.            ;
  2801.            ;       ENTRY:  AX:BX = spinlock handle
  2802.            ;
  2803.            ;       EXIT:   None
  2804.            ;
  2805.            ;       USES:   Flags
  2806.            ;
  2807.  
  2808.              hSpinLock       dd      ?            ; 16:16
  2809.  
  2810.              MOV     AX,hSpinLockHighWord         ; high word of handle
  2811.              MOV     BX,hSpinLockLowWord          ; low word of handle
  2812.              MOV     DL,DevHlp_ReleaseSpinLock    ;
  2813.              CALL    DevHlp
  2814.              JC      Error
  2815.  
  2816.  
  2817. ΓòÉΓòÉΓòÉ 8.1.5. DevHlp_Port_IO ΓòÉΓòÉΓòÉ
  2818.  
  2819. Description 
  2820.      Perform IO to a specified port. 
  2821.  
  2822.      This function is used to perform input/output operations to a specified 
  2823.      local port. 
  2824.  
  2825.  
  2826. Parameters 
  2827.      Pointer to a PORT_IO structure. 
  2828.  
  2829.  
  2830. Exit 
  2831.      Return code. 
  2832.  
  2833.  
  2834. Structures 
  2835.  
  2836.           typedef struct port_io_s
  2837.           {
  2838.              ulong_t port;   (Input)
  2839.              ulong_t data;   (Input/Output)
  2840.              ulong_t flags;  (Input)
  2841.           } PORT_IO;
  2842.  
  2843.    port    indicates which port to read to, or write from. 
  2844.    data    contains the data read from a read request, or the data to write if 
  2845.            a write request. 
  2846.    flags   indicate what operation to perform. 
  2847.  
  2848.       IO_READ_BYTE        Read a byte from the port 
  2849.       IO_READ_WORD        Read a word from the port 
  2850.       IO_READ_DWORD       Read a dword from the port 
  2851.       IO_WRITE_BYTE       Write a byte to the port 
  2852.       IO_WRITE_WORD       Write a word to the port 
  2853.       IO_WRITE_DWORD      Write a dword to the port 
  2854.  
  2855.  
  2856. Assembly language 
  2857.  
  2858.            ;       dh_Port_IO - Perform I/O to a specified port
  2859.            ;
  2860.            ;       This devhlp is called by device drivers to do
  2861.            ;       I/O to a specified local port.
  2862.            ;
  2863.            ;       ENTRY:  ES:DI = pointer to port_io structure
  2864.            ;
  2865.            ;       EXIT:   port_io.data filled in if I/O read
  2866.            ;
  2867.            ;       USES:   EAX, Flags
  2868.            ;
  2869.  
  2870.            port_io_s         STRUC
  2871.            port_io_port        DD   ?
  2872.            port_io_data        DD   ?
  2873.            port_io_flags       DD   ?
  2874.            port_io_s         ENDS
  2875.  
  2876.            IO_READ_BYTE      EQU  0000H
  2877.            IO_READ_WORD      EQU  0001H
  2878.            IO_READ_DWORD     EQU  0002H
  2879.            IO_WRITE_BYTE     EQU  0003H
  2880.            IO_WRITE_WORD     EQU  0004H
  2881.            IO_WRITE_DWORD    EQU  0005H
  2882.            IO_FLAGMASK       EQU  0007H
  2883.  
  2884.            MOV     PORT_IO.port_io_port,21h
  2885.            MOV     PORT_IO.port_io_data,08h
  2886.            MOV     PORT_IO.port_io_flags,IO_WRITE_BYTE
  2887.  
  2888.            LES     SI,PORT_IO
  2889.            MOV     DL,dh_Port_IO
  2890.            CALL    DevHlp
  2891.            JC      Error
  2892.  
  2893.            ;       EXIT:   port_io_struc.data filled in if I/O read
  2894.  
  2895.  
  2896. Notes 
  2897.      None. 
  2898.  
  2899.  
  2900. ΓòÉΓòÉΓòÉ 8.1.6. DevHlp_SetIRQMask ΓòÉΓòÉΓòÉ
  2901.  
  2902. Description 
  2903.      Enable/disable interrupt. 
  2904.  
  2905.      This function enables and/or disables interrupts for a specific IRQ. 
  2906.  
  2907.  
  2908. Parameters 
  2909.      Specified IRQ level. 
  2910.      Enable/disable flag. 
  2911.  
  2912.  
  2913. Exit 
  2914.      Return code. 
  2915.  
  2916.  
  2917. Assembly language 
  2918.  
  2919.            ;       dh_SetIRQMask - Masks/Unmasks a specified IRQ masks
  2920.            ;
  2921.            ;       This function enables/disables interrupts for a specific IRQ.
  2922.            ;
  2923.            ;       ENTRY   AL = IRQ to be enabled/disabled
  2924.            ;               AH =  0  enable IRQ (disable mask)
  2925.            ;                     1  disable IRQ (enable mask)
  2926.            ;
  2927.            ;       EXIT-SUCCESS
  2928.            ;           none
  2929.            ;
  2930.            ;       EXIT-FAILURE
  2931.            ;           NONE
  2932.            ;
  2933.  
  2934.              MOV     AL,IRQ to enable/disabled
  2935.              MOV     AH,mask operation (0=enabled,1=disabled)
  2936.              MOV     DL,DevHlp_SetIRQMask
  2937.              CALL    DevHlp
  2938.              JC      Error
  2939.  
  2940.  
  2941. ΓòÉΓòÉΓòÉ 8.1.7. DevHlp_GetIRQMask ΓòÉΓòÉΓòÉ
  2942.  
  2943. Description 
  2944.      Retrieve the mask state of an IRQ level. 
  2945.  
  2946.      This function reads the current IRQ mask state for the specified IRQ. 
  2947.  
  2948.  
  2949. Parameters 
  2950.      Specified IRQ level. 
  2951.  
  2952.  
  2953. Exit 
  2954.      EAX=0, mask disabled (IRQ enabled). 
  2955.      EAX=1, mask enabled  (IRQ disabled) 
  2956.  
  2957.  
  2958. Assembly language 
  2959.  
  2960.            ;       dh_GetIRQMask - Retrieve a specified IRQ mask state
  2961.            ;
  2962.            ;       This function reads the current IRQ mask state for the specified IRQ.
  2963.            ;
  2964.            ;       ENTRY   AL = IRQ
  2965.            ;
  2966.            ;       EXIT-SUCCESS
  2967.            ;           EAX - 0 = mask disabled (IRQ enabled)
  2968.            ;               - 1 = mask enabled (IRQ disabled)
  2969.            ;
  2970.            ;       EXIT-FAILURE
  2971.            ;           NONE
  2972.            ;
  2973.  
  2974.              MOV     AL,IRQ whose mask state is to be retrieved
  2975.              MOV     DL,DevHlp_GetIRQMask
  2976.              CALL    DevHlp
  2977.              JC      Error
  2978.  
  2979.  
  2980. ΓòÉΓòÉΓòÉ 8.2. Virtual Device Driver Helps ΓòÉΓòÉΓòÉ
  2981.  
  2982. The OS/2 kernel will provide new VDH services for VDDs to communicate with 
  2983. PSDs. 
  2984.  
  2985.  
  2986. ΓòÉΓòÉΓòÉ 8.2.1. VDHPortIO ΓòÉΓòÉΓòÉ
  2987.  
  2988. Description 
  2989.      Perform IO to a specified port. 
  2990.  
  2991.      This function is used to perform input/output operations to a specified 
  2992.      local port. 
  2993.  
  2994.  
  2995. Parameters 
  2996.      Pointer to a PORT_IO structure. 
  2997.  
  2998.  
  2999. Exit 
  3000.      Return code. 
  3001.  
  3002.  
  3003. Structures 
  3004.  
  3005.           typedef struct port_io_s
  3006.           {
  3007.              ulong_t port;   (Input)
  3008.              ulong_t data;   (Input/Output)
  3009.              ulong_t flags;  (Input)
  3010.           } PORT_IO;
  3011.  
  3012.    port    indicates which port to read to, or write from. 
  3013.    data    contains the data read from a read request, or the data to write if 
  3014.            a write request. 
  3015.    flags   indicate what operation to perform. 
  3016.  
  3017.       IO_READ_BYTE        Read a byte from the port 
  3018.       IO_READ_WORD        Read a word from the port 
  3019.       IO_READ_DWORD       Read a dword from the port 
  3020.       IO_WRITE_BYTE       Write a byte to the port 
  3021.       IO_WRITE_WORD       Write a word to the port 
  3022.       IO_WRITE_DWORD      Write a dword to the port 
  3023.  
  3024.  
  3025. Notes 
  3026.      None. 
  3027.  
  3028.  
  3029. ΓòÉΓòÉΓòÉ 9. New Kernel Debugger Commands ΓòÉΓòÉΓòÉ
  3030.  
  3031. The Kernel debugger architecture is such that only one thread can be in the 
  3032. debugger at any given time, so it uses a spinlock to serialize its access. 
  3033.  
  3034. If entered, the debugger must inform the user as to the state of all the 
  3035. processors, even though the other processors are still executing code. It 
  3036. accomplishes this by sending a spin command using and IPI (interprocessor 
  3037. interrupt) to all the other processors. When a processor receives a spin 
  3038. command sent by the kernel debugger, it saves its current state (all of its 
  3039. registers), acknowledges the spin command, and spins until released. This 
  3040. allows the user to switch to a slot which is currently executing on another 
  3041. processor and determines what it is doing. 
  3042.  
  3043. All kernel debugger commands work as before, but a few have been modified to 
  3044. display or use MP specific information, and new MP specific commands have been 
  3045. added. 
  3046.  
  3047. A list of new and changed commands follows: 
  3048.  
  3049. o A .DP (processor status) command has been added. This command dumps out a 
  3050.   processor control block verbosely.  As an argument it takes a * (real current 
  3051.   slot), a # (currently selected slot), and a 1 based processor number (e.g. 
  3052.   .DP 3 displays the processor status for processor 3), or a blank (e.g. .DP ) 
  3053.   which displays the processor status for all the processors. 
  3054.  
  3055. o A .DL (display processor spinlocks) command has been added. This command 
  3056.   displays all the spinlocks owned by a particular processor. As an argument it 
  3057.   takes a * (real current slot), a # (currently selected slot), a 1 based 
  3058.   processor number (e.g. .DL 3 displays all the spinlocks owned by processor 
  3059.   3), an address of a spinlock, or a blank which displays all the spinlocks 
  3060.   owned by all the processors. 
  3061.  
  3062. o The .R and the R (register commands) have been modified to indicate which 
  3063.   processor the currently selected slot is running on. A p=xxyy (xx = processor 
  3064.   number, yy = flags) has been added to the end of the third register line. 
  3065.   These processor numbers are 1- based (e.g. p=00 means that the currently 
  3066.   selected slot is not running on any processor or is blocked, p=01 means the 
  3067.   currently selected slot is running on processor 1). The flags are: 
  3068.  
  3069.    s   processor is currently spinning. 
  3070.    r   processor is attempting to grab the ring 0 suspend lock. 
  3071.  
  3072. o The .SS (change current slot) has been modified to change which PSA (process 
  3073.   or save area) you are currently looking at (e.g. when you change to a slot 
  3074.   which is currently running on a different processor and dump a variable in 
  3075.   the PSA, it will display the value of that variable on that particular 
  3076.   processor).  The .S command is now identical to the .SS command. The PLMA is 
  3077.   displayed properly for each processor. 
  3078.  
  3079.  
  3080. ΓòÉΓòÉΓòÉ 10. The Single Processor Utility Program ΓòÉΓòÉΓòÉ
  3081.  
  3082. As explained previously, some applications written for uniprocessor OS/2 may 
  3083. experience problems running under OS/2 for SMP V2.11 because they rely upon 
  3084. priorities between threads for accessing shared resources, or use the CLI/STI 
  3085. method for protecting resources like semaphores or memory. These types of 
  3086. application are called MP-safe. These programs will still run fine under OS/2 
  3087. for SMP V2.11 if they are run in a uniprocessor mode. 
  3088.  
  3089. The EXECMODE program is a utility which marks the executable (EXE) file to be 
  3090. run in a uniprocessor mode. The OS/2 loader detects this bit set and forces the 
  3091. application to run on a single processor. The EXECMODE utility can be used to 
  3092. set and reset the uniprocessor mode in an executable file, as well as list 
  3093. those programs that are marked as MP or SP. 
  3094.  
  3095. The syntax for the EXECMODE utility program is as follows: 
  3096.  
  3097.  
  3098.  execmode (options)[d:[\[path\]]]filenam1.ext( options) [filenam2.ext]...
  3099.  
  3100. The EXECMODE program accepts several command line options. Each option must be 
  3101. preceeded by a "/" or a "-". 
  3102.  
  3103. sp        Set file in single processor mode (default) 
  3104. mp        Set file for multiprocessor mode 
  3105. l         List files matching sp or mp 
  3106. s         Enable subdirectory searching 
  3107. f         Force changes on read-only files 
  3108. v         Set verbose mode on 
  3109. q         Set for quiet mode 
  3110. d         Display debug messages 
  3111. t         Set test mode (no disk writes) 
  3112.  
  3113. Up to 50 arguments, in any order, can be specified on the command line. 
  3114. Wildcards are permitted in filenames. 
  3115.  
  3116.  
  3117. ΓòÉΓòÉΓòÉ 11. OS/2 for SMP V2.11 Tools ΓòÉΓòÉΓòÉ
  3118.  
  3119. A Multiprocessor CPU Performance Monitor will be shipped with this product. 
  3120. This tool will display CPU utilization for each processor in bar graph and 
  3121. histogram modes. It will be written as a PM application and will display each 
  3122. processor's bar or line as a different color. This tool will also have the 
  3123. capability of placing each processor offline or online. This is useful to show 
  3124. the scalability of OS/2 for SMP V2.11. It may also be used for debug purposes. 
  3125. This tool will use the APIs described above. It is also desirable to be able to 
  3126. display the time spent waiting inside of the major spinlocks, such as the Ring 
  3127. 0 spinlock. It is also desirable to display the interrupt activity for each 
  3128. processor. 
  3129.  
  3130.  
  3131.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3132.     Γöé  OS/2 Symmetric MultiProcessor Performance Monitor   Γöé
  3133.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3134.     Γöé  Bar  Histogram  Interrupt  Status  Options  Help   Γöé
  3135.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3136.     Γöé                             Γöé
  3137.     Γöé                             Γöé
  3138.     Γöé  ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ  Γöé
  3139.     Γöé100Γöé                         Γöé  Γöé
  3140.     Γöé  Γöé                         Γöé  Γöé
  3141.     Γöé  Γöé                         Γöé  Γöé
  3142.     Γöé 90Γöé                         Γöé  Γöé
  3143.     Γöé  Γöé                         Γöé  Γöé
  3144.     Γöé  Γöé                         Γöé  Γöé
  3145.     Γöé 80Γöé                         Γöé  Γöé
  3146.     Γöé  Γöé                         Γöé  Γöé
  3147.     Γöé  Γöé                         Γöé  Γöé
  3148.     Γöé 70Γöé                         Γöé  Γöé
  3149.     Γöé  Γöé                         Γöé  Γöé
  3150.     Γöé  Γöé      ΓöîΓöÇΓöÇΓöÉ                  Γöé  Γöé
  3151.     Γöé 60Γöé      Γöé  Γöé       ΓöîΓöÇΓöÇΓöÉ          Γöé  Γöé
  3152.     Γöé  Γöé      Γöé  Γöé       Γöé  Γöé       ΓöîΓöÇΓöÇΓöÉ  Γöé  Γöé
  3153.     Γöé  Γöé      Γöé  Γöé       Γöé  Γöé   ΓöîΓöÇΓöÇΓöÉ   Γöé  Γöé  Γöé  Γöé
  3154.     Γöé 50Γöé  ΓöîΓöÇΓöÇΓöÉ   Γöé  Γöé       Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3155.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   ΓöîΓöÇΓöÇΓöÉ   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3156.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3157.     Γöé 40Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3158.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3159.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3160.     Γöé 30Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3161.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3162.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3163.     Γöé 20Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3164.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3165.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3166.     Γöé 10Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3167.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3168.     Γöé  Γöé  Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé  Γöé  Γöé
  3169.     Γöé  0ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ  Γöé
  3170.     Γöé %                            Γöé
  3171.     Γöé CPU  1    2    3    4    5    6     Γöé
  3172.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3173.  
  3174.  
  3175.         Figure 1.    CPU Monitor in BAR mode
  3176.  
  3177.         Monitors % of each processor used per second.
  3178.  
  3179.         NOTE: Each CPU to be a different color.
  3180.  
  3181.  
  3182.  
  3183.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3184.     Γöé  OS/2 Symmetric MultiProcessor Performance Monitor   Γöé
  3185.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3186.     Γöé  Bar  Histogram  Interrupt  Status  Options  Help   Γöé
  3187.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3188.     Γöé                             Γöé
  3189.     Γöé                             Γöé
  3190.     Γöé  ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ  Γöé
  3191.     Γöé100Γöé                         Γöé  Γöé
  3192.     Γöé  Γöé                         Γöé  Γöé
  3193.     Γöé  Γöé                         Γöé  Γöé
  3194.     Γöé 90Γöé                         Γöé  Γöé
  3195.     Γöé  Γöé                         Γöé  Γöé
  3196.     Γöé  Γöé                         Γöé  Γöé
  3197.     Γöé 80Γöé                         Γöé  Γöé
  3198.     Γöé  Γöé                         Γöé  Γöé
  3199.     Γöé  Γöé                         Γöé  Γöé
  3200.     Γöé 70Γöé                         Γöé  Γöé
  3201.     Γöé  Γöé                         Γöé  Γöé
  3202.     Γöé  Γöé                         Γöé  Γöé
  3203.     Γöé 60Γöé                         Γöé  Γöé
  3204.     Γöé  Γöé                         Γöé  Γöé
  3205.     Γöé  Γöé                         Γöé  Γöé
  3206.     Γöé 50Γöé                 ******     Γöé  Γöé
  3207.     Γöé  Γöé        *  ***      *    *     Γöé  Γöé
  3208.     Γöé  Γöé      **** **  ***    *     *    Γöé  Γöé
  3209.     Γöé 40Γöé  ***   *       *  * *      ****  Γöé  Γöé
  3210.     Γöé  Γöé**  *  *        * * *        *  Γöé  Γöé
  3211.     Γöé  Γöé    ***         *          **Γöé  Γöé
  3212.     Γöé 30Γöéx    -                   x Γöé  Γöé
  3213.     Γöé  Γöé x  ---- -xxx              xxx xxx xΓöé  Γöé
  3214.     Γöé  Γöé  x-  xxxx-  xx  -   xxxx  -     x  x  ---Γöé  Γöé
  3215.     Γöé 20Γöé  -x x   ----x- ---x   x- - ------x    -  Γöé  Γöé
  3216.     Γöé  Γöé--  x      -x  x---  -x  -  xxxx---  -   Γöé  Γöé
  3217.     Γöé  Γöé         xxx   --  xxxxx    - -   Γöé  Γöé
  3218.     Γöé 10Γöé                     -    Γöé  Γöé
  3219.     Γöé  Γöé                         Γöé  Γöé
  3220.     Γöé  Γöé                         Γöé  Γöé
  3221.     Γöé  0ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ  Γöé
  3222.     Γöé%/                            Γöé
  3223.     Γöé/Time  1    2    3    4    5    6     Γöé
  3224.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3225.  
  3226.  
  3227.         Figure 2.    CPU Monitor in HISTOGRAM mode
  3228.  
  3229.         Monitors % of each processor used over time.
  3230.  
  3231.         NOTE: Each CPU to be a different color.
  3232.  
  3233.  
  3234.  
  3235.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3236.     Γöé  OS/2 Symmetric MultiProcessor Performance Monitor   Γöé
  3237.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3238.     Γöé  Bar  Histogram  Interrupt  Status  Options  Help   Γöé
  3239.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3240.     Γöé                             Γöé
  3241.     Γöé                             Γöé
  3242.     Γöé   ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ  Γöé
  3243.     Γöé5000Γöé                        Γöé  Γöé
  3244.     Γöé   Γöé                        Γöé  Γöé
  3245.     Γöé   Γöé                        Γöé  Γöé
  3246.     Γöé4500Γöé                        Γöé  Γöé
  3247.     Γöé   Γöé                        Γöé  Γöé
  3248.     Γöé   Γöé                        Γöé  Γöé
  3249.     Γöé4000Γöé                        Γöé  Γöé
  3250.     Γöé   Γöé                        Γöé  Γöé
  3251.     Γöé   Γöé                        Γöé  Γöé
  3252.     Γöé3500Γöé                        Γöé  Γöé
  3253.     Γöé   Γöé                        Γöé  Γöé
  3254.     Γöé   Γöé             ΓöîΓöÇΓöÇΓöÉ          Γöé  Γöé
  3255.     Γöé3000Γöé             Γöé  Γöé          Γöé  Γöé
  3256.     Γöé   Γöé             Γöé  Γöé          Γöé  Γöé
  3257.     Γöé   Γöé     ΓöîΓöÇΓöÇΓöÉ       Γöé  Γöé          Γöé  Γöé
  3258.     Γöé2500Γöé     Γöé  Γöé       Γöé  Γöé          Γöé  Γöé
  3259.     Γöé   Γöé     Γöé  Γöé   ΓöîΓöÇΓöÇΓöÉ   Γöé  Γöé          Γöé  Γöé
  3260.     Γöé   Γöé     Γöé  Γöé   Γöé  Γöé   Γöé  Γöé          Γöé  Γöé
  3261.     Γöé2000Γöé ΓöîΓöÇΓöÇΓöÉ   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé          Γöé  Γöé
  3262.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé          Γöé  Γöé
  3263.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   ΓöîΓöÇΓöÇΓöÉ      Γöé  Γöé
  3264.     Γöé1500Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3265.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3266.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3267.     Γöé1000Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3268.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3269.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3270.     Γöé 500Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3271.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3272.     Γöé   Γöé Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé   Γöé  Γöé      Γöé  Γöé
  3273.     Γöé  0ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ  Γöé
  3274.     Γöé#/                            Γöé
  3275.     Γöé/Time  1    2    3    4    5    6     Γöé
  3276.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3277.  
  3278.  
  3279.         Figure 3.    CPU Monitor in INTERRUPT mode
  3280.  
  3281.         Monitors # of interrupts per second.
  3282.  
  3283.         NOTE: Each CPU to be a different color.
  3284.  
  3285.  
  3286.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3287.     Γöé    Processor ONLINE/OFFLINE STATUS Selection     Γöé
  3288.     Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3289.     Γöé                             Γöé
  3290.     Γöé                             Γöé
  3291.     Γöé                             Γöé
  3292.     Γöé    Please select/change the status of the      Γöé
  3293.     Γöé    desired processor(s).               Γöé
  3294.     Γöé                             Γöé
  3295.     Γöé    A Y means the processor is online         Γöé
  3296.     Γöé    A N means the processor is offline        Γöé
  3297.     Γöé                             Γöé
  3298.     Γöé    Selection toggles the Y/N             Γöé
  3299.     Γöé                             Γöé
  3300.     Γöé    CPU           ONLINE           Γöé
  3301.     Γöé                n X            Γöé
  3302.     Γöé     1           ΓöéYΓöé            Γöé
  3303.     Γöé                Γöé Γöé            Γöé
  3304.     Γöé     2           ΓöéYΓöé            Γöé
  3305.     Γöé                Γöé Γöé            Γöé
  3306.     Γöé     3           ΓöéNΓöé            Γöé
  3307.     Γöé                Γöé Γöé            Γöé
  3308.     Γöé     4           ΓöéYΓöé            Γöé
  3309.     Γöé                Γöé Γöé            Γöé
  3310.     Γöé     5           ΓöéYΓöé            Γöé
  3311.     Γöé                Γöé Γöé            Γöé
  3312.     Γöé     6           ΓöéNΓöé            Γöé
  3313.     Γöé                Γöé-Γöé            Γöé
  3314.     Γöé     7           ΓöéNΓöé            Γöé
  3315.     Γöé                Γöé Γöé            Γöé
  3316.     Γöé     8           ΓöéYΓöé            Γöé
  3317.     Γöé                Γöé Γöé            Γöé
  3318.     Γöé                             Γöé
  3319.     Γöé                             Γöé
  3320.     Γöé                             Γöé
  3321.     Γöé     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ    ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ    ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ       Γöé
  3322.     Γöé     Γöé  OK  Γöé    ΓöéCANCELΓöé    Γöé HELP Γöé       Γöé
  3323.     Γöé     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ    ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ    ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ       Γöé
  3324.     Γöé                             Γöé
  3325.     Γöé                             Γöé
  3326.     Γöé                             Γöé
  3327.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3328.  
  3329.  
  3330.         Figure 4.    CPU Monitor STATUS dialog box
  3331.  
  3332.  
  3333.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3334.     Γöé                             Γöé
  3335.     Γöé    Background color           -> (fig. 5b) Γöé
  3336.     Γöé    CPU graph color           -> (fig. 5a) Γöé
  3337.     Γöé    Freeze screen          Alt+F       Γöé
  3338.     Γöé    Fill               Alt+I       Γöé
  3339.     Γöé                             Γöé
  3340.     Γöé                             Γöé
  3341.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3342.  
  3343.         Figure 5.    CPU Monitor OPTIONS dialog box
  3344.  
  3345.  
  3346.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3347.     Γöé                             Γöé
  3348.     Γöé    CPU 1                       Γöé
  3349.     Γöé    CPU 2                       Γöé
  3350.     Γöé    CPU 3                       Γöé
  3351.     Γöé    CPU 4                       Γöé
  3352.     Γöé    CPU 5                       Γöé
  3353.     Γöé    CPU 6                       Γöé
  3354.     Γöé    CPU 7                       Γöé
  3355.     Γöé    CPU 8                       Γöé
  3356.     Γöé                             Γöé
  3357.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3358.  
  3359.  
  3360.         Figure 5a.    CPU Monitor GRAPH Color CPU selection
  3361.  
  3362.         NOTE: After selecting CPU, prompt for color
  3363.            selection (fig 5b).
  3364.  
  3365.  
  3366.     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3367.     Γöé                             Γöé
  3368.     Γöé                             Γöé
  3369.     Γöé    WHITE                       Γöé
  3370.     Γöé    BLACK                       Γöé
  3371.     Γöé    BLUE                       Γöé
  3372.     Γöé    RED                        Γöé
  3373.     Γöé    PINK                       Γöé
  3374.     Γöé    GREEN                       Γöé
  3375.     Γöé    CYAN                       Γöé
  3376.     Γöé    YELLOW                      Γöé
  3377.     Γöé    DARK GRAY                     Γöé
  3378.     Γöé    DARK BLUE                     Γöé
  3379.     Γöé    DARK RED                     Γöé
  3380.     Γöé    DARK PINK                     Γöé
  3381.     Γöé    DARK GREEN                    Γöé
  3382.     Γöé    DARK CYAN                     Γöé
  3383.     Γöé    BROWN                       Γöé
  3384.     Γöé    PALE GRAY                     Γöé
  3385.     Γöé                             Γöé
  3386.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3387.  
  3388.  
  3389.         Figure 5b.    CPU Monitor Color selection
  3390.  
  3391.  
  3392. ΓòÉΓòÉΓòÉ 12. Appendix A ΓòÉΓòÉΓòÉ
  3393.  
  3394. The following is the source code for an actual PSD. 
  3395.  
  3396.  
  3397. ΓòÉΓòÉΓòÉ 12.1. Main program ΓòÉΓòÉΓòÉ
  3398.  
  3399.  
  3400. #define INCL_ERROR_H
  3401.  
  3402. #include <os2.h>
  3403. #include <psd.h>
  3404. #include <alr.h>
  3405.  
  3406.  
  3407. extern ulong_t RMP2Available(void);
  3408.  
  3409.  
  3410. /*
  3411.  *  Global Variables
  3412.  */
  3413.  
  3414. P_F_2   router = 0;
  3415. char   *pParmString = 0;
  3416. int     IODelayCount = 30;
  3417. PLMA   *pPSDPLMA = 0;
  3418. ulong_t sizePLMA = 0;
  3419.  
  3420.  
  3421. /***  Disable - Disable interrupts
  3422.  *
  3423.  *    This function disables interrupts, and returns
  3424.  *    the original state of eflags
  3425.  *
  3426.  *    ENTRY   None
  3427.  *
  3428.  *    EXIT    EFLAGS
  3429.  *
  3430.  */
  3431.  
  3432. ulong_t Disable(void) {
  3433.  
  3434.    ulong_t eflags;
  3435.  
  3436.    _asm {
  3437.       pushfd
  3438.       pop   eax
  3439.       mov   eflags,eax
  3440.       cli
  3441.    };
  3442.  
  3443.    return (eflags);
  3444. }
  3445.  
  3446.  
  3447. /***  Enable - Restore the state of eflags
  3448.  *
  3449.  *    This function restores the state of eflags
  3450.  *
  3451.  *    ENTRY   eflags - state of eflags to restore
  3452.  *
  3453.  *    EXIT    None
  3454.  *
  3455.  */
  3456.  
  3457. void Enable(ulong_t eflags) {
  3458.  
  3459.    _asm {
  3460.       push  eflags
  3461.       popfd
  3462.    };
  3463.  
  3464.    return;
  3465. }
  3466.  
  3467.  
  3468.  /***  InByte - Read a byte from a port
  3469.   *
  3470.   *    This function reads a byte from a specified port
  3471.   *
  3472.   *    ENTRY   port - port number to read from
  3473.   *
  3474.   *    EXIT    data read
  3475.   *
  3476.   */
  3477.  
  3478.  ulong_t InByte(ulong_t port) {
  3479.  
  3480.     ulong_t data;
  3481.  
  3482.     _asm {
  3483.        mov   dx,port
  3484.        in    al,dx
  3485.        movzx eax,al
  3486.        mov   data,eax
  3487.     };
  3488.  
  3489.     return (data);
  3490. }
  3491.  
  3492.  
  3493. /***  OutByte - Writes a byte to a port
  3494.  *
  3495.  *    This function writes a byte to a specified port
  3496.  *
  3497.  *    ENTRY   port - port number to read from
  3498.  *            data - data to write
  3499.  *
  3500.  *    EXIT    None
  3501.  *
  3502.  */
  3503.  
  3504. void OutByte(ulong_t port, ulong_t data) {
  3505.  
  3506.    _asm {
  3507.       mov   dx,port
  3508.       mov   al,byte ptr data
  3509.       out   dx,al
  3510.    };
  3511.  
  3512.    return;
  3513. }
  3514.  
  3515.  
  3516. /***  SendEOI - Send an end of interrupt
  3517.  *
  3518.  *    This function sends an end of interrupt.
  3519.  *
  3520.  *    ENTRY   irq - irq level to end
  3521.  *
  3522.  *    EXIT    None
  3523.  *
  3524.  */
  3525.  
  3526. ulong_t SendEOI(ulong_t irq) {
  3527.  
  3528.    ulong_t flags;
  3529.  
  3530.    flags = Disable();
  3531.  
  3532.    if (irq < NUM_IRQ_PER_PIC)
  3533.       OutByte(PIC1_PORT0, OCW2_NON_SPECIFIC_EOI);
  3534.    else {
  3535.       OutByte(PIC2_PORT0, OCW2_NON_SPECIFIC_EOI);
  3536.       IODelay;
  3537.       OutByte(PIC1_PORT0, OCW2_NON_SPECIFIC_EOI);
  3538.    }
  3539.  
  3540.    Enable(flags);
  3541. }
  3542.  
  3543.  
  3544. /***  WHO_AM_I - Returns the current processor number
  3545.  *
  3546.  *    This function returns the current processor number
  3547.  *
  3548.  *    ENTRY   NONE
  3549.  *
  3550.  *    EXIT    Current processor number (P1 or P2)
  3551.  *
  3552.  */
  3553.  
  3554. ulong_t WHO_AM_I (void) {
  3555.    return(InByte(WHO_AM_I_PORT));
  3556. }
  3557.  
  3558.  
  3559. /***  IPIPresent - Detects the presence of an IPI
  3560.  *
  3561.  *    This function detects the presence of an IPI on the current
  3562.  *    processor
  3563.  *
  3564.  *    ENTRY   None
  3565.  *
  3566.  *    EXIT    NO_ERROR - IPI present
  3567.  *            -1       - IPI not present
  3568.  *
  3569.  */
  3570.  
  3571. ulong_t IPIPresent (void) {
  3572.  
  3573.    ulong_t rc = 0;
  3574.    struct control_s ctrl;
  3575.    ulong_t port;
  3576.  
  3577.    port = pPSDPLMA->controlport;
  3578.  
  3579.    ctrl.b_all = InByte(port);
  3580.    if (ctrl.b_387err)
  3581.    {
  3582.       OutByte (0xf0, 0); // The busy latch for NPX must be cleared.
  3583.                          // When we call the interrupt handler
  3584.                          // (w/ Call16bitDD int.asm), ints. are 1st enabled.
  3585.                          // If the busy latch is not cleared, then we
  3586.                          // will take this interrupt in again and will
  3587.                          // eventually nest until the interrupt stack is
  3588.                          // overrun.
  3589.       rc = -1;
  3590.    }
  3591.    return (rc);
  3592. }
  3593.  
  3594.  
  3595. /***  Install - Install PSD
  3596.  *
  3597.  *    This function checks to see if this PSD is installable on the
  3598.  *    current platform.
  3599.  *
  3600.  *    ENTRY   pinstall - pointer to an INSTALL structure
  3601.  *
  3602.  *    EXIT    NO_ERROR - PSD Installed
  3603.  *            -1       - PSD not valid for this platform
  3604.  *
  3605.  */
  3606.  
  3607. ulong_t Install(INSTALL *pinstall) {
  3608.  
  3609.    VMALLOC vmac;
  3610.    int i;
  3611.    char *p;
  3612.    ulong_t rc = 0;
  3613.    char ALR_String =  "PROVEISA";
  3614.  
  3615. // _asm int 3;
  3616.  
  3617.    /* Setup Global variables */
  3618.  
  3619.    router = pinstall->pPSDHlpRouter;
  3620.    pParmString = pinstall->pParmString;
  3621.    pPSDPLMA = (void *)pinstall->pPSDPLMA;
  3622.    sizePLMA = pinstall->sizePLMA;
  3623.  
  3624.    vmac.addr = BIOS_SEG << 4;
  3625.    vmac.cbsize = _64K;
  3626.    vmac.flags = VMALLOC_PHYS;
  3627.  
  3628.    /* Map BIOS area */
  3629.  
  3630.    if ((rc = PSDHelp(router, PSDHLP_VMALLOC, &vmac)) == NO_ERROR) {
  3631.  
  3632.       /* Check for ALR string */
  3633.  
  3634.       p = (char *)vmac.addr + ALR_STRING_OFFSET;
  3635.  
  3636.       for (i = 0; ALR_String i != '\0'; i++)
  3637.          if (p i  != ALR_String i) {
  3638.             rc = -1;
  3639.             break;
  3640.          }
  3641.  
  3642.       /* Free BIOS mapping */
  3643.  
  3644.       PSDHelp(router, PSDHLP_VMFREE, vmac.addr);
  3645.    }
  3646.  
  3647.    return (rc);
  3648. }
  3649.  
  3650.  
  3651. /***  DeInstall - DeInstall PSD
  3652.  *
  3653.  *    This function deinstalls the PSD.
  3654.  *
  3655.  *    ENTRY   None
  3656.  *
  3657.  *    EXIT    NO_ERROR
  3658.  *
  3659.  */
  3660.  
  3661. ulong_t DeInstall(void) {
  3662.  
  3663.    return (NO_ERROR);
  3664. }
  3665.  
  3666.  
  3667. /***  Init - Initialize the PSD
  3668.  *
  3669.  *    This function initializes the PSD.
  3670.  *
  3671.  *    ENTRY   None
  3672.  *
  3673.  *    EXIT    NO_ERROR - PSD initialized
  3674.  *            -1       - PSD not initialized
  3675.  *
  3676.  */
  3677.  
  3678. ulong_t Init(INIT *pinit) {
  3679.  
  3680.    struct control_s ctrl;
  3681.    SET_IRQ set_irq;
  3682.  
  3683.  
  3684.    /* Initialize P1 control port */
  3685.  
  3686.    ctrl.b_all = 0;
  3687.    ctrl.b_cacheon = 1;
  3688.  
  3689.  
  3690.    OutByte(P1_PROCESSOR_CONTROL_PORT, ctrl.b_all);
  3691.  
  3692.    /* Setup P2 interrupt vector */
  3693.  
  3694.    OutByte(P2_INTERRUPT_VECTOR_CONTROL_PORT, IPI_VECTOR);
  3695.  
  3696.    /* Setup IPI info */
  3697.  
  3698.    set_irq.irq = 13;
  3699.    set_irq.flags = IRQf_IPI;
  3700.    set_irq.vector = 0;
  3701.    set_irq.handler = (P_F_2)IPIPresent;
  3702.  
  3703.    PSDHelp(router, PSDHLP_SET_IRQ, &set_irq);
  3704.  
  3705.    /* Fill init structure */
  3706.  
  3707.    pinit->flags = INIT_EOI_IRQ13_ON_CPU0;           //76422
  3708.    pinit->version = VERSION;
  3709.  
  3710.    return (NO_ERROR);
  3711. }
  3712.  
  3713.  
  3714. /***  ProcInit - Processor initialization
  3715.  *
  3716.  *    This function initializes per processor items.
  3717.  *
  3718.  *    NOTE: This function is called once on each processor
  3719.  *          in the system.
  3720.  *
  3721.  *    ENTRY   None
  3722.  *
  3723.  *    EXIT    NO_ERROR - Processor initialized
  3724.  *            -1       - Processor not initialized
  3725.  *
  3726.  */
  3727.  
  3728. ulong_t ProcInit(void) {
  3729.  
  3730.    if (WHO_AM_I() == P1) {
  3731.       pPSDPLMA->procnum = 0;
  3732.       pPSDPLMA->controlport = P1_PROCESSOR_CONTROL_PORT;
  3733.    }
  3734.    else {
  3735.       pPSDPLMA->procnum = 1;
  3736.       pPSDPLMA->controlport = P2_PROCESSOR_CONTROL_PORT;
  3737.    }
  3738.  
  3739.    return (NO_ERROR);
  3740. }
  3741.  
  3742.  
  3743. /***  StartProcessor - Start a processor
  3744.  *
  3745.  *    This function starts a processor.
  3746.  *
  3747.  *    ENTRY   procnum - processor number to start (0-based)
  3748.  *
  3749.  *    EXIT    Return Code
  3750.  *
  3751.  */
  3752.  
  3753. ulong_t StartProcessor(ulong_t procnum) {
  3754.  
  3755.    CALL_REAL_MODE rm;
  3756.    struct control_s ctrl;
  3757.    ulong_t rc = -1;
  3758.  
  3759.  
  3760.    if (procnum == 1) {
  3761.  
  3762.       rm.function = (ulong_t)&RMP2Available;
  3763.       rm.pdata = 0;
  3764.  
  3765.       rc = PSDHelp(router, PSDHLP_CALL_REAL_MODE, &rm);
  3766.  
  3767.       if (rc & P2_AVAILABLE) {
  3768.  
  3769.          /* Dispatch P2 */
  3770.  
  3771.          ctrl.b_all = 0;
  3772.          ctrl.b_cacheon = 1;
  3773.  
  3774.          OutByte(P2_PROCESSOR_CONTROL_PORT, ctrl.b_all);
  3775.          rc = NO_ERROR;
  3776.       }
  3777.       else
  3778.          rc = -1;
  3779.    }
  3780.  
  3781.    return (rc);
  3782. }
  3783.  
  3784.  
  3785. /***  GetNumOfProcs - Get number of processors
  3786.  *
  3787.  *    This function gets the number of processors which exist on this
  3788.  *    platform.
  3789.  *
  3790.  *    ENTRY   None
  3791.  *
  3792.  *    EXIT    Number of processors
  3793.  *
  3794.  */
  3795.  
  3796. ulong_t GetNumOfProcs(void) {
  3797.  
  3798.    ulong_t cprocs = 2;
  3799.  
  3800.    return (cprocs);
  3801. }
  3802.  
  3803.  
  3804. /***  GenIPI - Generate an inter-processor interrupt
  3805.  *
  3806.  *    This function generates an IPI.
  3807.  *
  3808.  *    ENTRY   procnum - processor number to interrupt (0-based)
  3809.  *
  3810.  *    EXIT    NO_ERROR
  3811.  *
  3812.  */
  3813.  
  3814. ulong_t GenIPI(ulong_t procnum) {
  3815.  
  3816.    struct control_s ctrl;
  3817.    ulong_t port;
  3818.  
  3819.  
  3820.    if (procnum == 0)
  3821.       port = P1_PROCESSOR_CONTROL_PORT;
  3822.    else
  3823.       port = P2_PROCESSOR_CONTROL_PORT;
  3824.  
  3825.  
  3826.    ctrl.b_all = InByte(port);
  3827.    ctrl.b_pint = 1;
  3828.  
  3829.    OutByte(port, ctrl.b_all);
  3830.  
  3831.    return (NO_ERROR);
  3832. }
  3833.  
  3834.  
  3835. /***  EndIPI - End an inter-processor interrupt
  3836.  *
  3837.  *    This function ends an IPI.
  3838.  *
  3839.  *    ENTRY   procnum - processor number to end interrupt on (0-based)
  3840.  *
  3841.  *    EXIT    NO_ERROR
  3842.  *
  3843.  */
  3844.  
  3845. ulong_t EndIPI(ulong_t procnum) {
  3846.  
  3847.    struct control_s ctrl;
  3848.    ulong_t port;
  3849.  
  3850.    if (procnum == 0)
  3851.       port = P1_PROCESSOR_CONTROL_PORT;
  3852.    else
  3853.       port = P2_PROCESSOR_CONTROL_PORT;
  3854.  
  3855.    ctrl.b_all = InByte(port);
  3856.    ctrl.b_pint = 0;
  3857.  
  3858.    OutByte(port, ctrl.b_all);
  3859.  
  3860.    if (procnum == 0)
  3861.       SendEOI(IPI_IRQ);
  3862.  
  3863.    return (NO_ERROR);
  3864. }
  3865.  
  3866.  
  3867. ΓòÉΓòÉΓòÉ 12.2. Entry stub ΓòÉΓòÉΓòÉ
  3868.  
  3869. .386
  3870.  
  3871. _TEXT SEGMENT
  3872.  
  3873. ASSUME CS:_TEXT,DS:NOTHING
  3874.  
  3875.       PUBLIC  _RMP2Available
  3876.  
  3877. _RMP2Available PROC
  3878.  
  3879.       mov   ah,0E2h
  3880.       mov   al,0
  3881.       int   15h
  3882.       movzx eax,ax
  3883.       retf
  3884.  
  3885. _RMP2Available ENDP
  3886.  
  3887. _TEXT ENDS
  3888.  
  3889. END
  3890.  
  3891.  
  3892. ΓòÉΓòÉΓòÉ 12.3. PSD.H ΓòÉΓòÉΓòÉ
  3893.  
  3894. /*static char *SCCSID = "@(#)psd.h 1.0 93/18/08";*/
  3895.  
  3896.  
  3897. // XLATOFF
  3898.  
  3899. #ifndef ulong_t
  3900.  
  3901. typedef unsigned long   ulong_t;
  3902. typedef unsigned short  ushort_t;
  3903. typedef unsigned char   uchar_t;
  3904.  
  3905. #endif
  3906.  
  3907. typedef int (*P_F_1)(ulong_t arg);
  3908. typedef int (*P_F_2)(ulong_t arg1, ulong_t arg2);
  3909.  
  3910. #define PSDHelp(router, function, arg) \
  3911.    ((*router)((function), (ulong_t)(arg)))
  3912.  
  3913. // XLATON
  3914. /* ASM
  3915. P_F_1 struc
  3916. dd ?
  3917. P_F_1 ends
  3918. P_F_2 struc
  3919. dd ?
  3920. P_F_2 ends
  3921. */
  3922.  
  3923.  
  3924. #define WARM_REBOOT_VECTOR_SEG  0x40
  3925. #define WARM_REBOOT_VECTOR_OFF  0x67
  3926.  
  3927.  
  3928. /* PSD Info structure */
  3929.  
  3930. typedef struct info_s {                     /* psd */
  3931.    ulong_t  flags;                          /* PSD flags */
  3932.    ulong_t  version;                        /* PSD version */
  3933.    ulong_t  hmte;                           /* MTE handle of PSD */
  3934.    uchar_t *pParmString;                    /* Pointer to ASCIIZ PSD parameter*/
  3935.    ulong_t  IRQ_IPI;                        /* IRQ for IPI */
  3936.    ulong_t  IRQ_LSI;                        /* IRQ for LSI */
  3937.    ulong_t  IRQ_SPI;                        /* IRQ for SPI */
  3938. } PSDINFO;
  3939.  
  3940.  
  3941. /* PSD flags definition */
  3942.  
  3943. #define PSD_ADV_INT_MODE        0x20000000  /* PSD is in adv int mode #81531 */
  3944. #define PSD_INSTALLED           0x40000000  /* PSD has been installed */
  3945. #define PSD_INITIALIZED         0x80000000  /* PSD has been initialized */
  3946.  
  3947. /* PSD function numbers-structures */
  3948.  
  3949. #define PSD_INSTALL             0x00000000  /* Install PSD */
  3950.  
  3951. typedef struct install_s {                  /* install */
  3952.    P_F_2   pPSDHlpRouter;                   /* Address of PSDHlpRouter */
  3953.    char   *pParmString;                     /* Pointer to parameter string */
  3954.    void   *pPSDPLMA;                        /* Pointer to PSD's PLMA */
  3955.    ulong_t sizePLMA;                        /* Size of PLMA in bytes */
  3956. } INSTALL;
  3957.  
  3958. #define PSD_DEINSTALL           0x00000001  /* DeInstall PSD */
  3959.  
  3960. #define PSD_INIT                0x00000002  /* Initialize PSD */
  3961.  
  3962. typedef struct init_s {                     /* init */
  3963.    ulong_t flags;                           /* Init flags */
  3964.    ulong_t version;                         /* PSD Version number */
  3965. } INIT;
  3966.  
  3967. #define INIT_GLOBAL_IRQ_ACCESS  0x00000001  /* Platform has global IRQ access */
  3968. #define INIT_USE_FPERR_TRAP     0x00000002  /* Use Trap 16 to report FP err's */
  3969. #define INIT_EOI_IRQ13_ON_CPU0  0x00000004  /* eoi IRQ 13 only if on cpu 0    */
  3970. #define INIT_TIMER_CPU0         0x00000008  /* system timer is on CPU 0       */
  3971.  
  3972. #define PSD_PROC_INIT           0x00000003  /* Initialize processor */
  3973.  
  3974. #define PSD_START_PROC          0x00000004  /* Start processor */
  3975.  
  3976. #define PSD_GET_NUM_OF_PROCS    0x00000005  /* Get number of processors */
  3977.  
  3978. #define PSD_GEN_IPI             0x00000006  /* Generate an IPI */
  3979.  
  3980. #define PSD_END_IPI             0x00000007  /* End an IPI */
  3981.  
  3982. #define PSD_PORT_IO             0x00000008  /* Port I/O */
  3983.  
  3984. typedef struct port_io_s {                  /* port_io */
  3985.    ulong_t port;                            /* Port number to access */
  3986.    ulong_t data;                            /* Data read, or data to write */
  3987.    ulong_t flags;                           /* IO Flags */
  3988. } PORT_IO;
  3989.  
  3990. #define IO_READ_BYTE    0x0000              /* Read a byte from the port */
  3991. #define IO_READ_WORD    0x0001              /* Read a word from the port */
  3992. #define IO_READ_DWORD   0x0002              /* Read a dword from the port */
  3993. #define IO_WRITE_BYTE   0x0003              /* Write a byte to the port */
  3994. #define IO_WRITE_WORD   0x0004              /* Write a word to the port */
  3995. #define IO_WRITE_DWORD  0x0005              /* Write a dword to the port */
  3996.  
  3997. #define IO_FLAGMASK     0x0007              /* Flag mask */
  3998.  
  3999. #define PSD_IRQ_MASK            0x00000009  /* Mask/Unmask IRQ levels */
  4000.  
  4001. typedef struct psd_irq_s {                  /* psd_irq */
  4002.    ulong_t flags;                           /* IRQ flags */
  4003.    ulong_t data;                            /* IRQ data */
  4004.                                             /*   depending on type of irq */
  4005.                                             /*   operation, the data field */
  4006.                                             /*   can contain any of the */
  4007.                                             /*   following info: */
  4008.                                             /*   1) Mask or UNMasking data */
  4009.                                             /*   2) IRR or ISR reg values */
  4010.                                             /*   3) IRQ # for EOI operations */
  4011.    ulong_t procnum;                         /* Processor number */
  4012. } PSD_IRQ;
  4013.  
  4014. #define PSD_IRQ_REG             0x0000000A  /* Access IRQ related regs */
  4015.  
  4016. #define PSD_IRQ_EOI             0x0000000B  /* Issue an EOI */
  4017.  
  4018. #define IRQ_MASK                0x00000001  /* Turn on IRQ mask bits */
  4019. #define IRQ_UNMASK              0x00000002  /* Turn off IRQ mask bits */
  4020. #define IRQ_GETMASK             0x00000004  /* Get IRQ mask bits */
  4021. #define IRQ_NEWMASK             0x00000010  /* Set and/or Reset all masks */
  4022. #define IRQ_READ_IRR            0x00000100  /* Read the IRR reg */
  4023. #define IRQ_READ_ISR            0x00000200  /* Read the ISR reg */
  4024.  
  4025. #define PSD_APP_COMM            0x0000000C  /* PSD/APP Communication */
  4026.  
  4027. #define PSD_SET_ADV_INT_MODE    0x0000000D  /* Set advanced int mode */
  4028.  
  4029. #define PSD_SET_PROC_STATE      0x0000000E  /* Set proc state; idle, or busy */
  4030.  
  4031. #define PROC_STATE_IDLE         0x00000000  /* Processor is idle */
  4032. #define PROC_STATE_BUSY         0x00000001  /* Processor is busy */
  4033.  
  4034. #define PSD_QUERY_SYSTEM_TIMER  0x0000000F  /* Query Value of System Timer 0 */
  4035.  
  4036. typedef struct psd_qrytmr_s {               /* psd_qrytmr */
  4037.    ulong_t qw_ulLo_psd;                     /* Timer count */
  4038.    ulong_t qw_ulHi_psd;                     /* Timer count */
  4039.    ulong_t pqwTmr;                          /* 16:16 ptr to qwTmr */
  4040. } PSD_QRYTMR;
  4041.  
  4042. #define PSD_SET_SYSTEM_TIMER    0x00000010  /* Set System Timer 0 counter    */
  4043.  
  4044. typedef struct psd_settmr_s {               /* psd_settmr */
  4045.    ulong_t NewRollOver;                     /* NewRollover*/
  4046.    ulong_t pqwTmrRollover;                  /* 16:16 ptr to qwTmrRollover */
  4047. } PSD_SETTMR;
  4048.  
  4049. /* PSD helper function numbers-structures */
  4050.  
  4051. #define PSDHLP_VMALLOC          0x00000000  /* Allocate memory */
  4052.  
  4053. typedef struct vmalloc_s {                  /* vmalloc */
  4054.    ulong_t addr;                            /* Physical address to map */
  4055.                                             /*  if VMALLOC_PHYS */
  4056.                                             /* Lin addr to alloc at */
  4057.                                             /*  if VMALLOC_LOCSPECIFIC */
  4058.                                             /* on return, addr of allocation */
  4059.    ulong_t cbsize;                          /* Size of mapping in bytes */
  4060.    ulong_t flags;                           /* Allocation flags */
  4061. } VMALLOC;
  4062.  
  4063. #define VMALLOC_FIXED           0x00000001  /* Allocate resident memory */
  4064. #define VMALLOC_CONTIG          0x00000002  /* Allocate contiguous memory */
  4065. #define VMALLOC_LOCSPECIFIC     0x00000004  /* Alloc at a specific lin address */
  4066. #define VMALLOC_PHYS            0x00000008  /* Map physical address */
  4067. #define VMALLOC_1M              0x00000010  /* Allocate below 1M */
  4068.  
  4069. #define VMALLOC_FLAGMASK        0x0000001f  /* Valid flag mask */
  4070.  
  4071. #define PSDHLP_VMFREE           0x00000001  /* Free memory */
  4072.  
  4073. #define PSDHLP_SET_IRQ          0x00000002  /* Set up an IRQ */
  4074.  
  4075. typedef struct set_irq_s {                  /* set_irq */
  4076.    ushort_t irq;                            /* IRQ level */
  4077.    ushort_t flags;                          /* Set IRQ flags */
  4078.    ulong_t  vector;                         /* IRQ interrupt vector */
  4079.    P_F_2    handler;                        /* IRQ handler */
  4080. } SET_IRQ;
  4081.  
  4082. #define IRQf_IPI  0x0020                    /* IRQ for IPI */
  4083. #define IRQf_LSI  0x0040                    /* IRQ for LSI */
  4084. #define IRQf_SPI  0x0080                    /* IRQ for SPI */
  4085.  
  4086. #define PSDHLP_CALL_REAL_MODE   0x00000003  /* Call a function in real mode */
  4087.  
  4088. typedef struct call_real_mode_s {           /* call_real_mode */
  4089.    ulong_t function;                        /* Function address */
  4090.    ulong_t pdata;                           /* Pointer to data area */
  4091. } CALL_REAL_MODE;
  4092.  
  4093. #define PSDHLP_VMLINTOPHYS      0x00000004  /* Convert linear addr to phys */
  4094.  
  4095. #define PSDHLP_ADJ_PG_RANGES    0x00000005  /* Adjust page ranges */
  4096.  
  4097. typedef struct _pagerange_s {               /* pagerange */
  4098.    ulong_t lastframe;                       /* Last valid page in range */
  4099.    ulong_t firstframe;                      /* First valid page in range */
  4100. };
  4101.  
  4102. typedef struct adj_pg_ranges_s{             /* adj_pg_ranges */
  4103.    struct _pagerange_s *pprt;               /* Pointer to page range table */
  4104.    ulong_t nranges;                         /* Num of ranges in range table */
  4105. } ADJ_PG_RANGES;
  4106.  
  4107. /* PSD function prototypes */
  4108.  
  4109. extern void PSDEnter (ulong_t function, ulong_t arg, P_F_2 altEntry);
  4110.  
  4111.  
  4112. ΓòÉΓòÉΓòÉ 12.4. Specific header ΓòÉΓòÉΓòÉ
  4113.  
  4114.  
  4115. /*
  4116.  * Miscellaneous
  4117.  */
  4118.  
  4119. #define VERSION   0x00000010
  4120.  
  4121. #define _64K      (64 * 1024)
  4122.  
  4123. #define BIOS_SEG             0xF000
  4124. #define ALR_STRING_OFFSET   0xEC47
  4125.  
  4126. #define P2_AVAILABLE         0x00008000
  4127.  
  4128.  
  4129. /*
  4130.  * PLMA structure
  4131.  */
  4132.  
  4133. typedef struct plma_s {
  4134.    ulong_t procnum;       /* Current processor number (0-based) */
  4135.    ulong_t controlport;   /* Control port for current processor */
  4136. } PLMA;
  4137.  
  4138.  
  4139. /*
  4140.  * Generate delay between I/O instructions
  4141.  */
  4142.  
  4143. #define IODelay {int i; for(i = 0; i < IODelayCount; i++); }
  4144.  
  4145.  
  4146. /*
  4147.  * IPI info
  4148.  */
  4149.  
  4150. #define IPI_IRQ     0x0d      /* IRQ level for IPI */
  4151. #define IPI_VECTOR  0x75      /* Vector number for IPI */
  4152.  
  4153.  
  4154. /*
  4155.  * PIC Info
  4156.  */
  4157.  
  4158. #define NUM_IRQ_PER_PIC         0x08
  4159. #define OCW2_NON_SPECIFIC_EOI   0x20
  4160. #define PIC1_PORT0              0x20
  4161. #define PIC1_PORT1              0x21
  4162. #define PIC2_PORT0              0xA0
  4163. #define PIC2_PORT1              0xA1
  4164.  
  4165.  
  4166. /*
  4167.  * The contents of the WHO_AM_I port (read-only) can be used
  4168.  * by code to determine which processor we are currently on
  4169.  */
  4170.  
  4171. #define WHO_AM_I_PORT  0xC70
  4172. #define P1             0x00
  4173. #define P2             0xF0
  4174.  
  4175.  
  4176. /*
  4177.  * The processor control port contains the bits used to control
  4178.  * various functions of the associated processor
  4179.  */
  4180.  
  4181. #define P1_PROCESSOR_CONTROL_PORT  0x0C6A
  4182. #define P2_PROCESSOR_CONTROL_PORT  0xFC6A
  4183.  
  4184. struct _b_control_s {
  4185.    ulong_t _reset:1,      /* RESET - (Not implemented for P1) */
  4186.                           /*  1 = Resets processor */
  4187.  
  4188.            _387pres:1,    /* 387PRES - (Read only) */
  4189.                           /*  0 = 80387 is not installed */
  4190.                           /*  1 = 80387 is installed */
  4191.  
  4192.            _cacheon:1,    /* CACHEON - (Not implemented for P1) */
  4193.                           /*  0 = Disables cache */
  4194.                           /*  1 = Enables cache */
  4195.  
  4196.            _mbusaccess:1, /* M Bus Access (Not implemented for P1) */
  4197.                           /*  0 = Allows the processor to gain */
  4198.                           /*      control of the memory bus */
  4199.                           /*  1 = Prohibits the processor from gaining */
  4200.                           /*      access to the memory bus. The */
  4201.                           /*      processor can execute instructions */
  4202.                           /*      from its cache; however, cache read */
  4203.                           /*      misses, I/O, and writes cause the */
  4204.                           /*      processor to cease executing */
  4205.                           /*      instructions until the bit becomes */
  4206.                           /*      a "0" */
  4207.  
  4208.            _flush:1,      /* FLUSH */
  4209.                           /*  Writing a "1" to this bit followed by a "0" */
  4210.                           /*  causes invalidation of all cache address */
  4211.                           /*  information */
  4212.  
  4213.            _387err:1,     /* 387ERR */
  4214.                           /*  0 = No 80387 error */
  4215.                           /*  0 = An 80387 error has occurred. This bit */
  4216.                           /*      must be cleared by software */
  4217.  
  4218.            _pint:1,       /* PINT */
  4219.                           /*  A low-to-high transition of this bit causes */
  4220.                           /*  an interrupt. This bit must be cleared by  */
  4221.                           /*  software, preferably by the interrupt service */
  4222.                           /*  routine. On P2, the value stored in FC68h */
  4223.                           /*  contains the interrupt number. P1 is always */
  4224.                           /*  interrupted with IRQ13 */
  4225.  
  4226.            _intdis:1,     /* INTDIS */
  4227.                           /*  When set to "1", this bit disables interrupts */
  4228.                           /*  sent to the processor by way of the PINT bit. */
  4229.                           /*  The PINT bit can still be changed when */
  4230.                           /*  interrupts are disabled; however, the */
  4231.                           /*  low-to-high transition is not seen by the */
  4232.                           /*  processor until the INTDIS bit is made inactive */
  4233.            _pad:24;
  4234. };
  4235.  
  4236. struct _l_control_s {     /* to treat control as an unsigned long */
  4237.     unsigned long _long;
  4238. };
  4239.  
  4240. union _control_u {
  4241.     struct _b_control_s b_control_s;
  4242.     struct _l_control_s l_control_s;
  4243. };
  4244.  
  4245. struct control_s {
  4246.     union _control_u control_u;
  4247. };
  4248.  
  4249. #define b_reset       control_u.b_control_s._reset
  4250. #define b_387pres     control_u.b_control_s._387pres
  4251. #define b_cacheon     control_u.b_control_s._cacheon
  4252. #define b_mbusaccess  control_u.b_control_s._mbusaccess
  4253. #define b_flush       control_u.b_control_s._flush
  4254. #define b_387err      control_u.b_control_s._387err
  4255. #define b_pint        control_u.b_control_s._pint
  4256. #define b_intdis      control_u.b_control_s._intdis
  4257. #define b_all         control_u.l_control_s._long
  4258.  
  4259.  
  4260. /*
  4261.  * The interrupt vector control port contains the 8-bit interrupt
  4262.  * number that is executed when the PINT bit transitions from "0"
  4263.  * to "1". This vector is only used for P2. P1 is always interrupted
  4264.  * with IRQ 13.
  4265.  */
  4266.  
  4267. #define P2_INTERRUPT_VECTOR_CONTROL_PORT 0xFC68
  4268.  
  4269.  
  4270. /*
  4271.  * The following ports contain the EISA identification of the
  4272.  * system processor boards
  4273.  */
  4274.  
  4275. #define COMPAQ_ID1  0x0000000E
  4276. #define COMPAQ_ID2  0x00000011
  4277.  
  4278. #define P1_EISA_PRODUCT_ID_PORT1  0x0C80  /* Compressed COMPAQ ID - OEh */
  4279. #define P1_EISA_PRODUCT_ID_PORT2  0x0C81  /*                        11h */
  4280. #define P1_EISA_PRODUCT_ID_PORT3  0x0C82  /* Product code for the proc board */
  4281. #define P1_EISA_PRODUCT_ID_PORT4  0x0C83  /* Revision number */
  4282.  
  4283. #define P2_EISA_PRODUCT_ID_PORT1  0xFC80  /* Compressed COMPAQ ID - OEh */
  4284. #define P2_EISA_PRODUCT_ID_PORT2  0xFC81  /*                        11h */
  4285. #define P2_EISA_PRODUCT_ID_PORT3  0xFC82  /* Product code for the proc board */
  4286. #define P2_EISA_PRODUCT_ID_PORT4  0xFC83  /* Revision number */
  4287.  
  4288. /*
  4289.  * Any write to The RAM Relocation Register (memory mapped)
  4290.  * will flush the caches of both P1 and P2
  4291.  */
  4292.  
  4293. #define RAM_RELOCATION_REGISTER       0x80C00000
  4294.  
  4295.  
  4296. /*
  4297.  * The P1 Cache Control Register (memory mapped)
  4298.  */
  4299.  
  4300. #define P1_CACHE_CONTROL_REGISTER     0x80C00002
  4301.  
  4302. struct p1cache_s {
  4303.    ulong_t _reserved1:6,
  4304.            _p1cc:1,       /* P1 Cache Control */
  4305.                           /*  0 = Disables P1 cache */
  4306.                           /*  1 = Enables P1 cache */
  4307.            _reserved2:9;
  4308. };
  4309.  
  4310.  
  4311. /*
  4312.  * Expanision board control ports
  4313.  */
  4314.  
  4315. #define P1_EISA_EXPANSION_BOARD_CONTROL  0x0C84
  4316. #define P2_EISA_EXPANSION_BOARD_CONTROL  0xFC84
  4317.  
  4318.  
  4319. ΓòÉΓòÉΓòÉ 12.5. Makefile ΓòÉΓòÉΓòÉ
  4320.  
  4321. # SCCSID = @(#)makefile 6.7 92/06/03
  4322.  
  4323. #/***********************************************************************/
  4324. #/*                                                                     */
  4325. #/* PSD Name: ALR.PSD - ALR PSD                                         */
  4326. #/*           -----------------------------------                       */
  4327. #/*                                                                     */
  4328. #/* Source File Name: MAKEFILE                                          */
  4329. #/*                                                                     */
  4330. #/* Descriptive Name: MAKEFILE for the ALR PSD                          */
  4331. #/*                                                                     */
  4332. #/* Function:                                                           */
  4333. #/*                                                                     */
  4334. #/*                                                                     */
  4335. #/*---------------------------------------------------------------------*/
  4336. #/*                                                                     */
  4337. #/* Copyright (C) 1992 IBM Corporation                                  */
  4338. #/*                                                                     */
  4339. #/* DISCLAIMER OF WARRANTIES.  The following enclosed code is           */
  4340. #/* provided to you solely for the purpose of assisting you in          */
  4341. #/* the development of your applications. The code is provided          */
  4342. #/* "AS IS", without warranty of any kind. IBM shall not be liable      */
  4343. #/* for any damages arising out of your use of this code, even if       */
  4344. #/* they have been advised of the possibility of such damages.          */
  4345. #/*                                                                     */
  4346. #/*---------------------------------------------------------------------*/
  4347. #/*                                                                     */
  4348. #/* Change Log                                                          */
  4349. #/*                                                                     */
  4350. #/* Mark    Date      Programmer  Comment                               */
  4351. #/* ----    ----      ----------  -------                               */
  4352. #/* @nnnn   mm/dd/yy  NNN                                               */
  4353. #/*                                                                     */
  4354. #/*                                                                     */
  4355. #/***********************************************************************/
  4356.  
  4357. # ******  NOTE  ******
  4358. #
  4359. #       If you are using a SED command with TAB characters, many editors
  4360. #       will expand tabs causing unpredictable results in other programs.
  4361. #
  4362. #       Documentation:
  4363. #
  4364. #       Using SED command with TABS. Besure to invoke set tab save option
  4365. #       on your editor. If you don't, the program 'xyz' will not work
  4366. #       correctly.
  4367. #
  4368.  
  4369. #****************************************************************************
  4370. #  Dot directive definition area (usually just suffixes)
  4371. #****************************************************************************
  4372.  
  4373. .SUFFIXES:
  4374. .SUFFIXES: .com .sys .exe .obj .mbj .asm .inc .def .lnk .lrf .crf .ref
  4375. .SUFFIXES: .lst .sym .map .c .h .lib
  4376.  
  4377. #****************************************************************************
  4378. #  Environment Setup for the component(s).
  4379. #****************************************************************************
  4380.  
  4381. #
  4382. # Conditional Setup Area and User Defined Macros
  4383. #
  4384.  
  4385. #
  4386. # Compiler Location w/ includes, libs and tools
  4387. #
  4388.  
  4389. INC    = ..\..\..\inc
  4390. H      = ..\..\..\h
  4391. LIB    = ..\..\..\lib386;..\..\..\lib
  4392. TOOLSPATH = ..\..\..\tools
  4393.  
  4394. #
  4395. # Because the compiler/linker and other tools use environment
  4396. # variables ( INCLUDE, LIB, etc ) in order to get the location of files,
  4397. # the following line will check the environment for the LIFE of the
  4398. # makefile and will be specific to this set of instructions. All MAKEFILES
  4399. # are requested to use this format to insure that they are using the correct
  4400. # level of files and tools.
  4401. #
  4402.  
  4403. !if set INCLUDE=$(INC) || \
  4404.     set LIB=$(LIB) || set PATH=$(TOOLSPATH);$(DK_TOOLS)
  4405. !endif
  4406.  
  4407.  
  4408. #
  4409. # Compiler/tools Macros
  4410. #
  4411.  
  4412. AS=masm
  4413. CC=cl386
  4414. IMPLIB=implib
  4415. IPF=ipfc
  4416. LIBUTIL=lib
  4417. LINK=link386
  4418. MAPSYM=mapsym
  4419. RC=rc
  4420.  
  4421. #
  4422. # Compiler and Linker Options
  4423. #
  4424.  
  4425. AFLAGS = -MX -T -Z $(ENV)
  4426. AINC   = -I. -I$(INC)
  4427. CINC   = -I$(H) -I$(MAKEDIR)
  4428. CFLAGS = /c /Zp /Gs /AS $(ENV)
  4429. LFLAGS = /map /nod /exepack
  4430.  
  4431. LIBS = os2386.lib
  4432. DEF = ALR.def
  4433.  
  4434. #****************************************************************************
  4435. # Set up Macros that will contain all the different dependencies for the
  4436. # executables and dlls etc. that are generated.
  4437. #****************************************************************************
  4438.  
  4439. #
  4440. #
  4441. #
  4442. OBJ1 =  entry.obj main.obj
  4443.  
  4444. #
  4445. #       LIST Files
  4446. #
  4447. LIST =
  4448.  
  4449. OBJS = $(OBJ1)
  4450.  
  4451. #****************************************************************************
  4452. #   Setup the inference rules for compiling and assembling source code to
  4453. #   object code.
  4454. #****************************************************************************
  4455.  
  4456.  
  4457. .asm.obj:
  4458.         $(AS) $(AFLAGS) $(AINC) $*.asm;
  4459.  
  4460. .asm.mbj:
  4461.         $(AS) $(AFLAGS) -DMMIOPH $(AINC) $*.asm $*.mbj;
  4462.  
  4463. .asm.lst:
  4464.         $(AS) -l -n $(AFLAGS) $(AINC) $*.asm;
  4465.  
  4466. .c.obj:
  4467.         $(CC) $(CFLAGS) $(CINC) $*.c
  4468.  
  4469. .c.lst:
  4470.         $(CC) $(CFLAGS) /Fc $(CINC) $*.c
  4471.         copy $*.cod $*.lst
  4472.         del $*.cod
  4473.  
  4474.  
  4475. #****************************************************************************
  4476. #   Target Information
  4477. #****************************************************************************
  4478. #
  4479. # This is a very important step. The following small amount of code MUST
  4480. # NOT be removed from the program. The following directive will do
  4481. # dependency checking every time this component is built UNLESS the
  4482. # following is performed:
  4483. #               A specific tag is used -- ie. all
  4484. #
  4485. # This allows the developer as well as the B & I group to perform incremental
  4486. # build with a degree of accuracy that has not been used before.
  4487. # There are some instances where certain types of INCLUDE files must be
  4488. # created first. This type of format will allow the developer to require
  4489. # that file to be created first. In order to achieve that, all that has to
  4490. # be done is to make the DEPEND.MAK tag have your required target. Below is
  4491. # an example:
  4492. #
  4493. #    depend.mak:   { your file(s) } dephold
  4494. #
  4495. # Please DON'T remove the following line
  4496. #
  4497.  
  4498. !include      "$(H)\common.mak"
  4499. !include      "$(H)\version.mak"
  4500.  
  4501. #
  4502. # Should be the default tag for all general processing
  4503. #
  4504.  
  4505. all:    ALR.psd
  4506.  
  4507. list: $(LIST)
  4508.  
  4509. clean:
  4510.         if exist *.lnk    del *.lnk
  4511.         if exist *.obj    del *.obj
  4512.         if exist *.mbj    del *.mbj
  4513.         if exist *.map    del *.map
  4514.         if exist *.old    del *.old
  4515.         if exist *.lst    del *.lst
  4516.         if exist *.lsd    del *.lsd
  4517.         if exist *.sym    del *.sym
  4518.         if exist *.sys    del *.sys
  4519.  
  4520.  
  4521.  
  4522.  
  4523. #*****************************************************************************
  4524. #   Specific Description Block Information
  4525. #*****************************************************************************
  4526.  
  4527. # This section would only be for specific direction as to how to create
  4528. # unique elements that are necessary to the build process. This could
  4529. # be compiling or assembling, creation of DEF files and other unique
  4530. # files.
  4531. # If all compiler and assembly rules are the same, use an inference rule to
  4532. # perform the compilation.
  4533. #
  4534.  
  4535. alr.psd:  $(OBJS) makefile
  4536.         Rem Create DEF file <<$(DEF)
  4537. LIBRARY ALR
  4538.  
  4539. EXPORTS
  4540.  
  4541.    PSD_INSTALL          = _Install
  4542.    PSD_DEINSTALL        = _DeInstall
  4543.    PSD_INIT             = _Init
  4544.    PSD_PROC_INIT        = _ProcInit
  4545.    PSD_START_PROC       = _StartProcessor
  4546.    PSD_GET_NUM_OF_PROCS = _GetNumOfProcs
  4547.    PSD_GEN_IPI          = _GenIPI
  4548.    PSD_END_IPI          = _EndIPI
  4549. <<keep
  4550.         $(LINK) $(LFLAGS) @<<$(@B).lnk
  4551. $(OBJ1)
  4552. $*.psd
  4553. $*.map
  4554. $(LIBS)
  4555. $(DEF)
  4556. <<keep
  4557.         $(MAPSYM) $*.map
  4558.  
  4559.  
  4560.  
  4561. #****************************************************************************
  4562. #  Dependency generation and Checking
  4563. #****************************************************************************
  4564.  
  4565. depend.mak:  dephold
  4566.         touch depchk
  4567.         includes -e -sobj -llst -I. -I$(H) -I$(DISKH) -I$(INC) -P$$(H)=$(H) *.c *.asm >$@
  4568.         -del depchk
  4569.  
  4570. dephold:
  4571.         touch $@
  4572.  
  4573. !include depend.mak
  4574.  
  4575.  
  4576. ΓòÉΓòÉΓòÉ 13. Glossary ΓòÉΓòÉΓòÉ
  4577.  
  4578. MP-unsafe           Does not provide the necessary serialization to run on more 
  4579.                     than one CPU at a time. For example, a driver will be MP 
  4580.                     unsafe if it relies upon priorities between threads for 
  4581.                     accessing shared resources, or uses the CLI/STI method for 
  4582.                     protecting resources like semaphores or memory. 
  4583.  
  4584.  
  4585. MP-safe             Provides the necessary serialization to run properly in a 
  4586.                     system with greater than one processor. Does not use 
  4587.                     invalid UP serialization techniques. For example, a driver 
  4588.                     will be MP safe if it does not rely upon priorities between 
  4589.                     threads for accessing shared resources, or use the CLI/STI 
  4590.                     method for protecting resources like semaphores or memory. 
  4591.  
  4592.  
  4593. MP-exploitive       Provides proper MP serialization techniques which allow 
  4594.                     multiple threads to run concurrently on more than one CPU. 
  4595.