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