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        for_each_marker(m) {
 142                int chunk_len;
 143                char *data = &prop->val.val[m->offset];
 144
 145                if (m->type < TYPE_UINT8)
 146                        continue;
 147
 148                chunk_len = type_marker_length(m) ? : len;
 149                assert(chunk_len > 0);
 150                len -= chunk_len;
 151
 152                switch(m->type) {
 153                case TYPE_UINT16:
 154                        yaml_propval_int(emitter, m, data, chunk_len, 2);
 155                        break;
 156                case TYPE_UINT32:
 157                        yaml_propval_int(emitter, m, data, chunk_len, 4);
 158                        break;
 159                case TYPE_UINT64:
 160                        yaml_propval_int(emitter, m, data, chunk_len, 8);
 161                        break;
 162                case TYPE_STRING:
 163                        yaml_propval_string(emitter, data, chunk_len);
 164                        break;
 165                default:
 166                        yaml_propval_int(emitter, m, data, chunk_len, 1);
 167                        break;
 168                }
 169        }
 170
 171        yaml_sequence_end_event_initialize(&event);
 172        yaml_emitter_emit_or_die(emitter, &event);
 173}
 174
 175
 176static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
 177{
 178        struct property *prop;
 179        struct node *child;
 180        yaml_event_t event;
 181
 182        if (tree->deleted)
 183                return;
 184
 185        yaml_mapping_start_event_initialize(&event, NULL,
 186                (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
 187        yaml_emitter_emit_or_die(emitter, &event);
 188
 189        for_each_property(tree, prop)
 190                yaml_propval(emitter, prop);
 191
 192        /* Loop over all the children, emitting them into the map */
 193        for_each_child(tree, child) {
 194                yaml_scalar_event_initialize(&event, NULL,
 195                        (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
 196                        strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
 197                yaml_emitter_emit_or_die(emitter, &event);
 198                yaml_tree(child, emitter);
 199        }
 200
 201        yaml_mapping_end_event_initialize(&event);
 202        yaml_emitter_emit_or_die(emitter, &event);
 203}
 204
 205void dt_to_yaml(FILE *f, struct dt_info *dti)
 206{
 207        yaml_emitter_t emitter;
 208        yaml_event_t event;
 209
 210        yaml_emitter_initialize(&emitter);
 211        yaml_emitter_set_output_file(&emitter, f);
 212        yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
 213        yaml_emitter_emit_or_die(&emitter, &event);
 214
 215        yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
 216        yaml_emitter_emit_or_die(&emitter, &event);
 217
 218        yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
 219        yaml_emitter_emit_or_die(&emitter, &event);
 220
 221        yaml_tree(dti->dt, &emitter);
 222
 223        yaml_sequence_end_event_initialize(&event);
 224        yaml_emitter_emit_or_die(&emitter, &event);
 225
 226        yaml_document_end_event_initialize(&event, 0);
 227        yaml_emitter_emit_or_die(&emitter, &event);
 228
 229        yaml_stream_end_event_initialize(&event);
 230        yaml_emitter_emit_or_die(&emitter, &event);
 231
 232        yaml_emitter_delete(&emitter);
 233}
 234