When compiling the kernel as a whole program it is possible that these functions may be inlined and not emitted in the resulting binary. However at the same time the compiler may itself emit calls to these functions. Marking these functions as externally visible tells the compiler that there may be more usages of them than it sees immediately in the source code, in this cases usages that the compiler itself is going to generate
143 lines
3 KiB
C
143 lines
3 KiB
C
/*
|
|
* Copyright 2014, General Dynamics C4 Systems
|
|
*
|
|
* This software may be distributed and modified according to the terms of
|
|
* the GNU General Public License version 2. Note that NO WARRANTY is provided.
|
|
* See "LICENSE_GPLv2.txt" for details.
|
|
*
|
|
* @TAG(GD_GPL)
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <util.h>
|
|
|
|
/*
|
|
* memzero needs a custom type that allows us to use a word
|
|
* that has the aliasing properties of a char.
|
|
*/
|
|
typedef unsigned long __attribute__((__may_alias__)) ulong_alias;
|
|
|
|
/*
|
|
* Zero 'n' bytes of memory starting from 's'.
|
|
*
|
|
* 'n' and 's' must be word aligned.
|
|
*/
|
|
void
|
|
memzero(void *s, unsigned long n)
|
|
{
|
|
uint8_t *p = s;
|
|
|
|
/* Ensure alignment constraints are met. */
|
|
assert((unsigned long)s % sizeof(unsigned long) == 0);
|
|
assert(n % sizeof(unsigned long) == 0);
|
|
|
|
/* We will never memzero an area larger than the largest current
|
|
live object */
|
|
/** GHOSTUPD: "(gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state = 0
|
|
\<or> \<acute>n <= gs_get_assn cap_get_capSizeBits_'proc \<acute>ghost'state, id)" */
|
|
|
|
/* Write out words. */
|
|
while (n != 0) {
|
|
*(ulong_alias *)p = 0;
|
|
p += sizeof(ulong_alias);
|
|
n -= sizeof(ulong_alias);
|
|
}
|
|
}
|
|
|
|
void* VISIBLE
|
|
memset(void *s, unsigned long c, unsigned long n)
|
|
{
|
|
uint8_t *p;
|
|
|
|
/*
|
|
* If we are only writing zeros and we are word aligned, we can
|
|
* use the optimized 'memzero' function.
|
|
*/
|
|
if (likely(c == 0 && ((unsigned long)s % sizeof(unsigned long)) == 0 && (n % sizeof(unsigned long)) == 0)) {
|
|
memzero(s, n);
|
|
} else {
|
|
/* Otherwise, we use a slower, simple memset. */
|
|
for (p = (uint8_t *)s; n > 0; n--, p++) {
|
|
*p = (uint8_t)c;
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
void* VISIBLE
|
|
memcpy(void* ptr_dst, const void* ptr_src, unsigned long n)
|
|
{
|
|
uint8_t *p;
|
|
const uint8_t *q;
|
|
|
|
for (p = (uint8_t *)ptr_dst, q = (const uint8_t *)ptr_src; n; n--, p++, q++) {
|
|
*p = *q;
|
|
}
|
|
|
|
return ptr_dst;
|
|
}
|
|
|
|
int PURE
|
|
strncmp(const char* s1, const char* s2, int n)
|
|
{
|
|
word_t i;
|
|
int diff;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
diff = ((unsigned char*)s1)[i] - ((unsigned char*)s2)[i];
|
|
if (diff != 0 || s1[i] == '\0') {
|
|
return diff;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
long CONST
|
|
char_to_long(char c)
|
|
{
|
|
if (c >= '0' && c <= '9') {
|
|
return c - '0';
|
|
} else if (c >= 'A' && c <= 'F') {
|
|
return c - 'A' + 10;
|
|
} else if (c >= 'a' && c <= 'f') {
|
|
return c - 'a' + 10;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
long PURE
|
|
str_to_long(const char* str)
|
|
{
|
|
unsigned int base;
|
|
long res;
|
|
long val = 0;
|
|
char c;
|
|
|
|
/*check for "0x" */
|
|
if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
|
|
base = 16;
|
|
str += 2;
|
|
} else {
|
|
base = 10;
|
|
}
|
|
|
|
if (!*str) {
|
|
return -1;
|
|
}
|
|
|
|
c = *str;
|
|
while (c != '\0') {
|
|
res = char_to_long(c);
|
|
if (res == -1 || res >= base) {
|
|
return -1;
|
|
}
|
|
val = val * base + res;
|
|
str++;
|
|
c = *str;
|
|
}
|
|
|
|
return val;
|
|
}
|