diff options
author | marcel <marcel@FreeBSD.org> | 2003-11-06 04:26:40 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2003-11-06 04:26:40 +0000 |
commit | 636849aec5c4eb6b782ab6ad5f7623b8bea34680 (patch) | |
tree | af2c54a9c2dae1c2eb62a0a3a9675345e6fc3998 /sys/ia64 | |
parent | 96ae8eeca766dcb5847ec19ab6a191da8ae2387d (diff) | |
download | FreeBSD-src-636849aec5c4eb6b782ab6ad5f7623b8bea34680.zip FreeBSD-src-636849aec5c4eb6b782ab6ad5f7623b8bea34680.tar.gz |
Add support for unaligned ld2, st2, st4 and st8. While here, make
sure we handle stacked registers properly by taking into account
that:
1. bspstore points after the frame (due to cover),
2. we need to adjust for intermediate NaT collections.
Diffstat (limited to 'sys/ia64')
-rw-r--r-- | sys/ia64/ia64/unaligned.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/sys/ia64/ia64/unaligned.c b/sys/ia64/ia64/unaligned.c index bcbb638..0b04f38 100644 --- a/sys/ia64/ia64/unaligned.c +++ b/sys/ia64/ia64/unaligned.c @@ -74,12 +74,16 @@ static void * greg_ptr(mcontext_t *mc, int gr) { uint64_t *p; + int bias, nslots; if (gr <= 0 || gr >= 32 + (mc->mc_special.cfm & 0x7f)) return (NULL); if (gr >= 32) { p = (void*)mc->mc_special.bspstore; - p += gr - 32; + nslots = (mc->mc_special.cfm & 0x7f) - gr + 32; + bias = (0x1f8 - (mc->mc_special.bspstore & 0x1f8)) >> 3; + nslots += (nslots + bias) / 63; + p -= nslots; gr = 0; } else if (gr >= 14) { p = &mc->mc_scratch.gr14; @@ -134,6 +138,13 @@ fixup(struct asm_inst *i, mcontext_t *mc, uint64_t va) uint64_t postinc; switch (i->i_op) { + case ASM_OP_LD2: + copyin((void*)va, (void*)&buf.i, 2); + reg = greg_ptr(mc, (int)i->i_oper[1].o_value); + if (reg == NULL) + return (EINVAL); + wrreg(reg, buf.i & 0xffffU); + break; case ASM_OP_LD4: copyin((void*)va, (void*)&buf.i, 4); reg = greg_ptr(mc, (int)i->i_oper[1].o_value); @@ -155,6 +166,27 @@ fixup(struct asm_inst *i, mcontext_t *mc, uint64_t va) return (EINVAL); spillfd((void*)&buf.d, reg); break; + case ASM_OP_ST2: + reg = greg_ptr(mc, (int)i->i_oper[2].o_value); + if (reg == NULL) + return (EINVAL); + buf.i = rdreg(reg); + copyout((void*)&buf.i, (void*)va, 2); + break; + case ASM_OP_ST4: + reg = greg_ptr(mc, (int)i->i_oper[2].o_value); + if (reg == NULL) + return (EINVAL); + buf.i = rdreg(reg); + copyout((void*)&buf.i, (void*)va, 4); + break; + case ASM_OP_ST8: + reg = greg_ptr(mc, (int)i->i_oper[2].o_value); + if (reg == NULL) + return (EINVAL); + buf.i = rdreg(reg); + copyout((void*)&buf.i, (void*)va, 8); + break; default: return (ENOENT); } |