blob: 1bf439be91382b67fc92d30dcbb1a256e0db4b59 [file] [log] [blame]
Roy Franz7721da42013-09-22 15:45:27 -07001/*
2 * Helper functions used by the EFI stub on multiple
3 * architectures. This should be #included by the EFI stub
4 * implementation files.
5 *
6 * Copyright 2011 Intel Corporation; author Matt Fleming
7 *
8 * This file is part of the Linux kernel, and is made available
9 * under the terms of the GNU General Public License version 2.
10 *
11 */
12#define EFI_READ_CHUNK_SIZE (1024 * 1024)
13
Roy Franz36f89612013-09-22 15:45:40 -070014struct file_info {
Roy Franz7721da42013-09-22 15:45:27 -070015 efi_file_handle_t *handle;
16 u64 size;
17};
18
Roy Franz876dc362013-09-22 15:45:28 -070019static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
Roy Franz7721da42013-09-22 15:45:27 -070020{
21 char *s8;
22
23 for (s8 = str; *s8; s8++) {
24 efi_char16_t ch[2] = { 0 };
25
26 ch[0] = *s8;
27 if (*s8 == '\n') {
28 efi_char16_t nl[2] = { '\r', 0 };
Roy Franz876dc362013-09-22 15:45:28 -070029 efi_char16_printk(sys_table_arg, nl);
Roy Franz7721da42013-09-22 15:45:27 -070030 }
31
Roy Franz876dc362013-09-22 15:45:28 -070032 efi_char16_printk(sys_table_arg, ch);
Roy Franz7721da42013-09-22 15:45:27 -070033 }
34}
35
Roy Franzf966ea02013-12-13 11:04:49 -080036#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg)
37#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg)
38
Roy Franz7721da42013-09-22 15:45:27 -070039
Roy Franz86cc6532013-09-22 15:45:35 -070040static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
41 efi_memory_desc_t **map,
42 unsigned long *map_size,
Roy Franz1c089c62013-09-22 15:45:36 -070043 unsigned long *desc_size,
44 u32 *desc_ver,
45 unsigned long *key_ptr)
Roy Franz7721da42013-09-22 15:45:27 -070046{
47 efi_memory_desc_t *m = NULL;
48 efi_status_t status;
49 unsigned long key;
50 u32 desc_version;
51
52 *map_size = sizeof(*m) * 32;
53again:
54 /*
55 * Add an additional efi_memory_desc_t because we're doing an
56 * allocation which may be in a new descriptor region.
57 */
58 *map_size += sizeof(*m);
Matt Fleming204b0a12014-03-22 10:09:01 +000059 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
60 *map_size, (void **)&m);
Roy Franz7721da42013-09-22 15:45:27 -070061 if (status != EFI_SUCCESS)
62 goto fail;
63
Matt Fleming54b52d82014-01-10 15:27:14 +000064 *desc_size = 0;
65 key = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +000066 status = efi_call_early(get_memory_map, map_size, m,
67 &key, desc_size, &desc_version);
Roy Franz7721da42013-09-22 15:45:27 -070068 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming204b0a12014-03-22 10:09:01 +000069 efi_call_early(free_pool, m);
Roy Franz7721da42013-09-22 15:45:27 -070070 goto again;
71 }
72
73 if (status != EFI_SUCCESS)
Matt Fleming204b0a12014-03-22 10:09:01 +000074 efi_call_early(free_pool, m);
Matt Fleming54b52d82014-01-10 15:27:14 +000075
Roy Franz1c089c62013-09-22 15:45:36 -070076 if (key_ptr && status == EFI_SUCCESS)
77 *key_ptr = key;
78 if (desc_ver && status == EFI_SUCCESS)
79 *desc_ver = desc_version;
Roy Franz7721da42013-09-22 15:45:27 -070080
81fail:
82 *map = m;
83 return status;
84}
85
86/*
87 * Allocate at the highest possible address that is not above 'max'.
88 */
Roy Franz40e45302013-09-22 15:45:29 -070089static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
Roy Franz876dc362013-09-22 15:45:28 -070090 unsigned long size, unsigned long align,
91 unsigned long *addr, unsigned long max)
Roy Franz7721da42013-09-22 15:45:27 -070092{
93 unsigned long map_size, desc_size;
94 efi_memory_desc_t *map;
95 efi_status_t status;
96 unsigned long nr_pages;
97 u64 max_addr = 0;
98 int i;
99
Roy Franz1c089c62013-09-22 15:45:36 -0700100 status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,
101 NULL, NULL);
Roy Franz7721da42013-09-22 15:45:27 -0700102 if (status != EFI_SUCCESS)
103 goto fail;
104
Roy Franz38dd9c02013-09-22 15:45:30 -0700105 /*
106 * Enforce minimum alignment that EFI requires when requesting
107 * a specific address. We are doing page-based allocations,
108 * so we must be aligned to a page.
109 */
110 if (align < EFI_PAGE_SIZE)
111 align = EFI_PAGE_SIZE;
112
Roy Franz7721da42013-09-22 15:45:27 -0700113 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
114again:
115 for (i = 0; i < map_size / desc_size; i++) {
116 efi_memory_desc_t *desc;
117 unsigned long m = (unsigned long)map;
118 u64 start, end;
119
120 desc = (efi_memory_desc_t *)(m + (i * desc_size));
121 if (desc->type != EFI_CONVENTIONAL_MEMORY)
122 continue;
123
124 if (desc->num_pages < nr_pages)
125 continue;
126
127 start = desc->phys_addr;
128 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
129
130 if ((start + size) > end || (start + size) > max)
131 continue;
132
133 if (end - size > max)
134 end = max;
135
136 if (round_down(end - size, align) < start)
137 continue;
138
139 start = round_down(end - size, align);
140
141 /*
142 * Don't allocate at 0x0. It will confuse code that
143 * checks pointers against NULL.
144 */
145 if (start == 0x0)
146 continue;
147
148 if (start > max_addr)
149 max_addr = start;
150 }
151
152 if (!max_addr)
153 status = EFI_NOT_FOUND;
154 else {
Matt Fleming204b0a12014-03-22 10:09:01 +0000155 status = efi_call_early(allocate_pages,
156 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
157 nr_pages, &max_addr);
Roy Franz7721da42013-09-22 15:45:27 -0700158 if (status != EFI_SUCCESS) {
159 max = max_addr;
160 max_addr = 0;
161 goto again;
162 }
163
164 *addr = max_addr;
165 }
166
Matt Fleming204b0a12014-03-22 10:09:01 +0000167 efi_call_early(free_pool, map);
Roy Franz7721da42013-09-22 15:45:27 -0700168fail:
169 return status;
170}
171
172/*
173 * Allocate at the lowest possible address.
174 */
Roy Franz40e45302013-09-22 15:45:29 -0700175static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
176 unsigned long size, unsigned long align,
Roy Franz7721da42013-09-22 15:45:27 -0700177 unsigned long *addr)
178{
179 unsigned long map_size, desc_size;
180 efi_memory_desc_t *map;
181 efi_status_t status;
182 unsigned long nr_pages;
183 int i;
184
Roy Franz1c089c62013-09-22 15:45:36 -0700185 status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,
186 NULL, NULL);
Roy Franz7721da42013-09-22 15:45:27 -0700187 if (status != EFI_SUCCESS)
188 goto fail;
189
Roy Franz38dd9c02013-09-22 15:45:30 -0700190 /*
191 * Enforce minimum alignment that EFI requires when requesting
192 * a specific address. We are doing page-based allocations,
193 * so we must be aligned to a page.
194 */
195 if (align < EFI_PAGE_SIZE)
196 align = EFI_PAGE_SIZE;
197
Roy Franz7721da42013-09-22 15:45:27 -0700198 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
199 for (i = 0; i < map_size / desc_size; i++) {
200 efi_memory_desc_t *desc;
201 unsigned long m = (unsigned long)map;
202 u64 start, end;
203
204 desc = (efi_memory_desc_t *)(m + (i * desc_size));
205
206 if (desc->type != EFI_CONVENTIONAL_MEMORY)
207 continue;
208
209 if (desc->num_pages < nr_pages)
210 continue;
211
212 start = desc->phys_addr;
213 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
214
215 /*
216 * Don't allocate at 0x0. It will confuse code that
217 * checks pointers against NULL. Skip the first 8
218 * bytes so we start at a nice even number.
219 */
220 if (start == 0x0)
221 start += 8;
222
223 start = round_up(start, align);
224 if ((start + size) > end)
225 continue;
226
Matt Fleming204b0a12014-03-22 10:09:01 +0000227 status = efi_call_early(allocate_pages,
228 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
229 nr_pages, &start);
Roy Franz7721da42013-09-22 15:45:27 -0700230 if (status == EFI_SUCCESS) {
231 *addr = start;
232 break;
233 }
234 }
235
236 if (i == map_size / desc_size)
237 status = EFI_NOT_FOUND;
238
Matt Fleming204b0a12014-03-22 10:09:01 +0000239 efi_call_early(free_pool, map);
Roy Franz7721da42013-09-22 15:45:27 -0700240fail:
241 return status;
242}
243
Roy Franz40e45302013-09-22 15:45:29 -0700244static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
Roy Franz876dc362013-09-22 15:45:28 -0700245 unsigned long addr)
Roy Franz7721da42013-09-22 15:45:27 -0700246{
247 unsigned long nr_pages;
248
Roy Franz0e1cadb2013-09-22 15:45:38 -0700249 if (!size)
250 return;
251
Roy Franz7721da42013-09-22 15:45:27 -0700252 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
Matt Fleming204b0a12014-03-22 10:09:01 +0000253 efi_call_early(free_pages, addr, nr_pages);
Roy Franz7721da42013-09-22 15:45:27 -0700254}
255
256
257/*
Roy Franz36f89612013-09-22 15:45:40 -0700258 * Check the cmdline for a LILO-style file= arguments.
Roy Franz7721da42013-09-22 15:45:27 -0700259 *
Roy Franz36f89612013-09-22 15:45:40 -0700260 * We only support loading a file from the same filesystem as
261 * the kernel image.
Roy Franz7721da42013-09-22 15:45:27 -0700262 */
Roy Franz46f45822013-09-22 15:45:39 -0700263static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
264 efi_loaded_image_t *image,
265 char *cmd_line, char *option_string,
266 unsigned long max_addr,
267 unsigned long *load_addr,
268 unsigned long *load_size)
Roy Franz7721da42013-09-22 15:45:27 -0700269{
Roy Franz36f89612013-09-22 15:45:40 -0700270 struct file_info *files;
271 unsigned long file_addr;
Roy Franz36f89612013-09-22 15:45:40 -0700272 u64 file_size_total;
Leif Lindholm9403e462014-04-04 13:25:46 +0100273 efi_file_handle_t *fh = NULL;
Roy Franz7721da42013-09-22 15:45:27 -0700274 efi_status_t status;
Roy Franz36f89612013-09-22 15:45:40 -0700275 int nr_files;
Roy Franz7721da42013-09-22 15:45:27 -0700276 char *str;
277 int i, j, k;
278
Roy Franz36f89612013-09-22 15:45:40 -0700279 file_addr = 0;
280 file_size_total = 0;
Roy Franz7721da42013-09-22 15:45:27 -0700281
Roy Franz46f45822013-09-22 15:45:39 -0700282 str = cmd_line;
Roy Franz7721da42013-09-22 15:45:27 -0700283
284 j = 0; /* See close_handles */
285
Roy Franz46f45822013-09-22 15:45:39 -0700286 if (!load_addr || !load_size)
287 return EFI_INVALID_PARAMETER;
288
289 *load_addr = 0;
290 *load_size = 0;
291
Roy Franz7721da42013-09-22 15:45:27 -0700292 if (!str || !*str)
293 return EFI_SUCCESS;
294
Roy Franz36f89612013-09-22 15:45:40 -0700295 for (nr_files = 0; *str; nr_files++) {
Roy Franz46f45822013-09-22 15:45:39 -0700296 str = strstr(str, option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700297 if (!str)
298 break;
299
Roy Franz46f45822013-09-22 15:45:39 -0700300 str += strlen(option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700301
302 /* Skip any leading slashes */
303 while (*str == '/' || *str == '\\')
304 str++;
305
306 while (*str && *str != ' ' && *str != '\n')
307 str++;
308 }
309
Roy Franz36f89612013-09-22 15:45:40 -0700310 if (!nr_files)
Roy Franz7721da42013-09-22 15:45:27 -0700311 return EFI_SUCCESS;
312
Matt Fleming204b0a12014-03-22 10:09:01 +0000313 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
314 nr_files * sizeof(*files), (void **)&files);
Roy Franz7721da42013-09-22 15:45:27 -0700315 if (status != EFI_SUCCESS) {
Roy Franzf966ea02013-12-13 11:04:49 -0800316 pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n");
Roy Franz7721da42013-09-22 15:45:27 -0700317 goto fail;
318 }
319
Roy Franz46f45822013-09-22 15:45:39 -0700320 str = cmd_line;
Roy Franz36f89612013-09-22 15:45:40 -0700321 for (i = 0; i < nr_files; i++) {
322 struct file_info *file;
Roy Franz7721da42013-09-22 15:45:27 -0700323 efi_char16_t filename_16[256];
Roy Franz7721da42013-09-22 15:45:27 -0700324 efi_char16_t *p;
Roy Franz7721da42013-09-22 15:45:27 -0700325
Roy Franz46f45822013-09-22 15:45:39 -0700326 str = strstr(str, option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700327 if (!str)
328 break;
329
Roy Franz46f45822013-09-22 15:45:39 -0700330 str += strlen(option_string);
Roy Franz7721da42013-09-22 15:45:27 -0700331
Roy Franz36f89612013-09-22 15:45:40 -0700332 file = &files[i];
Roy Franz7721da42013-09-22 15:45:27 -0700333 p = filename_16;
334
335 /* Skip any leading slashes */
336 while (*str == '/' || *str == '\\')
337 str++;
338
339 while (*str && *str != ' ' && *str != '\n') {
340 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
341 break;
342
343 if (*str == '/') {
344 *p++ = '\\';
Roy Franz4e283082013-09-22 15:45:42 -0700345 str++;
Roy Franz7721da42013-09-22 15:45:27 -0700346 } else {
347 *p++ = *str++;
348 }
349 }
350
351 *p = '\0';
352
353 /* Only open the volume once. */
354 if (!i) {
Matt Fleming54b52d82014-01-10 15:27:14 +0000355 status = efi_open_volume(sys_table_arg, image,
356 (void **)&fh);
357 if (status != EFI_SUCCESS)
Roy Franz36f89612013-09-22 15:45:40 -0700358 goto free_files;
Roy Franz7721da42013-09-22 15:45:27 -0700359 }
360
Matt Fleming54b52d82014-01-10 15:27:14 +0000361 status = efi_file_size(sys_table_arg, fh, filename_16,
362 (void **)&file->handle, &file->size);
363 if (status != EFI_SUCCESS)
Roy Franz7721da42013-09-22 15:45:27 -0700364 goto close_handles;
Roy Franz7721da42013-09-22 15:45:27 -0700365
Matt Fleming54b52d82014-01-10 15:27:14 +0000366 file_size_total += file->size;
Roy Franz7721da42013-09-22 15:45:27 -0700367 }
368
Roy Franz36f89612013-09-22 15:45:40 -0700369 if (file_size_total) {
Roy Franz7721da42013-09-22 15:45:27 -0700370 unsigned long addr;
371
372 /*
Roy Franz36f89612013-09-22 15:45:40 -0700373 * Multiple files need to be at consecutive addresses in memory,
374 * so allocate enough memory for all the files. This is used
375 * for loading multiple files.
Roy Franz7721da42013-09-22 15:45:27 -0700376 */
Roy Franz36f89612013-09-22 15:45:40 -0700377 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000,
378 &file_addr, max_addr);
Roy Franz7721da42013-09-22 15:45:27 -0700379 if (status != EFI_SUCCESS) {
Roy Franzf966ea02013-12-13 11:04:49 -0800380 pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n");
Roy Franz7721da42013-09-22 15:45:27 -0700381 goto close_handles;
382 }
383
384 /* We've run out of free low memory. */
Roy Franz36f89612013-09-22 15:45:40 -0700385 if (file_addr > max_addr) {
Roy Franzf966ea02013-12-13 11:04:49 -0800386 pr_efi_err(sys_table_arg, "We've run out of free low memory\n");
Roy Franz7721da42013-09-22 15:45:27 -0700387 status = EFI_INVALID_PARAMETER;
Roy Franz36f89612013-09-22 15:45:40 -0700388 goto free_file_total;
Roy Franz7721da42013-09-22 15:45:27 -0700389 }
390
Roy Franz36f89612013-09-22 15:45:40 -0700391 addr = file_addr;
392 for (j = 0; j < nr_files; j++) {
Roy Franz6a5fe772013-09-22 15:45:41 -0700393 unsigned long size;
Roy Franz7721da42013-09-22 15:45:27 -0700394
Roy Franz36f89612013-09-22 15:45:40 -0700395 size = files[j].size;
Roy Franz7721da42013-09-22 15:45:27 -0700396 while (size) {
Roy Franz6a5fe772013-09-22 15:45:41 -0700397 unsigned long chunksize;
Roy Franz7721da42013-09-22 15:45:27 -0700398 if (size > EFI_READ_CHUNK_SIZE)
399 chunksize = EFI_READ_CHUNK_SIZE;
400 else
401 chunksize = size;
Matt Fleming54b52d82014-01-10 15:27:14 +0000402
Matt Fleming47514c92014-04-10 14:11:45 +0100403 status = efi_file_read(files[j].handle,
Matt Fleming54b52d82014-01-10 15:27:14 +0000404 &chunksize,
405 (void *)addr);
Roy Franz7721da42013-09-22 15:45:27 -0700406 if (status != EFI_SUCCESS) {
Roy Franzf966ea02013-12-13 11:04:49 -0800407 pr_efi_err(sys_table_arg, "Failed to read file\n");
Roy Franz36f89612013-09-22 15:45:40 -0700408 goto free_file_total;
Roy Franz7721da42013-09-22 15:45:27 -0700409 }
410 addr += chunksize;
411 size -= chunksize;
412 }
413
Matt Fleming47514c92014-04-10 14:11:45 +0100414 efi_file_close(files[j].handle);
Roy Franz7721da42013-09-22 15:45:27 -0700415 }
416
417 }
418
Matt Fleming204b0a12014-03-22 10:09:01 +0000419 efi_call_early(free_pool, files);
Roy Franz7721da42013-09-22 15:45:27 -0700420
Roy Franz36f89612013-09-22 15:45:40 -0700421 *load_addr = file_addr;
422 *load_size = file_size_total;
Roy Franz7721da42013-09-22 15:45:27 -0700423
424 return status;
425
Roy Franz36f89612013-09-22 15:45:40 -0700426free_file_total:
427 efi_free(sys_table_arg, file_size_total, file_addr);
Roy Franz7721da42013-09-22 15:45:27 -0700428
429close_handles:
430 for (k = j; k < i; k++)
Matt Fleming47514c92014-04-10 14:11:45 +0100431 efi_file_close(files[k].handle);
Roy Franz36f89612013-09-22 15:45:40 -0700432free_files:
Matt Fleming204b0a12014-03-22 10:09:01 +0000433 efi_call_early(free_pool, files);
Roy Franz7721da42013-09-22 15:45:27 -0700434fail:
Roy Franz46f45822013-09-22 15:45:39 -0700435 *load_addr = 0;
436 *load_size = 0;
Roy Franz7721da42013-09-22 15:45:27 -0700437
438 return status;
439}
Roy Franz4a9f3a72013-09-22 15:45:32 -0700440/*
441 * Relocate a kernel image, either compressed or uncompressed.
442 * In the ARM64 case, all kernel images are currently
443 * uncompressed, and as such when we relocate it we need to
444 * allocate additional space for the BSS segment. Any low
445 * memory that this function should avoid needs to be
446 * unavailable in the EFI memory map, as if the preferred
447 * address is not available the lowest available address will
448 * be used.
449 */
450static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
451 unsigned long *image_addr,
452 unsigned long image_size,
453 unsigned long alloc_size,
454 unsigned long preferred_addr,
455 unsigned long alignment)
Roy Franzc6866d72013-09-22 15:45:31 -0700456{
Roy Franz4a9f3a72013-09-22 15:45:32 -0700457 unsigned long cur_image_addr;
458 unsigned long new_addr = 0;
Roy Franzc6866d72013-09-22 15:45:31 -0700459 efi_status_t status;
Roy Franz4a9f3a72013-09-22 15:45:32 -0700460 unsigned long nr_pages;
461 efi_physical_addr_t efi_addr = preferred_addr;
462
463 if (!image_addr || !image_size || !alloc_size)
464 return EFI_INVALID_PARAMETER;
465 if (alloc_size < image_size)
466 return EFI_INVALID_PARAMETER;
467
468 cur_image_addr = *image_addr;
Roy Franzc6866d72013-09-22 15:45:31 -0700469
470 /*
471 * The EFI firmware loader could have placed the kernel image
Roy Franz4a9f3a72013-09-22 15:45:32 -0700472 * anywhere in memory, but the kernel has restrictions on the
473 * max physical address it can run at. Some architectures
474 * also have a prefered address, so first try to relocate
475 * to the preferred address. If that fails, allocate as low
476 * as possible while respecting the required alignment.
477 */
478 nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
Matt Fleming204b0a12014-03-22 10:09:01 +0000479 status = efi_call_early(allocate_pages,
480 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
481 nr_pages, &efi_addr);
Roy Franz4a9f3a72013-09-22 15:45:32 -0700482 new_addr = efi_addr;
483 /*
484 * If preferred address allocation failed allocate as low as
Roy Franzc6866d72013-09-22 15:45:31 -0700485 * possible.
486 */
Roy Franzc6866d72013-09-22 15:45:31 -0700487 if (status != EFI_SUCCESS) {
Roy Franz4a9f3a72013-09-22 15:45:32 -0700488 status = efi_low_alloc(sys_table_arg, alloc_size, alignment,
489 &new_addr);
490 }
491 if (status != EFI_SUCCESS) {
Roy Franzf966ea02013-12-13 11:04:49 -0800492 pr_efi_err(sys_table_arg, "Failed to allocate usable memory for kernel.\n");
Roy Franz4a9f3a72013-09-22 15:45:32 -0700493 return status;
Roy Franzc6866d72013-09-22 15:45:31 -0700494 }
495
Roy Franz4a9f3a72013-09-22 15:45:32 -0700496 /*
497 * We know source/dest won't overlap since both memory ranges
498 * have been allocated by UEFI, so we can safely use memcpy.
499 */
500 memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
Roy Franzc6866d72013-09-22 15:45:31 -0700501
Roy Franz4a9f3a72013-09-22 15:45:32 -0700502 /* Return the new address of the relocated image. */
503 *image_addr = new_addr;
Roy Franzc6866d72013-09-22 15:45:31 -0700504
505 return status;
506}
Roy Franz5fef3872013-09-22 15:45:33 -0700507
508/*
509 * Convert the unicode UEFI command line to ASCII to pass to kernel.
510 * Size of memory allocated return in *cmd_line_len.
511 * Returns NULL on error.
512 */
513static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg,
514 efi_loaded_image_t *image,
515 int *cmd_line_len)
516{
517 u16 *s2;
518 u8 *s1 = NULL;
519 unsigned long cmdline_addr = 0;
520 int load_options_size = image->load_options_size / 2; /* ASCII */
521 void *options = image->load_options;
522 int options_size = 0;
523 efi_status_t status;
524 int i;
525 u16 zero = 0;
526
527 if (options) {
528 s2 = options;
529 while (*s2 && *s2 != '\n' && options_size < load_options_size) {
530 s2++;
531 options_size++;
532 }
533 }
534
535 if (options_size == 0) {
536 /* No command line options, so return empty string*/
537 options_size = 1;
538 options = &zero;
539 }
540
541 options_size++; /* NUL termination */
Leif Lindholm9403e462014-04-04 13:25:46 +0100542
543 status = efi_low_alloc(sys_table_arg, options_size, 0, &cmdline_addr);
Roy Franz5fef3872013-09-22 15:45:33 -0700544 if (status != EFI_SUCCESS)
545 return NULL;
546
547 s1 = (u8 *)cmdline_addr;
548 s2 = (u16 *)options;
549
550 for (i = 0; i < options_size - 1; i++)
551 *s1++ = *s2++;
552
553 *s1 = '\0';
554
555 *cmd_line_len = options_size;
556 return (char *)cmdline_addr;
557}