1 /* $NetBSD: process_machdep.c,v 1.18 2010/12/20 00:25:24 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This file may seem a bit stylized, but that so that it's easier to port. 34 * Functions to be implemented here are: 35 * 36 * process_read_regs(proc, regs) 37 * Get the current user-visible register set from the process 38 * and copy it into the regs structure (<machine/reg.h>). 39 * The process is stopped at the time read_regs is called. 40 * 41 * process_write_regs(proc, regs) 42 * Update the current register set from the passed in regs 43 * structure. Take care to avoid clobbering special CPU 44 * registers or privileged bits in the PSL. 45 * The process is stopped at the time write_regs is called. 46 * 47 * process_sstep(proc) 48 * Arrange for the process to trap after executing a single instruction. 49 * 50 * process_set_pc(proc) 51 * Set the process's program counter. 52 */ 53 54 55 #include <sys/cdefs.h> 56 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.18 2010/12/20 00:25:24 matt Exp $"); 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/time.h> 61 #include <sys/kernel.h> 62 #include <sys/proc.h> 63 #include <sys/vnode.h> 64 #include <sys/ptrace.h> 65 66 #include <machine/psl.h> 67 #include <machine/reg.h> 68 #include <machine/segments.h> 69 #include <machine/fpu.h> 70 71 static inline struct trapframe *process_frame(struct lwp *); 72 static inline struct fxsave64 *process_fpframe(struct lwp *); 73 #if 0 74 static inline int verr_gdt(struct pmap *, int sel); 75 static inline int verr_ldt(struct pmap *, int sel); 76 #endif 77 78 static inline struct trapframe * 79 process_frame(struct lwp *l) 80 { 81 82 return (l->l_md.md_regs); 83 } 84 85 static inline struct fxsave64 * 86 process_fpframe(struct lwp *l) 87 { 88 struct pcb *pcb = lwp_getpcb(l); 89 90 return &pcb->pcb_savefpu.fp_fxsave; 91 } 92 93 int 94 process_read_regs(struct lwp *l, struct reg *regs) 95 { 96 struct trapframe *tf = process_frame(l); 97 98 #define copy_to_reg(reg, REG, idx) regs->regs[_REG_##REG] = tf->tf_##reg; 99 _FRAME_GREG(copy_to_reg) 100 #undef copy_to_reg 101 102 return (0); 103 } 104 105 int 106 process_read_fpregs(struct lwp *l, struct fpreg *regs) 107 { 108 struct fxsave64 *frame = process_fpframe(l); 109 110 if (l->l_md.md_flags & MDP_USEDFPU) { 111 fpusave_lwp(l, true); 112 } else { 113 uint16_t cw; 114 uint32_t mxcsr, mxcsr_mask; 115 116 /* 117 * Fake a FNINIT. 118 * The initial control word was already set by setregs(), so 119 * save it temporarily. 120 */ 121 cw = frame->fx_fcw; 122 mxcsr = frame->fx_mxcsr; 123 mxcsr_mask = frame->fx_mxcsr_mask; 124 memset(frame, 0, sizeof(*regs)); 125 frame->fx_fcw = cw; 126 frame->fx_fsw = 0x0000; 127 frame->fx_ftw = 0xff; 128 frame->fx_mxcsr = mxcsr; 129 frame->fx_mxcsr_mask = mxcsr_mask; 130 l->l_md.md_flags |= MDP_USEDFPU; 131 } 132 133 memcpy(®s->fxstate, frame, sizeof(*regs)); 134 return (0); 135 } 136 137 int 138 process_write_regs(struct lwp *l, const struct reg *regp) 139 { 140 struct trapframe *tf = process_frame(l); 141 int error; 142 const long *regs = regp->regs; 143 144 /* 145 * Check for security violations. 146 * Note that struct regs is compatible with 147 * the __gregs array in mcontext_t. 148 */ 149 error = check_mcontext(l, (const mcontext_t *)regs, tf); 150 if (error != 0) 151 return error; 152 153 #define copy_to_frame(reg, REG, idx) tf->tf_##reg = regs[_REG_##REG]; 154 _FRAME_GREG(copy_to_frame) 155 #undef copy_to_frame 156 157 return (0); 158 } 159 160 int 161 process_write_fpregs(struct lwp *l, const struct fpreg *regs) 162 { 163 struct fxsave64 *frame = process_fpframe(l); 164 165 if (l->l_md.md_flags & MDP_USEDFPU) { 166 fpusave_lwp(l, false); 167 } else { 168 l->l_md.md_flags |= MDP_USEDFPU; 169 } 170 171 memcpy(frame, ®s->fxstate, sizeof(*regs)); 172 return (0); 173 } 174 175 int 176 process_sstep(struct lwp *l, int sstep) 177 { 178 struct trapframe *tf = process_frame(l); 179 180 if (sstep) 181 tf->tf_rflags |= PSL_T; 182 else 183 tf->tf_rflags &= ~PSL_T; 184 185 return (0); 186 } 187 188 int 189 process_set_pc(struct lwp *l, void *addr) 190 { 191 struct trapframe *tf = process_frame(l); 192 193 if ((uint64_t)addr > VM_MAXUSER_ADDRESS) 194 return EINVAL; 195 tf->tf_rip = (uint64_t)addr; 196 197 return (0); 198 } 199