diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-14 13:08:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-14 13:08:40 -0500 |
commit | d42b3a2906a10b732ea7d7f849d49be79d242ef0 (patch) | |
tree | 1f4f2387bf53f8015aa87eb9c05ba8316cb5ed50 | |
parent | 18dd0bf22b6f0c1bd5e4e813a42245ed86ec57b6 (diff) | |
parent | e83af1f18c78c7b6aa720beecc927ecc8afd3647 (diff) |
Merge branch 'core-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 EFI update from Peter Anvin:
"EFI tree, from Matt Fleming. Most of the patches are the new efivarfs
filesystem by Matt Garrett & co. The balance are support for EFI
wallclock in the absence of a hardware-specific driver, and various
fixes and cleanups."
* 'core-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
efivarfs: Make efivarfs_fill_super() static
x86, efi: Check table header length in efi_bgrt_init()
efivarfs: Use query_variable_info() to limit kmalloc()
efivarfs: Fix return value of efivarfs_file_write()
efivarfs: Return a consistent error when efivarfs_get_inode() fails
efivarfs: Make 'datasize' unsigned long
efivarfs: Add unique magic number
efivarfs: Replace magic number with sizeof(attributes)
efivarfs: Return an error if we fail to read a variable
efi: Clarify GUID length calculations
efivarfs: Implement exclusive access for {get,set}_variable
efivarfs: efivarfs_fill_super() ensure we clean up correctly on error
efivarfs: efivarfs_fill_super() ensure we free our temporary name
efivarfs: efivarfs_fill_super() fix inode reference counts
efivarfs: efivarfs_create() ensure we drop our reference on inode on error
efivarfs: efivarfs_file_read ensure we free data in error paths
x86-64/efi: Use EFI to deal with platform wall clock (again)
x86/kernel: remove tboot 1:1 page table creation code
x86, efi: 1:1 pagetable mapping for virtual EFI calls
x86, mm: Include the entire kernel memory map in trampoline_pgd
...
-rw-r--r-- | Documentation/filesystems/00-INDEX | 2 | ||||
-rw-r--r-- | Documentation/filesystems/efivarfs.txt | 16 | ||||
-rw-r--r-- | arch/x86/include/asm/efi.h | 28 | ||||
-rw-r--r-- | arch/x86/kernel/tboot.c | 78 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 9 | ||||
-rw-r--r-- | arch/x86/mm/ioremap.c | 105 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 10 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi-bgrt.c | 2 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi.c | 30 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_64.c | 15 | ||||
-rw-r--r-- | arch/x86/realmode/init.c | 17 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 512 | ||||
-rw-r--r-- | include/linux/efi.h | 8 | ||||
-rw-r--r-- | include/uapi/linux/magic.h | 1 | ||||
-rw-r--r-- | init/main.c | 8 |
15 files changed, 714 insertions, 127 deletions
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index 8c624a18f67d..7b52ba7bf32a 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX | |||
@@ -38,6 +38,8 @@ dnotify_test.c | |||
38 | - example program for dnotify | 38 | - example program for dnotify |
39 | ecryptfs.txt | 39 | ecryptfs.txt |
40 | - docs on eCryptfs: stacked cryptographic filesystem for Linux. | 40 | - docs on eCryptfs: stacked cryptographic filesystem for Linux. |
41 | efivarfs.txt | ||
42 | - info for the efivarfs filesystem. | ||
41 | exofs.txt | 43 | exofs.txt |
42 | - info, usage, mount options, design about EXOFS. | 44 | - info, usage, mount options, design about EXOFS. |
43 | ext2.txt | 45 | ext2.txt |
diff --git a/Documentation/filesystems/efivarfs.txt b/Documentation/filesystems/efivarfs.txt new file mode 100644 index 000000000000..c477af086e65 --- /dev/null +++ b/Documentation/filesystems/efivarfs.txt | |||
@@ -0,0 +1,16 @@ | |||
1 | |||
2 | efivarfs - a (U)EFI variable filesystem | ||
3 | |||
4 | The efivarfs filesystem was created to address the shortcomings of | ||
5 | using entries in sysfs to maintain EFI variables. The old sysfs EFI | ||
6 | variables code only supported variables of up to 1024 bytes. This | ||
7 | limitation existed in version 0.99 of the EFI specification, but was | ||
8 | removed before any full releases. Since variables can now be larger | ||
9 | than a single page, sysfs isn't the best interface for this. | ||
10 | |||
11 | Variables can be created, deleted and modified with the efivarfs | ||
12 | filesystem. | ||
13 | |||
14 | efivarfs is typically mounted like this, | ||
15 | |||
16 | mount -t efivarfs none /sys/firmware/efi/efivars | ||
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 6e8fdf5ad113..fd13815fe85c 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h | |||
@@ -69,23 +69,37 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3, | |||
69 | efi_call6((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3), \ | 69 | efi_call6((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3), \ |
70 | (u64)(a4), (u64)(a5), (u64)(a6)) | 70 | (u64)(a4), (u64)(a5), (u64)(a6)) |
71 | 71 | ||
72 | extern unsigned long efi_call_virt_prelog(void); | ||
73 | extern void efi_call_virt_epilog(unsigned long); | ||
74 | |||
75 | #define efi_callx(x, func, ...) \ | ||
76 | ({ \ | ||
77 | efi_status_t __status; \ | ||
78 | unsigned long __pgd; \ | ||
79 | \ | ||
80 | __pgd = efi_call_virt_prelog(); \ | ||
81 | __status = efi_call##x(func, __VA_ARGS__); \ | ||
82 | efi_call_virt_epilog(__pgd); \ | ||
83 | __status; \ | ||
84 | }) | ||
85 | |||
72 | #define efi_call_virt0(f) \ | 86 | #define efi_call_virt0(f) \ |
73 | efi_call0((void *)(efi.systab->runtime->f)) | 87 | efi_callx(0, (void *)(efi.systab->runtime->f)) |
74 | #define efi_call_virt1(f, a1) \ | 88 | #define efi_call_virt1(f, a1) \ |
75 | efi_call1((void *)(efi.systab->runtime->f), (u64)(a1)) | 89 | efi_callx(1, (void *)(efi.systab->runtime->f), (u64)(a1)) |
76 | #define efi_call_virt2(f, a1, a2) \ | 90 | #define efi_call_virt2(f, a1, a2) \ |
77 | efi_call2((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2)) | 91 | efi_callx(2, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2)) |
78 | #define efi_call_virt3(f, a1, a2, a3) \ | 92 | #define efi_call_virt3(f, a1, a2, a3) \ |
79 | efi_call3((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ | 93 | efi_callx(3, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ |
80 | (u64)(a3)) | 94 | (u64)(a3)) |
81 | #define efi_call_virt4(f, a1, a2, a3, a4) \ | 95 | #define efi_call_virt4(f, a1, a2, a3, a4) \ |
82 | efi_call4((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ | 96 | efi_callx(4, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ |
83 | (u64)(a3), (u64)(a4)) | 97 | (u64)(a3), (u64)(a4)) |
84 | #define efi_call_virt5(f, a1, a2, a3, a4, a5) \ | 98 | #define efi_call_virt5(f, a1, a2, a3, a4, a5) \ |
85 | efi_call5((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ | 99 | efi_callx(5, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ |
86 | (u64)(a3), (u64)(a4), (u64)(a5)) | 100 | (u64)(a3), (u64)(a4), (u64)(a5)) |
87 | #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ | 101 | #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ |
88 | efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ | 102 | efi_callx(6, (void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \ |
89 | (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) | 103 | (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) |
90 | 104 | ||
91 | extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, | 105 | extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, |
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index f84fe00fad48..d4f460f962ee 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c | |||
@@ -103,71 +103,13 @@ void __init tboot_probe(void) | |||
103 | pr_debug("tboot_size: 0x%x\n", tboot->tboot_size); | 103 | pr_debug("tboot_size: 0x%x\n", tboot->tboot_size); |
104 | } | 104 | } |
105 | 105 | ||
106 | static pgd_t *tboot_pg_dir; | ||
107 | static struct mm_struct tboot_mm = { | ||
108 | .mm_rb = RB_ROOT, | ||
109 | .pgd = swapper_pg_dir, | ||
110 | .mm_users = ATOMIC_INIT(2), | ||
111 | .mm_count = ATOMIC_INIT(1), | ||
112 | .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem), | ||
113 | .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), | ||
114 | .mmlist = LIST_HEAD_INIT(init_mm.mmlist), | ||
115 | }; | ||
116 | |||
117 | static inline void switch_to_tboot_pt(void) | 106 | static inline void switch_to_tboot_pt(void) |
118 | { | 107 | { |
119 | write_cr3(virt_to_phys(tboot_pg_dir)); | 108 | #ifdef CONFIG_X86_32 |
120 | } | 109 | load_cr3(initial_page_table); |
121 | 110 | #else | |
122 | static int map_tboot_page(unsigned long vaddr, unsigned long pfn, | 111 | write_cr3(real_mode_header->trampoline_pgd); |
123 | pgprot_t prot) | 112 | #endif |
124 | { | ||
125 | pgd_t *pgd; | ||
126 | pud_t *pud; | ||
127 | pmd_t *pmd; | ||
128 | pte_t *pte; | ||
129 | |||
130 | pgd = pgd_offset(&tboot_mm, vaddr); | ||
131 | pud = pud_alloc(&tboot_mm, pgd, vaddr); | ||
132 | if (!pud) | ||
133 | return -1; | ||
134 | pmd = pmd_alloc(&tboot_mm, pud, vaddr); | ||
135 | if (!pmd) | ||
136 | return -1; | ||
137 | pte = pte_alloc_map(&tboot_mm, NULL, pmd, vaddr); | ||
138 | if (!pte) | ||
139 | return -1; | ||
140 | set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot)); | ||
141 | pte_unmap(pte); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int map_tboot_pages(unsigned long vaddr, unsigned long start_pfn, | ||
146 | unsigned long nr) | ||
147 | { | ||
148 | /* Reuse the original kernel mapping */ | ||
149 | tboot_pg_dir = pgd_alloc(&tboot_mm); | ||
150 | if (!tboot_pg_dir) | ||
151 | return -1; | ||
152 | |||
153 | for (; nr > 0; nr--, vaddr += PAGE_SIZE, start_pfn++) { | ||
154 | if (map_tboot_page(vaddr, start_pfn, PAGE_KERNEL_EXEC)) | ||
155 | return -1; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void tboot_create_trampoline(void) | ||
162 | { | ||
163 | u32 map_base, map_size; | ||
164 | |||
165 | /* Create identity map for tboot shutdown code. */ | ||
166 | map_base = PFN_DOWN(tboot->tboot_base); | ||
167 | map_size = PFN_UP(tboot->tboot_size); | ||
168 | if (map_tboot_pages(map_base << PAGE_SHIFT, map_base, map_size)) | ||
169 | panic("tboot: Error mapping tboot pages (mfns) @ 0x%x, 0x%x\n", | ||
170 | map_base, map_size); | ||
171 | } | 113 | } |
172 | 114 | ||
173 | #ifdef CONFIG_ACPI_SLEEP | 115 | #ifdef CONFIG_ACPI_SLEEP |
@@ -225,14 +167,6 @@ void tboot_shutdown(u32 shutdown_type) | |||
225 | if (!tboot_enabled()) | 167 | if (!tboot_enabled()) |
226 | return; | 168 | return; |
227 | 169 | ||
228 | /* | ||
229 | * if we're being called before the 1:1 mapping is set up then just | ||
230 | * return and let the normal shutdown happen; this should only be | ||
231 | * due to very early panic() | ||
232 | */ | ||
233 | if (!tboot_pg_dir) | ||
234 | return; | ||
235 | |||
236 | /* if this is S3 then set regions to MAC */ | 170 | /* if this is S3 then set regions to MAC */ |
237 | if (shutdown_type == TB_SHUTDOWN_S3) | 171 | if (shutdown_type == TB_SHUTDOWN_S3) |
238 | if (tboot_setup_sleep()) | 172 | if (tboot_setup_sleep()) |
@@ -343,8 +277,6 @@ static __init int tboot_late_init(void) | |||
343 | if (!tboot_enabled()) | 277 | if (!tboot_enabled()) |
344 | return 0; | 278 | return 0; |
345 | 279 | ||
346 | tboot_create_trampoline(); | ||
347 | |||
348 | atomic_set(&ap_wfs_count, 0); | 280 | atomic_set(&ap_wfs_count, 0); |
349 | register_hotcpu_notifier(&tboot_cpu_notifier); | 281 | register_hotcpu_notifier(&tboot_cpu_notifier); |
350 | 282 | ||
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 2ead3c8a4c84..07519a120449 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -108,13 +108,13 @@ void sync_global_pgds(unsigned long start, unsigned long end) | |||
108 | for (address = start; address <= end; address += PGDIR_SIZE) { | 108 | for (address = start; address <= end; address += PGDIR_SIZE) { |
109 | const pgd_t *pgd_ref = pgd_offset_k(address); | 109 | const pgd_t *pgd_ref = pgd_offset_k(address); |
110 | struct page *page; | 110 | struct page *page; |
111 | pgd_t *pgd; | ||
111 | 112 | ||
112 | if (pgd_none(*pgd_ref)) | 113 | if (pgd_none(*pgd_ref)) |
113 | continue; | 114 | continue; |
114 | 115 | ||
115 | spin_lock(&pgd_lock); | 116 | spin_lock(&pgd_lock); |
116 | list_for_each_entry(page, &pgd_list, lru) { | 117 | list_for_each_entry(page, &pgd_list, lru) { |
117 | pgd_t *pgd; | ||
118 | spinlock_t *pgt_lock; | 118 | spinlock_t *pgt_lock; |
119 | 119 | ||
120 | pgd = (pgd_t *)page_address(page) + pgd_index(address); | 120 | pgd = (pgd_t *)page_address(page) + pgd_index(address); |
@@ -130,6 +130,13 @@ void sync_global_pgds(unsigned long start, unsigned long end) | |||
130 | 130 | ||
131 | spin_unlock(pgt_lock); | 131 | spin_unlock(pgt_lock); |
132 | } | 132 | } |
133 | |||
134 | pgd = __va(real_mode_header->trampoline_pgd); | ||
135 | pgd += pgd_index(address); | ||
136 | |||
137 | if (pgd_none(*pgd)) | ||
138 | set_pgd(pgd, *pgd_ref); | ||
139 | |||
133 | spin_unlock(&pgd_lock); | 140 | spin_unlock(&pgd_lock); |
134 | } | 141 | } |
135 | } | 142 | } |
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 78fe3f1ac49f..e190f7b56653 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -50,6 +50,107 @@ int ioremap_change_attr(unsigned long vaddr, unsigned long size, | |||
50 | return err; | 50 | return err; |
51 | } | 51 | } |
52 | 52 | ||
53 | #ifdef CONFIG_X86_64 | ||
54 | static void ident_pte_range(unsigned long paddr, unsigned long vaddr, | ||
55 | pmd_t *ppmd, pmd_t *vpmd, unsigned long end) | ||
56 | { | ||
57 | pte_t *ppte = pte_offset_kernel(ppmd, paddr); | ||
58 | pte_t *vpte = pte_offset_kernel(vpmd, vaddr); | ||
59 | |||
60 | do { | ||
61 | set_pte(ppte, *vpte); | ||
62 | } while (ppte++, vpte++, vaddr += PAGE_SIZE, vaddr != end); | ||
63 | } | ||
64 | |||
65 | static int ident_pmd_range(unsigned long paddr, unsigned long vaddr, | ||
66 | pud_t *ppud, pud_t *vpud, unsigned long end) | ||
67 | { | ||
68 | pmd_t *ppmd = pmd_offset(ppud, paddr); | ||
69 | pmd_t *vpmd = pmd_offset(vpud, vaddr); | ||
70 | unsigned long next; | ||
71 | |||
72 | do { | ||
73 | next = pmd_addr_end(vaddr, end); | ||
74 | |||
75 | if (!pmd_present(*ppmd)) { | ||
76 | pte_t *ppte = (pte_t *)get_zeroed_page(GFP_KERNEL); | ||
77 | if (!ppte) | ||
78 | return 1; | ||
79 | |||
80 | set_pmd(ppmd, __pmd(_KERNPG_TABLE | __pa(ppte))); | ||
81 | } | ||
82 | |||
83 | ident_pte_range(paddr, vaddr, ppmd, vpmd, next); | ||
84 | } while (ppmd++, vpmd++, vaddr = next, vaddr != end); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int ident_pud_range(unsigned long paddr, unsigned long vaddr, | ||
90 | pgd_t *ppgd, pgd_t *vpgd, unsigned long end) | ||
91 | { | ||
92 | pud_t *ppud = pud_offset(ppgd, paddr); | ||
93 | pud_t *vpud = pud_offset(vpgd, vaddr); | ||
94 | unsigned long next; | ||
95 | |||
96 | do { | ||
97 | next = pud_addr_end(vaddr, end); | ||
98 | |||
99 | if (!pud_present(*ppud)) { | ||
100 | pmd_t *ppmd = (pmd_t *)get_zeroed_page(GFP_KERNEL); | ||
101 | if (!ppmd) | ||
102 | return 1; | ||
103 | |||
104 | set_pud(ppud, __pud(_KERNPG_TABLE | __pa(ppmd))); | ||
105 | } | ||
106 | |||
107 | if (ident_pmd_range(paddr, vaddr, ppud, vpud, next)) | ||
108 | return 1; | ||
109 | } while (ppud++, vpud++, vaddr = next, vaddr != end); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int insert_identity_mapping(resource_size_t paddr, unsigned long vaddr, | ||
115 | unsigned long size) | ||
116 | { | ||
117 | unsigned long end = vaddr + size; | ||
118 | unsigned long next; | ||
119 | pgd_t *vpgd, *ppgd; | ||
120 | |||
121 | /* Don't map over the guard hole. */ | ||
122 | if (paddr >= 0x800000000000 || paddr + size > 0x800000000000) | ||
123 | return 1; | ||
124 | |||
125 | ppgd = __va(real_mode_header->trampoline_pgd) + pgd_index(paddr); | ||
126 | |||
127 | vpgd = pgd_offset_k(vaddr); | ||
128 | do { | ||
129 | next = pgd_addr_end(vaddr, end); | ||
130 | |||
131 | if (!pgd_present(*ppgd)) { | ||
132 | pud_t *ppud = (pud_t *)get_zeroed_page(GFP_KERNEL); | ||
133 | if (!ppud) | ||
134 | return 1; | ||
135 | |||
136 | set_pgd(ppgd, __pgd(_KERNPG_TABLE | __pa(ppud))); | ||
137 | } | ||
138 | |||
139 | if (ident_pud_range(paddr, vaddr, ppgd, vpgd, next)) | ||
140 | return 1; | ||
141 | } while (ppgd++, vpgd++, vaddr = next, vaddr != end); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | #else | ||
146 | static inline int insert_identity_mapping(resource_size_t paddr, | ||
147 | unsigned long vaddr, | ||
148 | unsigned long size) | ||
149 | { | ||
150 | return 0; | ||
151 | } | ||
152 | #endif /* CONFIG_X86_64 */ | ||
153 | |||
53 | /* | 154 | /* |
54 | * Remap an arbitrary physical address space into the kernel virtual | 155 | * Remap an arbitrary physical address space into the kernel virtual |
55 | * address space. Needed when the kernel wants to access high addresses | 156 | * address space. Needed when the kernel wants to access high addresses |
@@ -163,6 +264,10 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
163 | ret_addr = (void __iomem *) (vaddr + offset); | 264 | ret_addr = (void __iomem *) (vaddr + offset); |
164 | mmiotrace_ioremap(unaligned_phys_addr, unaligned_size, ret_addr); | 265 | mmiotrace_ioremap(unaligned_phys_addr, unaligned_size, ret_addr); |
165 | 266 | ||
267 | if (insert_identity_mapping(phys_addr, vaddr, size)) | ||
268 | printk(KERN_WARNING "ioremap: unable to map 0x%llx in identity pagetable\n", | ||
269 | (unsigned long long)phys_addr); | ||
270 | |||
166 | /* | 271 | /* |
167 | * Check if the request spans more than any BAR in the iomem resource | 272 | * Check if the request spans more than any BAR in the iomem resource |
168 | * tree. | 273 | * tree. |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index a718e0d23503..931930a96160 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -919,11 +919,13 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages, | |||
919 | 919 | ||
920 | /* | 920 | /* |
921 | * On success we use clflush, when the CPU supports it to | 921 | * On success we use clflush, when the CPU supports it to |
922 | * avoid the wbindv. If the CPU does not support it and in the | 922 | * avoid the wbindv. If the CPU does not support it, in the |
923 | * error case we fall back to cpa_flush_all (which uses | 923 | * error case, and during early boot (for EFI) we fall back |
924 | * wbindv): | 924 | * to cpa_flush_all (which uses wbinvd): |
925 | */ | 925 | */ |
926 | if (!ret && cpu_has_clflush) { | 926 | if (early_boot_irqs_disabled) |
927 | __cpa_flush_all((void *)(long)cache); | ||
928 | else if (!ret && cpu_has_clflush) { | ||
927 | if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) { | 929 | if (cpa.flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) { |
928 | cpa_flush_array(addr, numpages, cache, | 930 | cpa_flush_array(addr, numpages, cache, |
929 | cpa.flags, pages); | 931 | cpa.flags, pages); |
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index f6a0c1b8e518..d9c1b95af17c 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c | |||
@@ -39,6 +39,8 @@ void efi_bgrt_init(void) | |||
39 | if (ACPI_FAILURE(status)) | 39 | if (ACPI_FAILURE(status)) |
40 | return; | 40 | return; |
41 | 41 | ||
42 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) | ||
43 | return; | ||
42 | if (bgrt_tab->version != 1) | 44 | if (bgrt_tab->version != 1) |
43 | return; | 45 | return; |
44 | if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) | 46 | if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) |
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index ad4439145f85..0a34d9e9c263 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -239,22 +239,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map( | |||
239 | return status; | 239 | return status; |
240 | } | 240 | } |
241 | 241 | ||
242 | static efi_status_t __init phys_efi_get_time(efi_time_t *tm, | 242 | static int efi_set_rtc_mmss(unsigned long nowtime) |
243 | efi_time_cap_t *tc) | ||
244 | { | ||
245 | unsigned long flags; | ||
246 | efi_status_t status; | ||
247 | |||
248 | spin_lock_irqsave(&rtc_lock, flags); | ||
249 | efi_call_phys_prelog(); | ||
250 | status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm), | ||
251 | virt_to_phys(tc)); | ||
252 | efi_call_phys_epilog(); | ||
253 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
254 | return status; | ||
255 | } | ||
256 | |||
257 | int efi_set_rtc_mmss(unsigned long nowtime) | ||
258 | { | 243 | { |
259 | int real_seconds, real_minutes; | 244 | int real_seconds, real_minutes; |
260 | efi_status_t status; | 245 | efi_status_t status; |
@@ -283,7 +268,7 @@ int efi_set_rtc_mmss(unsigned long nowtime) | |||
283 | return 0; | 268 | return 0; |
284 | } | 269 | } |
285 | 270 | ||
286 | unsigned long efi_get_time(void) | 271 | static unsigned long efi_get_time(void) |
287 | { | 272 | { |
288 | efi_status_t status; | 273 | efi_status_t status; |
289 | efi_time_t eft; | 274 | efi_time_t eft; |
@@ -639,18 +624,13 @@ static int __init efi_runtime_init(void) | |||
639 | } | 624 | } |
640 | /* | 625 | /* |
641 | * We will only need *early* access to the following | 626 | * We will only need *early* access to the following |
642 | * two EFI runtime services before set_virtual_address_map | 627 | * EFI runtime service before set_virtual_address_map |
643 | * is invoked. | 628 | * is invoked. |
644 | */ | 629 | */ |
645 | efi_phys.get_time = (efi_get_time_t *)runtime->get_time; | ||
646 | efi_phys.set_virtual_address_map = | 630 | efi_phys.set_virtual_address_map = |
647 | (efi_set_virtual_address_map_t *) | 631 | (efi_set_virtual_address_map_t *) |
648 | runtime->set_virtual_address_map; | 632 | runtime->set_virtual_address_map; |
649 | /* | 633 | |
650 | * Make efi_get_time can be called before entering | ||
651 | * virtual mode. | ||
652 | */ | ||
653 | efi.get_time = phys_efi_get_time; | ||
654 | early_iounmap(runtime, sizeof(efi_runtime_services_t)); | 634 | early_iounmap(runtime, sizeof(efi_runtime_services_t)); |
655 | 635 | ||
656 | return 0; | 636 | return 0; |
@@ -736,12 +716,10 @@ void __init efi_init(void) | |||
736 | efi_enabled = 0; | 716 | efi_enabled = 0; |
737 | return; | 717 | return; |
738 | } | 718 | } |
739 | #ifdef CONFIG_X86_32 | ||
740 | if (efi_is_native()) { | 719 | if (efi_is_native()) { |
741 | x86_platform.get_wallclock = efi_get_time; | 720 | x86_platform.get_wallclock = efi_get_time; |
742 | x86_platform.set_wallclock = efi_set_rtc_mmss; | 721 | x86_platform.set_wallclock = efi_set_rtc_mmss; |
743 | } | 722 | } |
744 | #endif | ||
745 | 723 | ||
746 | #if EFI_DEBUG | 724 | #if EFI_DEBUG |
747 | print_efi_memmap(); | 725 | print_efi_memmap(); |
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 95fd505dfeb6..06c8b2e662ab 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
@@ -58,6 +58,21 @@ static void __init early_code_mapping_set_exec(int executable) | |||
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
61 | unsigned long efi_call_virt_prelog(void) | ||
62 | { | ||
63 | unsigned long saved; | ||
64 | |||
65 | saved = read_cr3(); | ||
66 | write_cr3(real_mode_header->trampoline_pgd); | ||
67 | |||
68 | return saved; | ||
69 | } | ||
70 | |||
71 | void efi_call_virt_epilog(unsigned long saved) | ||
72 | { | ||
73 | write_cr3(saved); | ||
74 | } | ||
75 | |||
61 | void __init efi_call_phys_prelog(void) | 76 | void __init efi_call_phys_prelog(void) |
62 | { | 77 | { |
63 | unsigned long vaddress; | 78 | unsigned long vaddress; |
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index cbca565af5bd..8e6ab6137852 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c | |||
@@ -78,8 +78,21 @@ void __init setup_real_mode(void) | |||
78 | *trampoline_cr4_features = read_cr4(); | 78 | *trampoline_cr4_features = read_cr4(); |
79 | 79 | ||
80 | trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); | 80 | trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); |
81 | trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; | 81 | |
82 | trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; | 82 | /* |
83 | * Create an identity mapping for all of physical memory. | ||
84 | */ | ||
85 | for (i = 0; i <= pgd_index(max_pfn << PAGE_SHIFT); i++) { | ||
86 | int index = pgd_index(PAGE_OFFSET) + i; | ||
87 | |||
88 | trampoline_pgd[i] = (u64)pgd_val(swapper_pg_dir[index]); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Copy the upper-half of the kernel pages tables. | ||
93 | */ | ||
94 | for (i = pgd_index(PAGE_OFFSET); i < PTRS_PER_PGD; i++) | ||
95 | trampoline_pgd[i] = (u64)pgd_val(swapper_pg_dir[i]); | ||
83 | #endif | 96 | #endif |
84 | } | 97 | } |
85 | 98 | ||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 6e51c1e81f14..52c5d8956d7d 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
@@ -80,6 +80,10 @@ | |||
80 | #include <linux/slab.h> | 80 | #include <linux/slab.h> |
81 | #include <linux/pstore.h> | 81 | #include <linux/pstore.h> |
82 | 82 | ||
83 | #include <linux/fs.h> | ||
84 | #include <linux/ramfs.h> | ||
85 | #include <linux/pagemap.h> | ||
86 | |||
83 | #include <asm/uaccess.h> | 87 | #include <asm/uaccess.h> |
84 | 88 | ||
85 | #define EFIVARS_VERSION "0.08" | 89 | #define EFIVARS_VERSION "0.08" |
@@ -93,6 +97,12 @@ MODULE_VERSION(EFIVARS_VERSION); | |||
93 | #define DUMP_NAME_LEN 52 | 97 | #define DUMP_NAME_LEN 52 |
94 | 98 | ||
95 | /* | 99 | /* |
100 | * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")) | ||
101 | * not including trailing NUL | ||
102 | */ | ||
103 | #define GUID_LEN 36 | ||
104 | |||
105 | /* | ||
96 | * The maximum size of VariableName + Data = 1024 | 106 | * The maximum size of VariableName + Data = 1024 |
97 | * Therefore, it's reasonable to save that much | 107 | * Therefore, it's reasonable to save that much |
98 | * space in each part of the structure, | 108 | * space in each part of the structure, |
@@ -108,7 +118,6 @@ struct efi_variable { | |||
108 | __u32 Attributes; | 118 | __u32 Attributes; |
109 | } __attribute__((packed)); | 119 | } __attribute__((packed)); |
110 | 120 | ||
111 | |||
112 | struct efivar_entry { | 121 | struct efivar_entry { |
113 | struct efivars *efivars; | 122 | struct efivars *efivars; |
114 | struct efi_variable var; | 123 | struct efi_variable var; |
@@ -122,6 +131,9 @@ struct efivar_attribute { | |||
122 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); | 131 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); |
123 | }; | 132 | }; |
124 | 133 | ||
134 | static struct efivars __efivars; | ||
135 | static struct efivar_operations ops; | ||
136 | |||
125 | #define PSTORE_EFI_ATTRIBUTES \ | 137 | #define PSTORE_EFI_ATTRIBUTES \ |
126 | (EFI_VARIABLE_NON_VOLATILE | \ | 138 | (EFI_VARIABLE_NON_VOLATILE | \ |
127 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ | 139 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ |
@@ -629,14 +641,482 @@ static struct kobj_type efivar_ktype = { | |||
629 | .default_attrs = def_attrs, | 641 | .default_attrs = def_attrs, |
630 | }; | 642 | }; |
631 | 643 | ||
632 | static struct pstore_info efi_pstore_info; | ||
633 | |||
634 | static inline void | 644 | static inline void |
635 | efivar_unregister(struct efivar_entry *var) | 645 | efivar_unregister(struct efivar_entry *var) |
636 | { | 646 | { |
637 | kobject_put(&var->kobj); | 647 | kobject_put(&var->kobj); |
638 | } | 648 | } |
639 | 649 | ||
650 | static int efivarfs_file_open(struct inode *inode, struct file *file) | ||
651 | { | ||
652 | file->private_data = inode->i_private; | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static int efi_status_to_err(efi_status_t status) | ||
657 | { | ||
658 | int err; | ||
659 | |||
660 | switch (status) { | ||
661 | case EFI_INVALID_PARAMETER: | ||
662 | err = -EINVAL; | ||
663 | break; | ||
664 | case EFI_OUT_OF_RESOURCES: | ||
665 | err = -ENOSPC; | ||
666 | break; | ||
667 | case EFI_DEVICE_ERROR: | ||
668 | err = -EIO; | ||
669 | break; | ||
670 | case EFI_WRITE_PROTECTED: | ||
671 | err = -EROFS; | ||
672 | break; | ||
673 | case EFI_SECURITY_VIOLATION: | ||
674 | err = -EACCES; | ||
675 | break; | ||
676 | case EFI_NOT_FOUND: | ||
677 | err = -ENOENT; | ||
678 | break; | ||
679 | default: | ||
680 | err = -EINVAL; | ||
681 | } | ||
682 | |||
683 | return err; | ||
684 | } | ||
685 | |||
686 | static ssize_t efivarfs_file_write(struct file *file, | ||
687 | const char __user *userbuf, size_t count, loff_t *ppos) | ||
688 | { | ||
689 | struct efivar_entry *var = file->private_data; | ||
690 | struct efivars *efivars; | ||
691 | efi_status_t status; | ||
692 | void *data; | ||
693 | u32 attributes; | ||
694 | struct inode *inode = file->f_mapping->host; | ||
695 | unsigned long datasize = count - sizeof(attributes); | ||
696 | unsigned long newdatasize; | ||
697 | u64 storage_size, remaining_size, max_size; | ||
698 | ssize_t bytes = 0; | ||
699 | |||
700 | if (count < sizeof(attributes)) | ||
701 | return -EINVAL; | ||
702 | |||
703 | if (copy_from_user(&attributes, userbuf, sizeof(attributes))) | ||
704 | return -EFAULT; | ||
705 | |||
706 | if (attributes & ~(EFI_VARIABLE_MASK)) | ||
707 | return -EINVAL; | ||
708 | |||
709 | efivars = var->efivars; | ||
710 | |||
711 | /* | ||
712 | * Ensure that the user can't allocate arbitrarily large | ||
713 | * amounts of memory. Pick a default size of 64K if | ||
714 | * QueryVariableInfo() isn't supported by the firmware. | ||
715 | */ | ||
716 | spin_lock(&efivars->lock); | ||
717 | |||
718 | if (!efivars->ops->query_variable_info) | ||
719 | status = EFI_UNSUPPORTED; | ||
720 | else { | ||
721 | const struct efivar_operations *fops = efivars->ops; | ||
722 | status = fops->query_variable_info(attributes, &storage_size, | ||
723 | &remaining_size, &max_size); | ||
724 | } | ||
725 | |||
726 | spin_unlock(&efivars->lock); | ||
727 | |||
728 | if (status != EFI_SUCCESS) { | ||
729 | if (status != EFI_UNSUPPORTED) | ||
730 | return efi_status_to_err(status); | ||
731 | |||
732 | remaining_size = 65536; | ||
733 | } | ||
734 | |||
735 | if (datasize > remaining_size) | ||
736 | return -ENOSPC; | ||
737 | |||
738 | data = kmalloc(datasize, GFP_KERNEL); | ||
739 | if (!data) | ||
740 | return -ENOMEM; | ||
741 | |||
742 | if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) { | ||
743 | bytes = -EFAULT; | ||
744 | goto out; | ||
745 | } | ||
746 | |||
747 | if (validate_var(&var->var, data, datasize) == false) { | ||
748 | bytes = -EINVAL; | ||
749 | goto out; | ||
750 | } | ||
751 | |||
752 | /* | ||
753 | * The lock here protects the get_variable call, the conditional | ||
754 | * set_variable call, and removal of the variable from the efivars | ||
755 | * list (in the case of an authenticated delete). | ||
756 | */ | ||
757 | spin_lock(&efivars->lock); | ||
758 | |||
759 | status = efivars->ops->set_variable(var->var.VariableName, | ||
760 | &var->var.VendorGuid, | ||
761 | attributes, datasize, | ||
762 | data); | ||
763 | |||
764 | if (status != EFI_SUCCESS) { | ||
765 | spin_unlock(&efivars->lock); | ||
766 | kfree(data); | ||
767 | |||
768 | return efi_status_to_err(status); | ||
769 | } | ||
770 | |||
771 | bytes = count; | ||
772 | |||
773 | /* | ||
774 | * Writing to the variable may have caused a change in size (which | ||
775 | * could either be an append or an overwrite), or the variable to be | ||
776 | * deleted. Perform a GetVariable() so we can tell what actually | ||
777 | * happened. | ||
778 | */ | ||
779 | newdatasize = 0; | ||
780 | status = efivars->ops->get_variable(var->var.VariableName, | ||
781 | &var->var.VendorGuid, | ||
782 | NULL, &newdatasize, | ||
783 | NULL); | ||
784 | |||
785 | if (status == EFI_BUFFER_TOO_SMALL) { | ||
786 | spin_unlock(&efivars->lock); | ||
787 | mutex_lock(&inode->i_mutex); | ||
788 | i_size_write(inode, newdatasize + sizeof(attributes)); | ||
789 | mutex_unlock(&inode->i_mutex); | ||
790 | |||
791 | } else if (status == EFI_NOT_FOUND) { | ||
792 | list_del(&var->list); | ||
793 | spin_unlock(&efivars->lock); | ||
794 | efivar_unregister(var); | ||
795 | drop_nlink(inode); | ||
796 | dput(file->f_dentry); | ||
797 | |||
798 | } else { | ||
799 | spin_unlock(&efivars->lock); | ||
800 | pr_warn("efivarfs: inconsistent EFI variable implementation? " | ||
801 | "status = %lx\n", status); | ||
802 | } | ||
803 | |||
804 | out: | ||
805 | kfree(data); | ||
806 | |||
807 | return bytes; | ||
808 | } | ||
809 | |||
810 | static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, | ||
811 | size_t count, loff_t *ppos) | ||
812 | { | ||
813 | struct efivar_entry *var = file->private_data; | ||
814 | struct efivars *efivars = var->efivars; | ||
815 | efi_status_t status; | ||
816 | unsigned long datasize = 0; | ||
817 | u32 attributes; | ||
818 | void *data; | ||
819 | ssize_t size = 0; | ||
820 | |||
821 | spin_lock(&efivars->lock); | ||
822 | status = efivars->ops->get_variable(var->var.VariableName, | ||
823 | &var->var.VendorGuid, | ||
824 | &attributes, &datasize, NULL); | ||
825 | spin_unlock(&efivars->lock); | ||
826 | |||
827 | if (status != EFI_BUFFER_TOO_SMALL) | ||
828 | return efi_status_to_err(status); | ||
829 | |||
830 | data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); | ||
831 | |||
832 | if (!data) | ||
833 | return -ENOMEM; | ||
834 | |||
835 | spin_lock(&efivars->lock); | ||
836 | status = efivars->ops->get_variable(var->var.VariableName, | ||
837 | &var->var.VendorGuid, | ||
838 | &attributes, &datasize, | ||
839 | (data + sizeof(attributes))); | ||
840 | spin_unlock(&efivars->lock); | ||
841 | |||
842 | if (status != EFI_SUCCESS) { | ||
843 | size = efi_status_to_err(status); | ||
844 | goto out_free; | ||
845 | } | ||
846 | |||
847 | memcpy(data, &attributes, sizeof(attributes)); | ||
848 | size = simple_read_from_buffer(userbuf, count, ppos, | ||
849 | data, datasize + sizeof(attributes)); | ||
850 | out_free: | ||
851 | kfree(data); | ||
852 | |||
853 | return size; | ||
854 | } | ||
855 | |||
856 | static void efivarfs_evict_inode(struct inode *inode) | ||
857 | { | ||
858 | clear_inode(inode); | ||
859 | } | ||
860 | |||
861 | static const struct super_operations efivarfs_ops = { | ||
862 | .statfs = simple_statfs, | ||
863 | .drop_inode = generic_delete_inode, | ||
864 | .evict_inode = efivarfs_evict_inode, | ||
865 | .show_options = generic_show_options, | ||
866 | }; | ||
867 | |||
868 | static struct super_block *efivarfs_sb; | ||
869 | |||
870 | static const struct inode_operations efivarfs_dir_inode_operations; | ||
871 | |||
872 | static const struct file_operations efivarfs_file_operations = { | ||
873 | .open = efivarfs_file_open, | ||
874 | .read = efivarfs_file_read, | ||
875 | .write = efivarfs_file_write, | ||
876 | .llseek = no_llseek, | ||
877 | }; | ||
878 | |||
879 | static struct inode *efivarfs_get_inode(struct super_block *sb, | ||
880 | const struct inode *dir, int mode, dev_t dev) | ||
881 | { | ||
882 | struct inode *inode = new_inode(sb); | ||
883 | |||
884 | if (inode) { | ||
885 | inode->i_ino = get_next_ino(); | ||
886 | inode->i_uid = inode->i_gid = 0; | ||
887 | inode->i_mode = mode; | ||
888 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
889 | switch (mode & S_IFMT) { | ||
890 | case S_IFREG: | ||
891 | inode->i_fop = &efivarfs_file_operations; | ||
892 | break; | ||
893 | case S_IFDIR: | ||
894 | inode->i_op = &efivarfs_dir_inode_operations; | ||
895 | inode->i_fop = &simple_dir_operations; | ||
896 | inc_nlink(inode); | ||
897 | break; | ||
898 | } | ||
899 | } | ||
900 | return inode; | ||
901 | } | ||
902 | |||
903 | static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) | ||
904 | { | ||
905 | guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]); | ||
906 | guid->b[1] = hex_to_bin(str[4]) << 4 | hex_to_bin(str[5]); | ||
907 | guid->b[2] = hex_to_bin(str[2]) << 4 | hex_to_bin(str[3]); | ||
908 | guid->b[3] = hex_to_bin(str[0]) << 4 | hex_to_bin(str[1]); | ||
909 | guid->b[4] = hex_to_bin(str[11]) << 4 | hex_to_bin(str[12]); | ||
910 | guid->b[5] = hex_to_bin(str[9]) << 4 | hex_to_bin(str[10]); | ||
911 | guid->b[6] = hex_to_bin(str[16]) << 4 | hex_to_bin(str[17]); | ||
912 | guid->b[7] = hex_to_bin(str[14]) << 4 | hex_to_bin(str[15]); | ||
913 | guid->b[8] = hex_to_bin(str[19]) << 4 | hex_to_bin(str[20]); | ||
914 | guid->b[9] = hex_to_bin(str[21]) << 4 | hex_to_bin(str[22]); | ||
915 | guid->b[10] = hex_to_bin(str[24]) << 4 | hex_to_bin(str[25]); | ||
916 | guid->b[11] = hex_to_bin(str[26]) << 4 | hex_to_bin(str[27]); | ||
917 | guid->b[12] = hex_to_bin(str[28]) << 4 | hex_to_bin(str[29]); | ||
918 | guid->b[13] = hex_to_bin(str[30]) << 4 | hex_to_bin(str[31]); | ||
919 | guid->b[14] = hex_to_bin(str[32]) << 4 | hex_to_bin(str[33]); | ||
920 | guid->b[15] = hex_to_bin(str[34]) << 4 | hex_to_bin(str[35]); | ||
921 | } | ||
922 | |||
923 | static int efivarfs_create(struct inode *dir, struct dentry *dentry, | ||
924 | umode_t mode, bool excl) | ||
925 | { | ||
926 | struct inode *inode; | ||
927 | struct efivars *efivars = &__efivars; | ||
928 | struct efivar_entry *var; | ||
929 | int namelen, i = 0, err = 0; | ||
930 | |||
931 | /* | ||
932 | * We need a GUID, plus at least one letter for the variable name, | ||
933 | * plus the '-' separator | ||
934 | */ | ||
935 | if (dentry->d_name.len < GUID_LEN + 2) | ||
936 | return -EINVAL; | ||
937 | |||
938 | inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); | ||
939 | if (!inode) | ||
940 | return -ENOMEM; | ||
941 | |||
942 | var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); | ||
943 | if (!var) { | ||
944 | err = -ENOMEM; | ||
945 | goto out; | ||
946 | } | ||
947 | |||
948 | /* length of the variable name itself: remove GUID and separator */ | ||
949 | namelen = dentry->d_name.len - GUID_LEN - 1; | ||
950 | |||
951 | efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, | ||
952 | &var->var.VendorGuid); | ||
953 | |||
954 | for (i = 0; i < namelen; i++) | ||
955 | var->var.VariableName[i] = dentry->d_name.name[i]; | ||
956 | |||
957 | var->var.VariableName[i] = '\0'; | ||
958 | |||
959 | inode->i_private = var; | ||
960 | var->efivars = efivars; | ||
961 | var->kobj.kset = efivars->kset; | ||
962 | |||
963 | err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s", | ||
964 | dentry->d_name.name); | ||
965 | if (err) | ||
966 | goto out; | ||
967 | |||
968 | kobject_uevent(&var->kobj, KOBJ_ADD); | ||
969 | spin_lock(&efivars->lock); | ||
970 | list_add(&var->list, &efivars->list); | ||
971 | spin_unlock(&efivars->lock); | ||
972 | d_instantiate(dentry, inode); | ||
973 | dget(dentry); | ||
974 | out: | ||
975 | if (err) { | ||
976 | kfree(var); | ||
977 | iput(inode); | ||
978 | } | ||
979 | return err; | ||
980 | } | ||
981 | |||
982 | static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) | ||
983 | { | ||
984 | struct efivar_entry *var = dentry->d_inode->i_private; | ||
985 | struct efivars *efivars = var->efivars; | ||
986 | efi_status_t status; | ||
987 | |||
988 | spin_lock(&efivars->lock); | ||
989 | |||
990 | status = efivars->ops->set_variable(var->var.VariableName, | ||
991 | &var->var.VendorGuid, | ||
992 | 0, 0, NULL); | ||
993 | |||
994 | if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) { | ||
995 | list_del(&var->list); | ||
996 | spin_unlock(&efivars->lock); | ||
997 | efivar_unregister(var); | ||
998 | drop_nlink(dir); | ||
999 | dput(dentry); | ||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
1003 | spin_unlock(&efivars->lock); | ||
1004 | return -EINVAL; | ||
1005 | }; | ||
1006 | |||
1007 | static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | ||
1008 | { | ||
1009 | struct inode *inode = NULL; | ||
1010 | struct dentry *root; | ||
1011 | struct efivar_entry *entry, *n; | ||
1012 | struct efivars *efivars = &__efivars; | ||
1013 | char *name; | ||
1014 | |||
1015 | efivarfs_sb = sb; | ||
1016 | |||
1017 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
1018 | sb->s_blocksize = PAGE_CACHE_SIZE; | ||
1019 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | ||
1020 | sb->s_magic = EFIVARFS_MAGIC; | ||
1021 | sb->s_op = &efivarfs_ops; | ||
1022 | sb->s_time_gran = 1; | ||
1023 | |||
1024 | inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); | ||
1025 | if (!inode) | ||
1026 | return -ENOMEM; | ||
1027 | inode->i_op = &efivarfs_dir_inode_operations; | ||
1028 | |||
1029 | root = d_make_root(inode); | ||
1030 | sb->s_root = root; | ||
1031 | if (!root) | ||
1032 | return -ENOMEM; | ||
1033 | |||
1034 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | ||
1035 | struct dentry *dentry, *root = efivarfs_sb->s_root; | ||
1036 | unsigned long size = 0; | ||
1037 | int len, i; | ||
1038 | |||
1039 | inode = NULL; | ||
1040 | |||
1041 | len = utf16_strlen(entry->var.VariableName); | ||
1042 | |||
1043 | /* name, plus '-', plus GUID, plus NUL*/ | ||
1044 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); | ||
1045 | if (!name) | ||
1046 | goto fail; | ||
1047 | |||
1048 | for (i = 0; i < len; i++) | ||
1049 | name[i] = entry->var.VariableName[i] & 0xFF; | ||
1050 | |||
1051 | name[len] = '-'; | ||
1052 | |||
1053 | efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); | ||
1054 | |||
1055 | name[len+GUID_LEN+1] = '\0'; | ||
1056 | |||
1057 | inode = efivarfs_get_inode(efivarfs_sb, root->d_inode, | ||
1058 | S_IFREG | 0644, 0); | ||
1059 | if (!inode) | ||
1060 | goto fail_name; | ||
1061 | |||
1062 | dentry = d_alloc_name(root, name); | ||
1063 | if (!dentry) | ||
1064 | goto fail_inode; | ||
1065 | |||
1066 | /* copied by the above to local storage in the dentry. */ | ||
1067 | kfree(name); | ||
1068 | |||
1069 | spin_lock(&efivars->lock); | ||
1070 | efivars->ops->get_variable(entry->var.VariableName, | ||
1071 | &entry->var.VendorGuid, | ||
1072 | &entry->var.Attributes, | ||
1073 | &size, | ||
1074 | NULL); | ||
1075 | spin_unlock(&efivars->lock); | ||
1076 | |||
1077 | mutex_lock(&inode->i_mutex); | ||
1078 | inode->i_private = entry; | ||
1079 | i_size_write(inode, size+4); | ||
1080 | mutex_unlock(&inode->i_mutex); | ||
1081 | d_add(dentry, inode); | ||
1082 | } | ||
1083 | |||
1084 | return 0; | ||
1085 | |||
1086 | fail_inode: | ||
1087 | iput(inode); | ||
1088 | fail_name: | ||
1089 | kfree(name); | ||
1090 | fail: | ||
1091 | return -ENOMEM; | ||
1092 | } | ||
1093 | |||
1094 | static struct dentry *efivarfs_mount(struct file_system_type *fs_type, | ||
1095 | int flags, const char *dev_name, void *data) | ||
1096 | { | ||
1097 | return mount_single(fs_type, flags, data, efivarfs_fill_super); | ||
1098 | } | ||
1099 | |||
1100 | static void efivarfs_kill_sb(struct super_block *sb) | ||
1101 | { | ||
1102 | kill_litter_super(sb); | ||
1103 | efivarfs_sb = NULL; | ||
1104 | } | ||
1105 | |||
1106 | static struct file_system_type efivarfs_type = { | ||
1107 | .name = "efivarfs", | ||
1108 | .mount = efivarfs_mount, | ||
1109 | .kill_sb = efivarfs_kill_sb, | ||
1110 | }; | ||
1111 | |||
1112 | static const struct inode_operations efivarfs_dir_inode_operations = { | ||
1113 | .lookup = simple_lookup, | ||
1114 | .unlink = efivarfs_unlink, | ||
1115 | .create = efivarfs_create, | ||
1116 | }; | ||
1117 | |||
1118 | static struct pstore_info efi_pstore_info; | ||
1119 | |||
640 | #ifdef CONFIG_PSTORE | 1120 | #ifdef CONFIG_PSTORE |
641 | 1121 | ||
642 | static int efi_pstore_open(struct pstore_info *psi) | 1122 | static int efi_pstore_open(struct pstore_info *psi) |
@@ -1065,11 +1545,18 @@ efivar_create_sysfs_entry(struct efivars *efivars, | |||
1065 | efi_char16_t *variable_name, | 1545 | efi_char16_t *variable_name, |
1066 | efi_guid_t *vendor_guid) | 1546 | efi_guid_t *vendor_guid) |
1067 | { | 1547 | { |
1068 | int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38; | 1548 | int i, short_name_size; |
1069 | char *short_name; | 1549 | char *short_name; |
1070 | struct efivar_entry *new_efivar; | 1550 | struct efivar_entry *new_efivar; |
1071 | 1551 | ||
1072 | short_name = kzalloc(short_name_size + 1, GFP_KERNEL); | 1552 | /* |
1553 | * Length of the variable bytes in ASCII, plus the '-' separator, | ||
1554 | * plus the GUID, plus trailing NUL | ||
1555 | */ | ||
1556 | short_name_size = variable_name_size / sizeof(efi_char16_t) | ||
1557 | + 1 + GUID_LEN + 1; | ||
1558 | |||
1559 | short_name = kzalloc(short_name_size, GFP_KERNEL); | ||
1073 | new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); | 1560 | new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); |
1074 | 1561 | ||
1075 | if (!short_name || !new_efivar) { | 1562 | if (!short_name || !new_efivar) { |
@@ -1189,6 +1676,7 @@ void unregister_efivars(struct efivars *efivars) | |||
1189 | sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var); | 1676 | sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var); |
1190 | kfree(efivars->new_var); | 1677 | kfree(efivars->new_var); |
1191 | kfree(efivars->del_var); | 1678 | kfree(efivars->del_var); |
1679 | kobject_put(efivars->kobject); | ||
1192 | kset_unregister(efivars->kset); | 1680 | kset_unregister(efivars->kset); |
1193 | } | 1681 | } |
1194 | EXPORT_SYMBOL_GPL(unregister_efivars); | 1682 | EXPORT_SYMBOL_GPL(unregister_efivars); |
@@ -1220,6 +1708,14 @@ int register_efivars(struct efivars *efivars, | |||
1220 | goto out; | 1708 | goto out; |
1221 | } | 1709 | } |
1222 | 1710 | ||
1711 | efivars->kobject = kobject_create_and_add("efivars", parent_kobj); | ||
1712 | if (!efivars->kobject) { | ||
1713 | pr_err("efivars: Subsystem registration failed.\n"); | ||
1714 | error = -ENOMEM; | ||
1715 | kset_unregister(efivars->kset); | ||
1716 | goto out; | ||
1717 | } | ||
1718 | |||
1223 | /* | 1719 | /* |
1224 | * Per EFI spec, the maximum storage allocated for both | 1720 | * Per EFI spec, the maximum storage allocated for both |
1225 | * the variable name and variable data is 1024 bytes. | 1721 | * the variable name and variable data is 1024 bytes. |
@@ -1262,6 +1758,8 @@ int register_efivars(struct efivars *efivars, | |||
1262 | pstore_register(&efivars->efi_pstore_info); | 1758 | pstore_register(&efivars->efi_pstore_info); |
1263 | } | 1759 | } |
1264 | 1760 | ||
1761 | register_filesystem(&efivarfs_type); | ||
1762 | |||
1265 | out: | 1763 | out: |
1266 | kfree(variable_name); | 1764 | kfree(variable_name); |
1267 | 1765 | ||
@@ -1269,9 +1767,6 @@ out: | |||
1269 | } | 1767 | } |
1270 | EXPORT_SYMBOL_GPL(register_efivars); | 1768 | EXPORT_SYMBOL_GPL(register_efivars); |
1271 | 1769 | ||
1272 | static struct efivars __efivars; | ||
1273 | static struct efivar_operations ops; | ||
1274 | |||
1275 | /* | 1770 | /* |
1276 | * For now we register the efi subsystem with the firmware subsystem | 1771 | * For now we register the efi subsystem with the firmware subsystem |
1277 | * and the vars subsystem with the efi subsystem. In the future, it | 1772 | * and the vars subsystem with the efi subsystem. In the future, it |
@@ -1302,6 +1797,7 @@ efivars_init(void) | |||
1302 | ops.set_variable = efi.set_variable; | 1797 | ops.set_variable = efi.set_variable; |
1303 | ops.get_next_variable = efi.get_next_variable; | 1798 | ops.get_next_variable = efi.get_next_variable; |
1304 | ops.query_variable_info = efi.query_variable_info; | 1799 | ops.query_variable_info = efi.query_variable_info; |
1800 | |||
1305 | error = register_efivars(&__efivars, &ops, efi_kobj); | 1801 | error = register_efivars(&__efivars, &ops, efi_kobj); |
1306 | if (error) | 1802 | if (error) |
1307 | goto err_put; | 1803 | goto err_put; |
diff --git a/include/linux/efi.h b/include/linux/efi.h index b02099d0b4fc..02a69418be18 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -29,7 +29,12 @@ | |||
29 | #define EFI_UNSUPPORTED ( 3 | (1UL << (BITS_PER_LONG-1))) | 29 | #define EFI_UNSUPPORTED ( 3 | (1UL << (BITS_PER_LONG-1))) |
30 | #define EFI_BAD_BUFFER_SIZE ( 4 | (1UL << (BITS_PER_LONG-1))) | 30 | #define EFI_BAD_BUFFER_SIZE ( 4 | (1UL << (BITS_PER_LONG-1))) |
31 | #define EFI_BUFFER_TOO_SMALL ( 5 | (1UL << (BITS_PER_LONG-1))) | 31 | #define EFI_BUFFER_TOO_SMALL ( 5 | (1UL << (BITS_PER_LONG-1))) |
32 | #define EFI_NOT_READY ( 6 | (1UL << (BITS_PER_LONG-1))) | ||
33 | #define EFI_DEVICE_ERROR ( 7 | (1UL << (BITS_PER_LONG-1))) | ||
34 | #define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1))) | ||
35 | #define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1))) | ||
32 | #define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) | 36 | #define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) |
37 | #define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1))) | ||
33 | 38 | ||
34 | typedef unsigned long efi_status_t; | 39 | typedef unsigned long efi_status_t; |
35 | typedef u8 efi_bool_t; | 40 | typedef u8 efi_bool_t; |
@@ -582,8 +587,6 @@ extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size); | |||
582 | extern int __init efi_uart_console_only (void); | 587 | extern int __init efi_uart_console_only (void); |
583 | extern void efi_initialize_iomem_resources(struct resource *code_resource, | 588 | extern void efi_initialize_iomem_resources(struct resource *code_resource, |
584 | struct resource *data_resource, struct resource *bss_resource); | 589 | struct resource *data_resource, struct resource *bss_resource); |
585 | extern unsigned long efi_get_time(void); | ||
586 | extern int efi_set_rtc_mmss(unsigned long nowtime); | ||
587 | extern void efi_reserve_boot_services(void); | 590 | extern void efi_reserve_boot_services(void); |
588 | extern struct efi_memory_map memmap; | 591 | extern struct efi_memory_map memmap; |
589 | 592 | ||
@@ -729,6 +732,7 @@ struct efivars { | |||
729 | spinlock_t lock; | 732 | spinlock_t lock; |
730 | struct list_head list; | 733 | struct list_head list; |
731 | struct kset *kset; | 734 | struct kset *kset; |
735 | struct kobject *kobject; | ||
732 | struct bin_attribute *new_var, *del_var; | 736 | struct bin_attribute *new_var, *del_var; |
733 | const struct efivar_operations *ops; | 737 | const struct efivar_operations *ops; |
734 | struct efivar_entry *walk_entry; | 738 | struct efivar_entry *walk_entry; |
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index e15192cb9cf4..12f68c7ceba6 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #define ISOFS_SUPER_MAGIC 0x9660 | 27 | #define ISOFS_SUPER_MAGIC 0x9660 |
28 | #define JFFS2_SUPER_MAGIC 0x72b6 | 28 | #define JFFS2_SUPER_MAGIC 0x72b6 |
29 | #define PSTOREFS_MAGIC 0x6165676C | 29 | #define PSTOREFS_MAGIC 0x6165676C |
30 | #define EFIVARFS_MAGIC 0xde5e81e4 | ||
30 | 31 | ||
31 | #define MINIX_SUPER_MAGIC 0x137F /* minix v1 fs, 14 char names */ | 32 | #define MINIX_SUPER_MAGIC 0x137F /* minix v1 fs, 14 char names */ |
32 | #define MINIX_SUPER_MAGIC2 0x138F /* minix v1 fs, 30 char names */ | 33 | #define MINIX_SUPER_MAGIC2 0x138F /* minix v1 fs, 30 char names */ |
diff --git a/init/main.c b/init/main.c index 63ae904a99a8..6af5470b8067 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -463,6 +463,10 @@ static void __init mm_init(void) | |||
463 | percpu_init_late(); | 463 | percpu_init_late(); |
464 | pgtable_cache_init(); | 464 | pgtable_cache_init(); |
465 | vmalloc_init(); | 465 | vmalloc_init(); |
466 | #ifdef CONFIG_X86 | ||
467 | if (efi_enabled) | ||
468 | efi_enter_virtual_mode(); | ||
469 | #endif | ||
466 | } | 470 | } |
467 | 471 | ||
468 | asmlinkage void __init start_kernel(void) | 472 | asmlinkage void __init start_kernel(void) |
@@ -603,10 +607,6 @@ asmlinkage void __init start_kernel(void) | |||
603 | calibrate_delay(); | 607 | calibrate_delay(); |
604 | pidmap_init(); | 608 | pidmap_init(); |
605 | anon_vma_init(); | 609 | anon_vma_init(); |
606 | #ifdef CONFIG_X86 | ||
607 | if (efi_enabled) | ||
608 | efi_enter_virtual_mode(); | ||
609 | #endif | ||
610 | thread_info_cache_init(); | 610 | thread_info_cache_init(); |
611 | cred_init(); | 611 | cred_init(); |
612 | fork_init(totalram_pages); | 612 | fork_init(totalram_pages); |