提交 4f6e9572 创建 作者: Nickolai Zeldovich's avatar Nickolai Zeldovich

syscall/sysret support

上级 05f41512
......@@ -36,7 +36,7 @@ COMFLAGS = -static -fno-builtin -fno-strict-aliasing -O2 -Wall \
COMFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
CFLAGS := $(COMFLAGS) -std=c99 $(CFLAGS)
CXXFLAGS := $(COMFLAGS) -std=c++0x -Wno-sign-compare -fno-exceptions -fno-rtti -fcheck-new $(CXXFLAGS)
ASFLAGS = -Iinclude -m64 -gdwarf-2 -MD
ASFLAGS = -Iinclude -m64 -gdwarf-2 -MD -DHW_$(HW) -include param.h
LDFLAGS = -m elf_x86_64
all:
......
......@@ -138,6 +138,14 @@ writegs(u16 v)
__asm volatile("movw %0, %%gs" : : "r" (v));
}
static inline u16
readgs(void)
{
u16 v;
__asm volatile("movw %%gs, %0" : "=r" (v));
return v;
}
static inline u64
readmsr(u32 msr)
{
......@@ -231,6 +239,7 @@ rcr2(void)
// Layout of the trap frame built on the stack by the
// hardware and by trapasm.S, and passed to trap().
// Also used by sysentry (but sparsely populated).
struct trapframe {
u16 padding3[7];
u16 ds;
......
......@@ -44,6 +44,7 @@
// FS/GS base registers
#define MSR_FS_BASE 0xc0000100
#define MSR_GS_BASE 0xc0000101
#define MSR_GS_KERNBASE 0xc0000102
// SYSCALL and SYSRET registers
#define MSR_STAR 0xc0000081
......
......@@ -59,4 +59,5 @@ void threadhelper(void (*fn)(void *), void *arg);
struct trapframe;
void trap(struct trapframe *tf);
void sysentry(void);
void sysentry_c(void);
......@@ -129,3 +129,6 @@ struct taskstate
(u16) ((rip)&0xffff), (cs), 0, bits, (u16) (((rip)>>16)&0xffff), \
(u32) ((u64)(rip)>>32), 0, \
}
#define PROC_KSTACK_OFFSET 40
#define TRAPFRAME_SIZE 192
......@@ -180,6 +180,7 @@ inittls(void)
c = &cpus[cpunum()];
writegs(KDSEG);
writemsr(MSR_GS_BASE, (u64)&c->cpu);
writemsr(MSR_GS_KERNBASE, (u64)&c->cpu);
c->cpu = c;
c->proc = NULL;
c->kmem = &kmems[cpunum()];
......
......@@ -6,6 +6,8 @@
#include "cpu.hh"
#include "amd64.h"
#include "hwvm.hh"
#include "condvar.h"
#include "proc.hh"
static volatile int bstate;
......@@ -96,6 +98,13 @@ cmain(u64 mbmagic, u64 mbaddr)
kpml4.e[0] = 0; // don't need 1 GB identity mapping anymore
lcr3(rcr3());
if (PROC_KSTACK_OFFSET != __offsetof(struct proc, kstack))
panic("PROC_KSTACK_OFFSET mismatch: %d %ld\n",
PROC_KSTACK_OFFSET, __offsetof(struct proc, kstack));
if (TRAPFRAME_SIZE != sizeof(trapframe))
panic("TRAPFRAME_SIZE mismatch: %d %ld\n",
TRAPFRAME_SIZE, sizeof(trapframe));
scheduler();
panic("Unreachable");
}
......@@ -58,7 +58,8 @@ argint64(int n, u64 *ip)
case 2: *ip = myproc()->tf->rdx; break;
case 3: *ip = myproc()->tf->rcx; break;
case 4: *ip = myproc()->tf->r8; break;
case 5: *ip = myproc()->tf->r9; break;
// r9 is corrupted by sysentry
// case 5: *ip = myproc()->tf->r9; break;
default:
cprintf("argint64: bad arg %d\n", n);
return -1;
......
......@@ -17,6 +17,29 @@ struct intdesc idt[256] __attribute__((aligned(16)));
extern u64 trapentry[];
void
sysentry_c()
{
writegs(KDSEG);
writemsr(MSR_GS_BASE, (u64)&cpus[cpunum()].cpu);
sti();
if(myproc()->killed) {
mtstart(trap, myproc());
exit();
}
trapframe *tf = (trapframe*) (myproc()->kstack + KSTACKSIZE - sizeof(*tf));
myproc()->tf = tf;
syscall();
if(myproc()->killed) {
mtstart(trap, myproc());
exit();
}
}
void
trap(struct trapframe *tf)
{
writegs(KDSEG);
......@@ -30,7 +53,6 @@ trap(struct trapframe *tf)
panic("NMI");
}
// XXX(sbw) sysenter/sysexit
if(tf->trapno == T_SYSCALL){
sti();
if(myproc()->killed) {
......@@ -185,7 +207,6 @@ inittrap(void)
void
initseg(void)
{
extern void sysentry(void);
volatile struct desctr dtr;
struct cpu *c;
......@@ -201,7 +222,6 @@ initseg(void)
dtr.base = (u64)c->gdt;
lgdt((void *)&dtr.limit);
#if 0
// When executing a syscall instruction the CPU sets the SS selector
// to (star >> 32) + 8 and the CS selector to (star >> 32).
// When executing a sysret instruction the CPU sets the SS selector
......@@ -209,8 +229,7 @@ initseg(void)
u64 star = ((((u64)UCSEG|0x3) - 16)<<48)|((u64)KCSEG<<32);
writemsr(MSR_STAR, star);
writemsr(MSR_LSTAR, (u64)&sysentry);
writemsr(MSR_SFMASK, FL_TF);
#endif
writemsr(MSR_SFMASK, FL_TF | FL_IF);
}
// Pushcli/popcli are like cli/sti except that they are matched:
......
......@@ -18,13 +18,68 @@
#define TRAPCODE(x) _TRAP(x, EC)
.code64
#if 0
.globl sysentry
.align 8
sysentry:
jmp sysentry
#endif
// blow away %r9: syscalls can take at most 5 args
swapgs
movq %gs:8, %r9 // myproc()
swapgs
movq %ss:PROC_KSTACK_OFFSET(%r9), %r9
addq $(KSTACKSIZE-TRAPFRAME_SIZE), %r9
// syscall number: %rax
// function arguments: %rdi, %rsi, %rdx, %rcx, %r8, %r9 (killed)
// skip padding3, ds
movq %r15, %ss:0x10(%r9)
movq %r14, %ss:0x18(%r9)
movq %r13, %ss:0x20(%r9)
movq %r12, %ss:0x28(%r9)
movq %rbp, %ss:0x30(%r9)
movq %rbx, %ss:0x38(%r9)
// skip r11 (0x40)
// skip r10 (0x48)
// skip r9 (0x50)
movq %r8, %ss:0x58(%r9)
movq %rax, %ss:0x60(%r9)
movq %r10, %ss:0x68(%r9) // rcx saved by usys.S
movq %rdx, %ss:0x70(%r9)
movq %rsi, %ss:0x78(%r9)
movq %rdi, %ss:0x80(%r9)
// skip trapno (0x88)
// skip err, padding2 (0x90)
movq %rcx, %ss:0x98(%r9) // rip saved by syscall
// skip cs, padding (0xa0)
movq %r11, %ss:0xa8(%r9) // eflags saved by syscall
movq %rsp, %ss:0xb0(%r9)
movw $KDSEG, %ax
movw %ax, %ds
movw %ax, %es
movq %r9, %rsp
call sysentry_c
// return using SYSRET
cli
movq %rsp, %r11
movw $UDSEG, %ax
movw %ax, %ds
movw %ax, %es
movq %ss:0x10(%r11), %r15
movq %ss:0x18(%r11), %r14
movq %ss:0x20(%r11), %r13
movq %ss:0x28(%r11), %r12
movq %ss:0x30(%r11), %rbp
movq %ss:0x38(%r11), %rbx
movq %ss:0x60(%r11), %rax
movq %ss:0x98(%r11), %rcx // rip to be restored by sysret
movq %ss:0xb0(%r11), %rsp
movq %ss:0xa8(%r11), %r11 // eflags to be restored by sysret
sysretq
trapcommon:
pushq %rdi
pushq %rsi
......
......@@ -5,7 +5,8 @@
.globl name; \
name: \
movq $SYS_ ## name, %rax; \
int $T_SYSCALL; \
movq %rcx, %r10; \
syscall; \
ret
SYSCALL(fork)
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论