diff options
| -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); |
