oflib.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) Paul Mackerras 1997.
  4. */
  5. #include <stddef.h>
  6. #include "types.h"
  7. #include "elf.h"
  8. #include "string.h"
  9. #include "stdio.h"
  10. #include "page.h"
  11. #include "ops.h"
  12. #include "of.h"
  13. typedef u32 prom_arg_t;
  14. /* The following structure is used to communicate with open firmware.
  15. * All arguments in and out are in big endian format. */
  16. struct prom_args {
  17. __be32 service; /* Address of service name string. */
  18. __be32 nargs; /* Number of input arguments. */
  19. __be32 nret; /* Number of output arguments. */
  20. __be32 args[10]; /* Input/output arguments. */
  21. };
  22. #ifdef __powerpc64__
  23. extern int prom(void *);
  24. #else
  25. static int (*prom) (void *);
  26. #endif
  27. void of_init(void *promptr)
  28. {
  29. #ifndef __powerpc64__
  30. prom = (int (*)(void *))promptr;
  31. #endif
  32. }
  33. #define ADDR(x) (u32)(unsigned long)(x)
  34. int of_call_prom(const char *service, int nargs, int nret, ...)
  35. {
  36. int i;
  37. struct prom_args args;
  38. va_list list;
  39. args.service = cpu_to_be32(ADDR(service));
  40. args.nargs = cpu_to_be32(nargs);
  41. args.nret = cpu_to_be32(nret);
  42. va_start(list, nret);
  43. for (i = 0; i < nargs; i++)
  44. args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
  45. va_end(list);
  46. for (i = 0; i < nret; i++)
  47. args.args[nargs+i] = 0;
  48. if (prom(&args) < 0)
  49. return PROM_ERROR;
  50. return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
  51. }
  52. static int of_call_prom_ret(const char *service, int nargs, int nret,
  53. prom_arg_t *rets, ...)
  54. {
  55. int i;
  56. struct prom_args args;
  57. va_list list;
  58. args.service = cpu_to_be32(ADDR(service));
  59. args.nargs = cpu_to_be32(nargs);
  60. args.nret = cpu_to_be32(nret);
  61. va_start(list, rets);
  62. for (i = 0; i < nargs; i++)
  63. args.args[i] = cpu_to_be32(va_arg(list, prom_arg_t));
  64. va_end(list);
  65. for (i = 0; i < nret; i++)
  66. args.args[nargs+i] = 0;
  67. if (prom(&args) < 0)
  68. return PROM_ERROR;
  69. if (rets != NULL)
  70. for (i = 1; i < nret; ++i)
  71. rets[i-1] = be32_to_cpu(args.args[nargs+i]);
  72. return (nret > 0) ? be32_to_cpu(args.args[nargs]) : 0;
  73. }
  74. /* returns true if s2 is a prefix of s1 */
  75. static int string_match(const char *s1, const char *s2)
  76. {
  77. for (; *s2; ++s2)
  78. if (*s1++ != *s2)
  79. return 0;
  80. return 1;
  81. }
  82. /*
  83. * Older OF's require that when claiming a specific range of addresses,
  84. * we claim the physical space in the /memory node and the virtual
  85. * space in the chosen mmu node, and then do a map operation to
  86. * map virtual to physical.
  87. */
  88. static int need_map = -1;
  89. static ihandle chosen_mmu;
  90. static ihandle memory;
  91. static int check_of_version(void)
  92. {
  93. phandle oprom, chosen;
  94. char version[64];
  95. oprom = of_finddevice("/openprom");
  96. if (oprom == (phandle) -1)
  97. return 0;
  98. if (of_getprop(oprom, "model", version, sizeof(version)) <= 0)
  99. return 0;
  100. version[sizeof(version)-1] = 0;
  101. printf("OF version = '%s'\r\n", version);
  102. if (!string_match(version, "Open Firmware, 1.")
  103. && !string_match(version, "FirmWorks,3."))
  104. return 0;
  105. chosen = of_finddevice("/chosen");
  106. if (chosen == (phandle) -1) {
  107. chosen = of_finddevice("/chosen@0");
  108. if (chosen == (phandle) -1) {
  109. printf("no chosen\n");
  110. return 0;
  111. }
  112. }
  113. if (of_getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
  114. printf("no mmu\n");
  115. return 0;
  116. }
  117. memory = of_call_prom("open", 1, 1, "/memory");
  118. if (memory == PROM_ERROR) {
  119. memory = of_call_prom("open", 1, 1, "/memory@0");
  120. if (memory == PROM_ERROR) {
  121. printf("no memory node\n");
  122. return 0;
  123. }
  124. }
  125. printf("old OF detected\r\n");
  126. return 1;
  127. }
  128. unsigned int of_claim(unsigned long virt, unsigned long size,
  129. unsigned long align)
  130. {
  131. int ret;
  132. prom_arg_t result;
  133. if (need_map < 0)
  134. need_map = check_of_version();
  135. if (align || !need_map)
  136. return of_call_prom("claim", 3, 1, virt, size, align);
  137. ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory,
  138. align, size, virt);
  139. if (ret != 0 || result == -1)
  140. return -1;
  141. ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
  142. align, size, virt);
  143. /* 0x12 == coherent + read/write */
  144. ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu,
  145. 0x12, size, virt, virt);
  146. return virt;
  147. }
  148. void *of_vmlinux_alloc(unsigned long size)
  149. {
  150. unsigned long start = (unsigned long)_start, end = (unsigned long)_end;
  151. unsigned long addr;
  152. void *p;
  153. /* With some older POWER4 firmware we need to claim the area the kernel
  154. * will reside in. Newer firmwares don't need this so we just ignore
  155. * the return value.
  156. */
  157. addr = (unsigned long) of_claim(start, end - start, 0);
  158. printf("Trying to claim from 0x%lx to 0x%lx (0x%lx) got %lx\r\n",
  159. start, end, end - start, addr);
  160. p = malloc(size);
  161. if (!p)
  162. fatal("Can't allocate memory for kernel image!\n\r");
  163. return p;
  164. }
  165. void of_exit(void)
  166. {
  167. of_call_prom("exit", 0, 0);
  168. }
  169. /*
  170. * OF device tree routines
  171. */
  172. void *of_finddevice(const char *name)
  173. {
  174. return (void *) (unsigned long) of_call_prom("finddevice", 1, 1, name);
  175. }
  176. int of_getprop(const void *phandle, const char *name, void *buf,
  177. const int buflen)
  178. {
  179. return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
  180. }
  181. int of_setprop(const void *phandle, const char *name, const void *buf,
  182. const int buflen)
  183. {
  184. return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
  185. }