blob: 7a6b2b04f3d1d0a555b5dd9420cd2fa8503b31bf [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2019 MediaTek Inc.
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 <debug.h>
25#include <lib/android_dtbo.h>
26#include <lib/mempool.h>
27#include <libfdt.h>
28#include <platform.h>
29#include <trace.h>
30
31#include "blxboot_plat.h"
32#include "imageinfo.h"
33
34#define LOCAL_TRACE 0
35
36struct bootargs_overlay {
37 int noffset;
38 int len;
39 const void *path;
40 const char *prop;
41};
42
43int extract_fdt(void *fdt, int size)
44{
45 int ret = 0;
46
47 ret = fdt_open_into(fdt, fdt, size);
48 if (ret) {
49 dprintf(CRITICAL, "open fdt failed\n");
50 return ret;
51 }
52 ret = fdt_check_header(fdt);
53 if (ret) {
54 dprintf(CRITICAL, "check fdt failed\n");
55 return ret;
56 }
57
58 return ret;
59}
60
61static int dtbo_overlay(void *fdt_dtb, void *dtbo_entry)
62{
63 struct bootargs_overlay bootargs;
64 int noffset;
65
66 if (fdt_check_header(dtbo_entry)) {
67 LTRACEF("%s failed.\n", "dtbo check header");
68 return -1;
69 }
70
71 do {
72 noffset = fdt_path_offset(dtbo_entry, "/__symbols__");
73 if (noffset < 0)
74 break;
75
76 bootargs.path = fdt_getprop(dtbo_entry, noffset, "chosen", NULL);
77 if (bootargs.path == NULL)
78 break;
79
80 bootargs.noffset = fdt_path_offset(dtbo_entry, bootargs.path);
81 if (bootargs.noffset < 0)
82 break;
83
84 bootargs.prop = fdt_getprop(dtbo_entry, bootargs.noffset,
85 "bootargs_ext", &bootargs.len);
86 if (bootargs.prop == NULL)
87 break;
88
89 plat_fixup_append((char *)bootargs.prop);
90 } while (0);
91
92 if (fdt_overlay_apply(fdt_dtb, dtbo_entry)) {
93 LTRACEF("%s failed.\n", "fdt_overlay_apply");
94 return -1;
95 }
96
97 return 0;
98}
99
100static int android_dtbo_overlay(void *fdt_dtb, void *dtbo, bool update_cmd)
101{
102/* assume the maxium dtbo entries in dtbo.img */
103#define MAX_DTBO_ENTRIES_COUNT 100
104
105 static const char android_dtbo_param[] = "androidboot.dtbo_idx=";
106 uint32_t i;
107 uint32_t dtbo_entry_count;
108 uint32_t dtbo_version;
109 char *dtbo_idx_str;
110 char *dtbo_idx_str_end;
111 void *dtbo_entry;
112 struct dt_table_entry *tbl_entry;
113
114 if (android_dtbo_check_header(dtbo) != DTBO_RET_OK) {
115 LTRACEF("%s failed.\n", "android dtbo check header");
116 return -1;
117 }
118
119 dtbo_entry_count = android_dtbo_dt_entry_count(dtbo);
120 if (dtbo_entry_count >= MAX_DTBO_ENTRIES_COUNT) {
121 LTRACEF("Too many dtbo entries.\n");
122 return -1;
123 }
124
125 dtbo_idx_str_end = NULL;
126 if (update_cmd) {
127 dtbo_idx_str = mempool_alloc((dtbo_entry_count * 3) +
128 strlen(android_dtbo_param) + 1, MEMPOOL_ANY);
129 if (dtbo_idx_str == NULL) {
130 LTRACEF("mempool_alloc for dtboidx_str failed.\n");
131 return -1;
132 }
133 dtbo_idx_str_end = dtbo_idx_str;
134 sprintf(dtbo_idx_str_end, "%s", android_dtbo_param);
135 dtbo_idx_str_end += strlen(android_dtbo_param);
136 }
137
138 dtbo_version = android_dtbo_version(dtbo);
139 for (i = 0; i < dtbo_entry_count; i++) {
140 if (android_dtbo_get_dt_table_entry(dtbo, i, &tbl_entry) != DTBO_RET_OK)
141 break;
142
143 if (plat_compare_dtbo_hwinfo(dtbo_version, tbl_entry) != 0)
144 continue;
145
146 dtbo_entry = android_dtbo_get_dt_dtbo_entry(dtbo, i);
147 if (dtbo_entry == NULL)
148 break;
149
150 if (dtbo_overlay(fdt_dtb, dtbo_entry)) {
151 LTRACEF("fdt_overlay_apply failed: index=%u\n", i);
152 continue;
153 }
154
155 if (update_cmd) {
156 sprintf(dtbo_idx_str_end, "%d,", i);
157 dtbo_idx_str_end += i < 10 ? 2 : 3;
158 }
159 }
160
161 if (update_cmd) {
162 if (dtbo_idx_str_end != (dtbo_idx_str + strlen(android_dtbo_param))) {
163 *(dtbo_idx_str + strlen(dtbo_idx_str) - 1) = '\0';
164 plat_fixup_append(dtbo_idx_str);
165 }
166 mempool_free(dtbo_idx_str);
167 }
168
169 return 0;
170}
171
172int overlay_fdt(void *fdt_dtb, void *dtbo, void *vpd)
173{
174 /* [TODO] clarify: can we remove ERR_ADDR, just to check it against NULL */
175 if (fdt_dtb == (void *)ERR_ADDR) {
176 LTRACEF("no valid dtb.\n");
177 return -1;
178 }
179
180 if (extract_fdt(fdt_dtb, MAX_DTB_SIZE)) {
181 LTRACEF("%s failed.\n", "extract_fdt");
182 return -1;
183 }
184
185 if (vpd && (android_dtbo_overlay(fdt_dtb, vpd, false) != 0) &&
186 (dtbo_overlay(fdt_dtb, vpd) != 0))
187 return -1;
188
189 if (dtbo && (android_dtbo_overlay(fdt_dtb, dtbo, true) != 0) &&
190 (dtbo_overlay(fdt_dtb, dtbo) != 0))
191 return -1;
192
193 if (fdt_pack(fdt_dtb))
194 return -1;
195
196 return 0;
197}