boot.S 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* -*-Asm-*- */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/machine/boot.h>
  20. .text
  21. .align 4
  22. /*
  23. * We're writing the a.out header ourselves as newer
  24. * upstream versions of binutils no longer support
  25. * the a.out format on sparc64.
  26. *
  27. * The boot loader fits into 512 bytes with 32 bytes
  28. * used for the a.out header, hence the text segment
  29. * size is 512 - 32. There is no data segment and no
  30. * code relocation, thus those fields remain zero.
  31. */
  32. .word 0x1030107 /* Magic number. */
  33. .word 512 - GRUB_BOOT_AOUT_HEADER_SIZE /* Size of text segment. */
  34. .word 0 /* Size of initialized data. */
  35. .word 0 /* Size of uninitialized data. */
  36. .word 0 /* Size of symbol table || checksum. */
  37. .word _start /* Entry point. */
  38. .word 0 /* Size of text relocation. */
  39. .word 0 /* Size of data relocation. */
  40. .globl _start
  41. _start:
  42. /* OF CIF entry point arrives in %o4 */
  43. pic_base:
  44. call boot_continue
  45. mov %o4, CIF_REG
  46. #ifndef CDBOOT
  47. /* The offsets to these locations are defined by the
  48. * GRUB_BOOT_MACHINE_foo macros in include/grub/sparc64/ieee1275/boot.h,
  49. * and grub-setup uses this to patch these next three values as needed.
  50. *
  51. * The boot_path will be the OF device path of the partition where the
  52. * rest of the GRUB kernel image resides. kernel_sector will be set to
  53. * the location of the first block of the GRUB kernel, and
  54. * kernel_address is the location where we should load that first block.
  55. *
  56. * After loading in that block we will execute it by jumping to the
  57. * load address plus the size of the prepended A.OUT header (32 bytes).
  58. *
  59. * Since this assembly code includes the 32 bytes long a.out header,
  60. * we need to move the actual code entry point forward by the size
  61. * of the a.out header, i.e. += GRUB_BOOT_AOUT_HEADER_SIZE.
  62. */
  63. .org GRUB_BOOT_MACHINE_BOOT_DEVPATH + GRUB_BOOT_AOUT_HEADER_SIZE
  64. boot_path:
  65. .org GRUB_BOOT_MACHINE_KERNEL_BYTE + GRUB_BOOT_AOUT_HEADER_SIZE
  66. boot_path_end:
  67. kernel_byte: .xword (2 << 9)
  68. kernel_address: .word GRUB_BOOT_MACHINE_KERNEL_ADDR
  69. #else
  70. #define boot_path (_start + 512 + SCRATCH_PAD_BOOT_SIZE)
  71. #define boot_path_end (_start + 1024)
  72. #include <grub/offsets.h>
  73. .org 8 + GRUB_BOOT_AOUT_HEADER_SIZE
  74. kernel_byte: .xword (2 << 9)
  75. kernel_size: .word 512
  76. kernel_address: .word GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS
  77. #endif
  78. prom_finddev_name: .asciz "finddevice"
  79. prom_chosen_path: .asciz "/chosen"
  80. prom_getprop_name: .asciz "getprop"
  81. prom_stdout_name: .asciz "stdout"
  82. prom_write_name: .asciz "write"
  83. prom_bootpath_name: .asciz "bootpath"
  84. prom_open_name: .asciz "open"
  85. prom_seek_name: .asciz "seek"
  86. prom_read_name: .asciz "read"
  87. prom_exit_name: .asciz "exit"
  88. grub_name: .asciz "GRUB "
  89. #ifdef CDBOOT
  90. prom_close_name: .asciz "close"
  91. #endif
  92. #define GRUB_NAME_LEN 5
  93. .align 4
  94. prom_open_error:
  95. GET_ABS(prom_open_name, %o2)
  96. call console_write
  97. mov 4, %o3
  98. /* fallthru */
  99. prom_error:
  100. GET_ABS(prom_exit_name, %o0)
  101. /* fallthru */
  102. /* %o0: OF call name
  103. * %o1: input arg 1
  104. */
  105. prom_call_1_1_o2:
  106. clr %o2
  107. ba prom_call_x_1
  108. mov 1, %g1
  109. prom_call_getprop:
  110. mov 4, %g1
  111. stx %g1, [%l1 + 256]
  112. mov CHOSEN_NODE_REG, %o1
  113. ba prom_call_x_1
  114. GET_ABS(prom_getprop_name, %o0)
  115. prom_call_3_1_o1:
  116. ba prom_call_3_1
  117. mov BOOTDEV_REG, %o1
  118. /* %o2: message string
  119. * %o3: message length
  120. */
  121. console_write:
  122. GET_ABS(prom_write_name, %o0)
  123. mov STDOUT_NODE_REG, %o1
  124. /* fallthru */
  125. /* %o0: OF call name
  126. * %o1: input arg 1
  127. * %o2: input arg 2
  128. * %o3: input arg 3
  129. */
  130. prom_call_3_1:
  131. mov 3, %g1
  132. prom_call_x_1:
  133. mov 1, %o5
  134. /* fallthru */
  135. /* %o0: OF call name
  136. * %g1: num inputs
  137. * %o5: num outputs
  138. * %o1-%o4: inputs
  139. */
  140. prom_call:
  141. stx %o0, [%l1 + 0x00]
  142. stx %g1, [%l1 + 0x08]
  143. stx %o5, [%l1 + 0x10]
  144. stx %o1, [%l1 + 0x18]
  145. stx %o2, [%l1 + 0x20]
  146. stx %o3, [%l1 + 0x28]
  147. stx %o4, [%l1 + 0x30]
  148. jmpl CIF_REG, %g0
  149. mov %l1, %o0
  150. boot_continue:
  151. mov %o7, PIC_REG /* PIC base */
  152. #ifndef CDBOOT
  153. sethi %hi(SCRATCH_PAD_BOOT), %l1 /* OF argument slots */
  154. #else
  155. GET_ABS(_start + 512, %l1) /* OF argument slots */
  156. #endif
  157. /* Find the /chosen node so we can fetch the stdout handle,
  158. * and thus perform console output.
  159. *
  160. * chosen_node = prom_finddevice("/chosen")
  161. */
  162. GET_ABS(prom_finddev_name, %o0)
  163. call prom_call_1_1_o2
  164. GET_ABS(prom_chosen_path, %o1)
  165. ldx [%l1 + 0x20], CHOSEN_NODE_REG
  166. brz CHOSEN_NODE_REG, prom_error
  167. /* getprop(chosen_node, "stdout", &buffer, buffer_size) */
  168. GET_ABS(prom_stdout_name, %o2)
  169. add %l1, 256, %o3
  170. call prom_call_getprop
  171. mov 1024, %o4
  172. lduw [%l1 + 256], STDOUT_NODE_REG
  173. brz,pn STDOUT_NODE_REG, prom_error
  174. /* write(stdout_node, "GRUB ", strlen("GRUB ")) */
  175. GET_ABS(grub_name, %o2)
  176. call console_write
  177. mov GRUB_NAME_LEN, %o3
  178. GET_ABS(boot_path, %o3)
  179. #ifndef CDBOOT
  180. ldub [%o3], %o1
  181. brnz,pn %o1, bootpath_known
  182. #endif
  183. /* getprop(chosen_node, "bootpath", &buffer, buffer_size) */
  184. GET_ABS(prom_bootpath_name, %o2)
  185. call prom_call_getprop
  186. mov (boot_path_end - boot_path), %o4
  187. bootpath_known:
  188. /* Open up the boot_path, and use that handle to read the
  189. * first block of the GRUB kernel image.
  190. *
  191. * bootdev_handle = open(boot_path)
  192. */
  193. GET_ABS(prom_open_name, %o0)
  194. call prom_call_1_1_o2
  195. GET_ABS(boot_path, %o1)
  196. ldx [%l1 + 0x20], BOOTDEV_REG
  197. brz,pn BOOTDEV_REG, prom_open_error
  198. /* Since we have 64-bit cells, the high cell of the seek offset
  199. * is zero and the low cell is the entire value.
  200. *
  201. * seek(bootdev, 0, *kernel_byte)
  202. */
  203. GET_ABS(prom_seek_name, %o0)
  204. clr %o2
  205. call prom_call_3_1_o1
  206. LDX_ABS(kernel_byte, 0x00, %o3)
  207. /* read(bootdev, *kernel_address, 512) */
  208. GET_ABS(prom_read_name, %o0)
  209. LDUW_ABS(kernel_address, 0x00, %o2)
  210. call prom_call_3_1_o1
  211. #ifdef CDBOOT
  212. LDUW_ABS(kernel_size, 0x00, %o3)
  213. GET_ABS(prom_close_name, %o0)
  214. mov 1, %g1
  215. mov 0, %o5
  216. call prom_call
  217. mov BOOTDEV_REG, %o1
  218. #else
  219. mov 512, %o3
  220. #endif
  221. LDUW_ABS(kernel_address, 0x00, %o2)
  222. jmpl %o2, %o7
  223. #ifdef CDBOOT
  224. mov CIF_REG, %o4
  225. #else
  226. nop
  227. #endif
  228. .org GRUB_BOOT_MACHINE_CODE_END
  229. /* the last 4 bytes in the sector 0 contain the signature */
  230. .word GRUB_BOOT_MACHINE_SIGNATURE