Altivec registers in ppc64 u/sigcontext
Benjamin Herrenschmidt
benh at kernel.crashing.org
Wed Nov 26 18:59:42 EST 2003
I have a problem implementing the proper altivec stuffs on the signal
frame and context frames (based on current ameslab-2.5). I've already
added the context switch code so I can actually run altivec applications
on the g5/ppc64, and I'm now adding the signal part. I'll then implement
a sys_swapcontext syscall like ppc32 so that glibc can call this instead
of re-implementing it all, which should be more efficient.
The way the frame is defined currently is:
struct sigcontext {
unsigned long _unused[4];
int signal;
int _pad0;
unsigned long handler;
unsigned long oldmask;
struct pt_regs *regs;
elf_gregset_t gp_regs;
elf_fpregset_t fp_regs;
/*
* To maintain compatibility with current implementations the sigcontext is
* extended by appending a pointer (v_regs) to a quadword type (elf_vrreg_t)
* followed by an unstructured (vmx_reserve) field of 69 doublewords. This
* allows the array of vector registers to be quadword aligned independent of
* the alignment of the containing sigcontext or ucontext. It is the
* responsibility of the code setting the sigcontext to set this pointer to
* either NULL (if this processor does not support the VMX feature) or the
* address of the first quadword within the allocated (vmx_reserve) area.
*
* The pointer (v_regs) of vector type (elf_vrreg_t) is type compatible with
* an array of 34 quadword entries (elf_vrregset_t). The entries with
* indexes 0-31 contain the corresponding vector registers. The entry with
* index 32 contains the vscr as the last word (offset 12) within the
* quadword. This allows the vscr to be stored as either a quadword (since
* it must be copied via a vector register to/from storage) or as a word.
* The entry with index 33 contains the vrsave as the first word (offset 0)
* within the quadword.
*/
elf_vrreg_t *v_regs;
long vmx_reserve[ELF_NVRREG+ELF_NVRREG+1];
};
The problem is how does userland here (or swapcontext when getting a
sigcontext from userland, or even sigreturn) knows about the validity of
the vector registers in there ?
This isn't a _simple_ problem unfortunately, as there is a distinction
between having valid saved vector regs and a valid VRSAVE. The later is
_always_ saved and restored when the kernel has CONFIG_ALTIVEC so that
it can really be used as an indication of the current altivec usage of a
task (provided we even decide to _enforce_ that in the ABI and I'm all
for doing it) while the actual vector regs may or may not be depending
on an internal kernel flag indicating if the task ever used altivec.
What ppc32 does is that vrsave is always saved and we set MSR_VEC in the
context pt_regs' MSR copy whenever there's an altivec context
(regardless of the actual state of MSR_VEC in the task at the moment the
signal is issued).
This is fine... except for a small bug: we do that only with
CONFIG_ALTIVEC, which means that a kernel lacking that option will not
copy vrsave (which doesn't exist in the task struct) at all, but will
also not write a 0 there where it should do obviously.
So the problem only really happens if glibc ever _use_ that value. If
it's only ever the kernel manipulating this context structure, then a gi
en kernel will always have CONFIG_ALTIVEC either set or not set between
2 calls using the sigcontext. That would work provided glibc uses only
the kernel calls and doesn't do set/get_context by itself based on a
signal context.
With ppc64, I'm was tempted to use the v_regs pointer as an indication
that there is an altivec context, but that fails because of the need to
also have VRSAVE even when there's no altivec context.
So I'm setting up v_regs all the time when CONFIG_ALTIVEC is set, and
will set MSR_VEC like ppc32 when there's a valid context, while VRSAVE
will always be backed up/restored.
I'm also clearing v_regs when CONFIG_ALTIVEC is not set, so that at
least, this will be a reliable way in the future to know not to try to
tap VRSAVE from glibc if it ever want to do it. Earlier glibc's will
have a problem though...
However, if I add the sys_swapcontext syscall at the same time, then,
we are mostly fine, provided we consider that glibc will always rely on
the kernel for "altivec enabled" 64 bits environement and use it's own
implementation only for earlier kernels that don't support altivec at
all.
Any thoughs ?
Ben.
** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/
More information about the Linuxppc64-dev
mailing list