]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - FatPkg/EnhancedFatDxe/DiskCache.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / DiskCache.c
... / ...
CommitLineData
1/** @file\r
2 Cache implementation for EFI FAT File system driver.\r
3\r
4Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "Fat.h"\r
10\r
11/**\r
12\r
13 This function is used by the Data Cache.\r
14\r
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
17\r
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 read from media is older than\r
20 than the info in the cache; So need to update the relative info in the Buffer.\r
21\r
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
28\r
29**/\r
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
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
49 DiskCache = &Volume->DiskCache[CacheData];\r
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
64 if (IoMode == ReadDisk) {\r
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
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
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
102 IN CACHE_TAG *CacheTag,\r
103 IN FAT_TASK *Task\r
104 )\r
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
124 if (IoMode == ReadDisk) {\r
125 RealSize = (UINTN)1 << PageAlignment;\r
126 MaxSize = DiskCache->LimitAddress - EntryPos;\r
127 if (MaxSize < RealSize) {\r
128 DEBUG ((DEBUG_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));\r
129 RealSize = (UINTN)MaxSize;\r
130 }\r
131 }\r
132\r
133 WriteCount = 1;\r
134 if ((DataType == CacheFat) && (IoMode == WriteDisk)) {\r
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
142 Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress, Task);\r
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
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
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
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
192 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, NULL);\r
193 if (EFI_ERROR (Status)) {\r
194 return Status;\r
195 }\r
196 }\r
197\r
198 //\r
199 // Load new data from disk;\r
200 //\r
201 CacheTag->PageNo = PageNo;\r
202 Status = FatExchangeCachePage (Volume, CacheDataType, ReadDisk, CacheTag, NULL);\r
203\r
204 return Status;\r
205}\r
206\r
207/**\r
208\r
209 Read Length bytes from the position of Offset into Buffer, or\r
210 write Length bytes from Buffer into the position of Offset.\r
211\r
212 @param Volume - FAT file system volume.\r
213 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
214 @param IoMode - Indicate the type of disk access.\r
215 @param PageNo - The number of unaligned cache page.\r
216 @param Offset - The starting byte of cache page.\r
217 @param Length - The number of bytes that is read or written\r
218 @param Buffer - Buffer containing cache data.\r
219\r
220 @retval EFI_SUCCESS - The data was accessed correctly.\r
221 @return Others - An error occurred when accessing unaligned cache page.\r
222\r
223**/\r
224STATIC\r
225EFI_STATUS\r
226FatAccessUnalignedCachePage (\r
227 IN FAT_VOLUME *Volume,\r
228 IN CACHE_DATA_TYPE CacheDataType,\r
229 IN IO_MODE IoMode,\r
230 IN UINTN PageNo,\r
231 IN UINTN Offset,\r
232 IN UINTN Length,\r
233 IN OUT VOID *Buffer\r
234 )\r
235{\r
236 EFI_STATUS Status;\r
237 VOID *Source;\r
238 VOID *Destination;\r
239 DISK_CACHE *DiskCache;\r
240 CACHE_TAG *CacheTag;\r
241 UINTN GroupNo;\r
242\r
243 DiskCache = &Volume->DiskCache[CacheDataType];\r
244 GroupNo = PageNo & DiskCache->GroupMask;\r
245 CacheTag = &DiskCache->CacheTag[GroupNo];\r
246 Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);\r
247 if (!EFI_ERROR (Status)) {\r
248 Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;\r
249 Destination = Buffer;\r
250 if (IoMode != ReadDisk) {\r
251 CacheTag->Dirty = TRUE;\r
252 DiskCache->Dirty = TRUE;\r
253 Destination = Source;\r
254 Source = Buffer;\r
255 }\r
256\r
257 CopyMem (Destination, Source, Length);\r
258 }\r
259\r
260 return Status;\r
261}\r
262\r
263/**\r
264\r
265 Read BufferSize bytes from the position of Offset into Buffer,\r
266 or write BufferSize bytes from Buffer into the position of Offset.\r
267\r
268 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into\r
269 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):\r
270\r
271 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache\r
272 page hit, just return the cache page; else update the related cache page and return\r
273 the right cache page.\r
274 2. Access of Data cache (CACHE_DATA):\r
275 The access data will be divided into UnderRun data, Aligned data and OverRun data;\r
276 The UnderRun data and OverRun data will be accessed by the Data cache,\r
277 but the Aligned data will be accessed with disk directly.\r
278\r
279 @param Volume - FAT file system volume.\r
280 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
281 @param IoMode - Indicate the type of disk access.\r
282 @param Offset - The starting byte offset to read from.\r
283 @param BufferSize - Size of Buffer.\r
284 @param Buffer - Buffer containing cache data.\r
285 @param Task point to task instance.\r
286\r
287 @retval EFI_SUCCESS - The data was accessed correctly.\r
288 @retval EFI_MEDIA_CHANGED - The MediaId does not match the current device.\r
289 @return Others - An error occurred when accessing cache.\r
290\r
291**/\r
292EFI_STATUS\r
293FatAccessCache (\r
294 IN FAT_VOLUME *Volume,\r
295 IN CACHE_DATA_TYPE CacheDataType,\r
296 IN IO_MODE IoMode,\r
297 IN UINT64 Offset,\r
298 IN UINTN BufferSize,\r
299 IN OUT UINT8 *Buffer,\r
300 IN FAT_TASK *Task\r
301 )\r
302{\r
303 EFI_STATUS Status;\r
304 UINTN PageSize;\r
305 UINTN UnderRun;\r
306 UINTN OverRun;\r
307 UINTN AlignedSize;\r
308 UINTN Length;\r
309 UINTN PageNo;\r
310 UINTN AlignedPageCount;\r
311 UINTN OverRunPageNo;\r
312 DISK_CACHE *DiskCache;\r
313 UINT64 EntryPos;\r
314 UINT8 PageAlignment;\r
315\r
316 ASSERT (Volume->CacheBuffer != NULL);\r
317\r
318 Status = EFI_SUCCESS;\r
319 DiskCache = &Volume->DiskCache[CacheDataType];\r
320 EntryPos = Offset - DiskCache->BaseAddress;\r
321 PageAlignment = DiskCache->PageAlignment;\r
322 PageSize = (UINTN)1 << PageAlignment;\r
323 PageNo = (UINTN)RShiftU64 (EntryPos, PageAlignment);\r
324 UnderRun = ((UINTN)EntryPos) & (PageSize - 1);\r
325\r
326 if (UnderRun > 0) {\r
327 Length = PageSize - UnderRun;\r
328 if (Length > BufferSize) {\r
329 Length = BufferSize;\r
330 }\r
331\r
332 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);\r
333 if (EFI_ERROR (Status)) {\r
334 return Status;\r
335 }\r
336\r
337 Buffer += Length;\r
338 BufferSize -= Length;\r
339 PageNo++;\r
340 }\r
341\r
342 AlignedPageCount = BufferSize >> PageAlignment;\r
343 OverRunPageNo = PageNo + AlignedPageCount;\r
344 //\r
345 // The access of the Aligned data\r
346 //\r
347 if (AlignedPageCount > 0) {\r
348 //\r
349 // Accessing fat table cannot have alignment data\r
350 //\r
351 ASSERT (CacheDataType == CacheData);\r
352\r
353 EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);\r
354 AlignedSize = AlignedPageCount << PageAlignment;\r
355 Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer, Task);\r
356 if (EFI_ERROR (Status)) {\r
357 return Status;\r
358 }\r
359\r
360 //\r
361 // If these access data over laps the relative cache range, these cache pages need\r
362 // to be updated.\r
363 //\r
364 FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);\r
365 Buffer += AlignedSize;\r
366 BufferSize -= AlignedSize;\r
367 }\r
368\r
369 //\r
370 // The access of the OverRun data\r
371 //\r
372 OverRun = BufferSize;\r
373 if (OverRun > 0) {\r
374 //\r
375 // Last read is not a complete page\r
376 //\r
377 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);\r
378 }\r
379\r
380 return Status;\r
381}\r
382\r
383/**\r
384\r
385 Flush all the dirty cache back, include the FAT cache and the Data cache.\r
386\r
387 @param Volume - FAT file system volume.\r
388 @param Task point to task instance.\r
389\r
390 @retval EFI_SUCCESS - Flush all the dirty cache back successfully\r
391 @return other - An error occurred when writing the data into the disk\r
392\r
393**/\r
394EFI_STATUS\r
395FatVolumeFlushCache (\r
396 IN FAT_VOLUME *Volume,\r
397 IN FAT_TASK *Task\r
398 )\r
399{\r
400 EFI_STATUS Status;\r
401 CACHE_DATA_TYPE CacheDataType;\r
402 UINTN GroupIndex;\r
403 UINTN GroupMask;\r
404 DISK_CACHE *DiskCache;\r
405 CACHE_TAG *CacheTag;\r
406\r
407 for (CacheDataType = (CACHE_DATA_TYPE)0; CacheDataType < CacheMaxType; CacheDataType++) {\r
408 DiskCache = &Volume->DiskCache[CacheDataType];\r
409 if (DiskCache->Dirty) {\r
410 //\r
411 // Data cache or fat cache is dirty, write the dirty data back\r
412 //\r
413 GroupMask = DiskCache->GroupMask;\r
414 for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {\r
415 CacheTag = &DiskCache->CacheTag[GroupIndex];\r
416 if ((CacheTag->RealSize > 0) && CacheTag->Dirty) {\r
417 //\r
418 // Write back all Dirty Data Cache Page to disk\r
419 //\r
420 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, Task);\r
421 if (EFI_ERROR (Status)) {\r
422 return Status;\r
423 }\r
424 }\r
425 }\r
426\r
427 DiskCache->Dirty = FALSE;\r
428 }\r
429 }\r
430\r
431 //\r
432 // Flush the block device.\r
433 //\r
434 Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);\r
435 return Status;\r
436}\r
437\r
438/**\r
439\r
440 Initialize the disk cache according to Volume's FatType.\r
441\r
442 @param Volume - FAT file system volume.\r
443\r
444 @retval EFI_SUCCESS - The disk cache is successfully initialized.\r
445 @retval EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.\r
446\r
447**/\r
448EFI_STATUS\r
449FatInitializeDiskCache (\r
450 IN FAT_VOLUME *Volume\r
451 )\r
452{\r
453 DISK_CACHE *DiskCache;\r
454 UINTN FatCacheGroupCount;\r
455 UINTN DataCacheSize;\r
456 UINTN FatCacheSize;\r
457 UINT8 *CacheBuffer;\r
458\r
459 DiskCache = Volume->DiskCache;\r
460 //\r
461 // Configure the parameters of disk cache\r
462 //\r
463 if (Volume->FatType == Fat12) {\r
464 FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;\r
465 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;\r
466 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;\r
467 } else {\r
468 FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;\r
469 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;\r
470 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;\r
471 }\r
472\r
473 DiskCache[CacheData].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;\r
474 DiskCache[CacheData].BaseAddress = Volume->RootPos;\r
475 DiskCache[CacheData].LimitAddress = Volume->VolumeSize;\r
476 DiskCache[CacheFat].GroupMask = FatCacheGroupCount - 1;\r
477 DiskCache[CacheFat].BaseAddress = Volume->FatPos;\r
478 DiskCache[CacheFat].LimitAddress = Volume->FatPos + Volume->FatSize;\r
479 FatCacheSize = FatCacheGroupCount << DiskCache[CacheFat].PageAlignment;\r
480 DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CacheData].PageAlignment;\r
481 //\r
482 // Allocate the Fat Cache buffer\r
483 //\r
484 CacheBuffer = AllocateZeroPool (FatCacheSize + DataCacheSize);\r
485 if (CacheBuffer == NULL) {\r
486 return EFI_OUT_OF_RESOURCES;\r
487 }\r
488\r
489 Volume->CacheBuffer = CacheBuffer;\r
490 DiskCache[CacheFat].CacheBase = CacheBuffer;\r
491 DiskCache[CacheData].CacheBase = CacheBuffer + FatCacheSize;\r
492 return EFI_SUCCESS;\r
493}\r