Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

529 lines
11 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. iopm.c
  5. Abstract:
  6. This module implements interfaces that support manipulation of i386
  7. i/o access maps (IOPMs).
  8. These entry points only exist on i386 machines.
  9. Author:
  10. Bryan M. Willman (bryanwi) 18-Sep-91
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. #include "ki.h"
  16. //
  17. // Our notion of alignment is different, so force use of ours
  18. //
  19. #undef ALIGN_UP
  20. #undef ALIGN_DOWN
  21. #define ALIGN_DOWN(address,amt) ((ULONG)(address) & ~(( amt ) - 1))
  22. #define ALIGN_UP(address,amt) (ALIGN_DOWN( (address + (amt) - 1), (amt) ))
  23. //
  24. // Note on synchronization:
  25. //
  26. // IOPM edits are always done by code running at synchronization level on
  27. // the processor whose TSS (map) is being edited.
  28. //
  29. // IOPM only affects user mode code. User mode code can never interrupt
  30. // synchronization level code, therefore, edits and user code never race.
  31. //
  32. // Likewise, switching from one map to another occurs on the processor
  33. // for which the switch is being done by IPI_LEVEL code. The active
  34. // map could be switched in the middle of an edit of some map, but
  35. // the edit will always complete before any user code gets run on that
  36. // processor, therefore, there is no race.
  37. //
  38. // Multiple simultaneous calls to Ke386SetIoAccessMap *could* produce
  39. // weird mixes. Therefore, KiIopmLock must be acquired to
  40. // globally serialize edits.
  41. //
  42. //
  43. // Define forward referenced function prototypes.
  44. //
  45. VOID
  46. KiSetIoMap(
  47. IN PKIPI_CONTEXT SignalDone,
  48. IN PVOID MapSource,
  49. IN PVOID MapNumber,
  50. IN PVOID Parameter3
  51. );
  52. VOID
  53. KiLoadIopmOffset(
  54. IN PKIPI_CONTEXT SignalDone,
  55. IN PVOID Parameter1,
  56. IN PVOID Parameter2,
  57. IN PVOID Parameter3
  58. );
  59. BOOLEAN
  60. Ke386SetIoAccessMap (
  61. ULONG MapNumber,
  62. PKIO_ACCESS_MAP IoAccessMap
  63. )
  64. /*++
  65. Routine Description:
  66. The specified i/o access map will be set to match the
  67. definition specified by IoAccessMap (i.e. enable/disable
  68. those ports) before the call returns. The change will take
  69. effect on all processors.
  70. Ke386SetIoAccessMap does not give any process enhanced I/O
  71. access, it merely defines a particular access map.
  72. Arguments:
  73. MapNumber - Number of access map to set. Map 0 is fixed.
  74. IoAccessMap - Pointer to bitvector (64K bits, 8K bytes) which
  75. defines the specified access map. Must be in
  76. non-paged pool.
  77. Return Value:
  78. TRUE if successful. FALSE if failure (attempt to set a map
  79. which does not exist, attempt to set map 0)
  80. --*/
  81. {
  82. PKPROCESS CurrentProcess;
  83. KIRQL OldIrql;
  84. PKPRCB Prcb;
  85. PVOID pt;
  86. KAFFINITY TargetProcessors;
  87. //
  88. // Reject illegal requests
  89. //
  90. if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) {
  91. return FALSE;
  92. }
  93. //
  94. // Acquire the context swap lock so a context switch will not occur.
  95. //
  96. KiLockContextSwap(&OldIrql);
  97. //
  98. // Compute set of active processors other than this one, if non-empty
  99. // IPI them to set their maps.
  100. //
  101. Prcb = KeGetCurrentPrcb();
  102. #if !defined(NT_UP)
  103. TargetProcessors = KeActiveProcessors & ~Prcb->SetMember;
  104. if (TargetProcessors != 0) {
  105. KiIpiSendPacket(TargetProcessors,
  106. KiSetIoMap,
  107. IoAccessMap,
  108. (PVOID)MapNumber,
  109. NULL);
  110. }
  111. #endif
  112. //
  113. // Copy the IOPM map and load the map for the current process.
  114. //
  115. pt = &(KiPcr()->TSS->IoMaps[MapNumber-1].IoMap);
  116. RtlCopyMemory(pt, (PVOID)IoAccessMap, IOPM_SIZE);
  117. CurrentProcess = Prcb->CurrentThread->ApcState.Process;
  118. KiPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset;
  119. //
  120. // Wait until all of the target processors have finished copying the
  121. // new map.
  122. //
  123. #if !defined(NT_UP)
  124. if (TargetProcessors != 0) {
  125. KiIpiStallOnPacketTargets(TargetProcessors);
  126. }
  127. #endif
  128. //
  129. // Restore IRQL and unlock the context swap lock.
  130. //
  131. KiUnlockContextSwap(OldIrql);
  132. return TRUE;
  133. }
  134. #if !defined(NT_UP)
  135. VOID
  136. KiSetIoMap(
  137. IN PKIPI_CONTEXT SignalDone,
  138. IN PVOID MapSource,
  139. IN PVOID MapNumber,
  140. IN PVOID Parameter3
  141. )
  142. /*++
  143. Routine Description:
  144. copy the specified map into this processor's TSS.
  145. This procedure runs at IPI level.
  146. Arguments:
  147. Argument - actually a pointer to a KIPI_SET_IOPM structure
  148. ReadyFlag - pointer to flag to set once setiopm has completed
  149. Return Value:
  150. none
  151. --*/
  152. {
  153. PKPROCESS CurrentProcess;
  154. PKPRCB Prcb;
  155. PVOID pt;
  156. //
  157. // Copy the IOPM map and load the map for the current process.
  158. //
  159. Prcb = KeGetCurrentPrcb();
  160. pt = &(KiPcr()->TSS->IoMaps[((ULONG) MapNumber)-1].IoMap);
  161. RtlCopyMemory(pt, MapSource, IOPM_SIZE);
  162. CurrentProcess = Prcb->CurrentThread->ApcState.Process;
  163. KiPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset;
  164. KiIpiSignalPacketDone(SignalDone);
  165. return;
  166. }
  167. #endif
  168. BOOLEAN
  169. Ke386QueryIoAccessMap (
  170. ULONG MapNumber,
  171. PKIO_ACCESS_MAP IoAccessMap
  172. )
  173. /*++
  174. Routine Description:
  175. The specified i/o access map will be dumped into the buffer.
  176. map 0 is a constant, but will be dumped anyway.
  177. Arguments:
  178. MapNumber - Number of access map to set. map 0 is fixed.
  179. IoAccessMap - Pointer to buffer (64K bits, 8K bytes) which
  180. is to receive the definition of the access map.
  181. Must be in non-paged pool.
  182. Return Value:
  183. TRUE if successful. FALSE if failure (attempt to query a map
  184. which does not exist)
  185. --*/
  186. {
  187. ULONG i;
  188. PVOID Map;
  189. KIRQL OldIrql;
  190. PUCHAR p;
  191. //
  192. // Reject illegal requests
  193. //
  194. if (MapNumber > IOPM_COUNT) {
  195. return FALSE;
  196. }
  197. //
  198. // Acquire the context swap lock so a context switch will not occur.
  199. //
  200. KiLockContextSwap(&OldIrql);
  201. //
  202. // Copy out the map
  203. //
  204. if (MapNumber == IO_ACCESS_MAP_NONE) {
  205. //
  206. // no access case, simply return a map of all 1s
  207. //
  208. p = (PUCHAR)IoAccessMap;
  209. for (i = 0; i < IOPM_SIZE; i++) {
  210. p[i] = (UCHAR)-1;
  211. }
  212. } else {
  213. //
  214. // normal case, just copy the bits
  215. //
  216. Map = (PVOID)&(KiPcr()->TSS->IoMaps[MapNumber-1].IoMap);
  217. RtlCopyMemory((PVOID)IoAccessMap, Map, IOPM_SIZE);
  218. }
  219. //
  220. // Restore IRQL and unlock the context swap lock.
  221. //
  222. KiUnlockContextSwap(OldIrql);
  223. return TRUE;
  224. }
  225. BOOLEAN
  226. Ke386IoSetAccessProcess (
  227. PKPROCESS Process,
  228. ULONG MapNumber
  229. )
  230. /*++
  231. Routine Description:
  232. Set the i/o access map which controls user mode i/o access
  233. for a particular process.
  234. Arguments:
  235. Process - Pointer to kernel process object describing the
  236. process which for which a map is to be set.
  237. MapNumber - Number of the map to set. Value of map is
  238. defined by Ke386IoSetAccessProcess. Setting MapNumber
  239. to IO_ACCESS_MAP_NONE will disallow any user mode i/o
  240. access from the process.
  241. Return Value:
  242. TRUE if success, FALSE if failure (illegal MapNumber)
  243. --*/
  244. {
  245. USHORT MapOffset;
  246. KIRQL OldIrql;
  247. PKPRCB Prcb;
  248. KAFFINITY TargetProcessors;
  249. //
  250. // Reject illegal requests
  251. //
  252. if (MapNumber > IOPM_COUNT) {
  253. return FALSE;
  254. }
  255. MapOffset = KiComputeIopmOffset(MapNumber);
  256. //
  257. // Acquire the context swap lock so a context switch will not occur.
  258. //
  259. KiLockContextSwap(&OldIrql);
  260. //
  261. // Store new offset in process object, compute current set of
  262. // active processors for process, if this cpu is one, set IOPM.
  263. //
  264. Process->IopmOffset = MapOffset;
  265. TargetProcessors = Process->ActiveProcessors;
  266. Prcb = KeGetCurrentPrcb();
  267. if (TargetProcessors & Prcb->SetMember) {
  268. KiPcr()->TSS->IoMapBase = MapOffset;
  269. }
  270. //
  271. // Compute set of active processors other than this one, if non-empty
  272. // IPI them to load their IOPMs, wait for them.
  273. //
  274. #if !defined(NT_UP)
  275. TargetProcessors = TargetProcessors & ~Prcb->SetMember;
  276. if (TargetProcessors != 0) {
  277. KiIpiSendPacket(TargetProcessors,
  278. KiLoadIopmOffset,
  279. NULL,
  280. NULL,
  281. NULL);
  282. KiIpiStallOnPacketTargets(TargetProcessors);
  283. }
  284. #endif
  285. //
  286. // Restore IRQL and unlock the context swap lock.
  287. //
  288. KiUnlockContextSwap(OldIrql);
  289. return TRUE;
  290. }
  291. #if !defined(NT_UP)
  292. VOID
  293. KiLoadIopmOffset(
  294. IN PKIPI_CONTEXT SignalDone,
  295. IN PVOID Parameter1,
  296. IN PVOID Parameter2,
  297. IN PVOID Parameter3
  298. )
  299. /*++
  300. Routine Description:
  301. Edit IopmBase of Tss to match that of currently running process.
  302. Arguments:
  303. Argument - actually a pointer to a KIPI_LOAD_IOPM_OFFSET structure
  304. ReadyFlag - Pointer to flag to be set once we are done
  305. Return Value:
  306. none
  307. --*/
  308. {
  309. PKPROCESS CurrentProcess;
  310. PKPRCB Prcb;
  311. //
  312. // Update IOPM field in TSS from current process
  313. //
  314. Prcb = KeGetCurrentPrcb();
  315. CurrentProcess = Prcb->CurrentThread->ApcState.Process;
  316. KiPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset;
  317. KiIpiSignalPacketDone(SignalDone);
  318. return;
  319. }
  320. #endif
  321. VOID
  322. Ke386SetIOPL(
  323. IN PKPROCESS Process
  324. )
  325. /*++
  326. Routine Description:
  327. Gives IOPL to the specified process.
  328. All threads created from this point on will get IOPL. The current
  329. process will get IOPL. Must be called from context of thread and
  330. process that are to have IOPL.
  331. Iopl (to be made a boolean) in KPROCESS says all
  332. new threads to get IOPL.
  333. Iopl (to be made a boolean) in KTHREAD says given
  334. thread to get IOPL.
  335. N.B. If a kernel mode only thread calls this procedure, the
  336. result is (a) poinless and (b) will break the system.
  337. Arguments:
  338. Process - Pointer to the process == IGNORED!!!
  339. Return Value:
  340. none
  341. --*/
  342. {
  343. PKTHREAD Thread;
  344. PKPROCESS Process2;
  345. PKTRAP_FRAME TrapFrame;
  346. CONTEXT Context;
  347. //
  348. // get current thread and Process2, set flag for IOPL in both of them
  349. //
  350. Thread = KeGetCurrentThread();
  351. Process2 = Thread->ApcState.Process;
  352. Process2->Iopl = 1;
  353. Thread->Iopl = 1;
  354. //
  355. // Force IOPL to be on for current thread
  356. //
  357. TrapFrame = (PKTRAP_FRAME)((PUCHAR)Thread->InitialStack -
  358. ALIGN_UP(sizeof(KTRAP_FRAME),KTRAP_FRAME_ALIGN) -
  359. sizeof(FX_SAVE_AREA));
  360. Context.ContextFlags = CONTEXT_CONTROL;
  361. KeContextFromKframes(TrapFrame,
  362. NULL,
  363. &Context);
  364. Context.EFlags |= (EFLAGS_IOPL_MASK & -1); // IOPL == 3
  365. KeContextToKframes(TrapFrame,
  366. NULL,
  367. &Context,
  368. CONTEXT_CONTROL,
  369. UserMode);
  370. return;
  371. }