coreboot-v3/util/dtc/libdt.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
   3 *
   4 * 
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation; either version 2 of the
   8 * License, or (at your option) any later version.
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 *  General Public License for more details.
  14 *                                                                       
  15 *  You should have received a copy of the GNU General Public License    
  16 *  along with this program; if not, write to the Free Software          
  17 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
  18 *                                                                   USA 
  19 */
  20
  21#include <stdint.h>
  22#include <string.h>
  23
  24#include "flat_dt.h"
  25
  26#define DALIGN(x, a)    (((x) + ((a) - 1)) & ~((a) - 1))
  27#define PALIGN(p, a)    ((void *)(DALIGN((unsigned long)(p), (a))))
  28#define GET_CELL(p)     (p += 4, *((uint32_t *)(p-4)))
  29
  30static char *skip_name(char *p)
  31{
  32        while (*p != '\0')
  33                p++;
  34
  35        return PALIGN(p, sizeof(uint32_t));
  36}
  37
  38static char *skip_prop(void *blob, char *p)
  39{
  40        struct boot_param_header *bph = blob;
  41        uint32_t len, nameoff;
  42
  43        len = GET_CELL(p);
  44        nameoff = GET_CELL(p);
  45        if ((bph->version < 0x10) && (len >= sizeof(uint64_t)))
  46                p = PALIGN(p, sizeof(uint64_t));
  47        return PALIGN(p + len, sizeof(uint32_t));
  48}
  49
  50static char *get_unit(char *dtpath)
  51{
  52        char *p;
  53
  54        if (dtpath[0] != '/')
  55                return dtpath;
  56
  57        p = dtpath + strlen(dtpath);
  58        while (*p != '/')
  59                p--;
  60
  61        return p+1;
  62}
  63
  64static int first_seg_len(char *dtpath)
  65{
  66        int len = 0;
  67
  68        while ((dtpath[len] != '/') && (dtpath[len] != '\0'))
  69                len++;
  70
  71        return len;
  72}
  73
  74char *flat_dt_get_string(void *blob, uint32_t offset)
  75{
  76        struct boot_param_header *bph = blob;
  77
  78        return (char *)blob + bph->off_dt_strings + offset;
  79}
  80
  81void *flat_dt_get_subnode(void *blob, void *node, char *uname, int unamelen)
  82{
  83        struct boot_param_header *bph = blob;
  84        char *p = node;
  85        uint32_t tag;
  86        int depth = 0;
  87        char *nuname;
  88
  89        if (! unamelen)
  90                unamelen = strlen(uname);
  91
  92        do {
  93                tag = GET_CELL(p);
  94
  95                switch (tag) {
  96                case OF_DT_PROP:
  97                        p = skip_prop(blob, p);
  98                        break;
  99
 100                case OF_DT_BEGIN_NODE:
 101                        if (depth == 0) {
 102                                nuname = p;
 103
 104                                if (bph->version < 0x10)
 105                                        nuname = get_unit(nuname);
 106
 107                                p = skip_name(p);
 108
 109                                if (strncmp(nuname, uname, unamelen) == 0)
 110                                        return p;
 111                        }
 112                        depth++;
 113                        break;
 114
 115                case OF_DT_END_NODE:
 116                        depth--;
 117                        break;
 118
 119                case OF_DT_END:
 120                        /* looks like a malformed tree */
 121                        return NULL;
 122                        break;
 123
 124                default:
 125                        /* FIXME: throw some sort of error */
 126                        return NULL;
 127                }
 128        } while (depth >= 0);
 129
 130        return NULL;
 131}
 132
 133void *flat_dt_get_node(void *blob, char *path)
 134{
 135        struct boot_param_header *bph = blob;
 136        char *node;
 137        int seglen;
 138
 139        node = blob + bph->off_dt_struct;
 140        node += sizeof(uint32_t); /* skip initial OF_DT_BEGIN_NODE */
 141        node = skip_name(node); /* skip root node name */
 142
 143        while (node && (*path)) {
 144                if (path[0] == '/')
 145                        path++;
 146
 147                seglen = first_seg_len(path);
 148
 149                node = flat_dt_get_subnode(blob, node, path, seglen);
 150
 151                path += seglen;
 152        }
 153
 154        return node;
 155}
 156
 157void flat_dt_traverse(void *blob,
 158                      int (*fn)(void *blob, void *node, void *priv),
 159                      void *private)
 160{
 161        struct boot_param_header *bph = blob;
 162        char *p;
 163        uint32_t tag;
 164        int depth = 0;
 165        char *uname;
 166
 167        p = (char *)blob + bph->off_dt_struct;
 168
 169        tag = GET_CELL(p);
 170        while (tag != OF_DT_END) {
 171                switch (tag) {
 172                case OF_DT_BEGIN_NODE:
 173                        uname = p;
 174
 175                        if (bph->version < 0x10)
 176                                uname = get_unit(uname);
 177
 178                        p = skip_name(p);
 179
 180                        (*fn)(blob, p, private);
 181                        depth++;
 182                        break;
 183
 184                case OF_DT_END_NODE:
 185                        depth--;
 186                        break;
 187
 188                case OF_DT_PROP:
 189                        p = skip_prop(blob, p);
 190                        break;
 191
 192                default:
 193                        /* FIXME: badly formed tree */
 194                        return;
 195                }
 196        }
 197}
 198
 199void *flat_dt_get_prop(void *blob, void *node, char *name, uint32_t *len)
 200{
 201        struct boot_param_header *bph = blob;
 202        char *p = node;
 203
 204        do {
 205                uint32_t tag = GET_CELL(p);
 206                uint32_t sz, noff;
 207                const char *nstr;
 208
 209                if (tag != OF_DT_PROP)
 210                        return NULL;
 211
 212                sz = GET_CELL(p);
 213                noff = GET_CELL(p);
 214
 215                /* Old versions have variable alignment of the
 216                 * property value */
 217                if ((bph->version < 0x10) && (sz >= 8))
 218                    p = PALIGN(p, 8);
 219
 220                nstr = flat_dt_get_string(blob, noff);
 221
 222                if (strcmp(name, nstr) == 0) {
 223                        if (len)
 224                                *len = sz;
 225                        return (void *)p;
 226                }
 227
 228                p = PALIGN(p + sz, sizeof(uint32_t));
 229        } while(1);
 230}
 231
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.