linux/scripts/dtc/yamltree.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * (C) Copyright Linaro, Ltd. 2018
   4 * (C) Copyright Arm Holdings.  2017
   5 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
   6 */
   7
   8#include <stdlib.h>
   9#include <yaml.h>
  10#include "dtc.h"
  11#include "srcpos.h"
  12
  13char *yaml_error_name[] = {
  14        [YAML_NO_ERROR] = "no error",
  15        [YAML_MEMORY_ERROR] = "memory error",
  16        [YAML_READER_ERROR] = "reader error",
  17        [YAML_SCANNER_ERROR] = "scanner error",
  18        [YAML_PARSER_ERROR] = "parser error",
  19        [YAML_COMPOSER_ERROR] = "composer error",
  20        [YAML_WRITER_ERROR] = "writer error",
  21        [YAML_EMITTER_ERROR] = "emitter error",
  22};
  23
  24#define yaml_emitter_emit_or_die(emitter, event) (                      \
  25{                                                                       \
  26        if (!yaml_emitter_emit(emitter, event))                         \
  27                die("yaml '%s': %s in %s, line %i\n",                   \
  28                    yaml_error_name[(emitter)->error],                  \
  29                    (emitter)->problem, __func__, __LINE__);            \
  30})
  31
  32static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
  33{
  34        yaml_event_t event;
  35        void *tag;
  36        int off, start_offset = markers->offset;
  37
  38        switch(width) {
  39                case 1: tag = "!u8"; break;
  40                case 2: tag = "!u16"; break;
  41                case 4: tag = "!u32"; break;
  42                case 8: tag = "!u64"; break;
  43                default:
  44                        die("Invalid width %i", width);
  45        }
  46        assert(len % width == 0);
  47
  48        yaml_sequence_start_event_initialize(&event, NULL,
  49                (yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
  50        yaml_emitter_emit_or_die(emitter, &event);
  51
  52        for (off = 0; off < len; off += width) {
  53                char buf[32];
  54                struct marker *m;
  55                bool is_phandle = false;
  56
  57                switch(width) {
  58                case 1:
  59                        sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
  60                        break;
  61                case 2:
  62                        sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off)));
  63                        break;
  64                case 4:
  65                        sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off)));
  66                        m = markers;
  67                        is_phandle = false;
  68                        for_each_marker_of_type(m, REF_PHANDLE) {
  69                                if (m->offset == (start_offset + off)) {
  70                                        is_phandle = true;
  71                                        break;
  72                                }
  73                        }
  74                        break;
  75                case 8:
  76                        sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off)));
  77                        break;
  78                }
  79
  80                if (is_phandle)
  81                        yaml_scalar_event_initialize(&event, NULL,
  82                                (yaml_char_t*)"!phandle", (yaml_char_t *)buf,
  83                                strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
  84                else
  85                        yaml_scalar_event_initialize(&event, NULL,
  86                                (yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
  87                                strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
  88                yaml_emitter_emit_or_die(emitter, &event);
  89        }
  90
  91        yaml_sequence_end_event_initialize(&event);
  92        yaml_emitter_emit_or_die(emitter, &event);
  93}
  94
  95static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
  96{
  97        yaml_event_t event;
  98        int i;
  99
 100        assert(str[len-1] == '\0');
 101
 102        /* Make sure the entire string is in the lower 7-bit ascii range */
 103        for (i = 0; i < len; i++)
 104                assert(isascii(str[i]));
 105
 106        yaml_scalar_event_initialize(&event, NULL,
 107                (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
 108                len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
 109        yaml_emitter_emit_or_die(emitter, &event);
 110}
 111
 112static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
 113{
 114        yaml_event_t event;
 115        int len = prop->val.len;
 116        struct marker *m = prop->val.markers;
 117
 118        /* Emit the property name */
 119        yaml_scalar_event_initialize(&event, NULL,
 120                (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
 121                strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
 122        yaml_emitter_emit_or_die(emitter, &event);
 123
 124        /* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
 125        if (len == 0) {
 126                yaml_scalar_event_initialize(&event, NULL,
 127                        (yaml_char_t *)YAML_BOOL_TAG,
 128                        (yaml_char_t*)"true",
 129                        strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
 130                yaml_emitter_emit_or_die(emitter, &event);
 131                return;
 132        }
 133
 134        if (!m)
 135                die("No markers present in property '%s' value\n", prop->name);
 136
 137        yaml_sequence_start_event_initialize(&event, NULL,
 138                (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
 139        yaml_emitter_emit_or_die(emitter, &event);
 140
 141        /* Ensure we have a type marker before any phandle */
 142        for_each_marker(m) {
 143                int last_offset = 0;
 144                struct marker *type_m;
 145
 146                if (m->type >= TYPE_UINT8)
 147                        last_offset = m->offset;
 148
 149                if (!(m->next && m->next->type == REF_PHANDLE &&
 150                      last_offset < m->next->offset))
 151                        continue;
 152
 153                type_m = xmalloc(sizeof(*type_m));
 154                type_m->offset = m->next->offset;
 155                type_m->type = TYPE_UINT32;
 156                type_m->ref = NULL;
 157                type_m->next = m->next;
 158                m->next = type_m;
 159        }
 160
 161        m = prop->val.markers;
 162        for_each_marker(m) {
 163                int chunk_len;
 164                char *data = &prop->val.val[m->offset];
 165
 166                if (m->type < TYPE_UINT8)
 167                        continue;
 168
 169                chunk_len = type_marker_length(m) ? : len;
 170                assert(chunk_len > 0);
 171                len -= chunk_len;
 172
 173                switch(m->type) {
 174                case TYPE_UINT16:
 175                        yaml_propval_int(emitter, m, data, chunk_len, 2);
 176                        break;
 177                case TYPE_UINT32:
 178                        yaml_propval_int(emitter, m, data, chunk_len, 4);
 179                        break;
 180                case TYPE_UINT64:
 181                        yaml_propval_int(emitter, m, data, chunk_len, 8);
 182                        break;
 183                case TYPE_STRING:
 184                        yaml_propval_string(emitter, data, chunk_len);
 185                        break;
 186                default:
 187                        yaml_propval_int(emitter, m, data, chunk_len, 1);
 188                        break;
 189                }
 190        }
 191
 192        yaml_sequence_end_event_initialize(&event);
 193        yaml_emitter_emit_or_die(emitter, &event);
 194}
 195
 196
 197static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
 198{
 199        struct property *prop;
 200        struct node *child;
 201        yaml_event_t event;
 202
 203        if (tree->deleted)
 204                return;
 205
 206        yaml_mapping_start_event_initialize(&event, NULL,
 207                (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
 208        yaml_emitter_emit_or_die(emitter, &event);
 209
 210        for_each_property(tree, prop)
 211                yaml_propval(emitter, prop);
 212
 213        /* Loop over all the children, emitting them into the map */
 214        for_each_child(tree, child) {
 215                yaml_scalar_event_initialize(&event, NULL,
 216                        (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
 217                        strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
 218                yaml_emitter_emit_or_die(emitter, &event);
 219                yaml_tree(child, emitter);
 220        }
 221
 222        yaml_mapping_end_event_initialize(&event);
 223        yaml_emitter_emit_or_die(emitter, &event);
 224}
 225
 226void dt_to_yaml(FILE *f, struct dt_info *dti)
 227{
 228        yaml_emitter_t emitter;
 229        yaml_event_t event;
 230
 231        yaml_emitter_initialize(&emitter);
 232        yaml_emitter_set_output_file(&emitter, f);
 233        yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
 234        yaml_emitter_emit_or_die(&emitter, &event);
 235
 236        yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
 237        yaml_emitter_emit_or_die(&emitter, &event);
 238
 239        yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
 240        yaml_emitter_emit_or_die(&emitter, &event);
 241
 242        yaml_tree(dti->dt, &emitter);
 243
 244        yaml_sequence_end_event_initialize(&event);
 245        yaml_emitter_emit_or_die(&emitter, &event);
 246
 247        yaml_document_end_event_initialize(&event, 0);
 248        yaml_emitter_emit_or_die(&emitter, &event);
 249
 250        yaml_stream_end_event_initialize(&event);
 251        yaml_emitter_emit_or_die(&emitter, &event);
 252
 253        yaml_emitter_delete(&emitter);
 254}
 255