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 while (--result_len
> 0 && i
< cmdline_len
) {
108 if (cmdline
[i
] == L
'\0' ||
109 cmdline
[i
] == L
'\n' ||
112 *result
++ = cmdline
[i
++];
119 * Check the cmdline for a LILO-style file= arguments.
121 * We only support loading a file from the same filesystem as
124 static efi_status_t
handle_cmdline_files(efi_loaded_image_t
*image
,
125 const efi_char16_t
*optstr
,
127 unsigned long soft_limit
,
128 unsigned long hard_limit
,
129 unsigned long *load_addr
,
130 unsigned long *load_size
)
132 const efi_char16_t
*cmdline
= image
->load_options
;
133 int cmdline_len
= image
->load_options_size
/ 2;
134 unsigned long efi_chunk_size
= ULONG_MAX
;
135 efi_file_protocol_t
*volume
= NULL
;
136 efi_file_protocol_t
*file
;
137 unsigned long alloc_addr
;
138 unsigned long alloc_size
;
142 if (!load_addr
|| !load_size
)
143 return EFI_INVALID_PARAMETER
;
145 if (IS_ENABLED(CONFIG_X86
) && !nochunk())
146 efi_chunk_size
= EFI_READ_CHUNK_SIZE
;
148 alloc_addr
= alloc_size
= 0;
154 offset
= find_file_option(cmdline
, cmdline_len
,
156 fi
.filename
, ARRAY_SIZE(fi
.filename
));
162 cmdline_len
-= offset
;
165 status
= efi_open_volume(image
, &volume
);
166 if (status
!= EFI_SUCCESS
)
170 status
= efi_open_file(volume
, &fi
, &file
, &size
);
171 if (status
!= EFI_SUCCESS
)
172 goto err_close_volume
;
175 * Check whether the existing allocation can contain the next
176 * file. This condition will also trigger naturally during the
177 * first (and typically only) iteration of the loop, given that
178 * alloc_size == 0 in that case.
180 if (round_up(alloc_size
+ size
, EFI_ALLOC_ALIGN
) >
181 round_up(alloc_size
, EFI_ALLOC_ALIGN
)) {
182 unsigned long old_addr
= alloc_addr
;
184 status
= EFI_OUT_OF_RESOURCES
;
185 if (soft_limit
< hard_limit
)
186 status
= efi_allocate_pages(alloc_size
+ size
,
189 if (status
== EFI_OUT_OF_RESOURCES
)
190 status
= efi_allocate_pages(alloc_size
+ size
,
193 if (status
!= EFI_SUCCESS
) {
194 pr_efi_err("Failed to allocate memory for files\n");
200 * This is not the first time we've gone
201 * around this loop, and so we are loading
202 * multiple files that need to be concatenated
203 * and returned in a single buffer.
205 memcpy((void *)alloc_addr
, (void *)old_addr
, alloc_size
);
206 efi_free(alloc_size
, old_addr
);
210 addr
= (void *)alloc_addr
+ alloc_size
;
214 unsigned long chunksize
= min(size
, efi_chunk_size
);
216 status
= file
->read(file
, &chunksize
, addr
);
217 if (status
!= EFI_SUCCESS
) {
218 pr_efi_err("Failed to read file\n");
225 } while (offset
> 0);
227 *load_addr
= alloc_addr
;
228 *load_size
= alloc_size
;
231 volume
->close(volume
);
238 volume
->close(volume
);
239 efi_free(alloc_size
, alloc_addr
);
243 efi_status_t
efi_load_dtb(efi_loaded_image_t
*image
,
244 unsigned long *load_addr
,
245 unsigned long *load_size
)
247 return handle_cmdline_files(image
, L
"dtb=", sizeof(L
"dtb=") - 2,
248 ULONG_MAX
, ULONG_MAX
, load_addr
, load_size
);
251 efi_status_t
efi_load_initrd(efi_loaded_image_t
*image
,
252 unsigned long *load_addr
,
253 unsigned long *load_size
,
254 unsigned long soft_limit
,
255 unsigned long hard_limit
)
257 return handle_cmdline_files(image
, L
"initrd=", sizeof(L
"initrd=") - 2,
258 soft_limit
, hard_limit
, load_addr
, load_size
);