2 * Copyright (c) 2003 Marcel Moolenaar
3 * Copyright (c) 2001 Doug Rabson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
34 #include <sys/sysctl.h>
36 #include <vm/vm_extern.h>
37 #include <machine/frame.h>
38 #include <machine/md_var.h>
39 #include <ia64/disasm/disasm.h>
41 static int ia64_unaligned_print = 0;
42 SYSCTL_INT(_debug, OID_AUTO, unaligned_print, CTLFLAG_RW,
43 &ia64_unaligned_print, 0, "warn about unaligned accesses");
45 static int ia64_unaligned_test = 0;
46 SYSCTL_INT(_debug, OID_AUTO, unaligned_test, CTLFLAG_RW,
47 &ia64_unaligned_test, 0, "test emulation when PSR.ac is set");
50 fpreg_ptr(mcontext_t *mc, int fr)
54 if (fr <= 1 || fr >= 128)
57 p = &mc->mc_high_fp.fr32;
59 } else if (fr >= 16) {
60 p = &mc->mc_preserved_fp.fr16;
63 p = &mc->mc_scratch_fp.fr6;
66 p = &mc->mc_preserved_fp.fr2;
69 return ((void*)(p + fr));
73 greg_ptr(mcontext_t *mc, int gr)
78 if (gr <= 0 || gr >= 32 + (mc->mc_special.cfm & 0x7f))
81 nslots = IA64_CFM_SOF(mc->mc_special.cfm) - gr + 32;
82 p = (void *)ia64_bsp_adjust(mc->mc_special.bspstore, -nslots);
84 } else if (gr >= 14) {
85 p = &mc->mc_scratch.gr14;
87 } else if (gr == 13) {
88 p = &mc->mc_special.tp;
90 } else if (gr == 12) {
91 p = &mc->mc_special.sp;
94 p = &mc->mc_scratch.gr8;
97 p = &mc->mc_preserved.gr4;
100 p = &mc->mc_scratch.gr2;
103 p = &mc->mc_special.gp;
106 return ((void*)(p + gr));
110 rdreg(uint64_t *addr)
112 if ((uintptr_t)addr < VM_MAX_ADDRESS)
113 return (fuword(addr));
118 wrreg(uint64_t *addr, uint64_t val)
120 if ((uintptr_t)addr < VM_MAX_ADDRESS)
127 fixup(struct asm_inst *i, mcontext_t *mc, uint64_t va)
140 copyin((void*)va, (void*)&buf.i, 2);
141 reg = greg_ptr(mc, (int)i->i_oper[1].o_value);
144 wrreg(reg, buf.i & 0xffffU);
147 copyin((void*)va, (void*)&buf.i, 4);
148 reg = greg_ptr(mc, (int)i->i_oper[1].o_value);
151 wrreg(reg, buf.i & 0xffffffffU);
154 copyin((void*)va, (void*)&buf.i, 8);
155 reg = greg_ptr(mc, (int)i->i_oper[1].o_value);
161 copyin((void*)va, (void*)&buf.d, sizeof(buf.d));
162 reg = fpreg_ptr(mc, (int)i->i_oper[1].o_value);
165 __asm("ldfd f6=%1;; stf.spill %0=f6" : "=m"(*(double *)reg) :
169 copyin((void*)va, (void*)&buf.e, sizeof(buf.e));
170 reg = fpreg_ptr(mc, (int)i->i_oper[1].o_value);
173 __asm("ldfe f6=%1;; stf.spill %0=f6" :
174 "=m"(*(long double *)reg) : "m"(buf.e) : "f6");
177 copyin((void*)va, (void*)&buf.s, sizeof(buf.s));
178 reg = fpreg_ptr(mc, (int)i->i_oper[1].o_value);
181 __asm("ldfs f6=%1;; stf.spill %0=f6" : "=m"(*(float *)reg) :
185 reg = greg_ptr(mc, (int)i->i_oper[2].o_value);
189 copyout((void*)&buf.i, (void*)va, 2);
192 reg = greg_ptr(mc, (int)i->i_oper[2].o_value);
196 copyout((void*)&buf.i, (void*)va, 4);
199 reg = greg_ptr(mc, (int)i->i_oper[2].o_value);
203 copyout((void*)&buf.i, (void*)va, 8);
206 reg = fpreg_ptr(mc, (int)i->i_oper[2].o_value);
209 __asm("ldf.fill f6=%1;; stfd %0=f6" : "=m"(buf.d) :
210 "m"(*(double *)reg) : "f6");
211 copyout((void*)&buf.d, (void*)va, sizeof(buf.d));
214 reg = fpreg_ptr(mc, (int)i->i_oper[2].o_value);
217 __asm("ldf.fill f6=%1;; stfe %0=f6" : "=m"(buf.e) :
218 "m"(*(long double *)reg) : "f6");
219 copyout((void*)&buf.e, (void*)va, sizeof(buf.e));
222 reg = fpreg_ptr(mc, (int)i->i_oper[2].o_value);
225 __asm("ldf.fill f6=%1;; stfs %0=f6" : "=m"(buf.s) :
226 "m"(*(float *)reg) : "f6");
227 copyout((void*)&buf.s, (void*)va, sizeof(buf.s));
233 /* Handle post-increment. */
234 if (i->i_oper[3].o_type == ASM_OPER_GREG) {
235 reg = greg_ptr(mc, (int)i->i_oper[3].o_value);
238 postinc = rdreg(reg);
240 postinc = (i->i_oper[3].o_type == ASM_OPER_IMM)
241 ? i->i_oper[3].o_value : 0;
243 if (i->i_oper[1].o_type == ASM_OPER_MEM)
244 reg = greg_ptr(mc, (int)i->i_oper[1].o_value);
246 reg = greg_ptr(mc, (int)i->i_oper[2].o_value);
249 postinc += rdreg(reg);
256 unaligned_fixup(struct trapframe *tf, struct thread *td)
259 struct asm_bundle bundle;
262 slot = ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_0) ? 0 :
263 ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_1) ? 1 : 2;
265 if (ia64_unaligned_print) {
266 uprintf("pid %d (%s): unaligned access: va=0x%lx, pc=0x%lx\n",
267 td->td_proc->p_pid, td->td_proc->p_comm,
268 tf->tf_special.ifa, tf->tf_special.iip + slot);
272 * If PSR.ac is set, the process wants to be signalled about mis-
273 * aligned loads and stores. Send it a SIGBUS. In order for us to
274 * test the emulation of misaligned loads and stores, we have a
275 * sysctl that tells us that we must emulate the load or store,
276 * instead of sending the signal. We need the sysctl because if
277 * PSR.ac is not set, the CPU may (and likely will) deal with the
278 * misaligned load or store itself. As such, we won't get the
281 if ((tf->tf_special.psr & IA64_PSR_AC) && !ia64_unaligned_test)
284 if (!asm_decode(tf->tf_special.iip, &bundle))
287 get_mcontext(td, &context, 0);
289 error = fixup(bundle.b_inst + slot, &context, tf->tf_special.ifa);
290 if (error == ENOENT) {
291 printf("unhandled misaligned memory access:\n\t");
292 asm_print_inst(&bundle, slot, tf->tf_special.iip);
294 } else if (error != 0)
297 set_mcontext(td, &context);
299 /* Advance to the next instruction. */
301 tf->tf_special.psr &= ~IA64_PSR_RI;
302 tf->tf_special.iip += 16;
304 tf->tf_special.psr += IA64_PSR_RI_1;