]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/DiskCache.c
BaseTools: Library hashing fix and optimization for --hash feature
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / DiskCache.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Cache implementation for EFI FAT File system driver.\r
b9ec9330 3\r
149d6335 4Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
eb6cb4ce 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
b9ec9330 6\r
cae7420b 7**/\r
b9ec9330 8\r
cae7420b 9#include "Fat.h"\r
b9ec9330 10\r
cae7420b 11/**\r
b9ec9330 12\r
cae7420b 13 This function is used by the Data Cache.\r
b9ec9330 14\r
cae7420b
DB
15 When this function is called by write command, all entries in this range\r
16 are older than the contents in disk, so they are invalid; just mark them invalid.\r
b9ec9330 17\r
cae7420b
DB
18 When this function is called by read command, if any entry in this range\r
19 is dirty, it means that the relative info directly readed from media is older than\r
20 than the info in the cache; So need to update the relative info in the Buffer.\r
b9ec9330 21\r
cae7420b
DB
22 @param Volume - FAT file system volume.\r
23 @param IoMode - This function is called by read command or write command\r
24 @param StartPageNo - First PageNo to be checked in the cache.\r
25 @param EndPageNo - Last PageNo to be checked in the cache.\r
26 @param Buffer - The user buffer need to update. Only when doing the read command\r
27 and there is dirty cache in the cache range, this parameter will be used.\r
b9ec9330 28\r
cae7420b 29**/\r
b9ec9330
QH
30STATIC\r
31VOID\r
32FatFlushDataCacheRange (\r
33 IN FAT_VOLUME *Volume,\r
34 IN IO_MODE IoMode,\r
35 IN UINTN StartPageNo,\r
36 IN UINTN EndPageNo,\r
37 OUT UINT8 *Buffer\r
38 )\r
b9ec9330
QH
39{\r
40 UINTN PageNo;\r
41 UINTN GroupNo;\r
42 UINTN GroupMask;\r
43 UINTN PageSize;\r
44 UINT8 PageAlignment;\r
45 DISK_CACHE *DiskCache;\r
46 CACHE_TAG *CacheTag;\r
47 UINT8 *BaseAddress;\r
48\r
c1680e88 49 DiskCache = &Volume->DiskCache[CacheData];\r
b9ec9330
QH
50 BaseAddress = DiskCache->CacheBase;\r
51 GroupMask = DiskCache->GroupMask;\r
52 PageAlignment = DiskCache->PageAlignment;\r
53 PageSize = (UINTN)1 << PageAlignment;\r
54\r
55 for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {\r
56 GroupNo = PageNo & GroupMask;\r
57 CacheTag = &DiskCache->CacheTag[GroupNo];\r
58 if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) {\r
59 //\r
60 // When reading data form disk directly, if some dirty data\r
61 // in cache is in this rang, this data in the Buffer need to\r
62 // be updated with the cache's dirty data.\r
63 //\r
c1680e88 64 if (IoMode == ReadDisk) {\r
b9ec9330
QH
65 if (CacheTag->Dirty) {\r
66 CopyMem (\r
67 Buffer + ((PageNo - StartPageNo) << PageAlignment),\r
68 BaseAddress + (GroupNo << PageAlignment),\r
69 PageSize\r
70 );\r
71 }\r
72 } else {\r
73 //\r
74 // Make all valid entries in this range invalid.\r
75 //\r
76 CacheTag->RealSize = 0;\r
77 }\r
78 }\r
79 }\r
80}\r
81\r
cae7420b
DB
82/**\r
83\r
84 Exchange the cache page with the image on the disk\r
85\r
86 @param Volume - FAT file system volume.\r
87 @param DataType - Indicate the cache type.\r
88 @param IoMode - Indicate whether to load this page from disk or store this page to disk.\r
89 @param CacheTag - The Cache Tag for the current cache page.\r
90 @param Task point to task instance.\r
91\r
92 @retval EFI_SUCCESS - Cache page exchanged successfully.\r
93 @return Others - An error occurred when exchanging cache page.\r
94\r
95**/\r
b9ec9330
QH
96STATIC\r
97EFI_STATUS\r
98FatExchangeCachePage (\r
99 IN FAT_VOLUME *Volume,\r
100 IN CACHE_DATA_TYPE DataType,\r
101 IN IO_MODE IoMode,\r
149d6335
RN
102 IN CACHE_TAG *CacheTag,\r
103 IN FAT_TASK *Task\r
b9ec9330 104 )\r
b9ec9330
QH
105{\r
106 EFI_STATUS Status;\r
107 UINTN GroupNo;\r
108 UINTN PageNo;\r
109 UINTN WriteCount;\r
110 UINTN RealSize;\r
111 UINT64 EntryPos;\r
112 UINT64 MaxSize;\r
113 DISK_CACHE *DiskCache;\r
114 VOID *PageAddress;\r
115 UINT8 PageAlignment;\r
116\r
117 DiskCache = &Volume->DiskCache[DataType];\r
118 PageNo = CacheTag->PageNo;\r
119 GroupNo = PageNo & DiskCache->GroupMask;\r
120 PageAlignment = DiskCache->PageAlignment;\r
121 PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment);\r
122 EntryPos = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);\r
123 RealSize = CacheTag->RealSize;\r
c1680e88 124 if (IoMode == ReadDisk) {\r
b9ec9330
QH
125 RealSize = (UINTN)1 << PageAlignment;\r
126 MaxSize = DiskCache->LimitAddress - EntryPos;\r
127 if (MaxSize < RealSize) {\r
128 DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));\r
129 RealSize = (UINTN) MaxSize;\r
130 }\r
131 }\r
132\r
133 WriteCount = 1;\r
c1680e88 134 if (DataType == CacheFat && IoMode == WriteDisk) {\r
b9ec9330
QH
135 WriteCount = Volume->NumFats;\r
136 }\r
137\r
138 do {\r
139 //\r
140 // Only fat table writing will execute more than once\r
141 //\r
149d6335 142 Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress, Task);\r
b9ec9330
QH
143 if (EFI_ERROR (Status)) {\r
144 return Status;\r
145 }\r
146\r
147 EntryPos += Volume->FatSize;\r
148 } while (--WriteCount > 0);\r
149\r
150 CacheTag->Dirty = FALSE;\r
151 CacheTag->RealSize = RealSize;\r
152 return EFI_SUCCESS;\r
153}\r
154\r
cae7420b
DB
155/**\r
156\r
157 Get one cache page by specified PageNo.\r
158\r
159 @param Volume - FAT file system volume.\r
160 @param CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.\r
161 @param PageNo - PageNo to match with the cache.\r
162 @param CacheTag - The Cache Tag for the current cache page.\r
163\r
164 @retval EFI_SUCCESS - Get the cache page successfully.\r
165 @return other - An error occurred when accessing data.\r
166\r
167**/\r
b9ec9330
QH
168STATIC\r
169EFI_STATUS\r
170FatGetCachePage (\r
171 IN FAT_VOLUME *Volume,\r
172 IN CACHE_DATA_TYPE CacheDataType,\r
173 IN UINTN PageNo,\r
174 IN CACHE_TAG *CacheTag\r
175 )\r
b9ec9330
QH
176{\r
177 EFI_STATUS Status;\r
178 UINTN OldPageNo;\r
179\r
180 OldPageNo = CacheTag->PageNo;\r
181 if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {\r
182 //\r
183 // Cache Hit occurred\r
184 //\r
185 return EFI_SUCCESS;\r
186 }\r
187\r
188 //\r
189 // Write dirty cache page back to disk\r
190 //\r
191 if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
c1680e88 192 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, NULL);\r
b9ec9330
QH
193 if (EFI_ERROR (Status)) {\r
194 return Status;\r
195 }\r
196 }\r
197 //\r
198 // Load new data from disk;\r
199 //\r
200 CacheTag->PageNo = PageNo;\r
c1680e88 201 Status = FatExchangeCachePage (Volume, CacheDataType, ReadDisk, CacheTag, NULL);\r
b9ec9330
QH
202\r
203 return Status;\r
204}\r
205\r
cae7420b
DB
206/**\r
207\r
208 Read Length bytes from the position of Offset into Buffer, or\r
209 write Length bytes from Buffer into the position of Offset.\r
210\r
211 @param Volume - FAT file system volume.\r
212 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
213 @param IoMode - Indicate the type of disk access.\r
214 @param PageNo - The number of unaligned cache page.\r
215 @param Offset - The starting byte of cache page.\r
216 @param Length - The number of bytes that is read or written\r
217 @param Buffer - Buffer containing cache data.\r
218\r
219 @retval EFI_SUCCESS - The data was accessed correctly.\r
220 @return Others - An error occurred when accessing unaligned cache page.\r
221\r
222**/\r
b9ec9330
QH
223STATIC\r
224EFI_STATUS\r
225FatAccessUnalignedCachePage (\r
226 IN FAT_VOLUME *Volume,\r
227 IN CACHE_DATA_TYPE CacheDataType,\r
228 IN IO_MODE IoMode,\r
229 IN UINTN PageNo,\r
230 IN UINTN Offset,\r
231 IN UINTN Length,\r
232 IN OUT VOID *Buffer\r
233 )\r
b9ec9330
QH
234{\r
235 EFI_STATUS Status;\r
236 VOID *Source;\r
237 VOID *Destination;\r
238 DISK_CACHE *DiskCache;\r
239 CACHE_TAG *CacheTag;\r
240 UINTN GroupNo;\r
241\r
242 DiskCache = &Volume->DiskCache[CacheDataType];\r
243 GroupNo = PageNo & DiskCache->GroupMask;\r
244 CacheTag = &DiskCache->CacheTag[GroupNo];\r
245 Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);\r
246 if (!EFI_ERROR (Status)) {\r
247 Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;\r
248 Destination = Buffer;\r
c1680e88 249 if (IoMode != ReadDisk) {\r
b9ec9330
QH
250 CacheTag->Dirty = TRUE;\r
251 DiskCache->Dirty = TRUE;\r
252 Destination = Source;\r
253 Source = Buffer;\r
254 }\r
255\r
256 CopyMem (Destination, Source, Length);\r
257 }\r
258\r
259 return Status;\r
260}\r
261\r
cae7420b 262/**\r
b9ec9330
QH
263\r
264 Read BufferSize bytes from the position of Offset into Buffer,\r
265 or write BufferSize bytes from Buffer into the position of Offset.\r
266\r
267 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into\r
268 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):\r
269\r
270 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache\r
271 page hit, just return the cache page; else update the related cache page and return\r
272 the right cache page.\r
273 2. Access of Data cache (CACHE_DATA):\r
274 The access data will be divided into UnderRun data, Aligned data and OverRun data;\r
275 The UnderRun data and OverRun data will be accessed by the Data cache,\r
276 but the Aligned data will be accessed with disk directly.\r
277\r
cae7420b
DB
278 @param Volume - FAT file system volume.\r
279 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
280 @param IoMode - Indicate the type of disk access.\r
281 @param Offset - The starting byte offset to read from.\r
282 @param BufferSize - Size of Buffer.\r
283 @param Buffer - Buffer containing cache data.\r
284 @param Task point to task instance.\r
b9ec9330 285\r
cae7420b
DB
286 @retval EFI_SUCCESS - The data was accessed correctly.\r
287 @retval EFI_MEDIA_CHANGED - The MediaId does not match the current device.\r
288 @return Others - An error occurred when accessing cache.\r
b9ec9330 289\r
cae7420b
DB
290**/\r
291EFI_STATUS\r
292FatAccessCache (\r
293 IN FAT_VOLUME *Volume,\r
294 IN CACHE_DATA_TYPE CacheDataType,\r
295 IN IO_MODE IoMode,\r
296 IN UINT64 Offset,\r
297 IN UINTN BufferSize,\r
298 IN OUT UINT8 *Buffer,\r
299 IN FAT_TASK *Task\r
300 )\r
b9ec9330
QH
301{\r
302 EFI_STATUS Status;\r
303 UINTN PageSize;\r
304 UINTN UnderRun;\r
305 UINTN OverRun;\r
306 UINTN AlignedSize;\r
307 UINTN Length;\r
308 UINTN PageNo;\r
309 UINTN AlignedPageCount;\r
310 UINTN OverRunPageNo;\r
311 DISK_CACHE *DiskCache;\r
312 UINT64 EntryPos;\r
313 UINT8 PageAlignment;\r
314\r
315 ASSERT (Volume->CacheBuffer != NULL);\r
316\r
317 Status = EFI_SUCCESS;\r
318 DiskCache = &Volume->DiskCache[CacheDataType];\r
319 EntryPos = Offset - DiskCache->BaseAddress;\r
320 PageAlignment = DiskCache->PageAlignment;\r
321 PageSize = (UINTN)1 << PageAlignment;\r
322 PageNo = (UINTN) RShiftU64 (EntryPos, PageAlignment);\r
323 UnderRun = ((UINTN) EntryPos) & (PageSize - 1);\r
324\r
325 if (UnderRun > 0) {\r
326 Length = PageSize - UnderRun;\r
327 if (Length > BufferSize) {\r
328 Length = BufferSize;\r
329 }\r
330\r
331 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);\r
332 if (EFI_ERROR (Status)) {\r
333 return Status;\r
334 }\r
335\r
336 Buffer += Length;\r
337 BufferSize -= Length;\r
338 PageNo++;\r
339 }\r
340\r
341 AlignedPageCount = BufferSize >> PageAlignment;\r
342 OverRunPageNo = PageNo + AlignedPageCount;\r
343 //\r
344 // The access of the Aligned data\r
345 //\r
346 if (AlignedPageCount > 0) {\r
347 //\r
348 // Accessing fat table cannot have alignment data\r
349 //\r
c1680e88 350 ASSERT (CacheDataType == CacheData);\r
b9ec9330
QH
351\r
352 EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);\r
353 AlignedSize = AlignedPageCount << PageAlignment;\r
149d6335 354 Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer, Task);\r
b9ec9330
QH
355 if (EFI_ERROR (Status)) {\r
356 return Status;\r
357 }\r
358 //\r
359 // If these access data over laps the relative cache range, these cache pages need\r
360 // to be updated.\r
361 //\r
362 FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);\r
363 Buffer += AlignedSize;\r
364 BufferSize -= AlignedSize;\r
365 }\r
366 //\r
367 // The access of the OverRun data\r
368 //\r
369 OverRun = BufferSize;\r
370 if (OverRun > 0) {\r
371 //\r
372 // Last read is not a complete page\r
373 //\r
374 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);\r
375 }\r
376\r
377 return Status;\r
378}\r
379\r
cae7420b 380/**\r
b9ec9330
QH
381\r
382 Flush all the dirty cache back, include the FAT cache and the Data cache.\r
383\r
cae7420b
DB
384 @param Volume - FAT file system volume.\r
385 @param Task point to task instance.\r
b9ec9330 386\r
cae7420b
DB
387 @retval EFI_SUCCESS - Flush all the dirty cache back successfully\r
388 @return other - An error occurred when writing the data into the disk\r
b9ec9330 389\r
cae7420b
DB
390**/\r
391EFI_STATUS\r
392FatVolumeFlushCache (\r
393 IN FAT_VOLUME *Volume,\r
394 IN FAT_TASK *Task\r
395 )\r
b9ec9330
QH
396{\r
397 EFI_STATUS Status;\r
398 CACHE_DATA_TYPE CacheDataType;\r
399 UINTN GroupIndex;\r
400 UINTN GroupMask;\r
401 DISK_CACHE *DiskCache;\r
402 CACHE_TAG *CacheTag;\r
403\r
c1680e88 404 for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CacheMaxType; CacheDataType++) {\r
b9ec9330
QH
405 DiskCache = &Volume->DiskCache[CacheDataType];\r
406 if (DiskCache->Dirty) {\r
407 //\r
408 // Data cache or fat cache is dirty, write the dirty data back\r
409 //\r
410 GroupMask = DiskCache->GroupMask;\r
411 for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {\r
412 CacheTag = &DiskCache->CacheTag[GroupIndex];\r
413 if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
414 //\r
415 // Write back all Dirty Data Cache Page to disk\r
416 //\r
c1680e88 417 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, Task);\r
b9ec9330
QH
418 if (EFI_ERROR (Status)) {\r
419 return Status;\r
420 }\r
421 }\r
422 }\r
423\r
424 DiskCache->Dirty = FALSE;\r
425 }\r
426 }\r
427 //\r
428 // Flush the block device.\r
429 //\r
430 Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);\r
431 return Status;\r
432}\r
433\r
cae7420b 434/**\r
b9ec9330
QH
435\r
436 Initialize the disk cache according to Volume's FatType.\r
437\r
cae7420b 438 @param Volume - FAT file system volume.\r
b9ec9330 439\r
cae7420b
DB
440 @retval EFI_SUCCESS - The disk cache is successfully initialized.\r
441 @retval EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.\r
b9ec9330 442\r
cae7420b
DB
443**/\r
444EFI_STATUS\r
445FatInitializeDiskCache (\r
446 IN FAT_VOLUME *Volume\r
447 )\r
b9ec9330
QH
448{\r
449 DISK_CACHE *DiskCache;\r
450 UINTN FatCacheGroupCount;\r
451 UINTN DataCacheSize;\r
452 UINTN FatCacheSize;\r
453 UINT8 *CacheBuffer;\r
454\r
455 DiskCache = Volume->DiskCache;\r
456 //\r
457 // Configure the parameters of disk cache\r
458 //\r
c1680e88 459 if (Volume->FatType == Fat12) {\r
b9ec9330 460 FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;\r
c1680e88
DB
461 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;\r
462 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;\r
b9ec9330
QH
463 } else {\r
464 FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;\r
c1680e88
DB
465 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;\r
466 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;\r
b9ec9330
QH
467 }\r
468\r
c1680e88
DB
469 DiskCache[CacheData].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;\r
470 DiskCache[CacheData].BaseAddress = Volume->RootPos;\r
471 DiskCache[CacheData].LimitAddress = Volume->VolumeSize;\r
472 DiskCache[CacheFat].GroupMask = FatCacheGroupCount - 1;\r
473 DiskCache[CacheFat].BaseAddress = Volume->FatPos;\r
474 DiskCache[CacheFat].LimitAddress = Volume->FatPos + Volume->FatSize;\r
475 FatCacheSize = FatCacheGroupCount << DiskCache[CacheFat].PageAlignment;\r
476 DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CacheData].PageAlignment;\r
b9ec9330
QH
477 //\r
478 // Allocate the Fat Cache buffer\r
479 //\r
f4500fc1 480 CacheBuffer = AllocateZeroPool (FatCacheSize + DataCacheSize);\r
b9ec9330
QH
481 if (CacheBuffer == NULL) {\r
482 return EFI_OUT_OF_RESOURCES;\r
483 }\r
484\r
485 Volume->CacheBuffer = CacheBuffer;\r
c1680e88
DB
486 DiskCache[CacheFat].CacheBase = CacheBuffer;\r
487 DiskCache[CacheData].CacheBase = CacheBuffer + FatCacheSize;\r
b9ec9330
QH
488 return EFI_SUCCESS;\r
489}\r