1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
;
; Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
;
; This library is free software; you can redistribute it and/or modify
; it under the terms of the GNU Lesser General Public License as
; published by the Free Software Foundation; either version 2.1 of the
; License, or (at your option) any later version.
;
; This code is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; Lesser General Public License for more details.
;
; You should have received a copy of the GNU Lesser General
; Public License along with this library; if not, write to the
; Free Software Foundation, Inc., 59 Temple Place, Suite 330,
; Boston, MA 02111-1307 USA
;
;* Function: *
;* This file contains hardware bug fixes.
include VSA2.INC
include ISA.INC
include GX2.INC
include CHIPSET.INC
.model tiny,c
.586p
.CODE
externdef Nested_SMI: proc
externdef SysMgr_Entry: proc
externdef Restore_IDT: proc
externdef Install_IDT: proc
externdef Sample_SMI_Pin: proc
externdef Clear_SMI_Pin: proc
externdef Header_Addr: dword
externdef HC_Status: dword
externdef SMI_Sources: dword
externdef HardwareInfo: Hardware
;*******************************************************************************
; Remove the RTC fix if an RTC VSM is installed.
;*******************************************************************************
Remove_RTC_Fix proc
mov word ptr [Fix_RTC], 0C3F8h ; CLC RET
ret
Remove_RTC_Fix endp
; *******************************************************************************
; This routine is called upon entry to a non-nested SMI.
; *******************************************************************************
VSA_Entry proc
; Patch a "jmp Nested_SMI" at Start
mov word ptr ds:[1], OFFSET Nested_SMI-3
; Install exception handlers
call Install_IDT
ret
VSA_Entry endp
; *******************************************************************************
; This routine is called upon exit from a non-nested SMI.
; It performs:
; 1) RTC fix
; 2) USB fix
; 3) IDT restore
; 4) Re-enable Suspend Modulation
;
; If CF=1 is returned, then loop back to SMI handlers.
; *******************************************************************************
VSA_Exit proc
mov eax, [Header_Addr] ; Restore the original SMM header
mov ecx, MSR_SMM_HDR
wrmsr
call Fix_RTC
jc short Exit ; Don't exit from VSA
; Restore "JMP SysMgr_Entry" at Start
mov word ptr ds:[1], OFFSET SysMgr_Entry-3
call Restore_IDT ; Restore IDT
clc
Exit: ret
VSA_Exit endp
; *******************************************************************************
; Handle the case where the RTC UIP bit was clear, application code was about to
; read the RTC, but an SMI occurs. When VSA returns, the RTC is updating, so the
; application reads a bad value.
;
; The Solution:
;
; The Time Stamp Counter is read upon entry to VSA. On exit, if UIP is low or
; it is determined that the SMI has taken < 250 us, then just exit. This leaves
; 44 us for the application to finish reading the RTC safely. If the SMI has
; taken > 250 us, then spin for 500 us minus the time spent servicing the SMI.
; This guarantees the RTC has finished updating. Then set the SET bit, wait for
; UIP to go low, then clear the SET bit.
;
; *******************************************************************************
RTC_TIME equ 250
Fix_RTC proc
in al, CMOS_INDEX ; Get RTC index
cmp al, 9 ; Only RTC indices 0-9 are UIP sensitive
ja Exit
mov bl, al ; Save RTC index
push si
mov al, CMOS_STATUS_A ; Read RTC Status A
out CMOS_INDEX, al
in al, CMOS_DATA
test al, UIP
jz Restore_RTC_Index
mov al, CMOS_STATUS_B ; Exit if StatusB[SET] = 1
out CMOS_INDEX, al
in al, CMOS_DATA
test al, SET
jz Restore_RTC_Index
ASSUME SI: PTR System ; Compute time servicing SMI in us
mov si, OFFSET VSM_Header.SysStuff
rdtsc
sub eax, [si+0].StartTime
sbb edx, [si+4].StartTime
movzx ecx, [HardwareInfo].CPU_MHz
cmp edx, ecx ; If sitting in Dowser or Standby too long,
jae Restore_RTC_Index ; the divide could overflow.
div ecx
cmp eax, RTC_TIME ; If < RTC_TIME us, exit
jb Restore_RTC_Index
call Clear_SMI_Pin
WaitForUpdate:
call Sample_SMI_Pin
stc
jnz short SMI_Abort ; Yes, go process it
rdtsc ; Wait for additional 300 us
sub eax, [si+0].StartTime
sbb edx, [si+4].StartTime
div ecx
cmp eax, RTC_TIME + 300
jb WaitForUpdate
ASSUME SI: NOTHING
; StatusB[SET] = 1;
mov al, CMOS_STATUS_B ; Read RTC StatusB
out CMOS_INDEX, al
in al, CMOS_DATA
test al, SET ; If (SET == 1)
jnz short Restore_RTC_Index ; bail
or al, SET ; else
out CMOS_DATA, al ; SET = 1
; Wait for StatusA[UIP] to go inactive
mov cx, 0FFFFh ; RTC timeout
SpinUIP:
mov al, CMOS_STATUS_A ; Yes, spin until UIP is clear
out CMOS_INDEX, al
in al, CMOS_DATA
test al, UIP
loopnz SpinUIP
mov al, CMOS_STATUS_B ; SET = 0
out CMOS_INDEX, al
in al, CMOS_DATA
and al, NOT SET
out CMOS_DATA, al
Restore_RTC_Index:
clc
SMI_Abort:
pop si
mov al, bl ; Restore CMOS index
out CMOS_INDEX, al
Exit: ret
Fix_RTC endp
END
|