Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Hexagon: add support for ARCH_PFN_OFFSET

Add support for loading the kernel at a physical offset. The
offset should still be 4M aligned.

Signed-off-by: Richard Kuo <rkuo@codeaurora.org>

+91 -55
+6
arch/hexagon/Kconfig
··· 33 33 Qualcomm Hexagon is a processor architecture designed for high 34 34 performance and low power across a wide variety of applications. 35 35 36 + 36 37 config HEXAGON_ARCH_V1 37 38 bool 38 39 ··· 45 44 46 45 config HEXAGON_ARCH_V4 47 46 bool 47 + 48 + config HEXAGON_PHYS_OFFSET 49 + def_bool y 50 + ---help--- 51 + Platforms that don't load the kernel at zero set this. 48 52 49 53 config FRAME_POINTER 50 54 def_bool y
+24 -23
arch/hexagon/include/asm/hexagon_vm.h
··· 31 31 * for tracing/debugging. 32 32 */ 33 33 34 - /* 35 - * Lets make this stuff visible only if configured, 36 - * so we can unconditionally include the file. 37 - */ 34 + #define HVM_TRAP1_VMVERSION 0 35 + #define HVM_TRAP1_VMRTE 1 36 + #define HVM_TRAP1_VMSETVEC 2 37 + #define HVM_TRAP1_VMSETIE 3 38 + #define HVM_TRAP1_VMGETIE 4 39 + #define HVM_TRAP1_VMINTOP 5 40 + #define HVM_TRAP1_VMCLRMAP 10 41 + #define HVM_TRAP1_VMNEWMAP 11 42 + #define HVM_TRAP1_FORMERLY_VMWIRE 12 43 + #define HVM_TRAP1_VMCACHE 13 44 + #define HVM_TRAP1_VMGETTIME 14 45 + #define HVM_TRAP1_VMSETTIME 15 46 + #define HVM_TRAP1_VMWAIT 16 47 + #define HVM_TRAP1_VMYIELD 17 48 + #define HVM_TRAP1_VMSTART 18 49 + #define HVM_TRAP1_VMSTOP 19 50 + #define HVM_TRAP1_VMVPID 20 51 + #define HVM_TRAP1_VMSETREGS 21 52 + #define HVM_TRAP1_VMGETREGS 22 53 + #define HVM_TRAP1_VMTIMEROP 24 38 54 39 55 #ifndef __ASSEMBLY__ 40 56 ··· 191 175 192 176 #else /* Only assembly code should reference these */ 193 177 194 - #define HVM_TRAP1_VMRTE 1 195 - #define HVM_TRAP1_VMSETVEC 2 196 - #define HVM_TRAP1_VMSETIE 3 197 - #define HVM_TRAP1_VMGETIE 4 198 - #define HVM_TRAP1_VMINTOP 5 199 - #define HVM_TRAP1_VMCLRMAP 10 200 - #define HVM_TRAP1_VMNEWMAP 11 201 - #define HVM_TRAP1_FORMERLY_VMWIRE 12 202 - #define HVM_TRAP1_VMCACHE 13 203 - #define HVM_TRAP1_VMGETTIME 14 204 - #define HVM_TRAP1_VMSETTIME 15 205 - #define HVM_TRAP1_VMWAIT 16 206 - #define HVM_TRAP1_VMYIELD 17 207 - #define HVM_TRAP1_VMSTART 18 208 - #define HVM_TRAP1_VMSTOP 19 209 - #define HVM_TRAP1_VMVPID 20 210 - #define HVM_TRAP1_VMSETREGS 21 211 - #define HVM_TRAP1_VMGETREGS 22 212 - 213 178 #endif /* __ASSEMBLY__ */ 214 179 215 180 /* ··· 221 224 #define HVM_VMEST_UM_MSK 1 222 225 #define HVM_VMEST_IE_SFT 30 223 226 #define HVM_VMEST_IE_MSK 1 227 + #define HVM_VMEST_SS_SFT 29 228 + #define HVM_VMEST_SS_MSK 1 224 229 #define HVM_VMEST_EVENTNUM_SFT 16 225 230 #define HVM_VMEST_EVENTNUM_MSK 0xff 226 231 #define HVM_VMEST_CAUSE_SFT 0 ··· 259 260 #define HVM_GE_C_INVI 0x15 260 261 #define HVM_GE_C_PRIVI 0x1B 261 262 #define HVM_GE_C_XMAL 0x1C 263 + #define HVM_GE_C_WREG 0x1D 264 + #define HVM_GE_C_PCAL 0x1E 262 265 #define HVM_GE_C_RMAL 0x20 263 266 #define HVM_GE_C_WMAL 0x21 264 267 #define HVM_GE_C_RPROT 0x22
+15 -6
arch/hexagon/include/asm/mem-layout.h
··· 32 32 #define PAGE_OFFSET _AC(0xc0000000, UL) 33 33 34 34 /* 35 - * LOAD_ADDRESS is the physical/linear address of where in memory 36 - * the kernel gets loaded. The 12 least significant bits must be zero (0) 37 - * due to limitations on setting the EVB 38 - * 35 + * Compiling for a platform that needs a crazy physical offset 36 + * (like if the memory starts at 1GB and up) means we need 37 + * an actual PHYS_OFFSET. Should be set up in head.S. 39 38 */ 40 39 41 - #ifndef LOAD_ADDRESS 42 - #define LOAD_ADDRESS 0x00000000 40 + #ifdef CONFIG_HEXAGON_PHYS_OFFSET 41 + #ifndef __ASSEMBLY__ 42 + extern unsigned long __phys_offset; 43 43 #endif 44 + #define PHYS_OFFSET __phys_offset 45 + #endif 46 + 47 + #ifndef PHYS_OFFSET 48 + #define PHYS_OFFSET 0 49 + #endif 50 + 51 + #define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) 52 + #define ARCH_PFN_OFFSET PHYS_PFN_OFFSET 44 53 45 54 #define TASK_SIZE (PAGE_OFFSET) 46 55
+3 -2
arch/hexagon/include/asm/page.h
··· 96 96 * MIPS says they're only used during mem_init. 97 97 * also, check if we need a PHYS_OFFSET. 98 98 */ 99 - #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) 100 - #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) 99 + #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET) 100 + #define __va(x) ((void *)((unsigned long)(x) - PHYS_OFFSET + PAGE_OFFSET)) 101 101 102 102 /* The "page frame" descriptor is defined in linux/mm.h */ 103 103 struct page; ··· 147 147 */ 148 148 #define kern_addr_valid(addr) (1) 149 149 150 + #include <asm/mem-layout.h> 150 151 #include <asm-generic/memory_model.h> 151 152 /* XXX Todo: implement assembly-optimized version of getorder. */ 152 153 #include <asm-generic/getorder.h>
+18 -4
arch/hexagon/kernel/head.S
··· 43 43 * Symbol is kernel segment address, but we need 44 44 * the logical/physical address. 45 45 */ 46 - r24 = asl(r24, #2) 47 - r24 = lsr(r24, #2) 46 + r25 = pc; 47 + r2.h = #0xffc0; 48 + r2.l = #0x0000; 49 + r25 = and(r2,r25); /* R25 holds PHYS_OFFSET now */ 50 + r1.h = #HI(PAGE_OFFSET); 51 + r1.l = #LO(PAGE_OFFSET); 52 + r24 = sub(r24,r1); /* swapper_pg_dir - PAGE_OFFSET */ 53 + r24 = add(r24,r25); /* + PHYS_OFFSET */ 48 54 49 - r0 = r24 55 + r0 = r24; /* aka __pa(swapper_pg_dir) */ 50 56 51 57 /* 52 - * Initialize a 16MB PTE to make the virtual and physical 58 + * Initialize page dir to make the virtual and physical 53 59 * addresses where the kernel was loaded be identical. 60 + * Done in 4MB chunks. 54 61 */ 55 62 #define PTE_BITS ( __HVM_PTE_R | __HVM_PTE_W | __HVM_PTE_X \ 56 63 | __HEXAGON_C_WB_L2 << 6 \ ··· 149 142 150 143 r2 = sub(r2,r0); 151 144 call memset; 145 + 146 + /* Set PHYS_OFFSET; should still be in R25 */ 147 + #ifdef CONFIG_HEXAGON_PHYS_OFFSET 148 + r0.l = #LO(__phys_offset); 149 + r0.h = #HI(__phys_offset); 150 + memw(r0) = r25; 151 + #endif 152 152 153 153 /* Time to make the doughnuts. */ 154 154 call start_kernel
+2
arch/hexagon/kernel/setup.c
··· 68 68 */ 69 69 __vmsetvec(_K_VM_event_vector); 70 70 71 + printk(KERN_INFO "PHYS_OFFSET=0x%08x\n", PHYS_OFFSET); 72 + 71 73 /* 72 74 * Simulator has a few differences from the hardware. 73 75 * For now, check uninitialized-but-mapped memory
+2 -8
arch/hexagon/kernel/vmlinux.lds.S
··· 18 18 * 02110-1301, USA. 19 19 */ 20 20 21 - #define LOAD_OFFSET PAGE_OFFSET 22 - 23 21 #include <asm-generic/vmlinux.lds.h> 24 22 #include <asm/asm-offsets.h> /* Most of the kernel defines are here */ 25 23 #include <asm/mem-layout.h> /* except for page_offset */ ··· 34 36 35 37 #define PAGE_SIZE _PAGE_SIZE 36 38 37 - /* This LOAD_OFFSET is temporary for debugging on the simulator; it may change 38 - for hypervisor pseudo-physical memory. */ 39 - 40 - 41 39 SECTIONS 42 40 { 43 - . = PAGE_OFFSET + LOAD_ADDRESS; 41 + . = PAGE_OFFSET; 44 42 45 43 __init_begin = .; 46 44 HEAD_TEXT_SECTION ··· 46 52 47 53 . = ALIGN(_PAGE_SIZE); 48 54 _stext = .; 49 - .text : AT(ADDR(.text) - LOAD_OFFSET) { 55 + .text : AT(ADDR(.text)) { 50 56 _text = .; 51 57 TEXT_TEXT 52 58 SCHED_TEXT
+21 -12
arch/hexagon/mm/init.c
··· 31 31 * Define a startpg just past the end of the kernel image and a lastpg 32 32 * that corresponds to the end of real or simulated platform memory. 33 33 */ 34 - #define bootmem_startpg (PFN_UP(((unsigned long) _end) - PAGE_OFFSET)) 34 + #define bootmem_startpg (PFN_UP(((unsigned long) _end) - PAGE_OFFSET + PHYS_OFFSET)) 35 35 36 - unsigned long bootmem_lastpg; /* Should be set by platform code */ 36 + unsigned long bootmem_lastpg; /* Should be set by platform code */ 37 + unsigned long __phys_offset; /* physical kernel offset >> 12 */ 37 38 38 39 /* Set as variable to limit PMD copies */ 39 40 int max_kernel_seg = 0x303; ··· 45 44 /* indicate pfn's of high memory */ 46 45 unsigned long highstart_pfn, highend_pfn; 47 46 48 - /* struct mmu_gather defined in asm-generic.h; */ 49 47 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 50 48 51 49 /* Default cache attribute for newly created page tables */ ··· 71 71 { 72 72 /* No idea where this is actually declared. Seems to evade LXR. */ 73 73 totalram_pages += free_all_bootmem(); 74 - num_physpages = bootmem_lastpg; /* seriously, what? */ 74 + num_physpages = bootmem_lastpg-ARCH_PFN_OFFSET; 75 75 76 76 printk(KERN_INFO "totalram_pages = %ld\n", totalram_pages); 77 77 ··· 193 193 * This needs to change for highmem setups. 194 194 */ 195 195 196 + /* Prior to this, bootmem_lastpg is actually mem size */ 197 + bootmem_lastpg += ARCH_PFN_OFFSET; 198 + 196 199 /* Memory size needs to be a multiple of 16M */ 197 200 bootmem_lastpg = PFN_DOWN((bootmem_lastpg << PAGE_SHIFT) & 198 201 ~((BIG_KERNEL_PAGE_SIZE) - 1)); ··· 204 201 * Reserve the top DMA_RESERVE bytes of RAM for DMA (uncached) 205 202 * memory allocation 206 203 */ 207 - bootmap_size = init_bootmem(bootmem_startpg, bootmem_lastpg - 208 - PFN_DOWN(DMA_RESERVED_BYTES)); 204 + 205 + max_low_pfn = bootmem_lastpg - PFN_DOWN(DMA_RESERVED_BYTES); 206 + min_low_pfn = ARCH_PFN_OFFSET; 207 + bootmap_size = init_bootmem_node(NODE_DATA(0), bootmem_startpg, min_low_pfn, max_low_pfn); 209 208 210 209 printk(KERN_INFO "bootmem_startpg: 0x%08lx\n", bootmem_startpg); 211 210 printk(KERN_INFO "bootmem_lastpg: 0x%08lx\n", bootmem_lastpg); 212 211 printk(KERN_INFO "bootmap_size: %d\n", bootmap_size); 212 + printk(KERN_INFO "min_low_pfn: 0x%08lx\n", min_low_pfn); 213 213 printk(KERN_INFO "max_low_pfn: 0x%08lx\n", max_low_pfn); 214 214 215 215 /* ··· 227 221 /* this actually only goes to the end of the first gig */ 228 222 segtable_end = segtable + (1<<(30-22)); 229 223 230 - /* Move forward to the start of empty pages */ 231 - segtable += bootmem_lastpg >> (22-PAGE_SHIFT); 224 + /* 225 + * Move forward to the start of empty pages; take into account 226 + * phys_offset shift. 227 + */ 232 228 229 + segtable += (bootmem_lastpg-ARCH_PFN_OFFSET)>>(22-PAGE_SHIFT); 233 230 { 234 - int i; 231 + int i; 235 232 236 - for (i = 1 ; i <= DMA_RESERVE ; i++) 237 - segtable[-i] = ((segtable[-i] & __HVM_PTE_PGMASK_4MB) 233 + for (i = 1 ; i <= DMA_RESERVE ; i++) 234 + segtable[-i] = ((segtable[-i] & __HVM_PTE_PGMASK_4MB) 238 235 | __HVM_PTE_R | __HVM_PTE_W | __HVM_PTE_X 239 236 | __HEXAGON_C_UNC << 6 240 237 | __HVM_PDE_S_4MB); ··· 265 256 * Free all the memory that wasn't taken up by the bootmap, the DMA 266 257 * reserve, or kernel itself. 267 258 */ 268 - free_bootmem(PFN_PHYS(bootmem_startpg)+bootmap_size, 259 + free_bootmem(PFN_PHYS(bootmem_startpg) + bootmap_size, 269 260 PFN_PHYS(bootmem_lastpg - bootmem_startpg) - bootmap_size - 270 261 DMA_RESERVED_BYTES); 271 262