pc64: preserve user extern registers R14 and R15 across syscalls, use Ureg.bp (RARG) for syscall number
the 6c compiler reserves R14 and R15 for extern register variables, which is used by the kernel to hold the m and up pointers. until now, the meaning of R14 and R15 was undefined for userspace and extern register would not work as the kernel trashes R14 and R15 on syscalls. with this change, user extern registers R14 and R15 are zeroed on exec and otherwise preserved across syscalls. so userspace *could* use them for per process variables like the kernel does. use Ureg.bp (RARG) for syscall number instead of Ureg.ax. this is less confusing and mirrors the amd64 calling convention.
This commit is contained in:
parent
b603991593
commit
20b7a19c58
2 changed files with 41 additions and 37 deletions
|
@ -686,15 +686,20 @@ f3:
|
||||||
TEXT touser(SB), 1, $-4
|
TEXT touser(SB), 1, $-4
|
||||||
CLI
|
CLI
|
||||||
SWAPGS
|
SWAPGS
|
||||||
MOVQ $UDSEL, AX
|
|
||||||
|
MOVW $UDSEL, AX
|
||||||
MOVW AX, DS
|
MOVW AX, DS
|
||||||
MOVW AX, ES
|
MOVW AX, ES
|
||||||
|
|
||||||
|
MOVW $NULLSEL, AX
|
||||||
MOVW AX, FS
|
MOVW AX, FS
|
||||||
MOVW AX, GS
|
MOVW AX, GS
|
||||||
|
|
||||||
MOVQ $(UTZERO+0x28), CX /* ip */
|
MOVL $0, RMACH
|
||||||
MOVQ $0x200, R11 /* flags */
|
MOVL $0, RUSER
|
||||||
|
|
||||||
|
MOVQ $(UTZERO+0x28), CX /* ip */
|
||||||
|
MOVL $0x200, R11 /* flags */
|
||||||
MOVQ RARG, SP /* sp */
|
MOVQ RARG, SP /* sp */
|
||||||
|
|
||||||
BYTE $0x48; SYSRET /* SYSRETQ */
|
BYTE $0x48; SYSRET /* SYSRETQ */
|
||||||
|
@ -703,45 +708,55 @@ TEXT touser(SB), 1, $-4
|
||||||
*/
|
*/
|
||||||
TEXT syscallentry(SB), 1, $-4
|
TEXT syscallentry(SB), 1, $-4
|
||||||
SWAPGS
|
SWAPGS
|
||||||
BYTE $0x65; MOVQ 0, RMACH /* m-> (MOVQ GS:0x0, R15) */
|
BYTE $0x65; MOVQ 0, AX /* m-> (MOVQ GS:0x0, AX) */
|
||||||
MOVQ 16(RMACH), RUSER /* m->proc */
|
MOVQ 16(AX), BX /* m->proc */
|
||||||
MOVQ SP, R13
|
MOVQ SP, R13
|
||||||
MOVQ 16(RUSER), SP /* m->proc->kstack */
|
MOVQ 16(BX), SP /* m->proc->kstack */
|
||||||
ADDQ $KSTACK, SP
|
ADDQ $KSTACK, SP
|
||||||
|
|
||||||
PUSHQ $UDSEL /* old stack segment */
|
PUSHQ $UDSEL /* old stack segment */
|
||||||
PUSHQ R13 /* old sp */
|
PUSHQ R13 /* old sp */
|
||||||
PUSHQ R11 /* old flags */
|
PUSHQ R11 /* old flags */
|
||||||
PUSHQ $UESEL /* old code segment */
|
PUSHQ $UESEL /* old code segment */
|
||||||
PUSHQ CX /* old ip */
|
PUSHQ CX /* old ip */
|
||||||
|
|
||||||
SUBQ $(17*8), SP /* unsaved registers */
|
SUBQ $(16+16*8), SP /* unsaved registers */
|
||||||
PUSHQ RARG /* system call number */
|
|
||||||
|
|
||||||
MOVW $UDSEL, (15*8+0)(SP)
|
MOVW $UDSEL, (15*8+0)(SP)
|
||||||
MOVW ES, (15*8+2)(SP)
|
MOVW ES, (15*8+2)(SP)
|
||||||
MOVW FS, (15*8+4)(SP)
|
MOVW FS, (15*8+4)(SP)
|
||||||
MOVW GS, (15*8+6)(SP)
|
MOVW GS, (15*8+6)(SP)
|
||||||
|
|
||||||
|
MOVQ RMACH, (14*8)(SP)
|
||||||
|
MOVQ RUSER, (13*8)(SP)
|
||||||
|
|
||||||
|
MOVQ RARG, (6*8)(SP) /* system call number */
|
||||||
|
|
||||||
|
MOVQ AX, RMACH /* m */
|
||||||
|
MOVQ BX, RUSER /* up */
|
||||||
|
|
||||||
MOVQ SP, RARG
|
MOVQ SP, RARG
|
||||||
PUSHQ SP /* Ureg* */
|
PUSHQ SP
|
||||||
CALL syscall(SB)
|
CALL syscall(SB)
|
||||||
|
|
||||||
TEXT forkret(SB), 1, $-4
|
TEXT forkret(SB), 1, $-4
|
||||||
MOVQ 8(SP), AX /* Ureg.ax */
|
MOVQ 8(SP), AX
|
||||||
MOVQ (8+6*8)(SP), BP /* Ureg.bp */
|
ADDQ $(8+13*8), SP /* unsaved registers */
|
||||||
ADDQ $(16*8), SP /* registers + arguments */
|
|
||||||
|
|
||||||
CLI
|
CLI
|
||||||
SWAPGS
|
SWAPGS
|
||||||
MOVW 0(SP), DS
|
|
||||||
MOVW 2(SP), ES
|
|
||||||
MOVW 4(SP), FS
|
|
||||||
MOVW 6(SP), GS
|
|
||||||
|
|
||||||
MOVQ 24(SP), CX /* ip */
|
MOVW 22(SP), GS
|
||||||
MOVQ 40(SP), R11 /* flags */
|
MOVW 20(SP), FS
|
||||||
|
MOVW 18(SP), ES
|
||||||
|
MOVW 16(SP), DS
|
||||||
|
|
||||||
MOVQ 48(SP), SP /* sp */
|
MOVQ 8(SP), RMACH
|
||||||
|
MOVQ 0(SP), RUSER
|
||||||
|
|
||||||
|
MOVQ 40(SP), CX /* ip */
|
||||||
|
MOVQ 56(SP), R11 /* flags */
|
||||||
|
MOVQ 64(SP), SP /* sp */
|
||||||
|
|
||||||
BYTE $0x48; SYSRET /* SYSRETQ */
|
BYTE $0x48; SYSRET /* SYSRETQ */
|
||||||
|
|
||||||
|
|
|
@ -686,7 +686,7 @@ syscall(Ureg* ureg)
|
||||||
up->dbgreg = ureg;
|
up->dbgreg = ureg;
|
||||||
|
|
||||||
sp = ureg->sp;
|
sp = ureg->sp;
|
||||||
scallnr = ureg->ax;
|
scallnr = ureg->bp; /* RARG */
|
||||||
up->scallnr = scallnr;
|
up->scallnr = scallnr;
|
||||||
|
|
||||||
spllo();
|
spllo();
|
||||||
|
@ -735,13 +735,6 @@ syscall(Ureg* ureg)
|
||||||
up->errlab[i].sp, up->errlab[i].pc);
|
up->errlab[i].sp, up->errlab[i].pc);
|
||||||
panic("error stack");
|
panic("error stack");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Put return value in frame. On the x86 the syscall is
|
|
||||||
* just another trap and the return value from syscall is
|
|
||||||
* ignored. On other machines the return value is put into
|
|
||||||
* the results register by caller of syscall.
|
|
||||||
*/
|
|
||||||
ureg->ax = ret;
|
ureg->ax = ret;
|
||||||
|
|
||||||
if(0){
|
if(0){
|
||||||
|
@ -902,12 +895,8 @@ noted(Ureg* ureg, ulong arg0)
|
||||||
pexit("Suicide", 0);
|
pexit("Suicide", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* don't let user change system flags */
|
/* don't let user change system flags or segment registers */
|
||||||
nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
|
setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
|
||||||
nureg->cs |= 3;
|
|
||||||
nureg->ss |= 3;
|
|
||||||
|
|
||||||
memmove(ureg, nureg, sizeof(Ureg));
|
|
||||||
|
|
||||||
switch(arg0){
|
switch(arg0){
|
||||||
case NCONT:
|
case NCONT:
|
||||||
|
@ -965,6 +954,7 @@ execregs(uintptr entry, ulong ssize, ulong nargs)
|
||||||
ureg->cs = UESEL;
|
ureg->cs = UESEL;
|
||||||
ureg->ss = ureg->ds = ureg->es = UDSEL;
|
ureg->ss = ureg->ds = ureg->es = UDSEL;
|
||||||
ureg->fs = ureg->gs = NULLSEL;
|
ureg->fs = ureg->gs = NULLSEL;
|
||||||
|
ureg->r14 = ureg->r15 = 0; /* extern user registers */
|
||||||
return (uintptr)USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
|
return (uintptr)USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,7 +971,7 @@ userpc(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This routine must save the values of registers the user is not permitted
|
/* This routine must save the values of registers the user is not permitted
|
||||||
* to write from devproc and then restore the saved values before returning.
|
* to write from devproc and noted() and then restore the saved values before returning.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
setregisters(Ureg* ureg, char* pureg, char* uva, int n)
|
setregisters(Ureg* ureg, char* pureg, char* uva, int n)
|
||||||
|
@ -995,7 +985,7 @@ setregisters(Ureg* ureg, char* pureg, char* uva, int n)
|
||||||
if(ureg->fs != UDSEL)
|
if(ureg->fs != UDSEL)
|
||||||
ureg->fs = NULLSEL;
|
ureg->fs = NULLSEL;
|
||||||
if(ureg->gs != UDSEL)
|
if(ureg->gs != UDSEL)
|
||||||
ureg->gs = 0;
|
ureg->gs = NULLSEL;
|
||||||
ureg->flags = (ureg->flags & 0x00ff) | (flags & 0xff00);
|
ureg->flags = (ureg->flags & 0x00ff) | (flags & 0xff00);
|
||||||
ureg->pc &= UADDRMASK;
|
ureg->pc &= UADDRMASK;
|
||||||
}
|
}
|
||||||
|
@ -1063,8 +1053,7 @@ dbgpc(Proc *p)
|
||||||
Ureg *ureg;
|
Ureg *ureg;
|
||||||
|
|
||||||
ureg = p->dbgreg;
|
ureg = p->dbgreg;
|
||||||
if(ureg == 0)
|
if(ureg == nil)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ureg->pc;
|
return ureg->pc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue