Commit 161bd3bf authored by Helge Deller's avatar Helge Deller

parisc: fix kernel memory layout in vmlinux.ld.S

When building a 64bit kernel sometimes functions in the .init section were not
able to reach the standard kernel function. Main reason for this problem is,
that the linkage tables (.plt, .opd, .dlt) tend to become pretty huge and thus
the distance gets too big for short calls.

One option to avoid this is to use the -mlong-calls compiler option, but this
increases the binary size and introduces a performance penalty.

Instead, with this patch we just lay out the binary differently.  Init code is
stored first, followed by text, R/O and finally R/W data. This means, that init
and text code is now much closer to each other, which is sufficient to reach
each other by short calls.
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
parent c790b41b
...@@ -41,9 +41,7 @@ END(boot_args) ...@@ -41,9 +41,7 @@ END(boot_args)
.import fault_vector_11,code /* IVA parisc 1.1 32 bit */ .import fault_vector_11,code /* IVA parisc 1.1 32 bit */
.import $global$ /* forward declaration */ .import $global$ /* forward declaration */
#endif /*!CONFIG_64BIT*/ #endif /*!CONFIG_64BIT*/
.export _stext,data /* Kernel want it this way! */ ENTRY(parisc_kernel_start)
_stext:
ENTRY(stext)
.proc .proc
.callinfo .callinfo
...@@ -347,7 +345,7 @@ smp_slave_stext: ...@@ -347,7 +345,7 @@ smp_slave_stext:
.procend .procend
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
ENDPROC(stext) ENDPROC(parisc_kernel_start)
#ifndef CONFIG_64BIT #ifndef CONFIG_64BIT
.section .data..read_mostly .section .data..read_mostly
......
...@@ -6,24 +6,19 @@ ...@@ -6,24 +6,19 @@
* Copyright (C) 2000 Michael Ang <mang with subcarrier.org> * Copyright (C) 2000 Michael Ang <mang with subcarrier.org>
* Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
* Copyright (C) 2003 James Bottomley <jejb with parisc-linux.org> * Copyright (C) 2003 James Bottomley <jejb with parisc-linux.org>
* Copyright (C) 2006 Helge Deller <deller@gmx.de> * Copyright (C) 2006-2013 Helge Deller <deller@gmx.de>
* */
*
* This program is free software; you can redistribute it and/or modify /*
* it under the terms of the GNU General Public License as published by * Put page table entries (swapper_pg_dir) as the first thing in .bss. This
* the Free Software Foundation; either version 2 of the License, or * will ensure that it has .bss alignment (PAGE_SIZE).
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#define BSS_FIRST_SECTIONS *(.data..vm0.pmd) \
*(.data..vm0.pgd) \
*(.data..vm0.pte)
#include <asm-generic/vmlinux.lds.h> #include <asm-generic/vmlinux.lds.h>
/* needed for the processor specific cache alignment size */ /* needed for the processor specific cache alignment size */
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -39,7 +34,7 @@ OUTPUT_FORMAT("elf64-hppa-linux") ...@@ -39,7 +34,7 @@ OUTPUT_FORMAT("elf64-hppa-linux")
OUTPUT_ARCH(hppa:hppa2.0w) OUTPUT_ARCH(hppa:hppa2.0w)
#endif #endif
ENTRY(_stext) ENTRY(parisc_kernel_start)
#ifndef CONFIG_64BIT #ifndef CONFIG_64BIT
jiffies = jiffies_64 + 4; jiffies = jiffies_64 + 4;
#else #else
...@@ -49,11 +44,29 @@ SECTIONS ...@@ -49,11 +44,29 @@ SECTIONS
{ {
. = KERNEL_BINARY_TEXT_START; . = KERNEL_BINARY_TEXT_START;
__init_begin = .;
HEAD_TEXT_SECTION
INIT_TEXT_SECTION(8)
. = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(PAGE_SIZE)
/* we have to discard exit text and such at runtime, not link time */
.exit.text :
{
EXIT_TEXT
}
.exit.data :
{
EXIT_DATA
}
PERCPU_SECTION(8)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
_text = .; /* Text and read-only data */ _text = .; /* Text and read-only data */
.head ALIGN(16) : { _stext = .;
HEAD_TEXT .text ALIGN(PAGE_SIZE) : {
} = 0
.text ALIGN(16) : {
TEXT_TEXT TEXT_TEXT
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
...@@ -68,21 +81,28 @@ SECTIONS ...@@ -68,21 +81,28 @@ SECTIONS
*(.lock.text) /* out-of-line lock text */ *(.lock.text) /* out-of-line lock text */
*(.gnu.warning) *(.gnu.warning)
} }
/* End of text section */ . = ALIGN(PAGE_SIZE);
_etext = .; _etext = .;
/* End of text section */
/* Start of data section */ /* Start of data section */
_sdata = .; _sdata = .;
RODATA RO_DATA_SECTION(8)
/* writeable */ #ifdef CONFIG_64BIT
/* Make sure this is page aligned so . = ALIGN(16);
* that we can properly leave these /* Linkage tables */
* as writable .opd : {
*/ *(.opd)
. = ALIGN(PAGE_SIZE); } PROVIDE (__gp = .);
data_start = .; .plt : {
*(.plt)
}
.dlt : {
*(.dlt)
}
#endif
/* unwind info */ /* unwind info */
.PARISC.unwind : { .PARISC.unwind : {
...@@ -91,7 +111,15 @@ SECTIONS ...@@ -91,7 +111,15 @@ SECTIONS
__stop___unwind = .; __stop___unwind = .;
} }
EXCEPTION_TABLE(16) /* writeable */
/* Make sure this is page aligned so
* that we can properly leave these
* as writable
*/
. = ALIGN(PAGE_SIZE);
data_start = .;
EXCEPTION_TABLE(8)
NOTES NOTES
/* Data */ /* Data */
...@@ -107,54 +135,8 @@ SECTIONS ...@@ -107,54 +135,8 @@ SECTIONS
_edata = .; _edata = .;
/* BSS */ /* BSS */
__bss_start = .; BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 8)
/* page table entries need to be PAGE_SIZE aligned */
. = ALIGN(PAGE_SIZE);
.data..vmpages : {
*(.data..vm0.pmd)
*(.data..vm0.pgd)
*(.data..vm0.pte)
}
.bss : {
*(.bss)
*(COMMON)
}
__bss_stop = .;
#ifdef CONFIG_64BIT
. = ALIGN(16);
/* Linkage tables */
.opd : {
*(.opd)
} PROVIDE (__gp = .);
.plt : {
*(.plt)
}
.dlt : {
*(.dlt)
}
#endif
/* reserve space for interrupt stack by aligning __init* to 16k */
. = ALIGN(16384);
__init_begin = .;
INIT_TEXT_SECTION(16384)
. = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(16)
/* we have to discard exit text and such at runtime, not link time */
.exit.text :
{
EXIT_TEXT
}
.exit.data :
{
EXIT_DATA
}
PERCPU_SECTION(L1_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
_end = . ; _end = . ;
STABS_DEBUG STABS_DEBUG
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/sections.h> #include <asm/sections.h>
extern int data_start; extern int data_start;
extern void parisc_kernel_start(void); /* Kernel entry point in head.S */
#if PT_NLEVELS == 3 #if PT_NLEVELS == 3
/* NOTE: This layout exactly conforms to the hybrid L2/L3 page table layout /* NOTE: This layout exactly conforms to the hybrid L2/L3 page table layout
...@@ -324,8 +325,9 @@ static void __init setup_bootmem(void) ...@@ -324,8 +325,9 @@ static void __init setup_bootmem(void)
reserve_bootmem_node(NODE_DATA(0), 0UL, reserve_bootmem_node(NODE_DATA(0), 0UL,
(unsigned long)(PAGE0->mem_free + (unsigned long)(PAGE0->mem_free +
PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT); PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT);
reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text), reserve_bootmem_node(NODE_DATA(0), __pa(KERNEL_BINARY_TEXT_START),
(unsigned long)(_end - _text), BOOTMEM_DEFAULT); (unsigned long)(_end - KERNEL_BINARY_TEXT_START),
BOOTMEM_DEFAULT);
reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT), reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT), ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT),
BOOTMEM_DEFAULT); BOOTMEM_DEFAULT);
...@@ -378,6 +380,17 @@ static void __init setup_bootmem(void) ...@@ -378,6 +380,17 @@ static void __init setup_bootmem(void)
request_resource(&sysram_resources[0], &pdcdata_resource); request_resource(&sysram_resources[0], &pdcdata_resource);
} }
static int __init parisc_text_address(unsigned long vaddr)
{
static unsigned long head_ptr __initdata;
if (!head_ptr)
head_ptr = PAGE_MASK & (unsigned long)
dereference_function_descriptor(&parisc_kernel_start);
return core_kernel_text(vaddr) || vaddr == head_ptr;
}
static void __init map_pages(unsigned long start_vaddr, static void __init map_pages(unsigned long start_vaddr,
unsigned long start_paddr, unsigned long size, unsigned long start_paddr, unsigned long size,
pgprot_t pgprot, int force) pgprot_t pgprot, int force)
...@@ -466,7 +479,7 @@ static void __init map_pages(unsigned long start_vaddr, ...@@ -466,7 +479,7 @@ static void __init map_pages(unsigned long start_vaddr,
*/ */
if (force) if (force)
pte = __mk_pte(address, pgprot); pte = __mk_pte(address, pgprot);
else if (core_kernel_text(vaddr) && else if (parisc_text_address(vaddr) &&
address != fv_addr) address != fv_addr)
pte = __mk_pte(address, PAGE_KERNEL_EXEC); pte = __mk_pte(address, PAGE_KERNEL_EXEC);
else else
......
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