jehanne/sys/src/kern/amd64/vsvm.c

193 lines
3.5 KiB
C

/*
* Vestigial Segmented Virtual Memory.
* To do:
* dynamic allocation and free of descriptors;
* IST should perhaps point to a different handler;
* user-level descriptors (if not dynamic).
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "amd64.h"
#include "ureg.h"
typedef struct Gd Gd;
typedef uint64_t Sd;
typedef uint16_t Ss;
typedef struct Tss Tss;
struct Gd {
Sd sd;
uint64_t hi;
};
struct Tss {
uint32_t _0_;
uint32_t rsp0[2];
uint32_t rsp1[2];
uint32_t rsp2[2];
uint32_t _28_[2];
uint32_t ist[14];
uint16_t _92_[5];
uint16_t iomap;
};
enum {
Ngdt = 16, /* max. entries in gdt */
Nidt = 256, /* max. entries in idt */
};
static Sd gdt64[Ngdt] = {
0ull, /* NULL descriptor */
SdL|SdP|SdDPL0|SdS|SdCODE, /* CS */
SdG|SdD|SdP|SdDPL0|SdS|SdW, /* DS */
SdG|SdD|SdP|SdDPL3|SdS|SdCODE|SdR|Sd4G, /* User CS 32-bit */
SdG|SdD|SdP|SdDPL3|SdS|SdW|Sd4G, /* User DS */
SdL|SdP|SdDPL3|SdS|SdCODE, /* User CS 64-bit */
0ull, /* FS */
0ull, /* GS */
0ull, /* TSS lower */
0ull, /* TSS upper */
};
//static int ngdt64 = 10; // not used
static Gd idt64[Nidt];
static Sd
mksd(uint64_t base, uint64_t limit, uint64_t bits, uint64_t* upper)
{
Sd sd;
sd = bits;
sd |= (((limit & 0x00000000000f0000ull)>>16)<<48)
|(limit & 0x000000000000ffffull);
sd |= (((base & 0x00000000ff000000ull)>>24)<<56)
|(((base & 0x0000000000ff0000ull)>>16)<<32)
|((base & 0x000000000000ffffull)<<16);
if(upper != nil)
*upper = base>>32;
return sd;
}
static void
mkgd(Gd* gd, uint64_t offset, Ss ss, uint64_t bits, int ist)
{
Sd sd;
sd = bits;
sd |= (((offset & 0x00000000ffff0000ull)>>16)<<48)
|(offset & 0x000000000000ffffull);
sd |= ((ss & 0x000000000000ffffull)<<16);
sd |= (ist & (SdISTM>>32))<<32;
gd->sd = sd;
gd->hi = offset>>32;
}
static void
idtinit(void)
{
Gd *gd;
int ist, v;
uint64_t dpl;
uintptr_t offset;
gd = idt64;
offset = PTR2UINT(idthandlers);
for(v = 0; v < Nidt; v++){
ist = 0;
dpl = SdP|SdDPL0|SdIG;
switch(v){
default:
break;
case IdtBP: /* #BP */
dpl = SdP|SdDPL3|SdIG;
break;
case IdtUD: /* #UD */
case IdtDF: /* #DF */
ist = 1;
break;
}
mkgd(gd, offset, SSEL(SiCS, SsTIGDT|SsRPL0), dpl, ist);
gd++;
offset += 6;
}
}
void
tssrsp0(uintptr_t sp)
{
Tss *tss;
tss = m->tss;
tss->rsp0[0] = sp;
tss->rsp0[1] = sp>>32;
}
static void
tssinit(uintptr_t sp)
{
int ist;
Tss *tss;
tss = m->tss;
jehanne_memset(tss, 0, sizeof(Tss));
tssrsp0(sp);
sp = PTR2UINT(m->vsvm+PGSZ);
for(ist = 0; ist < 14; ist += 2){
tss->ist[ist] = sp;
tss->ist[ist+1] = sp>>32;
}
tss->iomap = 0xdfff;
}
void
vsvminit(int size)
{
Sd *sd;
uint64_t r;
if(m->machno == 0)
idtinit();
m->gdt = m->vsvm;
jehanne_memmove(m->gdt, gdt64, sizeof(gdt64));
m->tss = &m->vsvm[ROUNDUP(sizeof(gdt64), 16)];
sd = &((Sd*)m->gdt)[SiTSS];
*sd = mksd(PTR2UINT(m->tss), sizeof(Tss)-1, SdP|SdDPL0|SdaTSS, sd+1);
tssinit(m->stack+size);
gdtput(sizeof(gdt64)-1, PTR2UINT(m->gdt), SSEL(SiCS, SsTIGDT|SsRPL0));
idtput(sizeof(idt64)-1, PTR2UINT(idt64));
trput(SSEL(SiTSS, SsTIGDT|SsRPL0));
wrmsr(FSbase, 0ull);
wrmsr(GSbase, PTR2UINT(&sys->machptr[m->machno]));
wrmsr(KernelGSbase, 0ull);
r = rdmsr(Efer);
r |= Sce;
wrmsr(Efer, r);
r = ((uint64_t)SSEL(SiU32CS, SsRPL3))<<48;
r |= ((uint64_t)SSEL(SiCS, SsRPL0))<<32;
wrmsr(Star, r);
wrmsr(Lstar, PTR2UINT(syscallentry));
wrmsr(Sfmask, If);
}
int
userureg(Ureg* ureg)
{
return ureg->cs == SSEL(SiUCS, SsRPL3);
}