diff options
Diffstat (limited to 'lib')
30 files changed, 1907 insertions, 58 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 56ffdfa1839..0b089814d14 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -45,6 +45,15 @@ config BINMAN_FDT locate entries in the firmware image. See binman.h for the available functionality. +config BINMAN_DTB + string "binman DTB description" + depends on BINMAN + help + This enables option to point to different DTB file with binman node which + is outside of DTB used by the firmware. Use this option if information + about generated images shouldn't be the part of target binary. Or on system + with limited storage. + config CC_OPTIMIZE_LIBS_FOR_SPEED bool "Optimize libraries for speed" help diff --git a/lib/Makefile b/lib/Makefile index dbcfa87ebd6..d24ed629732 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -97,7 +97,7 @@ obj-$(CONFIG_LIBAVB) += libavb/ obj-$(CONFIG_$(PHASE_)OF_LIBFDT) += libfdt/ obj-$(CONFIG_$(PHASE_)OF_REAL) += fdtdec_common.o fdtdec.o -obj-$(CONFIG_MBEDTLS_LIB) += mbedtls/ +obj-$(CONFIG_$(XPL_)MBEDTLS_LIB) += mbedtls/ obj-$(CONFIG_NET_LWIP) += lwip/ diff --git a/lib/binman.c b/lib/binman.c index 93d85548116..9047f5275f3 100644 --- a/lib/binman.c +++ b/lib/binman.c @@ -137,7 +137,6 @@ int binman_init(void) { int ret; - return 0; binman = malloc(sizeof(struct binman_info)); if (!binman) return log_msg_ret("space for binman", -ENOMEM); diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index d93f28b8422..c46ffe3a9d8 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -2,7 +2,7 @@ menu "UEFI Support" config EFI_LOADER bool "Support running UEFI applications" - depends on OF_LIBFDT && ( \ + depends on ( \ ARM && (SYS_CPU = arm1136 || \ SYS_CPU = arm1176 || \ SYS_CPU = armv7 || \ @@ -21,6 +21,7 @@ config EFI_LOADER select EVENT_DYNAMIC select LIB_UUID select LMB + select OF_LIBFDT imply PARTITION_UUIDS select REGEX imply FAT @@ -476,6 +477,23 @@ config EFI_RISCV_BOOT_PROTOCOL replace the transfer via the device-tree. The latter is not possible on systems using ACPI. +config EFI_IP4_CONFIG2_PROTOCOL + bool "EFI_IP4_CONFIG2_PROTOCOL support" + default y if ARCH_QEMU || SANDBOX + depends on NET || NET_LWIP + help + Provides an implementation of the EFI_IP4_CONFIG2_PROTOCOL, this + protocol can be used to set and get the current ip address and + other network information. + +config EFI_HTTP_PROTOCOL + bool "EFI_HTTP_PROTOCOL support" + default y if ARCH_QEMU || SANDBOX + depends on WGET + help + Provides an EFI HTTP driver implementing the EFI_HTTP_PROTOCOL. and + EFI_HTTP_SERVICE_BINDING_PROTOCOL. + endmenu menu "Misc options" diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 87131ab911d..2a0b4172bd7 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -59,6 +59,8 @@ obj-$(CONFIG_EFI_ESRT) += efi_esrt.o obj-$(CONFIG_VIDEO) += efi_gop.o obj-$(CONFIG_BLK) += efi_disk.o obj-$(CONFIG_NETDEVICES) += efi_net.o +obj-$(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) += efi_ipconfig.o +obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_http.o obj-$(CONFIG_ACPI) += efi_acpi.o obj-$(CONFIG_SMBIOS) += efi_smbios.o obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c index a87006b3c0e..b677bbc3124 100644 --- a/lib/efi_loader/efi_bootbin.c +++ b/lib/efi_loader/efi_bootbin.c @@ -93,24 +93,34 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path, image_addr = buffer; image_size = buffer_size; +#if IS_ENABLED(CONFIG_NETDEVICES) + if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) { + ret = efi_net_set_dp(dev, devnr); + if (ret != EFI_SUCCESS) + goto error; + } +#endif + ret = efi_dp_from_name(dev, devnr, path, &device, &image); - if (ret == EFI_SUCCESS) { - bootefi_device_path = device; - if (image) { - /* FIXME: image should not contain device */ - struct efi_device_path *image_tmp = image; - - efi_dp_split_file_path(image, &device, &image); - efi_free_pool(image_tmp); - } - bootefi_image_path = image; - log_debug("- boot device %pD\n", device); - if (image) - log_debug("- image %pD\n", image); - } else { - log_debug("- efi_dp_from_name() failed, err=%lx\n", ret); - efi_clear_bootdev(); + if (ret != EFI_SUCCESS) + goto error; + + bootefi_device_path = device; + if (image) { + /* FIXME: image should not contain device */ + struct efi_device_path *image_tmp = image; + + efi_dp_split_file_path(image, &device, &image); + efi_free_pool(image_tmp); } + bootefi_image_path = image; + log_debug("- boot device %pD\n", device); + if (image) + log_debug("- image %pD\n", image); + return; +error: + log_debug("- efi_dp_from_name() failed, err=%lx\n", ret); + efi_clear_bootdev(); } /** diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 8c51a6ef2ed..c6124c590d9 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -479,7 +479,7 @@ static efi_status_t try_load_from_uri_path(struct efi_device_path_uri *uridp, } image_addr = hextoul(s, NULL); - err = wget_with_dns(image_addr, uridp->uri); + err = wget_do_request(image_addr, uridp->uri); if (err < 0) { ret = EFI_INVALID_PARAMETER; goto err; diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index ee387e1dfd4..c0633a736b6 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -974,6 +974,116 @@ struct efi_device_path __maybe_unused *efi_dp_from_eth(void) return start; } +/** + * efi_dp_from_ipv4() - set device path from IPv4 address + * + * Set the device path to an ethernet device path as provided by + * efi_dp_from_eth() concatenated with a device path of subtype + * DEVICE_PATH_SUB_TYPE_MSG_IPV4, and an END node. + * + * @ip: IPv4 local address + * @mask: network mask + * @srv: IPv4 remote/server address + * 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_device_path *dp1, *dp2, *pos; + struct { + struct efi_device_path_ipv4 ipv4dp; + struct efi_device_path end; + } dp; + + memset(&dp.ipv4dp, 0, sizeof(dp.ipv4dp)); + dp.ipv4dp.dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; + dp.ipv4dp.dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_IPV4; + dp.ipv4dp.dp.length = sizeof(dp.ipv4dp); + dp.ipv4dp.protocol = 6; + if (ip) + memcpy(&dp.ipv4dp.local_ip_address, ip, sizeof(*ip)); + if (mask) + memcpy(&dp.ipv4dp.subnet_mask, mask, sizeof(*mask)); + if (srv) + memcpy(&dp.ipv4dp.remote_ip_address, srv, sizeof(*srv)); + pos = &dp.end; + memcpy(pos, &END, sizeof(END)); + + dp1 = efi_dp_from_eth(); + if (!dp1) + return NULL; + + dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)&dp, 0); + + efi_free_pool(dp1); + + return dp2; +} + +/** + * efi_dp_from_http() - set device path from http + * + * Set the device path to an IPv4 path as provided by efi_dp_from_ipv4 + * concatenated with a device path of subtype DEVICE_PATH_SUB_TYPE_MSG_URI, + * and an END node. + * + * @server: URI of remote server + * Return: pointer to HTTP device path, NULL on error + */ +struct efi_device_path *efi_dp_from_http(const char *server) +{ + struct efi_device_path *dp1, *dp2; + struct efi_device_path_uri *uridp; + efi_uintn_t uridp_len; + char *pos; + char tmp[128]; + struct efi_ipv4_address ip; + struct efi_ipv4_address mask; + + if ((server && strlen("http://") + strlen(server) + 1 > sizeof(tmp)) || + (!server && IS_ENABLED(CONFIG_NET_LWIP))) + return NULL; + + efi_net_get_addr(&ip, &mask, NULL); + + dp1 = efi_dp_from_ipv4(&ip, &mask, NULL); + if (!dp1) + return NULL; + + strcpy(tmp, "http://"); + + if (server) { + strlcat(tmp, server, sizeof(tmp)); +#if !IS_ENABLED(CONFIG_NET_LWIP) + } else { + ip_to_string(net_server_ip, tmp + strlen("http://")); +#endif + } + + uridp_len = sizeof(struct efi_device_path) + strlen(tmp) + 1; + uridp = efi_alloc(uridp_len + sizeof(END)); + if (!uridp) { + log_err("Out of memory\n"); + return NULL; + } + uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; + uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI; + uridp->dp.length = uridp_len; + debug("device path: setting uri device path to %s\n", tmp); + memcpy(uridp->uri, tmp, strlen(tmp) + 1); + + pos = (char *)uridp + uridp_len; + memcpy(pos, &END, sizeof(END)); + + dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)uridp, 0); + + efi_free_pool(uridp); + efi_free_pool(dp1); + + return dp2; +} + /* Construct a device-path for memory-mapped image */ struct efi_device_path *efi_dp_from_mem(uint32_t memory_type, uint64_t start_address, @@ -1074,8 +1184,9 @@ 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")) { - dp = efi_dp_from_eth(); + } else if (IS_ENABLED(CONFIG_NETDEVICES) && + (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) { + efi_net_get_dp(&dp); } 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 0c7b30a26e7..481a9712d9d 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -8,6 +8,7 @@ #include <blk.h> #include <efi_loader.h> #include <malloc.h> +#include <net.h> #define MAC_OUTPUT_LEN 22 #define UNKNOWN_OUTPUT_LEN 23 @@ -170,6 +171,28 @@ static char *dp_msging(char *s, struct efi_device_path *dp) break; } + case DEVICE_PATH_SUB_TYPE_MSG_IPV4: { + struct efi_device_path_ipv4 *idp = + (struct efi_device_path_ipv4 *)dp; + + s += sprintf(s, "IPv4(%pI4,", &idp->remote_ip_address); + switch (idp->protocol) { + case IPPROTO_TCP: + s += sprintf(s, "TCP,"); + case IPPROTO_UDP: + s += sprintf(s, "UDP,"); + default: + s += sprintf(s, "0x%x,", idp->protocol); + } + s += sprintf(s, idp->static_ip_address ? "Static" : "DHCP"); + s += sprintf(s, ",%pI4", &idp->local_ip_address); + if (idp->dp.length == sizeof(struct efi_device_path_ipv4)) + s += sprintf(s, ",%pI4,%pI4", &idp->gateway_ip_address, + &idp->subnet_mask); + s += sprintf(s, ")"); + + break; + } case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: { struct efi_device_path_usb_class *ucdp = (struct efi_device_path_usb_class *)dp; diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index 6650c2b8071..112775daf4c 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -281,6 +281,10 @@ static efi_status_t efi_gen_capsule_guids(void) } for (i = 0; i < update_info.num_images; i++) { + if (!fw_array[i].fw_name) { + log_err("fw_name is not defined. Not generating capsule GUIDs\n"); + return EFI_INVALID_PARAMETER; + } gen_v5_guid(&namespace, &fw_array[i].image_type_id, compatible, strlen(compatible), diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c new file mode 100644 index 00000000000..694e1993418 --- /dev/null +++ b/lib/efi_loader/efi_http.c @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * An HTTP driver + * + * HTTP_PROTOCOL + * HTTP_SERVICE_BINDING_PROTOCOL + * IP4_CONFIG2_PROTOCOL + */ + +#include <charset.h> +#include <efi_loader.h> +#include <image.h> +#include <malloc.h> +#include <mapmem.h> +#include <net.h> + +static const efi_guid_t efi_http_service_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; +static const efi_guid_t efi_http_guid = EFI_HTTP_PROTOCOL_GUID; + +/** + * struct efi_http_instance - EFI object representing an HTTP protocol instance + * + * @http: EFI_HTTP_PROTOCOL interface + * @handle: handle to efi object + * @configured: configuration status + * @http_load_addr: data buffer + * @file_size: size of data + * @current_offset: offset in data buffer + * @status_code: HTTP status code + * @num_headers: number of received headers + * @headers: array of headers + * @headers_buffer: raw buffer with headers + */ +struct efi_http_instance { + struct efi_http_protocol http; + efi_handle_t handle; + bool configured; + void *http_load_addr; + ulong file_size; + ulong current_offset; + u32 status_code; + ulong num_headers; + struct http_header headers[MAX_HTTP_HEADERS]; + char headers_buffer[MAX_HTTP_HEADERS_SIZE]; +}; + +static int num_instances; + +/* + * efi_u32_to_httpstatus() - convert u32 to status + * + */ +enum efi_http_status_code efi_u32_to_httpstatus(u32 status); + +/* + * efi_http_send_data() - sends data to client + * + * + * @client_buffer: client buffer to send data to + * @client_buffer_size: size of the client buffer + * @inst: HTTP instance for which to send data + * + * Return: status code + */ +static efi_status_t efi_http_send_data(void *client_buffer, + efi_uintn_t *client_buffer_size, + struct efi_http_instance *inst) +{ + efi_status_t ret = EFI_SUCCESS; + ulong total_size, transfer_size; + uchar *ptr; + + // Amount of data left; + total_size = inst->file_size; + transfer_size = total_size - inst->current_offset; + debug("efi_http: sending data to client, total size %lu\n", total_size); + // Amount of data the client is willing to receive + if (transfer_size > *client_buffer_size) + transfer_size = *client_buffer_size; + else + *client_buffer_size = transfer_size; + debug("efi_http: transfer size %lu\n", transfer_size); + if (!transfer_size) // Ok, only headers + goto out; + + if (!client_buffer) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + // Send data + ptr = (uchar *)inst->http_load_addr + inst->current_offset; + memcpy(client_buffer, ptr, transfer_size); + + inst->current_offset += transfer_size; + + // Whole file served, clean the buffer: + if (inst->current_offset == inst->file_size) { + efi_free_pool(inst->http_load_addr); + inst->http_load_addr = NULL; + inst->current_offset = 0; + inst->file_size = 0; + } + +out: + return ret; +} + +/* EFI_HTTP_PROTOCOL */ + +/* + * efi_http_get_mode_data() - Gets the current operational status. + * + * This function implements EFI_HTTP_PROTOCOL.GetModeData(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @data: pointer to the buffer for operational parameters + * of this HTTP instance + * Return: status code + */ +static efi_status_t EFIAPI efi_http_get_mode_data(struct efi_http_protocol *this, + struct efi_http_config_data *data) +{ + EFI_ENTRY("%p, %p", this, data); + + efi_status_t ret = EFI_UNSUPPORTED; + + return EFI_EXIT(ret); +} + +/* + * efi_http_configure() - Initializes operational status for this + * EFI HTTP instance. + * + * This function implements EFI_HTTP_PROTOCOL.Configure(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @data: pointer to the buffer for operational parameters of + * this HTTP instance + * Return: status code + */ +static efi_status_t EFIAPI efi_http_configure(struct efi_http_protocol *this, + struct efi_http_config_data *data) +{ + EFI_ENTRY("%p, %p", this, data); + + efi_status_t ret = EFI_SUCCESS; + enum efi_http_version http_version; + struct efi_httpv4_access_point *ipv4_node; + struct efi_http_instance *http_instance; + + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + http_instance = (struct efi_http_instance *)this; + + if (!data) { + efi_free_pool(http_instance->http_load_addr); + http_instance->http_load_addr = NULL; + http_instance->current_offset = 0; + http_instance->configured = false; + + goto out; + } + + if (http_instance->configured) { + ret = EFI_ALREADY_STARTED; + goto out; + } + + http_version = data->http_version; + ipv4_node = data->access_point.ipv4_node; + + if ((http_version != HTTPVERSION10 && + http_version != HTTPVERSION11) || + data->is_ipv6 || !ipv4_node) { /* Only support ipv4 */ + ret = EFI_UNSUPPORTED; + goto out; + } + + 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); + } + + http_instance->current_offset = 0; + http_instance->configured = true; + +out: + return EFI_EXIT(ret); +} + +/* + * efi_http_request() - Queues an HTTP request to this HTTP instance + * + * This function implements EFI_HTTP_PROTOCOL.Request(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @token: pointer to storage containing HTTP request token + * Return: status code + */ +static efi_status_t EFIAPI efi_http_request(struct efi_http_protocol *this, + struct efi_http_token *token) +{ + EFI_ENTRY("%p, %p", this, token); + + efi_status_t ret = EFI_SUCCESS; + u8 *tmp; + u8 url_8[1024]; + u16 *url_16; + enum efi_http_method current_method; + struct efi_http_instance *http_instance; + + if (!token || !this || !token->message || + !token->message->data.request) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + http_instance = (struct efi_http_instance *)this; + + if (!http_instance->configured) { + ret = EFI_NOT_STARTED; + goto out; + } + + current_method = token->message->data.request->method; + url_16 = token->message->data.request->url; + + /* Parse URL. It comes in UCS-2 encoding and follows RFC3986 */ + tmp = url_8; + utf16_utf8_strncpy((char **)&tmp, url_16, 1024); + + 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); + if (ret != EFI_SUCCESS) + goto out; + + // We have a successful request + efi_net_parse_headers(&http_instance->num_headers, http_instance->headers); + http_instance->current_offset = 0; + token->status = EFI_SUCCESS; + goto out_signal; + +out_signal: + efi_signal_event(token->event); +out: + return EFI_EXIT(ret); +} + +/* + * efi_http_cancel() - Abort an asynchronous HTTP request or response token + * + * This function implements EFI_HTTP_PROTOCOL.Cancel(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @token: pointer to storage containing HTTP request token + * Return: status code + */ +static efi_status_t EFIAPI efi_http_cancel(struct efi_http_protocol *this, + struct efi_http_token *token) +{ + EFI_ENTRY("%p, %p", this, token); + + efi_status_t ret = EFI_UNSUPPORTED; + + return EFI_EXIT(ret); +} + +/* + * efi_http_response() - Queues an HTTP response to this HTTP instance + * + * This function implements EFI_HTTP_PROTOCOL.Response(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @token: pointer to storage containing HTTP request token + * Return: status code + */ +static efi_status_t EFIAPI efi_http_response(struct efi_http_protocol *this, + struct efi_http_token *token) +{ + EFI_ENTRY("%p, %p", this, token); + + efi_status_t ret = EFI_SUCCESS; + struct efi_http_instance *http_instance; + struct efi_http_header **client_headers; + struct efi_http_response_data *response; + + if (!token || !this || !token->message) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + http_instance = (struct efi_http_instance *)this; + + // Set HTTP status code + if (token->message->data.response) { // TODO extra check, see spec. + response = token->message->data.response; + response->status_code = efi_u32_to_httpstatus(http_instance->status_code); + } + + client_headers = &token->message->headers; + + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, + (http_instance->num_headers) * sizeof(struct efi_http_header), + (void **)client_headers); // This is deallocated by the client. + if (ret != EFI_SUCCESS) + goto out_bad_signal; + + // Send headers + token->message->header_count = http_instance->num_headers; + for (int i = 0; i < http_instance->num_headers; i++) { + (*client_headers)[i].field_name = http_instance->headers[i].name; + (*client_headers)[i].field_value = http_instance->headers[i].value; + } + + ret = efi_http_send_data(token->message->body, &token->message->body_length, http_instance); + if (ret != EFI_SUCCESS) + goto out_bad_signal; + + token->status = EFI_SUCCESS; + goto out_signal; + +out_bad_signal: + token->status = EFI_ABORTED; +out_signal: + efi_signal_event(token->event); +out: + return EFI_EXIT(ret); +} + +/* + * efi_http_poll() - Polls for incoming data packets and processes outgoing data packets + * + * This function implements EFI_HTTP_PROTOCOL.Poll(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @token: pointer to storage containing HTTP request token + * Return: status code + */ +static efi_status_t EFIAPI efi_http_poll(struct efi_http_protocol *this) +{ + EFI_ENTRY("%p", this); + + efi_status_t ret = EFI_UNSUPPORTED; + + return EFI_EXIT(ret); +} + +/* EFI_HTTP_SERVICE_BINDING_PROTOCOL */ + +/* + * efi_http_service_binding_create_child() - Creates a child handle + * and installs a protocol + * + * This function implements EFI_HTTP_SERVICE_BINDING.CreateChild(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @child_handle: pointer to child handle + * Return: status code + */ +static efi_status_t EFIAPI efi_http_service_binding_create_child( + struct efi_service_binding_protocol *this, + efi_handle_t *child_handle) +{ + EFI_ENTRY("%p, %p", this, child_handle); + + efi_status_t ret = EFI_SUCCESS; + struct efi_http_instance *new_instance; + + if (!child_handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + new_instance = calloc(1, sizeof(struct efi_http_instance)); + if (!new_instance) { + ret = EFI_OUT_OF_RESOURCES; + goto failure_to_add_protocol; + } + + if (*child_handle) { + new_instance->handle = *child_handle; + goto install; + } + + new_instance->handle = calloc(1, sizeof(struct efi_object)); + if (!new_instance->handle) { + efi_free_pool((void *)new_instance); + ret = EFI_OUT_OF_RESOURCES; + goto failure_to_add_protocol; + } + + efi_add_handle(new_instance->handle); + *child_handle = new_instance->handle; + +install: + ret = efi_add_protocol(new_instance->handle, &efi_http_guid, + &new_instance->http); + if (ret != EFI_SUCCESS) + goto failure_to_add_protocol; + + new_instance->http.get_mode_data = efi_http_get_mode_data; + new_instance->http.configure = efi_http_configure; + new_instance->http.request = efi_http_request; + new_instance->http.cancel = efi_http_cancel; + new_instance->http.response = efi_http_response; + new_instance->http.poll = efi_http_poll; + ++num_instances; + + return EFI_EXIT(EFI_SUCCESS); + +failure_to_add_protocol: + return EFI_EXIT(ret); +} + +/* + * efi_http_service_binding_destroy_child() - Destroys a child handle with + * a protocol installed on it + * + * This function implements EFI_HTTP_SERVICE_BINDING.DestroyChild(). + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @child_handle: child handle + * Return: status code + */ +static efi_status_t EFIAPI efi_http_service_binding_destroy_child( + struct efi_service_binding_protocol *this, + efi_handle_t child_handle) +{ + EFI_ENTRY("%p, %p", this, child_handle); + efi_status_t ret = EFI_SUCCESS; + struct efi_http_instance *http_instance; + struct efi_handler *phandler; + void *protocol_interface; + + if (num_instances == 0) + return EFI_EXIT(EFI_NOT_FOUND); + + if (!child_handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + efi_search_protocol(child_handle, &efi_http_guid, &phandler); + + if (phandler) + protocol_interface = phandler->protocol_interface; + + ret = efi_delete_handle(child_handle); + if (ret != EFI_SUCCESS) + return EFI_EXIT(ret); + + http_instance = (struct efi_http_instance *)protocol_interface; + efi_free_pool(http_instance->http_load_addr); + http_instance->http_load_addr = NULL; + + free(protocol_interface); + + num_instances--; + + return EFI_EXIT(EFI_SUCCESS); +} + +/** + * efi_http_register() - register the http protocol + * + */ +efi_status_t efi_http_register(const efi_handle_t handle, + struct efi_service_binding_protocol *http_service_binding) +{ + efi_status_t r = EFI_SUCCESS; + + r = efi_add_protocol(handle, &efi_http_service_binding_guid, + http_service_binding); + if (r != EFI_SUCCESS) + goto failure_to_add_protocol; + + http_service_binding->create_child = efi_http_service_binding_create_child; + http_service_binding->destroy_child = efi_http_service_binding_destroy_child; + + return EFI_SUCCESS; +failure_to_add_protocol: + return r; +} + +enum efi_http_status_code efi_u32_to_httpstatus(u32 status) +{ + switch (status) { + case 100: return HTTP_STATUS_100_CONTINUE; + case 101: return HTTP_STATUS_101_SWITCHING_PROTOCOLS; + case 200: return HTTP_STATUS_200_OK; + case 201: return HTTP_STATUS_201_CREATED; + case 202: return HTTP_STATUS_202_ACCEPTED; + case 203: return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION; + case 204: return HTTP_STATUS_204_NO_CONTENT; + case 205: return HTTP_STATUS_205_RESET_CONTENT; + case 206: return HTTP_STATUS_206_PARTIAL_CONTENT; + case 300: return HTTP_STATUS_300_MULTIPLE_CHOICES; + case 301: return HTTP_STATUS_301_MOVED_PERMANENTLY; + case 302: return HTTP_STATUS_302_FOUND; + case 303: return HTTP_STATUS_303_SEE_OTHER; + case 304: return HTTP_STATUS_304_NOT_MODIFIED; + case 305: return HTTP_STATUS_305_USE_PROXY; + case 307: return HTTP_STATUS_307_TEMPORARY_REDIRECT; + case 400: return HTTP_STATUS_400_BAD_REQUEST; + case 401: return HTTP_STATUS_401_UNAUTHORIZED; + case 402: return HTTP_STATUS_402_PAYMENT_REQUIRED; + case 403: return HTTP_STATUS_403_FORBIDDEN; + case 404: return HTTP_STATUS_404_NOT_FOUND; + case 405: return HTTP_STATUS_405_METHOD_NOT_ALLOWED; + case 406: return HTTP_STATUS_406_NOT_ACCEPTABLE; + case 407: return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED; + case 408: return HTTP_STATUS_408_REQUEST_TIME_OUT; + case 409: return HTTP_STATUS_409_CONFLICT; + case 410: return HTTP_STATUS_410_GONE; + case 411: return HTTP_STATUS_411_LENGTH_REQUIRED; + case 412: return HTTP_STATUS_412_PRECONDITION_FAILED; + case 413: return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE; + case 414: return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE; + case 415: return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE; + case 416: return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED; + case 417: return HTTP_STATUS_417_EXPECTATION_FAILED; + case 500: return HTTP_STATUS_500_INTERNAL_SERVER_ERROR; + case 501: return HTTP_STATUS_501_NOT_IMPLEMENTED; + case 502: return HTTP_STATUS_502_BAD_GATEWAY; + case 503: return HTTP_STATUS_503_SERVICE_UNAVAILABLE; + case 504: return HTTP_STATUS_504_GATEWAY_TIME_OUT; + case 505: return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED; + case 308: return HTTP_STATUS_308_PERMANENT_REDIRECT; + default: return HTTP_STATUS_UNSUPPORTED_STATUS; + } +} diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 0ddf69a0918..bb58cf1badb 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -13,6 +13,7 @@ #include <efi_loader.h> #include <log.h> #include <malloc.h> +#include <mapmem.h> #include <pe.h> #include <sort.h> #include <crypto/mscode.h> @@ -977,7 +978,7 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, } /* Flush cache */ - flush_cache((ulong)efi_reloc, + flush_cache(map_to_sysmem(efi_reloc), ALIGN(virt_size, EFI_CACHELINE_SIZE)); /* diff --git a/lib/efi_loader/efi_ipconfig.c b/lib/efi_loader/efi_ipconfig.c new file mode 100644 index 00000000000..0b247a4c028 --- /dev/null +++ b/lib/efi_loader/efi_ipconfig.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Implementation of EFI_IP4_CONFIG2_PROTOCOL + * + */ + +#include <efi_loader.h> +#include <image.h> +#include <malloc.h> +#include <mapmem.h> +#include <net.h> + +static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; + +struct efi_ip4_config2_manual_address current_http_ip; +static enum efi_ip4_config2_policy current_policy; +static char current_mac_addr[32]; + +/* EFI_IP4_CONFIG2_PROTOCOL */ + +/* + * efi_ip4_config2_set_data() - Set the configuration for the EFI IPv4 network + * stack running on the communication device + * + * This function implements EFI_IP4_CONFIG2_PROTOCOL.SetData() + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @data_type: the type of data to set + * @data_size: size of the buffer pointed to by data in bytes + * @data: the data buffer to set + * Return: status code + */ +static efi_status_t EFIAPI efi_ip4_config2_set_data(struct efi_ip4_config2_protocol *this, + enum efi_ip4_config2_data_type data_type, + efi_uintn_t data_size, + void *data) +{ + EFI_ENTRY("%p, %d, %zu, %p", this, data_type, data_size, data); + efi_status_t ret = EFI_SUCCESS; + + if (!this || (data && !data_size) || (!data && data_size)) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + switch (data_type) { + case EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO: + return EFI_EXIT(EFI_WRITE_PROTECTED); + case EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS: + if (current_policy != EFI_IP4_CONFIG2_POLICY_STATIC) + return EFI_EXIT(EFI_WRITE_PROTECTED); + if (!data_size && !data) { + memset((void *)¤t_http_ip, 0, + sizeof(current_http_ip)); + return EFI_EXIT(EFI_SUCCESS); + } + if (data && data_size == sizeof(struct efi_ip4_config2_manual_address)) { + 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); + return EFI_EXIT(EFI_SUCCESS); + } + return EFI_EXIT(EFI_BAD_BUFFER_SIZE); + case EFI_IP4_CONFIG2_DATA_TYPE_POLICY: + if (data && data_size == sizeof(enum efi_ip4_config2_policy)) { + current_policy = *(enum efi_ip4_config2_policy *)data; + return EFI_EXIT(EFI_SUCCESS); + } + return EFI_EXIT(EFI_BAD_BUFFER_SIZE); + + default: + return EFI_EXIT(EFI_UNSUPPORTED); + } + + return EFI_EXIT(ret); +} + +/* + * efi_ip4_config2_get_data() - Get the configuration for the EFI IPv4 network + * stack running on the communication device + * + * This function implements EFI_IP4_CONFIG2_PROTOCOL.GetData() + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @data_type: the type of data to get + * @data_size: size + * @data: the data buffer + * Return: status code + */ +static efi_status_t EFIAPI efi_ip4_config2_get_data(struct efi_ip4_config2_protocol *this, + enum efi_ip4_config2_data_type data_type, + efi_uintn_t *data_size, + void *data) +{ + EFI_ENTRY("%p, %d, %p, %p", this, data_type, data_size, data); + + efi_status_t ret = EFI_SUCCESS; + struct efi_ip4_config2_interface_info *info; + int tmp; + + if (!this || !data_size) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + if (*data_size && !data) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + tmp = sizeof(struct efi_ip4_config2_interface_info) + sizeof(struct efi_ip4_route_table); + + switch (data_type) { + case EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO: + if (*data_size < tmp) { + *data_size = tmp; + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + info = (struct efi_ip4_config2_interface_info *)data; + memset(info, 0, sizeof(*info)); + + info->hw_address_size = 6; + memcpy(info->hw_address.mac_addr, current_mac_addr, 6); + // Set the route table size + + info->route_table_size = 0; + break; + case EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS: + if (*data_size < sizeof(struct efi_ip4_config2_manual_address)) { + *data_size = sizeof(struct efi_ip4_config2_manual_address); + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + efi_net_get_addr(¤t_http_ip.address, ¤t_http_ip.subnet_mask, NULL); + memcpy(data, (void *)¤t_http_ip, + sizeof(struct efi_ip4_config2_manual_address)); + + break; + default: + return EFI_EXIT(EFI_NOT_FOUND); + } + return EFI_EXIT(ret); +} + +/* + * efi_ip4_config2_register_notify() - Register an event that is to be signaled whenever + * a configuration process on the specified configuration + * data is done + * + * This function implements EFI_IP4_CONFIG2_PROTOCOL.RegisterDataNotify() + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @data_type: the type of data to register the event for + * @event: the event to register + * Return: status code + */ +static efi_status_t EFIAPI efi_ip4_config2_register_notify(struct efi_ip4_config2_protocol *this, + enum efi_ip4_config2_data_type data_type, + struct efi_event *event) +{ + EFI_ENTRY("%p, %d, %p", this, data_type, event); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +/* + * efi_ip4_config2_unregister_notify() - Remove a previously registered eventfor + * the specified configuration data + * + * This function implements EFI_IP4_CONFIG2_PROTOCOL.UnregisterDataNotify() + * See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @data_type: the type of data to remove the event for + * @event: the event to unregister + * Return: status code + */ +static efi_status_t EFIAPI efi_ip4_config2_unregister_notify(struct efi_ip4_config2_protocol *this, + enum efi_ip4_config2_data_type data_type, + struct efi_event *event) +{ + EFI_ENTRY("%p, %d, %p", this, data_type, event); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +/** + * efi_ipconfig_register() - register the ip4_config2 protocol + * + */ +efi_status_t efi_ipconfig_register(const efi_handle_t handle, + struct efi_ip4_config2_protocol *ip4config) +{ + efi_status_t r = EFI_SUCCESS; + + r = efi_add_protocol(handle, &efi_ip4_config2_guid, + ip4config); + if (r != EFI_SUCCESS) { + log_err("ERROR: Failure to add protocol\n"); + return r; + } + + memcpy(current_mac_addr, eth_get_ethaddr(), 6); + + ip4config->set_data = efi_ip4_config2_set_data; + ip4config->get_data = efi_ip4_config2_get_data; + ip4config->register_data_notify = efi_ip4_config2_register_notify; + ip4config->unregister_data_notify = efi_ip4_config2_unregister_notify; + + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index e493934c713..edd7da7d8c6 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -814,7 +814,16 @@ static void add_u_boot_and_runtime(void) { unsigned long runtime_start, runtime_end, runtime_pages; unsigned long runtime_mask = EFI_PAGE_MASK; - + unsigned long uboot_start, uboot_pages; + unsigned long uboot_stack_size = CONFIG_STACK_SIZE; + + /* Add U-Boot */ + uboot_start = ((uintptr_t)map_sysmem(gd->start_addr_sp, 0) - + 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); #if defined(__aarch64__) /* * Runtime Services must be 64KiB aligned according to the diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 7cd536705f4..67593ef50c0 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -16,7 +16,10 @@ */ #include <efi_loader.h> +#include <dm.h> +#include <linux/sizes.h> #include <malloc.h> +#include <vsprintf.h> #include <net.h> static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; @@ -32,6 +35,19 @@ static int rx_packet_num; static struct efi_net_obj *netobj; /* + * 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. + */ +static struct efi_device_path *net_dp; + +static struct wget_http_info efi_wget_info = { + .set_bootdev = false, + .check_buffer_size = true, + +}; + +/* * The notification function of this event is called in every timer cycle * to check if a new network packet has been received. */ @@ -44,11 +60,13 @@ static struct efi_event *wait_for_packet; /** * struct efi_net_obj - EFI object representing a network interface * - * @header: EFI object header - * @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 + * @header: EFI object header + * @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 */ struct efi_net_obj { struct efi_object header; @@ -56,6 +74,12 @@ struct efi_net_obj { struct efi_simple_network_mode net_mode; struct efi_pxe_base_code_protocol pxe; struct efi_pxe_mode pxe_mode; +#if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) + struct efi_ip4_config2_protocol ip4_config2; +#endif +#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL) + struct efi_service_binding_protocol http_service_binding; +#endif }; /* @@ -901,8 +925,10 @@ efi_status_t efi_net_register(void) &netobj->net); if (r != EFI_SUCCESS) goto failure_to_add_protocol; + if (!net_dp) + efi_net_set_dp("Net", NULL); r = efi_add_protocol(&netobj->header, &efi_guid_device_path, - efi_dp_from_eth()); + net_dp); if (r != EFI_SUCCESS) goto failure_to_add_protocol; r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid, @@ -981,6 +1007,25 @@ efi_status_t efi_net_register(void) return r; } +#if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) + r = efi_ipconfig_register(&netobj->header, &netobj->ip4_config2); + if (r != EFI_SUCCESS) + goto failure_to_add_protocol; +#endif + +#ifdef CONFIG_EFI_HTTP_PROTOCOL + 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 + return EFI_SUCCESS; failure_to_add_protocol: printf("ERROR: Failure to add protocol\n"); @@ -997,3 +1042,317 @@ out_of_resources: printf("ERROR: Out of memory\n"); return EFI_OUT_OF_RESOURCES; } + +/** + * efi_net_set_dp() - set device path of efi net device + * + * 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 + * Return: status code + */ +efi_status_t efi_net_set_dp(const char *dev, const char *server) +{ + efi_free_pool(net_dp); + + net_dp = NULL; + if (!strcmp(dev, "Net")) + net_dp = efi_dp_from_eth(); + else if (!strcmp(dev, "Http")) + net_dp = efi_dp_from_http(server); + + if (!net_dp) + return EFI_OUT_OF_RESOURCES; + + return EFI_SUCCESS; +} + +/** + * efi_net_get_dp() - get device path of efi net device + * + * Produce a copy of the current device path + * + * @dp: copy of the current device path, or NULL on error + */ +void efi_net_get_dp(struct efi_device_path **dp) +{ + if (!dp) + return; + if (!net_dp) + efi_net_set_dp("Net", NULL); + if (net_dp) + *dp = efi_dp_dup(net_dp); +} + +/** + * efi_net_get_addr() - get IP address information + * + * Copy the current IP address, mask, and gateway into the + * efi_ipv4_address structs pointed to by ip, mask and gw, + * respectively. + * + * @ip: pointer to an efi_ipv4_address struct to + * be filled with the current IP address + * @mask: pointer to an efi_ipv4_address struct to + * be filled with the current network mask + * @gw: pointer to an efi_ipv4_address struct to be + * filled with the current network gateway + */ +void efi_net_get_addr(struct efi_ipv4_address *ip, + struct efi_ipv4_address *mask, + struct efi_ipv4_address *gw) +{ +#ifdef CONFIG_NET_LWIP + char ipstr[] = "ipaddr\0\0"; + char maskstr[] = "netmask\0\0"; + char gwstr[] = "gatewayip\0\0"; + int idx; + struct in_addr tmp; + char *env; + + idx = dev_seq(eth_get_dev()); + + if (idx < 0 || idx > 99) { + log_err("unexpected idx %d\n", idx); + return; + } + + if (idx) { + sprintf(ipstr, "ipaddr%d", idx); + sprintf(maskstr, "netmask%d", idx); + sprintf(gwstr, "gatewayip%d", idx); + } + + env = env_get(ipstr); + if (env && ip) { + tmp = string_to_ip(env); + memcpy(ip, &tmp, sizeof(tmp)); + } + + env = env_get(maskstr); + if (env && mask) { + tmp = string_to_ip(env); + memcpy(mask, &tmp, sizeof(tmp)); + } + env = env_get(gwstr); + if (env && gw) { + tmp = string_to_ip(env); + memcpy(gw, &tmp, sizeof(tmp)); + } +#else + if (ip) + memcpy(ip, &net_ip, sizeof(net_ip)); + if (mask) + memcpy(mask, &net_netmask, sizeof(net_netmask)); +#endif +} + +/** + * efi_net_set_addr() - set IP address information + * + * Set the current IP address, mask, and gateway to the + * efi_ipv4_address structs pointed to by ip, mask and gw, + * respectively. + * + * @ip: pointer to new IP address + * @mask: pointer to new network mask to set + * @gw: pointer to new network gateway + */ +void efi_net_set_addr(struct efi_ipv4_address *ip, + struct efi_ipv4_address *mask, + struct efi_ipv4_address *gw) +{ +#ifdef CONFIG_NET_LWIP + char ipstr[] = "ipaddr\0\0"; + char maskstr[] = "netmask\0\0"; + char gwstr[] = "gatewayip\0\0"; + int idx; + struct in_addr *addr; + char tmp[46]; + + idx = dev_seq(eth_get_dev()); + + if (idx < 0 || idx > 99) { + log_err("unexpected idx %d\n", idx); + return; + } + + if (idx) { + sprintf(ipstr, "ipaddr%d", idx); + sprintf(maskstr, "netmask%d", idx); + sprintf(gwstr, "gatewayip%d", idx); + } + + if (ip) { + addr = (struct in_addr *)ip; + ip_to_string(*addr, tmp); + env_set(ipstr, tmp); + } + + if (mask) { + addr = (struct in_addr *)mask; + ip_to_string(*addr, tmp); + env_set(maskstr, tmp); + } + + if (gw) { + addr = (struct in_addr *)gw; + ip_to_string(*addr, tmp); + env_set(gwstr, tmp); + } +#else + if (ip) + memcpy(&net_ip, ip, sizeof(*ip)); + if (mask) + memcpy(&net_netmask, mask, sizeof(*mask)); +#endif +} + +/** + * efi_net_set_buffer() - allocate a buffer of min 64K + * + * @buffer: allocated buffer + * @size: desired buffer size + * Return: status code + */ +static efi_status_t efi_net_set_buffer(void **buffer, size_t size) +{ + efi_status_t ret = EFI_SUCCESS; + + if (size < SZ_64K) + size = SZ_64K; + + *buffer = efi_alloc(size); + if (!*buffer) + ret = EFI_OUT_OF_RESOURCES; + + efi_wget_info.buffer_size = (ulong)size; + + return ret; +} + +/** + * efi_net_parse_headers() - parse HTTP headers + * + * Parses the raw buffer efi_wget_info.headers into an array headers + * of efi structs http_headers. The array should be at least + * MAX_HTTP_HEADERS long. + * + * @num_headers: number of headers + * @headers: caller provided array of struct http_headers + */ +void efi_net_parse_headers(ulong *num_headers, struct http_header *headers) +{ + if (!num_headers || !headers) + return; + + // Populate info with http headers. + *num_headers = 0; + const uchar *line_start = efi_wget_info.headers; + const uchar *line_end; + ulong count; + struct http_header *current_header; + const uchar *separator; + size_t name_length, value_length; + + // Skip the first line (request or status line) + line_end = strstr(line_start, "\r\n"); + + if (line_end) + line_start = line_end + 2; + + while ((line_end = strstr(line_start, "\r\n")) != NULL) { + count = *num_headers; + if (line_start == line_end || count >= MAX_HTTP_HEADERS) + break; + current_header = headers + count; + separator = strchr(line_start, ':'); + if (separator) { + name_length = separator - line_start; + ++separator; + while (*separator == ' ') + ++separator; + value_length = line_end - separator; + if (name_length < MAX_HTTP_HEADER_NAME && + value_length < MAX_HTTP_HEADER_VALUE) { + strncpy(current_header->name, line_start, name_length); + current_header->name[name_length] = '\0'; + strncpy(current_header->value, separator, value_length); + current_header->value[value_length] = '\0'; + (*num_headers)++; + } + } + line_start = line_end + 2; + } +} + +/** + * efi_net_do_request() - issue an HTTP request using wget + * + * @url: url + * @method: HTTP method + * @buffer: data buffer + * @status_code: HTTP status code + * @file_size: file size in bytes + * @headers_buffer: headers buffer + * 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) +{ + efi_status_t ret = EFI_SUCCESS; + int wget_ret; + static bool last_head; + + if (!buffer || !file_size) + return EFI_ABORTED; + + efi_wget_info.method = (enum wget_http_method)method; + efi_wget_info.headers = headers_buffer; + + 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; + 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 + efi_free_pool(*buffer); + ret = efi_net_set_buffer(buffer, (size_t)efi_wget_info.hdr_cont_len); + if (ret != EFI_SUCCESS) + goto out; + if (wget_request((ulong)*buffer, url, &efi_wget_info)) { + efi_free_pool(*buffer); + ret = EFI_DEVICE_ERROR; + goto out; + } + } else if (wget_ret) { + efi_free_pool(*buffer); + ret = EFI_DEVICE_ERROR; + goto out; + } + // Pass the actual number of received bytes to the application + *file_size = efi_wget_info.file_size; + *status_code = efi_wget_info.status_code; + last_head = false; + break; + case HTTP_METHOD_HEAD: + ret = efi_net_set_buffer(buffer, 0); + if (ret != EFI_SUCCESS) + goto out; + wget_request((ulong)*buffer, url, &efi_wget_info); + *file_size = 0; + *status_code = efi_wget_info.status_code; + last_head = true; + break; + default: + ret = EFI_UNSUPPORTED; + break; + } + +out: + return ret; +} diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 414701893f6..17fbfad116f 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -52,6 +52,8 @@ efi_selftest_watchdog.o obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o obj-$(CONFIG_NETDEVICES) += efi_selftest_snp.o +obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_http.o +obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_ipconfig.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \ diff --git a/lib/efi_selftest/efi_selftest_http.c b/lib/efi_selftest/efi_selftest_http.c new file mode 100644 index 00000000000..b63c401f055 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_http.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * efi_selftest_http + * + * This unit test covers the IPv4 Config2 Protocol, Http Service Binding Protocol, + * and Http Protocol. + * + * An Http HEAD and an Http GET request are sent to the same destination. The test + * is successful if the HEAD request gets a response with a valid Content-Length header + * and the subsequent GET request receives the amount of bytes informed by the previous + * Content-Length header. + * + */ + +#include <efi_selftest.h> +#include <charset.h> +#include <net.h> + +static struct efi_boot_services *boottime; + +static struct efi_http_protocol *http; +static struct efi_service_binding_protocol *http_service; +static struct efi_ip4_config2_protocol *ip4_config2; +static efi_handle_t http_protocol_handle; + +static const efi_guid_t efi_http_guid = EFI_HTTP_PROTOCOL_GUID; +static const efi_guid_t efi_http_service_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; +static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; +static int callback_done; + +/* + * Setup unit test. + * + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + efi_handle_t *net_handle; + efi_uintn_t num_handles; + efi_handle_t *handles; + struct efi_http_config_data http_config; + struct efi_httpv4_access_point ipv4_node; + + boottime = systable->boottime; + + num_handles = 0; + boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid, + NULL, &num_handles, &handles); + + if (!num_handles) { + efi_st_error("Failed to locate ipv4 config2 protocol\n"); + return EFI_ST_FAILURE; + } + + for (net_handle = handles; num_handles--; net_handle++) { + ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid, + (void **)&ip4_config2, 0, 0, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS || !ip4_config2) + continue; + ret = boottime->open_protocol(*net_handle, + &efi_http_service_binding_guid, + (void **)&http_service, 0, 0, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS || !http_service) + continue; + break; // Get first handle that supports both protocols + } + + if (!ip4_config2 || !http_service) { + efi_st_error("Failed to open ipv4 config2 or http service binding protocol\n"); + return EFI_ST_FAILURE; + } + + http_protocol_handle = NULL; + ret = http_service->create_child(http_service, &http_protocol_handle); + if (ret != EFI_SUCCESS || !http_protocol_handle) { + efi_st_error("Failed to create an http service instance\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->open_protocol(http_protocol_handle, &efi_http_guid, + (void **)&http, 0, 0, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS || !http) { + efi_st_error("Failed to open http protocol\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("HTTP Service Binding: child created successfully\n"); + + http_config.http_version = HTTPVERSION11; + http_config.is_ipv6 = false; + http_config.access_point.ipv4_node = &ipv4_node; + ipv4_node.use_default_address = true; + + ret = http->configure(http, &http_config); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to configure http instance\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +void EFIAPI efi_test_http_callback(struct efi_event *event, void *context) +{ + callback_done = 1; +} + +/* + * Execute unit test. + * + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_http_request_data request_data; + struct efi_http_message request_message; + struct efi_http_token request_token; + struct efi_http_response_data response_data; + struct efi_http_message response_message; + struct efi_http_token response_token; + enum efi_http_status_code status_code; + void *response_buffer; + efi_uintn_t len, sum; + char *url = "http://example.com/"; + u16 url_16[64]; + u16 *tmp; + + /* Setup may have failed */ + if (!ip4_config2 || !http) { + efi_st_error("Cannot proceed with test after setup failure\n"); + return EFI_ST_FAILURE; + } + + tmp = url_16; + utf8_utf16_strcpy(&tmp, url); + request_data.url = url_16; + request_data.method = HTTP_METHOD_GET; + + request_message.data.request = &request_data; + request_message.header_count = 3; + request_message.body_length = 0; + request_message.body = NULL; + + /* request token */ + request_token.event = NULL; + request_token.status = EFI_NOT_READY; + request_token.message = &request_message; + callback_done = 0; + ret = boottime->create_event(EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + efi_test_http_callback, + NULL, + &request_token.event); + + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create request event\n"); + return EFI_ST_FAILURE; + } + + ret = http->request(http, &request_token); + + if (ret != EFI_SUCCESS) { + boottime->close_event(request_token.event); + efi_st_printf("Failed to proceed with the http request\n"); + return EFI_ST_SUCCESS; + } + + while (!callback_done) + http->poll(http); + + response_data.status_code = HTTP_STATUS_UNSUPPORTED_STATUS; + response_message.data.response = &response_data; + response_message.header_count = 0; + response_message.headers = NULL; + response_message.body_length = 0; + response_message.body = NULL; + response_token.event = NULL; + + ret = boottime->create_event(EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + efi_test_http_callback, + NULL, + &response_token.event); + + if (ret != EFI_SUCCESS) { + boottime->close_event(request_token.event); + efi_st_error("Failed to create response event\n"); + return EFI_ST_FAILURE; + } + + response_token.status = EFI_SUCCESS; + response_token.message = &response_message; + + callback_done = 0; + ret = http->response(http, &response_token); + + if (ret != EFI_SUCCESS) { + efi_st_error("Failed http first response\n"); + goto fail; + } + + while (!callback_done) + http->poll(http); + + if (response_message.data.response->status_code != HTTP_STATUS_200_OK) { + status_code = response_message.data.response->status_code; + if (status_code == HTTP_STATUS_404_NOT_FOUND) { + efi_st_error("File not found\n"); + } else { + efi_st_error("Bad http status %d\n", + response_message.data.response->status_code); + } + goto fail_free_hdr; + } + + ret = boottime->allocate_pool(EFI_LOADER_CODE, response_message.body_length, + &response_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed allocating response buffer\n"); + goto fail_free_hdr; + } + + len = response_message.body_length; + sum = 0; + while (len) { + response_message.data.response = NULL; + response_message.header_count = 0; + response_message.headers = NULL; + response_message.body_length = len; + response_message.body = response_buffer + sum; + + response_token.message = &response_message; + response_token.status = EFI_NOT_READY; + + callback_done = 0; + ret = http->response(http, &response_token); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed http second response\n"); + goto fail_free_buf; + } + + while (!callback_done) + http->poll(http); + + if (!response_message.body_length) + break; + + len -= response_message.body_length; + sum += response_message.body_length; + } + + if (len) + goto fail_free_buf; + + boottime->free_pool(response_buffer); + if (response_message.headers) + boottime->free_pool(response_message.headers); + boottime->close_event(request_token.event); + boottime->close_event(response_token.event); + efi_st_printf("Efi Http request executed successfully\n"); + return EFI_ST_SUCCESS; + +fail_free_buf: + boottime->free_pool(response_buffer); +fail_free_hdr: + if (response_message.headers) + boottime->free_pool(response_message.headers); +fail: + boottime->close_event(request_token.event); + boottime->close_event(response_token.event); + return EFI_ST_FAILURE; +} + +/* + * Tear down unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + int exit_status = EFI_ST_SUCCESS; + + if (!http_service || !http_protocol_handle) { + efi_st_error("No handles to destroy http instance"); + exit_status = EFI_ST_FAILURE; + } else { + ret = http_service->destroy_child(http_service, http_protocol_handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to destroy http instance"); + exit_status = EFI_ST_FAILURE; + } + efi_st_printf("HTTP Service Binding: child destroyed successfully\n"); + } + + return exit_status; +} + +EFI_UNIT_TEST(http) = { + .name = "http protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +#ifdef CONFIG_SANDBOX + /* + * Running this test on the sandbox requires setting environment + * variable ethact to a network interface connected to a DHCP server and + * ethrotate to 'no'. + */ + .on_request = true, +#endif +}; diff --git a/lib/efi_selftest/efi_selftest_ipconfig.c b/lib/efi_selftest/efi_selftest_ipconfig.c new file mode 100644 index 00000000000..8d594f5e193 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_ipconfig.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * efi_selftest_ipconfig + * + * This unit test covers the IPv4 Config2 Protocol. + * + */ + +#include <efi_selftest.h> +#include <charset.h> +#include <net.h> + +static struct efi_boot_services *boottime; + +static struct efi_ip4_config2_protocol *ip4_config2; +static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; + +/* + * Setup unit test. + * + * Open IPv4 Config2 protocol + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + efi_handle_t *net_handle; + efi_uintn_t num_handles; + efi_handle_t *handles; + + boottime = systable->boottime; + + num_handles = 0; + boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid, + NULL, &num_handles, &handles); + + if (!num_handles) { + efi_st_error("Failed to locate ipv4 config2 protocol\n"); + return EFI_ST_FAILURE; + } + + for (net_handle = handles; num_handles--; net_handle++) { + ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid, + (void **)&ip4_config2, 0, 0, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS || !ip4_config2) + continue; + break; // Get first handle that supports ipv4 + } + + if (!ip4_config2) { + efi_st_error("Failed to open ipv4 config2 protocol\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + enum efi_ip4_config2_policy policy; + efi_uintn_t data_size; + struct efi_ip4_config2_manual_address manual_address; + struct efi_ip4_config2_manual_address orig_address; + u8 netmask[] = {255, 255, 255, 0}; + u8 ip[] = {10, 0, 0, 1}; + + /* Setup may have failed */ + if (!ip4_config2) { + efi_st_error("Setup failure, cannot proceed with test\n"); + return EFI_ST_FAILURE; + } + + /* Set policy to static */ + policy = EFI_IP4_CONFIG2_POLICY_STATIC; + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_POLICY, + sizeof(policy), (void *)&policy); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to set policy\n"); + return EFI_ST_FAILURE; + } + + /* Save original ip address and netmask */ + data_size = sizeof(manual_address); + ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, + &data_size, &orig_address); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to save original ip address and netmask\n"); + return EFI_ST_FAILURE; + } + + /* Set static ip and netmask */ + memcpy(&manual_address.address, ip, + sizeof(struct efi_ipv4_address)); + memcpy(&manual_address.subnet_mask, netmask, + sizeof(struct efi_ipv4_address)); + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, + sizeof(manual_address), &manual_address); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get ip address and netmask\n"); + return EFI_ST_FAILURE; + } + + /* Try to set interface info, this should fail */ + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, 0, NULL); + if (ret == EFI_SUCCESS) { + efi_st_error("Interface info is read-only\n"); + return EFI_ST_FAILURE; + } + + /* Get ip address and netmask and check that they match with the previously set ones */ + data_size = sizeof(manual_address); + ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, + &data_size, &manual_address); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get ip address and netmask\n"); + return EFI_ST_FAILURE; + } + if (memcmp(ip, &manual_address.address, + sizeof(struct efi_ipv4_address)) || + memcmp(netmask, &manual_address.subnet_mask, + sizeof(struct efi_ipv4_address))) { + efi_st_error("Ip address mismatch\n"); + return EFI_ST_FAILURE; + } + + /* Restore original ip address and netmask */ + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, + sizeof(orig_address), &orig_address); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to restore original ip address and netmask\n"); + return EFI_ST_FAILURE; + } + + efi_st_printf("Efi ipconfig test execute succeeded\n"); + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + int exit_status = EFI_ST_SUCCESS; + + return exit_status; +} + +EFI_UNIT_TEST(ipconfig) = { + .name = "IPv4 config2 protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +#ifdef CONFIG_SANDBOX + /* + * Running this test on the sandbox requires setting environment + * variable ethact to a network interface connected to a DHCP server and + * ethrotate to 'no'. + */ + .on_request = true, +#endif +}; diff --git a/lib/hashtable.c b/lib/hashtable.c index e8a59e2dcac..75c263b5053 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -221,11 +221,32 @@ static int do_callback(const struct env_entry *e, const char *name, const char *value, enum env_op op, int flags) { + int ret = 0; + #ifndef CONFIG_XPL_BUILD - if (e->callback) - return e->callback(name, value, op, flags); + static bool in_callback; + + if (!e->callback || in_callback) + return 0; + + /* + * In case there are two variables which each implement env callback + * that performs env_set() on the other variable, the callbacks will + * call each other recursively until the stack runs out. Prevent such + * a recursion from happening. + * + * Example which triggers this behavior: + * static int on_foo(...) { env_set("bar", 0); ... } + * static int on_bar(...) { env_set("foo", 0); ... } + * U_BOOT_ENV_CALLBACK(foo, on_foo); + * U_BOOT_ENV_CALLBACK(bar, on_bar); + */ + in_callback = true; + ret = e->callback(name, value, op, flags); + in_callback = false; #endif - return 0; + + return ret; } /* diff --git a/lib/lmb.c b/lib/lmb.c index 14b9b8466ff..b03237bc06c 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -201,15 +201,6 @@ static long lmb_add_region_flags(struct alist *lmb_rgn_lst, phys_addr_t base, phys_addr_t rgnbase = rgn[i].base; phys_size_t rgnsize = rgn[i].size; phys_size_t rgnflags = rgn[i].flags; - phys_addr_t end = base + size - 1; - phys_addr_t rgnend = rgnbase + rgnsize - 1; - if (rgnbase <= base && end <= rgnend) { - if (flags == rgnflags) - /* Already have this region, so we're done */ - return 0; - else - return -1; /* regions with new flags */ - } ret = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (ret > 0) { @@ -615,6 +606,7 @@ static __maybe_unused void lmb_reserve_common_spl(void) void lmb_add_memory(void) { int i; + phys_addr_t bank_end; phys_size_t size; u64 ram_top = gd->ram_top; struct bd_info *bd = gd->bd; @@ -628,6 +620,8 @@ void lmb_add_memory(void) for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { size = bd->bi_dram[i].size; + bank_end = bd->bi_dram[i].start + size; + if (size) { lmb_add(bd->bi_dram[i].start, size); @@ -639,6 +633,9 @@ void lmb_add_memory(void) if (bd->bi_dram[i].start >= ram_top) lmb_reserve_flags(bd->bi_dram[i].start, size, LMB_NOOVERWRITE); + else if (bank_end > ram_top) + lmb_reserve_flags(ram_top, bank_end - ram_top, + LMB_NOOVERWRITE); } } } diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile index 19e5c6897f5..fe2b64c9acc 100644 --- a/lib/lwip/Makefile +++ b/lib/lwip/Makefile @@ -54,5 +54,5 @@ obj-y += \ lwip/src/core/udp.o \ lwip/src/netif/ethernet.o -obj-$(CONFIG_MBEDTLS_LIB_TLS) += lwip/src/apps/altcp_tls/altcp_tls_mbedtls.o \ +obj-$(CONFIG_$(XPL_)MBEDTLS_LIB_TLS) += lwip/src/apps/altcp_tls/altcp_tls_mbedtls.o \ lwip/src/apps/altcp_tls/altcp_tls_mbedtls_mem.o 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 6643b05ee94..46421588fef 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 @@ -692,7 +692,9 @@ altcp_tls_set_session(struct altcp_pcb *conn, struct altcp_tls_session *session) if (session && conn && conn->state) { altcp_mbedtls_state_t *state = (altcp_mbedtls_state_t *)conn->state; int ret = -1; +#ifdef MBEDTLS_HAVE_TIME if (session->data.MBEDTLS_PRIVATE(start)) +#endif ret = mbedtls_ssl_set_session(&state->ssl_context, &session->data); return ret < 0 ? ERR_VAL : ERR_OK; } diff --git a/lib/lwip/u-boot/lwipopts.h b/lib/lwip/u-boot/lwipopts.h index 88d6faf327a..edac74ff7a2 100644 --- a/lib/lwip/u-boot/lwipopts.h +++ b/lib/lwip/u-boot/lwipopts.h @@ -5,6 +5,8 @@ #ifndef LWIP_UBOOT_LWIPOPTS_H #define LWIP_UBOOT_LWIPOPTS_H +#include <linux/kconfig.h> + #if defined(CONFIG_LWIP_DEBUG) #define LWIP_DEBUG 1 #define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL @@ -154,7 +156,7 @@ #define MEMP_MEM_INIT 1 #define MEM_LIBC_MALLOC 1 -#if defined(CONFIG_MBEDTLS_LIB_TLS) +#if CONFIG_IS_ENABLED(MBEDTLS_LIB_TLS) #define LWIP_ALTCP 1 #define LWIP_ALTCP_TLS 1 #define LWIP_ALTCP_TLS_MBEDTLS 1 diff --git a/lib/mbedtls/mbedtls_def_config.h b/lib/mbedtls/mbedtls_def_config.h index d27f017d084..1d2314e90e4 100644 --- a/lib/mbedtls/mbedtls_def_config.h +++ b/lib/mbedtls/mbedtls_def_config.h @@ -92,9 +92,6 @@ /* Generic options */ #define MBEDTLS_ENTROPY_HARDWARE_ALT -#define MBEDTLS_HAVE_TIME -#define MBEDTLS_PLATFORM_MS_TIME_ALT -#define MBEDTLS_PLATFORM_TIME_MACRO rtc_mktime #define MBEDTLS_PLATFORM_C #define MBEDTLS_SSL_CLI_C #define MBEDTLS_SSL_TLS_C diff --git a/lib/md5.c b/lib/md5.c index 2d8977b2e85..e3eab8a9149 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -272,14 +272,16 @@ md5_wd(const unsigned char *input, unsigned int len, unsigned char output[16], unsigned int chunk_sz) { MD5Context context; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) const unsigned char *end, *curr; int chunk; #endif MD5Init(&context); -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) curr = input; end = input + len; while (curr < end) { diff --git a/lib/sha1.c b/lib/sha1.c index a9d6497c4ce..be502c6126b 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -312,14 +312,16 @@ void sha1_csum_wd(const unsigned char *input, unsigned int ilen, unsigned char *output, unsigned int chunk_sz) { sha1_context ctx; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) const unsigned char *end, *curr; int chunk; #endif sha1_starts (&ctx); -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) curr = input; end = input + ilen; while (curr < end) { diff --git a/lib/sha256.c b/lib/sha256.c index 329802fd827..fb195d988f1 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -273,7 +273,8 @@ void sha256_csum_wd(const unsigned char *input, unsigned int ilen, unsigned char *output, unsigned int chunk_sz) { sha256_context ctx; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) const unsigned char *end; unsigned char *curr; int chunk; @@ -281,7 +282,8 @@ void sha256_csum_wd(const unsigned char *input, unsigned int ilen, sha256_starts(&ctx); -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) curr = (unsigned char *)input; end = input + ilen; while (curr < end) { diff --git a/lib/sha512.c b/lib/sha512.c index ea555ff33eb..0e75c1a943b 100644 --- a/lib/sha512.c +++ b/lib/sha512.c @@ -288,7 +288,8 @@ void sha384_csum_wd(const unsigned char *input, unsigned int ilen, unsigned char *output, unsigned int chunk_sz) { sha512_context ctx; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) const unsigned char *end; unsigned char *curr; int chunk; @@ -296,7 +297,8 @@ void sha384_csum_wd(const unsigned char *input, unsigned int ilen, sha384_starts(&ctx); -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) curr = (unsigned char *)input; end = input + ilen; while (curr < end) { @@ -351,7 +353,8 @@ void sha512_csum_wd(const unsigned char *input, unsigned int ilen, unsigned char *output, unsigned int chunk_sz) { sha512_context ctx; -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) const unsigned char *end; unsigned char *curr; int chunk; @@ -359,7 +362,8 @@ void sha512_csum_wd(const unsigned char *input, unsigned int ilen, sha512_starts(&ctx); -#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) +#if !defined(USE_HOSTCC) && \ + (defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)) curr = (unsigned char *)input; end = input + ilen; while (curr < end) { diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index cc1dfe61cf7..0503c17341f 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -312,7 +312,7 @@ static int _vprintf(struct printf_info *info, const char *fmt, va_list va) *info->bf = 0; info->bf = p; - while (*info->bf++ && width > 0) + while (width > 0 && info->bf && *info->bf++) width--; while (width-- > 0) info->putc(info, lz ? '0' : ' '); diff --git a/lib/uuid.c b/lib/uuid.c index 538a1ba6aa8..97388f597a6 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -175,6 +175,20 @@ static const struct { "Firmware Management", EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID }, +#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL) + { + "HTTP", + EFI_HTTP_PROTOCOL_GUID, + }, + { + "HTTP Service Binding", + EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID, + }, + { + "IPv4 Config2", + EFI_IP4_CONFIG2_PROTOCOL_GUID, + }, +#endif /* Configuration table GUIDs */ { "ACPI table", |