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
CopyBOOTSEC(VOID * Start,BOOTSEC * bsc)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 */
size2spc(UINT32 ts)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
TestSize(UINT32 ts)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
InitializeRamDiskDriver(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
GetDiskSize(EFI_HANDLE ImageHandle)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 */
FormatRamdisk(IN VOID * pStart,IN UINT32 Size)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 */
RamDiskReadBlocks(IN EFI_BLOCK_IO * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,OUT VOID * Buffer)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 */
RamDiskWriteBlocks(IN EFI_BLOCK_IO * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN UINTN BufferSize,IN VOID * Buffer)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 */
RamDiskFlushBlocks(IN EFI_BLOCK_IO * This)522 STATIC EFI_STATUS RamDiskFlushBlocks(
523 IN EFI_BLOCK_IO *This)
524 {
525 return EFI_SUCCESS;
526 }
527