diff options
Diffstat (limited to 'arch/tile/kernel/head_32.S')
-rw-r--r-- | arch/tile/kernel/head_32.S | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S new file mode 100644 index 000000000000..2b4f6c091701 --- /dev/null +++ b/arch/tile/kernel/head_32.S | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * TILE startup code. | ||
15 | */ | ||
16 | |||
17 | #include <linux/linkage.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <asm/page.h> | ||
20 | #include <asm/pgtable.h> | ||
21 | #include <asm/thread_info.h> | ||
22 | #include <asm/processor.h> | ||
23 | #include <asm/asm-offsets.h> | ||
24 | #include <hv/hypervisor.h> | ||
25 | #include <arch/chip.h> | ||
26 | |||
27 | /* | ||
28 | * This module contains the entry code for kernel images. It performs the | ||
29 | * minimal setup needed to call the generic C routines. | ||
30 | */ | ||
31 | |||
32 | __HEAD | ||
33 | ENTRY(_start) | ||
34 | /* Notify the hypervisor of what version of the API we want */ | ||
35 | { | ||
36 | movei r1, TILE_CHIP | ||
37 | movei r2, TILE_CHIP_REV | ||
38 | } | ||
39 | { | ||
40 | moveli r0, _HV_VERSION | ||
41 | jal hv_init | ||
42 | } | ||
43 | /* Get a reasonable default ASID in r0 */ | ||
44 | { | ||
45 | move r0, zero | ||
46 | jal hv_inquire_asid | ||
47 | } | ||
48 | /* Install the default page table */ | ||
49 | { | ||
50 | moveli r6, lo16(swapper_pgprot - PAGE_OFFSET) | ||
51 | move r4, r0 /* use starting ASID of range for this page table */ | ||
52 | } | ||
53 | { | ||
54 | moveli r0, lo16(swapper_pg_dir - PAGE_OFFSET) | ||
55 | auli r6, r6, ha16(swapper_pgprot - PAGE_OFFSET) | ||
56 | } | ||
57 | { | ||
58 | lw r2, r6 | ||
59 | addi r6, r6, 4 | ||
60 | } | ||
61 | { | ||
62 | lw r3, r6 | ||
63 | auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET) | ||
64 | } | ||
65 | { | ||
66 | inv r6 | ||
67 | move r1, zero /* high 32 bits of CPA is zero */ | ||
68 | } | ||
69 | { | ||
70 | moveli lr, lo16(1f) | ||
71 | move r5, zero | ||
72 | } | ||
73 | { | ||
74 | auli lr, lr, ha16(1f) | ||
75 | j hv_install_context | ||
76 | } | ||
77 | 1: | ||
78 | |||
79 | /* Get our processor number and save it away in SAVE_1_0. */ | ||
80 | jal hv_inquire_topology | ||
81 | mulll_uu r4, r1, r2 /* r1 == y, r2 == width */ | ||
82 | add r4, r4, r0 /* r0 == x, so r4 == cpu == y*width + x */ | ||
83 | |||
84 | #ifdef CONFIG_SMP | ||
85 | /* | ||
86 | * Load up our per-cpu offset. When the first (master) tile | ||
87 | * boots, this value is still zero, so we will load boot_pc | ||
88 | * with start_kernel, and boot_sp with init_stack + THREAD_SIZE. | ||
89 | * The master tile initializes the per-cpu offset array, so that | ||
90 | * when subsequent (secondary) tiles boot, they will instead load | ||
91 | * from their per-cpu versions of boot_sp and boot_pc. | ||
92 | */ | ||
93 | moveli r5, lo16(__per_cpu_offset) | ||
94 | auli r5, r5, ha16(__per_cpu_offset) | ||
95 | s2a r5, r4, r5 | ||
96 | lw r5, r5 | ||
97 | bnz r5, 1f | ||
98 | |||
99 | /* | ||
100 | * Save the width and height to the smp_topology variable | ||
101 | * for later use. | ||
102 | */ | ||
103 | moveli r0, lo16(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) | ||
104 | auli r0, r0, ha16(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) | ||
105 | { | ||
106 | sw r0, r2 | ||
107 | addi r0, r0, (HV_TOPOLOGY_HEIGHT_OFFSET - HV_TOPOLOGY_WIDTH_OFFSET) | ||
108 | } | ||
109 | sw r0, r3 | ||
110 | 1: | ||
111 | #else | ||
112 | move r5, zero | ||
113 | #endif | ||
114 | |||
115 | /* Load and go with the correct pc and sp. */ | ||
116 | { | ||
117 | addli r1, r5, lo16(boot_sp) | ||
118 | addli r0, r5, lo16(boot_pc) | ||
119 | } | ||
120 | { | ||
121 | auli r1, r1, ha16(boot_sp) | ||
122 | auli r0, r0, ha16(boot_pc) | ||
123 | } | ||
124 | lw r0, r0 | ||
125 | lw sp, r1 | ||
126 | or r4, sp, r4 | ||
127 | mtspr SYSTEM_SAVE_1_0, r4 /* save ksp0 + cpu */ | ||
128 | addi sp, sp, -STACK_TOP_DELTA | ||
129 | { | ||
130 | move lr, zero /* stop backtraces in the called function */ | ||
131 | jr r0 | ||
132 | } | ||
133 | ENDPROC(_start) | ||
134 | |||
135 | .section ".bss.page_aligned","w" | ||
136 | .align PAGE_SIZE | ||
137 | ENTRY(empty_zero_page) | ||
138 | .fill PAGE_SIZE,1,0 | ||
139 | END(empty_zero_page) | ||
140 | |||
141 | .macro PTE va, cpa, bits1, no_org=0 | ||
142 | .ifeq \no_org | ||
143 | .org swapper_pg_dir + HV_L1_INDEX(\va) * HV_PTE_SIZE | ||
144 | .endif | ||
145 | .word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \ | ||
146 | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) | ||
147 | .word (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN) | ||
148 | .endm | ||
149 | |||
150 | .section ".data.page_aligned","wa" | ||
151 | .align PAGE_SIZE | ||
152 | ENTRY(swapper_pg_dir) | ||
153 | /* | ||
154 | * All data pages from PAGE_OFFSET to MEM_USER_INTRPT are mapped as | ||
155 | * VA = PA + PAGE_OFFSET. We remap things with more precise access | ||
156 | * permissions and more respect for size of RAM later. | ||
157 | */ | ||
158 | .set addr, 0 | ||
159 | .rept (MEM_USER_INTRPT - PAGE_OFFSET) >> PGDIR_SHIFT | ||
160 | PTE addr + PAGE_OFFSET, addr, HV_PTE_READABLE | HV_PTE_WRITABLE | ||
161 | .set addr, addr + PGDIR_SIZE | ||
162 | .endr | ||
163 | |||
164 | /* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */ | ||
165 | PTE MEM_SV_INTRPT, 0, HV_PTE_READABLE | HV_PTE_EXECUTABLE | ||
166 | .org swapper_pg_dir + HV_L1_SIZE | ||
167 | END(swapper_pg_dir) | ||
168 | |||
169 | /* | ||
170 | * Isolate swapper_pgprot to its own cache line, since each cpu | ||
171 | * starting up will read it using VA-is-PA and local homing. | ||
172 | * This would otherwise likely conflict with other data on the cache | ||
173 | * line, once we have set its permanent home in the page tables. | ||
174 | */ | ||
175 | __INITDATA | ||
176 | .align CHIP_L2_LINE_SIZE() | ||
177 | ENTRY(swapper_pgprot) | ||
178 | PTE 0, 0, HV_PTE_READABLE | HV_PTE_WRITABLE, 1 | ||
179 | .align CHIP_L2_LINE_SIZE() | ||
180 | END(swapper_pgprot) | ||