00001
#include "ki.h"
00002
00003 #define STATIC
00004
00005 #define IDBG 0
00006
00007
#if DBG
00008
#define DBGMSG(a) DbgPrint(a)
00009
#else
00010 #define DBGMSG(a)
00011
#endif
00012
00013
00014
00015
00016
00017
NTSTATUS
00018
KiLoadMTRR (
00019 PVOID Context
00020 );
00021
00022
00023
00024
00025
00026
00027
00028 typedef struct _AMDK6_MTRR {
00029 ULONG
type:2;
00030 ULONG
mask:15;
00031 ULONG
base:15;
00032 }
AMDK6_MTRR, *
PAMDK6_MTRR;
00033
00034
00035
00036 typedef struct _AMDK6_MTRR_MSR_IMAGE {
00037
union {
00038
struct {
00039 AMDK6_MTRR mtrr0;
00040 AMDK6_MTRR mtrr1;
00041 } hw;
00042 ULONGLONG
QuadPart;
00043 } u;
00044 }
AMDK6_MTRR_MSR_IMAGE, *
PAMDK6_MTRR_MSR_IMAGE;
00045
00046
00047
00048 #define AMDK6_MTRR_TYPE_DISABLED 0
00049 #define AMDK6_MTRR_TYPE_UC 1
00050 #define AMDK6_MTRR_TYPE_WC 2
00051 #define AMDK6_MTRR_TYPE_MASK 3
00052
00053
00054
00055 #define AMDK6_MTRR_MSR 0xC0000085
00056
00057
00058
00059
00060
00061
00062
00063 typedef struct _AMDK6_MTRR_REGION {
00064 ULONG
BaseAddress;
00065 ULONG
Size;
00066 MEMORY_CACHING_TYPE RegionType;
00067 ULONG
RegionFlags;
00068 }
AMDK6_MTRR_REGION, *
PAMDK6_MTRR_REGION;
00069
00070 #define MAX_K6_REGIONS 2 // Limit the write combined regions to 2 since that's how many MTRRs we have available.
00071
00072
00073
00074
00075
00076 #define AMDK6_REGION_UNUSED 0xFFFFFFFF
00077
00078
00079
00080
00081
00082 #define AMDK6_REGION_FLAGS_BIOS 0x00000001
00083
00084
00085
00086
00087
00088 #define AMDK6_MAX_MTRR 2
00089
00090
00091
00092
00093
00094
VOID
00095
KiAmdK6InitializeMTRR (
00096 VOID
00097 );
00098
00099
NTSTATUS
00100
KiAmdK6RestoreMTRR (
00101 );
00102
00103
NTSTATUS
00104
KiAmdK6MtrrSetMemoryType (
00105 ULONG BaseAddress,
00106 ULONG Size,
00107 MEMORY_CACHING_TYPE Type
00108 );
00109
00110 BOOLEAN
00111
KiAmdK6AddRegion (
00112 ULONG BaseAddress,
00113 ULONG Size,
00114 MEMORY_CACHING_TYPE Type,
00115 ULONG Flags
00116 );
00117
00118
NTSTATUS
00119
KiAmdK6MtrrCommitChanges (
00120 VOID
00121 );
00122
00123
NTSTATUS
00124
KiAmdK6HandleWcRegionRequest (
00125 ULONG BaseAddress,
00126 ULONG Size
00127 );
00128
00129
VOID
00130
KiAmdK6MTRRAddRegionFromHW (
00131
AMDK6_MTRR RegImage
00132 );
00133
00134
PAMDK6_MTRR_REGION
00135
KiAmdK6FindFreeRegion (
00136 MEMORY_CACHING_TYPE Type
00137 );
00138
00139
#pragma alloc_text(INIT,KiAmdK6InitializeMTRR)
00140
#pragma alloc_text(PAGELK,KiAmdK6RestoreMTRR)
00141
#pragma alloc_text(PAGELK,KiAmdK6MtrrSetMemoryType)
00142
#pragma alloc_text(PAGELK,KiAmdK6AddRegion)
00143
#pragma alloc_text(PAGELK,KiAmdK6MtrrCommitChanges)
00144
#pragma alloc_text(PAGELK,KiAmdK6HandleWcRegionRequest)
00145
#pragma alloc_text(PAGELK,KiAmdK6MTRRAddRegionFromHW)
00146
#pragma alloc_text(PAGELK,KiAmdK6FindFreeRegion)
00147
00148
00149
00150 extern KSPIN_LOCK
KiRangeLock;
00151
00152
00153
00154 AMDK6_MTRR_REGION AmdK6Regions[
MAX_K6_REGIONS];
00155 ULONG
AmdK6RegionCount;
00156
00157
00158
00159 ULONG
AmdMtrrHwUsageCount;
00160
00161
00162
00163 AMDK6_MTRR_MSR_IMAGE KiAmdK6Mtrr;
00164
00165
00166
00167
VOID
00168 KiAmdK6InitializeMTRR (
00169 VOID
00170 )
00171 {
00172 ULONG i;
00173 KIRQL OldIrql;
00174
00175
DBGMSG(
"KiAmdK6InitializeMTRR: Initializing K6 MTRR support\n");
00176
00177
KiAmdK6Mtrr.
u.hw.mtrr0.type =
AMDK6_MTRR_TYPE_DISABLED;
00178
KiAmdK6Mtrr.
u.hw.mtrr1.type =
AMDK6_MTRR_TYPE_DISABLED;
00179
AmdK6RegionCount =
MAX_K6_REGIONS;
00180
AmdMtrrHwUsageCount = 0;
00181
00182
00183
00184
00185
00186
for (i = 0; i <
AmdK6RegionCount; i++) {
00187
AmdK6Regions[i].
BaseAddress =
AMDK6_REGION_UNUSED;
00188
AmdK6Regions[i].
RegionFlags = 0;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
KeInitializeSpinLock (&
KiRangeLock);
00199
00200
00201
00202
00203
00204
00205
00206
KeAcquireSpinLock (&
KiRangeLock, &OldIrql);
00207
00208
KiAmdK6Mtrr.
u.QuadPart =
RDMSR (
AMDK6_MTRR_MSR);
00209
00210
00211
00212
00213
00214
KiAmdK6MTRRAddRegionFromHW(
KiAmdK6Mtrr.
u.hw.mtrr0);
00215
00216
00217
00218
00219
00220
KiAmdK6MTRRAddRegionFromHW(
KiAmdK6Mtrr.
u.hw.mtrr1);
00221
00222
00223
00224
00225
00226
KeReleaseSpinLock (&
KiRangeLock, OldIrql);
00227 }
00228
00229
VOID
00230 KiAmdK6MTRRAddRegionFromHW (
00231
AMDK6_MTRR RegImage
00232 )
00233 {
00234 ULONG BaseAddress,
Size, TempMask;
00235
00236
00237
00238
00239
00240
if (RegImage.
type !=
AMDK6_MTRR_TYPE_DISABLED) {
00241
00242
00243
00244
00245
00246
00247
if ((RegImage.
type &
AMDK6_MTRR_TYPE_UC) == 0) {
00248
00249
00250
00251
00252
00253 BaseAddress = RegImage.
base << 17;
00254
00255
00256
00257
00258
00259 TempMask = RegImage.
mask;
00260
00261
00262
00263
00264
00265
ASSERT (TempMask != 0);
00266
00267
00268
00269
00270
00271
Size = 0x00020000;
00272
00273
while ((TempMask & 0x00000001) == 0) {
00274 TempMask >>= 1;
00275
Size <<= 1;
00276 }
00277
00278
00279
00280
00281
00282
KiAmdK6AddRegion(BaseAddress,
00283
Size,
00284
MmWriteCombined,
00285
AMDK6_REGION_FLAGS_BIOS);
00286
00287
AmdMtrrHwUsageCount++;
00288 }
00289 }
00290 }
00291
00292
00293
NTSTATUS
00294 KiAmdK6MtrrSetMemoryType (
00295 ULONG BaseAddress,
00296 ULONG Size,
00297 MEMORY_CACHING_TYPE Type
00298 )
00299 {
00300
NTSTATUS Status = STATUS_SUCCESS;
00301 KIRQL OldIrql;
00302
00303
switch(Type) {
00304
case MmWriteCombined:
00305
00306
00307
00308
00309
00310
00311
if (KeGetCurrentIrql() >=
DISPATCH_LEVEL) {
00312
00313
00314
00315
00316
00317
00318
DBGMSG (
"KeAmdK6SetPhysicalCacheTypeRange failed due to calling IRQL == DISPATCH_LEVEL\n");
00319
return STATUS_UNSUCCESSFUL;
00320 }
00321
00322
00323
00324
00325
00326
MmLockPagableSectionByHandle(
ExPageLockHandle);
00327
00328
00329
00330
00331
00332
KeAcquireSpinLock (&
KiRangeLock, &OldIrql);
00333
00334
Status =
KiAmdK6HandleWcRegionRequest(BaseAddress,
Size);
00335
00336
00337
00338
00339
00340
KeReleaseSpinLock (&
KiRangeLock, OldIrql);
00341
MmUnlockPagableImageSection(
ExPageLockHandle);
00342
00343
break;
00344
00345
case MmNonCached:
00346
00347
00348
00349
00350
00351
00352
00353
00354
break;
00355
00356
case MmCached:
00357
00358
00359
00360
00361
00362
00363
Status = STATUS_NOT_SUPPORTED;
00364
break;
00365
00366
default:
00367
DBGMSG (
"KeAmdK6SetPhysicalCacheTypeRange: no such cache type\n");
00368
Status = STATUS_INVALID_PARAMETER;
00369
break;
00370 }
00371
return Status;
00372 }
00373
00374
NTSTATUS
00375 KiAmdK6HandleWcRegionRequest (
00376 ULONG BaseAddress,
00377 ULONG Size
00378 )
00379 {
00380 ULONG i;
00381 ULONG AdjustedSize, AdjustedEndAddress, AlignmentMask;
00382 ULONG CombinedBase, CombinedSize, CombinedAdjustedSize;
00383
PAMDK6_MTRR_REGION pRegion;
00384 BOOLEAN bCanCombine, bValidRange;
00385
00386
00387
00388
00389
00390
00391
for (i = 0; i <
AmdK6RegionCount; i++) {
00392 pRegion = &
AmdK6Regions[i];
00393
if ((pRegion->
BaseAddress !=
AMDK6_REGION_UNUSED) &&
00394 (pRegion->
RegionType ==
MmWriteCombined)) {
00395
00396
00397
00398
00399
00400
00401
if (((pRegion->
BaseAddress >= BaseAddress) &&
00402 (pRegion->
BaseAddress <= (BaseAddress +
Size))) ||
00403 ((BaseAddress <= (pRegion->
BaseAddress + pRegion->
Size)) &&
00404 (BaseAddress >= pRegion->
BaseAddress))) {
00405
00406
00407
00408
00409
00410 AdjustedEndAddress = BaseAddress +
Size;
00411
00412
if (pRegion->
BaseAddress < BaseAddress) {
00413 CombinedBase = pRegion->
BaseAddress;
00414 }
else {
00415 CombinedBase = BaseAddress;
00416 }
00417
00418
if ((pRegion->
BaseAddress + pRegion->
Size) >
00419 AdjustedEndAddress) {
00420 CombinedSize = (pRegion->
BaseAddress + pRegion->
Size) -
00421 CombinedBase;
00422 }
else {
00423 CombinedSize = AdjustedEndAddress - CombinedBase;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 CombinedAdjustedSize = 0x80000000;
00435 AlignmentMask = 0x7fffffff;
00436 bCanCombine =
FALSE;
00437
00438
while (CombinedAdjustedSize > 0x00010000) {
00439
00440
00441
00442
00443
00444
if (CombinedAdjustedSize == CombinedSize) {
00445
00446
00447
00448
00449
00450
00451
if ((CombinedBase & AlignmentMask) == 0) {
00452 bCanCombine =
TRUE;
00453 }
00454
00455
break;
00456
00457 }
else {
00458
00459
00460
00461
00462
00463 CombinedAdjustedSize >>= 1;
00464 AlignmentMask >>= 1;
00465 }
00466 }
00467
00468
if (bCanCombine) {
00469
00470
00471
00472
00473
00474 pRegion->
BaseAddress = CombinedBase;
00475 pRegion->
Size = CombinedAdjustedSize;
00476
00477
00478
00479
00480
00481 pRegion->
RegionFlags &= ~
AMDK6_REGION_FLAGS_BIOS;
00482
00483
return KiAmdK6MtrrCommitChanges();
00484 }
00485 }
00486 }
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 AdjustedSize = 0x80000000;
00496 AlignmentMask = 0x7fffffff;
00497 bValidRange =
FALSE;
00498
00499
while (AdjustedSize > 0x00010000) {
00500
00501
00502
00503
00504
00505
if (AdjustedSize ==
Size) {
00506
00507
00508
00509
00510
00511
00512
00513
if ((BaseAddress & AlignmentMask) == 0) {
00514 bValidRange =
TRUE;
00515 }
00516
00517
00518
00519
00520
00521
break;
00522
00523 }
else {
00524
00525
00526
00527
00528
00529 AdjustedSize >>= 1;
00530 AlignmentMask >>= 1;
00531 }
00532 }
00533
00534
00535
00536
00537
00538
if (!bValidRange) {
00539
return STATUS_NOT_SUPPORTED;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
if (!
KiAmdK6AddRegion(BaseAddress, AdjustedSize,
MmWriteCombined, 0)) {
00549
return STATUS_UNSUCCESSFUL;
00550 }
00551
00552
00553
00554
00555
00556
return KiAmdK6MtrrCommitChanges();
00557 }
00558
00559 BOOLEAN
00560 KiAmdK6AddRegion (
00561 ULONG BaseAddress,
00562 ULONG Size,
00563 MEMORY_CACHING_TYPE Type,
00564 ULONG Flags
00565 )
00566 {
00567
PAMDK6_MTRR_REGION pRegion;
00568
00569
if ((pRegion =
KiAmdK6FindFreeRegion(Type)) ==
NULL) {
00570
return FALSE;
00571 }
00572 pRegion->
BaseAddress = BaseAddress;
00573 pRegion->
Size =
Size;
00574 pRegion->
RegionType = Type;
00575 pRegion->
RegionFlags = Flags;
00576
00577
return TRUE;
00578 }
00579
00580
PAMDK6_MTRR_REGION
00581 KiAmdK6FindFreeRegion (
00582 MEMORY_CACHING_TYPE Type
00583 )
00584 {
00585 ULONG i;
00586
00587
00588
00589
00590
00591
00592
if (Type ==
MmWriteCombined) {
00593
if (
AmdMtrrHwUsageCount >=
AMDK6_MAX_MTRR) {
00594
00595
00596
00597
00598
00599
00600
for (i = 0; i <
AmdK6RegionCount; i++) {
00601
if (
AmdK6Regions[i].
RegionFlags &
AMDK6_REGION_FLAGS_BIOS) {
00602
return &
AmdK6Regions[i];
00603 }
00604 }
00605
00606
00607
00608
00609
00610
return FALSE;
00611 }
00612 }
00613
00614
00615
00616
00617
00618
for (i = 0; i <
AmdK6RegionCount; i++) {
00619
if (
AmdK6Regions[i].
BaseAddress ==
AMDK6_REGION_UNUSED) {
00620
00621
if (Type ==
MmWriteCombined) {
00622
AmdMtrrHwUsageCount++;
00623 }
00624
return &
AmdK6Regions[i];
00625 }
00626 }
00627
00628
00629
DBGMSG(
"AmdK6FindFreeRegion: Region Table is Full!\n");
00630
00631
return NULL;
00632 }
00633
00634
NTSTATUS
00635 KiAmdK6MtrrCommitChanges (
00636 VOID
00637 )
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 {
00659 ULONG i, dwWcRangeCount = 0;
00660 ULONG RangeTemp, RangeMask;
00661
00662
00663
00664
00665
00666
KiAmdK6Mtrr.
u.hw.mtrr0.type =
AMDK6_MTRR_TYPE_DISABLED;
00667
KiAmdK6Mtrr.
u.hw.mtrr1.type =
AMDK6_MTRR_TYPE_DISABLED;
00668
00669
00670
00671
00672
00673
for (i = 0; i <
AmdK6RegionCount; i++) {
00674
00675
00676
00677
00678
00679
if ((
AmdK6Regions[i].
BaseAddress !=
AMDK6_REGION_UNUSED) &&
00680 (
AmdK6Regions[i].
RegionType ==
MmWriteCombined)) {
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691 RangeTemp = 0x00020000;
00692 RangeMask = 0xfffe0000;
00693
00694
while (RangeTemp != 0) {
00695
if (RangeTemp ==
AmdK6Regions[i].
Size) {
00696
break;
00697 }
00698 RangeTemp <<= 1;
00699 RangeMask <<= 1;
00700 }
00701
if (RangeTemp == 0) {
00702
00703
00704
00705
00706
00707
DBGMSG (
"AmdK6MtrrCommitChanges: Bad WC range in region table!\n");
00708
00709
return STATUS_NOT_SUPPORTED;
00710 }
00711
00712
00713
00714
00715
00716
if (dwWcRangeCount == 0) {
00717
00718
KiAmdK6Mtrr.
u.hw.mtrr0.base =
AmdK6Regions[i].
BaseAddress >> 17;
00719
KiAmdK6Mtrr.
u.hw.mtrr0.mask = RangeMask >> 17;
00720
KiAmdK6Mtrr.
u.hw.mtrr0.type =
AMDK6_MTRR_TYPE_WC;
00721 dwWcRangeCount++;
00722
00723 }
else if (dwWcRangeCount == 1) {
00724
00725
KiAmdK6Mtrr.
u.hw.mtrr1.base =
AmdK6Regions[i].
BaseAddress >> 17;
00726
KiAmdK6Mtrr.
u.hw.mtrr1.mask = RangeMask >> 17;
00727
KiAmdK6Mtrr.
u.hw.mtrr1.type =
AMDK6_MTRR_TYPE_WC;
00728 dwWcRangeCount++;
00729
00730 }
else {
00731
00732
00733
00734
00735
00736
00737
DBGMSG (
"AmdK6MtrrCommitChanges: Not enough MTRR registers to satisfy region table!\n");
00738
00739
return STATUS_NOT_SUPPORTED;
00740 }
00741 }
00742 }
00743
00744
00745
00746
00747
00748
KiLoadMTRR(
NULL);
00749
00750
return STATUS_SUCCESS;
00751 }
00752
00753
VOID
00754 KiAmdK6MtrrWRMSR (
00755 VOID
00756 )
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 {
00778
00779
00780
00781
00782
WRMSR (
AMDK6_MTRR_MSR,
KiAmdK6Mtrr.
u.QuadPart);
00783 }
00784
00785