aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/boot/compressed/eboot.c442
-rw-r--r--arch/x86/boot/compressed/eboot.h1
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c463
3 files changed, 464 insertions, 442 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index b7388a425f09..ab0eefcc5123 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -19,214 +19,10 @@
19 19
20static efi_system_table_t *sys_table; 20static efi_system_table_t *sys_table;
21 21
22static void efi_char16_printk(efi_char16_t *str)
23{
24 struct efi_simple_text_output_protocol *out;
25
26 out = (struct efi_simple_text_output_protocol *)sys_table->con_out;
27 efi_call_phys2(out->output_string, out, str);
28}
29
30static void efi_printk(char *str)
31{
32 char *s8;
33
34 for (s8 = str; *s8; s8++) {
35 efi_char16_t ch[2] = { 0 };
36
37 ch[0] = *s8;
38 if (*s8 == '\n') {
39 efi_char16_t nl[2] = { '\r', 0 };
40 efi_char16_printk(nl);
41 }
42
43 efi_char16_printk(ch);
44 }
45}
46
47static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size,
48 unsigned long *desc_size)
49{
50 efi_memory_desc_t *m = NULL;
51 efi_status_t status;
52 unsigned long key;
53 u32 desc_version;
54
55 *map_size = sizeof(*m) * 32;
56again:
57 /*
58 * Add an additional efi_memory_desc_t because we're doing an
59 * allocation which may be in a new descriptor region.
60 */
61 *map_size += sizeof(*m);
62 status = efi_call_phys3(sys_table->boottime->allocate_pool,
63 EFI_LOADER_DATA, *map_size, (void **)&m);
64 if (status != EFI_SUCCESS)
65 goto fail;
66
67 status = efi_call_phys5(sys_table->boottime->get_memory_map, map_size,
68 m, &key, desc_size, &desc_version);
69 if (status == EFI_BUFFER_TOO_SMALL) {
70 efi_call_phys1(sys_table->boottime->free_pool, m);
71 goto again;
72 }
73
74 if (status != EFI_SUCCESS)
75 efi_call_phys1(sys_table->boottime->free_pool, m);
76
77fail:
78 *map = m;
79 return status;
80}
81
82/*
83 * Allocate at the highest possible address that is not above 'max'.
84 */
85static efi_status_t high_alloc(unsigned long size, unsigned long align,
86 unsigned long *addr, unsigned long max)
87{
88 unsigned long map_size, desc_size;
89 efi_memory_desc_t *map;
90 efi_status_t status;
91 unsigned long nr_pages;
92 u64 max_addr = 0;
93 int i;
94
95 status = __get_map(&map, &map_size, &desc_size);
96 if (status != EFI_SUCCESS)
97 goto fail;
98
99 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
100again:
101 for (i = 0; i < map_size / desc_size; i++) {
102 efi_memory_desc_t *desc;
103 unsigned long m = (unsigned long)map;
104 u64 start, end;
105
106 desc = (efi_memory_desc_t *)(m + (i * desc_size));
107 if (desc->type != EFI_CONVENTIONAL_MEMORY)
108 continue;
109
110 if (desc->num_pages < nr_pages)
111 continue;
112 22
113 start = desc->phys_addr; 23#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
114 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
115 24
116 if ((start + size) > end || (start + size) > max)
117 continue;
118
119 if (end - size > max)
120 end = max;
121
122 if (round_down(end - size, align) < start)
123 continue;
124
125 start = round_down(end - size, align);
126
127 /*
128 * Don't allocate at 0x0. It will confuse code that
129 * checks pointers against NULL.
130 */
131 if (start == 0x0)
132 continue;
133
134 if (start > max_addr)
135 max_addr = start;
136 }
137
138 if (!max_addr)
139 status = EFI_NOT_FOUND;
140 else {
141 status = efi_call_phys4(sys_table->boottime->allocate_pages,
142 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
143 nr_pages, &max_addr);
144 if (status != EFI_SUCCESS) {
145 max = max_addr;
146 max_addr = 0;
147 goto again;
148 }
149
150 *addr = max_addr;
151 }
152
153free_pool:
154 efi_call_phys1(sys_table->boottime->free_pool, map);
155
156fail:
157 return status;
158}
159
160/*
161 * Allocate at the lowest possible address.
162 */
163static efi_status_t low_alloc(unsigned long size, unsigned long align,
164 unsigned long *addr)
165{
166 unsigned long map_size, desc_size;
167 efi_memory_desc_t *map;
168 efi_status_t status;
169 unsigned long nr_pages;
170 int i;
171
172 status = __get_map(&map, &map_size, &desc_size);
173 if (status != EFI_SUCCESS)
174 goto fail;
175
176 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
177 for (i = 0; i < map_size / desc_size; i++) {
178 efi_memory_desc_t *desc;
179 unsigned long m = (unsigned long)map;
180 u64 start, end;
181
182 desc = (efi_memory_desc_t *)(m + (i * desc_size));
183
184 if (desc->type != EFI_CONVENTIONAL_MEMORY)
185 continue;
186
187 if (desc->num_pages < nr_pages)
188 continue;
189
190 start = desc->phys_addr;
191 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
192
193 /*
194 * Don't allocate at 0x0. It will confuse code that
195 * checks pointers against NULL. Skip the first 8
196 * bytes so we start at a nice even number.
197 */
198 if (start == 0x0)
199 start += 8;
200
201 start = round_up(start, align);
202 if ((start + size) > end)
203 continue;
204
205 status = efi_call_phys4(sys_table->boottime->allocate_pages,
206 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
207 nr_pages, &start);
208 if (status == EFI_SUCCESS) {
209 *addr = start;
210 break;
211 }
212 }
213 25
214 if (i == map_size / desc_size)
215 status = EFI_NOT_FOUND;
216
217free_pool:
218 efi_call_phys1(sys_table->boottime->free_pool, map);
219fail:
220 return status;
221}
222
223static void low_free(unsigned long size, unsigned long addr)
224{
225 unsigned long nr_pages;
226
227 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
228 efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages);
229}
230 26
231static void find_bits(unsigned long mask, u8 *pos, u8 *size) 27static void find_bits(unsigned long mask, u8 *pos, u8 *size)
232{ 28{
@@ -624,242 +420,6 @@ void setup_graphics(struct boot_params *boot_params)
624 } 420 }
625} 421}
626 422
627struct initrd {
628 efi_file_handle_t *handle;
629 u64 size;
630};
631
632/*
633 * Check the cmdline for a LILO-style initrd= arguments.
634 *
635 * We only support loading an initrd from the same filesystem as the
636 * kernel image.
637 */
638static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
639 struct setup_header *hdr)
640{
641 struct initrd *initrds;
642 unsigned long initrd_addr;
643 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
644 u64 initrd_total;
645 efi_file_io_interface_t *io;
646 efi_file_handle_t *fh;
647 efi_status_t status;
648 int nr_initrds;
649 char *str;
650 int i, j, k;
651
652 initrd_addr = 0;
653 initrd_total = 0;
654
655 str = (char *)(unsigned long)hdr->cmd_line_ptr;
656
657 j = 0; /* See close_handles */
658
659 if (!str || !*str)
660 return EFI_SUCCESS;
661
662 for (nr_initrds = 0; *str; nr_initrds++) {
663 str = strstr(str, "initrd=");
664 if (!str)
665 break;
666
667 str += 7;
668
669 /* Skip any leading slashes */
670 while (*str == '/' || *str == '\\')
671 str++;
672
673 while (*str && *str != ' ' && *str != '\n')
674 str++;
675 }
676
677 if (!nr_initrds)
678 return EFI_SUCCESS;
679
680 status = efi_call_phys3(sys_table->boottime->allocate_pool,
681 EFI_LOADER_DATA,
682 nr_initrds * sizeof(*initrds),
683 &initrds);
684 if (status != EFI_SUCCESS) {
685 efi_printk("Failed to alloc mem for initrds\n");
686 goto fail;
687 }
688
689 str = (char *)(unsigned long)hdr->cmd_line_ptr;
690 for (i = 0; i < nr_initrds; i++) {
691 struct initrd *initrd;
692 efi_file_handle_t *h;
693 efi_file_info_t *info;
694 efi_char16_t filename_16[256];
695 unsigned long info_sz;
696 efi_guid_t info_guid = EFI_FILE_INFO_ID;
697 efi_char16_t *p;
698 u64 file_sz;
699
700 str = strstr(str, "initrd=");
701 if (!str)
702 break;
703
704 str += 7;
705
706 initrd = &initrds[i];
707 p = filename_16;
708
709 /* Skip any leading slashes */
710 while (*str == '/' || *str == '\\')
711 str++;
712
713 while (*str && *str != ' ' && *str != '\n') {
714 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
715 break;
716
717 if (*str == '/') {
718 *p++ = '\\';
719 *str++;
720 } else {
721 *p++ = *str++;
722 }
723 }
724
725 *p = '\0';
726
727 /* Only open the volume once. */
728 if (!i) {
729 efi_boot_services_t *boottime;
730
731 boottime = sys_table->boottime;
732
733 status = efi_call_phys3(boottime->handle_protocol,
734 image->device_handle, &fs_proto, &io);
735 if (status != EFI_SUCCESS) {
736 efi_printk("Failed to handle fs_proto\n");
737 goto free_initrds;
738 }
739
740 status = efi_call_phys2(io->open_volume, io, &fh);
741 if (status != EFI_SUCCESS) {
742 efi_printk("Failed to open volume\n");
743 goto free_initrds;
744 }
745 }
746
747 status = efi_call_phys5(fh->open, fh, &h, filename_16,
748 EFI_FILE_MODE_READ, (u64)0);
749 if (status != EFI_SUCCESS) {
750 efi_printk("Failed to open initrd file: ");
751 efi_char16_printk(filename_16);
752 efi_printk("\n");
753 goto close_handles;
754 }
755
756 initrd->handle = h;
757
758 info_sz = 0;
759 status = efi_call_phys4(h->get_info, h, &info_guid,
760 &info_sz, NULL);
761 if (status != EFI_BUFFER_TOO_SMALL) {
762 efi_printk("Failed to get initrd info size\n");
763 goto close_handles;
764 }
765
766grow:
767 status = efi_call_phys3(sys_table->boottime->allocate_pool,
768 EFI_LOADER_DATA, info_sz, &info);
769 if (status != EFI_SUCCESS) {
770 efi_printk("Failed to alloc mem for initrd info\n");
771 goto close_handles;
772 }
773
774 status = efi_call_phys4(h->get_info, h, &info_guid,
775 &info_sz, info);
776 if (status == EFI_BUFFER_TOO_SMALL) {
777 efi_call_phys1(sys_table->boottime->free_pool, info);
778 goto grow;
779 }
780
781 file_sz = info->file_size;
782 efi_call_phys1(sys_table->boottime->free_pool, info);
783
784 if (status != EFI_SUCCESS) {
785 efi_printk("Failed to get initrd info\n");
786 goto close_handles;
787 }
788
789 initrd->size = file_sz;
790 initrd_total += file_sz;
791 }
792
793 if (initrd_total) {
794 unsigned long addr;
795
796 /*
797 * Multiple initrd's need to be at consecutive
798 * addresses in memory, so allocate enough memory for
799 * all the initrd's.
800 */
801 status = high_alloc(initrd_total, 0x1000,
802 &initrd_addr, hdr->initrd_addr_max);
803 if (status != EFI_SUCCESS) {
804 efi_printk("Failed to alloc highmem for initrds\n");
805 goto close_handles;
806 }
807
808 /* We've run out of free low memory. */
809 if (initrd_addr > hdr->initrd_addr_max) {
810 efi_printk("We've run out of free low memory\n");
811 status = EFI_INVALID_PARAMETER;
812 goto free_initrd_total;
813 }
814
815 addr = initrd_addr;
816 for (j = 0; j < nr_initrds; j++) {
817 u64 size;
818
819 size = initrds[j].size;
820 while (size) {
821 u64 chunksize;
822 if (size > EFI_READ_CHUNK_SIZE)
823 chunksize = EFI_READ_CHUNK_SIZE;
824 else
825 chunksize = size;
826 status = efi_call_phys3(fh->read,
827 initrds[j].handle,
828 &chunksize, addr);
829 if (status != EFI_SUCCESS) {
830 efi_printk("Failed to read initrd\n");
831 goto free_initrd_total;
832 }
833 addr += chunksize;
834 size -= chunksize;
835 }
836
837 efi_call_phys1(fh->close, initrds[j].handle);
838 }
839
840 }
841
842 efi_call_phys1(sys_table->boottime->free_pool, initrds);
843
844 hdr->ramdisk_image = initrd_addr;
845 hdr->ramdisk_size = initrd_total;
846
847 return status;
848
849free_initrd_total:
850 low_free(initrd_total, initrd_addr);
851
852close_handles:
853 for (k = j; k < i; k++)
854 efi_call_phys1(fh->close, initrds[k].handle);
855free_initrds:
856 efi_call_phys1(sys_table->boottime->free_pool, initrds);
857fail:
858 hdr->ramdisk_image = 0;
859 hdr->ramdisk_size = 0;
860
861 return status;
862}
863 423
864/* 424/*
865 * Because the x86 boot code expects to be passed a boot_params we 425 * Because the x86 boot code expects to be passed a boot_params we
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index 02265107cce3..81b6b652b46a 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -10,7 +10,6 @@
10#define SEG_GRANULARITY_4KB (1 << 0) 10#define SEG_GRANULARITY_4KB (1 << 0)
11 11
12#define DESC_TYPE_CODE_DATA (1 << 0) 12#define DESC_TYPE_CODE_DATA (1 << 0)
13#define EFI_READ_CHUNK_SIZE (1024 * 1024)
14 13
15#define EFI_CONSOLE_OUT_DEVICE_GUID \ 14#define EFI_CONSOLE_OUT_DEVICE_GUID \
16 EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \ 15 EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
new file mode 100644
index 000000000000..8a83387fef92
--- /dev/null
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -0,0 +1,463 @@
1/*
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
14struct initrd {
15 efi_file_handle_t *handle;
16 u64 size;
17};
18
19
20
21
22static void efi_char16_printk(efi_char16_t *str)
23{
24 struct efi_simple_text_output_protocol *out;
25
26 out = (struct efi_simple_text_output_protocol *)sys_table->con_out;
27 efi_call_phys2(out->output_string, out, str);
28}
29
30static void efi_printk(char *str)
31{
32 char *s8;
33
34 for (s8 = str; *s8; s8++) {
35 efi_char16_t ch[2] = { 0 };
36
37 ch[0] = *s8;
38 if (*s8 == '\n') {
39 efi_char16_t nl[2] = { '\r', 0 };
40 efi_char16_printk(nl);
41 }
42
43 efi_char16_printk(ch);
44 }
45}
46
47
48static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size,
49 unsigned long *desc_size)
50{
51 efi_memory_desc_t *m = NULL;
52 efi_status_t status;
53 unsigned long key;
54 u32 desc_version;
55
56 *map_size = sizeof(*m) * 32;
57again:
58 /*
59 * Add an additional efi_memory_desc_t because we're doing an
60 * allocation which may be in a new descriptor region.
61 */
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)
66 goto fail;
67
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);
72 goto again;
73 }
74
75 if (status != EFI_SUCCESS)
76 efi_call_phys1(sys_table->boottime->free_pool, m);
77
78fail:
79 *map = m;
80 return status;
81}
82
83/*
84 * Allocate at the highest possible address that is not above 'max'.
85 */
86static efi_status_t high_alloc(unsigned long size, unsigned long align,
87 unsigned long *addr, unsigned long max)
88{
89 unsigned long map_size, desc_size;
90 efi_memory_desc_t *map;
91 efi_status_t status;
92 unsigned long nr_pages;
93 u64 max_addr = 0;
94 int i;
95
96 status = __get_map(&map, &map_size, &desc_size);
97 if (status != EFI_SUCCESS)
98 goto fail;
99
100 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
101again:
102 for (i = 0; i < map_size / desc_size; i++) {
103 efi_memory_desc_t *desc;
104 unsigned long m = (unsigned long)map;
105 u64 start, end;
106
107 desc = (efi_memory_desc_t *)(m + (i * desc_size));
108 if (desc->type != EFI_CONVENTIONAL_MEMORY)
109 continue;
110
111 if (desc->num_pages < nr_pages)
112 continue;
113
114 start = desc->phys_addr;
115 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
116
117 if ((start + size) > end || (start + size) > max)
118 continue;
119
120 if (end - size > max)
121 end = max;
122
123 if (round_down(end - size, align) < start)
124 continue;
125
126 start = round_down(end - size, align);
127
128 /*
129 * Don't allocate at 0x0. It will confuse code that
130 * checks pointers against NULL.
131 */
132 if (start == 0x0)
133 continue;
134
135 if (start > max_addr)
136 max_addr = start;
137 }
138
139 if (!max_addr)
140 status = EFI_NOT_FOUND;
141 else {
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) {
146 max = max_addr;
147 max_addr = 0;
148 goto again;
149 }
150
151 *addr = max_addr;
152 }
153
154free_pool:
155 efi_call_phys1(sys_table->boottime->free_pool, map);
156
157fail:
158 return status;
159}
160
161/*
162 * Allocate at the lowest possible address.
163 */
164static efi_status_t low_alloc(unsigned long size, unsigned long align,
165 unsigned long *addr)
166{
167 unsigned long map_size, desc_size;
168 efi_memory_desc_t *map;
169 efi_status_t status;
170 unsigned long nr_pages;
171 int i;
172
173 status = __get_map(&map, &map_size, &desc_size);
174 if (status != EFI_SUCCESS)
175 goto fail;
176
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;
181 u64 start, end;
182
183 desc = (efi_memory_desc_t *)(m + (i * desc_size));
184
185 if (desc->type != EFI_CONVENTIONAL_MEMORY)
186 continue;
187
188 if (desc->num_pages < nr_pages)
189 continue;
190
191 start = desc->phys_addr;
192 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
193
194 /*
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.
198 */
199 if (start == 0x0)
200 start += 8;
201
202 start = round_up(start, align);
203 if ((start + size) > end)
204 continue;
205
206 status = efi_call_phys4(sys_table->boottime->allocate_pages,
207 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
208 nr_pages, &start);
209 if (status == EFI_SUCCESS) {
210 *addr = start;
211 break;
212 }
213 }
214
215 if (i == map_size / desc_size)
216 status = EFI_NOT_FOUND;
217
218free_pool:
219 efi_call_phys1(sys_table->boottime->free_pool, map);
220fail:
221 return status;
222}
223
224static void low_free(unsigned long size, unsigned long addr)
225{
226 unsigned long nr_pages;
227
228 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
229 efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages);
230}
231
232
233/*
234 * Check the cmdline for a LILO-style initrd= arguments.
235 *
236 * We only support loading an initrd from the same filesystem as the
237 * kernel image.
238 */
239static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
240 struct setup_header *hdr)
241{
242 struct initrd *initrds;
243 unsigned long initrd_addr;
244 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
245 u64 initrd_total;
246 efi_file_io_interface_t *io;
247 efi_file_handle_t *fh;
248 efi_status_t status;
249 int nr_initrds;
250 char *str;
251 int i, j, k;
252
253 initrd_addr = 0;
254 initrd_total = 0;
255
256 str = (char *)(unsigned long)hdr->cmd_line_ptr;
257
258 j = 0; /* See close_handles */
259
260 if (!str || !*str)
261 return EFI_SUCCESS;
262
263 for (nr_initrds = 0; *str; nr_initrds++) {
264 str = strstr(str, "initrd=");
265 if (!str)
266 break;
267
268 str += 7;
269
270 /* Skip any leading slashes */
271 while (*str == '/' || *str == '\\')
272 str++;
273
274 while (*str && *str != ' ' && *str != '\n')
275 str++;
276 }
277
278 if (!nr_initrds)
279 return EFI_SUCCESS;
280
281 status = efi_call_phys3(sys_table->boottime->allocate_pool,
282 EFI_LOADER_DATA,
283 nr_initrds * sizeof(*initrds),
284 &initrds);
285 if (status != EFI_SUCCESS) {
286 efi_printk("Failed to alloc mem for initrds\n");
287 goto fail;
288 }
289
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;
298 efi_char16_t *p;
299 u64 file_sz;
300
301 str = strstr(str, "initrd=");
302 if (!str)
303 break;
304
305 str += 7;
306
307 initrd = &initrds[i];
308 p = filename_16;
309
310 /* Skip any leading slashes */
311 while (*str == '/' || *str == '\\')
312 str++;
313
314 while (*str && *str != ' ' && *str != '\n') {
315 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
316 break;
317
318 if (*str == '/') {
319 *p++ = '\\';
320 *str++;
321 } else {
322 *p++ = *str++;
323 }
324 }
325
326 *p = '\0';
327
328 /* Only open the volume once. */
329 if (!i) {
330 efi_boot_services_t *boottime;
331
332 boottime = sys_table->boottime;
333
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");
338 goto free_initrds;
339 }
340
341 status = efi_call_phys2(io->open_volume, io, &fh);
342 if (status != EFI_SUCCESS) {
343 efi_printk("Failed to open volume\n");
344 goto free_initrds;
345 }
346 }
347
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);
353 efi_printk("\n");
354 goto close_handles;
355 }
356
357 initrd->handle = h;
358
359 info_sz = 0;
360 status = efi_call_phys4(h->get_info, h, &info_guid,
361 &info_sz, NULL);
362 if (status != EFI_BUFFER_TOO_SMALL) {
363 efi_printk("Failed to get initrd info size\n");
364 goto close_handles;
365 }
366
367grow:
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");
372 goto close_handles;
373 }
374
375 status = efi_call_phys4(h->get_info, h, &info_guid,
376 &info_sz, info);
377 if (status == EFI_BUFFER_TOO_SMALL) {
378 efi_call_phys1(sys_table->boottime->free_pool, info);
379 goto grow;
380 }
381
382 file_sz = info->file_size;
383 efi_call_phys1(sys_table->boottime->free_pool, info);
384
385 if (status != EFI_SUCCESS) {
386 efi_printk("Failed to get initrd info\n");
387 goto close_handles;
388 }
389
390 initrd->size = file_sz;
391 initrd_total += file_sz;
392 }
393
394 if (initrd_total) {
395 unsigned long addr;
396
397 /*
398 * Multiple initrd's need to be at consecutive
399 * addresses in memory, so allocate enough memory for
400 * all the initrd's.
401 */
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");
406 goto close_handles;
407 }
408
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;
414 }
415
416 addr = initrd_addr;
417 for (j = 0; j < nr_initrds; j++) {
418 u64 size;
419
420 size = initrds[j].size;
421 while (size) {
422 u64 chunksize;
423 if (size > EFI_READ_CHUNK_SIZE)
424 chunksize = EFI_READ_CHUNK_SIZE;
425 else
426 chunksize = size;
427 status = efi_call_phys3(fh->read,
428 initrds[j].handle,
429 &chunksize, addr);
430 if (status != EFI_SUCCESS) {
431 efi_printk("Failed to read initrd\n");
432 goto free_initrd_total;
433 }
434 addr += chunksize;
435 size -= chunksize;
436 }
437
438 efi_call_phys1(fh->close, initrds[j].handle);
439 }
440
441 }
442
443 efi_call_phys1(sys_table->boottime->free_pool, initrds);
444
445 hdr->ramdisk_image = initrd_addr;
446 hdr->ramdisk_size = initrd_total;
447
448 return status;
449
450free_initrd_total:
451 low_free(initrd_total, initrd_addr);
452
453close_handles:
454 for (k = j; k < i; k++)
455 efi_call_phys1(fh->close, initrds[k].handle);
456free_initrds:
457 efi_call_phys1(sys_table->boottime->free_pool, initrds);
458fail:
459 hdr->ramdisk_image = 0;
460 hdr->ramdisk_size = 0;
461
462 return status;
463}