Subversion Repositories Kolibri OS

Rev

Rev 5351 | Rev 5360 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 5351 Rev 5356
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
3
;; Copyright (C) KolibriOS team 2004-2014. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
7
 
8
$Revision: 5351 $
8
$Revision: 5356 $
9
 
9
 
10
; Initializes MTRRs.
10
; Initializes MTRRs.
11
proc init_mtrr
11
proc init_mtrr
12
 
12
 
13
        cmp     [BOOT_VARS+BOOT_MTRR], byte 2
13
        cmp     [BOOT_VARS+BOOT_MTRR], byte 2
14
        je      .exit
14
        je      .exit
15
 
15
 
16
        bt      [cpu_caps], CAPS_MTRR
16
        bt      [cpu_caps], CAPS_MTRR
17
        jnc     .exit
17
        jnc     .exit
18
 
18
 
19
        call    mtrr_reconfigure
19
        call    mtrr_reconfigure
20
        stdcall set_mtrr, [LFBAddress], 0x1000000, MEM_WC
20
        stdcall set_mtrr, [LFBAddress], 0x1000000, MEM_WC
21
 
21
 
22
.exit:
22
.exit:
23
        ret
23
        ret
24
endp
24
endp
25
 
25
 
26
; Helper procedure for mtrr_reconfigure and set_mtrr,
26
; Helper procedure for mtrr_reconfigure and set_mtrr,
27
; called before changes in MTRRs.
27
; called before changes in MTRRs.
28
proc mtrr_begin_change
28
proc mtrr_begin_change
29
        mov     eax, cr0
29
        mov     eax, cr0
30
        or      eax, 0x60000000 ;disable caching
30
        or      eax, 0x60000000 ;disable caching
31
        mov     cr0, eax
31
        mov     cr0, eax
32
        wbinvd                  ;invalidate cache
32
        wbinvd                  ;invalidate cache
33
        ret
33
        ret
34
endp
34
endp
35
 
35
 
36
; Helper procedure for mtrr_reconfigure and set_mtrr,
36
; Helper procedure for mtrr_reconfigure and set_mtrr,
37
; called after changes in MTRRs.
37
; called after changes in MTRRs.
38
proc mtrr_end_change
38
proc mtrr_end_change
39
        wbinvd                  ;again invalidate
39
        wbinvd                  ;again invalidate
40
        mov     eax, cr0
40
        mov     eax, cr0
41
        and     eax, not 0x60000000
41
        and     eax, not 0x60000000
42
        mov     cr0, eax        ; enable caching
42
        mov     cr0, eax        ; enable caching
43
        ret
43
        ret
44
endp
44
endp
45
 
45
 
46
; Some limits to number of structures located in the stack.
46
; Some limits to number of structures located in the stack.
47
MAX_USEFUL_MTRRS = 16
47
MAX_USEFUL_MTRRS = 16
48
MAX_RANGES = 16
48
MAX_RANGES = 16
49
 
49
 
50
; mtrr_reconfigure keeps a list of MEM_WB ranges.
50
; mtrr_reconfigure keeps a list of MEM_WB ranges.
51
; This structure describes one item in the list.
51
; This structure describes one item in the list.
52
struct mtrr_range
52
struct mtrr_range
53
next            dd      ?       ; next item
53
next            dd      ?       ; next item
54
start           dq      ?       ; first byte
54
start           dq      ?       ; first byte
55
length          dq      ?       ; length in bytes
55
length          dq      ?       ; length in bytes
56
ends
56
ends
57
 
57
 
58
uglobal
58
uglobal
59
align 4
59
align 4
60
num_variable_mtrrs      dd      0       ; number of variable-range MTRRs
60
num_variable_mtrrs      dd      0       ; number of variable-range MTRRs
61
endg
61
endg
62
 
62
 
63
; Helper procedure for MTRR initialization.
63
; Helper procedure for MTRR initialization.
64
; Takes MTRR configured by BIOS and tries to recongifure them
64
; Takes MTRR configured by BIOS and tries to recongifure them
65
; in order to allow non-UC data at top of 4G memory.
65
; in order to allow non-UC data at top of 4G memory.
66
; Example: if low part of physical memory is 3.5G = 0xE0000000 bytes wide,
66
; Example: if low part of physical memory is 3.5G = 0xE0000000 bytes wide,
67
; BIOS can configure two MTRRs so that the first MTRR describes [0, 4G) as WB
67
; BIOS can configure two MTRRs so that the first MTRR describes [0, 4G) as WB
68
; and the second MTRR describes [3.5G, 4G) as UC;
68
; and the second MTRR describes [3.5G, 4G) as UC;
69
; WB+UC=UC, so the resulting memory map would be as needed,
69
; WB+UC=UC, so the resulting memory map would be as needed,
70
; but in this configuration our attempts to map LFB at (say) 0xE8000000 as WC
70
; but in this configuration our attempts to map LFB at (say) 0xE8000000 as WC
71
; would be ignored, WB+UC+WC is still UC.
71
; would be ignored, WB+UC+WC is still UC.
72
; So we must keep top of 4G memory not covered by MTRRs,
72
; So we must keep top of 4G memory not covered by MTRRs,
73
; using three WB MTRRs [0,2G) + [2G,3G) + [3G,3.5G),
73
; using three WB MTRRs [0,2G) + [2G,3G) + [3G,3.5G),
74
; this gives the same memory map, but allows to add further entries.
74
; this gives the same memory map, but allows to add further entries.
75
; See mtrrtest.asm for detailed input/output from real hardware+BIOS.
75
; See mtrrtest.asm for detailed input/output from real hardware+BIOS.
76
proc mtrr_reconfigure
76
proc mtrr_reconfigure
77
        push    ebp     ; we're called from init_LFB, and it feels hurt when ebp is destroyed
77
        push    ebp     ; we're called from init_LFB, and it feels hurt when ebp is destroyed
78
; 1. Prepare local variables.
78
; 1. Prepare local variables.
79
; 1a. Create list of MAX_RANGES free (aka not yet allocated) ranges.
79
; 1a. Create list of MAX_RANGES free (aka not yet allocated) ranges.
80
        xor     eax, eax
80
        xor     eax, eax
81
        lea     ecx, [eax+MAX_RANGES]
81
        lea     ecx, [eax+MAX_RANGES]
82
.init_ranges:
82
.init_ranges:
83
        sub     esp, sizeof.mtrr_range - 4
83
        sub     esp, sizeof.mtrr_range - 4
84
        push    eax
84
        push    eax
85
        mov     eax, esp
85
        mov     eax, esp
86
        dec     ecx
86
        dec     ecx
87
        jnz     .init_ranges
87
        jnz     .init_ranges
88
        mov     eax, esp
88
        mov     eax, esp
89
; 1b. Fill individual local variables.
89
; 1b. Fill individual local variables.
90
        xor     edx, edx
90
        xor     edx, edx
91
        sub     esp, MAX_USEFUL_MTRRS * 16      ; .mtrrs
91
        sub     esp, MAX_USEFUL_MTRRS * 16      ; .mtrrs
92
        push    edx             ; .mtrrs_end
92
        push    edx             ; .mtrrs_end
93
        push    edx             ; .num_used_mtrrs
93
        push    edx             ; .num_used_mtrrs
94
        push    eax             ; .first_free_range
94
        push    eax             ; .first_free_range
95
        push    edx             ; .first_range: no ranges yet
95
        push    edx             ; .first_range: no ranges yet
96
        mov     cl, [cpu_phys_addr_width]
96
        mov     cl, [cpu_phys_addr_width]
97
        or      eax, -1
97
        or      eax, -1
98
        shl     eax, cl ; note: this uses cl&31 = cl-32, not the entire cl
98
        shl     eax, cl ; note: this uses cl&31 = cl-32, not the entire cl
99
        push    eax     ; .phys_reserved_mask
99
        push    eax     ; .phys_reserved_mask
100
virtual at esp
100
virtual at esp
101
.phys_reserved_mask     dd      ?
101
.phys_reserved_mask     dd      ?
102
.first_range            dd      ?
102
.first_range            dd      ?
103
.first_free_range       dd      ?
103
.first_free_range       dd      ?
104
.num_used_mtrrs         dd      ?
104
.num_used_mtrrs         dd      ?
105
.mtrrs_end              dd      ?
105
.mtrrs_end              dd      ?
106
.mtrrs          rq      MAX_USEFUL_MTRRS * 2
106
.mtrrs          rq      MAX_USEFUL_MTRRS * 2
107
.local_vars_size = $ - esp
107
.local_vars_size = $ - esp
108
end virtual
108
end virtual
109
 
109
 
110
; 2. Get the number of variable-range MTRRs from MTRRCAP register.
110
; 2. Get the number of variable-range MTRRs from MTRRCAP register.
111
; Abort if zero.
111
; Abort if zero.
112
        mov     ecx, 0xFE
112
        mov     ecx, 0xFE
113
        rdmsr
113
        rdmsr
114
        test    al, al
114
        test    al, al
115
        jz      .abort
115
        jz      .abort
116
        mov     byte [num_variable_mtrrs], al
116
        mov     byte [num_variable_mtrrs], al
117
; 3. Validate MTRR_DEF_TYPE register.
117
; 3. Validate MTRR_DEF_TYPE register.
118
        mov     ecx, 0x2FF
118
        mov     ecx, 0x2FF
119
        rdmsr
119
        rdmsr
120
; If BIOS has not initialized variable-range MTRRs, fallback to step 7.
120
; If BIOS has not initialized variable-range MTRRs, fallback to step 7.
121
        test    ah, 8
121
        test    ah, 8
122
        jz      .fill_ranges_from_memory_map
122
        jz      .fill_ranges_from_memory_map
123
; If the default memory type (not covered by MTRRs) is not UC,
123
; If the default memory type (not covered by MTRRs) is not UC,
124
; then probably BIOS did something strange, so it is better to exit immediately
124
; then probably BIOS did something strange, so it is better to exit immediately
125
; hoping for the best.
125
; hoping for the best.
126
        cmp     al, MEM_UC
126
        cmp     al, MEM_UC
127
        jnz     .abort
127
        jnz     .abort
128
; 4. Validate all variable-range MTRRs
128
; 4. Validate all variable-range MTRRs
129
; and copy configured MTRRs to the local array [.mtrrs].
129
; and copy configured MTRRs to the local array [.mtrrs].
130
; 4a. Prepare for the loop over existing variable-range MTRRs.
130
; 4a. Prepare for the loop over existing variable-range MTRRs.
131
        mov     ecx, 0x200
131
        mov     ecx, 0x200
132
        lea     edi, [.mtrrs]
132
        lea     edi, [.mtrrs]
133
.get_used_mtrrs_loop:
133
.get_used_mtrrs_loop:
134
; 4b. For every MTRR, read PHYSBASEn and PHYSMASKn.
134
; 4b. For every MTRR, read PHYSBASEn and PHYSMASKn.
135
; In PHYSBASEn, clear upper bits and copy to ebp:ebx.
135
; In PHYSBASEn, clear upper bits and copy to ebp:ebx.
136
        rdmsr
136
        rdmsr
137
        or      edx, [.phys_reserved_mask]
137
        or      edx, [.phys_reserved_mask]
138
        xor     edx, [.phys_reserved_mask]
138
        xor     edx, [.phys_reserved_mask]
139
        mov     ebp, edx
139
        mov     ebp, edx
140
        mov     ebx, eax
140
        mov     ebx, eax
141
        inc     ecx
141
        inc     ecx
142
; If PHYSMASKn is not active, ignore this MTRR.
142
; If PHYSMASKn is not active, ignore this MTRR.
143
        rdmsr
143
        rdmsr
144
        inc     ecx
144
        inc     ecx
145
        test    ah, 8
145
        test    ah, 8
146
        jz      .get_used_mtrrs_next
146
        jz      .get_used_mtrrs_next
147
; 4c. For every active MTRR, check that number of local entries is not too large.
147
; 4c. For every active MTRR, check that number of local entries is not too large.
148
        inc     [.num_used_mtrrs]
148
        inc     [.num_used_mtrrs]
149
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
149
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
150
        ja      .abort
150
        ja      .abort
151
; 4d. For every active MTRR, store PHYSBASEn with upper bits cleared.
151
; 4d. For every active MTRR, store PHYSBASEn with upper bits cleared.
152
; This contains the MTRR base and the memory type in low byte.
152
; This contains the MTRR base and the memory type in low byte.
153
        mov     [edi], ebx
153
        mov     [edi], ebx
154
        mov     [edi+4], ebp
154
        mov     [edi+4], ebp
155
; 4e. For every active MTRR, check that the range is continuous:
155
; 4e. For every active MTRR, check that the range is continuous:
156
; PHYSMASKn with upper bits set must be negated power of two, and
156
; PHYSMASKn with upper bits set must be negated power of two, and
157
; low bits of PHYSBASEn must be zeroes:
157
; low bits of PHYSBASEn must be zeroes:
158
; PHYSMASKn = 1...10...0,
158
; PHYSMASKn = 1...10...0,
159
; PHYSBASEn = x...x0...0,
159
; PHYSBASEn = x...x0...0,
160
; this defines a continuous range from x...x0...0 to x...x1...1,
160
; this defines a continuous range from x...x0...0 to x...x1...1,
161
; length = 10...0 = negated PHYSMASKn.
161
; length = 10...0 = negated PHYSMASKn.
162
; Store length in the local array.
162
; Store length in the local array.
163
        and     eax, not 0xFFF
163
        and     eax, not 0xFFF
164
        or      edx, [.phys_reserved_mask]
164
        or      edx, [.phys_reserved_mask]
165
        mov     dword [edi+8], 0
165
        mov     dword [edi+8], 0
166
        mov     dword [edi+12], 0
166
        mov     dword [edi+12], 0
167
        sub     [edi+8], eax
167
        sub     [edi+8], eax
168
        sbb     [edi+12], edx
168
        sbb     [edi+12], edx
169
; (x and -x) is the maximum power of two that divides x.
169
; (x and -x) is the maximum power of two that divides x.
170
; Condition for powers of two: (x and -x) equals x.
170
; Condition for powers of two: (x and -x) equals x.
171
        and     eax, [edi+8]
171
        and     eax, [edi+8]
172
        and     edx, [edi+12]
172
        and     edx, [edi+12]
173
        cmp     eax, [edi+8]
173
        cmp     eax, [edi+8]
174
        jnz     .abort
174
        jnz     .abort
175
        cmp     edx, [edi+12]
175
        cmp     edx, [edi+12]
176
        jnz     .abort
176
        jnz     .abort
177
        sub     eax, 1
177
        sub     eax, 1
178
        sbb     edx, 0
178
        sbb     edx, 0
179
        and     eax, not 0xFFF
179
        and     eax, not 0xFFF
180
        and     eax, ebx
180
        and     eax, ebx
181
        jnz     .abort
181
        jnz     .abort
182
        and     edx, ebp
182
        and     edx, ebp
183
        jnz     .abort
183
        jnz     .abort
184
; 4f. For every active MTRR, validate memory type: it must be either WB or UC.
184
; 4f. For every active MTRR, validate memory type: it must be either WB or UC.
185
        add     edi, 16
185
        add     edi, 16
186
        cmp     bl, MEM_UC
186
        cmp     bl, MEM_UC
187
        jz      .get_used_mtrrs_next
187
        jz      .get_used_mtrrs_next
188
        cmp     bl, MEM_WB
188
        cmp     bl, MEM_WB
189
        jnz     .abort
189
        jnz     .abort
190
.get_used_mtrrs_next:
190
.get_used_mtrrs_next:
191
; 4g. Repeat the loop at 4b-4f for all [num_variable_mtrrs] entries.
191
; 4g. Repeat the loop at 4b-4f for all [num_variable_mtrrs] entries.
192
        mov     eax, [num_variable_mtrrs]
192
        mov     eax, [num_variable_mtrrs]
193
        lea     eax, [0x200+eax*2]
193
        lea     eax, [0x200+eax*2]
194
        cmp     ecx, eax
194
        cmp     ecx, eax
195
        jb      .get_used_mtrrs_loop
195
        jb      .get_used_mtrrs_loop
196
; 4h. If no active MTRRs were detected, fallback to step 7.
196
; 4h. If no active MTRRs were detected, fallback to step 7.
197
        cmp     [.num_used_mtrrs], 0
197
        cmp     [.num_used_mtrrs], 0
198
        jz      .fill_ranges_from_memory_map
198
        jz      .fill_ranges_from_memory_map
199
        mov     [.mtrrs_end], edi
199
        mov     [.mtrrs_end], edi
200
; 5. Generate sorted list of ranges marked as WB.
200
; 5. Generate sorted list of ranges marked as WB.
201
; 5a. Prepare for the loop over configured MTRRs filled at step 4.
201
; 5a. Prepare for the loop over configured MTRRs filled at step 4.
202
        lea     ecx, [.mtrrs]
202
        lea     ecx, [.mtrrs]
203
.fill_wb_ranges:
203
.fill_wb_ranges:
204
; 5b. Ignore non-WB MTRRs.
204
; 5b. Ignore non-WB MTRRs.
205
        mov     ebx, [ecx]
205
        mov     ebx, [ecx]
206
        cmp     bl, MEM_WB
206
        cmp     bl, MEM_WB
207
        jnz     .next_wb_range
207
        jnz     .next_wb_range
208
        mov     ebp, [ecx+4]
208
        mov     ebp, [ecx+4]
209
        and     ebx, not 0xFFF  ; clear memory type and reserved bits
209
        and     ebx, not 0xFFF  ; clear memory type and reserved bits
210
; ebp:ebx = start of the range described by the current MTRR.
210
; ebp:ebx = start of the range described by the current MTRR.
211
; 5c. Find the first existing range containing a point greater than ebp:ebx.
211
; 5c. Find the first existing range containing a point greater than ebp:ebx.
212
        lea     esi, [.first_range]
212
        lea     esi, [.first_range]
213
.find_range_wb:
213
.find_range_wb:
214
; If there is no next range or start of the next range is greater than ebp:ebx,
214
; If there is no next range or start of the next range is greater than ebp:ebx,
215
; exit the loop to 5d.
215
; exit the loop to 5d.
216
        mov     edi, [esi]
216
        mov     edi, [esi]
217
        test    edi, edi
217
        test    edi, edi
218
        jz      .found_place_wb
218
        jz      .found_place_wb
219
        mov     eax, ebx
219
        mov     eax, ebx
220
        mov     edx, ebp
220
        mov     edx, ebp
221
        sub     eax, dword [edi+mtrr_range.start]
221
        sub     eax, dword [edi+mtrr_range.start]
222
        sbb     edx, dword [edi+mtrr_range.start+4]
222
        sbb     edx, dword [edi+mtrr_range.start+4]
223
        jb      .found_place_wb
223
        jb      .found_place_wb
224
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
224
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
225
; exit the loop to 5e.
225
; exit the loop to 5e.
226
        mov     esi, edi
226
        mov     esi, edi
227
        sub     eax, dword [edi+mtrr_range.length]
227
        sub     eax, dword [edi+mtrr_range.length]
228
        sbb     edx, dword [edi+mtrr_range.length+4]
228
        sbb     edx, dword [edi+mtrr_range.length+4]
229
        jb      .expand_wb
229
        jb      .expand_wb
230
        or      eax, edx
230
        or      eax, edx
231
        jnz     .find_range_wb
231
        jnz     .find_range_wb
232
        jmp     .expand_wb
232
        jmp     .expand_wb
233
.found_place_wb:
233
.found_place_wb:
234
; 5d. ebp:ebx is not within any existing range.
234
; 5d. ebp:ebx is not within any existing range.
235
; Insert a new range between esi and edi.
235
; Insert a new range between esi and edi.
236
; (Later, during 5e, it can be merged with the following ranges.)
236
; (Later, during 5e, it can be merged with the following ranges.)
237
        mov     eax, [.first_free_range]
237
        mov     eax, [.first_free_range]
238
        test    eax, eax
238
        test    eax, eax
239
        jz      .abort
239
        jz      .abort
240
        mov     [esi], eax
240
        mov     [esi], eax
241
        mov     edx, [eax+mtrr_range.next]
241
        mov     edx, [eax+mtrr_range.next]
242
        mov     [.first_free_range], edx
242
        mov     [.first_free_range], edx
243
        mov     dword [eax+mtrr_range.start], ebx
243
        mov     dword [eax+mtrr_range.start], ebx
244
        mov     dword [eax+mtrr_range.start+4], ebp
244
        mov     dword [eax+mtrr_range.start+4], ebp
245
; Don't fill [eax+mtrr_range.next] and [eax+mtrr_range.length] yet,
245
; Don't fill [eax+mtrr_range.next] and [eax+mtrr_range.length] yet,
246
; they will be calculated including merges at step 5e.
246
; they will be calculated including merges at step 5e.
247
        mov     esi, edi
247
        mov     esi, edi
248
        mov     edi, eax
248
        mov     edi, eax
249
.expand_wb:
249
.expand_wb:
250
; 5e. The range at edi contains ebp:ebx, and esi points to the first range
250
; 5e. The range at edi contains ebp:ebx, and esi points to the first range
251
; to be checked for merge: esi=edi if ebp:ebx was found in an existing range,
251
; to be checked for merge: esi=edi if ebp:ebx was found in an existing range,
252
; esi is next after edi if a new range with ebp:ebx was created.
252
; esi is next after edi if a new range with ebp:ebx was created.
253
; Merge it with following ranges while start of the next range is not greater
253
; Merge it with following ranges while start of the next range is not greater
254
; than the end of the new range.
254
; than the end of the new range.
255
        add     ebx, [ecx+8]
255
        add     ebx, [ecx+8]
256
        adc     ebp, [ecx+12]
256
        adc     ebp, [ecx+12]
257
; ebp:ebx = end of the range described by the current MTRR.
257
; ebp:ebx = end of the range described by the current MTRR.
258
.expand_wb_loop:
258
.expand_wb_loop:
259
; If there is no next range or start of the next range is greater than ebp:ebx,
259
; If there is no next range or start of the next range is greater than ebp:ebx,
260
; exit the loop to 5g.
260
; exit the loop to 5g.
261
        test    esi, esi
261
        test    esi, esi
262
        jz      .expand_wb_done
262
        jz      .expand_wb_done
263
        mov     eax, ebx
263
        mov     eax, ebx
264
        mov     edx, ebp
264
        mov     edx, ebp
265
        sub     eax, dword [esi+mtrr_range.start]
265
        sub     eax, dword [esi+mtrr_range.start]
266
        sbb     edx, dword [esi+mtrr_range.start+4]
266
        sbb     edx, dword [esi+mtrr_range.start+4]
267
        jb      .expand_wb_done
267
        jb      .expand_wb_done
268
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
268
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
269
; exit the loop to 5f.
269
; exit the loop to 5f.
270
        sub     eax, dword [esi+mtrr_range.length]
270
        sub     eax, dword [esi+mtrr_range.length]
271
        sbb     edx, dword [esi+mtrr_range.length+4]
271
        sbb     edx, dword [esi+mtrr_range.length+4]
272
        jb      .expand_wb_last
272
        jb      .expand_wb_last
273
; Otherwise, the current range is completely within the new range.
273
; Otherwise, the current range is completely within the new range.
274
; Free it and continue the loop.
274
; Free it and continue the loop.
275
        mov     edx, [esi+mtrr_range.next]
275
        mov     edx, [esi+mtrr_range.next]
276
        cmp     esi, edi
276
        cmp     esi, edi
277
        jz      @f
277
        jz      @f
278
        mov     eax, [.first_free_range]
278
        mov     eax, [.first_free_range]
279
        mov     [esi+mtrr_range.next], eax
279
        mov     [esi+mtrr_range.next], eax
280
        mov     [.first_free_range], esi
280
        mov     [.first_free_range], esi
281
@@:
281
@@:
282
        mov     esi, edx
282
        mov     esi, edx
283
        jmp     .expand_wb_loop
283
        jmp     .expand_wb_loop
284
.expand_wb_last:
284
.expand_wb_last:
285
; 5f. Start of the new range is inside range described by esi,
285
; 5f. Start of the new range is inside range described by esi,
286
; end of the new range is inside range described by edi.
286
; end of the new range is inside range described by edi.
287
; If esi is equal to edi, the new range is completely within
287
; If esi is equal to edi, the new range is completely within
288
; an existing range, so proceed to the next range.
288
; an existing range, so proceed to the next range.
289
        cmp     esi, edi
289
        cmp     esi, edi
290
        jz      .next_wb_range
290
        jz      .next_wb_range
291
; Otherwise, set end of interval at esi to end of interval at edi
291
; Otherwise, set end of interval at esi to end of interval at edi
292
; and free range described by edi.
292
; and free range described by edi.
293
        mov     ebx, dword [esi+mtrr_range.start]
293
        mov     ebx, dword [esi+mtrr_range.start]
294
        mov     ebp, dword [esi+mtrr_range.start+4]
294
        mov     ebp, dword [esi+mtrr_range.start+4]
295
        add     ebx, dword [esi+mtrr_range.length]
295
        add     ebx, dword [esi+mtrr_range.length]
296
        adc     ebp, dword [esi+mtrr_range.length+4]
296
        adc     ebp, dword [esi+mtrr_range.length+4]
297
        mov     edx, [esi+mtrr_range.next]
297
        mov     edx, [esi+mtrr_range.next]
298
        mov     eax, [.first_free_range]
298
        mov     eax, [.first_free_range]
299
        mov     [esi+mtrr_range.next], eax
299
        mov     [esi+mtrr_range.next], eax
300
        mov     [.first_free_range], esi
300
        mov     [.first_free_range], esi
301
        mov     esi, edx
301
        mov     esi, edx
302
.expand_wb_done:
302
.expand_wb_done:
303
; 5g. We have found the next range (maybe 0) after merging and
303
; 5g. We have found the next range (maybe 0) after merging and
304
; the new end of range (maybe ebp:ebx from the new range
304
; the new end of range (maybe ebp:ebx from the new range
305
; or end of another existing interval calculated at step 5f).
305
; or end of another existing interval calculated at step 5f).
306
; Write them to range at edi.
306
; Write them to range at edi.
307
        mov     [edi+mtrr_range.next], esi
307
        mov     [edi+mtrr_range.next], esi
308
        sub     ebx, dword [edi+mtrr_range.start]
308
        sub     ebx, dword [edi+mtrr_range.start]
309
        sbb     ebp, dword [edi+mtrr_range.start+4]
309
        sbb     ebp, dword [edi+mtrr_range.start+4]
310
        mov     dword [edi+mtrr_range.length], ebx
310
        mov     dword [edi+mtrr_range.length], ebx
311
        mov     dword [edi+mtrr_range.length+4], ebp
311
        mov     dword [edi+mtrr_range.length+4], ebp
312
.next_wb_range:
312
.next_wb_range:
313
; 5h. Continue the loop 5b-5g over all configured MTRRs.
313
; 5h. Continue the loop 5b-5g over all configured MTRRs.
314
        add     ecx, 16
314
        add     ecx, 16
315
        cmp     ecx, [.mtrrs_end]
315
        cmp     ecx, [.mtrrs_end]
316
        jb      .fill_wb_ranges
316
        jb      .fill_wb_ranges
317
; 6. Exclude all ranges marked as UC.
317
; 6. Exclude all ranges marked as UC.
318
; 6a. Prepare for the loop over configured MTRRs filled at step 4.
318
; 6a. Prepare for the loop over configured MTRRs filled at step 4.
319
        lea     ecx, [.mtrrs]
319
        lea     ecx, [.mtrrs]
320
.fill_uc_ranges:
320
.fill_uc_ranges:
321
; 6b. Ignore non-UC MTRRs.
321
; 6b. Ignore non-UC MTRRs.
322
        mov     ebx, [ecx]
322
        mov     ebx, [ecx]
323
        cmp     bl, MEM_UC
323
        cmp     bl, MEM_UC
324
        jnz     .next_uc_range
324
        jnz     .next_uc_range
325
        mov     ebp, [ecx+4]
325
        mov     ebp, [ecx+4]
326
        and     ebx, not 0xFFF  ; clear memory type and reserved bits
326
        and     ebx, not 0xFFF  ; clear memory type and reserved bits
327
; ebp:ebx = start of the range described by the current MTRR.
327
; ebp:ebx = start of the range described by the current MTRR.
328
        lea     esi, [.first_range]
328
        lea     esi, [.first_range]
329
; 6c. Find the first existing range containing a point greater than ebp:ebx.
329
; 6c. Find the first existing range containing a point greater than ebp:ebx.
330
.find_range_uc:
330
.find_range_uc:
331
; If there is no next range, ignore this MTRR,
331
; If there is no next range, ignore this MTRR,
332
; exit the loop and continue to next MTRR.
332
; exit the loop and continue to next MTRR.
333
        mov     edi, [esi]
333
        mov     edi, [esi]
334
        test    edi, edi
334
        test    edi, edi
335
        jz      .next_uc_range
335
        jz      .next_uc_range
336
; If start of the next range is greater than or equal to ebp:ebx,
336
; If start of the next range is greater than or equal to ebp:ebx,
337
; exit the loop to 6e.
337
; exit the loop to 6e.
338
        mov     eax, dword [edi+mtrr_range.start]
338
        mov     eax, dword [edi+mtrr_range.start]
339
        mov     edx, dword [edi+mtrr_range.start+4]
339
        mov     edx, dword [edi+mtrr_range.start+4]
340
        sub     eax, ebx
340
        sub     eax, ebx
341
        sbb     edx, ebp
341
        sbb     edx, ebp
342
        jnb     .truncate_uc
342
        jnb     .truncate_uc
343
; Otherwise, continue the loop if end of the next range is less than ebp:ebx,
343
; Otherwise, continue the loop if end of the next range is less than ebp:ebx,
344
; exit the loop to 6d otherwise.
344
; exit the loop to 6d otherwise.
345
        mov     esi, edi
345
        mov     esi, edi
346
        add     eax, dword [edi+mtrr_range.length]
346
        add     eax, dword [edi+mtrr_range.length]
347
        adc     edx, dword [edi+mtrr_range.length+4]
347
        adc     edx, dword [edi+mtrr_range.length+4]
348
        jnb     .find_range_uc
348
        jnb     .find_range_uc
349
; 6d. ebp:ebx is inside (or at end of) an existing range.
349
; 6d. ebp:ebx is inside (or at end of) an existing range.
350
; Split the range. (The second range, maybe containing completely within UC-range,
350
; Split the range. (The second range, maybe containing completely within UC-range,
351
; maybe of zero length, can be removed at step 6e, if needed.)
351
; maybe of zero length, can be removed at step 6e, if needed.)
352
        mov     edi, [.first_free_range]
352
        mov     edi, [.first_free_range]
353
        test    edi, edi
353
        test    edi, edi
354
        jz      .abort
354
        jz      .abort
355
        mov     dword [edi+mtrr_range.start], ebx
355
        mov     dword [edi+mtrr_range.start], ebx
356
        mov     dword [edi+mtrr_range.start+4], ebp
356
        mov     dword [edi+mtrr_range.start+4], ebp
357
        mov     dword [edi+mtrr_range.length], eax
357
        mov     dword [edi+mtrr_range.length], eax
358
        mov     dword [edi+mtrr_range.length+4], edx
358
        mov     dword [edi+mtrr_range.length+4], edx
359
        mov     eax, [edi+mtrr_range.next]
359
        mov     eax, [edi+mtrr_range.next]
360
        mov     [.first_free_range], eax
360
        mov     [.first_free_range], eax
361
        mov     eax, [esi+mtrr_range.next]
361
        mov     eax, [esi+mtrr_range.next]
362
        mov     [edi+mtrr_range.next], eax
362
        mov     [edi+mtrr_range.next], eax
363
; don't change [esi+mtrr_range.next] yet, it will be filled at step 6e
363
; don't change [esi+mtrr_range.next] yet, it will be filled at step 6e
364
        mov     eax, ebx
364
        mov     eax, ebx
365
        mov     edx, ebp
365
        mov     edx, ebp
366
        sub     eax, dword [esi+mtrr_range.start]
366
        sub     eax, dword [esi+mtrr_range.start]
367
        sbb     edx, dword [esi+mtrr_range.start+4]
367
        sbb     edx, dword [esi+mtrr_range.start+4]
368
        mov     dword [esi+mtrr_range.length], eax
368
        mov     dword [esi+mtrr_range.length], eax
369
        mov     dword [esi+mtrr_range.length+4], edx
369
        mov     dword [esi+mtrr_range.length+4], edx
370
.truncate_uc:
370
.truncate_uc:
371
; 6e. edi is the first range after ebp:ebx, check it and next ranges
371
; 6e. edi is the first range after ebp:ebx, check it and next ranges
372
; for intersection with the new range, truncate heads.
372
; for intersection with the new range, truncate heads.
373
        add     ebx, [ecx+8]
373
        add     ebx, [ecx+8]
374
        adc     ebp, [ecx+12]
374
        adc     ebp, [ecx+12]
375
; ebp:ebx = end of the range described by the current MTRR.
375
; ebp:ebx = end of the range described by the current MTRR.
376
.truncate_uc_loop:
376
.truncate_uc_loop:
377
; If start of the next range is greater than ebp:ebx,
377
; If start of the next range is greater than ebp:ebx,
378
; exit the loop to 6g.
378
; exit the loop to 6g.
379
        mov     eax, ebx
379
        mov     eax, ebx
380
        mov     edx, ebp
380
        mov     edx, ebp
381
        sub     eax, dword [edi+mtrr_range.start]
381
        sub     eax, dword [edi+mtrr_range.start]
382
        sbb     edx, dword [edi+mtrr_range.start+4]
382
        sbb     edx, dword [edi+mtrr_range.start+4]
383
        jb      .truncate_uc_done
383
        jb      .truncate_uc_done
384
; Otherwise, if end of the next range is greater than ebp:ebx,
384
; Otherwise, if end of the next range is greater than ebp:ebx,
385
; exit the loop to 6f.
385
; exit the loop to 6f.
386
        sub     eax, dword [edi+mtrr_range.length]
386
        sub     eax, dword [edi+mtrr_range.length]
387
        sbb     edx, dword [edi+mtrr_range.length+4]
387
        sbb     edx, dword [edi+mtrr_range.length+4]
388
        jb      .truncate_uc_last
388
        jb      .truncate_uc_last
389
; Otherwise, the current range is completely within the new range.
389
; Otherwise, the current range is completely within the new range.
390
; Free it and continue the loop if there is a next range.
390
; Free it and continue the loop if there is a next range.
391
; If that was a last range, exit the loop to 6g.
391
; If that was a last range, exit the loop to 6g.
392
        mov     edx, [edi+mtrr_range.next]
392
        mov     edx, [edi+mtrr_range.next]
393
        mov     eax, [.first_free_range]
393
        mov     eax, [.first_free_range]
394
        mov     [.first_free_range], edi
394
        mov     [.first_free_range], edi
395
        mov     [edi+mtrr_range.next], eax
395
        mov     [edi+mtrr_range.next], eax
396
        mov     edi, edx
396
        mov     edi, edx
397
        test    edi, edi
397
        test    edi, edi
398
        jnz     .truncate_uc_loop
398
        jnz     .truncate_uc_loop
399
        jmp     .truncate_uc_done
399
        jmp     .truncate_uc_done
400
.truncate_uc_last:
400
.truncate_uc_last:
401
; 6f. The range at edi partially intersects with the UC-range described by MTRR.
401
; 6f. The range at edi partially intersects with the UC-range described by MTRR.
402
; Truncate it from the head.
402
; Truncate it from the head.
403
        mov     dword [edi+mtrr_range.start], ebx
403
        mov     dword [edi+mtrr_range.start], ebx
404
        mov     dword [edi+mtrr_range.start+4], ebp
404
        mov     dword [edi+mtrr_range.start+4], ebp
405
        neg     eax
405
        neg     eax
406
        adc     edx, 0
406
        adc     edx, 0
407
        neg     edx
407
        neg     edx
408
        mov     dword [edi+mtrr_range.length], eax
408
        mov     dword [edi+mtrr_range.length], eax
409
        mov     dword [edi+mtrr_range.length+4], edx
409
        mov     dword [edi+mtrr_range.length+4], edx
410
.truncate_uc_done:
410
.truncate_uc_done:
411
; 6g. We have found the next range (maybe 0) after intersection.
411
; 6g. We have found the next range (maybe 0) after intersection.
412
; Write it to [esi+mtrr_range.next].
412
; Write it to [esi+mtrr_range.next].
413
        mov     [esi+mtrr_range.next], edi
413
        mov     [esi+mtrr_range.next], edi
414
.next_uc_range:
414
.next_uc_range:
415
; 6h. Continue the loop 6b-6g over all configured MTRRs.
415
; 6h. Continue the loop 6b-6g over all configured MTRRs.
416
        add     ecx, 16
416
        add     ecx, 16
417
        cmp     ecx, [.mtrrs_end]
417
        cmp     ecx, [.mtrrs_end]
418
        jb      .fill_uc_ranges
418
        jb      .fill_uc_ranges
419
; Sanity check: if there are no ranges after steps 5-6,
419
; Sanity check: if there are no ranges after steps 5-6,
420
; fallback to step 7. Otherwise, go to 8.
420
; fallback to step 7. Otherwise, go to 8.
421
        cmp     [.first_range], 0
421
        cmp     [.first_range], 0
422
        jnz     .ranges_ok
422
        jnz     .ranges_ok
423
.fill_ranges_from_memory_map:
423
.fill_ranges_from_memory_map:
424
; 7. BIOS has not configured variable-range MTRRs.
424
; 7. BIOS has not configured variable-range MTRRs.
425
; Create one range from 0 to [MEM_AMOUNT].
425
; Create one range from 0 to [MEM_AMOUNT].
426
        mov     eax, [.first_free_range]
426
        mov     eax, [.first_free_range]
427
        mov     edx, [eax+mtrr_range.next]
427
        mov     edx, [eax+mtrr_range.next]
428
        mov     [.first_free_range], edx
428
        mov     [.first_free_range], edx
429
        mov     [.first_range], eax
429
        mov     [.first_range], eax
430
        xor     edx, edx
430
        xor     edx, edx
431
        mov     [eax+mtrr_range.next], edx
431
        mov     [eax+mtrr_range.next], edx
432
        mov     dword [eax+mtrr_range.start], edx
432
        mov     dword [eax+mtrr_range.start], edx
433
        mov     dword [eax+mtrr_range.start+4], edx
433
        mov     dword [eax+mtrr_range.start+4], edx
434
        mov     ecx, [MEM_AMOUNT]
434
        mov     ecx, [MEM_AMOUNT]
435
        mov     dword [eax+mtrr_range.length], ecx
435
        mov     dword [eax+mtrr_range.length], ecx
436
        mov     dword [eax+mtrr_range.length+4], edx
436
        mov     dword [eax+mtrr_range.length+4], edx
437
.ranges_ok:
437
.ranges_ok:
438
; 8. We have calculated list of WB-ranges.
438
; 8. We have calculated list of WB-ranges.
439
; Now we should calculate a list of MTRRs so that
439
; Now we should calculate a list of MTRRs so that
440
; * every MTRR describes a range with length = power of 2 and start that is aligned,
440
; * every MTRR describes a range with length = power of 2 and start that is aligned,
441
; * every MTRR can be WB or UC
441
; * every MTRR can be WB or UC
442
; * (sum of all WB ranges) minus (sum of all UC ranges) equals the calculated list
442
; * (sum of all WB ranges) minus (sum of all UC ranges) equals the calculated list
443
; * top of 4G memory must not be covered by any ranges
443
; * top of 4G memory must not be covered by any ranges
444
; Example: range [0,0xBC000000) can be converted to
444
; Example: range [0,0xBC000000) can be converted to
445
; [0,0x80000000)+[0x80000000,0xC0000000)-[0xBC000000,0xC0000000)
445
; [0,0x80000000)+[0x80000000,0xC0000000)-[0xBC000000,0xC0000000)
446
; WB            +WB                     -UC
446
; WB            +WB                     -UC
447
; but not to [0,0x100000000)-[0xC0000000,0x100000000)-[0xBC000000,0xC0000000).
447
; but not to [0,0x100000000)-[0xC0000000,0x100000000)-[0xBC000000,0xC0000000).
448
; 8a. Check that list of ranges is [0,something) plus, optionally, [4G,something).
448
; 8a. Check that list of ranges is [0,something) plus, optionally, [4G,something).
449
; This holds in practice (see mtrrtest.asm for real-life examples)
449
; This holds in practice (see mtrrtest.asm for real-life examples)
450
; and significantly simplifies the code: ranges are independent, start of range
450
; and significantly simplifies the code: ranges are independent, start of range
451
; is almost always aligned (the only exception >4G upper memory can be easily covered),
451
; is almost always aligned (the only exception >4G upper memory can be easily covered),
452
; there is no need to consider adding holes before start of range, only
452
; there is no need to consider adding holes before start of range, only
453
; append them to end of range.
453
; append them to end of range.
454
        xor     eax, eax
454
        xor     eax, eax
455
        mov     edi, [.first_range]
455
        mov     edi, [.first_range]
456
        cmp     dword [edi+mtrr_range.start], eax
456
        cmp     dword [edi+mtrr_range.start], eax
457
        jnz     .abort
457
        jnz     .abort
458
        cmp     dword [edi+mtrr_range.start+4], eax
458
        cmp     dword [edi+mtrr_range.start+4], eax
459
        jnz     .abort
459
        jnz     .abort
460
        cmp     dword [edi+mtrr_range.length+4], eax
460
        cmp     dword [edi+mtrr_range.length+4], eax
461
        jnz     .abort
461
        jnz     .abort
462
        mov     edx, [edi+mtrr_range.next]
462
        mov     edx, [edi+mtrr_range.next]
463
        test    edx, edx
463
        test    edx, edx
464
        jz      @f
464
        jz      @f
465
        cmp     dword [edx+mtrr_range.start], eax
465
        cmp     dword [edx+mtrr_range.start], eax
466
        jnz     .abort
466
        jnz     .abort
467
        cmp     dword [edx+mtrr_range.start+4], 1
467
        cmp     dword [edx+mtrr_range.start+4], 1
468
        jnz     .abort
468
        jnz     .abort
469
        cmp     [edx+mtrr_range.next], eax
469
        cmp     [edx+mtrr_range.next], eax
470
        jnz     .abort
470
        jnz     .abort
471
@@:
471
@@:
472
; 8b. Initialize: no MTRRs filled.
472
; 8b. Initialize: no MTRRs filled.
473
        mov     [.num_used_mtrrs], eax
473
        mov     [.num_used_mtrrs], eax
474
        lea     esi, [.mtrrs]
474
        lea     esi, [.mtrrs]
475
.range2mtrr_loop:
475
.range2mtrr_loop:
476
; 8c. If we are dealing with upper-memory range (after 4G)
476
; 8c. If we are dealing with upper-memory range (after 4G)
477
; with length > start, create one WB MTRR with [start,2*start),
477
; with length > start, create one WB MTRR with [start,2*start),
478
; reset start to 2*start and return to this step.
478
; reset start to 2*start and return to this step.
479
; Example: [4G,24G) -> [4G,8G) {returning} + [8G,16G) {returning}
479
; Example: [4G,24G) -> [4G,8G) {returning} + [8G,16G) {returning}
480
; + [16G,24G) {advancing to ?}.
480
; + [16G,24G) {advancing to ?}.
481
        mov     eax, dword [edi+mtrr_range.length+4]
481
        mov     eax, dword [edi+mtrr_range.length+4]
482
        test    eax, eax
482
        test    eax, eax
483
        jz      .less4G
483
        jz      .less4G
484
        mov     edx, dword [edi+mtrr_range.start+4]
484
        mov     edx, dword [edi+mtrr_range.start+4]
485
        cmp     eax, edx
485
        cmp     eax, edx
486
        jb      .start_aligned
486
        jb      .start_aligned
487
        inc     [.num_used_mtrrs]
487
        inc     [.num_used_mtrrs]
488
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
488
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
489
        ja      .abort
489
        ja      .abort
490
        mov     dword [esi], MEM_WB
490
        mov     dword [esi], MEM_WB
491
        mov     dword [esi+4], edx
491
        mov     dword [esi+4], edx
492
        mov     dword [esi+8], 0
492
        mov     dword [esi+8], 0
493
        mov     dword [esi+12], edx
493
        mov     dword [esi+12], edx
494
        add     esi, 16
494
        add     esi, 16
495
        add     dword [edi+mtrr_range.start+4], edx
495
        add     dword [edi+mtrr_range.start+4], edx
496
        sub     dword [edi+mtrr_range.length+4], edx
496
        sub     dword [edi+mtrr_range.length+4], edx
497
        jnz     .range2mtrr_loop
497
        jnz     .range2mtrr_loop
498
        cmp     dword [edi+mtrr_range.length], 0
498
        cmp     dword [edi+mtrr_range.length], 0
499
        jz      .range2mtrr_next
499
        jz      .range2mtrr_next
500
.less4G:
500
.less4G:
501
; 8d. If we are dealing with low-memory range (before 4G)
501
; 8d. If we are dealing with low-memory range (before 4G)
502
; and appending a maximal-size hole would create a range covering top of 4G,
502
; and appending a maximal-size hole would create a range covering top of 4G,
503
; create a maximal-size WB range and return to this step.
503
; create a maximal-size WB range and return to this step.
504
; Example: for [0,0xBC000000) the following steps would consider
504
; Example: for [0,0xBC000000) the following steps would consider
505
; variants [0,0x80000000)+(another range to be splitted) and
505
; variants [0,0x80000000)+(another range to be splitted) and
506
; [0,0x100000000)-(another range to be splitted); we forbid the last variant,
506
; [0,0x100000000)-(another range to be splitted); we forbid the last variant,
507
; so the first variant must be used.
507
; so the first variant must be used.
508
        bsr     ecx, dword [edi+mtrr_range.length]
508
        bsr     ecx, dword [edi+mtrr_range.length]
509
        xor     edx, edx
509
        xor     edx, edx
510
        inc     edx
510
        inc     edx
511
        shl     edx, cl
511
        shl     edx, cl
512
        lea     eax, [edx*2]
512
        lea     eax, [edx*2]
513
        add     eax, dword [edi+mtrr_range.start]
513
        add     eax, dword [edi+mtrr_range.start]
514
        jnz     .start_aligned
514
        jnz     .start_aligned
515
        inc     [.num_used_mtrrs]
515
        inc     [.num_used_mtrrs]
516
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
516
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
517
        ja      .abort
517
        ja      .abort
518
        mov     eax, dword [edi+mtrr_range.start]
518
        mov     eax, dword [edi+mtrr_range.start]
519
        mov     dword [esi], eax
519
        mov     dword [esi], eax
520
        or      dword [esi], MEM_WB
520
        or      dword [esi], MEM_WB
521
        mov     dword [esi+4], 0
521
        mov     dword [esi+4], 0
522
        mov     dword [esi+8], edx
522
        mov     dword [esi+8], edx
523
        mov     dword [esi+12], 0
523
        mov     dword [esi+12], 0
524
        add     esi, 16
524
        add     esi, 16
525
        add     dword [edi+mtrr_range.start], edx
525
        add     dword [edi+mtrr_range.start], edx
526
        sub     dword [edi+mtrr_range.length], edx
526
        sub     dword [edi+mtrr_range.length], edx
527
        jnz     .less4G
527
        jnz     .less4G
528
        jmp     .range2mtrr_next
528
        jmp     .range2mtrr_next
529
.start_aligned:
529
.start_aligned:
530
; Start is aligned for any allowed length, maximum-size hole is allowed.
530
; Start is aligned for any allowed length, maximum-size hole is allowed.
531
; Select the best MTRR configuration for one range.
531
; Select the best MTRR configuration for one range.
532
; length=...101101
532
; length=...101101
533
; Without hole at the end, we need one WB MTRR for every 1-bit in length:
533
; Without hole at the end, we need one WB MTRR for every 1-bit in length:
534
; length=...100000 + ...001000 + ...000100 + ...000001
534
; length=...100000 + ...001000 + ...000100 + ...000001
535
; We can also append one hole at the end so that one 0-bit (selected by us)
535
; We can also append one hole at the end so that one 0-bit (selected by us)
536
; becomes 1 and all lower bits become 0 for WB-range:
536
; becomes 1 and all lower bits become 0 for WB-range:
537
; length=...110000 - (...00010 + ...00001)
537
; length=...110000 - (...00010 + ...00001)
538
; In this way, we need one WB MTRR for every 1-bit higher than the selected bit,
538
; In this way, we need one WB MTRR for every 1-bit higher than the selected bit,
539
; one WB MTRR for the selected bit, one UC MTRR for every 0-bit between
539
; one WB MTRR for the selected bit, one UC MTRR for every 0-bit between
540
; the selected bit and lowest 1-bit (they become 1-bits after negation)
540
; the selected bit and lowest 1-bit (they become 1-bits after negation)
541
; and one UC MTRR for lowest 1-bit.
541
; and one UC MTRR for lowest 1-bit.
542
; So we need to select 0-bit with the maximal difference
542
; So we need to select 0-bit with the maximal difference
543
; (number of 0-bits) - (number of 1-bits) between selected and lowest 1-bit,
543
; (number of 0-bits) - (number of 1-bits) between selected and lowest 1-bit,
544
; this equals the gain from using a hole. If the difference is negative for
544
; this equals the gain from using a hole. If the difference is negative for
545
; all 0-bits, don't append hole.
545
; all 0-bits, don't append hole.
546
; Note that lowest 1-bit is not included when counting, but selected 0-bit is.
546
; Note that lowest 1-bit is not included when counting, but selected 0-bit is.
547
; 8e. Find the optimal bit position for hole.
547
; 8e. Find the optimal bit position for hole.
548
; eax = current difference, ebx = best difference,
548
; eax = current difference, ebx = best difference,
549
; ecx = hole bit position, edx = current bit position.
549
; ecx = hole bit position, edx = current bit position.
550
        xor     eax, eax
550
        xor     eax, eax
551
        xor     ebx, ebx
551
        xor     ebx, ebx
552
        xor     ecx, ecx
552
        xor     ecx, ecx
553
        bsf     edx, dword [edi+mtrr_range.length]
553
        bsf     edx, dword [edi+mtrr_range.length]
554
        jnz     @f
554
        jnz     @f
555
        bsf     edx, dword [edi+mtrr_range.length+4]
555
        bsf     edx, dword [edi+mtrr_range.length+4]
556
        add     edx, 32
556
        add     edx, 32
557
@@:
557
@@:
558
        push    edx     ; save position of lowest 1-bit for step 8f
558
        push    edx     ; save position of lowest 1-bit for step 8f
559
.calc_stat:
559
.calc_stat:
560
        inc     edx
560
        inc     edx
561
        cmp     edx, 64
561
        cmp     edx, 64
562
        jae     .stat_done
562
        jae     .stat_done
563
        inc     eax     ; increment difference in hope for 1-bit
563
        inc     eax     ; increment difference in hope for 1-bit
564
; Note: bt conveniently works with both .length and .length+4,
564
; Note: bt conveniently works with both .length and .length+4,
565
; depending on whether edx>=32.
565
; depending on whether edx>=32.
566
        bt      dword [edi+mtrr_range.length], edx
566
        bt      dword [edi+mtrr_range.length], edx
567
        jc      .calc_stat
567
        jc      .calc_stat
568
        dec     eax     ; hope was wrong, decrement difference to correct 'inc'
568
        dec     eax     ; hope was wrong, decrement difference to correct 'inc'
569
        dec     eax     ; and again, now getting the real difference
569
        dec     eax     ; and again, now getting the real difference
570
        cmp     eax, ebx
570
        cmp     eax, ebx
571
        jle     .calc_stat
571
        jle     .calc_stat
572
        mov     ebx, eax
572
        mov     ebx, eax
573
        mov     ecx, edx
573
        mov     ecx, edx
574
        jmp     .calc_stat
574
        jmp     .calc_stat
575
.stat_done:
575
.stat_done:
576
; 8f. If we decided to create a hole, flip all bits between lowest and selected.
576
; 8f. If we decided to create a hole, flip all bits between lowest and selected.
577
        pop     edx     ; restore position of lowest 1-bit saved at step 8e
577
        pop     edx     ; restore position of lowest 1-bit saved at step 8e
578
        test    ecx, ecx
578
        test    ecx, ecx
579
        jz      .fill_hi_init
579
        jz      .fill_hi_init
580
@@:
580
@@:
581
        inc     edx
581
        inc     edx
582
        cmp     edx, ecx
582
        cmp     edx, ecx
583
        ja      .fill_hi_init
583
        ja      .fill_hi_init
584
        btc     dword [edi+mtrr_range.length], edx
584
        btc     dword [edi+mtrr_range.length], edx
585
        jmp     @b
585
        jmp     @b
586
.fill_hi_init:
586
.fill_hi_init:
587
; 8g. Create MTRR ranges corresponding to upper 32 bits.
587
; 8g. Create MTRR ranges corresponding to upper 32 bits.
588
        sub     ecx, 32
588
        sub     ecx, 32
589
.fill_hi_loop:
589
.fill_hi_loop:
590
        bsr     edx, dword [edi+mtrr_range.length+4]
590
        bsr     edx, dword [edi+mtrr_range.length+4]
591
        jz      .fill_hi_done
591
        jz      .fill_hi_done
592
        inc     [.num_used_mtrrs]
592
        inc     [.num_used_mtrrs]
593
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
593
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
594
        ja      .abort
594
        ja      .abort
595
        mov     eax, dword [edi+mtrr_range.start]
595
        mov     eax, dword [edi+mtrr_range.start]
596
        mov     [esi], eax
596
        mov     [esi], eax
597
        mov     eax, dword [edi+mtrr_range.start+4]
597
        mov     eax, dword [edi+mtrr_range.start+4]
598
        mov     [esi+4], eax
598
        mov     [esi+4], eax
599
        xor     eax, eax
599
        xor     eax, eax
600
        mov     [esi+8], eax
600
        mov     [esi+8], eax
601
        bts     eax, edx
601
        bts     eax, edx
602
        mov     [esi+12], eax
602
        mov     [esi+12], eax
603
        cmp     edx, ecx
603
        cmp     edx, ecx
604
        jl      .fill_hi_uc
604
        jl      .fill_hi_uc
605
        or      dword [esi], MEM_WB
605
        or      dword [esi], MEM_WB
606
        add     dword [edi+mtrr_range.start+4], eax
606
        add     dword [edi+mtrr_range.start+4], eax
607
        jmp     @f
607
        jmp     @f
608
.fill_hi_uc:
608
.fill_hi_uc:
609
        sub     dword [esi+4], eax
609
        sub     dword [esi+4], eax
610
        sub     dword [edi+mtrr_range.start+4], eax
610
        sub     dword [edi+mtrr_range.start+4], eax
611
@@:
611
@@:
612
        add     esi, 16
612
        add     esi, 16
613
        sub     dword [edi+mtrr_range.length], eax
613
        sub     dword [edi+mtrr_range.length], eax
614
        jmp     .fill_hi_loop
614
        jmp     .fill_hi_loop
615
.fill_hi_done:
615
.fill_hi_done:
616
; 8h. Create MTRR ranges corresponding to lower 32 bits.
616
; 8h. Create MTRR ranges corresponding to lower 32 bits.
617
        add     ecx, 32
617
        add     ecx, 32
618
.fill_lo_loop:
618
.fill_lo_loop:
619
        bsr     edx, dword [edi+mtrr_range.length]
619
        bsr     edx, dword [edi+mtrr_range.length]
620
        jz      .range2mtrr_next
620
        jz      .range2mtrr_next
621
        inc     [.num_used_mtrrs]
621
        inc     [.num_used_mtrrs]
622
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
622
        cmp     [.num_used_mtrrs], MAX_USEFUL_MTRRS
623
        ja      .abort
623
        ja      .abort
624
        mov     eax, dword [edi+mtrr_range.start]
624
        mov     eax, dword [edi+mtrr_range.start]
625
        mov     [esi], eax
625
        mov     [esi], eax
626
        mov     eax, dword [edi+mtrr_range.start+4]
626
        mov     eax, dword [edi+mtrr_range.start+4]
627
        mov     [esi+4], eax
627
        mov     [esi+4], eax
628
        xor     eax, eax
628
        xor     eax, eax
629
        mov     [esi+12], eax
629
        mov     [esi+12], eax
630
        bts     eax, edx
630
        bts     eax, edx
631
        mov     [esi+8], eax
631
        mov     [esi+8], eax
632
        cmp     edx, ecx
632
        cmp     edx, ecx
633
        jl      .fill_lo_uc
633
        jl      .fill_lo_uc
634
        or      dword [esi], MEM_WB
634
        or      dword [esi], MEM_WB
635
        add     dword [edi+mtrr_range.start], eax
635
        add     dword [edi+mtrr_range.start], eax
636
        jmp     @f
636
        jmp     @f
637
.fill_lo_uc:
637
.fill_lo_uc:
638
        sub     dword [esi], eax
638
        sub     dword [esi], eax
639
        sub     dword [edi+mtrr_range.start], eax
639
        sub     dword [edi+mtrr_range.start], eax
640
@@:
640
@@:
641
        add     esi, 16
641
        add     esi, 16
642
        sub     dword [edi+mtrr_range.length], eax
642
        sub     dword [edi+mtrr_range.length], eax
643
        jmp     .fill_lo_loop
643
        jmp     .fill_lo_loop
644
.range2mtrr_next:
644
.range2mtrr_next:
645
; 8i. Repeat the loop at 8c-8h for all ranges.
645
; 8i. Repeat the loop at 8c-8h for all ranges.
646
        mov     edi, [edi+mtrr_range.next]
646
        mov     edi, [edi+mtrr_range.next]
647
        test    edi, edi
647
        test    edi, edi
648
        jnz     .range2mtrr_loop
648
        jnz     .range2mtrr_loop
649
; 9. We have calculated needed MTRRs, now setup them in the CPU.
649
; 9. We have calculated needed MTRRs, now setup them in the CPU.
650
; 9a. Abort if number of MTRRs is too large.
650
; 9a. Abort if number of MTRRs is too large.
651
        mov     eax, [num_variable_mtrrs]
651
        mov     eax, [num_variable_mtrrs]
652
        cmp     [.num_used_mtrrs], eax
652
        cmp     [.num_used_mtrrs], eax
653
        ja      .abort
653
        ja      .abort
654
 
654
 
655
; 9b. Prepare for changes.
655
; 9b. Prepare for changes.
656
        call    mtrr_begin_change
656
        call    mtrr_begin_change
657
 
657
 
658
; 9c. Prepare for loop over MTRRs.
658
; 9c. Prepare for loop over MTRRs.
659
        lea     esi, [.mtrrs]
659
        lea     esi, [.mtrrs]
660
        mov     ecx, 0x200
660
        mov     ecx, 0x200
661
@@:
661
@@:
662
; 9d. For every MTRR, copy PHYSBASEn as is: step 8 has configured
662
; 9d. For every MTRR, copy PHYSBASEn as is: step 8 has configured
663
; start value and type bits as needed.
663
; start value and type bits as needed.
664
        mov     eax, [esi]
664
        mov     eax, [esi]
665
        mov     edx, [esi+4]
665
        mov     edx, [esi+4]
666
        wrmsr
666
        wrmsr
667
        inc     ecx
667
        inc     ecx
668
; 9e. For every MTRR, calculate PHYSMASKn = -(length) or 0x800
668
; 9e. For every MTRR, calculate PHYSMASKn = -(length) or 0x800
669
; with upper bits cleared, 0x800 = MTRR is valid.
669
; with upper bits cleared, 0x800 = MTRR is valid.
670
        xor     eax, eax
670
        xor     eax, eax
671
        xor     edx, edx
671
        xor     edx, edx
672
        sub     eax, [esi+8]
672
        sub     eax, [esi+8]
673
        sbb     edx, [esi+12]
673
        sbb     edx, [esi+12]
674
        or      eax, 0x800
674
        or      eax, 0x800
675
        or      edx, [.phys_reserved_mask]
675
        or      edx, [.phys_reserved_mask]
676
        xor     edx, [.phys_reserved_mask]
676
        xor     edx, [.phys_reserved_mask]
677
        wrmsr
677
        wrmsr
678
        inc     ecx
678
        inc     ecx
679
; 9f. Continue steps 9d and 9e for all MTRRs calculated at step 8.
679
; 9f. Continue steps 9d and 9e for all MTRRs calculated at step 8.
680
        add     esi, 16
680
        add     esi, 16
681
        dec     [.num_used_mtrrs]
681
        dec     [.num_used_mtrrs]
682
        jnz     @b
682
        jnz     @b
683
; 9g. Zero other MTRRs.
683
; 9g. Zero other MTRRs.
684
        xor     eax, eax
684
        xor     eax, eax
685
        xor     edx, edx
685
        xor     edx, edx
686
        mov     ebx, [num_variable_mtrrs]
686
        mov     ebx, [num_variable_mtrrs]
687
        lea     ebx, [0x200+ebx*2]
687
        lea     ebx, [0x200+ebx*2]
688
@@:
688
@@:
689
        cmp     ecx, ebx
689
        cmp     ecx, ebx
690
        jae     @f
690
        jae     @f
691
        wrmsr
691
        wrmsr
692
        inc     ecx
692
        inc     ecx
693
        wrmsr
693
        wrmsr
694
        inc     ecx
694
        inc     ecx
695
        jmp     @b
695
        jmp     @b
696
@@:
696
@@:
697
 
697
 
698
; 9i. Configure MTRR_DEF_TYPE.
698
; 9i. Configure MTRR_DEF_TYPE.
699
        mov     ecx, 0x2FF
699
        mov     ecx, 0x2FF
700
        rdmsr
700
        rdmsr
701
        or      ah, 8   ; enable variable-ranges MTRR
701
        or      ah, 8   ; enable variable-ranges MTRR
702
        and     al, 0xF0; default memtype = UC
702
        and     al, 0xF0; default memtype = UC
703
        wrmsr
703
        wrmsr
704
 
704
 
705
; 9j. Changes are done.
705
; 9j. Changes are done.
706
        call    mtrr_end_change
706
        call    mtrr_end_change
707
 
707
 
708
.abort:
708
.abort:
709
        add     esp, .local_vars_size + MAX_RANGES * sizeof.mtrr_range
709
        add     esp, .local_vars_size + MAX_RANGES * sizeof.mtrr_range
710
        pop     ebp
710
        pop     ebp
711
        ret
711
        ret
712
endp
712
endp
713
 
713
 
714
; Allocate&set one MTRR for given range.
714
; Allocate&set one MTRR for given range.
715
; size must be power of 2 that divides base.
715
; size must be power of 2 that divides base.
716
proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword
716
proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword
717
; find unused register
717
; find unused register
718
        mov     ecx, 0x201
718
        mov     ecx, 0x201
719
.scan:
719
.scan:
720
        rdmsr
720
        rdmsr
721
        dec     ecx
721
        dec     ecx
722
        test    ah, 8
722
        test    ah, 8
723
        jz      .found
723
        jz      .found
724
        rdmsr
724
        rdmsr
725
        test    edx, edx
725
        test    edx, edx
726
        jnz     @f
726
        jnz     @f
727
        and     eax, not 0xFFF  ; clear reserved bits
727
        and     eax, not 0xFFF  ; clear reserved bits
728
        cmp     eax, [base]
728
        cmp     eax, [base]
729
        jz      .ret
729
        jz      .ret
730
@@:
730
@@:
731
        add     ecx, 3
731
        add     ecx, 3
732
        mov     eax, [num_variable_mtrrs]
732
        mov     eax, [num_variable_mtrrs]
733
        lea     eax, [0x200+eax*2]
733
        lea     eax, [0x200+eax*2]
734
        cmp     ecx, eax
734
        cmp     ecx, eax
735
        jb      .scan
735
        jb      .scan
736
; no free registers, ignore the call
736
; no free registers, ignore the call
737
.ret:
737
.ret:
738
        ret
738
        ret
739
.found:
739
.found:
740
; found, write values
740
; found, write values
741
        call    mtrr_begin_change
741
        call    mtrr_begin_change
742
        xor     edx, edx
742
        xor     edx, edx
743
        mov     eax, [base]
743
        mov     eax, [base]
744
        or      eax, [mem_type]
744
        or      eax, [mem_type]
745
        wrmsr
745
        wrmsr
746
 
746
 
747
        mov     al, [cpu_phys_addr_width]
747
        mov     al, [cpu_phys_addr_width]
748
        xor     edx, edx
748
        xor     edx, edx
749
        bts     edx, eax
749
        bts     edx, eax
750
        xor     eax, eax
750
        xor     eax, eax
751
        sub     eax, [size]
751
        sub     eax, [size]
752
        sbb     edx, 0
752
        sbb     edx, 0
753
        or      eax, 0x800
753
        or      eax, 0x800
754
        inc     ecx
754
        inc     ecx
755
        wrmsr
755
        wrmsr
756
        call    mtrr_end_change
756
        call    mtrr_end_change
757
        ret
757
        ret
758
endp
758
endp
759
 
759
 
760
; Helper procedure for mtrr_validate.
760
; Helper procedure for mtrr_validate.
761
; Calculates memory type for given address according to variable-range MTRRs.
761
; Calculates memory type for given address according to variable-range MTRRs.
762
; Assumes that MTRRs are enabled.
762
; Assumes that MTRRs are enabled.
763
; in: ebx = 32-bit physical address
763
; in: ebx = 32-bit physical address
764
; out: eax = memory type for ebx
764
; out: eax = memory type for ebx
765
proc mtrr_get_real_type
765
proc mtrr_get_real_type
766
; 1. Initialize: we have not yet found any MTRRs covering ebx.
766
; 1. Initialize: we have not yet found any MTRRs covering ebx.
767
        push    0
767
        push    0
768
        mov     ecx, 0x201
768
        mov     ecx, 0x201
769
.mtrr_loop:
769
.mtrr_loop:
770
; 2. For every MTRR, check whether it is valid; if not, continue to the next MTRR.
770
; 2. For every MTRR, check whether it is valid; if not, continue to the next MTRR.
771
        rdmsr
771
        rdmsr
772
        dec     ecx
772
        dec     ecx
773
        test    ah, 8
773
        test    ah, 8
774
        jz      .next
774
        jz      .next
775
; 3. For every valid MTRR, check whether (ebx and PHYSMASKn) == PHYSBASEn,
775
; 3. For every valid MTRR, check whether (ebx and PHYSMASKn) == PHYSBASEn,
776
; excluding low 12 bits.
776
; excluding low 12 bits.
777
        and     eax, ebx
777
        and     eax, ebx
778
        push    eax
778
        push    eax
779
        rdmsr
779
        rdmsr
780
        test    edx, edx
780
        test    edx, edx
781
        pop     edx
781
        pop     edx
782
        jnz     .next
782
        jnz     .next
783
        xor     edx, eax
783
        xor     edx, eax
784
        and     edx, not 0xFFF
784
        and     edx, not 0xFFF
785
        jnz     .next
785
        jnz     .next
786
; 4. If so, set the bit corresponding to memory type defined by this MTRR.
786
; 4. If so, set the bit corresponding to memory type defined by this MTRR.
787
        and     eax, 7
787
        and     eax, 7
788
        bts     [esp], eax
788
        bts     [esp], eax
789
.next:
789
.next:
790
; 5. Continue loop at 2-4 for all variable-range MTRRs.
790
; 5. Continue loop at 2-4 for all variable-range MTRRs.
791
        add     ecx, 3
791
        add     ecx, 3
792
        mov     eax, [num_variable_mtrrs]
792
        mov     eax, [num_variable_mtrrs]
793
        lea     eax, [0x200+eax*2]
793
        lea     eax, [0x200+eax*2]
794
        cmp     ecx, eax
794
        cmp     ecx, eax
795
        jb      .mtrr_loop
795
        jb      .mtrr_loop
796
; 6. If no MTRRs cover address in ebx, use default MTRR type from MTRR_DEF_CAP.
796
; 6. If no MTRRs cover address in ebx, use default MTRR type from MTRR_DEF_CAP.
797
        pop     edx
797
        pop     edx
798
        test    edx, edx
798
        test    edx, edx
799
        jz      .default
799
        jz      .default
800
; 7. Find&clear 1-bit in edx.
800
; 7. Find&clear 1-bit in edx.
801
        bsf     eax, edx
801
        bsf     eax, edx
802
        btr     edx, eax
802
        btr     edx, eax
803
; 8. If there was only one 1-bit, then all MTRRs are consistent, return that bit.
803
; 8. If there was only one 1-bit, then all MTRRs are consistent, return that bit.
804
        test    edx, edx
804
        test    edx, edx
805
        jz      .nothing
805
        jz      .nothing
806
; Otherwise, return MEM_UC (e.g. WB+UC is UC).
806
; Otherwise, return MEM_UC (e.g. WB+UC is UC).
807
        xor     eax, eax
807
        xor     eax, eax
808
.nothing:
808
.nothing:
809
        ret
809
        ret
810
.default:
810
.default:
811
        mov     ecx, 0x2FF
811
        mov     ecx, 0x2FF
812
        rdmsr
812
        rdmsr
813
        movzx   eax, al
813
        movzx   eax, al
814
        ret
814
        ret
815
endp
815
endp
816
 
816
 
817
; If MTRRs are configured improperly, this is not obvious to the user;
817
; If MTRRs are configured improperly, this is not obvious to the user;
818
; everything works, but the performance can be horrible.
818
; everything works, but the performance can be horrible.
819
; Try to detect this and let the user know that the low performance
819
; Try to detect this and let the user know that the low performance
820
; is caused by some problem and is not a global property of the system.
820
; is caused by some problem and is not a global property of the system.
821
; Let's hope he would report it to developers...
821
; Let's hope he would report it to developers...
822
proc mtrr_validate
822
proc mtrr_validate
823
; 1. If MTRRs are not supported, they cannot be configured improperly.
823
; 1. If MTRRs are not supported, they cannot be configured improperly.
824
; Note: VirtualBox claims MTRR support in cpuid, but emulates MTRRCAP=0,
824
; Note: VirtualBox claims MTRR support in cpuid, but emulates MTRRCAP=0,
825
; which is efficiently equivalent to absent MTRRs.
825
; which is efficiently equivalent to absent MTRRs.
826
; So check [num_variable_mtrrs] instead of CAPS_MTRR in [cpu_caps].
826
; So check [num_variable_mtrrs] instead of CAPS_MTRR in [cpu_caps].
827
        cmp     [num_variable_mtrrs], 0
827
        cmp     [num_variable_mtrrs], 0
828
        jz      .exit
828
        jz      .exit
829
; 2. If variable-range MTRRs are not configured, this is a problem.
829
; 2. If variable-range MTRRs are not configured, this is a problem.
830
        mov     ecx, 0x2FF
830
        mov     ecx, 0x2FF
831
        rdmsr
831
        rdmsr
832
        test    ah, 8
832
        test    ah, 8
833
        jz      .fail
833
        jz      .fail
834
; 3. Get the memory type for address somewhere inside working memory.
834
; 3. Get the memory type for address somewhere inside working memory.
835
; It must be write-back.
835
; It must be write-back.
836
        mov     ebx, 0x27FFFF
836
        mov     ebx, 0x27FFFF
837
        call    mtrr_get_real_type
837
        call    mtrr_get_real_type
838
        cmp     al, MEM_WB
838
        cmp     al, MEM_WB
839
        jnz     .fail
839
        jnz     .fail
840
; 4. If we're using a mode with LFB,
840
; 4. If we're using a mode with LFB,
841
; get the memory type for last pixel of the framebuffer.
841
; get the memory type for last pixel of the framebuffer.
842
; It must be write-combined.
842
; It must be write-combined.
843
        test    word [SCR_MODE], 0x4000
843
        test    word [SCR_MODE], 0x4000
844
        jz      .exit
844
        jz      .exit
845
        mov     eax, [_display.lfb_pitch]
845
        mov     eax, [_display.lfb_pitch]
846
        mul     [_display.height]
846
        mul     [_display.height]
847
        dec     eax
847
        dec     eax
848
; LFB is mapped to virtual address LFB_BASE,
848
; LFB is mapped to virtual address LFB_BASE,
849
; it uses global pages if supported by CPU.
849
; it uses global pages if supported by CPU.
850
        mov     ebx, [sys_proc+PROC.pdt_0+(LFB_BASE shr 20)]
850
        mov     ebx, [sys_proc+PROC.pdt_0+(LFB_BASE shr 20)]
851
        test    ebx, PG_LARGE
851
        test    ebx, PDE_LARGE
852
        jnz     @f
852
        jnz     @f
853
        mov     ebx, [page_tabs+(LFB_BASE shr 10)]
853
        mov     ebx, [page_tabs+(LFB_BASE shr 10)]
854
@@:
854
@@:
855
        and     ebx, not 0xFFF
855
        and     ebx, not 0xFFF
856
        add     ebx, eax
856
        add     ebx, eax
857
        call    mtrr_get_real_type
857
        call    mtrr_get_real_type
858
        cmp     al, MEM_WC
858
        cmp     al, MEM_WC
859
        jz      .exit
859
        jz      .exit
860
; 5. The check at step 4 fails on Bochs:
860
; 5. The check at step 4 fails on Bochs:
861
; Bochs BIOS configures MTRRs in a strange way not respecting [cpu_phys_addr_width],
861
; Bochs BIOS configures MTRRs in a strange way not respecting [cpu_phys_addr_width],
862
; so mtrr_reconfigure avoids to touch anything.
862
; so mtrr_reconfigure avoids to touch anything.
863
; However, Bochs core ignores MTRRs (keeping them only for rdmsr/wrmsr),
863
; However, Bochs core ignores MTRRs (keeping them only for rdmsr/wrmsr),
864
; so we don't care about proper setting for Bochs.
864
; so we don't care about proper setting for Bochs.
865
; Use northbridge PCI id to detect Bochs: it emulates either i440fx or i430fx
865
; Use northbridge PCI id to detect Bochs: it emulates either i440fx or i430fx
866
; depending on configuration file.
866
; depending on configuration file.
867
        mov     eax, [pcidev_list.fd]
867
        mov     eax, [pcidev_list.fd]
868
        cmp     eax, pcidev_list        ; sanity check: fail if no PCI devices
868
        cmp     eax, pcidev_list        ; sanity check: fail if no PCI devices
869
        jz      .fail
869
        jz      .fail
870
        cmp     [eax+PCIDEV.vendor_device_id], 0x12378086
870
        cmp     [eax+PCIDEV.vendor_device_id], 0x12378086
871
        jz      .exit
871
        jz      .exit
872
        cmp     [eax+PCIDEV.vendor_device_id], 0x01228086
872
        cmp     [eax+PCIDEV.vendor_device_id], 0x01228086
873
        jnz     .fail
873
        jnz     .fail
874
.exit:
874
.exit:
875
        ret
875
        ret
876
.fail:
876
.fail:
877
        mov     ebx, mtrr_user_message
877
        mov     ebx, mtrr_user_message
878
        mov     ebp, notifyapp
878
        mov     ebp, notifyapp
879
        call    fs_execute_from_sysdir_param
879
        call    fs_execute_from_sysdir_param
880
        ret
880
        ret
881
endp
881
endp