diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-11 20:48:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-11 20:48:30 -0500 |
commit | 69019d77c71472428a5d67ab8bb7cfa9145000d0 (patch) | |
tree | 370f038a801c5ceee5266bf95944a458bcc0bfbf /arch/x86/platform | |
parent | 6df1e7f2e96721dfdbfd8a034e52bc81916f978c (diff) | |
parent | 88392e9dd5a524b8194f1045369c7d0eb16d9f32 (diff) |
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 EFI changes from Ingo Molnar:
"Main changes:
- Add support for earlyprintk=efi which uses the EFI framebuffer.
Very useful for debugging boot problems.
- EFI stub support for large memory maps (more than 128 entries)
- EFI ARM support - this was mostly done by generalizing x86 <-> ARM
platform differences, such as by moving x86 EFI code into
drivers/firmware/efi/ and sharing it with ARM.
- Documentation updates
- misc fixes"
* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (26 commits)
x86/efi: Add EFI framebuffer earlyprintk support
boot, efi: Remove redundant memset()
x86/efi: Fix config_table_type array termination
x86 efi: bugfix interrupt disabling sequence
x86: EFI stub support for large memory maps
efi: resolve warnings found on ARM compile
efi: Fix types in EFI calls to match EFI function definitions.
efi: Renames in handle_cmdline_files() to complete generalization.
efi: Generalize handle_ramdisks() and rename to handle_cmdline_files().
efi: Allow efi_free() to be called with size of 0
efi: use efi_get_memory_map() to get final map for x86
efi: generalize efi_get_memory_map()
efi: Rename __get_map() to efi_get_memory_map()
efi: Move unicode to ASCII conversion to shared function.
efi: Generalize relocate_kernel() for use by other architectures.
efi: Move relocate_kernel() to shared file.
efi: Enforce minimum alignment of 1 page on allocations.
efi: Rename memory allocation/free functions
efi: Add system table pointer argument to shared functions.
efi: Move common EFI stub code from x86 arch code to common location
...
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/efi/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/platform/efi/early_printk.c | 191 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi.c | 126 |
3 files changed, 202 insertions, 116 deletions
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile index 6db1cc4c7534..b7b0b35c1981 100644 --- a/arch/x86/platform/efi/Makefile +++ b/arch/x86/platform/efi/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o | 1 | obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o |
2 | obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o | 2 | obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o |
3 | obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o | ||
diff --git a/arch/x86/platform/efi/early_printk.c b/arch/x86/platform/efi/early_printk.c new file mode 100644 index 000000000000..6599a0027b76 --- /dev/null +++ b/arch/x86/platform/efi/early_printk.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Intel Corporation; author Matt Fleming | ||
3 | * | ||
4 | * This file is part of the Linux kernel, and is made available under | ||
5 | * the terms of the GNU General Public License version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/console.h> | ||
9 | #include <linux/efi.h> | ||
10 | #include <linux/font.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/setup.h> | ||
14 | |||
15 | static const struct font_desc *font; | ||
16 | static u32 efi_x, efi_y; | ||
17 | |||
18 | static __init void early_efi_clear_scanline(unsigned int y) | ||
19 | { | ||
20 | unsigned long base, *dst; | ||
21 | u16 len; | ||
22 | |||
23 | base = boot_params.screen_info.lfb_base; | ||
24 | len = boot_params.screen_info.lfb_linelength; | ||
25 | |||
26 | dst = early_ioremap(base + y*len, len); | ||
27 | if (!dst) | ||
28 | return; | ||
29 | |||
30 | memset(dst, 0, len); | ||
31 | early_iounmap(dst, len); | ||
32 | } | ||
33 | |||
34 | static __init void early_efi_scroll_up(void) | ||
35 | { | ||
36 | unsigned long base, *dst, *src; | ||
37 | u16 len; | ||
38 | u32 i, height; | ||
39 | |||
40 | base = boot_params.screen_info.lfb_base; | ||
41 | len = boot_params.screen_info.lfb_linelength; | ||
42 | height = boot_params.screen_info.lfb_height; | ||
43 | |||
44 | for (i = 0; i < height - font->height; i++) { | ||
45 | dst = early_ioremap(base + i*len, len); | ||
46 | if (!dst) | ||
47 | return; | ||
48 | |||
49 | src = early_ioremap(base + (i + font->height) * len, len); | ||
50 | if (!src) { | ||
51 | early_iounmap(dst, len); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | memmove(dst, src, len); | ||
56 | |||
57 | early_iounmap(src, len); | ||
58 | early_iounmap(dst, len); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static void early_efi_write_char(u32 *dst, unsigned char c, unsigned int h) | ||
63 | { | ||
64 | const u32 color_black = 0x00000000; | ||
65 | const u32 color_white = 0x00ffffff; | ||
66 | const u8 *src; | ||
67 | u8 s8; | ||
68 | int m; | ||
69 | |||
70 | src = font->data + c * font->height; | ||
71 | s8 = *(src + h); | ||
72 | |||
73 | for (m = 0; m < 8; m++) { | ||
74 | if ((s8 >> (7 - m)) & 1) | ||
75 | *dst = color_white; | ||
76 | else | ||
77 | *dst = color_black; | ||
78 | dst++; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static __init void | ||
83 | early_efi_write(struct console *con, const char *str, unsigned int num) | ||
84 | { | ||
85 | struct screen_info *si; | ||
86 | unsigned long base; | ||
87 | unsigned int len; | ||
88 | const char *s; | ||
89 | void *dst; | ||
90 | |||
91 | base = boot_params.screen_info.lfb_base; | ||
92 | si = &boot_params.screen_info; | ||
93 | len = si->lfb_linelength; | ||
94 | |||
95 | while (num) { | ||
96 | unsigned int linemax; | ||
97 | unsigned int h, count = 0; | ||
98 | |||
99 | for (s = str; *s && *s != '\n'; s++) { | ||
100 | if (count == num) | ||
101 | break; | ||
102 | count++; | ||
103 | } | ||
104 | |||
105 | linemax = (si->lfb_width - efi_x) / font->width; | ||
106 | if (count > linemax) | ||
107 | count = linemax; | ||
108 | |||
109 | for (h = 0; h < font->height; h++) { | ||
110 | unsigned int n, x; | ||
111 | |||
112 | dst = early_ioremap(base + (efi_y + h) * len, len); | ||
113 | if (!dst) | ||
114 | return; | ||
115 | |||
116 | s = str; | ||
117 | n = count; | ||
118 | x = efi_x; | ||
119 | |||
120 | while (n-- > 0) { | ||
121 | early_efi_write_char(dst + x*4, *s, h); | ||
122 | x += font->width; | ||
123 | s++; | ||
124 | } | ||
125 | |||
126 | early_iounmap(dst, len); | ||
127 | } | ||
128 | |||
129 | num -= count; | ||
130 | efi_x += count * font->width; | ||
131 | str += count; | ||
132 | |||
133 | if (num > 0 && *s == '\n') { | ||
134 | efi_x = 0; | ||
135 | efi_y += font->height; | ||
136 | str++; | ||
137 | num--; | ||
138 | } | ||
139 | |||
140 | if (efi_x >= si->lfb_width) { | ||
141 | efi_x = 0; | ||
142 | efi_y += font->height; | ||
143 | } | ||
144 | |||
145 | if (efi_y + font->height >= si->lfb_height) { | ||
146 | u32 i; | ||
147 | |||
148 | efi_y -= font->height; | ||
149 | early_efi_scroll_up(); | ||
150 | |||
151 | for (i = 0; i < font->height; i++) | ||
152 | early_efi_clear_scanline(efi_y + i); | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static __init int early_efi_setup(struct console *con, char *options) | ||
158 | { | ||
159 | struct screen_info *si; | ||
160 | u16 xres, yres; | ||
161 | u32 i; | ||
162 | |||
163 | si = &boot_params.screen_info; | ||
164 | xres = si->lfb_width; | ||
165 | yres = si->lfb_height; | ||
166 | |||
167 | /* | ||
168 | * early_efi_write_char() implicitly assumes a framebuffer with | ||
169 | * 32-bits per pixel. | ||
170 | */ | ||
171 | if (si->lfb_depth != 32) | ||
172 | return -ENODEV; | ||
173 | |||
174 | font = get_default_font(xres, yres, -1, -1); | ||
175 | if (!font) | ||
176 | return -ENODEV; | ||
177 | |||
178 | efi_y = rounddown(yres, font->height) - font->height; | ||
179 | for (i = 0; i < (yres - efi_y) / font->height; i++) | ||
180 | early_efi_scroll_up(); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | struct console early_efi_console = { | ||
186 | .name = "earlyefi", | ||
187 | .write = early_efi_write, | ||
188 | .setup = early_efi_setup, | ||
189 | .flags = CON_PRINTBUFFER, | ||
190 | .index = -1, | ||
191 | }; | ||
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index c7e22ab29a5a..92c02344a060 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -60,19 +60,6 @@ | |||
60 | 60 | ||
61 | static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 }; | 61 | static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 }; |
62 | 62 | ||
63 | struct efi __read_mostly efi = { | ||
64 | .mps = EFI_INVALID_TABLE_ADDR, | ||
65 | .acpi = EFI_INVALID_TABLE_ADDR, | ||
66 | .acpi20 = EFI_INVALID_TABLE_ADDR, | ||
67 | .smbios = EFI_INVALID_TABLE_ADDR, | ||
68 | .sal_systab = EFI_INVALID_TABLE_ADDR, | ||
69 | .boot_info = EFI_INVALID_TABLE_ADDR, | ||
70 | .hcdp = EFI_INVALID_TABLE_ADDR, | ||
71 | .uga = EFI_INVALID_TABLE_ADDR, | ||
72 | .uv_systab = EFI_INVALID_TABLE_ADDR, | ||
73 | }; | ||
74 | EXPORT_SYMBOL(efi); | ||
75 | |||
76 | struct efi_memory_map memmap; | 63 | struct efi_memory_map memmap; |
77 | 64 | ||
78 | static struct efi efi_phys __initdata; | 65 | static struct efi efi_phys __initdata; |
@@ -80,6 +67,13 @@ static efi_system_table_t efi_systab __initdata; | |||
80 | 67 | ||
81 | unsigned long x86_efi_facility; | 68 | unsigned long x86_efi_facility; |
82 | 69 | ||
70 | static __initdata efi_config_table_type_t arch_tables[] = { | ||
71 | #ifdef CONFIG_X86_UV | ||
72 | {UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab}, | ||
73 | #endif | ||
74 | {NULL_GUID, NULL, NULL}, | ||
75 | }; | ||
76 | |||
83 | /* | 77 | /* |
84 | * Returns 1 if 'facility' is enabled, 0 otherwise. | 78 | * Returns 1 if 'facility' is enabled, 0 otherwise. |
85 | */ | 79 | */ |
@@ -399,6 +393,8 @@ int __init efi_memblock_x86_reserve_range(void) | |||
399 | 393 | ||
400 | memblock_reserve(pmap, memmap.nr_map * memmap.desc_size); | 394 | memblock_reserve(pmap, memmap.nr_map * memmap.desc_size); |
401 | 395 | ||
396 | efi.memmap = &memmap; | ||
397 | |||
402 | return 0; | 398 | return 0; |
403 | } | 399 | } |
404 | 400 | ||
@@ -578,80 +574,6 @@ static int __init efi_systab_init(void *phys) | |||
578 | return 0; | 574 | return 0; |
579 | } | 575 | } |
580 | 576 | ||
581 | static int __init efi_config_init(u64 tables, int nr_tables) | ||
582 | { | ||
583 | void *config_tables, *tablep; | ||
584 | int i, sz; | ||
585 | |||
586 | if (efi_enabled(EFI_64BIT)) | ||
587 | sz = sizeof(efi_config_table_64_t); | ||
588 | else | ||
589 | sz = sizeof(efi_config_table_32_t); | ||
590 | |||
591 | /* | ||
592 | * Let's see what config tables the firmware passed to us. | ||
593 | */ | ||
594 | config_tables = early_ioremap(tables, nr_tables * sz); | ||
595 | if (config_tables == NULL) { | ||
596 | pr_err("Could not map Configuration table!\n"); | ||
597 | return -ENOMEM; | ||
598 | } | ||
599 | |||
600 | tablep = config_tables; | ||
601 | pr_info(""); | ||
602 | for (i = 0; i < efi.systab->nr_tables; i++) { | ||
603 | efi_guid_t guid; | ||
604 | unsigned long table; | ||
605 | |||
606 | if (efi_enabled(EFI_64BIT)) { | ||
607 | u64 table64; | ||
608 | guid = ((efi_config_table_64_t *)tablep)->guid; | ||
609 | table64 = ((efi_config_table_64_t *)tablep)->table; | ||
610 | table = table64; | ||
611 | #ifdef CONFIG_X86_32 | ||
612 | if (table64 >> 32) { | ||
613 | pr_cont("\n"); | ||
614 | pr_err("Table located above 4GB, disabling EFI.\n"); | ||
615 | early_iounmap(config_tables, | ||
616 | efi.systab->nr_tables * sz); | ||
617 | return -EINVAL; | ||
618 | } | ||
619 | #endif | ||
620 | } else { | ||
621 | guid = ((efi_config_table_32_t *)tablep)->guid; | ||
622 | table = ((efi_config_table_32_t *)tablep)->table; | ||
623 | } | ||
624 | if (!efi_guidcmp(guid, MPS_TABLE_GUID)) { | ||
625 | efi.mps = table; | ||
626 | pr_cont(" MPS=0x%lx ", table); | ||
627 | } else if (!efi_guidcmp(guid, ACPI_20_TABLE_GUID)) { | ||
628 | efi.acpi20 = table; | ||
629 | pr_cont(" ACPI 2.0=0x%lx ", table); | ||
630 | } else if (!efi_guidcmp(guid, ACPI_TABLE_GUID)) { | ||
631 | efi.acpi = table; | ||
632 | pr_cont(" ACPI=0x%lx ", table); | ||
633 | } else if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) { | ||
634 | efi.smbios = table; | ||
635 | pr_cont(" SMBIOS=0x%lx ", table); | ||
636 | #ifdef CONFIG_X86_UV | ||
637 | } else if (!efi_guidcmp(guid, UV_SYSTEM_TABLE_GUID)) { | ||
638 | efi.uv_systab = table; | ||
639 | pr_cont(" UVsystab=0x%lx ", table); | ||
640 | #endif | ||
641 | } else if (!efi_guidcmp(guid, HCDP_TABLE_GUID)) { | ||
642 | efi.hcdp = table; | ||
643 | pr_cont(" HCDP=0x%lx ", table); | ||
644 | } else if (!efi_guidcmp(guid, UGA_IO_PROTOCOL_GUID)) { | ||
645 | efi.uga = table; | ||
646 | pr_cont(" UGA=0x%lx ", table); | ||
647 | } | ||
648 | tablep += sz; | ||
649 | } | ||
650 | pr_cont("\n"); | ||
651 | early_iounmap(config_tables, efi.systab->nr_tables * sz); | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int __init efi_runtime_init(void) | 577 | static int __init efi_runtime_init(void) |
656 | { | 578 | { |
657 | efi_runtime_services_t *runtime; | 579 | efi_runtime_services_t *runtime; |
@@ -745,7 +667,7 @@ void __init efi_init(void) | |||
745 | efi.systab->hdr.revision >> 16, | 667 | efi.systab->hdr.revision >> 16, |
746 | efi.systab->hdr.revision & 0xffff, vendor); | 668 | efi.systab->hdr.revision & 0xffff, vendor); |
747 | 669 | ||
748 | if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) | 670 | if (efi_config_init(arch_tables)) |
749 | return; | 671 | return; |
750 | 672 | ||
751 | set_bit(EFI_CONFIG_TABLES, &x86_efi_facility); | 673 | set_bit(EFI_CONFIG_TABLES, &x86_efi_facility); |
@@ -816,34 +738,6 @@ static void __init runtime_code_page_mkexec(void) | |||
816 | } | 738 | } |
817 | } | 739 | } |
818 | 740 | ||
819 | /* | ||
820 | * We can't ioremap data in EFI boot services RAM, because we've already mapped | ||
821 | * it as RAM. So, look it up in the existing EFI memory map instead. Only | ||
822 | * callable after efi_enter_virtual_mode and before efi_free_boot_services. | ||
823 | */ | ||
824 | void __iomem *efi_lookup_mapped_addr(u64 phys_addr) | ||
825 | { | ||
826 | void *p; | ||
827 | if (WARN_ON(!memmap.map)) | ||
828 | return NULL; | ||
829 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | ||
830 | efi_memory_desc_t *md = p; | ||
831 | u64 size = md->num_pages << EFI_PAGE_SHIFT; | ||
832 | u64 end = md->phys_addr + size; | ||
833 | if (!(md->attribute & EFI_MEMORY_RUNTIME) && | ||
834 | md->type != EFI_BOOT_SERVICES_CODE && | ||
835 | md->type != EFI_BOOT_SERVICES_DATA) | ||
836 | continue; | ||
837 | if (!md->virt_addr) | ||
838 | continue; | ||
839 | if (phys_addr >= md->phys_addr && phys_addr < end) { | ||
840 | phys_addr += md->virt_addr - md->phys_addr; | ||
841 | return (__force void __iomem *)(unsigned long)phys_addr; | ||
842 | } | ||
843 | } | ||
844 | return NULL; | ||
845 | } | ||
846 | |||
847 | void efi_memory_uc(u64 addr, unsigned long size) | 741 | void efi_memory_uc(u64 addr, unsigned long size) |
848 | { | 742 | { |
849 | unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; | 743 | unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; |