diff options
-rw-r--r-- | arch/powerpc/include/asm/page.h | 85 | ||||
-rw-r--r-- | arch/powerpc/mm/init_32.c | 7 |
2 files changed, 89 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index f149967ee6b5..f072e974f8a2 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h | |||
@@ -97,12 +97,26 @@ extern unsigned int HPAGE_SHIFT; | |||
97 | 97 | ||
98 | extern phys_addr_t memstart_addr; | 98 | extern phys_addr_t memstart_addr; |
99 | extern phys_addr_t kernstart_addr; | 99 | extern phys_addr_t kernstart_addr; |
100 | |||
101 | #ifdef CONFIG_RELOCATABLE_PPC32 | ||
102 | extern long long virt_phys_offset; | ||
100 | #endif | 103 | #endif |
104 | |||
105 | #endif /* __ASSEMBLY__ */ | ||
101 | #define PHYSICAL_START kernstart_addr | 106 | #define PHYSICAL_START kernstart_addr |
102 | #else | 107 | |
108 | #else /* !CONFIG_NONSTATIC_KERNEL */ | ||
103 | #define PHYSICAL_START ASM_CONST(CONFIG_PHYSICAL_START) | 109 | #define PHYSICAL_START ASM_CONST(CONFIG_PHYSICAL_START) |
104 | #endif | 110 | #endif |
105 | 111 | ||
112 | /* See Description below for VIRT_PHYS_OFFSET */ | ||
113 | #ifdef CONFIG_RELOCATABLE_PPC32 | ||
114 | #define VIRT_PHYS_OFFSET virt_phys_offset | ||
115 | #else | ||
116 | #define VIRT_PHYS_OFFSET (KERNELBASE - PHYSICAL_START) | ||
117 | #endif | ||
118 | |||
119 | |||
106 | #ifdef CONFIG_PPC64 | 120 | #ifdef CONFIG_PPC64 |
107 | #define MEMORY_START 0UL | 121 | #define MEMORY_START 0UL |
108 | #elif defined(CONFIG_NONSTATIC_KERNEL) | 122 | #elif defined(CONFIG_NONSTATIC_KERNEL) |
@@ -125,12 +139,77 @@ extern phys_addr_t kernstart_addr; | |||
125 | * determine MEMORY_START until then. However we can determine PHYSICAL_START | 139 | * determine MEMORY_START until then. However we can determine PHYSICAL_START |
126 | * from information at hand (program counter, TLB lookup). | 140 | * from information at hand (program counter, TLB lookup). |
127 | * | 141 | * |
142 | * On BookE with RELOCATABLE (RELOCATABLE_PPC32) | ||
143 | * | ||
144 | * With RELOCATABLE_PPC32, we support loading the kernel at any physical | ||
145 | * address without any restriction on the page alignment. | ||
146 | * | ||
147 | * We find the runtime address of _stext and relocate ourselves based on | ||
148 | * the following calculation: | ||
149 | * | ||
150 | * virtual_base = ALIGN_DOWN(KERNELBASE,256M) + | ||
151 | * MODULO(_stext.run,256M) | ||
152 | * and create the following mapping: | ||
153 | * | ||
154 | * ALIGN_DOWN(_stext.run,256M) => ALIGN_DOWN(KERNELBASE,256M) | ||
155 | * | ||
156 | * When we process relocations, we cannot depend on the | ||
157 | * existing equation for the __va()/__pa() translations: | ||
158 | * | ||
159 | * __va(x) = (x) - PHYSICAL_START + KERNELBASE | ||
160 | * | ||
161 | * Where: | ||
162 | * PHYSICAL_START = kernstart_addr = Physical address of _stext | ||
163 | * KERNELBASE = Compiled virtual address of _stext. | ||
164 | * | ||
165 | * This formula holds true iff, kernel load address is TLB page aligned. | ||
166 | * | ||
167 | * In our case, we need to also account for the shift in the kernel Virtual | ||
168 | * address. | ||
169 | * | ||
170 | * E.g., | ||
171 | * | ||
172 | * Let the kernel be loaded at 64MB and KERNELBASE be 0xc0000000 (same as PAGE_OFFSET). | ||
173 | * In this case, we would be mapping 0 to 0xc0000000, and kernstart_addr = 64M | ||
174 | * | ||
175 | * Now __va(1MB) = (0x100000) - (0x4000000) + 0xc0000000 | ||
176 | * = 0xbc100000 , which is wrong. | ||
177 | * | ||
178 | * Rather, it should be : 0xc0000000 + 0x100000 = 0xc0100000 | ||
179 | * according to our mapping. | ||
180 | * | ||
181 | * Hence we use the following formula to get the translations right: | ||
182 | * | ||
183 | * __va(x) = (x) - [ PHYSICAL_START - Effective KERNELBASE ] | ||
184 | * | ||
185 | * Where : | ||
186 | * PHYSICAL_START = dynamic load address.(kernstart_addr variable) | ||
187 | * Effective KERNELBASE = virtual_base = | ||
188 | * = ALIGN_DOWN(KERNELBASE,256M) + | ||
189 | * MODULO(PHYSICAL_START,256M) | ||
190 | * | ||
191 | * To make the cost of __va() / __pa() more light weight, we introduce | ||
192 | * a new variable virt_phys_offset, which will hold : | ||
193 | * | ||
194 | * virt_phys_offset = Effective KERNELBASE - PHYSICAL_START | ||
195 | * = ALIGN_DOWN(KERNELBASE,256M) - | ||
196 | * ALIGN_DOWN(PHYSICALSTART,256M) | ||
197 | * | ||
198 | * Hence : | ||
199 | * | ||
200 | * __va(x) = x - PHYSICAL_START + Effective KERNELBASE | ||
201 | * = x + virt_phys_offset | ||
202 | * | ||
203 | * and | ||
204 | * __pa(x) = x + PHYSICAL_START - Effective KERNELBASE | ||
205 | * = x - virt_phys_offset | ||
206 | * | ||
128 | * On non-Book-E PPC64 PAGE_OFFSET and MEMORY_START are constants so use | 207 | * On non-Book-E PPC64 PAGE_OFFSET and MEMORY_START are constants so use |
129 | * the other definitions for __va & __pa. | 208 | * the other definitions for __va & __pa. |
130 | */ | 209 | */ |
131 | #ifdef CONFIG_BOOKE | 210 | #ifdef CONFIG_BOOKE |
132 | #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) - PHYSICAL_START + KERNELBASE)) | 211 | #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + VIRT_PHYS_OFFSET)) |
133 | #define __pa(x) ((unsigned long)(x) + PHYSICAL_START - KERNELBASE) | 212 | #define __pa(x) ((unsigned long)(x) - VIRT_PHYS_OFFSET) |
134 | #else | 213 | #else |
135 | #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START)) | 214 | #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START)) |
136 | #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START) | 215 | #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START) |
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 161cefde5c15..60a4e4e84e8c 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c | |||
@@ -65,6 +65,13 @@ phys_addr_t memstart_addr = (phys_addr_t)~0ull; | |||
65 | EXPORT_SYMBOL(memstart_addr); | 65 | EXPORT_SYMBOL(memstart_addr); |
66 | phys_addr_t kernstart_addr; | 66 | phys_addr_t kernstart_addr; |
67 | EXPORT_SYMBOL(kernstart_addr); | 67 | EXPORT_SYMBOL(kernstart_addr); |
68 | |||
69 | #ifdef CONFIG_RELOCATABLE_PPC32 | ||
70 | /* Used in __va()/__pa() */ | ||
71 | long long virt_phys_offset; | ||
72 | EXPORT_SYMBOL(virt_phys_offset); | ||
73 | #endif | ||
74 | |||
68 | phys_addr_t lowmem_end_addr; | 75 | phys_addr_t lowmem_end_addr; |
69 | 76 | ||
70 | int boot_mapsize; | 77 | int boot_mapsize; |