diff options
-rw-r--r-- | src/commonlib/configstring.c | 54 | ||||
-rw-r--r-- | src/commonlib/include/commonlib/configstring.h | 209 |
2 files changed, 263 insertions, 0 deletions
diff --git a/src/commonlib/configstring.c b/src/commonlib/configstring.c new file mode 100644 index 0000000000..40beb1659c --- /dev/null +++ b/src/commonlib/configstring.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013-2016, The Regents of the University of California + *(Regents). + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Regents nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + * ARISING + * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS + * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED + * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE + * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include <config.h> +#include <assert.h> +#include <string.h> +#include <commonlib/configstring.h> + +void query_mem(const char *config_string, uintptr_t *base, size_t *size) +{ + query_result res = query_config_string(config_string, "ram{0{addr"); + *base = get_uint(res); + res = query_config_string(config_string, "ram{0{size"); + *size = get_uint(res); +} + +/* query_rtc returns the physical address of the rtc. */ +void query_rtc(const char *config_string, uintptr_t *mtime) +{ + query_result res = query_config_string(config_string, "rtc{addr"); + *mtime = (uintptr_t)get_uint(res); +} + +const char *configstring(void) +{ + uint32_t addr = *(uint32_t *)CONFIG_ARCH_CONFIGSTRING_RISCV; + return (const char *)(uintptr_t)addr; +} diff --git a/src/commonlib/include/commonlib/configstring.h b/src/commonlib/include/commonlib/configstring.h new file mode 100644 index 0000000000..8aacbda909 --- /dev/null +++ b/src/commonlib/include/commonlib/configstring.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013-2016, The Regents of the University of California + *(Regents). + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Regents nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, + * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, + * ARISING + * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS + * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED + * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE + * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef RISCV_CONFIG_STRING_H +#define RISCV_CONFIG_STRING_H + +#include <stddef.h> +#include <stdint.h> + +static const char *skip_whitespace(const char *str) +{ + while (*str && *str <= ' ') + str++; + return str; +} + +static const char *skip_string(const char *str) +{ + while (*str && *str++ != '"') + ; + return str; +} + +static int is_hex(char ch) +{ + return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || + (ch >= 'A' && ch <= 'F'); +} + +static int parse_hex(char ch) +{ + return (ch >= '0' && ch <= '9') ? ch - '0' : (ch >= 'a' && ch <= 'f') + ? ch - 'a' + 10 + : ch - 'A' + 10; +} + +static const char *skip_key(const char *str) +{ + while (*str >= 35 && *str <= 122 && *str != ';') + str++; + return str; +} + +typedef struct { + const char *start; + const char *end; +} query_result; + +static inline query_result query_config_string(const char *str, const char *k) +{ + size_t ksize = 0; + while (k[ksize] && k[ksize] != '{') + ksize++; + int last = !k[ksize]; + + query_result res = {0, 0}; + while (1) { + const char *key_start = str = skip_whitespace(str); + const char *key_end = str = skip_key(str); + int match = (size_t)(key_end - key_start) == ksize; + if (match) + for (size_t i = 0; i < ksize; i++) + if (key_start[i] != k[i]) + match = 0; + const char *value_start = str = skip_whitespace(str); + while (*str != ';') { + if (!*str) { + return res; + } else if (*str == '"') { + str = skip_string(str + 1); + } else if (*str == '{') { + const char *search_key = + match && !last ? k + ksize + 1 : ""; + query_result inner_res = + query_config_string(str + 1, search_key); + if (inner_res.start) + return inner_res; + str = inner_res.end + 1; + } else { + str = skip_key(str); + } + str = skip_whitespace(str); + } + res.end = str; + if (match && last) { + res.start = value_start; + return res; + } + str = skip_whitespace(str + 1); + if (*str == '}') { + res.end = str; + return res; + } + } +} + +static void parse_string(query_result r, char *buf) +{ + if (r.start < r.end) { + if (*r.start == '"') { + for (const char *p = r.start + 1; + p < r.end && *p != '"'; p++) { + char ch = p[0]; + if (ch == '\\' && p[1] == 'x' && is_hex(p[2])) { + ch = parse_hex(p[2]); + if (is_hex(p[3])) { + ch = + (ch << 4) + parse_hex(p[3]); + p++; + } + p += 2; + } + *buf++ = ch; + } + } else { + for (const char *p = r.start; p < r.end && *p > ' '; + p++) + *buf++ = *p; + } + } + *buf = 0; +} + +static uint64_t __get_uint_hex(const char *s) +{ + uint64_t res = 0; + while (*s) { + if (is_hex(*s)) + res = (res << 4) + parse_hex(*s); + else if (*s != '_') + break; + s++; + } + return res; +} + +static uint64_t __get_uint_dec(const char *s) +{ + uint64_t res = 0; + while (*s) { + if (*s >= '0' && *s <= '9') + res = res * 10 + (*s - '0'); + else + break; + s++; + } + return res; +} + +static uint64_t __get_uint(const char *s) +{ + if (s[0] == '0' && s[1] == 'x') + return __get_uint_hex(s + 2); + return __get_uint_dec(s); +} + +// This is nasty. But the original code used a much nastier thing, +// an array declared as an automatic, which triggered gcc warnings +// as it was sized by the res.end - res.start. We'll need a better +// solution, long term. Malloc is probably not it. +static char name[1024]; +static inline uint64_t get_uint(query_result res) +{ + uint64_t v; + parse_string(res, name); + v = __get_uint(name); + return v; +} + +static inline int64_t get_sint(query_result res) +{ + int64_t v; + parse_string(res, name); + if (name[0] == '-') + return -__get_uint(name + 1); + v = __get_uint(name); + return v; +} + +const char *configstring(void); +void query_mem(const char *config_string, uintptr_t *base, size_t *size); +void query_rtc(const char *config_string, uintptr_t *mtime); +#endif |