ffbae842f4
- Add support for pre-loading EFI environment variables from efiboot.plist. - Add support for device tree overlays specified in efiboot.plist. (Man page for efiboot forthcoming.)
197 lines
4.8 KiB
C
197 lines
4.8 KiB
C
/* $NetBSD: efienv.c,v 1.4 2019/04/21 22:30:41 thorpej Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2019 Jason R. Thorpe
|
|
* Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "efiboot.h"
|
|
#include "efienv.h"
|
|
|
|
#define EFIBOOT_VENDOR_GUID \
|
|
{ 0x97cde9bd, 0xac88, 0x4cf9, { 0x84, 0x86, 0x01, 0x33, 0x0f, 0xe1, 0x95, 0xd4 } }
|
|
|
|
static EFI_GUID EfibootVendorGuid = EFIBOOT_VENDOR_GUID;
|
|
|
|
void
|
|
efi_env_from_efibootplist(void)
|
|
{
|
|
/*
|
|
* We support pre-loading the EFI environment from efiboot.plist
|
|
* using the following schema:
|
|
*
|
|
* <key>environment-variables</key>
|
|
* <dict>
|
|
* <key>varname1</key>
|
|
* <string>value_for_varname1</string>
|
|
* <key>varname2</key>
|
|
* <string>value_for_varname2</string>
|
|
* </dict>
|
|
*
|
|
* Only string values are supported.
|
|
*/
|
|
prop_dictionary_t environment;
|
|
prop_dictionary_keysym_t key;
|
|
prop_string_t value;
|
|
prop_object_iterator_t iter;
|
|
|
|
const char *env_key;
|
|
char *env_value;
|
|
|
|
environment = prop_dictionary_get(efibootplist,
|
|
"environment-variables");
|
|
if (environment == NULL)
|
|
return;
|
|
|
|
iter = prop_dictionary_iterator(environment);
|
|
if (iter == NULL)
|
|
goto failed;
|
|
|
|
while ((key = prop_object_iterator_next(iter)) != NULL) {
|
|
value = prop_dictionary_get_keysym(environment, key);
|
|
if (value == NULL) {
|
|
printf("boot: env: failed to get value for '%s'\n",
|
|
prop_dictionary_keysym_cstring_nocopy(key));
|
|
continue;
|
|
}
|
|
if (prop_object_type(value) != PROP_TYPE_STRING) {
|
|
printf("boot: env: value for '%s' is not a string\n",
|
|
prop_dictionary_keysym_cstring_nocopy(key));
|
|
continue;
|
|
}
|
|
/* XXX __UNCONST because gnuefi */
|
|
env_key = prop_dictionary_keysym_cstring_nocopy(key);;
|
|
env_value = __UNCONST(prop_string_cstring_nocopy(value));;
|
|
#ifdef EFIBOOT_DEBUG
|
|
printf(">> efiboot.plist env: '%s' = '%s'\n", env_key,
|
|
env_value);
|
|
#endif
|
|
efi_env_set(env_key, env_value);
|
|
}
|
|
prop_object_iterator_release(iter);
|
|
|
|
return;
|
|
|
|
failed:
|
|
printf("boot: failed to load environment from efiboot.plist");
|
|
}
|
|
|
|
void
|
|
efi_env_set(const char *key, char *val)
|
|
{
|
|
EFI_STATUS status;
|
|
CHAR16 *ukey;
|
|
size_t len;
|
|
|
|
ukey = NULL;
|
|
utf8_to_ucs2(key, &ukey, &len);
|
|
status = LibSetNVVariable(ukey, &EfibootVendorGuid, strlen(val) + 1, val);
|
|
FreePool(ukey);
|
|
|
|
if (EFI_ERROR(status))
|
|
printf("env: failed to set variable '%s': %#lx\n", key, (u_long)status);
|
|
}
|
|
|
|
char *
|
|
efi_env_get(const char *key)
|
|
{
|
|
CHAR16 *ukey;
|
|
size_t len;
|
|
char *ret;
|
|
|
|
ukey = NULL;
|
|
utf8_to_ucs2(key, &ukey, &len);
|
|
ret = LibGetVariable(ukey, &EfibootVendorGuid);
|
|
FreePool(ukey);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
efi_env_clear(const char *key)
|
|
{
|
|
CHAR16 *ukey;
|
|
size_t len;
|
|
|
|
ukey = NULL;
|
|
utf8_to_ucs2(key, &ukey, &len);
|
|
LibDeleteVariable(ukey, &EfibootVendorGuid);
|
|
FreePool(ukey);
|
|
}
|
|
|
|
void
|
|
efi_env_reset(void)
|
|
{
|
|
EFI_STATUS status;
|
|
CHAR16 ukey[256];
|
|
EFI_GUID vendor;
|
|
UINTN size;
|
|
|
|
retry:
|
|
ukey[0] = '\0';
|
|
vendor = NullGuid;
|
|
|
|
for (;;) {
|
|
size = sizeof(ukey);
|
|
status = uefi_call_wrapper(RT->GetNextVariableName, 3, &size, ukey, &vendor);
|
|
if (status != EFI_SUCCESS)
|
|
break;
|
|
|
|
if (CompareGuid(&vendor, &EfibootVendorGuid) == 0) {
|
|
LibDeleteVariable(ukey, &vendor);
|
|
goto retry;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
efi_env_print(void)
|
|
{
|
|
EFI_STATUS status;
|
|
CHAR16 ukey[256];
|
|
EFI_GUID vendor;
|
|
UINTN size;
|
|
char *val;
|
|
|
|
ukey[0] = '\0';
|
|
vendor = NullGuid;
|
|
|
|
for (;;) {
|
|
size = sizeof(ukey);
|
|
status = uefi_call_wrapper(RT->GetNextVariableName, 3, &size, ukey, &vendor);
|
|
if (status != EFI_SUCCESS)
|
|
break;
|
|
|
|
if (CompareGuid(&vendor, &EfibootVendorGuid) != 0)
|
|
continue;
|
|
|
|
Print(L"\"%s\" = ", ukey);
|
|
|
|
val = LibGetVariable(ukey, &vendor);
|
|
printf("\"%s\"\n", val);
|
|
FreePool(val);
|
|
}
|
|
}
|