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