1/** @file
2Common basic Library Functions
3
4Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include <stdio.h>
16#include <string.h>
17#include <stdlib.h>
18#include <ctype.h>
19#ifdef __GNUC__
20#include <unistd.h>
21#else
22#include <direct.h>
23#endif
24#include "CommonLib.h"
25#include "EfiUtilityMsgs.h"
26
27VOID
28PeiZeroMem (
29  IN VOID   *Buffer,
30  IN UINTN  Size
31  )
32/*++
33
34Routine Description:
35
36  Set Buffer to zero for Size bytes.
37
38Arguments:
39
40  Buffer  - Memory to set.
41
42  Size    - Number of bytes to set
43
44Returns:
45
46  None
47
48--*/
49{
50  INT8  *Ptr;
51
52  Ptr = Buffer;
53  while (Size--) {
54    *(Ptr++) = 0;
55  }
56}
57
58VOID
59PeiCopyMem (
60  IN VOID   *Destination,
61  IN VOID   *Source,
62  IN UINTN  Length
63  )
64/*++
65
66Routine Description:
67
68  Copy Length bytes from Source to Destination.
69
70Arguments:
71
72  Destination - Target of copy
73
74  Source      - Place to copy from
75
76  Length      - Number of bytes to copy
77
78Returns:
79
80  None
81
82--*/
83{
84  CHAR8 *Destination8;
85  CHAR8 *Source8;
86
87  Destination8  = Destination;
88  Source8       = Source;
89  while (Length--) {
90    *(Destination8++) = *(Source8++);
91  }
92}
93
94VOID
95ZeroMem (
96  IN VOID   *Buffer,
97  IN UINTN  Size
98  )
99{
100  PeiZeroMem (Buffer, Size);
101}
102
103VOID
104CopyMem (
105  IN VOID   *Destination,
106  IN VOID   *Source,
107  IN UINTN  Length
108  )
109{
110  PeiCopyMem (Destination, Source, Length);
111}
112
113INTN
114CompareGuid (
115  IN EFI_GUID     *Guid1,
116  IN EFI_GUID     *Guid2
117  )
118/*++
119
120Routine Description:
121
122  Compares to GUIDs
123
124Arguments:
125
126  Guid1 - guid to compare
127  Guid2 - guid to compare
128
129Returns:
130  =  0  if Guid1 == Guid2
131  != 0  if Guid1 != Guid2
132
133--*/
134{
135  INT32 *g1;
136  INT32 *g2;
137  INT32 r;
138
139  //
140  // Compare 32 bits at a time
141  //
142  g1  = (INT32 *) Guid1;
143  g2  = (INT32 *) Guid2;
144
145  r   = g1[0] - g2[0];
146  r |= g1[1] - g2[1];
147  r |= g1[2] - g2[2];
148  r |= g1[3] - g2[3];
149
150  return r;
151}
152
153
154EFI_STATUS
155GetFileImage (
156  IN CHAR8    *InputFileName,
157  OUT CHAR8   **InputFileImage,
158  OUT UINT32  *BytesRead
159  )
160/*++
161
162Routine Description:
163
164  This function opens a file and reads it into a memory buffer.  The function
165  will allocate the memory buffer and returns the size of the buffer.
166
167Arguments:
168
169  InputFileName     The name of the file to read.
170  InputFileImage    A pointer to the memory buffer.
171  BytesRead         The size of the memory buffer.
172
173Returns:
174
175  EFI_SUCCESS              The function completed successfully.
176  EFI_INVALID_PARAMETER    One of the input parameters was invalid.
177  EFI_ABORTED              An error occurred.
178  EFI_OUT_OF_RESOURCES     No resource to complete operations.
179
180--*/
181{
182  FILE    *InputFile;
183  UINT32  FileSize;
184
185  //
186  // Verify input parameters.
187  //
188  if (InputFileName == NULL || strlen (InputFileName) == 0 || InputFileImage == NULL) {
189    return EFI_INVALID_PARAMETER;
190  }
191  //
192  // Open the file and copy contents into a memory buffer.
193  //
194  //
195  // Open the file
196  //
197  InputFile = fopen (LongFilePath (InputFileName), "rb");
198  if (InputFile == NULL) {
199    Error (NULL, 0, 0001, "Error opening the input file", InputFileName);
200    return EFI_ABORTED;
201  }
202  //
203  // Go to the end so that we can determine the file size
204  //
205  if (fseek (InputFile, 0, SEEK_END)) {
206    Error (NULL, 0, 0004, "Error reading the input file", InputFileName);
207    fclose (InputFile);
208    return EFI_ABORTED;
209  }
210  //
211  // Get the file size
212  //
213  FileSize = ftell (InputFile);
214  if (FileSize == -1) {
215    Error (NULL, 0, 0003, "Error parsing the input file", InputFileName);
216    fclose (InputFile);
217    return EFI_ABORTED;
218  }
219  //
220  // Allocate a buffer
221  //
222  *InputFileImage = malloc (FileSize);
223  if (*InputFileImage == NULL) {
224    fclose (InputFile);
225    return EFI_OUT_OF_RESOURCES;
226  }
227  //
228  // Reset to the beginning of the file
229  //
230  if (fseek (InputFile, 0, SEEK_SET)) {
231    Error (NULL, 0, 0004, "Error reading the input file", InputFileName);
232    fclose (InputFile);
233    free (*InputFileImage);
234    *InputFileImage = NULL;
235    return EFI_ABORTED;
236  }
237  //
238  // Read all of the file contents.
239  //
240  *BytesRead = fread (*InputFileImage, sizeof (UINT8), FileSize, InputFile);
241  if (*BytesRead != sizeof (UINT8) * FileSize) {
242    Error (NULL, 0, 0004, "Error reading the input file", InputFileName);
243    fclose (InputFile);
244    free (*InputFileImage);
245    *InputFileImage = NULL;
246    return EFI_ABORTED;
247  }
248  //
249  // Close the file
250  //
251  fclose (InputFile);
252
253  return EFI_SUCCESS;
254}
255
256EFI_STATUS
257PutFileImage (
258  IN CHAR8    *OutputFileName,
259  IN CHAR8    *OutputFileImage,
260  IN UINT32   BytesToWrite
261  )
262/*++
263
264Routine Description:
265
266  This function opens a file and writes OutputFileImage into the file.
267
268Arguments:
269
270  OutputFileName     The name of the file to write.
271  OutputFileImage    A pointer to the memory buffer.
272  BytesToWrite       The size of the memory buffer.
273
274Returns:
275
276  EFI_SUCCESS              The function completed successfully.
277  EFI_INVALID_PARAMETER    One of the input parameters was invalid.
278  EFI_ABORTED              An error occurred.
279  EFI_OUT_OF_RESOURCES     No resource to complete operations.
280
281--*/
282{
283  FILE    *OutputFile;
284  UINT32  BytesWrote;
285
286  //
287  // Verify input parameters.
288  //
289  if (OutputFileName == NULL || strlen (OutputFileName) == 0 || OutputFileImage == NULL) {
290    return EFI_INVALID_PARAMETER;
291  }
292  //
293  // Open the file and copy contents into a memory buffer.
294  //
295  //
296  // Open the file
297  //
298  OutputFile = fopen (LongFilePath (OutputFileName), "wb");
299  if (OutputFile == NULL) {
300    Error (NULL, 0, 0001, "Error opening the output file", OutputFileName);
301    return EFI_ABORTED;
302  }
303
304  //
305  // Write all of the file contents.
306  //
307  BytesWrote = fwrite (OutputFileImage, sizeof (UINT8), BytesToWrite, OutputFile);
308  if (BytesWrote != sizeof (UINT8) * BytesToWrite) {
309    Error (NULL, 0, 0002, "Error writing the output file", OutputFileName);
310    fclose (OutputFile);
311    return EFI_ABORTED;
312  }
313  //
314  // Close the file
315  //
316  fclose (OutputFile);
317
318  return EFI_SUCCESS;
319}
320
321UINT8
322CalculateChecksum8 (
323  IN UINT8        *Buffer,
324  IN UINTN        Size
325  )
326/*++
327
328Routine Description:
329
330  This function calculates the value needed for a valid UINT8 checksum
331
332Arguments:
333
334  Buffer      Pointer to buffer containing byte data of component.
335  Size        Size of the buffer
336
337Returns:
338
339  The 8 bit checksum value needed.
340
341--*/
342{
343  return (UINT8) (0x100 - CalculateSum8 (Buffer, Size));
344}
345
346UINT8
347CalculateSum8 (
348  IN UINT8  *Buffer,
349  IN UINTN  Size
350  )
351/*++
352
353Routine Description::
354
355  This function calculates the UINT8 sum for the requested region.
356
357Arguments:
358
359  Buffer      Pointer to buffer containing byte data of component.
360  Size        Size of the buffer
361
362Returns:
363
364  The 8 bit checksum value needed.
365
366--*/
367{
368  UINTN Index;
369  UINT8 Sum;
370
371  Sum = 0;
372
373  //
374  // Perform the byte sum for buffer
375  //
376  for (Index = 0; Index < Size; Index++) {
377    Sum = (UINT8) (Sum + Buffer[Index]);
378  }
379
380  return Sum;
381}
382
383UINT16
384CalculateChecksum16 (
385  IN UINT16       *Buffer,
386  IN UINTN        Size
387  )
388/*++
389
390Routine Description::
391
392  This function calculates the value needed for a valid UINT16 checksum
393
394Arguments:
395
396  Buffer      Pointer to buffer containing byte data of component.
397  Size        Size of the buffer
398
399Returns:
400
401  The 16 bit checksum value needed.
402
403--*/
404{
405  return (UINT16) (0x10000 - CalculateSum16 (Buffer, Size));
406}
407
408UINT16
409CalculateSum16 (
410  IN UINT16       *Buffer,
411  IN UINTN        Size
412  )
413/*++
414
415Routine Description:
416
417  This function calculates the UINT16 sum for the requested region.
418
419Arguments:
420
421  Buffer      Pointer to buffer containing byte data of component.
422  Size        Size of the buffer
423
424Returns:
425
426  The 16 bit checksum
427
428--*/
429{
430  UINTN   Index;
431  UINT16  Sum;
432
433  Sum = 0;
434
435  //
436  // Perform the word sum for buffer
437  //
438  for (Index = 0; Index < Size; Index++) {
439    Sum = (UINT16) (Sum + Buffer[Index]);
440  }
441
442  return (UINT16) Sum;
443}
444
445EFI_STATUS
446PrintGuid (
447  IN EFI_GUID *Guid
448  )
449/*++
450
451Routine Description:
452
453  This function prints a GUID to STDOUT.
454
455Arguments:
456
457  Guid    Pointer to a GUID to print.
458
459Returns:
460
461  EFI_SUCCESS             The GUID was printed.
462  EFI_INVALID_PARAMETER   The input was NULL.
463
464--*/
465{
466  if (Guid == NULL) {
467    Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value");
468    return EFI_INVALID_PARAMETER;
469  }
470
471  printf (
472    "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
473    (unsigned) Guid->Data1,
474    Guid->Data2,
475    Guid->Data3,
476    Guid->Data4[0],
477    Guid->Data4[1],
478    Guid->Data4[2],
479    Guid->Data4[3],
480    Guid->Data4[4],
481    Guid->Data4[5],
482    Guid->Data4[6],
483    Guid->Data4[7]
484    );
485  return EFI_SUCCESS;
486}
487
488EFI_STATUS
489PrintGuidToBuffer (
490  IN EFI_GUID     *Guid,
491  IN OUT UINT8    *Buffer,
492  IN UINT32       BufferLen,
493  IN BOOLEAN      Uppercase
494  )
495/*++
496
497Routine Description:
498
499  This function prints a GUID to a buffer
500
501Arguments:
502
503  Guid      - Pointer to a GUID to print.
504  Buffer    - Pointer to a user-provided buffer to print to
505  BufferLen - Size of the Buffer
506  Uppercase - If use upper case.
507
508Returns:
509
510  EFI_SUCCESS             The GUID was printed.
511  EFI_INVALID_PARAMETER   The input was NULL.
512  EFI_BUFFER_TOO_SMALL    The input buffer was not big enough
513
514--*/
515{
516  if (Guid == NULL) {
517    Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value");
518    return EFI_INVALID_PARAMETER;
519  }
520
521  if (BufferLen < PRINTED_GUID_BUFFER_SIZE) {
522    Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with invalid buffer size");
523    return EFI_BUFFER_TOO_SMALL;
524  }
525
526  if (Uppercase) {
527    sprintf (
528      (CHAR8 *)Buffer,
529      "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
530      (unsigned) Guid->Data1,
531      Guid->Data2,
532      Guid->Data3,
533      Guid->Data4[0],
534      Guid->Data4[1],
535      Guid->Data4[2],
536      Guid->Data4[3],
537      Guid->Data4[4],
538      Guid->Data4[5],
539      Guid->Data4[6],
540      Guid->Data4[7]
541      );
542  } else {
543    sprintf (
544      (CHAR8 *)Buffer,
545      "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
546      (unsigned) Guid->Data1,
547      Guid->Data2,
548      Guid->Data3,
549      Guid->Data4[0],
550      Guid->Data4[1],
551      Guid->Data4[2],
552      Guid->Data4[3],
553      Guid->Data4[4],
554      Guid->Data4[5],
555      Guid->Data4[6],
556      Guid->Data4[7]
557      );
558  }
559
560  return EFI_SUCCESS;
561}
562
563#ifdef __GNUC__
564
565size_t _filelength(int fd)
566{
567  struct stat stat_buf;
568  fstat(fd, &stat_buf);
569  return stat_buf.st_size;
570}
571
572#ifndef __CYGWIN__
573char *strlwr(char *s)
574{
575  char *p = s;
576  for(;*s;s++) {
577    *s = tolower(*s);
578  }
579  return p;
580}
581#endif
582#endif
583
584#define WINDOWS_EXTENSION_PATH "\\\\?\\"
585#define WINDOWS_UNC_EXTENSION_PATH "\\\\?\\UNC"
586
587//
588// Global data to store full file path. It is not required to be free.
589//
590CHAR8 mCommonLibFullPath[MAX_LONG_FILE_PATH];
591
592CHAR8 *
593LongFilePath (
594 IN CHAR8 *FileName
595 )
596/*++
597
598Routine Description:
599  Convert FileName to the long file path, which can support larger than 260 length.
600
601Arguments:
602  FileName         - FileName.
603
604Returns:
605  LongFilePath      A pointer to the converted long file path.
606
607--*/
608{
609#ifdef __GNUC__
610  //
611  // __GNUC__ may not be good way to differentiate unix and windows. Need more investigation here.
612  // unix has no limitation on file path. Just return FileName.
613  //
614  return FileName;
615#else
616  CHAR8 *RootPath;
617  CHAR8 *PathPointer;
618  CHAR8 *NextPointer;
619
620  PathPointer = (CHAR8 *) FileName;
621
622  if (FileName != NULL) {
623    //
624    // Add the extension string first to support long file path.
625    //
626    mCommonLibFullPath[0] = 0;
627    strcpy (mCommonLibFullPath, WINDOWS_EXTENSION_PATH);
628
629    if (strlen (FileName) > 1 && FileName[0] == '\\' && FileName[1] == '\\') {
630      //
631      // network path like \\server\share to \\?\UNC\server\share
632      //
633      strcpy (mCommonLibFullPath, WINDOWS_UNC_EXTENSION_PATH);
634      FileName ++;
635    } else if (strlen (FileName) < 3 || FileName[1] != ':' || (FileName[2] != '\\' && FileName[2] != '/')) {
636      //
637      // Relative file path. Convert it to absolute path.
638      //
639      RootPath = getcwd (NULL, 0);
640      if (RootPath != NULL) {
641        strcat (mCommonLibFullPath, RootPath);
642        if (FileName[0] != '\\' && FileName[0] != '/') {
643          //
644          // Attach directory separator
645          //
646          strcat (mCommonLibFullPath, "\\");
647        }
648        free (RootPath);
649      }
650    }
651
652    //
653    // Construct the full file path
654    //
655    if (strlen (mCommonLibFullPath) + strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
656      Error (NULL, 0, 2000, "Invalid parameter", "FileName %s is too long!", FileName);
657      return NULL;
658    }
659    strncat (mCommonLibFullPath, FileName, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
660
661    //
662    // Convert directory separator '/' to '\\'
663    //
664    PathPointer = (CHAR8 *) mCommonLibFullPath;
665    do {
666      if (*PathPointer == '/') {
667        *PathPointer = '\\';
668      }
669    } while (*PathPointer ++ != '\0');
670
671    //
672    // Convert ":\\\\" to ":\\", because it doesn't work with WINDOWS_EXTENSION_PATH.
673    //
674    if ((PathPointer = strstr (mCommonLibFullPath, ":\\\\")) != NULL) {
675      *(PathPointer + 2) = '\0';
676      strcat (mCommonLibFullPath, PathPointer + 3);
677    }
678
679    //
680    // Convert ".\\" to "", because it doesn't work with WINDOWS_EXTENSION_PATH.
681    //
682    while ((PathPointer = strstr (mCommonLibFullPath, ".\\")) != NULL) {
683      *PathPointer = '\0';
684      strcat (mCommonLibFullPath, PathPointer + 2);
685    }
686
687    //
688    // Convert "\\.\\" to "\\", because it doesn't work with WINDOWS_EXTENSION_PATH.
689    //
690    while ((PathPointer = strstr (mCommonLibFullPath, "\\.\\")) != NULL) {
691      *PathPointer = '\0';
692      strcat (mCommonLibFullPath, PathPointer + 2);
693    }
694
695    //
696    // Convert "\\..\\" to last directory, because it doesn't work with WINDOWS_EXTENSION_PATH.
697    //
698    while ((PathPointer = strstr (mCommonLibFullPath, "\\..\\")) != NULL) {
699      NextPointer = PathPointer + 3;
700      do {
701        PathPointer --;
702      } while (PathPointer > mCommonLibFullPath && *PathPointer != ':' && *PathPointer != '\\');
703
704      if (*PathPointer == '\\') {
705        //
706        // Skip one directory
707        //
708        *PathPointer = '\0';
709        strcat (mCommonLibFullPath, NextPointer);
710      } else {
711        //
712        // No directory is found. Just break.
713        //
714        break;
715      }
716    }
717
718    PathPointer = mCommonLibFullPath;
719  }
720
721  return PathPointer;
722#endif
723}
724