aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
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);
164#endif 164#endif
165EXPORT_SYMBOL(__gnu_mcount_nc); 165EXPORT_SYMBOL(__gnu_mcount_nc);
166#endif 166#endif
167
168#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
169EXPORT_SYMBOL(__pv_phys_offset);
170#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 @@
26#include <mach/debug-macro.S> 26#include <mach/debug-macro.S>
27#endif 27#endif
28 28
29#if (PHYS_OFFSET & 0x001fffff)
30#error "PHYS_OFFSET must be at an even 2MiB boundary!"
31#endif
32
33#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
34#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
35
36
37/* 29/*
38 * swapper_pg_dir is the virtual address of the initial page table. 30 * swapper_pg_dir is the virtual address of the initial page table.
39 * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must 31 * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
@@ -41,6 +33,7 @@
41 * the least significant 16 bits to be 0x8000, but we could probably 33 * the least significant 16 bits to be 0x8000, but we could probably
42 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. 34 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
43 */ 35 */
36#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
44#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 37#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
45#error KERNEL_RAM_VADDR must start at 0xXXXX8000 38#error KERNEL_RAM_VADDR must start at 0xXXXX8000
46#endif 39#endif
@@ -48,8 +41,8 @@
48 .globl swapper_pg_dir 41 .globl swapper_pg_dir
49 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 42 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
50 43
51 .macro pgtbl, rd 44 .macro pgtbl, rd, phys
52 ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) 45 add \rd, \phys, #TEXT_OFFSET - 0x4000
53 .endm 46 .endm
54 47
55#ifdef CONFIG_XIP_KERNEL 48#ifdef CONFIG_XIP_KERNEL
@@ -88,14 +81,26 @@ ENTRY(stext)
88 THUMB( it eq ) @ force fixup-able long branch encoding 81 THUMB( it eq ) @ force fixup-able long branch encoding
89 beq __error_p @ yes, error 'p' 82 beq __error_p @ yes, error 'p'
90 83
84#ifndef CONFIG_XIP_KERNEL
85 adr r3, 2f
86 ldmia r3, {r4, r8}
87 sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
88 add r8, r8, r4 @ PHYS_OFFSET
89#else
90 ldr r8, =PLAT_PHYS_OFFSET
91#endif
92
91 /* 93 /*
92 * r1 = machine no, r2 = atags, 94 * r1 = machine no, r2 = atags,
93 * r9 = cpuid, r10 = procinfo 95 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
94 */ 96 */
95 bl __vet_atags 97 bl __vet_atags
96#ifdef CONFIG_SMP_ON_UP 98#ifdef CONFIG_SMP_ON_UP
97 bl __fixup_smp 99 bl __fixup_smp
98#endif 100#endif
101#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
102 bl __fixup_pv_table
103#endif
99 bl __create_page_tables 104 bl __create_page_tables
100 105
101 /* 106 /*
@@ -114,21 +119,24 @@ ENTRY(stext)
1141: b __enable_mmu 1191: b __enable_mmu
115ENDPROC(stext) 120ENDPROC(stext)
116 .ltorg 121 .ltorg
122#ifndef CONFIG_XIP_KERNEL
1232: .long .
124 .long PAGE_OFFSET
125#endif
117 126
118/* 127/*
119 * Setup the initial page tables. We only setup the barest 128 * Setup the initial page tables. We only setup the barest
120 * amount which are required to get the kernel running, which 129 * amount which are required to get the kernel running, which
121 * generally means mapping in the kernel code. 130 * generally means mapping in the kernel code.
122 * 131 *
123 * r9 = cpuid 132 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
124 * r10 = procinfo
125 * 133 *
126 * Returns: 134 * Returns:
127 * r0, r3, r5-r7 corrupted 135 * r0, r3, r5-r7 corrupted
128 * r4 = physical page table address 136 * r4 = physical page table address
129 */ 137 */
130__create_page_tables: 138__create_page_tables:
131 pgtbl r4 @ page table address 139 pgtbl r4, r8 @ page table address
132 140
133 /* 141 /*
134 * Clear the 16K level 1 swapper page table 142 * Clear the 16K level 1 swapper page table
@@ -184,10 +192,8 @@ __create_page_tables:
184 /* 192 /*
185 * Map some ram to cover our .data and .bss areas. 193 * Map some ram to cover our .data and .bss areas.
186 */ 194 */
187 orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) 195 add r3, r8, #TEXT_OFFSET
188 .if (KERNEL_RAM_PADDR & 0x00f00000) 196 orr r3, r3, r7
189 orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
190 .endif
191 add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 197 add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
192 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! 198 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
193 ldr r6, =(_end - 1) 199 ldr r6, =(_end - 1)
@@ -200,14 +206,17 @@ __create_page_tables:
200#endif 206#endif
201 207
202 /* 208 /*
203 * Then map first 1MB of ram in case it contains our boot params. 209 * Then map boot params address in r2 or
210 * the first 1MB of ram if boot params address is not specified.
204 */ 211 */
205 add r0, r4, #PAGE_OFFSET >> 18 212 mov r0, r2, lsr #20
206 orr r6, r7, #(PHYS_OFFSET & 0xff000000) 213 movs r0, r0, lsl #20
207 .if (PHYS_OFFSET & 0x00f00000) 214 moveq r0, r8
208 orr r6, r6, #(PHYS_OFFSET & 0x00f00000) 215 sub r3, r0, r8
209 .endif 216 add r3, r3, #PAGE_OFFSET
210 str r6, [r0] 217 add r3, r4, r3, lsr #18
218 orr r6, r7, r0
219 str r6, [r3]
211 220
212#ifdef CONFIG_DEBUG_LL 221#ifdef CONFIG_DEBUG_LL
213#ifndef CONFIG_DEBUG_ICEDCC 222#ifndef CONFIG_DEBUG_ICEDCC
@@ -452,4 +461,129 @@ ENTRY(fixup_smp)
452 ldmfd sp!, {r4 - r6, pc} 461 ldmfd sp!, {r4 - r6, pc}
453ENDPROC(fixup_smp) 462ENDPROC(fixup_smp)
454 463
464#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
465
466/* __fixup_pv_table - patch the stub instructions with the delta between
467 * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
468 * can be expressed by an immediate shifter operand. The stub instruction
469 * has a form of '(add|sub) rd, rn, #imm'.
470 */
471 __HEAD
472__fixup_pv_table:
473 adr r0, 1f
474 ldmia r0, {r3-r5, r7}
475 sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
476 add r4, r4, r3 @ adjust table start address
477 add r5, r5, r3 @ adjust table end address
478 add r7, r7, r3 @ adjust __pv_phys_offset address
479 str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset
480#ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
481 mov r6, r3, lsr #24 @ constant for add/sub instructions
482 teq r3, r6, lsl #24 @ must be 16MiB aligned
483#else
484 mov r6, r3, lsr #16 @ constant for add/sub instructions
485 teq r3, r6, lsl #16 @ must be 64kiB aligned
486#endif
487THUMB( it ne @ cross section branch )
488 bne __error
489 str r6, [r7, #4] @ save to __pv_offset
490 b __fixup_a_pv_table
491ENDPROC(__fixup_pv_table)
492
493 .align
4941: .long .
495 .long __pv_table_begin
496 .long __pv_table_end
4972: .long __pv_phys_offset
498
499 .text
500__fixup_a_pv_table:
501#ifdef CONFIG_THUMB2_KERNEL
502#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
503 lsls r0, r6, #24
504 lsr r6, #8
505 beq 1f
506 clz r7, r0
507 lsr r0, #24
508 lsl r0, r7
509 bic r0, 0x0080
510 lsrs r7, #1
511 orrcs r0, #0x0080
512 orr r0, r0, r7, lsl #12
513#endif
5141: lsls r6, #24
515 beq 4f
516 clz r7, r6
517 lsr r6, #24
518 lsl r6, r7
519 bic r6, #0x0080
520 lsrs r7, #1
521 orrcs r6, #0x0080
522 orr r6, r6, r7, lsl #12
523 orr r6, #0x4000
524 b 4f
5252: @ at this point the C flag is always clear
526 add r7, r3
527#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
528 ldrh ip, [r7]
529 tst ip, 0x0400 @ the i bit tells us LS or MS byte
530 beq 3f
531 cmp r0, #0 @ set C flag, and ...
532 biceq ip, 0x0400 @ immediate zero value has a special encoding
533 streqh ip, [r7] @ that requires the i bit cleared
534#endif
5353: ldrh ip, [r7, #2]
536 and ip, 0x8f00
537 orrcc ip, r6 @ mask in offset bits 31-24
538 orrcs ip, r0 @ mask in offset bits 23-16
539 strh ip, [r7, #2]
5404: cmp r4, r5
541 ldrcc r7, [r4], #4 @ use branch for delay slot
542 bcc 2b
543 bx lr
544#else
545#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
546 and r0, r6, #255 @ offset bits 23-16
547 mov r6, r6, lsr #8 @ offset bits 31-24
548#else
549 mov r0, #0 @ just in case...
550#endif
551 b 3f
5522: ldr ip, [r7, r3]
553 bic ip, ip, #0x000000ff
554 tst ip, #0x400 @ rotate shift tells us LS or MS byte
555 orrne ip, ip, r6 @ mask in offset bits 31-24
556 orreq ip, ip, r0 @ mask in offset bits 23-16
557 str ip, [r7, r3]
5583: cmp r4, r5
559 ldrcc r7, [r4], #4 @ use branch for delay slot
560 bcc 2b
561 mov pc, lr
562#endif
563ENDPROC(__fixup_a_pv_table)
564
565ENTRY(fixup_pv_table)
566 stmfd sp!, {r4 - r7, lr}
567 ldr r2, 2f @ get address of __pv_phys_offset
568 mov r3, #0 @ no offset
569 mov r4, r0 @ r0 = table start
570 add r5, r0, r1 @ r1 = table size
571 ldr r6, [r2, #4] @ get __pv_offset
572 bl __fixup_a_pv_table
573 ldmfd sp!, {r4 - r7, pc}
574ENDPROC(fixup_pv_table)
575
576 .align
5772: .long __pv_phys_offset
578
579 .data
580 .globl __pv_phys_offset
581 .type __pv_phys_offset, %object
582__pv_phys_offset:
583 .long 0
584 .size __pv_phys_offset, . - __pv_phys_offset
585__pv_offset:
586 .long 0
587#endif
588
455#include "head-common.S" 589#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,
283 return NULL; 283 return NULL;
284} 284}
285 285
286extern void fixup_pv_table(const void *, unsigned long);
286extern void fixup_smp(const void *, unsigned long); 287extern void fixup_smp(const void *, unsigned long);
287 288
288int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, 289int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
289 struct module *mod) 290 struct module *mod)
290{ 291{
291 const Elf_Shdr * __maybe_unused s = NULL; 292 const Elf_Shdr *s = NULL;
292#ifdef CONFIG_ARM_UNWIND 293#ifdef CONFIG_ARM_UNWIND
293 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 294 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
294 const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; 295 const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
@@ -333,6 +334,11 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
333 maps[i].txt_sec->sh_addr, 334 maps[i].txt_sec->sh_addr,
334 maps[i].txt_sec->sh_size); 335 maps[i].txt_sec->sh_size);
335#endif 336#endif
337#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
338 s = find_mod_section(hdr, sechdrs, ".pv_table");
339 if (s)
340 fixup_pv_table((void *)s->sh_addr, s->sh_size);
341#endif
336 s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); 342 s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
337 if (s && !is_smp()) 343 if (s && !is_smp())
338 fixup_smp((void *)s->sh_addr, s->sh_size); 344 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, ...)
325 printk("%s", buf); 325 printk("%s", buf);
326} 326}
327 327
328static struct machine_desc * __init lookup_machine_type(unsigned int type)
329{
330 extern struct machine_desc __arch_info_begin[], __arch_info_end[];
331 struct machine_desc *p;
332
333 for (p = __arch_info_begin; p < __arch_info_end; p++)
334 if (type == p->nr)
335 return p;
336
337 early_print("\n"
338 "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
339 "Available machine support:\n\nID (hex)\tNAME\n", type);
340
341 for (p = __arch_info_begin; p < __arch_info_end; p++)
342 early_print("%08x\t%s\n", p->nr, p->name);
343
344 early_print("\nPlease check your kernel config and/or bootloader.\n");
345
346 while (true)
347 /* can't use cpu_relax() here as it may require MMU setup */;
348}
349
350static void __init feat_v6_fixup(void) 328static void __init feat_v6_fixup(void)
351{ 329{
352 int id = read_cpuid_id(); 330 int id = read_cpuid_id();
@@ -463,21 +441,29 @@ void cpu_init(void)
463 441
464static struct machine_desc * __init setup_machine(unsigned int nr) 442static struct machine_desc * __init setup_machine(unsigned int nr)
465{ 443{
466 struct machine_desc *list; 444 extern struct machine_desc __arch_info_begin[], __arch_info_end[];
445 struct machine_desc *p;
467 446
468 /* 447 /*
469 * locate machine in the list of supported machines. 448 * locate machine in the list of supported machines.
470 */ 449 */
471 list = lookup_machine_type(nr); 450 for (p = __arch_info_begin; p < __arch_info_end; p++)
472 if (!list) { 451 if (nr == p->nr) {
473 printk("Machine configuration botched (nr %d), unable " 452 printk("Machine: %s\n", p->name);
474 "to continue.\n", nr); 453 return p;
475 while (1); 454 }
476 }
477 455
478 printk("Machine: %s\n", list->name); 456 early_print("\n"
457 "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"
458 "Available machine support:\n\nID (hex)\tNAME\n", nr);
479 459
480 return list; 460 for (p = __arch_info_begin; p < __arch_info_end; p++)
461 early_print("%08x\t%s\n", p->nr, p->name);
462
463 early_print("\nPlease check your kernel config and/or bootloader.\n");
464
465 while (true)
466 /* can't use cpu_relax() here as it may require MMU setup */;
481} 467}
482 468
483static int __init arm_add_memory(unsigned long start, unsigned long size) 469static int __init arm_add_memory(unsigned long start, unsigned long size)
@@ -740,7 +726,7 @@ static struct init_tags {
740 { tag_size(tag_core), ATAG_CORE }, 726 { tag_size(tag_core), ATAG_CORE },
741 { 1, PAGE_SIZE, 0xff }, 727 { 1, PAGE_SIZE, 0xff },
742 { tag_size(tag_mem32), ATAG_MEM }, 728 { tag_size(tag_mem32), ATAG_MEM },
743 { MEM_SIZE, PHYS_OFFSET }, 729 { MEM_SIZE },
744 { 0, ATAG_NONE } 730 { 0, ATAG_NONE }
745}; 731};
746 732
@@ -839,6 +825,8 @@ void __init setup_arch(char **cmdline_p)
839 struct machine_desc *mdesc; 825 struct machine_desc *mdesc;
840 char *from = default_command_line; 826 char *from = default_command_line;
841 827
828 init_tags.mem.start = PHYS_OFFSET;
829
842 unwind_init(); 830 unwind_init();
843 831
844 setup_processor(); 832 setup_processor();
@@ -851,8 +839,25 @@ void __init setup_arch(char **cmdline_p)
851 839
852 if (__atags_pointer) 840 if (__atags_pointer)
853 tags = phys_to_virt(__atags_pointer); 841 tags = phys_to_virt(__atags_pointer);
854 else if (mdesc->boot_params) 842 else if (mdesc->boot_params) {
855 tags = phys_to_virt(mdesc->boot_params); 843#ifdef CONFIG_MMU
844 /*
845 * We still are executing with a minimal MMU mapping created
846 * with the presumption that the machine default for this
847 * is located in the first MB of RAM. Anything else will
848 * fault and silently hang the kernel at this point.
849 */
850 if (mdesc->boot_params < PHYS_OFFSET ||
851 mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
852 printk(KERN_WARNING
853 "Default boot params at physical 0x%08lx out of reach\n",
854 mdesc->boot_params);
855 } else
856#endif
857 {
858 tags = phys_to_virt(mdesc->boot_params);
859 }
860 }
856 861
857#if defined(CONFIG_DEPRECATED_PARAM_STRUCT) 862#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
858 /* 863 /*
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 @@
15#include <linux/string.h> /* memcpy */ 15#include <linux/string.h> /* memcpy */
16#include <asm/cputype.h> 16#include <asm/cputype.h>
17#include <asm/mach/map.h> 17#include <asm/mach/map.h>
18#include <mach/memory.h> 18#include <asm/memory.h>
19#include "tcm.h" 19#include "tcm.h"
20 20
21static struct gen_pool *tcm_pool; 21static 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
64 __smpalt_end = .; 64 __smpalt_end = .;
65#endif 65#endif
66 66
67 __pv_table_begin = .;
68 *(.pv_table)
69 __pv_table_end = .;
70
67 INIT_SETUP(16) 71 INIT_SETUP(16)
68 72
69 INIT_CALLS 73 INIT_CALLS