hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/scripts/dtc/libfdt/fdt_sw.c
....@@ -1,52 +1,7 @@
1
+// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
12 /*
23 * libfdt - Flat Device Tree manipulation
34 * Copyright (C) 2006 David Gibson, IBM Corporation.
4
- *
5
- * libfdt is dual licensed: you can use it either under the terms of
6
- * the GPL, or the BSD license, at your option.
7
- *
8
- * a) This library is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License as
10
- * published by the Free Software Foundation; either version 2 of the
11
- * License, or (at your option) any later version.
12
- *
13
- * This library is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public
19
- * License along with this library; if not, write to the Free
20
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21
- * MA 02110-1301 USA
22
- *
23
- * Alternatively,
24
- *
25
- * b) Redistribution and use in source and binary forms, with or
26
- * without modification, are permitted provided that the following
27
- * conditions are met:
28
- *
29
- * 1. Redistributions of source code must retain the above
30
- * copyright notice, this list of conditions and the following
31
- * disclaimer.
32
- * 2. Redistributions in binary form must reproduce the above
33
- * copyright notice, this list of conditions and the following
34
- * disclaimer in the documentation and/or other materials
35
- * provided with the distribution.
36
- *
37
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
505 */
516 #include "libfdt_env.h"
527
....@@ -55,25 +10,91 @@
5510
5611 #include "libfdt_internal.h"
5712
58
-static int fdt_sw_check_header_(void *fdt)
13
+static int fdt_sw_probe_(void *fdt)
5914 {
60
- if (fdt_magic(fdt) != FDT_SW_MAGIC)
61
- return -FDT_ERR_BADMAGIC;
62
- /* FIXME: should check more details about the header state */
15
+ if (!can_assume(VALID_INPUT)) {
16
+ if (fdt_magic(fdt) == FDT_MAGIC)
17
+ return -FDT_ERR_BADSTATE;
18
+ else if (fdt_magic(fdt) != FDT_SW_MAGIC)
19
+ return -FDT_ERR_BADMAGIC;
20
+ }
21
+
6322 return 0;
6423 }
6524
66
-#define FDT_SW_CHECK_HEADER(fdt) \
25
+#define FDT_SW_PROBE(fdt) \
6726 { \
6827 int err; \
69
- if ((err = fdt_sw_check_header_(fdt)) != 0) \
28
+ if ((err = fdt_sw_probe_(fdt)) != 0) \
7029 return err; \
7130 }
7231
32
+/* 'memrsv' state: Initial state after fdt_create()
33
+ *
34
+ * Allowed functions:
35
+ * fdt_add_reservemap_entry()
36
+ * fdt_finish_reservemap() [moves to 'struct' state]
37
+ */
38
+static int fdt_sw_probe_memrsv_(void *fdt)
39
+{
40
+ int err = fdt_sw_probe_(fdt);
41
+ if (err)
42
+ return err;
43
+
44
+ if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
45
+ return -FDT_ERR_BADSTATE;
46
+ return 0;
47
+}
48
+
49
+#define FDT_SW_PROBE_MEMRSV(fdt) \
50
+ { \
51
+ int err; \
52
+ if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
53
+ return err; \
54
+ }
55
+
56
+/* 'struct' state: Enter this state after fdt_finish_reservemap()
57
+ *
58
+ * Allowed functions:
59
+ * fdt_begin_node()
60
+ * fdt_end_node()
61
+ * fdt_property*()
62
+ * fdt_finish() [moves to 'complete' state]
63
+ */
64
+static int fdt_sw_probe_struct_(void *fdt)
65
+{
66
+ int err = fdt_sw_probe_(fdt);
67
+ if (err)
68
+ return err;
69
+
70
+ if (!can_assume(VALID_INPUT) &&
71
+ fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
72
+ return -FDT_ERR_BADSTATE;
73
+ return 0;
74
+}
75
+
76
+#define FDT_SW_PROBE_STRUCT(fdt) \
77
+ { \
78
+ int err; \
79
+ if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
80
+ return err; \
81
+ }
82
+
83
+static inline uint32_t sw_flags(void *fdt)
84
+{
85
+ /* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
86
+ return fdt_last_comp_version(fdt);
87
+}
88
+
89
+/* 'complete' state: Enter this state after fdt_finish()
90
+ *
91
+ * Allowed functions: none
92
+ */
93
+
7394 static void *fdt_grab_space_(void *fdt, size_t len)
7495 {
75
- int offset = fdt_size_dt_struct(fdt);
76
- int spaceleft;
96
+ unsigned int offset = fdt_size_dt_struct(fdt);
97
+ unsigned int spaceleft;
7798
7899 spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
79100 - fdt_size_dt_strings(fdt);
....@@ -85,26 +106,43 @@
85106 return fdt_offset_ptr_w_(fdt, offset);
86107 }
87108
88
-int fdt_create(void *buf, int bufsize)
109
+int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
89110 {
111
+ const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
112
+ sizeof(struct fdt_reserve_entry));
90113 void *fdt = buf;
91114
92
- if (bufsize < sizeof(struct fdt_header))
115
+ if (bufsize < hdrsize)
93116 return -FDT_ERR_NOSPACE;
117
+
118
+ if (flags & ~FDT_CREATE_FLAGS_ALL)
119
+ return -FDT_ERR_BADFLAGS;
94120
95121 memset(buf, 0, bufsize);
96122
123
+ /*
124
+ * magic and last_comp_version keep intermediate state during the fdt
125
+ * creation process, which is replaced with the proper FDT format by
126
+ * fdt_finish().
127
+ *
128
+ * flags should be accessed with sw_flags().
129
+ */
97130 fdt_set_magic(fdt, FDT_SW_MAGIC);
98131 fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
99
- fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
132
+ fdt_set_last_comp_version(fdt, flags);
133
+
100134 fdt_set_totalsize(fdt, bufsize);
101135
102
- fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
103
- sizeof(struct fdt_reserve_entry)));
136
+ fdt_set_off_mem_rsvmap(fdt, hdrsize);
104137 fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
105
- fdt_set_off_dt_strings(fdt, bufsize);
138
+ fdt_set_off_dt_strings(fdt, 0);
106139
107140 return 0;
141
+}
142
+
143
+int fdt_create(void *buf, int bufsize)
144
+{
145
+ return fdt_create_with_flags(buf, bufsize, 0);
108146 }
109147
110148 int fdt_resize(void *fdt, void *buf, int bufsize)
....@@ -112,12 +150,19 @@
112150 size_t headsize, tailsize;
113151 char *oldtail, *newtail;
114152
115
- FDT_SW_CHECK_HEADER(fdt);
153
+ FDT_SW_PROBE(fdt);
116154
117
- headsize = fdt_off_dt_struct(fdt);
155
+ if (bufsize < 0)
156
+ return -FDT_ERR_NOSPACE;
157
+
158
+ headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
118159 tailsize = fdt_size_dt_strings(fdt);
119160
120
- if ((headsize + tailsize) > bufsize)
161
+ if (!can_assume(VALID_DTB) &&
162
+ headsize + tailsize > fdt_totalsize(fdt))
163
+ return -FDT_ERR_INTERNAL;
164
+
165
+ if ((headsize + tailsize) > (unsigned)bufsize)
121166 return -FDT_ERR_NOSPACE;
122167
123168 oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
....@@ -133,8 +178,9 @@
133178 memmove(buf, fdt, headsize);
134179 }
135180
136
- fdt_set_off_dt_strings(buf, bufsize);
137181 fdt_set_totalsize(buf, bufsize);
182
+ if (fdt_off_dt_strings(buf))
183
+ fdt_set_off_dt_strings(buf, bufsize);
138184
139185 return 0;
140186 }
....@@ -144,10 +190,7 @@
144190 struct fdt_reserve_entry *re;
145191 int offset;
146192
147
- FDT_SW_CHECK_HEADER(fdt);
148
-
149
- if (fdt_size_dt_struct(fdt))
150
- return -FDT_ERR_BADSTATE;
193
+ FDT_SW_PROBE_MEMRSV(fdt);
151194
152195 offset = fdt_off_dt_struct(fdt);
153196 if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
....@@ -164,16 +207,23 @@
164207
165208 int fdt_finish_reservemap(void *fdt)
166209 {
167
- return fdt_add_reservemap_entry(fdt, 0, 0);
210
+ int err = fdt_add_reservemap_entry(fdt, 0, 0);
211
+
212
+ if (err)
213
+ return err;
214
+
215
+ fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
216
+ return 0;
168217 }
169218
170219 int fdt_begin_node(void *fdt, const char *name)
171220 {
172221 struct fdt_node_header *nh;
173
- int namelen = strlen(name) + 1;
222
+ int namelen;
174223
175
- FDT_SW_CHECK_HEADER(fdt);
224
+ FDT_SW_PROBE_STRUCT(fdt);
176225
226
+ namelen = strlen(name) + 1;
177227 nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
178228 if (! nh)
179229 return -FDT_ERR_NOSPACE;
....@@ -187,7 +237,7 @@
187237 {
188238 fdt32_t *en;
189239
190
- FDT_SW_CHECK_HEADER(fdt);
240
+ FDT_SW_PROBE_STRUCT(fdt);
191241
192242 en = fdt_grab_space_(fdt, FDT_TAGSIZE);
193243 if (! en)
....@@ -197,43 +247,73 @@
197247 return 0;
198248 }
199249
200
-static int fdt_find_add_string_(void *fdt, const char *s)
250
+static int fdt_add_string_(void *fdt, const char *s)
201251 {
202252 char *strtab = (char *)fdt + fdt_totalsize(fdt);
203
- const char *p;
253
+ unsigned int strtabsize = fdt_size_dt_strings(fdt);
254
+ unsigned int len = strlen(s) + 1;
255
+ unsigned int struct_top, offset;
256
+
257
+ offset = strtabsize + len;
258
+ struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
259
+ if (fdt_totalsize(fdt) - offset < struct_top)
260
+ return 0; /* no more room :( */
261
+
262
+ memcpy(strtab - offset, s, len);
263
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
264
+ return -offset;
265
+}
266
+
267
+/* Must only be used to roll back in case of error */
268
+static void fdt_del_last_string_(void *fdt, const char *s)
269
+{
204270 int strtabsize = fdt_size_dt_strings(fdt);
205271 int len = strlen(s) + 1;
206
- int struct_top, offset;
272
+
273
+ fdt_set_size_dt_strings(fdt, strtabsize - len);
274
+}
275
+
276
+static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
277
+{
278
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
279
+ int strtabsize = fdt_size_dt_strings(fdt);
280
+ const char *p;
281
+
282
+ *allocated = 0;
207283
208284 p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
209285 if (p)
210286 return p - strtab;
211287
212
- /* Add it */
213
- offset = -strtabsize - len;
214
- struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
215
- if (fdt_totalsize(fdt) + offset < struct_top)
216
- return 0; /* no more room :( */
288
+ *allocated = 1;
217289
218
- memcpy(strtab + offset, s, len);
219
- fdt_set_size_dt_strings(fdt, strtabsize + len);
220
- return offset;
290
+ return fdt_add_string_(fdt, s);
221291 }
222292
223293 int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
224294 {
225295 struct fdt_property *prop;
226296 int nameoff;
297
+ int allocated;
227298
228
- FDT_SW_CHECK_HEADER(fdt);
299
+ FDT_SW_PROBE_STRUCT(fdt);
229300
230
- nameoff = fdt_find_add_string_(fdt, name);
301
+ /* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
302
+ if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
303
+ allocated = 1;
304
+ nameoff = fdt_add_string_(fdt, name);
305
+ } else {
306
+ nameoff = fdt_find_add_string_(fdt, name, &allocated);
307
+ }
231308 if (nameoff == 0)
232309 return -FDT_ERR_NOSPACE;
233310
234311 prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
235
- if (! prop)
312
+ if (! prop) {
313
+ if (allocated)
314
+ fdt_del_last_string_(fdt, name);
236315 return -FDT_ERR_NOSPACE;
316
+ }
237317
238318 prop->tag = cpu_to_fdt32(FDT_PROP);
239319 prop->nameoff = cpu_to_fdt32(nameoff);
....@@ -262,7 +342,7 @@
262342 uint32_t tag;
263343 int offset, nextoffset;
264344
265
- FDT_SW_CHECK_HEADER(fdt);
345
+ FDT_SW_PROBE_STRUCT(fdt);
266346
267347 /* Add terminator */
268348 end = fdt_grab_space_(fdt, sizeof(*end));
....@@ -295,6 +375,10 @@
295375
296376 /* Finally, adjust the header */
297377 fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
378
+
379
+ /* And fix up fields that were keeping intermediate state. */
380
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
298381 fdt_set_magic(fdt, FDT_MAGIC);
382
+
299383 return 0;
300384 }