diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/kernel/efi.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/i386/kernel/efi.c')
-rw-r--r-- | arch/i386/kernel/efi.c | 635 |
1 files changed, 635 insertions, 0 deletions
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c new file mode 100644 index 000000000000..9e5e0d8bd36e --- /dev/null +++ b/arch/i386/kernel/efi.c | |||
@@ -0,0 +1,635 @@ | |||
1 | /* | ||
2 | * Extensible Firmware Interface | ||
3 | * | ||
4 | * Based on Extensible Firmware Interface Specification version 1.0 | ||
5 | * | ||
6 | * Copyright (C) 1999 VA Linux Systems | ||
7 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> | ||
8 | * Copyright (C) 1999-2002 Hewlett-Packard Co. | ||
9 | * David Mosberger-Tang <davidm@hpl.hp.com> | ||
10 | * Stephane Eranian <eranian@hpl.hp.com> | ||
11 | * | ||
12 | * All EFI Runtime Services are not implemented yet as EFI only | ||
13 | * supports physical mode addressing on SoftSDV. This is to be fixed | ||
14 | * in a future version. --drummond 1999-07-20 | ||
15 | * | ||
16 | * Implemented EFI runtime services and virtual mode calls. --davidm | ||
17 | * | ||
18 | * Goutham Rao: <goutham.rao@intel.com> | ||
19 | * Skip non-WB memory and ignore empty memory ranges. | ||
20 | */ | ||
21 | |||
22 | #include <linux/config.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/time.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/bootmem.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/efi.h> | ||
33 | |||
34 | #include <asm/setup.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/page.h> | ||
37 | #include <asm/pgtable.h> | ||
38 | #include <asm/processor.h> | ||
39 | #include <asm/desc.h> | ||
40 | #include <asm/tlbflush.h> | ||
41 | |||
42 | #define EFI_DEBUG 0 | ||
43 | #define PFX "EFI: " | ||
44 | |||
45 | extern efi_status_t asmlinkage efi_call_phys(void *, ...); | ||
46 | |||
47 | struct efi efi; | ||
48 | EXPORT_SYMBOL(efi); | ||
49 | static struct efi efi_phys __initdata; | ||
50 | struct efi_memory_map memmap __initdata; | ||
51 | |||
52 | /* | ||
53 | * We require an early boot_ioremap mapping mechanism initially | ||
54 | */ | ||
55 | extern void * boot_ioremap(unsigned long, unsigned long); | ||
56 | |||
57 | /* | ||
58 | * To make EFI call EFI runtime service in physical addressing mode we need | ||
59 | * prelog/epilog before/after the invocation to disable interrupt, to | ||
60 | * claim EFI runtime service handler exclusively and to duplicate a memory in | ||
61 | * low memory space say 0 - 3G. | ||
62 | */ | ||
63 | |||
64 | static unsigned long efi_rt_eflags; | ||
65 | static DEFINE_SPINLOCK(efi_rt_lock); | ||
66 | static pgd_t efi_bak_pg_dir_pointer[2]; | ||
67 | |||
68 | static void efi_call_phys_prelog(void) | ||
69 | { | ||
70 | unsigned long cr4; | ||
71 | unsigned long temp; | ||
72 | |||
73 | spin_lock(&efi_rt_lock); | ||
74 | local_irq_save(efi_rt_eflags); | ||
75 | |||
76 | /* | ||
77 | * If I don't have PSE, I should just duplicate two entries in page | ||
78 | * directory. If I have PSE, I just need to duplicate one entry in | ||
79 | * page directory. | ||
80 | */ | ||
81 | __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4)); | ||
82 | |||
83 | if (cr4 & X86_CR4_PSE) { | ||
84 | efi_bak_pg_dir_pointer[0].pgd = | ||
85 | swapper_pg_dir[pgd_index(0)].pgd; | ||
86 | swapper_pg_dir[0].pgd = | ||
87 | swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd; | ||
88 | } else { | ||
89 | efi_bak_pg_dir_pointer[0].pgd = | ||
90 | swapper_pg_dir[pgd_index(0)].pgd; | ||
91 | efi_bak_pg_dir_pointer[1].pgd = | ||
92 | swapper_pg_dir[pgd_index(0x400000)].pgd; | ||
93 | swapper_pg_dir[pgd_index(0)].pgd = | ||
94 | swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd; | ||
95 | temp = PAGE_OFFSET + 0x400000; | ||
96 | swapper_pg_dir[pgd_index(0x400000)].pgd = | ||
97 | swapper_pg_dir[pgd_index(temp)].pgd; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * After the lock is released, the original page table is restored. | ||
102 | */ | ||
103 | local_flush_tlb(); | ||
104 | |||
105 | cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address); | ||
106 | __asm__ __volatile__("lgdt %0":"=m" | ||
107 | (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0]))); | ||
108 | } | ||
109 | |||
110 | static void efi_call_phys_epilog(void) | ||
111 | { | ||
112 | unsigned long cr4; | ||
113 | |||
114 | cpu_gdt_descr[0].address = | ||
115 | (unsigned long) __va(cpu_gdt_descr[0].address); | ||
116 | __asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr)); | ||
117 | __asm__ __volatile__("movl %%cr4, %0":"=r"(cr4)); | ||
118 | |||
119 | if (cr4 & X86_CR4_PSE) { | ||
120 | swapper_pg_dir[pgd_index(0)].pgd = | ||
121 | efi_bak_pg_dir_pointer[0].pgd; | ||
122 | } else { | ||
123 | swapper_pg_dir[pgd_index(0)].pgd = | ||
124 | efi_bak_pg_dir_pointer[0].pgd; | ||
125 | swapper_pg_dir[pgd_index(0x400000)].pgd = | ||
126 | efi_bak_pg_dir_pointer[1].pgd; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * After the lock is released, the original page table is restored. | ||
131 | */ | ||
132 | local_flush_tlb(); | ||
133 | |||
134 | local_irq_restore(efi_rt_eflags); | ||
135 | spin_unlock(&efi_rt_lock); | ||
136 | } | ||
137 | |||
138 | static efi_status_t | ||
139 | phys_efi_set_virtual_address_map(unsigned long memory_map_size, | ||
140 | unsigned long descriptor_size, | ||
141 | u32 descriptor_version, | ||
142 | efi_memory_desc_t *virtual_map) | ||
143 | { | ||
144 | efi_status_t status; | ||
145 | |||
146 | efi_call_phys_prelog(); | ||
147 | status = efi_call_phys(efi_phys.set_virtual_address_map, | ||
148 | memory_map_size, descriptor_size, | ||
149 | descriptor_version, virtual_map); | ||
150 | efi_call_phys_epilog(); | ||
151 | return status; | ||
152 | } | ||
153 | |||
154 | static efi_status_t | ||
155 | phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) | ||
156 | { | ||
157 | efi_status_t status; | ||
158 | |||
159 | efi_call_phys_prelog(); | ||
160 | status = efi_call_phys(efi_phys.get_time, tm, tc); | ||
161 | efi_call_phys_epilog(); | ||
162 | return status; | ||
163 | } | ||
164 | |||
165 | inline int efi_set_rtc_mmss(unsigned long nowtime) | ||
166 | { | ||
167 | int real_seconds, real_minutes; | ||
168 | efi_status_t status; | ||
169 | efi_time_t eft; | ||
170 | efi_time_cap_t cap; | ||
171 | |||
172 | spin_lock(&efi_rt_lock); | ||
173 | status = efi.get_time(&eft, &cap); | ||
174 | spin_unlock(&efi_rt_lock); | ||
175 | if (status != EFI_SUCCESS) | ||
176 | panic("Ooops, efitime: can't read time!\n"); | ||
177 | real_seconds = nowtime % 60; | ||
178 | real_minutes = nowtime / 60; | ||
179 | |||
180 | if (((abs(real_minutes - eft.minute) + 15)/30) & 1) | ||
181 | real_minutes += 30; | ||
182 | real_minutes %= 60; | ||
183 | |||
184 | eft.minute = real_minutes; | ||
185 | eft.second = real_seconds; | ||
186 | |||
187 | if (status != EFI_SUCCESS) { | ||
188 | printk("Ooops: efitime: can't read time!\n"); | ||
189 | return -1; | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | /* | ||
194 | * This should only be used during kernel init and before runtime | ||
195 | * services have been remapped, therefore, we'll need to call in physical | ||
196 | * mode. Note, this call isn't used later, so mark it __init. | ||
197 | */ | ||
198 | inline unsigned long __init efi_get_time(void) | ||
199 | { | ||
200 | efi_status_t status; | ||
201 | efi_time_t eft; | ||
202 | efi_time_cap_t cap; | ||
203 | |||
204 | status = phys_efi_get_time(&eft, &cap); | ||
205 | if (status != EFI_SUCCESS) | ||
206 | printk("Oops: efitime: can't read time status: 0x%lx\n",status); | ||
207 | |||
208 | return mktime(eft.year, eft.month, eft.day, eft.hour, | ||
209 | eft.minute, eft.second); | ||
210 | } | ||
211 | |||
212 | int is_available_memory(efi_memory_desc_t * md) | ||
213 | { | ||
214 | if (!(md->attribute & EFI_MEMORY_WB)) | ||
215 | return 0; | ||
216 | |||
217 | switch (md->type) { | ||
218 | case EFI_LOADER_CODE: | ||
219 | case EFI_LOADER_DATA: | ||
220 | case EFI_BOOT_SERVICES_CODE: | ||
221 | case EFI_BOOT_SERVICES_DATA: | ||
222 | case EFI_CONVENTIONAL_MEMORY: | ||
223 | return 1; | ||
224 | } | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * We need to map the EFI memory map again after paging_init(). | ||
230 | */ | ||
231 | void __init efi_map_memmap(void) | ||
232 | { | ||
233 | memmap.map = NULL; | ||
234 | |||
235 | memmap.map = (efi_memory_desc_t *) | ||
236 | bt_ioremap((unsigned long) memmap.phys_map, | ||
237 | (memmap.nr_map * sizeof(efi_memory_desc_t))); | ||
238 | |||
239 | if (memmap.map == NULL) | ||
240 | printk(KERN_ERR PFX "Could not remap the EFI memmap!\n"); | ||
241 | } | ||
242 | |||
243 | #if EFI_DEBUG | ||
244 | static void __init print_efi_memmap(void) | ||
245 | { | ||
246 | efi_memory_desc_t *md; | ||
247 | int i; | ||
248 | |||
249 | for (i = 0; i < memmap.nr_map; i++) { | ||
250 | md = &memmap.map[i]; | ||
251 | printk(KERN_INFO "mem%02u: type=%u, attr=0x%llx, " | ||
252 | "range=[0x%016llx-0x%016llx) (%lluMB)\n", | ||
253 | i, md->type, md->attribute, md->phys_addr, | ||
254 | md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), | ||
255 | (md->num_pages >> (20 - EFI_PAGE_SHIFT))); | ||
256 | } | ||
257 | } | ||
258 | #endif /* EFI_DEBUG */ | ||
259 | |||
260 | /* | ||
261 | * Walks the EFI memory map and calls CALLBACK once for each EFI | ||
262 | * memory descriptor that has memory that is available for kernel use. | ||
263 | */ | ||
264 | void efi_memmap_walk(efi_freemem_callback_t callback, void *arg) | ||
265 | { | ||
266 | int prev_valid = 0; | ||
267 | struct range { | ||
268 | unsigned long start; | ||
269 | unsigned long end; | ||
270 | } prev, curr; | ||
271 | efi_memory_desc_t *md; | ||
272 | unsigned long start, end; | ||
273 | int i; | ||
274 | |||
275 | for (i = 0; i < memmap.nr_map; i++) { | ||
276 | md = &memmap.map[i]; | ||
277 | |||
278 | if ((md->num_pages == 0) || (!is_available_memory(md))) | ||
279 | continue; | ||
280 | |||
281 | curr.start = md->phys_addr; | ||
282 | curr.end = curr.start + (md->num_pages << EFI_PAGE_SHIFT); | ||
283 | |||
284 | if (!prev_valid) { | ||
285 | prev = curr; | ||
286 | prev_valid = 1; | ||
287 | } else { | ||
288 | if (curr.start < prev.start) | ||
289 | printk(KERN_INFO PFX "Unordered memory map\n"); | ||
290 | if (prev.end == curr.start) | ||
291 | prev.end = curr.end; | ||
292 | else { | ||
293 | start = | ||
294 | (unsigned long) (PAGE_ALIGN(prev.start)); | ||
295 | end = (unsigned long) (prev.end & PAGE_MASK); | ||
296 | if ((end > start) | ||
297 | && (*callback) (start, end, arg) < 0) | ||
298 | return; | ||
299 | prev = curr; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | if (prev_valid) { | ||
304 | start = (unsigned long) PAGE_ALIGN(prev.start); | ||
305 | end = (unsigned long) (prev.end & PAGE_MASK); | ||
306 | if (end > start) | ||
307 | (*callback) (start, end, arg); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | void __init efi_init(void) | ||
312 | { | ||
313 | efi_config_table_t *config_tables; | ||
314 | efi_runtime_services_t *runtime; | ||
315 | efi_char16_t *c16; | ||
316 | char vendor[100] = "unknown"; | ||
317 | unsigned long num_config_tables; | ||
318 | int i = 0; | ||
319 | |||
320 | memset(&efi, 0, sizeof(efi) ); | ||
321 | memset(&efi_phys, 0, sizeof(efi_phys)); | ||
322 | |||
323 | efi_phys.systab = EFI_SYSTAB; | ||
324 | memmap.phys_map = EFI_MEMMAP; | ||
325 | memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE; | ||
326 | memmap.desc_version = EFI_MEMDESC_VERSION; | ||
327 | |||
328 | efi.systab = (efi_system_table_t *) | ||
329 | boot_ioremap((unsigned long) efi_phys.systab, | ||
330 | sizeof(efi_system_table_t)); | ||
331 | /* | ||
332 | * Verify the EFI Table | ||
333 | */ | ||
334 | if (efi.systab == NULL) | ||
335 | printk(KERN_ERR PFX "Woah! Couldn't map the EFI system table.\n"); | ||
336 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) | ||
337 | printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n"); | ||
338 | if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0) | ||
339 | printk(KERN_ERR PFX | ||
340 | "Warning: EFI system table major version mismatch: " | ||
341 | "got %d.%02d, expected %d.%02d\n", | ||
342 | efi.systab->hdr.revision >> 16, | ||
343 | efi.systab->hdr.revision & 0xffff, | ||
344 | EFI_SYSTEM_TABLE_REVISION >> 16, | ||
345 | EFI_SYSTEM_TABLE_REVISION & 0xffff); | ||
346 | /* | ||
347 | * Grab some details from the system table | ||
348 | */ | ||
349 | num_config_tables = efi.systab->nr_tables; | ||
350 | config_tables = (efi_config_table_t *)efi.systab->tables; | ||
351 | runtime = efi.systab->runtime; | ||
352 | |||
353 | /* | ||
354 | * Show what we know for posterity | ||
355 | */ | ||
356 | c16 = (efi_char16_t *) boot_ioremap(efi.systab->fw_vendor, 2); | ||
357 | if (c16) { | ||
358 | for (i = 0; i < sizeof(vendor) && *c16; ++i) | ||
359 | vendor[i] = *c16++; | ||
360 | vendor[i] = '\0'; | ||
361 | } else | ||
362 | printk(KERN_ERR PFX "Could not map the firmware vendor!\n"); | ||
363 | |||
364 | printk(KERN_INFO PFX "EFI v%u.%.02u by %s \n", | ||
365 | efi.systab->hdr.revision >> 16, | ||
366 | efi.systab->hdr.revision & 0xffff, vendor); | ||
367 | |||
368 | /* | ||
369 | * Let's see what config tables the firmware passed to us. | ||
370 | */ | ||
371 | config_tables = (efi_config_table_t *) | ||
372 | boot_ioremap((unsigned long) config_tables, | ||
373 | num_config_tables * sizeof(efi_config_table_t)); | ||
374 | |||
375 | if (config_tables == NULL) | ||
376 | printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n"); | ||
377 | |||
378 | for (i = 0; i < num_config_tables; i++) { | ||
379 | if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) { | ||
380 | efi.mps = (void *)config_tables[i].table; | ||
381 | printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table); | ||
382 | } else | ||
383 | if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) { | ||
384 | efi.acpi20 = __va(config_tables[i].table); | ||
385 | printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table); | ||
386 | } else | ||
387 | if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) { | ||
388 | efi.acpi = __va(config_tables[i].table); | ||
389 | printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table); | ||
390 | } else | ||
391 | if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) { | ||
392 | efi.smbios = (void *) config_tables[i].table; | ||
393 | printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table); | ||
394 | } else | ||
395 | if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { | ||
396 | efi.hcdp = (void *)config_tables[i].table; | ||
397 | printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table); | ||
398 | } else | ||
399 | if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) { | ||
400 | efi.uga = (void *)config_tables[i].table; | ||
401 | printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table); | ||
402 | } | ||
403 | } | ||
404 | printk("\n"); | ||
405 | |||
406 | /* | ||
407 | * Check out the runtime services table. We need to map | ||
408 | * the runtime services table so that we can grab the physical | ||
409 | * address of several of the EFI runtime functions, needed to | ||
410 | * set the firmware into virtual mode. | ||
411 | */ | ||
412 | |||
413 | runtime = (efi_runtime_services_t *) boot_ioremap((unsigned long) | ||
414 | runtime, | ||
415 | sizeof(efi_runtime_services_t)); | ||
416 | if (runtime != NULL) { | ||
417 | /* | ||
418 | * We will only need *early* access to the following | ||
419 | * two EFI runtime services before set_virtual_address_map | ||
420 | * is invoked. | ||
421 | */ | ||
422 | efi_phys.get_time = (efi_get_time_t *) runtime->get_time; | ||
423 | efi_phys.set_virtual_address_map = | ||
424 | (efi_set_virtual_address_map_t *) | ||
425 | runtime->set_virtual_address_map; | ||
426 | } else | ||
427 | printk(KERN_ERR PFX "Could not map the runtime service table!\n"); | ||
428 | |||
429 | /* Map the EFI memory map for use until paging_init() */ | ||
430 | |||
431 | memmap.map = (efi_memory_desc_t *) | ||
432 | boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE); | ||
433 | |||
434 | if (memmap.map == NULL) | ||
435 | printk(KERN_ERR PFX "Could not map the EFI memory map!\n"); | ||
436 | |||
437 | if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) { | ||
438 | printk(KERN_WARNING PFX "Warning! Kernel-defined memdesc doesn't " | ||
439 | "match the one from EFI!\n"); | ||
440 | } | ||
441 | #if EFI_DEBUG | ||
442 | print_efi_memmap(); | ||
443 | #endif | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * This function will switch the EFI runtime services to virtual mode. | ||
448 | * Essentially, look through the EFI memmap and map every region that | ||
449 | * has the runtime attribute bit set in its memory descriptor and update | ||
450 | * that memory descriptor with the virtual address obtained from ioremap(). | ||
451 | * This enables the runtime services to be called without having to | ||
452 | * thunk back into physical mode for every invocation. | ||
453 | */ | ||
454 | |||
455 | void __init efi_enter_virtual_mode(void) | ||
456 | { | ||
457 | efi_memory_desc_t *md; | ||
458 | efi_status_t status; | ||
459 | int i; | ||
460 | |||
461 | efi.systab = NULL; | ||
462 | |||
463 | for (i = 0; i < memmap.nr_map; i++) { | ||
464 | md = &memmap.map[i]; | ||
465 | |||
466 | if (md->attribute & EFI_MEMORY_RUNTIME) { | ||
467 | md->virt_addr = | ||
468 | (unsigned long)ioremap(md->phys_addr, | ||
469 | md->num_pages << EFI_PAGE_SHIFT); | ||
470 | if (!(unsigned long)md->virt_addr) { | ||
471 | printk(KERN_ERR PFX "ioremap of 0x%lX failed\n", | ||
472 | (unsigned long)md->phys_addr); | ||
473 | } | ||
474 | |||
475 | if (((unsigned long)md->phys_addr <= | ||
476 | (unsigned long)efi_phys.systab) && | ||
477 | ((unsigned long)efi_phys.systab < | ||
478 | md->phys_addr + | ||
479 | ((unsigned long)md->num_pages << | ||
480 | EFI_PAGE_SHIFT))) { | ||
481 | unsigned long addr; | ||
482 | |||
483 | addr = md->virt_addr - md->phys_addr + | ||
484 | (unsigned long)efi_phys.systab; | ||
485 | efi.systab = (efi_system_table_t *)addr; | ||
486 | } | ||
487 | } | ||
488 | } | ||
489 | |||
490 | if (!efi.systab) | ||
491 | BUG(); | ||
492 | |||
493 | status = phys_efi_set_virtual_address_map( | ||
494 | sizeof(efi_memory_desc_t) * memmap.nr_map, | ||
495 | sizeof(efi_memory_desc_t), | ||
496 | memmap.desc_version, | ||
497 | memmap.phys_map); | ||
498 | |||
499 | if (status != EFI_SUCCESS) { | ||
500 | printk (KERN_ALERT "You are screwed! " | ||
501 | "Unable to switch EFI into virtual mode " | ||
502 | "(status=%lx)\n", status); | ||
503 | panic("EFI call to SetVirtualAddressMap() failed!"); | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * Now that EFI is in virtual mode, update the function | ||
508 | * pointers in the runtime service table to the new virtual addresses. | ||
509 | */ | ||
510 | |||
511 | efi.get_time = (efi_get_time_t *) efi.systab->runtime->get_time; | ||
512 | efi.set_time = (efi_set_time_t *) efi.systab->runtime->set_time; | ||
513 | efi.get_wakeup_time = (efi_get_wakeup_time_t *) | ||
514 | efi.systab->runtime->get_wakeup_time; | ||
515 | efi.set_wakeup_time = (efi_set_wakeup_time_t *) | ||
516 | efi.systab->runtime->set_wakeup_time; | ||
517 | efi.get_variable = (efi_get_variable_t *) | ||
518 | efi.systab->runtime->get_variable; | ||
519 | efi.get_next_variable = (efi_get_next_variable_t *) | ||
520 | efi.systab->runtime->get_next_variable; | ||
521 | efi.set_variable = (efi_set_variable_t *) | ||
522 | efi.systab->runtime->set_variable; | ||
523 | efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *) | ||
524 | efi.systab->runtime->get_next_high_mono_count; | ||
525 | efi.reset_system = (efi_reset_system_t *) | ||
526 | efi.systab->runtime->reset_system; | ||
527 | } | ||
528 | |||
529 | void __init | ||
530 | efi_initialize_iomem_resources(struct resource *code_resource, | ||
531 | struct resource *data_resource) | ||
532 | { | ||
533 | struct resource *res; | ||
534 | efi_memory_desc_t *md; | ||
535 | int i; | ||
536 | |||
537 | for (i = 0; i < memmap.nr_map; i++) { | ||
538 | md = &memmap.map[i]; | ||
539 | |||
540 | if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) > | ||
541 | 0x100000000ULL) | ||
542 | continue; | ||
543 | res = alloc_bootmem_low(sizeof(struct resource)); | ||
544 | switch (md->type) { | ||
545 | case EFI_RESERVED_TYPE: | ||
546 | res->name = "Reserved Memory"; | ||
547 | break; | ||
548 | case EFI_LOADER_CODE: | ||
549 | res->name = "Loader Code"; | ||
550 | break; | ||
551 | case EFI_LOADER_DATA: | ||
552 | res->name = "Loader Data"; | ||
553 | break; | ||
554 | case EFI_BOOT_SERVICES_DATA: | ||
555 | res->name = "BootServices Data"; | ||
556 | break; | ||
557 | case EFI_BOOT_SERVICES_CODE: | ||
558 | res->name = "BootServices Code"; | ||
559 | break; | ||
560 | case EFI_RUNTIME_SERVICES_CODE: | ||
561 | res->name = "Runtime Service Code"; | ||
562 | break; | ||
563 | case EFI_RUNTIME_SERVICES_DATA: | ||
564 | res->name = "Runtime Service Data"; | ||
565 | break; | ||
566 | case EFI_CONVENTIONAL_MEMORY: | ||
567 | res->name = "Conventional Memory"; | ||
568 | break; | ||
569 | case EFI_UNUSABLE_MEMORY: | ||
570 | res->name = "Unusable Memory"; | ||
571 | break; | ||
572 | case EFI_ACPI_RECLAIM_MEMORY: | ||
573 | res->name = "ACPI Reclaim"; | ||
574 | break; | ||
575 | case EFI_ACPI_MEMORY_NVS: | ||
576 | res->name = "ACPI NVS"; | ||
577 | break; | ||
578 | case EFI_MEMORY_MAPPED_IO: | ||
579 | res->name = "Memory Mapped IO"; | ||
580 | break; | ||
581 | case EFI_MEMORY_MAPPED_IO_PORT_SPACE: | ||
582 | res->name = "Memory Mapped IO Port Space"; | ||
583 | break; | ||
584 | default: | ||
585 | res->name = "Reserved"; | ||
586 | break; | ||
587 | } | ||
588 | res->start = md->phys_addr; | ||
589 | res->end = res->start + ((md->num_pages << EFI_PAGE_SHIFT) - 1); | ||
590 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
591 | if (request_resource(&iomem_resource, res) < 0) | ||
592 | printk(KERN_ERR PFX "Failed to allocate res %s : 0x%lx-0x%lx\n", | ||
593 | res->name, res->start, res->end); | ||
594 | /* | ||
595 | * We don't know which region contains kernel data so we try | ||
596 | * it repeatedly and let the resource manager test it. | ||
597 | */ | ||
598 | if (md->type == EFI_CONVENTIONAL_MEMORY) { | ||
599 | request_resource(res, code_resource); | ||
600 | request_resource(res, data_resource); | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | |||
605 | /* | ||
606 | * Convenience functions to obtain memory types and attributes | ||
607 | */ | ||
608 | |||
609 | u32 efi_mem_type(unsigned long phys_addr) | ||
610 | { | ||
611 | efi_memory_desc_t *md; | ||
612 | int i; | ||
613 | |||
614 | for (i = 0; i < memmap.nr_map; i++) { | ||
615 | md = &memmap.map[i]; | ||
616 | if ((md->phys_addr <= phys_addr) && (phys_addr < | ||
617 | (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) )) | ||
618 | return md->type; | ||
619 | } | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | u64 efi_mem_attributes(unsigned long phys_addr) | ||
624 | { | ||
625 | efi_memory_desc_t *md; | ||
626 | int i; | ||
627 | |||
628 | for (i = 0; i < memmap.nr_map; i++) { | ||
629 | md = &memmap.map[i]; | ||
630 | if ((md->phys_addr <= phys_addr) && (phys_addr < | ||
631 | (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) )) | ||
632 | return md->attribute; | ||
633 | } | ||
634 | return 0; | ||
635 | } | ||