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