summaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_load_options.c
blob: 68cd85ba2ee9e79d2e30c32417b534787cbd787a (plain)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: GPL-2.0+
/*
 *  EFI boot manager
 *
 *  Copyright (c) 2018 AKASHI Takahiro, et.al.
 */

#define LOG_CATEGORY LOGC_EFI

#include <common.h>
#include <charset.h>
#include <log.h>
#include <malloc.h>
#include <efi_loader.h>
#include <asm/unaligned.h>

/**
 * efi_set_load_options() - set the load options of a loaded image
 *
 * @handle:		the image handle
 * @load_options_size:	size of load options
 * @load_options:	pointer to load options
 * Return:		status code
 */
efi_status_t efi_set_load_options(efi_handle_t handle,
				  efi_uintn_t load_options_size,
				  void *load_options)
{
	struct efi_loaded_image *loaded_image_info;
	efi_status_t ret;

	ret = EFI_CALL(systab.boottime->open_protocol(
					handle,
					&efi_guid_loaded_image,
					(void **)&loaded_image_info,
					efi_root, NULL,
					EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
	if (ret != EFI_SUCCESS)
		return EFI_INVALID_PARAMETER;

	loaded_image_info->load_options = load_options;
	loaded_image_info->load_options_size = load_options_size;

	return EFI_CALL(systab.boottime->close_protocol(handle,
							&efi_guid_loaded_image,
							efi_root, NULL));
}

/**
 * efi_deserialize_load_option() - parse serialized data
 *
 * Parse serialized data describing a load option and transform it to the
 * efi_load_option structure.
 *
 * @lo:		pointer to target
 * @data:	serialized data
 * @size:	size of the load option, on return size of the optional data
 * Return:	status code
 */
efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
					 efi_uintn_t *size)
{
	efi_uintn_t len;

	len = sizeof(u32);
	if (*size < len + 2 * sizeof(u16))
		return EFI_INVALID_PARAMETER;
	lo->attributes = get_unaligned_le32(data);
	data += len;
	*size -= len;

	len = sizeof(u16);
	lo->file_path_length = get_unaligned_le16(data);
	data += len;
	*size -= len;

	lo->label = (u16 *)data;
	len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
	if (lo->label[len])
		return EFI_INVALID_PARAMETER;
	len = (len + 1) * sizeof(u16);
	if (*size < len)
		return EFI_INVALID_PARAMETER;
	data += len;
	*size -= len;

	len = lo->file_path_length;
	if (*size < len)
		return EFI_INVALID_PARAMETER;
	lo->file_path = (struct efi_device_path *)data;
	if (efi_dp_check_length(lo->file_path, len) < 0)
		return EFI_INVALID_PARAMETER;
	data += len;
	*size -= len;

	lo->optional_data = data;

	return EFI_SUCCESS;
}

/**
 * efi_serialize_load_option() - serialize load option
 *
 * Serialize efi_load_option structure into byte stream for BootXXXX.
 *
 * @data:	buffer for serialized data
 * @lo:		load option
 * Return:	size of allocated buffer
 */
unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
{
	unsigned long label_len;
	unsigned long size;
	u8 *p;

	label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);

	/* total size */
	size = sizeof(lo->attributes);
	size += sizeof(lo->file_path_length);
	size += label_len;
	size += lo->file_path_length;
	if (lo->optional_data)
		size += (utf8_utf16_strlen((const char *)lo->optional_data)
					   + 1) * sizeof(u16);
	p = malloc(size);
	if (!p)
		return 0;

	/* copy data */
	*data = p;
	memcpy(p, &lo->attributes, sizeof(lo->attributes));
	p += sizeof(lo->attributes);

	memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
	p += sizeof(lo->file_path_length);

	memcpy(p, lo->label, label_len);
	p += label_len;

	memcpy(p, lo->file_path, lo->file_path_length);
	p += lo->file_path_length;

	if (lo->optional_data) {
		utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
		p += sizeof(u16); /* size of trailing \0 */
	}
	return size;
}