switched to vidsys (not working yet)
[retroray] / src / dos / mtrr.c
1 #include "mtrr.h"
2
3 #define MSR_MTRRCAP                     0xfe
4 #define MSR_MTRRDEFTYPE         0x2ff
5 #define MSR_MTRRBASE(x)         (0x200 | ((x) << 1))
6 #define MSR_MTRRMASK(x)         (0x201 | ((x) << 1))
7 #define MTRRDEF_EN                      0x800
8 #define MTRRCAP_HAVE_WC         0x400
9 #define MTRRMASK_VALID          0x800
10
11 static const char *mtrr_type_name(int type);
12 static void print_mtrr(void);
13
14
15 int get_page_memtype(uint32_t addr, int num_ranges)
16 {
17         int i;
18         uint32_t rlow, rhigh;
19         uint32_t base, mask;
20
21         for(i=0; i<num_ranges; i++) {
22                 get_msr(MSR_MTRRMASK(i), &rlow, &rhigh);
23                 if(!(rlow & MTRRMASK_VALID)) {
24                         continue;
25                 }
26                 mask = rlow & 0xfffff000;
27
28                 get_msr(MSR_MTRRBASE(i), &rlow, &rhigh);
29                 base = rlow & 0xfffff000;
30
31                 if((addr & mask) == (base & mask)) {
32                         return rlow & 0xff;
33                 }
34         }
35
36         get_msr(MSR_MTRRDEFTYPE, &rlow, &rhigh);
37         return rlow & 0xff;
38 }
39
40 int check_wrcomb_enabled(uint32_t addr, int len, int num_ranges)
41 {
42         while(len > 0) {
43                 if(get_page_memtype(addr, num_ranges) != MTRR_WC) {
44                         return 0;
45                 }
46                 addr += 4096;
47                 len -= 4096;
48         }
49         return 1;
50 }
51
52 int alloc_mtrr(int num_ranges)
53 {
54         int i;
55         uint32_t rlow, rhigh;
56
57         for(i=0; i<num_ranges; i++) {
58                 get_msr(MSR_MTRRMASK(i), &rlow, &rhigh);
59                 if(!(rlow & MTRRMASK_VALID)) {
60                         return i;
61                 }
62         }
63         return -1;
64 }
65
66 void enable_wrcomb(uint32_t addr, int len)
67 {
68         int num_ranges, mtrr;
69         uint32_t rlow, rhigh;
70         uint32_t def, mask;
71
72         if(len <= 0 || (addr | (uint32_t)len) & 0xfff) {
73                 errormsg("failed to enable write combining, unaligned range: %p/%x\n",
74                                 (void*)addr, (unsigned int)len);
75                 return;
76         }
77
78         get_msr(MSR_MTRRCAP, &rlow, &rhigh);
79         num_ranges = rlow & 0xff;
80
81         infomsg("enable_wrcomb: addr=%p len=%x\n", (void*)addr, (unsigned int)len);
82
83         if(!(rlow & MTRRCAP_HAVE_WC)) {
84                 errormsg("failed to enable write combining, processor doesn't support it\n");
85                 return;
86         }
87
88         if(check_wrcomb_enabled(addr, len, num_ranges)) {
89                 return;
90         }
91
92         if((mtrr = alloc_mtrr(num_ranges)) == -1) {
93                 errormsg("failed to enable write combining, no free MTRRs\n");
94                 return;
95         }
96
97         mask = len - 1;
98         mask |= mask >> 1;
99         mask |= mask >> 2;
100         mask |= mask >> 4;
101         mask |= mask >> 8;
102         mask |= mask >> 16;
103         mask = ~mask & 0xfffff000;
104
105         infomsg("  ... mask: %08x\n", (unsigned int)mask);
106
107         _disable();
108         get_msr(MSR_MTRRDEFTYPE, &def, &rhigh);
109         set_msr(MSR_MTRRDEFTYPE, def & ~MTRRDEF_EN, rhigh);
110
111         set_msr(MSR_MTRRBASE(mtrr), addr | MTRR_WC, 0);
112         set_msr(MSR_MTRRMASK(mtrr), mask | MTRRMASK_VALID, 0);
113
114         set_msr(MSR_MTRRDEFTYPE, def | MTRRDEF_EN, 0);
115         _enable();
116 }
117
118 static const char *mtrr_names[] = { "N/A", "W C", "N/A", "N/A", "W T", "W P", "W B" };
119
120 static const char *mtrr_type_name(int type)
121 {
122         if(type < 0 || type >= sizeof mtrr_names / sizeof *mtrr_names) {
123                 return mtrr_names[0];
124         }
125         return mtrr_names[type];
126 }
127
128 static void print_mtrr(void)
129 {
130         int i, num_ranges;
131         uint32_t rlow, rhigh, base, mask;
132
133         get_msr(MSR_MTRRCAP, &rlow, &rhigh);
134         num_ranges = rlow & 0xff;
135
136         for(i=0; i<num_ranges; i++) {
137                 get_msr(MSR_MTRRBASE(i), &base, &rhigh);
138                 get_msr(MSR_MTRRMASK(i), &mask, &rhigh);
139
140                 if(mask & MTRRMASK_VALID) {
141                         infomsg("mtrr%d: base %p, mask %08x type %s\n", i, (void*)(base & 0xfffff000),
142                                         (unsigned int)(mask & 0xfffff000), mtrr_type_name(base & 0xff));
143                 } else {
144                         infomsg("mtrr%d unused (%08x/%08x)\n", i, (unsigned int)base,
145                                         (unsigned int)mask);
146                 }
147         }
148         /*fflush(stdout);*/
149 }