mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
a9c640ac96
The inclusion of <linux/kernel.h> was causing issue as the definition of __arch_hweight64 from arch/x86/include/asm/arch_hweight.h eventually gets included. The definition is problematic when compiled with -m16 (all code in arch/x86/boot/ is) as the "D" inline assembly constraint is rejected by both compilers when passed an argument of type long long (regardless of signedness, anything smaller is fine). Because GCC performs inlining before semantic analysis, and __arch_hweight64 is dead in this translation unit, GCC does not report any issues at compile time. Clang does the semantic analysis in the front end, before inlining (run in the middle) can determine the code is dead. I consider this another case of PR33587, which I think we can do more work to solve. It turns out that arch/x86/boot/string.c doesn't actually need linux/kernel.h, simply linux/limits.h and linux/compiler.h. Suggested-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Nathan Chancellor <natechancellor@gmail.com> Reviewed-by: Nathan Chancellor <natechancellor@gmail.com> Cc: bp@alien8.de Cc: niravd@google.com Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Chao Fan <fanc.fnst@cn.fujitsu.com> Cc: Uros Bizjak <ubizjak@gmail.com> Link: https://bugs.llvm.org/show_bug.cgi?id=33587 Link: https://github.com/ClangBuiltLinux/linux/issues/347 Link: https://lkml.kernel.org/r/20190314221458.83047-1-ndesaulniers@google.com
332 lines
6.9 KiB
C
332 lines
6.9 KiB
C
/* -*- linux-c -*- ------------------------------------------------------- *
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
|
*
|
|
* This file is part of the Linux kernel, and is made available under
|
|
* the terms of the GNU General Public License version 2.
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* Very basic string functions
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/limits.h>
|
|
#include <asm/asm.h>
|
|
#include "ctype.h"
|
|
#include "string.h"
|
|
|
|
#define KSTRTOX_OVERFLOW (1U << 31)
|
|
|
|
/*
|
|
* 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
|
|
|
|
int memcmp(const void *s1, const void *s2, size_t len)
|
|
{
|
|
bool diff;
|
|
asm("repe; cmpsb" CC_SET(nz)
|
|
: CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len));
|
|
return diff;
|
|
}
|
|
|
|
int strcmp(const char *str1, const char *str2)
|
|
{
|
|
const unsigned char *s1 = (const unsigned char *)str1;
|
|
const unsigned char *s2 = (const unsigned char *)str2;
|
|
int delta = 0;
|
|
|
|
while (*s1 || *s2) {
|
|
delta = *s1 - *s2;
|
|
if (delta)
|
|
return delta;
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* Works only for digits and letters, but small and fast */
|
|
#define TOLOWER(x) ((x) | 0x20)
|
|
|
|
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
|
|
*/
|
|
|
|
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
|
|
{
|
|
unsigned long long result = 0;
|
|
|
|
if (!base)
|
|
base = simple_guess_base(cp);
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
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);
|
|
}
|