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