2 * Helper functions used by the EFI stub on multiple
3 * architectures. This should be #included by the EFI stub
4 * implementation files.
6 * Copyright 2011 Intel Corporation; author Matt Fleming
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.
12 #define EFI_READ_CHUNK_SIZE (1024 * 1024)
15 efi_file_handle_t *handle;
22 static void efi_char16_printk(efi_char16_t *str)
24 struct efi_simple_text_output_protocol *out;
26 out = (struct efi_simple_text_output_protocol *)sys_table->con_out;
27 efi_call_phys2(out->output_string, out, str);
30 static void efi_printk(char *str)
34 for (s8 = str; *s8; s8++) {
35 efi_char16_t ch[2] = { 0 };
39 efi_char16_t nl[2] = { '\r', 0 };
40 efi_char16_printk(nl);
43 efi_char16_printk(ch);
48 static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size,
49 unsigned long *desc_size)
51 efi_memory_desc_t *m = NULL;
56 *map_size = sizeof(*m) * 32;
59 * Add an additional efi_memory_desc_t because we're doing an
60 * allocation which may be in a new descriptor region.
62 *map_size += sizeof(*m);
63 status = efi_call_phys3(sys_table->boottime->allocate_pool,
64 EFI_LOADER_DATA, *map_size, (void **)&m);
65 if (status != EFI_SUCCESS)
68 status = efi_call_phys5(sys_table->boottime->get_memory_map, map_size,
69 m, &key, desc_size, &desc_version);
70 if (status == EFI_BUFFER_TOO_SMALL) {
71 efi_call_phys1(sys_table->boottime->free_pool, m);
75 if (status != EFI_SUCCESS)
76 efi_call_phys1(sys_table->boottime->free_pool, m);
84 * Allocate at the highest possible address that is not above 'max'.
86 static efi_status_t high_alloc(unsigned long size, unsigned long align,
87 unsigned long *addr, unsigned long max)
89 unsigned long map_size, desc_size;
90 efi_memory_desc_t *map;
92 unsigned long nr_pages;
96 status = __get_map(&map, &map_size, &desc_size);
97 if (status != EFI_SUCCESS)
100 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
102 for (i = 0; i < map_size / desc_size; i++) {
103 efi_memory_desc_t *desc;
104 unsigned long m = (unsigned long)map;
107 desc = (efi_memory_desc_t *)(m + (i * desc_size));
108 if (desc->type != EFI_CONVENTIONAL_MEMORY)
111 if (desc->num_pages < nr_pages)
114 start = desc->phys_addr;
115 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
117 if ((start + size) > end || (start + size) > max)
120 if (end - size > max)
123 if (round_down(end - size, align) < start)
126 start = round_down(end - size, align);
129 * Don't allocate at 0x0. It will confuse code that
130 * checks pointers against NULL.
135 if (start > max_addr)
140 status = EFI_NOT_FOUND;
142 status = efi_call_phys4(sys_table->boottime->allocate_pages,
143 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
144 nr_pages, &max_addr);
145 if (status != EFI_SUCCESS) {
155 efi_call_phys1(sys_table->boottime->free_pool, map);
162 * Allocate at the lowest possible address.
164 static efi_status_t low_alloc(unsigned long size, unsigned long align,
167 unsigned long map_size, desc_size;
168 efi_memory_desc_t *map;
170 unsigned long nr_pages;
173 status = __get_map(&map, &map_size, &desc_size);
174 if (status != EFI_SUCCESS)
177 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
178 for (i = 0; i < map_size / desc_size; i++) {
179 efi_memory_desc_t *desc;
180 unsigned long m = (unsigned long)map;
183 desc = (efi_memory_desc_t *)(m + (i * desc_size));
185 if (desc->type != EFI_CONVENTIONAL_MEMORY)
188 if (desc->num_pages < nr_pages)
191 start = desc->phys_addr;
192 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
195 * Don't allocate at 0x0. It will confuse code that
196 * checks pointers against NULL. Skip the first 8
197 * bytes so we start at a nice even number.
202 start = round_up(start, align);
203 if ((start + size) > end)
206 status = efi_call_phys4(sys_table->boottime->allocate_pages,
207 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
209 if (status == EFI_SUCCESS) {
215 if (i == map_size / desc_size)
216 status = EFI_NOT_FOUND;
219 efi_call_phys1(sys_table->boottime->free_pool, map);
224 static void low_free(unsigned long size, unsigned long addr)
226 unsigned long nr_pages;
228 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
229 efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages);
234 * Check the cmdline for a LILO-style initrd= arguments.
236 * We only support loading an initrd from the same filesystem as the
239 static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
240 struct setup_header *hdr)
242 struct initrd *initrds;
243 unsigned long initrd_addr;
244 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
246 efi_file_io_interface_t *io;
247 efi_file_handle_t *fh;
256 str = (char *)(unsigned long)hdr->cmd_line_ptr;
258 j = 0; /* See close_handles */
263 for (nr_initrds = 0; *str; nr_initrds++) {
264 str = strstr(str, "initrd=");
270 /* Skip any leading slashes */
271 while (*str == '/' || *str == '\\')
274 while (*str && *str != ' ' && *str != '\n')
281 status = efi_call_phys3(sys_table->boottime->allocate_pool,
283 nr_initrds * sizeof(*initrds),
285 if (status != EFI_SUCCESS) {
286 efi_printk("Failed to alloc mem for initrds\n");
290 str = (char *)(unsigned long)hdr->cmd_line_ptr;
291 for (i = 0; i < nr_initrds; i++) {
292 struct initrd *initrd;
293 efi_file_handle_t *h;
294 efi_file_info_t *info;
295 efi_char16_t filename_16[256];
296 unsigned long info_sz;
297 efi_guid_t info_guid = EFI_FILE_INFO_ID;
301 str = strstr(str, "initrd=");
307 initrd = &initrds[i];
310 /* Skip any leading slashes */
311 while (*str == '/' || *str == '\\')
314 while (*str && *str != ' ' && *str != '\n') {
315 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
328 /* Only open the volume once. */
330 efi_boot_services_t *boottime;
332 boottime = sys_table->boottime;
334 status = efi_call_phys3(boottime->handle_protocol,
335 image->device_handle, &fs_proto, &io);
336 if (status != EFI_SUCCESS) {
337 efi_printk("Failed to handle fs_proto\n");
341 status = efi_call_phys2(io->open_volume, io, &fh);
342 if (status != EFI_SUCCESS) {
343 efi_printk("Failed to open volume\n");
348 status = efi_call_phys5(fh->open, fh, &h, filename_16,
349 EFI_FILE_MODE_READ, (u64)0);
350 if (status != EFI_SUCCESS) {
351 efi_printk("Failed to open initrd file: ");
352 efi_char16_printk(filename_16);
360 status = efi_call_phys4(h->get_info, h, &info_guid,
362 if (status != EFI_BUFFER_TOO_SMALL) {
363 efi_printk("Failed to get initrd info size\n");
368 status = efi_call_phys3(sys_table->boottime->allocate_pool,
369 EFI_LOADER_DATA, info_sz, &info);
370 if (status != EFI_SUCCESS) {
371 efi_printk("Failed to alloc mem for initrd info\n");
375 status = efi_call_phys4(h->get_info, h, &info_guid,
377 if (status == EFI_BUFFER_TOO_SMALL) {
378 efi_call_phys1(sys_table->boottime->free_pool, info);
382 file_sz = info->file_size;
383 efi_call_phys1(sys_table->boottime->free_pool, info);
385 if (status != EFI_SUCCESS) {
386 efi_printk("Failed to get initrd info\n");
390 initrd->size = file_sz;
391 initrd_total += file_sz;
398 * Multiple initrd's need to be at consecutive
399 * addresses in memory, so allocate enough memory for
402 status = high_alloc(initrd_total, 0x1000,
403 &initrd_addr, hdr->initrd_addr_max);
404 if (status != EFI_SUCCESS) {
405 efi_printk("Failed to alloc highmem for initrds\n");
409 /* We've run out of free low memory. */
410 if (initrd_addr > hdr->initrd_addr_max) {
411 efi_printk("We've run out of free low memory\n");
412 status = EFI_INVALID_PARAMETER;
413 goto free_initrd_total;
417 for (j = 0; j < nr_initrds; j++) {
420 size = initrds[j].size;
423 if (size > EFI_READ_CHUNK_SIZE)
424 chunksize = EFI_READ_CHUNK_SIZE;
427 status = efi_call_phys3(fh->read,
430 if (status != EFI_SUCCESS) {
431 efi_printk("Failed to read initrd\n");
432 goto free_initrd_total;
438 efi_call_phys1(fh->close, initrds[j].handle);
443 efi_call_phys1(sys_table->boottime->free_pool, initrds);
445 hdr->ramdisk_image = initrd_addr;
446 hdr->ramdisk_size = initrd_total;
451 low_free(initrd_total, initrd_addr);
454 for (k = j; k < i; k++)
455 efi_call_phys1(fh->close, initrds[k].handle);
457 efi_call_phys1(sys_table->boottime->free_pool, initrds);
459 hdr->ramdisk_image = 0;
460 hdr->ramdisk_size = 0;