1 // SPDX-License-Identifier: GPL-2.0
3 * Helper functions used by the EFI stub on multiple
4 * architectures. This should be #included by the EFI stub
5 * implementation files.
7 * Copyright 2011 Intel Corporation; author Matt Fleming
10 #include <linux/efi.h>
15 #define MAX_FILENAME_SIZE 256
18 * Some firmware implementations have problems reading files in one go.
19 * A read chunk size of 1MB seems to work for most platforms.
21 * Unfortunately, reading files in chunks triggers *other* bugs on some
22 * platforms, so we provide a way to disable this workaround, which can
23 * be done by passing "efi=nochunk" on the EFI boot stub command line.
25 * If you experience issues with initrd images being corrupt it's worth
26 * trying efi=nochunk, but chunking is enabled by default on x86 because
27 * there are far more machines that require the workaround than those that
28 * break with it enabled.
30 #define EFI_READ_CHUNK_SIZE SZ_1M
34 efi_char16_t filename
[MAX_FILENAME_SIZE
];
37 static efi_status_t
efi_open_file(efi_file_protocol_t
*volume
,
39 efi_file_protocol_t
**handle
,
40 unsigned long *file_size
)
42 efi_guid_t info_guid
= EFI_FILE_INFO_ID
;
43 efi_file_protocol_t
*fh
;
44 unsigned long info_sz
;
47 status
= volume
->open(volume
, &fh
, fi
->filename
, EFI_FILE_MODE_READ
, 0);
48 if (status
!= EFI_SUCCESS
) {
49 pr_efi_err("Failed to open file: ");
50 efi_char16_printk(fi
->filename
);
55 info_sz
= sizeof(struct finfo
);
56 status
= fh
->get_info(fh
, &info_guid
, &info_sz
, fi
);
57 if (status
!= EFI_SUCCESS
) {
58 pr_efi_err("Failed to get file info\n");
64 *file_size
= fi
->info
.file_size
;
68 static efi_status_t
efi_open_volume(efi_loaded_image_t
*image
,
69 efi_file_protocol_t
**fh
)
71 efi_guid_t fs_proto
= EFI_FILE_SYSTEM_GUID
;
72 efi_simple_file_system_protocol_t
*io
;
75 status
= efi_bs_call(handle_protocol
, image
->device_handle
, &fs_proto
,
77 if (status
!= EFI_SUCCESS
) {
78 pr_efi_err("Failed to handle fs_proto\n");
82 status
= io
->open_volume(io
, fh
);
83 if (status
!= EFI_SUCCESS
)
84 pr_efi_err("Failed to open volume\n");
89 static int find_file_option(const efi_char16_t
*cmdline
, int cmdline_len
,
90 const efi_char16_t
*prefix
, int prefix_size
,
91 efi_char16_t
*result
, int result_len
)
93 int prefix_len
= prefix_size
/ 2;
97 for (i
= prefix_len
; i
< cmdline_len
; i
++) {
98 if (!memcmp(&cmdline
[i
- prefix_len
], prefix
, prefix_size
)) {
107 /* Skip any leading slashes */
108 while (cmdline
[i
] == L
'/' || cmdline
[i
] == L
'\\')
111 while (--result_len
> 0 && i
< cmdline_len
) {
112 efi_char16_t c
= cmdline
[i
++];
114 if (c
== L
'\0' || c
== L
'\n' || c
== L
' ')
117 /* Replace UNIX dir separators with EFI standard ones */
127 * Check the cmdline for a LILO-style file= arguments.
129 * We only support loading a file from the same filesystem as
132 static efi_status_t
handle_cmdline_files(efi_loaded_image_t
*image
,
133 const efi_char16_t
*optstr
,
135 unsigned long soft_limit
,
136 unsigned long hard_limit
,
137 unsigned long *load_addr
,
138 unsigned long *load_size
)
140 const efi_char16_t
*cmdline
= image
->load_options
;
141 int cmdline_len
= image
->load_options_size
/ 2;
142 unsigned long efi_chunk_size
= ULONG_MAX
;
143 efi_file_protocol_t
*volume
= NULL
;
144 efi_file_protocol_t
*file
;
145 unsigned long alloc_addr
;
146 unsigned long alloc_size
;
150 if (!load_addr
|| !load_size
)
151 return EFI_INVALID_PARAMETER
;
153 if (IS_ENABLED(CONFIG_X86
) && !nochunk())
154 efi_chunk_size
= EFI_READ_CHUNK_SIZE
;
156 alloc_addr
= alloc_size
= 0;
162 offset
= find_file_option(cmdline
, cmdline_len
,
164 fi
.filename
, ARRAY_SIZE(fi
.filename
));
170 cmdline_len
-= offset
;
173 status
= efi_open_volume(image
, &volume
);
174 if (status
!= EFI_SUCCESS
)
178 status
= efi_open_file(volume
, &fi
, &file
, &size
);
179 if (status
!= EFI_SUCCESS
)
180 goto err_close_volume
;
183 * Check whether the existing allocation can contain the next
184 * file. This condition will also trigger naturally during the
185 * first (and typically only) iteration of the loop, given that
186 * alloc_size == 0 in that case.
188 if (round_up(alloc_size
+ size
, EFI_ALLOC_ALIGN
) >
189 round_up(alloc_size
, EFI_ALLOC_ALIGN
)) {
190 unsigned long old_addr
= alloc_addr
;
192 status
= EFI_OUT_OF_RESOURCES
;
193 if (soft_limit
< hard_limit
)
194 status
= efi_allocate_pages(alloc_size
+ size
,
197 if (status
== EFI_OUT_OF_RESOURCES
)
198 status
= efi_allocate_pages(alloc_size
+ size
,
201 if (status
!= EFI_SUCCESS
) {
202 pr_efi_err("Failed to allocate memory for files\n");
208 * This is not the first time we've gone
209 * around this loop, and so we are loading
210 * multiple files that need to be concatenated
211 * and returned in a single buffer.
213 memcpy((void *)alloc_addr
, (void *)old_addr
, alloc_size
);
214 efi_free(alloc_size
, old_addr
);
218 addr
= (void *)alloc_addr
+ alloc_size
;
222 unsigned long chunksize
= min(size
, efi_chunk_size
);
224 status
= file
->read(file
, &chunksize
, addr
);
225 if (status
!= EFI_SUCCESS
) {
226 pr_efi_err("Failed to read file\n");
233 } while (offset
> 0);
235 *load_addr
= alloc_addr
;
236 *load_size
= alloc_size
;
239 volume
->close(volume
);
246 volume
->close(volume
);
247 efi_free(alloc_size
, alloc_addr
);
251 efi_status_t
efi_load_dtb(efi_loaded_image_t
*image
,
252 unsigned long *load_addr
,
253 unsigned long *load_size
)
255 return handle_cmdline_files(image
, L
"dtb=", sizeof(L
"dtb=") - 2,
256 ULONG_MAX
, ULONG_MAX
, load_addr
, load_size
);
259 efi_status_t
efi_load_initrd(efi_loaded_image_t
*image
,
260 unsigned long *load_addr
,
261 unsigned long *load_size
,
262 unsigned long soft_limit
,
263 unsigned long hard_limit
)
265 return handle_cmdline_files(image
, L
"initrd=", sizeof(L
"initrd=") - 2,
266 soft_limit
, hard_limit
, load_addr
, load_size
);