diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-12 13:03:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-12 13:03:44 -0500 |
commit | 3940cf0b3d3c6c5817bb86f61a02277cd33f953a (patch) | |
tree | 119b7a593a3422ac4d6e2e1fa762a8f817f71a35 | |
parent | 9ad1aeecdbbf002637f0466e8935a3248d1843ad (diff) | |
parent | 018edcfac4c3b140366ad51b0907f3becb5bb624 (diff) |
Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI updates from Ingo Molnar:
"The main changes in this development cycle were:
- Implement EFI dev path parser and other changes to fully support
thunderbolt devices on Apple Macbooks (Lukas Wunner)
- Add RNG seeding via the EFI stub, on ARM/arm64 (Ard Biesheuvel)
- Expose EFI framebuffer configuration to user-space, to improve
tooling (Peter Jones)
- Misc fixes and cleanups (Ivan Hu, Wei Yongjun, Yisheng Xie, Dan
Carpenter, Roy Franz)"
* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
efi/libstub: Make efi_random_alloc() allocate below 4 GB on 32-bit
thunderbolt: Compile on x86 only
thunderbolt, efi: Fix Kconfig dependencies harder
thunderbolt, efi: Fix Kconfig dependencies
thunderbolt: Use Device ROM retrieved from EFI
x86/efi: Retrieve and assign Apple device properties
efi: Allow bitness-agnostic protocol calls
efi: Add device path parser
efi/arm*/libstub: Invoke EFI_RNG_PROTOCOL to seed the UEFI RNG table
efi/libstub: Add random.c to ARM build
efi: Add support for seeding the RNG from a UEFI config table
MAINTAINERS: Add ARM and arm64 EFI specific files to EFI subsystem
efi/libstub: Fix allocation size calculations
efi/efivar_ssdt_load: Don't return success on allocation failure
efifb: Show framebuffer layout as device attributes
efi/efi_test: Use memdup_user() as a cleanup
efi/efi_test: Fix uninitialized variable 'rv'
efi/efi_test: Fix uninitialized variable 'datasize'
efi/arm*: Fix efi_init() error handling
efi: Remove unused include of <linux/version.h>
24 files changed, 872 insertions, 62 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 37babf91f2cb..86a31dfc036e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1062,6 +1062,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
1062 | 1062 | ||
1063 | dscc4.setup= [NET] | 1063 | dscc4.setup= [NET] |
1064 | 1064 | ||
1065 | dump_apple_properties [X86] | ||
1066 | Dump name and content of EFI device properties on | ||
1067 | x86 Macs. Useful for driver authors to determine | ||
1068 | what data is available or for reverse-engineering. | ||
1069 | |||
1065 | dyndbg[="val"] [KNL,DYNAMIC_DEBUG] | 1070 | dyndbg[="val"] [KNL,DYNAMIC_DEBUG] |
1066 | module.dyndbg[="val"] | 1071 | module.dyndbg[="val"] |
1067 | Enable debug messages at boot time. See | 1072 | Enable debug messages at boot time. See |
diff --git a/MAINTAINERS b/MAINTAINERS index e2463baf33e5..cfbb164acd20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4645,12 +4645,14 @@ L: linux-efi@vger.kernel.org | |||
4645 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git | 4645 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git |
4646 | S: Maintained | 4646 | S: Maintained |
4647 | F: Documentation/efi-stub.txt | 4647 | F: Documentation/efi-stub.txt |
4648 | F: arch/ia64/kernel/efi.c | 4648 | F: arch/*/kernel/efi.c |
4649 | F: arch/x86/boot/compressed/eboot.[ch] | 4649 | F: arch/x86/boot/compressed/eboot.[ch] |
4650 | F: arch/x86/include/asm/efi.h | 4650 | F: arch/*/include/asm/efi.h |
4651 | F: arch/x86/platform/efi/ | 4651 | F: arch/x86/platform/efi/ |
4652 | F: drivers/firmware/efi/ | 4652 | F: drivers/firmware/efi/ |
4653 | F: include/linux/efi*.h | 4653 | F: include/linux/efi*.h |
4654 | F: arch/arm/boot/compressed/efi-header.S | ||
4655 | F: arch/arm64/kernel/efi-entry.S | ||
4654 | 4656 | ||
4655 | EFI VARIABLE FILESYSTEM | 4657 | EFI VARIABLE FILESYSTEM |
4656 | M: Matthew Garrett <matthew.garrett@nebula.com> | 4658 | M: Matthew Garrett <matthew.garrett@nebula.com> |
diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index 766bf9b78160..0b06f5341b45 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h | |||
@@ -57,6 +57,9 @@ void efi_virtmap_unload(void); | |||
57 | #define __efi_call_early(f, ...) f(__VA_ARGS__) | 57 | #define __efi_call_early(f, ...) f(__VA_ARGS__) |
58 | #define efi_is_64bit() (false) | 58 | #define efi_is_64bit() (false) |
59 | 59 | ||
60 | #define efi_call_proto(protocol, f, instance, ...) \ | ||
61 | ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) | ||
62 | |||
60 | struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg); | 63 | struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg); |
61 | void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si); | 64 | void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si); |
62 | 65 | ||
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index a9e54aad15ef..771b3f0bc757 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h | |||
@@ -51,6 +51,9 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); | |||
51 | #define __efi_call_early(f, ...) f(__VA_ARGS__) | 51 | #define __efi_call_early(f, ...) f(__VA_ARGS__) |
52 | #define efi_is_64bit() (true) | 52 | #define efi_is_64bit() (true) |
53 | 53 | ||
54 | #define efi_call_proto(protocol, f, instance, ...) \ | ||
55 | ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) | ||
56 | |||
54 | #define alloc_screen_info(x...) &screen_info | 57 | #define alloc_screen_info(x...) &screen_info |
55 | #define free_screen_info(x...) | 58 | #define free_screen_info(x...) |
56 | 59 | ||
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index cc69e37548db..ff01c8fc76f7 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c | |||
@@ -537,6 +537,69 @@ free_handle: | |||
537 | efi_call_early(free_pool, pci_handle); | 537 | efi_call_early(free_pool, pci_handle); |
538 | } | 538 | } |
539 | 539 | ||
540 | static void retrieve_apple_device_properties(struct boot_params *boot_params) | ||
541 | { | ||
542 | efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID; | ||
543 | struct setup_data *data, *new; | ||
544 | efi_status_t status; | ||
545 | u32 size = 0; | ||
546 | void *p; | ||
547 | |||
548 | status = efi_call_early(locate_protocol, &guid, NULL, &p); | ||
549 | if (status != EFI_SUCCESS) | ||
550 | return; | ||
551 | |||
552 | if (efi_table_attr(apple_properties_protocol, version, p) != 0x10000) { | ||
553 | efi_printk(sys_table, "Unsupported properties proto version\n"); | ||
554 | return; | ||
555 | } | ||
556 | |||
557 | efi_call_proto(apple_properties_protocol, get_all, p, NULL, &size); | ||
558 | if (!size) | ||
559 | return; | ||
560 | |||
561 | do { | ||
562 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, | ||
563 | size + sizeof(struct setup_data), &new); | ||
564 | if (status != EFI_SUCCESS) { | ||
565 | efi_printk(sys_table, | ||
566 | "Failed to alloc mem for properties\n"); | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | status = efi_call_proto(apple_properties_protocol, get_all, p, | ||
571 | new->data, &size); | ||
572 | |||
573 | if (status == EFI_BUFFER_TOO_SMALL) | ||
574 | efi_call_early(free_pool, new); | ||
575 | } while (status == EFI_BUFFER_TOO_SMALL); | ||
576 | |||
577 | new->type = SETUP_APPLE_PROPERTIES; | ||
578 | new->len = size; | ||
579 | new->next = 0; | ||
580 | |||
581 | data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data; | ||
582 | if (!data) | ||
583 | boot_params->hdr.setup_data = (unsigned long)new; | ||
584 | else { | ||
585 | while (data->next) | ||
586 | data = (struct setup_data *)(unsigned long)data->next; | ||
587 | data->next = (unsigned long)new; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | static void setup_quirks(struct boot_params *boot_params) | ||
592 | { | ||
593 | efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 }; | ||
594 | efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long) | ||
595 | efi_table_attr(efi_system_table, fw_vendor, sys_table); | ||
596 | |||
597 | if (!memcmp(fw_vendor, apple, sizeof(apple))) { | ||
598 | if (IS_ENABLED(CONFIG_APPLE_PROPERTIES)) | ||
599 | retrieve_apple_device_properties(boot_params); | ||
600 | } | ||
601 | } | ||
602 | |||
540 | static efi_status_t | 603 | static efi_status_t |
541 | setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) | 604 | setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) |
542 | { | 605 | { |
@@ -1098,6 +1161,8 @@ struct boot_params *efi_main(struct efi_config *c, | |||
1098 | 1161 | ||
1099 | setup_efi_pci(boot_params); | 1162 | setup_efi_pci(boot_params); |
1100 | 1163 | ||
1164 | setup_quirks(boot_params); | ||
1165 | |||
1101 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, | 1166 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, |
1102 | sizeof(*gdt), (void **)&gdt); | 1167 | sizeof(*gdt), (void **)&gdt); |
1103 | if (status != EFI_SUCCESS) { | 1168 | if (status != EFI_SUCCESS) { |
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 389d700b961e..e99675b9c861 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h | |||
@@ -210,12 +210,18 @@ static inline bool efi_is_64bit(void) | |||
210 | return __efi_early()->is64; | 210 | return __efi_early()->is64; |
211 | } | 211 | } |
212 | 212 | ||
213 | #define efi_table_attr(table, attr, instance) \ | ||
214 | (efi_is_64bit() ? \ | ||
215 | ((table##_64_t *)(unsigned long)instance)->attr : \ | ||
216 | ((table##_32_t *)(unsigned long)instance)->attr) | ||
217 | |||
218 | #define efi_call_proto(protocol, f, instance, ...) \ | ||
219 | __efi_early()->call(efi_table_attr(protocol, f, instance), \ | ||
220 | instance, ##__VA_ARGS__) | ||
221 | |||
213 | #define efi_call_early(f, ...) \ | 222 | #define efi_call_early(f, ...) \ |
214 | __efi_early()->call(efi_is_64bit() ? \ | 223 | __efi_early()->call(efi_table_attr(efi_boot_services, f, \ |
215 | ((efi_boot_services_64_t *)(unsigned long) \ | 224 | __efi_early()->boot_services), __VA_ARGS__) |
216 | __efi_early()->boot_services)->f : \ | ||
217 | ((efi_boot_services_32_t *)(unsigned long) \ | ||
218 | __efi_early()->boot_services)->f, __VA_ARGS__) | ||
219 | 225 | ||
220 | #define __efi_call_early(f, ...) \ | 226 | #define __efi_call_early(f, ...) \ |
221 | __efi_early()->call((unsigned long)f, __VA_ARGS__); | 227 | __efi_early()->call((unsigned long)f, __VA_ARGS__); |
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index c18ce67495fa..b10bf319ed20 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #define SETUP_DTB 2 | 7 | #define SETUP_DTB 2 |
8 | #define SETUP_PCI 3 | 8 | #define SETUP_PCI 3 |
9 | #define SETUP_EFI 4 | 9 | #define SETUP_EFI 4 |
10 | #define SETUP_APPLE_PROPERTIES 5 | ||
10 | 11 | ||
11 | /* ram_size flags */ | 12 | /* ram_size flags */ |
12 | #define RAMDISK_IMAGE_START_MASK 0x07FF | 13 | #define RAMDISK_IMAGE_START_MASK 0x07FF |
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index c981be17d3c0..2e78b0b96d74 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig | |||
@@ -129,7 +129,25 @@ config EFI_TEST | |||
129 | Say Y here to enable the runtime services support via /dev/efi_test. | 129 | Say Y here to enable the runtime services support via /dev/efi_test. |
130 | If unsure, say N. | 130 | If unsure, say N. |
131 | 131 | ||
132 | config APPLE_PROPERTIES | ||
133 | bool "Apple Device Properties" | ||
134 | depends on EFI_STUB && X86 | ||
135 | select EFI_DEV_PATH_PARSER | ||
136 | select UCS2_STRING | ||
137 | help | ||
138 | Retrieve properties from EFI on Apple Macs and assign them to | ||
139 | devices, allowing for improved support of Apple hardware. | ||
140 | Properties that would otherwise be missing include the | ||
141 | Thunderbolt Device ROM and GPU configuration data. | ||
142 | |||
143 | If unsure, say Y if you have a Mac. Otherwise N. | ||
144 | |||
132 | endmenu | 145 | endmenu |
133 | 146 | ||
134 | config UEFI_CPER | 147 | config UEFI_CPER |
135 | bool | 148 | bool |
149 | |||
150 | config EFI_DEV_PATH_PARSER | ||
151 | bool | ||
152 | depends on ACPI | ||
153 | default n | ||
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index c8a439f6d715..ad67342313ed 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile | |||
@@ -21,6 +21,8 @@ obj-$(CONFIG_EFI_STUB) += libstub/ | |||
21 | obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o | 21 | obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o |
22 | obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o | 22 | obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o |
23 | obj-$(CONFIG_EFI_TEST) += test/ | 23 | obj-$(CONFIG_EFI_TEST) += test/ |
24 | obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o | ||
25 | obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o | ||
24 | 26 | ||
25 | arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o | 27 | arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o |
26 | obj-$(CONFIG_ARM) += $(arm-obj-y) | 28 | obj-$(CONFIG_ARM) += $(arm-obj-y) |
diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c new file mode 100644 index 000000000000..c473f4c5ca34 --- /dev/null +++ b/drivers/firmware/efi/apple-properties.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * apple-properties.c - EFI device properties on Macs | ||
3 | * Copyright (C) 2016 Lukas Wunner <lukas@wunner.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License (version 2) as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #define pr_fmt(fmt) "apple-properties: " fmt | ||
19 | |||
20 | #include <linux/bootmem.h> | ||
21 | #include <linux/dmi.h> | ||
22 | #include <linux/efi.h> | ||
23 | #include <linux/property.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/ucs2_string.h> | ||
26 | #include <asm/setup.h> | ||
27 | |||
28 | static bool dump_properties __initdata; | ||
29 | |||
30 | static int __init dump_properties_enable(char *arg) | ||
31 | { | ||
32 | dump_properties = true; | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | __setup("dump_apple_properties", dump_properties_enable); | ||
37 | |||
38 | struct dev_header { | ||
39 | u32 len; | ||
40 | u32 prop_count; | ||
41 | struct efi_dev_path path[0]; | ||
42 | /* | ||
43 | * followed by key/value pairs, each key and value preceded by u32 len, | ||
44 | * len includes itself, value may be empty (in which case its len is 4) | ||
45 | */ | ||
46 | }; | ||
47 | |||
48 | struct properties_header { | ||
49 | u32 len; | ||
50 | u32 version; | ||
51 | u32 dev_count; | ||
52 | struct dev_header dev_header[0]; | ||
53 | }; | ||
54 | |||
55 | static u8 one __initdata = 1; | ||
56 | |||
57 | static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, | ||
58 | struct device *dev, void *ptr, | ||
59 | struct property_entry entry[]) | ||
60 | { | ||
61 | int i; | ||
62 | |||
63 | for (i = 0; i < dev_header->prop_count; i++) { | ||
64 | int remaining = dev_header->len - (ptr - (void *)dev_header); | ||
65 | u32 key_len, val_len; | ||
66 | char *key; | ||
67 | |||
68 | if (sizeof(key_len) > remaining) | ||
69 | break; | ||
70 | |||
71 | key_len = *(typeof(key_len) *)ptr; | ||
72 | if (key_len + sizeof(val_len) > remaining || | ||
73 | key_len < sizeof(key_len) + sizeof(efi_char16_t) || | ||
74 | *(efi_char16_t *)(ptr + sizeof(key_len)) == 0) { | ||
75 | dev_err(dev, "invalid property name len at %#zx\n", | ||
76 | ptr - (void *)dev_header); | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | val_len = *(typeof(val_len) *)(ptr + key_len); | ||
81 | if (key_len + val_len > remaining || | ||
82 | val_len < sizeof(val_len)) { | ||
83 | dev_err(dev, "invalid property val len at %#zx\n", | ||
84 | ptr - (void *)dev_header + key_len); | ||
85 | break; | ||
86 | } | ||
87 | |||
88 | /* 4 bytes to accommodate UTF-8 code points + null byte */ | ||
89 | key = kzalloc((key_len - sizeof(key_len)) * 4 + 1, GFP_KERNEL); | ||
90 | if (!key) { | ||
91 | dev_err(dev, "cannot allocate property name\n"); | ||
92 | break; | ||
93 | } | ||
94 | ucs2_as_utf8(key, ptr + sizeof(key_len), | ||
95 | key_len - sizeof(key_len)); | ||
96 | |||
97 | entry[i].name = key; | ||
98 | entry[i].is_array = true; | ||
99 | entry[i].length = val_len - sizeof(val_len); | ||
100 | entry[i].pointer.raw_data = ptr + key_len + sizeof(val_len); | ||
101 | if (!entry[i].length) { | ||
102 | /* driver core doesn't accept empty properties */ | ||
103 | entry[i].length = 1; | ||
104 | entry[i].pointer.raw_data = &one; | ||
105 | } | ||
106 | |||
107 | if (dump_properties) { | ||
108 | dev_info(dev, "property: %s\n", entry[i].name); | ||
109 | print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, | ||
110 | 16, 1, entry[i].pointer.raw_data, | ||
111 | entry[i].length, true); | ||
112 | } | ||
113 | |||
114 | ptr += key_len + val_len; | ||
115 | } | ||
116 | |||
117 | if (i != dev_header->prop_count) { | ||
118 | dev_err(dev, "got %d device properties, expected %u\n", i, | ||
119 | dev_header->prop_count); | ||
120 | print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET, | ||
121 | 16, 1, dev_header, dev_header->len, true); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | dev_info(dev, "assigning %d device properties\n", i); | ||
126 | } | ||
127 | |||
128 | static int __init unmarshal_devices(struct properties_header *properties) | ||
129 | { | ||
130 | size_t offset = offsetof(struct properties_header, dev_header[0]); | ||
131 | |||
132 | while (offset + sizeof(struct dev_header) < properties->len) { | ||
133 | struct dev_header *dev_header = (void *)properties + offset; | ||
134 | struct property_entry *entry = NULL; | ||
135 | struct device *dev; | ||
136 | size_t len; | ||
137 | int ret, i; | ||
138 | void *ptr; | ||
139 | |||
140 | if (offset + dev_header->len > properties->len || | ||
141 | dev_header->len <= sizeof(*dev_header)) { | ||
142 | pr_err("invalid len in dev_header at %#zx\n", offset); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | ptr = dev_header->path; | ||
147 | len = dev_header->len - sizeof(*dev_header); | ||
148 | |||
149 | dev = efi_get_device_by_path((struct efi_dev_path **)&ptr, &len); | ||
150 | if (IS_ERR(dev)) { | ||
151 | pr_err("device path parse error %ld at %#zx:\n", | ||
152 | PTR_ERR(dev), ptr - (void *)dev_header); | ||
153 | print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET, | ||
154 | 16, 1, dev_header, dev_header->len, true); | ||
155 | dev = NULL; | ||
156 | goto skip_device; | ||
157 | } | ||
158 | |||
159 | entry = kcalloc(dev_header->prop_count + 1, sizeof(*entry), | ||
160 | GFP_KERNEL); | ||
161 | if (!entry) { | ||
162 | dev_err(dev, "cannot allocate properties\n"); | ||
163 | goto skip_device; | ||
164 | } | ||
165 | |||
166 | unmarshal_key_value_pairs(dev_header, dev, ptr, entry); | ||
167 | if (!entry[0].name) | ||
168 | goto skip_device; | ||
169 | |||
170 | ret = device_add_properties(dev, entry); /* makes deep copy */ | ||
171 | if (ret) | ||
172 | dev_err(dev, "error %d assigning properties\n", ret); | ||
173 | |||
174 | for (i = 0; entry[i].name; i++) | ||
175 | kfree(entry[i].name); | ||
176 | |||
177 | skip_device: | ||
178 | kfree(entry); | ||
179 | put_device(dev); | ||
180 | offset += dev_header->len; | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int __init map_properties(void) | ||
187 | { | ||
188 | struct properties_header *properties; | ||
189 | struct setup_data *data; | ||
190 | u32 data_len; | ||
191 | u64 pa_data; | ||
192 | int ret; | ||
193 | |||
194 | if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.") && | ||
195 | !dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc.")) | ||
196 | return 0; | ||
197 | |||
198 | pa_data = boot_params.hdr.setup_data; | ||
199 | while (pa_data) { | ||
200 | data = ioremap(pa_data, sizeof(*data)); | ||
201 | if (!data) { | ||
202 | pr_err("cannot map setup_data header\n"); | ||
203 | return -ENOMEM; | ||
204 | } | ||
205 | |||
206 | if (data->type != SETUP_APPLE_PROPERTIES) { | ||
207 | pa_data = data->next; | ||
208 | iounmap(data); | ||
209 | continue; | ||
210 | } | ||
211 | |||
212 | data_len = data->len; | ||
213 | iounmap(data); | ||
214 | |||
215 | data = ioremap(pa_data, sizeof(*data) + data_len); | ||
216 | if (!data) { | ||
217 | pr_err("cannot map setup_data payload\n"); | ||
218 | return -ENOMEM; | ||
219 | } | ||
220 | |||
221 | properties = (struct properties_header *)data->data; | ||
222 | if (properties->version != 1) { | ||
223 | pr_err("unsupported version:\n"); | ||
224 | print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET, | ||
225 | 16, 1, properties, data_len, true); | ||
226 | ret = -ENOTSUPP; | ||
227 | } else if (properties->len != data_len) { | ||
228 | pr_err("length mismatch, expected %u\n", data_len); | ||
229 | print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET, | ||
230 | 16, 1, properties, data_len, true); | ||
231 | ret = -EINVAL; | ||
232 | } else | ||
233 | ret = unmarshal_devices(properties); | ||
234 | |||
235 | /* | ||
236 | * Can only free the setup_data payload but not its header | ||
237 | * to avoid breaking the chain of ->next pointers. | ||
238 | */ | ||
239 | data->len = 0; | ||
240 | iounmap(data); | ||
241 | free_bootmem_late(pa_data + sizeof(*data), data_len); | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | fs_initcall(map_properties); | ||
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 8efe13075c92..f853ad2c4ca0 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c | |||
@@ -244,8 +244,10 @@ void __init efi_init(void) | |||
244 | "Unexpected EFI_MEMORY_DESCRIPTOR version %ld", | 244 | "Unexpected EFI_MEMORY_DESCRIPTOR version %ld", |
245 | efi.memmap.desc_version); | 245 | efi.memmap.desc_version); |
246 | 246 | ||
247 | if (uefi_init() < 0) | 247 | if (uefi_init() < 0) { |
248 | efi_memmap_unmap(); | ||
248 | return; | 249 | return; |
250 | } | ||
249 | 251 | ||
250 | reserve_regions(); | 252 | reserve_regions(); |
251 | efi_memattr_init(); | 253 | efi_memattr_init(); |
diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c new file mode 100644 index 000000000000..85d1834ee9b7 --- /dev/null +++ b/drivers/firmware/efi/dev-path-parser.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * dev-path-parser.c - EFI Device Path parser | ||
3 | * Copyright (C) 2016 Lukas Wunner <lukas@wunner.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License (version 2) as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/acpi.h> | ||
19 | #include <linux/efi.h> | ||
20 | #include <linux/pci.h> | ||
21 | |||
22 | struct acpi_hid_uid { | ||
23 | struct acpi_device_id hid[2]; | ||
24 | char uid[11]; /* UINT_MAX + null byte */ | ||
25 | }; | ||
26 | |||
27 | static int __init match_acpi_dev(struct device *dev, void *data) | ||
28 | { | ||
29 | struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data; | ||
30 | struct acpi_device *adev = to_acpi_device(dev); | ||
31 | |||
32 | if (acpi_match_device_ids(adev, hid_uid.hid)) | ||
33 | return 0; | ||
34 | |||
35 | if (adev->pnp.unique_id) | ||
36 | return !strcmp(adev->pnp.unique_id, hid_uid.uid); | ||
37 | else | ||
38 | return !strcmp("0", hid_uid.uid); | ||
39 | } | ||
40 | |||
41 | static long __init parse_acpi_path(struct efi_dev_path *node, | ||
42 | struct device *parent, struct device **child) | ||
43 | { | ||
44 | struct acpi_hid_uid hid_uid = {}; | ||
45 | struct device *phys_dev; | ||
46 | |||
47 | if (node->length != 12) | ||
48 | return -EINVAL; | ||
49 | |||
50 | sprintf(hid_uid.hid[0].id, "%c%c%c%04X", | ||
51 | 'A' + ((node->acpi.hid >> 10) & 0x1f) - 1, | ||
52 | 'A' + ((node->acpi.hid >> 5) & 0x1f) - 1, | ||
53 | 'A' + ((node->acpi.hid >> 0) & 0x1f) - 1, | ||
54 | node->acpi.hid >> 16); | ||
55 | sprintf(hid_uid.uid, "%u", node->acpi.uid); | ||
56 | |||
57 | *child = bus_find_device(&acpi_bus_type, NULL, &hid_uid, | ||
58 | match_acpi_dev); | ||
59 | if (!*child) | ||
60 | return -ENODEV; | ||
61 | |||
62 | phys_dev = acpi_get_first_physical_node(to_acpi_device(*child)); | ||
63 | if (phys_dev) { | ||
64 | get_device(phys_dev); | ||
65 | put_device(*child); | ||
66 | *child = phys_dev; | ||
67 | } | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int __init match_pci_dev(struct device *dev, void *data) | ||
73 | { | ||
74 | unsigned int devfn = *(unsigned int *)data; | ||
75 | |||
76 | return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn; | ||
77 | } | ||
78 | |||
79 | static long __init parse_pci_path(struct efi_dev_path *node, | ||
80 | struct device *parent, struct device **child) | ||
81 | { | ||
82 | unsigned int devfn; | ||
83 | |||
84 | if (node->length != 6) | ||
85 | return -EINVAL; | ||
86 | if (!parent) | ||
87 | return -EINVAL; | ||
88 | |||
89 | devfn = PCI_DEVFN(node->pci.dev, node->pci.fn); | ||
90 | |||
91 | *child = device_find_child(parent, &devfn, match_pci_dev); | ||
92 | if (!*child) | ||
93 | return -ENODEV; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Insert parsers for further node types here. | ||
100 | * | ||
101 | * Each parser takes a pointer to the @node and to the @parent (will be NULL | ||
102 | * for the first device path node). If a device corresponding to @node was | ||
103 | * found below @parent, its reference count should be incremented and the | ||
104 | * device returned in @child. | ||
105 | * | ||
106 | * The return value should be 0 on success or a negative int on failure. | ||
107 | * The special return values 0x01 (EFI_DEV_END_INSTANCE) and 0xFF | ||
108 | * (EFI_DEV_END_ENTIRE) signal the end of the device path, only | ||
109 | * parse_end_path() is supposed to return this. | ||
110 | * | ||
111 | * Be sure to validate the node length and contents before commencing the | ||
112 | * search for a device. | ||
113 | */ | ||
114 | |||
115 | static long __init parse_end_path(struct efi_dev_path *node, | ||
116 | struct device *parent, struct device **child) | ||
117 | { | ||
118 | if (node->length != 4) | ||
119 | return -EINVAL; | ||
120 | if (node->sub_type != EFI_DEV_END_INSTANCE && | ||
121 | node->sub_type != EFI_DEV_END_ENTIRE) | ||
122 | return -EINVAL; | ||
123 | if (!parent) | ||
124 | return -ENODEV; | ||
125 | |||
126 | *child = get_device(parent); | ||
127 | return node->sub_type; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * efi_get_device_by_path - find device by EFI Device Path | ||
132 | * @node: EFI Device Path | ||
133 | * @len: maximum length of EFI Device Path in bytes | ||
134 | * | ||
135 | * Parse a series of EFI Device Path nodes at @node and find the corresponding | ||
136 | * device. If the device was found, its reference count is incremented and a | ||
137 | * pointer to it is returned. The caller needs to drop the reference with | ||
138 | * put_device() after use. The @node pointer is updated to point to the | ||
139 | * location immediately after the "End of Hardware Device Path" node. | ||
140 | * | ||
141 | * If another Device Path instance follows, @len is decremented by the number | ||
142 | * of bytes consumed. Otherwise @len is set to %0. | ||
143 | * | ||
144 | * If a Device Path node is malformed or its corresponding device is not found, | ||
145 | * @node is updated to point to this offending node and an ERR_PTR is returned. | ||
146 | * | ||
147 | * If @len is initially %0, the function returns %NULL. Thus, to iterate over | ||
148 | * all instances in a path, the following idiom may be used: | ||
149 | * | ||
150 | * while (!IS_ERR_OR_NULL(dev = efi_get_device_by_path(&node, &len))) { | ||
151 | * // do something with dev | ||
152 | * put_device(dev); | ||
153 | * } | ||
154 | * if (IS_ERR(dev)) | ||
155 | * // report error | ||
156 | * | ||
157 | * Devices can only be found if they're already instantiated. Most buses | ||
158 | * instantiate devices in the "subsys" initcall level, hence the earliest | ||
159 | * initcall level in which this function should be called is "fs". | ||
160 | * | ||
161 | * Returns the device on success or | ||
162 | * %ERR_PTR(-ENODEV) if no device was found, | ||
163 | * %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len, | ||
164 | * %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented. | ||
165 | */ | ||
166 | struct device * __init efi_get_device_by_path(struct efi_dev_path **node, | ||
167 | size_t *len) | ||
168 | { | ||
169 | struct device *parent = NULL, *child; | ||
170 | long ret = 0; | ||
171 | |||
172 | if (!*len) | ||
173 | return NULL; | ||
174 | |||
175 | while (!ret) { | ||
176 | if (*len < 4 || *len < (*node)->length) | ||
177 | ret = -EINVAL; | ||
178 | else if ((*node)->type == EFI_DEV_ACPI && | ||
179 | (*node)->sub_type == EFI_DEV_BASIC_ACPI) | ||
180 | ret = parse_acpi_path(*node, parent, &child); | ||
181 | else if ((*node)->type == EFI_DEV_HW && | ||
182 | (*node)->sub_type == EFI_DEV_PCI) | ||
183 | ret = parse_pci_path(*node, parent, &child); | ||
184 | else if (((*node)->type == EFI_DEV_END_PATH || | ||
185 | (*node)->type == EFI_DEV_END_PATH2)) | ||
186 | ret = parse_end_path(*node, parent, &child); | ||
187 | else | ||
188 | ret = -ENOTSUPP; | ||
189 | |||
190 | put_device(parent); | ||
191 | if (ret < 0) | ||
192 | return ERR_PTR(ret); | ||
193 | |||
194 | parent = child; | ||
195 | *node = (void *)*node + (*node)->length; | ||
196 | *len -= (*node)->length; | ||
197 | } | ||
198 | |||
199 | if (ret == EFI_DEV_END_ENTIRE) | ||
200 | *len = 0; | ||
201 | |||
202 | return child; | ||
203 | } | ||
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 1ac199cd75e7..92914801e388 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -23,7 +23,10 @@ | |||
23 | #include <linux/of.h> | 23 | #include <linux/of.h> |
24 | #include <linux/of_fdt.h> | 24 | #include <linux/of_fdt.h> |
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/kexec.h> | ||
26 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/random.h> | ||
29 | #include <linux/reboot.h> | ||
27 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
28 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
29 | #include <linux/ucs2_string.h> | 32 | #include <linux/ucs2_string.h> |
@@ -48,6 +51,7 @@ struct efi __read_mostly efi = { | |||
48 | .esrt = EFI_INVALID_TABLE_ADDR, | 51 | .esrt = EFI_INVALID_TABLE_ADDR, |
49 | .properties_table = EFI_INVALID_TABLE_ADDR, | 52 | .properties_table = EFI_INVALID_TABLE_ADDR, |
50 | .mem_attr_table = EFI_INVALID_TABLE_ADDR, | 53 | .mem_attr_table = EFI_INVALID_TABLE_ADDR, |
54 | .rng_seed = EFI_INVALID_TABLE_ADDR, | ||
51 | }; | 55 | }; |
52 | EXPORT_SYMBOL(efi); | 56 | EXPORT_SYMBOL(efi); |
53 | 57 | ||
@@ -259,8 +263,10 @@ static __init int efivar_ssdt_load(void) | |||
259 | } | 263 | } |
260 | 264 | ||
261 | data = kmalloc(size, GFP_KERNEL); | 265 | data = kmalloc(size, GFP_KERNEL); |
262 | if (!data) | 266 | if (!data) { |
267 | ret = -ENOMEM; | ||
263 | goto free_entry; | 268 | goto free_entry; |
269 | } | ||
264 | 270 | ||
265 | ret = efivar_entry_get(entry, NULL, &size, data); | 271 | ret = efivar_entry_get(entry, NULL, &size, data); |
266 | if (ret) { | 272 | if (ret) { |
@@ -438,6 +444,7 @@ static __initdata efi_config_table_type_t common_tables[] = { | |||
438 | {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt}, | 444 | {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt}, |
439 | {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table}, | 445 | {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table}, |
440 | {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, | 446 | {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, |
447 | {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, | ||
441 | {NULL_GUID, NULL, NULL}, | 448 | {NULL_GUID, NULL, NULL}, |
442 | }; | 449 | }; |
443 | 450 | ||
@@ -499,6 +506,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, | |||
499 | pr_cont("\n"); | 506 | pr_cont("\n"); |
500 | set_bit(EFI_CONFIG_TABLES, &efi.flags); | 507 | set_bit(EFI_CONFIG_TABLES, &efi.flags); |
501 | 508 | ||
509 | if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) { | ||
510 | struct linux_efi_random_seed *seed; | ||
511 | u32 size = 0; | ||
512 | |||
513 | seed = early_memremap(efi.rng_seed, sizeof(*seed)); | ||
514 | if (seed != NULL) { | ||
515 | size = seed->size; | ||
516 | early_memunmap(seed, sizeof(*seed)); | ||
517 | } else { | ||
518 | pr_err("Could not map UEFI random seed!\n"); | ||
519 | } | ||
520 | if (size > 0) { | ||
521 | seed = early_memremap(efi.rng_seed, | ||
522 | sizeof(*seed) + size); | ||
523 | if (seed != NULL) { | ||
524 | add_device_randomness(seed->bits, seed->size); | ||
525 | early_memunmap(seed, sizeof(*seed) + size); | ||
526 | } else { | ||
527 | pr_err("Could not map UEFI random seed!\n"); | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | |||
502 | /* Parse the EFI Properties table if it exists */ | 532 | /* Parse the EFI Properties table if it exists */ |
503 | if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { | 533 | if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { |
504 | efi_properties_table_t *tbl; | 534 | efi_properties_table_t *tbl; |
@@ -822,3 +852,47 @@ int efi_status_to_err(efi_status_t status) | |||
822 | 852 | ||
823 | return err; | 853 | return err; |
824 | } | 854 | } |
855 | |||
856 | #ifdef CONFIG_KEXEC | ||
857 | static int update_efi_random_seed(struct notifier_block *nb, | ||
858 | unsigned long code, void *unused) | ||
859 | { | ||
860 | struct linux_efi_random_seed *seed; | ||
861 | u32 size = 0; | ||
862 | |||
863 | if (!kexec_in_progress) | ||
864 | return NOTIFY_DONE; | ||
865 | |||
866 | seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB); | ||
867 | if (seed != NULL) { | ||
868 | size = min(seed->size, 32U); | ||
869 | memunmap(seed); | ||
870 | } else { | ||
871 | pr_err("Could not map UEFI random seed!\n"); | ||
872 | } | ||
873 | if (size > 0) { | ||
874 | seed = memremap(efi.rng_seed, sizeof(*seed) + size, | ||
875 | MEMREMAP_WB); | ||
876 | if (seed != NULL) { | ||
877 | seed->size = size; | ||
878 | get_random_bytes(seed->bits, seed->size); | ||
879 | memunmap(seed); | ||
880 | } else { | ||
881 | pr_err("Could not map UEFI random seed!\n"); | ||
882 | } | ||
883 | } | ||
884 | return NOTIFY_DONE; | ||
885 | } | ||
886 | |||
887 | static struct notifier_block efi_random_seed_nb = { | ||
888 | .notifier_call = update_efi_random_seed, | ||
889 | }; | ||
890 | |||
891 | static int register_update_efi_random_seed(void) | ||
892 | { | ||
893 | if (efi.rng_seed == EFI_INVALID_TABLE_ADDR) | ||
894 | return 0; | ||
895 | return register_reboot_notifier(&efi_random_seed_nb); | ||
896 | } | ||
897 | late_initcall(register_update_efi_random_seed); | ||
898 | #endif | ||
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5e23e2d305e7..6621b13c370f 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile | |||
@@ -36,11 +36,11 @@ arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c | |||
36 | $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE | 36 | $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE |
37 | $(call if_changed_rule,cc_o_c) | 37 | $(call if_changed_rule,cc_o_c) |
38 | 38 | ||
39 | lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ | 39 | lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o random.o \ |
40 | $(patsubst %.c,lib-%.o,$(arm-deps)) | 40 | $(patsubst %.c,lib-%.o,$(arm-deps)) |
41 | 41 | ||
42 | lib-$(CONFIG_ARM) += arm32-stub.o | 42 | lib-$(CONFIG_ARM) += arm32-stub.o |
43 | lib-$(CONFIG_ARM64) += arm64-stub.o random.o | 43 | lib-$(CONFIG_ARM64) += arm64-stub.o |
44 | CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 44 | CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
45 | 45 | ||
46 | # | 46 | # |
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 993aa56755f6..b4f7d78f9e8b 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c | |||
@@ -340,6 +340,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, | |||
340 | if (status != EFI_SUCCESS) | 340 | if (status != EFI_SUCCESS) |
341 | pr_efi_err(sys_table, "Failed initrd from command line!\n"); | 341 | pr_efi_err(sys_table, "Failed initrd from command line!\n"); |
342 | 342 | ||
343 | efi_random_get_seed(sys_table); | ||
344 | |||
343 | new_fdt_addr = fdt_addr; | 345 | new_fdt_addr = fdt_addr; |
344 | status = allocate_new_fdt_and_exit_boot(sys_table, handle, | 346 | status = allocate_new_fdt_and_exit_boot(sys_table, handle, |
345 | &new_fdt_addr, dram_base + MAX_FDT_OFFSET, | 347 | &new_fdt_addr, dram_base + MAX_FDT_OFFSET, |
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index aded10662020..757badc1debb 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c | |||
@@ -32,15 +32,6 @@ | |||
32 | 32 | ||
33 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; | 33 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; |
34 | 34 | ||
35 | /* | ||
36 | * Allow the platform to override the allocation granularity: this allows | ||
37 | * systems that have the capability to run with a larger page size to deal | ||
38 | * with the allocations for initrd and fdt more efficiently. | ||
39 | */ | ||
40 | #ifndef EFI_ALLOC_ALIGN | ||
41 | #define EFI_ALLOC_ALIGN EFI_PAGE_SIZE | ||
42 | #endif | ||
43 | |||
44 | #define EFI_MMAP_NR_SLACK_SLOTS 8 | 35 | #define EFI_MMAP_NR_SLACK_SLOTS 8 |
45 | 36 | ||
46 | struct file_info { | 37 | struct file_info { |
@@ -186,14 +177,16 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, | |||
186 | goto fail; | 177 | goto fail; |
187 | 178 | ||
188 | /* | 179 | /* |
189 | * Enforce minimum alignment that EFI requires when requesting | 180 | * Enforce minimum alignment that EFI or Linux requires when |
190 | * a specific address. We are doing page-based allocations, | 181 | * requesting a specific address. We are doing page-based (or |
191 | * so we must be aligned to a page. | 182 | * larger) allocations, and both the address and size must meet |
183 | * alignment constraints. | ||
192 | */ | 184 | */ |
193 | if (align < EFI_ALLOC_ALIGN) | 185 | if (align < EFI_ALLOC_ALIGN) |
194 | align = EFI_ALLOC_ALIGN; | 186 | align = EFI_ALLOC_ALIGN; |
195 | 187 | ||
196 | nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; | 188 | size = round_up(size, EFI_ALLOC_ALIGN); |
189 | nr_pages = size / EFI_PAGE_SIZE; | ||
197 | again: | 190 | again: |
198 | for (i = 0; i < map_size / desc_size; i++) { | 191 | for (i = 0; i < map_size / desc_size; i++) { |
199 | efi_memory_desc_t *desc; | 192 | efi_memory_desc_t *desc; |
@@ -208,7 +201,7 @@ again: | |||
208 | continue; | 201 | continue; |
209 | 202 | ||
210 | start = desc->phys_addr; | 203 | start = desc->phys_addr; |
211 | end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); | 204 | end = start + desc->num_pages * EFI_PAGE_SIZE; |
212 | 205 | ||
213 | if (end > max) | 206 | if (end > max) |
214 | end = max; | 207 | end = max; |
@@ -278,14 +271,16 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, | |||
278 | goto fail; | 271 | goto fail; |
279 | 272 | ||
280 | /* | 273 | /* |
281 | * Enforce minimum alignment that EFI requires when requesting | 274 | * Enforce minimum alignment that EFI or Linux requires when |
282 | * a specific address. We are doing page-based allocations, | 275 | * requesting a specific address. We are doing page-based (or |
283 | * so we must be aligned to a page. | 276 | * larger) allocations, and both the address and size must meet |
277 | * alignment constraints. | ||
284 | */ | 278 | */ |
285 | if (align < EFI_ALLOC_ALIGN) | 279 | if (align < EFI_ALLOC_ALIGN) |
286 | align = EFI_ALLOC_ALIGN; | 280 | align = EFI_ALLOC_ALIGN; |
287 | 281 | ||
288 | nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; | 282 | size = round_up(size, EFI_ALLOC_ALIGN); |
283 | nr_pages = size / EFI_PAGE_SIZE; | ||
289 | for (i = 0; i < map_size / desc_size; i++) { | 284 | for (i = 0; i < map_size / desc_size; i++) { |
290 | efi_memory_desc_t *desc; | 285 | efi_memory_desc_t *desc; |
291 | unsigned long m = (unsigned long)map; | 286 | unsigned long m = (unsigned long)map; |
@@ -300,7 +295,7 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, | |||
300 | continue; | 295 | continue; |
301 | 296 | ||
302 | start = desc->phys_addr; | 297 | start = desc->phys_addr; |
303 | end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); | 298 | end = start + desc->num_pages * EFI_PAGE_SIZE; |
304 | 299 | ||
305 | /* | 300 | /* |
306 | * Don't allocate at 0x0. It will confuse code that | 301 | * Don't allocate at 0x0. It will confuse code that |
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index ee49cd23ee63..b98824e3800a 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h | |||
@@ -15,6 +15,15 @@ | |||
15 | */ | 15 | */ |
16 | #undef __init | 16 | #undef __init |
17 | 17 | ||
18 | /* | ||
19 | * Allow the platform to override the allocation granularity: this allows | ||
20 | * systems that have the capability to run with a larger page size to deal | ||
21 | * with the allocations for initrd and fdt more efficiently. | ||
22 | */ | ||
23 | #ifndef EFI_ALLOC_ALIGN | ||
24 | #define EFI_ALLOC_ALIGN EFI_PAGE_SIZE | ||
25 | #endif | ||
26 | |||
18 | void efi_char16_printk(efi_system_table_t *, efi_char16_t *); | 27 | void efi_char16_printk(efi_system_table_t *, efi_char16_t *); |
19 | 28 | ||
20 | efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, | 29 | efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, |
@@ -62,4 +71,6 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, | |||
62 | 71 | ||
63 | efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); | 72 | efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); |
64 | 73 | ||
74 | efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); | ||
75 | |||
65 | #endif | 76 | #endif |
diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index 0c9f58c5ba50..7e72954d5860 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/efi.h> | 10 | #include <linux/efi.h> |
11 | #include <linux/log2.h> | ||
11 | #include <asm/efi.h> | 12 | #include <asm/efi.h> |
12 | 13 | ||
13 | #include "efistub.h" | 14 | #include "efistub.h" |
@@ -41,21 +42,23 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg, | |||
41 | */ | 42 | */ |
42 | static unsigned long get_entry_num_slots(efi_memory_desc_t *md, | 43 | static unsigned long get_entry_num_slots(efi_memory_desc_t *md, |
43 | unsigned long size, | 44 | unsigned long size, |
44 | unsigned long align) | 45 | unsigned long align_shift) |
45 | { | 46 | { |
46 | u64 start, end; | 47 | unsigned long align = 1UL << align_shift; |
48 | u64 first_slot, last_slot, region_end; | ||
47 | 49 | ||
48 | if (md->type != EFI_CONVENTIONAL_MEMORY) | 50 | if (md->type != EFI_CONVENTIONAL_MEMORY) |
49 | return 0; | 51 | return 0; |
50 | 52 | ||
51 | start = round_up(md->phys_addr, align); | 53 | region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1); |
52 | end = round_down(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - size, | ||
53 | align); | ||
54 | 54 | ||
55 | if (start > end) | 55 | first_slot = round_up(md->phys_addr, align); |
56 | last_slot = round_down(region_end - size + 1, align); | ||
57 | |||
58 | if (first_slot > last_slot) | ||
56 | return 0; | 59 | return 0; |
57 | 60 | ||
58 | return (end - start + 1) / align; | 61 | return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1; |
59 | } | 62 | } |
60 | 63 | ||
61 | /* | 64 | /* |
@@ -98,7 +101,7 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, | |||
98 | efi_memory_desc_t *md = (void *)memory_map + map_offset; | 101 | efi_memory_desc_t *md = (void *)memory_map + map_offset; |
99 | unsigned long slots; | 102 | unsigned long slots; |
100 | 103 | ||
101 | slots = get_entry_num_slots(md, size, align); | 104 | slots = get_entry_num_slots(md, size, ilog2(align)); |
102 | MD_NUM_SLOTS(md) = slots; | 105 | MD_NUM_SLOTS(md) = slots; |
103 | total_slots += slots; | 106 | total_slots += slots; |
104 | } | 107 | } |
@@ -141,3 +144,51 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, | |||
141 | 144 | ||
142 | return status; | 145 | return status; |
143 | } | 146 | } |
147 | |||
148 | #define RANDOM_SEED_SIZE 32 | ||
149 | |||
150 | efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg) | ||
151 | { | ||
152 | efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; | ||
153 | efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW; | ||
154 | efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID; | ||
155 | struct efi_rng_protocol *rng; | ||
156 | struct linux_efi_random_seed *seed; | ||
157 | efi_status_t status; | ||
158 | |||
159 | status = efi_call_early(locate_protocol, &rng_proto, NULL, | ||
160 | (void **)&rng); | ||
161 | if (status != EFI_SUCCESS) | ||
162 | return status; | ||
163 | |||
164 | status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA, | ||
165 | sizeof(*seed) + RANDOM_SEED_SIZE, | ||
166 | (void **)&seed); | ||
167 | if (status != EFI_SUCCESS) | ||
168 | return status; | ||
169 | |||
170 | status = rng->get_rng(rng, &rng_algo_raw, RANDOM_SEED_SIZE, | ||
171 | seed->bits); | ||
172 | if (status == EFI_UNSUPPORTED) | ||
173 | /* | ||
174 | * Use whatever algorithm we have available if the raw algorithm | ||
175 | * is not implemented. | ||
176 | */ | ||
177 | status = rng->get_rng(rng, NULL, RANDOM_SEED_SIZE, | ||
178 | seed->bits); | ||
179 | |||
180 | if (status != EFI_SUCCESS) | ||
181 | goto err_freepool; | ||
182 | |||
183 | seed->size = RANDOM_SEED_SIZE; | ||
184 | status = efi_call_early(install_configuration_table, &rng_table_guid, | ||
185 | seed); | ||
186 | if (status != EFI_SUCCESS) | ||
187 | goto err_freepool; | ||
188 | |||
189 | return EFI_SUCCESS; | ||
190 | |||
191 | err_freepool: | ||
192 | efi_call_early(free_pool, seed); | ||
193 | return status; | ||
194 | } | ||
diff --git a/drivers/firmware/efi/test/efi_test.c b/drivers/firmware/efi/test/efi_test.c index f61bb52be318..8cd578f62059 100644 --- a/drivers/firmware/efi/test/efi_test.c +++ b/drivers/firmware/efi/test/efi_test.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/version.h> | ||
12 | #include <linux/miscdevice.h> | 11 | #include <linux/miscdevice.h> |
13 | #include <linux/module.h> | 12 | #include <linux/module.h> |
14 | #include <linux/init.h> | 13 | #include <linux/init.h> |
@@ -156,7 +155,7 @@ static long efi_runtime_get_variable(unsigned long arg) | |||
156 | { | 155 | { |
157 | struct efi_getvariable __user *getvariable_user; | 156 | struct efi_getvariable __user *getvariable_user; |
158 | struct efi_getvariable getvariable; | 157 | struct efi_getvariable getvariable; |
159 | unsigned long datasize, prev_datasize, *dz; | 158 | unsigned long datasize = 0, prev_datasize, *dz; |
160 | efi_guid_t vendor_guid, *vd = NULL; | 159 | efi_guid_t vendor_guid, *vd = NULL; |
161 | efi_status_t status; | 160 | efi_status_t status; |
162 | efi_char16_t *name = NULL; | 161 | efi_char16_t *name = NULL; |
@@ -266,14 +265,10 @@ static long efi_runtime_set_variable(unsigned long arg) | |||
266 | return rv; | 265 | return rv; |
267 | } | 266 | } |
268 | 267 | ||
269 | data = kmalloc(setvariable.data_size, GFP_KERNEL); | 268 | data = memdup_user(setvariable.data, setvariable.data_size); |
270 | if (!data) { | 269 | if (IS_ERR(data)) { |
271 | kfree(name); | 270 | kfree(name); |
272 | return -ENOMEM; | 271 | return PTR_ERR(data); |
273 | } | ||
274 | if (copy_from_user(data, setvariable.data, setvariable.data_size)) { | ||
275 | rv = -EFAULT; | ||
276 | goto out; | ||
277 | } | 272 | } |
278 | 273 | ||
279 | status = efi.set_variable(name, &vendor_guid, | 274 | status = efi.set_variable(name, &vendor_guid, |
@@ -429,7 +424,7 @@ static long efi_runtime_get_nextvariablename(unsigned long arg) | |||
429 | efi_guid_t *vd = NULL; | 424 | efi_guid_t *vd = NULL; |
430 | efi_guid_t vendor_guid; | 425 | efi_guid_t vendor_guid; |
431 | efi_char16_t *name = NULL; | 426 | efi_char16_t *name = NULL; |
432 | int rv; | 427 | int rv = 0; |
433 | 428 | ||
434 | getnextvariablename_user = (struct efi_getnextvariablename __user *)arg; | 429 | getnextvariablename_user = (struct efi_getnextvariablename __user *)arg; |
435 | 430 | ||
diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig index c121acc15bfe..d35db16aa43f 100644 --- a/drivers/thunderbolt/Kconfig +++ b/drivers/thunderbolt/Kconfig | |||
@@ -1,6 +1,8 @@ | |||
1 | menuconfig THUNDERBOLT | 1 | menuconfig THUNDERBOLT |
2 | tristate "Thunderbolt support for Apple devices" | 2 | tristate "Thunderbolt support for Apple devices" |
3 | depends on PCI | 3 | depends on PCI |
4 | depends on X86 || COMPILE_TEST | ||
5 | select APPLE_PROPERTIES if EFI_STUB && X86 | ||
4 | select CRC32 | 6 | select CRC32 |
5 | help | 7 | help |
6 | Cactus Ridge Thunderbolt Controller driver | 8 | Cactus Ridge Thunderbolt Controller driver |
diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index 2b9602c2c355..6392990c984d 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/crc32.h> | 7 | #include <linux/crc32.h> |
8 | #include <linux/property.h> | ||
8 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
9 | #include "tb.h" | 10 | #include "tb.h" |
10 | 11 | ||
@@ -360,6 +361,40 @@ static int tb_drom_parse_entries(struct tb_switch *sw) | |||
360 | } | 361 | } |
361 | 362 | ||
362 | /** | 363 | /** |
364 | * tb_drom_copy_efi - copy drom supplied by EFI to sw->drom if present | ||
365 | */ | ||
366 | static int tb_drom_copy_efi(struct tb_switch *sw, u16 *size) | ||
367 | { | ||
368 | struct device *dev = &sw->tb->nhi->pdev->dev; | ||
369 | int len, res; | ||
370 | |||
371 | len = device_property_read_u8_array(dev, "ThunderboltDROM", NULL, 0); | ||
372 | if (len < 0 || len < sizeof(struct tb_drom_header)) | ||
373 | return -EINVAL; | ||
374 | |||
375 | sw->drom = kmalloc(len, GFP_KERNEL); | ||
376 | if (!sw->drom) | ||
377 | return -ENOMEM; | ||
378 | |||
379 | res = device_property_read_u8_array(dev, "ThunderboltDROM", sw->drom, | ||
380 | len); | ||
381 | if (res) | ||
382 | goto err; | ||
383 | |||
384 | *size = ((struct tb_drom_header *)sw->drom)->data_len + | ||
385 | TB_DROM_DATA_START; | ||
386 | if (*size > len) | ||
387 | goto err; | ||
388 | |||
389 | return 0; | ||
390 | |||
391 | err: | ||
392 | kfree(sw->drom); | ||
393 | sw->drom = NULL; | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | /** | ||
363 | * tb_drom_read - copy drom to sw->drom and parse it | 398 | * tb_drom_read - copy drom to sw->drom and parse it |
364 | */ | 399 | */ |
365 | int tb_drom_read(struct tb_switch *sw) | 400 | int tb_drom_read(struct tb_switch *sw) |
@@ -374,6 +409,13 @@ int tb_drom_read(struct tb_switch *sw) | |||
374 | 409 | ||
375 | if (tb_route(sw) == 0) { | 410 | if (tb_route(sw) == 0) { |
376 | /* | 411 | /* |
412 | * Apple's NHI EFI driver supplies a DROM for the root switch | ||
413 | * in a device property. Use it if available. | ||
414 | */ | ||
415 | if (tb_drom_copy_efi(sw, &size) == 0) | ||
416 | goto parse; | ||
417 | |||
418 | /* | ||
377 | * The root switch contains only a dummy drom (header only, | 419 | * The root switch contains only a dummy drom (header only, |
378 | * no entries). Hardcode the configuration here. | 420 | * no entries). Hardcode the configuration here. |
379 | */ | 421 | */ |
@@ -418,6 +460,7 @@ int tb_drom_read(struct tb_switch *sw) | |||
418 | if (res) | 460 | if (res) |
419 | goto err; | 461 | goto err; |
420 | 462 | ||
463 | parse: | ||
421 | header = (void *) sw->drom; | 464 | header = (void *) sw->drom; |
422 | 465 | ||
423 | if (header->data_len + TB_DROM_DATA_START != size) { | 466 | if (header->data_len + TB_DROM_DATA_START != size) { |
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 9840fdecb73b..c6f30b1695a9 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c | |||
@@ -460,7 +460,7 @@ int tb_switch_resume(struct tb_switch *sw) | |||
460 | tb_sw_warn(sw, "uid read failed\n"); | 460 | tb_sw_warn(sw, "uid read failed\n"); |
461 | return err; | 461 | return err; |
462 | } | 462 | } |
463 | if (sw->uid != uid) { | 463 | if (sw != sw->tb->root_switch && sw->uid != uid) { |
464 | tb_sw_info(sw, | 464 | tb_sw_info(sw, |
465 | "changed while suspended (uid %#llx -> %#llx)\n", | 465 | "changed while suspended (uid %#llx -> %#llx)\n", |
466 | sw->uid, uid); | 466 | sw->uid, uid); |
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 37a37c4d04cb..8c4dc1e1f94f 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c | |||
@@ -118,6 +118,31 @@ static inline bool fb_base_is_valid(void) | |||
118 | return false; | 118 | return false; |
119 | } | 119 | } |
120 | 120 | ||
121 | #define efifb_attr_decl(name, fmt) \ | ||
122 | static ssize_t name##_show(struct device *dev, \ | ||
123 | struct device_attribute *attr, \ | ||
124 | char *buf) \ | ||
125 | { \ | ||
126 | return sprintf(buf, fmt "\n", (screen_info.lfb_##name)); \ | ||
127 | } \ | ||
128 | static DEVICE_ATTR_RO(name) | ||
129 | |||
130 | efifb_attr_decl(base, "0x%x"); | ||
131 | efifb_attr_decl(linelength, "%u"); | ||
132 | efifb_attr_decl(height, "%u"); | ||
133 | efifb_attr_decl(width, "%u"); | ||
134 | efifb_attr_decl(depth, "%u"); | ||
135 | |||
136 | static struct attribute *efifb_attrs[] = { | ||
137 | &dev_attr_base.attr, | ||
138 | &dev_attr_linelength.attr, | ||
139 | &dev_attr_width.attr, | ||
140 | &dev_attr_height.attr, | ||
141 | &dev_attr_depth.attr, | ||
142 | NULL | ||
143 | }; | ||
144 | ATTRIBUTE_GROUPS(efifb); | ||
145 | |||
121 | static int efifb_probe(struct platform_device *dev) | 146 | static int efifb_probe(struct platform_device *dev) |
122 | { | 147 | { |
123 | struct fb_info *info; | 148 | struct fb_info *info; |
@@ -205,14 +230,13 @@ static int efifb_probe(struct platform_device *dev) | |||
205 | } else { | 230 | } else { |
206 | /* We cannot make this fatal. Sometimes this comes from magic | 231 | /* We cannot make this fatal. Sometimes this comes from magic |
207 | spaces our resource handlers simply don't know about */ | 232 | spaces our resource handlers simply don't know about */ |
208 | printk(KERN_WARNING | 233 | pr_warn("efifb: cannot reserve video memory at 0x%lx\n", |
209 | "efifb: cannot reserve video memory at 0x%lx\n", | ||
210 | efifb_fix.smem_start); | 234 | efifb_fix.smem_start); |
211 | } | 235 | } |
212 | 236 | ||
213 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); | 237 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); |
214 | if (!info) { | 238 | if (!info) { |
215 | printk(KERN_ERR "efifb: cannot allocate framebuffer\n"); | 239 | pr_err("efifb: cannot allocate framebuffer\n"); |
216 | err = -ENOMEM; | 240 | err = -ENOMEM; |
217 | goto err_release_mem; | 241 | goto err_release_mem; |
218 | } | 242 | } |
@@ -230,16 +254,15 @@ static int efifb_probe(struct platform_device *dev) | |||
230 | 254 | ||
231 | info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len); | 255 | info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len); |
232 | if (!info->screen_base) { | 256 | if (!info->screen_base) { |
233 | printk(KERN_ERR "efifb: abort, cannot ioremap video memory " | 257 | pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", |
234 | "0x%x @ 0x%lx\n", | ||
235 | efifb_fix.smem_len, efifb_fix.smem_start); | 258 | efifb_fix.smem_len, efifb_fix.smem_start); |
236 | err = -EIO; | 259 | err = -EIO; |
237 | goto err_release_fb; | 260 | goto err_release_fb; |
238 | } | 261 | } |
239 | 262 | ||
240 | printk(KERN_INFO "efifb: framebuffer at 0x%lx, using %dk, total %dk\n", | 263 | pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n", |
241 | efifb_fix.smem_start, size_remap/1024, size_total/1024); | 264 | efifb_fix.smem_start, size_remap/1024, size_total/1024); |
242 | printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", | 265 | pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", |
243 | efifb_defined.xres, efifb_defined.yres, | 266 | efifb_defined.xres, efifb_defined.yres, |
244 | efifb_defined.bits_per_pixel, efifb_fix.line_length, | 267 | efifb_defined.bits_per_pixel, efifb_fix.line_length, |
245 | screen_info.pages); | 268 | screen_info.pages); |
@@ -247,7 +270,7 @@ static int efifb_probe(struct platform_device *dev) | |||
247 | efifb_defined.xres_virtual = efifb_defined.xres; | 270 | efifb_defined.xres_virtual = efifb_defined.xres; |
248 | efifb_defined.yres_virtual = efifb_fix.smem_len / | 271 | efifb_defined.yres_virtual = efifb_fix.smem_len / |
249 | efifb_fix.line_length; | 272 | efifb_fix.line_length; |
250 | printk(KERN_INFO "efifb: scrolling: redraw\n"); | 273 | pr_info("efifb: scrolling: redraw\n"); |
251 | efifb_defined.yres_virtual = efifb_defined.yres; | 274 | efifb_defined.yres_virtual = efifb_defined.yres; |
252 | 275 | ||
253 | /* some dummy values for timing to make fbset happy */ | 276 | /* some dummy values for timing to make fbset happy */ |
@@ -265,7 +288,7 @@ static int efifb_probe(struct platform_device *dev) | |||
265 | efifb_defined.transp.offset = screen_info.rsvd_pos; | 288 | efifb_defined.transp.offset = screen_info.rsvd_pos; |
266 | efifb_defined.transp.length = screen_info.rsvd_size; | 289 | efifb_defined.transp.length = screen_info.rsvd_size; |
267 | 290 | ||
268 | printk(KERN_INFO "efifb: %s: " | 291 | pr_info("efifb: %s: " |
269 | "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", | 292 | "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", |
270 | "Truecolor", | 293 | "Truecolor", |
271 | screen_info.rsvd_size, | 294 | screen_info.rsvd_size, |
@@ -285,12 +308,19 @@ static int efifb_probe(struct platform_device *dev) | |||
285 | info->fix = efifb_fix; | 308 | info->fix = efifb_fix; |
286 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; | 309 | info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; |
287 | 310 | ||
288 | if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { | 311 | err = sysfs_create_groups(&dev->dev.kobj, efifb_groups); |
289 | printk(KERN_ERR "efifb: cannot allocate colormap\n"); | 312 | if (err) { |
313 | pr_err("efifb: cannot add sysfs attrs\n"); | ||
290 | goto err_unmap; | 314 | goto err_unmap; |
291 | } | 315 | } |
292 | if ((err = register_framebuffer(info)) < 0) { | 316 | err = fb_alloc_cmap(&info->cmap, 256, 0); |
293 | printk(KERN_ERR "efifb: cannot register framebuffer\n"); | 317 | if (err < 0) { |
318 | pr_err("efifb: cannot allocate colormap\n"); | ||
319 | goto err_groups; | ||
320 | } | ||
321 | err = register_framebuffer(info); | ||
322 | if (err < 0) { | ||
323 | pr_err("efifb: cannot register framebuffer\n"); | ||
294 | goto err_fb_dealoc; | 324 | goto err_fb_dealoc; |
295 | } | 325 | } |
296 | fb_info(info, "%s frame buffer device\n", info->fix.id); | 326 | fb_info(info, "%s frame buffer device\n", info->fix.id); |
@@ -298,6 +328,8 @@ static int efifb_probe(struct platform_device *dev) | |||
298 | 328 | ||
299 | err_fb_dealoc: | 329 | err_fb_dealoc: |
300 | fb_dealloc_cmap(&info->cmap); | 330 | fb_dealloc_cmap(&info->cmap); |
331 | err_groups: | ||
332 | sysfs_remove_groups(&dev->dev.kobj, efifb_groups); | ||
301 | err_unmap: | 333 | err_unmap: |
302 | iounmap(info->screen_base); | 334 | iounmap(info->screen_base); |
303 | err_release_fb: | 335 | err_release_fb: |
@@ -313,6 +345,7 @@ static int efifb_remove(struct platform_device *pdev) | |||
313 | struct fb_info *info = platform_get_drvdata(pdev); | 345 | struct fb_info *info = platform_get_drvdata(pdev); |
314 | 346 | ||
315 | unregister_framebuffer(info); | 347 | unregister_framebuffer(info); |
348 | sysfs_remove_groups(&pdev->dev.kobj, efifb_groups); | ||
316 | framebuffer_release(info); | 349 | framebuffer_release(info); |
317 | 350 | ||
318 | return 0; | 351 | return 0; |
diff --git a/include/linux/efi.h b/include/linux/efi.h index 2d089487d2da..a07a476178cd 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -443,6 +443,22 @@ typedef struct { | |||
443 | #define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 | 443 | #define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 |
444 | #define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 | 444 | #define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 |
445 | 445 | ||
446 | typedef struct { | ||
447 | u32 version; | ||
448 | u32 get; | ||
449 | u32 set; | ||
450 | u32 del; | ||
451 | u32 get_all; | ||
452 | } apple_properties_protocol_32_t; | ||
453 | |||
454 | typedef struct { | ||
455 | u64 version; | ||
456 | u64 get; | ||
457 | u64 set; | ||
458 | u64 del; | ||
459 | u64 get_all; | ||
460 | } apple_properties_protocol_64_t; | ||
461 | |||
446 | /* | 462 | /* |
447 | * Types and defines for EFI ResetSystem | 463 | * Types and defines for EFI ResetSystem |
448 | */ | 464 | */ |
@@ -589,8 +605,10 @@ void efi_native_runtime_setup(void); | |||
589 | #define DEVICE_TREE_GUID EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) | 605 | #define DEVICE_TREE_GUID EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) |
590 | #define EFI_PROPERTIES_TABLE_GUID EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) | 606 | #define EFI_PROPERTIES_TABLE_GUID EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) |
591 | #define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) | 607 | #define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) |
608 | #define EFI_RNG_ALGORITHM_RAW EFI_GUID(0xe43176d7, 0xb6e8, 0x4827, 0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61) | ||
592 | #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) | 609 | #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) |
593 | #define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) | 610 | #define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) |
611 | #define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb, 0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0) | ||
594 | 612 | ||
595 | /* | 613 | /* |
596 | * This GUID is used to pass to the kernel proper the struct screen_info | 614 | * This GUID is used to pass to the kernel proper the struct screen_info |
@@ -599,6 +617,7 @@ void efi_native_runtime_setup(void); | |||
599 | */ | 617 | */ |
600 | #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) | 618 | #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) |
601 | #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) | 619 | #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) |
620 | #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) | ||
602 | 621 | ||
603 | typedef struct { | 622 | typedef struct { |
604 | efi_guid_t guid; | 623 | efi_guid_t guid; |
@@ -872,6 +891,7 @@ extern struct efi { | |||
872 | unsigned long esrt; /* ESRT table */ | 891 | unsigned long esrt; /* ESRT table */ |
873 | unsigned long properties_table; /* properties table */ | 892 | unsigned long properties_table; /* properties table */ |
874 | unsigned long mem_attr_table; /* memory attributes table */ | 893 | unsigned long mem_attr_table; /* memory attributes table */ |
894 | unsigned long rng_seed; /* UEFI firmware random seed */ | ||
875 | efi_get_time_t *get_time; | 895 | efi_get_time_t *get_time; |
876 | efi_set_time_t *set_time; | 896 | efi_set_time_t *set_time; |
877 | efi_get_wakeup_time_t *get_wakeup_time; | 897 | efi_get_wakeup_time_t *get_wakeup_time; |
@@ -1145,6 +1165,26 @@ struct efi_generic_dev_path { | |||
1145 | u16 length; | 1165 | u16 length; |
1146 | } __attribute ((packed)); | 1166 | } __attribute ((packed)); |
1147 | 1167 | ||
1168 | struct efi_dev_path { | ||
1169 | u8 type; /* can be replaced with unnamed */ | ||
1170 | u8 sub_type; /* struct efi_generic_dev_path; */ | ||
1171 | u16 length; /* once we've moved to -std=c11 */ | ||
1172 | union { | ||
1173 | struct { | ||
1174 | u32 hid; | ||
1175 | u32 uid; | ||
1176 | } acpi; | ||
1177 | struct { | ||
1178 | u8 fn; | ||
1179 | u8 dev; | ||
1180 | } pci; | ||
1181 | }; | ||
1182 | } __attribute ((packed)); | ||
1183 | |||
1184 | #if IS_ENABLED(CONFIG_EFI_DEV_PATH_PARSER) | ||
1185 | struct device *efi_get_device_by_path(struct efi_dev_path **node, size_t *len); | ||
1186 | #endif | ||
1187 | |||
1148 | static inline void memrange_efi_to_native(u64 *addr, u64 *npages) | 1188 | static inline void memrange_efi_to_native(u64 *addr, u64 *npages) |
1149 | { | 1189 | { |
1150 | *npages = PFN_UP(*addr + (*npages<<EFI_PAGE_SHIFT)) - PFN_DOWN(*addr); | 1190 | *npages = PFN_UP(*addr + (*npages<<EFI_PAGE_SHIFT)) - PFN_DOWN(*addr); |
@@ -1493,4 +1533,10 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table, | |||
1493 | struct efi_boot_memmap *map, | 1533 | struct efi_boot_memmap *map, |
1494 | void *priv, | 1534 | void *priv, |
1495 | efi_exit_boot_map_processing priv_func); | 1535 | efi_exit_boot_map_processing priv_func); |
1536 | |||
1537 | struct linux_efi_random_seed { | ||
1538 | u32 size; | ||
1539 | u8 bits[]; | ||
1540 | }; | ||
1541 | |||
1496 | #endif /* _LINUX_EFI_H */ | 1542 | #endif /* _LINUX_EFI_H */ |