Change license from GPLv3 to LGPLv3.
[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(unsigned index)
28 {
29     unsigned long long ret;
30
31     asm ("rdmsr" : "=A"(ret) : "c"(index));
32     return ret;
33 }
34
35 static void wrmsr(unsigned index, u64 val)
36 {
37     asm volatile ("wrmsr" : : "c"(index), "A"(val));
38 }
39
40 static void wrmsr_smp(u32 index, u64 val)
41 {
42     // XXX - should run this on other CPUs also.
43     wrmsr(index, val);
44 }
45
46 void mtrr_setup(void)
47 {
48     if (! CONFIG_KVM)
49         return;
50     dprintf(3, "init mtrr\n");
51
52     int i, vcnt, fix, wc;
53     u32 ram_size = GET_GLOBAL(RamSize);
54     u32 mtrr_cap;
55     union {
56         u8 valb[8];
57         u64 val;
58     } u;
59
60     mtrr_cap = rdmsr(MSR_MTRRcap);
61     vcnt = mtrr_cap & 0xff;
62     fix = mtrr_cap & 0x100;
63     wc = mtrr_cap & 0x400;
64     if (!vcnt || !fix)
65        return;
66     u.val = 0;
67     for (i = 0; i < 8; ++i)
68         if (ram_size >= 65536 * (i + 1))
69             u.valb[i] = 6;
70     wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
71     u.val = 0;
72     for (i = 0; i < 8; ++i)
73         if (ram_size >= 65536 * 8 + 16384 * (i + 1))
74             u.valb[i] = 6;
75     wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
76     wrmsr_smp(MSR_MTRRfix16K_A0000, 0);
77     wrmsr_smp(MSR_MTRRfix4K_C0000, 0);
78     wrmsr_smp(MSR_MTRRfix4K_C8000, 0);
79     wrmsr_smp(MSR_MTRRfix4K_D0000, 0);
80     wrmsr_smp(MSR_MTRRfix4K_D8000, 0);
81     wrmsr_smp(MSR_MTRRfix4K_E0000, 0);
82     wrmsr_smp(MSR_MTRRfix4K_E8000, 0);
83     wrmsr_smp(MSR_MTRRfix4K_F0000, 0);
84     wrmsr_smp(MSR_MTRRfix4K_F8000, 0);
85     /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
86     wrmsr_smp(MTRRphysBase_MSR(0), 0xe0000000ull | 0);
87     wrmsr_smp(MTRRphysMask_MSR(0), ~(0x20000000ull - 1) | 0x800);
88     wrmsr_smp(MSR_MTRRdefType, 0xc06);
89 }