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