binman: Tweak collect_contents_to_file() and docs
[platform/kernel/u-boot.git] / boot / pxe_utils.c
index 48fb707..0c24bec 100644 (file)
 #include <errno.h>
 #include <linux/list.h>
 
+#ifdef CONFIG_DM_RNG
+#include <dm.h>
+#include <rng.h>
+#endif
+
 #include <splash.h>
 #include <asm/io.h>
 
 
 #define MAX_TFTP_PATH_LEN 512
 
+int pxe_get_file_size(ulong *sizep)
+{
+       const char *val;
+
+       val = from_env("filesize");
+       if (!val)
+               return -ENOENT;
+
+       if (strict_strtoul(val, 16, sizep) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
 /**
  * format_mac_pxe() - obtain a MAC address in the PXE format
  *
@@ -42,7 +61,7 @@
  *
  * @outbuf: Buffer to write string to
  * @outbuf_len: length of buffer
- * @return 1 if OK, -ENOSPC if buffer is too small, -ENOENT is there is no
+ * Return: 1 if OK, -ENOSPC if buffer is too small, -ENOENT is there is no
  *     current ethernet device
  */
 int format_mac_pxe(char *outbuf, size_t outbuf_len)
@@ -75,14 +94,17 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len)
  * @ctx: PXE context
  * @file_path: File path to read (relative to the PXE file)
  * @file_addr: Address to load file to
+ * @filesizep: If not NULL, returns the file size in bytes
  * Returns 1 for success, or < 0 on error
  */
 static int get_relfile(struct pxe_context *ctx, const char *file_path,
-                      unsigned long file_addr)
+                      unsigned long file_addr, ulong *filesizep)
 {
        size_t path_len;
        char relfile[MAX_TFTP_PATH_LEN + 1];
        char addr_buf[18];
+       ulong size;
+       int ret;
 
        if (file_path[0] == '/' && ctx->allow_abs_path)
                *relfile = '\0';
@@ -103,7 +125,13 @@ static int get_relfile(struct pxe_context *ctx, const char *file_path,
 
        sprintf(addr_buf, "%lx", file_addr);
 
-       return ctx->getfile(ctx, relfile, addr_buf);
+       ret = ctx->getfile(ctx, relfile, addr_buf, &size);
+       if (ret < 0)
+               return log_msg_ret("get", ret);
+       if (filesizep)
+               *filesizep = size;
+
+       return 1;
 }
 
 /**
@@ -117,29 +145,17 @@ static int get_relfile(struct pxe_context *ctx, const char *file_path,
  * Returns 1 for success, or < 0 on error
  */
 int get_pxe_file(struct pxe_context *ctx, const char *file_path,
-                unsigned long file_addr)
+                ulong file_addr)
 {
-       unsigned long config_file_size;
-       char *tftp_filesize;
+       ulong size;
        int err;
        char *buf;
 
-       err = get_relfile(ctx, file_path, file_addr);
+       err = get_relfile(ctx, file_path, file_addr, &size);
        if (err < 0)
                return err;
 
-       /*
-        * the file comes without a NUL byte at the end, so find out its size
-        * and add the NUL byte.
-        */
-       tftp_filesize = from_env("filesize");
-       if (!tftp_filesize)
-               return -ENOENT;
-
-       if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
-               return -EINVAL;
-
-       buf = map_sysmem(file_addr + config_file_size, 1);
+       buf = map_sysmem(file_addr + size, 1);
        *buf = '\0';
        unmap_sysmem(buf);
 
@@ -184,12 +200,13 @@ int get_pxelinux_path(struct pxe_context *ctx, const char *file,
  * @file_path: File path to read (relative to the PXE file)
  * @envaddr_name: Name of environment variable which contains the address to
  *     load to
+ * @filesizep: Returns the file size in bytes
  * Returns 1 on success, -ENOENT if @envaddr_name does not exist as an
  *     environment variable, -EINVAL if its format is not valid hex, or other
  *     value < 0 on other error
  */
 static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path,
-                              const char *envaddr_name)
+                              const char *envaddr_name, ulong *filesizep)
 {
        unsigned long file_addr;
        char *envaddr;
@@ -201,7 +218,7 @@ static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path,
        if (strict_strtoul(envaddr, 16, &file_addr) < 0)
                return -EINVAL;
 
-       return get_relfile(ctx, file_path, file_addr);
+       return get_relfile(ctx, file_path, file_addr, filesizep);
 }
 
 /**
@@ -299,6 +316,67 @@ static int label_localboot(struct pxe_label *label)
        return run_command_list(localcmd, strlen(localcmd), 0);
 }
 
+/*
+ * label_boot_kaslrseed generate kaslrseed from hw rng
+ */
+
+static void label_boot_kaslrseed(void)
+{
+#ifdef CONFIG_DM_RNG
+       ulong fdt_addr;
+       struct fdt_header *working_fdt;
+       size_t n = 0x8;
+       struct udevice *dev;
+       u64 *buf;
+       int nodeoffset;
+       int err;
+
+       /* Get the main fdt and map it */
+       fdt_addr = hextoul(env_get("fdt_addr_r"), NULL);
+       working_fdt = map_sysmem(fdt_addr, 0);
+       err = fdt_check_header(working_fdt);
+       if (err)
+               return;
+
+       /* add extra size for holding kaslr-seed */
+       /* err is new fdt size, 0 or negtive */
+       err = fdt_shrink_to_minimum(working_fdt, 512);
+       if (err <= 0)
+               return;
+
+       if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) {
+               printf("No RNG device\n");
+               return;
+       }
+
+       nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
+       if (nodeoffset < 0) {
+               printf("Reading chosen node failed\n");
+               return;
+       }
+
+       buf = malloc(n);
+       if (!buf) {
+               printf("Out of memory\n");
+               return;
+       }
+
+       if (dm_rng_read(dev, buf, n)) {
+               printf("Reading RNG failed\n");
+               goto err;
+       }
+
+       err = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, sizeof(buf));
+       if (err < 0) {
+               printf("Unable to set kaslr-seed on chosen node: %s\n", fdt_strerror(err));
+               goto err;
+       }
+err:
+       free(buf);
+#endif
+       return;
+}
+
 /**
  * label_boot_fdtoverlay() - Loads fdt overlays specified in 'fdtoverlays'
  *
@@ -357,8 +435,8 @@ static void label_boot_fdtoverlay(struct pxe_context *ctx,
                        goto skip_overlay;
 
                /* Load overlay file */
-               err = get_relfile_envaddr(ctx, overlayfile,
-                                         "fdtoverlay_addr_r");
+               err = get_relfile_envaddr(ctx, overlayfile, "fdtoverlay_addr_r",
+                                         NULL);
                if (err < 0) {
                        printf("Failed loading overlay %s\n", overlayfile);
                        goto skip_overlay;
@@ -443,21 +521,25 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
        }
 
        if (label->initrd) {
-               if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r") < 0) {
+               ulong size;
+
+               if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
+                                       &size) < 0) {
                        printf("Skipping %s for failure retrieving initrd\n",
                               label->name);
                        return 1;
                }
 
                initrd_addr_str = env_get("ramdisk_addr_r");
-               strncpy(initrd_filesize, env_get("filesize"), 9);
+               strcpy(initrd_filesize, simple_xtoa(size));
 
                strncpy(initrd_str, initrd_addr_str, 18);
                strcat(initrd_str, ":");
                strncat(initrd_str, initrd_filesize, 9);
        }
 
-       if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r") < 0) {
+       if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r",
+                               NULL) < 0) {
                printf("Skipping %s for failure retrieving kernel\n",
                       label->name);
                return 1;
@@ -534,7 +616,10 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
         * Scenario 2: If there is an fdt_addr specified, pass it along to
         * bootm, and adjust argc appropriately.
         *
-        * Scenario 3: fdt blob is not available.
+        * Scenario 3: If there is an fdtcontroladdr specified, pass it along to
+        * bootm, and adjust argc appropriately.
+        *
+        * Scenario 4: fdt blob is not available.
         */
        bootm_argv[3] = env_get("fdt_addr_r");
 
@@ -599,7 +684,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
 
                if (fdtfile) {
                        int err = get_relfile_envaddr(ctx, fdtfile,
-                                                     "fdt_addr_r");
+                                                     "fdt_addr_r", NULL);
 
                        free(fdtfilefree);
                        if (err < 0) {
@@ -612,6 +697,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
                                }
                        }
 
+               if (label->kaslrseed)
+                       label_boot_kaslrseed();
+
 #ifdef CONFIG_OF_LIBFDT_OVERLAY
                        if (label->fdtoverlays)
                                label_boot_fdtoverlay(ctx, label);
@@ -636,6 +724,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
        if (!bootm_argv[3])
                bootm_argv[3] = env_get("fdt_addr");
 
+       if (!bootm_argv[3])
+               bootm_argv[3] = env_get("fdtcontroladdr");
+
        if (bootm_argv[3]) {
                if (!bootm_argv[2])
                        bootm_argv[2] = "-";
@@ -688,6 +779,7 @@ enum token_type {
        T_ONTIMEOUT,
        T_IPAPPEND,
        T_BACKGROUND,
+       T_KASLRSEED,
        T_INVALID
 };
 
@@ -719,6 +811,7 @@ static const struct token keywords[] = {
        {"ontimeout", T_ONTIMEOUT,},
        {"ipappend", T_IPAPPEND,},
        {"background", T_BACKGROUND,},
+       {"kaslrseed", T_KASLRSEED,},
        {NULL, T_INVALID}
 };
 
@@ -1172,6 +1265,10 @@ static int parse_label(char **c, struct pxe_menu *cfg)
                        err = parse_integer(c, &label->ipappend);
                        break;
 
+               case T_KASLRSEED:
+                       label->kaslrseed = 1;
+                       break;
+
                case T_EOL:
                        break;
 
@@ -1333,9 +1430,11 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        struct pxe_label *label;
        struct list_head *pos;
        struct menu *m;
+       char *label_override;
        int err;
        int i = 1;
        char *default_num = NULL;
+       char *override_num = NULL;
 
        /*
         * Create a menu and add items for all the labels.
@@ -1345,6 +1444,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        if (!m)
                return NULL;
 
+       label_override = env_get("pxe_label_override");
+
        list_for_each(pos, &cfg->labels) {
                label = list_entry(pos, struct pxe_label, list);
 
@@ -1356,6 +1457,17 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
                if (cfg->default_label &&
                    (strcmp(label->name, cfg->default_label) == 0))
                        default_num = label->num;
+               if (label_override && !strcmp(label->name, label_override))
+                       override_num = label->num;
+       }
+
+
+       if (label_override) {
+               if (override_num)
+                       default_num = override_num;
+               else
+                       printf("Missing override pxe label: %s\n",
+                             label_override);
        }
 
        /*
@@ -1403,7 +1515,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
        if (IS_ENABLED(CONFIG_CMD_BMP)) {
                /* display BMP if available */
                if (cfg->bmp) {
-                       if (get_relfile(ctx, cfg->bmp, image_load_addr)) {
+                       if (get_relfile(ctx, cfg->bmp, image_load_addr, NULL)) {
                                if (CONFIG_IS_ENABLED(CMD_CLS))
                                        run_command("cls", 0);
                                bmp_display(image_load_addr,