diff options
Diffstat (limited to 'arch/x86/realmode/init.c')
-rw-r--r-- | arch/x86/realmode/init.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 705e3fffb4a1..5db706f14111 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c | |||
@@ -1,9 +1,11 @@ | |||
1 | #include <linux/io.h> | 1 | #include <linux/io.h> |
2 | #include <linux/slab.h> | ||
2 | #include <linux/memblock.h> | 3 | #include <linux/memblock.h> |
3 | 4 | ||
4 | #include <asm/cacheflush.h> | 5 | #include <asm/cacheflush.h> |
5 | #include <asm/pgtable.h> | 6 | #include <asm/pgtable.h> |
6 | #include <asm/realmode.h> | 7 | #include <asm/realmode.h> |
8 | #include <asm/tlbflush.h> | ||
7 | 9 | ||
8 | struct real_mode_header *real_mode_header; | 10 | struct real_mode_header *real_mode_header; |
9 | u32 *trampoline_cr4_features; | 11 | u32 *trampoline_cr4_features; |
@@ -11,25 +13,37 @@ u32 *trampoline_cr4_features; | |||
11 | /* Hold the pgd entry used on booting additional CPUs */ | 13 | /* Hold the pgd entry used on booting additional CPUs */ |
12 | pgd_t trampoline_pgd_entry; | 14 | pgd_t trampoline_pgd_entry; |
13 | 15 | ||
16 | void __init set_real_mode_mem(phys_addr_t mem, size_t size) | ||
17 | { | ||
18 | void *base = __va(mem); | ||
19 | |||
20 | real_mode_header = (struct real_mode_header *) base; | ||
21 | printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", | ||
22 | base, (unsigned long long)mem, size); | ||
23 | } | ||
24 | |||
14 | void __init reserve_real_mode(void) | 25 | void __init reserve_real_mode(void) |
15 | { | 26 | { |
16 | phys_addr_t mem; | 27 | phys_addr_t mem; |
17 | unsigned char *base; | 28 | size_t size = real_mode_size_needed(); |
18 | size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); | 29 | |
30 | if (!size) | ||
31 | return; | ||
32 | |||
33 | WARN_ON(slab_is_available()); | ||
19 | 34 | ||
20 | /* Has to be under 1M so we can execute real-mode AP code. */ | 35 | /* Has to be under 1M so we can execute real-mode AP code. */ |
21 | mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); | 36 | mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); |
22 | if (!mem) | 37 | if (!mem) { |
23 | panic("Cannot allocate trampoline\n"); | 38 | pr_info("No sub-1M memory is available for the trampoline\n"); |
39 | return; | ||
40 | } | ||
24 | 41 | ||
25 | base = __va(mem); | ||
26 | memblock_reserve(mem, size); | 42 | memblock_reserve(mem, size); |
27 | real_mode_header = (struct real_mode_header *) base; | 43 | set_real_mode_mem(mem, size); |
28 | printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", | ||
29 | base, (unsigned long long)mem, size); | ||
30 | } | 44 | } |
31 | 45 | ||
32 | void __init setup_real_mode(void) | 46 | static void __init setup_real_mode(void) |
33 | { | 47 | { |
34 | u16 real_mode_seg; | 48 | u16 real_mode_seg; |
35 | const u32 *rel; | 49 | const u32 *rel; |
@@ -84,7 +98,7 @@ void __init setup_real_mode(void) | |||
84 | 98 | ||
85 | trampoline_header->start = (u64) secondary_startup_64; | 99 | trampoline_header->start = (u64) secondary_startup_64; |
86 | trampoline_cr4_features = &trampoline_header->cr4; | 100 | trampoline_cr4_features = &trampoline_header->cr4; |
87 | *trampoline_cr4_features = __read_cr4(); | 101 | *trampoline_cr4_features = mmu_cr4_features; |
88 | 102 | ||
89 | trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); | 103 | trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); |
90 | trampoline_pgd[0] = trampoline_pgd_entry.pgd; | 104 | trampoline_pgd[0] = trampoline_pgd_entry.pgd; |
@@ -100,7 +114,7 @@ void __init setup_real_mode(void) | |||
100 | * need to mark it executable at do_pre_smp_initcalls() at least, | 114 | * need to mark it executable at do_pre_smp_initcalls() at least, |
101 | * thus run it as a early_initcall(). | 115 | * thus run it as a early_initcall(). |
102 | */ | 116 | */ |
103 | static int __init set_real_mode_permissions(void) | 117 | static void __init set_real_mode_permissions(void) |
104 | { | 118 | { |
105 | unsigned char *base = (unsigned char *) real_mode_header; | 119 | unsigned char *base = (unsigned char *) real_mode_header; |
106 | size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); | 120 | size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); |
@@ -119,7 +133,16 @@ static int __init set_real_mode_permissions(void) | |||
119 | set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); | 133 | set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); |
120 | set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); | 134 | set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); |
121 | set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); | 135 | set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); |
136 | } | ||
137 | |||
138 | static int __init init_real_mode(void) | ||
139 | { | ||
140 | if (!real_mode_header) | ||
141 | panic("Real mode trampoline was not allocated"); | ||
142 | |||
143 | setup_real_mode(); | ||
144 | set_real_mode_permissions(); | ||
122 | 145 | ||
123 | return 0; | 146 | return 0; |
124 | } | 147 | } |
125 | early_initcall(set_real_mode_permissions); | 148 | early_initcall(init_real_mode); |