From eff1369cab8fc04802c43231ec8ac2445d0a29da Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 21 Jul 2011 00:48:35 +0200 Subject: [PATCH] print kernel stacktrace for exceptions in kernel fpu alignment check feature, checksum feature --- common/include/arch/i386/archtypes.h | 1 + kernel/Makefile | 2 +- kernel/arch/i386/arch_system.c | 40 ++++++++++++++++++++++++--- kernel/arch/i386/include/arch_proto.h | 8 +++--- kernel/arch/i386/sconst.h | 2 +- kernel/debug.h | 2 ++ kernel/proc.c | 4 +++ kernel/proto.h | 3 ++ kernel/system/do_fork.c | 5 +++- kernel/system/do_mcontext.c | 1 + kernel/system/do_sigreturn.c | 2 ++ 11 files changed, 59 insertions(+), 11 deletions(-) diff --git a/common/include/arch/i386/archtypes.h b/common/include/arch/i386/archtypes.h index fb424c977..e16f77801 100644 --- a/common/include/arch/i386/archtypes.h +++ b/common/include/arch/i386/archtypes.h @@ -37,6 +37,7 @@ struct fpu_state_s { /* fpu_image includes 512 bytes of image itself and * additional 15 bytes required for manual 16-byte alignment. */ char fpu_image[527]; + u32_t checksum; }; #define INMEMORY(p) (!p->p_seg.p_cr3 || get_cpulocal_var(ptproc) == p) diff --git a/kernel/Makefile b/kernel/Makefile index deb33e353..bbc4cb6cc 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -14,7 +14,7 @@ SRCS += smp.c .endif DPADD+= ${LIBTIMERS} ${LIBSYS} ${LIBEXEC} -LDADD+= -ltimers -lsys -lexec +LDADD+= -ltimers -lsys -lexec -lz CFLAGS += -D__kernel__ diff --git a/kernel/arch/i386/arch_system.c b/kernel/arch/i386/arch_system.c index 2c32b82c6..a7f230573 100644 --- a/kernel/arch/i386/arch_system.c +++ b/kernel/arch/i386/arch_system.c @@ -58,6 +58,27 @@ FORWARD _PROTOTYPE( void ser_dump_proc_cpu, (void)); FORWARD _PROTOTYPE( void ser_init, (void)); #endif +PRIVATE u32_t fpusum(struct proc *p) +{ + void *save_area = p->p_fpu_state.fpu_save_area_p; + return crc32(0, save_area, FPU_XFP_SIZE); +} + +PUBLIC void fpu_makechecksum(struct proc *p) +{ + p->p_fpu_state.checksum = fpusum(p); +} + +PUBLIC void fpu_verifychecksum(struct proc *p) +{ + static int n; + n++; + if(p->p_fpu_state.checksum != fpusum(p)) { + printf("%d / %s fpu state broken!", p->p_endpoint, p->p_name); + util_stacktrace(); + } +} + PUBLIC __dead void arch_monitor(void) { monitor(); @@ -252,16 +273,23 @@ PUBLIC void fpu_init(void) PUBLIC void save_local_fpu(struct proc *pr) { + static int n; + phys_bytes save_area = (phys_bytes) pr->p_fpu_state.fpu_save_area_p; if(!is_fpu()) return; + /* save area must be 16-byte aligned */ + assert(!(save_area % FPUALIGN)); + /* Save changed FPU context. */ if(osfxsr_feature) { - fxsave(pr->p_fpu_state.fpu_save_area_p); + fxsave(save_area); fninit(); } else { - fnsave(pr->p_fpu_state.fpu_save_area_p); + fnsave(save_area); } + + fpu_makechecksum(pr); } PUBLIC void save_fpu(struct proc *pr) @@ -304,10 +332,14 @@ PUBLIC void restore_fpu(struct proc *pr) fninit(); pr->p_misc_flags |= MF_FPU_INITIALIZED; } else { + phys_bytes save_area = (phys_bytes) pr->p_fpu_state.fpu_save_area_p; + /* save area must be 16-byte aligned */ + assert(!(save_area % FPUALIGN)); + fpu_verifychecksum(pr); if(osfxsr_feature) { - fxrstor(pr->p_fpu_state.fpu_save_area_p); + fxrstor(save_area); } else { - frstor(pr->p_fpu_state.fpu_save_area_p); + frstor(save_area); } } } diff --git a/kernel/arch/i386/include/arch_proto.h b/kernel/arch/i386/include/arch_proto.h index af605c6ed..fb5666123 100644 --- a/kernel/arch/i386/include/arch_proto.h +++ b/kernel/arch/i386/include/arch_proto.h @@ -95,10 +95,10 @@ _PROTOTYPE( void ia32_msr_read, (u32_t reg, u32_t * hi, u32_t * lo) ); _PROTOTYPE( void ia32_msr_write, (u32_t reg, u32_t hi, u32_t lo) ); _PROTOTYPE( void fninit, (void)); _PROTOTYPE( void clts, (void)); -_PROTOTYPE( void fxsave, (void *)); -_PROTOTYPE( void fnsave, (void *)); -_PROTOTYPE( void fxrstor, (void *)); -_PROTOTYPE( void frstor, (void *)); +_PROTOTYPE( void fxsave, (vir_bytes)); +_PROTOTYPE( void fnsave, (vir_bytes)); +_PROTOTYPE( void fxrstor, (vir_bytes)); +_PROTOTYPE( void frstor, (vir_bytes)); _PROTOTYPE( unsigned short fnstsw, (void)); _PROTOTYPE( void fnstcw, (unsigned short* cw)); diff --git a/kernel/arch/i386/sconst.h b/kernel/arch/i386/sconst.h index 5f2bd6e09..d48640b6d 100644 --- a/kernel/arch/i386/sconst.h +++ b/kernel/arch/i386/sconst.h @@ -28,7 +28,7 @@ SSREG = SPREG+W P_STACKTOP = SSREG+W FP_SAVE_AREA_P = P_STACKTOP - P_LDT_SEL = FP_SAVE_AREA_P + 532 + P_LDT_SEL = FP_SAVE_AREA_P + 536 P_CR3 = P_LDT_SEL+W P_CR3_V = P_CR3+4 P_LDT = P_CR3_V+W diff --git a/kernel/debug.h b/kernel/debug.h index ce808f31a..fc422e62c 100644 --- a/kernel/debug.h +++ b/kernel/debug.h @@ -37,6 +37,8 @@ */ #define DEBUG_RACE 0 +#define DEBUG_FPUCHECK 1 + /* DEBUG_DUMPIPC dumps all IPC to serial; due to the amount of logging it is * strongly recommended to set "ctty 0" in the boot monitor and run inside a * virtual machine if you enable this; on the hardware it would take forever diff --git a/kernel/proc.c b/kernel/proc.c index b8cf5cf99..820bda02d 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -257,6 +257,10 @@ PUBLIC void switch_to_user(void) int tlb_must_refresh = 0; #endif + char buf[100]; + u32_t c; + c = crc32(0, buf, 100); + p = get_cpulocal_var(proc_ptr); /* * if the current process is still runnable check the misc flags and let diff --git a/kernel/proto.h b/kernel/proto.h index 3aae90a34..9d1090d36 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -223,6 +223,9 @@ _PROTOTYPE( int copy_msg_to_user, (struct proc * p, message * src, _PROTOTYPE(void switch_address_space, (struct proc * p)); _PROTOTYPE(void release_address_space, (struct proc *pr)); +_PROTOTYPE(void fpu_makechecksum, (struct proc *p)); +_PROTOTYPE(void fpu_verifychecksum, (struct proc *p)); + _PROTOTYPE(void enable_fpu_exception, (void)); _PROTOTYPE(void disable_fpu_exception, (void)); _PROTOTYPE(void release_fpu, (struct proc * p)); diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index 0b6236196..f2576843b 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -65,10 +65,13 @@ PUBLIC int do_fork(struct proc * caller, message * m_ptr) #if (_MINIX_CHIP == _CHIP_INTEL) rpc->p_seg.p_ldt_sel = old_ldt_sel; /* restore descriptors */ rpc->p_fpu_state.fpu_save_area_p = old_fpu_save_area_p; - if(proc_used_fpu(rpp)) + if(proc_used_fpu(rpp)) { + fpu_verifychecksum(rpp); memcpy(rpc->p_fpu_state.fpu_save_area_p, rpp->p_fpu_state.fpu_save_area_p, FPU_XFP_SIZE); + fpu_verifychecksum(rpc); + } #endif if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */ gen = 1; /* generation number wraparound */ diff --git a/kernel/system/do_mcontext.c b/kernel/system/do_mcontext.c index c105acf5e..4bfc8ff94 100644 --- a/kernel/system/do_mcontext.c +++ b/kernel/system/do_mcontext.c @@ -86,6 +86,7 @@ PUBLIC int do_setmcontext(struct proc * caller, message * m_ptr) rp->p_misc_flags |= MF_FPU_INITIALIZED; memcpy(rp->p_fpu_state.fpu_save_area_p, &(mc.mc_fpu_state), FPU_XFP_SIZE); + fpu_makechecksum(rp); } else rp->p_misc_flags &= ~MF_FPU_INITIALIZED; /* force reloading FPU in either case */ diff --git a/kernel/system/do_sigreturn.c b/kernel/system/do_sigreturn.c index 592c8e2a2..e8a5232ba 100644 --- a/kernel/system/do_sigreturn.c +++ b/kernel/system/do_sigreturn.c @@ -56,8 +56,10 @@ PUBLIC int do_sigreturn(struct proc * caller, message * m_ptr) #if (_MINIX_CHIP == _CHIP_INTEL) if(sc.sc_flags & MF_FPU_INITIALIZED) { + fpu_verifychecksum(rp); memcpy(rp->p_fpu_state.fpu_save_area_p, &sc.sc_fpu_state, FPU_XFP_SIZE); + fpu_makechecksum(rp); rp->p_misc_flags |= MF_FPU_INITIALIZED; /* Restore math usage flag. */ /* force reloading FPU */ release_fpu(rp);