]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/EdkFvbServiceLib/Fvb.c
Fix bug in function EfiFvbEraseBlock()
[mirror_edk2.git] / MdeModulePkg / Library / EdkFvbServiceLib / Fvb.c
CommitLineData
a190687a 1/**@file\r
2\r
3 Firmware Volume Block Protocol Runtime Abstraction\r
4\r
5 mFvbEntry is an array of Handle Fvb pairs. The Fvb Lib Instance matches the\r
6 index in the mFvbEntry array. This should be the same sequence as the FVB's\r
7 were described in the HOB. We have to remember the handle so we can tell if\r
8 the protocol has been reinstalled and it needs updateing.\r
9\r
10 If you are using any of these lib functions.you must first call FvbInitialize ().\r
11\r
12Copyright (c) 2006, Intel Corporation\r
13All rights reserved. This program and the accompanying materials\r
14are licensed and made available under the terms and conditions of the BSD License\r
15which accompanies this distribution. The full text of the license may be found at\r
16http://opensource.org/licenses/bsd-license.php\r
17\r
18THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
19WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
20\r
21**/\r
22\r
23\r
24#include "Fvb.h"\r
25\r
26//\r
85363c1e 27// Event for Set Virtual Map Changed Event\r
a190687a 28//\r
85363c1e 29STATIC EFI_EVENT mSetVirtualMapChangedEvent = NULL;\r
a190687a 30\r
31//\r
32// Lib will ASSERT if more FVB devices than this are added to the system.\r
33//\r
34STATIC FVB_ENTRY *mFvbEntry;\r
35STATIC EFI_EVENT mFvbRegistration;\r
a190687a 36STATIC UINTN mFvbCount;\r
37\r
38/**\r
39 Check whether an address is runtime memory or not.\r
40\r
41 @param Address The Address being checked.\r
42\r
43 @retval TRUE The address is runtime memory.\r
44 @retval FALSE The address is not runtime memory.\r
45**/\r
46BOOLEAN\r
47IsRuntimeMemory (\r
48 IN VOID *Address\r
49 )\r
50{\r
51 EFI_STATUS Status;\r
52 UINT8 TmpMemoryMap[1];\r
53 UINTN MapKey;\r
54 UINTN DescriptorSize;\r
55 UINT32 DescriptorVersion;\r
56 UINTN MemoryMapSize;\r
57 EFI_MEMORY_DESCRIPTOR *MemoryMap;\r
58 EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;\r
59 BOOLEAN IsRuntime;\r
60 UINTN Index;\r
61\r
62 IsRuntime = FALSE;\r
63\r
64 //\r
65 // Get System MemoryMapSize\r
66 //\r
67 MemoryMapSize = 1;\r
68 Status = gBS->GetMemoryMap (\r
69 &MemoryMapSize,\r
70 (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,\r
71 &MapKey,\r
72 &DescriptorSize,\r
73 &DescriptorVersion\r
74 );\r
75 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
76 //\r
77 // Enlarge space here, because we will allocate pool now.\r
78 //\r
79 MemoryMapSize += EFI_PAGE_SIZE;\r
80 Status = gBS->AllocatePool (\r
81 EfiBootServicesData,\r
82 MemoryMapSize,\r
83 (VOID**)&MemoryMap\r
84 );\r
85 ASSERT_EFI_ERROR (Status);\r
86\r
87 //\r
88 // Get System MemoryMap\r
89 //\r
90 Status = gBS->GetMemoryMap (\r
91 &MemoryMapSize,\r
92 MemoryMap,\r
93 &MapKey,\r
94 &DescriptorSize,\r
95 &DescriptorVersion\r
96 );\r
97 ASSERT_EFI_ERROR (Status);\r
98\r
99 MemoryMapPtr = MemoryMap;\r
100 //\r
101 // Search the request Address\r
102 //\r
103 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {\r
104 if (((EFI_PHYSICAL_ADDRESS)(UINTN)Address >= MemoryMap->PhysicalStart) &&\r
105 ((EFI_PHYSICAL_ADDRESS)(UINTN)Address < MemoryMap->PhysicalStart\r
106 + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT))) {\r
107 //\r
108 // Found it\r
109 //\r
110 if (MemoryMap->Attribute & EFI_MEMORY_RUNTIME) {\r
111 IsRuntime = TRUE;\r
112 }\r
113 break;\r
114 }\r
115 //\r
116 // Get next item\r
117 //\r
118 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);\r
119 }\r
120\r
121 //\r
122 // Done\r
123 //\r
124 gBS->FreePool (MemoryMapPtr);\r
125\r
126 return IsRuntime;\r
127}\r
128\r
129/**\r
130 Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is\r
131 reinstalled.\r
132\r
133 @param Event The Event that is being processed\r
134 @param Context Event Context\r
135\r
136**/\r
137STATIC\r
138VOID\r
139EFIAPI\r
140FvbNotificationEvent (\r
141 IN EFI_EVENT Event,\r
142 IN VOID *Context\r
143 )\r
144{\r
145 EFI_STATUS Status;\r
146 UINTN BufferSize;\r
147 EFI_HANDLE Handle;\r
148 UINTN Index;\r
149 UINTN UpdateIndex;\r
150\r
151 while (TRUE) {\r
152 BufferSize = sizeof (Handle);\r
153 Status = gBS->LocateHandle (\r
154 ByRegisterNotify,\r
155 &gEfiFirmwareVolumeBlockProtocolGuid,\r
156 mFvbRegistration,\r
157 &BufferSize,\r
158 &Handle\r
159 );\r
160 if (EFI_ERROR (Status)) {\r
161 //\r
162 // Exit Path of While Loop....\r
163 //\r
164 break;\r
165 }\r
166\r
167 UpdateIndex = MAX_FVB_COUNT;\r
168 for (Index = 0; Index < mFvbCount; Index++) {\r
169 if (mFvbEntry[Index].Handle == Handle) {\r
170 //\r
171 // If the handle is already in the table just update the protocol\r
172 //\r
173 UpdateIndex = Index;\r
174 break;\r
175 }\r
176 }\r
177\r
178 if (UpdateIndex == MAX_FVB_COUNT) {\r
179 //\r
180 // Use the next free slot for a new entry\r
181 //\r
182 UpdateIndex = mFvbCount++;\r
183 //\r
184 // Check the UpdateIndex whether exceed the maximum value.\r
185 //\r
186 ASSERT (UpdateIndex < MAX_FVB_COUNT);\r
187 mFvbEntry[UpdateIndex].Handle = Handle;\r
188 }\r
189 //\r
190 // The array does not have enough entries\r
191 //\r
192 ASSERT (UpdateIndex < MAX_FVB_COUNT);\r
193\r
194 //\r
195 // Get the interface pointer and if it's ours, skip it\r
196 //\r
197 Status = gBS->HandleProtocol (\r
198 Handle,\r
199 &gEfiFirmwareVolumeBlockProtocolGuid,\r
200 (VOID **) &mFvbEntry[UpdateIndex].Fvb\r
201 );\r
202 ASSERT_EFI_ERROR (Status);\r
203\r
204 Status = gBS->HandleProtocol (\r
205 Handle,\r
206 &gEfiFvbExtensionProtocolGuid,\r
207 (VOID **) &mFvbEntry[UpdateIndex].FvbExtension\r
208 );\r
209 if (Status != EFI_SUCCESS) {\r
210 mFvbEntry[UpdateIndex].FvbExtension = NULL;\r
211 }\r
212\r
213 //\r
214 // Check the FVB can be accessed in RUNTIME, The FVBs in FVB handle list comes\r
215 // from two way:\r
216 // 1) Dxe Core. (FVB information is transferred from FV HOB).\r
217 // 2) FVB driver.\r
218 // The FVB produced Dxe core is used for discoverying DXE driver and dispatch. These\r
219 // FVBs can only be accessed in boot time.\r
220 // FVB driver will discovery all FV in FLASH and these FVBs can be accessed in runtime.\r
221 // The FVB itself produced by FVB driver is allocated in runtime memory. So we can\r
222 // determine the what FVB can be accessed in RUNTIME by judging whether FVB itself is allocated\r
223 // in RUNTIME memory.\r
224 //\r
225 mFvbEntry[UpdateIndex].IsRuntimeAccess = IsRuntimeMemory (mFvbEntry[UpdateIndex].Fvb);\r
226 }\r
227}\r
228\r
229/**\r
230 Convert all pointers in mFvbEntry after ExitBootServices.\r
231\r
232 @param Event The Event that is being processed\r
233 @param Context Event Context\r
234\r
235**/\r
236VOID\r
237EFIAPI\r
238FvbVirtualAddressChangeNotifyEvent (\r
239 IN EFI_EVENT Event,\r
240 IN VOID *Context\r
241 )\r
242{\r
243 UINTN Index;\r
244 if (mFvbEntry != NULL) {\r
245 for (Index = 0; Index < MAX_FVB_COUNT; Index++) {\r
246 if (!mFvbEntry[Index].IsRuntimeAccess) {\r
247 continue;\r
248 }\r
249\r
250 if (NULL != mFvbEntry[Index].Fvb) {\r
251 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetBlockSize);\r
252 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetPhysicalAddress);\r
253 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetAttributes);\r
254 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->SetAttributes);\r
255 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Read);\r
256 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Write);\r
257 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->EraseBlocks);\r
258 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb);\r
259 }\r
260\r
261 if (NULL != mFvbEntry[Index].FvbExtension) {\r
262 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension->EraseFvbCustomBlock);\r
263 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension);\r
264 }\r
265 }\r
266\r
267 EfiConvertPointer (0x0, (VOID **) &mFvbEntry);\r
268 }\r
269}\r
270\r
271/**\r
272 Library constructor function entry.\r
273\r
274 @param ImageHandle The handle of image who call this libary.\r
275 @param SystemTable The point of System Table.\r
276\r
277 @retval EFI_SUCESS Sucess construct this library.\r
278 @retval Others Fail to contruct this libary.\r
279**/\r
280EFI_STATUS\r
281EFIAPI\r
282FvbLibInitialize (\r
283 IN EFI_HANDLE ImageHandle,\r
284 IN EFI_SYSTEM_TABLE *SystemTable\r
285 )\r
286{\r
287 UINTN Status;\r
288 mFvbCount = 0;\r
289\r
290 Status = gBS->AllocatePool (\r
291 EfiRuntimeServicesData,\r
292 (UINTN) sizeof (FVB_ENTRY) * MAX_FVB_COUNT,\r
293 (VOID *) &mFvbEntry\r
294 );\r
295\r
296 if (EFI_ERROR (Status)) {\r
297 return Status;\r
298 }\r
299\r
300 ZeroMem (mFvbEntry, sizeof (FVB_ENTRY) * MAX_FVB_COUNT);\r
301\r
302 EfiCreateProtocolNotifyEvent (\r
303 &gEfiFirmwareVolumeBlockProtocolGuid,\r
304 TPL_CALLBACK,\r
305 FvbNotificationEvent,\r
306 NULL,\r
307 &mFvbRegistration\r
308 );\r
309\r
310 //\r
311 // Register SetVirtualAddressMap () notify function\r
312 //\r
313 Status = gBS->CreateEvent (\r
85363c1e 314 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
a190687a 315 TPL_NOTIFY,\r
316 FvbVirtualAddressChangeNotifyEvent,\r
317 NULL,\r
85363c1e 318 &mSetVirtualMapChangedEvent\r
a190687a 319 );\r
320 ASSERT_EFI_ERROR (Status);\r
321\r
a190687a 322 return EFI_SUCCESS;\r
323}\r
324\r
325//\r
326// =============================================================================\r
327// The following functions wrap Fvb protocol in the Runtime Lib functions.\r
328// The Instance translates into Fvb instance. The Fvb order defined by HOBs and\r
329// thus the sequence of FVB protocol addition define Instance.\r
330//\r
331// EfiFvbInitialize () must be called before any of the following functions\r
332// must be called.\r
333// =============================================================================\r
334//\r
335\r
336/**\r
337 Reads specified number of bytes into a buffer from the specified block\r
338\r
339 @param Instance The FV instance to be read from.\r
340 @param Lba The logical block address to be read from\r
341 @param Offset Offset into the block at which to begin reading\r
342 @param NumBytes Pointer that on input contains the total size of\r
343 the buffer. On output, it contains the total number\r
344 of bytes read\r
345 @param Buffer Pointer to a caller allocated buffer that will be\r
346 used to hold the data read\r
347\r
348 @retval EFI_INVALID_PARAMETER Invalid parameter\r
349 @retval EFI_SUCESS Sucess to Read block\r
350 @retval Others Fail to read block\r
351**/\r
352EFI_STATUS\r
353EfiFvbReadBlock (\r
354 IN UINTN Instance,\r
355 IN EFI_LBA Lba,\r
356 IN UINTN Offset,\r
357 IN OUT UINTN *NumBytes,\r
358 IN UINT8 *Buffer\r
359 )\r
360{\r
361 if (Instance >= mFvbCount) {\r
362 return EFI_INVALID_PARAMETER;\r
363 }\r
364\r
365 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
366 return EFI_INVALID_PARAMETER;\r
367 }\r
368\r
369 return mFvbEntry[Instance].Fvb->Read (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer);\r
370}\r
371\r
372/**\r
373 Writes specified number of bytes from the input buffer to the block\r
374\r
375 @param Instance The FV instance to be written to\r
376 @param Lba The starting logical block index to write to\r
377 @param Offset Offset into the block at which to begin writing\r
378 @param NumBytes Pointer that on input contains the total size of\r
379 the buffer. On output, it contains the total number\r
380 of bytes actually written\r
381 @param Buffer Pointer to a caller allocated buffer that contains\r
382 the source for the write\r
383\r
384 @retval EFI_INVALID_PARAMETER Invalid parameter\r
385 @retval EFI_SUCESS Sucess to write block\r
386 @retval Others Fail to write block\r
387**/\r
388EFI_STATUS\r
389EfiFvbWriteBlock (\r
390 IN UINTN Instance,\r
391 IN EFI_LBA Lba,\r
392 IN UINTN Offset,\r
393 IN OUT UINTN *NumBytes,\r
394 IN UINT8 *Buffer\r
395 )\r
396{\r
397 if (Instance >= mFvbCount) {\r
398 return EFI_INVALID_PARAMETER;\r
399 }\r
400\r
401 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
402 return EFI_INVALID_PARAMETER;\r
403 }\r
404\r
405 return mFvbEntry[Instance].Fvb->Write (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer);\r
406}\r
407\r
408/**\r
409 Erases and initializes a firmware volume block\r
410\r
411 @param Instance The FV instance to be erased\r
412 @param Lba The logical block index to be erased\r
413\r
414 @retval EFI_INVALID_PARAMETER Invalid parameter\r
415 @retval EFI_SUCESS Sucess to erase block\r
416 @retval Others Fail to erase block\r
417**/\r
418EFI_STATUS\r
419EfiFvbEraseBlock (\r
420 IN UINTN Instance,\r
421 IN EFI_LBA Lba\r
422 )\r
423{\r
424 if (Instance >= mFvbCount) {\r
425 return EFI_INVALID_PARAMETER;\r
426 }\r
427\r
428 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
429 return EFI_INVALID_PARAMETER;\r
430 }\r
431\r
e2591cb2 432 return mFvbEntry[Instance].Fvb->EraseBlocks (mFvbEntry[Instance].Fvb, Lba, 1, EFI_LBA_LIST_TERMINATOR);\r
a190687a 433}\r
434\r
435/**\r
436 Retrieves attributes, insures positive polarity of attribute bits, returns\r
437 resulting attributes in output parameter\r
438\r
439 @param Instance The FV instance whose attributes is going to be returned\r
440 @param Attributes Output buffer which contains attributes\r
441\r
442 @retval EFI_INVALID_PARAMETER Invalid parameter\r
443 @retval EFI_SUCESS Sucess to get Fv attribute\r
444 @retval Others Fail to get Fv attribute\r
445**/\r
446EFI_STATUS\r
447EfiFvbGetVolumeAttributes (\r
448 IN UINTN Instance,\r
449 OUT EFI_FVB_ATTRIBUTES *Attributes\r
450 )\r
451{\r
452 if (Instance >= mFvbCount) {\r
453 return EFI_INVALID_PARAMETER;\r
454 }\r
455\r
456 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
457 return EFI_INVALID_PARAMETER;\r
458 }\r
459\r
460 return mFvbEntry[Instance].Fvb->GetAttributes (mFvbEntry[Instance].Fvb, Attributes);\r
461}\r
462\r
463/**\r
464 Modifies the current settings of the firmware volume according to the\r
465 input parameter, and returns the new setting of the volume\r
466\r
467 @param Instance The FV instance whose attributes is going to be\r
468 modified\r
469 @param Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES\r
470 containing the desired firmware volume settings.\r
471 On successful return, it contains the new settings\r
472 of the firmware volume\r
473\r
474 @retval EFI_INVALID_PARAMETER Invalid parameter\r
475 @retval EFI_SUCESS Sucess to set Fv attribute\r
476 @retval Others Fail to set Fv attribute\r
477**/\r
478EFI_STATUS\r
479EfiFvbSetVolumeAttributes (\r
d3a58e2d 480 IN UINTN Instance,\r
481 IN OUT EFI_FVB_ATTRIBUTES *Attributes\r
a190687a 482 )\r
483{\r
484 if (Instance >= mFvbCount) {\r
485 return EFI_INVALID_PARAMETER;\r
486 }\r
487\r
488 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
489 return EFI_INVALID_PARAMETER;\r
490 }\r
491\r
d3a58e2d 492 return mFvbEntry[Instance].Fvb->SetAttributes (mFvbEntry[Instance].Fvb, Attributes);\r
a190687a 493}\r
494\r
495/**\r
496 Retrieves the physical address of a memory mapped FV\r
497\r
498 @param Instance The FV instance whose base address is going to be\r
499 returned\r
500 @param BaseAddress Pointer to a caller allocated EFI_PHYSICAL_ADDRESS\r
501 that on successful return, contains the base address\r
502 of the firmware volume.\r
503\r
504 @retval EFI_INVALID_PARAMETER Invalid parameter\r
505 @retval EFI_SUCESS Sucess to get physical address\r
506 @retval Others Fail to get physical address\r
507**/\r
508EFI_STATUS\r
509EfiFvbGetPhysicalAddress (\r
510 IN UINTN Instance,\r
511 OUT EFI_PHYSICAL_ADDRESS *BaseAddress\r
512 )\r
513{\r
514 if (Instance >= mFvbCount) {\r
515 return EFI_INVALID_PARAMETER;\r
516 }\r
517\r
518 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
519 return EFI_INVALID_PARAMETER;\r
520 }\r
521\r
522 return mFvbEntry[Instance].Fvb->GetPhysicalAddress (mFvbEntry[Instance].Fvb, BaseAddress);\r
523}\r
524\r
525/**\r
526 Retrieve the size of a logical block\r
527\r
528 @param Instance The FV instance whose block size is going to be\r
529 returned\r
530 @param Lba Indicates which block to return the size for.\r
531 @param BlockSize A pointer to a caller allocated UINTN in which\r
532 the size of the block is returned\r
533 @param NumOfBlocks a pointer to a caller allocated UINTN in which the\r
534 number of consecutive blocks starting with Lba is\r
535 returned. All blocks in this range have a size of\r
536 BlockSize\r
537\r
538 @retval EFI_INVALID_PARAMETER Invalid parameter\r
539 @retval EFI_SUCESS Sucess to get block size\r
540 @retval Others Fail to get block size\r
541**/\r
542EFI_STATUS\r
543EfiFvbGetBlockSize (\r
544 IN UINTN Instance,\r
545 IN EFI_LBA Lba,\r
546 OUT UINTN *BlockSize,\r
547 OUT UINTN *NumOfBlocks\r
548 )\r
549{\r
550 if (Instance >= mFvbCount) {\r
551 return EFI_INVALID_PARAMETER;\r
552 }\r
553\r
554 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
555 return EFI_INVALID_PARAMETER;\r
556 }\r
557\r
558 return mFvbEntry[Instance].Fvb->GetBlockSize (mFvbEntry[Instance].Fvb, Lba, BlockSize, NumOfBlocks);\r
559}\r
560\r
561/**\r
562 Erases and initializes a specified range of a firmware volume\r
563\r
564 @param Instance The FV instance to be erased\r
565 @param StartLba The starting logical block index to be erased\r
566 @param OffsetStartLba Offset into the starting block at which to\r
567 begin erasing\r
568 @param LastLba The last logical block index to be erased\r
569 @param OffsetLastLba Offset into the last block at which to end erasing\r
570\r
571 @retval EFI_INVALID_PARAMETER Invalid parameter\r
572 @retval EFI_SUCESS Sucess to erase custom block range\r
573 @retval Others Fail to erase custom block range\r
574**/\r
575EFI_STATUS\r
576EfiFvbEraseCustomBlockRange (\r
577 IN UINTN Instance,\r
578 IN EFI_LBA StartLba,\r
579 IN UINTN OffsetStartLba,\r
580 IN EFI_LBA LastLba,\r
581 IN UINTN OffsetLastLba\r
582 )\r
583{\r
584 if (Instance >= mFvbCount) {\r
585 return EFI_INVALID_PARAMETER;\r
586 }\r
587\r
588 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {\r
589 return EFI_INVALID_PARAMETER;\r
590 }\r
591\r
592 if (!(mFvbEntry[Instance].FvbExtension)) {\r
593 return EFI_UNSUPPORTED;\r
594 }\r
595\r
596 if (!(mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock)) {\r
597 return EFI_UNSUPPORTED;\r
598 }\r
599\r
600 return mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock (\r
601 mFvbEntry[Instance].FvbExtension,\r
602 StartLba,\r
603 OffsetStartLba,\r
604 LastLba,\r
605 OffsetLastLba\r
606 );\r
607}\r