mpacpi.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * minimal acpi support for multiprocessors.
  3. *
  4. * avoids AML but that's only enough to discover
  5. * the processors, not the interrupt routing details.
  6. */
  7. #include "u.h"
  8. #include "../port/lib.h"
  9. #include "mem.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. #include "io.h"
  13. #include "mp.h"
  14. #include "mpacpi.h"
  15. /* 8c says: out of fixed registers */
  16. #define L64GET(p) ((uvlong)L32GET((p)+4) << 32 | L32GET(p))
  17. enum {
  18. /* apic types */
  19. Apiclproc,
  20. Apicio,
  21. Apicintrsrcoverride,
  22. Apicnmisrc,
  23. Apiclnmi,
  24. Apicladdroverride,
  25. Apicios,
  26. Apicls,
  27. Apicintrsrc,
  28. Apiclx2,
  29. Apiclx2nmi,
  30. PcmpUsed = 1ul<<31, /* Apic->flags addition */
  31. Lapicbase = 0x1b, /* msr */
  32. Lapicae = 1<<11, /* apic enable in Lapicbase */
  33. };
  34. #define dprint(...) if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
  35. /* from mp.c */
  36. int mpdebug;
  37. int mpmachno;
  38. Apic mpapic[MaxAPICNO+1];
  39. int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */
  40. Apic *bootapic;
  41. static int nprocid;
  42. static uvlong
  43. l64get(uchar *p)
  44. {
  45. return L64GET(p);
  46. }
  47. int
  48. apicset(Apic *apic, int type, int apicno, int f)
  49. {
  50. if(apicno > MaxAPICNO)
  51. return -1;
  52. apic->type = type;
  53. apic->apicno = apicno;
  54. apic->flags = f | PcmpEN | PcmpUsed;
  55. return 0;
  56. }
  57. int
  58. mpnewproc(Apic *apic, int apicno, int f)
  59. {
  60. if(apic->flags & PcmpUsed) {
  61. print("mpnewproc: apic already enabled\n");
  62. return -1;
  63. }
  64. if (apicset(apic, PcmpPROCESSOR, apicno, f) < 0)
  65. return -1;
  66. apic->lintr[1] = apic->lintr[0] = ApicIMASK;
  67. /* botch! just enumerate */
  68. if(apic->flags & PcmpBP)
  69. apic->machno = 0;
  70. else
  71. apic->machno = ++mpmachno;
  72. machno2apicno[apic->machno] = apicno;
  73. return 0;
  74. }
  75. static int
  76. mpacpiproc(uchar *p, ulong laddr)
  77. {
  78. int id, f;
  79. ulong *vladdr;
  80. vlong base;
  81. char *already;
  82. Apic *apic;
  83. /* p bytes: type (0), len (8), cpuid, cpu_lapic id, flags[4] */
  84. id = p[3];
  85. /* cpu unusable flag or id out of range? */
  86. if((L32GET(p+4) & 1) == 0 || id > MaxAPICNO)
  87. return -1;
  88. vladdr = nil;
  89. already = "";
  90. f = 0;
  91. apic = &mpapic[id];
  92. apic->paddr = laddr;
  93. if (nprocid++ == 0) {
  94. f = PcmpBP;
  95. vladdr = vmap(apic->paddr, 1024);
  96. if(apic->addr == nil){
  97. print("proc apic %d: failed to map %#p\n", id,
  98. apic->paddr);
  99. already = "(fail)";
  100. }
  101. bootapic = apic;
  102. }
  103. apic->addr = vladdr;
  104. if(apic->flags & PcmpUsed)
  105. already = "(on)";
  106. else
  107. mpnewproc(apic, id, f);
  108. if (0)
  109. dprint("\tapic proc %d/%d apicid %d flags%s%s %s\n", nprocid-1,
  110. apic->machno, id, f & PcmpBP? " boot": "",
  111. f & PcmpEN? " enabled": "", already);
  112. USED(already);
  113. rdmsr(Lapicbase, &base);
  114. if (!(base & Lapicae)) {
  115. dprint("mpacpiproc: enabling lapic\n");
  116. wrmsr(Lapicbase, base | Lapicae);
  117. }
  118. return 0;
  119. }
  120. static void
  121. mpacpicpus(Madt *madt)
  122. {
  123. int i, n;
  124. ulong laddr;
  125. uchar *p;
  126. laddr = L32GET(madt->addr);
  127. dprint("APIC mpacpicpus lapic addr %#lux, flags %#ux\n",
  128. laddr, L32GET(madt->flags));
  129. n = L32GET(&madt->sdthdr[4]);
  130. p = madt->structures;
  131. /* byte 0 is assumed to be type, 1 is assumed to be length */
  132. for(i = offsetof(Madt, structures[0]); i < n; i += p[1], p += p[1])
  133. switch(p[0]){
  134. case Apiclproc:
  135. mpacpiproc(p, laddr);
  136. break;
  137. }
  138. }
  139. /* returns nil iff checksum is bad */
  140. static void *
  141. mpacpirsdchecksum(void* addr, int length)
  142. {
  143. uchar *p, sum;
  144. sum = 0;
  145. for(p = addr; length-- > 0; p++)
  146. sum += *p;
  147. return sum == 0? addr: nil;
  148. }
  149. static void *
  150. mpacpirsdscan(uchar* addr, int len, char* signature)
  151. {
  152. int sl;
  153. uchar *e, *p;
  154. sl = strlen(signature);
  155. e = addr + len - sl;
  156. for(p = addr; p < e; p += 16)
  157. if(memcmp(p, signature, sl) == 0)
  158. return p;
  159. return nil;
  160. }
  161. static void *
  162. mpacpirsdsearch(char* signature)
  163. {
  164. uintptr p;
  165. uchar *bda;
  166. Rsd *rsd;
  167. /*
  168. * Search for the data structure signature:
  169. * 1) in the first KB of the EBDA;
  170. * 2) in the BIOS ROM between 0xE0000 and 0xFFFFF.
  171. */
  172. if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4) == 0){
  173. bda = BIOSSEG(0x40);
  174. p = bda[0x0F]<<8 | bda[0x0E];
  175. if(p != 0 &&
  176. (rsd = mpacpirsdscan(KADDR(p), 1024, signature)) != nil)
  177. return rsd;
  178. }
  179. return mpacpirsdscan(BIOSSEG(0xE000), 0x20000, signature);
  180. }
  181. /* call func for each acpi table found */
  182. static void
  183. mpacpiscan(void (*func)(uchar *))
  184. {
  185. int asize, i, tbllen, sdtlen;
  186. uintptr dhpa, sdtpa;
  187. uchar *tbl, *sdt;
  188. Rsd *rsd;
  189. dprint("ACPI...");
  190. if((rsd = mpacpirsdsearch("RSD PTR ")) == nil) {
  191. dprint("none\n");
  192. return;
  193. }
  194. dprint("rsd %#p physaddr %#ux length %ud %#llux rev %d oem %.6s\n",
  195. rsd, L32GET(rsd->raddr), L32GET(rsd->length),
  196. l64get(rsd->xaddr), rsd->revision, (char*)rsd->oemid);
  197. if(rsd->revision == 2){
  198. if(mpacpirsdchecksum(rsd, 36) == nil)
  199. return;
  200. asize = 8;
  201. sdtpa = l64get(rsd->xaddr);
  202. } else {
  203. if(mpacpirsdchecksum(rsd, 20) == nil)
  204. return;
  205. asize = 4;
  206. sdtpa = L32GET(rsd->raddr);
  207. }
  208. if((sdt = vmap(sdtpa, 8)) == nil)
  209. return;
  210. if((sdt[0] != 'R' && sdt[0] != 'X') || memcmp(sdt+1, "SDT", 3) != 0){
  211. vunmap(sdt, 8);
  212. return;
  213. }
  214. sdtlen = L32GET(sdt + 4);
  215. vunmap(sdt, 8);
  216. if((sdt = vmap(sdtpa, sdtlen)) == nil)
  217. return;
  218. if(mpacpirsdchecksum(sdt, sdtlen) != nil)
  219. for(i = 36; i < sdtlen; i += asize){
  220. if(asize == 8)
  221. dhpa = l64get(sdt+i);
  222. else
  223. dhpa = L32GET(sdt+i);
  224. if((tbl = vmap(dhpa, 8)) == nil)
  225. continue;
  226. tbllen = L32GET(tbl + 4);
  227. vunmap(tbl, 8);
  228. if((tbl = vmap(dhpa, tbllen)) == nil)
  229. continue;
  230. if(mpacpirsdchecksum(tbl, tbllen) != nil)
  231. (*func)(tbl);
  232. vunmap(tbl, tbllen);
  233. }
  234. vunmap(sdt, sdtlen);
  235. }
  236. static void
  237. mpacpitbl(uchar *p)
  238. {
  239. /* for now, just activate any idle cpus */
  240. if (memcmp(p, "APIC", 4) == 0)
  241. mpacpicpus((Madt *)p);
  242. }
  243. static void
  244. mpacpi(void)
  245. {
  246. mpdebug = getconf("*debugmp") != nil;
  247. mpacpiscan(mpacpitbl);
  248. }
  249. void (*mpacpifunc)(void) = mpacpi;