Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * Given a hdata dump, output the device tree.
4 : : *
5 : : * Copyright 2013-2020 IBM Corp.
6 : : */
7 : :
8 : : #include <sys/types.h>
9 : : #include <sys/stat.h>
10 : : #include <sys/mman.h>
11 : : #include <fcntl.h>
12 : : #include <assert.h>
13 : : #include <stdlib.h>
14 : : #include <unistd.h>
15 : : #include <stdint.h>
16 : : #include <mem_region-malloc.h>
17 : :
18 : : #include <interrupts.h>
19 : : #include <bitutils.h>
20 : :
21 : : #include <skiboot-valgrind.h>
22 : :
23 : : #include "../../libfdt/fdt.c"
24 : : #include "../../libfdt/fdt_ro.c"
25 : : #include "../../libfdt/fdt_sw.c"
26 : : #include "../../libfdt/fdt_strerror.c"
27 : :
28 : : struct dt_node *opal_node;
29 : :
30 : : /* Our actual map. */
31 : : static void *spira_heap;
32 : : static off_t spira_heap_size;
33 : : static uint64_t base_addr;
34 : :
35 : : /* Override ntuple_addr. */
36 : : #define ntuple_addr ntuple_addr
37 : : struct spira_ntuple;
38 : : static void *ntuple_addr(const struct spira_ntuple *n);
39 : :
40 : : /* Stuff which core expects. */
41 : : struct cpu_thread *my_fake_cpu;
42 : 0 : static struct cpu_thread *this_cpu(void)
43 : : {
44 : 0 : return my_fake_cpu;
45 : : }
46 : :
47 : : unsigned long tb_hz = 512000000;
48 : :
49 : : /* Don't include processor-specific stuff. */
50 : : #define __PROCESSOR_H
51 : : /* PVR bits */
52 : : #define SPR_PVR_TYPE 0xffff0000
53 : : #define SPR_PVR_VERS_MAJ 0x00000f00
54 : : #define SPR_PVR_VERS_MIN 0x000000ff
55 : :
56 : : #define PVR_TYPE(_pvr) GETFIELD(SPR_PVR_TYPE, _pvr)
57 : : #define PVR_VERS_MAJ(_pvr) GETFIELD(SPR_PVR_VERS_MAJ, _pvr)
58 : : #define PVR_VERS_MIN(_pvr) GETFIELD(SPR_PVR_VERS_MIN, _pvr)
59 : :
60 : : /* PVR definitions - copied from skiboot include/processor.h */
61 : : #define PVR_TYPE_P8E 0x004b
62 : : #define PVR_TYPE_P8 0x004d
63 : : #define PVR_TYPE_P8NVL 0x004c
64 : : #define PVR_TYPE_P9 0x004e
65 : : #define PVR_TYPE_P9P 0x004f
66 : : #define PVR_TYPE_P10 0x0080
67 : : #define PVR_P8E 0x004b0201
68 : : #define PVR_P8 0x004d0200
69 : : #define PVR_P8NVL 0x004c0100
70 : : #define PVR_P9 0x004e0200
71 : : #define PVR_P9P 0x004f0100
72 : : #define PVR_P10 0x00800100
73 : :
74 : : #define SPR_PVR 0x11f /* RO: Processor version register */
75 : :
76 : : #define MSR_SF 0x8000000000000000ULL
77 : : #define MSR_HV 0x1000000000000000ULL
78 : :
79 : : #define __CPU_H
80 : : struct cpu_thread {
81 : : uint32_t pir;
82 : : uint32_t chip_id;
83 : : bool is_fused_core;
84 : : };
85 : : struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
86 : : const char *name,
87 : : void (*func)(void *data), void *data,
88 : : bool no_return);
89 : : void cpu_wait_job(struct cpu_job *job, bool free_it);
90 : : void cpu_process_local_jobs(void);
91 : : struct cpu_job *cpu_queue_job_on_node(uint32_t chip_id,
92 : : const char *name,
93 : : void (*func)(void *data), void *data);
94 : 0 : static inline struct cpu_job *cpu_queue_job(struct cpu_thread *cpu,
95 : : const char *name,
96 : : void (*func)(void *data),
97 : : void *data)
98 : : {
99 : 0 : return __cpu_queue_job(cpu, name, func, data, false);
100 : : }
101 : :
102 : : struct cpu_thread __boot_cpu, *boot_cpu = &__boot_cpu;
103 : : static unsigned long fake_pvr = PVR_P8;
104 : :
105 : : unsigned int cpu_thread_count = 8;
106 : :
107 : : bool lpar_per_core;
108 : :
109 : 11 : static inline unsigned long mfspr(unsigned int spr)
110 : : {
111 : 11 : assert(spr == SPR_PVR);
112 : 11 : return fake_pvr;
113 : : }
114 : :
115 : 0 : struct dt_node *add_ics_node(void)
116 : : {
117 : 0 : return NULL;
118 : : }
119 : :
120 : : // Copied from processor.h:
121 : 0 : static inline bool is_power9n(uint32_t version)
122 : : {
123 : 0 : if (PVR_TYPE(version) != PVR_TYPE_P9)
124 : 0 : return false;
125 : : /*
126 : : * Bit 13 tells us:
127 : : * 0 = Scale out (aka Nimbus)
128 : : * 1 = Scale up (aka Cumulus)
129 : : */
130 : 0 : if ((version >> 13) & 1)
131 : 0 : return false;
132 : 0 : return true;
133 : : }
134 : :
135 : : #include <config.h>
136 : : #include <bitutils.h>
137 : :
138 : : /* Your pointers won't be correct, that's OK. */
139 : : #define spira_check_ptr spira_check_ptr
140 : :
141 : : static bool spira_check_ptr(const void *ptr, const char *file, unsigned int line);
142 : :
143 : : /* should probably check this */
144 : : #define BITS_PER_LONG 64
145 : : /* not used, just needs to exist */
146 : : #define cpu_max_pir 0x7
147 : :
148 : : #include "../cpu-common.c"
149 : : #include "../fsp.c"
150 : : #include "../hdif.c"
151 : : #include "../iohub.c"
152 : : #include "../memory.c"
153 : : #include "../pcia.c"
154 : : #include "../spira.c"
155 : : #include "../vpd.c"
156 : : #include "../vpd-common.c"
157 : : #include "../slca.c"
158 : : #include "../hostservices.c"
159 : : #include "../i2c.c"
160 : : #include "../tpmrel.c"
161 : : #include "../../core/vpd.c"
162 : : #include "../../core/device.c"
163 : : #include "../../core/chip.c"
164 : : #include "../../test/dt_common.c"
165 : : #include "../../core/fdt.c"
166 : : #include "../../hw/phys-map.c"
167 : : #include "../../core/mem_region.c"
168 : :
169 : : #include <err.h>
170 : :
171 : : #include <op-panel.h>
172 : :
173 : 0 : bool fsp_present()
174 : : {
175 : 0 : return false;
176 : : }
177 : :
178 : 0 : void op_display(enum op_severity s, enum op_module m, uint16_t code)
179 : : {
180 : 0 : fprintf(stderr, "op_panel Severity: 0x%x (%s), module %x, %x\n",
181 : : s, (s == OP_FATAL) ? "FATAL" : "non-fatal",
182 : : m, code);
183 : 0 : if (s == OP_FATAL)
184 : 0 : exit(EXIT_FAILURE);
185 : 0 : }
186 : :
187 : : char __rodata_start[1], __rodata_end[1];
188 : :
189 : : enum proc_gen proc_gen = proc_gen_p8;
190 : :
191 : 380 : static bool spira_check_ptr(const void *ptr, const char *file, unsigned int line)
192 : : {
193 : 380 : if (!ptr)
194 : 1 : return false;
195 : : /* we fake the SPIRA pointer as it's relative to where it was loaded
196 : : * on real hardware */
197 : : (void)file;
198 : : (void)line;
199 : 379 : return true;
200 : : }
201 : :
202 : 230 : static void *ntuple_addr(const struct spira_ntuple *n)
203 : : {
204 : 230 : uint64_t addr = be64_to_cpu(n->addr);
205 : 230 : if (n->addr == 0)
206 : 1 : return NULL;
207 : 229 : if (addr < base_addr) {
208 : 0 : fprintf(stderr, "assert failed: addr >= base_addr (%"PRIu64" >= %"PRIu64")\n", addr, base_addr);
209 : 0 : exit(EXIT_FAILURE);
210 : : }
211 : 229 : if (addr >= base_addr + spira_heap_size) {
212 : 0 : fprintf(stderr, "assert failed: addr not in spira_heap\n");
213 : 0 : exit(EXIT_FAILURE);
214 : : }
215 : 229 : return spira_heap + ((unsigned long)addr - base_addr);
216 : : }
217 : :
218 : : /* Make sure valgrind knows these are undefined bytes. */
219 : 1 : static void undefined_bytes(void *p, size_t len)
220 : : {
221 : : VALGRIND_MAKE_MEM_UNDEFINED(p, len);
222 : 1 : }
223 : :
224 : 3 : static u32 hash_prop(const struct dt_property *p)
225 : : {
226 : 3 : u32 i, hash = 0;
227 : :
228 : : /* a stupid checksum */
229 : 135171 : for (i = 0; i < p->len; i++)
230 : 135168 : hash += (((signed char)p->prop[i] & ~0x10) + 1) * i;
231 : :
232 : 3 : return hash;
233 : : }
234 : :
235 : : /*
236 : : * This filters out VPD blobs and other annoyances from the devicetree output.
237 : : * We don't actually care about the contents of the blob, we just want to make
238 : : * sure it's there and that we aren't accidently corrupting the contents.
239 : : */
240 : 80 : static void squash_blobs(struct dt_node *root)
241 : : {
242 : : struct dt_node *n;
243 : : struct dt_property *p;
244 : :
245 : 849 : list_for_each(&root->properties, p, list) {
246 : 769 : if (strstarts(p->name, DT_PRIVATE))
247 : 3 : continue;
248 : :
249 : : /*
250 : : * Consider any property larger than 512 bytes a blob that can
251 : : * be removed. This number was picked out of thin in so don't
252 : : * feel bad about changing it.
253 : : */
254 : 766 : if (p->len > 512) {
255 : 3 : u32 hash = hash_prop(p);
256 : 3 : u32 *val = (u32 *) p->prop;
257 : :
258 : : /* Add a sentinel so we know it was truncated */
259 : 3 : val[0] = cpu_to_be32(0xcafebeef);
260 : 3 : val[1] = cpu_to_be32(p->len);
261 : 3 : val[2] = cpu_to_be32(hash);
262 : 3 : p->len = 3 * sizeof(u32);
263 : : }
264 : : }
265 : :
266 : 159 : list_for_each(&root->children, n, list)
267 : 79 : squash_blobs(n);
268 : 80 : }
269 : :
270 : 1 : static void dump_hdata_fdt(struct dt_node *root)
271 : : {
272 : : struct dt_node *n;
273 : : void *fdt_blob;
274 : :
275 : : /* delete some properties that hardcode pointers */
276 : 80 : dt_for_each_node(dt_root, n) {
277 : : struct dt_property *base;
278 : :
279 : : /*
280 : : * sml-base is a raw pointer into the HDAT area so it changes
281 : : * on each execution of hdata_to_dt. Work around this by
282 : : * zeroing it.
283 : : */
284 : 79 : base = __dt_find_property(n, "linux,sml-base");
285 : 79 : if (base)
286 : 0 : memset(base->prop, 0, base->len);
287 : : }
288 : :
289 : 1 : fdt_blob = create_dtb(root, false);
290 : :
291 : 1 : if (!fdt_blob) {
292 : 0 : fprintf(stderr, "Unable to make flattened DT, no FDT written\n");
293 : 0 : return;
294 : : }
295 : :
296 : 1 : fwrite(fdt_blob, fdt_totalsize(fdt_blob), 1, stdout);
297 : :
298 : 1 : free(fdt_blob);
299 : : }
300 : :
301 : 1 : int main(int argc, char *argv[])
302 : : {
303 : 1 : int fd, r, i = 0, opt_count = 0;
304 : 1 : bool verbose = false, quiet = false, blobs = false;
305 : :
306 : 4 : while (argv[++i]) {
307 : 3 : if (strcmp(argv[i], "-v") == 0) {
308 : 0 : verbose = true;
309 : 0 : opt_count++;
310 : 3 : } else if (strcmp(argv[i], "-q") == 0) {
311 : 0 : quiet = true;
312 : 0 : opt_count++;
313 : 3 : } else if (strcmp(argv[i], "-b") == 0) {
314 : 0 : blobs = true;
315 : 0 : opt_count++;
316 : 3 : } else if (strcmp(argv[i], "-8E") == 0) {
317 : 1 : fake_pvr = PVR_P8E;
318 : 1 : proc_gen = proc_gen_p8;
319 : 1 : opt_count++;
320 : 2 : } else if (strcmp(argv[i], "-8") == 0) {
321 : 0 : fake_pvr = PVR_P8;
322 : 0 : proc_gen = proc_gen_p8;
323 : 0 : opt_count++;
324 : 2 : } else if (strcmp(argv[i], "-9") == 0) {
325 : 0 : fake_pvr = PVR_P9;
326 : 0 : proc_gen = proc_gen_p9;
327 : 0 : opt_count++;
328 : 2 : } else if (strcmp(argv[i], "-9P") == 0) {
329 : 0 : fake_pvr = PVR_P9P;
330 : 0 : proc_gen = proc_gen_p9;
331 : 0 : opt_count++;
332 : 2 : } else if (strcmp(argv[i], "-10") == 0) {
333 : 0 : fake_pvr = PVR_P10;
334 : 0 : proc_gen = proc_gen_p10;
335 : 0 : opt_count++;
336 : : }
337 : : }
338 : :
339 : 1 : argc -= opt_count;
340 : 1 : argv += opt_count;
341 : 1 : if (argc != 3) {
342 : 0 : errx(1, "Converts HDAT dumps to DTB.\n"
343 : : "\n"
344 : : "Usage:\n"
345 : : " hdata <opts> <spirah-dump> <spiras-dump>\n"
346 : : "Options: \n"
347 : : " -v Verbose\n"
348 : : " -q Quiet mode\n"
349 : : " -b Keep blobs in the output\n"
350 : : "\n"
351 : : " -8 Force PVR to POWER8\n"
352 : : " -8E Force PVR to POWER8E\n"
353 : : " -9 Force PVR to POWER9 (nimbus)\n"
354 : : " -9P Force PVR to POWER9P (Axone)\n"
355 : : " -10 Force PVR to POWER10\n"
356 : : "\n"
357 : : "When no PVR is specified -8 is assumed"
358 : : "\n"
359 : : "Pipe to 'dtc -I dtb -O dts' for human readable output\n");
360 : : }
361 : :
362 : : /* We don't have phys mapping for P8 */
363 : 1 : if (proc_gen != proc_gen_p8)
364 : 0 : phys_map_init(fake_pvr);
365 : :
366 : : /* Copy in spira dump (assumes little has changed!). */
367 : 1 : fd = open(argv[1], O_RDONLY);
368 : 1 : if (fd < 0)
369 : 0 : err(1, "opening %s", argv[1]);
370 : 1 : r = read(fd, &spirah, sizeof(spirah));
371 : 1 : if (r < sizeof(spirah.hdr))
372 : 0 : err(1, "reading %s gave %i", argv[1], r);
373 : 1 : if (verbose)
374 : 0 : printf("verbose: read spirah %u bytes\n", r);
375 : 1 : close(fd);
376 : :
377 : 1 : undefined_bytes((void *)&spirah + r, sizeof(spirah) - r);
378 : :
379 : 1 : base_addr = be64_to_cpu(spirah.ntuples.hs_data_area.addr);
380 : 1 : if (!base_addr)
381 : 0 : errx(1, "Invalid base addr");
382 : 1 : if (verbose)
383 : 0 : printf("verbose: map.base_addr = %llx\n", (long long)base_addr);
384 : :
385 : 1 : fd = open(argv[2], O_RDONLY);
386 : 1 : if (fd < 0)
387 : 0 : err(1, "opening %s", argv[2]);
388 : 1 : spira_heap_size = lseek(fd, 0, SEEK_END);
389 : 1 : if (spira_heap_size < 0)
390 : 0 : err(1, "lseek on %s", argv[2]);
391 : 1 : spira_heap = mmap(NULL, spira_heap_size, PROT_READ, MAP_SHARED, fd, 0);
392 : 1 : if (spira_heap == MAP_FAILED)
393 : 0 : err(1, "mmaping %s", argv[3]);
394 : 1 : if (verbose)
395 : 0 : printf("verbose: mapped %zu at %p\n",
396 : : spira_heap_size, spira_heap);
397 : 1 : close(fd);
398 : :
399 : : /* SPIRA-S defined to be at the start of the SPIRA Host Data Area */
400 : 1 : spiras = (struct spiras *)spira_heap;
401 : :
402 : 1 : if (quiet) {
403 : 0 : fclose(stdout);
404 : 0 : fclose(stderr);
405 : : }
406 : :
407 : 1 : dt_root = dt_new_root("");
408 : :
409 : 1 : if(parse_hdat(false) < 0) {
410 : 0 : fprintf(stderr, "FATAL ERROR parsing HDAT\n");
411 : 0 : dt_free(dt_root);
412 : 0 : exit(EXIT_FAILURE);
413 : : }
414 : :
415 : 1 : mem_region_init();
416 : 1 : mem_region_release_unused();
417 : :
418 : 1 : if (!blobs)
419 : 1 : squash_blobs(dt_root);
420 : :
421 : 1 : if (!quiet)
422 : 1 : dump_hdata_fdt(dt_root);
423 : :
424 : 1 : dt_free(dt_root);
425 : 1 : return 0;
426 : : }
|