#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
/*
* task state segment. Plan 9 ignores all the task switching goo and just
* uses the tss for esp0 and ss0 on gate's into the kernel, interrupts,
* and exceptions. The rest is completely ignored.
*
* This means that we only need one tss in the whole system.
*/
typedef struct Tss Tss;
struct Tss
{
ulong backlink; /* unused */
ulong sp0; /* pl0 stack pointer */
ulong ss0; /* pl0 stack selector */
ulong sp1; /* pl1 stack pointer */
ulong ss1; /* pl1 stack selector */
ulong sp2; /* pl2 stack pointer */
ulong ss2; /* pl2 stack selector */
ulong cr3; /* page table descriptor */
ulong eip; /* instruction pointer */
ulong eflags; /* processor flags */
ulong eax; /* general (hah?) registers */
ulong ecx;
ulong edx;
ulong ebx;
ulong esp;
ulong ebp;
ulong esi;
ulong edi;
ulong es; /* segment selectors */
ulong cs;
ulong ss;
ulong ds;
ulong fs;
ulong gs;
ulong ldt; /* local descriptor table */
ulong iomap; /* io map base */
};
Tss tss;
/*
* segment descriptor initializers
*/
#define DATASEGM(p) { 0xFFFF, SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
#define EXECSEGM(p) { 0xFFFF, SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
#define CALLGATE(s,o,p) { ((o)&0xFFFF)|((s)<<16), (o)&0xFFFF0000|SEGP|SEGPL(p)|SEGCG }
#define D16SEGM(p) { 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
#define E16SEGM(p) { 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
#define TSSSEGM(b,p) { ((b)<<16)|sizeof(Tss),\
((b)&0xFF000000)|(((b)<<16)&0xFF)|SEGTSS|SEGPL(p)|SEGP }
/*
* global descriptor table describing all segments
*/
Segdesc gdt[] =
{
[NULLSEG] { 0, 0}, /* null descriptor */
[KDSEG] DATASEGM(0), /* kernel data/stack */
[KESEG] EXECSEGM(0), /* kernel code */
[UDSEG] DATASEGM(3), /* user data/stack */
[UESEG] EXECSEGM(3), /* user code */
[SYSGATE] CALLGATE(KESEL,0,3), /* call gate for system calls */
[RDSEG] D16SEGM(0), /* reboot data/stack */
[RESEG] E16SEGM(0), /* reboot code */
[TSSSEG] TSSSEGM(0,0), /* tss segment */
};
static ulong *toppt; /* top level page table */
static ulong *kpt; /* kernel level page tables */
static ulong *upt; /* page table for struct User */
#define ROUNDUP(s,v) (((s)+(v-1))&~(v-1))
void
mmuinit(void)
{
int i, n, nkpt;
ulong x;
ulong y;
/*
* set up the global descriptor table
*/
x = (ulong)systrap;
gdt[SYSGATE].d0 = (x&0xFFFF)|(KESEL<<16);
gdt[SYSGATE].d1 = (x&0xFFFF0000)|SEGP|SEGPL(3)|SEGCG;
x = (long)&tss;
gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss);
gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP;
lgdt(gdt, sizeof gdt);
/*
* set up system page tables.
* map all of physical memory to start at KZERO.
* leave a map for a user area.
*/
/* allocate and fill low level page tables for physical mem */
nkpt = ROUNDUP(conf.npage0+conf.npage1, 4*1024*1024);
nkpt = nkpt/(4*1024*1024);
kpt = ialloc(nkpt*BY2PG, 1);
n = ROUNDUP(conf.npage0+conf.npage1, 1*1024*1024);
n = n/(4*1024);
for(i = 0; i < n; i++){
kpt[i] = (i<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE;
}
/* allocate page table for u-> */
upt = ialloc(BY2PG, 1);
/* allocate top level table and put pointers to lower tables in it */
toppt = ialloc(BY2PG, 1);
x = KZERO>>(2*PGSHIFT-2);
y = ((ulong)kpt)&~KZERO;
for(i = 0; i < nkpt; i++){
/* toppt[i] = (y+i*BY2PG)|PTEVALID|PTEKERNEL|PTEWRITE;/**/
toppt[x+i] = (y+i*BY2PG)|PTEVALID|PTEKERNEL|PTEWRITE;
}
x = USERADDR>>(2*PGSHIFT-2);
y = ((ulong)upt)&~KZERO;
toppt[x] = y|PTEVALID|PTEKERNEL|PTEWRITE;
lcr3(((ulong)toppt)&~KZERO);
/*
* set up the task segment
*/
tss.sp0 = USERADDR;
tss.ss0 = KDSEL;
tss.cr3 = (ulong)toppt;
ltr(TSSSEL);
}
void
mapstack(Proc *p)
{
}
void
flushmmu(void)
{
}
void
mmurelease(Proc *p)
{
}
void
putmmu(ulong x, ulong y, Page *z)
{
}
void
invalidateu(void)
{
}
void
systrap(void)
{
panic("system trap from user");
}
void
exit(void)
{
int i;
u = 0;
print("exiting\n");
for(i = 0; i < WD2PG; i++)
toppt[i] = 0;
lcr3(((ulong)toppt)&~KZERO);
}