blob: cb64907f8fd309ca9983e7efe4e4c1b9ffdf6bba [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/*
2 * Copyright (c) 1999, 2000
3 * Intel Corporation.
4 * All rights reserved.
5 * Copyright (c) Huawei Technologies Co., Ltd. 2013. 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/MemoryAllocationLib.h>
50
51#include <Library/DevicePathLib.h>
52#include "./ramdisk.h"
53
54#define DEFAULT_DISK_SIZE 30 /* in MBs */
55
56UINT32 GetDiskSize( EFI_HANDLE ImageHandle );
57
58/* Embedded version string for VERS utility */
59//static char v[] = "version_number=1.00 ";
60
61/* EFI device path definition */
62static RAM_DISK_DEVICE_PATH RamDiskDevicePath =
63{
64 {
65 MESSAGING_DEVICE_PATH,
66 MSG_VENDOR_DP,
67 {
68 sizeof(RAM_DISK_DEVICE_PATH) - END_DEVICE_PATH_LENGTH,
69 0
70 },
71 },
72 // {06ED4DD0-FF78-11d3-BDC4-00A0C94053D1}
73 {
74 0x6ed4dd0, 0xff78, 0x11d3,
75 {0xbd, 0xc4, 0x0, 0xa0, 0xc9, 0x40, 0x53, 0xd1},
76 },
77 {0,0,0,0,0,0,0,0}, // ID assigned below
78 {
79 END_DEVICE_PATH_TYPE,
80 END_ENTIRE_DEVICE_PATH_SUBTYPE,
81 {
82 END_DEVICE_PATH_LENGTH,
83 0
84 },
85 },
86};
87
88/* Lookup table of total sectors vs. cluster size.
89 * Ramdisk sizes between 0x20D0 (4.1MB) and 0x100000 (512MB) sectors are valid FAT16 drive sizes.
90 */
91/* #define MIN_DISK_SIZE 5 */
92#define MIN_DISK_SIZE 1
93#define MAX_DISK_SIZE 512
94static FAT16TABLE fat16tbl[] =
95{
96 /* {0x000020D0, 0}, */
97 {0x00000800, 1}, /* 800 sectors * 1 sec/cluster * 512 bytes = 1 M */
98 {0x00001000, 1}, /* 1000 sectors * 1 sec/cluster * 512 bytes = 2 M */
99 {0x00001800, 1}, /* 1800 sectors * 1 sec/cluster * 512 bytes = 3 M */
100 {0x00007FA8, 2},
101 {0x00040000, 4},
102 {0x00080000, 8},
103 {0x00100000,16},
104 {0xFFFFFFFF, 0}
105};
106
107VOID CopyBOOTSEC(VOID* Start,BOOTSEC* bsc)
108{
109UINT32 index=0;
110UINT8* pStart=(UINT8*)Start;
111
112CopyMem(&(pStart[index]), &(bsc->BS_jmpBoot[0]), sizeof(bsc->BS_jmpBoot));
113index+=sizeof(bsc->BS_jmpBoot);
114
115CopyMem(&(pStart[index]), &(bsc->BS_OEMName[0]), sizeof(bsc->BS_OEMName));
116index+=sizeof(bsc->BS_OEMName);
117
118CopyMem(&(pStart[index]), &(bsc->BPB_BytsPerSec), sizeof(bsc->BPB_BytsPerSec));
119index+=sizeof(bsc->BPB_BytsPerSec);
120
121CopyMem(&(pStart[index]), &(bsc->BPB_SecPerClus), sizeof(bsc->BPB_SecPerClus));
122index+=sizeof(bsc->BPB_SecPerClus);
123
124CopyMem(&(pStart[index]), &(bsc->BPB_RsvdSecCnt), sizeof(bsc->BPB_RsvdSecCnt));
125index+=sizeof(bsc->BPB_RsvdSecCnt);
126
127CopyMem(&(pStart[index]), &(bsc->BPB_NumFATs), sizeof(bsc->BPB_NumFATs));
128index+=sizeof(bsc->BPB_NumFATs);
129
130CopyMem(&(pStart[index]), &(bsc->BPB_NumFATs), sizeof(bsc->BPB_NumFATs));
131index+=sizeof(bsc->BPB_NumFATs);
132
133CopyMem(&(pStart[index]), &(bsc->BPB_RootEntCnt), sizeof(bsc->BPB_RootEntCnt));
134index+=sizeof(bsc->BPB_RootEntCnt);
135
136CopyMem(&(pStart[index]), &(bsc->BPB_TotSec16), sizeof(bsc->BPB_TotSec16));
137index+=sizeof(bsc->BPB_TotSec16);
138
139CopyMem(&(pStart[index]), &(bsc->BPB_Media), sizeof(bsc->BPB_Media));
140index+=sizeof(bsc->BPB_Media);
141
142CopyMem(&(pStart[index]), &(bsc->BPB_FATSz16), sizeof(bsc->BPB_FATSz16));
143index+=sizeof(bsc->BPB_FATSz16);
144
145CopyMem(&(pStart[index]), &(bsc->BPB_SecPerTrk), sizeof(bsc->BPB_SecPerTrk));
146index+=sizeof(bsc->BPB_SecPerTrk);
147
148CopyMem(&(pStart[index]), &(bsc->BPB_NumHeads), sizeof(bsc->BPB_NumHeads));
149index+=sizeof(bsc->BPB_NumHeads);
150
151CopyMem(&(pStart[index]), &(bsc->BPB_HiddSec), sizeof(bsc->BPB_HiddSec));
152index+=sizeof(bsc->BPB_HiddSec);
153
154CopyMem(&(pStart[index]), &(bsc->BPB_TotSec32), sizeof(bsc->BPB_TotSec32));
155index+=sizeof(bsc->BPB_TotSec32);
156
157CopyMem(&(pStart[index]), &(bsc->BS_DrvNum), sizeof(bsc->BS_DrvNum));
158index+=sizeof(bsc->BS_DrvNum);
159
160CopyMem(&(pStart[index]), &(bsc->BS_Reserved1), sizeof(bsc->BS_Reserved1));
161index+=sizeof(bsc->BS_Reserved1);
162
163CopyMem(&(pStart[index]), &(bsc->BS_BootSig), sizeof(bsc->BS_BootSig));
164index+=sizeof(bsc->BS_BootSig);
165
166CopyMem(&(pStart[index]), &(bsc->BS_VolID), sizeof(bsc->BS_VolID));
167index+=sizeof(bsc->BS_VolID);
168
169CopyMem(&(pStart[index]), &(bsc->BS_VolLab[0]), sizeof(bsc->BS_VolLab));
170index+=sizeof(bsc->BS_VolLab);
171
172CopyMem(&(pStart[index]), &(bsc->BS_FilSysType[0]), sizeof(bsc->BS_FilSysType));
173index+=sizeof(bsc->BS_FilSysType);
174
175CopyMem(&(pStart[index]), &(bsc->BS_Code[0]), sizeof(bsc->BS_Code));
176index+=sizeof(bsc->BS_Code);
177
178CopyMem(&(pStart[index]), &(bsc->BS_Sig), sizeof(bsc->BS_Sig));
179
180}
181
182/*++
183
184Routine Description:
185
186 Convert hex string to uint
187
188Arguments:
189
190 Str - The string
191
192Returns:
193
194--*/
195STATIC UINTN Atoi ( CHAR16 *str)
196{
197 UINTN u;
198 CHAR16 c;
199 UINTN m;
200 UINTN n;
201
202 ASSERT (str != NULL);
203
204 m = (UINTN) -1 / 10;
205 n = (UINTN) -1 % 10;
206 //
207 // skip preceeding white space
208 //
209 while (*str && (*str == ' '))
210 {
211 str += 1;
212 }
213 //
214 // convert digits
215 //
216 u = 0;
217 c = *(str++);
218 while (c)
219 {
220 if ((c >= '0') && (c <= '9'))
221 {
222 if ((u >= m) && ((c - '0') > (INTN) n))
223 {
224 return (UINTN) -1;
225 }
226
227 u = (u * 10) + c - '0';
228 }
229 else
230 {
231 break;
232 }
233
234 c = *(str++);
235 }
236
237 return u;
238}
239
240/* Helper function to compute cluster size
241 * vs. total sectors on drive.
242 */
243STATIC UINT8 size2spc(UINT32 ts)
244{
245 int i = 0;
246
247 while(fat16tbl[i].size != 0xFFFFFFFF)
248 {
249 if(ts <= fat16tbl[i].size)
250 return fat16tbl[i].spc;
251 ++i;
252 }
253
254 return 0;
255}
256
257UINT8 TestSize(UINT32 ts)
258{
259 int i = 0;
260
261 while(fat16tbl[i].size != 0xFFFFFFFF)
262 {
263 if(ts <= fat16tbl[i].size)
264 return fat16tbl[i].spc;
265 ++i;
266 }
267
268 return 0;
269}
270
271EFI_SYSTEM_TABLE BackupSystemTable;
272
273/*
274 * Entry point for RamDisk driver.
275 */
276
277EFI_STATUS InitializeRamDiskDriver(
278 IN EFI_HANDLE ImageHandle,
279 IN EFI_SYSTEM_TABLE *SystemTable)
280{
281 EFI_STATUS Status;
282 RAM_DISK_DEV *RamDiskDev;
283 UINT32 RamDiskSize;
284 UINT32 NumPages;
285 UINT32 BlockSize;
286 UINT64 DiskId;
287
288 /*
289 * Make a copy of the system table to workaround load command bug
290 */
291 CopyMem(&BackupSystemTable,SystemTable,sizeof(BackupSystemTable));
292
293 /*
294 * Initialize EFI library
295 */
296 //InitializeLib(ImageHandle,&BackupSystemTable);
297
298 /* IA64 compiler is removing version string (unused?) so I use it */
299 //v[0] = 'v';
300
301 /*
302 * Set the disk size
303 */
304 RamDiskSize = GetDiskSize(ImageHandle);
305 BlockSize = 512;
306
307 /* Allocate storage for ramdisk device info on the heap.
308 */
309 RamDiskDev = AllocateZeroPool(sizeof(RAM_DISK_DEV));
310 if(RamDiskDev == NULL)
311 return EFI_OUT_OF_RESOURCES;
312
313 /*
314 * Compute the number of 4KB pages needed by the ramdisk and allocate the memory.
315 */
316 NumPages = RamDiskSize / EFI_PAGE_SIZE;
317 if(NumPages % RamDiskSize)
318 NumPages++;
319
320 Status = gBS->AllocatePages(AllocateAnyPages,EfiBootServicesData,NumPages,&RamDiskDev->Start);
321 if(EFI_ERROR(Status)) {
322 FreePool(RamDiskDev);
323 return Status;
324 }
325
326 /*
327 * Initialize the ramdisk's device info.
328 */
329 (void)gBS->GetNextMonotonicCount(&DiskId);
330 CopyMem(&RamDiskDevicePath.DiskId, &DiskId, sizeof(DiskId));
331
332 RamDiskDev->Signature = PBLOCK_DEVICE_SIGNATURE;
333 RamDiskDev->BlkIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;
334 RamDiskDev->BlkIo.Media = &RamDiskDev->Media;
335 RamDiskDev->Media.RemovableMedia = FALSE;
336 RamDiskDev->Media.MediaPresent = TRUE;
337
338 RamDiskDev->Media.LastBlock = RamDiskSize/BlockSize - 1;
339 RamDiskDev->Media.BlockSize = BlockSize;
340 RamDiskDev->Media.LogicalPartition = TRUE;
341 RamDiskDev->Media.ReadOnly = FALSE;
342 RamDiskDev->Media.WriteCaching = TRUE;
343
344 RamDiskDev->BlkIo.ReadBlocks = RamDiskReadBlocks;
345 RamDiskDev->BlkIo.WriteBlocks = RamDiskWriteBlocks;
346 RamDiskDev->BlkIo.FlushBlocks = RamDiskFlushBlocks;
347
348 RamDiskDev->DevicePath = DuplicateDevicePath((EFI_DEVICE_PATH*)&RamDiskDevicePath);
349
350 /*
351 * Build a FAT16 file system on the ramdisk.
352 */
353 FormatRamdisk((VOID*)(UINTN)RamDiskDev->Start,RamDiskSize);
354
355 /*
356 * Install the device.
357 */
358
359 Status = gBS->InstallMultipleProtocolInterfaces(
360 &ImageHandle,
361 &gEfiBlockIoProtocolGuid,
362 &RamDiskDev->BlkIo,
363 &gEfiDevicePathProtocolGuid,
364 RamDiskDev->DevicePath,
365 NULL);
366
367DEBUG((EFI_D_ERROR,"ramdisk:blckio install. Status=%r\n",Status));
368 return Status;
369}
370
371UINT32
372GetDiskSize( EFI_HANDLE ImageHandle )
373{
374 EFI_STATUS Status;
375 EFI_LOADED_IMAGE *Image;
376 UINT32 DiskSize = DEFAULT_DISK_SIZE;
377
378 /*
379 * Check load options to see if they want to specify disk size in MBs
380 */
381 Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&Image);
382 if (!EFI_ERROR(Status)) {
383 if (Image->LoadOptions && Image->LoadOptionsSize) {
384#define MAX_ARG_SIZE 32
385 CHAR16 Size[ MAX_ARG_SIZE ];
386 CHAR16 *CmdLine = Image->LoadOptions;
387 INT32 CmdLen = (INT32)Image->LoadOptionsSize;
388
389 /*
390 * Get past program name
391 */
392 while( CmdLen > 0 && *CmdLine != L' ' ) {
393 CmdLen -= sizeof(CHAR16);
394 CmdLine++;
395 }
396
397 if ( CmdLen > 0 ) {
398 /*
399 * Make sure we're null terminated
400 */
401 CopyMem( Size, CmdLine, MIN(CmdLen, sizeof(Size)));
402 Size[MAX_ARG_SIZE - 1] = 0;
403
404 /*
405 * Atoi() will skip any leading white space
406 */
407 DiskSize = (UINT32)Atoi(Size);
408 if (DiskSize == 0)
409 DiskSize = DEFAULT_DISK_SIZE;
410 DiskSize = MAX(DiskSize, MIN_DISK_SIZE);
411 DiskSize = MIN(DiskSize, MAX_DISK_SIZE);
412 }
413 }
414 }
415
416 return (DiskSize * 1024 * 1024);
417}
418
419/* Given a block of memory representing a ramdisk, build a pseudo-boot sector
420 * and initialize the drive.
421 *
422 * Assumes the global boot sector structure g_bs has been filled out with the
423 * static information the boot sector requires. Also assumes the ramdisk size
424 * is between 4.1MB and 512MB as appropriate for FAT16 file system.
425 */
426STATIC VOID FormatRamdisk(
427 IN VOID* pStart,
428 IN UINT32 Size)
429{
430 UINT32 TotalSectors,RootDirSectors,FatSz,tmp1,tmp2;
431 UINT8 *Fat1,*Fat2;
432 BOOTSEC g_bs={
433 /* BS_jmpBoot */ {0xeb,0x0,0x90},
434 /* BS_OEMName */ {'E','F','I','R','D','I','S','K'},
435 /* BPB_BytsPerSec */ 512,
436 /* BPB_SecPerClus */ 0,
437 /* BPB_RsvdSecCnt */ 1,
438 /* BPB_NumFATs */ 2,
439 /* BPB_RootEntCnt */ 512,
440 /* BPB_TotSec16 */ 0,
441 /* BPB_Media */ 0xF8,
442 /* BPB_FATSz16 */ 0,
443 /* BPB_SecPerTrk */ 0,
444 /* BPB_NumHeads */ 0,
445 /* BPB_HiddSec */ 0,
446 /* BPB_TotSec32 */ 0,
447 /* BS_DrvNum */ 0,
448 /* BS_Reserved1 */ 0,
449 /* BS_BootSig */ 0x29,
450 /* BS_VolID */ 0,
451 /* BS_VolLab */ {'N','O',' ','N','A','M','E',' ',' ',' '},
452 /* BS_FilSysType */ {'F','A','T','1','6',' ',' ',' '}
453};
454
455 /* The boot signature needs to be filled out */
456 g_bs.BS_Sig = 0xAA55;
457
458 /* Compute the total sectors and appropriate cluster size */
459 TotalSectors = Size / g_bs.BPB_BytsPerSec;
460 g_bs.BPB_SecPerClus = size2spc(TotalSectors);
461 ASSERT(g_bs.BPB_SecPerClus != 0);
462
463 /* Compute how many root directory sectors are needed */
464 RootDirSectors = (g_bs.BPB_RootEntCnt * 32 + g_bs.BPB_BytsPerSec - 1) / g_bs.BPB_BytsPerSec;
465
466 /* Compute how many sectors are required per FAT */
467 tmp1 = TotalSectors - (g_bs.BPB_RsvdSecCnt + RootDirSectors);
468 tmp2 = 256 * g_bs.BPB_SecPerClus + g_bs.BPB_NumFATs;
469 FatSz = (tmp1 + tmp2 - 1) / tmp2;
470 ASSERT(FatSz <= 0xFFFF);
471
472 /* Store the total sectors and fat size values */
473 if(TotalSectors > 0xFFFF)
474 g_bs.BPB_TotSec32 = TotalSectors;
475 else
476 g_bs.BPB_TotSec16 = (UINT16)TotalSectors;
477
478 g_bs.BPB_FATSz16 = (UINT16)FatSz;
479
480 /* The FAT table and root directory need to be all zeroes.
481 * We'll zero the whole drive.
482 */
483 ZeroMem(pStart,Size);
484
485 /* Write the completed boot sector to the ramdisk */
486 CopyMem(pStart,&g_bs,512);
487
488 /* Compute the starting offsets of the two FATs */
489 Fat1 = (UINT8*)pStart + g_bs.BPB_RsvdSecCnt * 512;
490 Fat2 = (UINT8*)pStart + (g_bs.BPB_RsvdSecCnt + FatSz) * 512;
491
492 /* Initialize FAT1 */
493 Fat1[0] = g_bs.BPB_Media;
494 Fat1[1] = 0xFF;
495 Fat1[2] = 0xFF;
496 Fat1[3] = 0xFF;
497
498 /* Initialize FAT2 */
499 Fat2[0] = g_bs.BPB_Media;
500 Fat2[1] = 0xFF;
501 Fat2[2] = 0xFF;
502 Fat2[3] = 0xFF;
503}
504
505/* Implementation of block I/O read */
506STATIC EFI_STATUS RamDiskReadBlocks(
507 IN EFI_BLOCK_IO *This,
508 IN UINT32 MediaId,
509 IN EFI_LBA LBA,
510 IN UINTN BufferSize,
511 OUT VOID *Buffer)
512{
513 EFI_BLOCK_IO_MEDIA *Media;
514 RAM_DISK_DEV *RamDiskDev;
515 EFI_PHYSICAL_ADDRESS RamDiskLBA;
516
517 Media = This->Media;
518
519 if(BufferSize % Media->BlockSize != 0)
520 return EFI_BAD_BUFFER_SIZE;
521
522 if(LBA > Media->LastBlock)
523 return EFI_DEVICE_ERROR;
524
525 if(LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock)
526 return EFI_DEVICE_ERROR;
527
528 RamDiskDev = RAM_DISK_FROM_THIS(This);
529 RamDiskLBA = RamDiskDev->Start + MultU64x32(LBA,Media->BlockSize);
530 CopyMem(Buffer,(VOID*)(UINTN)RamDiskLBA,BufferSize);
531
532 return EFI_SUCCESS;
533}
534
535
536/* Implementation of block I/O write */
537STATIC EFI_STATUS RamDiskWriteBlocks(
538 IN EFI_BLOCK_IO *This,
539 IN UINT32 MediaId,
540 IN EFI_LBA LBA,
541 IN UINTN BufferSize,
542 IN VOID *Buffer)
543{
544 EFI_BLOCK_IO_MEDIA *Media;
545 RAM_DISK_DEV *RamDiskDev;
546 EFI_PHYSICAL_ADDRESS RamDiskLBA;
547
548 Media = This->Media;
549 if(Media->ReadOnly)
550 return EFI_WRITE_PROTECTED;
551
552 if(BufferSize % Media->BlockSize != 0)
553 return EFI_BAD_BUFFER_SIZE;
554
555 if(LBA > Media->LastBlock)
556 return EFI_DEVICE_ERROR;
557
558 if(LBA + BufferSize / Media->BlockSize - 1 > Media->LastBlock)
559 return EFI_DEVICE_ERROR;
560
561 RamDiskDev = RAM_DISK_FROM_THIS(This);
562 RamDiskLBA = RamDiskDev->Start + MultU64x32(LBA,Media->BlockSize);
563 CopyMem((VOID*)(UINTN)RamDiskLBA,Buffer,BufferSize);
564
565 return EFI_SUCCESS;
566}
567
568/* Implementation of block I/O flush */
569STATIC EFI_STATUS RamDiskFlushBlocks(
570 IN EFI_BLOCK_IO *This)
571{
572 return EFI_SUCCESS;
573}