xref: /freebsd-src/stand/efi/libefi/env.c (revision 3e15b01d6914c927e37d1699645783acf286655c)
1ca987d46SWarner Losh /*
252467047SWarner Losh  * Copyright (c) 2015 Netflix, Inc.
3ca987d46SWarner Losh  *
4ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
5ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
6ca987d46SWarner Losh  * are met:
7ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
8ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
9ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
10ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
11ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
12ca987d46SWarner Losh  *
13ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23ca987d46SWarner Losh  * SUCH DAMAGE.
24ca987d46SWarner Losh  */
25ca987d46SWarner Losh 
26ca987d46SWarner Losh #include <stand.h>
27ca987d46SWarner Losh #include <string.h>
28ca987d46SWarner Losh #include <efi.h>
2965641822SToomas Soome #include <efichar.h>
30ca987d46SWarner Losh #include <efilib.h>
3165641822SToomas Soome #include <efigpt.h>	/* Partition GUIDS */
3265641822SToomas Soome #include <Guid/MemoryTypeInformation.h>
3365641822SToomas Soome #include <Guid/MtcVendor.h>
3465641822SToomas Soome #include <Guid/ZeroGuid.h>
3565641822SToomas Soome #include <Protocol/EdidActive.h>
3665641822SToomas Soome #include <Protocol/EdidDiscovered.h>
37ca987d46SWarner Losh #include <uuid.h>
38ca987d46SWarner Losh #include <stdbool.h>
3965641822SToomas Soome #include <sys/param.h>
40ca987d46SWarner Losh #include "bootstrap.h"
41ca987d46SWarner Losh 
4265641822SToomas Soome /*
4365641822SToomas Soome  * About ENABLE_UPDATES
4465641822SToomas Soome  *
4565641822SToomas Soome  * The UEFI variables are identified only by GUID and name, there is no
4665641822SToomas Soome  * way to (auto)detect the type for the value, so we need to process the
4765641822SToomas Soome  * variables case by case, as we do learn about them.
4865641822SToomas Soome  *
4965641822SToomas Soome  * While showing the variable name and the value is safe, we must not store
5065641822SToomas Soome  * random values nor allow removing (random) variables.
5165641822SToomas Soome  *
5265641822SToomas Soome  * Since we do have stub code to set/unset the variables, I do want to keep
5365641822SToomas Soome  * it to make the future development a bit easier, but the updates are disabled
5465641822SToomas Soome  * by default till:
5565641822SToomas Soome  *	a) the validation and data translation to values is properly implemented
5665641822SToomas Soome  *	b) We have established which variables we do allow to be updated.
5765641822SToomas Soome  * Therefore the set/unset code is included only for developers aid.
5865641822SToomas Soome  */
5965641822SToomas Soome 
6065641822SToomas Soome static struct efi_uuid_mapping {
6165641822SToomas Soome 	const char *efi_guid_name;
6265641822SToomas Soome 	EFI_GUID efi_guid;
6365641822SToomas Soome } efi_uuid_mapping[] = {
6465641822SToomas Soome 	{ .efi_guid_name = "global", .efi_guid = EFI_GLOBAL_VARIABLE },
6565641822SToomas Soome 	{ .efi_guid_name = "freebsd", .efi_guid = FREEBSD_BOOT_VAR_GUID },
6665641822SToomas Soome 	/* EFI Systab entry names. */
6765641822SToomas Soome 	{ .efi_guid_name = "MPS Table", .efi_guid = MPS_TABLE_GUID },
6865641822SToomas Soome 	{ .efi_guid_name = "ACPI Table", .efi_guid = ACPI_TABLE_GUID },
6965641822SToomas Soome 	{ .efi_guid_name = "ACPI 2.0 Table", .efi_guid = ACPI_20_TABLE_GUID },
7065641822SToomas Soome 	{ .efi_guid_name = "SMBIOS Table", .efi_guid = SMBIOS_TABLE_GUID },
7165641822SToomas Soome 	{ .efi_guid_name = "SMBIOS3 Table", .efi_guid = SMBIOS3_TABLE_GUID },
7265641822SToomas Soome 	{ .efi_guid_name = "DXE Table", .efi_guid = DXE_SERVICES_TABLE_GUID },
7365641822SToomas Soome 	{ .efi_guid_name = "HOB List Table", .efi_guid = HOB_LIST_TABLE_GUID },
7465641822SToomas Soome 	{ .efi_guid_name = EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
7565641822SToomas Soome 	    .efi_guid = EFI_MEMORY_TYPE_INFORMATION_GUID },
7665641822SToomas Soome 	{ .efi_guid_name = "Debug Image Info Table",
7765641822SToomas Soome 	    .efi_guid = DEBUG_IMAGE_INFO_TABLE_GUID },
7865641822SToomas Soome 	{ .efi_guid_name = "FDT Table", .efi_guid = FDT_TABLE_GUID },
7965641822SToomas Soome 	/*
8065641822SToomas Soome 	 * Protocol names for debug purposes.
8165641822SToomas Soome 	 * Can be removed along with lsefi command.
8265641822SToomas Soome 	 */
8365641822SToomas Soome 	{ .efi_guid_name = "device path", .efi_guid = DEVICE_PATH_PROTOCOL },
8465641822SToomas Soome 	{ .efi_guid_name = "block io", .efi_guid = BLOCK_IO_PROTOCOL },
8565641822SToomas Soome 	{ .efi_guid_name = "disk io", .efi_guid = DISK_IO_PROTOCOL },
8665641822SToomas Soome 	{ .efi_guid_name = "disk info", .efi_guid =
8765641822SToomas Soome 	    EFI_DISK_INFO_PROTOCOL_GUID },
8865641822SToomas Soome 	{ .efi_guid_name = "simple fs",
8965641822SToomas Soome 	    .efi_guid = SIMPLE_FILE_SYSTEM_PROTOCOL },
9065641822SToomas Soome 	{ .efi_guid_name = "load file", .efi_guid = LOAD_FILE_PROTOCOL },
9165641822SToomas Soome 	{ .efi_guid_name = "device io", .efi_guid = DEVICE_IO_PROTOCOL },
9265641822SToomas Soome 	{ .efi_guid_name = "unicode collation",
9365641822SToomas Soome 	    .efi_guid = UNICODE_COLLATION_PROTOCOL },
9465641822SToomas Soome 	{ .efi_guid_name = "unicode collation2",
9565641822SToomas Soome 	    .efi_guid = EFI_UNICODE_COLLATION2_PROTOCOL_GUID },
9665641822SToomas Soome 	{ .efi_guid_name = "simple network",
9765641822SToomas Soome 	    .efi_guid = EFI_SIMPLE_NETWORK_PROTOCOL },
9865641822SToomas Soome 	{ .efi_guid_name = "simple text output",
9965641822SToomas Soome 	    .efi_guid = SIMPLE_TEXT_OUTPUT_PROTOCOL },
10065641822SToomas Soome 	{ .efi_guid_name = "simple text input",
10165641822SToomas Soome 	    .efi_guid = SIMPLE_TEXT_INPUT_PROTOCOL },
10265641822SToomas Soome 	{ .efi_guid_name = "simple text ex input",
10365641822SToomas Soome 	    .efi_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID },
10465641822SToomas Soome 	{ .efi_guid_name = "console control",
10565641822SToomas Soome 	    .efi_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID },
10665641822SToomas Soome 	{ .efi_guid_name = "stdin", .efi_guid = EFI_CONSOLE_IN_DEVICE_GUID },
10765641822SToomas Soome 	{ .efi_guid_name = "stdout", .efi_guid = EFI_CONSOLE_OUT_DEVICE_GUID },
10865641822SToomas Soome 	{ .efi_guid_name = "stderr",
10965641822SToomas Soome 	    .efi_guid = EFI_STANDARD_ERROR_DEVICE_GUID },
11065641822SToomas Soome 	{ .efi_guid_name = "GOP",
11165641822SToomas Soome 	    .efi_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID },
11265641822SToomas Soome 	{ .efi_guid_name = "UGA draw", .efi_guid = EFI_UGA_DRAW_PROTOCOL_GUID },
11365641822SToomas Soome 	{ .efi_guid_name = "PXE base code",
11465641822SToomas Soome 	    .efi_guid = EFI_PXE_BASE_CODE_PROTOCOL },
11565641822SToomas Soome 	{ .efi_guid_name = "PXE base code callback",
11665641822SToomas Soome 	    .efi_guid = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL },
11765641822SToomas Soome 	{ .efi_guid_name = "serial io", .efi_guid = SERIAL_IO_PROTOCOL },
11865641822SToomas Soome 	{ .efi_guid_name = "loaded image", .efi_guid = LOADED_IMAGE_PROTOCOL },
11965641822SToomas Soome 	{ .efi_guid_name = "loaded image device path",
12065641822SToomas Soome 	    .efi_guid = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID },
12165641822SToomas Soome 	{ .efi_guid_name = "ISA io", .efi_guid = EFI_ISA_IO_PROTOCOL_GUID },
12265641822SToomas Soome 	{ .efi_guid_name = "IDE controller init",
12365641822SToomas Soome 	    .efi_guid = EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID },
12465641822SToomas Soome 	{ .efi_guid_name = "ISA ACPI", .efi_guid = EFI_ISA_ACPI_PROTOCOL_GUID },
12565641822SToomas Soome 	{ .efi_guid_name = "PCI", .efi_guid = EFI_PCI_IO_PROTOCOL_GUID },
12665641822SToomas Soome 	{ .efi_guid_name = "PCI root", .efi_guid = EFI_PCI_ROOT_IO_GUID },
12765641822SToomas Soome 	{ .efi_guid_name = "PCI enumeration",
12865641822SToomas Soome 	    .efi_guid = EFI_PCI_ENUMERATION_COMPLETE_GUID },
12965641822SToomas Soome         { .efi_guid_name = "Driver diagnostics",
13065641822SToomas Soome 	    .efi_guid = EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID },
13165641822SToomas Soome         { .efi_guid_name = "Driver diagnostics2",
13265641822SToomas Soome 	    .efi_guid = EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID },
13365641822SToomas Soome         { .efi_guid_name = "simple pointer",
13465641822SToomas Soome 	    .efi_guid = EFI_SIMPLE_POINTER_PROTOCOL_GUID },
13565641822SToomas Soome         { .efi_guid_name = "absolute pointer",
13665641822SToomas Soome 	    .efi_guid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID },
13765641822SToomas Soome         { .efi_guid_name = "VLAN config",
13865641822SToomas Soome 	    .efi_guid = EFI_VLAN_CONFIG_PROTOCOL_GUID },
13965641822SToomas Soome         { .efi_guid_name = "ARP service binding",
14065641822SToomas Soome 	    .efi_guid = EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID },
14165641822SToomas Soome         { .efi_guid_name = "ARP", .efi_guid = EFI_ARP_PROTOCOL_GUID },
14265641822SToomas Soome         { .efi_guid_name = "IPv4 service binding",
14365641822SToomas Soome 	    .efi_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL },
14465641822SToomas Soome         { .efi_guid_name = "IPv4", .efi_guid = EFI_IP4_PROTOCOL },
14565641822SToomas Soome         { .efi_guid_name = "IPv4 config",
14665641822SToomas Soome 	    .efi_guid = EFI_IP4_CONFIG_PROTOCOL_GUID },
14765641822SToomas Soome         { .efi_guid_name = "IPv6 service binding",
14865641822SToomas Soome 	    .efi_guid = EFI_IP6_SERVICE_BINDING_PROTOCOL },
14965641822SToomas Soome         { .efi_guid_name = "IPv6", .efi_guid = EFI_IP6_PROTOCOL },
15065641822SToomas Soome         { .efi_guid_name = "IPv6 config",
15165641822SToomas Soome 	    .efi_guid = EFI_IP6_CONFIG_PROTOCOL_GUID },
15265641822SToomas Soome         { .efi_guid_name = "UDPv4", .efi_guid = EFI_UDP4_PROTOCOL },
15365641822SToomas Soome         { .efi_guid_name = "UDPv4 service binding",
15465641822SToomas Soome 	    .efi_guid = EFI_UDP4_SERVICE_BINDING_PROTOCOL },
15565641822SToomas Soome         { .efi_guid_name = "UDPv6", .efi_guid = EFI_UDP6_PROTOCOL },
15665641822SToomas Soome         { .efi_guid_name = "UDPv6 service binding",
15765641822SToomas Soome 	    .efi_guid = EFI_UDP6_SERVICE_BINDING_PROTOCOL },
15865641822SToomas Soome         { .efi_guid_name = "TCPv4", .efi_guid = EFI_TCP4_PROTOCOL },
15965641822SToomas Soome         { .efi_guid_name = "TCPv4 service binding",
16065641822SToomas Soome 	    .efi_guid = EFI_TCP4_SERVICE_BINDING_PROTOCOL },
16165641822SToomas Soome         { .efi_guid_name = "TCPv6", .efi_guid = EFI_TCP6_PROTOCOL },
16265641822SToomas Soome         { .efi_guid_name = "TCPv6 service binding",
16365641822SToomas Soome 	    .efi_guid = EFI_TCP6_SERVICE_BINDING_PROTOCOL },
16465641822SToomas Soome         { .efi_guid_name = "EFI System partition",
16565641822SToomas Soome 	    .efi_guid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID },
16665641822SToomas Soome         { .efi_guid_name = "MBR legacy",
16765641822SToomas Soome 	    .efi_guid = EFI_PART_TYPE_LEGACY_MBR_GUID },
16865641822SToomas Soome         { .efi_guid_name = "device tree", .efi_guid = EFI_DEVICE_TREE_GUID },
16965641822SToomas Soome         { .efi_guid_name = "USB io", .efi_guid = EFI_USB_IO_PROTOCOL_GUID },
17065641822SToomas Soome         { .efi_guid_name = "USB2 HC", .efi_guid = EFI_USB2_HC_PROTOCOL_GUID },
17165641822SToomas Soome         { .efi_guid_name = "component name",
17265641822SToomas Soome 	    .efi_guid = EFI_COMPONENT_NAME_PROTOCOL_GUID },
17365641822SToomas Soome         { .efi_guid_name = "component name2",
17465641822SToomas Soome 	    .efi_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID },
17565641822SToomas Soome         { .efi_guid_name = "driver binding",
17665641822SToomas Soome 	    .efi_guid = EFI_DRIVER_BINDING_PROTOCOL_GUID },
17765641822SToomas Soome         { .efi_guid_name = "driver configuration",
17865641822SToomas Soome 	    .efi_guid = EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID },
17965641822SToomas Soome         { .efi_guid_name = "driver configuration2",
18065641822SToomas Soome 	    .efi_guid = EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID },
18165641822SToomas Soome         { .efi_guid_name = "decompress",
18265641822SToomas Soome 	    .efi_guid = EFI_DECOMPRESS_PROTOCOL_GUID },
18365641822SToomas Soome         { .efi_guid_name = "ebc interpreter",
18465641822SToomas Soome 	    .efi_guid = EFI_EBC_INTERPRETER_PROTOCOL_GUID },
18565641822SToomas Soome         { .efi_guid_name = "network interface identifier",
18665641822SToomas Soome 	    .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL },
18765641822SToomas Soome         { .efi_guid_name = "network interface identifier_31",
18865641822SToomas Soome 	    .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 },
18965641822SToomas Soome         { .efi_guid_name = "managed network service binding",
19065641822SToomas Soome 	    .efi_guid = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID },
19165641822SToomas Soome         { .efi_guid_name = "managed network",
19265641822SToomas Soome 	    .efi_guid = EFI_MANAGED_NETWORK_PROTOCOL_GUID },
19365641822SToomas Soome         { .efi_guid_name = "form browser",
19465641822SToomas Soome 	    .efi_guid = EFI_FORM_BROWSER2_PROTOCOL_GUID },
19565641822SToomas Soome         { .efi_guid_name = "HII config routing",
19665641822SToomas Soome 	    .efi_guid = EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID },
19765641822SToomas Soome         { .efi_guid_name = "HII database",
19865641822SToomas Soome 	    .efi_guid = EFI_HII_DATABASE_PROTOCOL_GUID },
19965641822SToomas Soome         { .efi_guid_name = "HII string",
20065641822SToomas Soome 	    .efi_guid = EFI_HII_STRING_PROTOCOL_GUID },
20165641822SToomas Soome         { .efi_guid_name = "HII image",
20265641822SToomas Soome 	    .efi_guid = EFI_HII_IMAGE_PROTOCOL_GUID },
20365641822SToomas Soome         { .efi_guid_name = "HII font", .efi_guid = EFI_HII_FONT_PROTOCOL_GUID },
20465641822SToomas Soome         { .efi_guid_name = "HII config",
20565641822SToomas Soome 	    .efi_guid = EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID },
20665641822SToomas Soome         { .efi_guid_name = "MTFTP4 service binding",
20765641822SToomas Soome 	    .efi_guid = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID },
20865641822SToomas Soome         { .efi_guid_name = "MTFTP4", .efi_guid = EFI_MTFTP4_PROTOCOL_GUID },
20965641822SToomas Soome         { .efi_guid_name = "MTFTP6 service binding",
21065641822SToomas Soome 	    .efi_guid = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID },
21165641822SToomas Soome         { .efi_guid_name = "MTFTP6", .efi_guid = EFI_MTFTP6_PROTOCOL_GUID },
21265641822SToomas Soome         { .efi_guid_name = "DHCP4 service binding",
21365641822SToomas Soome 	    .efi_guid = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID },
21465641822SToomas Soome         { .efi_guid_name = "DHCP4", .efi_guid = EFI_DHCP4_PROTOCOL_GUID },
21565641822SToomas Soome         { .efi_guid_name = "DHCP6 service binding",
21665641822SToomas Soome 	    .efi_guid = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID },
21765641822SToomas Soome         { .efi_guid_name = "DHCP6", .efi_guid = EFI_DHCP6_PROTOCOL_GUID },
21865641822SToomas Soome         { .efi_guid_name = "SCSI io", .efi_guid = EFI_SCSI_IO_PROTOCOL_GUID },
21965641822SToomas Soome         { .efi_guid_name = "SCSI pass thru",
22065641822SToomas Soome 	    .efi_guid = EFI_SCSI_PASS_THRU_PROTOCOL_GUID },
22165641822SToomas Soome         { .efi_guid_name = "SCSI pass thru ext",
22265641822SToomas Soome 	    .efi_guid = EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID },
22365641822SToomas Soome         { .efi_guid_name = "Capsule arch",
22465641822SToomas Soome 	    .efi_guid = EFI_CAPSULE_ARCH_PROTOCOL_GUID },
22565641822SToomas Soome         { .efi_guid_name = "monotonic counter arch",
22665641822SToomas Soome 	    .efi_guid = EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID },
22765641822SToomas Soome         { .efi_guid_name = "realtime clock arch",
22865641822SToomas Soome 	    .efi_guid = EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID },
22965641822SToomas Soome         { .efi_guid_name = "variable arch",
23065641822SToomas Soome 	    .efi_guid = EFI_VARIABLE_ARCH_PROTOCOL_GUID },
23165641822SToomas Soome         { .efi_guid_name = "variable write arch",
23265641822SToomas Soome 	    .efi_guid = EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID },
23365641822SToomas Soome         { .efi_guid_name = "watchdog timer arch",
23465641822SToomas Soome 	    .efi_guid = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID },
23565641822SToomas Soome         { .efi_guid_name = "ACPI support",
23665641822SToomas Soome 	    .efi_guid = EFI_ACPI_SUPPORT_PROTOCOL_GUID },
23765641822SToomas Soome         { .efi_guid_name = "BDS arch", .efi_guid = EFI_BDS_ARCH_PROTOCOL_GUID },
23865641822SToomas Soome         { .efi_guid_name = "metronome arch",
23965641822SToomas Soome 	    .efi_guid = EFI_METRONOME_ARCH_PROTOCOL_GUID },
24065641822SToomas Soome         { .efi_guid_name = "timer arch",
24165641822SToomas Soome 	    .efi_guid = EFI_TIMER_ARCH_PROTOCOL_GUID },
24265641822SToomas Soome         { .efi_guid_name = "DPC", .efi_guid = EFI_DPC_PROTOCOL_GUID },
24365641822SToomas Soome         { .efi_guid_name = "print2", .efi_guid = EFI_PRINT2_PROTOCOL_GUID },
24465641822SToomas Soome         { .efi_guid_name = "device path to text",
24565641822SToomas Soome 	    .efi_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID },
24665641822SToomas Soome         { .efi_guid_name = "reset arch",
24765641822SToomas Soome 	    .efi_guid = EFI_RESET_ARCH_PROTOCOL_GUID },
24865641822SToomas Soome         { .efi_guid_name = "CPU arch", .efi_guid = EFI_CPU_ARCH_PROTOCOL_GUID },
24965641822SToomas Soome         { .efi_guid_name = "CPU IO2", .efi_guid = EFI_CPU_IO2_PROTOCOL_GUID },
25065641822SToomas Soome         { .efi_guid_name = "Legacy 8259",
25165641822SToomas Soome 	    .efi_guid = EFI_LEGACY_8259_PROTOCOL_GUID },
25265641822SToomas Soome         { .efi_guid_name = "Security arch",
25365641822SToomas Soome 	    .efi_guid = EFI_SECURITY_ARCH_PROTOCOL_GUID },
25465641822SToomas Soome         { .efi_guid_name = "Security2 arch",
25565641822SToomas Soome 	    .efi_guid = EFI_SECURITY2_ARCH_PROTOCOL_GUID },
25665641822SToomas Soome         { .efi_guid_name = "Runtime arch",
25765641822SToomas Soome 	    .efi_guid = EFI_RUNTIME_ARCH_PROTOCOL_GUID },
25865641822SToomas Soome         { .efi_guid_name = "status code runtime",
25965641822SToomas Soome 	    .efi_guid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID },
26065641822SToomas Soome         { .efi_guid_name = "data hub", .efi_guid = EFI_DATA_HUB_PROTOCOL_GUID },
26165641822SToomas Soome         { .efi_guid_name = "PCD", .efi_guid = PCD_PROTOCOL_GUID },
26265641822SToomas Soome         { .efi_guid_name = "EFI PCD", .efi_guid = EFI_PCD_PROTOCOL_GUID },
26365641822SToomas Soome         { .efi_guid_name = "firmware volume block",
26465641822SToomas Soome 	    .efi_guid = EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID },
26565641822SToomas Soome         { .efi_guid_name = "firmware volume2",
26665641822SToomas Soome 	    .efi_guid = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID },
26765641822SToomas Soome         { .efi_guid_name = "firmware volume dispatch",
26865641822SToomas Soome 	    .efi_guid = EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID },
26965641822SToomas Soome         { .efi_guid_name = "lzma compress", .efi_guid = LZMA_COMPRESS_GUID },
27065641822SToomas Soome         { .efi_guid_name = "MP services",
27165641822SToomas Soome 	    .efi_guid = EFI_MP_SERVICES_PROTOCOL_GUID },
27265641822SToomas Soome         { .efi_guid_name = MTC_VARIABLE_NAME, .efi_guid = MTC_VENDOR_GUID },
27365641822SToomas Soome         { .efi_guid_name = "RTC", .efi_guid = { 0x378D7B65, 0x8DA9, 0x4773,
27465641822SToomas Soome 	    { 0xB6, 0xE4, 0xA4, 0x78, 0x26, 0xA8, 0x33, 0xE1} } },
27565641822SToomas Soome         { .efi_guid_name = "Active EDID",
27665641822SToomas Soome 	    .efi_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID },
27765641822SToomas Soome         { .efi_guid_name = "Discovered EDID",
27865641822SToomas Soome 	    .efi_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID }
27965641822SToomas Soome };
28065641822SToomas Soome 
28165641822SToomas Soome bool
efi_guid_to_str(const EFI_GUID * guid,char ** sp)28265641822SToomas Soome efi_guid_to_str(const EFI_GUID *guid, char **sp)
28365641822SToomas Soome {
28465641822SToomas Soome 	uint32_t status;
28565641822SToomas Soome 
28665641822SToomas Soome 	uuid_to_string((const uuid_t *)guid, sp, &status);
28765641822SToomas Soome 	return (status == uuid_s_ok ? true : false);
28865641822SToomas Soome }
28965641822SToomas Soome 
29065641822SToomas Soome bool
efi_str_to_guid(const char * s,EFI_GUID * guid)29165641822SToomas Soome efi_str_to_guid(const char *s, EFI_GUID *guid)
29265641822SToomas Soome {
29365641822SToomas Soome 	uint32_t status;
29465641822SToomas Soome 
29565641822SToomas Soome 	uuid_from_string(s, (uuid_t *)guid, &status);
29665641822SToomas Soome 	return (status == uuid_s_ok ? true : false);
29765641822SToomas Soome }
29865641822SToomas Soome 
29965641822SToomas Soome bool
efi_name_to_guid(const char * name,EFI_GUID * guid)30065641822SToomas Soome efi_name_to_guid(const char *name, EFI_GUID *guid)
30165641822SToomas Soome {
30265641822SToomas Soome 	uint32_t i;
30365641822SToomas Soome 
30465641822SToomas Soome 	for (i = 0; i < nitems(efi_uuid_mapping); i++) {
30565641822SToomas Soome 		if (strcasecmp(name, efi_uuid_mapping[i].efi_guid_name) == 0) {
30665641822SToomas Soome 			*guid = efi_uuid_mapping[i].efi_guid;
30765641822SToomas Soome 			return (true);
30865641822SToomas Soome 		}
30965641822SToomas Soome 	}
31065641822SToomas Soome 	return (efi_str_to_guid(name, guid));
31165641822SToomas Soome }
31265641822SToomas Soome 
31365641822SToomas Soome bool
efi_guid_to_name(EFI_GUID * guid,char ** name)31465641822SToomas Soome efi_guid_to_name(EFI_GUID *guid, char **name)
31565641822SToomas Soome {
31665641822SToomas Soome 	uint32_t i;
31765641822SToomas Soome 	int rv;
31865641822SToomas Soome 
31965641822SToomas Soome 	for (i = 0; i < nitems(efi_uuid_mapping); i++) {
32065641822SToomas Soome 		rv = uuid_equal((uuid_t *)guid,
32165641822SToomas Soome 		    (uuid_t *)&efi_uuid_mapping[i].efi_guid, NULL);
32265641822SToomas Soome 		if (rv != 0) {
32365641822SToomas Soome 			*name = strdup(efi_uuid_mapping[i].efi_guid_name);
32465641822SToomas Soome 			if (*name == NULL)
32565641822SToomas Soome 				return (false);
32665641822SToomas Soome 			return (true);
32765641822SToomas Soome 		}
32865641822SToomas Soome 	}
32965641822SToomas Soome 	return (efi_guid_to_str(guid, name));
33065641822SToomas Soome }
33165641822SToomas Soome 
332ca987d46SWarner Losh void
efi_init_environment(void)333ca987d46SWarner Losh efi_init_environment(void)
334ca987d46SWarner Losh {
335ca987d46SWarner Losh 	char var[128];
336ca987d46SWarner Losh 
337ca987d46SWarner Losh 	snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
338ca987d46SWarner Losh 	    ST->Hdr.Revision & 0xffff);
339ca987d46SWarner Losh 	env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
340ca987d46SWarner Losh }
341ca987d46SWarner Losh 
342ca987d46SWarner Losh COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
343ca987d46SWarner Losh 
34465641822SToomas Soome static int
efi_print_other_value(uint8_t * data,UINTN datasz)34565641822SToomas Soome efi_print_other_value(uint8_t *data, UINTN datasz)
34665641822SToomas Soome {
34765641822SToomas Soome 	UINTN i;
34865641822SToomas Soome 	bool is_ascii = true;
34965641822SToomas Soome 
35065641822SToomas Soome 	printf(" = ");
35165641822SToomas Soome 	for (i = 0; i < datasz - 1; i++) {
35265641822SToomas Soome 		/*
35365641822SToomas Soome 		 * Quick hack to see if this ascii-ish string is printable
35465641822SToomas Soome 		 * range plus tab, cr and lf.
35565641822SToomas Soome 		 */
35665641822SToomas Soome 		if ((data[i] < 32 || data[i] > 126)
35765641822SToomas Soome 		    && data[i] != 9 && data[i] != 10 && data[i] != 13) {
35865641822SToomas Soome 			is_ascii = false;
35965641822SToomas Soome 			break;
36065641822SToomas Soome 		}
36165641822SToomas Soome 	}
36265641822SToomas Soome 	if (data[datasz - 1] != '\0')
36365641822SToomas Soome 		is_ascii = false;
36465641822SToomas Soome 	if (is_ascii == true) {
36565641822SToomas Soome 		printf("%s", data);
36665641822SToomas Soome 		if (pager_output("\n"))
36765641822SToomas Soome 			return (CMD_WARN);
36865641822SToomas Soome 	} else {
36965641822SToomas Soome 		if (pager_output("\n"))
37065641822SToomas Soome 			return (CMD_WARN);
37165641822SToomas Soome 		/*
37265641822SToomas Soome 		 * Dump hex bytes grouped by 4.
37365641822SToomas Soome 		 */
37465641822SToomas Soome 		for (i = 0; i < datasz; i++) {
37565641822SToomas Soome 			printf("%02x ", data[i]);
37665641822SToomas Soome 			if ((i + 1) % 4 == 0)
37765641822SToomas Soome 				printf(" ");
37865641822SToomas Soome 			if ((i + 1) % 20 == 0) {
37965641822SToomas Soome 				if (pager_output("\n"))
38065641822SToomas Soome 					return (CMD_WARN);
38165641822SToomas Soome 			}
38265641822SToomas Soome 		}
38365641822SToomas Soome 		if (pager_output("\n"))
38465641822SToomas Soome 			return (CMD_WARN);
38565641822SToomas Soome 	}
38665641822SToomas Soome 
38765641822SToomas Soome 	return (CMD_OK);
38865641822SToomas Soome }
38965641822SToomas Soome 
39065641822SToomas Soome /* This appears to be some sort of UEFI shell alias table. */
39165641822SToomas Soome static int
efi_print_shell_str(const CHAR16 * varnamearg __unused,uint8_t * data,UINTN datasz __unused)39265641822SToomas Soome efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data,
39365641822SToomas Soome     UINTN datasz __unused)
39465641822SToomas Soome {
39565641822SToomas Soome 	printf(" = %S", (CHAR16 *)data);
39665641822SToomas Soome 	if (pager_output("\n"))
39765641822SToomas Soome 		return (CMD_WARN);
39865641822SToomas Soome 	return (CMD_OK);
39965641822SToomas Soome }
40065641822SToomas Soome 
40134ada209SToomas Soome const char *
efi_memory_type(EFI_MEMORY_TYPE type)40234ada209SToomas Soome efi_memory_type(EFI_MEMORY_TYPE type)
40334ada209SToomas Soome {
40434ada209SToomas Soome 	const char *types[] = {
40534ada209SToomas Soome 	    "Reserved",
40634ada209SToomas Soome 	    "LoaderCode",
40734ada209SToomas Soome 	    "LoaderData",
40834ada209SToomas Soome 	    "BootServicesCode",
40934ada209SToomas Soome 	    "BootServicesData",
41034ada209SToomas Soome 	    "RuntimeServicesCode",
41134ada209SToomas Soome 	    "RuntimeServicesData",
41234ada209SToomas Soome 	    "ConventionalMemory",
41334ada209SToomas Soome 	    "UnusableMemory",
41434ada209SToomas Soome 	    "ACPIReclaimMemory",
41534ada209SToomas Soome 	    "ACPIMemoryNVS",
41634ada209SToomas Soome 	    "MemoryMappedIO",
41734ada209SToomas Soome 	    "MemoryMappedIOPortSpace",
41834ada209SToomas Soome 	    "PalCode",
41934ada209SToomas Soome 	    "PersistentMemory"
42034ada209SToomas Soome 	};
42134ada209SToomas Soome 
42234ada209SToomas Soome 	switch (type) {
42334ada209SToomas Soome 	case EfiReservedMemoryType:
42434ada209SToomas Soome 	case EfiLoaderCode:
42534ada209SToomas Soome 	case EfiLoaderData:
42634ada209SToomas Soome 	case EfiBootServicesCode:
42734ada209SToomas Soome 	case EfiBootServicesData:
42834ada209SToomas Soome 	case EfiRuntimeServicesCode:
42934ada209SToomas Soome 	case EfiRuntimeServicesData:
43034ada209SToomas Soome 	case EfiConventionalMemory:
43134ada209SToomas Soome 	case EfiUnusableMemory:
43234ada209SToomas Soome 	case EfiACPIReclaimMemory:
43334ada209SToomas Soome 	case EfiACPIMemoryNVS:
43434ada209SToomas Soome 	case EfiMemoryMappedIO:
43534ada209SToomas Soome 	case EfiMemoryMappedIOPortSpace:
43634ada209SToomas Soome 	case EfiPalCode:
43734ada209SToomas Soome 	case EfiPersistentMemory:
43834ada209SToomas Soome 		return (types[type]);
43934ada209SToomas Soome 	default:
44034ada209SToomas Soome 		return ("Unknown");
44134ada209SToomas Soome 	}
44234ada209SToomas Soome }
44334ada209SToomas Soome 
44465641822SToomas Soome /* Print memory type table. */
44565641822SToomas Soome static int
efi_print_mem_type(const CHAR16 * varnamearg __unused,uint8_t * data,UINTN datasz)44665641822SToomas Soome efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data,
44765641822SToomas Soome     UINTN datasz)
44865641822SToomas Soome {
44965641822SToomas Soome 	int i, n;
45065641822SToomas Soome 	EFI_MEMORY_TYPE_INFORMATION *ti;
45165641822SToomas Soome 
45265641822SToomas Soome 	ti = (EFI_MEMORY_TYPE_INFORMATION *)data;
45365641822SToomas Soome 	if (pager_output(" = \n"))
45465641822SToomas Soome 		return (CMD_WARN);
45565641822SToomas Soome 
45665641822SToomas Soome 	n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION);
45765641822SToomas Soome 	for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) {
45865641822SToomas Soome 		printf("\t%23s pages: %u", efi_memory_type(ti[i].Type),
45965641822SToomas Soome 		    ti[i].NumberOfPages);
46065641822SToomas Soome 		if (pager_output("\n"))
46165641822SToomas Soome 			return (CMD_WARN);
46265641822SToomas Soome 	}
46365641822SToomas Soome 
46465641822SToomas Soome 	return (CMD_OK);
46565641822SToomas Soome }
46665641822SToomas Soome 
46765641822SToomas Soome /*
46865641822SToomas Soome  * Print FreeBSD variables.
46965641822SToomas Soome  * We have LoaderPath and LoaderDev as CHAR16 strings.
47065641822SToomas Soome  */
47165641822SToomas Soome static int
efi_print_freebsd(const CHAR16 * varnamearg,uint8_t * data,UINTN datasz __unused)47265641822SToomas Soome efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data,
47365641822SToomas Soome     UINTN datasz __unused)
47465641822SToomas Soome {
47565641822SToomas Soome 	int rv = -1;
47665641822SToomas Soome 	char *var = NULL;
47765641822SToomas Soome 
47865641822SToomas Soome 	if (ucs2_to_utf8(varnamearg, &var) != 0)
47965641822SToomas Soome 		return (CMD_ERROR);
48065641822SToomas Soome 
48165641822SToomas Soome 	if (strcmp("LoaderPath", var) == 0 ||
48265641822SToomas Soome 	    strcmp("LoaderDev", var) == 0) {
48365641822SToomas Soome 		printf(" = ");
48465641822SToomas Soome 		printf("%S", (CHAR16 *)data);
48565641822SToomas Soome 
48665641822SToomas Soome 		if (pager_output("\n"))
48765641822SToomas Soome 			rv = CMD_WARN;
48865641822SToomas Soome 		else
48965641822SToomas Soome 			rv = CMD_OK;
49065641822SToomas Soome 	}
49165641822SToomas Soome 
49265641822SToomas Soome 	free(var);
49365641822SToomas Soome 	return (rv);
49465641822SToomas Soome }
49565641822SToomas Soome 
49665641822SToomas Soome /* Print global variables. */
49765641822SToomas Soome static int
efi_print_global(const CHAR16 * varnamearg,uint8_t * data,UINTN datasz)49865641822SToomas Soome efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz)
49965641822SToomas Soome {
50065641822SToomas Soome 	int rv = -1;
50165641822SToomas Soome 	char *var = NULL;
50265641822SToomas Soome 
50365641822SToomas Soome 	if (ucs2_to_utf8(varnamearg, &var) != 0)
50465641822SToomas Soome 		return (CMD_ERROR);
50565641822SToomas Soome 
50665641822SToomas Soome 	if (strcmp("AuditMode", var) == 0) {
50765641822SToomas Soome 		printf(" = ");
50865641822SToomas Soome 		printf("0x%x", *data);	/* 8-bit int */
50965641822SToomas Soome 		goto done;
51065641822SToomas Soome 	}
51165641822SToomas Soome 
51265641822SToomas Soome 	if (strcmp("BootOptionSupport", var) == 0) {
51365641822SToomas Soome 		printf(" = ");
51465641822SToomas Soome 		printf("0x%x", *((uint32_t *)data));	/* UINT32 */
51565641822SToomas Soome 		goto done;
51665641822SToomas Soome 	}
51765641822SToomas Soome 
51865641822SToomas Soome 	if (strcmp("BootCurrent", var) == 0 ||
51965641822SToomas Soome 	    strcmp("BootNext", var) == 0 ||
52065641822SToomas Soome 	    strcmp("Timeout", var) == 0) {
52165641822SToomas Soome 		printf(" = ");
52265641822SToomas Soome 		printf("%u", *((uint16_t *)data));	/* UINT16 */
52365641822SToomas Soome 		goto done;
52465641822SToomas Soome 	}
52565641822SToomas Soome 
52665641822SToomas Soome 	if (strcmp("BootOrder", var) == 0 ||
52765641822SToomas Soome 	    strcmp("DriverOrder", var) == 0) {
52865641822SToomas Soome 		UINTN i;
52965641822SToomas Soome 		UINT16 *u16 = (UINT16 *)data;
53065641822SToomas Soome 
53165641822SToomas Soome 		printf(" =");
53265641822SToomas Soome 		for (i = 0; i < datasz / sizeof (UINT16); i++)
53365641822SToomas Soome 			printf(" %u", u16[i]);
53465641822SToomas Soome 		goto done;
53565641822SToomas Soome 	}
53665641822SToomas Soome 	if (strncmp("Boot", var, 4) == 0 ||
537*39ae24e3SAlfonso Gregory 	    strncmp("Driver", var, 6) == 0 ||
53865641822SToomas Soome 	    strncmp("SysPrep", var, 7) == 0 ||
53965641822SToomas Soome 	    strncmp("OsRecovery", var, 10) == 0) {
54065641822SToomas Soome 		UINT16 filepathlistlen;
54165641822SToomas Soome 		CHAR16 *text;
54265641822SToomas Soome 		int desclen;
54365641822SToomas Soome 		EFI_DEVICE_PATH *dp;
54465641822SToomas Soome 
54565641822SToomas Soome 		data += sizeof(UINT32);
54665641822SToomas Soome 		filepathlistlen = *(uint16_t *)data;
54765641822SToomas Soome 		data += sizeof (UINT16);
54865641822SToomas Soome 		text = (CHAR16 *)data;
54965641822SToomas Soome 
55065641822SToomas Soome 		for (desclen = 0; text[desclen] != 0; desclen++)
55165641822SToomas Soome 			;
55265641822SToomas Soome 		if (desclen != 0) {
55365641822SToomas Soome 			/* Add terminating zero and we have CHAR16. */
55465641822SToomas Soome 			desclen = (desclen + 1) * 2;
55565641822SToomas Soome 		}
55665641822SToomas Soome 
55765641822SToomas Soome 		printf(" = ");
55865641822SToomas Soome 		printf("%S", text);
55965641822SToomas Soome 		if (filepathlistlen != 0) {
56065641822SToomas Soome 			/* Output pathname from new line. */
56165641822SToomas Soome 			if (pager_output("\n")) {
56265641822SToomas Soome 				rv = CMD_WARN;
56365641822SToomas Soome 				goto done;
56465641822SToomas Soome 			}
56565641822SToomas Soome 			dp = malloc(filepathlistlen);
56665641822SToomas Soome 			if (dp == NULL)
56765641822SToomas Soome 				goto done;
56865641822SToomas Soome 
56965641822SToomas Soome 			memcpy(dp, data + desclen, filepathlistlen);
57065641822SToomas Soome 			text = efi_devpath_name(dp);
57165641822SToomas Soome 			if (text != NULL) {
57265641822SToomas Soome 				printf("\t%S", text);
57365641822SToomas Soome 				efi_free_devpath_name(text);
57465641822SToomas Soome 			}
57565641822SToomas Soome 			free(dp);
57665641822SToomas Soome 		}
57765641822SToomas Soome 		goto done;
57865641822SToomas Soome 	}
57965641822SToomas Soome 
58065641822SToomas Soome 	if (strcmp("ConIn", var) == 0 ||
58165641822SToomas Soome 	    strcmp("ConInDev", var) == 0 ||
58265641822SToomas Soome 	    strcmp("ConOut", var) == 0 ||
58365641822SToomas Soome 	    strcmp("ConOutDev", var) == 0 ||
58465641822SToomas Soome 	    strcmp("ErrOut", var) == 0 ||
58565641822SToomas Soome 	    strcmp("ErrOutDev", var) == 0) {
58665641822SToomas Soome 		CHAR16 *text;
58765641822SToomas Soome 
58865641822SToomas Soome 		printf(" = ");
58965641822SToomas Soome 		text = efi_devpath_name((EFI_DEVICE_PATH *)data);
59065641822SToomas Soome 		if (text != NULL) {
59165641822SToomas Soome 			printf("%S", text);
59265641822SToomas Soome 			efi_free_devpath_name(text);
59365641822SToomas Soome 		}
59465641822SToomas Soome 		goto done;
59565641822SToomas Soome 	}
59665641822SToomas Soome 
59765641822SToomas Soome 	if (strcmp("PlatformLang", var) == 0 ||
59865641822SToomas Soome 	    strcmp("PlatformLangCodes", var) == 0 ||
59965641822SToomas Soome 	    strcmp("LangCodes", var) == 0 ||
60065641822SToomas Soome 	    strcmp("Lang", var) == 0) {
60165641822SToomas Soome 		printf(" = ");
60265641822SToomas Soome 		printf("%s", data);	/* ASCII string */
60365641822SToomas Soome 		goto done;
60465641822SToomas Soome 	}
60565641822SToomas Soome 
60665641822SToomas Soome 	/*
60765641822SToomas Soome 	 * Feature bitmap from firmware to OS.
60865641822SToomas Soome 	 * Older UEFI provides UINT32, newer UINT64.
60965641822SToomas Soome 	 */
61065641822SToomas Soome 	if (strcmp("OsIndicationsSupported", var) == 0) {
61165641822SToomas Soome 		printf(" = ");
61265641822SToomas Soome 		if (datasz == 4)
61365641822SToomas Soome 			printf("0x%x", *((uint32_t *)data));
61465641822SToomas Soome 		else
61565641822SToomas Soome 			printf("0x%jx", *((uint64_t *)data));
61665641822SToomas Soome 		goto done;
61765641822SToomas Soome 	}
61865641822SToomas Soome 
61965641822SToomas Soome 	/* Fallback for anything else. */
62065641822SToomas Soome 	rv = efi_print_other_value(data, datasz);
62165641822SToomas Soome done:
62265641822SToomas Soome 	if (rv == -1) {
62365641822SToomas Soome 		if (pager_output("\n"))
62465641822SToomas Soome 			rv = CMD_WARN;
62565641822SToomas Soome 		else
62665641822SToomas Soome 			rv = CMD_OK;
62765641822SToomas Soome 	}
62865641822SToomas Soome 	free(var);
62965641822SToomas Soome 	return (rv);
63065641822SToomas Soome }
63165641822SToomas Soome 
63265641822SToomas Soome static void
efi_print_var_attr(UINT32 attr)63365641822SToomas Soome efi_print_var_attr(UINT32 attr)
63465641822SToomas Soome {
63565641822SToomas Soome 	bool comma = false;
63665641822SToomas Soome 
63765641822SToomas Soome 	if (attr & EFI_VARIABLE_NON_VOLATILE) {
63865641822SToomas Soome 		printf("NV");
63965641822SToomas Soome 		comma = true;
64065641822SToomas Soome 	}
64165641822SToomas Soome 	if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) {
64265641822SToomas Soome 		if (comma == true)
64365641822SToomas Soome 			printf(",");
64465641822SToomas Soome 		printf("BS");
64565641822SToomas Soome 		comma = true;
64665641822SToomas Soome 	}
64765641822SToomas Soome 	if (attr & EFI_VARIABLE_RUNTIME_ACCESS) {
64865641822SToomas Soome 		if (comma == true)
64965641822SToomas Soome 			printf(",");
65065641822SToomas Soome 		printf("RS");
65165641822SToomas Soome 		comma = true;
65265641822SToomas Soome 	}
65365641822SToomas Soome 	if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
65465641822SToomas Soome 		if (comma == true)
65565641822SToomas Soome 			printf(",");
65665641822SToomas Soome 		printf("HR");
65765641822SToomas Soome 		comma = true;
65865641822SToomas Soome 	}
65965641822SToomas Soome 	if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
66065641822SToomas Soome 		if (comma == true)
66165641822SToomas Soome 			printf(",");
66265641822SToomas Soome 		printf("AT");
66365641822SToomas Soome 		comma = true;
66465641822SToomas Soome 	}
66565641822SToomas Soome }
66665641822SToomas Soome 
667ca987d46SWarner Losh static int
efi_print_var(CHAR16 * varnamearg,EFI_GUID * matchguid,int lflag)668ca987d46SWarner Losh efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
669ca987d46SWarner Losh {
67065641822SToomas Soome 	UINTN		datasz;
671ca987d46SWarner Losh 	EFI_STATUS	status;
672ca987d46SWarner Losh 	UINT32		attr;
673ca987d46SWarner Losh 	char		*str;
67465641822SToomas Soome 	uint8_t		*data;
67565641822SToomas Soome 	int		rv = CMD_OK;
676ca987d46SWarner Losh 
67765641822SToomas Soome 	str = NULL;
678ca987d46SWarner Losh 	datasz = 0;
67965641822SToomas Soome 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL);
680ca987d46SWarner Losh 	if (status != EFI_BUFFER_TOO_SMALL) {
681ca987d46SWarner Losh 		printf("Can't get the variable: error %#lx\n",
682ca987d46SWarner Losh 		    EFI_ERROR_CODE(status));
683ca987d46SWarner Losh 		return (CMD_ERROR);
684ca987d46SWarner Losh 	}
685ca987d46SWarner Losh 	data = malloc(datasz);
68665641822SToomas Soome 	if (data == NULL) {
68765641822SToomas Soome 		printf("Out of memory\n");
68865641822SToomas Soome 		return (CMD_ERROR);
68965641822SToomas Soome 	}
69065641822SToomas Soome 
69165641822SToomas Soome 	status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data);
692ca987d46SWarner Losh 	if (status != EFI_SUCCESS) {
693ca987d46SWarner Losh 		printf("Can't get the variable: error %#lx\n",
694ca987d46SWarner Losh 		    EFI_ERROR_CODE(status));
69565641822SToomas Soome 		free(data);
696ca987d46SWarner Losh 		return (CMD_ERROR);
697ca987d46SWarner Losh 	}
69865641822SToomas Soome 
69965641822SToomas Soome 	if (efi_guid_to_name(matchguid, &str) == false) {
70065641822SToomas Soome 		rv = CMD_ERROR;
70165641822SToomas Soome 		goto done;
702ca987d46SWarner Losh 	}
703ca987d46SWarner Losh 	printf("%s ", str);
70465641822SToomas Soome 	efi_print_var_attr(attr);
70565641822SToomas Soome 	printf(" %S", varnamearg);
70665641822SToomas Soome 
70765641822SToomas Soome 	if (lflag == 0) {
70865641822SToomas Soome 		if (strcmp(str, "global") == 0)
70965641822SToomas Soome 			rv = efi_print_global(varnamearg, data, datasz);
71065641822SToomas Soome 		else if (strcmp(str, "freebsd") == 0)
71165641822SToomas Soome 			rv = efi_print_freebsd(varnamearg, data, datasz);
71265641822SToomas Soome 		else if (strcmp(str,
71365641822SToomas Soome 		    EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0)
71465641822SToomas Soome 			rv = efi_print_mem_type(varnamearg, data, datasz);
71565641822SToomas Soome 		else if (strcmp(str,
71665641822SToomas Soome 		    "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0)
71765641822SToomas Soome 			rv = efi_print_shell_str(varnamearg, data, datasz);
71865641822SToomas Soome 		else if (strcmp(str, MTC_VARIABLE_NAME) == 0) {
71965641822SToomas Soome 			printf(" = ");
72065641822SToomas Soome 			printf("%u", *((uint32_t *)data));	/* UINT32 */
72165641822SToomas Soome 			rv = CMD_OK;
722ca987d46SWarner Losh 			if (pager_output("\n"))
72365641822SToomas Soome 				rv = CMD_WARN;
72465641822SToomas Soome 		} else
72565641822SToomas Soome 			rv = efi_print_other_value(data, datasz);
72665641822SToomas Soome 	} else if (pager_output("\n"))
72765641822SToomas Soome 		rv =  CMD_WARN;
72865641822SToomas Soome 
72965641822SToomas Soome done:
73065641822SToomas Soome 	free(str);
73165641822SToomas Soome 	free(data);
73265641822SToomas Soome 	return (rv);
733ca987d46SWarner Losh }
734ca987d46SWarner Losh 
735ca987d46SWarner Losh static int
command_efi_show(int argc,char * argv[])736ca987d46SWarner Losh command_efi_show(int argc, char *argv[])
737ca987d46SWarner Losh {
738ca987d46SWarner Losh 	/*
739ca987d46SWarner Losh 	 * efi-show [-a]
740ca987d46SWarner Losh 	 *	print all the env
74111df3a28SWarner Losh 	 * efi-show -g UUID
742ca987d46SWarner Losh 	 *	print all the env vars tagged with UUID
743ca987d46SWarner Losh 	 * efi-show -v var
744ca987d46SWarner Losh 	 *	search all the env vars and print the ones matching var
74511df3a28SWarner Losh 	 * efi-show -g UUID -v var
74611df3a28SWarner Losh 	 * efi-show UUID var
747ca987d46SWarner Losh 	 *	print all the env vars that match UUID and var
748ca987d46SWarner Losh 	 */
749ca987d46SWarner Losh 	/* NB: We assume EFI_GUID is the same as uuid_t */
750ca987d46SWarner Losh 	int		aflag = 0, gflag = 0, lflag = 0, vflag = 0;
751ca987d46SWarner Losh 	int		ch, rv;
752ca987d46SWarner Losh 	unsigned	i;
753ca987d46SWarner Losh 	EFI_STATUS	status;
75465641822SToomas Soome 	EFI_GUID	varguid = ZERO_GUID;
75565641822SToomas Soome 	EFI_GUID	matchguid = ZERO_GUID;
756ca987d46SWarner Losh 	CHAR16		*varname;
757ca987d46SWarner Losh 	CHAR16		*newnm;
758ca987d46SWarner Losh 	CHAR16		varnamearg[128];
759ca987d46SWarner Losh 	UINTN		varalloc;
760ca987d46SWarner Losh 	UINTN		varsz;
761ca987d46SWarner Losh 
76265641822SToomas Soome 	optind = 1;
76365641822SToomas Soome 	optreset = 1;
76465641822SToomas Soome 	opterr = 1;
76565641822SToomas Soome 
766ca987d46SWarner Losh 	while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
767ca987d46SWarner Losh 		switch (ch) {
768ca987d46SWarner Losh 		case 'a':
769ca987d46SWarner Losh 			aflag = 1;
770ca987d46SWarner Losh 			break;
771ca987d46SWarner Losh 		case 'g':
772ca987d46SWarner Losh 			gflag = 1;
77365641822SToomas Soome 			if (efi_name_to_guid(optarg, &matchguid) == false) {
77465641822SToomas Soome 				printf("uuid %s could not be parsed\n", optarg);
775ca987d46SWarner Losh 				return (CMD_ERROR);
776ca987d46SWarner Losh 			}
777ca987d46SWarner Losh 			break;
778ca987d46SWarner Losh 		case 'l':
779ca987d46SWarner Losh 			lflag = 1;
780ca987d46SWarner Losh 			break;
781ca987d46SWarner Losh 		case 'v':
782ca987d46SWarner Losh 			vflag = 1;
783ca987d46SWarner Losh 			if (strlen(optarg) >= nitems(varnamearg)) {
78465641822SToomas Soome 				printf("Variable %s is longer than %zu "
78565641822SToomas Soome 				    "characters\n", optarg, nitems(varnamearg));
786ca987d46SWarner Losh 				return (CMD_ERROR);
787ca987d46SWarner Losh 			}
78865641822SToomas Soome 			cpy8to16(optarg, varnamearg, nitems(varnamearg));
789ca987d46SWarner Losh 			break;
790ca987d46SWarner Losh 		default:
791ca987d46SWarner Losh 			return (CMD_ERROR);
792ca987d46SWarner Losh 		}
793ca987d46SWarner Losh 	}
794ca987d46SWarner Losh 
79565641822SToomas Soome 	if (argc == 1)		/* default is -a */
79665641822SToomas Soome 		aflag = 1;
79765641822SToomas Soome 
798ca987d46SWarner Losh 	if (aflag && (gflag || vflag)) {
79965641822SToomas Soome 		printf("-a isn't compatible with -g or -v\n");
800ca987d46SWarner Losh 		return (CMD_ERROR);
801ca987d46SWarner Losh 	}
802ca987d46SWarner Losh 
803ca987d46SWarner Losh 	if (aflag && optind < argc) {
804ca987d46SWarner Losh 		printf("-a doesn't take any args\n");
805ca987d46SWarner Losh 		return (CMD_ERROR);
806ca987d46SWarner Losh 	}
807ca987d46SWarner Losh 
808ca987d46SWarner Losh 	argc -= optind;
809ca987d46SWarner Losh 	argv += optind;
810ca987d46SWarner Losh 
811ca987d46SWarner Losh 	pager_open();
812ca987d46SWarner Losh 	if (vflag && gflag) {
813ca987d46SWarner Losh 		rv = efi_print_var(varnamearg, &matchguid, lflag);
81465641822SToomas Soome 		if (rv == CMD_WARN)
81565641822SToomas Soome 			rv = CMD_OK;
816ca987d46SWarner Losh 		pager_close();
817ca987d46SWarner Losh 		return (rv);
818ca987d46SWarner Losh 	}
819ca987d46SWarner Losh 
820ca987d46SWarner Losh 	if (argc == 2) {
821ca987d46SWarner Losh 		optarg = argv[0];
822ca987d46SWarner Losh 		if (strlen(optarg) >= nitems(varnamearg)) {
82365641822SToomas Soome 			printf("Variable %s is longer than %zu characters\n",
824ca987d46SWarner Losh 			    optarg, nitems(varnamearg));
825ca987d46SWarner Losh 			pager_close();
826ca987d46SWarner Losh 			return (CMD_ERROR);
827ca987d46SWarner Losh 		}
828ca987d46SWarner Losh 		for (i = 0; i < strlen(optarg); i++)
829ca987d46SWarner Losh 			varnamearg[i] = optarg[i];
830ca987d46SWarner Losh 		varnamearg[i] = 0;
831ca987d46SWarner Losh 		optarg = argv[1];
83265641822SToomas Soome 		if (efi_name_to_guid(optarg, &matchguid) == false) {
83365641822SToomas Soome 			printf("uuid %s could not be parsed\n", optarg);
834ca987d46SWarner Losh 			pager_close();
835ca987d46SWarner Losh 			return (CMD_ERROR);
836ca987d46SWarner Losh 		}
837ca987d46SWarner Losh 		rv = efi_print_var(varnamearg, &matchguid, lflag);
83865641822SToomas Soome 		if (rv == CMD_WARN)
83965641822SToomas Soome 			rv = CMD_OK;
840ca987d46SWarner Losh 		pager_close();
841ca987d46SWarner Losh 		return (rv);
842ca987d46SWarner Losh 	}
843ca987d46SWarner Losh 
844ca987d46SWarner Losh 	if (argc > 0) {
84565641822SToomas Soome 		printf("Too many args: %d\n", argc);
846ca987d46SWarner Losh 		pager_close();
847ca987d46SWarner Losh 		return (CMD_ERROR);
848ca987d46SWarner Losh 	}
849ca987d46SWarner Losh 
850ca987d46SWarner Losh 	/*
851ca987d46SWarner Losh 	 * Initiate the search -- note the standard takes pain
852ca987d46SWarner Losh 	 * to specify the initial call must be a poiner to a NULL
853ca987d46SWarner Losh 	 * character.
854ca987d46SWarner Losh 	 */
855ca987d46SWarner Losh 	varalloc = 1024;
856ca987d46SWarner Losh 	varname = malloc(varalloc);
857ca987d46SWarner Losh 	if (varname == NULL) {
858ca987d46SWarner Losh 		printf("Can't allocate memory to get variables\n");
859ca987d46SWarner Losh 		pager_close();
860ca987d46SWarner Losh 		return (CMD_ERROR);
861ca987d46SWarner Losh 	}
862ca987d46SWarner Losh 	varname[0] = 0;
863ca987d46SWarner Losh 	while (1) {
864ca987d46SWarner Losh 		varsz = varalloc;
865ca987d46SWarner Losh 		status = RS->GetNextVariableName(&varsz, varname, &varguid);
866ca987d46SWarner Losh 		if (status == EFI_BUFFER_TOO_SMALL) {
867ca987d46SWarner Losh 			varalloc = varsz;
868ca987d46SWarner Losh 			newnm = realloc(varname, varalloc);
869ca987d46SWarner Losh 			if (newnm == NULL) {
87065641822SToomas Soome 				printf("Can't allocate memory to get "
87165641822SToomas Soome 				    "variables\n");
87265641822SToomas Soome 				rv = CMD_ERROR;
87365641822SToomas Soome 				break;
874ca987d46SWarner Losh 			}
875ca987d46SWarner Losh 			varname = newnm;
876ca987d46SWarner Losh 			continue; /* Try again with bigger buffer */
877ca987d46SWarner Losh 		}
87865641822SToomas Soome 		if (status == EFI_NOT_FOUND) {
87965641822SToomas Soome 			rv = CMD_OK;
880ca987d46SWarner Losh 			break;
88165641822SToomas Soome 		}
88265641822SToomas Soome 		if (status != EFI_SUCCESS) {
88365641822SToomas Soome 			rv = CMD_ERROR;
88465641822SToomas Soome 			break;
88565641822SToomas Soome 		}
88665641822SToomas Soome 
887ca987d46SWarner Losh 		if (aflag) {
88865641822SToomas Soome 			rv = efi_print_var(varname, &varguid, lflag);
88965641822SToomas Soome 			if (rv != CMD_OK) {
89065641822SToomas Soome 				if (rv == CMD_WARN)
89165641822SToomas Soome 					rv = CMD_OK;
892ca987d46SWarner Losh 				break;
89365641822SToomas Soome 			}
894ca987d46SWarner Losh 			continue;
895ca987d46SWarner Losh 		}
896ca987d46SWarner Losh 		if (vflag) {
897ca987d46SWarner Losh 			if (wcscmp(varnamearg, varname) == 0) {
89865641822SToomas Soome 				rv = efi_print_var(varname, &varguid, lflag);
89965641822SToomas Soome 				if (rv != CMD_OK) {
90065641822SToomas Soome 					if (rv == CMD_WARN)
90165641822SToomas Soome 						rv = CMD_OK;
902ca987d46SWarner Losh 					break;
90365641822SToomas Soome 				}
904ca987d46SWarner Losh 				continue;
905ca987d46SWarner Losh 			}
906ca987d46SWarner Losh 		}
907ca987d46SWarner Losh 		if (gflag) {
90865641822SToomas Soome 			rv = uuid_equal((uuid_t *)&varguid,
90965641822SToomas Soome 			    (uuid_t *)&matchguid, NULL);
91065641822SToomas Soome 			if (rv != 0) {
91165641822SToomas Soome 				rv = efi_print_var(varname, &varguid, lflag);
91265641822SToomas Soome 				if (rv != CMD_OK) {
91365641822SToomas Soome 					if (rv == CMD_WARN)
91465641822SToomas Soome 						rv = CMD_OK;
915ca987d46SWarner Losh 					break;
91665641822SToomas Soome 				}
917ca987d46SWarner Losh 				continue;
918ca987d46SWarner Losh 			}
919ca987d46SWarner Losh 		}
920ca987d46SWarner Losh 	}
921ca987d46SWarner Losh 	free(varname);
922ca987d46SWarner Losh 	pager_close();
923ca987d46SWarner Losh 
92465641822SToomas Soome 	return (rv);
925ca987d46SWarner Losh }
926ca987d46SWarner Losh 
927ca987d46SWarner Losh COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
928ca987d46SWarner Losh 
929ca987d46SWarner Losh static int
command_efi_set(int argc,char * argv[])930ca987d46SWarner Losh command_efi_set(int argc, char *argv[])
931ca987d46SWarner Losh {
932ca987d46SWarner Losh 	char *uuid, *var, *val;
933ca987d46SWarner Losh 	CHAR16 wvar[128];
934ca987d46SWarner Losh 	EFI_GUID guid;
93565641822SToomas Soome #if defined(ENABLE_UPDATES)
936ca987d46SWarner Losh 	EFI_STATUS err;
93765641822SToomas Soome #endif
938ca987d46SWarner Losh 
939ca987d46SWarner Losh 	if (argc != 4) {
940ca987d46SWarner Losh 		printf("efi-set uuid var new-value\n");
941ca987d46SWarner Losh 		return (CMD_ERROR);
942ca987d46SWarner Losh 	}
943ca987d46SWarner Losh 	uuid = argv[1];
944ca987d46SWarner Losh 	var = argv[2];
945ca987d46SWarner Losh 	val = argv[3];
94665641822SToomas Soome 	if (efi_name_to_guid(uuid, &guid) == false) {
94765641822SToomas Soome 		printf("Invalid uuid %s\n", uuid);
948ca987d46SWarner Losh 		return (CMD_ERROR);
949ca987d46SWarner Losh 	}
95065641822SToomas Soome 	cpy8to16(var, wvar, nitems(wvar));
95165641822SToomas Soome #if defined(ENABLE_UPDATES)
95265641822SToomas Soome 	err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE |
95365641822SToomas Soome 	    EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
954ca987d46SWarner Losh 	    strlen(val) + 1, val);
955ca987d46SWarner Losh 	if (EFI_ERROR(err)) {
95665641822SToomas Soome 		printf("Failed to set variable: error %lu\n",
95765641822SToomas Soome 		    EFI_ERROR_CODE(err));
958ca987d46SWarner Losh 		return (CMD_ERROR);
959ca987d46SWarner Losh 	}
96065641822SToomas Soome #else
96165641822SToomas Soome 	printf("would set %s %s = %s\n", uuid, var, val);
96265641822SToomas Soome #endif
963ca987d46SWarner Losh 	return (CMD_OK);
964ca987d46SWarner Losh }
965ca987d46SWarner Losh 
966ca987d46SWarner Losh COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
967ca987d46SWarner Losh 
968ca987d46SWarner Losh static int
command_efi_unset(int argc,char * argv[])969ca987d46SWarner Losh command_efi_unset(int argc, char *argv[])
970ca987d46SWarner Losh {
971ca987d46SWarner Losh 	char *uuid, *var;
972ca987d46SWarner Losh 	CHAR16 wvar[128];
973ca987d46SWarner Losh 	EFI_GUID guid;
97465641822SToomas Soome #if defined(ENABLE_UPDATES)
975ca987d46SWarner Losh 	EFI_STATUS err;
97665641822SToomas Soome #endif
977ca987d46SWarner Losh 
978ca987d46SWarner Losh 	if (argc != 3) {
979ca987d46SWarner Losh 		printf("efi-unset uuid var\n");
980ca987d46SWarner Losh 		return (CMD_ERROR);
981ca987d46SWarner Losh 	}
982ca987d46SWarner Losh 	uuid = argv[1];
983ca987d46SWarner Losh 	var = argv[2];
98465641822SToomas Soome 	if (efi_name_to_guid(uuid, &guid) == false) {
985ca987d46SWarner Losh 		printf("Invalid uuid %s\n", uuid);
986ca987d46SWarner Losh 		return (CMD_ERROR);
987ca987d46SWarner Losh 	}
98865641822SToomas Soome 	cpy8to16(var, wvar, nitems(wvar));
98965641822SToomas Soome #if defined(ENABLE_UPDATES)
990ca987d46SWarner Losh 	err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
991ca987d46SWarner Losh 	if (EFI_ERROR(err)) {
99265641822SToomas Soome 		printf("Failed to unset variable: error %lu\n",
99365641822SToomas Soome 		    EFI_ERROR_CODE(err));
994ca987d46SWarner Losh 		return (CMD_ERROR);
995ca987d46SWarner Losh 	}
99665641822SToomas Soome #else
99765641822SToomas Soome 	printf("would unset %s %s \n", uuid, var);
99865641822SToomas Soome #endif
999ca987d46SWarner Losh 	return (CMD_OK);
1000ca987d46SWarner Losh }
1001