diff options
| author | Tom Rini <[email protected]> | 2024-08-09 16:03:21 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2024-08-09 16:03:21 -0600 |
| commit | f4f845b859266790b97421f0740efce36bc9b8d2 (patch) | |
| tree | 72a80e6e3a5e4b19c2c4ccdc5876da035bd745fb /common | |
| parent | 49d7b206fb3a30553795fb5c1dd21573d82a98aa (diff) | |
| parent | 3403422767650d3ff4f3129ee959e1b5de525161 (diff) | |
Merge patch series "Universal Payload initial series"
Simon Glass <[email protected]> says:
Universal Payload (UPL) is an Industry Standard for firmware
components[1]. UPL is designed to improve interoperability within the
firmware industry, allowing mixing and matching of projects with less
friction and fewer project-specific implementations. UPL is
cross-platform, supporting ARM, x86 and RISC-V initially.
This series provides some initial support for this, targeting 0.9.1 and
sandbox only.
Features still to come include:
- Support for architectures
- FIT validation
- Handoff validation
- Interoperability tests
Diffstat (limited to 'common')
| -rw-r--r-- | common/board_f.c | 22 | ||||
| -rw-r--r-- | common/board_r.c | 2 | ||||
| -rw-r--r-- | common/spl/Makefile | 2 | ||||
| -rw-r--r-- | common/spl/spl.c | 8 | ||||
| -rw-r--r-- | common/spl/spl_fit.c | 9 | ||||
| -rw-r--r-- | common/spl/spl_upl.c | 172 |
6 files changed, 215 insertions, 0 deletions
diff --git a/common/board_f.c b/common/board_f.c index 29e185137ad..d71005d9f83 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -40,6 +40,7 @@ #include <sysreset.h> #include <timer.h> #include <trace.h> +#include <upl.h> #include <video.h> #include <watchdog.h> #include <asm/cache.h> @@ -859,6 +860,26 @@ __weak int clear_bss(void) return 0; } +static int initf_upl(void) +{ + struct upl *upl; + int ret; + + if (!IS_ENABLED(CONFIG_UPL_IN) || !(gd->flags & GD_FLG_UPL)) + return 0; + + upl = malloc(sizeof(struct upl)); + if (upl) + ret = upl_read_handoff(upl, oftree_default()); + if (ret) { + printf("UPL handoff: read failure (err=%dE)\n", ret); + return ret; + } + gd_set_upl(upl); + + return 0; +} + static const init_fnc_t init_sequence_f[] = { setup_mon_len, #ifdef CONFIG_OF_CONTROL @@ -868,6 +889,7 @@ static const init_fnc_t init_sequence_f[] = { trace_early_init, #endif initf_malloc, + initf_upl, log_init, initf_bootstage, /* uses its own timer, so does not need DM */ event_init, diff --git a/common/board_r.c b/common/board_r.c index d4ba245ac69..f445803d7a4 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -521,6 +521,8 @@ static int dm_announce(void) uclass_count); if (CONFIG_IS_ENABLED(OF_REAL)) printf(", devicetree: %s", fdtdec_get_srcname()); + if (CONFIG_IS_ENABLED(UPL)) + printf(", universal payload active"); printf("\n"); if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE) && (gd->fdt_src == FDTSRC_SEPARATE || diff --git a/common/spl/Makefile b/common/spl/Makefile index 4809f9c3ec1..137b18428bd 100644 --- a/common/spl/Makefile +++ b/common/spl/Makefile @@ -37,3 +37,5 @@ obj-$(CONFIG_$(SPL_TPL_)SPI_LOAD) += spl_spi.o obj-$(CONFIG_$(SPL_TPL_)RAM_SUPPORT) += spl_ram.o obj-$(CONFIG_$(SPL_TPL_)USB_SDP_SUPPORT) += spl_sdp.o endif + +obj-$(CONFIG_$(SPL_TPL_)UPL) += spl_upl.o diff --git a/common/spl/spl.c b/common/spl/spl.c index 7794ddccade..d6a364de6ee 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -810,6 +810,14 @@ void board_init_r(gd_t *dummy1, ulong dummy2) printf(SPL_TPL_PROMPT "SPL hand-off write failed (err=%d)\n", ret); } + if (CONFIG_IS_ENABLED(UPL_OUT) && (gd->flags & GD_FLG_UPL)) { + ret = spl_write_upl_handoff(&spl_image); + if (ret) { + printf(SPL_TPL_PROMPT + "UPL hand-off write failed (err=%d)\n", ret); + hang(); + } + } if (CONFIG_IS_ENABLED(BLOBLIST)) { ret = bloblist_finish(); if (ret) diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 2a097f4464c..1ad5a69d807 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -12,6 +12,7 @@ #include <memalign.h> #include <mapmem.h> #include <spl.h> +#include <upl.h> #include <sysinfo.h> #include <asm/global_data.h> #include <asm/io.h> @@ -336,6 +337,8 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, image_info->entry_point = FDT_ERROR; } + upl_add_image(fit, node, load_addr, length); + return 0; } @@ -847,6 +850,8 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, spl_image->entry_point = spl_image->load_addr; spl_image->flags |= SPL_FIT_FOUND; + upl_set_fit_info(map_to_sysmem(ctx.fit), ctx.conf_node, + spl_image->entry_point); return 0; } @@ -941,6 +946,10 @@ int spl_load_fit_image(struct spl_image_info *spl_image, if (ret < 0) return ret; } + spl_image->flags |= SPL_FIT_FOUND; + + upl_set_fit_info(map_to_sysmem(header), conf_noffset, + spl_image->entry_point); return 0; } diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c new file mode 100644 index 00000000000..067d437150f --- /dev/null +++ b/common/spl/spl_upl.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UPL handoff parsing + * + * Copyright 2024 Google LLC + * Written by Simon Glass <[email protected]> + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <alist.h> +#include <bloblist.h> +#include <dm.h> +#include <image.h> +#include <mapmem.h> +#include <serial.h> +#include <spl.h> +#include <upl.h> +#include <video.h> +#include <asm/global_data.h> +#include <dm/read.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct upl s_upl; + +void upl_set_fit_addr(ulong fit) +{ + struct upl *upl = &s_upl; + + upl->fit = fit; +} + +void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr) +{ + struct upl *upl = &s_upl; + + upl->fit = fit; + upl->conf_offset = conf_offset; + log_debug("upl: add fit %lx conf %x\n", fit, conf_offset); +} + +int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc) +{ + struct upl *upl = &s_upl; + struct upl_image img; + + img.load = load_addr; + img.size = size; + img.offset = node; + img.description = desc; + if (!alist_add(&upl->image, img)) + return -ENOMEM; + log_debug("upl: add image %s at %lx size %lx\n", desc, load_addr, size); + + return 0; +} + +static int write_serial(struct upl_serial *ser) +{ + struct udevice *dev = gd->cur_serial_dev; + struct serial_device_info info; + struct memregion region; + int ret; + + if (!dev) + return log_msg_ret("ser", -ENOENT); + ret = serial_getinfo(dev, &info); + if (ret) + return log_msg_ret("inf", ret); + + ser->compatible = ofnode_read_string(dev_ofnode(dev), "compatible"); + ser->clock_frequency = info.clock; + ser->current_speed = gd->baudrate; + region.base = info.addr; + region.size = info.size; + alist_init_struct(&ser->reg, struct memregion); + if (!alist_add(&ser->reg, region)) + return -ENOMEM; + ser->reg_io_shift = info.reg_shift; + ser->reg_offset = info.reg_offset; + ser->reg_io_width = info.reg_width; + ser->virtual_reg = 0; + ser->access_type = info.addr_space; + + return 0; +} + +static int write_graphics(struct upl_graphics *gra) +{ + struct video_uc_plat *plat; + struct video_priv *priv; + struct memregion region; + struct udevice *dev; + + alist_init_struct(&gra->reg, struct memregion); + uclass_find_first_device(UCLASS_VIDEO, &dev); + if (!dev || !device_active(dev)) + return log_msg_ret("vid", -ENOENT); + + plat = dev_get_uclass_plat(dev); + region.base = plat->base; + region.size = plat->size; + if (!alist_add(&gra->reg, region)) + return log_msg_ret("reg", -ENOMEM); + + priv = dev_get_uclass_priv(dev); + gra->width = priv->xsize; + gra->height = priv->ysize; + gra->stride = priv->line_length; /* private field */ + switch (priv->format) { + case VIDEO_RGBA8888: + case VIDEO_X8R8G8B8: + gra->format = UPLGF_ARGB32; + break; + case VIDEO_X8B8G8R8: + gra->format = UPLGF_ABGR32; + break; + case VIDEO_X2R10G10B10: + log_debug("device '%s': VIDEO_X2R10G10B10 not supported\n", + dev->name); + return log_msg_ret("for", -EPROTO); + case VIDEO_UNKNOWN: + log_debug("device '%s': Unknown video format\n", dev->name); + return log_msg_ret("for", -EPROTO); + } + + return 0; +} + +int spl_write_upl_handoff(struct spl_image_info *spl_image) +{ + struct upl *upl = &s_upl; + struct abuf buf; + ofnode root; + void *ptr; + int ret; + + log_debug("UPL: Writing handoff - image_count=%d\n", upl->image.count); + upl->addr_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1; + upl->size_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1; + upl->bootmode = UPLBM_DEFAULT; + ret = write_serial(&upl->serial); + if (ret) + return log_msg_ret("ser", ret); + ret = write_graphics(&upl->graphics); + if (ret && ret != -ENOENT) + return log_msg_ret("gra", ret); + + root = ofnode_root(); + ret = upl_write_handoff(upl, root, true); + if (ret) + return log_msg_ret("wr", ret); + + ret = oftree_to_fdt(oftree_default(), &buf); + if (ret) + return log_msg_ret("fdt", ret); + log_debug("FDT size %zx\n", abuf_size(&buf)); + + ptr = bloblist_add(BLOBLISTT_CONTROL_FDT, abuf_size(&buf), 0); + if (!ptr) + return log_msg_ret("blo", -ENOENT); + memcpy(ptr, abuf_data(&buf), abuf_size(&buf)); + + return 0; +} + +void spl_upl_init(void) +{ + upl_init(&s_upl); +} |
