|
@@ -0,0 +1,243 @@
|
|
|
+/*
|
|
|
+ * 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 <u.h>
|
|
|
+#include <libc.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 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);
|
|
|
+}
|
|
|
+
|
|
|
+static inline uint64_t get_uint(query_result res)
|
|
|
+{
|
|
|
+ uint64_t v;
|
|
|
+ char *name;
|
|
|
+
|
|
|
+ name = malloc(res.end - res.start + 1);
|
|
|
+ parse_string(res, name);
|
|
|
+ v = __get_uint(name);
|
|
|
+ free(name);
|
|
|
+ return v;
|
|
|
+}
|
|
|
+
|
|
|
+/* this will be needed, but just not yet.*/
|
|
|
+#if 0
|
|
|
+static inline int64_t get_sint(query_result res)
|
|
|
+{
|
|
|
+ int64_t v;
|
|
|
+ char *name;
|
|
|
+
|
|
|
+ name = malloc(res.end - res.start + 1);
|
|
|
+ parse_string(res, name);
|
|
|
+ if (name[0] == '-')
|
|
|
+ return -__get_uint(name + 1);
|
|
|
+ v = __get_uint(name);
|
|
|
+ free(name);
|
|
|
+ return v;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+void query_mem(const char *config_string, uintptr_t *base, size_t *size)
|
|
|
+{
|
|
|
+ *base = 0;
|
|
|
+ *size = 0;
|
|
|
+ query_result res = query_config_string(config_string, "ram{0{addr");
|
|
|
+ if (!res.start)
|
|
|
+ return;
|
|
|
+ *base = get_uint(res);
|
|
|
+ res = query_config_string(config_string, "ram{0{size");
|
|
|
+ if (!res.start)
|
|
|
+ return;
|
|
|
+ *size = get_uint(res);
|
|
|
+}
|
|
|
+
|
|
|
+/* query_rtc returns the physical address of the rtc. */
|
|
|
+void query_rtc(const char *config_string, uintptr_t *mtime)
|
|
|
+{
|
|
|
+ *mtime = 0;
|
|
|
+ query_result res = query_config_string(config_string, "rtc{addr");
|
|
|
+ if (!res.start)
|
|
|
+ return;
|
|
|
+ *mtime = (uintptr_t)get_uint(res);
|
|
|
+}
|
|
|
+
|
|
|
+int query_uint(const char *configstring, char *name, uintptr_t *res)
|
|
|
+{
|
|
|
+ query_result m;
|
|
|
+
|
|
|
+ m = query_config_string(configstring, name);
|
|
|
+ if (m.start) {
|
|
|
+ *res = (uintptr_t)get_uint(m);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|