vsvm.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * Vestigial Segmented Virtual Memory.
  11. * To do:
  12. * dynamic allocation and free of descriptors;
  13. * IST should perhaps point to a different handler;
  14. * user-level descriptors (if not dynamic).
  15. */
  16. #include "u.h"
  17. #include "../port/lib.h"
  18. #include "mem.h"
  19. #include "dat.h"
  20. #include "fns.h"
  21. #include "amd64.h"
  22. #include "ureg.h"
  23. typedef struct Gd Gd;
  24. typedef uint64_t Sd;
  25. typedef uint16_t Ss;
  26. typedef struct Tss Tss;
  27. struct Gd {
  28. Sd sd;
  29. uint64_t hi;
  30. };
  31. struct Tss {
  32. uint32_t _0_;
  33. uint32_t rsp0[2];
  34. uint32_t rsp1[2];
  35. uint32_t rsp2[2];
  36. uint32_t _28_[2];
  37. uint32_t ist[14];
  38. uint16_t _92_[5];
  39. uint16_t iomap;
  40. };
  41. enum {
  42. Ngdt = 16, /* max. entries in gdt */
  43. Nidt = 256, /* max. entries in idt */
  44. };
  45. static Sd gdt64[Ngdt] = {
  46. 0ull, /* NULL descriptor */
  47. SdL|SdP|SdDPL0|SdS|SdCODE, /* CS */
  48. SdG|SdD|SdP|SdDPL0|SdS|SdW, /* DS */
  49. SdG|SdD|SdP|SdDPL3|SdS|SdCODE|SdR|Sd4G, /* User CS 32-bit */
  50. SdG|SdD|SdP|SdDPL3|SdS|SdW|Sd4G, /* User DS */
  51. SdL|SdP|SdDPL3|SdS|SdCODE, /* User CS 64-bit */
  52. 0ull, /* FS */
  53. 0ull, /* GS */
  54. 0ull, /* TSS lower */
  55. 0ull, /* TSS upper */
  56. };
  57. //static int ngdt64 = 10;
  58. static Gd idt64[Nidt];
  59. static Gd acidt64[Nidt]; /* NIX application core IDT */
  60. static Sd
  61. mksd(uint64_t base, uint64_t limit, uint64_t bits, uint64_t* upper)
  62. {
  63. Sd sd;
  64. sd = bits;
  65. sd |= (((limit & 0x00000000000f0000ull)>>16)<<48)
  66. |(limit & 0x000000000000ffffull);
  67. sd |= (((base & 0x00000000ff000000ull)>>24)<<56)
  68. |(((base & 0x0000000000ff0000ull)>>16)<<32)
  69. |((base & 0x000000000000ffffull)<<16);
  70. if(upper != nil)
  71. *upper = base>>32;
  72. return sd;
  73. }
  74. static void
  75. mkgd(Gd* gd, uint64_t offset, Ss ss, uint64_t bits, int ist)
  76. {
  77. Sd sd;
  78. sd = bits;
  79. sd |= (((offset & 0x00000000ffff0000ull)>>16)<<48)
  80. |(offset & 0x000000000000ffffull);
  81. sd |= ((ss & 0x000000000000ffffull)<<16);
  82. sd |= (ist & (SdISTM>>32))<<32;
  83. gd->sd = sd;
  84. gd->hi = offset>>32;
  85. }
  86. static void
  87. idtinit(Gd *gd, uintptr_t offset)
  88. {
  89. int ist, v;
  90. uint64_t dpl;
  91. for(v = 0; v < Nidt; v++){
  92. ist = 0;
  93. dpl = SdP|SdDPL0|SdIG;
  94. switch(v){
  95. default:
  96. break;
  97. case IdtBP: /* #BP */
  98. dpl = SdP|SdDPL3|SdIG;
  99. break;
  100. case IdtUD: /* #UD */
  101. case IdtDF: /* #DF */
  102. ist = 1;
  103. break;
  104. }
  105. mkgd(gd, offset, SSEL(SiCS, SsTIGDT|SsRPL0), dpl, ist);
  106. gd++;
  107. offset += 6;
  108. }
  109. }
  110. void
  111. tssrsp0(Mach *mach, uintptr_t sp)
  112. {
  113. Tss *tss;
  114. tss = mach->tss;
  115. tss->rsp0[0] = sp;
  116. tss->rsp0[1] = sp>>32;
  117. }
  118. static void
  119. tssinit(Mach *mach, uintptr_t sp)
  120. {
  121. int ist;
  122. Tss *tss;
  123. tss = mach->tss;
  124. memset(tss, 0, sizeof(Tss));
  125. tssrsp0(mach, sp);
  126. sp = PTR2UINT(mach->vsvm+PGSZ);
  127. for(ist = 0; ist < 14; ist += 2){
  128. tss->ist[ist] = sp;
  129. tss->ist[ist+1] = sp>>32;
  130. }
  131. tss->iomap = 0xdfff;
  132. }
  133. void acsyscallentry(void)
  134. {
  135. panic("acsyscallentry");
  136. }
  137. void
  138. vsvminit(int size, int nixtype, Mach *mach)
  139. {
  140. Sd *sd;
  141. uint64_t r;
  142. if(mach->machno == 0){
  143. idtinit(idt64, PTR2UINT(idthandlers));
  144. idtinit(acidt64, PTR2UINT(acidthandlers));
  145. }
  146. mach->gdt = mach->vsvm;
  147. memmove(mach->gdt, gdt64, sizeof(gdt64));
  148. mach->tss = &mach->vsvm[ROUNDUP(sizeof(gdt64), 16)];
  149. sd = &((Sd*)mach->gdt)[SiTSS];
  150. *sd = mksd(PTR2UINT(mach->tss), sizeof(Tss)-1, SdP|SdDPL0|SdaTSS, sd+1);
  151. *(uintptr_t*)mach->stack = STACKGUARD;
  152. tssinit(mach, mach->stack+size);
  153. gdtput(sizeof(gdt64)-1, PTR2UINT(mach->gdt), SSEL(SiCS, SsTIGDT|SsRPL0));
  154. #if 0 // NO ACs YET
  155. if(nixtype != NIXAC)
  156. #endif
  157. idtput(sizeof(idt64)-1, PTR2UINT(idt64));
  158. #if 0
  159. else
  160. idtput(sizeof(acidt64)-1, PTR2UINT(acidt64));
  161. #endif
  162. // I have no idea how to do this another way.
  163. //trput(SSEL(SiTSS, SsTIGDT|SsRPL0));
  164. asm volatile("ltr %w0"::"q" (SSEL(SiTSS, SsTIGDT|SsRPL0)));
  165. wrmsr(FSbase, 0ull);
  166. wrmsr(GSbase, PTR2UINT(mach));
  167. wrmsr(KernelGSbase, 0ull);
  168. r = rdmsr(Efer);
  169. r |= Sce;
  170. wrmsr(Efer, r);
  171. /* Hey! This is weird! Why a 32-bit CS?
  172. * Because, when you do a retq, the CPU adds 16 to
  173. * the bits derived from 63:48, and then uses that. See the
  174. * GDT above: 64-bit CS is 16 more than the 32-bit CS.
  175. * If you return with 32-bit ret, then the CS is taken
  176. * as-is. For the SS, 8 is added and you get the DS
  177. * shown above.
  178. */
  179. r = ((uint64_t)SSEL(SiU32CS, SsRPL3))<<48;
  180. r |= ((uint64_t)SSEL(SiCS, SsRPL0))<<32;
  181. wrmsr(Star, r);
  182. if(nixtype != NIXAC)
  183. wrmsr(Lstar, PTR2UINT(syscallentry));
  184. else
  185. wrmsr(Lstar, PTR2UINT(acsyscallentry));
  186. wrmsr(Sfmask, If);
  187. if (mach != machp()) {
  188. panic("vsvminit: m is not machp() at end\n");
  189. }
  190. }
  191. int
  192. userureg(Ureg* ureg)
  193. {
  194. return ureg->cs == SSEL(SiUCS, SsRPL3);
  195. }