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* 30 DiagnosticInitLog ( 31 UINTN MaxBufferChar 32 ) 33 { 34 mLogRemainChar = MaxBufferChar; 35 mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16)); 36 return mLogBuffer; 37 } 38 39 UINTN 40 DiagnosticLog ( 41 CONST CHAR16* Str 42 ) 43 { 44 UINTN len = StrLen (Str); 45 if (len <= mLogRemainChar) { 46 mLogRemainChar -= len; 47 StrCpy (mLogBuffer, Str); 48 mLogBuffer += len; 49 return len; 50 } else { 51 return 0; 52 } 53 } 54 55 VOID 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 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 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 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