summaryrefslogtreecommitdiff
path: root/drivers/firmware/efi/libstub/bli.c
blob: 10696886d2229520e81e73118c0b03ddc537b2d1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// SPDX-License-Identifier: GPL-2.0

#include <generated/utsrelease.h>

#include <linux/efi.h>
#include <linux/unaligned.h>

#include "efistub.h"

static efi_guid_t loader_entry_guid = LINUX_EFI_LOADER_ENTRY_GUID;

static const struct efi_hd_dev_path *
efi_bli_find_hd_node(const struct efi_dev_path *path)
{
	const struct efi_dev_path *node;
	u16 node_len;

	for (node = path;
	     node->header.type != EFI_DEV_END_PATH &&
	     node->header.type != EFI_DEV_END_PATH2;
	     node = (const void *)node + node_len) {
		node_len = get_unaligned_le16(&node->header.length);

		if (node_len < sizeof(node->header))
			return NULL;

		if (node->header.type != EFI_DEV_MEDIA ||
		    node->header.sub_type != EFI_DEV_MEDIA_HARD_DRIVE)
			continue;

		if (node_len < sizeof(node->hd))
			return NULL;

		if (node->hd.partition_format != EFI_HD_PARTITION_FORMAT_GPT ||
		    node->hd.signature_type != EFI_HD_SIGNATURE_TYPE_GUID)
			continue;

		return &node->hd;
	}

	return NULL;
}

static void efi_bli_populate_loader_part_uuid(const efi_loaded_image_t *image)
{
	static efi_guid_t device_path_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
	efi_char16_t partuuid[UUID_STRING_LEN + 1];
	const struct efi_hd_dev_path *hd_node;
	const struct efi_dev_path *path;

	if (efi_bs_call(handle_protocol, efi_table_attr(image, device_handle),
			&device_path_guid, (void **)&path) != EFI_SUCCESS)
		return;

	hd_node = efi_bli_find_hd_node(path);
	if (!hd_node)
		return;

	if (efi_snprintf(partuuid, ARRAY_SIZE(partuuid), "%pUl",
			 &hd_node->signature) != UUID_STRING_LEN)
		return;

	set_efi_var(L"LoaderDevicePartUUID", &loader_entry_guid,
		    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
		    sizeof(partuuid), partuuid);
}

void efi_bli_set_variables(const efi_loaded_image_t *image)
{
	static efi_char16_t loader_info[] = L"Linux EFI stub " UTS_RELEASE;
	unsigned long size = 0;

	if (!image)
		return;

	if (get_efi_var(L"LoaderInfo", &loader_entry_guid,
			NULL, &size, NULL) != EFI_NOT_FOUND)
		return;

	if (set_efi_var(L"LoaderInfo", &loader_entry_guid,
			EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
			sizeof(loader_info), loader_info) != EFI_SUCCESS)
		return;

	efi_bli_populate_loader_part_uuid(image);
}