aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King2011-03-16 23:35:27 +0000
committerRussell King2011-03-16 23:35:27 +0000
commit05e34754518b6a90d5c392790c032575fab12d66 (patch)
tree318d321262269eff585573ab2acf04a2ff2b65f4 /arch/arm/kernel
parentbd1274dc005c2cee41771a7cc616f4709a6e6323 (diff)
parentb511d75d6150892e67c8ebfa9dc8eb37ebd02aa3 (diff)
Merge branch 'p2v' into devel
Conflicts: arch/arm/kernel/module.c arch/arm/mach-s5pv210/sleep.S
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/armksyms.c4
-rw-r--r--arch/arm/kernel/head.S184
-rw-r--r--arch/arm/kernel/module.c8
-rw-r--r--arch/arm/kernel/setup.c73
-rw-r--r--arch/arm/kernel/tcm.c2
-rw-r--r--arch/arm/kernel/vmlinux.lds.S4
6 files changed, 214 insertions, 61 deletions
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index d5d4185f0c24..acca35aebe28 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -164,3 +164,7 @@ EXPORT_SYMBOL(mcount);
#endif
EXPORT_SYMBOL(__gnu_mcount_nc);
#endif
+
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+EXPORT_SYMBOL(__pv_phys_offset);
+#endif
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 60fe2795f4a3..c9173cfbbc74 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -26,14 +26,6 @@
#include <mach/debug-macro.S>
#endif
-#if (PHYS_OFFSET & 0x001fffff)
-#error "PHYS_OFFSET must be at an even 2MiB boundary!"
-#endif
-
-#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
-#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
-
-
/*
* swapper_pg_dir is the virtual address of the initial page table.
* We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
@@ -41,6 +33,7 @@
* the least significant 16 bits to be 0x8000, but we could probably
* relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
*/
+#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
#error KERNEL_RAM_VADDR must start at 0xXXXX8000
#endif
@@ -48,8 +41,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
+ add \rd, \phys, #TEXT_OFFSET - 0x4000
.endm
#ifdef CONFIG_XIP_KERNEL
@@ -88,14 +81,26 @@ ENTRY(stext)
THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p'
+#ifndef CONFIG_XIP_KERNEL
+ adr r3, 2f
+ ldmia r3, {r4, r8}
+ sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
+ add r8, r8, r4 @ PHYS_OFFSET
+#else
+ ldr r8, =PLAT_PHYS_OFFSET
+#endif
+
/*
* r1 = machine no, r2 = atags,
- * r9 = cpuid, r10 = procinfo
+ * r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP
bl __fixup_smp
#endif
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+ bl __fixup_pv_table
+#endif
bl __create_page_tables
/*
@@ -114,21 +119,24 @@ ENTRY(stext)
1: b __enable_mmu
ENDPROC(stext)
.ltorg
+#ifndef CONFIG_XIP_KERNEL
+2: .long .
+ .long PAGE_OFFSET
+#endif
/*
* Setup the initial page tables. We only setup the barest
* amount which are required to get the kernel running, which
* generally means mapping in the kernel code.
*
- * r9 = cpuid
- * r10 = procinfo
+ * r8 = phys_offset, r9 = cpuid, r10 = procinfo
*
* Returns:
* r0, r3, r5-r7 corrupted
* r4 = physical page table address
*/
__create_page_tables:
- pgtbl r4 @ page table address
+ pgtbl r4, r8 @ page table address
/*
* Clear the 16K level 1 swapper page table
@@ -184,10 +192,8 @@ __create_page_tables:
/*
* Map some ram to cover our .data and .bss areas.
*/
- orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
- .if (KERNEL_RAM_PADDR & 0x00f00000)
- orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
- .endif
+ add r3, r8, #TEXT_OFFSET
+ orr r3, r3, r7
add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
ldr r6, =(_end - 1)
@@ -200,14 +206,17 @@ __create_page_tables:
#endif
/*
- * Then map first 1MB of ram in case it contains our boot params.
+ * Then map boot params address in r2 or
+ * the first 1MB of ram if boot params address is not specified.
*/
- add r0, r4, #PAGE_OFFSET >> 18
- orr r6, r7, #(PHYS_OFFSET & 0xff000000)
- .if (PHYS_OFFSET & 0x00f00000)
- orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
- .endif
- str r6, [r0]
+ mov r0, r2, lsr #20
+ movs r0, r0, lsl #20
+ moveq r0, r8
+ sub r3, r0, r8
+ add r3, r3, #PAGE_OFFSET
+ add r3, r4, r3, lsr #18
+ orr r6, r7, r0
+ str r6, [r3]
#ifdef CONFIG_DEBUG_LL
#ifndef CONFIG_DEBUG_ICEDCC
@@ -452,4 +461,129 @@ ENTRY(fixup_smp)
ldmfd sp!, {r4 - r6, pc}
ENDPROC(fixup_smp)
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+
+/* __fixup_pv_table - patch the stub instructions with the delta between
+ * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
+ * can be expressed by an immediate shifter operand. The stub instruction
+ * has a form of '(add|sub) rd, rn, #imm'.
+ */
+ __HEAD
+__fixup_pv_table:
+ adr r0, 1f
+ ldmia r0, {r3-r5, r7}
+ sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
+ add r4, r4, r3 @ adjust table start address
+ add r5, r5, r3 @ adjust table end address
+ add r7, r7, r3 @ adjust __pv_phys_offset address
+ str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset
+#ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+ mov r6, r3, lsr #24 @ constant for add/sub instructions
+ teq r3, r6, lsl #24 @ must be 16MiB aligned
+#else
+ mov r6, r3, lsr #16 @ constant for add/sub instructions
+ teq r3, r6, lsl #16 @ must be 64kiB aligned
+#endif
+THUMB( it ne @ cross section branch )
+ bne __error
+ str r6, [r7, #4] @ save to __pv_offset
+ b __fixup_a_pv_table
+ENDPROC(__fixup_pv_table)
+
+ .align
+1: .long .
+ .long __pv_table_begin
+ .long __pv_table_end
+2: .long __pv_phys_offset
+
+ .text
+__fixup_a_pv_table:
+#ifdef CONFIG_THUMB2_KERNEL
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+ lsls r0, r6, #24
+ lsr r6, #8
+ beq 1f
+ clz r7, r0
+ lsr r0, #24
+ lsl r0, r7
+ bic r0, 0x0080
+ lsrs r7, #1
+ orrcs r0, #0x0080
+ orr r0, r0, r7, lsl #12
+#endif
+1: lsls r6, #24
+ beq 4f
+ clz r7, r6
+ lsr r6, #24
+ lsl r6, r7
+ bic r6, #0x0080
+ lsrs r7, #1
+ orrcs r6, #0x0080
+ orr r6, r6, r7, lsl #12
+ orr r6, #0x4000
+ b 4f
+2: @ at this point the C flag is always clear
+ add r7, r3
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+ ldrh ip, [r7]
+ tst ip, 0x0400 @ the i bit tells us LS or MS byte
+ beq 3f
+ cmp r0, #0 @ set C flag, and ...
+ biceq ip, 0x0400 @ immediate zero value has a special encoding
+ streqh ip, [r7] @ that requires the i bit cleared
+#endif
+3: ldrh ip, [r7, #2]
+ and ip, 0x8f00
+ orrcc ip, r6 @ mask in offset bits 31-24
+ orrcs ip, r0 @ mask in offset bits 23-16
+ strh ip, [r7, #2]
+4: cmp r4, r5
+ ldrcc r7, [r4], #4 @ use branch for delay slot
+ bcc 2b
+ bx lr
+#else
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
+ and r0, r6, #255 @ offset bits 23-16
+ mov r6, r6, lsr #8 @ offset bits 31-24
+#else
+ mov r0, #0 @ just in case...
+#endif
+ b 3f
+2: ldr ip, [r7, r3]
+ bic ip, ip, #0x000000ff
+ tst ip, #0x400 @ rotate shift tells us LS or MS byte
+ orrne ip, ip, r6 @ mask in offset bits 31-24
+ orreq ip, ip, r0 @ mask in offset bits 23-16
+ str ip, [r7, r3]
+3: cmp r4, r5
+ ldrcc r7, [r4], #4 @ use branch for delay slot
+ bcc 2b
+ mov pc, lr
+#endif
+ENDPROC(__fixup_a_pv_table)
+
+ENTRY(fixup_pv_table)
+ stmfd sp!, {r4 - r7, lr}
+ ldr r2, 2f @ get address of __pv_phys_offset
+ mov r3, #0 @ no offset
+ mov r4, r0 @ r0 = table start
+ add r5, r0, r1 @ r1 = table size
+ ldr r6, [r2, #4] @ get __pv_offset
+ bl __fixup_a_pv_table
+ ldmfd sp!, {r4 - r7, pc}
+ENDPROC(fixup_pv_table)
+
+ .align
+2: .long __pv_phys_offset
+
+ .data
+ .globl __pv_phys_offset
+ .type __pv_phys_offset, %object
+__pv_phys_offset:
+ .long 0
+ .size __pv_phys_offset, . - __pv_phys_offset
+__pv_offset:
+ .long 0
+#endif
+
#include "head-common.S"
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 6fcf22cf385c..fee7c36349eb 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -283,12 +283,13 @@ static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr,
return NULL;
}
+extern void fixup_pv_table(const void *, unsigned long);
extern void fixup_smp(const void *, unsigned long);
int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
struct module *mod)
{
- const Elf_Shdr * __maybe_unused s = NULL;
+ const Elf_Shdr *s = NULL;
#ifdef CONFIG_ARM_UNWIND
const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
@@ -333,6 +334,11 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
maps[i].txt_sec->sh_addr,
maps[i].txt_sec->sh_size);
#endif
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+ s = find_mod_section(hdr, sechdrs, ".pv_table");
+ if (s)
+ fixup_pv_table((void *)s->sh_addr, s->sh_size);
+#endif
s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
if (s && !is_smp())
fixup_smp((void *)s->sh_addr, s->sh_size);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index db2382853450..d1da92174277 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -325,28 +325,6 @@ static void __init early_print(const char *str, ...)
printk("%s", buf);
}
-static struct machine_desc * __init lookup_machine_type(unsigned int type)
-{
- extern struct machine_desc __arch_info_begin[], __arch_info_end[];
- struct machine_desc *p;
-
- for (p = __arch_info_begin; p < __arch_info_end; p++)
- if (type == p->nr)
- return p;
-
- early_print("\n"
- "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
- "Available machine support:\n\nID (hex)\tNAME\n", type);
-
- for (p = __arch_info_begin; p < __arch_info_end; p++)
- early_print("%08x\t%s\n", p->nr, p->name);
-
- early_print("\nPlease check your kernel config and/or bootloader.\n");
-
- while (true)
- /* can't use cpu_relax() here as it may require MMU setup */;
-}
-
static void __init feat_v6_fixup(void)
{
int id = read_cpuid_id();
@@ -463,21 +441,29 @@ void cpu_init(void)
static struct machine_desc * __init setup_machine(unsigned int nr)
{
- struct machine_desc *list;
+ extern struct machine_desc __arch_info_begin[], __arch_info_end[];
+ struct machine_desc *p;
/*
* locate machine in the list of supported machines.
*/
- list = lookup_machine_type(nr);
- if (!list) {
- printk("Machine configuration botched (nr %d), unable "
- "to continue.\n", nr);
- while (1);
- }
+ for (p = __arch_info_begin; p < __arch_info_end; p++)
+ if (nr == p->nr) {
+ printk("Machine: %s\n", p->name);
+ return p;
+ }
- printk("Machine: %s\n", list->name);
+ early_print("\n"
+ "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
+ "Available machine support:\n\nID (hex)\tNAME\n", nr);
- return list;
+ for (p = __arch_info_begin; p < __arch_info_end; p++)
+ early_print("%08x\t%s\n", p->nr, p->name);
+
+ early_print("\nPlease check your kernel config and/or bootloader.\n");
+
+ while (true)
+ /* can't use cpu_relax() here as it may require MMU setup */;
}
static int __init arm_add_memory(unsigned long start, unsigned long size)
@@ -740,7 +726,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 }
};
@@ -839,6 +825,8 @@ void __init setup_arch(char **cmdline_p)
struct machine_desc *mdesc;
char *from = default_command_line;
+ init_tags.mem.start = PHYS_OFFSET;
+
unwind_init();
setup_processor();
@@ -851,8 +839,25 @@ void __init setup_arch(char **cmdline_p)
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);
- else if (mdesc->boot_params)
- tags = phys_to_virt(mdesc->boot_params);
+ else if (mdesc->boot_params) {
+#ifdef CONFIG_MMU
+ /*
+ * We still are executing with a minimal MMU mapping created
+ * with the presumption that the machine default for this
+ * is located in the first MB of RAM. Anything else will
+ * fault and silently hang the kernel at this point.
+ */
+ if (mdesc->boot_params < PHYS_OFFSET ||
+ mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
+ printk(KERN_WARNING
+ "Default boot params at physical 0x%08lx out of reach\n",
+ mdesc->boot_params);
+ } else
+#endif
+ {
+ tags = phys_to_virt(mdesc->boot_params);
+ }
+ }
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
/*
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c
index 26685c2f7a49..f5cf660eefcc 100644
--- a/arch/arm/kernel/tcm.c
+++ b/arch/arm/kernel/tcm.c
@@ -15,7 +15,7 @@
#include <linux/string.h> /* memcpy */
#include <asm/cputype.h>
#include <asm/mach/map.h>
-#include <mach/memory.h>
+#include <asm/memory.h>
#include "tcm.h"
static struct gen_pool *tcm_pool;
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 61462790757f..dfbb377e251d 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -64,6 +64,10 @@ SECTIONS
__smpalt_end = .;
#endif
+ __pv_table_begin = .;
+ *(.pv_table)
+ __pv_table_end = .;
+
INIT_SETUP(16)
INIT_CALLS