relocate_kernel.S 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * relocate_kernel.S - put the kernel image in place to boot
  3. * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
  4. *
  5. * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
  6. *
  7. * This source code is licensed under the GNU General Public License,
  8. * Version 2. See the file COPYING for more details.
  9. */
  10. #include <asm/reg.h>
  11. #include <asm/ppc_asm.h>
  12. #include <asm/processor.h>
  13. #include <asm/kexec.h>
  14. #define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
  15. /*
  16. * Must be relocatable PIC code callable as a C function.
  17. */
  18. .globl relocate_new_kernel
  19. relocate_new_kernel:
  20. /* r3 = page_list */
  21. /* r4 = reboot_code_buffer */
  22. /* r5 = start_address */
  23. li r0, 0
  24. /*
  25. * Set Machine Status Register to a known status,
  26. * switch the MMU off and jump to 1: in a single step.
  27. */
  28. mr r8, r0
  29. ori r8, r8, MSR_RI|MSR_ME
  30. mtspr SPRN_SRR1, r8
  31. addi r8, r4, 1f - relocate_new_kernel
  32. mtspr SPRN_SRR0, r8
  33. sync
  34. rfi
  35. 1:
  36. /* from this point address translation is turned off */
  37. /* and interrupts are disabled */
  38. /* set a new stack at the bottom of our page... */
  39. /* (not really needed now) */
  40. addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
  41. stw r0, 0(r1)
  42. /* Do the copies */
  43. li r6, 0 /* checksum */
  44. mr r0, r3
  45. b 1f
  46. 0: /* top, read another word for the indirection page */
  47. lwzu r0, 4(r3)
  48. 1:
  49. /* is it a destination page? (r8) */
  50. rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
  51. beq 2f
  52. rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
  53. b 0b
  54. 2: /* is it an indirection page? (r3) */
  55. rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
  56. beq 2f
  57. rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
  58. subi r3, r3, 4
  59. b 0b
  60. 2: /* are we done? */
  61. rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
  62. beq 2f
  63. b 3f
  64. 2: /* is it a source page? (r9) */
  65. rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
  66. beq 0b
  67. rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
  68. li r7, PAGE_SIZE / 4
  69. mtctr r7
  70. subi r9, r9, 4
  71. subi r8, r8, 4
  72. 9:
  73. lwzu r0, 4(r9) /* do the copy */
  74. xor r6, r6, r0
  75. stwu r0, 4(r8)
  76. dcbst 0, r8
  77. sync
  78. icbi 0, r8
  79. bdnz 9b
  80. addi r9, r9, 4
  81. addi r8, r8, 4
  82. b 0b
  83. 3:
  84. /* To be certain of avoiding problems with self-modifying code
  85. * execute a serializing instruction here.
  86. */
  87. isync
  88. sync
  89. /* jump to the entry point, usually the setup routine */
  90. mtlr r5
  91. blrl
  92. 1: b 1b
  93. relocate_new_kernel_end:
  94. .globl relocate_new_kernel_size
  95. relocate_new_kernel_size:
  96. .long relocate_new_kernel_end - relocate_new_kernel