elf.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (C) 2014 Imagination Technologies
  3. * Author: Paul Burton <paul.burton@imgtec.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. */
  10. #include <linux/elf.h>
  11. #include <linux/sched.h>
  12. enum {
  13. FP_ERROR = -1,
  14. FP_DOUBLE_64A = -2,
  15. };
  16. int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
  17. bool is_interp, struct arch_elf_state *state)
  18. {
  19. struct elf32_hdr *ehdr = _ehdr;
  20. struct elf32_phdr *phdr = _phdr;
  21. struct mips_elf_abiflags_v0 abiflags;
  22. int ret;
  23. if (config_enabled(CONFIG_64BIT) &&
  24. (ehdr->e_ident[EI_CLASS] != ELFCLASS32))
  25. return 0;
  26. if (phdr->p_type != PT_MIPS_ABIFLAGS)
  27. return 0;
  28. if (phdr->p_filesz < sizeof(abiflags))
  29. return -EINVAL;
  30. ret = kernel_read(elf, phdr->p_offset, (char *)&abiflags,
  31. sizeof(abiflags));
  32. if (ret < 0)
  33. return ret;
  34. if (ret != sizeof(abiflags))
  35. return -EIO;
  36. /* Record the required FP ABIs for use by mips_check_elf */
  37. if (is_interp)
  38. state->interp_fp_abi = abiflags.fp_abi;
  39. else
  40. state->fp_abi = abiflags.fp_abi;
  41. return 0;
  42. }
  43. static inline unsigned get_fp_abi(struct elf32_hdr *ehdr, int in_abi)
  44. {
  45. /* If the ABI requirement is provided, simply return that */
  46. if (in_abi != -1)
  47. return in_abi;
  48. /* If the EF_MIPS_FP64 flag was set, return MIPS_ABI_FP_64 */
  49. if (ehdr->e_flags & EF_MIPS_FP64)
  50. return MIPS_ABI_FP_64;
  51. /* Default to MIPS_ABI_FP_DOUBLE */
  52. return MIPS_ABI_FP_DOUBLE;
  53. }
  54. int arch_check_elf(void *_ehdr, bool has_interpreter,
  55. struct arch_elf_state *state)
  56. {
  57. struct elf32_hdr *ehdr = _ehdr;
  58. unsigned fp_abi, interp_fp_abi, abi0, abi1;
  59. /* Ignore non-O32 binaries */
  60. if (config_enabled(CONFIG_64BIT) &&
  61. (ehdr->e_ident[EI_CLASS] != ELFCLASS32))
  62. return 0;
  63. fp_abi = get_fp_abi(ehdr, state->fp_abi);
  64. if (has_interpreter) {
  65. interp_fp_abi = get_fp_abi(ehdr, state->interp_fp_abi);
  66. abi0 = min(fp_abi, interp_fp_abi);
  67. abi1 = max(fp_abi, interp_fp_abi);
  68. } else {
  69. abi0 = abi1 = fp_abi;
  70. }
  71. state->overall_abi = FP_ERROR;
  72. if (abi0 == abi1) {
  73. state->overall_abi = abi0;
  74. } else if (abi0 == MIPS_ABI_FP_ANY) {
  75. state->overall_abi = abi1;
  76. } else if (abi0 == MIPS_ABI_FP_DOUBLE) {
  77. switch (abi1) {
  78. case MIPS_ABI_FP_XX:
  79. state->overall_abi = MIPS_ABI_FP_DOUBLE;
  80. break;
  81. case MIPS_ABI_FP_64A:
  82. state->overall_abi = FP_DOUBLE_64A;
  83. break;
  84. }
  85. } else if (abi0 == MIPS_ABI_FP_SINGLE ||
  86. abi0 == MIPS_ABI_FP_SOFT) {
  87. /* Cannot link with other ABIs */
  88. } else if (abi0 == MIPS_ABI_FP_OLD_64) {
  89. switch (abi1) {
  90. case MIPS_ABI_FP_XX:
  91. case MIPS_ABI_FP_64:
  92. case MIPS_ABI_FP_64A:
  93. state->overall_abi = MIPS_ABI_FP_64;
  94. break;
  95. }
  96. } else if (abi0 == MIPS_ABI_FP_XX ||
  97. abi0 == MIPS_ABI_FP_64 ||
  98. abi0 == MIPS_ABI_FP_64A) {
  99. state->overall_abi = MIPS_ABI_FP_64;
  100. }
  101. switch (state->overall_abi) {
  102. case MIPS_ABI_FP_64:
  103. case MIPS_ABI_FP_64A:
  104. case FP_DOUBLE_64A:
  105. if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
  106. return -ELIBBAD;
  107. break;
  108. case FP_ERROR:
  109. return -ELIBBAD;
  110. }
  111. return 0;
  112. }
  113. void mips_set_personality_fp(struct arch_elf_state *state)
  114. {
  115. if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS)) {
  116. /*
  117. * Use hybrid FPRs for all code which can correctly execute
  118. * with that mode.
  119. */
  120. switch (state->overall_abi) {
  121. case MIPS_ABI_FP_DOUBLE:
  122. case MIPS_ABI_FP_SINGLE:
  123. case MIPS_ABI_FP_SOFT:
  124. case MIPS_ABI_FP_XX:
  125. case MIPS_ABI_FP_ANY:
  126. /* FR=1, FRE=1 */
  127. clear_thread_flag(TIF_32BIT_FPREGS);
  128. set_thread_flag(TIF_HYBRID_FPREGS);
  129. return;
  130. }
  131. }
  132. switch (state->overall_abi) {
  133. case MIPS_ABI_FP_DOUBLE:
  134. case MIPS_ABI_FP_SINGLE:
  135. case MIPS_ABI_FP_SOFT:
  136. /* FR=0 */
  137. set_thread_flag(TIF_32BIT_FPREGS);
  138. clear_thread_flag(TIF_HYBRID_FPREGS);
  139. break;
  140. case FP_DOUBLE_64A:
  141. /* FR=1, FRE=1 */
  142. clear_thread_flag(TIF_32BIT_FPREGS);
  143. set_thread_flag(TIF_HYBRID_FPREGS);
  144. break;
  145. case MIPS_ABI_FP_64:
  146. case MIPS_ABI_FP_64A:
  147. /* FR=1, FRE=0 */
  148. clear_thread_flag(TIF_32BIT_FPREGS);
  149. clear_thread_flag(TIF_HYBRID_FPREGS);
  150. break;
  151. case MIPS_ABI_FP_XX:
  152. case MIPS_ABI_FP_ANY:
  153. if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
  154. set_thread_flag(TIF_32BIT_FPREGS);
  155. else
  156. clear_thread_flag(TIF_32BIT_FPREGS);
  157. clear_thread_flag(TIF_HYBRID_FPREGS);
  158. break;
  159. default:
  160. case FP_ERROR:
  161. BUG();
  162. }
  163. }