2019-06-04 08:11:30 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2007-07-11 19:18:41 +00:00
|
|
|
/* -*- linux-c -*- ------------------------------------------------------- *
|
|
|
|
*
|
|
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
|
|
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Very basic string functions
|
|
|
|
*/
|
|
|
|
|
2014-04-25 17:46:11 +00:00
|
|
|
#include <linux/types.h>
|
2019-03-14 22:14:57 +00:00
|
|
|
#include <linux/compiler.h>
|
2019-01-23 11:08:44 +00:00
|
|
|
#include <linux/errno.h>
|
2019-03-14 22:14:57 +00:00
|
|
|
#include <linux/limits.h>
|
2018-06-29 14:28:44 +00:00
|
|
|
#include <asm/asm.h>
|
2014-04-25 17:46:11 +00:00
|
|
|
#include "ctype.h"
|
2017-01-07 09:38:31 +00:00
|
|
|
#include "string.h"
|
2007-07-11 19:18:41 +00:00
|
|
|
|
2019-01-23 11:08:44 +00:00
|
|
|
#define KSTRTOX_OVERFLOW (1U << 31)
|
|
|
|
|
2017-07-24 23:51:55 +00:00
|
|
|
/*
|
|
|
|
* Undef these macros so that the functions that we provide
|
|
|
|
* here will have the correct names regardless of how string.h
|
|
|
|
* may have chosen to #define them.
|
|
|
|
*/
|
|
|
|
#undef memcpy
|
|
|
|
#undef memset
|
|
|
|
#undef memcmp
|
|
|
|
|
2014-03-18 19:26:39 +00:00
|
|
|
int memcmp(const void *s1, const void *s2, size_t len)
|
|
|
|
{
|
2016-06-08 19:38:38 +00:00
|
|
|
bool diff;
|
2018-06-29 14:28:44 +00:00
|
|
|
asm("repe; cmpsb" CC_SET(nz)
|
|
|
|
: CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len));
|
2014-03-18 19:26:39 +00:00
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
2019-08-07 22:15:32 +00:00
|
|
|
/*
|
|
|
|
* Clang may lower `memcmp == 0` to `bcmp == 0`.
|
|
|
|
*/
|
|
|
|
int bcmp(const void *s1, const void *s2, size_t len)
|
|
|
|
{
|
|
|
|
return memcmp(s1, s2, len);
|
|
|
|
}
|
|
|
|
|
2007-07-11 19:18:41 +00:00
|
|
|
int strcmp(const char *str1, const char *str2)
|
|
|
|
{
|
|
|
|
const unsigned char *s1 = (const unsigned char *)str1;
|
|
|
|
const unsigned char *s2 = (const unsigned char *)str2;
|
2023-12-19 14:13:04 +00:00
|
|
|
int delta;
|
2007-07-11 19:18:41 +00:00
|
|
|
|
|
|
|
while (*s1 || *s2) {
|
x86/boot: Standardize strcmp()
strcmp() is always expected to return 0 when arguments are equal,
negative when its first argument @str1 is less than its second argument
@str2 and a positive value otherwise. Previously strcmp("a", "b")
returned 1. Now it gives -1, as it is supposed to.
Until now this bug never triggered, because all uses for strcmp() in the
boot code tested for nonzero:
triton:~/tip> git grep strcmp arch/x86/boot/
arch/x86/boot/boot.h:int strcmp(const char *str1, const char *str2);
arch/x86/boot/edd.c: if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) {
arch/x86/boot/edd.c: else if (!strcmp(eddarg, "off"))
arch/x86/boot/edd.c: else if (!strcmp(eddarg, "on"))
should in the future strcmp() be used in a comparative way in the boot
code, it might have led to (not so subtle) bugs.
Signed-off-by: Arjun Sreedharan <arjun024@gmail.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1426520267-1803-1-git-send-email-arjun024@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-03-16 15:37:47 +00:00
|
|
|
delta = *s1 - *s2;
|
2007-07-11 19:18:41 +00:00
|
|
|
if (delta)
|
|
|
|
return delta;
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-11 08:06:57 +00:00
|
|
|
int strncmp(const char *cs, const char *ct, size_t count)
|
|
|
|
{
|
|
|
|
unsigned char c1, c2;
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
c1 = *cs++;
|
|
|
|
c2 = *ct++;
|
|
|
|
if (c1 != c2)
|
|
|
|
return c1 < c2 ? -1 : 1;
|
|
|
|
if (!c1)
|
|
|
|
break;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-11 19:18:41 +00:00
|
|
|
size_t strnlen(const char *s, size_t maxlen)
|
|
|
|
{
|
|
|
|
const char *es = s;
|
|
|
|
while (*es && maxlen) {
|
|
|
|
es++;
|
|
|
|
maxlen--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (es - s);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int atou(const char *s)
|
|
|
|
{
|
|
|
|
unsigned int i = 0;
|
|
|
|
while (isdigit(*s))
|
|
|
|
i = i * 10 + (*s++ - '0');
|
|
|
|
return i;
|
|
|
|
}
|
2010-07-11 08:06:57 +00:00
|
|
|
|
|
|
|
/* Works only for digits and letters, but small and fast */
|
|
|
|
#define TOLOWER(x) ((x) | 0x20)
|
|
|
|
|
2010-07-13 20:35:17 +00:00
|
|
|
static unsigned int simple_guess_base(const char *cp)
|
|
|
|
{
|
|
|
|
if (cp[0] == '0') {
|
|
|
|
if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
|
|
|
|
return 16;
|
|
|
|
else
|
|
|
|
return 8;
|
|
|
|
} else {
|
|
|
|
return 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* simple_strtoull - convert a string to an unsigned long long
|
|
|
|
* @cp: The start of the string
|
|
|
|
* @endp: A pointer to the end of the parsed string will be placed here
|
|
|
|
* @base: The number base to use
|
|
|
|
*/
|
2010-07-11 08:06:57 +00:00
|
|
|
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
|
|
|
|
{
|
|
|
|
unsigned long long result = 0;
|
|
|
|
|
2010-07-13 20:35:17 +00:00
|
|
|
if (!base)
|
|
|
|
base = simple_guess_base(cp);
|
|
|
|
|
2010-07-11 08:06:57 +00:00
|
|
|
if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
|
|
|
|
cp += 2;
|
|
|
|
|
|
|
|
while (isxdigit(*cp)) {
|
|
|
|
unsigned int value;
|
|
|
|
|
|
|
|
value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
|
|
|
|
if (value >= base)
|
|
|
|
break;
|
|
|
|
result = result * base + value;
|
|
|
|
cp++;
|
|
|
|
}
|
|
|
|
if (endp)
|
|
|
|
*endp = (char *)cp;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
x86, efi: EFI boot stub support
There is currently a large divide between kernel development and the
development of EFI boot loaders. The idea behind this patch is to give
the kernel developers full control over the EFI boot process. As
H. Peter Anvin put it,
"The 'kernel carries its own stub' approach been very successful in
dealing with BIOS, and would make a lot of sense to me for EFI as
well."
This patch introduces an EFI boot stub that allows an x86 bzImage to
be loaded and executed by EFI firmware. The bzImage appears to the
firmware as an EFI application. Luckily there are enough free bits
within the bzImage header so that it can masquerade as an EFI
application, thereby coercing the EFI firmware into loading it and
jumping to its entry point. The beauty of this masquerading approach
is that both BIOS and EFI boot loaders can still load and run the same
bzImage, thereby allowing a single kernel image to work in any boot
environment.
The EFI boot stub supports multiple initrds, but they must exist on
the same partition as the bzImage. Command-line arguments for the
kernel can be appended after the bzImage name when run from the EFI
shell, e.g.
Shell> bzImage console=ttyS0 root=/dev/sdb initrd=initrd.img
v7:
- Fix checkpatch warnings.
v6:
- Try to allocate initrd memory just below hdr->inird_addr_max.
v5:
- load_options_size is UTF-16, which needs dividing by 2 to convert
to the corresponding ASCII size.
v4:
- Don't read more than image->load_options_size
v3:
- Fix following warnings when compiling CONFIG_EFI_STUB=n
arch/x86/boot/tools/build.c: In function ‘main’:
arch/x86/boot/tools/build.c:138:24: warning: unused variable ‘pe_header’
arch/x86/boot/tools/build.c:138:15: warning: unused variable ‘file_sz’
- As reported by Matthew Garrett, some Apple machines have GOPs that
don't have hardware attached. We need to weed these out by
searching for ones that handle the PCIIO protocol.
- Don't allocate memory if no initrds are on cmdline
- Don't trust image->load_options_size
Maarten Lankhorst noted:
- Don't strip first argument when booted from efibootmgr
- Don't allocate too much memory for cmdline
- Don't update cmdline_size, the kernel considers it read-only
- Don't accept '\n' for initrd names
v2:
- File alignment was too large, was 8192 should be 512. Reported by
Maarten Lankhorst on LKML.
- Added UGA support for graphics
- Use VIDEO_TYPE_EFI instead of hard-coded number.
- Move linelength assignment until after we've assigned depth
- Dynamically fill out AddressOfEntryPoint in tools/build.c
- Don't use magic number for GDT/TSS stuff. Requested by Andi Kleen
- The bzImage may need to be relocated as it may have been loaded at
a high address address by the firmware. This was required to get my
macbook booting because the firmware loaded it at 0x7cxxxxxx, which
triggers this error in decompress_kernel(),
if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
error("Destination address too large");
Cc: Mike Waychison <mikew@google.com>
Cc: Matthew Garrett <mjg@redhat.com>
Tested-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Link: http://lkml.kernel.org/r/1321383097.2657.9.camel@mfleming-mobl1.ger.corp.intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2011-12-12 21:27:52 +00:00
|
|
|
|
2017-05-13 05:46:28 +00:00
|
|
|
long simple_strtol(const char *cp, char **endp, unsigned int base)
|
|
|
|
{
|
|
|
|
if (*cp == '-')
|
|
|
|
return -simple_strtoull(cp + 1, endp, base);
|
|
|
|
|
|
|
|
return simple_strtoull(cp, endp, base);
|
|
|
|
}
|
|
|
|
|
x86, efi: EFI boot stub support
There is currently a large divide between kernel development and the
development of EFI boot loaders. The idea behind this patch is to give
the kernel developers full control over the EFI boot process. As
H. Peter Anvin put it,
"The 'kernel carries its own stub' approach been very successful in
dealing with BIOS, and would make a lot of sense to me for EFI as
well."
This patch introduces an EFI boot stub that allows an x86 bzImage to
be loaded and executed by EFI firmware. The bzImage appears to the
firmware as an EFI application. Luckily there are enough free bits
within the bzImage header so that it can masquerade as an EFI
application, thereby coercing the EFI firmware into loading it and
jumping to its entry point. The beauty of this masquerading approach
is that both BIOS and EFI boot loaders can still load and run the same
bzImage, thereby allowing a single kernel image to work in any boot
environment.
The EFI boot stub supports multiple initrds, but they must exist on
the same partition as the bzImage. Command-line arguments for the
kernel can be appended after the bzImage name when run from the EFI
shell, e.g.
Shell> bzImage console=ttyS0 root=/dev/sdb initrd=initrd.img
v7:
- Fix checkpatch warnings.
v6:
- Try to allocate initrd memory just below hdr->inird_addr_max.
v5:
- load_options_size is UTF-16, which needs dividing by 2 to convert
to the corresponding ASCII size.
v4:
- Don't read more than image->load_options_size
v3:
- Fix following warnings when compiling CONFIG_EFI_STUB=n
arch/x86/boot/tools/build.c: In function ‘main’:
arch/x86/boot/tools/build.c:138:24: warning: unused variable ‘pe_header’
arch/x86/boot/tools/build.c:138:15: warning: unused variable ‘file_sz’
- As reported by Matthew Garrett, some Apple machines have GOPs that
don't have hardware attached. We need to weed these out by
searching for ones that handle the PCIIO protocol.
- Don't allocate memory if no initrds are on cmdline
- Don't trust image->load_options_size
Maarten Lankhorst noted:
- Don't strip first argument when booted from efibootmgr
- Don't allocate too much memory for cmdline
- Don't update cmdline_size, the kernel considers it read-only
- Don't accept '\n' for initrd names
v2:
- File alignment was too large, was 8192 should be 512. Reported by
Maarten Lankhorst on LKML.
- Added UGA support for graphics
- Use VIDEO_TYPE_EFI instead of hard-coded number.
- Move linelength assignment until after we've assigned depth
- Dynamically fill out AddressOfEntryPoint in tools/build.c
- Don't use magic number for GDT/TSS stuff. Requested by Andi Kleen
- The bzImage may need to be relocated as it may have been loaded at
a high address address by the firmware. This was required to get my
macbook booting because the firmware loaded it at 0x7cxxxxxx, which
triggers this error in decompress_kernel(),
if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
error("Destination address too large");
Cc: Mike Waychison <mikew@google.com>
Cc: Matthew Garrett <mjg@redhat.com>
Tested-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Link: http://lkml.kernel.org/r/1321383097.2657.9.camel@mfleming-mobl1.ger.corp.intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2011-12-12 21:27:52 +00:00
|
|
|
/**
|
|
|
|
* strlen - Find the length of a string
|
|
|
|
* @s: The string to be sized
|
|
|
|
*/
|
|
|
|
size_t strlen(const char *s)
|
|
|
|
{
|
|
|
|
const char *sc;
|
|
|
|
|
|
|
|
for (sc = s; *sc != '\0'; ++sc)
|
|
|
|
/* nothing */;
|
|
|
|
return sc - s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* strstr - Find the first substring in a %NUL terminated string
|
|
|
|
* @s1: The string to be searched
|
|
|
|
* @s2: The string to search for
|
|
|
|
*/
|
|
|
|
char *strstr(const char *s1, const char *s2)
|
|
|
|
{
|
|
|
|
size_t l1, l2;
|
|
|
|
|
|
|
|
l2 = strlen(s2);
|
|
|
|
if (!l2)
|
|
|
|
return (char *)s1;
|
|
|
|
l1 = strlen(s1);
|
|
|
|
while (l1 >= l2) {
|
|
|
|
l1--;
|
|
|
|
if (!memcmp(s1, s2, l2))
|
|
|
|
return (char *)s1;
|
|
|
|
s1++;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-01-11 23:20:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* strchr - Find the first occurrence of the character c in the string s.
|
|
|
|
* @s: the string to be searched
|
|
|
|
* @c: the character to search for
|
|
|
|
*/
|
|
|
|
char *strchr(const char *s, int c)
|
|
|
|
{
|
|
|
|
while (*s != (char)c)
|
|
|
|
if (*s++ == '\0')
|
|
|
|
return NULL;
|
|
|
|
return (char *)s;
|
|
|
|
}
|
2019-01-23 11:08:44 +00:00
|
|
|
|
|
|
|
static inline u64 __div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
u64 v64;
|
|
|
|
u32 v32[2];
|
|
|
|
} d = { dividend };
|
|
|
|
u32 upper;
|
|
|
|
|
|
|
|
upper = d.v32[1];
|
|
|
|
d.v32[1] = 0;
|
|
|
|
if (upper >= divisor) {
|
|
|
|
d.v32[1] = upper / divisor;
|
|
|
|
upper %= divisor;
|
|
|
|
}
|
|
|
|
asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
|
|
|
|
"rm" (divisor), "0" (d.v32[0]), "1" (upper));
|
|
|
|
return d.v64;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 __div_u64(u64 dividend, u32 divisor)
|
|
|
|
{
|
|
|
|
u32 remainder;
|
|
|
|
|
|
|
|
return __div_u64_rem(dividend, divisor, &remainder);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline char _tolower(const char c)
|
|
|
|
{
|
|
|
|
return c | 0x20;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
|
|
|
|
{
|
|
|
|
if (*base == 0) {
|
|
|
|
if (s[0] == '0') {
|
|
|
|
if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
|
|
|
|
*base = 16;
|
|
|
|
else
|
|
|
|
*base = 8;
|
|
|
|
} else
|
|
|
|
*base = 10;
|
|
|
|
}
|
|
|
|
if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
|
|
|
|
s += 2;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert non-negative integer string representation in explicitly given radix
|
|
|
|
* to an integer.
|
|
|
|
* Return number of characters consumed maybe or-ed with overflow bit.
|
|
|
|
* If overflow occurs, result integer (incorrect) is still returned.
|
|
|
|
*
|
|
|
|
* Don't you dare use this function.
|
|
|
|
*/
|
|
|
|
static unsigned int _parse_integer(const char *s,
|
|
|
|
unsigned int base,
|
|
|
|
unsigned long long *p)
|
|
|
|
{
|
|
|
|
unsigned long long res;
|
|
|
|
unsigned int rv;
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
rv = 0;
|
|
|
|
while (1) {
|
|
|
|
unsigned int c = *s;
|
|
|
|
unsigned int lc = c | 0x20; /* don't tolower() this line */
|
|
|
|
unsigned int val;
|
|
|
|
|
|
|
|
if ('0' <= c && c <= '9')
|
|
|
|
val = c - '0';
|
|
|
|
else if ('a' <= lc && lc <= 'f')
|
|
|
|
val = lc - 'a' + 10;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (val >= base)
|
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* Check for overflow only if we are within range of
|
|
|
|
* it in the max base we support (16)
|
|
|
|
*/
|
|
|
|
if (unlikely(res & (~0ull << 60))) {
|
|
|
|
if (res > __div_u64(ULLONG_MAX - val, base))
|
|
|
|
rv |= KSTRTOX_OVERFLOW;
|
|
|
|
}
|
|
|
|
res = res * base + val;
|
|
|
|
rv++;
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
*p = res;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
|
|
|
|
{
|
|
|
|
unsigned long long _res;
|
|
|
|
unsigned int rv;
|
|
|
|
|
|
|
|
s = _parse_integer_fixup_radix(s, &base);
|
|
|
|
rv = _parse_integer(s, base, &_res);
|
|
|
|
if (rv & KSTRTOX_OVERFLOW)
|
|
|
|
return -ERANGE;
|
|
|
|
if (rv == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
s += rv;
|
|
|
|
if (*s == '\n')
|
|
|
|
s++;
|
|
|
|
if (*s)
|
|
|
|
return -EINVAL;
|
|
|
|
*res = _res;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* kstrtoull - convert a string to an unsigned long long
|
|
|
|
* @s: The start of the string. The string must be null-terminated, and may also
|
|
|
|
* include a single newline before its terminating null. The first character
|
|
|
|
* may also be a plus sign, but not a minus sign.
|
|
|
|
* @base: The number base to use. The maximum supported base is 16. If base is
|
|
|
|
* given as 0, then the base of the string is automatically detected with the
|
|
|
|
* conventional semantics - If it begins with 0x the number will be parsed as a
|
|
|
|
* hexadecimal (case insensitive), if it otherwise begins with 0, it will be
|
|
|
|
* parsed as an octal number. Otherwise it will be parsed as a decimal.
|
|
|
|
* @res: Where to write the result of the conversion on success.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
|
|
|
|
* Used as a replacement for the obsolete simple_strtoull. Return code must
|
|
|
|
* be checked.
|
|
|
|
*/
|
|
|
|
int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
|
|
|
|
{
|
|
|
|
if (s[0] == '+')
|
|
|
|
s++;
|
|
|
|
return _kstrtoull(s, base, res);
|
|
|
|
}
|
2020-04-23 12:39:47 +00:00
|
|
|
|
|
|
|
static int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
|
|
|
|
{
|
|
|
|
unsigned long long tmp;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
rv = kstrtoull(s, base, &tmp);
|
|
|
|
if (rv < 0)
|
|
|
|
return rv;
|
|
|
|
if (tmp != (unsigned long)tmp)
|
|
|
|
return -ERANGE;
|
|
|
|
*res = tmp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-10-31 09:48:35 +00:00
|
|
|
* boot_kstrtoul - convert a string to an unsigned long
|
2020-04-23 12:39:47 +00:00
|
|
|
* @s: The start of the string. The string must be null-terminated, and may also
|
|
|
|
* include a single newline before its terminating null. The first character
|
|
|
|
* may also be a plus sign, but not a minus sign.
|
|
|
|
* @base: The number base to use. The maximum supported base is 16. If base is
|
|
|
|
* given as 0, then the base of the string is automatically detected with the
|
|
|
|
* conventional semantics - If it begins with 0x the number will be parsed as a
|
|
|
|
* hexadecimal (case insensitive), if it otherwise begins with 0, it will be
|
|
|
|
* parsed as an octal number. Otherwise it will be parsed as a decimal.
|
|
|
|
* @res: Where to write the result of the conversion on success.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
|
|
|
|
* Used as a replacement for the simple_strtoull.
|
|
|
|
*/
|
|
|
|
int boot_kstrtoul(const char *s, unsigned int base, unsigned long *res)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We want to shortcut function call, but
|
|
|
|
* __builtin_types_compatible_p(unsigned long, unsigned long long) = 0.
|
|
|
|
*/
|
|
|
|
if (sizeof(unsigned long) == sizeof(unsigned long long) &&
|
|
|
|
__alignof__(unsigned long) == __alignof__(unsigned long long))
|
|
|
|
return kstrtoull(s, base, (unsigned long long *)res);
|
|
|
|
else
|
|
|
|
return _kstrtoul(s, base, res);
|
|
|
|
}
|