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