View | Details | Raw Unified | Return to bug 23202
Collapse All | Expand All

(-)a/arch/x86/include/asm/efi.h (+3 lines)
Lines 93-98 extern int add_efi_memmap; Link Here
93
extern void efi_memblock_x86_reserve_range(void);
93
extern void efi_memblock_x86_reserve_range(void);
94
extern void efi_call_phys_prelog(void);
94
extern void efi_call_phys_prelog(void);
95
extern void efi_call_phys_epilog(void);
95
extern void efi_call_phys_epilog(void);
96
extern void efi_call_phys_prelog_in_physmode(void);
97
extern void efi_call_phys_epilog_in_physmode(void);
98
extern void efi_pagetable_init(void);
96
99
97
#ifndef CONFIG_EFI
100
#ifndef CONFIG_EFI
98
/*
101
/*
(-)a/arch/x86/platform/efi/efi.c (-2 / +140 lines)
Lines 58-63 struct efi_memory_map memmap; Link Here
58
58
59
static struct efi efi_phys __initdata;
59
static struct efi efi_phys __initdata;
60
static efi_system_table_t efi_systab __initdata;
60
static efi_system_table_t efi_systab __initdata;
61
static efi_runtime_services_t phys_runtime;
61
62
62
static int __init setup_noefi(char *arg)
63
static int __init setup_noefi(char *arg)
63
{
64
{
Lines 172-178 static efi_status_t __init phys_efi_set_virtual_address_map( Link Here
172
	return status;
173
	return status;
173
}
174
}
174
175
175
static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
176
static efi_status_t __init phys_efi_get_time_early(efi_time_t *tm,
176
					     efi_time_cap_t *tc)
177
					     efi_time_cap_t *tc)
177
{
178
{
178
	efi_status_t status;
179
	efi_status_t status;
Lines 183-188 static efi_status_t __init phys_efi_get_time(efi_time_t *tm, Link Here
183
	return status;
184
	return status;
184
}
185
}
185
186
187
static efi_status_t phys_efi_get_time(efi_time_t *tm,
188
				      efi_time_cap_t *tc)
189
{
190
	efi_status_t status;
191
192
	efi_call_phys_prelog_in_physmode();
193
	status = efi_call_phys2((void*)phys_runtime.get_time, tm, tc);
194
	efi_call_phys_epilog_in_physmode();
195
	return status;
196
}
197
198
static efi_status_t __init phys_efi_set_time(efi_time_t *tm)
199
{
200
	efi_status_t status;
201
202
	efi_call_phys_prelog_in_physmode();
203
	status = efi_call_phys1((void*)phys_runtime.set_time, tm);
204
	efi_call_phys_epilog_in_physmode();
205
	return status;
206
}
207
208
static efi_status_t phys_efi_get_wakeup_time(efi_bool_t *enabled,
209
                                             efi_bool_t *pending,
210
                                             efi_time_t *tm)
211
{
212
	efi_status_t status;
213
214
	efi_call_phys_prelog_in_physmode();
215
	status = efi_call_phys3((void*)phys_runtime.get_wakeup_time, enabled,
216
				pending, tm);
217
	efi_call_phys_epilog_in_physmode();
218
	return status;
219
}
220
221
static efi_status_t phys_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
222
{
223
	efi_status_t status;
224
	efi_call_phys_prelog_in_physmode();
225
	status = efi_call_phys2((void*)phys_runtime.set_wakeup_time, enabled,
226
				tm);
227
	efi_call_phys_epilog_in_physmode();
228
	return status;
229
}
230
231
static efi_status_t phys_efi_get_variable(efi_char16_t *name,
232
					  efi_guid_t *vendor,
233
					  u32 *attr,
234
					  unsigned long *data_size,
235
					  void *data)
236
{
237
	efi_status_t status;
238
	efi_call_phys_prelog_in_physmode();
239
	status = efi_call_phys5((void*)phys_runtime.get_variable, name, vendor,
240
				attr, data_size, data);
241
	efi_call_phys_epilog_in_physmode();
242
	return status;
243
}
244
245
static efi_status_t phys_efi_get_next_variable(unsigned long *name_size,
246
					       efi_char16_t *name,
247
					       efi_guid_t *vendor)
248
{
249
	efi_status_t status;
250
251
	efi_call_phys_prelog_in_physmode();
252
	status = efi_call_phys3((void*)phys_runtime.get_next_variable,
253
				name_size, name, vendor);
254
	efi_call_phys_epilog_in_physmode();
255
	return status;
256
}
257
258
static efi_status_t phys_efi_set_variable(efi_char16_t *name,
259
					  efi_guid_t *vendor,
260
					  unsigned long attr,
261
					  unsigned long data_size,
262
					  void *data)
263
{
264
	efi_status_t status;
265
	efi_call_phys_prelog_in_physmode();
266
	status = efi_call_phys5((void*)phys_runtime.set_variable, name,
267
				vendor, attr, data_size, data);
268
	efi_call_phys_epilog_in_physmode();
269
	return status;
270
}
271
272
static efi_status_t phys_efi_get_next_high_mono_count(u32 *count)
273
{
274
	efi_status_t status;
275
	efi_call_phys_prelog_in_physmode();
276
	status = efi_call_phys1((void*)phys_runtime.get_next_high_mono_count,
277
				count);
278
	efi_call_phys_epilog_in_physmode();
279
	return status;
280
}
281
282
static void phys_efi_reset_system(int reset_type,
283
                                  efi_status_t status,
284
                                  unsigned long data_size,
285
                                  efi_char16_t *data)
286
{
287
	efi_call_phys_prelog_in_physmode();
288
	efi_call_phys4((void*)phys_runtime.reset_system, reset_type, status,
289
				data_size, data);
290
	efi_call_phys_epilog_in_physmode();
291
}
292
186
int efi_set_rtc_mmss(unsigned long nowtime)
293
int efi_set_rtc_mmss(unsigned long nowtime)
187
{
294
{
188
	int real_seconds, real_minutes;
295
	int real_seconds, real_minutes;
Lines 435-441 void __init efi_init(void) Link Here
435
		 * Make efi_get_time can be called before entering
542
		 * Make efi_get_time can be called before entering
436
		 * virtual mode.
543
		 * virtual mode.
437
		 */
544
		 */
438
		efi.get_time = phys_efi_get_time;
545
		efi.get_time = phys_efi_get_time_early;
546
547
		memcpy(&phys_runtime, runtime, sizeof(efi_runtime_services_t));
439
	} else
548
	} else
440
		printk(KERN_ERR "Could not map the EFI runtime service "
549
		printk(KERN_ERR "Could not map the EFI runtime service "
441
		       "table!\n");
550
		       "table!\n");
Lines 466-471 void __init efi_init(void) Link Here
466
#if EFI_DEBUG
575
#if EFI_DEBUG
467
	print_efi_memmap();
576
	print_efi_memmap();
468
#endif
577
#endif
578
579
#ifndef CONFIG_X86_64
580
	/*
581
	 * Only x86_64 supports physical mode as of now. Use virtual mode
582
	 * forcibly.
583
	 */
584
	usevirtefi = 1;
585
#endif
469
}
586
}
470
587
471
static void __init runtime_code_page_mkexec(void)
588
static void __init runtime_code_page_mkexec(void)
Lines 579-584 void __init efi_enter_virtual_mode(void) Link Here
579
	memmap.map = NULL;
696
	memmap.map = NULL;
580
}
697
}
581
698
699
void __init efi_setup_physical_mode(void)
700
{
701
#ifdef CONFIG_X86_64
702
	efi_pagetable_init();
703
#endif
704
	efi.get_time = phys_efi_get_time;
705
	efi.set_time = phys_efi_set_time;
706
	efi.get_wakeup_time = phys_efi_get_wakeup_time;
707
	efi.set_wakeup_time = phys_efi_set_wakeup_time;
708
	efi.get_variable = phys_efi_get_variable;
709
	efi.get_next_variable = phys_efi_get_next_variable;
710
	efi.set_variable = phys_efi_set_variable;
711
	efi.get_next_high_mono_count =
712
		phys_efi_get_next_high_mono_count;
713
	efi.reset_system = phys_efi_reset_system;
714
	efi.set_virtual_address_map = NULL; /* Not needed */
715
716
	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
717
	memmap.map = NULL;
718
}
719
582
/*
720
/*
583
 * Convenience functions to obtain memory types and attributes
721
 * Convenience functions to obtain memory types and attributes
584
 */
722
 */
(-)a/arch/x86/platform/efi/efi_32.c (+4 lines)
Lines 110-112 void efi_call_phys_epilog(void) Link Here
110
110
111
	local_irq_restore(efi_rt_eflags);
111
	local_irq_restore(efi_rt_eflags);
112
}
112
}
113
114
void efi_call_phys_prelog_in_physmode(void) { /* Not supported */ }
115
void efi_call_phys_epilog_in_physmode(void) { /* Not supported */ }
116
(-)a/arch/x86/platform/efi/efi_64.c (-3 / +93 lines)
Lines 39-45 Link Here
39
#include <asm/fixmap.h>
39
#include <asm/fixmap.h>
40
40
41
static pgd_t save_pgd __initdata;
41
static pgd_t save_pgd __initdata;
42
static unsigned long efi_flags __initdata;
42
static DEFINE_PER_CPU(unsigned long, efi_flags);
43
static DEFINE_PER_CPU(unsigned long, save_cr3);
44
static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
43
45
44
static void __init early_mapping_set_exec(unsigned long start,
46
static void __init early_mapping_set_exec(unsigned long start,
45
					  unsigned long end,
47
					  unsigned long end,
Lines 80-86 void __init efi_call_phys_prelog(void) Link Here
80
	unsigned long vaddress;
82
	unsigned long vaddress;
81
83
82
	early_runtime_code_mapping_set_exec(1);
84
	early_runtime_code_mapping_set_exec(1);
83
	local_irq_save(efi_flags);
85
	local_irq_save(get_cpu_var(efi_flags));
84
	vaddress = (unsigned long)__va(0x0UL);
86
	vaddress = (unsigned long)__va(0x0UL);
85
	save_pgd = *pgd_offset_k(0x0UL);
87
	save_pgd = *pgd_offset_k(0x0UL);
86
	set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
88
	set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
Lines 94-103 void __init efi_call_phys_epilog(void) Link Here
94
	 */
96
	 */
95
	set_pgd(pgd_offset_k(0x0UL), save_pgd);
97
	set_pgd(pgd_offset_k(0x0UL), save_pgd);
96
	__flush_tlb_all();
98
	__flush_tlb_all();
97
	local_irq_restore(efi_flags);
99
	local_irq_restore(get_cpu_var(efi_flags));
98
	early_runtime_code_mapping_set_exec(0);
100
	early_runtime_code_mapping_set_exec(0);
99
}
101
}
100
102
103
void efi_call_phys_prelog_in_physmode(void)
104
{
105
	local_irq_save(get_cpu_var(efi_flags));
106
	get_cpu_var(save_cr3)= read_cr3();
107
	write_cr3(virt_to_phys(efi_pgd));
108
}
109
110
void efi_call_phys_epilog_in_physmode(void)
111
{
112
	write_cr3(get_cpu_var(save_cr3));
113
	local_irq_restore(get_cpu_var(efi_flags));
114
}
115
101
void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
116
void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
102
				 u32 type)
117
				 u32 type)
103
{
118
{
Lines 112-114 void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size, Link Here
112
127
113
	return (void __iomem *)__va(phys_addr);
128
	return (void __iomem *)__va(phys_addr);
114
}
129
}
130
131
static pud_t *fill_pud(pgd_t *pgd, unsigned long vaddr)
132
{
133
	if (pgd_none(*pgd)) {
134
		pud_t *pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
135
		set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
136
		if (pud != pud_offset(pgd, 0))
137
			printk(KERN_ERR "EFI PAGETABLE BUG #00! %p <-> %p\n",
138
			       pud, pud_offset(pgd, 0));
139
	}
140
	return pud_offset(pgd, vaddr);
141
}
142
143
static pmd_t *fill_pmd(pud_t *pud, unsigned long vaddr)
144
{
145
	if (pud_none(*pud)) {
146
		pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
147
		set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
148
		if (pmd != pmd_offset(pud, 0))
149
			printk(KERN_ERR "EFI PAGETABLE BUG #01! %p <-> %p\n",
150
			       pmd, pmd_offset(pud, 0));
151
	}
152
	return pmd_offset(pud, vaddr);
153
}
154
155
static pte_t *fill_pte(pmd_t *pmd, unsigned long vaddr)
156
{
157
	if (pmd_none(*pmd)) {
158
		pte_t *pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
159
		set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)));
160
		if (pte != pte_offset_kernel(pmd, 0))
161
			printk(KERN_ERR "EFI PAGETABLE BUG #02!\n");
162
	}
163
	return pte_offset_kernel(pmd, vaddr);
164
}
165
166
void __init efi_pagetable_init(void)
167
{
168
	efi_memory_desc_t *md;
169
	unsigned long size;
170
	u64 start_pfn, end_pfn, pfn, vaddr;
171
	void *p;
172
	pgd_t *pgd;
173
	pud_t *pud;
174
	pmd_t *pmd;
175
	pte_t *pte;
176
177
	memset(efi_pgd, 0, sizeof(efi_pgd));
178
	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
179
		md = p;
180
		if (!(md->type & EFI_RUNTIME_SERVICES_CODE) &&
181
		    !(md->type & EFI_RUNTIME_SERVICES_DATA))
182
			continue;
183
184
		start_pfn = md->phys_addr >> PAGE_SHIFT;
185
		size = md->num_pages << EFI_PAGE_SHIFT;
186
		end_pfn = PFN_UP(md->phys_addr + size);
187
188
		for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
189
			vaddr = pfn << PAGE_SHIFT;
190
			pgd = efi_pgd + pgd_index(vaddr);
191
			pud = fill_pud(pgd, vaddr);
192
			pmd = fill_pmd(pud, vaddr);
193
			pte = fill_pte(pmd, vaddr);
194
			if (md->type & EFI_RUNTIME_SERVICES_CODE)
195
				set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
196
			else
197
				set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
198
		}
199
	}
200
	pgd = efi_pgd + pgd_index(PAGE_OFFSET);
201
	set_pgd(pgd, *pgd_offset_k(PAGE_OFFSET));
202
	pgd = efi_pgd + pgd_index(__START_KERNEL_map);
203
	set_pgd(pgd, *pgd_offset_k(__START_KERNEL_map));
204
}
(-)a/include/linux/efi.h (+1 lines)
Lines 290-295 extern void efi_map_pal_code (void); Link Here
290
extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
290
extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
291
extern void efi_gettimeofday (struct timespec *ts);
291
extern void efi_gettimeofday (struct timespec *ts);
292
extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
292
extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
293
extern void efi_setup_physical_mode(void);
293
extern u64 efi_get_iobase (void);
294
extern u64 efi_get_iobase (void);
294
extern u32 efi_mem_type (unsigned long phys_addr);
295
extern u32 efi_mem_type (unsigned long phys_addr);
295
extern u64 efi_mem_attributes (unsigned long phys_addr);
296
extern u64 efi_mem_attributes (unsigned long phys_addr);
(-)a/include/linux/init.h (+1 lines)
Lines 149-154 extern int do_one_initcall(initcall_t fn); Link Here
149
extern char __initdata boot_command_line[];
149
extern char __initdata boot_command_line[];
150
extern char *saved_command_line;
150
extern char *saved_command_line;
151
extern unsigned int reset_devices;
151
extern unsigned int reset_devices;
152
extern unsigned int usevirtefi;
152
153
153
/* used by init/main.c */
154
/* used by init/main.c */
154
void setup_arch(char **);
155
void setup_arch(char **);
(-)a/init/main.c (-3 / +14 lines)
Lines 197-202 static int __init set_reset_devices(char *str) Link Here
197
197
198
__setup("reset_devices", set_reset_devices);
198
__setup("reset_devices", set_reset_devices);
199
199
200
unsigned int usevirtefi;
201
static int __init set_virt_efi(char *str)
202
{
203
	usevirtefi = 1;
204
	return 1;
205
}
206
__setup("virtefi", set_virt_efi);
207
200
static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
208
static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
201
const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
209
const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
202
static const char *panic_later, *panic_param;
210
static const char *panic_later, *panic_param;
Lines 669-676 asmlinkage void __init start_kernel(void) Link Here
669
	pidmap_init();
677
	pidmap_init();
670
	anon_vma_init();
678
	anon_vma_init();
671
#ifdef CONFIG_X86
679
#ifdef CONFIG_X86
672
	if (efi_enabled)
680
	if (efi_enabled) {
673
		efi_enter_virtual_mode();
681
		if (usevirtefi)
682
			efi_enter_virtual_mode();
683
		else
684
			efi_setup_physical_mode();
685
	}
674
#endif
686
#endif
675
	thread_info_cache_init();
687
	thread_info_cache_init();
676
	cred_init();
688
	cred_init();
677
- 

Return to bug 23202