• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Diagnostics Protocol implementation for the MMC DXE driver
3 
4   Copyright (c) 2011-2014, ARM Limited. All rights reserved.
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 #include <Uefi.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/BaseLib.h>
21 
22 #include "Mmc.h"
23 
24 #define DIAGNOSTIC_LOGBUFFER_MAXCHAR  1024
25 
26 CHAR16* mLogBuffer = NULL;
27 UINTN   mLogRemainChar = 0;
28 
29 CHAR16*
DiagnosticInitLog(UINTN MaxBufferChar)30 DiagnosticInitLog (
31   UINTN MaxBufferChar
32   )
33 {
34   mLogRemainChar = MaxBufferChar;
35   mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16));
36   return mLogBuffer;
37 }
38 
39 UINTN
DiagnosticLog(CONST CHAR16 * Str)40 DiagnosticLog (
41   CONST CHAR16* Str
42   )
43 {
44   UINTN len = StrLen (Str);
45   if (len < mLogRemainChar) {
46     StrCpyS (mLogBuffer, mLogRemainChar, Str);
47     mLogRemainChar -= len;
48     mLogBuffer += len;
49     return len;
50   } else {
51     return 0;
52   }
53 }
54 
55 VOID
GenerateRandomBuffer(VOID * Buffer,UINTN BufferSize)56 GenerateRandomBuffer (
57   VOID* Buffer,
58   UINTN BufferSize
59   )
60 {
61   UINT64  i;
62   UINT64* Buffer64 = (UINT64*)Buffer;
63 
64   for (i = 0; i < (BufferSize >> 3); i++) {
65     *Buffer64 = i | (~i << 32);
66     Buffer64++;
67   }
68 }
69 
70 BOOLEAN
CompareBuffer(VOID * BufferA,VOID * BufferB,UINTN BufferSize)71 CompareBuffer (
72   VOID  *BufferA,
73   VOID  *BufferB,
74   UINTN BufferSize
75   )
76 {
77   UINTN i;
78   UINT64* BufferA64 = (UINT64*)BufferA;
79   UINT64* BufferB64 = (UINT64*)BufferB;
80 
81   for (i = 0; i < (BufferSize >> 3); i++) {
82     if (*BufferA64 != *BufferB64) {
83       DEBUG ((EFI_D_ERROR, "CompareBuffer: Error at %i", i));
84       DEBUG ((EFI_D_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64));
85       return FALSE;
86     }
87     BufferA64++;
88     BufferB64++;
89   }
90   return TRUE;
91 }
92 
93 EFI_STATUS
MmcReadWriteDataTest(MMC_HOST_INSTANCE * MmcHostInstance,EFI_LBA Lba,UINTN BufferSize)94 MmcReadWriteDataTest (
95   MMC_HOST_INSTANCE *MmcHostInstance,
96   EFI_LBA           Lba,
97   UINTN             BufferSize
98   )
99 {
100   VOID                        *BackBuffer;
101   VOID                        *WriteBuffer;
102   VOID                        *ReadBuffer;
103   EFI_STATUS                  Status;
104 
105   // Check if a Media is Present
106   if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
107     DiagnosticLog (L"ERROR: No Media Present\n");
108     return EFI_NO_MEDIA;
109   }
110 
111   if (MmcHostInstance->State != MmcTransferState) {
112     DiagnosticLog (L"ERROR: Not ready for Transfer state\n");
113     return EFI_NOT_READY;
114   }
115 
116   BackBuffer = AllocatePool (BufferSize);
117   WriteBuffer = AllocatePool (BufferSize);
118   ReadBuffer = AllocatePool (BufferSize);
119 
120   // Read (and save) buffer at a specific location
121   Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
122   if (Status != EFI_SUCCESS) {
123     DiagnosticLog (L"ERROR: Fail to Read Block (1)\n");
124     return Status;
125   }
126 
127   // Write buffer at the same location
128   GenerateRandomBuffer (WriteBuffer,BufferSize);
129   Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,WriteBuffer);
130   if (Status != EFI_SUCCESS) {
131     DiagnosticLog (L"ERROR: Fail to Write Block (1)\n");
132     return Status;
133   }
134 
135   // Read the buffer at the same location
136   Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
137   if (Status != EFI_SUCCESS) {
138     DiagnosticLog (L"ERROR: Fail to Read Block (2)\n");
139     return Status;
140   }
141 
142   // Check that is conform
143   if (!CompareBuffer (ReadBuffer,WriteBuffer,BufferSize)) {
144     DiagnosticLog (L"ERROR: Fail to Read/Write Block (1)\n");
145     return EFI_INVALID_PARAMETER;
146   }
147 
148   // Restore content at the original location
149   Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
150   if (Status != EFI_SUCCESS) {
151     DiagnosticLog (L"ERROR: Fail to Write Block (2)\n");
152     return Status;
153   }
154 
155   // Read the restored content
156   Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
157   if (Status != EFI_SUCCESS) {
158     DiagnosticLog (L"ERROR: Fail to Read Block (3)\n");
159     return Status;
160   }
161 
162   // Check the content is correct
163   if (!CompareBuffer (ReadBuffer,BackBuffer,BufferSize)) {
164     DiagnosticLog (L"ERROR: Fail to Read/Write Block (2)\n");
165     return EFI_INVALID_PARAMETER;
166   }
167 
168   return EFI_SUCCESS;
169 }
170 
171 EFI_STATUS
172 EFIAPI
MmcDriverDiagnosticsRunDiagnostics(IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE ChildHandle OPTIONAL,IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,IN CHAR8 * Language,OUT EFI_GUID ** ErrorType,OUT UINTN * BufferSize,OUT CHAR16 ** Buffer)173 MmcDriverDiagnosticsRunDiagnostics (
174   IN  EFI_DRIVER_DIAGNOSTICS_PROTOCOL               *This,
175   IN  EFI_HANDLE                                    ControllerHandle,
176   IN  EFI_HANDLE                                    ChildHandle  OPTIONAL,
177   IN  EFI_DRIVER_DIAGNOSTIC_TYPE                    DiagnosticType,
178   IN  CHAR8                                         *Language,
179   OUT EFI_GUID                                      **ErrorType,
180   OUT UINTN                                         *BufferSize,
181   OUT CHAR16                                        **Buffer
182   )
183 {
184   LIST_ENTRY              *CurrentLink;
185   MMC_HOST_INSTANCE       *MmcHostInstance;
186   EFI_STATUS              Status;
187 
188   if ((Language         == NULL) ||
189       (ErrorType        == NULL) ||
190       (Buffer           == NULL) ||
191       (ControllerHandle == NULL) ||
192       (BufferSize       == NULL)) {
193     return EFI_INVALID_PARAMETER;
194   }
195 
196   // Check Language is supported (i.e. is "en-*" - only English is supported)
197   if (AsciiStrnCmp (Language, "en", 2) != 0) {
198     return EFI_UNSUPPORTED;
199   }
200 
201   Status = EFI_SUCCESS;
202   *ErrorType  = NULL;
203   *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR;
204   *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR);
205 
206   DiagnosticLog (L"MMC Driver Diagnostics\n");
207 
208   // Find the MMC Host instance on which we have been asked to run diagnostics
209   MmcHostInstance = NULL;
210   CurrentLink = mMmcHostPool.ForwardLink;
211   while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
212     MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
213     ASSERT(MmcHostInstance != NULL);
214     if (MmcHostInstance->MmcHandle == ControllerHandle) {
215       break;
216     }
217     CurrentLink = CurrentLink->ForwardLink;
218   }
219 
220   // If we didn't find the controller, return EFI_UNSUPPORTED
221   if ((MmcHostInstance == NULL)
222       || (MmcHostInstance->MmcHandle != ControllerHandle)) {
223     return EFI_UNSUPPORTED;
224   }
225 
226   // LBA=1 Size=BlockSize
227   DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n");
228   Status = MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize);
229 
230   // LBA=2 Size=BlockSize
231   DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n");
232   Status = MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize);
233 
234   // LBA=10 Size=BlockSize
235   DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n");
236   Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock >> 1, MmcHostInstance->BlockIo.Media->BlockSize);
237 
238   // LBA=LastBlock Size=BlockSize
239   DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n");
240   Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, MmcHostInstance->BlockIo.Media->BlockSize);
241 
242   // LBA=1 Size=2*BlockSize
243   DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n");
244   Status = MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance->BlockIo.Media->BlockSize);
245 
246   return Status;
247 }
248 
249 //
250 // EFI Driver Diagnostics 2 Protocol
251 //
252 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = {
253   (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) MmcDriverDiagnosticsRunDiagnostics,
254   "en"
255 };
256