x86, powerpc: Rename memcpy_mcsafe() to copy_mc_to_{user, kernel}()
[linux-2.6-microblaze.git] / lib / bootconfig.c
index ec3ce7f..a5f7011 100644 (file)
@@ -29,12 +29,14 @@ static int xbc_node_num __initdata;
 static char *xbc_data __initdata;
 static size_t xbc_data_size __initdata;
 static struct xbc_node *last_parent __initdata;
+static const char *xbc_err_msg __initdata;
+static int xbc_err_pos __initdata;
 
 static int __init xbc_parse_error(const char *msg, const char *p)
 {
-       int pos = p - xbc_data;
+       xbc_err_msg = msg;
+       xbc_err_pos = (int)(p - xbc_data);
 
-       pr_err("Parse error at pos %d: %s\n", pos, msg);
        return -EINVAL;
 }
 
@@ -327,22 +329,30 @@ const char * __init xbc_node_find_next_key_value(struct xbc_node *root,
 
 /* XBC parse and tree build */
 
+static int __init xbc_init_node(struct xbc_node *node, char *data, u32 flag)
+{
+       unsigned long offset = data - xbc_data;
+
+       if (WARN_ON(offset >= XBC_DATA_MAX))
+               return -EINVAL;
+
+       node->data = (u16)offset | flag;
+       node->child = 0;
+       node->next = 0;
+
+       return 0;
+}
+
 static struct xbc_node * __init xbc_add_node(char *data, u32 flag)
 {
        struct xbc_node *node;
-       unsigned long offset;
 
        if (xbc_node_num == XBC_NODE_MAX)
                return NULL;
 
        node = &xbc_nodes[xbc_node_num++];
-       offset = data - xbc_data;
-       node->data = (u16)offset;
-       if (WARN_ON(offset >= XBC_DATA_MAX))
+       if (xbc_init_node(node, data, flag) < 0)
                return NULL;
-       node->data |= flag;
-       node->child = 0;
-       node->next = 0;
 
        return node;
 }
@@ -601,7 +611,9 @@ static int __init xbc_parse_kv(char **k, char *v, int op)
        if (c < 0)
                return c;
 
-       if (!xbc_add_sibling(v, XBC_VALUE))
+       if (op == ':' && child) {
+               xbc_init_node(child, v, XBC_VALUE);
+       } else if (!xbc_add_sibling(v, XBC_VALUE))
                return -ENOMEM;
 
        if (c == ',') { /* Array */
@@ -738,33 +750,44 @@ void __init xbc_destroy_all(void)
 /**
  * xbc_init() - Parse given XBC file and build XBC internal tree
  * @buf: boot config text
+ * @emsg: A pointer of const char * to store the error message
+ * @epos: A pointer of int to store the error position
  *
  * This parses the boot config text in @buf. @buf must be a
  * null terminated string and smaller than XBC_DATA_MAX.
  * Return the number of stored nodes (>0) if succeeded, or -errno
  * if there is any error.
+ * In error cases, @emsg will be updated with an error message and
+ * @epos will be updated with the error position which is the byte offset
+ * of @buf. If the error is not a parser error, @epos will be -1.
  */
-int __init xbc_init(char *buf)
+int __init xbc_init(char *buf, const char **emsg, int *epos)
 {
        char *p, *q;
        int ret, c;
 
+       if (epos)
+               *epos = -1;
+
        if (xbc_data) {
-               pr_err("Error: bootconfig is already initialized.\n");
+               if (emsg)
+                       *emsg = "Bootconfig is already initialized";
                return -EBUSY;
        }
 
        ret = strlen(buf);
        if (ret > XBC_DATA_MAX - 1 || ret == 0) {
-               pr_err("Error: Config data is %s.\n",
-                       ret ? "too big" : "empty");
+               if (emsg)
+                       *emsg = ret ? "Config data is too big" :
+                               "Config data is empty";
                return -ERANGE;
        }
 
        xbc_nodes = memblock_alloc(sizeof(struct xbc_node) * XBC_NODE_MAX,
                                   SMP_CACHE_BYTES);
        if (!xbc_nodes) {
-               pr_err("Failed to allocate memory for bootconfig nodes.\n");
+               if (emsg)
+                       *emsg = "Failed to allocate bootconfig nodes";
                return -ENOMEM;
        }
        memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX);
@@ -774,7 +797,7 @@ int __init xbc_init(char *buf)
 
        p = buf;
        do {
-               q = strpbrk(p, "{}=+;\n#");
+               q = strpbrk(p, "{}=+;:\n#");
                if (!q) {
                        p = skip_spaces(p);
                        if (*p != '\0')
@@ -785,9 +808,12 @@ int __init xbc_init(char *buf)
                c = *q;
                *q++ = '\0';
                switch (c) {
+               case ':':
                case '+':
                        if (*q++ != '=') {
-                               ret = xbc_parse_error("Wrong '+' operator",
+                               ret = xbc_parse_error(c == '+' ?
+                                               "Wrong '+' operator" :
+                                               "Wrong ':' operator",
                                                        q - 2);
                                break;
                        }
@@ -814,9 +840,13 @@ int __init xbc_init(char *buf)
        if (!ret)
                ret = xbc_verify_tree();
 
-       if (ret < 0)
+       if (ret < 0) {
+               if (epos)
+                       *epos = xbc_err_pos;
+               if (emsg)
+                       *emsg = xbc_err_msg;
                xbc_destroy_all();
-       else
+       else
                ret = xbc_node_num;
 
        return ret;