head.S 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Kernel relocation stub for MIPS devices
  3. *
  4. * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
  5. *
  6. * Based on:
  7. *
  8. * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
  9. *
  10. * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
  11. *
  12. * Some parts of this code was based on the OpenWrt specific lzma-loader
  13. * for the BCM47xx and ADM5120 based boards:
  14. * Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
  15. * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
  16. *
  17. * This program is free software; you can redistribute it and/or modify it
  18. * under the terms of the GNU General Public License version 2 as published
  19. * by the Free Software Foundation.
  20. */
  21. #include <asm/asm.h>
  22. #include <asm/regdef.h>
  23. #include "cp0regdef.h"
  24. #include "cacheops.h"
  25. #define KSEG0 0x80000000
  26. .macro ehb
  27. sll zero, 3
  28. .endm
  29. .macro reset
  30. li t0, 0xbe000034
  31. lw t1, 0(t0)
  32. ori t1, 1
  33. sw t1, 0(t0)
  34. .endm
  35. .text
  36. LEAF(startup)
  37. .set noreorder
  38. .set mips32
  39. .fill 0x10000
  40. mtc0 zero, CP0_WATCHLO # clear watch registers
  41. mtc0 zero, CP0_WATCHHI
  42. mtc0 zero, CP0_CAUSE # clear before writing status register
  43. mfc0 t0, CP0_STATUS
  44. li t1, 0x1000001f
  45. or t0, t1
  46. xori t0, 0x1f
  47. mtc0 t0, CP0_STATUS
  48. ehb
  49. mtc0 zero, CP0_COUNT
  50. mtc0 zero, CP0_COMPARE
  51. ehb
  52. la t0, __reloc_label # get linked address of label
  53. bal __reloc_label # branch and link to label to
  54. nop # get actual address
  55. __reloc_label:
  56. subu t0, ra, t0 # get reloc_delta
  57. /* Copy our code to the right place */
  58. la t1, _code_start # get linked address of _code_start
  59. la t2, _code_end # get linked address of _code_end
  60. addu t4, t2, t0 # calculate actual address of _code_end
  61. lw t5, 0(t4) # get extra data size
  62. add t2, t5
  63. add t2, 4
  64. add t0, t1 # calculate actual address of _code_start
  65. __reloc_copy:
  66. lw t3, 0(t0)
  67. sw t3, 0(t1)
  68. add t1, 4
  69. blt t1, t2, __reloc_copy
  70. add t0, 4
  71. /* flush cache */
  72. la t0, _code_start
  73. la t1, _code_end
  74. li t2, ~(CONFIG_CACHELINE_SIZE - 1)
  75. and t0, t2
  76. and t1, t2
  77. li t2, CONFIG_CACHELINE_SIZE
  78. b __flush_check
  79. nop
  80. __flush_line:
  81. cache Hit_Writeback_Inv_D, 0(t0)
  82. cache Hit_Invalidate_I, 0(t0)
  83. add t0, t2
  84. __flush_check:
  85. bne t0, t1, __flush_line
  86. nop
  87. sync
  88. la t0, __reloc_back
  89. j t0
  90. nop
  91. __reloc_back:
  92. la t0, _code_end
  93. add t0, 4
  94. addu t1, t0, t5
  95. li t2, KERNEL_ADDR
  96. __kernel_copy:
  97. lw t3, 0(t0)
  98. sw t3, 0(t2)
  99. add t0, 4
  100. blt t0, t1, __kernel_copy
  101. add t2, 4
  102. /* flush cache */
  103. li t0, KERNEL_ADDR
  104. addu t1, t0, t5
  105. add t1, CONFIG_CACHELINE_SIZE - 1
  106. li t2, ~(CONFIG_CACHELINE_SIZE - 1)
  107. and t0, t2
  108. and t1, t2
  109. li t2, CONFIG_CACHELINE_SIZE
  110. b __kernel_flush_check
  111. nop
  112. __kernel_flush_line:
  113. cache Hit_Writeback_Inv_D, 0(t0)
  114. cache Hit_Invalidate_I, 0(t0)
  115. add t0, t2
  116. __kernel_flush_check:
  117. bne t0, t1, __kernel_flush_line
  118. nop
  119. sync
  120. li t0, KERNEL_ADDR
  121. jr t0
  122. nop
  123. .set reorder
  124. END(startup)