andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 1 | /** @file
|
| 2 | Diagnostics Protocol implementation for the MMC DXE driver
|
| 3 |
|
Olivier Martin | 5c5a34d | 2014-01-09 19:15:06 +0000 | [diff] [blame] | 4 | Copyright (c) 2011-2014, ARM Limited. All rights reserved.
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 5 |
|
Ronald Cron | 3402aac | 2014-08-19 13:29:52 +0000 | [diff] [blame] | 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.
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 13 |
|
| 14 | **/
|
| 15 |
|
| 16 | #include <Uefi.h>
|
| 17 | #include <Library/DebugLib.h>
|
| 18 | #include <Library/BaseMemoryLib.h>
|
| 19 | #include <Library/MemoryAllocationLib.h>
|
Olivier Martin | c8af31e | 2013-09-23 09:43:51 +0000 | [diff] [blame] | 20 | #include <Library/BaseLib.h>
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 21 |
|
| 22 | #include "Mmc.h"
|
| 23 |
|
| 24 | #define DIAGNOSTIC_LOGBUFFER_MAXCHAR 1024
|
| 25 |
|
| 26 | CHAR16* mLogBuffer = NULL;
|
| 27 | UINTN mLogRemainChar = 0;
|
| 28 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 29 | CHAR16*
|
| 30 | DiagnosticInitLog (
|
| 31 | UINTN MaxBufferChar
|
| 32 | )
|
| 33 | {
|
| 34 | mLogRemainChar = MaxBufferChar;
|
Olivier Martin | c8af31e | 2013-09-23 09:43:51 +0000 | [diff] [blame] | 35 | mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16));
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 36 | return mLogBuffer;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 37 | }
|
| 38 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 53 | }
|
| 54 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 55 | VOID
|
| 56 | GenerateRandomBuffer (
|
| 57 | VOID* Buffer,
|
| 58 | UINTN BufferSize
|
| 59 | )
|
| 60 | {
|
| 61 | UINT64 i;
|
| 62 | UINT64* Buffer64 = (UINT64*)Buffer;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 63 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 64 | for (i = 0; i < (BufferSize >> 3); i++) {
|
| 65 | *Buffer64 = i | (~i << 32);
|
| 66 | Buffer64++;
|
| 67 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 68 | }
|
| 69 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 80 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 81 | for (i = 0; i < (BufferSize >> 3); i++) {
|
| 82 | if (*BufferA64 != *BufferB64) {
|
Olivier Martin | c8af31e | 2013-09-23 09:43:51 +0000 | [diff] [blame] | 83 | DEBUG ((EFI_D_ERROR, "CompareBuffer: Error at %i", i));
|
| 84 | DEBUG ((EFI_D_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64));
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 85 | return FALSE;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 86 | }
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 87 | BufferA64++;
|
| 88 | BufferB64++;
|
| 89 | }
|
| 90 | return TRUE;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 91 | }
|
| 92 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 104 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 110 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 111 | if (MmcHostInstance->State != MmcTransferState) {
|
| 112 | DiagnosticLog (L"ERROR: Not ready for Transfer state\n");
|
| 113 | return EFI_NOT_READY;
|
| 114 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 115 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 116 | BackBuffer = AllocatePool (BufferSize);
|
| 117 | WriteBuffer = AllocatePool (BufferSize);
|
| 118 | ReadBuffer = AllocatePool (BufferSize);
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 119 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 126 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 134 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 141 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 147 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 154 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 161 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 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;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 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 | {
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 184 | LIST_ENTRY *CurrentLink;
|
| 185 | MMC_HOST_INSTANCE *MmcHostInstance;
|
| 186 | EFI_STATUS Status;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 187 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 188 | if ((Language == NULL) ||
|
| 189 | (ErrorType == NULL) ||
|
| 190 | (Buffer == NULL) ||
|
| 191 | (ControllerHandle == NULL) ||
|
| 192 | (BufferSize == NULL)) {
|
| 193 | return EFI_INVALID_PARAMETER;
|
| 194 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 195 |
|
Olivier Martin | c8af31e | 2013-09-23 09:43:51 +0000 | [diff] [blame] | 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 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 201 | Status = EFI_SUCCESS;
|
| 202 | *ErrorType = NULL;
|
| 203 | *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR;
|
| 204 | *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR);
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 205 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 206 | DiagnosticLog (L"MMC Driver Diagnostics\n");
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 207 |
|
Olivier Martin | 5c5a34d | 2014-01-09 19:15:06 +0000 | [diff] [blame] | 208 | // Find the MMC Host instance on which we have been asked to run diagnostics
|
| 209 | MmcHostInstance = NULL;
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 210 | CurrentLink = mMmcHostPool.ForwardLink;
|
| 211 | while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
|
Olivier Martin | 5c5a34d | 2014-01-09 19:15:06 +0000 | [diff] [blame] | 212 | MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
|
| 213 | ASSERT(MmcHostInstance != NULL);
|
| 214 | if (MmcHostInstance->MmcHandle == ControllerHandle) {
|
| 215 | break;
|
| 216 | }
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 217 | CurrentLink = CurrentLink->ForwardLink;
|
| 218 | }
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 219 |
|
Olivier Martin | 5c5a34d | 2014-01-09 19:15:06 +0000 | [diff] [blame] | 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 |
|
oliviermartin | 11c20f4 | 2011-09-22 22:53:54 +0000 | [diff] [blame] | 246 | return Status;
|
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 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 | };
|