diff options
author | Huang Ying <ying.huang@intel.com> | 2008-10-30 21:48:08 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-31 05:01:56 -0400 |
commit | 92be3d6bdf2cb34972ab50e12ad4da1076e690da (patch) | |
tree | 6ed10cb8a14615ca0bda48f64520c82480397d00 /arch/x86/kernel/machine_kexec_32.c | |
parent | 31498a01496ffca3b542bae72b8ec499cd9302db (diff) |
kexec/i386: allocate page table pages dynamically
Impact: save .text size when kexec is built in but not loaded
This patch adds an architecture specific struct kimage_arch into
struct kimage. The pointers to page table pages used by kexec are
added to struct kimage_arch. The page tables pages are dynamically
allocated in machine_kexec_prepare instead of statically from BSS
segment. This will save up to 20k memory when kexec image is not
loaded.
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/machine_kexec_32.c')
-rw-r--r-- | arch/x86/kernel/machine_kexec_32.c | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/arch/x86/kernel/machine_kexec_32.c b/arch/x86/kernel/machine_kexec_32.c index 7a385746509a..1100312847a5 100644 --- a/arch/x86/kernel/machine_kexec_32.c +++ b/arch/x86/kernel/machine_kexec_32.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/numa.h> | 13 | #include <linux/numa.h> |
14 | #include <linux/ftrace.h> | 14 | #include <linux/ftrace.h> |
15 | #include <linux/suspend.h> | 15 | #include <linux/suspend.h> |
16 | #include <linux/gfp.h> | ||
16 | 17 | ||
17 | #include <asm/pgtable.h> | 18 | #include <asm/pgtable.h> |
18 | #include <asm/pgalloc.h> | 19 | #include <asm/pgalloc.h> |
@@ -25,15 +26,6 @@ | |||
25 | #include <asm/system.h> | 26 | #include <asm/system.h> |
26 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
27 | 28 | ||
28 | #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) | ||
29 | static u32 kexec_pgd[1024] PAGE_ALIGNED; | ||
30 | #ifdef CONFIG_X86_PAE | ||
31 | static u32 kexec_pmd0[1024] PAGE_ALIGNED; | ||
32 | static u32 kexec_pmd1[1024] PAGE_ALIGNED; | ||
33 | #endif | ||
34 | static u32 kexec_pte0[1024] PAGE_ALIGNED; | ||
35 | static u32 kexec_pte1[1024] PAGE_ALIGNED; | ||
36 | |||
37 | static void set_idt(void *newidt, __u16 limit) | 29 | static void set_idt(void *newidt, __u16 limit) |
38 | { | 30 | { |
39 | struct desc_ptr curidt; | 31 | struct desc_ptr curidt; |
@@ -76,6 +68,37 @@ static void load_segments(void) | |||
76 | #undef __STR | 68 | #undef __STR |
77 | } | 69 | } |
78 | 70 | ||
71 | static void machine_kexec_free_page_tables(struct kimage *image) | ||
72 | { | ||
73 | free_page((unsigned long)image->arch.pgd); | ||
74 | #ifdef CONFIG_X86_PAE | ||
75 | free_page((unsigned long)image->arch.pmd0); | ||
76 | free_page((unsigned long)image->arch.pmd1); | ||
77 | #endif | ||
78 | free_page((unsigned long)image->arch.pte0); | ||
79 | free_page((unsigned long)image->arch.pte1); | ||
80 | } | ||
81 | |||
82 | static int machine_kexec_alloc_page_tables(struct kimage *image) | ||
83 | { | ||
84 | image->arch.pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL); | ||
85 | #ifdef CONFIG_X86_PAE | ||
86 | image->arch.pmd0 = (pmd_t *)get_zeroed_page(GFP_KERNEL); | ||
87 | image->arch.pmd1 = (pmd_t *)get_zeroed_page(GFP_KERNEL); | ||
88 | #endif | ||
89 | image->arch.pte0 = (pte_t *)get_zeroed_page(GFP_KERNEL); | ||
90 | image->arch.pte1 = (pte_t *)get_zeroed_page(GFP_KERNEL); | ||
91 | if (!image->arch.pgd || | ||
92 | #ifdef CONFIG_X86_PAE | ||
93 | !image->arch.pmd0 || !image->arch.pmd1 || | ||
94 | #endif | ||
95 | !image->arch.pte0 || !image->arch.pte1) { | ||
96 | machine_kexec_free_page_tables(image); | ||
97 | return -ENOMEM; | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
79 | /* | 102 | /* |
80 | * A architecture hook called to validate the | 103 | * A architecture hook called to validate the |
81 | * proposed image and prepare the control pages | 104 | * proposed image and prepare the control pages |
@@ -87,13 +110,14 @@ static void load_segments(void) | |||
87 | * reboot code buffer to allow us to avoid allocations | 110 | * reboot code buffer to allow us to avoid allocations |
88 | * later. | 111 | * later. |
89 | * | 112 | * |
90 | * Make control page executable. | 113 | * - Make control page executable. |
114 | * - Allocate page tables | ||
91 | */ | 115 | */ |
92 | int machine_kexec_prepare(struct kimage *image) | 116 | int machine_kexec_prepare(struct kimage *image) |
93 | { | 117 | { |
94 | if (nx_enabled) | 118 | if (nx_enabled) |
95 | set_pages_x(image->control_code_page, 1); | 119 | set_pages_x(image->control_code_page, 1); |
96 | return 0; | 120 | return machine_kexec_alloc_page_tables(image); |
97 | } | 121 | } |
98 | 122 | ||
99 | /* | 123 | /* |
@@ -104,6 +128,7 @@ void machine_kexec_cleanup(struct kimage *image) | |||
104 | { | 128 | { |
105 | if (nx_enabled) | 129 | if (nx_enabled) |
106 | set_pages_nx(image->control_code_page, 1); | 130 | set_pages_nx(image->control_code_page, 1); |
131 | machine_kexec_free_page_tables(image); | ||
107 | } | 132 | } |
108 | 133 | ||
109 | /* | 134 | /* |
@@ -150,18 +175,18 @@ void machine_kexec(struct kimage *image) | |||
150 | relocate_kernel_ptr = control_page; | 175 | relocate_kernel_ptr = control_page; |
151 | page_list[PA_CONTROL_PAGE] = __pa(control_page); | 176 | page_list[PA_CONTROL_PAGE] = __pa(control_page); |
152 | page_list[VA_CONTROL_PAGE] = (unsigned long)control_page; | 177 | page_list[VA_CONTROL_PAGE] = (unsigned long)control_page; |
153 | page_list[PA_PGD] = __pa(kexec_pgd); | 178 | page_list[PA_PGD] = __pa(image->arch.pgd); |
154 | page_list[VA_PGD] = (unsigned long)kexec_pgd; | 179 | page_list[VA_PGD] = (unsigned long)image->arch.pgd; |
155 | #ifdef CONFIG_X86_PAE | 180 | #ifdef CONFIG_X86_PAE |
156 | page_list[PA_PMD_0] = __pa(kexec_pmd0); | 181 | page_list[PA_PMD_0] = __pa(image->arch.pmd0); |
157 | page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; | 182 | page_list[VA_PMD_0] = (unsigned long)image->arch.pmd0; |
158 | page_list[PA_PMD_1] = __pa(kexec_pmd1); | 183 | page_list[PA_PMD_1] = __pa(image->arch.pmd1); |
159 | page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; | 184 | page_list[VA_PMD_1] = (unsigned long)image->arch.pmd1; |
160 | #endif | 185 | #endif |
161 | page_list[PA_PTE_0] = __pa(kexec_pte0); | 186 | page_list[PA_PTE_0] = __pa(image->arch.pte0); |
162 | page_list[VA_PTE_0] = (unsigned long)kexec_pte0; | 187 | page_list[VA_PTE_0] = (unsigned long)image->arch.pte0; |
163 | page_list[PA_PTE_1] = __pa(kexec_pte1); | 188 | page_list[PA_PTE_1] = __pa(image->arch.pte1); |
164 | page_list[VA_PTE_1] = (unsigned long)kexec_pte1; | 189 | page_list[VA_PTE_1] = (unsigned long)image->arch.pte1; |
165 | 190 | ||
166 | if (image->type == KEXEC_TYPE_DEFAULT) | 191 | if (image->type == KEXEC_TYPE_DEFAULT) |
167 | page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) | 192 | page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) |