Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1#include <linux/io.h>
  2#include <linux/slab.h>
  3#include <linux/memblock.h>
  4
  5#include <asm/cacheflush.h>
  6#include <asm/pgtable.h>
  7#include <asm/realmode.h>
  8#include <asm/tlbflush.h>
  9
 10struct real_mode_header *real_mode_header;
 11u32 *trampoline_cr4_features;
 12
 13/* Hold the pgd entry used on booting additional CPUs */
 14pgd_t trampoline_pgd_entry;
 15
 16void __init set_real_mode_mem(phys_addr_t mem, size_t size)
 17{
 18	void *base = __va(mem);
 19
 20	real_mode_header = (struct real_mode_header *) base;
 21	printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
 22	       base, (unsigned long long)mem, size);
 23}
 24
 25void __init reserve_real_mode(void)
 26{
 27	phys_addr_t mem;
 28	size_t size = real_mode_size_needed();
 29
 30	if (!size)
 31		return;
 32
 33	WARN_ON(slab_is_available());
 34
 35	/* Has to be under 1M so we can execute real-mode AP code. */
 36	mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
 37	if (!mem) {
 38		pr_info("No sub-1M memory is available for the trampoline\n");
 39		return;
 40	}
 41
 42	memblock_reserve(mem, size);
 43	set_real_mode_mem(mem, size);
 44}
 45
 46static void __init setup_real_mode(void)
 47{
 48	u16 real_mode_seg;
 49	const u32 *rel;
 50	u32 count;
 51	unsigned char *base;
 52	unsigned long phys_base;
 53	struct trampoline_header *trampoline_header;
 54	size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
 55#ifdef CONFIG_X86_64
 56	u64 *trampoline_pgd;
 57	u64 efer;
 58#endif
 59
 60	base = (unsigned char *)real_mode_header;
 61
 62	memcpy(base, real_mode_blob, size);
 63
 64	phys_base = __pa(base);
 65	real_mode_seg = phys_base >> 4;
 66
 67	rel = (u32 *) real_mode_relocs;
 68
 69	/* 16-bit segment relocations. */
 70	count = *rel++;
 71	while (count--) {
 72		u16 *seg = (u16 *) (base + *rel++);
 73		*seg = real_mode_seg;
 74	}
 75
 76	/* 32-bit linear relocations. */
 77	count = *rel++;
 78	while (count--) {
 79		u32 *ptr = (u32 *) (base + *rel++);
 80		*ptr += phys_base;
 81	}
 82
 83	/* Must be perfomed *after* relocation. */
 84	trampoline_header = (struct trampoline_header *)
 85		__va(real_mode_header->trampoline_header);
 86
 87#ifdef CONFIG_X86_32
 88	trampoline_header->start = __pa_symbol(startup_32_smp);
 89	trampoline_header->gdt_limit = __BOOT_DS + 7;
 90	trampoline_header->gdt_base = __pa_symbol(boot_gdt);
 91#else
 92	/*
 93	 * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR
 94	 * so we need to mask it out.
 95	 */
 96	rdmsrl(MSR_EFER, efer);
 97	trampoline_header->efer = efer & ~EFER_LMA;
 98
 99	trampoline_header->start = (u64) secondary_startup_64;
100	trampoline_cr4_features = &trampoline_header->cr4;
101	*trampoline_cr4_features = mmu_cr4_features;
102
103	trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
104	trampoline_pgd[0] = trampoline_pgd_entry.pgd;
105	trampoline_pgd[511] = init_level4_pgt[511].pgd;
106#endif
107}
108
109/*
110 * reserve_real_mode() gets called very early, to guarantee the
111 * availability of low memory. This is before the proper kernel page
112 * tables are set up, so we cannot set page permissions in that
113 * function. Also trampoline code will be executed by APs so we
114 * need to mark it executable at do_pre_smp_initcalls() at least,
115 * thus run it as a early_initcall().
116 */
117static void __init set_real_mode_permissions(void)
118{
119	unsigned char *base = (unsigned char *) real_mode_header;
120	size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
121
122	size_t ro_size =
123		PAGE_ALIGN(real_mode_header->ro_end) -
124		__pa(base);
125
126	size_t text_size =
127		PAGE_ALIGN(real_mode_header->ro_end) -
128		real_mode_header->text_start;
129
130	unsigned long text_start =
131		(unsigned long) __va(real_mode_header->text_start);
132
133	set_memory_nx((unsigned long) base, size >> PAGE_SHIFT);
134	set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT);
135	set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT);
136}
137
138static int __init init_real_mode(void)
139{
140	if (!real_mode_header)
141		panic("Real mode trampoline was not allocated");
142
143	setup_real_mode();
144	set_real_mode_permissions();
145
146	return 0;
147}
148early_initcall(init_real_mode);