/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ /* Utility functions for Chrome EC */ #include "util.h" size_t strlen(const char *s) { int len = 0; while (*s++) len++; return len; } size_t strnlen(const char *s, size_t maxlen) { size_t len = 0; while (len < maxlen && *s) { s++; len++; } return len; } int isspace(int c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; } int isdigit(int c) { return c >= '0' && c <= '9'; } int isalpha(int c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } int isprint(int c) { return c >= ' ' && c <= '~'; } int tolower(int c) { return c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c; } int strcasecmp(const char *s1, const char *s2) { int diff; do { diff = tolower(*s1) - tolower(*s2); if (diff) return diff; } while (*(s1++) && *(s2++)); return 0; } int strncasecmp(const char *s1, const char *s2, size_t size) { int diff; if (!size) return 0; do { diff = tolower(*s1) - tolower(*s2); if (diff) return diff; } while (*(s1++) && *(s2++) && --size); return 0; } int atoi(const char *nptr) { int result = 0; int neg = 0; char c = '\0'; while ((c = *nptr++) && isspace(c)) ; if (c == '-') { neg = 1; c = *nptr++; } while (isdigit(c)) { result = result * 10 + (c - '0'); c = *nptr++; } return neg ? -result : result; } /* Like strtol(), but for integers */ int strtoi(const char *nptr, char **endptr, int base) { int result = 0; int neg = 0; int c = '\0'; if (endptr) *endptr = (char *)nptr; while ((c = *nptr++) && isspace(c)) ; if (c == '0' && *nptr == 'x') { base = 16; c = nptr[1]; nptr += 2; } else if (base == 0) { base = 10; if (c == '-') { neg = 1; c = *nptr++; } } while (c) { if (c >= '0' && c < '0' + MIN(base, 10)) result = result * base + (c - '0'); else if (c >= 'A' && c < 'A' + base - 10) result = result * base + (c - 'A' + 10); else if (c >= 'a' && c < 'a' + base - 10) result = result * base + (c - 'a' + 10); else break; if (endptr) *endptr = (char *)nptr; c = *nptr++; } return neg ? -result : result; } uint64_t strtoul(const char *nptr, char **endptr, int base) { uint64_t result = 0; int c = '\0'; if (endptr) *endptr = (char *)nptr; while ((c = *nptr++) && isspace(c)) ; if (c == '0' && *nptr == 'x') { base = 16; c = nptr[1]; nptr += 2; } else if (base == 0) { base = 10; if (c == '-') return result; } while (c) { if (c >= '0' && c < '0' + MIN(base, 10)) result = result * base + (c - '0'); else if (c >= 'A' && c < 'A' + base - 10) result = result * base + (c - 'A' + 10); else if (c >= 'a' && c < 'a' + base - 10) result = result * base + (c - 'a' + 10); else break; if (endptr) *endptr = (char *)nptr; c = *nptr++; } return result; } int parse_bool(const char *s, int *dest) { /* off, disable, false, no */ if (!strcasecmp(s, "off") || !strncasecmp(s, "dis", 3) || tolower(*s) == 'f' || tolower(*s) == 'n') { *dest = 0; return 1; } /* on, enable, true, yes */ if (!strcasecmp(s, "on") || !strncasecmp(s, "ena", 3) || tolower(*s) == 't' || tolower(*s) == 'y') { *dest = 1; return 1; } /* dunno */ return 0; } int memcmp(const void *s1, const void *s2, size_t len) { const char *sa = s1; const char *sb = s2; int diff = 0; while (len-- > 0) { diff = *(sa++) - *(sb++); if (diff) return diff; } return 0; } /* Constant-time memory comparison */ int safe_memcmp(const void *s1, const void *s2, size_t size) { const uint8_t *us1 = s1; const uint8_t *us2 = s2; int result = 0; if (size == 0) return 0; /* * Code snippet without data-dependent branch due to Nate Lawson * (nate@root.org) of Root Labs. */ while (size--) result |= *us1++ ^ *us2++; return result != 0; } void *memcpy(void *dest, const void *src, size_t len) { char *d = (char *)dest; const char *s = (const char *)src; uint32_t *dw; const uint32_t *sw; char *head; char * const tail = (char *)dest + len; /* Set 'body' to the last word boundary */ uint32_t * const body = (uint32_t *)((uintptr_t)tail & ~3); if (((uintptr_t)dest & 3) != ((uintptr_t)src & 3)) { /* Misaligned. no body, no tail. */ head = tail; } else { /* Aligned */ if ((uintptr_t)tail < (((uintptr_t)d + 3) & ~3)) /* len is shorter than the first word boundary */ head = tail; else /* Set 'head' to the first word boundary */ head = (char *)(((uintptr_t)d + 3) & ~3); } /* Copy head */ while (d < head) *(d++) = *(s++); /* Copy body */ dw = (uint32_t *)d; sw = (uint32_t *)s; while (dw < body) *(dw++) = *(sw++); /* Copy tail */ d = (char *)dw; s = (const char *)sw; while (d < tail) *(d++) = *(s++); return dest; } void *memset(void *dest, int c, size_t len) { char *d = (char *)dest; uint32_t cccc; uint32_t *dw; char *head; char * const tail = (char *)dest + len; /* Set 'body' to the last word boundary */ uint32_t * const body = (uint32_t *)((uintptr_t)tail & ~3); c &= 0xff; /* Clear upper bits before ORing below */ cccc = c | (c << 8) | (c << 16) | (c << 24); if ((uintptr_t)tail < (((uintptr_t)d + 3) & ~3)) /* len is shorter than the first word boundary */ head = tail; else /* Set 'head' to the first word boundary */ head = (char *)(((uintptr_t)d + 3) & ~3); /* Copy head */ while (d < head) *(d++) = c; /* Copy body */ dw = (uint32_t *)d; while (dw < body) *(dw++) = cccc; /* Copy tail */ d = (char *)dw; while (d < tail) *(d++) = c; return dest; } void *memmove(void *dest, const void *src, size_t len) { if ((uintptr_t)dest <= (uintptr_t)src || (uintptr_t)dest >= (uintptr_t)src + len) { /* Start of destination doesn't overlap source, so just use * memcpy(). */ return memcpy(dest, src, len); } else { /* Need to copy from tail because there is overlap. */ char *d = (char *)dest + len; const char *s = (const char *)src + len; uint32_t *dw; const uint32_t *sw; char *head; char * const tail = (char *)dest; /* Set 'body' to the last word boundary */ uint32_t * const body = (uint32_t *)(((uintptr_t)tail+3) & ~3); if (((uintptr_t)dest & 3) != ((uintptr_t)src & 3)) { /* Misaligned. no body, no tail. */ head = tail; } else { /* Aligned */ if ((uintptr_t)tail > ((uintptr_t)d & ~3)) /* Shorter than the first word boundary */ head = tail; else /* Set 'head' to the first word boundary */ head = (char *)((uintptr_t)d & ~3); } /* Copy head */ while (d > head) *(--d) = *(--s); /* Copy body */ dw = (uint32_t *)d; sw = (uint32_t *)s; while (dw > body) *(--dw) = *(--sw); /* Copy tail */ d = (char *)dw; s = (const char *)sw; while (d > tail) *(--d) = *(--s); return dest; } } void *memchr(const void *buffer, int c, size_t n) { char *current = (char *)buffer; char *end = current + n; while (current != end) { if (*current == c) return current; current++; } return NULL; } void reverse(void *dest, size_t len) { int i; uint8_t *start = dest; uint8_t *end = start + len; for (i = 0; i < len / 2; ++i) { uint8_t tmp = *start; *start++ = *--end; *end = tmp; } } char *strzcpy(char *dest, const char *src, int len) { char *d = dest; if (len <= 0) return dest; while (len > 1 && *src) { *(d++) = *(src++); len--; } *d = '\0'; return dest; } char *strncpy(char *dest, const char *src, size_t n) { char *d = dest; while (n && *src) { *d++ = *src++; n--; } if (n) *d = '\0'; return dest; } int strncmp(const char *s1, const char *s2, size_t n) { while (n--) { if (*s1 != *s2) return *s1 - *s2; if (!*s1) break; s1++; s2++; } return 0; } int uint64divmod(uint64_t *n, int d) { uint64_t q = 0, mask; int r = 0; /* Divide-by-zero returns zero */ if (!d) { *n = 0; return 0; } /* Common powers of 2 = simple shifts */ if (d == 2) { r = *n & 1; *n >>= 1; return r; } else if (d == 16) { r = *n & 0xf; *n >>= 4; return r; } /* If v fits in 32-bit, we're done. */ if (*n <= 0xffffffff) { uint32_t v32 = *n; r = v32 % d; *n = v32 / d; return r; } /* Otherwise do integer division the slow way. */ for (mask = (1ULL << 63); mask; mask >>= 1) { r <<= 1; if (*n & mask) r |= 1; if (r >= d) { r -= d; q |= mask; } } *n = q; return r; } int get_next_bit(uint32_t *mask) { int bit = 31 - __builtin_clz(*mask); *mask &= ~(1 << bit); return bit; } /****************************************************************************/ /* stateful conditional stuff */ enum cond_internal_bits { COND_CURR_MASK = (1 << 0), /* current value */ COND_RISE_MASK = (1 << 1), /* set if 0->1 */ COND_FALL_MASK = (1 << 2), /* set if 1->0 */ }; void cond_init(cond_t *c, int val) { if (val) *c = COND_CURR_MASK; else *c = 0; } int cond_is(cond_t *c, int val) { if (val) return *c & COND_CURR_MASK; else return !(*c & COND_CURR_MASK); } void cond_set(cond_t *c, int val) { if (val && cond_is(c, 0)) *c |= COND_RISE_MASK; else if (!val && cond_is(c, 1)) *c |= COND_FALL_MASK; if (val) *c |= COND_CURR_MASK; else *c &= ~COND_CURR_MASK; } int cond_went(cond_t *c, int val) { int ret; if (val) { ret = *c & COND_RISE_MASK; *c &= ~COND_RISE_MASK; } else { ret = *c & COND_FALL_MASK; *c &= ~COND_FALL_MASK; } return ret; } /****************************************************************************/ /* console command parsing */ /** * Parse offset and size from command line argv[shift] and argv[shift+1] * * Default values: If argc<=shift, leaves offset unchanged, returning error if * *offset<0. If argc shift) { i = (uint32_t)strtoi(argv[shift], &e, 0); if (*e) return EC_ERROR_PARAM1; *offset = i; } else if (*offset < 0) return EC_ERROR_PARAM_COUNT; if (argc > shift + 1) { i = (uint32_t)strtoi(argv[shift + 1], &e, 0); if (*e) return EC_ERROR_PARAM2; *size = i; } else if (*size < 0) return EC_ERROR_PARAM_COUNT; return EC_SUCCESS; }