Guest User

0001-efi-run-efi-in-physical-mode-instead-of-virtual-mode

a guest
Apr 9th, 2012
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 12.89 KB | None | 0 0
  1. From 2621de478a92bbfec35d53a336f9411b4944423b Mon Sep 17 00:00:00 2001
  2. From: Dan Yang <dsyang92 (at) gmail (dot) com>
  3. Date: Mon, 9 Apr 2012 22:20:47 -0400
  4. Subject: [PATCH] efi: run efi in physical mode instead of virtual mode
  5.  
  6. ---
  7. arch/x86/include/asm/efi.h     |    3 +
  8.  arch/x86/platform/efi/efi.c    |  142 +++++++++++++++++++++++++++++++++++++++-
  9.  arch/x86/platform/efi/efi_32.c |    4 ++
  10.  arch/x86/platform/efi/efi_64.c |   96 ++++++++++++++++++++++++++-
  11.  include/linux/efi.h            |    1 +
  12.  include/linux/init.h           |    1 +
  13.  init/main.c                    |   16 ++++-
  14.  7 files changed, 256 insertions(+), 7 deletions(-)
  15.  
  16. diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
  17. index 7093e4a..ed6f6fb 100644
  18. --- a/arch/x86/include/asm/efi.h
  19. +++ b/arch/x86/include/asm/efi.h
  20. @@ -94,6 +94,9 @@ extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
  21.  extern void efi_memblock_x86_reserve_range(void);
  22.  extern void efi_call_phys_prelog(void);
  23.  extern void efi_call_phys_epilog(void);
  24. +extern void efi_call_phys_prelog_in_physmode(void);
  25. +extern void efi_call_phys_epilog_in_physmode(void);
  26. +extern void efi_pagetable_init(void);
  27.  
  28.  #ifndef CONFIG_EFI
  29.  /*
  30. diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
  31. index 37718f0..ced4504 100644
  32. --- a/arch/x86/platform/efi/efi.c
  33. +++ b/arch/x86/platform/efi/efi.c
  34. @@ -69,6 +69,7 @@ struct efi_memory_map memmap;
  35.  
  36.  static struct efi efi_phys __initdata;
  37.  static efi_system_table_t efi_systab __initdata;
  38. +static efi_runtime_services_t phys_runtime;
  39.  
  40.  static int __init setup_noefi(char *arg)
  41.  {
  42. @@ -230,7 +231,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
  43.     return status;
  44.  }
  45.  
  46. -static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
  47. +static efi_status_t __init phys_efi_get_time_early(efi_time_t *tm,
  48.                          efi_time_cap_t *tc)
  49.  {
  50.     unsigned long flags;
  51. @@ -244,6 +245,112 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
  52.     return status;
  53.  }
  54.  
  55. +static efi_status_t phys_efi_get_time(efi_time_t *tm,
  56. +                     efi_time_cap_t *tc)
  57. +{
  58. +   efi_status_t status;
  59. +
  60. +   efi_call_phys_prelog_in_physmode();
  61. +   status = efi_call_phys2((void*)phys_runtime.get_time, tm, tc);
  62. +   efi_call_phys_epilog_in_physmode();
  63. +   return status;
  64. +}
  65. +
  66. +static efi_status_t __init phys_efi_set_time(efi_time_t *tm)
  67. +{
  68. +   efi_status_t status;
  69. +
  70. +   efi_call_phys_prelog_in_physmode();
  71. +   status = efi_call_phys1((void*)phys_runtime.set_time, tm);
  72. +   efi_call_phys_epilog_in_physmode();
  73. +   return status;
  74. +}
  75. +
  76. +static efi_status_t phys_efi_get_wakeup_time(efi_bool_t *enabled,
  77. +                                             efi_bool_t *pending,
  78. +                                             efi_time_t *tm)
  79. +{
  80. +   efi_status_t status;
  81. +
  82. +   efi_call_phys_prelog_in_physmode();
  83. +   status = efi_call_phys3((void*)phys_runtime.get_wakeup_time, enabled,
  84. +               pending, tm);
  85. +   efi_call_phys_epilog_in_physmode();
  86. +   return status;
  87. +}
  88. +
  89. +static efi_status_t phys_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
  90. +{
  91. +   efi_status_t status;
  92. +   efi_call_phys_prelog_in_physmode();
  93. +   status = efi_call_phys2((void*)phys_runtime.set_wakeup_time, enabled,
  94. +               tm);
  95. +   efi_call_phys_epilog_in_physmode();
  96. +   return status;
  97. +}
  98. +
  99. +static efi_status_t phys_efi_get_variable(efi_char16_t *name,
  100. +                     efi_guid_t *vendor,
  101. +                     u32 *attr,
  102. +                     unsigned long *data_size,
  103. +                     void *data)
  104. +{
  105. +   efi_status_t status;
  106. +   efi_call_phys_prelog_in_physmode();
  107. +   status = efi_call_phys5((void*)phys_runtime.get_variable, name, vendor,
  108. +               attr, data_size, data);
  109. +   efi_call_phys_epilog_in_physmode();
  110. +   return status;
  111. +}
  112. +
  113. +static efi_status_t phys_efi_get_next_variable(unsigned long *name_size,
  114. +                          efi_char16_t *name,
  115. +                          efi_guid_t *vendor)
  116. +{
  117. +   efi_status_t status;
  118. +
  119. +   efi_call_phys_prelog_in_physmode();
  120. +   status = efi_call_phys3((void*)phys_runtime.get_next_variable,
  121. +               name_size, name, vendor);
  122. +   efi_call_phys_epilog_in_physmode();
  123. +   return status;
  124. +}
  125. +
  126. +static efi_status_t phys_efi_set_variable(efi_char16_t *name,
  127. +                     efi_guid_t *vendor,
  128. +                     unsigned long attr,
  129. +                     unsigned long data_size,
  130. +                     void *data)
  131. +{
  132. +   efi_status_t status;
  133. +   efi_call_phys_prelog_in_physmode();
  134. +   status = efi_call_phys5((void*)phys_runtime.set_variable, name,
  135. +               vendor, attr, data_size, data);
  136. +   efi_call_phys_epilog_in_physmode();
  137. +   return status;
  138. +}
  139. +
  140. +static efi_status_t phys_efi_get_next_high_mono_count(u32 *count)
  141. +{
  142. +   efi_status_t status;
  143. +   efi_call_phys_prelog_in_physmode();
  144. +   status = efi_call_phys1((void*)phys_runtime.get_next_high_mono_count,
  145. +               count);
  146. +   efi_call_phys_epilog_in_physmode();
  147. +   return status;
  148. +}
  149. +
  150. +static void phys_efi_reset_system(int reset_type,
  151. +                                  efi_status_t status,
  152. +                                  unsigned long data_size,
  153. +                                  efi_char16_t *data)
  154. +{
  155. +   efi_call_phys_prelog_in_physmode();
  156. +   efi_call_phys4((void*)phys_runtime.reset_system, reset_type, status,
  157. +               data_size, data);
  158. +   efi_call_phys_epilog_in_physmode();
  159. +}
  160. +
  161.  int efi_set_rtc_mmss(unsigned long nowtime)
  162.  {
  163.     int real_seconds, real_minutes;
  164. @@ -551,7 +658,9 @@ void __init efi_init(void)
  165.          * Make efi_get_time can be called before entering
  166.          * virtual mode.
  167.          */
  168. -       efi.get_time = phys_efi_get_time;
  169. +       efi.get_time = phys_efi_get_time_early;
  170. +
  171. +       memcpy(&phys_runtime, runtime, sizeof(efi_runtime_services_t));
  172.     } else
  173.         printk(KERN_ERR "Could not map the EFI runtime service "
  174.                "table!\n");
  175. @@ -579,6 +688,14 @@ void __init efi_init(void)
  176.  #if EFI_DEBUG
  177.     print_efi_memmap();
  178.  #endif
  179. +
  180. +#ifndef CONFIG_X86_64
  181. +   /*
  182. +    * Only x86_64 supports physical mode as of now. Use virtual mode
  183. +    * forcibly.
  184. +    */
  185. +   usevirtefi = 1;
  186. +#endif
  187.  }
  188.  
  189.  void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
  190. @@ -751,6 +868,27 @@ void __init efi_enter_virtual_mode(void)
  191.     kfree(new_memmap);
  192.  }
  193.  
  194. +void __init efi_setup_physical_mode(void)
  195. +{
  196. +#ifdef CONFIG_X86_64
  197. +   efi_pagetable_init();
  198. +#endif
  199. +   efi.get_time = phys_efi_get_time;
  200. +   efi.set_time = phys_efi_set_time;
  201. +   efi.get_wakeup_time = phys_efi_get_wakeup_time;
  202. +   efi.set_wakeup_time = phys_efi_set_wakeup_time;
  203. +   efi.get_variable = phys_efi_get_variable;
  204. +   efi.get_next_variable = phys_efi_get_next_variable;
  205. +   efi.set_variable = phys_efi_set_variable;
  206. +   efi.get_next_high_mono_count =
  207. +       phys_efi_get_next_high_mono_count;
  208. +   efi.reset_system = phys_efi_reset_system;
  209. +   efi.set_virtual_address_map = NULL; /* Not needed */
  210. +
  211. +   early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
  212. +   memmap.map = NULL;
  213. +}
  214. +
  215.  /*
  216.   * Convenience functions to obtain memory types and attributes
  217.   */
  218. diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
  219. index 40e4469..d494d70 100644
  220. --- a/arch/x86/platform/efi/efi_32.c
  221. +++ b/arch/x86/platform/efi/efi_32.c
  222. @@ -67,3 +67,7 @@ void efi_call_phys_epilog(void)
  223.  
  224.     local_irq_restore(efi_rt_eflags);
  225.  }
  226. +
  227. +void efi_call_phys_prelog_in_physmode(void) { /* Not supported */ }
  228. +void efi_call_phys_epilog_in_physmode(void) { /* Not supported */ }
  229. +
  230. diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
  231. index ac3aa54..999af26 100644
  232. --- a/arch/x86/platform/efi/efi_64.c
  233. +++ b/arch/x86/platform/efi/efi_64.c
  234. @@ -39,7 +39,9 @@
  235.  #include <asm/fixmap.h>
  236.  
  237.  static pgd_t save_pgd __initdata;
  238. -static unsigned long efi_flags __initdata;
  239. +static DEFINE_PER_CPU(unsigned long, efi_flags);
  240. +static DEFINE_PER_CPU(unsigned long, save_cr3);
  241. +static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
  242.  
  243.  static void __init early_code_mapping_set_exec(int executable)
  244.  {
  245. @@ -63,7 +65,7 @@ void __init efi_call_phys_prelog(void)
  246.     unsigned long vaddress;
  247.  
  248.     early_code_mapping_set_exec(1);
  249. -   local_irq_save(efi_flags);
  250. +   local_irq_save(get_cpu_var(efi_flags));
  251.     vaddress = (unsigned long)__va(0x0UL);
  252.     save_pgd = *pgd_offset_k(0x0UL);
  253.     set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
  254. @@ -77,10 +79,23 @@ void __init efi_call_phys_epilog(void)
  255.      */
  256.     set_pgd(pgd_offset_k(0x0UL), save_pgd);
  257.     __flush_tlb_all();
  258. -   local_irq_restore(efi_flags);
  259. +   local_irq_restore(get_cpu_var(efi_flags));
  260.     early_code_mapping_set_exec(0);
  261.  }
  262.  
  263. +void efi_call_phys_prelog_in_physmode(void)
  264. +{
  265. +   local_irq_save(get_cpu_var(efi_flags));
  266. +   get_cpu_var(save_cr3)= read_cr3();
  267. +   write_cr3(virt_to_phys(efi_pgd));
  268. +}
  269. +
  270. +void efi_call_phys_epilog_in_physmode(void)
  271. +{
  272. +   write_cr3(get_cpu_var(save_cr3));
  273. +   local_irq_restore(get_cpu_var(efi_flags));
  274. +}
  275. +
  276.  void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
  277.                  u32 type)
  278.  {
  279. @@ -97,3 +112,78 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
  280.  
  281.     return (void __iomem *)__va(phys_addr);
  282.  }
  283. +
  284. +static pud_t *fill_pud(pgd_t *pgd, unsigned long vaddr)
  285. +{
  286. +   if (pgd_none(*pgd)) {
  287. +       pud_t *pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
  288. +       set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
  289. +       if (pud != pud_offset(pgd, 0))
  290. +           printk(KERN_ERR "EFI PAGETABLE BUG #00! %p <-> %p\n",
  291. +                  pud, pud_offset(pgd, 0));
  292. +   }
  293. +   return pud_offset(pgd, vaddr);
  294. +}
  295. +
  296. +static pmd_t *fill_pmd(pud_t *pud, unsigned long vaddr)
  297. +{
  298. +   if (pud_none(*pud)) {
  299. +       pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
  300. +       set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
  301. +       if (pmd != pmd_offset(pud, 0))
  302. +           printk(KERN_ERR "EFI PAGETABLE BUG #01! %p <-> %p\n",
  303. +                  pmd, pmd_offset(pud, 0));
  304. +   }
  305. +   return pmd_offset(pud, vaddr);
  306. +}
  307. +
  308. +static pte_t *fill_pte(pmd_t *pmd, unsigned long vaddr)
  309. +{
  310. +   if (pmd_none(*pmd)) {
  311. +       pte_t *pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
  312. +       set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)));
  313. +       if (pte != pte_offset_kernel(pmd, 0))
  314. +           printk(KERN_ERR "EFI PAGETABLE BUG #02!\n");
  315. +   }
  316. +   return pte_offset_kernel(pmd, vaddr);
  317. +}
  318. +
  319. +void __init efi_pagetable_init(void)
  320. +{
  321. +   efi_memory_desc_t *md;
  322. +   unsigned long size;
  323. +   u64 start_pfn, end_pfn, pfn, vaddr;
  324. +   void *p;
  325. +   pgd_t *pgd;
  326. +   pud_t *pud;
  327. +   pmd_t *pmd;
  328. +   pte_t *pte;
  329. +
  330. +   memset(efi_pgd, 0, sizeof(efi_pgd));
  331. +   for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
  332. +       md = p;
  333. +       if (!(md->type & EFI_RUNTIME_SERVICES_CODE) &&
  334. +           !(md->type & EFI_RUNTIME_SERVICES_DATA))
  335. +           continue;
  336. +
  337. +       start_pfn = md->phys_addr >> PAGE_SHIFT;
  338. +       size = md->num_pages << EFI_PAGE_SHIFT;
  339. +       end_pfn = PFN_UP(md->phys_addr + size);
  340. +
  341. +       for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
  342. +           vaddr = pfn << PAGE_SHIFT;
  343. +           pgd = efi_pgd + pgd_index(vaddr);
  344. +           pud = fill_pud(pgd, vaddr);
  345. +           pmd = fill_pmd(pud, vaddr);
  346. +           pte = fill_pte(pmd, vaddr);
  347. +           if (md->type & EFI_RUNTIME_SERVICES_CODE)
  348. +               set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
  349. +           else
  350. +               set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
  351. +       }
  352. +   }
  353. +   pgd = efi_pgd + pgd_index(PAGE_OFFSET);
  354. +   set_pgd(pgd, *pgd_offset_k(PAGE_OFFSET));
  355. +   pgd = efi_pgd + pgd_index(__START_KERNEL_map);
  356. +   set_pgd(pgd, *pgd_offset_k(__START_KERNEL_map));
  357. +}
  358. diff --git a/include/linux/efi.h b/include/linux/efi.h
  359. index 2362a0b..86300d4 100644
  360. --- a/include/linux/efi.h
  361. +++ b/include/linux/efi.h
  362. @@ -326,6 +326,7 @@ extern void efi_map_pal_code (void);
  363.  extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
  364.  extern void efi_gettimeofday (struct timespec *ts);
  365.  extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
  366. +extern void efi_setup_physical_mode(void);
  367.  extern u64 efi_get_iobase (void);
  368.  extern u32 efi_mem_type (unsigned long phys_addr);
  369.  extern u64 efi_mem_attributes (unsigned long phys_addr);
  370. diff --git a/include/linux/init.h b/include/linux/init.h
  371. index 9146f39..0801c0f 100644
  372. --- a/include/linux/init.h
  373. +++ b/include/linux/init.h
  374. @@ -149,6 +149,7 @@ extern int do_one_initcall(initcall_t fn);
  375.  extern char __initdata boot_command_line[];
  376.  extern char *saved_command_line;
  377.  extern unsigned int reset_devices;
  378. +extern unsigned int usevirtefi;
  379.  
  380.  /* used by init/main.c */
  381.  void setup_arch(char **);
  382. diff --git a/init/main.c b/init/main.c
  383. index 217ed23..d045381 100644
  384. --- a/init/main.c
  385. +++ b/init/main.c
  386. @@ -149,6 +149,14 @@ static int __init set_reset_devices(char *str)
  387.  
  388.  __setup("reset_devices", set_reset_devices);
  389.  
  390. +unsigned int usevirtefi;
  391. +static int __init set_virt_efi(char *str)
  392. +{
  393. +   usevirtefi = 1;
  394. +   return 1;
  395. +}
  396. +__setup("virtefi", set_virt_efi);
  397. +
  398.  static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
  399.  const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
  400.  static const char *panic_later, *panic_param;
  401. @@ -609,8 +617,12 @@ asmlinkage void __init start_kernel(void)
  402.     pidmap_init();
  403.     anon_vma_init();
  404.  #ifdef CONFIG_X86
  405. -   if (efi_enabled)
  406. -       efi_enter_virtual_mode();
  407. +   if (efi_enabled) {
  408. +       if (usevirtefi)
  409. +           efi_enter_virtual_mode();
  410. +       else
  411. +           efi_setup_physical_mode();
  412. +   }
  413.  #endif
  414.     thread_info_cache_init();
  415.     cred_init();
  416. --
  417. 1.7.10
Advertisement
Add Comment
Please, Sign In to add comment