summaryrefslogtreecommitdiff
path: root/util/cbfstool/fmd_parser.y
blob: a29c9d64ac3d21384f4707c639cfc2d9c64ae4d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* parser generator for flashmap descriptor language */
/* SPDX-License-Identifier: GPL-2.0-only */

%{
#include "fmd_scanner.h"
#include "common.h"

#include <stdlib.h>

struct flashmap_descriptor *res = NULL;
%}

%union {
	unsigned intval;
	char *strval;
	struct unsigned_option maybe_intval;
	struct flashmap_descriptor *region_ptr;
	union flashmap_flags flags;
	struct descriptor_list region_listhdr;
}

%code requires {
#include "fmd.h"
#include "option.h"

#include <stdbool.h>

struct descriptor_node {
	struct flashmap_descriptor *val;
	struct descriptor_node *next;
};

struct descriptor_list {
	size_t len;
	struct descriptor_node *head;
	struct descriptor_node *tail;
};

extern struct flashmap_descriptor *res;

struct flashmap_descriptor *parse_descriptor(
	char *name, union flashmap_flags flags, struct unsigned_option offset,
	struct unsigned_option size, struct descriptor_list children);
void yyerror(const char *s);
}

%token <intval> INTEGER
%token OCTAL
%token <strval> STRING
%token FLAG_CBFS
%token FLAG_PRESERVE

%type <region_ptr> flash_region
%type <strval> region_name
%type <flags> region_flags_opt
%type <flags> region_flags
%type <flags> region_flag
%type <maybe_intval> region_offset_opt
%type <maybe_intval> region_offset
%type <maybe_intval> region_size_opt
%type <maybe_intval> region_size
%type <region_listhdr> region_list_opt
%type <region_listhdr> region_list
%type <region_listhdr> region_list_entries

%%

flash_chip: region_name region_offset_opt region_size region_list
{
	union flashmap_flags flags = { .v=0 };
	if (!(res = parse_descriptor($1, flags, $2, $3, $4)))
		YYABORT;
};
flash_region: region_name region_flags_opt region_offset_opt region_size_opt
	      region_list_opt
{
	struct flashmap_descriptor *node = parse_descriptor($1, $2, $3, $4, $5);
	if (!node)
		YYABORT;

	if (node->flags.f.cbfs && !fmd_process_flag_cbfs(node)) {
		ERROR("Section '%s' cannot have flag 'CBFS''\n", node->name);
		YYABORT;
	}

	$$ = node;
};
region_name: STRING
{
	if (!$1) {
		perror("E: While allocating section name");
		YYABORT;
	}
};
region_flags_opt: { $$ = (union flashmap_flags){ .v=0 }; }
	| '(' region_flags ')' { $$ = $2; };
region_flags: region_flag | region_flag region_flags { $$.v = $1.v | $2.v; };
region_flag: FLAG_CBFS { $$.v = 0; $$.f.cbfs = 1; };
region_flag: FLAG_PRESERVE { $$.v = 0; $$.f.preserve = 1; };
region_offset_opt: { $$ = (struct unsigned_option){false, 0}; }
	| region_offset;
region_offset: '@' INTEGER { $$ = (struct unsigned_option){true, $2}; };
region_size_opt: { $$ = (struct unsigned_option){false, 0}; }
	| region_size;
region_size: INTEGER { $$ = (struct unsigned_option){true, $1}; };
region_list_opt:
{
	$$ = (struct descriptor_list)
					{.len = 0, .head = NULL, .tail = NULL};
}
	| region_list;
region_list: '{' region_list_entries '}' { $$ = $2; };
region_list_entries: flash_region
{
	struct descriptor_node *node = malloc(sizeof(*node));
	if (!node) {
		perror("E: While allocating linked list node");
		YYABORT;
	}
	node->val = $1;
	node->next = NULL;
	$$ = (struct descriptor_list){.len = 1, .head = node, .tail = node};
}
	| region_list_entries flash_region
{
	struct descriptor_node *node = malloc(sizeof(*node));
	if (!node) {
		perror("E: While allocating linked list node");
		YYABORT;
	}
	node->val = $2;
	node->next = NULL;

	$1.tail->next = node;
	$$ = (struct descriptor_list)
			{.len = $1.len + 1, .head = $1.head, .tail = node};
};

%%

struct flashmap_descriptor *parse_descriptor(
	char *name, union flashmap_flags flags, struct unsigned_option offset,
	struct unsigned_option size, struct descriptor_list children)
{
	struct flashmap_descriptor *region = malloc(sizeof(*region));
	if (!region) {
		perror("E: While allocating descriptor section");
		return NULL;
	}
	region->name = name;
	region->flags = flags;
	region->offset_known = offset.val_known;
	region->offset = offset.val;
	region->size_known = size.val_known;
	region->size = size.val;
	region->list_len = children.len;
	if (region->list_len) {
		region->list = malloc(region->list_len * sizeof(*region->list));
		if (!region->list) {
			perror("E: While allocating node children array");
			return NULL;
		}
		struct descriptor_node *cur_node = children.head;
		for (unsigned idx = 0; idx < region->list_len; ++idx) {
			region->list[idx] = cur_node->val;

			struct descriptor_node *next_node = cur_node->next;
			free(cur_node);
			cur_node = next_node;
		}
	} else {
		region->list = NULL;
	}
	return region;
}

void yyerror(const char *s)
{
	fprintf(stderr, "%s\n", s);
}