The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/fdt/fdt_loader_cmd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2009-2010 The FreeBSD Foundation
    3  * All rights reserved.
    4  *
    5  * This software was developed by Semihalf under sponsorship from
    6  * the FreeBSD Foundation.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/9.0/sys/boot/fdt/fdt_loader_cmd.c 208538 2010-05-25 15:21:39Z raj $");
   32 
   33 #include <stand.h>
   34 #include <fdt.h>
   35 #include <libfdt.h>
   36 
   37 #include "bootstrap.h"
   38 #include "glue.h"
   39 
   40 #define DEBUG
   41 
   42 #ifdef DEBUG
   43 #define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
   44     printf(fmt,##args); } while (0)
   45 #else
   46 #define debugf(fmt, args...)
   47 #endif
   48 
   49 #define FDT_CWD_LEN     256
   50 #define FDT_MAX_DEPTH   6
   51 
   52 #define FDT_PROP_SEP    " = "
   53 
   54 #define STR(number) #number
   55 #define STRINGIFY(number) STR(number)
   56 
   57 #define MIN(num1, num2) (((num1) < (num2)) ? (num1):(num2))
   58 
   59 static struct fdt_header *fdtp = NULL;
   60 
   61 static int fdt_cmd_nyi(int argc, char *argv[]);
   62 
   63 static int fdt_cmd_mkprop(int argc, char *argv[]);
   64 static int fdt_cmd_cd(int argc, char *argv[]);
   65 static int fdt_cmd_hdr(int argc, char *argv[]);
   66 static int fdt_cmd_ls(int argc, char *argv[]);
   67 static int fdt_cmd_prop(int argc, char *argv[]);
   68 static int fdt_cmd_pwd(int argc, char *argv[]);
   69 static int fdt_cmd_rm(int argc, char *argv[]);
   70 static int fdt_cmd_mknode(int argc, char *argv[]);
   71 
   72 typedef int cmdf_t(int, char *[]);
   73 
   74 struct cmdtab {
   75         char    *name;
   76         cmdf_t  *handler;
   77 };
   78 
   79 static const struct cmdtab commands[] = {
   80         { "alias", &fdt_cmd_nyi },
   81         { "cd", &fdt_cmd_cd },
   82         { "header", &fdt_cmd_hdr },
   83         { "ls", &fdt_cmd_ls },
   84         { "mknode", &fdt_cmd_mknode },
   85         { "mkprop", &fdt_cmd_mkprop },
   86         { "mres", &fdt_cmd_nyi },
   87         { "prop", &fdt_cmd_prop },
   88         { "pwd", &fdt_cmd_pwd },
   89         { "rm", &fdt_cmd_rm },
   90         { NULL, NULL }
   91 };
   92 
   93 static char cwd[FDT_CWD_LEN] = "/";
   94 
   95 static int
   96 fdt_setup_fdtp()
   97 {
   98         struct preloaded_file *bfp;
   99         int err;
  100 
  101         /*
  102          * Find the device tree blob.
  103          */
  104         bfp = file_findfile(NULL, "dtb");
  105         if (bfp == NULL) {
  106                 command_errmsg = "no device tree blob loaded";
  107                 return (CMD_ERROR);
  108         }
  109         fdtp = (struct fdt_header *)bfp->f_addr;
  110 
  111         /*
  112          * Validate the blob.
  113          */
  114         err = fdt_check_header(fdtp);
  115         if (err < 0) {
  116                 if (err == -FDT_ERR_BADVERSION)
  117                         sprintf(command_errbuf,
  118                             "incompatible blob version: %d, should be: %d",
  119                             fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
  120 
  121                 else
  122                         sprintf(command_errbuf, "error validating blob: %s",
  123                             fdt_strerror(err));
  124                 return (CMD_ERROR);
  125         }
  126         return (CMD_OK);
  127 }
  128 
  129 #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
  130     (cellbuf), (lim), (cellsize), 0);
  131 
  132 /* Force using base 16 */
  133 #define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
  134     (cellbuf), (lim), (cellsize), 16);
  135 
  136 static int
  137 _fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize,
  138     uint8_t base)
  139 {
  140         char *buf = str;
  141         char *end = str + strlen(str) - 2;
  142         uint32_t *u32buf = NULL;
  143         uint8_t *u8buf = NULL;
  144         int cnt = 0;
  145 
  146         if (cellsize == sizeof(uint32_t))
  147                 u32buf = (uint32_t *)cellbuf;
  148         else
  149                 u8buf = (uint8_t *)cellbuf;
  150 
  151         if (lim == 0)
  152                 return (0);
  153 
  154         while (buf < end) {
  155 
  156                 /* Skip white whitespace(s)/separators */
  157                 while (!isxdigit(*buf) && buf < end)
  158                         buf++;
  159 
  160                 if (u32buf != NULL)
  161                         u32buf[cnt] =
  162                             cpu_to_fdt32((uint32_t)strtol(buf, NULL, base));
  163 
  164                 else
  165                         u8buf[cnt] = (uint8_t)strtol(buf, NULL, base);
  166 
  167                 if (cnt + 1 <= lim - 1)
  168                         cnt++;
  169                 else
  170                         break;
  171                 buf++;
  172                 /* Find another number */
  173                 while ((isxdigit(*buf) || *buf == 'x') && buf < end)
  174                         buf++;
  175         }
  176         return (cnt);
  177 }
  178 
  179 #define TMP_MAX_ETH     8
  180 
  181 void
  182 fixup_ethernet(const char *env, char *ethstr, int *eth_no, int len)
  183 {
  184         char *end, *str;
  185         uint8_t tmp_addr[6];
  186         int i, n;
  187 
  188         /* Extract interface number */
  189         i = strtol(env + 3, &end, 10);
  190         if (end == (env + 3))
  191                 /* 'ethaddr' means interface 0 address */
  192                 n = 0;
  193         else
  194                 n = i;
  195 
  196         if (n > TMP_MAX_ETH)
  197                 return;
  198 
  199         str = ub_env_get(env);
  200 
  201         /* Convert macaddr string into a vector of uints */
  202         fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
  203         if (n != 0) {
  204                 i = strlen(env) - 7;
  205                 strncpy(ethstr + 8, env + 3, i);
  206         }
  207         /* Set actual property to a value from vect */
  208         fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
  209             "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
  210 
  211         /* Clear ethernet..XXXX.. string */
  212         bzero(ethstr + 8, len - 8);
  213 
  214         if (n + 1 > *eth_no)
  215                 *eth_no = n + 1;
  216 }
  217 
  218 void
  219 fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
  220 {
  221         int lo, o = 0, o2, maxo = 0, depth;
  222         const uint32_t zero = 0;
  223 
  224         /* We want to modify every subnode of /cpus */
  225         o = fdt_path_offset(fdtp, "/cpus");
  226 
  227         /* maxo should contain offset of node next to /cpus */
  228         depth = 0;
  229         maxo = o;
  230         while (depth != -1)
  231                 maxo = fdt_next_node(fdtp, maxo, &depth);
  232 
  233         /* Find CPU frequency properties */
  234         o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency",
  235             &zero, sizeof(uint32_t));
  236 
  237         o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero,
  238             sizeof(uint32_t));
  239 
  240         lo = MIN(o, o2);
  241 
  242         while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) {
  243 
  244                 o = fdt_node_offset_by_prop_value(fdtp, lo,
  245                     "clock-frequency", &zero, sizeof(uint32_t));
  246 
  247                 o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency",
  248                     &zero, sizeof(uint32_t));
  249 
  250                 /* We're only interested in /cpus subnode(s) */
  251                 if (lo > maxo)
  252                         break;
  253 
  254                 fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency",
  255                     (uint32_t)cpufreq);
  256 
  257                 fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency",
  258                     (uint32_t)busfreq);
  259 
  260                 lo = MIN(o, o2);
  261         }
  262 }
  263 
  264 int
  265 fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
  266 {
  267         int cells_in_tuple, i, tuples, tuple_size;
  268         uint32_t cur_start, cur_size;
  269 
  270         cells_in_tuple = (addr_cells + size_cells);
  271         tuple_size = cells_in_tuple * sizeof(uint32_t);
  272         tuples = len / tuple_size;
  273         if (tuples == 0)
  274                 return (EINVAL);
  275 
  276         for (i = 0; i < tuples; i++) {
  277                 if (addr_cells == 2)
  278                         cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]);
  279                 else
  280                         cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]);
  281 
  282                 if (size_cells == 2)
  283                         cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]);
  284                 else
  285                         cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]);
  286 
  287                 if (cur_size == 0)
  288                         return (EINVAL);
  289 
  290                 debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n",
  291                     i, cur_start, cur_size);
  292         }
  293         return (0);
  294 }
  295 
  296 void
  297 fixup_memory(struct sys_info *si)
  298 {
  299         struct mem_region *curmr;
  300         uint32_t addr_cells, size_cells;
  301         uint32_t *addr_cellsp, *reg,  *size_cellsp;
  302         int err, i, len, memory, realmrno, root;
  303         uint8_t *buf, *sb;
  304 
  305         root = fdt_path_offset(fdtp, "/");
  306         if (root < 0) {
  307                 sprintf(command_errbuf, "Could not find root node !");
  308                 return;
  309         }
  310 
  311         memory = fdt_path_offset(fdtp, "/memory");
  312         if (memory <= 0) {
  313                 /* Create proper '/memory' node. */
  314                 memory = fdt_add_subnode(fdtp, root, "memory");
  315                 if (memory <= 0) {
  316                         sprintf(command_errbuf, "Could not fixup '/memory' "
  317                             "node, error code : %d!\n", memory);
  318                         return;
  319                 }
  320 
  321                 err = fdt_setprop(fdtp, memory, "device_type", "memory",
  322                     sizeof("memory"));
  323 
  324                 if (err < 0)
  325                         return;
  326         }
  327 
  328         addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells",
  329             NULL);
  330         size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL);
  331 
  332         if (addr_cellsp == NULL || size_cellsp == NULL) {
  333                 sprintf(command_errbuf, "Could not fixup '/memory' node : "
  334                     "%s %s property not found in root node!\n",
  335                     (!addr_cellsp) ? "#address-cells" : "",
  336                     (!size_cellsp) ? "#size-cells" : "");
  337                 return;
  338         }
  339 
  340         addr_cells = fdt32_to_cpu(*addr_cellsp);
  341         size_cells = fdt32_to_cpu(*size_cellsp);
  342 
  343         /* Count valid memory regions entries in sysinfo. */
  344         realmrno = si->mr_no;
  345         for (i = 0; i < si->mr_no; i++)
  346                 if (si->mr[i].start == 0 && si->mr[i].size == 0)
  347                         realmrno--;
  348 
  349         if (realmrno == 0) {
  350                 sprintf(command_errbuf, "Could not fixup '/memory' node : "
  351                     "sysinfo doesn't contain valid memory regions info!\n");
  352                 return;
  353         }
  354 
  355         if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg",
  356             &len)) != NULL) {
  357 
  358                 if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0)
  359                         /*
  360                          * Do not apply fixup if existing 'reg' property
  361                          * seems to be valid.
  362                          */
  363                         return;
  364         }
  365 
  366         len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t);
  367         sb = buf = (uint8_t *)malloc(len);
  368         if (!buf)
  369                 return;
  370 
  371         bzero(buf, len);
  372 
  373         for (i = 0; i < si->mr_no; i++) {
  374                 curmr = &si->mr[i];
  375                 if (curmr->size != 0) {
  376                         /* Ensure endianess, and put cells into a buffer */
  377                         if (addr_cells == 2)
  378                                 *(uint64_t *)buf =
  379                                     cpu_to_fdt64(curmr->start);
  380                         else
  381                                 *(uint32_t *)buf =
  382                                     cpu_to_fdt32(curmr->start);
  383 
  384                         buf += sizeof(uint32_t) * addr_cells;
  385                         if (size_cells == 2)
  386                                 *(uint64_t *)buf =
  387                                     cpu_to_fdt64(curmr->size);
  388                         else
  389                                 *(uint32_t *)buf =
  390                                     cpu_to_fdt32(curmr->size);
  391 
  392                         buf += sizeof(uint32_t) * size_cells;
  393                 }
  394         }
  395 
  396         /* Set property */
  397         if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
  398                 sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
  399 }
  400 
  401 void
  402 fixup_stdout(const char *env)
  403 {
  404         const char *str;
  405         char *ptr;
  406         int serialno;
  407         int len, no, sero;
  408         const struct fdt_property *prop;
  409         char *tmp[10];
  410 
  411         str = ub_env_get(env);
  412         ptr = (char *)str + strlen(str) - 1;
  413         while (ptr > str && isdigit(*(str - 1)))
  414                 str--;
  415 
  416         if (ptr == str)
  417                 return;
  418 
  419         serialno = (int)strtol(ptr, NULL, 0);
  420         no = fdt_path_offset(fdtp, "/chosen");
  421         if (no < 0)
  422                 return;
  423 
  424         prop = fdt_get_property(fdtp, no, "stdout", &len);
  425 
  426         /* If /chosen/stdout does not extist, create it */
  427         if (prop == NULL || (prop != NULL && len == 0)) {
  428 
  429                 bzero(tmp, 10 * sizeof(char));
  430                 strcpy((char *)&tmp, "serial");
  431                 if (strlen(ptr) > 3)
  432                         /* Serial number too long */
  433                         return;
  434 
  435                 strncpy((char *)tmp + 6, ptr, 3);
  436                 sero = fdt_path_offset(fdtp, (const char *)tmp);
  437                 if (sero < 0)
  438                         /*
  439                          * If serial device we're trying to assign
  440                          * stdout to doesn't exist in DT -- return.
  441                          */
  442                         return;
  443 
  444                 fdt_setprop(fdtp, no, "stdout", &tmp,
  445                     strlen((char *)&tmp) + 1);
  446                 fdt_setprop(fdtp, no, "stdin", &tmp,
  447                     strlen((char *)&tmp) + 1);
  448         }
  449 }
  450 
  451 int
  452 fdt_fixup(void)
  453 {
  454         const char *env;
  455         char *ethstr;
  456         int chosen, err, eth_no, len;
  457         struct sys_info *si;
  458 
  459         env = NULL;
  460         eth_no = 0;
  461         ethstr = NULL;
  462         len = 0;
  463 
  464         if (!fdtp) {
  465                 err = fdt_setup_fdtp();
  466                 if (err) {
  467                         sprintf(command_errbuf, "Could not perform blob "
  468                             "fixups. Error code: %d\n", err);
  469                         return (err);
  470                 }
  471         }
  472 
  473         /* Create /chosen node (if not exists) */
  474         if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) ==
  475             -FDT_ERR_NOTFOUND)
  476                 chosen = fdt_add_subnode(fdtp, 0, "chosen");
  477 
  478         /* Value assigned to fixup-applied does not matter. */
  479         if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
  480                 return (CMD_OK);
  481 
  482         /* Acquire sys_info */
  483         si = ub_get_sys_info();
  484 
  485         while ((env = ub_env_enum(env)) != NULL) {
  486                 if (strncmp(env, "eth", 3) == 0 &&
  487                     strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
  488                         /*
  489                          * Handle Ethernet addrs: parse uboot env eth%daddr
  490                          */
  491 
  492                         if (!eth_no) {
  493                                 /*
  494                                  * Check how many chars we will need to store
  495                                  * maximal eth iface number.
  496                                  */
  497                                 len = strlen(STRINGIFY(TMP_MAX_ETH)) +
  498                                     strlen("ethernet");
  499 
  500                                 /*
  501                                  * Reserve mem for string "ethernet" and len
  502                                  * chars for iface no.
  503                                  */
  504                                 ethstr = (char *)malloc(len * sizeof(char));
  505                                 bzero(ethstr, len * sizeof(char));
  506                                 strcpy(ethstr, "ethernet0");
  507                         }
  508 
  509                         /* Modify blob */
  510                         fixup_ethernet(env, ethstr, &eth_no, len);
  511 
  512                 } else if (strcmp(env, "consoledev") == 0)
  513                         fixup_stdout(env);
  514         }
  515 
  516         /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
  517         fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
  518 
  519         /* Fixup memory regions */
  520         fixup_memory(si);
  521 
  522         fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
  523 
  524         return (CMD_OK);
  525 }
  526 
  527 int
  528 command_fdt_internal(int argc, char *argv[])
  529 {
  530         cmdf_t *cmdh;
  531         char *cmd;
  532         int i, err;
  533 
  534         if (argc < 2) {
  535                 command_errmsg = "usage is 'fdt <command> [<args>]";
  536                 return (CMD_ERROR);
  537         }
  538 
  539         /*
  540          * Check if uboot env vars were parsed already. If not, do it now.
  541          */
  542         fdt_fixup();
  543 
  544         /*
  545          * Validate fdt <command>.
  546          */
  547         cmd = strdup(argv[1]);
  548         i = 0;
  549         cmdh = NULL;
  550         while (!(commands[i].name == NULL)) {
  551                 if (strcmp(cmd, commands[i].name) == 0) {
  552                         /* found it */
  553                         cmdh = commands[i].handler;
  554                         break;
  555                 }
  556                 i++;
  557         }
  558         if (cmdh == NULL) {
  559                 command_errmsg = "unknown command";
  560                 return (CMD_ERROR);
  561         }
  562 
  563         if (!fdtp)
  564                 if (fdt_setup_fdtp())
  565                         return (CMD_ERROR);
  566 
  567         /*
  568          * Call command handler.
  569          */
  570         err = (*cmdh)(argc, argv);
  571 
  572         return (err);
  573 }
  574 
  575 static int
  576 fdt_cmd_cd(int argc, char *argv[])
  577 {
  578         char *path;
  579         char tmp[FDT_CWD_LEN];
  580         int len, o;
  581 
  582         path = (argc > 2) ? argv[2] : "/";
  583 
  584         if (path[0] == '/') {
  585                 len = strlen(path);
  586                 if (len >= FDT_CWD_LEN)
  587                         goto fail;
  588         } else {
  589                 /* Handle path specification relative to cwd */
  590                 len = strlen(cwd) + strlen(path) + 1;
  591                 if (len >= FDT_CWD_LEN)
  592                         goto fail;
  593 
  594                 strcpy(tmp, cwd);
  595                 strcat(tmp, "/");
  596                 strcat(tmp, path);
  597                 path = tmp;
  598         }
  599 
  600         o = fdt_path_offset(fdtp, path);
  601         if (o < 0) {
  602                 sprintf(command_errbuf, "could not find node: '%s'", path);
  603                 return (CMD_ERROR);
  604         }
  605 
  606         strcpy(cwd, path);
  607         return (CMD_OK);
  608 
  609 fail:
  610         sprintf(command_errbuf, "path too long: %d, max allowed: %d",
  611             len, FDT_CWD_LEN - 1);
  612         return (CMD_ERROR);
  613 }
  614 
  615 static int
  616 fdt_cmd_hdr(int argc __unused, char *argv[] __unused)
  617 {
  618         char line[80];
  619         int ver;
  620 
  621         if (fdtp == NULL) {
  622                 command_errmsg = "no device tree blob pointer?!";
  623                 return (CMD_ERROR);
  624         }
  625 
  626         ver = fdt_version(fdtp);
  627         pager_open();
  628         sprintf(line, "\nFlattened device tree header (%p):\n", fdtp);
  629         pager_output(line);
  630         sprintf(line, " magic                   = 0x%08x\n", fdt_magic(fdtp));
  631         pager_output(line);
  632         sprintf(line, " size                    = %d\n", fdt_totalsize(fdtp));
  633         pager_output(line);
  634         sprintf(line, " off_dt_struct           = 0x%08x\n",
  635             fdt_off_dt_struct(fdtp));
  636         pager_output(line);
  637         sprintf(line, " off_dt_strings          = 0x%08x\n",
  638             fdt_off_dt_strings(fdtp));
  639         pager_output(line);
  640         sprintf(line, " off_mem_rsvmap          = 0x%08x\n",
  641             fdt_off_mem_rsvmap(fdtp));
  642         pager_output(line);
  643         sprintf(line, " version                 = %d\n", ver); 
  644         pager_output(line);
  645         sprintf(line, " last compatible version = %d\n",
  646             fdt_last_comp_version(fdtp));
  647         pager_output(line);
  648         if (ver >= 2) {
  649                 sprintf(line, " boot_cpuid              = %d\n",
  650                     fdt_boot_cpuid_phys(fdtp));
  651                 pager_output(line);
  652         }
  653         if (ver >= 3) {
  654                 sprintf(line, " size_dt_strings         = %d\n",
  655                     fdt_size_dt_strings(fdtp));
  656                 pager_output(line);
  657         }
  658         if (ver >= 17) {
  659                 sprintf(line, " size_dt_struct          = %d\n",
  660                     fdt_size_dt_struct(fdtp));
  661                 pager_output(line);
  662         }
  663         pager_close();
  664 
  665         return (CMD_OK);
  666 }
  667 
  668 static int
  669 fdt_cmd_ls(int argc, char *argv[])
  670 {
  671         const char *prevname[FDT_MAX_DEPTH] = { NULL };
  672         const char *name;
  673         char *path;
  674         int i, o, depth, len;
  675 
  676         path = (argc > 2) ? argv[2] : NULL;
  677         if (path == NULL)
  678                 path = cwd;
  679 
  680         o = fdt_path_offset(fdtp, path);
  681         if (o < 0) {
  682                 sprintf(command_errbuf, "could not find node: '%s'", path);
  683                 return (CMD_ERROR);
  684         }
  685 
  686         for (depth = 0;
  687             (o >= 0) && (depth >= 0);
  688             o = fdt_next_node(fdtp, o, &depth)) {
  689 
  690                 name = fdt_get_name(fdtp, o, &len);
  691 
  692                 if (depth > FDT_MAX_DEPTH) {
  693                         printf("max depth exceeded: %d\n", depth);
  694                         continue;
  695                 }
  696 
  697                 prevname[depth] = name;
  698 
  699                 /* Skip root (i = 1) when printing devices */
  700                 for (i = 1; i <= depth; i++) {
  701                         if (prevname[i] == NULL)
  702                                 break;
  703 
  704                         if (strcmp(cwd, "/") == 0)
  705                                 printf("/");
  706                         printf("%s", prevname[i]);
  707                 }
  708                 printf("\n");
  709         }
  710 
  711         return (CMD_OK);
  712 }
  713 
  714 static __inline int
  715 isprint(int c)
  716 {
  717 
  718         return (c >= ' ' && c <= 0x7e);
  719 }
  720 
  721 static int
  722 fdt_isprint(const void *data, int len, int *count)
  723 {
  724         const char *d;
  725         char ch;
  726         int yesno, i;
  727 
  728         if (len == 0)
  729                 return (0);
  730 
  731         d = (const char *)data;
  732         if (d[len - 1] != '\0')
  733                 return (0);
  734 
  735         *count = 0;
  736         yesno = 1;
  737         for (i = 0; i < len; i++) {
  738                 ch = *(d + i);
  739                 if (isprint(ch) || (ch == '\0' && i > 0)) {
  740                         /* Count strings */
  741                         if (ch == '\0')
  742                                 (*count)++;
  743                         continue;
  744                 }
  745 
  746                 yesno = 0;
  747                 break;
  748         }
  749 
  750         return (yesno);
  751 }
  752 
  753 static int
  754 fdt_data_str(const void *data, int len, int count, char **buf)
  755 {
  756         char tmp[80], *b;
  757         const char *d;
  758         int i, l;
  759 
  760         /*
  761          * Calculate the length for the string and allocate memory.
  762          *
  763          * Note len already includes at least one terminator.
  764          */
  765         l = len;
  766         if (count > 1) {
  767                 /*
  768                  * Each token had already a terminator buried in 'len', but we
  769                  * only need one eventually, don't count space for these.
  770                  */
  771                 l -= count - 1;
  772 
  773                 /* Each consecutive token requires a ", " separator. */
  774                 l += count * 2;
  775         }
  776         /* Space for surrounding double quotes. */
  777         l += count * 2;
  778 
  779         b = (char *)malloc(l);
  780         if (b == NULL)
  781                 return (1);
  782         b[0] = '\0';
  783 
  784         /*
  785          * Now that we have space, format the string.
  786          */
  787         i = 0;
  788         do {
  789                 d = (const char *)data + i;
  790                 l = strlen(d) + 1;
  791 
  792                 sprintf(tmp, "\"%s\"%s", d,
  793                     (i + l) < len ?  ", " : "");
  794                 strcat(b, tmp);
  795 
  796                 i += l;
  797 
  798         } while (i < len);
  799         *buf = b;
  800 
  801         return (0);
  802 }
  803 
  804 static int
  805 fdt_data_cell(const void *data, int len, char **buf)
  806 {
  807         char tmp[80], *b;
  808         const uint32_t *c;
  809         int count, i, l;
  810 
  811         /* Number of cells */
  812         count = len / 4;
  813 
  814         /*
  815          * Calculate the length for the string and allocate memory.
  816          */
  817 
  818         /* Each byte translates to 2 output characters */
  819         l = len * 2;
  820         if (count > 1) {
  821                 /* Each consecutive cell requires a " " separator. */
  822                 l += (count - 1) * 1;
  823         }
  824         /* Each cell will have a "0x" prefix */
  825         l += count * 2;
  826         /* Space for surrounding <> and terminator */
  827         l += 3;
  828 
  829         b = (char *)malloc(l);
  830         if (b == NULL)
  831                 return (1);
  832 
  833         b[0] = '\0';
  834         strcat(b, "<");
  835 
  836         for (i = 0; i < len; i += 4) {
  837                 c = (const uint32_t *)((const uint8_t *)data + i);
  838                 sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c),
  839                     i < (len - 4) ? " " : "");
  840                 strcat(b, tmp);
  841         }
  842         strcat(b, ">");
  843         *buf = b;
  844 
  845         return (0);
  846 }
  847 
  848 static int
  849 fdt_data_bytes(const void *data, int len, char **buf)
  850 {
  851         char tmp[80], *b;
  852         const char *d;
  853         int i, l;
  854 
  855         /*
  856          * Calculate the length for the string and allocate memory.
  857          */
  858 
  859         /* Each byte translates to 2 output characters */
  860         l = len * 2;
  861         if (len > 1)
  862                 /* Each consecutive byte requires a " " separator. */
  863                 l += (len - 1) * 1;
  864         /* Each byte will have a "0x" prefix */
  865         l += len * 2;
  866         /* Space for surrounding [] and terminator. */
  867         l += 3;
  868 
  869         b = (char *)malloc(l);
  870         if (b == NULL)
  871                 return (1);
  872 
  873         b[0] = '\0';
  874         strcat(b, "[");
  875 
  876         for (i = 0, d = data; i < len; i++) {
  877                 sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : "");
  878                 strcat(b, tmp);
  879         }
  880         strcat(b, "]");
  881         *buf = b;
  882 
  883         return (0);
  884 }
  885 
  886 static int
  887 fdt_data_fmt(const void *data, int len, char **buf)
  888 {
  889         int count;
  890 
  891         if (len == 0) {
  892                 *buf = NULL;
  893                 return (1);
  894         }
  895 
  896         if (fdt_isprint(data, len, &count))
  897                 return (fdt_data_str(data, len, count, buf));
  898 
  899         else if ((len % 4) == 0)
  900                 return (fdt_data_cell(data, len, buf));
  901 
  902         else
  903                 return (fdt_data_bytes(data, len, buf));
  904 }
  905 
  906 static int
  907 fdt_prop(int offset)
  908 {
  909         char *line, *buf;
  910         const struct fdt_property *prop;
  911         const char *name;
  912         const void *data;
  913         int len, rv;
  914 
  915         line = NULL;
  916         prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop));
  917         if (prop == NULL)
  918                 return (1);
  919 
  920         name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
  921         len = fdt32_to_cpu(prop->len);
  922 
  923         rv = 0;
  924         buf = NULL;
  925         if (len == 0) {
  926                 /* Property without value */
  927                 line = (char *)malloc(strlen(name) + 2);
  928                 if (line == NULL) {
  929                         rv = 2;
  930                         goto out2;
  931                 }
  932                 sprintf(line, "%s\n", name);
  933                 goto out1;
  934         }
  935 
  936         /*
  937          * Process property with value
  938          */
  939         data = prop->data;
  940 
  941         if (fdt_data_fmt(data, len, &buf) != 0) {
  942                 rv = 3;
  943                 goto out2;
  944         }
  945 
  946         line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) +
  947             strlen(buf) + 2);
  948         if (line == NULL) {
  949                 sprintf(command_errbuf, "could not allocate space for string");
  950                 rv = 4;
  951                 goto out2;
  952         }
  953 
  954         sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf);
  955 
  956 out1:
  957         pager_open();
  958         pager_output(line);
  959         pager_close();
  960 
  961 out2:
  962         if (buf)
  963                 free(buf);
  964 
  965         if (line)
  966                 free(line);
  967 
  968         return (rv);
  969 }
  970 
  971 static int
  972 fdt_modprop(int nodeoff, char *propname, void *value, char mode)
  973 {
  974         uint32_t cells[100];
  975         char *buf;
  976         int len, rv;
  977         const struct fdt_property *p;
  978 
  979         p = fdt_get_property(fdtp, nodeoff, propname, NULL);
  980 
  981         if (p != NULL) {
  982                 if (mode == 1) {
  983                          /* Adding inexistant value in mode 1 is forbidden */
  984                         sprintf(command_errbuf, "property already exists!");
  985                         return (CMD_ERROR);
  986                 }
  987         } else if (mode == 0) {
  988                 sprintf(command_errbuf, "property does not exist!");
  989                 return (CMD_ERROR);
  990         }
  991         len = strlen(value);
  992         rv = 0;
  993         buf = (char *)value;
  994 
  995         switch (*buf) {
  996         case '&':
  997                 /* phandles */
  998                 break;
  999         case '<':
 1000                 /* Data cells */
 1001                 len = fdt_strtovect(buf, (void *)&cells, 100,
 1002                     sizeof(uint32_t));
 1003 
 1004                 rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
 1005                     len * sizeof(uint32_t));
 1006                 break;
 1007         case '[':
 1008                 /* Data bytes */
 1009                 len = fdt_strtovect(buf, (void *)&cells, 100,
 1010                     sizeof(uint8_t));
 1011 
 1012                 rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
 1013                     len * sizeof(uint8_t));
 1014                 break;
 1015         case '"':
 1016         default:
 1017                 /* Default -- string */
 1018                 rv = fdt_setprop_string(fdtp, nodeoff, propname, value);
 1019                 break;
 1020         }
 1021 
 1022         return (rv);
 1023 }
 1024 
 1025 /* Merge strings from argv into a single string */
 1026 static int
 1027 fdt_merge_strings(int argc, char *argv[], int start, char **buffer)
 1028 {
 1029         char *buf;
 1030         int i, idx, sz;
 1031 
 1032         *buffer = NULL;
 1033         sz = 0;
 1034 
 1035         for (i = start; i < argc; i++)
 1036                 sz += strlen(argv[i]);
 1037 
 1038         /* Additional bytes for whitespaces between args */
 1039         sz += argc - start;
 1040 
 1041         buf = (char *)malloc(sizeof(char) * sz);
 1042         bzero(buf, sizeof(char) * sz);
 1043 
 1044         if (buf == NULL) {
 1045                 sprintf(command_errbuf, "could not allocate space "
 1046                     "for string");
 1047                 return (1);
 1048         }
 1049 
 1050         idx = 0;
 1051         for (i = start, idx = 0; i < argc; i++) {
 1052                 strcpy(buf + idx, argv[i]);
 1053                 idx += strlen(argv[i]);
 1054                 buf[idx] = ' ';
 1055                 idx++;
 1056         }
 1057         buf[sz - 1] = '\0';
 1058         *buffer = buf;
 1059         return (0);
 1060 }
 1061 
 1062 /* Extract offset and name of node/property from a given path */
 1063 static int
 1064 fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff)
 1065 {
 1066         int o;
 1067         char *path = *pathp, *name = NULL, *subpath = NULL;
 1068 
 1069         subpath = strrchr(path, '/');
 1070         if (subpath == NULL) {
 1071                 o = fdt_path_offset(fdtp, cwd);
 1072                 name = path;
 1073                 path = (char *)&cwd;
 1074         } else {
 1075                 *subpath = '\0';
 1076                 if (strlen(path) == 0)
 1077                         path = cwd;
 1078 
 1079                 name = subpath + 1;
 1080                 o = fdt_path_offset(fdtp, path);
 1081         }
 1082 
 1083         if (strlen(name) == 0) {
 1084                 sprintf(command_errbuf, "name not specified");
 1085                 return (1);
 1086         }
 1087         if (o < 0) {
 1088                 sprintf(command_errbuf, "could not find node: '%s'", path);
 1089                 return (1);
 1090         }
 1091         *namep = name;
 1092         *nodeoff = o;
 1093         *pathp = path;
 1094         return (0);
 1095 }
 1096 
 1097 static int
 1098 fdt_cmd_prop(int argc, char *argv[])
 1099 {
 1100         char *path, *propname, *value;
 1101         int o, next, depth, rv;
 1102         uint32_t tag;
 1103 
 1104         path = (argc > 2) ? argv[2] : NULL;
 1105 
 1106         value = NULL;
 1107 
 1108         if (argc > 3) {
 1109                 /* Merge property value strings into one */
 1110                 if (fdt_merge_strings(argc, argv, 3, &value) != 0)
 1111                         return (CMD_ERROR);
 1112         } else
 1113                 value = NULL;
 1114 
 1115         if (path == NULL)
 1116                 path = cwd;
 1117 
 1118         rv = CMD_OK;
 1119 
 1120         if (value) {
 1121                 /* If value is specified -- try to modify prop. */
 1122                 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
 1123                         return (CMD_ERROR);
 1124 
 1125                 rv = fdt_modprop(o, propname, value, 0);
 1126                 if (rv)
 1127                         return (CMD_ERROR);
 1128                 return (CMD_OK);
 1129 
 1130         }
 1131         /* User wants to display properties */
 1132         o = fdt_path_offset(fdtp, path);
 1133 
 1134         if (o < 0) {
 1135                 sprintf(command_errbuf, "could not find node: '%s'", path);
 1136                 rv = CMD_ERROR;
 1137                 goto out;
 1138         }
 1139 
 1140         depth = 0;
 1141         while (depth >= 0) {
 1142                 tag = fdt_next_tag(fdtp, o, &next);
 1143                 switch (tag) {
 1144                 case FDT_NOP:
 1145                         break;
 1146                 case FDT_PROP:
 1147                         if (depth > 1)
 1148                                 /* Don't process properties of nested nodes */
 1149                                 break;
 1150 
 1151                         if (fdt_prop(o) != 0) {
 1152                                 sprintf(command_errbuf, "could not process "
 1153                                     "property");
 1154                                 rv = CMD_ERROR;
 1155                                 goto out;
 1156                         }
 1157                         break;
 1158                 case FDT_BEGIN_NODE:
 1159                         depth++;
 1160                         if (depth > FDT_MAX_DEPTH) {
 1161                                 printf("warning: nesting too deep: %d\n",
 1162                                     depth);
 1163                                 goto out;
 1164                         }
 1165                         break;
 1166                 case FDT_END_NODE:
 1167                         depth--;
 1168                         if (depth == 0)
 1169                                 /*
 1170                                  * This is the end of our starting node, force
 1171                                  * the loop finish.
 1172                                  */
 1173                                 depth--;
 1174                         break;
 1175                 }
 1176                 o = next;
 1177         }
 1178 out:
 1179         return (rv);
 1180 }
 1181 
 1182 static int
 1183 fdt_cmd_mkprop(int argc, char *argv[])
 1184 {
 1185         int o;
 1186         char *path, *propname, *value;
 1187 
 1188         path = (argc > 2) ? argv[2] : NULL;
 1189 
 1190         value = NULL;
 1191 
 1192         if (argc > 3) {
 1193                 /* Merge property value strings into one */
 1194                 if (fdt_merge_strings(argc, argv, 3, &value) != 0)
 1195                         return (CMD_ERROR);
 1196         } else
 1197                 value = NULL;
 1198 
 1199         if (fdt_extract_nameloc(&path, &propname, &o) != 0)
 1200                 return (CMD_ERROR);
 1201 
 1202         if (fdt_modprop(o, propname, value, 1))
 1203                 return (CMD_ERROR);
 1204 
 1205         return (CMD_OK);
 1206 }
 1207 
 1208 static int
 1209 fdt_cmd_rm(int argc, char *argv[])
 1210 {
 1211         int o, rv;
 1212         char *path = NULL, *propname;
 1213 
 1214         if (argc > 2)
 1215                 path = argv[2];
 1216         else {
 1217                 sprintf(command_errbuf, "no node/property name specified");
 1218                 return (CMD_ERROR);
 1219         }
 1220 
 1221         o = fdt_path_offset(fdtp, path);
 1222         if (o < 0) {
 1223                 /* If node not found -- try to find & delete property */
 1224                 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
 1225                         return (CMD_ERROR);
 1226 
 1227                 if ((rv = fdt_delprop(fdtp, o, propname)) != 0) {
 1228                         sprintf(command_errbuf, "could not delete"
 1229                             "%s\n", (rv == -FDT_ERR_NOTFOUND) ?
 1230                             "(property/node does not exist)" : "");
 1231                         return (CMD_ERROR);
 1232 
 1233                 } else
 1234                         return (CMD_OK);
 1235         }
 1236         /* If node exists -- remove node */
 1237         rv = fdt_del_node(fdtp, o);
 1238         if (rv) {
 1239                 sprintf(command_errbuf, "could not delete node");
 1240                 return (CMD_ERROR);
 1241         }
 1242         return (CMD_OK);
 1243 }
 1244 
 1245 static int
 1246 fdt_cmd_mknode(int argc, char *argv[])
 1247 {
 1248         int o, rv;
 1249         char *path = NULL, *nodename = NULL;
 1250 
 1251         if (argc > 2)
 1252                 path = argv[2];
 1253         else {
 1254                 sprintf(command_errbuf, "no node name specified");
 1255                 return (CMD_ERROR);
 1256         }
 1257 
 1258         if (fdt_extract_nameloc(&path, &nodename, &o) != 0)
 1259                 return (CMD_ERROR);
 1260 
 1261         rv = fdt_add_subnode(fdtp, o, nodename);
 1262 
 1263         if (rv < 0) {
 1264                 sprintf(command_errbuf, "could not delete node %s\n",
 1265                     (rv == -FDT_ERR_NOTFOUND) ?
 1266                     "(node does not exist)" : "");
 1267                 return (CMD_ERROR);
 1268         }
 1269         return (CMD_OK);
 1270 }
 1271 
 1272 static int
 1273 fdt_cmd_pwd(int argc, char *argv[])
 1274 {
 1275         char line[80];
 1276 
 1277         pager_open();
 1278         sprintf(line, "%s\n", cwd);
 1279         pager_output(line);
 1280         pager_close();
 1281         return (CMD_OK);
 1282 }
 1283 
 1284 static int
 1285 fdt_cmd_nyi(int argc, char *argv[])
 1286 {
 1287 
 1288         printf("command not yet implemented\n");
 1289         return (CMD_ERROR);
 1290 }

Cache object: 0eb644d1ef4f06cfd08b33607e5640df


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.