1*9ef1f84bSDavid du Colombier /*
2*9ef1f84bSDavid du Colombier * Vestigial Segmented Virtual Memory.
3*9ef1f84bSDavid du Colombier * To do:
4*9ef1f84bSDavid du Colombier * dynamic allocation and free of descriptors;
5*9ef1f84bSDavid du Colombier * IST should perhaps point to a different handler;
6*9ef1f84bSDavid du Colombier * user-level descriptors (if not dynamic).
7*9ef1f84bSDavid du Colombier */
8*9ef1f84bSDavid du Colombier #include "u.h"
9*9ef1f84bSDavid du Colombier #include "../port/lib.h"
10*9ef1f84bSDavid du Colombier #include "mem.h"
11*9ef1f84bSDavid du Colombier #include "dat.h"
12*9ef1f84bSDavid du Colombier #include "fns.h"
13*9ef1f84bSDavid du Colombier
14*9ef1f84bSDavid du Colombier #include "amd64.h"
15*9ef1f84bSDavid du Colombier #include "ureg.h"
16*9ef1f84bSDavid du Colombier
17*9ef1f84bSDavid du Colombier typedef struct Gd Gd;
18*9ef1f84bSDavid du Colombier typedef u64int Sd;
19*9ef1f84bSDavid du Colombier typedef u16int Ss;
20*9ef1f84bSDavid du Colombier typedef struct Tss Tss;
21*9ef1f84bSDavid du Colombier
22*9ef1f84bSDavid du Colombier struct Gd {
23*9ef1f84bSDavid du Colombier Sd sd;
24*9ef1f84bSDavid du Colombier u64int hi;
25*9ef1f84bSDavid du Colombier };
26*9ef1f84bSDavid du Colombier
27*9ef1f84bSDavid du Colombier struct Tss {
28*9ef1f84bSDavid du Colombier u32int _0_;
29*9ef1f84bSDavid du Colombier u32int rsp0[2];
30*9ef1f84bSDavid du Colombier u32int rsp1[2];
31*9ef1f84bSDavid du Colombier u32int rsp2[2];
32*9ef1f84bSDavid du Colombier u32int _28_[2];
33*9ef1f84bSDavid du Colombier u32int ist[14];
34*9ef1f84bSDavid du Colombier u16int _92_[5];
35*9ef1f84bSDavid du Colombier u16int iomap;
36*9ef1f84bSDavid du Colombier };
37*9ef1f84bSDavid du Colombier
38*9ef1f84bSDavid du Colombier enum {
39*9ef1f84bSDavid du Colombier Ngdt = 16, /* max. entries in gdt */
40*9ef1f84bSDavid du Colombier Nidt = 256, /* max. entries in idt */
41*9ef1f84bSDavid du Colombier };
42*9ef1f84bSDavid du Colombier
43*9ef1f84bSDavid du Colombier static Sd gdt64[Ngdt] = {
44*9ef1f84bSDavid du Colombier 0ull, /* NULL descriptor */
45*9ef1f84bSDavid du Colombier SdL|SdP|SdDPL0|SdS|SdCODE, /* CS */
46*9ef1f84bSDavid du Colombier SdG|SdD|SdP|SdDPL0|SdS|SdW, /* DS */
47*9ef1f84bSDavid du Colombier SdG|SdD|SdP|SdDPL3|SdS|SdCODE|SdR|Sd4G, /* User CS 32-bit */
48*9ef1f84bSDavid du Colombier SdG|SdD|SdP|SdDPL3|SdS|SdW|Sd4G, /* User DS */
49*9ef1f84bSDavid du Colombier SdL|SdP|SdDPL3|SdS|SdCODE, /* User CS 64-bit */
50*9ef1f84bSDavid du Colombier
51*9ef1f84bSDavid du Colombier 0ull, /* FS */
52*9ef1f84bSDavid du Colombier 0ull, /* GS */
53*9ef1f84bSDavid du Colombier
54*9ef1f84bSDavid du Colombier 0ull, /* TSS lower */
55*9ef1f84bSDavid du Colombier 0ull, /* TSS upper */
56*9ef1f84bSDavid du Colombier };
57*9ef1f84bSDavid du Colombier static int ngdt64 = 10;
58*9ef1f84bSDavid du Colombier
59*9ef1f84bSDavid du Colombier static Gd idt64[Nidt];
60*9ef1f84bSDavid du Colombier
61*9ef1f84bSDavid du Colombier static Sd
mksd(u64int base,u64int limit,u64int bits,u64int * upper)62*9ef1f84bSDavid du Colombier mksd(u64int base, u64int limit, u64int bits, u64int* upper)
63*9ef1f84bSDavid du Colombier {
64*9ef1f84bSDavid du Colombier Sd sd;
65*9ef1f84bSDavid du Colombier
66*9ef1f84bSDavid du Colombier sd = bits;
67*9ef1f84bSDavid du Colombier sd |= (((limit & 0x00000000000f0000ull)>>16)<<48)
68*9ef1f84bSDavid du Colombier |(limit & 0x000000000000ffffull);
69*9ef1f84bSDavid du Colombier sd |= (((base & 0x00000000ff000000ull)>>24)<<56)
70*9ef1f84bSDavid du Colombier |(((base & 0x0000000000ff0000ull)>>16)<<32)
71*9ef1f84bSDavid du Colombier |((base & 0x000000000000ffffull)<<16);
72*9ef1f84bSDavid du Colombier if(upper != nil)
73*9ef1f84bSDavid du Colombier *upper = base>>32;
74*9ef1f84bSDavid du Colombier
75*9ef1f84bSDavid du Colombier return sd;
76*9ef1f84bSDavid du Colombier }
77*9ef1f84bSDavid du Colombier
78*9ef1f84bSDavid du Colombier static void
mkgd(Gd * gd,u64int offset,Ss ss,u64int bits,int ist)79*9ef1f84bSDavid du Colombier mkgd(Gd* gd, u64int offset, Ss ss, u64int bits, int ist)
80*9ef1f84bSDavid du Colombier {
81*9ef1f84bSDavid du Colombier Sd sd;
82*9ef1f84bSDavid du Colombier
83*9ef1f84bSDavid du Colombier sd = bits;
84*9ef1f84bSDavid du Colombier sd |= (((offset & 0x00000000ffff0000ull)>>16)<<48)
85*9ef1f84bSDavid du Colombier |(offset & 0x000000000000ffffull);
86*9ef1f84bSDavid du Colombier sd |= ((ss & 0x000000000000ffffull)<<16);
87*9ef1f84bSDavid du Colombier sd |= (ist & (SdISTM>>32))<<32;
88*9ef1f84bSDavid du Colombier gd->sd = sd;
89*9ef1f84bSDavid du Colombier gd->hi = offset>>32;
90*9ef1f84bSDavid du Colombier }
91*9ef1f84bSDavid du Colombier
92*9ef1f84bSDavid du Colombier static void
idtinit(void)93*9ef1f84bSDavid du Colombier idtinit(void)
94*9ef1f84bSDavid du Colombier {
95*9ef1f84bSDavid du Colombier Gd *gd;
96*9ef1f84bSDavid du Colombier int ist, v;
97*9ef1f84bSDavid du Colombier u64int dpl;
98*9ef1f84bSDavid du Colombier uintptr offset;
99*9ef1f84bSDavid du Colombier
100*9ef1f84bSDavid du Colombier gd = idt64;
101*9ef1f84bSDavid du Colombier offset = PTR2UINT(idthandlers);
102*9ef1f84bSDavid du Colombier
103*9ef1f84bSDavid du Colombier for(v = 0; v < Nidt; v++){
104*9ef1f84bSDavid du Colombier ist = 0;
105*9ef1f84bSDavid du Colombier dpl = SdP|SdDPL0|SdIG;
106*9ef1f84bSDavid du Colombier switch(v){
107*9ef1f84bSDavid du Colombier default:
108*9ef1f84bSDavid du Colombier break;
109*9ef1f84bSDavid du Colombier case IdtBP: /* #BP */
110*9ef1f84bSDavid du Colombier dpl = SdP|SdDPL3|SdIG;
111*9ef1f84bSDavid du Colombier break;
112*9ef1f84bSDavid du Colombier case IdtUD: /* #UD */
113*9ef1f84bSDavid du Colombier case IdtDF: /* #DF */
114*9ef1f84bSDavid du Colombier ist = 1;
115*9ef1f84bSDavid du Colombier break;
116*9ef1f84bSDavid du Colombier }
117*9ef1f84bSDavid du Colombier mkgd(gd, offset, SSEL(SiCS, SsTIGDT|SsRPL0), dpl, ist);
118*9ef1f84bSDavid du Colombier gd++;
119*9ef1f84bSDavid du Colombier offset += 6;
120*9ef1f84bSDavid du Colombier }
121*9ef1f84bSDavid du Colombier }
122*9ef1f84bSDavid du Colombier
123*9ef1f84bSDavid du Colombier void
tssrsp0(uintptr sp)124*9ef1f84bSDavid du Colombier tssrsp0(uintptr sp)
125*9ef1f84bSDavid du Colombier {
126*9ef1f84bSDavid du Colombier Tss *tss;
127*9ef1f84bSDavid du Colombier
128*9ef1f84bSDavid du Colombier tss = m->tss;
129*9ef1f84bSDavid du Colombier tss->rsp0[0] = sp;
130*9ef1f84bSDavid du Colombier tss->rsp0[1] = sp>>32;
131*9ef1f84bSDavid du Colombier }
132*9ef1f84bSDavid du Colombier
133*9ef1f84bSDavid du Colombier static void
tssinit(uintptr sp)134*9ef1f84bSDavid du Colombier tssinit(uintptr sp)
135*9ef1f84bSDavid du Colombier {
136*9ef1f84bSDavid du Colombier int ist;
137*9ef1f84bSDavid du Colombier Tss *tss;
138*9ef1f84bSDavid du Colombier
139*9ef1f84bSDavid du Colombier tss = m->tss;
140*9ef1f84bSDavid du Colombier memset(tss, 0, sizeof(Tss));
141*9ef1f84bSDavid du Colombier
142*9ef1f84bSDavid du Colombier tssrsp0(sp);
143*9ef1f84bSDavid du Colombier
144*9ef1f84bSDavid du Colombier sp = PTR2UINT(m->vsvm+PGSZ);
145*9ef1f84bSDavid du Colombier for(ist = 0; ist < 14; ist += 2){
146*9ef1f84bSDavid du Colombier tss->ist[ist] = sp;
147*9ef1f84bSDavid du Colombier tss->ist[ist+1] = sp>>32;
148*9ef1f84bSDavid du Colombier }
149*9ef1f84bSDavid du Colombier tss->iomap = 0xdfff;
150*9ef1f84bSDavid du Colombier }
151*9ef1f84bSDavid du Colombier
152*9ef1f84bSDavid du Colombier void
vsvminit(int size)153*9ef1f84bSDavid du Colombier vsvminit(int size)
154*9ef1f84bSDavid du Colombier {
155*9ef1f84bSDavid du Colombier Sd *sd;
156*9ef1f84bSDavid du Colombier u64int r;
157*9ef1f84bSDavid du Colombier
158*9ef1f84bSDavid du Colombier if(m->machno == 0)
159*9ef1f84bSDavid du Colombier idtinit();
160*9ef1f84bSDavid du Colombier
161*9ef1f84bSDavid du Colombier m->gdt = m->vsvm;
162*9ef1f84bSDavid du Colombier memmove(m->gdt, gdt64, sizeof(gdt64));
163*9ef1f84bSDavid du Colombier m->tss = &m->vsvm[ROUNDUP(sizeof(gdt64), 16)];
164*9ef1f84bSDavid du Colombier
165*9ef1f84bSDavid du Colombier sd = &((Sd*)m->gdt)[SiTSS];
166*9ef1f84bSDavid du Colombier *sd = mksd(PTR2UINT(m->tss), sizeof(Tss)-1, SdP|SdDPL0|SdaTSS, sd+1);
167*9ef1f84bSDavid du Colombier
168*9ef1f84bSDavid du Colombier tssinit(m->stack+size);
169*9ef1f84bSDavid du Colombier
170*9ef1f84bSDavid du Colombier gdtput(sizeof(gdt64)-1, PTR2UINT(m->gdt), SSEL(SiCS, SsTIGDT|SsRPL0));
171*9ef1f84bSDavid du Colombier idtput(sizeof(idt64)-1, PTR2UINT(idt64));
172*9ef1f84bSDavid du Colombier trput(SSEL(SiTSS, SsTIGDT|SsRPL0));
173*9ef1f84bSDavid du Colombier
174*9ef1f84bSDavid du Colombier wrmsr(FSbase, 0ull);
175*9ef1f84bSDavid du Colombier wrmsr(GSbase, PTR2UINT(&sys->machptr[m->machno]));
176*9ef1f84bSDavid du Colombier wrmsr(KernelGSbase, 0ull);
177*9ef1f84bSDavid du Colombier
178*9ef1f84bSDavid du Colombier r = rdmsr(Efer);
179*9ef1f84bSDavid du Colombier r |= Sce;
180*9ef1f84bSDavid du Colombier wrmsr(Efer, r);
181*9ef1f84bSDavid du Colombier r = ((u64int)SSEL(SiU32CS, SsRPL3))<<48;
182*9ef1f84bSDavid du Colombier r |= ((u64int)SSEL(SiCS, SsRPL0))<<32;
183*9ef1f84bSDavid du Colombier wrmsr(Star, r);
184*9ef1f84bSDavid du Colombier wrmsr(Lstar, PTR2UINT(syscallentry));
185*9ef1f84bSDavid du Colombier wrmsr(Sfmask, If);
186*9ef1f84bSDavid du Colombier }
187*9ef1f84bSDavid du Colombier
188*9ef1f84bSDavid du Colombier int
userureg(Ureg * ureg)189*9ef1f84bSDavid du Colombier userureg(Ureg* ureg)
190*9ef1f84bSDavid du Colombier {
191*9ef1f84bSDavid du Colombier return ureg->cs == SSEL(SiUCS, SsRPL3);
192*9ef1f84bSDavid du Colombier }
193