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