| 1 | |
| 2 | |
| 3 | * (C) Copyright Linaro, Ltd. 2018
|
| 4 | * (C) Copyright Arm Holdings. 2017
|
| 5 | * (C) Copyright David Gibson <[email protected]>, IBM Corporation. 2005.
|
| 6 |
|
| 7 |
|
| 8 | #include <stdlib.h>
|
| 9 | #include <yaml.h>
|
| 10 | #include "dtc.h"
|
| 11 | #include "srcpos.h"
|
| 12 |
|
| 13 | char *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 |
|
| 32 | static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers,
|
| 33 | char *data, unsigned int seq_offset, unsigned int len, int width)
|
| 34 | {
|
| 35 | yaml_event_t event;
|
| 36 | void *tag;
|
| 37 | unsigned int off;
|
| 38 |
|
| 39 | switch(width) {
|
| 40 | case 1: tag = "!u8"; break;
|
| 41 | case 2: tag = "!u16"; break;
|
| 42 | case 4: tag = "!u32"; break;
|
| 43 | case 8: tag = "!u64"; break;
|
| 44 | default:
|
| 45 | die("Invalid width %i", width);
|
| 46 | }
|
| 47 | assert(len % width == 0);
|
| 48 |
|
| 49 | yaml_sequence_start_event_initialize(&event, NULL,
|
| 50 | (yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
|
| 51 | yaml_emitter_emit_or_die(emitter, &event);
|
| 52 |
|
| 53 | for (off = 0; off < len; off += width) {
|
| 54 | char buf[32];
|
| 55 | struct marker *m;
|
| 56 | bool is_phandle = false;
|
| 57 |
|
| 58 | switch(width) {
|
| 59 | case 1:
|
| 60 | sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
|
| 61 | break;
|
| 62 | case 2:
|
| 63 | sprintf(buf, "0x%"PRIx16, dtb_ld16(data + off));
|
| 64 | break;
|
| 65 | case 4:
|
| 66 | sprintf(buf, "0x%"PRIx32, dtb_ld32(data + off));
|
| 67 | m = markers;
|
| 68 | is_phandle = false;
|
| 69 | for_each_marker_of_type(m, REF_PHANDLE) {
|
| 70 | if (m->offset == (seq_offset + off)) {
|
| 71 | is_phandle = true;
|
| 72 | break;
|
| 73 | }
|
| 74 | }
|
| 75 | break;
|
| 76 | case 8:
|
| 77 | sprintf(buf, "0x%"PRIx64, dtb_ld64(data + off));
|
| 78 | break;
|
| 79 | }
|
| 80 |
|
| 81 | if (is_phandle)
|
| 82 | yaml_scalar_event_initialize(&event, NULL,
|
| 83 | (yaml_char_t*)"!phandle", (yaml_char_t *)buf,
|
| 84 | strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
|
| 85 | else
|
| 86 | yaml_scalar_event_initialize(&event, NULL,
|
| 87 | (yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
|
| 88 | strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
|
| 89 | yaml_emitter_emit_or_die(emitter, &event);
|
| 90 | }
|
| 91 |
|
| 92 | yaml_sequence_end_event_initialize(&event);
|
| 93 | yaml_emitter_emit_or_die(emitter, &event);
|
| 94 | }
|
| 95 |
|
| 96 | static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
|
| 97 | {
|
| 98 | yaml_event_t event;
|
| 99 | int i;
|
| 100 |
|
| 101 | assert(str[len-1] == '\0');
|
| 102 |
|
| 103 |
|
| 104 | for (i = 0; i < len; i++)
|
| 105 | assert(isascii(str[i]));
|
| 106 |
|
| 107 | yaml_scalar_event_initialize(&event, NULL,
|
| 108 | (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
|
| 109 | len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
|
| 110 | yaml_emitter_emit_or_die(emitter, &event);
|
| 111 | }
|
| 112 |
|
| 113 | static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
|
| 114 | {
|
| 115 | yaml_event_t event;
|
| 116 | unsigned int len = prop->val.len;
|
| 117 | struct marker *m = prop->val.markers;
|
| 118 | struct marker *markers = prop->val.markers;
|
| 119 |
|
| 120 |
|
| 121 | yaml_scalar_event_initialize(&event, NULL,
|
| 122 | (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
|
| 123 | strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
|
| 124 | yaml_emitter_emit_or_die(emitter, &event);
|
| 125 |
|
| 126 |
|
| 127 | if (len == 0) {
|
| 128 | yaml_scalar_event_initialize(&event, NULL,
|
| 129 | (yaml_char_t *)YAML_BOOL_TAG,
|
| 130 | (yaml_char_t*)"true",
|
| 131 | strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
|
| 132 | yaml_emitter_emit_or_die(emitter, &event);
|
| 133 | return;
|
| 134 | }
|
| 135 |
|
| 136 | if (!m)
|
| 137 | die("No markers present in property '%s' value\n", prop->name);
|
| 138 |
|
| 139 | yaml_sequence_start_event_initialize(&event, NULL,
|
| 140 | (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
|
| 141 | yaml_emitter_emit_or_die(emitter, &event);
|
| 142 |
|
| 143 | for_each_marker(m) {
|
| 144 | int chunk_len;
|
| 145 | char *data = &prop->val.val[m->offset];
|
| 146 |
|
| 147 | if (m->type < TYPE_UINT8)
|
| 148 | continue;
|
| 149 |
|
| 150 | chunk_len = type_marker_length(m) ? : len;
|
| 151 | assert(chunk_len > 0);
|
| 152 | len -= chunk_len;
|
| 153 |
|
| 154 | switch(m->type) {
|
| 155 | case TYPE_UINT16:
|
| 156 | yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2);
|
| 157 | break;
|
| 158 | case TYPE_UINT32:
|
| 159 | yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4);
|
| 160 | break;
|
| 161 | case TYPE_UINT64:
|
| 162 | yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8);
|
| 163 | break;
|
| 164 | case TYPE_STRING:
|
| 165 | yaml_propval_string(emitter, data, chunk_len);
|
| 166 | break;
|
| 167 | default:
|
| 168 | yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1);
|
| 169 | break;
|
| 170 | }
|
| 171 | }
|
| 172 |
|
| 173 | yaml_sequence_end_event_initialize(&event);
|
| 174 | yaml_emitter_emit_or_die(emitter, &event);
|
| 175 | }
|
| 176 |
|
| 177 |
|
| 178 | static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
|
| 179 | {
|
| 180 | struct property *prop;
|
| 181 | struct node *child;
|
| 182 | yaml_event_t event;
|
| 183 |
|
| 184 | if (tree->deleted)
|
| 185 | return;
|
| 186 |
|
| 187 | yaml_mapping_start_event_initialize(&event, NULL,
|
| 188 | (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
|
| 189 | yaml_emitter_emit_or_die(emitter, &event);
|
| 190 |
|
| 191 | for_each_property(tree, prop)
|
| 192 | yaml_propval(emitter, prop);
|
| 193 |
|
| 194 |
|
| 195 | for_each_child(tree, child) {
|
| 196 | yaml_scalar_event_initialize(&event, NULL,
|
| 197 | (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
|
| 198 | strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
|
| 199 | yaml_emitter_emit_or_die(emitter, &event);
|
| 200 | yaml_tree(child, emitter);
|
| 201 | }
|
| 202 |
|
| 203 | yaml_mapping_end_event_initialize(&event);
|
| 204 | yaml_emitter_emit_or_die(emitter, &event);
|
| 205 | }
|
| 206 |
|
| 207 | void dt_to_yaml(FILE *f, struct dt_info *dti)
|
| 208 | {
|
| 209 | yaml_emitter_t emitter;
|
| 210 | yaml_event_t event;
|
| 211 |
|
| 212 | yaml_emitter_initialize(&emitter);
|
| 213 | yaml_emitter_set_output_file(&emitter, f);
|
| 214 | yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
|
| 215 | yaml_emitter_emit_or_die(&emitter, &event);
|
| 216 |
|
| 217 | yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
|
| 218 | yaml_emitter_emit_or_die(&emitter, &event);
|
| 219 |
|
| 220 | yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
|
| 221 | yaml_emitter_emit_or_die(&emitter, &event);
|
| 222 |
|
| 223 | yaml_tree(dti->dt, &emitter);
|
| 224 |
|
| 225 | yaml_sequence_end_event_initialize(&event);
|
| 226 | yaml_emitter_emit_or_die(&emitter, &event);
|
| 227 |
|
| 228 | yaml_document_end_event_initialize(&event, 0);
|
| 229 | yaml_emitter_emit_or_die(&emitter, &event);
|
| 230 |
|
| 231 | yaml_stream_end_event_initialize(&event);
|
| 232 | yaml_emitter_emit_or_die(&emitter, &event);
|
| 233 |
|
| 234 | yaml_emitter_delete(&emitter);
|
| 235 | }
|