head.S 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * linux/arch/unicore32/kernel/head.S
  3. *
  4. * Code specific to PKUnity SoC and UniCore ISA
  5. *
  6. * Copyright (C) 2001-2010 GUAN Xue-tao
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/linkage.h>
  13. #include <linux/init.h>
  14. #include <asm/assembler.h>
  15. #include <asm/ptrace.h>
  16. #include <generated/asm-offsets.h>
  17. #include <asm/memory.h>
  18. #include <asm/thread_info.h>
  19. #include <asm/hwdef-copro.h>
  20. #include <asm/pgtable-hwdef.h>
  21. #if (PHYS_OFFSET & 0x003fffff)
  22. #error "PHYS_OFFSET must be at an even 4MiB boundary!"
  23. #endif
  24. #define KERNEL_RAM_VADDR (PAGE_OFFSET + KERNEL_IMAGE_START)
  25. #define KERNEL_RAM_PADDR (PHYS_OFFSET + KERNEL_IMAGE_START)
  26. #define KERNEL_PGD_PADDR (KERNEL_RAM_PADDR - 0x1000)
  27. #define KERNEL_PGD_VADDR (KERNEL_RAM_VADDR - 0x1000)
  28. #define KERNEL_START KERNEL_RAM_VADDR
  29. #define KERNEL_END _end
  30. /*
  31. * swapper_pg_dir is the virtual address of the initial page table.
  32. * We place the page tables 4K below KERNEL_RAM_VADDR. Therefore, we must
  33. * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect
  34. * the least significant 16 bits to be 0x8000, but we could probably
  35. * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x1000.
  36. */
  37. #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
  38. #error KERNEL_RAM_VADDR must start at 0xXXXX8000
  39. #endif
  40. .globl swapper_pg_dir
  41. .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x1000
  42. /*
  43. * Kernel startup entry point.
  44. * ---------------------------
  45. *
  46. * This is normally called from the decompressor code. The requirements
  47. * are: MMU = off, D-cache = off, I-cache = dont care
  48. *
  49. * This code is mostly position independent, so if you link the kernel at
  50. * 0xc0008000, you call this at __pa(0xc0008000).
  51. */
  52. __HEAD
  53. ENTRY(stext)
  54. @ set asr
  55. mov r0, #PRIV_MODE @ ensure priv mode
  56. or r0, #PSR_R_BIT | PSR_I_BIT @ disable irqs
  57. mov.a asr, r0
  58. @ process identify
  59. movc r0, p0.c0, #0 @ cpuid
  60. movl r1, 0xff00ffff @ mask
  61. movl r2, 0x4d000863 @ value
  62. and r0, r1, r0
  63. cxor.a r0, r2
  64. bne __error_p @ invalid processor id
  65. /*
  66. * Clear the 4K level 1 swapper page table
  67. */
  68. movl r0, #KERNEL_PGD_PADDR @ page table address
  69. mov r1, #0
  70. add r2, r0, #0x1000
  71. 101: stw.w r1, [r0]+, #4
  72. stw.w r1, [r0]+, #4
  73. stw.w r1, [r0]+, #4
  74. stw.w r1, [r0]+, #4
  75. cxor.a r0, r2
  76. bne 101b
  77. movl r4, #KERNEL_PGD_PADDR @ page table address
  78. mov r7, #PMD_TYPE_SECT | PMD_PRESENT @ page size: section
  79. or r7, r7, #PMD_SECT_CACHEABLE @ cacheable
  80. or r7, r7, #PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC
  81. /*
  82. * Create identity mapping for first 4MB of kernel to
  83. * cater for the MMU enable. This identity mapping
  84. * will be removed by paging_init(). We use our current program
  85. * counter to determine corresponding section base address.
  86. */
  87. mov r6, pc
  88. mov r6, r6 >> #22 @ start of kernel section
  89. or r1, r7, r6 << #22 @ flags + kernel base
  90. stw r1, [r4+], r6 << #2 @ identity mapping
  91. /*
  92. * Now setup the pagetables for our kernel direct
  93. * mapped region.
  94. */
  95. add r0, r4, #(KERNEL_START & 0xff000000) >> 20
  96. stw.w r1, [r0+], #(KERNEL_START & 0x00c00000) >> 20
  97. movl r6, #(KERNEL_END - 1)
  98. add r0, r0, #4
  99. add r6, r4, r6 >> #20
  100. 102: csub.a r0, r6
  101. add r1, r1, #1 << 22
  102. bua 103f
  103. stw.w r1, [r0]+, #4
  104. b 102b
  105. 103:
  106. /*
  107. * Then map first 4MB of ram in case it contains our boot params.
  108. */
  109. add r0, r4, #PAGE_OFFSET >> 20
  110. or r6, r7, #(PHYS_OFFSET & 0xffc00000)
  111. stw r6, [r0]
  112. ldw r15, __switch_data @ address to jump to after
  113. /*
  114. * Initialise TLB, Caches, and MMU state ready to switch the MMU
  115. * on.
  116. */
  117. mov r0, #0
  118. movc p0.c5, r0, #28 @ cache invalidate all
  119. nop8
  120. movc p0.c6, r0, #6 @ TLB invalidate all
  121. nop8
  122. /*
  123. * ..V. .... ..TB IDAM
  124. * ..1. .... ..01 1111
  125. */
  126. movl r0, #0x201f @ control register setting
  127. /*
  128. * Setup common bits before finally enabling the MMU. Essentially
  129. * this is just loading the page table pointer and domain access
  130. * registers.
  131. */
  132. #ifndef CONFIG_ALIGNMENT_TRAP
  133. andn r0, r0, #CR_A
  134. #endif
  135. #ifdef CONFIG_CPU_DCACHE_DISABLE
  136. andn r0, r0, #CR_D
  137. #endif
  138. #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
  139. andn r0, r0, #CR_B
  140. #endif
  141. #ifdef CONFIG_CPU_ICACHE_DISABLE
  142. andn r0, r0, #CR_I
  143. #endif
  144. movc p0.c2, r4, #0 @ set pgd
  145. b __turn_mmu_on
  146. ENDPROC(stext)
  147. /*
  148. * Enable the MMU. This completely changes the structure of the visible
  149. * memory space. You will not be able to trace execution through this.
  150. *
  151. * r0 = cp#0 control register
  152. * r15 = *virtual* address to jump to upon completion
  153. */
  154. .align 5
  155. __turn_mmu_on:
  156. mov r0, r0
  157. movc p0.c1, r0, #0 @ write control reg
  158. nop @ fetch inst by phys addr
  159. mov pc, r15
  160. nop8 @ fetch inst by phys addr
  161. ENDPROC(__turn_mmu_on)
  162. /*
  163. * Setup the initial page tables. We only setup the barest
  164. * amount which are required to get the kernel running, which
  165. * generally means mapping in the kernel code.
  166. *
  167. * r9 = cpuid
  168. * r10 = procinfo
  169. *
  170. * Returns:
  171. * r0, r3, r6, r7 corrupted
  172. * r4 = physical page table address
  173. */
  174. .ltorg
  175. .align 2
  176. .type __switch_data, %object
  177. __switch_data:
  178. .long __mmap_switched
  179. .long __bss_start @ r6
  180. .long _end @ r7
  181. .long cr_alignment @ r8
  182. .long init_thread_union + THREAD_START_SP @ sp
  183. /*
  184. * The following fragment of code is executed with the MMU on in MMU mode,
  185. * and uses absolute addresses; this is not position independent.
  186. *
  187. * r0 = cp#0 control register
  188. */
  189. __mmap_switched:
  190. adr r3, __switch_data + 4
  191. ldm.w (r6, r7, r8), [r3]+
  192. ldw sp, [r3]
  193. mov fp, #0 @ Clear BSS (and zero fp)
  194. 203: csub.a r6, r7
  195. bea 204f
  196. stw.w fp, [r6]+,#4
  197. b 203b
  198. 204:
  199. andn r1, r0, #CR_A @ Clear 'A' bit
  200. stm (r0, r1), [r8]+ @ Save control register values
  201. b start_kernel
  202. ENDPROC(__mmap_switched)
  203. /*
  204. * Exception handling. Something went wrong and we can't proceed. We
  205. * ought to tell the user, but since we don't have any guarantee that
  206. * we're even running on the right architecture, we do virtually nothing.
  207. *
  208. * If CONFIG_DEBUG_LL is set we try to print out something about the error
  209. * and hope for the best (useful if bootloader fails to pass a proper
  210. * machine ID for example).
  211. */
  212. __error_p:
  213. #ifdef CONFIG_DEBUG_LL
  214. adr r0, str_p1
  215. b.l printascii
  216. mov r0, r9
  217. b.l printhex8
  218. adr r0, str_p2
  219. b.l printascii
  220. 901: nop8
  221. b 901b
  222. str_p1: .asciz "\nError: unrecognized processor variant (0x"
  223. str_p2: .asciz ").\n"
  224. .align
  225. #endif
  226. ENDPROC(__error_p)