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 33ENTRY(_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 } 771: 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 1101: 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 137ENTRY(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 152ENTRY(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() 177ENTRY(swapper_pgprot) 178 PTE 0, 0, HV_PTE_READABLE | HV_PTE_WRITABLE, 1 179 .align CHIP_L2_LINE_SIZE() 180 END(swapper_pgprot) 181