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