00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
#include "ki.h"
00026
00027 extern BOOLEAN
KeI386FxsrPresent;
00028 extern BOOLEAN
KeI386XMMIPresent;
00029
00030
00031
00032
00033 typedef struct _CONTROL_WORD {
00034 USHORT ControlWord;
00035 ULONG
MXCsr;
00036 }
CONTROL_WORD, *
PCONTROL_WORD;
00037
00038 typedef struct {
00039 UCHAR Flags;
00040 KIRQL Irql;
00041 KIRQL PreviousNpxIrql;
00042 UCHAR Spare[2];
00043
00044
union {
00045 CONTROL_WORD Fcw;
00046 PFX_SAVE_AREA Context;
00047 } u;
00048 ULONG Cr0NpxState;
00049
00050 PKTHREAD Thread;
00051
00052 }
FLOAT_SAVE, *
PFLOAT_SAVE;
00053
00054
00055 #define FLOAT_SAVE_COMPLETE_CONTEXT 0x01
00056 #define FLOAT_SAVE_FREE_CONTEXT_HEAP 0x02
00057 #define FLOAT_SAVE_VALID 0x04
00058 #define FLOAT_SAVE_RESERVED 0xF8
00059
00060
#pragma warning(disable:4035) // re-enable below
00061
00062
00063
00064
00065 __inline
00066 KIRQL
00067 Kix86FxSave(
00068 PULONG NpxFrame
00069 )
00070 {
00071 _asm {
00072 mov eax, NpxFrame
00073 ;fxsave [eax]
00074 _emit 0fh
00075 _emit 0aeh
00076 _emit 0
00077 }
00078 }
00079
00080
00081
00082 __inline
00083 KIRQL
00084 Kix86FnSave(
00085 PULONG NpxFrame
00086 )
00087 {
00088 __asm {
00089 mov eax, NpxFrame
00090 fnsave [eax]
00091 }
00092 }
00093
00094
00095
00096
00097 __inline
00098 KIRQL
00099 Kix86LdMXCsr(
00100 PULONG MXCsr
00101 )
00102 {
00103 _asm {
00104 mov eax, MXCsr
00105 ;LDMXCSR [eax]
00106 _emit 0fh
00107 _emit 0aeh
00108 _emit 10h
00109 }
00110 }
00111
00112
00113
00114
00115 __inline
00116 KIRQL
00117 Kix86StMXCsr(
00118 PULONG MXCsr
00119 )
00120 {
00121 _asm {
00122 mov eax, MXCsr
00123 ;STMXCSR [eax]
00124 _emit 0fh
00125 _emit 0aeh
00126 _emit 18h
00127 }
00128 }
00129
#pragma warning(default:4035)
00130
00131
00132
NTSTATUS
00133 KeSaveFloatingPointState (
00134 OUT PKFLOATING_SAVE PublicFloatSave
00135 )
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 {
00151
PKTHREAD Thread;
00152 PFX_SAVE_AREA NpxFrame;
00153 KIRQL Irql;
00154
USHORT ControlWord;
00155 ULONG MXCsr;
00156 PKPRCB Prcb;
00157
PFLOAT_SAVE FloatSave;
00158
00159
00160
00161
00162
00163
00164
if (!
KeI386NpxPresent) {
00165
return STATUS_ILLEGAL_FLOAT_CONTEXT;
00166 }
00167
00168
00169
00170
00171
00172 FloatSave = (
PFLOAT_SAVE) PublicFloatSave;
00173
00174 Irql = KeGetCurrentIrql();
00175 Thread =
KeGetCurrentThread();
00176
00177
ASSERT (Thread->
NpxIrql <= Irql);
00178
00179 FloatSave->Flags = 0;
00180 FloatSave->Irql = Irql;
00181 FloatSave->PreviousNpxIrql = Thread->
NpxIrql;
00182 FloatSave->Thread = Thread;
00183
00184
00185
00186
00187
00188
00189
if (Thread->
NpxIrql != Irql) {
00190
00191
00192
00193
00194
00195
00196
if (Irql ==
APC_LEVEL) {
00197 FloatSave->u.Context =
ExAllocatePoolWithTag (
00198
NonPagedPool,
00199
sizeof (FX_SAVE_AREA),
00200 ' XPN'
00201 );
00202
00203
if (!FloatSave->u.Context) {
00204
return STATUS_INSUFFICIENT_RESOURCES;
00205 }
00206
00207 FloatSave->Flags |=
FLOAT_SAVE_FREE_CONTEXT_HEAP;
00208
00209 }
else {
00210
00211
ASSERT (Irql ==
DISPATCH_LEVEL);
00212 FloatSave->u.Context = &
KeGetCurrentPrcb()->NpxSaveArea;
00213
00214 }
00215
00216 FloatSave->Flags |=
FLOAT_SAVE_COMPLETE_CONTEXT;
00217 }
00218
00219
00220
00221
00222
00223 _asm {
00224 cli
00225 mov eax, cr0
00226 mov ecx, eax
00227 and eax, not (CR0_MP|CR0_EM|CR0_TS)
00228 cmp eax, ecx
00229 je
short sav10
00230
00231 mov cr0, eax
00232 sav10:
00233 }
00234
00235 Prcb =
KeGetCurrentPrcb();
00236
00237
00238
00239
00240
00241
if (Prcb->NpxThread != Thread) {
00242
00243
00244
00245
00246
00247
if (Prcb->NpxThread) {
00248
00249 NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Prcb->NpxThread->InitialStack) -
00250
sizeof(FX_SAVE_AREA)));
00251
00252
if (
KeI386FxsrPresent) {
00253
Kix86FxSave((PULONG)NpxFrame);
00254 }
else {
00255
Kix86FnSave((PULONG)NpxFrame);
00256 }
00257
00258 NpxFrame->NpxSavedCpu = 0;
00259 Prcb->NpxThread->NpxState = NPX_STATE_NOT_LOADED;
00260
00261 }
00262
00263 Prcb->NpxThread = Thread;
00264 }
00265
00266 NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->
InitialStack) -
00267
sizeof(FX_SAVE_AREA)));
00268
00269
00270
00271
00272
00273
00274
if (FloatSave->Flags &
FLOAT_SAVE_COMPLETE_CONTEXT) {
00275
00276
00277
00278
00279
00280
if (Thread->
NpxState == NPX_STATE_LOADED) {
00281
if (
KeI386FxsrPresent) {
00282
Kix86FxSave ((PULONG)(FloatSave->u.Context));
00283 }
else {
00284
Kix86FnSave ((PULONG)(FloatSave->u.Context));
00285 }
00286
00287 FloatSave->u.Context->NpxSavedCpu = 0;
00288 FloatSave->u.Context->Cr0NpxState = NpxFrame->Cr0NpxState;
00289
00290 }
else {
00291 RtlCopyMemory (FloatSave->u.Context, NpxFrame,
sizeof(FX_SAVE_AREA));
00292 FloatSave->u.Context->NpxSavedCpu = 0;
00293
00294 }
00295
00296 }
else {
00297
00298
00299
00300
00301
00302
if (Thread->
NpxState == NPX_STATE_LOADED) {
00303
00304 _asm {
00305 mov eax, FloatSave
00306 fnstcw [eax]
FLOAT_SAVE.u.Fcw.ControlWord
00307 }
00308
00309
if ((
KeI386FxsrPresent) && (
KeI386XMMIPresent)) {
00310
Kix86StMXCsr(&FloatSave->u.Fcw.MXCsr);
00311 }
00312
00313 }
else {
00314
00315
00316
00317
00318
if (
KeI386FxsrPresent) {
00319 FloatSave->u.Fcw.ControlWord = (
USHORT) NpxFrame->U.FxArea.ControlWord;
00320 FloatSave->u.Fcw.MXCsr = NpxFrame->U.FxArea.MXCsr;
00321
00322 }
else {
00323 FloatSave->u.Fcw.ControlWord = (
USHORT) NpxFrame->U.FnArea.ControlWord;
00324 }
00325 }
00326
00327
00328
00329
00330
00331
00332
00333 FloatSave->Cr0NpxState = NpxFrame->Cr0NpxState & ~CR0_TS;
00334 }
00335
00336
00337
00338
00339
00340
00341 NpxFrame->Cr0NpxState = 0;
00342 Thread->
NpxState = NPX_STATE_LOADED;
00343 Thread->
NpxIrql = Irql;
00344 ControlWord = 0x27f;
00345 MXCsr = 0x1f80;
00346
00347 _asm {
00348 fninit
00349 fldcw ControlWord
00350 }
00351
00352
if ((
KeI386FxsrPresent) && (
KeI386XMMIPresent)) {
00353
Kix86LdMXCsr(&MXCsr);
00354 }
00355
00356 _asm {
00357 sti
00358 }
00359
00360 FloatSave->Flags |=
FLOAT_SAVE_VALID;
00361
return STATUS_SUCCESS;
00362 }
00363
00364
00365
NTSTATUS
00366 KeRestoreFloatingPointState (
00367 IN PKFLOATING_SAVE PublicFloatSave
00368 )
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 {
00384
PKTHREAD Thread;
00385 PFX_SAVE_AREA NpxFrame;
00386 ULONG Cr0State;
00387
PFLOAT_SAVE FloatSave;
00388
00389
ASSERT (
KeI386NpxPresent);
00390
00391 FloatSave = (
PFLOAT_SAVE) PublicFloatSave;
00392 Thread = FloatSave->Thread;
00393
00394 NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->
InitialStack) -
00395
sizeof(FX_SAVE_AREA)));
00396
00397
00398
00399
00400
00401
00402
if ((FloatSave->Flags & (
FLOAT_SAVE_VALID |
FLOAT_SAVE_RESERVED)) !=
FLOAT_SAVE_VALID) {
00403
00404
00405
00406
DbgPrint(
"KeRestoreFloatingPointState: Invalid float save area\n");
00407 DbgBreakPoint();
00408 }
00409
00410
if (FloatSave->Irql != KeGetCurrentIrql()) {
00411
00412
00413
DbgPrint(
"KeRestoreFloatingPointState: Invalid IRQL\n");
00414 DbgBreakPoint();
00415 }
00416
00417
if (Thread !=
KeGetCurrentThread()) {
00418
00419
00420
DbgPrint(
"KeRestoreFloatingPointState: Invalid thread\n");
00421 DbgBreakPoint();
00422 }
00423
00424
00425
00426
00427
00428
00429 _asm {
00430 cli
00431 }
00432
00433
00434
00435
00436
00437
if (FloatSave->Flags &
FLOAT_SAVE_COMPLETE_CONTEXT) {
00438
00439
00440
00441
00442
00443
if (Thread->
NpxState == NPX_STATE_LOADED) {
00444
00445
00446
00447
00448
00449 Thread->
NpxState = NPX_STATE_NOT_LOADED;
00450
KeGetCurrentPrcb()->NpxThread =
NULL;
00451 }
00452
00453
00454
00455
00456
00457 RtlCopyMemory (NpxFrame, FloatSave->u.Context,
sizeof(FX_SAVE_AREA));
00458
00459 }
else {
00460
00461
00462
00463
00464
00465
if (Thread->
NpxState == NPX_STATE_LOADED) {
00466
00467
00468
00469
00470
00471 _asm {
00472 fninit
00473 mov eax, FloatSave
00474 fldcw [eax]
FLOAT_SAVE.u.Fcw.ControlWord
00475 }
00476
00477
00478
if ((
KeI386FxsrPresent) && (
KeI386XMMIPresent)) {
00479
Kix86LdMXCsr(&FloatSave->u.Fcw.MXCsr);
00480 }
00481
00482
00483 }
else {
00484
00485
00486
00487
00488
00489
if (
KeI386FxsrPresent) {
00490 NpxFrame->U.FxArea.ControlWord = FloatSave->u.Fcw.ControlWord;
00491 NpxFrame->U.FxArea.StatusWord = 0;
00492 NpxFrame->U.FxArea.TagWord = 0;
00493 NpxFrame->NpxSavedCpu = 0;
00494 NpxFrame->U.FxArea.MXCsr = FloatSave->u.Fcw.MXCsr;
00495
00496 }
else {
00497 NpxFrame->U.FnArea.ControlWord = FloatSave->u.Fcw.ControlWord;
00498 NpxFrame->U.FnArea.StatusWord = 0;
00499 NpxFrame->U.FnArea.TagWord = 0xffff;
00500 }
00501
00502 }
00503
00504 NpxFrame->Cr0NpxState = FloatSave->Cr0NpxState;
00505 }
00506
00507
00508
00509
00510
00511 Thread->
NpxIrql = FloatSave->PreviousNpxIrql;
00512 Cr0State = Thread->
NpxState | NpxFrame->Cr0NpxState;
00513
00514 _asm {
00515 mov eax, cr0
00516 mov ecx, eax
00517 and eax, not (CR0_MP|CR0_EM|CR0_TS)
00518 or eax, Cr0State
00519 cmp eax, ecx
00520 je
short res10
00521 mov cr0, eax
00522 res10:
00523 sti
00524 }
00525
00526
00527
00528
00529
00530
if (FloatSave->Flags &
FLOAT_SAVE_FREE_CONTEXT_HEAP) {
00531
ExFreePool (FloatSave->u.Context);
00532 }
00533
00534 FloatSave->Flags = 0;
00535
return STATUS_SUCCESS;
00536 }
00537
00538
#pragma optimize( "y", off ) // disable frame pointer omission (FPO)
00539
00540
VOID
00541 __cdecl
00542 KeSaveStateForHibernate(
00543 IN PKPROCESSOR_STATE ProcessorState
00544 )
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 {
00570 RtlCaptureContext(&ProcessorState->ContextFrame);
00571
KiSaveProcessorControlState(ProcessorState);
00572 }
00573
#pragma optimize( "y", off ) // disable frame pointer omission (FPO)