12837e00c6d3dc50bcc6ef31be52d8c3d50733a7
[seabios.git] / src / mtrr.c
1 // Initialize MTRRs - mostly useful on KVM.
2 //
3 // Copyright (C) 2006 Fabrice Bellard
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // dprintf
8 #include "biosvar.h" // GET_EBDA
9
10 #define MSR_MTRRcap                    0x000000fe
11 #define MSR_MTRRfix64K_00000           0x00000250
12 #define MSR_MTRRfix16K_80000           0x00000258
13 #define MSR_MTRRfix16K_A0000           0x00000259
14 #define MSR_MTRRfix4K_C0000            0x00000268
15 #define MSR_MTRRfix4K_C8000            0x00000269
16 #define MSR_MTRRfix4K_D0000            0x0000026a
17 #define MSR_MTRRfix4K_D8000            0x0000026b
18 #define MSR_MTRRfix4K_E0000            0x0000026c
19 #define MSR_MTRRfix4K_E8000            0x0000026d
20 #define MSR_MTRRfix4K_F0000            0x0000026e
21 #define MSR_MTRRfix4K_F8000            0x0000026f
22 #define MSR_MTRRdefType                0x000002ff
23
24 #define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
25 #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
26
27 static u64 rdmsr(u32 index)
28 {
29     u64 ret;
30     asm ("rdmsr" : "=A"(ret) : "c"(index));
31     return ret;
32 }
33
34 static void wrmsr(u32 index, u64 val)
35 {
36     asm volatile ("wrmsr" : : "c"(index), "A"(val));
37 }
38
39 static void wrmsr_smp(u32 index, u64 val)
40 {
41     // XXX - should run this on other CPUs also.
42     wrmsr(index, val);
43 }
44
45 void mtrr_setup(void)
46 {
47     if (! CONFIG_KVM)
48         return;
49     dprintf(3, "init mtrr\n");
50
51     int i, vcnt, fix, wc;
52     u32 ram_size = GET_GLOBAL(RamSize);
53     u32 mtrr_cap;
54     union {
55         u8 valb[8];
56         u64 val;
57     } u;
58
59     mtrr_cap = rdmsr(MSR_MTRRcap);
60     vcnt = mtrr_cap & 0xff;
61     fix = mtrr_cap & 0x100;
62     wc = mtrr_cap & 0x400;
63     if (!vcnt || !fix)
64        return;
65     u.val = 0;
66     for (i = 0; i < 8; ++i)
67         if (ram_size >= 65536 * (i + 1))
68             u.valb[i] = 6;
69     wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
70     u.val = 0;
71     for (i = 0; i < 8; ++i)
72         if (ram_size >= 65536 * 8 + 16384 * (i + 1))
73             u.valb[i] = 6;
74     wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
75     wrmsr_smp(MSR_MTRRfix16K_A0000, 0);
76     wrmsr_smp(MSR_MTRRfix4K_C0000, 0);
77     wrmsr_smp(MSR_MTRRfix4K_C8000, 0);
78     wrmsr_smp(MSR_MTRRfix4K_D0000, 0);
79     wrmsr_smp(MSR_MTRRfix4K_D8000, 0);
80     wrmsr_smp(MSR_MTRRfix4K_E0000, 0);
81     wrmsr_smp(MSR_MTRRfix4K_E8000, 0);
82     wrmsr_smp(MSR_MTRRfix4K_F0000, 0);
83     wrmsr_smp(MSR_MTRRfix4K_F8000, 0);
84     /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
85     wrmsr_smp(MTRRphysBase_MSR(0), 0xe0000000ull | 0);
86     wrmsr_smp(MTRRphysMask_MSR(0), ~(0x20000000ull - 1) | 0x800);
87     wrmsr_smp(MSR_MTRRdefType, 0xc06);
88 }