PERFORCE change 29267 for review
Marcel Moolenaar
marcel at FreeBSD.org
Sat Apr 19 14:39:15 PDT 2003
http://perforce.freebsd.org/chv.cgi?CH=29267
Change 29267 by marcel at marcel_nfs on 2003/04/19 14:38:55
o Change the prototype of trap(). We don't need to pass cr.iim
as the second argument, because it's available as cr.ifa in
the trapframe.
o Add support for "legacy" syscalls. This is implemented by
forcing a RSE flush on break instruction faults so that the
stacked registers in the current frame can be accessed.
o Make sure thread0's trapframe is marked as FRAME_SYSCALL
so that we take the syscall_return path into init(8).
o Instruduce do_ast() as the centralized place where we check
whether we have an AST. This may be hand-inlined in the
future, but for now it keeps the assembly in syscall.s
unencumbered.
o Use atomic operations to increment the vmmeter counters.
o Change the prototype of syscall() to return the error. This
way we can handle ERESTART in the most convenient way. The
"legacy" syscall handles ERESTART already. The EPC based
syscalls need to have support added still.
o Style changes.
o Remove some bogus prototypes.
Affected files ...
.. //depot/projects/ia64_epc/sys/ia64/ia64/exception.s#13 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/genassym.c#7 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/locore.s#13 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/machdep.c#13 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/syscall.s#8 edit
.. //depot/projects/ia64_epc/sys/ia64/ia64/trap.c#9 edit
.. //depot/projects/ia64_epc/sys/ia64/include/cpu.h#6 edit
Differences ...
==== //depot/projects/ia64_epc/sys/ia64/ia64/exception.s#13 (text+ko) ====
@@ -559,16 +559,23 @@
{ .mib ; \
nop _n_ ; \
mov r16=ip ; \
- br.sptk.few exception_save ; \
+ br.sptk exception_save ; \
+} ; \
+{ .mmi ; \
+(p11) ssm psr.i ;; \
+ alloc r15=ar.pfs,0,0,2,0 ; \
+ mov out0=_n_ ;; \
+} ; \
+{ .mmb ; \
+ mov out1=sp ; \
+ add sp=-16,sp ; \
+ br.call.sptk rp=trap ; \
} ; \
-(p11) ssm psr.i; \
- alloc r15=ar.pfs,0,0,3,0; \
- mov out0=_n_; \
- mov out1=r14; \
- mov out2=sp;; \
- add sp=-16,sp;; \
- br.call.sptk.few rp=trap; \
-3: br.sptk.many exception_restore
+{ .mfb ; \
+ nop 0 ; \
+ nop 0 ; \
+ br.sptk exception_restore ; \
+}
#define IVT_ENTRY(name, offset) \
.org ia64_vector_table + offset; \
@@ -1088,12 +1095,36 @@
nop 0
;;
}
+{ .mib
+ srlz.d
+ mov r16=ip
+ br.sptk exception_save
+ ;;
+}
+{ .mmi
+ flushrs
+(p11) ssm psr.i
+ nop 0
+ ;;
+}
+{ .mmi
+ alloc r15=ar.pfs,0,0,2,0
+ mov out0=11
+ mov out1=sp
+ ;;
+}
{ .mfb
- srlz.d
+ add sp=-16,sp
+ nop 0
+ br.call.sptk rp=trap
+ ;;
+}
+{ .mfb
nop 0
nop 0
+ br.sptk exception_restore
+ ;;
}
- TRAP(11)
IVT_END(Break_Instruction)
IVT_ENTRY(External_Interrupt, 0x3000)
==== //depot/projects/ia64_epc/sys/ia64/ia64/genassym.c#7 (text+ko) ====
@@ -74,6 +74,7 @@
ASSYM(EFAULT, EFAULT);
ASSYM(ENAMETOOLONG, ENAMETOOLONG);
+ASSYM(ERESTART, ERESTART);
ASSYM(FRAME_SYSCALL, FRAME_SYSCALL);
@@ -117,9 +118,7 @@
ASSYM(TDF_ASTPENDING, TDF_ASTPENDING);
ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED);
-ASSYM(TF_SPECIAL_NDIRTY,offsetof(struct trapframe, tf_special.ndirty));
-ASSYM(TF_SPECIAL_PFS, offsetof(struct trapframe, tf_special.pfs));
-ASSYM(TF_SPECIAL_PSR, offsetof(struct trapframe, tf_special.psr));
+ASSYM(TF_SPECIAL_NDIRTY, offsetof(struct trapframe, tf_special.ndirty));
ASSYM(UC_MCONTEXT, offsetof(ucontext_t, uc_mcontext));
==== //depot/projects/ia64_epc/sys/ia64/ia64/locore.s#13 (text+ko) ====
@@ -158,10 +158,17 @@
.global enter_userland
.type enter_userland, @function
enter_userland:
-{ .mfb
+{ .mmi
+ add r14=24,sp
+ ;;
+ ld8 r14=[r14]
nop 0
- nop 0
- br.sptk syscall_return
+ ;;
+}
+{ .mbb
+ cmp.eq p6,p7=r0,r14
+(p6) br.sptk exception_restore
+(p7) br.sptk syscall_return
;;
}
END(fork_trampoline)
==== //depot/projects/ia64_epc/sys/ia64/ia64/machdep.c#13 (text+ko) ====
@@ -736,6 +736,8 @@
* XXX what is all this +/- 16 stuff?
*/
thread0.td_frame = (struct trapframe *)thread0.td_pcb - 1;
+ thread0.td_frame->tf_length = sizeof(struct trapframe);
+ thread0.td_frame->tf_flags = FRAME_SYSCALL;
thread0.td_pcb->pcb_special.sp =
(u_int64_t)thread0.td_frame - 16;
thread0.td_pcb->pcb_special.bspstore = (u_int64_t)proc0kstack;
@@ -1063,36 +1065,60 @@
}
/*
- * Clear registers on exec
+ * Clear registers on exec.
*/
void
exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings)
{
- struct trapframe *frame;
+ struct trapframe *tf;
- frame = td->td_frame;
- bzero(frame, sizeof(*frame));
- frame->tf_length = sizeof(*frame);
- frame->tf_flags = FRAME_SYSCALL;
- frame->tf_special.sp = (stack & ~15) - 16;
- frame->tf_special.rp = entry;
- frame->tf_special.pfs = (3UL<<62) | (3UL<<7) | 3UL;
- frame->tf_special.bspstore = td->td_md.md_bspstore + 24;
- frame->tf_special.rsc = 0xf;
- frame->tf_special.fpsr = IA64_FPSR_DEFAULT;
- frame->tf_special.psr = IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT |
+ tf = td->td_frame;
+ if ((tf->tf_flags & FRAME_SYSCALL) == 0) { /* break syscalls. */
+ uint64_t *args;
+ uint64_t ndirty;
+ ndirty = tf->tf_special.ndirty;
+ bzero(&tf->tf_special, sizeof(tf->tf_special));
+ tf->tf_special.ndirty = ndirty;
+ bzero(&tf->tf_scratch, sizeof(tf->tf_scratch));
+ bzero(&tf->tf_scratch_fp, sizeof(tf->tf_scratch_fp));
+ tf->tf_special.iip = entry;
+ tf->tf_special.cfm = (1UL<<63) | (3UL<<7) | 3UL;
+ tf->tf_special.bspstore = td->td_md.md_bspstore;
+ /*
+ * Copy the arguments onto the kernel register stack so that
+ * they get loaded by the loadrs. This involves some NaT
+ * collection magic.
+ */
+ args = (uint64_t*)(td->td_kstack + ndirty);
+ args -= (((uintptr_t)args & 0x1ff) < 24) ? 4 : 3;
+ *args++ = stack;
+ if (((uintptr_t)args & 0x1ff) == 0x1f8)
+ args++;
+ *args++ = ps_strings;
+ if (((uintptr_t)args & 0x1ff) == 0x1f8)
+ args++;
+ *args = 0;
+ } else { /* epc syscalls (default). */
+ bzero(&tf->tf_special, sizeof(tf->tf_special));
+ tf->tf_special.rp = entry;
+ tf->tf_special.pfs = (3UL<<62) | (3UL<<7) | 3UL;
+ tf->tf_special.bspstore = td->td_md.md_bspstore + 24;
+ /*
+ * Write values for out0, out1 and out2 to the user's backing
+ * store and arrange for them to be restored into the user's
+ * initial register frame.
+ * Assumes that (bspstore & 0x1f8) < 0x1e0.
+ */
+ suword((caddr_t)tf->tf_special.bspstore - 24, stack);
+ suword((caddr_t)tf->tf_special.bspstore - 16, ps_strings);
+ suword((caddr_t)tf->tf_special.bspstore - 8, 0);
+ }
+ tf->tf_special.sp = (stack & ~15) - 16;
+ tf->tf_special.rsc = 0xf;
+ tf->tf_special.fpsr = IA64_FPSR_DEFAULT;
+ tf->tf_special.psr = IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT |
IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | IA64_PSR_BN |
IA64_PSR_CPL_USER;
-
- /*
- * Write values for out0, out1 and out2 to the user's backing
- * store and arrange for them to be restored into the user's
- * initial register frame. Assumes that (bspstore & 0x1f8) <
- * 0x1e0.
- */
- suword((caddr_t)frame->tf_special.bspstore - 24, stack);
- suword((caddr_t)frame->tf_special.bspstore - 16, ps_strings);
- suword((caddr_t)frame->tf_special.bspstore - 8, 0);
}
int
==== //depot/projects/ia64_epc/sys/ia64/ia64/syscall.s#8 (text+ko) ====
@@ -251,6 +251,12 @@
br.call.sptk rp=syscall
;;
}
+{ .mfb
+ add out0=16,sp
+ nop 0
+ br.call.sptk rp=do_ast
+ ;;
+}
.global syscall_return
.type syscall_return, @function
==== //depot/projects/ia64_epc/sys/ia64/ia64/trap.c#9 (text+ko) ====
@@ -80,6 +80,8 @@
CTLFLAG_RW, &print_usertrap, 0, "");
extern int unaligned_fixup(struct trapframe *framep, struct thread *td);
+
+static void break_syscall(struct trapframe *tf);
static void ia32_syscall(struct trapframe *framep);
/*
@@ -279,7 +281,7 @@
}
static void
-printtrap(int vector, int imm, struct trapframe *framep, int isfatal, int user)
+printtrap(int vector, struct trapframe *framep, int isfatal, int user)
{
printf("\n");
printf("%s %s trap (cpu %d):\n", isfatal? "fatal" : "handled",
@@ -295,7 +297,6 @@
printisr(framep->tf_special.isr);
printf(")\n");
printf(" cr.ifa = 0x%lx\n", framep->tf_special.ifa);
- printf(" cr.iim = 0x%x\n", imm);
if (framep->tf_special.psr & IA64_PSR_IS) {
printf(" ar.cflg = 0x%lx\n", ia64_get_cflg());
printf(" ar.csd = 0x%lx\n", ia64_get_csd());
@@ -309,34 +310,55 @@
}
/*
+ *
+ */
+void
+do_ast(struct trapframe *tf)
+{
+ while (1) {
+ disable_intr();
+ if (curthread->td_flags & (TDF_ASTPENDING|TDF_NEEDRESCHED)) {
+ enable_intr();
+ printf("XXX calling ast()\n");
+ ast(tf);
+ } else
+ break;
+ }
+ /* Keep interrupts disabled. */
+}
+
+/*
* Trap is called from exception.s to handle most types of processor traps.
- * System calls are broken out for efficiency and ASTs are broken out
- * to make the code a bit cleaner and more representative of the
- * architecture.
*/
/*ARGSUSED*/
void
-trap(int vector, int imm, struct trapframe *framep)
+trap(int vector, struct trapframe *framep)
{
+ struct proc *p;
struct thread *td;
- struct proc *p;
+ u_int64_t ucode;
int i;
- u_int64_t ucode;
u_int sticks;
int user;
- cnt.v_trap++;
+ user = ((framep->tf_special.psr & IA64_PSR_CPL) == IA64_PSR_CPL_USER);
+
+ /* Short-circuit break instruction based system calls. */
+ if (vector == IA64_VEC_BREAK && user &&
+ framep->tf_special.ifa == 0x100000) {
+ break_syscall(framep);
+ return;
+ }
+
+ /* Sanitize the FP state in case the user has trashed it. */
+ ia64_set_fpsr(IA64_FPSR_DEFAULT);
+
+ atomic_add_int(&cnt.v_trap, 1);
+
td = curthread;
p = td->td_proc;
ucode = 0;
- /*
- * Make sure we have a sane floating-point state in case the
- * user has trashed it.
- */
- ia64_set_fpsr(IA64_FPSR_DEFAULT);
-
- user = ((framep->tf_special.psr & IA64_PSR_CPL) == IA64_PSR_CPL_USER);
if (user) {
sticks = td->td_sticks;
td->td_frame = framep;
@@ -354,7 +376,8 @@
}
switch (vector) {
- case IA64_VEC_UNALIGNED_REFERENCE:
+
+ case IA64_VEC_UNALIGNED_REFERENCE: {
/*
* If user-land, do whatever fixups, printing, and
* signalling is appropriate (based on system-wide
@@ -384,9 +407,9 @@
* does cause an unaligned access it's a kernel bug.
*/
goto dopanic;
+ }
- case IA64_VEC_FLOATING_POINT_FAULT:
- {
+ case IA64_VEC_FLOATING_POINT_FAULT: {
FP_STATE fp_state;
FPSWA_RET fpswa_ret;
FPSWA_BUNDLE bundle;
@@ -461,8 +484,7 @@
}
}
- case IA64_VEC_FLOATING_POINT_TRAP:
- {
+ case IA64_VEC_FLOATING_POINT_TRAP: {
FP_STATE fp_state;
FPSWA_RET fpswa_ret;
FPSWA_BUNDLE bundle;
@@ -594,8 +616,7 @@
case IA64_VEC_PAGE_NOT_PRESENT:
case IA64_VEC_INST_ACCESS_RIGHTS:
- case IA64_VEC_DATA_ACCESS_RIGHTS:
- {
+ case IA64_VEC_DATA_ACCESS_RIGHTS: {
vm_offset_t va;
struct vmspace *vm;
vm_map_t map;
@@ -687,10 +708,10 @@
break;
}
+ case IA64_VEC_BREAK:
+ case IA64_VEC_DEBUG:
case IA64_VEC_SINGLE_STEP_TRAP:
- case IA64_VEC_DEBUG:
- case IA64_VEC_TAKEN_BRANCH_TRAP:
- case IA64_VEC_BREAK:
+ case IA64_VEC_TAKEN_BRANCH_TRAP: {
/*
* These are always fatal in kernel, and should never happen.
*/
@@ -711,26 +732,28 @@
}
i = SIGTRAP;
break;
+ }
- case IA64_VEC_GENERAL_EXCEPTION:
+ case IA64_VEC_GENERAL_EXCEPTION: {
if (user) {
ucode = vector;
i = SIGILL;
break;
}
goto dopanic;
+ }
case IA64_VEC_UNSUPP_DATA_REFERENCE:
- case IA64_VEC_LOWER_PRIVILEGE_TRANSFER:
+ case IA64_VEC_LOWER_PRIVILEGE_TRANSFER: {
if (user) {
ucode = vector;
i = SIGBUS;
break;
}
goto dopanic;
+ }
- case IA64_VEC_IA32_EXCEPTION:
- {
+ case IA64_VEC_IA32_EXCEPTION: {
u_int64_t isr = framep->tf_special.isr;
switch ((isr >> 16) & 0xffff) {
@@ -787,7 +810,7 @@
break;
}
- case IA64_VEC_IA32_INTERRUPT:
+ case IA64_VEC_IA32_INTERRUPT: {
/*
* INT n instruction - probably a syscall.
*/
@@ -799,20 +822,24 @@
i = SIGILL;
break;
}
+ }
- case IA64_VEC_IA32_INTERCEPT:
+ case IA64_VEC_IA32_INTERCEPT: {
/*
* Maybe need to emulate ia32 instruction.
*/
goto dopanic;
+ }
default:
goto dopanic;
}
if (print_usertrap)
- printtrap(vector, imm, framep, 1, user);
+ printtrap(vector, framep, 1, user);
+
trapsignal(td, i, ucode);
+
out:
if (user) {
userret(td, framep, sticks);
@@ -820,45 +847,80 @@
#ifdef DIAGNOSTIC
cred_free_thread(td);
#endif
+ do_ast(framep);
}
return;
dopanic:
- printtrap(vector, imm, framep, 1, user);
-
- /* XXX dump registers */
-
+ printtrap(vector, framep, 1, user);
#ifdef DDB
kdb_trap(vector, framep);
#endif
+ panic("trap");
+}
- panic("trap");
+
+/*
+ * Handle break instruction based system calls.
+ */
+void
+break_syscall(struct trapframe *tf)
+{
+ uint64_t *bsp, *tfp;
+ uint64_t iip, psr;
+ int error, nargs;
+
+ /* Save address of break instruction. */
+ iip = tf->tf_special.iip;
+ psr = tf->tf_special.psr;
+
+ /* Advance to the next instruction. */
+ tf->tf_special.psr += IA64_PSR_RI_1;
+ if ((tf->tf_special.psr & IA64_PSR_RI) > IA64_PSR_RI_2) {
+ tf->tf_special.iip += 16;
+ tf->tf_special.psr &= ~IA64_PSR_RI;
+ }
+
+ /*
+ * Copy the arguments on the register stack into the trapframe
+ * to avoid having interleaved NaT collections.
+ */
+ tfp = &tf->tf_scratch.gr16;
+ nargs = tf->tf_special.cfm & 0x7f;
+ bsp = (uint64_t*)(curthread->td_kstack + tf->tf_special.ndirty);
+ bsp -= (((uintptr_t)bsp & 0x1ff) < 64) ? (nargs + 1): nargs;
+ while (nargs--) {
+ *tfp++ = *bsp++;
+ if (((uintptr_t)bsp & 0x1ff) == 0x1e8)
+ bsp++;
+ }
+ error = syscall(tf->tf_scratch.gr15, &tf->tf_scratch.gr16, tf);
+ if (error == ERESTART) {
+ tf->tf_special.iip = iip;
+ tf->tf_special.psr = psr;
+ }
+
+ do_ast(tf);
}
/*
* Process a system call.
*
- * System calls are strange beasts. They are passed the syscall number
- * in r15, and the arguments in the registers (as normal). They return
- * an error flag in r10 (if r10 != 0 on return, the syscall had an error),
- * and the return value (if any) in r8 and r9.
- *
- * The assembly stub takes care of moving the call number into a register
- * we can get to, and moves all of the argument registers into a stack
- * buffer. On return, it restores r8-r10 from the frame before
- * returning to the user process.
+ * See syscall.s for details as to how we get here. In order to support
+ * the ERESTART case, we return the error to our caller. They deal with
+ * the hairy details.
*/
-void
+int
syscall(int code, u_int64_t *args, struct trapframe *framep)
{
struct sysent *callp;
+ struct proc *p;
struct thread *td;
- struct proc *p;
- int error = 0;
- u_int64_t oldip, oldri;
+ int error;
u_int sticks;
- cnt.v_syscall++;
+ atomic_add_int(&cnt.v_syscall, 1);
+
td = curthread;
p = td->td_proc;
@@ -866,24 +928,8 @@
sticks = td->td_sticks;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
-
- /*
- * Skip past the break instruction. Remember old address in case
- * we have to restart.
- */
- oldip = framep->tf_special.iip;
- oldri = framep->tf_special.psr & IA64_PSR_RI;
- framep->tf_special.psr += IA64_PSR_RI_1;
- if ((framep->tf_special.psr & IA64_PSR_RI) > IA64_PSR_RI_2) {
- framep->tf_special.psr &= ~IA64_PSR_RI;
- framep->tf_special.iip += 16;
- }
-
if (p->p_flag & P_THREADED)
thread_user_enter(p, td);
-#ifdef DIAGNOSTIC
- ia64_fpstate_check(td);
-#endif
if (p->p_sysent->sv_prepsyscall) {
/* (*p->p_sysent->sv_prepsyscall)(framep, args, &code, ¶ms); */
@@ -919,14 +965,13 @@
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, (callp->sy_narg & SYF_ARGMASK), args);
#endif
- if (error == 0) {
- td->td_retval[0] = 0;
- td->td_retval[1] = 0;
+
+ td->td_retval[0] = 0;
+ td->td_retval[1] = 0;
- STOPEVENT(p, S_SCE, (callp->sy_narg & SYF_ARGMASK));
+ STOPEVENT(p, S_SCE, (callp->sy_narg & SYF_ARGMASK));
- error = (*callp->sy_call)(td, args);
- }
+ error = (*callp->sy_call)(td, args);
switch (error) {
case 0:
@@ -935,16 +980,13 @@
framep->tf_scratch.gr10 = 0;
break;
case ERESTART:
- framep->tf_special.iip = oldip;
- framep->tf_special.psr =
- (framep->tf_special.psr & ~IA64_PSR_RI) | oldri;
break;
case EJUSTRETURN:
break;
default:
if (p->p_sysent->sv_errsize) {
if (error >= p->p_sysent->sv_errsize)
- error = -1; /* XXX */
+ error = -1; /* XXX */
else
error = p->p_sysent->sv_errtbl[error];
}
@@ -965,6 +1007,7 @@
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(code, error, td->td_retval[0]);
#endif
+
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
@@ -975,10 +1018,13 @@
#ifdef DIAGNOSTIC
cred_free_thread(td);
#endif
+
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
syscallnames[code]);
mtx_assert(&sched_lock, MA_NOTOWNED);
mtx_assert(&Giant, MA_NOTOWNED);
+
+ return (error);
}
#include <i386/include/psl.h>
==== //depot/projects/ia64_epc/sys/ia64/include/cpu.h#6 (text+ko) ====
@@ -104,12 +104,11 @@
extern struct rpb *hwrpb;
extern volatile int mc_expected, mc_received;
-int badaddr (void *, size_t);
+int badaddr(void *, size_t);
int badaddr_read(void *, size_t, void *);
u_int64_t console_restart(u_int64_t, u_int64_t, u_int64_t);
-void do_sir(void);
+void do_ast(struct trapframe *);
void dumpconf(void);
-void exception_restore(void); /* MAGIC */
void frametoreg(struct trapframe *, struct reg *);
long fswintrberr(void); /* MAGIC */
int ia64_highfp_drop(struct thread *);
@@ -119,16 +118,16 @@
int ia64_pa_access(u_long);
void init_prom_interface(struct rpb*);
void interrupt(u_int64_t, struct trapframe *);
-void machine_check
- (unsigned long, struct trapframe *, unsigned long, unsigned long);
+void machine_check(unsigned long, struct trapframe *, unsigned long,
+ unsigned long);
u_int64_t hwrpb_checksum(void);
void hwrpb_restart_setup(void);
void regdump(struct trapframe *);
void regtoframe(struct reg *, struct trapframe *);
void set_iointr(void (*)(void *, unsigned long));
void fork_trampoline(void); /* MAGIC */
-void syscall(int, u_int64_t *, struct trapframe *);
-void trap(int vector, int imm, struct trapframe *framep);
+int syscall(int, u_int64_t *, struct trapframe *);
+void trap(int vector, struct trapframe *framep);
void ia64_probe_sapics(void);
int ia64_count_cpus(void);
void map_gateway_page(void);
More information about the p4-projects
mailing list