1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <assert.h>
8#include <stdint.h>
9#include <util.h>
10
11/*
12 * memzero needs a custom type that allows us to use a word
13 * that has the aliasing properties of a char.
14 */
15typedef unsigned long __attribute__((__may_alias__)) ulong_alias;
16
17/*
18 * Zero 'n' bytes of memory starting from 's'.
19 *
20 * 'n' and 's' must be word aligned.
21 */
22void memzero(void *s, unsigned long n)
23{
24    uint8_t *p = s;
25
26    /* Ensure alignment constraints are met. */
27    assert((unsigned long)s % sizeof(unsigned long) == 0);
28    assert(n % sizeof(unsigned long) == 0);
29
30    /* We will never memzero an area larger than the largest current
31       live object */
32    /** GHOSTUPD: "(gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
33        \<or> \<acute>n <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state, id)" */
34
35    /* Write out words. */
36    while (n != 0) {
37        *(ulong_alias *)p = 0;
38        p += sizeof(ulong_alias);
39        n -= sizeof(ulong_alias);
40    }
41}
42
43void *VISIBLE memset(void *s, unsigned long c, unsigned long n)
44{
45    uint8_t *p;
46
47    /*
48     * If we are only writing zeros and we are word aligned, we can
49     * use the optimized 'memzero' function.
50     */
51    if (likely(c == 0 && ((unsigned long)s % sizeof(unsigned long)) == 0 && (n % sizeof(unsigned long)) == 0)) {
52        memzero(s, n);
53    } else {
54        /* Otherwise, we use a slower, simple memset. */
55        for (p = (uint8_t *)s; n > 0; n--, p++) {
56            *p = (uint8_t)c;
57        }
58    }
59
60    return s;
61}
62
63void *VISIBLE memcpy(void *ptr_dst, const void *ptr_src, unsigned long n)
64{
65    uint8_t *p;
66    const uint8_t *q;
67
68    for (p = (uint8_t *)ptr_dst, q = (const uint8_t *)ptr_src; n; n--, p++, q++) {
69        *p = *q;
70    }
71
72    return ptr_dst;
73}
74
75int PURE strncmp(const char *s1, const char *s2, int n)
76{
77    word_t i;
78    int diff;
79
80    for (i = 0; i < n; i++) {
81        diff = ((unsigned char *)s1)[i] - ((unsigned char *)s2)[i];
82        if (diff != 0 || s1[i] == '\0') {
83            return diff;
84        }
85    }
86
87    return 0;
88}
89
90long CONST char_to_long(char c)
91{
92    if (c >= '0' && c <= '9') {
93        return c - '0';
94    } else if (c >= 'A' && c <= 'F') {
95        return c - 'A' + 10;
96    } else if (c >= 'a' && c <= 'f') {
97        return c - 'a' + 10;
98    }
99    return -1;
100}
101
102long PURE str_to_long(const char *str)
103{
104    unsigned int base;
105    long res;
106    long val = 0;
107    char c;
108
109    /*check for "0x" */
110    if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
111        base = 16;
112        str += 2;
113    } else {
114        base = 10;
115    }
116
117    if (!*str) {
118        return -1;
119    }
120
121    c = *str;
122    while (c != '\0') {
123        res = char_to_long(c);
124        if (res == -1 || res >= base) {
125            return -1;
126        }
127        val = val * base + res;
128        str++;
129        c = *str;
130    }
131
132    return val;
133}
134
135#ifdef CONFIG_ARCH_RISCV
136uint32_t __clzsi2(uint32_t x)
137{
138    uint32_t count = 0;
139    while (!(x & 0x80000000U) && count < 34) {
140        x <<= 1;
141        count++;
142    }
143    return count;
144}
145
146uint32_t __ctzsi2(uint32_t x)
147{
148    uint32_t count = 0;
149    while (!(x & 0x000000001) && count <= 32) {
150        x >>= 1;
151        count++;
152    }
153    return count;
154}
155
156uint32_t __clzdi2(uint64_t x)
157{
158    uint32_t count = 0;
159    while (!(x & 0x8000000000000000U) && count < 65) {
160        x <<= 1;
161        count++;
162    }
163    return count;
164}
165
166uint32_t __ctzdi2(uint64_t x)
167{
168    uint32_t count = 0;
169    while (!(x & 0x00000000000000001) && count <= 64) {
170        x >>= 1;
171        count++;
172    }
173    return count;
174}
175#endif /* CONFIG_ARCH_RISCV */
176