diff options
| -rw-r--r-- | arch/x86/include/asm/kexec.h | 27 | ||||
| -rw-r--r-- | arch/x86/kernel/machine_kexec_64.c | 82 | ||||
| -rw-r--r-- | arch/x86/kernel/relocate_kernel_64.S | 125 |
3 files changed, 67 insertions, 167 deletions
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index c61d8b2ab8b9..0ceb6d19ed30 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h | |||
| @@ -9,23 +9,8 @@ | |||
| 9 | # define PAGES_NR 4 | 9 | # define PAGES_NR 4 |
| 10 | #else | 10 | #else |
| 11 | # define PA_CONTROL_PAGE 0 | 11 | # define PA_CONTROL_PAGE 0 |
| 12 | # define VA_CONTROL_PAGE 1 | 12 | # define PA_TABLE_PAGE 1 |
| 13 | # define PA_PGD 2 | 13 | # define PAGES_NR 2 |
| 14 | # define VA_PGD 3 | ||
| 15 | # define PA_PUD_0 4 | ||
| 16 | # define VA_PUD_0 5 | ||
| 17 | # define PA_PMD_0 6 | ||
| 18 | # define VA_PMD_0 7 | ||
| 19 | # define PA_PTE_0 8 | ||
| 20 | # define VA_PTE_0 9 | ||
| 21 | # define PA_PUD_1 10 | ||
| 22 | # define VA_PUD_1 11 | ||
| 23 | # define PA_PMD_1 12 | ||
| 24 | # define VA_PMD_1 13 | ||
| 25 | # define PA_PTE_1 14 | ||
| 26 | # define VA_PTE_1 15 | ||
| 27 | # define PA_TABLE_PAGE 16 | ||
| 28 | # define PAGES_NR 17 | ||
| 29 | #endif | 14 | #endif |
| 30 | 15 | ||
| 31 | #ifdef CONFIG_X86_32 | 16 | #ifdef CONFIG_X86_32 |
| @@ -157,9 +142,9 @@ relocate_kernel(unsigned long indirection_page, | |||
| 157 | unsigned long start_address) ATTRIB_NORET; | 142 | unsigned long start_address) ATTRIB_NORET; |
| 158 | #endif | 143 | #endif |
| 159 | 144 | ||
| 160 | #ifdef CONFIG_X86_32 | ||
| 161 | #define ARCH_HAS_KIMAGE_ARCH | 145 | #define ARCH_HAS_KIMAGE_ARCH |
| 162 | 146 | ||
| 147 | #ifdef CONFIG_X86_32 | ||
| 163 | struct kimage_arch { | 148 | struct kimage_arch { |
| 164 | pgd_t *pgd; | 149 | pgd_t *pgd; |
| 165 | #ifdef CONFIG_X86_PAE | 150 | #ifdef CONFIG_X86_PAE |
| @@ -169,6 +154,12 @@ struct kimage_arch { | |||
| 169 | pte_t *pte0; | 154 | pte_t *pte0; |
| 170 | pte_t *pte1; | 155 | pte_t *pte1; |
| 171 | }; | 156 | }; |
| 157 | #else | ||
| 158 | struct kimage_arch { | ||
| 159 | pud_t *pud; | ||
| 160 | pmd_t *pmd; | ||
| 161 | pte_t *pte; | ||
| 162 | }; | ||
| 172 | #endif | 163 | #endif |
| 173 | 164 | ||
| 174 | #endif /* __ASSEMBLY__ */ | 165 | #endif /* __ASSEMBLY__ */ |
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index c43caa3a91f3..6993d51b7fd8 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c | |||
| @@ -18,15 +18,6 @@ | |||
| 18 | #include <asm/mmu_context.h> | 18 | #include <asm/mmu_context.h> |
| 19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
| 20 | 20 | ||
| 21 | #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) | ||
| 22 | static u64 kexec_pgd[512] PAGE_ALIGNED; | ||
| 23 | static u64 kexec_pud0[512] PAGE_ALIGNED; | ||
| 24 | static u64 kexec_pmd0[512] PAGE_ALIGNED; | ||
| 25 | static u64 kexec_pte0[512] PAGE_ALIGNED; | ||
| 26 | static u64 kexec_pud1[512] PAGE_ALIGNED; | ||
| 27 | static u64 kexec_pmd1[512] PAGE_ALIGNED; | ||
| 28 | static u64 kexec_pte1[512] PAGE_ALIGNED; | ||
| 29 | |||
| 30 | static void init_level2_page(pmd_t *level2p, unsigned long addr) | 21 | static void init_level2_page(pmd_t *level2p, unsigned long addr) |
| 31 | { | 22 | { |
| 32 | unsigned long end_addr; | 23 | unsigned long end_addr; |
| @@ -107,12 +98,65 @@ out: | |||
| 107 | return result; | 98 | return result; |
| 108 | } | 99 | } |
| 109 | 100 | ||
| 101 | static void free_transition_pgtable(struct kimage *image) | ||
| 102 | { | ||
| 103 | free_page((unsigned long)image->arch.pud); | ||
| 104 | free_page((unsigned long)image->arch.pmd); | ||
| 105 | free_page((unsigned long)image->arch.pte); | ||
| 106 | } | ||
| 107 | |||
| 108 | static int init_transition_pgtable(struct kimage *image, pgd_t *pgd) | ||
| 109 | { | ||
| 110 | pud_t *pud; | ||
| 111 | pmd_t *pmd; | ||
| 112 | pte_t *pte; | ||
| 113 | unsigned long vaddr, paddr; | ||
| 114 | int result = -ENOMEM; | ||
| 115 | |||
| 116 | vaddr = (unsigned long)relocate_kernel; | ||
| 117 | paddr = __pa(page_address(image->control_code_page)+PAGE_SIZE); | ||
| 118 | pgd += pgd_index(vaddr); | ||
| 119 | if (!pgd_present(*pgd)) { | ||
| 120 | pud = (pud_t *)get_zeroed_page(GFP_KERNEL); | ||
| 121 | if (!pud) | ||
| 122 | goto err; | ||
| 123 | image->arch.pud = pud; | ||
| 124 | set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE)); | ||
| 125 | } | ||
| 126 | pud = pud_offset(pgd, vaddr); | ||
| 127 | if (!pud_present(*pud)) { | ||
| 128 | pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL); | ||
| 129 | if (!pmd) | ||
| 130 | goto err; | ||
| 131 | image->arch.pmd = pmd; | ||
| 132 | set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); | ||
| 133 | } | ||
| 134 | pmd = pmd_offset(pud, vaddr); | ||
| 135 | if (!pmd_present(*pmd)) { | ||
| 136 | pte = (pte_t *)get_zeroed_page(GFP_KERNEL); | ||
| 137 | if (!pte) | ||
| 138 | goto err; | ||
| 139 | image->arch.pte = pte; | ||
| 140 | set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE)); | ||
| 141 | } | ||
| 142 | pte = pte_offset_kernel(pmd, vaddr); | ||
| 143 | set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC)); | ||
| 144 | return 0; | ||
| 145 | err: | ||
| 146 | free_transition_pgtable(image); | ||
| 147 | return result; | ||
| 148 | } | ||
| 149 | |||
| 110 | 150 | ||
| 111 | static int init_pgtable(struct kimage *image, unsigned long start_pgtable) | 151 | static int init_pgtable(struct kimage *image, unsigned long start_pgtable) |
| 112 | { | 152 | { |
| 113 | pgd_t *level4p; | 153 | pgd_t *level4p; |
| 154 | int result; | ||
| 114 | level4p = (pgd_t *)__va(start_pgtable); | 155 | level4p = (pgd_t *)__va(start_pgtable); |
| 115 | return init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT); | 156 | result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT); |
| 157 | if (result) | ||
| 158 | return result; | ||
| 159 | return init_transition_pgtable(image, level4p); | ||
| 116 | } | 160 | } |
| 117 | 161 | ||
| 118 | static void set_idt(void *newidt, u16 limit) | 162 | static void set_idt(void *newidt, u16 limit) |
| @@ -174,7 +218,7 @@ int machine_kexec_prepare(struct kimage *image) | |||
| 174 | 218 | ||
| 175 | void machine_kexec_cleanup(struct kimage *image) | 219 | void machine_kexec_cleanup(struct kimage *image) |
| 176 | { | 220 | { |
| 177 | return; | 221 | free_transition_pgtable(image); |
| 178 | } | 222 | } |
| 179 | 223 | ||
| 180 | /* | 224 | /* |
| @@ -195,22 +239,6 @@ void machine_kexec(struct kimage *image) | |||
| 195 | memcpy(control_page, relocate_kernel, PAGE_SIZE); | 239 | memcpy(control_page, relocate_kernel, PAGE_SIZE); |
| 196 | 240 | ||
| 197 | page_list[PA_CONTROL_PAGE] = virt_to_phys(control_page); | 241 | page_list[PA_CONTROL_PAGE] = virt_to_phys(control_page); |
| 198 | page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; | ||
| 199 | page_list[PA_PGD] = virt_to_phys(&kexec_pgd); | ||
| 200 | page_list[VA_PGD] = (unsigned long)kexec_pgd; | ||
| 201 | page_list[PA_PUD_0] = virt_to_phys(&kexec_pud0); | ||
| 202 | page_list[VA_PUD_0] = (unsigned long)kexec_pud0; | ||
| 203 | page_list[PA_PMD_0] = virt_to_phys(&kexec_pmd0); | ||
| 204 | page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; | ||
| 205 | page_list[PA_PTE_0] = virt_to_phys(&kexec_pte0); | ||
| 206 | page_list[VA_PTE_0] = (unsigned long)kexec_pte0; | ||
| 207 | page_list[PA_PUD_1] = virt_to_phys(&kexec_pud1); | ||
| 208 | page_list[VA_PUD_1] = (unsigned long)kexec_pud1; | ||
| 209 | page_list[PA_PMD_1] = virt_to_phys(&kexec_pmd1); | ||
| 210 | page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; | ||
| 211 | page_list[PA_PTE_1] = virt_to_phys(&kexec_pte1); | ||
| 212 | page_list[VA_PTE_1] = (unsigned long)kexec_pte1; | ||
| 213 | |||
| 214 | page_list[PA_TABLE_PAGE] = | 242 | page_list[PA_TABLE_PAGE] = |
| 215 | (unsigned long)__pa(page_address(image->control_code_page)); | 243 | (unsigned long)__pa(page_address(image->control_code_page)); |
| 216 | 244 | ||
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index f5afe665a82b..b0bbdd4829c9 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S | |||
| @@ -29,122 +29,6 @@ relocate_kernel: | |||
| 29 | * %rdx start address | 29 | * %rdx start address |
| 30 | */ | 30 | */ |
| 31 | 31 | ||
| 32 | /* map the control page at its virtual address */ | ||
| 33 | |||
| 34 | movq $0x0000ff8000000000, %r10 /* mask */ | ||
| 35 | mov $(39 - 3), %cl /* bits to shift */ | ||
| 36 | movq PTR(VA_CONTROL_PAGE)(%rsi), %r11 /* address to map */ | ||
| 37 | |||
| 38 | movq %r11, %r9 | ||
| 39 | andq %r10, %r9 | ||
| 40 | shrq %cl, %r9 | ||
| 41 | |||
| 42 | movq PTR(VA_PGD)(%rsi), %r8 | ||
| 43 | addq %r8, %r9 | ||
| 44 | movq PTR(PA_PUD_0)(%rsi), %r8 | ||
| 45 | orq $PAGE_ATTR, %r8 | ||
| 46 | movq %r8, (%r9) | ||
| 47 | |||
| 48 | shrq $9, %r10 | ||
| 49 | sub $9, %cl | ||
| 50 | |||
| 51 | movq %r11, %r9 | ||
| 52 | andq %r10, %r9 | ||
| 53 | shrq %cl, %r9 | ||
| 54 | |||
| 55 | movq PTR(VA_PUD_0)(%rsi), %r8 | ||
| 56 | addq %r8, %r9 | ||
| 57 | movq PTR(PA_PMD_0)(%rsi), %r8 | ||
| 58 | orq $PAGE_ATTR, %r8 | ||
| 59 | movq %r8, (%r9) | ||
| 60 | |||
| 61 | shrq $9, %r10 | ||
| 62 | sub $9, %cl | ||
| 63 | |||
| 64 | movq %r11, %r9 | ||
| 65 | andq %r10, %r9 | ||
| 66 | shrq %cl, %r9 | ||
| 67 | |||
| 68 | movq PTR(VA_PMD_0)(%rsi), %r8 | ||
| 69 | addq %r8, %r9 | ||
| 70 | movq PTR(PA_PTE_0)(%rsi), %r8 | ||
| 71 | orq $PAGE_ATTR, %r8 | ||
| 72 | movq %r8, (%r9) | ||
| 73 | |||
| 74 | shrq $9, %r10 | ||
| 75 | sub $9, %cl | ||
| 76 | |||
| 77 | movq %r11, %r9 | ||
| 78 | andq %r10, %r9 | ||
| 79 | shrq %cl, %r9 | ||
| 80 | |||
| 81 | movq PTR(VA_PTE_0)(%rsi), %r8 | ||
| 82 | addq %r8, %r9 | ||
| 83 | movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 | ||
| 84 | orq $PAGE_ATTR, %r8 | ||
| 85 | movq %r8, (%r9) | ||
| 86 | |||
| 87 | /* identity map the control page at its physical address */ | ||
| 88 | |||
| 89 | movq $0x0000ff8000000000, %r10 /* mask */ | ||
| 90 | mov $(39 - 3), %cl /* bits to shift */ | ||
| 91 | movq PTR(PA_CONTROL_PAGE)(%rsi), %r11 /* address to map */ | ||
| 92 | |||
| 93 | movq %r11, %r9 | ||
| 94 | andq %r10, %r9 | ||
| 95 | shrq %cl, %r9 | ||
| 96 | |||
| 97 | movq PTR(VA_PGD)(%rsi), %r8 | ||
| 98 | addq %r8, %r9 | ||
| 99 | movq PTR(PA_PUD_1)(%rsi), %r8 | ||
| 100 | orq $PAGE_ATTR, %r8 | ||
| 101 | movq %r8, (%r9) | ||
| 102 | |||
| 103 | shrq $9, %r10 | ||
| 104 | sub $9, %cl | ||
| 105 | |||
| 106 | movq %r11, %r9 | ||
| 107 | andq %r10, %r9 | ||
| 108 | shrq %cl, %r9 | ||
| 109 | |||
| 110 | movq PTR(VA_PUD_1)(%rsi), %r8 | ||
| 111 | addq %r8, %r9 | ||
| 112 | movq PTR(PA_PMD_1)(%rsi), %r8 | ||
| 113 | orq $PAGE_ATTR, %r8 | ||
| 114 | movq %r8, (%r9) | ||
| 115 | |||
| 116 | shrq $9, %r10 | ||
| 117 | sub $9, %cl | ||
| 118 | |||
| 119 | movq %r11, %r9 | ||
| 120 | andq %r10, %r9 | ||
| 121 | shrq %cl, %r9 | ||
| 122 | |||
| 123 | movq PTR(VA_PMD_1)(%rsi), %r8 | ||
| 124 | addq %r8, %r9 | ||
| 125 | movq PTR(PA_PTE_1)(%rsi), %r8 | ||
| 126 | orq $PAGE_ATTR, %r8 | ||
| 127 | movq %r8, (%r9) | ||
| 128 | |||
| 129 | shrq $9, %r10 | ||
| 130 | sub $9, %cl | ||
| 131 | |||
| 132 | movq %r11, %r9 | ||
| 133 | andq %r10, %r9 | ||
| 134 | shrq %cl, %r9 | ||
| 135 | |||
| 136 | movq PTR(VA_PTE_1)(%rsi), %r8 | ||
| 137 | addq %r8, %r9 | ||
| 138 | movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 | ||
| 139 | orq $PAGE_ATTR, %r8 | ||
| 140 | movq %r8, (%r9) | ||
| 141 | |||
| 142 | relocate_new_kernel: | ||
| 143 | /* %rdi indirection_page | ||
| 144 | * %rsi page_list | ||
| 145 | * %rdx start address | ||
| 146 | */ | ||
| 147 | |||
| 148 | /* zero out flags, and disable interrupts */ | 32 | /* zero out flags, and disable interrupts */ |
| 149 | pushq $0 | 33 | pushq $0 |
| 150 | popfq | 34 | popfq |
| @@ -156,9 +40,8 @@ relocate_new_kernel: | |||
| 156 | /* get physical address of page table now too */ | 40 | /* get physical address of page table now too */ |
| 157 | movq PTR(PA_TABLE_PAGE)(%rsi), %rcx | 41 | movq PTR(PA_TABLE_PAGE)(%rsi), %rcx |
| 158 | 42 | ||
| 159 | /* switch to new set of page tables */ | 43 | /* Switch to the identity mapped page tables */ |
| 160 | movq PTR(PA_PGD)(%rsi), %r9 | 44 | movq %rcx, %cr3 |
| 161 | movq %r9, %cr3 | ||
| 162 | 45 | ||
| 163 | /* setup a new stack at the end of the physical control page */ | 46 | /* setup a new stack at the end of the physical control page */ |
| 164 | lea PAGE_SIZE(%r8), %rsp | 47 | lea PAGE_SIZE(%r8), %rsp |
| @@ -194,9 +77,7 @@ identity_mapped: | |||
| 194 | jmp 1f | 77 | jmp 1f |
| 195 | 1: | 78 | 1: |
| 196 | 79 | ||
| 197 | /* Switch to the identity mapped page tables, | 80 | /* Flush the TLB (needed?) */ |
| 198 | * and flush the TLB. | ||
| 199 | */ | ||
| 200 | movq %rcx, %cr3 | 81 | movq %rcx, %cr3 |
| 201 | 82 | ||
| 202 | /* Do the copies */ | 83 | /* Do the copies */ |
