• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
4 
5 
6   This program and the accompanying materials are licensed and made available under
7 
8   the terms and conditions of the BSD License that accompanies this distribution.
9 
10   The full text of the license may be found at
11 
12   http://opensource.org/licenses/bsd-license.php.
13 
14 
15 
16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 
18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 
21 
22 
23 
24 **/
25 
26 #include <PiDxe.h>
27 
28 #include <Library/FlashDeviceLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/BaseLib.h>
31 #include <Library/UefiBootServicesTableLib.h>
32 #include <Library/UefiRuntimeServicesTableLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/UefiRuntimeLib.h>
SpiFlashErase(UINT8 * BaseAddress,UINTN NumBytes)35 #include <Protocol/SmmBase2.h>
36 #include <Guid/EventGroup.h>
37 #include "SpiChipDefinitions.h"
38 
39 UINTN FlashDeviceBase = FLASH_DEVICE_BASE_ADDRESS;
40 
41 EFI_SPI_PROTOCOL *mSpiProtocol = NULL;
42 
43 EFI_STATUS
44 SpiFlashErase (
45   UINT8 *BaseAddress,
46   UINTN NumBytes
47   )
48 {
49   EFI_STATUS          Status = EFI_SUCCESS;
50   UINT32              SectorSize;
51   UINT32              SpiAddress;
52 
53   SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
54   SectorSize = SECTOR_SIZE_4KB;
55   while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
56     Status = mSpiProtocol->Execute (
57                              mSpiProtocol,
58                              SPI_SERASE,
59                              SPI_WREN,
60                              FALSE,
61                              TRUE,
62                              FALSE,
63                              (UINT32) SpiAddress,
64                              0,
65                              NULL,
66                              EnumSpiRegionBios
67                              );
68     if (EFI_ERROR (Status)) {
69       break;
70     }
SpiFlashBlockErase(UINT8 * BaseAddress,UINTN NumBytes)71     SpiAddress += SectorSize;
72     NumBytes   -= SectorSize;
73   }
74 
75   return Status;
76 }
77 
78 
79 EFI_STATUS
80 SpiFlashBlockErase (
81   UINT8 *BaseAddress,
82   UINTN NumBytes
83   )
84 {
85   EFI_STATUS          Status = EFI_SUCCESS;
86   UINT32              SectorSize;
87   UINT32              SpiAddress;
88 
89   SpiAddress = (UINT32)(UINTN)(BaseAddress) - (UINT32)FlashDeviceBase;
90   SectorSize = SECTOR_SIZE_64KB;
91   while ( (NumBytes > 0) && (NumBytes <= MAX_FWH_SIZE) ) {
92     Status = mSpiProtocol->Execute (
93                              mSpiProtocol,
94                              SPI_BERASE,
95                              SPI_WREN,
96                              FALSE,
97                              TRUE,
98                              FALSE,
99                              (UINT32) SpiAddress,
100                              0,
101                              NULL,
102                              EnumSpiRegionBios
103                              );
104     if (EFI_ERROR (Status)) {
105       break;
106     }
107     SpiAddress += SectorSize;
SpiFlashWrite(UINT8 * DstBufferPtr,UINT8 * Byte,IN UINTN Length)108     NumBytes   -= SectorSize;
109   }
110 
111   return Status;
112 }
113 
114 
115 static
116 EFI_STATUS
117 SpiFlashWrite (
118   UINT8 *DstBufferPtr,
119   UINT8 *Byte,
120   IN  UINTN Length
121   )
122 {
123   EFI_STATUS                Status;
124   UINT32                    NumBytes = (UINT32)Length;
125   UINT8*                    pBuf8 = Byte;
126   UINT32                    SpiAddress;
127 
128   SpiAddress = (UINT32)(UINTN)(DstBufferPtr) - (UINT32)FlashDeviceBase;
129   Status = mSpiProtocol->Execute (
130                            mSpiProtocol,
131                            SPI_PROG,
132                            SPI_WREN,
133                            TRUE,
134                            TRUE,
135                            TRUE,
136                            (UINT32)SpiAddress,
137                            NumBytes,
138                            pBuf8,
139                            EnumSpiRegionBios
140                            );
141   return Status;
142 }
143 
144 /**
145   Read the Serial Flash Status Registers.
146 
ReadStatusRegister(UINT8 * SpiStatus)147   @param  SpiStatus         Pointer to a caller-allocated UINT8. On successful return, it contains the
148                             status data read from the Serial Flash Status Register.
149 
150 
151   @retval EFI_SUCCESS       Operation success, status is returned in SpiStatus.
152   @retval EFI_DEVICE_ERROR  The block device is not functioning correctly and the operation failed.
153 
154 **/
155 EFI_STATUS
156 ReadStatusRegister (
157   UINT8   *SpiStatus
158   )
159 {
160   EFI_STATUS          Status;
161 
162   Status = mSpiProtocol->Execute (
163              mSpiProtocol,
164              SPI_RDSR,
165              SPI_WREN,
166              TRUE,
167              FALSE,
168              FALSE,
169              0,
170              1,
171              SpiStatus,
172              EnumSpiRegionBios
173              );
174   return Status;
175 }
176 
177 EFI_STATUS
178 SpiFlashLock (
179     IN  UINT8  *BaseAddress,
180     IN  UINTN  NumBytes,
181     IN  BOOLEAN  Lock
182   )
183 {
184   EFI_STATUS          Status;
185   UINT8               SpiData;
186   UINT8               SpiStatus;
187 
188   if (Lock) {
189     SpiData = SF_SR_WPE;
190   } else {
191     SpiData = 0;
192   }
193 
194   //
195   // Always disable block protection to workaround tool issue.
196   // Feature may be re-enabled in a future bios.
197   //
198   SpiData = 0;
199   Status = mSpiProtocol->Execute (
200                            mSpiProtocol,
201                            SPI_WRSR,
202                            SPI_EWSR,
203                            TRUE,
204                            TRUE,
205                            TRUE,
206                            0,
207                            1,
208                            &SpiData,
209                            EnumSpiRegionBios
210                            );
211   if (EFI_ERROR (Status)) {
212     return Status;
213   }
214 
215   Status = ReadStatusRegister (&SpiStatus);
216   if (EFI_ERROR (Status)) {
217     return Status;
218   }
219 
220   if ((SpiStatus & SpiData) != SpiData) {
221     Status = EFI_DEVICE_ERROR;
222   }
223 
224   return Status;
225 }
226 
227 
228 /**
229   Read NumBytes bytes of data from the address specified by
230   PAddress into Buffer.
231 
232   @param[in]      PAddress          The starting physical address of the read.
233   @param[in,out]  NumBytes          On input, the number of bytes to read. On output, the number
LibFvbFlashDeviceRead(IN UINTN PAddress,IN OUT UINTN * NumBytes,OUT UINT8 * Buffer)234                                     of bytes actually read.
235   @param[out]     Buffer            The destination data buffer for the read.
236 
237   @retval         EFI_SUCCESS.      Opertion is successful.
238   @retval         EFI_DEVICE_ERROR  If there is any device errors.
239 
240 **/
241 EFI_STATUS
242 EFIAPI
243 LibFvbFlashDeviceRead (
244   IN      UINTN                           PAddress,
245   IN  OUT UINTN                           *NumBytes,
246       OUT UINT8                           *Buffer
247   )
248 {
249   CopyMem(Buffer, (VOID*)PAddress, *NumBytes);
250   return EFI_SUCCESS;
251 }
252 
253 
254 /**
255   Write NumBytes bytes of data from Buffer to the address specified by
256   PAddresss.
257 
258   @param[in]      PAddress          The starting physical address of the write.
259   @param[in,out]  NumBytes          On input, the number of bytes to write. On output,
LibFvbFlashDeviceWrite(IN UINTN PAddress,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)260                                     the actual number of bytes written.
261   @param[in]      Buffer            The source data buffer for the write.
262 
263   @retval         EFI_SUCCESS.      Opertion is successful.
264   @retval         EFI_DEVICE_ERROR  If there is any device errors.
265 
266 **/
267 EFI_STATUS
268 EFIAPI
269 LibFvbFlashDeviceWrite (
270   IN        UINTN                           PAddress,
271   IN OUT    UINTN                           *NumBytes,
272   IN        UINT8                           *Buffer
273   )
274 {
275 EFI_STATUS Status;
276   Status =  SpiFlashWrite((UINT8 *)PAddress, Buffer, *NumBytes);
277  return Status;
278 }
279 
280 
281 /**
282   Erase the block staring at PAddress.
283 
284   @param[in]  PAddress          The starting physical address of the block to be erased.
285                                 This library assume that caller garantee that the PAddress
LibFvbFlashDeviceBlockErase(IN UINTN PAddress,IN UINTN LbaLength)286                                 is at the starting address of this block.
287   @param[in]  LbaLength         The length of the logical block to be erased.
288 
289   @retval     EFI_SUCCESS.      Opertion is successful.
290   @retval     EFI_DEVICE_ERROR  If there is any device errors.
291 
292 **/
293 EFI_STATUS
294 EFIAPI
295 LibFvbFlashDeviceBlockErase (
296   IN    UINTN                     PAddress,
297   IN    UINTN                     LbaLength
298   )
299 {
300   EFI_STATUS Status;
301   Status = SpiFlashBlockErase((UINT8 *)PAddress, LbaLength);
302 
303   return Status;
304 }
305 
306 
307 /**
308   Lock or unlock the block staring at PAddress.
309 
310   @param[in]  PAddress        The starting physical address of region to be (un)locked.
LibFvbFlashDeviceBlockLock(IN UINTN PAddress,IN UINTN LbaLength,IN BOOLEAN Lock)311   @param[in]  LbaLength       The length of the logical block to be erased.
312   @param[in]  Lock            TRUE to lock. FALSE to unlock.
313 
314   @retval     EFI_SUCCESS.      Opertion is successful.
315   @retval     EFI_DEVICE_ERROR  If there is any device errors.
316 
317 **/
318 EFI_STATUS
319 EFIAPI
320 LibFvbFlashDeviceBlockLock (
321   IN    UINTN                          PAddress,
322   IN    UINTN                          LbaLength,
323   IN    BOOLEAN                        Lock
324   )
325 {
326   EFI_STATUS Status;
327 
328     Status = SpiFlashLock((UINT8*)PAddress, LbaLength, Lock);
329   return Status;
330 }
331 
332 VOID
333 EFIAPI
334 LibFvbFlashDeviceVirtualAddressChangeNotifyEvent (
335   IN EFI_EVENT        Event,
336   IN VOID             *Context
337   )
338 {
339   gRT->ConvertPointer (0, (VOID **) &mSpiProtocol);
340   gRT->ConvertPointer (0, (VOID **) &FlashDeviceBase);
341 }
342 
343 
344 /**
345   The library constructuor.
346 
347   The function does the necessary initialization work for this library
348   instance. Please put all initialization works in it.
349 
350   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
LibFvbFlashDeviceSupportInit(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)351   @param[in]  SystemTable       A pointer to the EFI system table.
352 
353   @retval     EFI_SUCCESS       The function always return EFI_SUCCESS for now.
354                                 It will ASSERT on error for debug version.
355   @retval     EFI_ERROR         Please reference LocateProtocol for error code details.
356 
357 **/
358 EFI_STATUS
359 EFIAPI
360 LibFvbFlashDeviceSupportInit (
361   IN EFI_HANDLE         ImageHandle,
362   IN EFI_SYSTEM_TABLE   *SystemTable
363   )
364 {
365   EFI_STATUS Status;
366   EFI_EVENT  Event;
367   UINT8                         SfId[3];
368   UINT8                         FlashIndex;
369   UINT8                         SpiReadError;
370   UINT8                         SpiNotMatchError;
371   EFI_SMM_BASE2_PROTOCOL       *SmmBase;
372   BOOLEAN                       InSmm;
373 
374   SpiReadError     = 0x00;
375   SpiNotMatchError = 0x00;
376 
377   InSmm = FALSE;
378   Status = gBS->LocateProtocol (
379                   &gEfiSmmBase2ProtocolGuid,
380                   NULL,
381                   (void **)&SmmBase
382                   );
383   if (!EFI_ERROR(Status)) {
384     Status = SmmBase->InSmm(SmmBase, &InSmm);
385     if (EFI_ERROR(Status)) {
386       InSmm = FALSE;
387     }
388   }
389 
390   if (!InSmm) {
391     Status = gBS->LocateProtocol (
392                   &gEfiSpiProtocolGuid,
393                   NULL,
394                   (VOID **)&mSpiProtocol
395                   );
396     ASSERT_EFI_ERROR (Status);
397 
398     Status = gBS->CreateEventEx (
399                   EVT_NOTIFY_SIGNAL,
400                   TPL_NOTIFY,
401                   LibFvbFlashDeviceVirtualAddressChangeNotifyEvent,
402                   NULL,
403                   &gEfiEventVirtualAddressChangeGuid,
404                   &Event
405                   );
406     ASSERT_EFI_ERROR (Status);
407   } else {
408     Status = gBS->LocateProtocol (
409                     &gEfiSmmSpiProtocolGuid,
410                     NULL,
411                     (VOID **)&mSpiProtocol
412                     );
413     ASSERT_EFI_ERROR (Status);
414   }
415 
416 
417   for (FlashIndex = EnumSpiFlashW25Q64; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
418     Status = mSpiProtocol->Init (mSpiProtocol, &(mInitTable[FlashIndex]));
419     if (!EFI_ERROR (Status)) {
420       //
421       // Read Vendor/Device IDs to check if the driver supports the Serial Flash device.
422       //
423       Status = mSpiProtocol->Execute (
424                                mSpiProtocol,
425                                SPI_READ_ID,
426                                SPI_WREN,
427                                TRUE,
428                                FALSE,
429                                FALSE,
430                                0,
431                                3,
432                                SfId,
433                                EnumSpiRegionAll
434                                );
435       if (!EFI_ERROR (Status)) {
436         if ((SfId[0] == mInitTable[FlashIndex].VendorId)  &&
437             (SfId[1] == mInitTable[FlashIndex].DeviceId0) &&
438             (SfId[2] == mInitTable[FlashIndex].DeviceId1)) {
439             //
440             // Found a matching SPI device, FlashIndex now contains flash device.
441             //
442             DEBUG ((EFI_D_ERROR, "OK - Found SPI Flash Type in SPI Flash Driver, Device Type ID 0 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId0));
443             DEBUG ((EFI_D_ERROR, "Device Type ID 1 = 0x%02x!\n", mInitTable[FlashIndex].DeviceId1));
444 
445             if (mInitTable[FlashIndex].BiosStartOffset == (UINTN) (-1)) {
446               DEBUG ((EFI_D_ERROR, "ERROR - The size of BIOS image is bigger than SPI Flash device!\n"));
447               CpuDeadLoop ();
448             }
449             break;
450         } else {
451           SpiNotMatchError++;
452         }
453       } else {
454         SpiReadError++;
455       }
456     }
457   }
458 
459   DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2]));
460 
461   if (FlashIndex < EnumSpiFlashMax)  {
462     return EFI_SUCCESS;
463   } else {
464   if (SpiReadError != 0) {
465       DEBUG ((EFI_D_ERROR, "ERROR - SPI Read ID execution failed! Error Count = %d\n", SpiReadError));
466    }
467     else {
468       if (SpiNotMatchError != 0) {
469         DEBUG ((EFI_D_ERROR, "ERROR - No supported SPI flash chip found! Error Count = %d\n", SpiNotMatchError));
470         DEBUG ((EFI_D_ERROR, "SPI flash chip VID = 0x%X, DID0 = 0x%X, DID1 = 0x%X\n", SfId[0], SfId[1], SfId[2]));
471       }
472     }
473     return EFI_UNSUPPORTED;
474   }
475 }
476 
477