alder_lake_bios/Insyde/InsydeModulePkg/Library/StdLib/baselib.c

837 lines
19 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2012 - 2019, Insyde Software Corporation. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
/*++
This file contains a standard c library
--*/
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Portions copyright (c) 1999, 2000
* Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by the University of
* California, Berkeley, Intel Corporation, and its contributors.
*
* 4. Neither the name of University, Intel Corporation, or their respective
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS,
* INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include "StdCLibSupport.h"
//
// setjmp.h
//
void longjmp(jmp_buf env, int val)
{
LongJump(env, (UINTN)((val == 0) ? 1 : val));
}
//
// ctype.h
//
int tolower (int c)
{
if (('A' <= (c)) && ((c) <= 'Z')) {
return ((c - ('A' - 'a')));
}
return (c);
}
int
isdigit(int c)
{
return ((((c) >= '0') && ((c) <= '9')));
}
int
isalpha(int c)
{
return (((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')));
}
int
isupper(int c)
{
return ((c<='Z' && c>='A'));
}
int
isascii(int c)
{
/* c is a simulated unsigned integer */
return ((c <= 127));
}
int
isspace(int c) {
return ((c<=' ' && (c==' ' || (c<=13 && c>=9))));
}
//
// stdlib.h
//
int
abs(int j)
{
return(j < 0 ? -j : j);
}
void *
calloc(size_t NMemb, size_t MembSize )
{
return AllocateZeroPool (NMemb * MembSize);
}
void
free (void *buf) {
ASSERT (buf != NULL);
FreePool (buf);
}
void *
malloc(
size_t Size
)
{
return AllocatePool ((UINTN) Size);
}
long int
labs (long int i)
{
return i < 0 ? -i : i;
}
//
// Duplicated from EDKII BaseSortLib for qsort() wrapper
//
typedef
int
(*SORT_COMPARE2)(
IN VOID *Buffer1,
IN VOID *Buffer2
);
STATIC
VOID
QuickSortWorker (
IN OUT VOID *BufferToSort,
IN CONST UINTN Count,
IN CONST UINTN ElementSize,
IN SORT_COMPARE2 CompareFunction,
IN VOID *Buffer
)
{
VOID *Pivot;
UINTN LoopCount;
UINTN NextSwapLocation;
ASSERT(BufferToSort != NULL);
ASSERT(CompareFunction != NULL);
ASSERT(Buffer != NULL);
if (Count < 2 || ElementSize < 1) {
return;
}
NextSwapLocation = 0;
//
// Pick a pivot (we choose last element)
//
Pivot = ((UINT8 *)BufferToSort + ((Count - 1) * ElementSize));
//
// Now get the pivot such that all on "left" are below it
// and everything "right" are above it
//
for (LoopCount = 0; LoopCount < Count - 1; LoopCount++)
{
//
// If the element is less than the pivot
//
if (CompareFunction ((VOID *)((UINT8 *)BufferToSort + ((LoopCount) * ElementSize)), Pivot) <= 0) {
//
// Swap
//
CopyMem (Buffer, (UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), ElementSize);
CopyMem ((UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), (UINT8 *)BufferToSort + ((LoopCount) * ElementSize), ElementSize);
CopyMem ((UINT8 *)BufferToSort + ((LoopCount) * ElementSize), Buffer, ElementSize);
//
// Increment NextSwapLocation
//
NextSwapLocation++;
}
}
//
// Swap pivot to it's final position (NextSwapLocaiton)
//
CopyMem (Buffer, Pivot, ElementSize);
CopyMem (Pivot, (UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), ElementSize);
CopyMem ((UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), Buffer, ElementSize);
//
// Now recurse on 2 paritial lists. Neither of these will have the 'pivot' element.
// IE list is sorted left half, pivot element, sorted right half...
//
QuickSortWorker (
BufferToSort,
NextSwapLocation,
ElementSize,
CompareFunction,
Buffer
);
QuickSortWorker (
(UINT8 *)BufferToSort + (NextSwapLocation + 1) * ElementSize,
Count - NextSwapLocation - 1,
ElementSize,
CompareFunction,
Buffer
);
return;
}
/* Performs a quick sort */
void qsort (void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
{
VOID *Buffer;
ASSERT (base != NULL);
ASSERT (compare != NULL);
if ((base == NULL) || (compare == NULL)) {
return;
}
Buffer = AllocatePool (width);
ASSERT (Buffer != NULL);
//
// Re-use PerformQuickSort() function Implementation in EDKII BaseSortLib.
//
QuickSortWorker (base, (UINTN)num, (UINTN)width, (SORT_COMPARE2)compare, Buffer);
FreePool (Buffer);
return;
}
void *
realloc(
void *OldPtr,
size_t NewSize
)
{
void *NewPtr;
if (OldPtr == NULL) {
return AllocatePool (NewSize);
} else if (NewSize == 0) {
FreePool (OldPtr);
} else {
NewPtr = AllocatePool (NewSize);
if (NewPtr != NULL) {
CopyMem (NewPtr, OldPtr, NewSize);
FreePool (OldPtr);
return NewPtr;
}
}
return NULL;
}
#ifdef __GNUC__
#if !defined(MDE_CPU_ARM) && !defined(MDE_CPU_AARCH64)
VOID *
memcpy (
OUT VOID *Dest,
IN const VOID *Src,
IN UINTN Count
)
{
volatile UINT8 *Ptr;
const UINT8 *Source;
for (Ptr = Dest, Source = Src; Count > 0; Count--, Source++, Ptr++) {
*Ptr = *Source;
}
return Dest;
}
VOID *
memset (
OUT VOID *Dest,
IN int Char,
IN UINTN Count
)
{
volatile UINT8 *Ptr;
for (Ptr = Dest; Count > 0; Count--, Ptr++) {
*Ptr = (UINT8) Char;
}
return Dest;
}
#endif
#endif
#if !defined(MDE_CPU_ARM)
void *
memmove(void *dst0, const void *src0, size_t size0)
{
char *dst = (char *)dst0;
char *src = (char *)src0;
INTN size = size0;
if (size <= 0)
return dst;
if (src >= dst+size || dst >= src+size)
return memcpy(dst, src, size);
if (src > dst) {
while (--size >= 0)
*dst++ = *src++;
}
else if (src < dst) {
src += size;
dst += size;
while (--size >= 0)
*--dst = *--src;
}
return dst0;
}
#endif
char *
strcat(register char *s, register const char *append)
{
char *save = s;
for (; *s; ++s);
while ((*s++ = *append++) != 0);
return(save);
}
int
strcmp(register const char *s1, register const char *s2)
{
while (*s1 == *s2++)
if (*s1++ == 0)
return (0);
return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}
char *
strcpy(register char *to, register const char * from)
{
char *save = to;
for (; (*to = *from) != 0; ++from, ++to);
return(save);
}
size_t
strlen(const char *str)
{
register const char *s;
for (s = str; *s; ++s);
return (size_t)(s - str);
}
int
strncmp(register const char *s1, register const char *s2, register size_t n)
{
if (n == 0)
return (0);
do {
if (*s1 != *s2++)
return (*(const unsigned char *)s1 -
*(const unsigned char *)(s2 - 1));
if (*s1++ == 0)
break;
} while (--n != 0);
return (0);
}
char *
strncpy(char *dst, const char *src, register size_t n)
{
if (n != 0) {
register char *d = dst;
register const char *s = src;
do {
if ((*d++ = *s++) == 0) {
/* NUL pad the remaining n-1 bytes */
while (--n != 0)
*d++ = 0;
break;
}
} while (--n != 0);
}
return (dst);
}
/*
* Find the first occurrence of find in s.
*/
char *
strstr(register const char *s, register const char *find)
{
register char c, sc;
register size_t len;
if ((c = *find++) != 0) {
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return (NULL);
} while (sc != c);
} while (strncmp(s, find, len) != 0);
s--;
}
return ((char *)s);
}
int
strcmpi(register const char *s1, register const char *s2)
{
while (tolower(*s1) == tolower(*s2++))
if (*s1++ == 0)
return (0);
return (tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)(s2 - 1)));
}
char *
strdup(const char *str)
{
if (str != NULL) {
register char *copy = malloc(strlen(str) + 1);
if (copy != NULL)
return strcpy(copy, str);
}
return NULL;
}
//
// wchar.c
//
unsigned short *
wcsdup(unsigned short *str)
{
if (str != NULL) {
register unsigned short *copy = malloc((wcslen(str) + 1) * sizeof (wchar_t));
if (copy != NULL) {
return wcscpy(copy, str);
}
}
return NULL;
}
unsigned long
strtoul(char *nptr, char **endptr, register int base)
{
register const char *s = nptr;
register unsigned long acc;
register unsigned char c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* See strtol for comments as to the logic used.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
// errno = ERANGE;
} else if (neg)
acc = (unsigned long)(-(long)acc);
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
long
strtol(const char *nptr, char **endptr, register int base)
{
register const char *s = nptr;
register unsigned long acc;
register unsigned char c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? LONG_MIN+1 : LONG_MAX; /* XXX EFI port */
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (!isascii(c))
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
// errno = ERANGE;
} else if (neg)
acc = (unsigned long)(-(long)acc); /* XXX cast for EFI port */
if (endptr != 0)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
long wcstol(unsigned short *nptr, unsigned short **endptr , int base )
{
register const unsigned short *s = nptr;
register unsigned long acc;
register unsigned short c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? LONG_MIN+1 : LONG_MAX; /* XXX EFI port */
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (c > 128) // ascii check
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
// errno = ERANGE;
} else if (neg)
acc = (unsigned long)(-(long)acc); /* XXX cast for EFI port */
if (endptr != 0)
*endptr = (unsigned short *)(any ? s - 1 : nptr);
return (acc);
}
unsigned long wcstoul(unsigned short *nptr, unsigned short **endptr , unsigned int base )
{
register const unsigned short *s = nptr;
register unsigned long acc;
register unsigned short c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* See strtol for comments as to the logic used.
*/
do {
c = *s++;
} while (isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (c > 127) // ascii check
break;
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
// errno = ERANGE;
} else if (neg)
acc = (unsigned long)(-(long)acc);
if (endptr != 0)
*endptr = (unsigned short *)(any ? s - 1 : nptr);
return (acc);
}
int wcscasecmp (wchar_t *s1, wchar_t *s2)
{
register const wchar_t
*us1 = (const wchar_t *)s1,
*us2 = (const wchar_t *)s2;
while (tolower(*us1) == tolower(*us2++))
if (*us1++ == '\0')
return (0);
return (tolower(*us1) - tolower(*--us2));
}
wchar_t*
wcscpy(register wchar_t *to, register const wchar_t *from)
{
unsigned short *save = to;
for (; (*to = *from) != 0; ++from, ++to);
return(save);
}
size_t
wcslen(const wchar_t *str)
{
register const wchar_t *s;
for (s = str; *s; ++s);
return (size_t)(s - str);
}
wchar_t *
wcscat(register wchar_t *s, register const wchar_t * append)
{
wchar_t *save = s;
for (; *s; ++s);
while ((*s++ = *append++) != 0);
return(save);
}
int
wcscmp(register const wchar_t *s1, register const wchar_t *s2)
{
while (*s1 == *s2++)
if (*s1++ == 0)
return (0);
return (*(const wchar_t *)s1 - *(const wchar_t *)(s2 - 1));
}
wchar_t *
wcsncpy(wchar_t *dst, const wchar_t * src, register size_t n)
{
if (n != 0) {
register wchar_t *d = dst;
register const wchar_t *s = src;
do {
if ((*d++ = *s++) == 0) {
/* NUL pad the remaining n-1 wide characters */
while (--n != 0)
*d++ = 0;
break;
}
} while (--n != 0);
}
return (dst);
}