From patchwork Sat Apr 6 14:01:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 786486 Delivered-To: patch@linaro.org Received: by 2002:a05:6000:1101:b0:343:f27d:c44e with SMTP id z1csp628613wrw; Sat, 6 Apr 2024 07:03:51 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXT4YXMukUSbjLVqleQPEAOromAZGC4aPjtBznByuD8VSZ61q0lzQsux7SEacX9exsABBxWjILB5Yt/wrENtxeG X-Google-Smtp-Source: AGHT+IEk2DePpSKikMt5aW/SbkpbuZ1LDYkpezMVlTY8P3NS3MX01yUsGJQF5GK5LgJQ+PtbpFqG X-Received: by 2002:a17:906:aeda:b0:a4e:1b02:81d6 with SMTP id me26-20020a170906aeda00b00a4e1b0281d6mr2698381ejb.10.1712412231201; Sat, 06 Apr 2024 07:03:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712412231; cv=none; d=google.com; s=arc-20160816; b=m27o2N4HnOoFbiR/lj2KZ4PFehBe3mMKov0rLczxhdZXRRQWQg12NDhXQ/M/6mNo+N bZrctLAjm03b6JroJFlEkdkZN7rwoxCrhgGeBM1pQb0APO3XBLRlRFvaSOsLtyQvpMmD zG9TalwPvory8BNg1qVvoOtbj0NvWz4j+FBO+qeCRSVZj8psIvrNjIQBTgH2mxXm/riW aCB2FVl6pcx+UHX3cvq700tkt0OZV0aBtGrh0v6Ew3EuYxkVBHy0uLlZ3+4iGoBU8I13 rcG1s6YAAQxMnFOZvG4agyZiByhcY1/mDzaTHggUfQChJMOxAc2TSbt+Xx8i91iQgn3e Hm5Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=Xfx58Fx+VretUB6RvdI5IVG6BjbRnfg8/KNb6nU4VHM=; fh=QIJlrBEqCQUlXEuFOoM0fROuZa77jE4reeiI8CilqhY=; b=impjAazYYf251Ng44g6j8TaNiMnvuiI+HAxQ82gLH+Yej9bryi7CCxM8o2js0RyywO mKNjuFPGtNxRAnJCfU2WgI2/nQOVqDhdRAIW8bb7OPUTJUQ1Hz7/+1qEBocQAA0HGP7/ olp7iXiWheo/QmAzO3+F/illuJuiLoXx+bfZOTbywp1I6nvUNs2Vn6cNYwIQmfiM2dMl SUMIuXFKryv7bywleO5XiwsHSrbiwcMcvZ4410wmB8WOV4ZAioca8yf8NLJ+LGq+M/jr TjjojZu95pMwQfmDnk7Vhghe2Fu/jIgibl4D8+Pc+XBBiaICgEXC8J/UEs5/hV1D9rKl zhPA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=uzJN3yMY; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id s13-20020a17090699cd00b00a51b6dd77d7si799429ejn.48.2024.04.06.07.03.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 06 Apr 2024 07:03:51 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=uzJN3yMY; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 47E74882C5; Sat, 6 Apr 2024 16:03:01 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="uzJN3yMY"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DD8F387EA8; Sat, 6 Apr 2024 16:02:59 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 43BAE88177 for ; Sat, 6 Apr 2024 16:02:57 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-4163de6d2afso2192275e9.0 for ; Sat, 06 Apr 2024 07:02:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1712412177; x=1713016977; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Xfx58Fx+VretUB6RvdI5IVG6BjbRnfg8/KNb6nU4VHM=; b=uzJN3yMYyXuCOcPd3Zva/h3RXK6ftRsJO4f5cpkgB5B7ezj5bssSJ6etOgmYgpf3/H b0XYqtHT7VJSInlVo18/j3wf6V4yYnzrFa/c7bDjy/jn4r5MEKlYhgvcDezS4Y5kfVdM pC8uFmssAM0qrH5QYgDrK0iN8Wwbgc1/EhMzoQCz93qSVd+Wa1FbtEappSl1bZNEUNlf Uh91/1PoBBApJDv2ZeIZbo30L+ApfpVvcm8/VmeoMggEx8mPuNhP0EDFu6X82w+J/p9s 9v2C/DunKr4D/7O29ar7F2VZAdHDNkYLtotM9XKeB4GEwVGi3iXtELZmaxKzG5nSx0/e e6Iw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712412177; x=1713016977; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Xfx58Fx+VretUB6RvdI5IVG6BjbRnfg8/KNb6nU4VHM=; b=cmg+hXf99JrZp8IT2uabV6SOAgFkcC3TOXE+AiA9beTgiH8/SQ6bhMMAU2vvMZMsuN h/5MzzaVQIyQsRjQMFDplJw7Kiw6Znc9XkR1VkYMOKEAYZ3MRSwaeLoTl1NHxa8+H7Ax mqOeERM0g7pdlfC0FFoxC/qSJjkoFl/Ew0GB1s/XA/1WmWhAprLyfUYHFaMIpt1T88gO Gw4PvWT9UipkUjkHzbojn6gonapJZ5fzun5uv4icysCZKfK/acx6y6Dqi6KeWWd/GpFh PZQI/XZi1JBuXYNd9EYmLNAaISD9C7klvx+5e16hes5pwdsWIuFDdW8pWLeGrkkA9zU0 dWUw== X-Forwarded-Encrypted: i=1; AJvYcCVYj4nBSGp1kENMdTryY+/gibVQcyxQcjN6wYJwWLGY1q0BGg/iR5/RK79xI/6v9xZCfiipK8ux2LFasu/vNEZHfDv3vw== X-Gm-Message-State: AOJu0YzZNjGlHyTaOYf14fjP3T50R30DFf8tPwyma9mCU/To37oxyWEi tNA6SNDJQHCDL3xtaVDTohOMCmjDHqFKiycoDuXrRRX94y8ZT6yaOR7OPm3xMPM= X-Received: by 2002:a05:600c:1f07:b0:414:7e73:1f8c with SMTP id bd7-20020a05600c1f0700b004147e731f8cmr3674139wmb.37.1712412176726; Sat, 06 Apr 2024 07:02:56 -0700 (PDT) Received: from hades.. (ppp089210071137.access.hol.gr. [89.210.71.137]) by smtp.gmail.com with ESMTPSA id j19-20020a05600c1c1300b004163de6cfabsm1729756wms.11.2024.04.06.07.02.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 06 Apr 2024 07:02:56 -0700 (PDT) From: Ilias Apalodimas To: xypron.glpk@gmx.de, kettenis@openbsd.org Cc: caleb.connolly@linaro.org, sumit.garg@linaro.org, quic_llindhol@quicinc.com, ardb@kernel.org, pbrobinson@gmail.com, pjones@redhat.com, Ilias Apalodimas , Tom Rini , Masahisa Kojima , AKASHI Takahiro , Bin Meng , Raymond Mao , Simon Glass , Abdellatif El Khlifi , Sughosh Ganu , Weizhao Ouyang , Alper Nebi Yasak , u-boot@lists.denx.de Subject: [PATCH v1 3/4] efi_loader: add an EFI variable with the variable file contents Date: Sat, 6 Apr 2024 17:01:59 +0300 Message-Id: <20240406140203.248211-9-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20240406140203.248211-1-ilias.apalodimas@linaro.org> References: <20240406140203.248211-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Previous patches enabled SetVariableRT using a RAM backend. Although EBBR [0] defines a variable format we can teach userspace tools and write the altered variables, it's better if we skip the ABI requirements completely. So let's add a new variable, in its own namespace called "VarToFile" which contains a binary dump of the updated RT, BS and, NV variables. Some adjustments are needed to do that. Currently we discard BS-only variables in EBS(). We need to preserve those on the OS RAM backend that exposes the variables. Since BS-only variables can't appear at RT we need to move the memory masking checks from efi_var_collect() to efi_get_next_variable_name_mem()/efi_get_variable_mem() and do the filtering at runtime. We also need to make efi_var_collect() available at runtime, in order to construct the "VarToFile" buffer with BS, RT & NV variables. All users and applications (for linux) have to do when updating a variable is dd that variable in the file described by "RTStorageVolatile". Linux efivarfs uses a first 4 bytes of the output to represent attributes in little-endian format. So, storing variables works like this: $~ efibootmgr -n 0001 $~ dd if=/sys/firmware/efi/efivars/VarToFile-b2ac5fc9-92b7-4acd-aeac-11e818c3130c of=/boot/efi/ubootefi.var skip=4 bs=1 [0] https://arm-software.github.io/ebbr/index.html#document-chapter5-variable-storage Suggested-by:Ard Biesheuvel # dumping all variables to a variable Signed-off-by: Ilias Apalodimas --- include/efi_variable.h | 15 +++- lib/efi_loader/efi_boottime.c | 2 + lib/efi_loader/efi_var_common.c | 43 +++++------ lib/efi_loader/efi_var_file.c | 1 - lib/efi_loader/efi_var_mem.c | 90 ++++++++++------------- lib/efi_loader/efi_variable.c | 118 ++++++++++++++++++++++++------ lib/efi_loader/efi_variable_tee.c | 1 - 7 files changed, 164 insertions(+), 106 deletions(-) -- 2.37.2 diff --git a/include/efi_variable.h b/include/efi_variable.h index 42a2b7c52bef..8963339b9bb6 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -271,13 +271,15 @@ const efi_guid_t *efi_auth_var_get_guid(const u16 *name); * * @variable_name_size: size of variable_name buffer in bytes * @variable_name: name of uefi variable's name in u16 + * @mask: bitmask with required attributes of variables to be collected. + * variables are only collected if all of the required * @vendor: vendor's guid * * Return: status code */ efi_status_t __efi_runtime efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_name, - efi_guid_t *vendor); + efi_guid_t *vendor, u32 mask); /** * efi_get_variable_mem() - Runtime common code across efi variable * implementations for GetVariable() from @@ -289,12 +291,14 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_na * @data_size: size of the buffer to which the variable value is copied * @data: buffer to which the variable value is copied * @timep: authentication time (seconds since start of epoch) + * @mask: bitmask with required attributes of variables to be collected. + * variables are only collected if all of the required * Return: status code */ efi_status_t __efi_runtime efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data, - u64 *timep); + u64 *timep, u32 mask); /** * efi_get_variable_runtime() - runtime implementation of GetVariable() @@ -334,4 +338,11 @@ efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, */ void efi_var_buf_update(struct efi_var_file *var_buf); +/** + * efi_prealloced_rt_memory() - Get a pointer to preallocated EFI memory + * available at runtime + * + * Return: pointer to preallocated runtime usable buffer + */ +void __efi_runtime *efi_prealloced_rt_memory(void); #endif diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1951291747cd..39481c89a688 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -97,6 +97,8 @@ const efi_guid_t efi_guid_load_file_protocol = EFI_LOAD_FILE_PROTOCOL_GUID; 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; +/* used by special U-Boot variables during SetVariableRT */ +const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID; static efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c index 07b9603d49f3..4abc90e411e7 100644 --- a/lib/efi_loader/efi_var_common.c +++ b/lib/efi_loader/efi_var_common.c @@ -182,7 +182,8 @@ efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid, { efi_status_t ret; - ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL); + ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, + data, NULL, EFI_VARIABLE_RUNTIME_ACCESS); /* Remove EFI_VARIABLE_READ_ONLY flag */ if (attributes) @@ -195,7 +196,8 @@ efi_status_t __efi_runtime EFIAPI efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *guid) { - return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid); + return efi_get_next_variable_name_mem(variable_name_size, variable_name, + guid, EFI_VARIABLE_RUNTIME_ACCESS); } /** @@ -427,18 +429,15 @@ void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size) * * Return: Status code */ -efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp, - u32 check_attr_mask) +efi_status_t __efi_runtime +efi_var_collect(struct efi_var_file **bufp, loff_t *lenp, u32 check_attr_mask) { size_t len = EFI_VAR_BUF_SIZE; struct efi_var_file *buf; struct efi_var_entry *var, *old_var; size_t old_var_name_length = 2; - *bufp = NULL; /* Avoid double free() */ - buf = calloc(1, len); - if (!buf) - return EFI_OUT_OF_RESOURCES; + buf = (struct efi_var_file *)efi_prealloced_rt_memory(); var = buf->var; old_var = var; for (;;) { @@ -451,32 +450,26 @@ efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t * return EFI_BUFFER_TOO_SMALL; var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name; - memcpy(var->name, old_var->name, old_var_name_length); - guidcpy(&var->guid, &old_var->guid); - ret = efi_get_next_variable_name_int( - &var_name_length, var->name, &var->guid); + efi_memcpy_runtime(var->name, old_var->name, old_var_name_length); + efi_memcpy_runtime(&var->guid, &old_var->guid, sizeof(efi_guid_t)); + ret = efi_get_next_variable_name_mem(&var_name_length, var->name, + &var->guid, check_attr_mask); if (ret == EFI_NOT_FOUND) break; - if (ret != EFI_SUCCESS) { - free(buf); + if (ret != EFI_SUCCESS) return ret; - } old_var_name_length = var_name_length; old_var = var; data = (u8 *)var->name + old_var_name_length; data_length = (uintptr_t)buf + len - (uintptr_t)data; - ret = efi_get_variable_int(var->name, &var->guid, + ret = efi_get_variable_mem(var->name, &var->guid, &var->attr, &data_length, data, - &var->time); - if (ret != EFI_SUCCESS) { - free(buf); + &var->time, check_attr_mask); + if (ret != EFI_SUCCESS) return ret; - } - if ((var->attr & check_attr_mask) == check_attr_mask) { - var->length = data_length; - var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8); - } + var->length = data_length; + var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8); } buf->reserved = 0; @@ -490,5 +483,3 @@ efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t * return EFI_SUCCESS; } - - diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c index 413e1794e88c..8614e3d34706 100644 --- a/lib/efi_loader/efi_var_file.c +++ b/lib/efi_loader/efi_var_file.c @@ -83,7 +83,6 @@ efi_status_t efi_var_to_file(void) error: if (ret != EFI_SUCCESS) log_err("Failed to persist EFI variables\n"); - free(buf); return ret; #else return EFI_SUCCESS; diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c index 6c21cec5d457..a7af0604733e 100644 --- a/lib/efi_loader/efi_var_mem.c +++ b/lib/efi_loader/efi_var_mem.c @@ -16,6 +16,7 @@ * relocation during SetVirtualAddressMap(). */ static struct efi_var_file __efi_runtime_data *efi_var_buf; +static void __efi_runtime_data *efi_rt_prealloced; static struct efi_var_entry __efi_runtime_data *efi_current_var; /** @@ -184,53 +185,6 @@ u64 __efi_runtime efi_var_mem_free(void) sizeof(struct efi_var_entry); } -/** - * efi_var_mem_bs_del() - delete boot service only variables - */ -static void efi_var_mem_bs_del(void) -{ - struct efi_var_entry *var = efi_var_buf->var; - - for (;;) { - struct efi_var_entry *last; - - last = (struct efi_var_entry *) - ((uintptr_t)efi_var_buf + efi_var_buf->length); - if (var >= last) - break; - if (var->attr & EFI_VARIABLE_RUNTIME_ACCESS) { - u16 *data; - - /* skip variable */ - for (data = var->name; *data; ++data) - ; - ++data; - var = (struct efi_var_entry *) - ALIGN((uintptr_t)data + var->length, 8); - } else { - /* delete variable */ - efi_var_mem_del(var); - } - } -} - -/** - * efi_var_mem_notify_exit_boot_services() - ExitBootService callback - * - * @event: callback event - * @context: callback context - */ -static void EFIAPI -efi_var_mem_notify_exit_boot_services(struct efi_event *event, void *context) -{ - EFI_ENTRY("%p, %p", event, context); - - /* Delete boot service only variables */ - efi_var_mem_bs_del(); - - EFI_EXIT(EFI_SUCCESS); -} - /** * efi_var_mem_notify_exit_boot_services() - SetVirtualMemoryMap callback * @@ -241,6 +195,7 @@ static void EFIAPI __efi_runtime efi_var_mem_notify_virtual_address_map(struct efi_event *event, void *context) { efi_convert_pointer(0, (void **)&efi_var_buf); + efi_convert_pointer(0, (void **)&efi_rt_prealloced); efi_current_var = NULL; } @@ -261,13 +216,21 @@ efi_status_t efi_var_mem_init(void) efi_var_buf->magic = EFI_VAR_FILE_MAGIC; efi_var_buf->length = (uintptr_t)efi_var_buf->var - (uintptr_t)efi_var_buf; - /* crc32 for 0 bytes = 0 */ - ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, - efi_var_mem_notify_exit_boot_services, NULL, - NULL, &event); + /* + * efi_var_collect() needs to run at runtime and provide us + * copies of variables used for the VarToFile variable. + * Preallocate memory equal to the variable storage and + * preserve it to copy variables around + */ + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + efi_size_in_pages(EFI_VAR_BUF_SIZE), + &memory); if (ret != EFI_SUCCESS) return ret; + efi_rt_prealloced = (void *)(uintptr_t)memory; + ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_CALLBACK, efi_var_mem_notify_virtual_address_map, NULL, NULL, &event); @@ -279,7 +242,7 @@ efi_status_t efi_var_mem_init(void) efi_status_t __efi_runtime efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data, - u64 *timep) + u64 *timep, u32 mask) { efi_uintn_t old_size; struct efi_var_entry *var; @@ -291,6 +254,9 @@ efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, if (!var) return EFI_NOT_FOUND; + if (mask && !((var->attr & mask) == mask)) + return EFI_NOT_FOUND; + if (attributes) *attributes = var->attr; if (timep) @@ -315,7 +281,8 @@ efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, efi_status_t __efi_runtime efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, - u16 *variable_name, efi_guid_t *vendor) + u16 *variable_name, efi_guid_t *vendor, + u32 mask) { struct efi_var_entry *var; efi_uintn_t len, old_size; @@ -324,6 +291,7 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, if (!variable_name_size || !variable_name || !vendor) return EFI_INVALID_PARAMETER; +skip: len = *variable_name_size >> 1; if (u16_strnlen(variable_name, len) == len) return EFI_INVALID_PARAMETER; @@ -347,6 +315,11 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, efi_memcpy_runtime(variable_name, var->name, *variable_name_size); efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t)); + if (mask && !((var->attr & mask) == mask)) { + *variable_name_size = old_size; + goto skip; + } + return EFI_SUCCESS; } @@ -354,3 +327,14 @@ void efi_var_buf_update(struct efi_var_file *var_buf) { memcpy(efi_var_buf, var_buf, EFI_VAR_BUF_SIZE); } + +void __efi_runtime *efi_prealloced_rt_memory(void) +{ + char *s; + int count = EFI_VAR_BUF_SIZE; + + s = (char *)efi_rt_prealloced; + while (count--) + *s++ = 0; + return efi_rt_prealloced; +} diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index f97c8c57f75c..4f529169ea54 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -22,6 +22,8 @@ #include #include +static const efi_guid_t __efi_runtime_data efi_guid_efi_rt_var_file = + U_BOOT_EFI_RT_VAR_FILE_GUID; #ifdef CONFIG_EFI_SECURE_BOOT /** @@ -208,14 +210,16 @@ efi_get_variable_int(const u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data, u64 *timep) { - return efi_get_variable_mem(variable_name, vendor, attributes, data_size, data, timep); + return efi_get_variable_mem(variable_name, vendor, attributes, data_size, + data, timep, 0); } efi_status_t __efi_runtime efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *vendor) { - return efi_get_next_variable_name_mem(variable_name_size, variable_name, vendor); + return efi_get_next_variable_name_mem(variable_name_size, variable_name, + vendor, 0); } /** @@ -479,6 +483,8 @@ if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { efi_uintn_t ret; bool append, delete; u64 time = 0; + struct efi_var_file *buf; + loff_t len; /* * Authenticated variables are not supported the rest of the checks @@ -520,30 +526,60 @@ if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { return EFI_NOT_FOUND; } - if (delete) { + if (!delete) { + /* + * We always insert new variabes and delete the old one when + * appending + */ + len = 2 * (u16_strlen(variable_name) + 1) + data_size + + sizeof(struct efi_var_entry); + if (var && append) + len += 2 * var->length; + /* + * We will copy the variable update into VarToFile, + * account for it twice + */ + len *= 2; + if (len > efi_var_mem_free()) + return EFI_OUT_OF_RESOURCES; + if (append && var) { + u16 *old_data = var->name; + + for (; *old_data; ++old_data) + ; + ++old_data; + ret = efi_var_mem_ins(variable_name, vendor, attributes, + var->length, old_data, data_size, + data, time); + } else { + ret = efi_var_mem_ins(variable_name, vendor, attributes, + data_size, data, 0, NULL, time); + } + } else { /* EFI_NOT_FOUND has been handled before */ attributes = var->attr; ret = EFI_SUCCESS; - } else if (append && var) { - u16 *old_data = var->name; - - for (; *old_data; ++old_data) - ; - ++old_data; - ret = efi_var_mem_ins(variable_name, vendor, attributes, - var->length, old_data, data_size, data, - time); - } else { - ret = efi_var_mem_ins(variable_name, vendor, attributes, - data_size, data, 0, NULL, time); } - if (ret != EFI_SUCCESS) return ret; /* We are always inserting new variables, get rid of the old copy */ efi_var_mem_del(var); - return EFI_SUCCESS; + /* + * Create a volatile variable that userspace apps can dd and + * update the file contents + */ + ret = efi_var_collect(&buf, &len, EFI_VARIABLE_NON_VOLATILE); + if (ret != EFI_SUCCESS) + return ret; + var = efi_var_mem_find(&efi_guid_efi_rt_var_file, u"VarToFile", NULL); + if (var) + efi_var_mem_del(var); + + ret = efi_var_mem_ins(u"VarToFile", &efi_guid_efi_rt_var_file, + EFI_VARIABLE_RUNTIME_ACCESS, len, buf, 0, + NULL, time); + return ret; } else return EFI_UNSUPPORTED; @@ -557,11 +593,11 @@ void efi_variables_boot_exit_notify(void) const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID; const efi_guid_t rt_prop_guid = EFI_RT_PROPERTIES_TABLE_GUID; efi_status_t ret; + struct efi_var_file *buf; + loff_t len; + bool fail = false; if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { - struct efi_rt_properties_table *rt_prop = - efi_get_configuration_table(&rt_prop_guid); - ret = efi_set_variable_int(u"RTStorageVolatile", &efi_guid_efi_rt_var_file, EFI_VARIABLE_BOOTSERVICE_ACCESS | @@ -569,11 +605,47 @@ void efi_variables_boot_exit_notify(void) EFI_VARIABLE_READ_ONLY, sizeof(EFI_VAR_FILE_NAME), EFI_VAR_FILE_NAME, false); + if (ret != EFI_SUCCESS) { + fail = true; + goto out; + } + + ret = efi_var_collect(&buf, &len, EFI_VARIABLE_NON_VOLATILE); + if (ret != EFI_SUCCESS) { + fail = true; + goto out; + } + + ret = efi_set_variable_int(u"VarToFile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + len, + buf, false); if (ret != EFI_SUCCESS) - rt_prop->runtime_services_supported |= ~EFI_RT_SUPPORTED_SET_VARIABLE; - else - log_err("Can't RTStorage. SetVariableRT won't be available\n"); + fail = true; +out: + if (fail) { + efi_set_variable_int(u"RTStorageVolatile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, 0, 0, + false); + efi_set_variable_int(u"VarToFile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, 0, 0, + false); + } else { + struct efi_rt_properties_table *rt_prop = + efi_get_configuration_table(&rt_prop_guid); + + rt_prop->runtime_services_supported |= + EFI_RT_SUPPORTED_SET_VARIABLE; + } } + /* Switch variable services functions to runtime version */ efi_runtime_services.get_variable = efi_get_variable_runtime; efi_runtime_services.get_next_variable_name = diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index dde135fd9f81..9d0e270591ea 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -969,7 +969,6 @@ void efi_variables_boot_exit_notify(void) log_err("Can't populate EFI variables. No runtime variables will be available\n"); else efi_var_buf_update(var_buf); - free(var_buf); /* Update runtime service table */ efi_runtime_services.query_variable_info =