diff options
author | Roy Franz <roy.franz@linaro.org> | 2013-09-22 18:45:27 -0400 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-09-25 07:34:34 -0400 |
commit | 7721da4c1ebf96ff815987011c1a0edef596b50a (patch) | |
tree | 66eaab33c5af6a00d65f75200c6b7838fd00302f /arch | |
parent | ed37ddffe201bfad7be3c45bc08bd65b5298adca (diff) |
efi: Move common EFI stub code from x86 arch code to common location
No code changes made, just moving functions and #define from x86 arch
directory to common location. Code is shared using #include, similar
to how decompression code is shared among architectures.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Acked-by: Mark Salter <msalter@redhat.com>
Reviewed-by: Grant Likely <grant.likely@linaro.org>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/boot/compressed/eboot.c | 442 | ||||
-rw-r--r-- | arch/x86/boot/compressed/eboot.h | 1 |
2 files changed, 1 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 | ||
20 | static efi_system_table_t *sys_table; | 20 | static efi_system_table_t *sys_table; |
21 | 21 | ||
22 | static 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 | |||
30 | static 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 | static 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; | ||
56 | again: | ||
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 | |||
77 | fail: | ||
78 | *map = m; | ||
79 | return status; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Allocate at the highest possible address that is not above 'max'. | ||
84 | */ | ||
85 | static 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; | ||
100 | again: | ||
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 | |||
153 | free_pool: | ||
154 | efi_call_phys1(sys_table->boottime->free_pool, map); | ||
155 | |||
156 | fail: | ||
157 | return status; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Allocate at the lowest possible address. | ||
162 | */ | ||
163 | static 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 | |||
217 | free_pool: | ||
218 | efi_call_phys1(sys_table->boottime->free_pool, map); | ||
219 | fail: | ||
220 | return status; | ||
221 | } | ||
222 | |||
223 | static 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 | ||
231 | static void find_bits(unsigned long mask, u8 *pos, u8 *size) | 27 | static 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 | ||
627 | struct 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 | */ | ||
638 | static 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 | |||
766 | grow: | ||
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 | |||
849 | free_initrd_total: | ||
850 | low_free(initrd_total, initrd_addr); | ||
851 | |||
852 | close_handles: | ||
853 | for (k = j; k < i; k++) | ||
854 | efi_call_phys1(fh->close, initrds[k].handle); | ||
855 | free_initrds: | ||
856 | efi_call_phys1(sys_table->boottime->free_pool, initrds); | ||
857 | fail: | ||
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, \ |