1 2 /* 3 * Copyright (c) 1999, 2000 4 * Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without modification, 8 * are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * 3. All advertising materials mentioning features or use of this software must 18 * display the following acknowledgement: 19 * 20 * This product includes software developed by Intel Corporation and its 21 * contributors. 22 * 23 * 4. Neither the name of Intel Corporation or its contributors may be used to 24 * endorse or promote products derived from this software without specific 25 * prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 * DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR 31 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 34 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 * 38 */ 39 #include <Uefi.h> 40 41 #include <Protocol/BlockIo.h> 42 #include <Protocol/LoadedImage.h> 43 #include <Library/DebugLib.h> 44 #include <Library/BaseMemoryLib.h> 45 #include <Library/UefiDriverEntryPoint.h> 46 #include <Library/UefiBootServicesTableLib.h> 47 #include <Library/UefiLib.h> 48 #include <Library/BaseLib.h> 49 #include <Library/PcdLib.h> 50 #include <Library/MemoryAllocationLib.h> 51 #include <Library/DevicePathLib.h> 52 53 #include <Guid/RamDiskGuid.h> 54 #include "ramdisk.h" 55 56 57 UINT32 GetDiskSize( EFI_HANDLE ImageHandle ); 58 59 /* Embedded version string for VERS utility */ 60 //static char v[] = "version_number=1.00 "; 61 62 /* EFI device path definition */ 63 static RAM_DISK_DEVICE_PATH RamDiskDevicePath = 64 { 65 {MESSAGING_DEVICE_PATH, 66 MSG_VENDOR_DP, 67 {sizeof(RAM_DISK_DEVICE_PATH) - END_DEVICE_PATH_LENGTH, 68 0}}, 69 RAM_DISK_GUID, 70 {0,0,0,0,0,0,0,0}, // ID assigned below 71 {END_DEVICE_PATH_TYPE, 72 END_ENTIRE_DEVICE_PATH_SUBTYPE, 73 {END_DEVICE_PATH_LENGTH}} 74 }; 75 76 /* Lookup table of total sectors vs. cluster size. 77 * Ramdisk sizes between 0x20D0 (4.1MB) and 0x100000 (512MB) sectors are valid FAT16 drive sizes. 78 */ 79 #define MIN_DISK_SIZE 1 80 #define MAX_DISK_SIZE 512 81 static FAT16TABLE fat16tbl[] = 82 { 83 {0x00000800, 1}, /* 800 sectors * 1 sec/cluster * 512 bytes = 1 M */ 84 {0x00001000, 1}, /* 1000 sectors * 1 sec/cluster * 512 bytes = 2 M */ 85 {0x00001800, 1}, /* 1800 sectors * 1 sec/cluster * 512 bytes = 3 M */ 86 {0x00007FA8, 2}, 87 {0x00040000, 4}, 88 {0x00080000, 8}, 89 {0x00100000,16}, 90 {0xFFFFFFFF, 0} 91 }; 92 93 VOID CopyBOOTSEC(VOID* Start,BOOTSEC* bsc) 94 { 95 UINT32 index=0; 96 UINT8* pStart=(UINT8*)Start; 97 98 CopyMem(&(pStart[index]), &(bsc->BS_jmpBoot[0]), sizeof(bsc->BS_jmpBoot)); 99 index+=sizeof(bsc->BS_jmpBoot); 100 101 CopyMem(&(pStart[index]), &(bsc->BS_OEMName[0]), sizeof(bsc->BS_OEMName)); 102 index+=sizeof(bsc->BS_OEMName); 103 104 CopyMem(&(pStart[index]), &(bsc->BPB_BytsPerSec), sizeof(bsc->BPB_BytsPerSec)); 105 index+=sizeof(bsc->BPB_BytsPerSec); 106 107 CopyMem(&(pStart[index]), &(bsc->BPB_SecPerClus), sizeof(bsc->BPB_SecPerClus)); 108 index+=sizeof(bsc->BPB_SecPerClus); 109 110 CopyMem(&(pStart[index]), &(bsc->BPB_RsvdSecCnt), sizeof(bsc->BPB_RsvdSecCnt)); 111 index+=sizeof(bsc->BPB_RsvdSecCnt); 112 113 CopyMem(&(pStart[index]), &(bsc->BPB_NumFATs), sizeof(bsc->BPB_NumFATs)); 114 index+=sizeof(bsc->BPB_NumFATs); 115 116 CopyMem(&(pStart[index]), &(bsc->BPB_NumFATs), sizeof(bsc->BPB_NumFATs)); 117 index+=sizeof(bsc->BPB_NumFATs); 118 119 CopyMem(&(pStart[index]), &(bsc->BPB_RootEntCnt), sizeof(bsc->BPB_RootEntCnt)); 120 index+=sizeof(bsc->BPB_RootEntCnt); 121 122 CopyMem(&(pStart[index]), &(bsc->BPB_TotSec16), sizeof(bsc->BPB_TotSec16)); 123 index+=sizeof(bsc->BPB_TotSec16); 124 125 CopyMem(&(pStart[index]), &(bsc->BPB_Media), sizeof(bsc->BPB_Media)); 126 index+=sizeof(bsc->BPB_Media); 127 128 CopyMem(&(pStart[index]), &(bsc->BPB_FATSz16), sizeof(bsc->BPB_FATSz16)); 129 index+=sizeof(bsc->BPB_FATSz16); 130 131 CopyMem(&(pStart[index]), &(bsc->BPB_SecPerTrk), sizeof(bsc->BPB_SecPerTrk)); 132 index+=sizeof(bsc->BPB_SecPerTrk); 133 134 CopyMem(&(pStart[index]), &(bsc->BPB_NumHeads), sizeof(bsc->BPB_NumHeads)); 135 index+=sizeof(bsc->BPB_NumHeads); 136 137 CopyMem(&(pStart[index]), &(bsc->BPB_HiddSec), sizeof(bsc->BPB_HiddSec)); 138 index+=sizeof(bsc->BPB_HiddSec); 139 140 CopyMem(&(pStart[index]), &(bsc->BPB_TotSec32), sizeof(bsc->BPB_TotSec32)); 141 index+=sizeof(bsc->BPB_TotSec32); 142 143 CopyMem(&(pStart[index]), &(bsc->BS_DrvNum), sizeof(bsc->BS_DrvNum)); 144 index+=sizeof(bsc->BS_DrvNum); 145 146 CopyMem(&(pStart[index]), &(bsc->BS_Reserved1), sizeof(bsc->BS_Reserved1)); 147 index+=sizeof(bsc->BS_Reserved1); 148 149 CopyMem(&(pStart[index]), &(bsc->BS_BootSig), sizeof(bsc->BS_BootSig)); 150 index+=sizeof(bsc->BS_BootSig); 151 152 CopyMem(&(pStart[index]), &(bsc->BS_VolID), sizeof(bsc->BS_VolID)); 153 index+=sizeof(bsc->BS_VolID); 154 155 CopyMem(&(pStart[index]), &(bsc->BS_VolLab[0]), sizeof(bsc->BS_VolLab)); 156 index+=sizeof(bsc->BS_VolLab); 157 158 CopyMem(&(pStart[index]), &(bsc->BS_FilSysType[0]), sizeof(bsc->BS_FilSysType)); 159 index+=sizeof(bsc->BS_FilSysType); 160 161 CopyMem(&(pStart[index]), &(bsc->BS_Code[0]), sizeof(bsc->BS_Code)); 162 index+=sizeof(bsc->BS_Code); 163 164 CopyMem(&(pStart[index]), &(bsc->BS_Sig), sizeof(bsc->BS_Sig)); 165 166 } 167 168 169 170 /* Helper function to compute cluster size 171 * vs. total sectors on drive. 172 */ 173 STATIC UINT8 size2spc(UINT32 ts) 174 { 175 int i = 0; 176 177 while(fat16tbl[i].size != 0xFFFFFFFF) 178 { 179 if(ts <= fat16tbl[i].size) 180 return fat16tbl[i].spc; 181 ++i; 182 } 183 184 return 0; 185 } 186 187 UINT8 TestSize(UINT32 ts) 188 { 189 int i = 0; 190 191 while(fat16tbl[i].size != 0xFFFFFFFF) 192 { 193 if(ts <= fat16tbl[i].size) 194 return fat16tbl[i].spc; 195 ++i; 196 } 197 198 return 0; 199 } 200 201 EFI_SYSTEM_TABLE BackupSystemTable; 202 203 /* 204 * Entry point for RamDisk driver. 205 */ 206 207 EFI_STATUS InitializeRamDiskDriver( 208 IN EFI_HANDLE ImageHandle, 209 IN EFI_SYSTEM_TABLE *SystemTable) 210 { 211 EFI_STATUS Status; 212 RAM_DISK_DEV *RamDiskDev; 213 UINT32 RamDiskSize; 214 UINT32 NumPages; 215 UINT32 BlockSize; 216 UINT64 DiskId; 217 218 /* 219 * Make a copy of the system table to workaround load command bug 220 */ 221 CopyMem(&BackupSystemTable,SystemTable,sizeof(BackupSystemTable)); 222 223 /* 224 * Initialize EFI library 225 */ 226 //InitializeLib(ImageHandle,&BackupSystemTable); 227 228 /* IA64 compiler is removing version string (unused?) so I use it */ 229 //v[0] = 'v'; 230 231 /* 232 * Set the disk size 233 */ 234 RamDiskSize = GetDiskSize(ImageHandle); 235 BlockSize = 512; 236 237 /* Allocate storage for ramdisk device info on the heap. 238 */ 239 RamDiskDev = AllocateZeroPool(sizeof(RAM_DISK_DEV)); 240 if(RamDiskDev == NULL) 241 return EFI_OUT_OF_RESOURCES; 242 243 /* 244 * Compute the number of 4KB pages needed by the ramdisk and allocate the memory. 245 */ 246 NumPages = RamDiskSize / EFI_PAGE_SIZE; 247 if(NumPages % RamDiskSize) 248 NumPages++; 249 250 Status = gBS->AllocatePages(AllocateAnyPages,EfiBootServicesData,NumPages,&RamDiskDev->Start); 251 if(EFI_ERROR(Status)) { 252 FreePool(RamDiskDev); 253 return Status; 254 } 255 256 /* 257 * Initialize the ramdisk's device info. 258 */ 259 (void)gBS->GetNextMonotonicCount(&DiskId); 260 CopyMem(&RamDiskDevicePath.DiskId, &DiskId, sizeof(DiskId)); 261 262 RamDiskDev->Signature = PBLOCK_DEVICE_SIGNATURE; 263 RamDiskDev->BlkIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION; 264 RamDiskDev->BlkIo.Media = &RamDiskDev->Media; 265 RamDiskDev->Media.RemovableMedia = FALSE; 266 RamDiskDev->Media.MediaPresent = TRUE; 267 268 RamDiskDev->Media.LastBlock = RamDiskSize/BlockSize - 1; 269 RamDiskDev->Media.BlockSize = BlockSize; 270 RamDiskDev->Media.LogicalPartition = TRUE; 271 RamDiskDev->Media.ReadOnly = FALSE; 272 RamDiskDev->Media.WriteCaching = TRUE; 273 274 RamDiskDev->BlkIo.ReadBlocks = RamDiskReadBlocks; 275 RamDiskDev->BlkIo.WriteBlocks = RamDiskWriteBlocks; 276 RamDiskDev->BlkIo.FlushBlocks = RamDiskFlushBlocks; 277 278 RamDiskDev->DevicePath = DuplicateDevicePath((EFI_DEVICE_PATH*)&RamDiskDevicePath); 279 280 /* 281 * Build a FAT16 file system on the ramdisk. 282 */ 283 FormatRamdisk((VOID*)(UINTN)RamDiskDev->Start,RamDiskSize); 284 285 /* 286 * Install the device. 287 */ 288 289 Status = gBS->InstallMultipleProtocolInterfaces( 290 &ImageHandle, 291 &gEfiBlockIoProtocolGuid, 292 &RamDiskDev->BlkIo, 293 &gEfiDevicePathProtocolGuid, 294 RamDiskDev->DevicePath, 295 NULL); 296 297 DEBUG((EFI_D_ERROR,"ramdisk:blckio install. Status=%r\n",Status)); 298 return Status; 299 } 300 301 UINT32 302 GetDiskSize( EFI_HANDLE ImageHandle ) 303 { 304 EFI_STATUS Status; 305 EFI_LOADED_IMAGE *Image; 306 UINT32 DiskSize = PcdGet32(PcdRamDiskMaxSize); 307 308 /* 309 * Check load options to see if they want to specify disk size in MBs 310 */ 311 Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&Image); 312 if (!EFI_ERROR(Status)) { 313 if (Image->LoadOptions && Image->LoadOptionsSize) { 314 #define MAX_ARG_SIZE 32 315 CHAR16 Size[ MAX_ARG_SIZE ]; 316 CHAR16 *CmdLine = Image->LoadOptions; 317 INT32 CmdLen = (INT32)Image->LoadOptionsSize; 318 319 /* 320 * Get past program name 321 */ 322 while( CmdLen > 0 && *CmdLine != L' ' ) { 323 CmdLen -= sizeof(CHAR16); 324 CmdLine++; 325 } 326 327 if ( CmdLen > 0 ) { 328 /* 329 * Make sure we're null terminated 330 */ 331 CopyMem( Size, CmdLine, MIN(CmdLen, (INT32)sizeof(Size))); 332 Size[MAX_ARG_SIZE - 1] = 0; 333 334 /* 335 * Atoi() will skip any leading white space 336 */ 337 DiskSize = (UINT32)StrDecimalToUintn(Size); 338 if (DiskSize == 0) 339 DiskSize = PcdGet32(PcdRamDiskMaxSize); 340 DiskSize = MAX(DiskSize, MIN_DISK_SIZE); 341 DiskSize = MIN(DiskSize, MAX_DISK_SIZE); 342 } 343 } 344 } 345 346 return (DiskSize * 1024 * 1024); 347 } 348 349 /* Given a block of memory representing a ramdisk, build a pseudo-boot sector 350 * and initialize the drive. 351 * 352 * Assumes the global boot sector structure g_bs has been filled out with the 353 * static information the boot sector requires. Also assumes the ramdisk size 354 * is between 4.1MB and 512MB as appropriate for FAT16 file system. 355 */ 356 STATIC VOID FormatRamdisk( 357 IN VOID* pStart, 358 IN UINT32 Size) 359 { 360 UINT32 TotalSectors,RootDirSectors,FatSz,tmp1,tmp2; 361 UINT8 *Fat1,*Fat2; 362 BOOTSEC g_bs; 363 364 g_bs.BS_jmpBoot[0] = 0xeb; 365 g_bs.BS_jmpBoot[1] = 0x0; 366 g_bs.BS_jmpBoot[2] = 0x90; 367 g_bs.BS_OEMName[0] = 'E'; 368 g_bs.BS_OEMName[1] = 'F'; 369 g_bs.BS_OEMName[2] = 'I'; 370 g_bs.BS_OEMName[3] = 'R'; 371 g_bs.BS_OEMName[4] = 'D'; 372 g_bs.BS_OEMName[5] = 'I'; 373 g_bs.BS_OEMName[6] = 'S'; 374 g_bs.BS_OEMName[7] = 'K'; 375 g_bs.BPB_BytsPerSec = 512; 376 g_bs.BPB_SecPerClus = 0; 377 g_bs.BPB_RsvdSecCnt = 1; 378 g_bs.BPB_NumFATs = 2; 379 g_bs.BPB_RootEntCnt = 512; 380 g_bs.BPB_TotSec16 = 0; 381 g_bs.BPB_Media = 0xF8; 382 g_bs.BPB_FATSz16 = 0; 383 g_bs.BPB_SecPerTrk = 0; 384 g_bs.BPB_NumHeads = 0; 385 g_bs.BPB_HiddSec = 0; 386 g_bs.BPB_TotSec32 = 0; 387 g_bs.BS_DrvNum = 0; 388 g_bs.BS_Reserved1 = 0; 389 g_bs.BS_BootSig = 0x29; 390 g_bs.BS_VolID = 0; 391 g_bs.BS_VolLab[0] = 'N'; 392 g_bs.BS_VolLab[1] = 'O'; 393 g_bs.BS_VolLab[2] = ' '; 394 g_bs.BS_VolLab[3] = 'N'; 395 g_bs.BS_VolLab[4] = 'A'; 396 g_bs.BS_VolLab[5] = 'M'; 397 g_bs.BS_VolLab[6] = 'E'; 398 g_bs.BS_VolLab[7] = ' '; 399 g_bs.BS_VolLab[8] = ' '; 400 g_bs.BS_FilSysType[0] = 'F'; 401 g_bs.BS_FilSysType[1] = 'A'; 402 g_bs.BS_FilSysType[2] = 'T'; 403 g_bs.BS_FilSysType[3] = '1'; 404 g_bs.BS_FilSysType[4] = '6'; 405 g_bs.BS_FilSysType[5] = ' '; 406 g_bs.BS_FilSysType[6] = ' '; 407 g_bs.BS_FilSysType[7] = ' '; 408 /* The boot signature needs to be filled out */ 409 g_bs.BS_Sig = 0xAA55; 410 411 /* Compute the total sectors and appropriate cluster size */ 412 TotalSectors = Size / g_bs.BPB_BytsPerSec; 413 g_bs.BPB_SecPerClus = size2spc(TotalSectors); 414 ASSERT(g_bs.BPB_SecPerClus != 0); 415 416 /* Compute how many root directory sectors are needed */ 417 RootDirSectors = (g_bs.BPB_RootEntCnt * 32 + g_bs.BPB_BytsPerSec - 1) / g_bs.BPB_BytsPerSec; 418 419 /* Compute how many sectors are required per FAT */ 420 tmp1 = TotalSectors - (g_bs.BPB_RsvdSecCnt + RootDirSectors); 421 tmp2 = 256 * g_bs.BPB_SecPerClus + g_bs.BPB_NumFATs; 422 FatSz = (tmp1 + tmp2 - 1) / tmp2; 423 ASSERT(FatSz <= 0xFFFF); 424 425 /* Store the total sectors and fat size values */ 426 if(TotalSectors > 0xFFFF) 427 g_bs.BPB_TotSec32 = TotalSectors; 428 else 429 g_bs.BPB_TotSec16 = (UINT16)TotalSectors; 430 431 g_bs.BPB_FATSz16 = (UINT16)FatSz; 432 433 /* The FAT table and root directory need to be all zeroes. 434 * We'll zero the whole drive. 435 */ 436 ZeroMem(pStart,Size); 437 438 /* Write the completed boot sector to the ramdisk */ 439 CopyMem(pStart,&g_bs,512); 440 441 /* Compute the starting offsets of the two FATs */ 442 Fat1 = (UINT8*)pStart + g_bs.BPB_RsvdSecCnt * 512; 443 Fat2 = (UINT8*)pStart + (UINTN)(g_bs.BPB_RsvdSecCnt + FatSz) * 512; 444 445 /* Initialize FAT1 */ 446 Fat1[0] = g_bs.BPB_Media; 447 Fat1[1] = 0xFF; 448 Fat1[2] = 0xFF; 449 Fat1[3] = 0xFF; 450 451 /* Initialize FAT2 */ 452 Fat2[0] = g_bs.BPB_Media; 453 Fat2[1] = 0xFF; 454 Fat2[2] = 0xFF; 455 Fat2[3] = 0xFF; 456 } 457 458 /* Implementation of block I/O read */ 459 STATIC EFI_STATUS RamDiskReadBlocks( 460 IN EFI_BLOCK_IO *This, 461 IN UINT32 MediaId, 462 IN EFI_LBA LBA, 463 IN UINTN BufferSize, 464 OUT VOID *Buffer) 465 { 466 EFI_BLOCK_IO_MEDIA *Media; 467 RAM_DISK_DEV *RamDiskDev; 468 EFI_PHYSICAL_ADDRESS RamDiskLBA; 469 470 Media = This->Media; 471 472 if(BufferSize % Media->BlockSize != 0) 473 return EFI_BAD_BUFFER_SIZE; 474 475 if(LBA > Media->LastBlock) 476 return EFI_DEVICE_ERROR; 477 478 if(LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock) 479 return EFI_DEVICE_ERROR; 480 481 RamDiskDev = RAM_DISK_FROM_THIS(This); 482 RamDiskLBA = RamDiskDev->Start + MultU64x32(LBA,Media->BlockSize); 483 CopyMem(Buffer,(VOID*)(UINTN)RamDiskLBA,BufferSize); 484 485 return EFI_SUCCESS; 486 } 487 488 489 /* Implementation of block I/O write */ 490 STATIC EFI_STATUS RamDiskWriteBlocks( 491 IN EFI_BLOCK_IO *This, 492 IN UINT32 MediaId, 493 IN EFI_LBA LBA, 494 IN UINTN BufferSize, 495 IN VOID *Buffer) 496 { 497 EFI_BLOCK_IO_MEDIA *Media; 498 RAM_DISK_DEV *RamDiskDev; 499 EFI_PHYSICAL_ADDRESS RamDiskLBA; 500 501 Media = This->Media; 502 if(Media->ReadOnly) 503 return EFI_WRITE_PROTECTED; 504 505 if(BufferSize % Media->BlockSize != 0) 506 return EFI_BAD_BUFFER_SIZE; 507 508 if(LBA > Media->LastBlock) 509 return EFI_DEVICE_ERROR; 510 511 if(LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock) 512 return EFI_DEVICE_ERROR; 513 514 RamDiskDev = RAM_DISK_FROM_THIS(This); 515 RamDiskLBA = RamDiskDev->Start + MultU64x32(LBA,Media->BlockSize); 516 CopyMem((VOID*)(UINTN)RamDiskLBA,Buffer,BufferSize); 517 518 return EFI_SUCCESS; 519 } 520 521 /* Implementation of block I/O flush */ 522 STATIC EFI_STATUS RamDiskFlushBlocks( 523 IN EFI_BLOCK_IO *This) 524 { 525 return EFI_SUCCESS; 526 } 527