test: ldtsup.c Source File

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

# ldtsup.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1991  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     ldtsup.c
    00008
    00009 Abstract:
    00010
    00011     This module implements interfaces that support manipulation of i386 Ldts.
    00012     These entry points only exist on i386 machines.
    00013
    00014 Author:
    00015
    00016     Bryan M. Willman (bryanwi) 14-May-1991
    00017
    00018 Environment:
    00019
    00020     Kernel mode only.
    00021
    00022 Revision History:
    00023
    00024 --*/
    00025
    00026 #include "ki.h"
    00027
    00028 //
    00029 // Low level assembler support procedures
    00030 //
    00031
    00032 VOID
    00033 KiLoadLdtr(
    00034     VOID
    00035     );
    00036
    00037 VOID
    00038 KiFlushDescriptors(
    00039     VOID
    00040     );
    00041
    00042 //
    00043 // Local service procedures
    00044 //
    00045
    00046 VOID
    00047 Ki386LoadTargetLdtr (
    00048     IN PKIPI_CONTEXT SignalDone,
    00049     IN PVOID Parameter1,
    00050     IN PVOID Parameter2,
    00051     IN PVOID Parameter3
    00052     );
    00053
    00054 VOID
    00055 Ki386FlushTargetDescriptors (
    00056     IN PKIPI_CONTEXT SignalDone,
    00057     IN PVOID Parameter1,
    00058     IN PVOID Parameter2,
    00059     IN PVOID Parameter3
    00060     );
    00061
    00062 VOID
    00063 Ke386SetLdtProcess (
    00064     IN PKPROCESS Process,
    00065     IN PLDT_ENTRY Ldt,
    00066     IN ULONG Limit
    00067     )
    00068 /*++
    00069
    00070 Routine Description:
    00071
    00072     The specified LDT (which may be null) will be made the active Ldt of
    00073     the specified process, for all threads thereof, on whichever
    00074     processors they are running.  The change will take effect before the
    00075     call returns.
    00076
    00077     An Ldt address of NULL or a Limit of 0 will cause the process to
    00078     receive the NULL Ldt.
    00079
    00080     This function only exists on i386 and i386 compatible processors.
    00081
    00082     No checking is done on the validity of Ldt entries.
    00083
    00084
    00085     N.B.
    00086
    00087     While a single Ldt structure can be shared amoung processes, any
    00088     edits to the Ldt of one of those processes will only be synchronized
    00089     for that process.  Thus, processes other than the one the change is
    00090     applied to may not see the change correctly.
    00091
    00092 Arguments:
    00093
    00094     Process - Pointer to KPROCESS object describing the process for
    00095         which the Ldt is to be set.
    00096
    00097     Ldt - Pointer to an array of LDT_ENTRYs (that is, a pointer to an
    00098         Ldt.)
    00099
    00100     Limit - Ldt limit (must be 0 mod 8)
    00101
    00102 Return Value:
    00103
    00104     None.
    00105
    00106 --*/
    00107
    00108 {
    00109
    00110     KGDTENTRY LdtDescriptor;
    00111     BOOLEAN LocalProcessor;
    00112     KIRQL OldIrql;
    00113     PKPRCB Prcb;
    00114     KAFFINITY TargetProcessors;
    00115
    00116     //
    00117     // Compute the contents of the Ldt descriptor
    00118     //
    00119
    00120     if ((Ldt == NULL) || (Limit == 0)) {
    00121
    00122         //
    00123         //  Set up an empty descriptor
    00124         //
    00125
    00126         LdtDescriptor.LimitLow = 0;
    00127         LdtDescriptor.BaseLow = 0;
    00128         LdtDescriptor.HighWord.Bytes.BaseMid = 0;
    00129         LdtDescriptor.HighWord.Bytes.Flags1 = 0;
    00130         LdtDescriptor.HighWord.Bytes.Flags2 = 0;
    00131         LdtDescriptor.HighWord.Bytes.BaseHi = 0;
    00132
    00133     } else {
    00134
    00135         //
    00136         // Insure that the unfilled fields of the selector are zero
    00137         // N.B.  If this is not done, random values appear in the high
    00138         //       portion of the Ldt limit.
    00139         //
    00140
    00141         LdtDescriptor.HighWord.Bytes.Flags1 = 0;
    00142         LdtDescriptor.HighWord.Bytes.Flags2 = 0;
    00143
    00144         //
    00145         //  Set the limit and base
    00146         //
    00147
    00148         LdtDescriptor.LimitLow = (USHORT) ((ULONG) Limit - 1);
    00149         LdtDescriptor.BaseLow = (USHORT)  ((ULONG) Ldt & 0xffff);
    00150         LdtDescriptor.HighWord.Bytes.BaseMid = (UCHAR) (((ULONG)Ldt & 0xff0000) >> 16);
    00151         LdtDescriptor.HighWord.Bytes.BaseHi =  (UCHAR) (((ULONG)Ldt & 0xff000000) >> 24);
    00152
    00153         //
    00154         //  Type is LDT, DPL = 0
    00155         //
    00156
    00157         LdtDescriptor.HighWord.Bits.Type = TYPE_LDT;
    00158         LdtDescriptor.HighWord.Bits.Dpl = DPL_SYSTEM;
    00159
    00160         //
    00161         // Make it present
    00162         //
    00163
    00164         LdtDescriptor.HighWord.Bits.Pres = 1;
    00165
    00166     }
    00167
    00168     //
    00169     // Acquire the context swap lock so a context switch cannot occur.
    00170     //
    00171
    00172     KiLockContextSwap(&OldIrql);
    00173
    00174     //
    00175     // Set the Ldt fields in the process object.
    00176     //
    00177
    00178     Process->LdtDescriptor = LdtDescriptor;
    00179
    00180     //
    00181     // Tell all processors active for this process to reload their LDTs
    00182     //
    00183
    00184 #ifdef NT_UP
    00185
    00186     KiLoadLdtr();
    00187
    00188 #else
    00189
    00190     Prcb = KeGetCurrentPrcb();
    00191     TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
    00192     if (TargetProcessors != 0) {
    00193         KiIpiSendPacket(TargetProcessors,
    00194                         Ki386LoadTargetLdtr,
    00195                         NULL,
    00196                         NULL,
    00197                         NULL);
    00198     }
    00199
    00200     KiLoadLdtr();
    00201     if (TargetProcessors != 0) {
    00202
    00203         //
    00204         //  Stall until target processor(s) release us
    00205         //
    00206
    00207         KiIpiStallOnPacketTargets(TargetProcessors);
    00208     }
    00209
    00210 #endif
    00211
    00212     //
    00213     // Restore IRQL and release the context swap lock.
    00214     //
    00215
    00216     KiUnlockContextSwap(OldIrql);
    00217     return;
    00218 }
    00219
    00220 VOID
    00221 Ki386LoadTargetLdtr (
    00222     IN PKIPI_CONTEXT SignalDone,
    00223     IN PVOID Parameter1,
    00224     IN PVOID Parameter2,
    00225     IN PVOID Parameter3
    00226     )
    00227 /*++
    00228
    00229 Routine Description:
    00230
    00231     Reload local Ldt register and clear signal bit in TargetProcessor mask
    00232
    00233 Arguments:
    00234
    00235     Argument - pointer to a ipi packet structure.
    00236     ReadyFlag - Pointer to flag to be set once LDTR has been reloaded
    00237
    00238 Return Value:
    00239
    00240     none.
    00241
    00242 --*/
    00243 {
    00244
    00245     //
    00246     // Reload the LDTR register from currently active process object
    00247     //
    00248
    00249     KiLoadLdtr();
    00250     KiIpiSignalPacketDone(SignalDone);
    00251     return;
    00252 }
    00253
    00254 VOID
    00255 Ke386SetDescriptorProcess (
    00256     IN PKPROCESS Process,
    00257     IN ULONG Offset,
    00258     IN LDT_ENTRY LdtEntry
    00259     )
    00260 /*++
    00261
    00262 Routine Description:
    00263
    00264     The specified LdtEntry (which could be 0, not present, etc) will be
    00265     edited into the specified Offset in the Ldt of the specified Process.
    00266     This will be synchronzied accross all the processors executing the
    00267     process.  The edit will take affect on all processors before the call
    00268     returns.
    00269
    00270     N.B.
    00271
    00272     Editing an Ldt descriptor requires stalling all processors active
    00273     for the process, to prevent accidental loading of descriptors in
    00274     an inconsistent state.
    00275
    00276 Arguments:
    00277
    00278     Process - Pointer to KPROCESS object describing the process for
    00279         which the descriptor edit is to be performed.
    00280
    00281     Offset - Byte offset into the Ldt of the descriptor to edit.
    00282         Must be 0 mod 8.
    00283
    00284     LdtEntry - Value to edit into the descriptor in hardware format.
    00285         No checking is done on the validity of this item.
    00286
    00287 Return Value:
    00288
    00289     none.
    00290
    00291 --*/
    00292
    00293 {
    00294
    00295     PLDT_ENTRY Ldt;
    00296     KIRQL OldIrql;
    00297     PKPRCB Prcb;
    00298     KAFFINITY TargetProcessors;
    00299
    00300     //
    00301     // Compute address of descriptor to edit.
    00302     //
    00303
    00304     Ldt =
    00305         (PLDT_ENTRY)
    00306          ((Process->LdtDescriptor.HighWord.Bytes.BaseHi << 24) |
    00307          ((Process->LdtDescriptor.HighWord.Bytes.BaseMid << 16) & 0xff0000) |
    00308          (Process->LdtDescriptor.BaseLow & 0xffff));
    00309     Offset = Offset / 8;
    00310     MmLockPagedPool(&Ldt[Offset], sizeof(LDT_ENTRY));
    00311     KiLockContextSwap(&OldIrql);
    00312
    00313 #ifdef NT_UP
    00314
    00315     //
    00316     // Edit the Ldt.
    00317     //
    00318
    00319     Ldt[Offset] = LdtEntry;
    00320
    00321 #else
    00322
    00323     Prcb = KeGetCurrentPrcb();
    00324     TargetProcessors = Process->ActiveProcessors & ~Prcb->SetMember;
    00325     if (TargetProcessors != 0) {
    00326         KiIpiSendSynchronousPacket(
    00327             Prcb,
    00328             TargetProcessors,
    00329             Ki386FlushTargetDescriptors,
    00330             (PVOID)&Prcb->ReverseStall,
    00331             NULL,
    00332             NULL);
    00333
    00334         KiIpiStallOnPacketTargets(TargetProcessors);
    00335     }
    00336
    00337     //
    00338     // All target processors have flushed the segment descriptors and
    00339     // are waiting to proceed. Edit the ldt on the current processor,
    00340     // then continue the execution of target processors.
    00341     //
    00342
    00343     Ldt[Offset] = LdtEntry;
    00344     if (TargetProcessors != 0) {
    00345         Prcb->ReverseStall += 1;
    00346     }
    00347
    00348 #endif
    00349
    00350     //
    00351     // Restore IRQL and release the context swap lock.
    00352     //
    00353
    00354     KiUnlockContextSwap(OldIrql);
    00355     MmUnlockPagedPool(&Ldt[Offset], sizeof(LDT_ENTRY));
    00356     return;
    00357 }
    00358
    00359 VOID
    00360 Ki386FlushTargetDescriptors (
    00361     IN PKIPI_CONTEXT SignalDone,
    00362     IN PVOID Proceed,
    00363     IN PVOID Parameter2,
    00364     IN PVOID Parameter3
    00365     )
    00366
    00367 /*++
    00368
    00369 Routine Description:
    00370
    00371     This function flushes the segment descriptors on the current processor.
    00372
    00373 Arguments:
    00374
    00375     Argument - pointer to a _KIPI_FLUSH_DESCRIPTOR structure.
    00376
    00377     ReadyFlag - pointer to flag to syncroize with
    00378
    00379 Return Value:
    00380
    00381     none.
    00382
    00383 --*/
    00384
    00385 {
    00386     //
    00387     // Flush the segment descriptors on the current processor and signal that
    00388     // the descriptors have been flushed.
    00389     //
    00390
    00391     KiFlushDescriptors();
    00392     KiIpiSignalPacketDoneAndStall (SignalDone, Proceed);
    00393     return;
    00394 }