1 /*++ 2 3 Caution: This file is used for Duet platform only, do not use them in real platform. 4 All variable code, variable metadata, and variable data used by Duet platform are on 5 disk. They can be changed by user. BIOS is not able to protoect those. 6 Duet trusts all meta data from disk. If variable code, variable metadata and variable 7 data is modified in inproper way, the behavior is undefined. 8 9 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 10 This program and the accompanying materials 11 are licensed and made available under the terms and conditions of the BSD License 12 which accompanies this distribution. The full text of the license may be found at 13 http://opensource.org/licenses/bsd-license.php 14 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 17 18 Module Name: 19 20 FileStorage.c 21 22 Abstract: 23 24 handles variable store/reads on file 25 26 Revision History 27 28 --*/ 29 #include "FSVariable.h" 30 31 VOID *mSFSRegistration; 32 33 // 34 // Prototypes 35 // 36 37 VOID 38 EFIAPI 39 OnVirtualAddressChangeFs ( 40 IN EFI_EVENT Event, 41 IN VOID *Context 42 ); 43 44 EFI_STATUS 45 EFIAPI 46 FileEraseStore( 47 IN VARIABLE_STORAGE *This 48 ); 49 50 EFI_STATUS 51 EFIAPI 52 FileWriteStore ( 53 IN VARIABLE_STORAGE *This, 54 IN UINTN Offset, 55 IN UINTN BufferSize, 56 IN VOID *Buffer 57 ); 58 59 EFI_STATUS 60 OpenStore ( 61 IN EFI_DEVICE_PATH_PROTOCOL *Device, 62 IN CHAR16 *FilePathName, 63 IN UINT64 OpenMode, 64 OUT EFI_FILE_PROTOCOL **File 65 ); 66 67 // 68 // Implementation below: 69 // 70 VOID 71 FileClose ( 72 IN EFI_FILE_PROTOCOL *File 73 ) 74 { 75 EFI_STATUS Status; 76 77 Status = File->Flush (File); 78 ASSERT_EFI_ERROR (Status); 79 80 Status = File->Close (File); 81 ASSERT_EFI_ERROR (Status); 82 } 83 84 EFI_STATUS 85 CheckStore ( 86 IN EFI_HANDLE SimpleFileSystemHandle, 87 IN UINT32 VolumeId, 88 OUT EFI_DEVICE_PATH_PROTOCOL **Device 89 ) 90 { 91 #define BLOCK_SIZE 0x200 92 #define FAT16_VOLUME_ID_OFFSET 39 93 #define FAT32_VOLUME_ID_OFFSET 67 94 EFI_STATUS Status; 95 EFI_BLOCK_IO_PROTOCOL *BlkIo; 96 UINT8 BootSector[BLOCK_SIZE]; 97 98 *Device = NULL; 99 Status = gBS->HandleProtocol ( 100 SimpleFileSystemHandle, 101 &gEfiBlockIoProtocolGuid, // BlockIo should be supported if it supports SimpleFileSystem 102 (VOID*)&BlkIo 103 ); 104 105 if (EFI_ERROR (Status)) { 106 goto ErrHandle; 107 } 108 if (!BlkIo->Media->MediaPresent) { 109 DEBUG ((EFI_D_ERROR, "FileStorage: Media not present!\n")); 110 Status = EFI_NO_MEDIA; 111 goto ErrHandle; 112 } 113 if (BlkIo->Media->ReadOnly) { 114 DEBUG ((EFI_D_ERROR, "FileStorage: Media is read-only!\n")); 115 Status = EFI_ACCESS_DENIED; 116 goto ErrHandle; 117 } 118 119 Status = BlkIo->ReadBlocks( 120 BlkIo, 121 BlkIo->Media->MediaId, 122 0, 123 BLOCK_SIZE, 124 BootSector 125 ); 126 ASSERT_EFI_ERROR (Status); 127 if ((*(UINT32 *) &BootSector[FAT16_VOLUME_ID_OFFSET] != VolumeId) && 128 (*(UINT32 *) &BootSector[FAT32_VOLUME_ID_OFFSET] != VolumeId) 129 ) { 130 Status = EFI_NOT_FOUND; 131 goto ErrHandle; 132 } 133 134 *Device = DuplicateDevicePath (DevicePathFromHandle (SimpleFileSystemHandle)); 135 ASSERT (*Device != NULL); 136 137 ErrHandle: 138 return Status; 139 } 140 141 EFI_STATUS 142 CheckStoreExists ( 143 IN EFI_DEVICE_PATH_PROTOCOL *Device 144 ) 145 { 146 EFI_HANDLE Handle; 147 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; 148 EFI_STATUS Status; 149 150 Status = gBS->LocateDevicePath ( 151 &gEfiSimpleFileSystemProtocolGuid, 152 &Device, 153 &Handle 154 ); 155 156 if (EFI_ERROR (Status)) { 157 return Status; 158 } 159 160 Status = gBS->HandleProtocol ( 161 Handle, 162 &gEfiSimpleFileSystemProtocolGuid, 163 (VOID **) &Volume 164 ); 165 if (EFI_ERROR (Status)) { 166 return Status; 167 } 168 169 return EFI_SUCCESS; 170 } 171 172 // this routine is still running in BS period, no limitation 173 // call FileInitStorage(), which load variable content file to memory 174 // read the store_header, init store_header if it has not been inited (read sth. about format/heathy) 175 // reclaim space using scratch memory 176 177 VOID 178 EFIAPI 179 OnSimpleFileSystemInstall ( 180 IN EFI_EVENT Event, 181 IN VOID *Context 182 ) 183 { 184 EFI_STATUS Status; 185 UINTN HandleSize; 186 EFI_HANDLE Handle; 187 EFI_DEVICE_PATH_PROTOCOL *Device; 188 VS_DEV *Dev; 189 EFI_FILE_PROTOCOL *File; 190 UINTN NumBytes; 191 192 Dev = (VS_DEV *) Context; 193 194 if (VAR_FILE_DEVICEPATH (Dev) != NULL && 195 !EFI_ERROR (CheckStoreExists (VAR_FILE_DEVICEPATH (Dev))) 196 ) { 197 DEBUG ((EFI_D_ERROR, "FileStorage: Already mapped!\n")); 198 return ; 199 } 200 201 while (TRUE) { 202 HandleSize = sizeof (EFI_HANDLE); 203 Status = gBS->LocateHandle ( 204 ByRegisterNotify, 205 NULL, 206 mSFSRegistration, 207 &HandleSize, 208 &Handle 209 ); 210 if (EFI_ERROR (Status)) { 211 return ; 212 } 213 214 Status = CheckStore (Handle, VAR_FILE_VOLUMEID (Dev), &Device); 215 if (!EFI_ERROR (Status)) { 216 break; 217 } 218 } 219 220 VAR_FILE_DEVICEPATH (Dev) = Device; 221 Status = OpenStore ( 222 VAR_FILE_DEVICEPATH (Dev), 223 VAR_FILE_FILEPATH (Dev), 224 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE, 225 &File 226 ); 227 ASSERT_EFI_ERROR (Status); 228 229 NumBytes = Dev->Size; 230 Status = File->Write (File, &NumBytes, VAR_DATA_PTR (Dev)); 231 ASSERT_EFI_ERROR (Status); 232 FileClose (File); 233 DEBUG ((EFI_D_ERROR, "FileStorage: Mapped to file!\n")); 234 } 235 236 EFI_STATUS 237 FileStorageConstructor ( 238 OUT VARIABLE_STORAGE **VarStore, 239 OUT EFI_EVENT_NOTIFY *GoVirtualEvent, 240 IN EFI_PHYSICAL_ADDRESS NvStorageBase, 241 IN UINTN Size, 242 IN UINT32 VolumeId, 243 IN CHAR16 *FilePath 244 ) 245 { 246 VS_DEV *Dev; 247 EFI_STATUS Status; 248 EFI_EVENT Event; 249 250 Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof(VS_DEV), (VOID **) &Dev); 251 ASSERT_EFI_ERROR (Status); 252 ZeroMem (Dev, sizeof(VS_DEV)); 253 254 Dev->Signature = VS_DEV_SIGNATURE; 255 Dev->Size = Size; 256 VAR_DATA_PTR (Dev) = (UINT8 *) (UINTN) NvStorageBase; 257 VAR_FILE_VOLUMEID (Dev) = VolumeId; 258 StrCpy (VAR_FILE_FILEPATH (Dev), FilePath); 259 Dev->VarStore.Erase = FileEraseStore; 260 Dev->VarStore.Write = FileWriteStore; 261 262 DEBUG ((EFI_D_ERROR, "FileStorageConstructor(0x%0x:0x%0x): added!\n", NvStorageBase, Size)); 263 264 // add notify on SFS's installation. 265 266 Status = gBS->CreateEvent ( 267 EVT_NOTIFY_SIGNAL, 268 TPL_CALLBACK, 269 OnSimpleFileSystemInstall, 270 Dev, 271 &Event 272 ); 273 ASSERT_EFI_ERROR (Status); 274 275 Status = gBS->RegisterProtocolNotify ( 276 &gEfiSimpleFileSystemProtocolGuid, 277 Event, 278 &mSFSRegistration 279 ); 280 ASSERT_EFI_ERROR (Status); 281 282 *VarStore = &Dev->VarStore; 283 *GoVirtualEvent = OnVirtualAddressChangeFs; 284 return EFI_SUCCESS; 285 } 286 287 EFI_STATUS 288 EFIAPI 289 FileEraseStore( 290 IN VARIABLE_STORAGE *This 291 ) 292 { 293 EFI_STATUS Status; 294 VS_DEV *Dev; 295 EFI_FILE_PROTOCOL *File; 296 UINTN NumBytes; 297 298 Status = EFI_SUCCESS; 299 Dev = DEV_FROM_THIS(This); 300 301 SetMem (VAR_DATA_PTR (Dev), Dev->Size, VAR_DEFAULT_VALUE); 302 303 if (!EfiAtRuntime () && VAR_FILE_DEVICEPATH (Dev) != NULL) { 304 Status = OpenStore ( 305 VAR_FILE_DEVICEPATH (Dev), 306 VAR_FILE_FILEPATH (Dev), 307 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 308 &File 309 ); 310 ASSERT_EFI_ERROR (Status); 311 NumBytes = Dev->Size; 312 Status = File->Write (File, &NumBytes, VAR_DATA_PTR (Dev)); 313 ASSERT_EFI_ERROR (Status); 314 FileClose (File); 315 } 316 317 return Status; 318 } 319 320 EFI_STATUS 321 EFIAPI 322 FileWriteStore ( 323 IN VARIABLE_STORAGE *This, 324 IN UINTN Offset, 325 IN UINTN BufferSize, 326 IN VOID *Buffer 327 ) 328 { 329 EFI_STATUS Status; 330 VS_DEV *Dev; 331 EFI_FILE_PROTOCOL *File; 332 333 Status = EFI_SUCCESS; 334 Dev = DEV_FROM_THIS(This); 335 336 ASSERT (Buffer != NULL); 337 ASSERT (Offset + BufferSize <= Dev->Size); 338 339 CopyMem (VAR_DATA_PTR (Dev) + Offset, Buffer, BufferSize); 340 341 if (!EfiAtRuntime () && VAR_FILE_DEVICEPATH (Dev) != NULL) { 342 Status = OpenStore ( 343 VAR_FILE_DEVICEPATH (Dev), 344 VAR_FILE_FILEPATH (Dev), 345 EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 346 &File 347 ); 348 Status = File->SetPosition (File, Offset); 349 ASSERT_EFI_ERROR (Status); 350 Status = File->Write (File, &BufferSize, Buffer); 351 ASSERT_EFI_ERROR (Status); 352 FileClose (File); 353 } 354 return Status; 355 } 356 357 VOID 358 EFIAPI 359 OnVirtualAddressChangeFs ( 360 IN EFI_EVENT Event, 361 IN VOID *Context 362 ) 363 { 364 VS_DEV *Dev; 365 366 Dev = DEV_FROM_THIS (Context); 367 368 EfiConvertPointer (0, (VOID **) &VAR_DATA_PTR (Dev)); 369 EfiConvertPointer (0, (VOID **) &Dev->VarStore.Erase); 370 EfiConvertPointer (0, (VOID **) &Dev->VarStore.Write); 371 } 372 373 EFI_STATUS 374 OpenStore ( 375 IN EFI_DEVICE_PATH_PROTOCOL *Device, 376 IN CHAR16 *FilePathName, 377 IN UINT64 OpenMode, 378 OUT EFI_FILE_PROTOCOL **File 379 ) 380 { 381 EFI_HANDLE Handle; 382 EFI_FILE_HANDLE Root; 383 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; 384 EFI_STATUS Status; 385 386 *File = NULL; 387 388 Status = gBS->LocateDevicePath ( 389 &gEfiSimpleFileSystemProtocolGuid, 390 &Device, 391 &Handle 392 ); 393 394 if (EFI_ERROR (Status)) { 395 return Status; 396 } 397 398 Status = gBS->HandleProtocol ( 399 Handle, 400 &gEfiSimpleFileSystemProtocolGuid, 401 (VOID **) &Volume 402 ); 403 if (EFI_ERROR (Status)) { 404 return Status; 405 } 406 407 // 408 // Open the root directory of the volume 409 // 410 Root = NULL; 411 Status = Volume->OpenVolume ( 412 Volume, 413 &Root 414 ); 415 ASSERT_EFI_ERROR (Status); 416 ASSERT (Root != NULL); 417 418 // 419 // Open file 420 // 421 Status = Root->Open ( 422 Root, 423 File, 424 FilePathName, 425 OpenMode, 426 0 427 ); 428 if (EFI_ERROR (Status)) { 429 *File = NULL; 430 } 431 432 // 433 // Close the Root directory 434 // 435 Root->Close (Root); 436 return Status; 437 } 438