diff options
Diffstat (limited to 'lib')
33 files changed, 925 insertions, 380 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 1a683dea670..17954461114 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -445,7 +445,9 @@ config CIRCBUF source "lib/dhry/Kconfig" menu "Alternative crypto libraries" -source lib/mbedtls/Kconfig + +source "lib/mbedtls/Kconfig" + endmenu menu "Security support" @@ -1008,14 +1010,14 @@ config OF_LIBFDT_OVERLAY This enables the FDT library (libfdt) overlay support. config SYS_FDT_PAD - hex "Maximum size of the FDT memory area passeed to the OS" + hex "Free space added to device-tree before booting" depends on OF_LIBFDT default 0x13000 if FMAN_ENET || QE || U_QE default 0x3000 help - During OS boot, we allocate a region of memory within the bootmap - for the FDT. This is the size that we will expand the FDT that we - are using will be extended to be, in bytes. + The operating system may need a free area at the end of the device- + tree for fix-ups. This setting defines by how many bytes U-Boot + extends the device-tree before booting. config SPL_OF_LIBFDT bool "Enable the FDT library for SPL" diff --git a/lib/Makefile b/lib/Makefile index a7bc2f3134a..41de2671cc6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -28,11 +28,7 @@ obj-y += charset.o endif endif -ifdef CONFIG_USB_TTY -obj-y += circbuf.o -else obj-$(CONFIG_CIRCBUF) += circbuf.o -endif obj-y += crc8.o obj-$(CONFIG_ERRNO_STR) += errno_str.o @@ -129,7 +125,7 @@ obj-y += hang.o obj-y += linux_compat.o obj-y += linux_string.o obj-$(CONFIG_$(PHASE_)LMB) += lmb.o -obj-y += membuff.o +obj-y += membuf.o obj-$(CONFIG_REGEX) += slre.o obj-y += string.o obj-y += tables_csum.o diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index f4d5c1e25d0..596301a43fe 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -6,11 +6,18 @@ */ #include <mapmem.h> +#include <tables_csum.h> #include <acpi/acpi_table.h> #include <asm/global_data.h> DECLARE_GLOBAL_DATA_PTR; +void acpi_update_checksum(struct acpi_table_header *header) +{ + header->checksum = 0; + header->checksum = table_compute_checksum(header, header->length); +} + struct acpi_table_header *acpi_find_table(const char *sig) { struct acpi_rsdp *rsdp; diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index c0ed24984af..43b71182133 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -66,6 +66,7 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags) dmar->host_address_width = info.address_width - 1; dmar->flags = flags; + header->checksum = table_compute_checksum(dmar, header->length); return 0; } @@ -195,9 +196,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table) (sizeof(u32) * (i + 1)); /* Re-calculate checksum */ - rsdt->header.checksum = 0; - rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, - rsdt->header.length); + acpi_update_checksum(&rsdt->header); } if (ctx->xsdt) { @@ -228,9 +227,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table) (sizeof(u64) * (i + 1)); /* Re-calculate checksum */ - xsdt->header.checksum = 0; - xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, - xsdt->header.length); + acpi_update_checksum(&xsdt->header); } return 0; @@ -255,8 +252,8 @@ int acpi_write_fadt(struct acpi_ctx *ctx, const struct acpi_writer *entry) header->creator_revision = 1; fadt->minor_revision = 2; - fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); - fadt->x_dsdt = map_to_sysmem(ctx->dsdt); + fadt->x_firmware_ctrl = nomap_to_sysmem(ctx->facs); + fadt->x_dsdt = nomap_to_sysmem(ctx->dsdt); if (fadt->x_firmware_ctrl < 0x100000000ULL) fadt->firmware_ctrl = fadt->x_firmware_ctrl; @@ -268,7 +265,7 @@ int acpi_write_fadt(struct acpi_ctx *ctx, const struct acpi_writer *entry) acpi_fill_fadt(fadt); - header->checksum = table_compute_checksum(fadt, header->length); + acpi_update_checksum(header); return acpi_add_fadt(ctx, fadt); } @@ -303,7 +300,7 @@ int acpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry) if (IS_ENABLED(CONFIG_ACPI_PARKING_PROTOCOL)) acpi_write_park(madt); - header->checksum = table_compute_checksum((void *)madt, header->length); + acpi_update_checksum(header); acpi_add_table(ctx, madt); ctx->current = (void *)madt + madt->header.length; @@ -374,7 +371,7 @@ void acpi_create_dbg2(struct acpi_dbg2_header *dbg2, /* Update structure lengths and checksum */ device->length = current - (uintptr_t)device; header->length = current - (uintptr_t)dbg2; - header->checksum = table_compute_checksum(dbg2, header->length); + acpi_update_checksum(header); } int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev, @@ -549,7 +546,7 @@ static int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry spcr->baud_rate = 0; /* Fix checksum */ - header->checksum = table_compute_checksum((void *)spcr, header->length); + acpi_update_checksum(header); acpi_add_table(ctx, spcr); acpi_inc(ctx, spcr->header.length); @@ -615,6 +612,7 @@ int acpi_iort_add_named_component(struct acpi_ctx *ctx, node->length += strlen(device_name) + 1; comp = (struct acpi_iort_named_component *)node->node_data; + memset(comp, '\0', sizeof(struct acpi_iort_named_component)); comp->node_flags = node_flags; comp->memory_properties = memory_properties; @@ -635,6 +633,7 @@ int acpi_iort_add_rc(struct acpi_ctx *ctx, const struct acpi_iort_id_mapping *map) { struct acpi_iort_id_mapping *mapping; + struct acpi_iort_node *output_node; struct acpi_iort_node *node; struct acpi_iort_rc *rc; int offset; @@ -646,12 +645,18 @@ int acpi_iort_add_rc(struct acpi_ctx *ctx, node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX; node->revision = 2; + node->mapping_count = num_mappings; + if (num_mappings) + node->mapping_offset = sizeof(struct acpi_iort_node) + + sizeof(struct acpi_iort_rc); node->length = sizeof(struct acpi_iort_node); node->length += sizeof(struct acpi_iort_rc); node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings; rc = (struct acpi_iort_rc *)node->node_data; + memset(rc, '\0', sizeof(struct acpi_iort_rc)); + rc->mem_access_properties = mem_access_properties; rc->ats_attributes = ats_attributes; rc->pci_segment_number = pci_segment_number; @@ -659,6 +664,13 @@ int acpi_iort_add_rc(struct acpi_ctx *ctx, mapping = (struct acpi_iort_id_mapping *)(rc + 1); for (int i = 0; i < num_mappings; i++) { + /* Validate input */ + output_node = (struct acpi_iort_node *)ctx->tab_start + map[i].output_reference; + /* ID mappings can use SMMUs or ITS groups as output references */ + assert(output_node && ((output_node->type == ACPI_IORT_NODE_ITS_GROUP) || + (output_node->type == ACPI_IORT_NODE_SMMU) || + (output_node->type == ACPI_IORT_NODE_SMMU_V3))); + memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping)); mapping++; } @@ -683,6 +695,7 @@ int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx, const struct acpi_iort_id_mapping *map) { struct acpi_iort_node *node; + struct acpi_iort_node *output_node; struct acpi_iort_smmu_v3 *smmu; struct acpi_iort_id_mapping *mapping; int offset; @@ -695,13 +708,16 @@ int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx, node->type = ACPI_IORT_NODE_SMMU_V3; node->revision = 5; node->mapping_count = num_mappings; - node->mapping_offset = sizeof(struct acpi_iort_node) + sizeof(struct acpi_iort_smmu_v3); + if (num_mappings) + node->mapping_offset = sizeof(struct acpi_iort_node) + + sizeof(struct acpi_iort_smmu_v3); node->length = sizeof(struct acpi_iort_node); node->length += sizeof(struct acpi_iort_smmu_v3); node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings; smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + memset(smmu, '\0', sizeof(struct acpi_iort_smmu_v3)); smmu->base_address = base_address; smmu->flags = flags; @@ -716,6 +732,14 @@ int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx, mapping = (struct acpi_iort_id_mapping *)(smmu + 1); for (int i = 0; i < num_mappings; i++) { + /* Validate input */ + output_node = (struct acpi_iort_node *)ctx->tab_start + map[i].output_reference; + /* + * ID mappings of an SMMUv3 node can only have ITS group nodes + * as output references. + */ + assert(output_node && output_node->type == ACPI_IORT_NODE_ITS_GROUP); + memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping)); mapping++; } @@ -759,7 +783,7 @@ static int acpi_write_iort(struct acpi_ctx *ctx, const struct acpi_writer *entry /* (Re)calculate length and checksum */ iort->header.length = ctx->current - (void *)iort; - iort->header.checksum = table_compute_checksum((void *)iort, iort->header.length); + acpi_update_checksum(&iort->header); log_debug("IORT at %p, length %x\n", iort, iort->header.length); /* Drop the table if it is empty */ diff --git a/lib/acpi/base.c b/lib/acpi/base.c index 8b6af2bc43a..5c755b14c16 100644 --- a/lib/acpi/base.c +++ b/lib/acpi/base.c @@ -50,8 +50,7 @@ static void acpi_write_rsdt(struct acpi_rsdt *rsdt) /* Entries are filled in later, we come with an empty set */ /* Fix checksum */ - header->checksum = table_compute_checksum(rsdt, - sizeof(struct acpi_rsdt)); + acpi_update_checksum(header); } static void acpi_write_xsdt(struct acpi_xsdt *xsdt) @@ -66,8 +65,7 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt) /* Entries are filled in later, we come with an empty set */ /* Fix checksum */ - header->checksum = table_compute_checksum(xsdt, - sizeof(struct acpi_xsdt)); + acpi_update_checksum(header); } static int acpi_write_base(struct acpi_ctx *ctx, diff --git a/lib/acpi/csrt.c b/lib/acpi/csrt.c index 00927e53406..b863c644c07 100644 --- a/lib/acpi/csrt.c +++ b/lib/acpi/csrt.c @@ -40,7 +40,7 @@ int acpi_write_csrt(struct acpi_ctx *ctx, const struct acpi_writer *entry) /* (Re)calculate length and checksum */ header->length = (ulong)ctx->current - (ulong)csrt; - header->checksum = table_compute_checksum(csrt, header->length); + acpi_update_checksum(header); acpi_add_table(ctx, csrt); diff --git a/lib/acpi/mcfg.c b/lib/acpi/mcfg.c index 8b8a5bfafae..e21fe7ce123 100644 --- a/lib/acpi/mcfg.c +++ b/lib/acpi/mcfg.c @@ -57,7 +57,7 @@ int acpi_write_mcfg(struct acpi_ctx *ctx, const struct acpi_writer *entry) /* (Re)calculate length and checksum */ header->length = (ulong)ctx->current - (ulong)mcfg; - header->checksum = table_compute_checksum(mcfg, header->length); + acpi_update_checksum(header); acpi_add_table(ctx, mcfg); diff --git a/lib/acpi/ssdt.c b/lib/acpi/ssdt.c index df1d739d117..41e2d3c2f6c 100644 --- a/lib/acpi/ssdt.c +++ b/lib/acpi/ssdt.c @@ -35,7 +35,7 @@ int acpi_write_ssdt(struct acpi_ctx *ctx, const struct acpi_writer *entry) /* (Re)calculate length and checksum */ ssdt->length = ctx->current - (void *)ssdt; - ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length); + acpi_update_checksum(ssdt); log_debug("SSDT at %p, length %x\n", ssdt, ssdt->length); /* Drop the table if it is empty */ diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c index 1c5dde60691..f0095e9dbcf 100644 --- a/lib/ecdsa/ecdsa-libcrypto.c +++ b/lib/ecdsa/ecdsa-libcrypto.c @@ -363,8 +363,10 @@ int ecdsa_add_verify_data(struct image_sign_info *info, void *fdt) ret = prepare_ctx(&ctx, info); if (ret >= 0) { ret = do_add(&ctx, fdt, fdt_key_name, info); - if (ret < 0) - ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; + if (ret < 0) { + free_ctx(&ctx); + return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; + } } free_ctx(&ctx); diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index d4f6b56afaa..6130af14337 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -27,6 +27,7 @@ config EFI_LOADER select REGEX imply FAT imply FAT_WRITE + imply FAT_RENAME imply USB_KEYBOARD_FN_KEYS imply VIDEO_ANSI help diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c index 10ec5e9ada3..deafb2ce1c2 100644 --- a/lib/efi_loader/efi_bootbin.c +++ b/lib/efi_loader/efi_bootbin.c @@ -16,6 +16,7 @@ #include <log.h> #include <malloc.h> #include <mapmem.h> +#include <net.h> static struct efi_device_path *bootefi_image_path; static struct efi_device_path *bootefi_device_path; @@ -67,7 +68,7 @@ static efi_status_t calculate_paths(const char *dev, const char *devnr, #if IS_ENABLED(CONFIG_NETDEVICES) if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) { - ret = efi_net_set_dp(dev, devnr); + ret = efi_net_new_dp(dev, devnr, eth_get_dev()); if (ret != EFI_SUCCESS) return ret; } diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index c6124c590d9..f9534ef85ed 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -18,6 +18,8 @@ #include <efi_loader.h> #include <efi_variable.h> #include <asm/unaligned.h> +#include <linux/kernel.h> +#include <linux/sizes.h> static const struct efi_boot_services *bs; static const struct efi_runtime_services *rs; @@ -348,6 +350,7 @@ static efi_status_t prepare_loaded_image(u16 *label, ulong addr, ulong size, struct efi_device_path **dp, struct udevice **blk) { + u64 pages; efi_status_t ret; struct udevice *ramdisk_blk; @@ -362,13 +365,18 @@ static efi_status_t prepare_loaded_image(u16 *label, ulong addr, ulong size, } /* - * TODO: expose the ramdisk to OS. - * Need to pass the ramdisk information by the architecture-specific - * methods such as 'pmem' device-tree node. + * Linux supports 'pmem' which allows OS installers to find, reclaim + * the mounted images and continue the installation since the contents + * of the pmem region are treated as local media. + * + * The memory regions used for it needs to be carved out of the EFI + * memory map. */ - ret = efi_add_memory_map(addr, size, EFI_RESERVED_MEMORY_TYPE); + pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK)); + ret = efi_update_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, + false, true); if (ret != EFI_SUCCESS) { - log_err("Memory reservation failed\n"); + log_err("Failed to reserve memory\n"); goto err; } @@ -490,6 +498,13 @@ static efi_status_t try_load_from_uri_path(struct efi_device_path_uri *uridp, ret = EFI_INVALID_PARAMETER; goto err; } + /* + * Depending on the kernel configuration, pmem memory areas must be + * page aligned or 2MiB aligned. PowerPC is an exception here and + * requires 16MiB alignment, but since we don't have EFI support for + * it, limit the alignment to 2MiB. + */ + image_size = ALIGN(image_size, SZ_2M); /* * If the file extension is ".iso" or ".img", mount it and try to load diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5164cb15986..f220daa048f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -15,13 +15,13 @@ #include <irq_func.h> #include <log.h> #include <malloc.h> +#include <net-common.h> #include <pe.h> #include <time.h> #include <u-boot/crc.h> #include <usb.h> #include <watchdog.h> #include <asm/global_data.h> -#include <asm/setjmp.h> #include <linux/libfdt_env.h> DECLARE_GLOBAL_DATA_PTR; @@ -60,9 +60,9 @@ static efi_handle_t current_image; static volatile gd_t *efi_gd, *app_gd; #endif -static efi_status_t efi_uninstall_protocol - (efi_handle_t handle, const efi_guid_t *protocol, - void *protocol_interface, bool preserve); +efi_status_t efi_uninstall_protocol + (efi_handle_t handle, const efi_guid_t *protocol, + void *protocol_interface, bool preserve); /* 1 if inside U-Boot code, 0 if inside EFI payload code */ static int entry_count = 1; @@ -100,12 +100,11 @@ const efi_guid_t efi_guid_load_file2_protocol = EFI_LOAD_FILE2_PROTOCOL_GUID; /* GUID of the SMBIOS table */ const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; -static efi_status_t EFIAPI efi_disconnect_controller( +efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, efi_handle_t driver_image_handle, efi_handle_t child_handle); -static efi_status_t EFIAPI efi_connect_controller(efi_handle_t controller_handle, efi_handle_t *driver_image_handle, struct efi_device_path *remain_device_path, @@ -1039,7 +1038,7 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) * * Return: status code */ -static efi_status_t EFIAPI efi_close_event(struct efi_event *event) +efi_status_t EFIAPI efi_close_event(struct efi_event *event) { struct efi_register_notify_event *item, *next; @@ -1380,9 +1379,9 @@ static efi_status_t efi_disconnect_all_drivers * * Return: status code */ -static efi_status_t efi_uninstall_protocol - (efi_handle_t handle, const efi_guid_t *protocol, - void *protocol_interface, bool preserve) +efi_status_t efi_uninstall_protocol + (efi_handle_t handle, const efi_guid_t *protocol, + void *protocol_interface, bool preserve) { struct efi_handler *handler; struct efi_open_protocol_info_item *item; @@ -2233,8 +2232,8 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, if (!efi_st_keep_devices) { bootm_disable_interrupts(); - if (IS_ENABLED(CONFIG_USB_DEVICE)) - udc_disconnect(); + if (IS_ENABLED(CONFIG_DM_ETH)) + eth_halt(); board_quiesce_devices(); dm_remove_devices_active(); } @@ -3199,7 +3198,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, void *info; efi_handle_t parent_image = current_image; efi_status_t exit_status; - struct jmp_buf_data exit_jmp; + jmp_buf exit_jmp; EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); @@ -3238,7 +3237,7 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, } /* call the image! */ - if (setjmp(&exit_jmp)) { + if (setjmp(exit_jmp)) { /* * We called the entry point of the child image with EFI_CALL * in the lines below. The child image called the Exit() boot @@ -3444,7 +3443,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, struct efi_loaded_image *loaded_image_protocol; struct efi_loaded_image_obj *image_obj = (struct efi_loaded_image_obj *)image_handle; - struct jmp_buf_data *exit_jmp; + jmp_buf *exit_jmp; EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status, exit_data_size, exit_data); @@ -3511,7 +3510,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, */ efi_restore_gd(); - longjmp(exit_jmp, 1); + longjmp(*exit_jmp, 1); panic("EFI application exited"); out: @@ -3665,7 +3664,7 @@ static efi_status_t efi_connect_single_controller( * * Return: status code */ -static efi_status_t EFIAPI efi_connect_controller( +efi_status_t EFIAPI efi_connect_controller( efi_handle_t controller_handle, efi_handle_t *driver_image_handle, struct efi_device_path *remain_device_path, @@ -3844,7 +3843,7 @@ static efi_status_t efi_get_child_controllers( * * Return: status code */ -static efi_status_t EFIAPI efi_disconnect_controller( +efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, efi_handle_t driver_image_handle, efi_handle_t child_handle) diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index c0633a736b6..c9bf2726fe2 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -954,20 +954,20 @@ struct efi_device_path *efi_dp_from_uart(void) return buf; } -struct efi_device_path __maybe_unused *efi_dp_from_eth(void) +struct efi_device_path __maybe_unused *efi_dp_from_eth(struct udevice *dev) { void *buf, *start; unsigned dpsize = 0; - assert(eth_get_dev()); + assert(dev); - dpsize += dp_size(eth_get_dev()); + dpsize += dp_size(dev); start = buf = efi_alloc(dpsize + sizeof(END)); if (!buf) return NULL; - buf = dp_fill(buf, eth_get_dev()); + buf = dp_fill(buf, dev); *((struct efi_device_path *)buf) = END; @@ -984,11 +984,13 @@ struct efi_device_path __maybe_unused *efi_dp_from_eth(void) * @ip: IPv4 local address * @mask: network mask * @srv: IPv4 remote/server address + * @dev: net udevice * Return: pointer to device path, NULL on error */ static struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip, struct efi_ipv4_address *mask, - struct efi_ipv4_address *srv) + struct efi_ipv4_address *srv, + struct udevice *dev) { struct efi_device_path *dp1, *dp2, *pos; struct { @@ -1010,7 +1012,7 @@ static struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip, pos = &dp.end; memcpy(pos, &END, sizeof(END)); - dp1 = efi_dp_from_eth(); + dp1 = efi_dp_from_eth(dev); if (!dp1) return NULL; @@ -1029,9 +1031,10 @@ static struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip, * and an END node. * * @server: URI of remote server + * @dev: net udevice * Return: pointer to HTTP device path, NULL on error */ -struct efi_device_path *efi_dp_from_http(const char *server) +struct efi_device_path *efi_dp_from_http(const char *server, struct udevice *dev) { struct efi_device_path *dp1, *dp2; struct efi_device_path_uri *uridp; @@ -1045,12 +1048,13 @@ struct efi_device_path *efi_dp_from_http(const char *server) (!server && IS_ENABLED(CONFIG_NET_LWIP))) return NULL; - efi_net_get_addr(&ip, &mask, NULL); + efi_net_get_addr(&ip, &mask, NULL, dev); - dp1 = efi_dp_from_ipv4(&ip, &mask, NULL); + dp1 = efi_dp_from_ipv4(&ip, &mask, NULL, dev); if (!dp1) return NULL; + strcpy(tmp, "http://"); if (server) { @@ -1185,8 +1189,8 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, (uintptr_t)image_addr, image_size); } else if (IS_ENABLED(CONFIG_NETDEVICES) && - (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) { - efi_net_get_dp(&dp); + (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) { + efi_net_dp_from_dev(&dp, eth_get_dev(), false); } else if (!strcmp(dev, "Uart")) { dp = efi_dp_from_uart(); } else { diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index f6889cb7399..452ec1b2e8b 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -181,10 +181,13 @@ static char *dp_msging(char *s, struct efi_device_path *dp) switch (idp->protocol) { case IPPROTO_TCP: s += sprintf(s, "TCP,"); + break; case IPPROTO_UDP: s += sprintf(s, "UDP,"); + break; default: s += sprintf(s, "0x%x,", idp->protocol); + break; } s += sprintf(s, idp->static_ip_address ? "Static" : "DHCP"); s += sprintf(s, ",%pI4", &idp->local_ip_address); diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 201fa5f8f3c..7d81da8f2d8 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -40,7 +40,7 @@ struct file_handle { struct fs_dir_stream *dirs; struct fs_dirent *dent; - char path[0]; + char *path; }; #define to_fh(x) container_of(x, struct file_handle, base) @@ -178,6 +178,7 @@ static struct efi_file_handle *file_open(struct file_system *fs, u64 attributes) { struct file_handle *fh; + char *path; char f0[MAX_UTF8_PER_UTF16] = {0}; int plen = 0; int flen = 0; @@ -194,11 +195,13 @@ static struct efi_file_handle *file_open(struct file_system *fs, plen = strlen(parent->path) + 1; } + fh = calloc(1, sizeof(*fh)); /* +2 is for null and '/' */ - fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); - if (!fh) - return NULL; + path = calloc(1, plen + (flen * MAX_UTF8_PER_UTF16) + 2); + if (!fh || !path) + goto error; + fh->path = path; fh->open_mode = open_mode; fh->base = efi_file_handle_protocol; fh->fs = fs; @@ -245,6 +248,7 @@ static struct efi_file_handle *file_open(struct file_system *fs, return &fh->base; error: + free(fh->path); free(fh); return NULL; } @@ -368,6 +372,7 @@ out: static efi_status_t file_close(struct file_handle *fh) { fs_closedir(fh->dirs); + free(fh->path); free(fh); return EFI_SUCCESS; } @@ -949,6 +954,7 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_UNSUPPORTED; + char *new_file_name = NULL, *new_path = NULL; EFI_ENTRY("%p, %pUs, %zu, %p", file, info_type, buffer_size, buffer); @@ -978,13 +984,43 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, pos = new_file_name; utf16_utf8_strcpy(&pos, info->file_name); if (strcmp(new_file_name, filename)) { - /* TODO: we do not support renaming */ - EFI_PRINT("Renaming not supported\n"); - free(new_file_name); - ret = EFI_ACCESS_DENIED; - goto out; + int dlen; + int rv; + + if (set_blk_dev(fh)) { + ret = EFI_DEVICE_ERROR; + goto out; + } + dlen = filename - fh->path; + new_path = calloc(1, dlen + strlen(new_file_name) + 1); + if (!new_path) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + memcpy(new_path, fh->path, dlen); + strcpy(new_path + dlen, new_file_name); + sanitize_path(new_path); + rv = fs_exists(new_path); + if (rv) { + ret = EFI_ACCESS_DENIED; + goto out; + } + /* fs_exists() calls fs_close(), so open file system again */ + if (set_blk_dev(fh)) { + ret = EFI_DEVICE_ERROR; + goto out; + } + rv = fs_rename(fh->path, new_path); + if (rv) { + ret = EFI_ACCESS_DENIED; + goto out; + } + free(fh->path); + fh->path = new_path; + /* Prevent new_path from being freed on out */ + new_path = NULL; + ret = EFI_SUCCESS; } - free(new_file_name); /* Check for truncation */ if (!fh->isdir) { ret = efi_get_file_size(fh, &file_size); @@ -1007,6 +1043,8 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, ret = EFI_UNSUPPORTED; } out: + free(new_path); + free(new_file_name); return EFI_EXIT(ret); } diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 04b2efc4a3b..8c32059edda 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -5,6 +5,7 @@ #define LOG_CATEGORY LOGC_EFI +#include <blkmap.h> #include <bootm.h> #include <env.h> #include <image.h> @@ -454,22 +455,29 @@ efi_status_t efi_env_set_load_options(efi_handle_t handle, */ static efi_status_t copy_fdt(void **fdtp) { - unsigned long fdt_ram_start = -1L, fdt_pages; efi_status_t ret = 0; void *fdt, *new_fdt; - u64 new_fdt_addr; - uint fdt_size; - int i; + static u64 new_fdt_addr; + static efi_uintn_t fdt_pages; + ulong fdt_size; - for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - u64 ram_start = gd->bd->bi_dram[i].start; - u64 ram_size = gd->bd->bi_dram[i].size; + /* + * Remove the configuration table that might already be + * installed, ignoring EFI_NOT_FOUND if no device-tree + * is installed + */ + efi_install_configuration_table(&efi_guid_fdt, NULL); - if (!ram_size) - continue; + if (new_fdt_addr) { + log_debug("%s: Found allocated memory at %#llx, with %#zx pages\n", + __func__, new_fdt_addr, fdt_pages); - if (ram_start < fdt_ram_start) - fdt_ram_start = ram_start; + ret = efi_free_pages(new_fdt_addr, fdt_pages); + if (ret != EFI_SUCCESS) + log_err("Unable to free up existing FDT memory region\n"); + + new_fdt_addr = 0; + fdt_pages = 0; } /* @@ -485,15 +493,18 @@ static efi_status_t copy_fdt(void **fdtp) &new_fdt_addr); if (ret != EFI_SUCCESS) { log_err("Failed to reserve space for FDT\n"); - goto done; + return ret; } + log_debug("%s: Allocated memory at %#llx, with %#zx pages\n", + __func__, new_fdt_addr, fdt_pages); + new_fdt = (void *)(uintptr_t)new_fdt_addr; memcpy(new_fdt, fdt, fdt_totalsize(fdt)); fdt_set_totalsize(new_fdt, fdt_size); - *fdtp = (void *)(uintptr_t)new_fdt_addr; -done: - return ret; + *fdtp = new_fdt; + + return EFI_SUCCESS; } /** @@ -546,9 +557,6 @@ efi_status_t efi_install_fdt(void *fdt) const char *fdt_opt; uintptr_t fdt_addr; - /* Look for device tree that is already installed */ - if (efi_get_configuration_table(&efi_guid_fdt)) - return EFI_SUCCESS; /* Check if there is a hardware device tree */ fdt_opt = env_get("fdt_addr"); /* Use our own device tree as fallback */ @@ -680,3 +688,44 @@ out: return ret; } + +/** + * pmem_node_efi_memmap_setup() - Add pmem node and tweak EFI memmap + * @fdt: The devicetree to which pmem node is added + * @addr: start address of the pmem node + * @size: size of the memory of the pmem node + * + * The function adds the pmem node to the device-tree along with removing + * the corresponding region from the EFI memory map. Used primarily to + * pass the information of a RAM based ISO image to the OS. + * + * Return: 0 on success, -ve value on error + */ +static int pmem_node_efi_memmap_setup(void *fdt, u64 addr, u64 size) +{ + int ret; + u64 pages; + efi_status_t status; + + ret = fdt_fixup_pmem_region(fdt, addr, size); + if (ret) { + log_err("Failed to setup pmem node for addr %#llx, size %#llx, err %d\n", + addr, size, ret); + return ret; + } + + /* Remove the pmem region from the EFI memory map */ + pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK)); + status = efi_update_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, + false, true); + if (status != EFI_SUCCESS) + return -1; + + return 0; +} + +int fdt_efi_pmem_setup(void *fdt) +{ + return blkmap_get_preserved_pmem_slices(pmem_node_efi_memmap_setup, + fdt); +} diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c index 88816256b03..189317fe2d2 100644 --- a/lib/efi_loader/efi_http.c +++ b/lib/efi_loader/efi_http.c @@ -36,6 +36,7 @@ static const efi_guid_t efi_http_guid = EFI_HTTP_PROTOCOL_GUID; struct efi_http_instance { struct efi_http_protocol http; efi_handle_t handle; + struct efi_service_binding_protocol *parent; bool configured; void *http_load_addr; ulong file_size; @@ -188,7 +189,7 @@ static efi_status_t EFIAPI efi_http_configure(struct efi_http_protocol *this, if (!ipv4_node->use_default_address) { efi_net_set_addr((struct efi_ipv4_address *)&ipv4_node->local_address, - (struct efi_ipv4_address *)&ipv4_node->local_subnet, NULL); + (struct efi_ipv4_address *)&ipv4_node->local_subnet, NULL, NULL); } http_instance->current_offset = 0; @@ -243,7 +244,7 @@ static efi_status_t EFIAPI efi_http_request(struct efi_http_protocol *this, ret = efi_net_do_request(url_8, current_method, &http_instance->http_load_addr, &http_instance->status_code, &http_instance->file_size, - http_instance->headers_buffer); + http_instance->headers_buffer, http_instance->parent); if (ret != EFI_SUCCESS) goto out; @@ -408,6 +409,7 @@ static efi_status_t EFIAPI efi_http_service_binding_create_child( goto failure_to_add_protocol; } + new_instance->parent = this; efi_add_handle(new_instance->handle); *child_handle = new_instance->handle; diff --git a/lib/efi_loader/efi_ipconfig.c b/lib/efi_loader/efi_ipconfig.c index f1c092daafd..9f51f77fa9a 100644 --- a/lib/efi_loader/efi_ipconfig.c +++ b/lib/efi_loader/efi_ipconfig.c @@ -60,7 +60,7 @@ static efi_status_t EFIAPI efi_ip4_config2_set_data(struct efi_ip4_config2_proto memcpy((void *)¤t_http_ip, data, sizeof(struct efi_ip4_config2_manual_address)); efi_net_set_addr(¤t_http_ip.address, - ¤t_http_ip.subnet_mask, NULL); + ¤t_http_ip.subnet_mask, NULL, NULL); return EFI_EXIT(EFI_SUCCESS); } return EFI_EXIT(EFI_BAD_BUFFER_SIZE); @@ -133,7 +133,7 @@ static efi_status_t EFIAPI efi_ip4_config2_get_data(struct efi_ip4_config2_proto return EFI_EXIT(EFI_BUFFER_TOO_SMALL); } - efi_net_get_addr(¤t_http_ip.address, ¤t_http_ip.subnet_mask, NULL); + efi_net_get_addr(¤t_http_ip.address, ¤t_http_ip.subnet_mask, NULL, NULL); memcpy(data, (void *)¤t_http_ip, sizeof(struct efi_ip4_config2_manual_address)); diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 6d00b186250..0abb1f6159a 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -258,7 +258,7 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map, } /** - * efi_add_memory_map_pg() - add pages to the memory map + * efi_update_memory_map() - update the memory map by adding/removing pages * * @start: start address, must be a multiple of * EFI_PAGE_SIZE @@ -266,12 +266,11 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map, * @memory_type: type of memory added * @overlap_conventional: region may only overlap free(conventional) * memory + * @remove: remove memory map * Return: status code */ -static -efi_status_t efi_add_memory_map_pg(u64 start, u64 pages, - int memory_type, - bool overlap_conventional) +efi_status_t efi_update_memory_map(u64 start, u64 pages, int memory_type, + bool overlap_conventional, bool remove) { struct efi_mem_list *lmem; struct efi_mem_list *newlist; @@ -279,9 +278,9 @@ efi_status_t efi_add_memory_map_pg(u64 start, u64 pages, uint64_t carved_pages = 0; struct efi_event *evt; - EFI_PRINT("%s: 0x%llx 0x%llx %d %s\n", __func__, + EFI_PRINT("%s: 0x%llx 0x%llx %d %s %s\n", __func__, start, pages, memory_type, overlap_conventional ? - "yes" : "no"); + "yes" : "no", remove ? "remove" : "add"); if (memory_type >= EFI_MAX_MEMORY_TYPE) return EFI_INVALID_PARAMETER; @@ -364,7 +363,10 @@ efi_status_t efi_add_memory_map_pg(u64 start, u64 pages, } /* Add our new map */ - list_add_tail(&newlist->link, &efi_mem); + if (!remove) + list_add_tail(&newlist->link, &efi_mem); + else + free(newlist); /* And make sure memory is listed in descending order */ efi_mem_sort(); @@ -401,7 +403,7 @@ efi_status_t efi_add_memory_map(u64 start, u64 size, int memory_type) pages = efi_size_in_pages(size + (start & EFI_PAGE_MASK)); start &= ~EFI_PAGE_MASK; - return efi_add_memory_map_pg(start, pages, memory_type, false); + return efi_update_memory_map(start, pages, memory_type, false, false); } /** @@ -491,8 +493,7 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type, return EFI_NOT_FOUND; addr = map_to_sysmem((void *)(uintptr_t)*memory); - addr = (u64)lmb_alloc_addr(addr, len, flags); - if (!addr) + if (lmb_alloc_addr(addr, len, flags)) return EFI_NOT_FOUND; break; default: @@ -502,7 +503,7 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type, efi_addr = (u64)(uintptr_t)map_sysmem(addr, 0); /* Reserve that map in our memory maps */ - ret = efi_add_memory_map_pg(efi_addr, pages, memory_type, true); + ret = efi_update_memory_map(efi_addr, pages, memory_type, true, false); if (ret != EFI_SUCCESS) { /* Map would overlap, bail out */ lmb_free_flags(addr, (u64)pages << EFI_PAGE_SHIFT, flags); @@ -823,8 +824,8 @@ static void add_u_boot_and_runtime(void) uboot_stack_size) & ~EFI_PAGE_MASK; uboot_pages = ((uintptr_t)map_sysmem(gd->ram_top - 1, 0) - uboot_start + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; - efi_add_memory_map_pg(uboot_start, uboot_pages, EFI_BOOT_SERVICES_CODE, - false); + efi_update_memory_map(uboot_start, uboot_pages, EFI_BOOT_SERVICES_CODE, + false, false); #if defined(__aarch64__) /* * Runtime Services must be 64KiB aligned according to the @@ -842,8 +843,8 @@ static void add_u_boot_and_runtime(void) runtime_end = (uintptr_t)__efi_runtime_stop; runtime_end = (runtime_end + runtime_mask) & ~runtime_mask; runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT; - efi_add_memory_map_pg(runtime_start, runtime_pages, - EFI_RUNTIME_SERVICES_CODE, false); + efi_update_memory_map(runtime_start, runtime_pages, + EFI_RUNTIME_SERVICES_CODE, false, false); } int efi_memory_init(void) @@ -878,11 +879,11 @@ int efi_map_update_notify(phys_addr_t addr, phys_size_t size, pages = efi_size_in_pages(size + (efi_addr & EFI_PAGE_MASK)); efi_addr &= ~EFI_PAGE_MASK; - status = efi_add_memory_map_pg(efi_addr, pages, + status = efi_update_memory_map(efi_addr, pages, op == LMB_MAP_OP_RESERVE ? EFI_BOOT_SERVICES_DATA : EFI_CONVENTIONAL_MEMORY, - false); + false, false); if (status != EFI_SUCCESS) { log_err("LMB Map notify failure %lu\n", status & ~EFI_ERROR_MASK); diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 60aa076feaa..b3291b4f1d5 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -24,54 +24,70 @@ #include <vsprintf.h> #include <net.h> -static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; +#define MAX_EFI_NET_OBJS 10 +#define MAX_NUM_DHCP_ENTRIES 10 +#define MAX_NUM_DP_ENTRIES 10 + +const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; static const efi_guid_t efi_pxe_base_code_protocol_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID; -static struct efi_pxe_packet *dhcp_ack; -static void *new_tx_packet; -static void *transmit_buffer; -static uchar **receive_buffer; -static size_t *receive_lengths; -static int rx_packet_idx; -static int rx_packet_num; -static struct efi_net_obj *netobj; + +struct dp_entry { + struct efi_device_path *net_dp; + struct udevice *dev; + bool is_valid; +}; /* - * The current network device path. This device path is updated when a new - * bootfile is downloaded from the network. If then the bootfile is loaded - * as an efi image, net_dp is passed as the device path of the loaded image. + * The network device path cache. An entry is added when a new bootfile + * is downloaded from the network. If the bootfile is then loaded as an + * efi image, the most recent entry corresponding to the device is passed + * as the device path of the loaded image. */ -static struct efi_device_path *net_dp; +static struct dp_entry dp_cache[MAX_NUM_DP_ENTRIES]; +static int next_dp_entry; +#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL) static struct wget_http_info efi_wget_info = { .set_bootdev = false, .check_buffer_size = true, }; +#endif -/* - * The notification function of this event is called in every timer cycle - * to check if a new network packet has been received. - */ -static struct efi_event *network_timer_event; -/* - * This event is signaled when a packet has been received. - */ -static struct efi_event *wait_for_packet; +struct dhcp_entry { + struct efi_pxe_packet *dhcp_ack; + struct udevice *dev; + bool is_valid; +}; + +static struct dhcp_entry dhcp_cache[MAX_NUM_DHCP_ENTRIES]; +static int next_dhcp_entry; /** * struct efi_net_obj - EFI object representing a network interface * * @header: EFI object header + * @dev: net udevice * @net: simple network protocol interface * @net_mode: status of the network interface * @pxe: PXE base code protocol interface * @pxe_mode: status of the PXE base code protocol * @ip4_config2: IP4 Config2 protocol interface * @http_service_binding: Http service binding protocol interface + * @new_tx_packet: new transmit packet + * @transmit_buffer: transmit buffer + * @receive_buffer: array of receive buffers + * @receive_lengths: array of lengths for received packets + * @rx_packet_idx: index of the current receive packet + * @rx_packet_num: number of received packets + * @wait_for_packet: signaled when a packet has been received + * @network_timer_event: event to check for new network packets. + * @efi_seq_num: sequence number of the EFI net object. */ struct efi_net_obj { struct efi_object header; + struct udevice *dev; struct efi_simple_network net; struct efi_simple_network_mode net_mode; struct efi_pxe_base_code_protocol pxe; @@ -82,8 +98,54 @@ struct efi_net_obj { #if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL) struct efi_service_binding_protocol http_service_binding; #endif + void *new_tx_packet; + void *transmit_buffer; + uchar **receive_buffer; + size_t *receive_lengths; + int rx_packet_idx; + int rx_packet_num; + struct efi_event *wait_for_packet; + struct efi_event *network_timer_event; + int efi_seq_num; }; +static int curr_efi_net_obj; +static struct efi_net_obj *net_objs[MAX_EFI_NET_OBJS]; + +/** + * efi_netobj_is_active() - checks if a netobj is active in the efi subsystem + * + * @netobj: pointer to efi_net_obj + * Return: true if active + */ +static bool efi_netobj_is_active(struct efi_net_obj *netobj) +{ + if (!netobj || !efi_search_obj(&netobj->header)) + return false; + + return true; +} + +/* + * efi_netobj_from_snp() - get efi_net_obj from simple network protocol + * + * + * @snp: pointer to the simple network protocol + * Return: pointer to efi_net_obj, NULL on error + */ +static struct efi_net_obj *efi_netobj_from_snp(struct efi_simple_network *snp) +{ + int i; + + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && &net_objs[i]->net == snp) { + // Do not register duplicate devices + return net_objs[i]; + } + } + return NULL; +} + /* * efi_net_start() - start the network interface * @@ -97,20 +159,22 @@ struct efi_net_obj { static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) { efi_status_t ret = EFI_SUCCESS; + struct efi_net_obj *nt; EFI_ENTRY("%p", this); - /* Check parameters */ if (!this) { ret = EFI_INVALID_PARAMETER; goto out; } + nt = efi_netobj_from_snp(this); + if (this->mode->state != EFI_NETWORK_STOPPED) { ret = EFI_ALREADY_STARTED; } else { this->int_status = 0; - wait_for_packet->is_signaled = false; + nt->wait_for_packet->is_signaled = false; this->mode->state = EFI_NETWORK_STARTED; } out: @@ -130,6 +194,7 @@ out: static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) { efi_status_t ret = EFI_SUCCESS; + struct efi_net_obj *nt; EFI_ENTRY("%p", this); @@ -139,13 +204,17 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) goto out; } + nt = efi_netobj_from_snp(this); + if (this->mode->state == EFI_NETWORK_STOPPED) { ret = EFI_NOT_STARTED; } else { /* Disable hardware and put it into the reset state */ + eth_set_dev(nt->dev); + env_set("ethact", eth_get_name()); eth_halt(); /* Clear cache of packets */ - rx_packet_num = 0; + nt->rx_packet_num = 0; this->mode->state = EFI_NETWORK_STOPPED; } out: @@ -169,6 +238,7 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, { int ret; efi_status_t r = EFI_SUCCESS; + struct efi_net_obj *nt; EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx); @@ -177,6 +247,7 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, r = EFI_INVALID_PARAMETER; goto out; } + nt = efi_netobj_from_snp(this); switch (this->mode->state) { case EFI_NETWORK_INITIALIZED: @@ -189,14 +260,13 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, /* Setup packet buffers */ net_init(); - /* Disable hardware and put it into the reset state */ - eth_halt(); /* Clear cache of packets */ - rx_packet_num = 0; - /* Set current device according to environment variables */ - eth_set_current(); + nt->rx_packet_num = 0; + /* Set the net device corresponding to the efi net object */ + eth_set_dev(nt->dev); + env_set("ethact", eth_get_name()); /* Get hardware ready for send and receive operations */ - ret = eth_init(); + ret = eth_start_udev(nt->dev); if (ret < 0) { eth_halt(); this->mode->state = EFI_NETWORK_STOPPED; @@ -204,7 +274,7 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, goto out; } else { this->int_status = 0; - wait_for_packet->is_signaled = false; + nt->wait_for_packet->is_signaled = false; this->mode->state = EFI_NETWORK_INITIALIZED; } out: @@ -265,6 +335,7 @@ out: static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) { efi_status_t ret = EFI_SUCCESS; + struct efi_net_obj *nt; EFI_ENTRY("%p", this); @@ -273,6 +344,7 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) ret = EFI_INVALID_PARAMETER; goto out; } + nt = efi_netobj_from_snp(this); switch (this->mode->state) { case EFI_NETWORK_INITIALIZED: @@ -285,9 +357,12 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) goto out; } + eth_set_dev(nt->dev); + env_set("ethact", eth_get_name()); eth_halt(); + this->int_status = 0; - wait_for_packet->is_signaled = false; + nt->wait_for_packet->is_signaled = false; this->mode->state = EFI_NETWORK_STARTED; out: @@ -463,6 +538,7 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, u32 *int_status, void **txbuf) { efi_status_t ret = EFI_SUCCESS; + struct efi_net_obj *nt; EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); @@ -474,6 +550,8 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, goto out; } + nt = efi_netobj_from_snp(this); + switch (this->mode->state) { case EFI_NETWORK_STOPPED: ret = EFI_NOT_STARTED; @@ -490,9 +568,9 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, this->int_status = 0; } if (txbuf) - *txbuf = new_tx_packet; + *txbuf = nt->new_tx_packet; - new_tx_packet = NULL; + nt->new_tx_packet = NULL; out: return EFI_EXIT(ret); } @@ -519,6 +597,7 @@ static efi_status_t EFIAPI efi_net_transmit struct efi_mac_address *dest_addr, u16 *protocol) { efi_status_t ret = EFI_SUCCESS; + struct efi_net_obj *nt; EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this, (unsigned long)header_size, (unsigned long)buffer_size, @@ -532,6 +611,8 @@ static efi_status_t EFIAPI efi_net_transmit goto out; } + nt = efi_netobj_from_snp(this); + /* We do not support jumbo packets */ if (buffer_size > PKTSIZE_ALIGN) { ret = EFI_INVALID_PARAMETER; @@ -576,11 +657,14 @@ static efi_status_t EFIAPI efi_net_transmit break; } + eth_set_dev(nt->dev); + env_set("ethact", eth_get_name()); + /* Ethernet packets always fit, just bounce */ - memcpy(transmit_buffer, buffer, buffer_size); - net_send_packet(transmit_buffer, buffer_size); + memcpy(nt->transmit_buffer, buffer, buffer_size); + net_send_packet(nt->transmit_buffer, buffer_size); - new_tx_packet = buffer; + nt->new_tx_packet = buffer; this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; out: return EFI_EXIT(ret); @@ -611,6 +695,7 @@ static efi_status_t EFIAPI efi_net_receive struct ethernet_hdr *eth_hdr; size_t hdr_size = sizeof(struct ethernet_hdr); u16 protlen; + struct efi_net_obj *nt; EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, buffer_size, buffer, src_addr, dest_addr, protocol); @@ -624,6 +709,8 @@ static efi_status_t EFIAPI efi_net_receive goto out; } + nt = efi_netobj_from_snp(this); + switch (this->mode->state) { case EFI_NETWORK_STOPPED: ret = EFI_NOT_STARTED; @@ -635,16 +722,16 @@ static efi_status_t EFIAPI efi_net_receive break; } - if (!rx_packet_num) { + if (!nt->rx_packet_num) { ret = EFI_NOT_READY; goto out; } /* Fill export parameters */ - eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx]; + eth_hdr = (struct ethernet_hdr *)nt->receive_buffer[nt->rx_packet_idx]; protlen = ntohs(eth_hdr->et_protlen); if (protlen == 0x8100) { hdr_size += 4; - protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]); + protlen = ntohs(*(u16 *)&nt->receive_buffer[nt->rx_packet_idx][hdr_size - 2]); } if (header_size) *header_size = hdr_size; @@ -654,20 +741,20 @@ static efi_status_t EFIAPI efi_net_receive memcpy(src_addr, eth_hdr->et_src, ARP_HLEN); if (protocol) *protocol = protlen; - if (*buffer_size < receive_lengths[rx_packet_idx]) { + if (*buffer_size < nt->receive_lengths[nt->rx_packet_idx]) { /* Packet doesn't fit, try again with bigger buffer */ - *buffer_size = receive_lengths[rx_packet_idx]; + *buffer_size = nt->receive_lengths[nt->rx_packet_idx]; ret = EFI_BUFFER_TOO_SMALL; goto out; } /* Copy packet */ - memcpy(buffer, receive_buffer[rx_packet_idx], - receive_lengths[rx_packet_idx]); - *buffer_size = receive_lengths[rx_packet_idx]; - rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV; - rx_packet_num--; - if (rx_packet_num) - wait_for_packet->is_signaled = true; + memcpy(buffer, nt->receive_buffer[nt->rx_packet_idx], + nt->receive_lengths[nt->rx_packet_idx]); + *buffer_size = nt->receive_lengths[nt->rx_packet_idx]; + nt->rx_packet_idx = (nt->rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV; + nt->rx_packet_num--; + if (nt->rx_packet_num) + nt->wait_for_packet->is_signaled = true; else this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; out: @@ -684,18 +771,35 @@ out: */ void efi_net_set_dhcp_ack(void *pkt, int len) { - int maxsize = sizeof(*dhcp_ack); + struct efi_pxe_packet **dhcp_ack; + struct udevice *dev; + int i; - if (!dhcp_ack) { - dhcp_ack = malloc(maxsize); - if (!dhcp_ack) + dhcp_ack = &dhcp_cache[next_dhcp_entry].dhcp_ack; + + /* For now this function gets called only by the current device */ + dev = eth_get_dev(); + + int maxsize = sizeof(**dhcp_ack); + + if (!*dhcp_ack) { + *dhcp_ack = malloc(maxsize); + if (!*dhcp_ack) return; } - memset(dhcp_ack, 0, maxsize); - memcpy(dhcp_ack, pkt, min(len, maxsize)); + memset(*dhcp_ack, 0, maxsize); + memcpy(*dhcp_ack, pkt, min(len, maxsize)); + + dhcp_cache[next_dhcp_entry].is_valid = true; + dhcp_cache[next_dhcp_entry].dev = dev; + next_dhcp_entry++; + next_dhcp_entry %= MAX_NUM_DHCP_ENTRIES; - if (netobj) - netobj->pxe_mode.dhcp_ack = *dhcp_ack; + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && net_objs[i]->dev == dev) { + net_objs[i]->pxe_mode.dhcp_ack = **dhcp_ack; + } + } } /** @@ -709,6 +813,11 @@ void efi_net_set_dhcp_ack(void *pkt, int len) static void efi_net_push(void *pkt, int len) { int rx_packet_next; + struct efi_net_obj *nt; + + nt = net_objs[curr_efi_net_obj]; + if (!nt) + return; /* Check that we at least received an Ethernet header */ if (len < sizeof(struct ethernet_hdr)) @@ -719,15 +828,15 @@ static void efi_net_push(void *pkt, int len) return; /* Can't store more than pre-alloced buffer */ - if (rx_packet_num >= ETH_PACKETS_BATCH_RECV) + if (nt->rx_packet_num >= ETH_PACKETS_BATCH_RECV) return; - rx_packet_next = (rx_packet_idx + rx_packet_num) % + rx_packet_next = (nt->rx_packet_idx + nt->rx_packet_num) % ETH_PACKETS_BATCH_RECV; - memcpy(receive_buffer[rx_packet_next], pkt, len); - receive_lengths[rx_packet_next] = len; + memcpy(nt->receive_buffer[rx_packet_next], pkt, len); + nt->receive_lengths[rx_packet_next] = len; - rx_packet_num++; + nt->rx_packet_num++; } /** @@ -742,6 +851,7 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event, void *context) { struct efi_simple_network *this = (struct efi_simple_network *)context; + struct efi_net_obj *nt; EFI_ENTRY("%p, %p", event, context); @@ -752,14 +862,19 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event, if (!this || this->mode->state != EFI_NETWORK_INITIALIZED) goto out; - if (!rx_packet_num) { + nt = efi_netobj_from_snp(this); + curr_efi_net_obj = nt->efi_seq_num; + + if (!nt->rx_packet_num) { + eth_set_dev(nt->dev); + env_set("ethact", eth_get_name()); push_packet = efi_net_push; eth_rx(); push_packet = NULL; - if (rx_packet_num) { + if (nt->rx_packet_num) { this->int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; - wait_for_packet->is_signaled = true; + nt->wait_for_packet->is_signaled = true; } } out: @@ -879,30 +994,179 @@ static efi_status_t EFIAPI efi_pxe_base_code_set_packets( } /** + * efi_netobj_set_dp() - set device path of a netobj + * + * @netobj: pointer to efi_net_obj + * @dp: device path to set, allocated by caller + * Return: status code + */ +efi_status_t efi_netobj_set_dp(struct efi_net_obj *netobj, struct efi_device_path *dp) +{ + efi_status_t ret; + struct efi_handler *phandler; + struct efi_device_path *new_net_dp; + + if (!efi_netobj_is_active(netobj)) + return EFI_SUCCESS; + + // Create a device path for the netobj + new_net_dp = dp; + if (!new_net_dp) + return EFI_OUT_OF_RESOURCES; + + phandler = NULL; + efi_search_protocol(&netobj->header, &efi_guid_device_path, &phandler); + + // If the device path protocol is not yet installed, install it + if (!phandler) + goto add; + + // If it is already installed, try to update it + ret = efi_reinstall_protocol_interface(&netobj->header, &efi_guid_device_path, + phandler->protocol_interface, new_net_dp); + if (ret != EFI_SUCCESS) + return ret; + + return EFI_SUCCESS; +add: + ret = efi_add_protocol(&netobj->header, &efi_guid_device_path, + new_net_dp); + if (ret != EFI_SUCCESS) + return ret; + + return EFI_SUCCESS; +} + +/** + * efi_netobj_get_dp() - get device path of a netobj + * + * @netobj: pointer to efi_net_obj + * Return: device path, NULL on error + */ +static struct efi_device_path *efi_netobj_get_dp(struct efi_net_obj *netobj) +{ + struct efi_handler *phandler; + + if (!efi_netobj_is_active(netobj)) + return NULL; + + phandler = NULL; + efi_search_protocol(&netobj->header, &efi_guid_device_path, &phandler); + + if (phandler && phandler->protocol_interface) + return efi_dp_dup(phandler->protocol_interface); + + return NULL; +} + +/** + * efi_net_do_start() - start the efi network stack + * + * This gets called from do_bootefi_exec() each time a payload gets executed. + * + * @dev: net udevice + * Return: status code + */ +efi_status_t efi_net_do_start(struct udevice *dev) +{ + efi_status_t r = EFI_SUCCESS; + struct efi_net_obj *netobj; + struct efi_device_path *net_dp; + int i; + + netobj = NULL; + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && net_objs[i]->dev == dev) { + netobj = net_objs[i]; + break; + } + } + + if (!efi_netobj_is_active(netobj)) + return r; + + efi_net_dp_from_dev(&net_dp, netobj->dev, true); + // If no dp cache entry applies and there already + // is a device path installed, continue + if (!net_dp) { + if (efi_netobj_get_dp(netobj)) + goto set_addr; + else + net_dp = efi_dp_from_eth(netobj->dev); + + } + + if (!net_dp) + return EFI_OUT_OF_RESOURCES; + + r = efi_netobj_set_dp(netobj, net_dp); + if (r != EFI_SUCCESS) + return r; +set_addr: +#ifdef CONFIG_EFI_HTTP_PROTOCOL + /* + * No harm on doing the following. If the PXE handle is present, the client could + * find it and try to get its IP address from it. In here the PXE handle is present + * but the PXE protocol is not yet implmenented, so we add this in the meantime. + */ + efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip, + (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL, dev); +#endif + + return r; +} + +/** * efi_net_register() - register the simple network protocol * * This gets called from do_bootefi_exec(). + * @dev: net udevice */ -efi_status_t efi_net_register(void) +efi_status_t efi_net_register(struct udevice *dev) { efi_status_t r; - int i; - - if (!eth_get_dev()) { + int seq_num; + struct efi_net_obj *netobj; + void *transmit_buffer = NULL; + uchar **receive_buffer = NULL; + size_t *receive_lengths; + int i, j; + + if (!dev) { /* No network device active, don't expose any */ return EFI_SUCCESS; } + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && net_objs[i]->dev == dev) { + // Do not register duplicate devices + return EFI_SUCCESS; + } + } + + seq_num = -1; + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (!net_objs[i]) { + seq_num = i; + break; + } + } + if (seq_num < 0) + return EFI_OUT_OF_RESOURCES; + /* We only expose the "active" network device, so one is enough */ netobj = calloc(1, sizeof(*netobj)); if (!netobj) goto out_of_resources; + netobj->dev = dev; + /* Allocate an aligned transmit buffer */ transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN); if (!transmit_buffer) goto out_of_resources; transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN); + netobj->transmit_buffer = transmit_buffer; /* Allocate a number of receive buffers */ receive_buffer = calloc(ETH_PACKETS_BATCH_RECV, @@ -914,10 +1178,13 @@ efi_status_t efi_net_register(void) if (!receive_buffer[i]) goto out_of_resources; } + netobj->receive_buffer = receive_buffer; + receive_lengths = calloc(ETH_PACKETS_BATCH_RECV, sizeof(*receive_lengths)); if (!receive_lengths) goto out_of_resources; + netobj->receive_lengths = receive_lengths; /* Hook net up to the device list */ efi_add_handle(&netobj->header); @@ -928,14 +1195,6 @@ efi_status_t efi_net_register(void) if (r != EFI_SUCCESS) goto failure_to_add_protocol; - if (net_dp) - r = efi_add_protocol(&netobj->header, &efi_guid_device_path, - net_dp); - else - r = efi_net_set_dp("Net", NULL); - if (r != EFI_SUCCESS) - goto failure_to_add_protocol; - r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid, &netobj->pxe); if (r != EFI_SUCCESS) @@ -956,7 +1215,9 @@ efi_status_t efi_net_register(void) netobj->net.receive = efi_net_receive; netobj->net.mode = &netobj->net_mode; netobj->net_mode.state = EFI_NETWORK_STOPPED; - memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); + if (dev_get_plat(dev)) + memcpy(netobj->net_mode.current_address.mac_addr, + ((struct eth_pdata *)dev_get_plat(dev))->enetaddr, 6); netobj->net_mode.hwaddr_size = ARP_HLEN; netobj->net_mode.media_header_size = ETHER_HDR_SIZE; netobj->net_mode.max_packet_size = PKTSIZE; @@ -976,20 +1237,31 @@ efi_status_t efi_net_register(void) netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip; netobj->pxe.set_packets = efi_pxe_base_code_set_packets; netobj->pxe.mode = &netobj->pxe_mode; - if (dhcp_ack) - netobj->pxe_mode.dhcp_ack = *dhcp_ack; + + /* + * Scan dhcp entries for one corresponding + * to this udevice, from newest to oldest + */ + i = (next_dhcp_entry + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES; + for (j = 0; dhcp_cache[i].is_valid && j < MAX_NUM_DHCP_ENTRIES; + i = (i + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES, j++) { + if (dev == dhcp_cache[i].dev) { + netobj->pxe_mode.dhcp_ack = *dhcp_cache[i].dhcp_ack; + break; + } + } /* * Create WaitForPacket event. */ r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_network_timer_notify, NULL, NULL, - &wait_for_packet); + &netobj->wait_for_packet); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register network event\n"); return r; } - netobj->net.wait_for_packet = wait_for_packet; + netobj->net.wait_for_packet = netobj->wait_for_packet; /* * Create a timer event. * @@ -1000,13 +1272,13 @@ efi_status_t efi_net_register(void) */ r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY, efi_network_timer_notify, &netobj->net, NULL, - &network_timer_event); + &netobj->network_timer_event); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register network event\n"); return r; } /* Network is time critical, create event in every timer cycle */ - r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0); + r = efi_set_timer(netobj->network_timer_event, EFI_TIMER_PERIODIC, 0); if (r != EFI_SUCCESS) { printf("ERROR: Failed to set network timer\n"); return r; @@ -1022,15 +1294,9 @@ efi_status_t efi_net_register(void) r = efi_http_register(&netobj->header, &netobj->http_service_binding); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - /* - * No harm on doing the following. If the PXE handle is present, the client could - * find it and try to get its IP address from it. In here the PXE handle is present - * but the PXE protocol is not yet implmenented, so we add this in the meantime. - */ - efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip, - (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL); #endif - + netobj->efi_seq_num = seq_num; + net_objs[seq_num] = netobj; return EFI_SUCCESS; failure_to_add_protocol: printf("ERROR: Failure to add protocol\n"); @@ -1049,86 +1315,103 @@ out_of_resources: } /** - * efi_net_set_dp() - set device path of efi net device + * efi_net_new_dp() - update device path associated to a net udevice * * This gets called to update the device path when a new boot * file is downloaded * * @dev: dev to set the device path from * @server: remote server address + * @udev: net udevice * Return: status code */ -efi_status_t efi_net_set_dp(const char *dev, const char *server) +efi_status_t efi_net_new_dp(const char *dev, const char *server, struct udevice *udev) { - efi_status_t ret = EFI_SUCCESS; - struct efi_handler *phandler; + efi_status_t ret; + struct efi_net_obj *netobj; struct efi_device_path *old_net_dp, *new_net_dp; + struct efi_device_path **dp; + int i; - old_net_dp = net_dp; + dp = &dp_cache[next_dp_entry].net_dp; + + dp_cache[next_dp_entry].dev = udev; + dp_cache[next_dp_entry].is_valid = true; + next_dp_entry++; + next_dp_entry %= MAX_NUM_DP_ENTRIES; + + old_net_dp = *dp; new_net_dp = NULL; if (!strcmp(dev, "Net")) - new_net_dp = efi_dp_from_eth(); + new_net_dp = efi_dp_from_eth(udev); else if (!strcmp(dev, "Http")) - new_net_dp = efi_dp_from_http(server); - - if (!new_net_dp) { + new_net_dp = efi_dp_from_http(server, udev); + if (!new_net_dp) return EFI_OUT_OF_RESOURCES; - } - - // If netobj is not started yet, end here. - if (!netobj) { - goto exit; - } - - phandler = NULL; - efi_search_protocol(&netobj->header, &efi_guid_device_path, &phandler); - // If the device path protocol is not yet installed, install it - if (!phandler) - goto add; - - // If it is already installed, try to update it - ret = efi_reinstall_protocol_interface(&netobj->header, &efi_guid_device_path, - old_net_dp, new_net_dp); - if (ret != EFI_SUCCESS) - goto error; - - net_dp = new_net_dp; + *dp = new_net_dp; + // Free the old cache entry efi_free_pool(old_net_dp); - return EFI_SUCCESS; -add: - ret = efi_add_protocol(&netobj->header, &efi_guid_device_path, - new_net_dp); - if (ret != EFI_SUCCESS) - goto error; -exit: - net_dp = new_net_dp; - efi_free_pool(old_net_dp); + netobj = NULL; + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && net_objs[i]->dev == udev) { + netobj = net_objs[i]; + break; + } + } + if (!netobj) + return EFI_SUCCESS; - return ret; -error: - // Failed, restore - efi_free_pool(new_net_dp); + new_net_dp = efi_dp_dup(*dp); + if (!new_net_dp) + return EFI_OUT_OF_RESOURCES; + ret = efi_netobj_set_dp(netobj, new_net_dp); + if (ret != EFI_SUCCESS) + efi_free_pool(new_net_dp); return ret; } /** - * efi_net_get_dp() - get device path of efi net device + * efi_net_dp_from_dev() - get device path associated to a net udevice * * Produce a copy of the current device path * - * @dp: copy of the current device path, or NULL on error + * @dp: copy of the current device path + * @udev: net udevice + * @cache_only: get device path from cache only */ -void efi_net_get_dp(struct efi_device_path **dp) +void efi_net_dp_from_dev(struct efi_device_path **dp, struct udevice *udev, bool cache_only) { + int i, j; + if (!dp) return; - if (!net_dp) - efi_net_set_dp("Net", NULL); - if (net_dp) - *dp = efi_dp_dup(net_dp); + + *dp = NULL; + + if (cache_only) + goto cache; + + // If a netobj matches: + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && net_objs[i]->dev == udev) { + *dp = efi_netobj_get_dp(net_objs[i]); + if (*dp) + return; + } + } +cache: + // Search in the cache + i = (next_dp_entry + MAX_NUM_DP_ENTRIES - 1) % MAX_NUM_DP_ENTRIES; + for (j = 0; dp_cache[i].is_valid && j < MAX_NUM_DP_ENTRIES; + i = (i + MAX_NUM_DP_ENTRIES - 1) % MAX_NUM_DP_ENTRIES, j++) { + if (dp_cache[i].dev == udev) { + *dp = efi_dp_dup(dp_cache[i].net_dp); + return; + } + } } /** @@ -1144,11 +1427,15 @@ void efi_net_get_dp(struct efi_device_path **dp) * be filled with the current network mask * @gw: pointer to an efi_ipv4_address struct to be * filled with the current network gateway + * @dev: udevice */ void efi_net_get_addr(struct efi_ipv4_address *ip, struct efi_ipv4_address *mask, - struct efi_ipv4_address *gw) + struct efi_ipv4_address *gw, + struct udevice *dev) { + if (!dev) + dev = eth_get_dev(); #ifdef CONFIG_NET_LWIP char ipstr[] = "ipaddr\0\0"; char maskstr[] = "netmask\0\0"; @@ -1157,7 +1444,7 @@ void efi_net_get_addr(struct efi_ipv4_address *ip, struct in_addr tmp; char *env; - idx = dev_seq(eth_get_dev()); + idx = dev_seq(dev); if (idx < 0 || idx > 99) { log_err("unexpected idx %d\n", idx); @@ -1204,11 +1491,15 @@ void efi_net_get_addr(struct efi_ipv4_address *ip, * @ip: pointer to new IP address * @mask: pointer to new network mask to set * @gw: pointer to new network gateway + * @dev: udevice */ void efi_net_set_addr(struct efi_ipv4_address *ip, struct efi_ipv4_address *mask, - struct efi_ipv4_address *gw) + struct efi_ipv4_address *gw, + struct udevice *dev) { + if (!dev) + dev = eth_get_dev(); #ifdef CONFIG_NET_LWIP char ipstr[] = "ipaddr\0\0"; char maskstr[] = "netmask\0\0"; @@ -1217,7 +1508,7 @@ void efi_net_set_addr(struct efi_ipv4_address *ip, struct in_addr *addr; char tmp[46]; - idx = dev_seq(eth_get_dev()); + idx = dev_seq(dev); if (idx < 0 || idx > 99) { log_err("unexpected idx %d\n", idx); @@ -1255,6 +1546,7 @@ void efi_net_set_addr(struct efi_ipv4_address *ip, #endif } +#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL) /** * efi_net_set_buffer() - allocate a buffer of min 64K * @@ -1342,26 +1634,41 @@ void efi_net_parse_headers(ulong *num_headers, struct http_header *headers) * @status_code: HTTP status code * @file_size: file size in bytes * @headers_buffer: headers buffer + * @parent: service binding protocol * Return: status code */ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buffer, - u32 *status_code, ulong *file_size, char *headers_buffer) + u32 *status_code, ulong *file_size, char *headers_buffer, + struct efi_service_binding_protocol *parent) { efi_status_t ret = EFI_SUCCESS; int wget_ret; static bool last_head; + struct udevice *dev; + int i; - if (!buffer || !file_size) + if (!buffer || !file_size || !parent) return EFI_ABORTED; efi_wget_info.method = (enum wget_http_method)method; efi_wget_info.headers = headers_buffer; + // Set corresponding udevice + dev = NULL; + for (i = 0; i < MAX_EFI_NET_OBJS; i++) { + if (net_objs[i] && &net_objs[i]->http_service_binding == parent) + dev = net_objs[i]->dev; + } + if (!dev) + return EFI_ABORTED; + switch (method) { case HTTP_METHOD_GET: ret = efi_net_set_buffer(buffer, last_head ? (size_t)efi_wget_info.hdr_cont_len : 0); if (ret != EFI_SUCCESS) goto out; + eth_set_dev(dev); + env_set("ethact", eth_get_name()); wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info); if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) { // Try again with updated buffer size @@ -1369,6 +1676,8 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf ret = efi_net_set_buffer(buffer, (size_t)efi_wget_info.hdr_cont_len); if (ret != EFI_SUCCESS) goto out; + eth_set_dev(dev); + env_set("ethact", eth_get_name()); if (wget_request((ulong)*buffer, url, &efi_wget_info)) { efi_free_pool(*buffer); ret = EFI_DEVICE_ERROR; @@ -1388,6 +1697,8 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf ret = efi_net_set_buffer(buffer, 0); if (ret != EFI_SUCCESS) goto out; + eth_set_dev(dev); + env_set("ethact", eth_get_name()); wget_request((ulong)*buffer, url, &efi_wget_info); *file_size = 0; *status_code = efi_wget_info.status_code; @@ -1401,3 +1712,4 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buf out: return ret; } +#endif diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index aa59bc7779d..48f91da5df7 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -11,7 +11,9 @@ #include <efi_variable.h> #include <log.h> #include <asm-generic/unaligned.h> +#include <net.h> +#define OBJ_LIST_INITIALIZED 0 #define OBJ_LIST_NOT_INITIALIZED 1 efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED; @@ -209,6 +211,21 @@ out: } /** + * efi_start_obj_list() - Start EFI object list + * + * Return: status code + */ +static efi_status_t efi_start_obj_list(void) +{ + efi_status_t ret = EFI_SUCCESS; + + if (IS_ENABLED(CONFIG_NETDEVICES)) + ret = efi_net_do_start(eth_get_dev()); + + return ret; +} + +/** * efi_init_obj_list() - Initialize and populate EFI object list * * Return: status code @@ -217,7 +234,9 @@ efi_status_t efi_init_obj_list(void) { efi_status_t ret = EFI_SUCCESS; - /* Initialize once only */ + /* Initialize only once, but start every time if correctly initialized*/ + if (efi_obj_list_initialized == OBJ_LIST_INITIALIZED) + return efi_start_obj_list(); if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) return efi_obj_list_initialized; @@ -318,7 +337,7 @@ efi_status_t efi_init_obj_list(void) goto out; } if (IS_ENABLED(CONFIG_NETDEVICES)) { - ret = efi_net_register(); + ret = efi_net_register(eth_get_dev()); if (ret != EFI_SUCCESS) goto out; } @@ -349,6 +368,10 @@ efi_status_t efi_init_obj_list(void) if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) && !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) ret = efi_launch_capsules(); + if (ret != EFI_SUCCESS) + goto out; + + ret = efi_start_obj_list(); out: efi_obj_list_initialized = ret; return ret; diff --git a/lib/efi_loader/elf_efi.ldsi b/lib/efi_loader/elf_efi.ldsi index 190a88fb69e..4fa5ca43872 100644 --- a/lib/efi_loader/elf_efi.ldsi +++ b/lib/efi_loader/elf_efi.ldsi @@ -21,10 +21,10 @@ SECTIONS *(.gnu.linkonce.t.*) *(.srodata) *(.rodata*) - . = ALIGN(16); - *(.dynamic); - . = ALIGN(512); } + . = ALIGN(16); + .dynamic : { *(.dynamic) } + . = ALIGN(512); .rela.dyn : { *(.rela.dyn) } .rela.plt : { *(.rela.plt) } .rela.got : { *(.rela.got) } diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c index 15af8d3e18c..b00c76c2f17 100644 --- a/lib/efi_selftest/efi_selftest_snp.c +++ b/lib/efi_selftest/efi_selftest_snp.c @@ -67,7 +67,6 @@ struct dhcp { static struct efi_boot_services *boottime; static struct efi_simple_network *net; static struct efi_event *timer; -static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; /* IP packet ID */ static unsigned int net_ip_id; diff --git a/lib/lmb.c b/lib/lmb.c index 93fc1bea07c..bb6f232f6bc 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -23,6 +23,9 @@ DECLARE_GLOBAL_DATA_PTR; +#define LMB_RGN_OVERLAP 1 +#define LMB_RGN_ADJACENT 2 + /* * The following low level LMB functions must not access the global LMB memory * map since they are also used to manage IOVA memory maps in iommu drivers like @@ -49,8 +52,22 @@ static long lmb_addrs_adjacent(phys_addr_t base1, phys_size_t size1, return 0; } -static long lmb_regions_overlap(struct alist *lmb_rgn_lst, unsigned long r1, - unsigned long r2) +/** + * lmb_regions_check() - Check if the regions overlap, or are adjacent + * @lmb_rgn_lst: List of LMB regions + * @r1: First region to check + * @r2: Second region to check + * + * Check if the two regions with matching flags, r1 and r2 are + * adjacent to each other, or if they overlap. + * + * Return: + * * %LMB_RGN_OVERLAP - Regions overlap + * * %LMB_RGN_ADJACENT - Regions adjacent to each other + * * 0 - Neither of the above, or flags mismatch + */ +static long lmb_regions_check(struct alist *lmb_rgn_lst, unsigned long r1, + unsigned long r2) { struct lmb_region *rgn = lmb_rgn_lst->data; phys_addr_t base1 = rgn[r1].base; @@ -58,19 +75,15 @@ static long lmb_regions_overlap(struct alist *lmb_rgn_lst, unsigned long r1, phys_addr_t base2 = rgn[r2].base; phys_size_t size2 = rgn[r2].size; - return lmb_addrs_overlap(base1, size1, base2, size2); -} + if (rgn[r1].flags != rgn[r2].flags) + return 0; -static long lmb_regions_adjacent(struct alist *lmb_rgn_lst, unsigned long r1, - unsigned long r2) -{ - struct lmb_region *rgn = lmb_rgn_lst->data; - phys_addr_t base1 = rgn[r1].base; - phys_size_t size1 = rgn[r1].size; - phys_addr_t base2 = rgn[r2].base; - phys_size_t size2 = rgn[r2].size; + if (lmb_addrs_overlap(base1, size1, base2, size2)) + return LMB_RGN_OVERLAP; + else if (lmb_addrs_adjacent(base1, size1, base2, size2)) + return LMB_RGN_ADJACENT; - return lmb_addrs_adjacent(base1, size1, base2, size2); + return 0; } static void lmb_remove_region(struct alist *lmb_rgn_lst, unsigned long r) @@ -96,25 +109,6 @@ static void lmb_coalesce_regions(struct alist *lmb_rgn_lst, unsigned long r1, lmb_remove_region(lmb_rgn_lst, r2); } -/*Assumption : base addr of region 1 < base addr of region 2*/ -static void lmb_fix_over_lap_regions(struct alist *lmb_rgn_lst, - unsigned long r1, unsigned long r2) -{ - struct lmb_region *rgn = lmb_rgn_lst->data; - - phys_addr_t base1 = rgn[r1].base; - phys_size_t size1 = rgn[r1].size; - phys_addr_t base2 = rgn[r2].base; - phys_size_t size2 = rgn[r2].size; - - if (base1 + size1 > base2 + size2) { - printf("This will not be a case any time\n"); - return; - } - rgn[r1].size = base2 + size2 - base1; - lmb_remove_region(lmb_rgn_lst, r2); -} - static long lmb_resize_regions(struct alist *lmb_rgn_lst, unsigned long idx_start, phys_addr_t base, phys_size_t size) @@ -209,14 +203,11 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, break; } else if (ret < 0) { if (flags != rgnflags) - break; + continue; rgn[i].size += size; coalesced++; break; } else if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) { - if (flags != LMB_NONE) - return -EEXIST; - ret = lmb_resize_regions(lmb_rgn_lst, i, base, size); if (ret < 0) return -1; @@ -229,16 +220,21 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, } if (lmb_rgn_lst->count && i < lmb_rgn_lst->count - 1) { - rgn = lmb_rgn_lst->data; - if (rgn[i].flags == rgn[i + 1].flags) { - if (lmb_regions_adjacent(lmb_rgn_lst, i, i + 1)) { - lmb_coalesce_regions(lmb_rgn_lst, i, i + 1); - coalesced++; - } else if (lmb_regions_overlap(lmb_rgn_lst, i, i + 1)) { - /* fix overlapping area */ - lmb_fix_over_lap_regions(lmb_rgn_lst, i, i + 1); - coalesced++; - } + ret = lmb_regions_check(lmb_rgn_lst, i, i + 1); + if (ret == LMB_RGN_ADJACENT) { + lmb_coalesce_regions(lmb_rgn_lst, i, i + 1); + coalesced++; + } else if (ret == LMB_RGN_OVERLAP) { + /* fix overlapping areas */ + phys_addr_t rgnbase = rgn[i].base; + phys_size_t rgnsize = rgn[i].size; + + ret = lmb_resize_regions(lmb_rgn_lst, i, + rgnbase, rgnsize); + if (ret < 0) + return -1; + + coalesced++; } } @@ -561,6 +557,39 @@ static __maybe_unused void lmb_reserve_common_spl(void) } } +/** + * lmb_can_reserve_region() - check if the region can be reserved + * @base: base address of region to be reserved + * @size: size of region to be reserved + * @flags: flag of the region to be reserved + * + * Go through all the reserved regions and ensure that the requested + * region does not overlap with any existing regions. An overlap is + * allowed only when the flag of the request region and the existing + * region is LMB_NONE. + * + * Return: true if region can be reserved, false otherwise + */ +static bool lmb_can_reserve_region(phys_addr_t base, phys_size_t size, + u32 flags) +{ + uint i; + struct lmb_region *lmb_reserved = lmb.used_mem.data; + + for (i = 0; i < lmb.used_mem.count; i++) { + u32 rgnflags = lmb_reserved[i].flags; + phys_addr_t rgnbase = lmb_reserved[i].base; + phys_size_t rgnsize = lmb_reserved[i].size; + + if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) { + if (flags != LMB_NONE || flags != rgnflags) + return false; + } + } + + return true; +} + void lmb_add_memory(void) { int i; @@ -633,6 +662,9 @@ long lmb_reserve(phys_addr_t base, phys_size_t size, u32 flags) long ret = 0; struct alist *lmb_rgn_lst = &lmb.used_mem; + if (!lmb_can_reserve_region(base, size, flags)) + return -EEXIST; + ret = lmb_add_region_flags(lmb_rgn_lst, base, size, flags); if (ret) return ret; @@ -692,29 +724,25 @@ static phys_addr_t _lmb_alloc_base(phys_size_t size, ulong align, base = ALIGN_DOWN(res_base - size, align); } } + + log_debug("%s: Failed to allocate 0x%lx bytes below 0x%lx\n", + __func__, (ulong)size, (ulong)max_addr); + return 0; } phys_addr_t lmb_alloc(phys_size_t size, ulong align) { - return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE, LMB_NONE); + return _lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE, LMB_NONE); } phys_addr_t lmb_alloc_base(phys_size_t size, ulong align, phys_addr_t max_addr, uint flags) { - phys_addr_t alloc; - - alloc = _lmb_alloc_base(size, align, max_addr, flags); - - if (alloc == 0) - printf("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n", - (ulong)size, (ulong)max_addr); - - return alloc; + return _lmb_alloc_base(size, align, max_addr, flags); } -phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size, u32 flags) +int lmb_alloc_addr(phys_addr_t base, phys_size_t size, u32 flags) { long rgn; struct lmb_region *lmb_memory = lmb.available_mem.data; @@ -731,11 +759,11 @@ phys_addr_t lmb_alloc_addr(phys_addr_t base, phys_size_t size, u32 flags) base + size - 1, 1)) { /* ok, reserve the memory */ if (!lmb_reserve(base, size, flags)) - return base; + return 0; } } - return 0; + return -1; } /* Return number of bytes from a given address that are free */ diff --git a/lib/lwip/lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c b/lib/lwip/lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c index 46421588fef..ef51a5ac168 100644 --- a/lib/lwip/lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c +++ b/lib/lwip/lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c @@ -298,6 +298,9 @@ altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t * if (ret != 0) { LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret)); /* handshake failed, connection has to be closed */ + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + printf("Certificate verification failed\n"); + } if (conn->err) { conn->err(conn->arg, ERR_CLSD); } @@ -786,6 +789,7 @@ altcp_tls_create_config(int is_server, u8_t cert_count, u8_t pkey_count, int hav int ret; struct altcp_tls_config *conf; mbedtls_x509_crt *mem; + int authmode = have_ca ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE; if (TCP_WND < MBEDTLS_SSL_IN_CONTENT_LEN || TCP_WND < MBEDTLS_SSL_OUT_CONTENT_LEN) { LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG|LWIP_DBG_LEVEL_SERIOUS, @@ -840,7 +844,10 @@ altcp_tls_create_config(int is_server, u8_t cert_count, u8_t pkey_count, int hav altcp_mbedtls_free_config(conf); return NULL; } - mbedtls_ssl_conf_authmode(&conf->conf, ALTCP_MBEDTLS_AUTHMODE); + if (authmode == MBEDTLS_SSL_VERIFY_NONE) { + printf("WARNING: no CA certificates, HTTPS connections not authenticated\n"); + } + mbedtls_ssl_conf_authmode(&conf->conf, authmode); mbedtls_ssl_conf_rng(&conf->conf, mbedtls_ctr_drbg_random, &altcp_tls_entropy_rng->ctr_drbg); #if ALTCP_MBEDTLS_LIB_DEBUG != LWIP_DBG_OFF diff --git a/lib/lwip/lwip/src/include/lwip/apps/altcp_tls_mbedtls_opts.h b/lib/lwip/lwip/src/include/lwip/apps/altcp_tls_mbedtls_opts.h index e41301c061c..71aa5993935 100644 --- a/lib/lwip/lwip/src/include/lwip/apps/altcp_tls_mbedtls_opts.h +++ b/lib/lwip/lwip/src/include/lwip/apps/altcp_tls_mbedtls_opts.h @@ -100,12 +100,6 @@ #define ALTCP_MBEDTLS_SESSION_TICKET_TIMEOUT_SECONDS (60 * 60 * 24) #endif -/** Certificate verification mode: MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL (default), - * MBEDTLS_SSL_VERIFY_REQUIRED (recommended)*/ -#ifndef ALTCP_MBEDTLS_AUTHMODE -#define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_OPTIONAL -#endif - #endif /* LWIP_ALTCP */ #endif /* LWIP_HDR_ALTCP_TLS_OPTS_H */ diff --git a/lib/mbedtls/pkcs7_parser.c b/lib/mbedtls/pkcs7_parser.c index ecfcc46edfa..bf8ee17b5b8 100644 --- a/lib/mbedtls/pkcs7_parser.c +++ b/lib/mbedtls/pkcs7_parser.c @@ -189,10 +189,6 @@ static int authattrs_parse(struct pkcs7_message *msg, void *aa, size_t aa_len, len)) { if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) return -EINVAL; - - if (msg->data_type != OID_msIndirectData && - msg->data_type != OID_data) - return -EINVAL; } else if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_MICROSOFT_SPOPUSINFO, inner_p, len)) { if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) diff --git a/lib/membuff.c b/lib/membuf.c index b242a38ff1c..f38ff36cb0b 100644 --- a/lib/membuff.c +++ b/lib/membuf.c @@ -9,17 +9,17 @@ #include <errno.h> #include <log.h> #include <malloc.h> -#include "membuff.h" +#include "membuf.h" -void membuff_purge(struct membuff *mb) +void membuf_purge(struct membuf *mb) { /* set mb->head and mb->tail so the buffers look empty */ mb->head = mb->start; mb->tail = mb->start; } -static int membuff_putrawflex(struct membuff *mb, int maxlen, bool update, - char ***data, int *offsetp) +static int membuf_putrawflex(struct membuf *mb, int maxlen, bool update, + char ***data, int *offsetp) { int len; @@ -72,30 +72,30 @@ static int membuff_putrawflex(struct membuff *mb, int maxlen, bool update, return len; } -int membuff_putraw(struct membuff *mb, int maxlen, bool update, char **data) +int membuf_putraw(struct membuf *mb, int maxlen, bool update, char **data) { char **datap; int offset; int size; - size = membuff_putrawflex(mb, maxlen, update, &datap, &offset); + size = membuf_putrawflex(mb, maxlen, update, &datap, &offset); *data = *datap + offset; return size; } -bool membuff_putbyte(struct membuff *mb, int ch) +bool membuf_putbyte(struct membuf *mb, int ch) { char *data; - if (membuff_putraw(mb, 1, true, &data) != 1) + if (membuf_putraw(mb, 1, true, &data) != 1) return false; *data = ch; return true; } -int membuff_getraw(struct membuff *mb, int maxlen, bool update, char **data) +int membuf_getraw(struct membuf *mb, int maxlen, bool update, char **data) { int len; @@ -146,21 +146,21 @@ int membuff_getraw(struct membuff *mb, int maxlen, bool update, char **data) return len; } -int membuff_getbyte(struct membuff *mb) +int membuf_getbyte(struct membuf *mb) { char *data = 0; - return membuff_getraw(mb, 1, true, &data) != 1 ? -1 : *(uint8_t *)data; + return membuf_getraw(mb, 1, true, &data) != 1 ? -1 : *(uint8_t *)data; } -int membuff_peekbyte(struct membuff *mb) +int membuf_peekbyte(struct membuf *mb) { char *data = 0; - return membuff_getraw(mb, 1, false, &data) != 1 ? -1 : *(uint8_t *)data; + return membuf_getraw(mb, 1, false, &data) != 1 ? -1 : *(uint8_t *)data; } -int membuff_get(struct membuff *mb, char *buff, int maxlen) +int membuf_get(struct membuf *mb, char *buff, int maxlen) { char *data = 0, *buffptr = buff; int len = 1, i; @@ -171,7 +171,7 @@ int membuff_get(struct membuff *mb, char *buff, int maxlen) */ for (i = 0; len && i < 2; i++) { /* get a pointer to the data available */ - len = membuff_getraw(mb, maxlen, true, &data); + len = membuf_getraw(mb, maxlen, true, &data); /* copy it into the buffer */ memcpy(buffptr, data, len); @@ -183,14 +183,14 @@ int membuff_get(struct membuff *mb, char *buff, int maxlen) return buffptr - buff; } -int membuff_put(struct membuff *mb, const char *buff, int length) +int membuf_put(struct membuf *mb, const char *buff, int length) { char *data; int towrite, i, written; for (i = written = 0; i < 2; i++) { /* ask where some data can be written */ - towrite = membuff_putraw(mb, length, true, &data); + towrite = membuf_putraw(mb, length, true, &data); /* and write it, updating the bytes length */ memcpy(data, buff, towrite); @@ -203,14 +203,14 @@ int membuff_put(struct membuff *mb, const char *buff, int length) return written; } -bool membuff_isempty(struct membuff *mb) +bool membuf_isempty(struct membuf *mb) { return mb->head == mb->tail; } -int membuff_avail(struct membuff *mb) +int membuf_avail(struct membuf *mb) { - struct membuff copy; + struct membuf copy; int i, avail; char *data = 0; @@ -219,18 +219,18 @@ int membuff_avail(struct membuff *mb) /* now read everything out of the copied buffer */ for (i = avail = 0; i < 2; i++) - avail += membuff_getraw(©, -1, true, &data); + avail += membuf_getraw(©, -1, true, &data); /* and return how much we read */ return avail; } -int membuff_size(struct membuff *mb) +int membuf_size(struct membuf *mb) { return mb->end - mb->start; } -bool membuff_makecontig(struct membuff *mb) +bool membuf_makecontig(struct membuf *mb) { int topsize, botsize; @@ -281,13 +281,14 @@ bool membuff_makecontig(struct membuff *mb) return true; } -int membuff_free(struct membuff *mb) +int membuf_free(struct membuf *mb) { return mb->end == mb->start ? 0 : - (mb->end - mb->start) - 1 - membuff_avail(mb); + (mb->end - mb->start) - 1 - membuf_avail(mb); } -int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch, bool must_fit) +int membuf_readline(struct membuf *mb, char *str, int maxlen, int minch, + bool must_fit) { int len; /* number of bytes read (!= string length) */ char *s, *end; @@ -322,7 +323,7 @@ int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch, bool return len; } -int membuff_extend_by(struct membuff *mb, int by, int max) +int membuf_extend_by(struct membuf *mb, int by, int max) { int oldhead, oldtail; int size, orig; @@ -358,32 +359,32 @@ int membuff_extend_by(struct membuff *mb, int by, int max) return 0; } -void membuff_init(struct membuff *mb, char *buff, int size) +void membuf_init(struct membuf *mb, char *buff, int size) { mb->start = buff; mb->end = mb->start + size; - membuff_purge(mb); + membuf_purge(mb); } -int membuff_new(struct membuff *mb, int size) +int membuf_new(struct membuf *mb, int size) { mb->start = malloc(size); if (!mb->start) return -ENOMEM; - membuff_init(mb, mb->start, size); + membuf_init(mb, mb->start, size); return 0; } -void membuff_uninit(struct membuff *mb) +void membuf_uninit(struct membuf *mb) { mb->end = NULL; mb->start = NULL; - membuff_purge(mb); + membuf_purge(mb); } -void membuff_dispose(struct membuff *mb) +void membuf_dispose(struct membuf *mb) { - free(&mb->start); - membuff_uninit(mb); + free(mb->start); + membuf_uninit(mb); } diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index d3b4f71d6be..4a0418a75f1 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -449,6 +449,11 @@ static int rsa_verify_with_keynode(struct image_sign_info *info, } algo = fdt_getprop(blob, node, "algo", NULL); + if (!algo) { + debug("%s: Missing 'algo' property\n", __func__); + return -EFAULT; + } + if (strcmp(info->name, algo)) { debug("%s: Wrong algo: have %s, expected %s\n", __func__, info->name, algo); @@ -565,6 +570,11 @@ int rsa_verify(struct image_sign_info *info, uint8_t hash[info->crypto->key_len]; int ret; +#ifdef USE_HOSTCC + if (!info->fdt_blob) + return rsa_verify_openssl(info, region, region_count, sig, sig_len); +#endif + /* * Verify that the checksum-length does not exceed the * rsa-signature-length diff --git a/lib/smbios.c b/lib/smbios.c index 78cee8c0c26..7c9701a57f9 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -429,6 +429,8 @@ static int smbios_write_type1(ulong *current, int handle, struct smbios_type1 *t; int len = sizeof(*t); char *serial_str = env_get("serial#"); + size_t uuid_len; + void *uuid; t = map_sysmem(*current, len); memset(t, 0, len); @@ -450,6 +452,10 @@ static int smbios_write_type1(ulong *current, int handle, SYSID_SM_SYSTEM_SERIAL, NULL); } + if (!sysinfo_get_data(ctx->dev, SYSID_SM_SYSTEM_UUID, &uuid, + &uuid_len) && + uuid_len == sizeof(t->uuid)) + memcpy(t->uuid, uuid, sizeof(t->uuid)); t->wakeup_type = smbios_get_val_si(ctx, "wakeup-type", SYSID_SM_SYSTEM_WAKEUP, SMBIOS_WAKEUP_TYPE_UNKNOWN); diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index 0503c17341f..2a7a4d286c0 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -211,6 +211,7 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va) bool lz = false; int width = 0; bool islong = false; + bool force_char = false; ch = *(fmt++); if (ch == '-') @@ -282,8 +283,9 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va) break; } islong = true; - /* no break */ + fallthrough; case 'x': + case 'X': if (islong) { num = va_arg(va, unsigned long); div = 1UL << (sizeof(long) * 8 - 4); @@ -300,6 +302,8 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va) break; case 'c': out(info, (char)(va_arg(va, int))); + /* For the case when it's \0 char */ + force_char = true; break; case 's': p = va_arg(va, char*); @@ -317,8 +321,10 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va) while (width-- > 0) info->putc(info, lz ? '0' : ' '); if (p) { - while ((ch = *p++)) + while ((ch = *p++) || force_char) { info->putc(info, ch); + force_char = false; + } } } } diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c index b4c72cc2c5c..2b7a464f74f 100644 --- a/lib/zlib/inflate.c +++ b/lib/zlib/inflate.c @@ -420,6 +420,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; + fallthrough; case TIME: NEEDBITS(32); if (state->head != Z_NULL) @@ -427,6 +428,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; + fallthrough; case OS: NEEDBITS(16); if (state->head != Z_NULL) { @@ -436,6 +438,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; + fallthrough; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); @@ -448,6 +451,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; + fallthrough; case EXTRA: if (state->flags & 0x0400) { copy = state->length; @@ -471,6 +475,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } state->length = 0; state->mode = NAME; + fallthrough; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; @@ -492,6 +497,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; + fallthrough; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; @@ -512,6 +518,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; + fallthrough; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); @@ -535,6 +542,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) strm->adler = state->check = REVERSE(hold); INITBITS(); state->mode = DICT; + fallthrough; case DICT: if (state->havedict == 0) { RESTORE(); @@ -542,9 +550,11 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; + fallthrough; case TYPE: schedule(); if (flush == Z_BLOCK) goto inf_leave; + fallthrough; case TYPEDO: if (state->last) { BYTEBITS(); @@ -590,6 +600,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) state->length)); INITBITS(); state->mode = COPY; + fallthrough; case COPY: copy = state->length; if (copy) { @@ -625,6 +636,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; + fallthrough; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); @@ -646,6 +658,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; + fallthrough; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { @@ -720,6 +733,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; + fallthrough; case LEN: schedule(); if (have >= 6 && left >= 258) { @@ -764,6 +778,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } state->extra = (unsigned)(this.op) & 15; state->mode = LENEXT; + fallthrough; case LENEXT: if (state->extra) { NEEDBITS(state->extra); @@ -772,6 +787,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } Tracevv((stderr, "inflate: length %u\n", state->length)); state->mode = DIST; + fallthrough; case DIST: for (;;) { this = state->distcode[BITS(state->distbits)]; @@ -797,6 +813,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) state->offset = (unsigned)this.val; state->extra = (unsigned)(this.op) & 15; state->mode = DISTEXT; + fallthrough; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); @@ -817,6 +834,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; + fallthrough; case MATCH: if (left == 0) goto inf_leave; copy = out - left; @@ -872,6 +890,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } #ifdef GUNZIP state->mode = LENGTH; + fallthrough; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); @@ -885,6 +904,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) } #endif state->mode = DONE; + fallthrough; case DONE: ret = Z_STREAM_END; goto inf_leave; @@ -894,6 +914,7 @@ __rcode int ZEXPORT inflate(z_streamp strm, int flush) case MEM: return Z_MEM_ERROR; case SYNC: + fallthrough; default: return Z_STREAM_ERROR; } |