LCOV - code coverage report
Current view: top level - hdata/test - hdata_to_dt.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 92 152 60.5 %
Date: 2024-09-10 18:37:41 Functions: 8 14 57.1 %
Branches: 0 0 -

           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                 :            : }

Generated by: LCOV version 1.14