"Das U-Boot" Source Tree
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

upl: Add support for reading a upl handoff

Universal Payload provides a standard way of handing off control between
two firmware phases. Add support for reading the handoff information into
a structure.

Signed-off-by: Simon Glass <sjg@chromium.org>

authored by

Simon Glass and committed by
Tom Rini
90469da3 16b9c64c

+1075
+7
MAINTAINERS
··· 1709 1709 S: Maintained 1710 1710 F: drivers/ufs/ 1711 1711 1712 + UPL 1713 + M: Simon Glass <sjg@chromium.org> 1714 + S: Maintained 1715 + T: git https://source.denx.de/u-boot/custodians/u-boot-dm.git 1716 + F: boot/upl* 1717 + F: include/upl.h 1718 + 1712 1719 USB 1713 1720 M: Marek Vasut <marex@denx.de> 1714 1721 S: Maintained
+19
boot/Kconfig
··· 745 745 This provides a way to try out standard boot on an existing boot flow. 746 746 It is not enabled by default to save space. 747 747 748 + config UPL 749 + bool "upl - Universal Payload Specification" 750 + imply UPL_READ 751 + help 752 + Provides support for UPL payloads and handoff information. U-Boot 753 + supports generating and accepting handoff information. The mkimage 754 + tool will eventually support creating payloads. 755 + 756 + if UPL 757 + 758 + config UPL_READ 759 + bool "upl - Support reading a Universal Payload handoff" 760 + help 761 + Provides support for decoding a UPL-format payload into a C structure 762 + which can be used elsewhere in U-Boot. This is just the reading 763 + implementation, useful for trying it out. 764 + 765 + endif # UPL 766 + 748 767 endif # BOOTSTD 749 768 750 769 config LEGACY_IMAGE_FORMAT
+3
boot/Makefile
··· 43 43 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o 44 44 obj-$(CONFIG_$(SPL_TPL_)FDT_SIMPLEFB) += fdt_simplefb.o 45 45 46 + obj-$(CONFIG_$(SPL_TPL_)UPL) += upl_common.o 47 + obj-$(CONFIG_$(SPL_TPL_)UPL_READ) += upl_read.o 48 + 46 49 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o 47 50 obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o 48 51 obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
+60
boot/upl_common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * UPL handoff command functions 4 + * 5 + * Copyright 2024 Google LLC 6 + * Written by Simon Glass <sjg@chromium.org> 7 + */ 8 + 9 + #define LOG_CATEGORY UCLASS_BOOTSTD 10 + 11 + #include <string.h> 12 + #include <upl.h> 13 + 14 + /* Names of bootmodes */ 15 + const char *const bootmode_names[UPLBM_COUNT] = { 16 + [UPLBM_FULL] = "full", 17 + [UPLBM_MINIMAL] = "minimal", 18 + [UPLBM_FAST] = "fast", 19 + [UPLBM_DIAG] = "diag", 20 + [UPLBM_DEFAULT] = "default", 21 + [UPLBM_S2] = "s2", 22 + [UPLBM_S3] = "s3", 23 + [UPLBM_S4] = "s4", 24 + [UPLBM_S5] = "s5", 25 + [UPLBM_FACTORY] = "factory", 26 + [UPLBM_FLASH] = "flash", 27 + [UPLBM_RECOVERY] = "recovery", 28 + }; 29 + 30 + /* Names of memory usages */ 31 + const char *const usage_names[UPLUS_COUNT] = { 32 + [UPLUS_ACPI_RECLAIM] = "acpi-reclaim", 33 + [UPLUS_ACPI_NVS] = "acpi-nvs", 34 + [UPLUS_BOOT_CODE] = "boot-code", 35 + [UPLUS_BOOT_DATA] = "boot-data", 36 + [UPLUS_RUNTIME_CODE] = "runtime-code", 37 + [UPLUS_RUNTIME_DATA] = "runtime-data", 38 + }; 39 + 40 + /* Names of access types */ 41 + const char *const access_types[UPLUS_COUNT] = { 42 + [UPLAT_MMIO] = "mmio", 43 + [UPLAT_IO] = "io", 44 + }; 45 + 46 + /* Names of graphics formats */ 47 + const char *const graphics_formats[UPLUS_COUNT] = { 48 + [UPLGF_ARGB32] = "a8r8g8b8", 49 + [UPLGF_ABGR32] = "a8b8g8r8", 50 + [UPLGF_ABGR64] = "a16b16g16r16", 51 + }; 52 + 53 + void upl_init(struct upl *upl) 54 + { 55 + memset(upl, '\0', sizeof(struct upl)); 56 + alist_init_struct(&upl->image, struct upl_image); 57 + alist_init_struct(&upl->mem, struct upl_mem); 58 + alist_init_struct(&upl->memmap, struct upl_memmap); 59 + alist_init_struct(&upl->memres, struct upl_memres); 60 + }
+24
boot/upl_common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * UPL handoff command functions 4 + * 5 + * Copyright 2024 Google LLC 6 + * Written by Simon Glass <sjg@chromium.org> 7 + */ 8 + 9 + #ifndef __UPL_COMMON_H 10 + #define __UPL_COMMON_H 11 + 12 + /* Names of bootmodes */ 13 + extern const char *const bootmode_names[UPLBM_COUNT]; 14 + 15 + /* Names of memory usages */ 16 + extern const char *const usage_names[UPLUS_COUNT]; 17 + 18 + /* Names of access types */ 19 + extern const char *const access_types[UPLUS_COUNT]; 20 + 21 + /* Names of graphics formats */ 22 + extern const char *const graphics_formats[UPLUS_COUNT]; 23 + 24 + #endif /* __UPL_COMMON_H */
+588
boot/upl_read.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * UPL handoff parsing 4 + * 5 + * Copyright 2024 Google LLC 6 + * Written by Simon Glass <sjg@chromium.org> 7 + */ 8 + 9 + #define LOG_CATEGORY UCLASS_BOOTSTD 10 + 11 + #include <log.h> 12 + #include <upl.h> 13 + #include <dm/ofnode.h> 14 + #include "upl_common.h" 15 + 16 + /** 17 + * read_addr() - Read an address 18 + * 19 + * Reads an address in the correct format, either 32- or 64-bit 20 + * 21 + * @upl: UPL state 22 + * @node: Node to read from 23 + * @prop: Property name to read 24 + * @addr: Place to put the address 25 + * Return: 0 if OK, -ve on error 26 + */ 27 + static int read_addr(const struct upl *upl, ofnode node, const char *prop, 28 + ulong *addrp) 29 + { 30 + int ret; 31 + 32 + if (upl->addr_cells == 1) { 33 + u32 val; 34 + 35 + ret = ofnode_read_u32(node, prop, &val); 36 + if (!ret) 37 + *addrp = val; 38 + } else { 39 + u64 val; 40 + 41 + ret = ofnode_read_u64(node, prop, &val); 42 + if (!ret) 43 + *addrp = val; 44 + } 45 + 46 + return ret; 47 + } 48 + 49 + /** 50 + * read_size() - Read a size 51 + * 52 + * Reads a size in the correct format, either 32- or 64-bit 53 + * 54 + * @upl: UPL state 55 + * @node: Node to read from 56 + * @prop: Property name to read 57 + * @addr: Place to put the size 58 + * Return: 0 if OK, -ve on error 59 + */ 60 + static int read_size(const struct upl *upl, ofnode node, const char *prop, 61 + ulong *sizep) 62 + { 63 + int ret; 64 + 65 + if (upl->size_cells == 1) { 66 + u32 val; 67 + 68 + ret = ofnode_read_u32(node, prop, &val); 69 + if (!ret) 70 + *sizep = val; 71 + } else { 72 + u64 val; 73 + 74 + ret = ofnode_read_u64(node, prop, &val); 75 + if (!ret) 76 + *sizep = val; 77 + } 78 + 79 + return ret; 80 + } 81 + 82 + /** 83 + * ofnode_read_bitmask() - Read a bit mask from a string list 84 + * 85 + * @node: Node to read from 86 + * @prop: Property name to read 87 + * @names: Array of names for each bit 88 + * @count: Number of array entries 89 + * @value: Returns resulting bit-mask value on success 90 + * Return: 0 if OK, -EINVAL if a bit number is not defined, -ENOSPC if the 91 + * string is too long for the (internal) buffer, -EINVAL if no such property 92 + */ 93 + static int ofnode_read_bitmask(ofnode node, const char *prop, 94 + const char *const names[], uint count, 95 + uint *valuep) 96 + { 97 + const char **list; 98 + const char **strp; 99 + uint val; 100 + uint bit; 101 + int ret; 102 + 103 + ret = ofnode_read_string_list(node, prop, &list); 104 + if (ret < 0) 105 + return log_msg_ret("rea", ret); 106 + 107 + val = 0; 108 + for (strp = list; *strp; strp++) { 109 + const char *str = *strp; 110 + bool found = false; 111 + 112 + for (bit = 0; bit < count; bit++) { 113 + if (!strcmp(str, names[bit])) { 114 + found = true; 115 + break; 116 + } 117 + } 118 + if (found) 119 + val |= BIT(bit); 120 + else 121 + log_warning("%s/%s: Invalid value '%s'\n", 122 + ofnode_get_name(node), prop, str); 123 + } 124 + *valuep = val; 125 + 126 + return 0; 127 + } 128 + 129 + /** 130 + * ofnode_read_value() - Read a string value as an int using a lookup 131 + * 132 + * @node: Node to read from 133 + * @prop: Property name to read 134 + * @names: Array of names for each int value 135 + * @count: Number of array entries 136 + * @valuep: Returns int value read 137 + * Return: 0 if OK, -EINVAL if a bit number is not defined, -ENOENT if the 138 + * property does not exist 139 + */ 140 + static int ofnode_read_value(ofnode node, const char *prop, 141 + const char *const names[], uint count, 142 + uint *valuep) 143 + { 144 + const char *str; 145 + int i; 146 + 147 + str = ofnode_read_string(node, prop); 148 + if (!str) 149 + return log_msg_ret("rd", -ENOENT); 150 + 151 + for (i = 0; i < count; i++) { 152 + if (!strcmp(names[i], str)) { 153 + *valuep = i; 154 + return 0; 155 + } 156 + } 157 + 158 + log_debug("Unnamed value '%s'\n", str); 159 + return log_msg_ret("val", -EINVAL); 160 + } 161 + 162 + static int read_uint(ofnode node, const char *prop, uint *valp) 163 + { 164 + u32 val; 165 + int ret; 166 + 167 + ret = ofnode_read_u32(node, prop, &val); 168 + if (ret) 169 + return ret; 170 + *valp = val; 171 + 172 + return 0; 173 + } 174 + 175 + /** 176 + * decode_root_props() - Decode root properties from the tree 177 + * 178 + * @upl: UPL state 179 + * @node: Node to decode 180 + * Return 0 if OK, -ve on error 181 + */ 182 + static int decode_root_props(struct upl *upl, ofnode node) 183 + { 184 + int ret; 185 + 186 + ret = read_uint(node, UPLP_ADDRESS_CELLS, &upl->addr_cells); 187 + if (!ret) 188 + ret = read_uint(node, UPLP_SIZE_CELLS, &upl->size_cells); 189 + if (ret) 190 + return log_msg_ret("cel", ret); 191 + 192 + return 0; 193 + } 194 + 195 + /** 196 + * decode_root_props() - Decode UPL parameters from the tree 197 + * 198 + * @upl: UPL state 199 + * @node: Node to decode 200 + * Return 0 if OK, -ve on error 201 + */ 202 + static int decode_upl_params(struct upl *upl, ofnode options) 203 + { 204 + ofnode node; 205 + int ret; 206 + 207 + node = ofnode_find_subnode(options, UPLN_UPL_PARAMS); 208 + if (!ofnode_valid(node)) 209 + return log_msg_ret("par", -EINVAL); 210 + log_debug("decoding '%s'\n", ofnode_get_name(node)); 211 + 212 + ret = read_addr(upl, node, UPLP_SMBIOS, &upl->smbios); 213 + if (ret) 214 + return log_msg_ret("smb", ret); 215 + ret = read_addr(upl, node, UPLP_ACPI, &upl->acpi); 216 + if (ret) 217 + return log_msg_ret("acp", ret); 218 + ret = ofnode_read_bitmask(node, UPLP_BOOTMODE, bootmode_names, 219 + UPLBM_COUNT, &upl->bootmode); 220 + if (ret) 221 + return log_msg_ret("boo", ret); 222 + ret = read_uint(node, UPLP_ADDR_WIDTH, &upl->addr_width); 223 + if (ret) 224 + return log_msg_ret("add", ret); 225 + ret = read_uint(node, UPLP_ACPI_NVS_SIZE, &upl->acpi_nvs_size); 226 + if (ret) 227 + return log_msg_ret("nvs", ret); 228 + 229 + return 0; 230 + } 231 + 232 + /** 233 + * decode_upl_images() - Decode /options/upl-image nodes 234 + * 235 + * @node: /options node in which to look for the node 236 + * Return 0 if OK, -ve on error 237 + */ 238 + static int decode_upl_images(struct upl *upl, ofnode options) 239 + { 240 + ofnode node, images; 241 + int ret; 242 + 243 + images = ofnode_find_subnode(options, UPLN_UPL_IMAGE); 244 + if (!ofnode_valid(images)) 245 + return log_msg_ret("img", -EINVAL); 246 + log_debug("decoding '%s'\n", ofnode_get_name(images)); 247 + 248 + ret = read_addr(upl, images, UPLP_FIT, &upl->fit); 249 + if (!ret) 250 + ret = read_uint(images, UPLP_CONF_OFFSET, &upl->conf_offset); 251 + if (ret) 252 + return log_msg_ret("cnf", ret); 253 + 254 + ofnode_for_each_subnode(node, images) { 255 + struct upl_image img; 256 + 257 + ret = read_addr(upl, node, UPLP_LOAD, &img.load); 258 + if (!ret) 259 + ret = read_size(upl, node, UPLP_SIZE, &img.size); 260 + if (!ret) 261 + ret = read_uint(node, UPLP_OFFSET, &img.offset); 262 + img.description = ofnode_read_string(node, UPLP_DESCRIPTION); 263 + if (!img.description) 264 + return log_msg_ret("sim", ret); 265 + if (!alist_add(&upl->image, img)) 266 + return log_msg_ret("img", -ENOMEM); 267 + } 268 + 269 + return 0; 270 + } 271 + 272 + /** 273 + * decode_addr_size() - Decide a set of addr/size pairs 274 + * 275 + * Each base/size value from the devicetree is written to the region list 276 + * 277 + * @upl: UPL state 278 + * @buf: Bytes to decode 279 + * @size: Number of bytes to decode 280 + * @regions: List of regions to process (struct memregion) 281 + * Returns: number of regions found, if OK, else -ve on error 282 + */ 283 + static int decode_addr_size(const struct upl *upl, const char *buf, int size, 284 + struct alist *regions) 285 + { 286 + const char *ptr, *end = buf + size; 287 + int i; 288 + 289 + alist_init_struct(regions, struct memregion); 290 + ptr = buf; 291 + for (i = 0; ptr < end; i++) { 292 + struct memregion reg; 293 + 294 + if (upl->addr_cells == 1) 295 + reg.base = fdt32_to_cpu(*(u32 *)ptr); 296 + else 297 + reg.base = fdt64_to_cpu(*(u64 *)ptr); 298 + ptr += upl->addr_cells * sizeof(u32); 299 + 300 + if (upl->size_cells == 1) 301 + reg.size = fdt32_to_cpu(*(u32 *)ptr); 302 + else 303 + reg.size = fdt64_to_cpu(*(u64 *)ptr); 304 + ptr += upl->size_cells * sizeof(u32); 305 + if (ptr > end) 306 + return -ENOSPC; 307 + 308 + if (!alist_add(regions, reg)) 309 + return log_msg_ret("reg", -ENOMEM); 310 + } 311 + 312 + return i; 313 + } 314 + 315 + /** 316 + * node_matches_at() - Check if a node name matches "base@..." 317 + * 318 + * Return: true if the node name matches the base string followed by an @ sign; 319 + * false otherwise 320 + */ 321 + static bool node_matches_at(ofnode node, const char *base) 322 + { 323 + const char *name = ofnode_get_name(node); 324 + int len = strlen(base); 325 + 326 + return !strncmp(base, name, len) && name[len] == '@'; 327 + } 328 + 329 + /** 330 + * decode_upl_memory_node() - Decode a /memory node from the tree 331 + * 332 + * @upl: UPL state 333 + * @node: Node to decode 334 + * Return 0 if OK, -ve on error 335 + */ 336 + static int decode_upl_memory_node(struct upl *upl, ofnode node) 337 + { 338 + struct upl_mem mem; 339 + const char *buf; 340 + int size, len; 341 + 342 + buf = ofnode_read_prop(node, UPLP_REG, &size); 343 + if (!buf) { 344 + log_warning("Node '%s': Missing '%s' property\n", 345 + ofnode_get_name(node), UPLP_REG); 346 + return log_msg_ret("reg", -EINVAL); 347 + } 348 + len = decode_addr_size(upl, buf, size, &mem.region); 349 + if (len < 0) 350 + return log_msg_ret("buf", len); 351 + mem.hotpluggable = ofnode_read_bool(node, UPLP_HOTPLUGGABLE); 352 + if (!alist_add(&upl->mem, mem)) 353 + return log_msg_ret("mem", -ENOMEM); 354 + 355 + return 0; 356 + } 357 + 358 + /** 359 + * decode_upl_memmap() - Decode memory-map nodes from the tree 360 + * 361 + * @upl: UPL state 362 + * @root: Parent node containing the /memory-map nodes 363 + * Return 0 if OK, -ve on error 364 + */ 365 + static int decode_upl_memmap(struct upl *upl, ofnode root) 366 + { 367 + ofnode node; 368 + 369 + ofnode_for_each_subnode(node, root) { 370 + struct upl_memmap memmap; 371 + int size, len, ret; 372 + const char *buf; 373 + 374 + memmap.name = ofnode_get_name(node); 375 + memmap.usage = 0; 376 + 377 + buf = ofnode_read_prop(node, UPLP_REG, &size); 378 + if (!buf) { 379 + log_warning("Node '%s': Missing '%s' property\n", 380 + ofnode_get_name(node), UPLP_REG); 381 + continue; 382 + } 383 + 384 + len = decode_addr_size(upl, buf, size, &memmap.region); 385 + if (len < 0) 386 + return log_msg_ret("buf", len); 387 + ret = ofnode_read_bitmask(node, UPLP_USAGE, usage_names, 388 + UPLUS_COUNT, &memmap.usage); 389 + if (ret && ret != -EINVAL) /* optional property */ 390 + return log_msg_ret("bit", ret); 391 + 392 + if (!alist_add(&upl->memmap, memmap)) 393 + return log_msg_ret("mmp", -ENOMEM); 394 + } 395 + 396 + return 0; 397 + } 398 + 399 + /** 400 + * decode_upl_memres() - Decode reserved-memory nodes from the tree 401 + * 402 + * @upl: UPL state 403 + * @root: Parent node containing the reserved-memory nodes 404 + * Return 0 if OK, -ve on error 405 + */ 406 + static int decode_upl_memres(struct upl *upl, ofnode root) 407 + { 408 + ofnode node; 409 + 410 + ofnode_for_each_subnode(node, root) { 411 + struct upl_memres memres; 412 + const char *buf; 413 + int size, len; 414 + 415 + log_debug("decoding '%s'\n", ofnode_get_name(node)); 416 + memres.name = ofnode_get_name(node); 417 + 418 + buf = ofnode_read_prop(node, UPLP_REG, &size); 419 + if (!buf) { 420 + log_warning("Node '%s': Missing 'reg' property\n", 421 + ofnode_get_name(node)); 422 + continue; 423 + } 424 + 425 + len = decode_addr_size(upl, buf, size, &memres.region); 426 + if (len < 0) 427 + return log_msg_ret("buf", len); 428 + memres.no_map = ofnode_read_bool(node, UPLP_NO_MAP); 429 + 430 + if (!alist_add(&upl->memres, memres)) 431 + return log_msg_ret("mre", -ENOMEM); 432 + } 433 + 434 + return 0; 435 + } 436 + 437 + /** 438 + * decode_upl_serial() - Decode the serial node 439 + * 440 + * @upl: UPL state 441 + * @root: Parent node contain node 442 + * Return 0 if OK, -ve on error 443 + */ 444 + static int decode_upl_serial(struct upl *upl, ofnode node) 445 + { 446 + struct upl_serial *ser = &upl->serial; 447 + const char *buf; 448 + int len, size; 449 + int ret; 450 + 451 + ser->compatible = ofnode_read_string(node, UPLP_COMPATIBLE); 452 + if (!ser->compatible) { 453 + log_warning("Node '%s': Missing compatible string\n", 454 + ofnode_get_name(node)); 455 + return log_msg_ret("com", -EINVAL); 456 + } 457 + ret = read_uint(node, UPLP_CLOCK_FREQUENCY, &ser->clock_frequency); 458 + if (!ret) 459 + ret = read_uint(node, UPLP_CURRENT_SPEED, &ser->current_speed); 460 + if (ret) 461 + return log_msg_ret("spe", ret); 462 + 463 + buf = ofnode_read_prop(node, UPLP_REG, &size); 464 + if (!buf) { 465 + log_warning("Node '%s': Missing 'reg' property\n", 466 + ofnode_get_name(node)); 467 + return log_msg_ret("reg", -EINVAL); 468 + } 469 + 470 + len = decode_addr_size(upl, buf, sizeof(buf), &ser->reg); 471 + if (len < 0) 472 + return log_msg_ret("buf", len); 473 + 474 + /* set defaults */ 475 + ser->reg_io_shift = UPLD_REG_IO_SHIFT; 476 + ser->reg_offset = UPLD_REG_OFFSET; 477 + ser->reg_io_width = UPLD_REG_IO_WIDTH; 478 + read_uint(node, UPLP_REG_IO_SHIFT, &ser->reg_io_shift); 479 + read_uint(node, UPLP_REG_OFFSET, &ser->reg_offset); 480 + read_uint(node, UPLP_REG_IO_WIDTH, &ser->reg_io_width); 481 + read_addr(upl, node, UPLP_VIRTUAL_REG, &ser->virtual_reg); 482 + ret = ofnode_read_value(node, UPLP_ACCESS_TYPE, access_types, 483 + ARRAY_SIZE(access_types), &ser->access_type); 484 + if (ret && ret != -ENOENT) 485 + return log_msg_ret("ser", ret); 486 + 487 + return 0; 488 + } 489 + 490 + /** 491 + * decode_upl_graphics() - Decode graphics node 492 + * 493 + * @upl: UPL state 494 + * @root: Node to decode 495 + * Return 0 if OK, -ve on error 496 + */ 497 + static int decode_upl_graphics(struct upl *upl, ofnode node) 498 + { 499 + struct upl_graphics *gra = &upl->graphics; 500 + const char *buf, *compat; 501 + int len, size; 502 + int ret; 503 + 504 + compat = ofnode_read_string(node, UPLP_COMPATIBLE); 505 + if (!compat) { 506 + log_warning("Node '%s': Missing compatible string\n", 507 + ofnode_get_name(node)); 508 + return log_msg_ret("com", -EINVAL); 509 + } 510 + if (strcmp(UPLC_GRAPHICS, compat)) { 511 + log_warning("Node '%s': Ignoring compatible '%s'\n", 512 + ofnode_get_name(node), compat); 513 + return 0; 514 + } 515 + 516 + buf = ofnode_read_prop(node, UPLP_REG, &size); 517 + if (!buf) { 518 + log_warning("Node '%s': Missing 'reg' property\n", 519 + ofnode_get_name(node)); 520 + return log_msg_ret("reg", -EINVAL); 521 + } 522 + 523 + len = decode_addr_size(upl, buf, sizeof(buf), &gra->reg); 524 + if (len < 0) 525 + return log_msg_ret("buf", len); 526 + 527 + ret = read_uint(node, UPLP_WIDTH, &gra->width); 528 + if (!ret) 529 + ret = read_uint(node, UPLP_HEIGHT, &gra->height); 530 + if (!ret) 531 + ret = read_uint(node, UPLP_STRIDE, &gra->stride); 532 + if (!ret) { 533 + ret = ofnode_read_value(node, UPLP_GRAPHICS_FORMAT, 534 + graphics_formats, 535 + ARRAY_SIZE(graphics_formats), 536 + &gra->format); 537 + } 538 + if (ret) 539 + return log_msg_ret("pro", ret); 540 + 541 + return 0; 542 + } 543 + 544 + int upl_read_handoff(struct upl *upl, oftree tree) 545 + { 546 + ofnode root, node; 547 + int ret; 548 + 549 + if (!oftree_valid(tree)) 550 + return log_msg_ret("tre", -EINVAL); 551 + 552 + root = oftree_root(tree); 553 + 554 + upl_init(upl); 555 + ret = decode_root_props(upl, root); 556 + if (ret) 557 + return log_msg_ret("roo", ret); 558 + 559 + ofnode_for_each_subnode(node, root) { 560 + const char *name = ofnode_get_name(node); 561 + 562 + log_debug("decoding '%s'\n", name); 563 + if (!strcmp(UPLN_OPTIONS, name)) { 564 + ret = decode_upl_params(upl, node); 565 + if (ret) 566 + return log_msg_ret("opt", ret); 567 + 568 + ret = decode_upl_images(upl, node); 569 + } else if (node_matches_at(node, UPLN_MEMORY)) { 570 + ret = decode_upl_memory_node(upl, node); 571 + } else if (!strcmp(UPLN_MEMORY_MAP, name)) { 572 + ret = decode_upl_memmap(upl, node); 573 + } else if (!strcmp(UPLN_MEMORY_RESERVED, name)) { 574 + ret = decode_upl_memres(upl, node); 575 + } else if (node_matches_at(node, UPLN_SERIAL)) { 576 + ret = decode_upl_serial(upl, node); 577 + } else if (node_matches_at(node, UPLN_GRAPHICS)) { 578 + ret = decode_upl_graphics(upl, node); 579 + } else { 580 + log_debug("Unknown node '%s'\n", name); 581 + ret = 0; 582 + } 583 + if (ret) 584 + return log_msg_ret("err", ret); 585 + } 586 + 587 + return 0; 588 + }
+1
configs/sandbox_defconfig
··· 16 16 CONFIG_FIT_CIPHER=y 17 17 CONFIG_FIT_VERBOSE=y 18 18 CONFIG_BOOTMETH_ANDROID=y 19 + CONFIG_UPL=y 19 20 CONFIG_LEGACY_IMAGE_FORMAT=y 20 21 CONFIG_MEASURED_BOOT=y 21 22 CONFIG_BOOTSTAGE=y
+373
include/upl.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + /* 3 + * UPL handoff generation 4 + * 5 + * Copyright 2024 Google LLC 6 + * Written by Simon Glass <sjg@chromium.org> 7 + */ 8 + 9 + #ifndef __UPL_WRITE_H 10 + #define __UPL_WRITE_H 11 + 12 + #ifndef USE_HOSTCC 13 + 14 + #include <alist.h> 15 + #include <image.h> 16 + #include <dm/ofnode_decl.h> 17 + 18 + struct unit_test_state; 19 + 20 + #define UPLP_ADDRESS_CELLS "#address-cells" 21 + #define UPLP_SIZE_CELLS "#size-cells" 22 + 23 + #define UPLN_OPTIONS "options" 24 + #define UPLN_UPL_PARAMS "upl-params" 25 + #define UPLP_SMBIOS "smbios" 26 + #define UPLP_ACPI "acpi" 27 + #define UPLP_BOOTMODE "bootmode" 28 + #define UPLP_ADDR_WIDTH "addr-width" 29 + #define UPLP_ACPI_NVS_SIZE "acpi-nvs-size" 30 + 31 + #define UPLPATH_UPL_IMAGE "/options/upl-image" 32 + #define UPLN_UPL_IMAGE "upl-image" 33 + #define UPLN_IMAGE "image" 34 + #define UPLP_FIT "fit" 35 + #define UPLP_CONF_OFFSET "conf-offset" 36 + #define UPLP_LOAD "load" 37 + #define UPLP_SIZE "size" 38 + #define UPLP_OFFSET "offset" 39 + #define UPLP_DESCRIPTION "description" 40 + 41 + #define UPLN_MEMORY "memory" 42 + #define UPLP_HOTPLUGGABLE "hotpluggable" 43 + 44 + #define UPLPATH_MEMORY_MAP "/memory-map" 45 + #define UPLN_MEMORY_MAP "memory-map" 46 + #define UPLP_USAGE "usage" 47 + 48 + #define UPLN_MEMORY_RESERVED "reserved-memory" 49 + #define UPLPATH_MEMORY_RESERVED "/reserved-memory" 50 + #define UPLP_NO_MAP "no-map" 51 + 52 + #define UPLN_SERIAL "serial" 53 + #define UPLP_REG "reg" 54 + #define UPLP_COMPATIBLE "compatible" 55 + #define UPLP_CLOCK_FREQUENCY "clock-frequency" 56 + #define UPLP_CURRENT_SPEED "current-speed" 57 + #define UPLP_REG_IO_SHIFT "reg-io-shift" 58 + #define UPLP_REG_OFFSET "reg-offset" 59 + #define UPLP_REG_IO_WIDTH "reg-io-width" 60 + #define UPLP_VIRTUAL_REG "virtual-reg" 61 + #define UPLP_ACCESS_TYPE "access-type" 62 + 63 + #define UPLN_GRAPHICS "framebuffer" 64 + #define UPLC_GRAPHICS "simple-framebuffer" 65 + #define UPLP_WIDTH "width" 66 + #define UPLP_HEIGHT "height" 67 + #define UPLP_STRIDE "stride" 68 + #define UPLP_GRAPHICS_FORMAT "format" 69 + 70 + /** 71 + * enum upl_boot_mode - Encodes the boot mode 72 + * 73 + * Each is a bit number from the boot_mode mask 74 + */ 75 + enum upl_boot_mode { 76 + UPLBM_FULL, 77 + UPLBM_MINIMAL, 78 + UPLBM_FAST, 79 + UPLBM_DIAG, 80 + UPLBM_DEFAULT, 81 + UPLBM_S2, 82 + UPLBM_S3, 83 + UPLBM_S4, 84 + UPLBM_S5, 85 + UPLBM_FACTORY, 86 + UPLBM_FLASH, 87 + UPLBM_RECOVERY, 88 + 89 + UPLBM_COUNT, 90 + }; 91 + 92 + /** 93 + * struct upl_image - UPL image informaiton 94 + * 95 + * @load: Address image was loaded to 96 + * @size: Size of image in bytes 97 + * @offset: Offset of the image in the FIT (0=none) 98 + * @desc: Description of the iamge (taken from the FIT) 99 + */ 100 + struct upl_image { 101 + ulong load; 102 + ulong size; 103 + uint offset; 104 + const char *description; 105 + }; 106 + 107 + /** 108 + * struct memregion - Information about a region of memory 109 + * 110 + * @base: Base address 111 + * @size: Size in bytes 112 + */ 113 + struct memregion { 114 + ulong base; 115 + ulong size; 116 + }; 117 + 118 + /** 119 + * struct upl_mem - Information about physical-memory layout 120 + * 121 + * TODO: Figure out initial-mapped-area 122 + * 123 + * @region: Memory region list (struct memregion) 124 + * @hotpluggable: true if hotpluggable 125 + */ 126 + struct upl_mem { 127 + struct alist region; 128 + bool hotpluggable; 129 + }; 130 + 131 + /** 132 + * enum upl_usage - Encodes the usage 133 + * 134 + * Each is a bit number from the usage mask 135 + */ 136 + enum upl_usage { 137 + UPLUS_ACPI_RECLAIM, 138 + UPLUS_ACPI_NVS, 139 + UPLUS_BOOT_CODE, 140 + UPLUS_BOOT_DATA, 141 + UPLUS_RUNTIME_CODE, 142 + UPLUS_RUNTIME_DATA, 143 + UPLUS_COUNT 144 + }; 145 + 146 + /** 147 + * struct upl_memmap - Information about logical-memory layout 148 + * 149 + * @name: Node name to use 150 + * @region: Memory region list (struct memregion) 151 + * @usage: Memory-usage mask (enum upl_usage) 152 + */ 153 + struct upl_memmap { 154 + const char *name; 155 + struct alist region; 156 + uint usage; 157 + }; 158 + 159 + /** 160 + * struct upl_memres - Reserved memory 161 + * 162 + * @name: Node name to use 163 + * @region: Reserved memory region list (struct memregion) 164 + * @no_map: true to indicate that a virtual mapping must not be created 165 + */ 166 + struct upl_memres { 167 + const char *name; 168 + struct alist region; 169 + bool no_map; 170 + }; 171 + 172 + enum upl_serial_access_type { 173 + UPLSAT_MMIO, 174 + UPLSAT_IO, 175 + }; 176 + 177 + /* serial defaults */ 178 + enum { 179 + UPLD_REG_IO_SHIFT = 0, 180 + UPLD_REG_OFFSET = 0, 181 + UPLD_REG_IO_WIDTH = 1, 182 + }; 183 + 184 + /** 185 + * enum upl_access_type - Access types 186 + * 187 + * @UPLAT_MMIO: Memory-mapped I/O 188 + * @UPLAT_IO: Separate I/O 189 + */ 190 + enum upl_access_type { 191 + UPLAT_MMIO, 192 + UPLAT_IO, 193 + }; 194 + 195 + /** 196 + * struct upl_serial - Serial console 197 + * 198 + * @compatible: Compatible string (NULL if there is no serial console) 199 + * @clock_frequency: Input clock frequency of UART 200 + * @current_speed: Current baud rate of UART 201 + * @reg: List of base address and size of registers (struct memregion) 202 + * @reg_shift_log2: log2 of distance between each register 203 + * @reg_offset: Offset of registers from the base address 204 + * @reg_width: Register width in bytes 205 + * @virtual_reg: Virtual register access (0 for none) 206 + * @access_type: Register access type to use 207 + */ 208 + struct upl_serial { 209 + const char *compatible; 210 + uint clock_frequency; 211 + uint current_speed; 212 + struct alist reg; 213 + uint reg_io_shift; 214 + uint reg_offset; 215 + uint reg_io_width; 216 + ulong virtual_reg; 217 + enum upl_serial_access_type access_type; 218 + }; 219 + 220 + /** 221 + * enum upl_graphics_format - Graphics formats 222 + * 223 + * @UPLGF_ARGB32: 32bpp format using 0xaarrggbb 224 + * @UPLGF_ABGR32: 32bpp format using 0xaabbggrr 225 + * @UPLGF_ARGB64: 64bpp format using 0xaaaabbbbggggrrrr 226 + */ 227 + enum upl_graphics_format { 228 + UPLGF_ARGB32, 229 + UPLGF_ABGR32, 230 + UPLGF_ABGR64, 231 + }; 232 + 233 + /** 234 + * @reg: List of base address and size of registers (struct memregion) 235 + * @width: Width of display in pixels 236 + * @height: Height of display in pixels 237 + * @stride: Number of bytes from one line to the next 238 + * @format: Pixel format 239 + */ 240 + struct upl_graphics { 241 + struct alist reg; 242 + uint width; 243 + uint height; 244 + uint stride; 245 + enum upl_graphics_format format; 246 + }; 247 + 248 + /* 249 + * Information about the UPL state 250 + * 251 + * @addr_cells: Number of address cells used in the handoff 252 + * @size_cells: Number of size cells used in the handoff 253 + * @bootmode: Boot-mode mask (enum upl_boot_mode) 254 + * @fit: Address of FIT image that was loaded 255 + * @conf_offset: Offset in FIT of the configuration that was selected 256 + * @addr_width: Adress-bus width of machine, e.g. 46 for 46 bits 257 + * @acpi_nvs_size: Size of the ACPI non-volatile-storage area in bytes 258 + * @image: Information about each image (struct upl_image) 259 + * @mem: Information about physical-memory regions (struct upl_mem) 260 + * @nennap: Information about logical-memory regions (struct upl_memmap) 261 + * @nennap: Information about reserved-memory regions (struct upl_memres) 262 + */ 263 + struct upl { 264 + int addr_cells; 265 + int size_cells; 266 + 267 + ulong smbios; 268 + ulong acpi; 269 + uint bootmode; 270 + ulong fit; 271 + uint conf_offset; 272 + uint addr_width; 273 + uint acpi_nvs_size; 274 + 275 + struct alist image; 276 + struct alist mem; 277 + struct alist memmap; 278 + struct alist memres; 279 + struct upl_serial serial; 280 + struct upl_graphics graphics; 281 + }; 282 + 283 + /** 284 + * upl_write_handoff() - Write a Unversal Payload handoff structure 285 + * 286 + * upl: UPL state to write 287 + * @root: root node to write it to 288 + * @skip_existing: Avoid recreating any nodes which already exist in the 289 + * devicetree. For example, if there is a serial node, just leave it alone, 290 + * since don't need to create a new one 291 + * Return: 0 on success, -ve on error 292 + */ 293 + int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing); 294 + 295 + /** 296 + * upl_create_handoff_tree() - Write a Unversal Payload handoff structure 297 + * 298 + * upl: UPL state to write 299 + * @treep: Returns a new tree containing the handoff 300 + * Return: 0 on success, -ve on error 301 + */ 302 + int upl_create_handoff_tree(const struct upl *upl, oftree *treep); 303 + 304 + /** 305 + * upl_read_handoff() - Read a Unversal Payload handoff structure 306 + * 307 + * upl: UPL state to read into 308 + * @tree: Devicetree containing the data to read 309 + * Return: 0 on success, -ve on error 310 + */ 311 + int upl_read_handoff(struct upl *upl, oftree tree); 312 + #endif /* USE_HOSTCC */ 313 + 314 + #if CONFIG_IS_ENABLED(UPL) && defined(CONFIG_SPL_BUILD) 315 + 316 + /** 317 + * upl_set_fit_info() - Set up basic info about the FIT 318 + * 319 + * @fit: Address of FIT 320 + * @conf_offset: Configuration node being used 321 + * @entry_addr: Entry address for next phase 322 + */ 323 + void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr); 324 + 325 + /** 326 + * upl_set_fit_addr() - Set up the address of the FIT 327 + * 328 + * @fit: Address of FIT 329 + */ 330 + void upl_set_fit_addr(ulong fit); 331 + 332 + #else 333 + static inline void upl_set_fit_addr(ulong fit) {} 334 + static inline void upl_set_fit_info(ulong fit, int conf_offset, 335 + ulong entry_addr) {} 336 + #endif /* UPL && SPL */ 337 + 338 + /** 339 + * _upl_add_image() - Internal function to add a new image to the UPL 340 + * 341 + * @node: Image node offset in FIT 342 + * @load_addr: Address to which images was loaded 343 + * @size: Image size in bytes 344 + * @desc: Description of image 345 + * Return: 0 if OK, -ENOMEM if out of memory 346 + */ 347 + int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc); 348 + 349 + /** 350 + * upl_add_image() - Add a new image to the UPL 351 + * 352 + * @fit: Pointer to FIT 353 + * @node: Image node offset in FIT 354 + * @load_addr: Address to which images was loaded 355 + * @size: Image size in bytes 356 + * Return: 0 if OK, -ENOMEM if out of memory 357 + */ 358 + static inline int upl_add_image(const void *fit, int node, ulong load_addr, 359 + ulong size) 360 + { 361 + if (CONFIG_IS_ENABLED(UPL) && IS_ENABLED(CONFIG_SPL_BUILD)) { 362 + const char *desc = fdt_getprop(fit, node, FIT_DESC_PROP, NULL); 363 + 364 + return _upl_add_image(node, load_addr, size, desc); 365 + } 366 + 367 + return 0; 368 + } 369 + 370 + /** upl_init() - Set up a UPL struct */ 371 + void upl_init(struct upl *upl); 372 + 373 + #endif /* __UPL_WRITE_H */