Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / fw / 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 "config.h" // CONFIG_*
8 #include "hw/pci.h" // pcimem_start
9 #include "output.h" // dprintf
10 #include "paravirt.h" // RamSize
11 #include "util.h" // mtrr_setup
12 #include "x86.h" // cpuid
13
14 #define MSR_MTRRcap                    0x000000fe
15 #define MSR_MTRRfix64K_00000           0x00000250
16 #define MSR_MTRRfix16K_80000           0x00000258
17 #define MSR_MTRRfix16K_A0000           0x00000259
18 #define MSR_MTRRfix4K_C0000            0x00000268
19 #define MSR_MTRRfix4K_C8000            0x00000269
20 #define MSR_MTRRfix4K_D0000            0x0000026a
21 #define MSR_MTRRfix4K_D8000            0x0000026b
22 #define MSR_MTRRfix4K_E0000            0x0000026c
23 #define MSR_MTRRfix4K_E8000            0x0000026d
24 #define MSR_MTRRfix4K_F0000            0x0000026e
25 #define MSR_MTRRfix4K_F8000            0x0000026f
26 #define MSR_MTRRdefType                0x000002ff
27
28 #define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
29 #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
30
31 #define MTRR_MEMTYPE_UC 0
32 #define MTRR_MEMTYPE_WC 1
33 #define MTRR_MEMTYPE_WT 4
34 #define MTRR_MEMTYPE_WP 5
35 #define MTRR_MEMTYPE_WB 6
36
37 void mtrr_setup(void)
38 {
39     if (!CONFIG_MTRR_INIT)
40         return;
41
42     u32 eax, ebx, ecx, edx, cpuid_features;
43     cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
44     if (!(cpuid_features & CPUID_MTRR))
45         return;
46     if (!(cpuid_features & CPUID_MSR))
47         return;
48
49     dprintf(3, "init mtrr\n");
50
51     u32 mtrr_cap = rdmsr(MSR_MTRRcap);
52     int vcnt = mtrr_cap & 0xff;
53     int fix = mtrr_cap & 0x100;
54     if (!vcnt || !fix)
55        return;
56
57     // Disable MTRRs
58     wrmsr_smp(MSR_MTRRdefType, 0);
59
60     // Set fixed MTRRs
61     union u64b {
62         u8 valb[8];
63         u64 val;
64     } u;
65     u.val = 0;
66     int i;
67     for (i = 0; i < 8; i++)
68         if (RamSize >= 65536 * (i + 1))
69             u.valb[i] = MTRR_MEMTYPE_WB;
70     wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
71     u.val = 0;
72     for (i = 0; i < 8; i++)
73         if (RamSize >= 0x80000 + 16384 * (i + 1))
74             u.valb[i] = MTRR_MEMTYPE_WB;
75     wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
76     wrmsr_smp(MSR_MTRRfix16K_A0000, 0);   // 0xA0000-0xC0000 is uncached
77     int j;
78     for (j = 0; j < 8; j++) {
79         u.val = 0;
80         for (i = 0; i < 8; i++)
81             if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
82                 u.valb[i] = MTRR_MEMTYPE_WP;
83         wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
84     }
85
86     // Set variable MTRRs
87     int phys_bits = 36;
88     cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
89     if (eax >= 0x80000008) {
90         /* Get physical bits from leaf 0x80000008 (if available) */
91         cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
92         phys_bits = eax & 0xff;
93     }
94     u64 phys_mask = ((1ull << phys_bits) - 1);
95     for (i=0; i<vcnt; i++) {
96         wrmsr_smp(MTRRphysBase_MSR(i), 0);
97         wrmsr_smp(MTRRphysMask_MSR(i), 0);
98     }
99     /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
100     wrmsr_smp(MTRRphysBase_MSR(0), pcimem_start | MTRR_MEMTYPE_UC);
101     wrmsr_smp(MTRRphysMask_MSR(0)
102               , (-((1ull<<32)-pcimem_start) & phys_mask) | 0x800);
103
104     // Enable fixed and variable MTRRs; set default type.
105     wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
106 }