• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   TCG MOR (Memory Overwrite Request) Control Driver.
3 
4   This driver initilize MemoryOverwriteRequestControl variable. It
5   will clear MOR_CLEAR_MEMORY_BIT bit if it is set. It will also do TPer Reset for
6   those encrypted drives through EFI_STORAGE_SECURITY_COMMAND_PROTOCOL at EndOfDxe.
7 
8 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution.  The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13 
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 
17 **/
18 
19 #include "TcgMor.h"
20 
21 UINT8    mMorControl;
22 
23 /**
24   Ready to Boot Event notification handler.
25 
26   Sequence of OS boot events is measured in this event notification handler.
27 
28   @param[in]  Event     Event whose notification function is being invoked
29   @param[in]  Context   Pointer to the notification function's context
30 
31 **/
32 VOID
33 EFIAPI
OnReadyToBoot(IN EFI_EVENT Event,IN VOID * Context)34 OnReadyToBoot (
35   IN      EFI_EVENT                 Event,
36   IN      VOID                      *Context
37   )
38 {
39   EFI_STATUS  Status;
40   UINTN       DataSize;
41 
42   if (MOR_CLEAR_MEMORY_VALUE (mMorControl) == 0x0) {
43     //
44     // MorControl is expected, directly return to avoid unnecessary variable operation
45     //
46     return ;
47   }
48   //
49   // Clear MOR_CLEAR_MEMORY_BIT
50   //
51   DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n"));
52   mMorControl &= 0xFE;
53 
54   DataSize = sizeof (mMorControl);
55   Status   = gRT->SetVariable (
56                MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
57                &gEfiMemoryOverwriteControlDataGuid,
58                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
59                DataSize,
60                &mMorControl
61                );
62   if (EFI_ERROR (Status)) {
63     DEBUG ((EFI_D_ERROR, "TcgMor: Clear MOR_CLEAR_MEMORY_BIT failure, Status = %r\n"));
64   }
65 }
66 
67 /**
68   Send TPer Reset command to reset eDrive to lock all protected bands.
69   Typically, there are 2 mechanism for resetting eDrive. They are:
70   1. TPer Reset through IEEE 1667 protocol.
71   2. TPer Reset through native TCG protocol.
72   This routine will detect what protocol the attached eDrive comform to, TCG or
73   IEEE 1667 protocol. Then send out TPer Reset command separately.
74 
75   @param[in] Ssp      The pointer to EFI_STORAGE_SECURITY_COMMAND_PROTOCOL instance.
76   @param[in] MediaId  ID of the medium to receive data from or send data to.
77 
78 **/
79 VOID
InitiateTPerReset(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL * Ssp,IN UINT32 MediaId)80 InitiateTPerReset (
81   IN  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *Ssp,
82   IN  UINT32                                   MediaId
83   )
84 {
85 
86   EFI_STATUS                                   Status;
87   UINT8                                        *Buffer;
88   UINTN                                        XferSize;
89   UINTN                                        Len;
90   UINTN                                        Index;
91   BOOLEAN                                      TcgFlag;
92   BOOLEAN                                      IeeeFlag;
93   SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA  *Data;
94 
95   Buffer        = NULL;
96   TcgFlag       = FALSE;
97   IeeeFlag      = FALSE;
98 
99   //
100   // ATA8-ACS 7.57.6.1 indicates the Transfer Length field requirements a multiple of 512.
101   // If the length of the TRUSTED RECEIVE parameter data is greater than the Transfer Length,
102   // then the device shall return the TRUSTED RECEIVE parameter data truncated to the requested Transfer Length.
103   //
104   Len           = ROUNDUP512(sizeof(SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA));
105   Buffer        = AllocateZeroPool(Len);
106 
107   if (Buffer == NULL) {
108     return;
109   }
110 
111   //
112   // When the Security Protocol field is set to 00h, and SP Specific is set to 0000h in a TRUSTED RECEIVE
113   // command, the device basic information data shall be returned.
114   //
115   Status = Ssp->ReceiveData (
116                   Ssp,
117                   MediaId,
118                   100000000,                    // Timeout 10-sec
119                   0,                            // SecurityProtocol
120                   0,                            // SecurityProtocolSpecifcData
121                   Len,                          // PayloadBufferSize,
122                   Buffer,                       // PayloadBuffer
123                   &XferSize
124                   );
125   if (EFI_ERROR (Status)) {
126     goto Exit;
127   }
128 
129   //
130   // In returned data, the ListLength field indicates the total length, in bytes,
131   // of the supported security protocol list.
132   //
133   Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA*)Buffer;
134   Len  = ROUNDUP512(sizeof (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA) +
135                     (Data->SupportedSecurityListLength[0] << 8) +
136                     (Data->SupportedSecurityListLength[1])
137                     );
138 
139   //
140   // Free original buffer and allocate new buffer.
141   //
142   FreePool(Buffer);
143   Buffer = AllocateZeroPool(Len);
144   if (Buffer == NULL) {
145     return;
146   }
147 
148   //
149   // Read full supported security protocol list from device.
150   //
151   Status = Ssp->ReceiveData (
152                   Ssp,
153                   MediaId,
154                   100000000,                    // Timeout 10-sec
155                   0,                            // SecurityProtocol
156                   0,                            // SecurityProtocolSpecifcData
157                   Len,                          // PayloadBufferSize,
158                   Buffer,                       // PayloadBuffer
159                   &XferSize
160                   );
161 
162   if (EFI_ERROR (Status)) {
163     goto Exit;
164   }
165 
166   Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA*)Buffer;
167   Len  = (Data->SupportedSecurityListLength[0] << 8) + Data->SupportedSecurityListLength[1];
168 
169   //
170   // Iterate full supported security protocol list to check if TCG or IEEE 1667 protocol
171   // is supported.
172   //
173   for (Index = 0; Index < Len; Index++) {
174     if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_TCG) {
175       //
176       // Found a  TCG device.
177       //
178       TcgFlag = TRUE;
179       DEBUG ((EFI_D_INFO, "This device is a TCG protocol device\n"));
180       break;
181     }
182 
183     if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_IEEE1667) {
184       //
185       // Found a IEEE 1667 device.
186       //
187       IeeeFlag = TRUE;
188       DEBUG ((EFI_D_INFO, "This device is a IEEE 1667 protocol device\n"));
189       break;
190     }
191   }
192 
193   if (!TcgFlag && !IeeeFlag) {
194     DEBUG ((EFI_D_INFO, "Neither a TCG nor IEEE 1667 protocol device is found\n"));
195     goto Exit;
196   }
197 
198   if (TcgFlag) {
199     //
200     // As long as TCG protocol is supported, send out a TPer Reset
201     // TCG command to the device via the TrustedSend command with a non-zero Transfer Length.
202     //
203     Status = Ssp->SendData (
204                     Ssp,
205                     MediaId,
206                     100000000,                    // Timeout 10-sec
207                     SECURITY_PROTOCOL_TCG,        // SecurityProtocol
208                     0x0400,                       // SecurityProtocolSpecifcData
209                     512,                          // PayloadBufferSize,
210                     Buffer                        // PayloadBuffer
211                     );
212 
213     if (!EFI_ERROR (Status)) {
214       DEBUG ((EFI_D_INFO, "Send TPer Reset Command Successfully !\n"));
215     } else {
216       DEBUG ((EFI_D_INFO, "Send TPer Reset Command Fail !\n"));
217     }
218   }
219 
220   if (IeeeFlag) {
221     //
222     // TBD : Perform a TPer Reset via IEEE 1667 Protocol
223     //
224     DEBUG ((EFI_D_INFO, "IEEE 1667 Protocol didn't support yet!\n"));
225   }
226 
227 Exit:
228 
229   if (Buffer != NULL) {
230     FreePool(Buffer);
231   }
232 }
233 
234 /**
235   Notification function of END_OF_DXE.
236 
237   This is a notification function registered on END_OF_DXE event.
238   It is to get VarCheckPcdBin.
239 
240   @param[in] Event      Event whose notification function is being invoked.
241   @param[in] Context    Pointer to the notification function's context.
242 
243 **/
244 VOID
245 EFIAPI
TPerResetAtEndOfDxe(IN EFI_EVENT Event,IN VOID * Context)246 TPerResetAtEndOfDxe (
247   IN EFI_EVENT  Event,
248   IN VOID       *Context
249   )
250 {
251   EFI_STORAGE_SECURITY_COMMAND_PROTOCOL   *Ssp;
252   EFI_BLOCK_IO_PROTOCOL                   *BlockIo;
253   EFI_STATUS                              Status;
254   UINTN                                   HandleCount;
255   EFI_HANDLE                              *HandleBuffer;
256   UINTN                                   Index;
257 
258   //
259   // Locate all SSP protocol instances.
260   //
261   HandleCount  = 0;
262   HandleBuffer = NULL;
263 
264   Status = gBS->LocateHandleBuffer (
265                   ByProtocol,
266                   &gEfiStorageSecurityCommandProtocolGuid,
267                   NULL,
268                   &HandleCount,
269                   &HandleBuffer
270                   );
271 
272   if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) {
273     return;
274   }
275 
276   for (Index = 0; Index < HandleCount; Index ++) {
277     //
278     // Get the SSP interface.
279     //
280     Status = gBS->HandleProtocol(
281                     HandleBuffer[Index],
282                     &gEfiStorageSecurityCommandProtocolGuid,
283                     (VOID **) &Ssp
284                     );
285 
286     if (EFI_ERROR (Status)) {
287       continue;
288     }
289 
290     Status = gBS->HandleProtocol(
291                     HandleBuffer[Index],
292                     &gEfiBlockIoProtocolGuid,
293                     (VOID **) &BlockIo
294                     );
295 
296     if (EFI_ERROR (Status)) {
297       continue;
298     }
299 
300     InitiateTPerReset (Ssp, BlockIo->Media->MediaId);
301   }
302 }
303 
304 /**
305   Entry Point for TCG MOR Control driver.
306 
307   @param[in] ImageHandle  Image handle of this driver.
308   @param[in] SystemTable  A Pointer to the EFI System Table.
309 
310   @retval EFI_SUCEESS
311   @return Others          Some error occurs.
312 **/
313 EFI_STATUS
314 EFIAPI
MorDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)315 MorDriverEntryPoint (
316   IN EFI_HANDLE        ImageHandle,
317   IN EFI_SYSTEM_TABLE  *SystemTable
318   )
319 {
320   EFI_STATUS  Status;
321   UINTN       DataSize;
322   EFI_EVENT   Event;
323 
324   ///
325   /// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable.
326   ///
327 
328   DataSize = sizeof (mMorControl);
329   Status = gRT->GetVariable (
330                   MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
331                   &gEfiMemoryOverwriteControlDataGuid,
332                   NULL,
333                   &DataSize,
334                   &mMorControl
335                   );
336   if (EFI_ERROR (Status)) {
337     //
338     // Set default value to 0
339     //
340     mMorControl = 0;
341     Status = gRT->SetVariable (
342                     MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
343                     &gEfiMemoryOverwriteControlDataGuid,
344                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
345                     DataSize,
346                     &mMorControl
347                     );
348     DEBUG ((EFI_D_INFO, "TcgMor: Create MOR variable! Status = %r\n", Status));
349   } else {
350     //
351     // Create a Ready To Boot Event and Clear the MorControl bit in the call back function.
352     //
353     DEBUG ((EFI_D_INFO, "TcgMor: Create ReadyToBoot Event for MorControl Bit cleanning!\n"));
354     Status = EfiCreateEventReadyToBootEx (
355                TPL_CALLBACK,
356                OnReadyToBoot,
357                NULL,
358                &Event
359                );
360     if (EFI_ERROR (Status)) {
361       return Status;
362     }
363 
364     //
365     // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
366     //
367     DEBUG ((EFI_D_INFO, "TcgMor: Create EndofDxe Event for Mor TPer Reset!\n"));
368     Status = gBS->CreateEventEx (
369                     EVT_NOTIFY_SIGNAL,
370                     TPL_CALLBACK,
371                     TPerResetAtEndOfDxe,
372                     NULL,
373                     &gEfiEndOfDxeEventGroupGuid,
374                     &Event
375                     );
376     if (EFI_ERROR (Status)) {
377       return Status;
378     }
379   }
380 
381   return Status;
382 }
383 
384 
385