Commit ff04a0fd authored by David Mosberger's avatar David Mosberger

ia64: Still more gate DSO tuning. Turns out a linker bug prevented

	us from building the gate DSO in a way that makes it fit in
	<= 1 page. If a fixed linker is available, we do it in this
	space-saving way now. Otherwise, we'll do it the old way
	(the gate DSO will then take up about 18KB instead of just
	~3KB).  Thanks to Roland McGrath for making this all work.
parent 92f3b57c
......@@ -27,6 +27,10 @@ GCC_MINOR_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' |
GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC) $(OBJDUMP))
arch-cppflags := $(shell arch/ia64/scripts/toolchain-flags $(CC) $(LD) $(OBJDUMP))
cflags-y += $(arch-cppflags)
AFLAGS += $(arch-cppflags)
ifeq ($(GAS_STATUS),buggy)
$(error Sorry, you need a newer version of the assember, one that is built from \
a source-tree that post-dates 18-Dec-2002. You can find a pre-compiled \
......
......@@ -12,21 +12,46 @@ SECTIONS
{
. = GATE_ADDR + SIZEOF_HEADERS;
.hash : { *(.hash) } :rodata
.hash : { *(.hash) } :readable
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.data.patch.mckinley_e9 : { *(.data.patch.mckinley_e9) }
.data.patch.fsyscall_table : { *(.data.patch.fsyscall_table) }
.data.patch.vtop : { *(.data.patch.vtop) }
.data.patch.brl_fsys_bubble_down : { *(.data.patch.brl_fsys_bubble_down) }
.IA_64.unwind_info : { *(.IA_64.unwind_info*) }
.IA_64.unwind : { *(.IA_64.unwind*) } :rodata :unwind
.dynamic : { *(.dynamic) } :rodata :dynamic
.dynamic : { *(.dynamic) } :readable :dynamic
/*
* This linker script is used both with -r and with -shared. For the layouts to match,
* we need to skip more than enough space for the dynamic symbol table et al. If this
* amount is insufficient, ld -shared will barf. Just increase it here.
*/
. = GATE_ADDR + 0x500;
.data.patch : {
__start_gate_mckinley_e9_patchlist = .;
*(.data.patch.mckinley_e9)
__end_gate_mckinley_e9_patchlist = .;
.text (GATE_ADDR + PAGE_SIZE) : { *(.text) } :rodata
__start_gate_vtop_patchlist = .;
*(.data.patch.vtop)
__end_gate_vtop_patchlist = .;
__start_gate_fsyscall_patchlist = .;
*(.data.patch.fsyscall_table)
__end_gate_fsyscall_patchlist = .;
__start_gate_brl_fsys_bubble_down_patchlist = .;
*(.data.patch.brl_fsys_bubble_down)
__end_gate_brl_fsys_bubble_down_patchlist = .;
} :readable
.IA_64.unwind_info : { *(.IA_64.unwind_info*) }
.IA_64.unwind : { *(.IA_64.unwind*) } :readable :unwind
#ifdef HAVE_BUGGY_SEGREL
.text (GATE_ADDR + PAGE_SIZE) : { *(.text) *(.text.*) } :readable
#else
. = ALIGN (PERCPU_PAGE_SIZE) + (. & (PERCPU_PAGE_SIZE - 1));
.text : { *(.text) *(.text.*) } :epc
#endif
/DISCARD/ : {
*(.got.plt) *(.got)
......@@ -43,9 +68,12 @@ SECTIONS
*/
PHDRS
{
rodata PT_LOAD FILEHDR PHDRS FLAGS(4); /* PF_R */
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
unwind 0x70000001; /* PT_IA_64_UNWIND */
readable PT_LOAD FILEHDR PHDRS FLAGS(4); /* PF_R */
#ifndef HAVE_BUGGY_SEGREL
epc PT_LOAD FILEHDR PHDRS FLAGS(1); /* PF_X */
#endif
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
unwind 0x70000001; /* PT_IA_64_UNWIND, but ld doesn't match the name */
}
/*
......@@ -64,4 +92,4 @@ VERSION
}
/* The ELF entry point can be used to set the AT_SYSINFO value. */
ENTRY(syscall_via_epc)
ENTRY(__kernel_syscall_via_epc)
......@@ -99,7 +99,7 @@ ia64_patch_vtop (unsigned long start, unsigned long end)
/* replace virtual address with corresponding physical address: */
ia64_patch_imm64(ip, ia64_tpa(get_imm64(ip)));
ia64_fc(ip);
ia64_fc((void *) ip);
++offp;
}
ia64_sync_i();
......@@ -143,11 +143,16 @@ patch_fsyscall_table (unsigned long start, unsigned long end)
{
extern unsigned long fsyscall_table[NR_syscalls];
s32 *offp = (s32 *) start;
u64 ip;
while (offp < (s32 *) end) {
ia64_patch_imm64((u64) ia64_imva((char *) offp + *offp), (u64) fsyscall_table);
ip = (u64) ia64_imva((char *) offp + *offp);
ia64_patch_imm64(ip, (u64) fsyscall_table);
ia64_fc((void *) ip);
++offp;
}
ia64_sync_i();
ia64_srlz_i();
}
static void
......@@ -161,52 +166,29 @@ patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
ip = (u64) offp + *offp;
ia64_patch_imm60((u64) ia64_imva((void *) ip),
(u64) (fsys_bubble_down - (ip & -16)) / 16);
ia64_fc((void *) ip);
++offp;
}
ia64_sync_i();
ia64_srlz_i();
}
void
ia64_patch_gate (Elf64_Ehdr *ehdr)
ia64_patch_gate (void)
{
Elf64_Shdr *shdr, *strsec, *sec;
Elf64_Half i;
unsigned long start, end;
char *strtab, *name;
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0 || ehdr->e_type != ET_DYN
|| !elf_check_arch(ehdr))
/*
* Without the gate shared library, we can't do signal return or fast
* system calls. In other words, the kernel will crash quickly anyhow, so
* we might just as well do it now...
*/
panic("%s: gate shared library at %p not a valid ELF object!\n",
__FUNCTION__, ehdr);
shdr = (void *) ((char *) ehdr + ehdr->e_shoff);
strsec = (void *) ((char *) shdr + ehdr->e_shstrndx * ehdr->e_shentsize);
strtab = (void *) ((char *) ehdr + strsec->sh_offset);
for (i = 0; i < ehdr->e_shnum; ++i) {
sec = (void *) ((char *) shdr + i * ehdr->e_shentsize);
if (strncmp(strtab + sec->sh_name, ".data.patch.", 12) != 0)
continue;
if (sec->sh_size == 0)
continue;
name = strtab + sec->sh_name + 12;
start = sec->sh_addr;
end = start + sec->sh_size;
if (strcmp(name, "fsyscall_table") == 0)
patch_fsyscall_table(start, end);
else if (strcmp(name, "brl_fsys_bubble_down") == 0)
patch_brl_fsys_bubble_down(start, end);
else if (strcmp(name, "top") == 0)
ia64_patch_vtop(start, end);
else if (strcmp(name, "mckinley_e9") == 0)
ia64_patch_mckinley_e9(start, end);
else
panic("%s: found unknown patch-list `%s'\n", __FUNCTION__, name);
}
extern char __start_gate_mckinley_e9_patchlist;
extern char __end_gate_mckinley_e9_patchlist;
extern char __start_gate_vtop_patchlist;
extern char __end_gate_vtop_patchlist;
extern char __start_gate_fsyscall_patchlist;
extern char __end_gate_fsyscall_patchlist;
extern char __start_gate_brl_fsys_bubble_down_patchlist;
extern char __end_gate_brl_fsys_bubble_down_patchlist;
# define START(name) ((unsigned long) &__start_gate_##name##_patchlist)
# define END(name) ((unsigned long)&__end_gate_##name##_patchlist)
patch_fsyscall_table(START(fsyscall), END(fsyscall));
patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down));
ia64_patch_vtop(START(vtop), END(vtop));
ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
}
......@@ -287,19 +287,22 @@ put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot)
static void
setup_gate (void)
{
struct page *page0, *page1;
struct page *page;
extern char __start_gate_section[];
/*
* Install the gate pages: one read-only page containing the ELF headers etc. and
* one execute-only page, which enables privilege-promotion via "epc":
* Map the gate page twice: once read-only to export the ELF headers etc. and once
* execute-only page to enable privilege-promotion via "epc":
*/
page0 = virt_to_page(ia64_imva(__start_gate_section));
page1 = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE));
put_kernel_page(page0, GATE_ADDR, PAGE_READONLY);
put_kernel_page(page1, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
ia64_patch_gate((Elf64_Ehdr *) __start_gate_section);
page = virt_to_page(ia64_imva(__start_gate_section));
put_kernel_page(page, GATE_ADDR, PAGE_READONLY);
#ifdef HAVE_BUGGY_SEGREL
page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE));
put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
#else
put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
#endif
ia64_patch_gate();
}
void __init
......
......@@ -2,8 +2,11 @@
dir=$(dirname $0)
CC=$1
OBJDUMP=$2
$CC -c $dir/check-gas-asm.S
res=$($OBJDUMP -r --section .data check-gas-asm.o | fgrep 00004 | tr -s ' ' |cut -f3 -d' ')
tmp=${TMPDIR:-/tmp}
out=$tmp/out$$.o
$CC -c $dir/check-gas-asm.S -o $out
res=$($OBJDUMP -r --section .data $out | fgrep 00004 | tr -s ' ' |cut -f3 -d' ')
rm -f $out
if [ $res != ".text" ]; then
echo buggy
else
......
.rodata
data4 @segrel(start)
.data
start:
SECTIONS {
. = SIZEOF_HEADERS;
.rodata : { *(.rodata) } :ro
. = 0xa0000;
.data : { *(.data) } :dat
/DISCARD/ : { *(*) }
}
PHDRS {
ro PT_LOAD FILEHDR PHDRS;
dat PT_LOAD;
}
#!/bin/sh
#
# Check whether linker can handle cross-segment @segrel():
#
CC=$1
LD=$2
OBJDUMP=$3
dir=$(dirname $0)
tmp=${TMPDIR:-/tmp}
out=$tmp/out$$
$CC -c $dir/check-segrel.S -o $out.o
$LD -static -T$dir/check-segrel.lds $out.o -o $out
res=$($OBJDUMP --full --section .rodata $out | fgrep 000 | cut -f3 -d' ')
rm -f $out $out.o
if [ $res != 00000a00 ]; then
echo " -DHAVE_BUGGY_SEGREL"
cat >&2 <<EOF
warning: your linker cannot handle cross-segment segment-relative relocations.
please upgrade to a newer version (it is safe to use this linker, but
the kernel will be bigger than strictly necessary).
EOF
fi
......@@ -20,6 +20,6 @@ extern void ia64_patch_imm60 (u64 insn_addr, u64 val); /* patch "brl" w/ip-rel
extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end);
extern void ia64_patch_vtop (unsigned long start, unsigned long end);
extern void ia64_patch_gate (Elf64_Ehdr *ehdr);
extern void ia64_patch_gate (void);
#endif /* _ASM_IA64_PATCH_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment