* 8MB ROM the start address is 0xfff80000.
* @write_fname: Filename to add to the image
* @offset_uboot_top: Offset of the top of U-Boot
+ * @offset_uboot_start: Offset of the start of U-Boot
* @return number of bytes written if OK, -ve on error
*/
static int write_data(char *image, int size, unsigned int addr,
- const char *write_fname, int offset_uboot_top)
+ const char *write_fname, int offset_uboot_top,
+ int offset_uboot_start)
{
int write_fd, write_size;
int offset;
return write_fd;
offset = (uint32_t)(addr + size);
- if (offset_uboot_top && offset_uboot_top >= offset) {
- fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
- write_fname);
- fprintf(stderr,
- "U-Boot finishes at offset %x, file starts at %x\n",
- offset_uboot_top, offset);
- return -EXDEV;
+ if (offset_uboot_top) {
+ if (offset_uboot_start < offset &&
+ offset_uboot_top >= offset) {
+ fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+ write_fname);
+ fprintf(stderr,
+ "U-Boot finishes at offset %x, file starts at %x\n",
+ offset_uboot_top, offset);
+ return -EXDEV;
+ }
+ if (offset_uboot_start > offset &&
+ offset_uboot_start <= offset + write_size) {
+ fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+ write_fname);
+ fprintf(stderr,
+ "U-Boot starts at offset %x, file finishes at %x\n",
+ offset_uboot_start, offset + write_size);
+ return -EXDEV;
+ }
}
debug("Writing %s to offset %#x\n", write_fname, offset);
return -ENOENT;
}
+ if (ucode_base)
+ memcpy(ucode, data, data_size);
ucode += data_size;
}
return ucode - ucode_base;
}
+static int remove_ucode(char *blob)
+{
+ int node, count;
+ int ret;
+
+ /* Keep going until we find no more microcode to remove */
+ do {
+ for (node = 0, count = 0; node >= 0;) {
+ int ret;
+
+ node = fdt_node_offset_by_compatible(blob, node,
+ "intel,microcode");
+ if (node < 0)
+ break;
+
+ ret = fdt_delprop(blob, node, "data");
+
+ /*
+ * -FDT_ERR_NOTFOUND means we already removed the
+ * data for this one, so we just continue.
+ * 0 means we did remove it, so offsets may have
+ * changed and we need to restart our scan.
+ * Anything else indicates an error we should report.
+ */
+ if (ret == -FDT_ERR_NOTFOUND)
+ continue;
+ else if (!ret)
+ node = 0;
+ else
+ return ret;
+ }
+ } while (count);
+
+ /* Pack down to remove excees space */
+ ret = fdt_pack(blob);
+ if (ret)
+ return ret;
+
+ return fdt_totalsize(blob);
+}
+
static int write_ucode(char *image, int size, struct input_file *fdt,
- int fdt_size, unsigned int ucode_ptr)
+ int fdt_size, unsigned int ucode_ptr,
+ int collate_ucode)
{
const char *data = NULL;
+ char *ucode_buf;
const void *blob;
+ char *ucode_base;
uint32_t *ptr;
int ucode_size;
int data_size;
int offset;
int count;
+ int ret;
blob = (void *)image + (uint32_t)(fdt->addr + size);
return -ENOENT;
}
- if (count > 1) {
+ if (count > 1 && !collate_ucode) {
fprintf(stderr,
- "Cannot handle multiple microcode blocks\n");
+ "Cannot handle multiple microcode blocks - please use -C flag to collate them\n");
return -EMLINK;
}
+ /*
+ * Collect the microcode into a buffer, remove it from the device
+ * tree and place it immediately above the (now smaller) device tree.
+ */
+ if (collate_ucode && count > 1) {
+ ucode_buf = malloc(ucode_size);
+ if (!ucode_buf) {
+ fprintf(stderr,
+ "Out of memory for microcode (%d bytes)\n",
+ ucode_size);
+ return -ENOMEM;
+ }
+ ret = scan_ucode(blob, ucode_buf, NULL, NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Remove the microcode from the device tree */
+ ret = remove_ucode((char *)blob);
+ if (ret < 0) {
+ debug("Could not remove FDT microcode: %s\n",
+ fdt_strerror(ret));
+ return -EINVAL;
+ }
+ debug("Collated %d microcode block(s)\n", count);
+ debug("Device tree reduced from %x to %x bytes\n",
+ fdt_size, ret);
+ fdt_size = ret;
+
+ /*
+ * Place microcode area immediately above the FDT, aligned
+ * to a 16-byte boundary.
+ */
+ ucode_base = (char *)(((unsigned long)blob + fdt_size + 15) &
+ ~15);
+
+ data = ucode_base;
+ data_size = ucode_size;
+ memcpy(ucode_base, ucode_buf, ucode_size);
+ free(ucode_buf);
+ }
+
offset = (uint32_t)(ucode_ptr + size);
ptr = (void *)image + offset;
debug("Wrote microcode pointer at %x: addr=%x, size=%x\n", ucode_ptr,
ptr[0], ptr[1]);
- return 0;
+ return (collate_ucode ? data + data_size : (char *)blob + fdt_size) -
+ image;
}
/**
* @return 0 if OK, -ve on error
*/
static int write_uboot(char *image, int size, struct input_file *uboot,
- struct input_file *fdt, unsigned int ucode_ptr)
+ struct input_file *fdt, unsigned int ucode_ptr,
+ int collate_ucode, int *offset_uboot_top,
+ int *offset_uboot_start)
{
- const void *blob;
int uboot_size, fdt_size;
+ int uboot_top;
- uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0);
+ uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0, 0);
if (uboot_size < 0)
return uboot_size;
fdt->addr = uboot->addr + uboot_size;
debug("U-Boot size %#x, FDT at %#x\n", uboot_size, fdt->addr);
- fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0);
+ fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0, 0);
if (fdt_size < 0)
return fdt_size;
- blob = (void *)image + (uint32_t)(fdt->addr + size);
- if (ucode_ptr)
- return write_ucode(image, size, fdt, fdt_size, ucode_ptr);
+ uboot_top = (uint32_t)(fdt->addr + size) + fdt_size;
+
+ if (ucode_ptr) {
+ uboot_top = write_ucode(image, size, fdt, fdt_size, ucode_ptr,
+ collate_ucode);
+ if (uboot_top < 0)
+ return uboot_top;
+ }
- return ((char *)blob + fdt_size) - image;
+ if (offset_uboot_top && offset_uboot_start) {
+ *offset_uboot_top = uboot_top;
+ *offset_uboot_start = (uint32_t)(uboot->addr + size);
+ }
+
+ return 0;
}
static void print_version(void)
int mode_dump = 0, mode_extract = 0, mode_inject = 0;
int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0;
int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0;
- int create = 0;
+ int create = 0, collate_ucode = 0;
char *region_type_string = NULL, *inject_fname = NULL;
char *desc_fname = NULL, *addr_str = NULL;
int region_type = -1, inputfreq = 0;
int ret;
static struct option long_options[] = {
{"create", 0, NULL, 'c'},
+ {"collate-microcode", 0, NULL, 'C'},
{"dump", 0, NULL, 'd'},
{"descriptor", 1, NULL, 'D'},
{"em100", 0, NULL, 'e'},
{0, 0, 0, 0}
};
- while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lm:r:s:uU:vw:x?",
+ while ((opt = getopt_long(argc, argv, "cCdD:ef:hi:lm:r:s:uU:vw:x?",
long_options, &option_index)) != EOF) {
switch (opt) {
case 'c':
create = 1;
break;
+ case 'C':
+ collate_ucode = 1;
+ break;
case 'd':
mode_dump = 1;
break;
}
if (mode_write_descriptor)
- ret = write_data(image, size, -size, desc_fname, 0);
+ ret = write_data(image, size, -size, desc_fname, 0, 0);
if (mode_inject)
ret = inject_region(image, size, region_type, inject_fname);
if (mode_write) {
int offset_uboot_top = 0;
+ int offset_uboot_start = 0;
for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
ifile = &input_file[wr_idx];
continue;
} else if (ifile->type == IF_uboot) {
ret = write_uboot(image, size, ifile, fdt,
- ucode_ptr);
- offset_uboot_top = ret;
+ ucode_ptr, collate_ucode,
+ &offset_uboot_top,
+ &offset_uboot_start);
} else {
ret = write_data(image, size, ifile->addr,
- ifile->fname, offset_uboot_top);
+ ifile->fname, offset_uboot_top,
+ offset_uboot_start);
}
if (ret < 0)
break;