Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3117558imu; Sun, 6 Jan 2019 19:25:25 -0800 (PST) X-Google-Smtp-Source: AFSGD/VrUoVF2vHQFRfD3ZLSkIuu+NMDJbMhgPZXXYFJrwLYu4OslZjCsJ/HnPFfUzdfe05nIXzG X-Received: by 2002:a62:3006:: with SMTP id w6mr62025310pfw.258.1546831525646; Sun, 06 Jan 2019 19:25:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1546831525; cv=none; d=google.com; s=arc-20160816; b=Rn5UDJ+GVtix2QvEhqMhEyU6MmzkFonWOOZI3GVSHfb+GVTo0xg55MgzGXFERjbpyI XnkxwM492jVtZV8CvOwfJla/MkEfQhUYG5evWGzJtuAc1VBJMSd05nis0JLBEypdDkx+ Zarc/FtREE9/5vWoSL/9yEaJSubpYIU4LT/kESW4phiSA13Vg7LbNdCKExC1G3IDKGJv ILRu3S/pvj3vl/gHwnDGF34jAB2YWrnTpytybLA1GzzLECWgXQiZZL11W16azwB8bJ88 8JMqsU2npePHx0JEm7U7xqRwDuWSXT4yOqn07S7hfXg8EIKEefGIOfJA+n8JQUrUeXW2 5QWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=JbcDUcRUcmSQIK8neV6pdgYovyP72zqh7K02Mwu3uiY=; b=jUtTp/5V1oaCt9zlRGfnrKBnqd3xpPktMcSBfvnSAOVmJgoNYVTYaPSCw8PSPUHSWC M8U9ucCQWnd8DuIvTNyqocjMAy2SlV43Sr99HNrfPIg5ufD/Fo4uk5It8d2MzNd9s8gr wO9ZQYfbeZ3KNaOQuwGINq5jr82lA7DjMz/m9wCzuZSrEttq0HH6O2oNXhJHDw30QPt7 zLKVaTRgvftKWbNWOWglimvMwiG0kL1CykTv7GfJfJk0WF5pL/QUSQMksoxmg9qxh0nY 8++CeCbFYII7IAldiR1fa3kqH9f3bpN8D+D/e6mOFwT2G2nH7zFWo6FsE0E/ymrfeBtL 7H+A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q9si62096098pgi.89.2019.01.06.19.25.10; Sun, 06 Jan 2019 19:25:25 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726459AbfAGDX4 (ORCPT + 99 others); Sun, 6 Jan 2019 22:23:56 -0500 Received: from mail.cn.fujitsu.com ([183.91.158.132]:15467 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726402AbfAGDXy (ORCPT ); Sun, 6 Jan 2019 22:23:54 -0500 X-IronPort-AV: E=Sophos;i="5.56,449,1539619200"; d="scan'208";a="51438972" Received: from unknown (HELO cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 07 Jan 2019 11:23:50 +0800 Received: from G08CNEXCHPEKD01.g08.fujitsu.local (unknown [10.167.33.80]) by cn.fujitsu.com (Postfix) with ESMTP id 4BADC4B7EC53; Mon, 7 Jan 2019 11:23:34 +0800 (CST) Received: from localhost.local (10.167.225.56) by G08CNEXCHPEKD01.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.408.0; Mon, 7 Jan 2019 11:23:39 +0800 From: Chao Fan To: , , , , , , , , CC: , , Subject: [PATCH v15 1/6] x86/boot: Copy kstrtoull() to boot/string.c instead of using simple_strtoull() Date: Mon, 7 Jan 2019 11:22:38 +0800 Message-ID: <20190107032243.25324-2-fanc.fnst@cn.fujitsu.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190107032243.25324-1-fanc.fnst@cn.fujitsu.com> References: <20190107032243.25324-1-fanc.fnst@cn.fujitsu.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-Originating-IP: [10.167.225.56] X-yoursite-MailScanner-ID: 4BADC4B7EC53.A9E76 X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: fanc.fnst@cn.fujitsu.com X-Spam-Status: No Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Copy kstrtoull() and necessary functions from lib/kstrtox.c to boot/string.c so that code in boot/ can use kstrtoull() and the old simple_strtoull() can be replaced. In boot/string.c, using div_u64() from math64.h directly will cause the dividend handled as 64-bit value and bring ld error. The solution is to separate the dividend to upper and lower in boot/string.o. So copy the useful div_u64() and div_u64_rem() to boot/string.c also. To avoid redefinition in i386, rename them as __div_u64() and __div_u64_rem(). Signed-off-by: Chao Fan --- arch/x86/boot/string.c | 137 +++++++++++++++++++++++++++++++++++++++++ arch/x86/boot/string.h | 2 + 2 files changed, 139 insertions(+) diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index c4428a176973..3de8de39a1ca 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -13,6 +13,8 @@ */ #include +#include +#include #include #include "ctype.h" #include "string.h" @@ -187,3 +189,138 @@ char *strchr(const char *s, int c) 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; +} + +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. + */ +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); +} diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h index 3d78e27077f4..171007c99acc 100644 --- a/arch/x86/boot/string.h +++ b/arch/x86/boot/string.h @@ -29,4 +29,6 @@ extern unsigned int atou(const char *s); extern unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base); +int kstrtoull(const char *s, unsigned int base, unsigned long long *res); +#define KSTRTOX_OVERFLOW (1U << 31) #endif /* BOOT_STRING_H */ -- 2.20.1