examples/fips_validation: fix buffer overflow
[dpdk.git] / drivers / common / dpaax / dpaa_of.c
1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2  *
3  * Copyright 2010-2016 Freescale Semiconductor Inc.
4  * Copyright 2017 NXP
5  *
6  */
7
8 #include <dpaa_of.h>
9 #include <assert.h>
10 #include <rte_string_fns.h>
11 #include <dpaax_logs.h>
12
13 static int alive;
14 static struct dt_dir root_dir;
15 static const char *base_dir;
16 static COMPAT_LIST_HEAD(linear);
17
18 static int
19 of_open_dir(const char *relative_path, struct dirent ***d)
20 {
21         int ret;
22         char full_path[PATH_MAX];
23
24         snprintf(full_path, PATH_MAX, "%s/%s", base_dir, relative_path);
25         ret = scandir(full_path, d, 0, versionsort);
26         if (ret < 0)
27                 DPAAX_LOG(ERR, "Failed to open directory %s",
28                              full_path);
29         return ret;
30 }
31
32 static void
33 of_close_dir(struct dirent **d, int num)
34 {
35         while (num--)
36                 free(d[num]);
37         free(d);
38 }
39
40 static int
41 of_open_file(const char *relative_path)
42 {
43         int ret;
44         char full_path[PATH_MAX];
45
46         snprintf(full_path, PATH_MAX, "%s/%s", base_dir, relative_path);
47         ret = open(full_path, O_RDONLY);
48         if (ret < 0)
49                 DPAAX_LOG(ERR, "Failed to open directory %s",
50                              full_path);
51         return ret;
52 }
53
54 static void
55 process_file(struct dirent *dent, struct dt_dir *parent)
56 {
57         int fd;
58         struct dt_file *f = malloc(sizeof(*f));
59
60         if (!f) {
61                 DPAAX_LOG(DEBUG, "Unable to allocate memory for file node");
62                 return;
63         }
64         f->node.is_file = 1;
65         strlcpy(f->node.node.name, dent->d_name, NAME_MAX);
66         snprintf(f->node.node.full_name, PATH_MAX, "%s/%s",
67                  parent->node.node.full_name, dent->d_name);
68         f->parent = parent;
69         fd = of_open_file(f->node.node.full_name);
70         if (fd < 0) {
71                 DPAAX_LOG(DEBUG, "Unable to open file node");
72                 free(f);
73                 return;
74         }
75         f->len = read(fd, f->buf, OF_FILE_BUF_MAX);
76         close(fd);
77         if (f->len < 0) {
78                 DPAAX_LOG(DEBUG, "Unable to read file node");
79                 free(f);
80                 return;
81         }
82         list_add_tail(&f->node.list, &parent->files);
83 }
84
85 static const struct dt_dir *
86 node2dir(const struct device_node *n)
87 {
88         struct dt_node *dn = container_of((struct device_node *)n,
89                                           struct dt_node, node);
90         const struct dt_dir *d = container_of(dn, struct dt_dir, node);
91
92         assert(!dn->is_file);
93         return d;
94 }
95
96 /* process_dir() calls iterate_dir(), but the latter will also call the former
97  * when recursing into sub-directories, so a predeclaration is needed.
98  */
99 static int process_dir(const char *relative_path, struct dt_dir *dt);
100
101 static int
102 iterate_dir(struct dirent **d, int num, struct dt_dir *dt)
103 {
104         int loop;
105         /* Iterate the directory contents */
106         for (loop = 0; loop < num; loop++) {
107                 struct dt_dir *subdir;
108                 int ret;
109                 /* Ignore dot files of all types (especially "..") */
110                 if (d[loop]->d_name[0] == '.')
111                         continue;
112                 switch (d[loop]->d_type) {
113                 case DT_REG:
114                         process_file(d[loop], dt);
115                         break;
116                 case DT_DIR:
117                         subdir = malloc(sizeof(*subdir));
118                         if (!subdir) {
119                                 perror("malloc");
120                                 return -ENOMEM;
121                         }
122                         strlcpy(subdir->node.node.name, d[loop]->d_name,
123                                 NAME_MAX);
124                         snprintf(subdir->node.node.full_name, PATH_MAX,
125                                  "%s/%s", dt->node.node.full_name,
126                                  d[loop]->d_name);
127                         subdir->parent = dt;
128                         ret = process_dir(subdir->node.node.full_name, subdir);
129                         if (ret)
130                                 return ret;
131                         list_add_tail(&subdir->node.list, &dt->subdirs);
132                         break;
133                 default:
134                         DPAAX_LOG(DEBUG, "Ignoring invalid dt entry %s/%s",
135                                      dt->node.node.full_name, d[loop]->d_name);
136                 }
137         }
138         return 0;
139 }
140
141 static int
142 process_dir(const char *relative_path, struct dt_dir *dt)
143 {
144         struct dirent **d;
145         int ret, num;
146
147         dt->node.is_file = 0;
148         INIT_LIST_HEAD(&dt->subdirs);
149         INIT_LIST_HEAD(&dt->files);
150         ret = of_open_dir(relative_path, &d);
151         if (ret < 0)
152                 return ret;
153         num = ret;
154         ret = iterate_dir(d, num, dt);
155         of_close_dir(d, num);
156         return (ret < 0) ? ret : 0;
157 }
158
159 static void
160 linear_dir(struct dt_dir *d)
161 {
162         struct dt_file *f;
163         struct dt_dir *dd;
164
165         d->compatible = NULL;
166         d->status = NULL;
167         d->lphandle = NULL;
168         d->a_cells = NULL;
169         d->s_cells = NULL;
170         d->reg = NULL;
171         list_for_each_entry(f, &d->files, node.list) {
172                 if (!strcmp(f->node.node.name, "compatible")) {
173                         if (d->compatible)
174                                 DPAAX_LOG(DEBUG, "Duplicate compatible in"
175                                              " %s", d->node.node.full_name);
176                         d->compatible = f;
177                 } else if (!strcmp(f->node.node.name, "status")) {
178                         if (d->status)
179                                 DPAAX_LOG(DEBUG, "Duplicate status in %s",
180                                              d->node.node.full_name);
181                         d->status = f;
182                 } else if (!strcmp(f->node.node.name, "linux,phandle")) {
183                         if (d->lphandle)
184                                 DPAAX_LOG(DEBUG, "Duplicate lphandle in %s",
185                                              d->node.node.full_name);
186                         d->lphandle = f;
187                 } else if (!strcmp(f->node.node.name, "phandle")) {
188                         if (d->lphandle)
189                                 DPAAX_LOG(DEBUG, "Duplicate lphandle in %s",
190                                              d->node.node.full_name);
191                         d->lphandle = f;
192                 } else if (!strcmp(f->node.node.name, "#address-cells")) {
193                         if (d->a_cells)
194                                 DPAAX_LOG(DEBUG, "Duplicate a_cells in %s",
195                                              d->node.node.full_name);
196                         d->a_cells = f;
197                 } else if (!strcmp(f->node.node.name, "#size-cells")) {
198                         if (d->s_cells)
199                                 DPAAX_LOG(DEBUG, "Duplicate s_cells in %s",
200                                              d->node.node.full_name);
201                         d->s_cells = f;
202                 } else if (!strcmp(f->node.node.name, "reg")) {
203                         if (d->reg)
204                                 DPAAX_LOG(DEBUG, "Duplicate reg in %s",
205                                              d->node.node.full_name);
206                         d->reg = f;
207                 }
208         }
209
210         list_for_each_entry(dd, &d->subdirs, node.list) {
211                 list_add_tail(&dd->linear, &linear);
212                 linear_dir(dd);
213         }
214 }
215
216 int
217 of_init_path(const char *dt_path)
218 {
219         int ret;
220
221         base_dir = dt_path;
222
223         /* This needs to be singleton initialization */
224         DPAAX_HWWARN(alive, "Double-init of device-tree driver!");
225
226         /* Prepare root node (the remaining fields are set in process_dir()) */
227         root_dir.node.node.name[0] = '\0';
228         root_dir.node.node.full_name[0] = '\0';
229         INIT_LIST_HEAD(&root_dir.node.list);
230         root_dir.parent = NULL;
231
232         /* Kick things off... */
233         ret = process_dir("", &root_dir);
234         if (ret) {
235                 DPAAX_LOG(ERR, "Unable to parse device tree");
236                 return ret;
237         }
238
239         /* Now make a flat, linear list of directories */
240         linear_dir(&root_dir);
241         alive = 1;
242         return 0;
243 }
244
245 static void
246 destroy_dir(struct dt_dir *d)
247 {
248         struct dt_file *f, *tmpf;
249         struct dt_dir *dd, *tmpd;
250
251         list_for_each_entry_safe(f, tmpf, &d->files, node.list) {
252                 list_del(&f->node.list);
253                 free(f);
254         }
255         list_for_each_entry_safe(dd, tmpd, &d->subdirs, node.list) {
256                 destroy_dir(dd);
257                 list_del(&dd->node.list);
258                 free(dd);
259         }
260 }
261
262 void
263 of_finish(void)
264 {
265         DPAAX_HWWARN(!alive, "Double-finish of device-tree driver!");
266
267         destroy_dir(&root_dir);
268         INIT_LIST_HEAD(&linear);
269         alive = 0;
270 }
271
272 static const struct dt_dir *
273 next_linear(const struct dt_dir *f)
274 {
275         if (f->linear.next == &linear)
276                 return NULL;
277         return list_entry(f->linear.next, struct dt_dir, linear);
278 }
279
280 static int
281 check_compatible(const struct dt_file *f, const char *compatible)
282 {
283         const char *c = (char *)f->buf;
284         unsigned int len, remains = f->len;
285
286         while (remains) {
287                 len = strlen(c);
288                 if (!strcmp(c, compatible))
289                         return 1;
290
291                 if (remains < len + 1)
292                         break;
293
294                 c += (len + 1);
295                 remains -= (len + 1);
296         }
297         return 0;
298 }
299
300 const struct device_node *
301 of_find_compatible_node(const struct device_node *from,
302                         const char *type __rte_unused,
303                         const char *compatible)
304 {
305         const struct dt_dir *d;
306
307         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
308
309         if (list_empty(&linear))
310                 return NULL;
311         if (!from)
312                 d = list_entry(linear.next, struct dt_dir, linear);
313         else
314                 d = node2dir(from);
315         for (d = next_linear(d); d && (!d->compatible ||
316                                        !check_compatible(d->compatible,
317                                        compatible));
318                         d = next_linear(d))
319                 ;
320         if (d)
321                 return &d->node.node;
322         return NULL;
323 }
324
325 const void *
326 of_get_property(const struct device_node *from, const char *name,
327                 size_t *lenp)
328 {
329         const struct dt_dir *d;
330         const struct dt_file *f;
331
332         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
333
334         d = node2dir(from);
335         list_for_each_entry(f, &d->files, node.list)
336                 if (!strcmp(f->node.node.name, name)) {
337                         if (lenp)
338                                 *lenp = f->len;
339                         return f->buf;
340                 }
341         return NULL;
342 }
343
344 bool
345 of_device_is_available(const struct device_node *dev_node)
346 {
347         const struct dt_dir *d;
348
349         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
350         d = node2dir(dev_node);
351         if (!d->status)
352                 return true;
353         if (!strcmp((char *)d->status->buf, "okay"))
354                 return true;
355         if (!strcmp((char *)d->status->buf, "ok"))
356                 return true;
357         return false;
358 }
359
360 const struct device_node *
361 of_find_node_by_phandle(uint64_t ph)
362 {
363         const struct dt_dir *d;
364
365         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
366         list_for_each_entry(d, &linear, linear)
367                 if (d->lphandle && (d->lphandle->len == 4) &&
368                     !memcmp(d->lphandle->buf, &ph, 4))
369                         return &d->node.node;
370         return NULL;
371 }
372
373 const struct device_node *
374 of_get_parent(const struct device_node *dev_node)
375 {
376         const struct dt_dir *d;
377
378         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
379
380         if (!dev_node)
381                 return NULL;
382         d = node2dir(dev_node);
383         if (!d->parent)
384                 return NULL;
385         return &d->parent->node.node;
386 }
387
388 const struct device_node *
389 of_get_next_child(const struct device_node *dev_node,
390                   const struct device_node *prev)
391 {
392         const struct dt_dir *p, *c;
393
394         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
395
396         if (!dev_node)
397                 return NULL;
398         p = node2dir(dev_node);
399         if (prev) {
400                 c = node2dir(prev);
401                 DPAAX_HWWARN((c->parent != p), "Parent/child mismatch");
402                 if (c->parent != p)
403                         return NULL;
404                 if (c->node.list.next == &p->subdirs)
405                         /* prev was the last child */
406                         return NULL;
407                 c = list_entry(c->node.list.next, struct dt_dir, node.list);
408                 return &c->node.node;
409         }
410         /* Return first child */
411         if (list_empty(&p->subdirs))
412                 return NULL;
413         c = list_entry(p->subdirs.next, struct dt_dir, node.list);
414         return &c->node.node;
415 }
416
417 uint32_t
418 of_n_addr_cells(const struct device_node *dev_node)
419 {
420         const struct dt_dir *d;
421
422         DPAAX_HWWARN(!alive, "Device-tree driver not initialised");
423         if (!dev_node)
424                 return OF_DEFAULT_NA;
425         d = node2dir(dev_node);
426         while ((d = d->parent))
427                 if (d->a_cells) {
428                         unsigned char *buf =
429                                 (unsigned char *)&d->a_cells->buf[0];
430                         assert(d->a_cells->len == 4);
431                         return ((uint32_t)buf[0] << 24) |
432                                 ((uint32_t)buf[1] << 16) |
433                                 ((uint32_t)buf[2] << 8) |
434                                 (uint32_t)buf[3];
435                 }
436         return OF_DEFAULT_NA;
437 }
438
439 uint32_t
440 of_n_size_cells(const struct device_node *dev_node)
441 {
442         const struct dt_dir *d;
443
444         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
445         if (!dev_node)
446                 return OF_DEFAULT_NA;
447         d = node2dir(dev_node);
448         while ((d = d->parent))
449                 if (d->s_cells) {
450                         unsigned char *buf =
451                                 (unsigned char *)&d->s_cells->buf[0];
452                         assert(d->s_cells->len == 4);
453                         return ((uint32_t)buf[0] << 24) |
454                                 ((uint32_t)buf[1] << 16) |
455                                 ((uint32_t)buf[2] << 8) |
456                                 (uint32_t)buf[3];
457                 }
458         return OF_DEFAULT_NS;
459 }
460
461 const uint32_t *
462 of_get_address(const struct device_node *dev_node, size_t idx,
463                uint64_t *size, uint32_t *flags __rte_unused)
464 {
465         const struct dt_dir *d;
466         const unsigned char *buf;
467         uint32_t na = of_n_addr_cells(dev_node);
468         uint32_t ns = of_n_size_cells(dev_node);
469
470         if (!dev_node)
471                 d = &root_dir;
472         else
473                 d = node2dir(dev_node);
474         if (!d->reg)
475                 return NULL;
476         assert(d->reg->len % ((na + ns) * 4) == 0);
477         assert(d->reg->len / ((na + ns) * 4) > (unsigned int) idx);
478         buf = (const unsigned char *)&d->reg->buf[0];
479         buf += (na + ns) * idx * 4;
480         if (size)
481                 for (*size = 0; ns > 0; ns--, na++)
482                         *size = (*size << 32) +
483                                 (((uint32_t)buf[4 * na] << 24) |
484                                 ((uint32_t)buf[4 * na + 1] << 16) |
485                                 ((uint32_t)buf[4 * na + 2] << 8) |
486                                 (uint32_t)buf[4 * na + 3]);
487         return (const uint32_t *)buf;
488 }
489
490 uint64_t
491 of_translate_address(const struct device_node *dev_node,
492                      const uint32_t *addr)
493 {
494         uint64_t phys_addr, tmp_addr;
495         const struct device_node *parent;
496         const uint32_t *ranges;
497         size_t rlen;
498         uint32_t na, pna;
499
500         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
501         assert(dev_node != NULL);
502
503         na = of_n_addr_cells(dev_node);
504         phys_addr = of_read_number(addr, na);
505
506         dev_node = of_get_parent(dev_node);
507         if (!dev_node)
508                 return 0;
509         else if (node2dir(dev_node) == &root_dir)
510                 return phys_addr;
511
512         do {
513                 pna = of_n_addr_cells(dev_node);
514                 parent = of_get_parent(dev_node);
515                 if (!parent)
516                         return 0;
517
518                 ranges = of_get_property(dev_node, "ranges", &rlen);
519                 /* "ranges" property is missing. Translation breaks */
520                 if (!ranges)
521                         return 0;
522                 /* "ranges" property is empty. Do 1:1 translation */
523                 else if (rlen == 0)
524                         continue;
525                 else
526                         tmp_addr = of_read_number(ranges + na, pna);
527
528                 na = pna;
529                 dev_node = parent;
530                 phys_addr += tmp_addr;
531         } while (node2dir(parent) != &root_dir);
532
533         return phys_addr;
534 }
535
536 bool
537 of_device_is_compatible(const struct device_node *dev_node,
538                         const char *compatible)
539 {
540         const struct dt_dir *d;
541
542         DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
543         if (!dev_node)
544                 d = &root_dir;
545         else
546                 d = node2dir(dev_node);
547         if (d->compatible && check_compatible(d->compatible, compatible))
548                 return true;
549         return false;
550 }
551
552 static const void *of_get_mac_addr(const struct device_node *np,
553                 const char *name)
554 {
555         return of_get_property(np, name, NULL);
556 }
557
558 /**
559  * Search the device tree for the best MAC address to use.  'mac-address' is
560  * checked first, because that is supposed to contain to "most recent" MAC
561  * address. If that isn't set, then 'local-mac-address' is checked next,
562  * because that is the default address.  If that isn't set, then the obsolete
563  * 'address' is checked, just in case we're using an old device tree.
564  *
565  * Note that the 'address' property is supposed to contain a virtual address of
566  * the register set, but some DTS files have redefined that property to be the
567  * MAC address.
568  *
569  * All-zero MAC addresses are rejected, because those could be properties that
570  * exist in the device tree, but were not set by U-Boot.  For example, the
571  * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
572  * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
573  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
574  * but is all zeros.
575  */
576 const void *of_get_mac_address(const struct device_node *np)
577 {
578         const void *addr;
579
580         addr = of_get_mac_addr(np, "mac-address");
581         if (addr)
582                 return addr;
583
584         addr = of_get_mac_addr(np, "local-mac-address");
585         if (addr)
586                 return addr;
587
588         return of_get_mac_addr(np, "address");
589 }