-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <jarkko.sakkinen@intel.com> Link: http://lkml.kernel.org/r/1336501366-28617-4-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
- Loading branch information
Jarkko Sakkinen
authored and
H. Peter Anvin
committed
May 8, 2012
1 parent
b3266bd
commit 084ee1c
Showing
4 changed files
with
108 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#ifndef _ARCH_X86_REALMODE_H | ||
#define _ARCH_X86_REALMODE_H | ||
|
||
#include <linux/types.h> | ||
#include <asm/io.h> | ||
|
||
/* This must match data at realmode.S */ | ||
struct real_mode_header { | ||
u32 text_start; | ||
u32 ro_end; | ||
u32 end; | ||
} __attribute__((__packed__)); | ||
|
||
extern struct real_mode_header real_mode_header; | ||
extern unsigned char *real_mode_base; | ||
|
||
extern unsigned long init_rsp; | ||
extern unsigned long initial_code; | ||
extern unsigned long initial_gs; | ||
|
||
extern unsigned char real_mode_blob[]; | ||
extern unsigned char real_mode_relocs[]; | ||
|
||
extern void __init setup_real_mode(void); | ||
|
||
#endif /* _ARCH_X86_REALMODE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#include <linux/io.h> | ||
#include <linux/memblock.h> | ||
|
||
#include <asm/cacheflush.h> | ||
#include <asm/pgtable.h> | ||
#include <asm/realmode.h> | ||
|
||
unsigned char *real_mode_base; | ||
struct real_mode_header real_mode_header; | ||
|
||
void __init setup_real_mode(void) | ||
{ | ||
phys_addr_t mem; | ||
u16 real_mode_seg; | ||
u32 *rel; | ||
u32 count; | ||
u32 *ptr; | ||
u16 *seg; | ||
int i; | ||
|
||
struct real_mode_header *header = | ||
(struct real_mode_header *) real_mode_blob; | ||
|
||
size_t size = PAGE_ALIGN(header->end); | ||
|
||
/* 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"); | ||
|
||
real_mode_base = __va(mem); | ||
memblock_reserve(mem, size); | ||
|
||
printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", | ||
real_mode_base, (unsigned long long)mem, size); | ||
|
||
memcpy(real_mode_base, real_mode_blob, size); | ||
|
||
real_mode_seg = __pa(real_mode_base) >> 4; | ||
rel = (u32 *) real_mode_relocs; | ||
|
||
/* 16-bit segment relocations. */ | ||
count = rel[0]; | ||
rel = &rel[1]; | ||
for (i = 0; i < count; i++) { | ||
seg = (u16 *) (real_mode_base + rel[i]); | ||
*seg = real_mode_seg; | ||
} | ||
|
||
/* 32-bit linear relocations. */ | ||
count = rel[i]; | ||
rel = &rel[i + 1]; | ||
for (i = 0; i < count; i++) { | ||
ptr = (u32 *) (real_mode_base + rel[i]); | ||
*ptr += __pa(real_mode_base); | ||
} | ||
|
||
/* Copied header will contain relocated physical addresses. */ | ||
memcpy(&real_mode_header, real_mode_base, | ||
sizeof(struct real_mode_header)); | ||
} | ||
|
||
/* | ||
* set_real_mode_permissions() 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. | ||
*/ | ||
static int __init set_real_mode_permissions(void) | ||
{ | ||
size_t all_size = | ||
PAGE_ALIGN(real_mode_header.end) - | ||
__pa(real_mode_base); | ||
|
||
set_memory_x((unsigned long) real_mode_base, all_size >> PAGE_SHIFT); | ||
return 0; | ||
} | ||
|
||
arch_initcall(set_real_mode_permissions); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters