Skip to content

Commit 084ee1c

Browse files
Jarkko SakkinenH. Peter Anvin
authored andcommitted
x86, realmode: Relocator for realmode code
Implements relocator for real mode code that is called as part of setup_arch(). Processes segment relocations and linear relocations. Real-mode code is relocated to a free hole below 1 MB. Signed-off-by: Jarkko Sakkinen <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: H. Peter Anvin <[email protected]>
1 parent b3266bd commit 084ee1c

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

arch/x86/include/asm/realmode.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef _ARCH_X86_REALMODE_H
2+
#define _ARCH_X86_REALMODE_H
3+
4+
#include <linux/types.h>
5+
#include <asm/io.h>
6+
7+
/* This must match data at realmode.S */
8+
struct real_mode_header {
9+
u32 text_start;
10+
u32 ro_end;
11+
u32 end;
12+
} __attribute__((__packed__));
13+
14+
extern struct real_mode_header real_mode_header;
15+
extern unsigned char *real_mode_base;
16+
17+
extern unsigned long init_rsp;
18+
extern unsigned long initial_code;
19+
extern unsigned long initial_gs;
20+
21+
extern unsigned char real_mode_blob[];
22+
extern unsigned char real_mode_relocs[];
23+
24+
extern void __init setup_real_mode(void);
25+
26+
#endif /* _ARCH_X86_REALMODE_H */

arch/x86/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ obj-y += pci-iommu_table.o
3636
obj-y += resource.o
3737

3838
obj-y += trampoline.o trampoline_$(BITS).o
39+
obj-y += realmode.o
3940
obj-y += process.o
4041
obj-y += i387.o xsave.o
4142
obj-y += ptrace.o

arch/x86/kernel/realmode.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include <linux/io.h>
2+
#include <linux/memblock.h>
3+
4+
#include <asm/cacheflush.h>
5+
#include <asm/pgtable.h>
6+
#include <asm/realmode.h>
7+
8+
unsigned char *real_mode_base;
9+
struct real_mode_header real_mode_header;
10+
11+
void __init setup_real_mode(void)
12+
{
13+
phys_addr_t mem;
14+
u16 real_mode_seg;
15+
u32 *rel;
16+
u32 count;
17+
u32 *ptr;
18+
u16 *seg;
19+
int i;
20+
21+
struct real_mode_header *header =
22+
(struct real_mode_header *) real_mode_blob;
23+
24+
size_t size = PAGE_ALIGN(header->end);
25+
26+
/* Has to be in very low memory so we can execute real-mode AP code. */
27+
mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE);
28+
if (!mem)
29+
panic("Cannot allocate trampoline\n");
30+
31+
real_mode_base = __va(mem);
32+
memblock_reserve(mem, size);
33+
34+
printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n",
35+
real_mode_base, (unsigned long long)mem, size);
36+
37+
memcpy(real_mode_base, real_mode_blob, size);
38+
39+
real_mode_seg = __pa(real_mode_base) >> 4;
40+
rel = (u32 *) real_mode_relocs;
41+
42+
/* 16-bit segment relocations. */
43+
count = rel[0];
44+
rel = &rel[1];
45+
for (i = 0; i < count; i++) {
46+
seg = (u16 *) (real_mode_base + rel[i]);
47+
*seg = real_mode_seg;
48+
}
49+
50+
/* 32-bit linear relocations. */
51+
count = rel[i];
52+
rel = &rel[i + 1];
53+
for (i = 0; i < count; i++) {
54+
ptr = (u32 *) (real_mode_base + rel[i]);
55+
*ptr += __pa(real_mode_base);
56+
}
57+
58+
/* Copied header will contain relocated physical addresses. */
59+
memcpy(&real_mode_header, real_mode_base,
60+
sizeof(struct real_mode_header));
61+
}
62+
63+
/*
64+
* set_real_mode_permissions() gets called very early, to guarantee the
65+
* availability of low memory. This is before the proper kernel page
66+
* tables are set up, so we cannot set page permissions in that
67+
* function. Thus, we use an arch_initcall instead.
68+
*/
69+
static int __init set_real_mode_permissions(void)
70+
{
71+
size_t all_size =
72+
PAGE_ALIGN(real_mode_header.end) -
73+
__pa(real_mode_base);
74+
75+
set_memory_x((unsigned long) real_mode_base, all_size >> PAGE_SHIFT);
76+
return 0;
77+
}
78+
79+
arch_initcall(set_real_mode_permissions);

arch/x86/kernel/setup.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include <asm/mtrr.h>
7575
#include <asm/apic.h>
7676
#include <asm/trampoline.h>
77+
#include <asm/realmode.h>
7778
#include <asm/e820.h>
7879
#include <asm/mpspec.h>
7980
#include <asm/setup.h>
@@ -918,6 +919,7 @@ void __init setup_arch(char **cmdline_p)
918919
max_pfn_mapped<<PAGE_SHIFT);
919920

920921
setup_trampolines();
922+
setup_real_mode();
921923

922924
init_gbpages();
923925

0 commit comments

Comments
 (0)