diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/boot/compressed/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/boot/compressed/head.S | 49 | ||||
-rw-r--r-- | arch/arm/include/asm/memory.h | 5 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 31 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 10 |
6 files changed, 90 insertions, 9 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 62ec97f5928c..fa492c2e051a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1166,6 +1166,9 @@ config UACCESS_WITH_MEMCPY However, if the CPU data cache is using a write-allocate mode, this option is unlikely to provide any performance gain. +config RUNTIME_PHYS_OFFSET + bool + endmenu menu "Boot options" diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index ce39dc540085..b0bba0911f22 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -4,6 +4,7 @@ # create a compressed vmlinuz image from the original vmlinux # +AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) HEAD = head.o OBJS = misc.o FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 4515728c5345..4a7649025228 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -112,6 +112,16 @@ #endif .endm + .macro debug_passed_physoffset +#ifdef DEBUG + bleq 1f + kputc #'!' + kphex r9, 8 + kputc #'\n' +1: +#endif + .endm + .section ".start", #alloc, #execinstr /* * sort out different calling conventions @@ -129,6 +139,7 @@ start: .word _edata @ zImage end address 1: mov r7, r1 @ save architecture ID mov r8, r2 @ save atags pointer + mov r9, r3 @ save phys_offset #ifndef __ARM_ARCH_2__ /* @@ -222,6 +233,43 @@ not_relocated: mov r0, #0 cmp r2, r3 blo 1b +#ifdef CONFIG_RUNTIME_PHYS_OFFSET + /* + * assert physoffset passed by bootloader is properly + * 2MiB-aligned, ... + */ + ldr r10, =0x001fffff + + tst r9, r10 + debug_passed_physoffset + tst r9, r10 + + /* + * ... if not guess it based on sp. + * sp & 0xf8000000 should work for most machines. The needed + * preconditions are: + * - physoffset is aligned to a 128MiB boundary + * (As of Jan 2010 all but s3c2400, u300 and at91 have it. + * For the latter it depends on configuration.) + * - sp < physoffset + 128MiB (which is definitely true if you + * only have 128MiB of RAM or less) + */ + andne r9, sp, #0xf8000000 +#ifdef DEBUG + kputc #'P' + kphex r9, 8 + kputc #'\n' +#endif + + add r4, r9, #TEXT_OFFSET +#else /* ifdef CONFIG_RUNTIME_PHYS_OFFSET */ + /* warn on r4(ZRELADDR) != r9 + TEXT_OFFSET */ + add r10, r9, #TEXT_OFFSET + cmp r10, r4 + debug_passed_physoffset + +#endif /* ifdef CONFIG_RUNTIME_PHYS_OFFSET / else */ + /* * The C runtime environment should now be setup * sufficiently. Turn the cache on, set up some @@ -545,6 +593,7 @@ call_kernel: bl cache_clean_flush mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer + sub r3, r4, #TEXT_OFFSET @ physoffset mov pc, r4 @ call kernel /* diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 85763db87449..b325f46a6ad3 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -24,6 +24,11 @@ */ #define UL(x) _AC(x, UL) +#if defined(CONFIG_RUNTIME_PHYS_OFFSET) && !defined(__ASSEMBLY__) +extern unsigned long phys_offset; +#define PHYS_OFFSET phys_offset +#endif + #ifdef CONFIG_MMU /* diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 21e17dc94cb5..7d8d4b0ce66e 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -22,12 +22,14 @@ #include <asm/thread_info.h> #include <asm/system.h> +#if !defined(CONFIG_RUNTIME_PHYS_OFFSET) #if (PHYS_OFFSET & 0x001fffff) #error "PHYS_OFFSET must be at an even 2MiB boundary!" #endif +#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) +#endif #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) -#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) /* @@ -44,8 +46,8 @@ .globl swapper_pg_dir .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 - .macro pgtbl, rd - ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) + .macro pgtbl, rd, phys_offset + add \rd, \phys_offset, #(TEXT_OFFSET - 0x4000) .endm #ifdef CONFIG_XIP_KERNEL @@ -210,9 +212,25 @@ ENDPROC(__turn_mmu_on) * Returns: * r0, r3, r6, r7 corrupted * r4 = physical page table address + * r5 = physical start address of (the first bank of) RAM (PHYS_OFFSET) */ __create_page_tables: - pgtbl r4 @ page table address +#if defined(CONFIG_RUNTIME_PHYS_OFFSET) + @ stext is at PHYS_OFFSET + TEXT_OFFSET. As PHYS_OFFSET has to be + @ 2MiB-aligned and assuming that TEXT_OFFSET < 2MiB + @ stext & 0xffe00000 yields PHYS_OFFSET + adr r5, stext + ldr r4, =0xffe00000 + and r5, r5, r4 + + @ save phys_offset + ldr r4, =(phys_offset - PAGE_OFFSET) + str r5, [r4, r5] +#else + ldr r5, =PHYS_OFFSET +#endif + + pgtbl r4, r5 @ r4 = page table address /* * Clear the 16K level 1 swapper page table @@ -276,10 +294,7 @@ __create_page_tables: * Then map first 1MB of ram in case it contains our boot params. */ add r0, r4, #PAGE_OFFSET >> 18 - orr r6, r7, #(PHYS_OFFSET & 0xff000000) - .if (PHYS_OFFSET & 0x00f00000) - orr r6, r6, #(PHYS_OFFSET & 0x00f00000) - .endif + orr r6, r7, r5 str r6, [r0] #ifdef CONFIG_DEBUG_LL diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index bc5e4128f9f3..f17193b64f57 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -64,6 +64,12 @@ __setup("fpe=", fpe_setup); extern void paging_init(struct machine_desc *desc); extern void reboot_setup(char *str); +#if defined(CONFIG_RUNTIME_PHYS_OFFSET) +/* assign a value to prevent phys_offset from ending in up bss */ +unsigned long phys_offset = 0xdeadbeef; +EXPORT_SYMBOL(phys_offset); +#endif + unsigned int processor_id; EXPORT_SYMBOL(processor_id); unsigned int __machine_arch_type; @@ -665,7 +671,7 @@ static struct init_tags { { tag_size(tag_core), ATAG_CORE }, { 1, PAGE_SIZE, 0xff }, { tag_size(tag_mem32), ATAG_MEM }, - { MEM_SIZE, PHYS_OFFSET }, + { MEM_SIZE, }, { 0, ATAG_NONE } }; @@ -699,6 +705,8 @@ void __init setup_arch(char **cmdline_p) tags = phys_to_virt(__atags_pointer); else if (mdesc->boot_params) tags = phys_to_virt(mdesc->boot_params); + else + init_tags.mem.start = PHYS_OFFSET; /* * If we have the old style parameters, convert them to |