Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: yamltree.c,v 1.1.1.1 2019/12/22 12:34:03 skrll Exp $	*/
      2 
      3 // SPDX-License-Identifier: GPL-2.0-or-later
      4 /*
      5  * (C) Copyright Linaro, Ltd. 2018
      6  * (C) Copyright Arm Holdings.  2017
      7  * (C) Copyright David Gibson <dwg (at) au1.ibm.com>, IBM Corporation.  2005.
      8  */
      9 
     10 #include <stdlib.h>
     11 #include <yaml.h>
     12 #include "dtc.h"
     13 #include "srcpos.h"
     14 
     15 char *yaml_error_name[] = {
     16 	[YAML_NO_ERROR] = "no error",
     17 	[YAML_MEMORY_ERROR] = "memory error",
     18 	[YAML_READER_ERROR] = "reader error",
     19 	[YAML_SCANNER_ERROR] = "scanner error",
     20 	[YAML_PARSER_ERROR] = "parser error",
     21 	[YAML_COMPOSER_ERROR] = "composer error",
     22 	[YAML_WRITER_ERROR] = "writer error",
     23 	[YAML_EMITTER_ERROR] = "emitter error",
     24 };
     25 
     26 #define yaml_emitter_emit_or_die(emitter, event) (			\
     27 {									\
     28 	if (!yaml_emitter_emit(emitter, event))				\
     29 		die("yaml '%s': %s in %s, line %i\n",			\
     30 		    yaml_error_name[(emitter)->error], 			\
     31 		    (emitter)->problem, __func__, __LINE__);		\
     32 })
     33 
     34 static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
     35 {
     36 	yaml_event_t event;
     37 	void *tag;
     38 	int off, start_offset = markers->offset;
     39 
     40 	switch(width) {
     41 		case 1: tag = "!u8"; break;
     42 		case 2: tag = "!u16"; break;
     43 		case 4: tag = "!u32"; break;
     44 		case 8: tag = "!u64"; break;
     45 		default:
     46 			die("Invalid width %i", width);
     47 	}
     48 	assert(len % width == 0);
     49 
     50 	yaml_sequence_start_event_initialize(&event, NULL,
     51 		(yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
     52 	yaml_emitter_emit_or_die(emitter, &event);
     53 
     54 	for (off = 0; off < len; off += width) {
     55 		char buf[32];
     56 		struct marker *m;
     57 		bool is_phandle = false;
     58 
     59 		switch(width) {
     60 		case 1:
     61 			sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
     62 			break;
     63 		case 2:
     64 			sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off)));
     65 			break;
     66 		case 4:
     67 			sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off)));
     68 			m = markers;
     69 			is_phandle = false;
     70 			for_each_marker_of_type(m, REF_PHANDLE) {
     71 				if (m->offset == (start_offset + off)) {
     72 					is_phandle = true;
     73 					break;
     74 				}
     75 			}
     76 			break;
     77 		case 8:
     78 			sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off)));
     79 			break;
     80 		}
     81 
     82 		if (is_phandle)
     83 			yaml_scalar_event_initialize(&event, NULL,
     84 				(yaml_char_t*)"!phandle", (yaml_char_t *)buf,
     85 				strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
     86 		else
     87 			yaml_scalar_event_initialize(&event, NULL,
     88 				(yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
     89 				strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
     90 		yaml_emitter_emit_or_die(emitter, &event);
     91 	}
     92 
     93 	yaml_sequence_end_event_initialize(&event);
     94 	yaml_emitter_emit_or_die(emitter, &event);
     95 }
     96 
     97 static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
     98 {
     99 	yaml_event_t event;
    100 	int i;
    101 
    102 	assert(str[len-1] == '\0');
    103 
    104 	/* Make sure the entire string is in the lower 7-bit ascii range */
    105 	for (i = 0; i < len; i++)
    106 		assert(isascii(str[i]));
    107 
    108 	yaml_scalar_event_initialize(&event, NULL,
    109 		(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
    110 		len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
    111 	yaml_emitter_emit_or_die(emitter, &event);
    112 }
    113 
    114 static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
    115 {
    116 	yaml_event_t event;
    117 	int len = prop->val.len;
    118 	struct marker *m = prop->val.markers;
    119 
    120 	/* Emit the property name */
    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 	/* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
    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, m, data, chunk_len, 2);
    157 			break;
    158 		case TYPE_UINT32:
    159 			yaml_propval_int(emitter, m, data, chunk_len, 4);
    160 			break;
    161 		case TYPE_UINT64:
    162 			yaml_propval_int(emitter, m, data, 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, m, data, 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 	/* Loop over all the children, emitting them into the map */
    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 }
    236