Leaked source code of windows server 2003
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.

472 lines
9.6 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 DPC 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. // DPC level code, therefore, edits and user code never race.
  31. //
  32. //
  33. // Define a structure to hold the map change info we pass to DPC's
  34. //
  35. typedef struct _MAPINFO {
  36. PVOID MapSource;
  37. PKPROCESS Process;
  38. ULONG MapNumber;
  39. USHORT MapOffset;
  40. } MAPINFO, *PMAPINFO;
  41. //
  42. // Define forward referenced function prototypes.
  43. //
  44. VOID
  45. KiSetIoMap(
  46. PKDPC Dpc,
  47. IN PVOID DeferredContext,
  48. IN PVOID SystemArgument1,
  49. IN PVOID SystemArgument2
  50. );
  51. VOID
  52. KiLoadIopmOffset(
  53. IN PKIPI_CONTEXT SignalDone,
  54. IN PVOID Parameter1,
  55. IN PVOID Parameter2,
  56. IN PVOID Parameter3
  57. );
  58. BOOLEAN
  59. Ke386SetIoAccessMap (
  60. ULONG MapNumber,
  61. PKIO_ACCESS_MAP IoAccessMap
  62. )
  63. /*++
  64. Routine Description:
  65. The specified i/o access map will be set to match the
  66. definition specified by IoAccessMap (i.e. enable/disable
  67. those ports) before the call returns. The change will take
  68. effect on all processors.
  69. Ke386SetIoAccessMap does not give any process enhanced I/O
  70. access, it merely defines a particular access map.
  71. Arguments:
  72. MapNumber - Number of access map to set. Map 0 is fixed.
  73. IoAccessMap - Pointer to bitvector (64K bits, 8K bytes) which
  74. defines the specified access map. Must be in
  75. non-paged pool.
  76. Return Value:
  77. TRUE if successful. FALSE if failure (attempt to set a map
  78. which does not exist, attempt to set map 0)
  79. --*/
  80. {
  81. MAPINFO MapInfo;
  82. //
  83. // Reject illegal requests
  84. //
  85. if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) {
  86. return FALSE;
  87. }
  88. MapInfo.MapSource = IoAccessMap;
  89. MapInfo.MapNumber = MapNumber;
  90. MapInfo.Process = KeGetCurrentThread()->ApcState.Process;
  91. KeGenericCallDpc (KiSetIoMap,
  92. &MapInfo);
  93. return TRUE;
  94. }
  95. VOID
  96. KiSetIoMap(
  97. PKDPC Dpc,
  98. IN PVOID DeferredContext,
  99. IN PVOID SystemArgument1,
  100. IN PVOID SystemArgument2
  101. )
  102. /*++
  103. Routine Description:
  104. copy the specified map into this processor's TSS.
  105. This procedure runs at IPI level.
  106. Arguments:
  107. Dpc - DPC used to initiate this call
  108. DeferredContext - Context
  109. SystemArgument1 - System context, Used to signal completion of this call
  110. SystemArgument2 - System context
  111. Return Value:
  112. none
  113. --*/
  114. {
  115. PKPROCESS CurrentProcess;
  116. PKPCR Pcr;
  117. PKPRCB Prcb;
  118. PVOID pt;
  119. PMAPINFO MapInfo;
  120. UNREFERENCED_PARAMETER (Dpc);
  121. UNREFERENCED_PARAMETER (SystemArgument2);
  122. MapInfo = DeferredContext;
  123. //
  124. // Copy the IOPM map and load the map for the current process.
  125. // We only do this if the current process is running on this processor.
  126. //
  127. Pcr = KiPcr ();
  128. Prcb = Pcr->Prcb;
  129. CurrentProcess = Prcb->CurrentThread->ApcState.Process;
  130. pt = &(Pcr->TSS->IoMaps[MapInfo->MapNumber-1].IoMap);
  131. RtlCopyMemory (pt, MapInfo->MapSource, IOPM_SIZE);
  132. Pcr->TSS->IoMapBase = CurrentProcess->IopmOffset;
  133. //
  134. // Signal that all processing has been done
  135. //
  136. KeSignalCallDpcDone (SystemArgument1);
  137. return;
  138. }
  139. BOOLEAN
  140. Ke386QueryIoAccessMap (
  141. ULONG MapNumber,
  142. PKIO_ACCESS_MAP IoAccessMap
  143. )
  144. /*++
  145. Routine Description:
  146. The specified i/o access map will be dumped into the buffer.
  147. map 0 is a constant, but will be dumped anyway.
  148. Arguments:
  149. MapNumber - Number of access map to set. map 0 is fixed.
  150. IoAccessMap - Pointer to buffer (64K bits, 8K bytes) which
  151. is to receive the definition of the access map.
  152. Must be in non-paged pool.
  153. Return Value:
  154. TRUE if successful. FALSE if failure (attempt to query a map
  155. which does not exist)
  156. --*/
  157. {
  158. ULONG i;
  159. PVOID Map;
  160. KIRQL OldIrql;
  161. PUCHAR p;
  162. //
  163. // Reject illegal requests
  164. //
  165. if (MapNumber > IOPM_COUNT) {
  166. return FALSE;
  167. }
  168. //
  169. // Copy out the map
  170. //
  171. if (MapNumber == IO_ACCESS_MAP_NONE) {
  172. //
  173. // no access case, simply return a map of all 1s
  174. //
  175. p = (PUCHAR)IoAccessMap;
  176. for (i = 0; i < IOPM_SIZE; i++) {
  177. p[i] = (UCHAR)-1;
  178. }
  179. } else {
  180. //
  181. // Raise to DISPATCH_LEVEL to obtain read access to the structure
  182. //
  183. KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
  184. //
  185. // normal case, just copy the bits
  186. //
  187. Map = (PVOID)&(KiPcr ()->TSS->IoMaps[MapNumber-1].IoMap);
  188. RtlCopyMemory ((PVOID)IoAccessMap, Map, IOPM_SIZE);
  189. //
  190. // Restore IRQL.
  191. //
  192. KeLowerIrql (OldIrql);
  193. }
  194. return TRUE;
  195. }
  196. BOOLEAN
  197. Ke386IoSetAccessProcess (
  198. PKPROCESS Process,
  199. ULONG MapNumber
  200. )
  201. /*++
  202. Routine Description:
  203. Set the i/o access map which controls user mode i/o access
  204. for a particular process.
  205. Arguments:
  206. Process - Pointer to kernel process object describing the
  207. process which for which a map is to be set.
  208. MapNumber - Number of the map to set. Value of map is
  209. defined by Ke386IoSetAccessProcess. Setting MapNumber
  210. to IO_ACCESS_MAP_NONE will disallow any user mode i/o
  211. access from the process.
  212. Return Value:
  213. TRUE if success, FALSE if failure (illegal MapNumber)
  214. --*/
  215. {
  216. MAPINFO MapInfo;
  217. USHORT MapOffset;
  218. //
  219. // Reject illegal requests
  220. //
  221. if (MapNumber > IOPM_COUNT) {
  222. return FALSE;
  223. }
  224. MapOffset = KiComputeIopmOffset (MapNumber);
  225. //
  226. // Do the update on all processors at DISPATCH_LEVEL
  227. //
  228. MapInfo.Process = Process;
  229. MapInfo.MapOffset = MapOffset;
  230. KeGenericCallDpc (KiLoadIopmOffset,
  231. &MapInfo);
  232. return TRUE;
  233. }
  234. VOID
  235. KiLoadIopmOffset(
  236. PKDPC Dpc,
  237. IN PVOID DeferredContext,
  238. IN PVOID SystemArgument1,
  239. IN PVOID SystemArgument2
  240. )
  241. /*++
  242. Routine Description:
  243. Edit IopmBase of Tss to match that of currently running process.
  244. Arguments:
  245. Dpc - DPC used to initiate this call
  246. DeferredContext - Context
  247. SystemArgument1 - System context, Used to signal completion of this call
  248. SystemArgument2 - System context
  249. Return Value:
  250. none
  251. --*/
  252. {
  253. PKPCR Pcr;
  254. PKPRCB Prcb;
  255. PKPROCESS CurrentProcess;
  256. PMAPINFO MapInfo;
  257. UNREFERENCED_PARAMETER (Dpc);
  258. UNREFERENCED_PARAMETER (SystemArgument2);
  259. //
  260. // Update IOPM field in TSS from current process
  261. //
  262. MapInfo = DeferredContext;
  263. Pcr = KiPcr ();
  264. Prcb = Pcr->Prcb;
  265. CurrentProcess = Prcb->CurrentThread->ApcState.Process;
  266. //
  267. // Set the process IOPM offset first so its available to all.
  268. // Any context swaps after this point will pick up the new value
  269. // This store may occur multiple times but that doesn't matter
  270. //
  271. MapInfo->Process->IopmOffset = MapInfo->MapOffset;
  272. Pcr->TSS->IoMapBase = CurrentProcess->IopmOffset;
  273. //
  274. // Signal that all processing has been done
  275. //
  276. KeSignalCallDpcDone (SystemArgument1);
  277. return;
  278. }
  279. VOID
  280. Ke386SetIOPL(
  281. VOID
  282. )
  283. /*++
  284. Routine Description:
  285. Gives IOPL to the specified process.
  286. All threads created from this point on will get IOPL. The current
  287. process will get IOPL. Must be called from context of thread and
  288. process that are to have IOPL.
  289. Iopl (to be made a boolean) in KPROCESS says all
  290. new threads to get IOPL.
  291. Iopl (to be made a boolean) in KTHREAD says given
  292. thread to get IOPL.
  293. N.B. If a kernel mode only thread calls this procedure, the
  294. result is (a) poinless and (b) will break the system.
  295. Arguments:
  296. None.
  297. Return Value:
  298. None.
  299. --*/
  300. {
  301. PKTHREAD Thread;
  302. PKPROCESS Process2;
  303. PKTRAP_FRAME TrapFrame;
  304. CONTEXT Context;
  305. //
  306. // get current thread and Process2, set flag for IOPL in both of them
  307. //
  308. Thread = KeGetCurrentThread();
  309. Process2 = Thread->ApcState.Process;
  310. Process2->Iopl = 1;
  311. Thread->Iopl = 1;
  312. //
  313. // Force IOPL to be on for current thread
  314. //
  315. TrapFrame = (PKTRAP_FRAME)((PUCHAR)Thread->InitialStack -
  316. ALIGN_UP(sizeof(KTRAP_FRAME),KTRAP_FRAME_ALIGN) -
  317. sizeof(FX_SAVE_AREA));
  318. Context.ContextFlags = CONTEXT_CONTROL;
  319. KeContextFromKframes(TrapFrame,
  320. NULL,
  321. &Context);
  322. Context.EFlags |= (EFLAGS_IOPL_MASK & -1); // IOPL == 3
  323. KeContextToKframes(TrapFrame,
  324. NULL,
  325. &Context,
  326. CONTEXT_CONTROL,
  327. UserMode);
  328. return;
  329. }