075d45fa7fa8ac2125229650ca18a680ae094c6b
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Library / QNCSmmLib / QNCSmmLib.c
1 /** @file
2 QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.
3
4 Copyright (c) 2013-2015 Intel Corporation.
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include <Base.h>
18 #include <IntelQNCRegs.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/IoLib.h>
22 #include <Uefi/UefiBaseType.h>
23 #include <Library/QNCAccessLib.h>
24
25 #define BOOT_SERVICE_SOFTWARE_SMI_DATA 0
26 #define RUNTIME_SOFTWARE_SMI_DATA 1
27
28 /**
29 Triggers a run time or boot time SMI.
30
31 This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.
32
33 @param Data The value to set the APMC status.
34
35 **/
36 VOID
37 InternalTriggerSmi (
38 IN UINT8 Data
39 )
40 {
41 UINT16 GPE0BLK_Base;
42 UINT32 NewValue;
43
44 //
45 // Get GPE0BLK_Base
46 //
47 GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
48
49
50 //
51 // Enable APM SMI
52 //
53 IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);
54
55 //
56 // Enable SMI globally
57 //
58 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
59 NewValue |= SMI_EN;
60 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
61
62 //
63 // Set APM_STS
64 //
65 IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);
66
67 //
68 // Generate the APM SMI
69 //
70 IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));
71
72 //
73 // Clear the APM SMI Status Bit
74 //
75 IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
76
77 //
78 // Set the EOS Bit
79 //
80 IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
81 }
82
83
84 /**
85 Triggers an SMI at boot time.
86
87 This function triggers a software SMM interrupt at boot time.
88
89 **/
90 VOID
91 EFIAPI
92 TriggerBootServiceSoftwareSmi (
93 VOID
94 )
95 {
96 InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA);
97 }
98
99
100 /**
101 Triggers an SMI at run time.
102
103 This function triggers a software SMM interrupt at run time.
104
105 **/
106 VOID
107 EFIAPI
108 TriggerRuntimeSoftwareSmi (
109 VOID
110 )
111 {
112 InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA);
113 }
114
115
116 /**
117 Gets the software SMI data.
118
119 This function tests if a software SMM interrupt happens. If a software SMI happens,
120 it retrieves the SMM data and returns it as a non-negative value; otherwise a negative
121 value is returned.
122
123 @return Data The data retrieved from SMM data port in case of a software SMI;
124 otherwise a negative value.
125
126 **/
127 INTN
128 InternalGetSwSmiData (
129 VOID
130 )
131 {
132 UINT8 SmiStatus;
133 UINT8 Data;
134
135 SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
136 if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) &&
137 (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) {
138 Data = IoRead8 (PcdGet16 (PcdSmmDataPort));
139 return (INTN)(UINTN)Data;
140 }
141
142 return -1;
143 }
144
145
146 /**
147 Test if a boot time software SMI happened.
148
149 This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
150 it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE.
151
152 @retval TRUE A software SMI triggered at boot time happened.
153 @retval FLASE No software SMI happened or the software SMI was triggered at run time.
154
155 **/
156 BOOLEAN
157 EFIAPI
158 IsBootServiceSoftwareSmi (
159 VOID
160 )
161 {
162 return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA);
163 }
164
165
166 /**
167 Test if a run time software SMI happened.
168
169 This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
170 it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE.
171
172 @retval TRUE A software SMI triggered at run time happened.
173 @retval FLASE No software SMI happened or the software SMI was triggered at boot time.
174
175 **/
176 BOOLEAN
177 EFIAPI
178 IsRuntimeSoftwareSmi (
179 VOID
180 )
181 {
182 return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA);
183 }
184
185
186
187 /**
188
189 Clear APM SMI Status Bit; Set the EOS bit.
190
191 **/
192 VOID
193 EFIAPI
194 ClearSmi (
195 VOID
196 )
197 {
198
199 UINT16 GPE0BLK_Base;
200
201 //
202 // Get GpeBase
203 //
204 GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
205
206 //
207 // Clear the APM SMI Status Bit
208 //
209 IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM);
210
211 //
212 // Set the EOS Bit
213 //
214 IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);
215 }
216
217 /**
218 This routine is the chipset code that accepts a request to "open" a region of SMRAM.
219 The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
220 The use of "open" means that the memory is visible from all boot-service
221 and SMM agents.
222
223 @retval FALSE Cannot open a locked SMRAM region
224 @retval TRUE Success to open SMRAM region.
225 **/
226 BOOLEAN
227 EFIAPI
228 QNCOpenSmramRegion (
229 VOID
230 )
231 {
232 UINT32 Smram;
233
234 // Read the SMRAM register
235 Smram = QncHsmmcRead ();
236
237 //
238 // Is the platform locked?
239 //
240 if (Smram & SMM_LOCKED) {
241 // Cannot Open a locked region
242 DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n"));
243 return FALSE;
244 }
245
246 //
247 // Open all SMRAM regions for Host access only
248 //
249 Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN); // Open for Host.
250 Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN); // Not for others.
251
252 //
253 // Write the SMRAM register
254 //
255 QncHsmmcWrite (Smram);
256
257 return TRUE;
258 }
259
260 /**
261 This routine is the chipset code that accepts a request to "close" a region of SMRAM.
262 The region could be legacy AB or TSEG near top of physical memory.
263 The use of "close" means that the memory is only visible from SMM agents,
264 not from BS or RT code.
265
266 @retval FALSE Cannot open a locked SMRAM region
267 @retval TRUE Success to open SMRAM region.
268 **/
269 BOOLEAN
270 EFIAPI
271 QNCCloseSmramRegion (
272 VOID
273 )
274 {
275 UINT32 Smram;
276
277 // Read the SMRAM register.
278 Smram = QncHsmmcRead ();
279
280 //
281 // Is the platform locked?
282 //
283 if(Smram & SMM_LOCKED) {
284 // Cannot Open a locked region
285 DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n"));
286 return FALSE;
287 }
288
289 Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN));
290
291 QncHsmmcWrite (Smram);
292
293 return TRUE;
294 }
295
296 /**
297 This routine is the chipset code that accepts a request to "lock" SMRAM.
298 The region could be legacy AB or TSEG near top of physical memory.
299 The use of "lock" means that the memory can no longer be opened
300 to BS state.
301 **/
302 VOID
303 EFIAPI
304 QNCLockSmramRegion (
305 VOID
306 )
307 {
308 UINT32 Smram;
309
310 // Read the SMRAM register.
311 Smram = QncHsmmcRead ();
312 if(Smram & SMM_LOCKED) {
313 DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n"));
314 }
315 Smram |= SMM_LOCKED;
316
317 QncHsmmcWrite (Smram);
318
319 return;
320 }