1 /*
2 * Copyright (c) 2022 Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <inttypes.h>
25 #include <lib/dtb_embedded/dtb_embedded.h>
26 #include <libfdt.h>
27 #include <lk/compiler.h>
28 #include <lk/macros.h>
29 #include <lk/trace.h>
30 #include <stdint.h>
31 #include <uapi/uapi/err.h>
32
33 #define LOCAL_TRACE (0)
34
35 extern char __trusty_dtb_start;
36 extern char __trusty_dtb_end;
37
38 struct dtb_embedded_iterator {
39 uintptr_t offset;
40 };
41
dtb_embedded_iterator_reset(struct dtb_embedded_iterator * iter)42 void dtb_embedded_iterator_reset(struct dtb_embedded_iterator* iter) {
43 if (iter) {
44 iter->offset = 0;
45 }
46 }
47
dtb_embedded_iterator_new(struct dtb_embedded_iterator ** piter)48 int dtb_embedded_iterator_new(struct dtb_embedded_iterator** piter) {
49 ASSERT(piter);
50
51 struct dtb_embedded_iterator* iter = (struct dtb_embedded_iterator*)calloc(
52 1, sizeof(struct dtb_embedded_iterator));
53 if (!iter) {
54 TRACEF("failed to allocate iterator\n");
55 return ERR_NO_MEMORY;
56 }
57
58 dtb_embedded_iterator_reset(iter);
59 *piter = iter;
60
61 return NO_ERROR;
62 }
63
dtb_embedded_iterator_free(struct dtb_embedded_iterator ** piter)64 void dtb_embedded_iterator_free(struct dtb_embedded_iterator** piter) {
65 ASSERT(piter);
66
67 if (*piter) {
68 free(*piter);
69 *piter = NULL;
70 }
71 }
72
dtb_embedded_iterator_next(struct dtb_embedded_iterator * iter,const void ** dtb,size_t * dtb_size)73 int dtb_embedded_iterator_next(struct dtb_embedded_iterator* iter,
74 const void** dtb,
75 size_t* dtb_size) {
76 if (!iter) {
77 TRACEF("Invalid iterator\n");
78 return ERR_INVALID_ARGS;
79 }
80 if (!dtb) {
81 TRACEF("Invalid dtb pointer\n");
82 return ERR_INVALID_ARGS;
83 }
84 if (!dtb_size) {
85 TRACEF("Invalid dtb size pointer\n");
86 return ERR_INVALID_ARGS;
87 }
88
89 /* Check that the iterator is within the embedded dtb range */
90 uintptr_t end = (uintptr_t)&__trusty_dtb_end;
91 uintptr_t start = (uintptr_t)&__trusty_dtb_start;
92 uintptr_t total_size = end - start;
93 if (iter->offset >= total_size) {
94 TRACEF("Embedded dtb iterator at offset %" PRIuPTR "out of range\n",
95 iter->offset);
96 return ERR_OUT_OF_RANGE;
97 }
98
99 /* Validate the header of the next dtb */
100 const void* dtb_start = (const void*)(start + iter->offset);
101 int rc = fdt_check_header(dtb_start);
102 if (rc < 0) {
103 TRACEF("Embedded dtb at offset %" PRIuPTR
104 " has an invalid header (%d)\n",
105 iter->offset, rc);
106 return ERR_BAD_STATE;
107 }
108
109 /*
110 * Check that the dtb size is in the expected range. Each dtb's size is read
111 * from its header plus 4 bytes from the symbol size inserted by
112 * INCBIN_ALIGNED. Then we round up to 8 bytes since each individual dtb is
113 * 8-byte aligned.
114 */
115 const size_t dtb_alignment = 8;
116 const size_t sym_size = 4;
117 size_t next_dtb_size =
118 round_up(fdt_totalsize(dtb_start) + sym_size, dtb_alignment);
119 if (next_dtb_size + iter->offset > total_size) {
120 TRACEF("Embedded dtb at offset %" PRIuPTR " has invalid size %zu\n",
121 iter->offset, next_dtb_size);
122 return ERR_BAD_LEN;
123 }
124 iter->offset += next_dtb_size;
125 *dtb = dtb_start;
126 *dtb_size = next_dtb_size;
127 LTRACEF("Found embedded dtb at offset %" PRIuPTR "\n", iter->offset);
128 return NO_ERROR;
129 }
130