test: iopm.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# iopm.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1991  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     iopm.c
    00008
    00009 Abstract:
    00010
    00011     This module implements interfaces that support manipulation of i386
    00012     i/o access maps (IOPMs).
    00013
    00014     These entry points only exist on i386 and IA64 machines.
    00015
    00016 Author:
    00017
    00018     Bryan M. Willman (bryanwi) 18-Sep-91
    00019
    00020 Environment:
    00021
    00022     Kernel mode only.
    00023
    00024 Revision History:
    00025
    00026     Charles Spirakis (intel): 25 Jul 1996 - Don't have TSS anymore,
    00027         so don't need TSS handling or any synchronization of the TSS.
    00028
    00029 --*/
    00030
    00031 #include "ki.h"
    00032
    00033 BOOLEAN KiIA32SetPortMemory(PKPROCESS Process);
    00034
    00035 //
    00036 // For IA64, only need to worry about synchronization for SetIoAccessMap
    00037 // since there is no longer a TSS and no worry about partial TSS states
    00038 // (and no need for any IPI's to do updates...)
    00039 //
    00040
    00041 //
    00042 // Holds all of the possible IO maps (currently 1)
    00043 //
    00044 static PKIO_ACCESS_MAP VdmIoMaps[IOPM_COUNT];
    00045
    00046
    00047 BOOLEAN
    00048 KeIA32SetIoAccessMap (
    00049     ULONG MapNumber,
    00050     PKIO_ACCESS_MAP IoAccessMap
    00051     )
    00052
    00053 /*++
    00054
    00055 Routine Description:
    00056
    00057     The specified i/o access map will be set to match the
    00058     definition specified by IoAccessMap (i.e. enable/disable
    00059     those ports) before the call returns.  The change will take
    00060     effect on all processors.
    00061
    00062     KeIA32SetIoAccessMap does not give any process enhanced I/O
    00063     access, it merely defines a particular access map.
    00064
    00065 Arguments:
    00066
    00067     MapNumber - Number of access map to set.  Map 0 is fixed.
    00068
    00069     IoAccessMap - Pointer to bitvector (64K bits, 8K bytes) which
    00070            defines the specified access map.  Must be in
    00071            non-paged pool.
    00072
    00073 Return Value:
    00074
    00075     TRUE if successful.  FALSE if failure (attempt to set a map
    00076     which does not exist, attempt to set map 0)
    00077
    00078 --*/
    00079
    00080 {
    00081
    00082     PKPROCESS CurrentProcess;
    00083     KIRQL OldIrql;
    00084     PVOID pt;
    00085     PUCHAR p;
    00086     ULONG i;
    00087     BOOLEAN res;
    00088
    00089     //
    00090     // Reject illegal requests
    00091     //
    00092
    00093     if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE)) {
    00094         return FALSE;
    00095     }
    00096
    00097     //
    00098     // If the map N hasn't been allocated, then allocate it now.
    00099     // Don't need to ever free this since it is a system wide
    00100     // resource... Once allocated, stays till reboot.
    00101     // This implies we might want to allocate it early, but we can
    00102     // deal with that later...
    00103     //
    00104
    00105     if (VdmIoMaps[MapNumber - 1] == NULL) {
    00106         // Allocate a little extra to handle wrap-around...
    00107         p = (PUCHAR) ExAllocatePool(NonPagedPool, PIOPM_SIZE);
    00108         if (p == NULL) {
    00109             return FALSE;
    00110         }
    00111
    00112         //
    00113         // And set it all to "no-access"
    00114                 // (and don't forget the little extra)
    00115         //
    00116                 RtlFillMemory((PVOID) p, PIOPM_SIZE, 0x0ff);
    00117
    00118         VdmIoMaps[MapNumber - 1] = p;
    00119     }
    00120
    00121     //
    00122     // Acquire the context swap lock so a context switch will not occur.
    00123     //
    00124     // BUGBUG: Is this really needed?
    00125     //
    00126
    00127     KiLockContextSwap(&OldIrql);
    00128
    00129     //
    00130     // Copy the IOPM map and load the map for the current process.
    00131     //
    00132
    00133     pt = VdmIoMaps[MapNumber-1];
    00134     RtlMoveMemory(pt, (PVOID)IoAccessMap, IOPM_SIZE);
    00135     CurrentProcess = PsGetCurrentProcess();
    00136
    00137     CurrentProcess->IOCurMap = MapNumber;
    00138
    00139         //
    00140         // BUGBUG: Need to set the EFLAGS.iopl to 3 for this process
    00141         // and all threads in the process as well?
    00142         //
    00143
    00144     res = KiIA32SetPortMemory(CurrentProcess);
    00145
    00146     //
    00147     // Restore IRQL and unlock the context swap lock.
    00148     //
    00149
    00150     KiUnlockContextSwap(OldIrql);
    00151     return res;
    00152 }
    00153
    00154
    00155 BOOLEAN
    00156 KeIA32QueryIoAccessMap (
    00157     ULONG MapNumber,
    00158     PKIO_ACCESS_MAP IoAccessMap
    00159     )
    00160
    00161 /*++
    00162
    00163 Routine Description:
    00164
    00165     The specified i/o access map will be dumped into the buffer.
    00166     map 0 is a constant, but will be dumped anyway.
    00167
    00168 Arguments:
    00169
    00170     MapNumber - Number of access map to set.  map 0 is fixed.
    00171
    00172     IoAccessMap - Pointer to buffer (64K bits, 8K bytes) which
    00173            is to receive the definition of the access map.
    00174            Must be in non-paged pool.
    00175
    00176 Return Value:
    00177
    00178     TRUE if successful.  FALSE if failure (attempt to query a map
    00179     which does not exist)
    00180
    00181 --*/
    00182
    00183 {
    00184     PVOID Map;
    00185     KIRQL OldIrql;
    00186
    00187     //
    00188     // Reject illegal requests
    00189     //
    00190
    00191     if (MapNumber > IOPM_COUNT) {
    00192         return FALSE;
    00193     }
    00194
    00195     //
    00196     // BUGBUG: Do we care if a context switch occurs? What if someone
    00197     // else is modifying map N? (just an issue with MP systems...)
    00198     //
    00199
    00200     //
    00201     // Copy out the map
    00202     //
    00203
    00204     if (MapNumber == IO_ACCESS_MAP_NONE) {
    00205
    00206         //
    00207         // no access case, simply return a map of all 1s
    00208         //
    00209                 RtlFillMemory((PVOID) IoAccessMap, IOPM_SIZE, 0x0ff);
    00210
    00211     } else {
    00212
    00213         //
    00214         // normal case, just copy the bits
    00215         //
    00216
    00217         Map = VdmIoMaps[MapNumber-1];
    00218         ASSERT(Map != NULL);
    00219         RtlMoveMemory((PVOID)IoAccessMap, Map, IOPM_SIZE);
    00220     }
    00221
    00222     return TRUE;
    00223 }
    00224
    00225
    00226 BOOLEAN
    00227 KeIA32IoSetAccessProcess (
    00228     PKPROCESS Process,
    00229     ULONG MapNumber
    00230     )
    00231 /*++
    00232
    00233 Routine Description:
    00234
    00235     Set the i/o access map which controls user mode i/o access
    00236     for a particular process.
    00237
    00238 Arguments:
    00239
    00240     Process - Pointer to kernel process object describing the
    00241     process which for which a map is to be set.
    00242
    00243     MapNumber - Number of the map to set.  Value of map is
    00244     defined by KeIA32IoSetAccessProcess.  Setting MapNumber
    00245     to IO_ACCESS_MAP_NONE will disallow any user mode i/o
    00246     access from the process.
    00247
    00248 Return Value:
    00249
    00250     TRUE if success, FALSE if failure (illegal MapNumber)
    00251
    00252 --*/
    00253
    00254 {
    00255     //
    00256     // Reject illegal requests
    00257     //
    00258
    00259     if (MapNumber > IOPM_COUNT) {
    00260         return FALSE;
    00261     }
    00262
    00263     //
    00264     // Store new offset in process object,  compute current set of
    00265     // active processors for process, if this cpu is one, set IOPM.
    00266     //
    00267
    00268     Process->IOCurMap = MapNumber;
    00269     if (Process->IOCurMap == IO_ACCESS_MAP_NONE) {
    00270         //
    00271         // BUGBUG: Need to set the EFLAGS.iopl back to 0 for this process
    00272         // And all its threads?
    00273         //
    00274         }
    00275         else {
    00276         //
    00277         // BUGBUG: Need to set the EFLAGS.iopl to 3 for this process
    00278         // And all its threads?
    00279         //
    00280         }
    00281
    00282     return (KiIA32SetPortMemory(Process));
    00283 }
    00284
    00285
    00286 BOOLEAN
    00287 KeIA32PortIsAccessable(
    00288     PKPROCESS Process,
    00289     ULONG Port,
    00290     ULONG Size
    00291     )
    00292 /*++
    00293
    00294 Routine Description:
    00295
    00296     Checks to see if a particular port is accessable by a particular process
    00297
    00298 Arguments:
    00299
    00300     Process - Pointer to kernel process object
    00301
    00302     Port - port number to check
    00303
    00304     Size - size of access (1, 2 or 4 bytes)
    00305
    00306 Return Value:
    00307
    00308     TRUE if port is accessable, false if port is not
    00309
    00310 --*/
    00311 {
    00312     ULONG byte;
    00313     ULONG bit;
    00314     ULONG val;
    00315     ULONG ToTest;
    00316     PUCHAR ioBits;
    00317
    00318     if (Process->IOCurMap == IO_ACCESS_MAP_NONE) {
    00319         return FALSE;
    00320     }
    00321
    00322     //
    00323     // Make sure everything is legit...
    00324     //
    00325     ASSERT (Process->IOCurMap <= IOPM_COUNT);
    00326     ASSERT (Port < (64 * 1024));
    00327     ASSERT((Size == 1) || (Size == 2) || (Size == 4));
    00328
    00329     ioBits = VdmIoMaps[Process->IOCurMap - 1];
    00330
    00331     //
    00332     // Get the byte to be tested
    00333     //
    00334     byte = Port >> 3;
    00335
    00336     //
    00337     // This handles boundary conditions...
    00338     //
    00339     ToTest = ioBits[byte] | (ioBits[byte + 1] << 8);
    00340
    00341     //
    00342     // And get the specific bit
    00343     //
    00344     bit = Port & 0x07;
    00345
    00346     //
    00347     // Really want Size to be 1, 2, or 3 so we can use it for shifting and
    00348     // we want val to be a mask for the port access
    00349     // (2^Size -1 == mask for size of port access)...
    00350     //
    00351     if (Size == 4) {
    00352         val = 7 << bit;
    00353     }
    00354     else {
    00355         val = ((1 << Size) - 1) << bit;
    00356     }
    00357
    00358     return (! (ToTest & val));
    00359 }
    00360
    00361
    00362 BOOLEAN
    00363 KiIA32SetPortMemory(
    00364     PKPROCESS Process
    00365     )
    00366 /*++
    00367
    00368 Routine Description:
    00369
    00370     Based on the IO access allowed for a particular process, set the memory
    00371     map accordingly...
    00372
    00373 Arguments:
    00374
    00375     Process - Pointer to kernel process object
    00376
    00377 Return Value:
    00378
    00379     TRUE if able to setup the memory pages
    00380
    00381 Notes:
    00382         It would be a lot faster to use a bit searching algorithm
    00383         looking for the first 0 bit (accessible) instead of
    00384         doing 8192 calls to the memory system... Of course, we may
    00385         do this infrequently enough that it may not matter...
    00386
    00387 --*/
    00388 {
    00389     PUCHAR ioBits;
    00390     ULONG i;
    00391     PVOID VirtualPort;
    00392
    00393     if (Process->IOCurMap == IO_ACCESS_MAP_NONE) {
    00394         // Unmap all of the IOBASE memory?
    00395         // Or set them all as Inaccesable?
    00396
    00397         return TRUE;
    00398     }
    00399
    00400     ioBits = VdmIoMaps[Process->IOCurMap - 1];
    00401
    00402     for (i = 0; i < IOPM_SIZE; i++) {
    00403         // VirtualPort = (i << SHIFT_8K) + IOBASE;
    00404         if ((*ioBits & 0x000f) == 0) {
    00405             // These four ports can be set read/writable
    00406             // Call memory manager to set read/writable + IO special
    00407         }
    00408         else {
    00409             // Call memory manager to set as inaccessable/unmap
    00410         }
    00411
    00412         // VirtualPort = (i << SHIFT_8K) + IOBASE + (4K_PAGE);
    00413         if ((*ioBits++ & 0x00f0) == 0) {
    00414             // These four ports can be set read/writable
    00415             // Call memory manager to set read/writable + IO special
    00416         }
    00417         else {
    00418             // Call memory manager to set as inaccessable/unmap
    00419         }
    00420     }
    00421
    00422     return TRUE;
    00423 }