]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'origin/x86/mm' into x86/mm2
authorH. Peter Anvin <hpa@linux.intel.com>
Fri, 1 Feb 2013 10:25:06 +0000 (02:25 -0800)
committerH. Peter Anvin <hpa@linux.intel.com>
Fri, 1 Feb 2013 10:28:36 +0000 (02:28 -0800)
Explicitly merging these two branches due to nontrivial conflicts and
to allow further work.

Resolved Conflicts:
arch/x86/kernel/head32.c
arch/x86/kernel/head64.c
arch/x86/mm/init_64.c
arch/x86/realmode/init.c

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
1  2 
arch/x86/include/asm/page.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/setup.c
arch/x86/mm/init_64.c
arch/x86/mm/pageattr.c
arch/x86/platform/efi/efi.c
arch/x86/realmode/init.c

index 100a20c7b98dbebc90f68fe6abc935e57c028552,3698a6a0a940cdcf607cab91c0c67b7231922213..c87892442e53d4081f4ff1276524e0298cf73617
  
  struct page;
  
 +#include <linux/range.h>
 +extern struct range pfn_mapped[];
 +extern int nr_pfn_mapped;
 +
  static inline void clear_user_page(void *page, unsigned long vaddr,
                                   struct page *pg)
  {
@@@ -48,7 -44,8 +48,8 @@@ static inline void copy_user_page(void 
   * case properly. Once all supported versions of gcc understand it, we can
   * remove this Voodoo magic stuff. (i.e. once gcc3.x is deprecated)
   */
- #define __pa_symbol(x)        __pa(__phys_reloc_hide((unsigned long)(x)))
+ #define __pa_symbol(x) \
+       __phys_addr_symbol(__phys_reloc_hide((unsigned long)(x)))
  
  #define __va(x)                       ((void *)((unsigned long)(x)+PAGE_OFFSET))
  
index 3c7c6985045d1c84109f1bb59432cee143793f24,bc28e6fe705287e29d55da8bc78a07726c8b0150..b6e41b8cd659fa791f8458eead7d622c721c5e52
@@@ -390,6 -390,7 +390,7 @@@ pte_t *populate_extra_pte(unsigned lon
  
  #ifndef __ASSEMBLY__
  #include <linux/mm_types.h>
+ #include <linux/log2.h>
  
  static inline int pte_none(pte_t pte)
  {
@@@ -615,8 -616,6 +616,8 @@@ static inline int pgd_none(pgd_t pgd
  #ifndef __ASSEMBLY__
  
  extern int direct_gbpages;
 +void init_mem_mapping(void);
 +void early_alloc_pgt_buf(void);
  
  /* local pte updates need not use xchg for locking */
  static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
@@@ -783,6 -782,19 +784,19 @@@ static inline void clone_pgd_range(pgd_
         memcpy(dst, src, count * sizeof(pgd_t));
  }
  
+ #define PTE_SHIFT ilog2(PTRS_PER_PTE)
+ static inline int page_level_shift(enum pg_level level)
+ {
+       return (PAGE_SHIFT - PTE_SHIFT) + level * PTE_SHIFT;
+ }
+ static inline unsigned long page_level_size(enum pg_level level)
+ {
+       return 1UL << page_level_shift(level);
+ }
+ static inline unsigned long page_level_mask(enum pg_level level)
+ {
+       return ~(page_level_size(level) - 1);
+ }
  
  #include <asm-generic/pgtable.h>
  #endif        /* __ASSEMBLY__ */
index 696fa7eafb1d8873bceea72ba4dde5840b974b09,9f82690f81ed71a8fbc5b7c25c1cc4107206dfa8..e6423002c10b5211af8fd45cb1cefa120d45c534
@@@ -321,6 -321,7 +321,6 @@@ int phys_mem_access_prot_allowed(struc
  /* Install a pte for a particular vaddr in kernel space. */
  void set_pte_vaddr(unsigned long vaddr, pte_t pte);
  
 -extern void native_pagetable_reserve(u64 start, u64 end);
  #ifdef CONFIG_X86_32
  extern void native_pagetable_init(void);
  #else
  struct seq_file;
  extern void arch_report_meminfo(struct seq_file *m);
  
- enum {
+ enum pg_level {
        PG_LEVEL_NONE,
        PG_LEVEL_4K,
        PG_LEVEL_2M,
@@@ -351,6 -352,7 +351,7 @@@ static inline void update_page_count(in
   * as a pte too.
   */
  extern pte_t *lookup_address(unsigned long address, unsigned int *level);
+ extern phys_addr_t slow_virt_to_phys(void *__address);
  
  #endif        /* !__ASSEMBLY__ */
  
index a24c462888f0722915ff40c2ba1a6ccad1e58d66,fdfefa27b94832fb672651d922c185ed4fa218d3..1905ce98bee01d667a0b6604d3c18f4d7c34e0fb
@@@ -17,6 -17,7 +17,6 @@@
  
  #ifdef CONFIG_X86_64
  #include <linux/topology.h>
 -#include <asm/numa_64.h>
  #endif
  
  #include "cpu.h"
@@@ -167,7 -168,7 +167,7 @@@ int __cpuinit ppro_with_ram_bug(void
  #ifdef CONFIG_X86_F00F_BUG
  static void __cpuinit trap_init_f00f_bug(void)
  {
-       __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);
+       __set_fixmap(FIX_F00F_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
  
        /*
         * Update the IDT descriptor and reload the IDT so that
diff --combined arch/x86/kernel/setup.c
index a74701af74e33b18e9fd530d6c8e362eea37e7e0,8354399b3aae21082d94cb6478cf29ca93e4ee84..be6e435cfc0549502f1cadda7cd3cd5d35505451
  #include <asm/topology.h>
  #include <asm/apicdef.h>
  #include <asm/amd_nb.h>
 -#ifdef CONFIG_X86_64
 -#include <asm/numa_64.h>
 -#endif
  #include <asm/mce.h>
  #include <asm/alternative.h>
  #include <asm/prom.h>
  
  /*
 - * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
 - * The direct mapping extends to max_pfn_mapped, so that we can directly access
 - * apertures, ACPI and other tables without having to play with fixmaps.
 + * max_low_pfn_mapped: highest direct mapped pfn under 4GB
 + * max_pfn_mapped:     highest direct mapped pfn over 4GB
 + *
 + * The direct mapping only covers E820_RAM regions, so the ranges and gaps are
 + * represented by pfn_mapped
   */
  unsigned long max_low_pfn_mapped;
  unsigned long max_pfn_mapped;
@@@ -275,7 -276,18 +275,7 @@@ void * __init extend_brk(size_t size, s
        return ret;
  }
  
 -#ifdef CONFIG_X86_64
 -static void __init init_gbpages(void)
 -{
 -      if (direct_gbpages && cpu_has_gbpages)
 -              printk(KERN_INFO "Using GB pages for direct mapping\n");
 -      else
 -              direct_gbpages = 0;
 -}
 -#else
 -static inline void init_gbpages(void)
 -{
 -}
 +#ifdef CONFIG_X86_32
  static void __init cleanup_highmap(void)
  {
  }
  static void __init reserve_brk(void)
  {
        if (_brk_end > _brk_start)
-               memblock_reserve(__pa(_brk_start),
-                                __pa(_brk_end) - __pa(_brk_start));
+               memblock_reserve(__pa_symbol(_brk_start),
+                                _brk_end - _brk_start);
  
        /* Mark brk area as locked down and no longer taking any
           new allocations */
  
  #ifdef CONFIG_BLK_DEV_INITRD
  
 +static u64 __init get_ramdisk_image(void)
 +{
 +      u64 ramdisk_image = boot_params.hdr.ramdisk_image;
 +
 +      ramdisk_image |= (u64)boot_params.ext_ramdisk_image << 32;
 +
 +      return ramdisk_image;
 +}
 +static u64 __init get_ramdisk_size(void)
 +{
 +      u64 ramdisk_size = boot_params.hdr.ramdisk_size;
 +
 +      ramdisk_size |= (u64)boot_params.ext_ramdisk_size << 32;
 +
 +      return ramdisk_size;
 +}
 +
  #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT)
  static void __init relocate_initrd(void)
  {
        /* Assume only end is not page aligned */
 -      u64 ramdisk_image = boot_params.hdr.ramdisk_image;
 -      u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
 +      u64 ramdisk_image = get_ramdisk_image();
 +      u64 ramdisk_size  = get_ramdisk_size();
        u64 area_size     = PAGE_ALIGN(ramdisk_size);
 -      u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
        u64 ramdisk_here;
        unsigned long slop, clen, mapaddr;
        char *p, *q;
  
 -      /* We need to move the initrd down into lowmem */
 -      ramdisk_here = memblock_find_in_range(0, end_of_lowmem, area_size,
 -                                       PAGE_SIZE);
 +      /* We need to move the initrd down into directly mapped mem */
 +      ramdisk_here = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
 +                                               area_size, PAGE_SIZE);
  
        if (!ramdisk_here)
                panic("Cannot find place for new RAMDISK of size %lld\n",
                         ramdisk_size);
  
 -      /* Note: this includes all the lowmem currently occupied by
 +      /* Note: this includes all the mem currently occupied by
           the initrd, we rely on that fact to keep the data intact. */
        memblock_reserve(ramdisk_here, area_size);
        initrd_start = ramdisk_here + PAGE_OFFSET;
  
        q = (char *)initrd_start;
  
 -      /* Copy any lowmem portion of the initrd */
 -      if (ramdisk_image < end_of_lowmem) {
 -              clen = end_of_lowmem - ramdisk_image;
 -              p = (char *)__va(ramdisk_image);
 -              memcpy(q, p, clen);
 -              q += clen;
 -              ramdisk_image += clen;
 -              ramdisk_size  -= clen;
 -      }
 -
 -      /* Copy the highmem portion of the initrd */
 +      /* Copy the initrd */
        while (ramdisk_size) {
                slop = ramdisk_image & ~PAGE_MASK;
                clen = ramdisk_size;
                ramdisk_image += clen;
                ramdisk_size  -= clen;
        }
 -      /* high pages is not converted by early_res_to_bootmem */
 -      ramdisk_image = boot_params.hdr.ramdisk_image;
 -      ramdisk_size  = boot_params.hdr.ramdisk_size;
 +
 +      ramdisk_image = get_ramdisk_image();
 +      ramdisk_size  = get_ramdisk_size();
        printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to"
                " [mem %#010llx-%#010llx]\n",
                ramdisk_image, ramdisk_image + ramdisk_size - 1,
                ramdisk_here, ramdisk_here + ramdisk_size - 1);
  }
  
 +static void __init early_reserve_initrd(void)
 +{
 +      /* Assume only end is not page aligned */
 +      u64 ramdisk_image = get_ramdisk_image();
 +      u64 ramdisk_size  = get_ramdisk_size();
 +      u64 ramdisk_end   = PAGE_ALIGN(ramdisk_image + ramdisk_size);
 +
 +      if (!boot_params.hdr.type_of_loader ||
 +          !ramdisk_image || !ramdisk_size)
 +              return;         /* No initrd provided by bootloader */
 +
 +      memblock_reserve(ramdisk_image, ramdisk_end - ramdisk_image);
 +}
  static void __init reserve_initrd(void)
  {
        /* Assume only end is not page aligned */
 -      u64 ramdisk_image = boot_params.hdr.ramdisk_image;
 -      u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
 +      u64 ramdisk_image = get_ramdisk_image();
 +      u64 ramdisk_size  = get_ramdisk_size();
        u64 ramdisk_end   = PAGE_ALIGN(ramdisk_image + ramdisk_size);
 -      u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT;
 +      u64 mapped_size;
  
        if (!boot_params.hdr.type_of_loader ||
            !ramdisk_image || !ramdisk_size)
  
        initrd_start = 0;
  
 -      if (ramdisk_size >= (end_of_lowmem>>1)) {
 +      mapped_size = memblock_mem_size(max_pfn_mapped);
 +      if (ramdisk_size >= (mapped_size>>1))
                panic("initrd too large to handle, "
                       "disabling initrd (%lld needed, %lld available)\n",
 -                     ramdisk_size, end_of_lowmem>>1);
 -      }
 +                     ramdisk_size, mapped_size>>1);
  
        printk(KERN_INFO "RAMDISK: [mem %#010llx-%#010llx]\n", ramdisk_image,
                        ramdisk_end - 1);
  
 -
 -      if (ramdisk_end <= end_of_lowmem) {
 -              /* All in lowmem, easy case */
 -              /*
 -               * don't need to reserve again, already reserved early
 -               * in i386_start_kernel
 -               */
 +      if (pfn_range_is_mapped(PFN_DOWN(ramdisk_image),
 +                              PFN_DOWN(ramdisk_end))) {
 +              /* All are mapped, easy case */
                initrd_start = ramdisk_image + PAGE_OFFSET;
                initrd_end = initrd_start + ramdisk_size;
                return;
        memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);
  }
  #else
 +static void __init early_reserve_initrd(void)
 +{
 +}
  static void __init reserve_initrd(void)
  {
  }
@@@ -425,6 -419,8 +425,6 @@@ static void __init parse_setup_data(voi
        struct setup_data *data;
        u64 pa_data;
  
 -      if (boot_params.hdr.version < 0x0209)
 -              return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
                u32 data_len, map_len;
@@@ -460,6 -456,8 +460,6 @@@ static void __init e820_reserve_setup_d
        u64 pa_data;
        int found = 0;
  
 -      if (boot_params.hdr.version < 0x0209)
 -              return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
                data = early_memremap(pa_data, sizeof(*data));
@@@ -483,6 -481,8 +483,6 @@@ static void __init memblock_x86_reserve
        struct setup_data *data;
        u64 pa_data;
  
 -      if (boot_params.hdr.version < 0x0209)
 -              return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
                data = early_memremap(pa_data, sizeof(*data));
  /*
   * Keep the crash kernel below this limit.  On 32 bits earlier kernels
   * would limit the kernel to the low 512 MiB due to mapping restrictions.
 - * On 64 bits, kexec-tools currently limits us to 896 MiB; increase this
 - * limit once kexec-tools are fixed.
   */
  #ifdef CONFIG_X86_32
  # define CRASH_KERNEL_ADDR_MAX        (512 << 20)
  #else
 -# define CRASH_KERNEL_ADDR_MAX        (896 << 20)
 +# define CRASH_KERNEL_ADDR_MAX        MAXMEM
  #endif
  
 +static void __init reserve_crashkernel_low(void)
 +{
 +#ifdef CONFIG_X86_64
 +      const unsigned long long alignment = 16<<20;    /* 16M */
 +      unsigned long long low_base = 0, low_size = 0;
 +      unsigned long total_low_mem;
 +      unsigned long long base;
 +      int ret;
 +
 +      total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT));
 +      ret = parse_crashkernel_low(boot_command_line, total_low_mem,
 +                                              &low_size, &base);
 +      if (ret != 0 || low_size <= 0)
 +              return;
 +
 +      low_base = memblock_find_in_range(low_size, (1ULL<<32),
 +                                      low_size, alignment);
 +
 +      if (!low_base) {
 +              pr_info("crashkernel low reservation failed - No suitable area found.\n");
 +
 +              return;
 +      }
 +
 +      memblock_reserve(low_base, low_size);
 +      pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (System low RAM: %ldMB)\n",
 +                      (unsigned long)(low_size >> 20),
 +                      (unsigned long)(low_base >> 20),
 +                      (unsigned long)(total_low_mem >> 20));
 +      crashk_low_res.start = low_base;
 +      crashk_low_res.end   = low_base + low_size - 1;
 +      insert_resource(&iomem_resource, &crashk_low_res);
 +#endif
 +}
 +
  static void __init reserve_crashkernel(void)
  {
 +      const unsigned long long alignment = 16<<20;    /* 16M */
        unsigned long long total_mem;
        unsigned long long crash_size, crash_base;
        int ret;
  
        /* 0 means: find the address automatically */
        if (crash_base <= 0) {
 -              const unsigned long long alignment = 16<<20;    /* 16M */
 -
                /*
                 *  kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
                 */
                        pr_info("crashkernel reservation failed - No suitable area found.\n");
                        return;
                }
 +
        } else {
                unsigned long long start;
  
        crashk_res.start = crash_base;
        crashk_res.end   = crash_base + crash_size - 1;
        insert_resource(&iomem_resource, &crashk_res);
 +
 +      if (crash_base >= (1ULL<<32))
 +              reserve_crashkernel_low();
  }
  #else
  static void __init reserve_crashkernel(void)
@@@ -747,27 -711,6 +747,27 @@@ static void __init trim_bios_range(void
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
  }
  
 +/* called before trim_bios_range() to spare extra sanitize */
 +static void __init e820_add_kernel_range(void)
 +{
 +      u64 start = __pa_symbol(_text);
 +      u64 size = __pa_symbol(_end) - start;
 +
 +      /*
 +       * Complain if .text .data and .bss are not marked as E820_RAM and
 +       * attempt to fix it by adding the range. We may have a confused BIOS,
 +       * or the user may have used memmap=exactmap or memmap=xxM$yyM to
 +       * exclude kernel range. If we really are running on top non-RAM,
 +       * we will crash later anyways.
 +       */
 +      if (e820_all_mapped(start, start + size, E820_RAM))
 +              return;
 +
 +      pr_warn(".text .data .bss are not marked as E820_RAM!\n");
 +      e820_remove_range(start, size, E820_RAM, 0);
 +      e820_add_region(start, size, E820_RAM);
 +}
 +
  static int __init parse_reservelow(char *p)
  {
        unsigned long long size;
@@@ -805,17 -748,6 +805,17 @@@ early_param("reservelow", parse_reserve
  
  void __init setup_arch(char **cmdline_p)
  {
 +      memblock_reserve(__pa_symbol(_text),
 +                       (unsigned long)__bss_stop - (unsigned long)_text);
 +
 +      early_reserve_initrd();
 +
 +      /*
 +       * At this point everything still needed from the boot loader
 +       * or BIOS or kernel text should be early reserved or marked not
 +       * RAM in e820. All other memory is free game.
 +       */
 +
  #ifdef CONFIG_X86_32
        memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
        visws_early_detect();
        init_mm.end_data = (unsigned long) _edata;
        init_mm.brk = _brk_end;
  
-       code_resource.start = virt_to_phys(_text);
-       code_resource.end = virt_to_phys(_etext)-1;
-       data_resource.start = virt_to_phys(_etext);
-       data_resource.end = virt_to_phys(_edata)-1;
-       bss_resource.start = virt_to_phys(&__bss_start);
-       bss_resource.end = virt_to_phys(&__bss_stop)-1;
+       code_resource.start = __pa_symbol(_text);
+       code_resource.end = __pa_symbol(_etext)-1;
+       data_resource.start = __pa_symbol(_etext);
+       data_resource.end = __pa_symbol(_edata)-1;
+       bss_resource.start = __pa_symbol(__bss_start);
+       bss_resource.end = __pa_symbol(__bss_stop)-1;
  
  #ifdef CONFIG_CMDLINE_BOOL
  #ifdef CONFIG_CMDLINE_OVERRIDE
        insert_resource(&iomem_resource, &data_resource);
        insert_resource(&iomem_resource, &bss_resource);
  
 +      e820_add_kernel_range();
        trim_bios_range();
  #ifdef CONFIG_X86_32
        if (ppro_with_ram_bug()) {
  
        reserve_ibft_region();
  
 +      early_alloc_pgt_buf();
 +
        /*
         * Need to conclude brk, before memblock_x86_fill()
         *  it could use memblock_find_in_range, could overlap with
  
        cleanup_highmap();
  
 -      memblock.current_limit = get_max_mapped();
 +      memblock.current_limit = ISA_END_ADDRESS;
        memblock_x86_fill();
  
        /*
        setup_bios_corruption_check();
  #endif
  
 +#ifdef CONFIG_X86_32
        printk(KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n",
                        (max_pfn_mapped<<PAGE_SHIFT) - 1);
 +#endif
  
 -      setup_real_mode();
 +      reserve_real_mode();
  
        trim_platform_memory_ranges();
  
 -      init_gbpages();
 -
 -      /* max_pfn_mapped is updated here */
 -      max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
 -      max_pfn_mapped = max_low_pfn_mapped;
 -
 -#ifdef CONFIG_X86_64
 -      if (max_pfn > max_low_pfn) {
 -              int i;
 -              unsigned long start, end;
 -              unsigned long start_pfn, end_pfn;
 -
 -              for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn,
 -                                                       NULL) {
 +      init_mem_mapping();
  
 -                      end = PFN_PHYS(end_pfn);
 -                      if (end <= (1UL<<32))
 -                              continue;
 +      early_trap_pf_init();
  
 -                      start = PFN_PHYS(start_pfn);
 -                      max_pfn_mapped = init_memory_mapping(
 -                                              max((1UL<<32), start), end);
 -              }
 +      setup_real_mode();
  
 -              /* can we preseve max_low_pfn ?*/
 -              max_low_pfn = max_pfn;
 -      }
 -#endif
        memblock.current_limit = get_max_mapped();
        dma_contiguous_reserve(0);
  
diff --combined arch/x86/mm/init_64.c
index e2fcbc34c9dfa40cae669a562301cdc88599a309,287c6d6a9ef1ff1ba140801f875443e092c8c550..edaa2daf4b3729ad3da4b561786ae72964b128b8
  #include <asm/uv/uv.h>
  #include <asm/setup.h>
  
 +#include "mm_internal.h"
 +
 +static void ident_pmd_init(unsigned long pmd_flag, pmd_t *pmd_page,
 +                         unsigned long addr, unsigned long end)
 +{
 +      addr &= PMD_MASK;
 +      for (; addr < end; addr += PMD_SIZE) {
 +              pmd_t *pmd = pmd_page + pmd_index(addr);
 +
 +              if (!pmd_present(*pmd))
 +                      set_pmd(pmd, __pmd(addr | pmd_flag));
 +      }
 +}
 +static int ident_pud_init(struct x86_mapping_info *info, pud_t *pud_page,
 +                        unsigned long addr, unsigned long end)
 +{
 +      unsigned long next;
 +
 +      for (; addr < end; addr = next) {
 +              pud_t *pud = pud_page + pud_index(addr);
 +              pmd_t *pmd;
 +
 +              next = (addr & PUD_MASK) + PUD_SIZE;
 +              if (next > end)
 +                      next = end;
 +
 +              if (pud_present(*pud)) {
 +                      pmd = pmd_offset(pud, 0);
 +                      ident_pmd_init(info->pmd_flag, pmd, addr, next);
 +                      continue;
 +              }
 +              pmd = (pmd_t *)info->alloc_pgt_page(info->context);
 +              if (!pmd)
 +                      return -ENOMEM;
 +              ident_pmd_init(info->pmd_flag, pmd, addr, next);
 +              set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
 +      }
 +
 +      return 0;
 +}
 +
 +int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
 +                            unsigned long addr, unsigned long end)
 +{
 +      unsigned long next;
 +      int result;
 +      int off = info->kernel_mapping ? pgd_index(__PAGE_OFFSET) : 0;
 +
 +      for (; addr < end; addr = next) {
 +              pgd_t *pgd = pgd_page + pgd_index(addr) + off;
 +              pud_t *pud;
 +
 +              next = (addr & PGDIR_MASK) + PGDIR_SIZE;
 +              if (next > end)
 +                      next = end;
 +
 +              if (pgd_present(*pgd)) {
 +                      pud = pud_offset(pgd, 0);
 +                      result = ident_pud_init(info, pud, addr, next);
 +                      if (result)
 +                              return result;
 +                      continue;
 +              }
 +
 +              pud = (pud_t *)info->alloc_pgt_page(info->context);
 +              if (!pud)
 +                      return -ENOMEM;
 +              result = ident_pud_init(info, pud, addr, next);
 +              if (result)
 +                      return result;
 +              set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
 +      }
 +
 +      return 0;
 +}
 +
  static int __init parse_direct_gbpages_off(char *arg)
  {
        direct_gbpages = 0;
@@@ -378,18 -302,10 +378,18 @@@ void __init init_extra_mapping_uc(unsig
  void __init cleanup_highmap(void)
  {
        unsigned long vaddr = __START_KERNEL_map;
 -      unsigned long vaddr_end = __START_KERNEL_map + (max_pfn_mapped << PAGE_SHIFT);
 +      unsigned long vaddr_end = __START_KERNEL_map + KERNEL_IMAGE_SIZE;
        unsigned long end = roundup((unsigned long)_brk_end, PMD_SIZE) - 1;
        pmd_t *pmd = level2_kernel_pgt;
  
 +      /*
 +       * Native path, max_pfn_mapped is not set yet.
 +       * Xen has valid max_pfn_mapped set in
 +       *      arch/x86/xen/mmu.c:xen_setup_kernel_pagetable().
 +       */
 +      if (max_pfn_mapped)
 +              vaddr_end = __START_KERNEL_map + (max_pfn_mapped << PAGE_SHIFT);
 +
        for (; vaddr + PMD_SIZE - 1 < vaddr_end; pmd++, vaddr += PMD_SIZE) {
                if (pmd_none(*pmd))
                        continue;
        }
  }
  
 -static __ref void *alloc_low_page(unsigned long *phys)
 -{
 -      unsigned long pfn = pgt_buf_end++;
 -      void *adr;
 -
 -      if (after_bootmem) {
 -              adr = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
 -              *phys = __pa(adr);
 -
 -              return adr;
 -      }
 -
 -      if (pfn >= pgt_buf_top)
 -              panic("alloc_low_page: ran out of memory");
 -
 -      adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
 -      clear_page(adr);
 -      *phys  = pfn * PAGE_SIZE;
 -      return adr;
 -}
 -
 -static __ref void *map_low_page(void *virt)
 -{
 -      void *adr;
 -      unsigned long phys, left;
 -
 -      if (after_bootmem)
 -              return virt;
 -
 -      phys = __pa(virt);
 -      left = phys & (PAGE_SIZE - 1);
 -      adr = early_memremap(phys & PAGE_MASK, PAGE_SIZE);
 -      adr = (void *)(((unsigned long)adr) | left);
 -
 -      return adr;
 -}
 -
 -static __ref void unmap_low_page(void *adr)
 -{
 -      if (after_bootmem)
 -              return;
 -
 -      early_iounmap((void *)((unsigned long)adr & PAGE_MASK), PAGE_SIZE);
 -}
 -
  static unsigned long __meminit
  phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end,
              pgprot_t prot)
  {
 -      unsigned pages = 0;
 +      unsigned long pages = 0, next;
        unsigned long last_map_addr = end;
        int i;
  
        pte_t *pte = pte_page + pte_index(addr);
  
 -      for(i = pte_index(addr); i < PTRS_PER_PTE; i++, addr += PAGE_SIZE, pte++) {
 -
 +      for (i = pte_index(addr); i < PTRS_PER_PTE; i++, addr = next, pte++) {
 +              next = (addr & PAGE_MASK) + PAGE_SIZE;
                if (addr >= end) {
 -                      if (!after_bootmem) {
 -                              for(; i < PTRS_PER_PTE; i++, pte++)
 -                                      set_pte(pte, __pte(0));
 -                      }
 -                      break;
 +                      if (!after_bootmem &&
 +                          !e820_any_mapped(addr & PAGE_MASK, next, E820_RAM) &&
 +                          !e820_any_mapped(addr & PAGE_MASK, next, E820_RESERVED_KERN))
 +                              set_pte(pte, __pte(0));
 +                      continue;
                }
  
                /*
@@@ -453,25 -414,28 +453,25 @@@ phys_pmd_init(pmd_t *pmd_page, unsigne
        int i = pmd_index(address);
  
        for (; i < PTRS_PER_PMD; i++, address = next) {
 -              unsigned long pte_phys;
                pmd_t *pmd = pmd_page + pmd_index(address);
                pte_t *pte;
                pgprot_t new_prot = prot;
  
 +              next = (address & PMD_MASK) + PMD_SIZE;
                if (address >= end) {
 -                      if (!after_bootmem) {
 -                              for (; i < PTRS_PER_PMD; i++, pmd++)
 -                                      set_pmd(pmd, __pmd(0));
 -                      }
 -                      break;
 +                      if (!after_bootmem &&
 +                          !e820_any_mapped(address & PMD_MASK, next, E820_RAM) &&
 +                          !e820_any_mapped(address & PMD_MASK, next, E820_RESERVED_KERN))
 +                              set_pmd(pmd, __pmd(0));
 +                      continue;
                }
  
 -              next = (address & PMD_MASK) + PMD_SIZE;
 -
                if (pmd_val(*pmd)) {
                        if (!pmd_large(*pmd)) {
                                spin_lock(&init_mm.page_table_lock);
 -                              pte = map_low_page((pte_t *)pmd_page_vaddr(*pmd));
 +                              pte = (pte_t *)pmd_page_vaddr(*pmd);
                                last_map_addr = phys_pte_init(pte, address,
                                                                end, prot);
 -                              unmap_low_page(pte);
                                spin_unlock(&init_mm.page_table_lock);
                                continue;
                        }
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
                        set_pte((pte_t *)pmd,
 -                              pfn_pte(address >> PAGE_SHIFT,
 +                              pfn_pte((address & PMD_MASK) >> PAGE_SHIFT,
                                        __pgprot(pgprot_val(prot) | _PAGE_PSE)));
                        spin_unlock(&init_mm.page_table_lock);
                        last_map_addr = next;
                        continue;
                }
  
 -              pte = alloc_low_page(&pte_phys);
 +              pte = alloc_low_page();
                last_map_addr = phys_pte_init(pte, address, end, new_prot);
 -              unmap_low_page(pte);
  
                spin_lock(&init_mm.page_table_lock);
 -              pmd_populate_kernel(&init_mm, pmd, __va(pte_phys));
 +              pmd_populate_kernel(&init_mm, pmd, pte);
                spin_unlock(&init_mm.page_table_lock);
        }
        update_page_count(PG_LEVEL_2M, pages);
@@@ -527,24 -492,27 +527,24 @@@ phys_pud_init(pud_t *pud_page, unsigne
        int i = pud_index(addr);
  
        for (; i < PTRS_PER_PUD; i++, addr = next) {
 -              unsigned long pmd_phys;
                pud_t *pud = pud_page + pud_index(addr);
                pmd_t *pmd;
                pgprot_t prot = PAGE_KERNEL;
  
 -              if (addr >= end)
 -                      break;
 -
                next = (addr & PUD_MASK) + PUD_SIZE;
 -
 -              if (!after_bootmem && !e820_any_mapped(addr, next, 0)) {
 -                      set_pud(pud, __pud(0));
 +              if (addr >= end) {
 +                      if (!after_bootmem &&
 +                          !e820_any_mapped(addr & PUD_MASK, next, E820_RAM) &&
 +                          !e820_any_mapped(addr & PUD_MASK, next, E820_RESERVED_KERN))
 +                              set_pud(pud, __pud(0));
                        continue;
                }
  
                if (pud_val(*pud)) {
                        if (!pud_large(*pud)) {
 -                              pmd = map_low_page(pmd_offset(pud, 0));
 +                              pmd = pmd_offset(pud, 0);
                                last_map_addr = phys_pmd_init(pmd, addr, end,
                                                         page_size_mask, prot);
 -                              unmap_low_page(pmd);
                                __flush_tlb_all();
                                continue;
                        }
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
                        set_pte((pte_t *)pud,
 -                              pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
 +                              pfn_pte((addr & PUD_MASK) >> PAGE_SHIFT,
 +                                      PAGE_KERNEL_LARGE));
                        spin_unlock(&init_mm.page_table_lock);
                        last_map_addr = next;
                        continue;
                }
  
 -              pmd = alloc_low_page(&pmd_phys);
 +              pmd = alloc_low_page();
                last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask,
                                              prot);
 -              unmap_low_page(pmd);
  
                spin_lock(&init_mm.page_table_lock);
 -              pud_populate(&init_mm, pud, __va(pmd_phys));
 +              pud_populate(&init_mm, pud, pmd);
                spin_unlock(&init_mm.page_table_lock);
        }
        __flush_tlb_all();
@@@ -610,23 -578,28 +610,23 @@@ kernel_physical_mapping_init(unsigned l
  
        for (; start < end; start = next) {
                pgd_t *pgd = pgd_offset_k(start);
 -              unsigned long pud_phys;
                pud_t *pud;
  
 -              next = (start + PGDIR_SIZE) & PGDIR_MASK;
 -              if (next > end)
 -                      next = end;
 +              next = (start & PGDIR_MASK) + PGDIR_SIZE;
  
                if (pgd_val(*pgd)) {
 -                      pud = map_low_page((pud_t *)pgd_page_vaddr(*pgd));
 +                      pud = (pud_t *)pgd_page_vaddr(*pgd);
                        last_map_addr = phys_pud_init(pud, __pa(start),
                                                 __pa(end), page_size_mask);
 -                      unmap_low_page(pud);
                        continue;
                }
  
 -              pud = alloc_low_page(&pud_phys);
 -              last_map_addr = phys_pud_init(pud, __pa(start), __pa(next),
 +              pud = alloc_low_page();
 +              last_map_addr = phys_pud_init(pud, __pa(start), __pa(end),
                                                 page_size_mask);
 -              unmap_low_page(pud);
  
                spin_lock(&init_mm.page_table_lock);
 -              pgd_populate(&init_mm, pgd, __va(pud_phys));
 +              pgd_populate(&init_mm, pgd, pud);
                spin_unlock(&init_mm.page_table_lock);
                pgd_changed = true;
        }
@@@ -691,11 -664,13 +691,11 @@@ int arch_add_memory(int nid, u64 start
  {
        struct pglist_data *pgdat = NODE_DATA(nid);
        struct zone *zone = pgdat->node_zones + ZONE_NORMAL;
 -      unsigned long last_mapped_pfn, start_pfn = start >> PAGE_SHIFT;
 +      unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
        int ret;
  
 -      last_mapped_pfn = init_memory_mapping(start, start + size);
 -      if (last_mapped_pfn > max_pfn_mapped)
 -              max_pfn_mapped = last_mapped_pfn;
 +      init_memory_mapping(start, start + size);
  
        ret = __add_pages(nid, zone, start_pfn, nr_pages);
        WARN_ON_ONCE(ret);
@@@ -711,16 -686,6 +711,16 @@@ EXPORT_SYMBOL_GPL(arch_add_memory)
  
  static struct kcore_list kcore_vsyscall;
  
 +static void __init register_page_bootmem_info(void)
 +{
 +#ifdef CONFIG_NUMA
 +      int i;
 +
 +      for_each_online_node(i)
 +              register_page_bootmem_info_node(NODE_DATA(i));
 +#endif
 +}
 +
  void __init mem_init(void)
  {
        long codesize, reservedpages, datasize, initsize;
        reservedpages = 0;
  
        /* this will put all low memory onto the freelists */
 -#ifdef CONFIG_NUMA
 -      totalram_pages = numa_free_all_bootmem();
 -#else
 +      register_page_bootmem_info();
        totalram_pages = free_all_bootmem();
 -#endif
  
        absent_pages = absent_pages_in_range(0, max_pfn);
        reservedpages = max_pfn - totalram_pages - absent_pages;
@@@ -804,13 -772,10 +804,11 @@@ void set_kernel_text_ro(void
  void mark_rodata_ro(void)
  {
        unsigned long start = PFN_ALIGN(_text);
-       unsigned long rodata_start =
-               ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK;
+       unsigned long rodata_start = PFN_ALIGN(__start_rodata);
        unsigned long end = (unsigned long) &__end_rodata_hpage_align;
-       unsigned long text_end = PAGE_ALIGN((unsigned long) &__stop___ex_table);
-       unsigned long rodata_end = PAGE_ALIGN((unsigned long) &__end_rodata);
-       unsigned long data_start = (unsigned long) &_sdata;
+       unsigned long text_end = PFN_ALIGN(&__stop___ex_table);
+       unsigned long rodata_end = PFN_ALIGN(&__end_rodata);
 +      unsigned long all_end = PFN_ALIGN(&_end);
  
        printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
               (end - start) >> 10);
        kernel_set_to_readonly = 1;
  
        /*
 -       * The rodata section (but not the kernel text!) should also be
 -       * not-executable.
 +       * The rodata/data/bss/brk section (but not the kernel text!)
 +       * should also be not-executable.
         */
 -      set_memory_nx(rodata_start, (end - rodata_start) >> PAGE_SHIFT);
 +      set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT);
  
        rodata_test();
  
  #endif
  
        free_init_pages("unused kernel memory",
-                       (unsigned long) page_address(virt_to_page(text_end)),
-                       (unsigned long)
-                                page_address(virt_to_page(rodata_start)));
+                       (unsigned long) __va(__pa_symbol(text_end)),
+                       (unsigned long) __va(__pa_symbol(rodata_start)));
        free_init_pages("unused kernel memory",
-                       (unsigned long) page_address(virt_to_page(rodata_end)),
-                       (unsigned long) page_address(virt_to_page(data_start)));
+                       (unsigned long) __va(__pa_symbol(rodata_end)),
+                       (unsigned long) __va(__pa_symbol(_sdata)));
  }
  
  #endif
diff --combined arch/x86/mm/pageattr.c
index 44acfcd6c16f2730f8235e302b62f80d5955378c,6d13d2a3f825306a11195a258fb7f78ed073c887..a1b1c88f9caf5f6c1eaf6a8b6a95477dad36a5f8
@@@ -94,12 -94,12 +94,12 @@@ static inline void split_page_count(in
  
  static inline unsigned long highmap_start_pfn(void)
  {
-       return __pa(_text) >> PAGE_SHIFT;
+       return __pa_symbol(_text) >> PAGE_SHIFT;
  }
  
  static inline unsigned long highmap_end_pfn(void)
  {
-       return __pa(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT;
+       return __pa_symbol(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT;
  }
  
  #endif
@@@ -276,8 -276,8 +276,8 @@@ static inline pgprot_t static_protectio
         * The .rodata section needs to be read-only. Using the pfn
         * catches all aliases.
         */
-       if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
-                  __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
+       if (within(pfn, __pa_symbol(__start_rodata) >> PAGE_SHIFT,
+                  __pa_symbol(__end_rodata) >> PAGE_SHIFT))
                pgprot_val(forbidden) |= _PAGE_RW;
  
  #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
@@@ -363,6 -363,37 +363,37 @@@ pte_t *lookup_address(unsigned long add
  }
  EXPORT_SYMBOL_GPL(lookup_address);
  
+ /*
+  * This is necessary because __pa() does not work on some
+  * kinds of memory, like vmalloc() or the alloc_remap()
+  * areas on 32-bit NUMA systems.  The percpu areas can
+  * end up in this kind of memory, for instance.
+  *
+  * This could be optimized, but it is only intended to be
+  * used at inititalization time, and keeping it
+  * unoptimized should increase the testing coverage for
+  * the more obscure platforms.
+  */
+ phys_addr_t slow_virt_to_phys(void *__virt_addr)
+ {
+       unsigned long virt_addr = (unsigned long)__virt_addr;
+       phys_addr_t phys_addr;
+       unsigned long offset;
+       enum pg_level level;
+       unsigned long psize;
+       unsigned long pmask;
+       pte_t *pte;
+       pte = lookup_address(virt_addr, &level);
+       BUG_ON(!pte);
+       psize = page_level_size(level);
+       pmask = page_level_mask(level);
+       offset = virt_addr & ~pmask;
+       phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+       return (phys_addr | offset);
+ }
+ EXPORT_SYMBOL_GPL(slow_virt_to_phys);
  /*
   * Set the new pmd in all the pgds we know about:
   */
@@@ -396,7 -427,7 +427,7 @@@ try_preserve_large_page(pte_t *kpte, un
        pte_t new_pte, old_pte, *tmp;
        pgprot_t old_prot, new_prot, req_prot;
        int i, do_split = 1;
-       unsigned int level;
+       enum pg_level level;
  
        if (cpa->force_split)
                return 1;
  
        switch (level) {
        case PG_LEVEL_2M:
-               psize = PMD_PAGE_SIZE;
-               pmask = PMD_PAGE_MASK;
-               break;
  #ifdef CONFIG_X86_64
        case PG_LEVEL_1G:
-               psize = PUD_PAGE_SIZE;
-               pmask = PUD_PAGE_MASK;
-               break;
  #endif
+               psize = page_level_size(level);
+               pmask = page_level_mask(level);
+               break;
        default:
                do_split = -EINVAL;
                goto out_unlock;
@@@ -551,10 -579,16 +579,10 @@@ static int split_large_page(pte_t *kpte
        for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
                set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
  
 -      if (address >= (unsigned long)__va(0) &&
 -              address < (unsigned long)__va(max_low_pfn_mapped << PAGE_SHIFT))
 +      if (pfn_range_is_mapped(PFN_DOWN(__pa(address)),
 +                              PFN_DOWN(__pa(address)) + 1))
                split_page_count(level);
  
 -#ifdef CONFIG_X86_64
 -      if (address >= (unsigned long)__va(1UL<<32) &&
 -              address < (unsigned long)__va(max_pfn_mapped << PAGE_SHIFT))
 -              split_page_count(level);
 -#endif
 -
        /*
         * Install the new, split up pagetable.
         *
@@@ -723,9 -757,13 +751,9 @@@ static int cpa_process_alias(struct cpa
        unsigned long vaddr;
        int ret;
  
 -      if (cpa->pfn >= max_pfn_mapped)
 +      if (!pfn_range_is_mapped(cpa->pfn, cpa->pfn + 1))
                return 0;
  
 -#ifdef CONFIG_X86_64
 -      if (cpa->pfn >= max_low_pfn_mapped && cpa->pfn < (1UL<<(32-PAGE_SHIFT)))
 -              return 0;
 -#endif
        /*
         * No need to redo, when the primary call touched the direct
         * mapping already:
index 36e53f0a9ce3e101774f677b8bc2cd03c21e720b,1b600266265e4892eb06004642caf3e737699396..1743c1c924119bb1d8d4d8824ad5dada74dc166e
@@@ -410,8 -410,8 +410,8 @@@ void __init efi_reserve_boot_services(v
                 * - Not within any part of the kernel
                 * - Not the bios reserved area
                */
-               if ((start+size >= virt_to_phys(_text)
-                               && start <= virt_to_phys(_end)) ||
+               if ((start+size >= __pa_symbol(_text)
+                               && start <= __pa_symbol(_end)) ||
                        !e820_all_mapped(start, start+size, E820_RAM) ||
                        memblock_is_region_reserved(start, size)) {
                        /* Could not reserve, skip it */
@@@ -835,7 -835,7 +835,7 @@@ void __init efi_enter_virtual_mode(void
        efi_memory_desc_t *md, *prev_md = NULL;
        efi_status_t status;
        unsigned long size;
 -      u64 end, systab, end_pfn;
 +      u64 end, systab, start_pfn, end_pfn;
        void *p, *va, *new_memmap = NULL;
        int count = 0;
  
                size = md->num_pages << EFI_PAGE_SHIFT;
                end = md->phys_addr + size;
  
 +              start_pfn = PFN_DOWN(md->phys_addr);
                end_pfn = PFN_UP(end);
 -              if (end_pfn <= max_low_pfn_mapped
 -                  || (end_pfn > (1UL << (32 - PAGE_SHIFT))
 -                      && end_pfn <= max_pfn_mapped)) {
 +              if (pfn_range_is_mapped(start_pfn, end_pfn)) {
                        va = __va(md->phys_addr);
  
                        if (!(md->attribute & EFI_MEMORY_WB))
diff --combined arch/x86/realmode/init.c
index 4b5bdc8c8710e299c607a45949713b67d4b6a5fa,80450261215c50b8c62b3fd559b0dd7a82f6275d..a44f457e70a19f7ffce772c5497e0090ee514db6
@@@ -8,26 -8,9 +8,26 @@@
  struct real_mode_header *real_mode_header;
  u32 *trampoline_cr4_features;
  
 -void __init setup_real_mode(void)
 +void __init reserve_real_mode(void)
  {
        phys_addr_t mem;
 +      unsigned char *base;
 +      size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
 +
 +      /* Has to be under 1M so we can execute real-mode AP code. */
 +      mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
 +      if (!mem)
 +              panic("Cannot allocate trampoline\n");
 +
 +      base = __va(mem);
 +      memblock_reserve(mem, size);
 +      real_mode_header = (struct real_mode_header *) base;
 +      printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
 +             base, (unsigned long long)mem, size);
 +}
 +
 +void __init setup_real_mode(void)
 +{
        u16 real_mode_seg;
        u32 *rel;
        u32 count;
        u64 efer;
  #endif
  
 -      /* Has to be in very low memory so we can execute real-mode AP code. */
 -      mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
 -      if (!mem)
 -              panic("Cannot allocate trampoline\n");
 -
 -      base = __va(mem);
 -      memblock_reserve(mem, size);
 -      real_mode_header = (struct real_mode_header *) base;
 -      printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
 -             base, (unsigned long long)mem, size);
 +      base = (unsigned char *)real_mode_header;
  
        memcpy(base, real_mode_blob, size);
  
@@@ -70,9 -62,9 +70,9 @@@
                __va(real_mode_header->trampoline_header);
  
  #ifdef CONFIG_X86_32
-       trampoline_header->start = __pa(startup_32_smp);
+       trampoline_header->start = __pa_symbol(startup_32_smp);
        trampoline_header->gdt_limit = __BOOT_DS + 7;
-       trampoline_header->gdt_base = __pa(boot_gdt);
+       trampoline_header->gdt_base = __pa_symbol(boot_gdt);
  #else
        /*
         * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR
        *trampoline_cr4_features = read_cr4();
  
        trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
 -      trampoline_pgd[0] = __pa_symbol(level3_ident_pgt) + _KERNPG_TABLE;
 -      trampoline_pgd[511] = __pa_symbol(level3_kernel_pgt) + _KERNPG_TABLE;
 +      trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd;
 +      trampoline_pgd[511] = init_level4_pgt[511].pgd;
  #endif
  }
  
  /*
 - * set_real_mode_permissions() gets called very early, to guarantee the
 - * availability of low memory.  This is before the proper kernel page
 + * reserve_real_mode() gets called very early, to guarantee the
 + * availability of low memory. This is before the proper kernel page
   * tables are set up, so we cannot set page permissions in that
 - * function.  Thus, we use an arch_initcall instead.
 + * function. Also trampoline code will be executed by APs so we
 + * need to mark it executable at do_pre_smp_initcalls() at least,
 + * thus run it as a early_initcall().
   */
  static int __init set_real_mode_permissions(void)
  {
  
        return 0;
  }
 -
 -arch_initcall(set_real_mode_permissions);
 +early_initcall(set_real_mode_permissions);