Commit 3a810fc8 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.4.0-test2pre9

parent cca405a2
......@@ -18,7 +18,7 @@ export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
pci-dma.o i386_ksyms.o
pci-dma.o i386_ksyms.o i387.o
ifdef CONFIG_PCI
......
......@@ -323,6 +323,11 @@ ENTRY(coprocessor_error)
pushl $ SYMBOL_NAME(do_coprocessor_error)
jmp error_code
ENTRY(simd_coprocessor_error)
pushl $0
pushl $ SYMBOL_NAME(do_simd_coprocessor_error)
jmp error_code
ENTRY(device_not_available)
pushl $-1 # mark this as an int
SAVE_ALL
......@@ -414,11 +419,6 @@ ENTRY(spurious_interrupt_bug)
pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
jmp error_code
ENTRY(xmm_fault)
pushl $0
pushl $ SYMBOL_NAME(do_xmm_fault)
jmp error_code
.data
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
......
......@@ -14,6 +14,7 @@
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
#include <asm/io.h>
......@@ -24,7 +25,6 @@
#include <asm/desc.h>
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(elf_fpregset_t *);
extern spinlock_t rtc_lock;
#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
......@@ -51,6 +51,7 @@ EXPORT_SYMBOL(MCA_bus);
EXPORT_SYMBOL(__verify_write);
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(dump_extended_fpu);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(__io_virt_debug);
......
This diff is collapsed.
......@@ -2,8 +2,9 @@
* linux/arch/i386/kernel/process.c
*
* Copyright (C) 1995 Linus Torvalds
* Pentium III code by Ingo Molnar with changes and support for
* OS exception support by Goutham Rao
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
......@@ -38,6 +39,7 @@
#include <asm/io.h>
#include <asm/ldt.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/desc.h>
#include <asm/mmu_context.h>
#ifdef CONFIG_MATH_EMULATION
......@@ -471,94 +473,6 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
return;
}
#ifdef CONFIG_X86_FXSR
int i387_hard_to_user ( struct _fpstate * user,
struct i387_hard_struct * hard)
{
int i, err = 0;
short *tmp, *tmp2;
long *ltmp1, *ltmp2;
err |= put_user(hard->cwd, &user->cw);
err |= put_user(hard->swd, &user->sw);
err |= put_user(fputag_KNIto387(hard->twd), &user->tag);
err |= put_user(hard->fip, &user->ipoff);
err |= put_user(hard->fcs, &user->cssel);
err |= put_user(hard->fdp, &user->dataoff);
err |= put_user(hard->fds, &user->datasel);
err |= put_user(hard->mxcsr, &user->mxcsr);
tmp = (short *)&user->_st;
tmp2 = (short *)&hard->st_space;
/*
* Transform the two layouts:
* (we do not mix 32-bit access with 16-bit access because
* thats suboptimal on PPros)
*/
for (i = 0; i < 8; i++)
{
err |= put_user(*tmp2, tmp); tmp++; tmp2++;
err |= put_user(*tmp2, tmp); tmp++; tmp2++;
err |= put_user(*tmp2, tmp); tmp++; tmp2++;
err |= put_user(*tmp2, tmp); tmp++; tmp2++;
err |= put_user(*tmp2, tmp); tmp++; tmp2 += 3;
}
ltmp1 = (unsigned long *)&(user->_xmm[0]);
ltmp2 = (unsigned long *)&(hard->xmm_space[0]);
for(i = 0; i < 88; i++)
{
err |= put_user(*ltmp2, ltmp1);
ltmp1++; ltmp2++;
}
return err;
}
int i387_user_to_hard (struct i387_hard_struct * hard,
struct _fpstate * user)
{
int i, err = 0;
short *tmp, *tmp2;
long *ltmp1, *ltmp2;
err |= get_user(hard->cwd, &user->cw);
err |= get_user(hard->swd, &user->sw);
err |= get_user(hard->twd, &user->tag);
hard->twd = fputag_387toKNI(hard->twd);
err |= get_user(hard->fip, &user->ipoff);
err |= get_user(hard->fcs, &user->cssel);
err |= get_user(hard->fdp, &user->dataoff);
err |= get_user(hard->fds, &user->datasel);
err |= get_user(hard->mxcsr, &user->mxcsr);
tmp2 = (short *)&hard->st_space;
tmp = (short *)&user->_st;
for (i = 0; i < 8; i++)
{
err |= get_user(*tmp2, tmp); tmp++; tmp2++;
err |= get_user(*tmp2, tmp); tmp++; tmp2++;
err |= get_user(*tmp2, tmp); tmp++; tmp2++;
err |= get_user(*tmp2, tmp); tmp++; tmp2++;
err |= get_user(*tmp2, tmp); tmp++; tmp2 += 3;
}
ltmp1 = (unsigned long *)(&user->_xmm[0]);
ltmp2 = (unsigned long *)(&hard->xmm_space[0]);
for(i = 0; i < (88); i++)
{
err |= get_user(*ltmp2, ltmp1);
ltmp2++; ltmp1++;
}
return err;
}
#endif
/*
* Save a segment.
*/
......@@ -589,23 +503,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
return 0;
}
/*
* fill in the FPU structure for a core dump.
*/
int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
{
int fpvalid;
struct task_struct *tsk = current;
fpvalid = tsk->used_math;
if (fpvalid) {
unlazy_fpu(tsk);
memcpy(fpu,&tsk->thread.i387.hard,sizeof(*fpu));
}
return fpvalid;
}
/*
* fill in the user structure for a core dump..
*/
......
/* ptrace.c */
/* By Ross Biro 1/23/92 */
/* FXSAVE/FXRSTOR support by Ingo Molnar and modifications by Goutham Rao */
/* edited by Linus Torvalds */
/*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
#include <linux/config.h> /* for CONFIG_MATH_EMULATION */
#include <linux/kernel.h>
......@@ -17,6 +19,7 @@
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/debugreg.h>
/*
......@@ -392,48 +395,62 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
if (!access_ok(VERIFY_WRITE, (unsigned *)data, sizeof(struct user_i387_struct))) {
if (!access_ok(VERIFY_WRITE, (unsigned *)data,
sizeof(struct user_i387_struct))) {
ret = -EIO;
break;
}
ret = 0;
if ( !child->used_math ) {
/* Simulate an empty FPU. */
i387_set_cwd(child->thread.i387.hard, 0x037f);
i387_set_swd(child->thread.i387.hard, 0x0000);
i387_set_twd(child->thread.i387.hard, 0xffff);
}
#ifdef CONFIG_MATH_EMULATION
if ( boot_cpu_data.hard_math ) {
#endif
i387_hard_to_user((struct _fpstate *)data, &child->thread.i387.hard);
#ifdef CONFIG_MATH_EMULATION
} else {
save_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data);
set_fpu_cwd(child, 0x037f);
set_fpu_swd(child, 0x0000);
set_fpu_twd(child, 0xffff);
}
#endif
get_fpregs((struct user_i387_struct *)data, child);
break;
}
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
if (!access_ok(VERIFY_READ, (unsigned *)data, sizeof(struct user_i387_struct))) {
if (!access_ok(VERIFY_READ, (unsigned *)data,
sizeof(struct user_i387_struct))) {
ret = -EIO;
break;
}
child->used_math = 1;
#ifdef CONFIG_MATH_EMULATION
if ( boot_cpu_data.hard_math ) {
#endif
i387_user_to_hard(&child->thread.i387.hard,(struct _fpstate *)data);
#ifdef CONFIG_MATH_EMULATION
} else {
restore_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data);
}
#endif
set_fpregs(child, (struct user_i387_struct *)data);
ret = 0;
break;
}
case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
if (!access_ok(VERIFY_WRITE, (unsigned *)data,
sizeof(struct user_fxsr_struct))) {
ret = -EIO;
break;
}
if ( !child->used_math ) {
/* Simulate an empty FPU. */
set_fpu_cwd(child, 0x037f);
set_fpu_swd(child, 0x0000);
set_fpu_twd(child, 0xffff);
set_fpu_mxcsr(child, 0x1f80);
}
ret = get_fpxregs((struct user_fxsr_struct *)data, child);
break;
}
case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */
if (!access_ok(VERIFY_READ, (unsigned *)data,
sizeof(struct user_fxsr_struct))) {
ret = -EIO;
break;
}
child->used_math = 1;
ret = set_fpxregs(child, (struct user_fxsr_struct *)data);
break;
}
default:
ret = -EIO;
break;
......
......@@ -39,8 +39,10 @@
* Detection for Celeron coppermine, identify_cpu() overhauled,
* and a few other clean ups.
* Dave Jones <dave@powertweak.com>, April 2000
* Pentium-III code by Ingo Molnar and modifications by Goutham Rao
*
* Pentium III FXSR, SSE support
* General FPU state handling cleanups
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
......@@ -784,20 +786,6 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
#endif
#ifdef CONFIG_X86_FXSR
if (boot_cpu_data.x86_capability & X86_FEATURE_FXSR)
{
printk("Enabling extended fast FPU save and restore ... ");
set_in_cr4(X86_CR4_OSFXSR);
printk("done.\n");
}
if (boot_cpu_data.x86_capability & X86_FEATURE_XMM)
{
printk("Enabling KNI unmasked exception support ... ");
set_in_cr4(X86_CR4_OSXMMEXCPT);
printk("done.\n");
}
#endif
}
static int __init get_model_name(struct cpuinfo_x86 *c)
......
......@@ -4,8 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
* Pentium III support by Ingo Molnar, modifications and OS Exception support
* by Goutham Rao
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
*/
#include <linux/config.h>
......@@ -23,6 +22,7 @@
#include <linux/stddef.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
#define DEBUG_SIG 0
......@@ -187,29 +187,6 @@ struct rt_sigframe
char retcode[8];
};
static inline int restore_i387_hard(struct _fpstate *buf)
{
struct task_struct *tsk = current;
clear_fpu(tsk);
return i387_user_to_hard(&tsk->thread.i387.hard, buf);
}
static inline int restore_i387(struct _fpstate *buf)
{
int err;
#ifndef CONFIG_MATH_EMULATION
err = restore_i387_hard(buf);
#else
if (boot_cpu_data.hard_math)
err = restore_i387_hard(buf);
else
err = restore_i387_soft(&current->thread.i387.soft, buf);
#endif
current->used_math = 1;
return err;
}
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax)
{
......@@ -340,35 +317,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
* Set up a signal frame.
*/
static inline int save_i387_hard(struct _fpstate * buf)
{
struct task_struct *tsk = current;
unlazy_fpu(tsk);
tsk->thread.i387.hard.status = tsk->thread.i387.hard.swd;
if (i387_hard_to_user(buf, &tsk->thread.i387.hard))
return -1;
return 1;
}
static int save_i387(struct _fpstate *buf)
{
if (!current->used_math)
return 0;
/* This will cause a "finit" to be triggered by the next
attempted FPU operation by the 'current' process.
*/
current->used_math = 0;
#ifndef CONFIG_MATH_EMULATION
return save_i387_hard(buf);
#else
return boot_cpu_data.hard_math ? save_i387_hard(buf)
: save_i387_soft(&current->thread.i387.soft, buf);
#endif
}
static int
setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate,
struct pt_regs *regs, unsigned long mask)
......
......@@ -2,7 +2,9 @@
* linux/arch/i386/traps.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* FXSAVE/FXRSTOR support by Ingo Molnar, OS exception support by Goutham Rao
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
......@@ -35,6 +37,7 @@
#include <asm/atomic.h>
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/smp.h>
#include <asm/pgalloc.h>
......@@ -152,10 +155,10 @@ asmlinkage void stack_segment(void);
asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
asmlinkage void simd_coprocessor_error(void);
asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void xmm_fault(void);
int kstack_depth_to_print = 24;
......@@ -318,7 +321,6 @@ DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, current, BUS_ADRALN, get_cr2())
DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
DO_VM86_ERROR(19, SIGFPE, "XMM fault", xmm_fault, current)
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
......@@ -584,13 +586,13 @@ void math_error(void *eip)
{
struct task_struct * task;
siginfo_t info;
unsigned short cwd, swd;
/*
* Save the info for the exception handler
* (this will also clear the error)
* Save the info for the exception handler and clear the error.
*/
task = current;
save_fpu(task);
save_init_fpu(task);
task->thread.trap_no = 16;
task->thread.error_code = 0;
info.si_signo = SIGFPE;
......@@ -607,9 +609,9 @@ void math_error(void *eip)
* and it will suffer the consequences since we won't be able to
* fully reproduce the context of the exception
*/
switch(((~task->thread.i387.hard.cwd) &
task->thread.i387.hard.swd & 0x3f) |
(task->thread.i387.hard.swd & 0x240)) {
cwd = get_fpu_cwd(task);
swd = get_fpu_swd(task);
switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
case 0x000:
default:
break;
......@@ -641,6 +643,79 @@ asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
math_error((void *)regs->eip);
}
void simd_math_error(void *eip)
{
struct task_struct * task;
siginfo_t info;
unsigned short mxcsr;
/*
* Save the info for the exception handler and clear the error.
*/
task = current;
save_init_fpu(task);
load_mxcsr(0x1f80);
task->thread.trap_no = 19;
task->thread.error_code = 0;
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = __SI_FAULT;
info.si_addr = eip;
/*
* The SIMD FPU exceptions are handled a little differently, as there
* is only a single status/control register. Thus, to determine which
* unmasked exception was caught we must mask the exception mask bits
* at 0x1f80, and then use these to mask the exception bits at 0x3f.
*/
mxcsr = get_fpu_mxcsr(task);
switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
case 0x000:
default:
break;
case 0x001: /* Invalid Op */
info.si_code = FPE_FLTINV;
break;
case 0x002: /* Denormalize */
case 0x010: /* Underflow */
info.si_code = FPE_FLTUND;
break;
case 0x004: /* Zero Divide */
info.si_code = FPE_FLTDIV;
break;
case 0x008: /* Overflow */
info.si_code = FPE_FLTOVF;
break;
case 0x020: /* Precision */
info.si_code = FPE_FLTRES;
break;
}
force_sig_info(SIGFPE, &info, task);
}
asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
long error_code)
{
if (cpu_has_xmm) {
/* Handle SIMD FPU exceptions on PIII+ processors. */
ignore_irq13 = 1;
simd_math_error((void *)regs->eip);
} else {
/*
* Handle strange cache flush from user space exception
* in all other cases. This is undocumented behaviour.
*/
if (regs->eflags & VM_MASK) {
handle_vm86_fault((struct kernel_vm86_regs *)regs,
error_code);
return;
}
die_if_kernel("cache flush denied", regs, error_code);
current->thread.trap_no = 19;
current->thread.error_code = error_code;
force_sig(SIGSEGV, current);
}
}
asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
long error_code)
{
......@@ -661,17 +736,16 @@ asmlinkage void math_state_restore(struct pt_regs regs)
{
__asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */
if(current->used_math)
i387_restore_hard(current->thread.i387);
else
{
if (current->used_math) {
restore_fpu(current);
} else {
/*
* Our first FPU usage, clean the chip.
*/
__asm__("fninit");
current->used_math = 1;
}
current->flags|=PF_USEDFPU; /* So we fnsave on switch_to() */
current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */
}
#ifndef CONFIG_MATH_EMULATION
......@@ -905,7 +979,7 @@ void __init trap_init(void)
set_trap_gate(15,&spurious_interrupt_bug);
set_trap_gate(16,&coprocessor_error);
set_trap_gate(17,&alignment_check);
set_trap_gate(19,&xmm_fault);
set_trap_gate(19,&simd_coprocessor_error);
set_system_gate(SYSCALL_VECTOR,&system_call);
......
......@@ -8,6 +8,9 @@
* <rreilova@ececs.uc.edu>
* - Channing Corn (tests & fixes),
* - Andrew D. Balsa (code cleanup).
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
/*
......@@ -19,6 +22,7 @@
#include <linux/config.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/msr.h>
static int __init no_halt(char *s)
......@@ -62,6 +66,9 @@ static void __init copro_timeout(void)
static double __initdata x = 4195835.0;
static double __initdata y = 3145727.0;
static float __initdata zero[4] = { 0.0, 0.0, 0.0, 0.0 };
static float __initdata one[4] = { 1.0, 1.0, 1.0, 1.0 };
static void __init check_fpu(void)
{
unsigned short control_word;
......@@ -139,6 +146,37 @@ static void __init check_fpu(void)
printk("OK, FPU using exception 16 error reporting.\n");
else
printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n");
#if defined(CONFIG_X86_FXSR) || defined(CONFIG_X86_RUNTIME_FXSR)
/*
* Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
*/
if (offsetof(struct task_struct, thread.i387.fxsave) & 15)
panic("Kernel compiled for PII/PIII+ with FXSR, data not 16-byte aligned!");
if (cpu_has_fxsr) {
printk(KERN_INFO "Enabling fast FPU save and restore... ");
set_in_cr4(X86_CR4_OSFXSR);
printk("done.\n");
}
#endif
#ifdef CONFIG_X86_XMM
if (cpu_has_xmm) {
printk(KERN_INFO "Enabling unmasked SIMD FPU exception support... ");
set_in_cr4(X86_CR4_OSXMMEXCPT);
printk("done.\n");
/* Check if exception 19 works okay. */
load_mxcsr(0x0000);
printk(KERN_INFO "Checking SIMD FPU exceptions... ");
__asm__("movups %0,%%xmm0\n\t"
"movups %1,%%xmm1\n\t"
"divps %%xmm0,%%xmm1\n\t"
: : "m" (*&zero), "m" (*&one));
printk("OK, SIMD FPU using exception 19 error reporting.\n");
load_mxcsr(0x1f80);
}
#endif
}
static void __init check_hlt(void)
......@@ -424,6 +462,14 @@ static void __init check_config(void)
&& (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
panic("Kernel compiled for PPro+, assumes a local APIC without the read-before-write bug!");
#endif
/*
* If we configured ourselves for FXSR, we'd better have it.
*/
#ifdef CONFIG_X86_FXSR
if (!cpu_has_fxsr)
panic("Kernel compiled for PII/PIII+, requires FXSR feature!");
#endif
}
static void __init check_bugs(void)
......
......@@ -14,6 +14,7 @@ typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t;
typedef struct user_fxsr_struct elf_fpxregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
......
/*
* include/asm-i386/i387.h
*
* Copyright (C) 1994 Linus Torvalds
*
* Pentium III FXSR, SSE support
* General FPU state handling cleanups
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
#ifndef __ASM_I386_I387_H
#define __ASM_I386_I387_H
#include <linux/config.h>
#include <linux/sched.h>
#include <asm/processor.h>
#include <asm/sigcontext.h>
#include <asm/user.h>
/*
* FPU lazy state save handling...
*/
extern void save_fpu( struct task_struct *tsk );
extern void save_init_fpu( struct task_struct *tsk );
extern void restore_fpu( struct task_struct *tsk );
#define unlazy_fpu( tsk ) do { \
if ( tsk->flags & PF_USEDFPU ) \
save_fpu( tsk ); \
} while (0)
#define clear_fpu( tsk ) do { \
if ( tsk->flags & PF_USEDFPU ) { \
tsk->flags &= ~PF_USEDFPU; \
stts(); \
} \
} while (0)
/*
* FPU state interaction...
*/
extern unsigned short get_fpu_cwd( struct task_struct *tsk );
extern unsigned short get_fpu_swd( struct task_struct *tsk );
extern unsigned short get_fpu_twd( struct task_struct *tsk );
extern unsigned short get_fpu_mxcsr( struct task_struct *tsk );
extern void set_fpu_cwd( struct task_struct *tsk, unsigned short cwd );
extern void set_fpu_swd( struct task_struct *tsk, unsigned short swd );
extern void set_fpu_twd( struct task_struct *tsk, unsigned short twd );
extern void set_fpu_mxcsr( struct task_struct *tsk, unsigned short mxcsr );
#define load_mxcsr( val ) do { \
if ( cpu_has_xmm ) { \
unsigned long __mxcsr = ((unsigned long)(val) & 0xffff); \
asm volatile( "ldmxcsr %0" : : "m" (__mxcsr) ); \
} \
} while (0)
/*
* Signal frame handlers...
*/
extern int save_i387( struct _fpstate *buf );
extern int restore_i387( struct _fpstate *buf );
/*
* ptrace request handers...
*/
extern int get_fpregs( struct user_i387_struct *buf,
struct task_struct *tsk );
extern int set_fpregs( struct task_struct *tsk,
struct user_i387_struct *buf );
extern int get_fpxregs( struct user_fxsr_struct *buf,
struct task_struct *tsk );
extern int set_fpxregs( struct task_struct *tsk,
struct user_fxsr_struct *buf );
/*
* FPU state for core dumps...
*/
extern int dump_fpu( struct pt_regs *regs,
struct user_i387_struct *fpu );
extern int dump_extended_fpu( struct pt_regs *regs,
struct user_fxsr_struct *fpu );
#endif /* __ASM_I386_I387_H */
......@@ -83,24 +83,22 @@ struct cpuinfo_x86 {
#define X86_FEATURE_PGE 0x00002000 /* Page Global Enable */
#define X86_FEATURE_MCA 0x00004000 /* Machine Check Architecture */
#define X86_FEATURE_CMOV 0x00008000 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
#define X86_FEATURE_PAT 0x00010000 /* Page Attribute Table */
#define X86_FEATURE_PAT 0x00010000 /* Page Attribute Table */
#define X86_FEATURE_PSE36 0x00020000 /* 36-bit PSEs */
#define X86_FEATURE_18 0x00040000
#define X86_FEATURE_19 0x00080000
#define X86_FEATURE_20 0x00100000
#define X86_FEATURE_21 0x00200000
#define X86_FEATURE_22 0x00400000
#define X86_FEATURE_MMX 0x00800000 /* multimedia extensions */
#define X86_FEATURE_MMX 0x00800000 /* Multimedia Extensions */
#define X86_FEATURE_FXSR 0x01000000 /* FXSAVE and FXRSTOR instructions (fast save and restore of FPU context), and CR4.OSFXSR (OS uses these instructions) available */
#define X86_FEATURE_XMM 0x02000000 /* Intel MMX2 instruction set */
#define X86_FEATURE_XMM 0x02000000 /* Streaming SIMD Extensions */
#define X86_FEATURE_26 0x04000000
#define X86_FEATURE_27 0x08000000
#define X86_FEATURE_28 0x10000000
#define X86_FEATURE_29 0x20000000
#define X86_FEATURE_30 0x40000000
#define X86_FEATURE_AMD3D 0x80000000
#define X86_CR4_OSFXSR 0x0200 /* fast FPU save/restore */
#define X86_CR4_OSXMMEXCPT 0x0400 /* KNI (MMX2) unmasked exception 16 */
extern struct cpuinfo_x86 boot_cpu_data;
extern struct tss_struct init_tss[NR_CPUS];
......@@ -125,6 +123,10 @@ extern struct cpuinfo_x86 cpu_data[];
(boot_cpu_data.x86_capability & X86_FEATURE_DE)
#define cpu_has_vme \
(boot_cpu_data.x86_capability & X86_FEATURE_VME)
#define cpu_has_fxsr \
(boot_cpu_data.x86_capability & X86_FEATURE_FXSR)
#define cpu_has_xmm \
(boot_cpu_data.x86_capability & X86_FEATURE_XMM)
extern char ignore_irq13;
......@@ -150,15 +152,17 @@ extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
/*
* Intel CPU features in CR4
*/
#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
#define X86_CR4_DE 0x0008 /* enable debugging extensions */
#define X86_CR4_PSE 0x0010 /* enable page size extensions */
#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
#define X86_CR4_MCE 0x0040 /* Machine check enable */
#define X86_CR4_PGE 0x0080 /* enable global pages */
#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
#define X86_CR4_DE 0x0008 /* enable debugging extensions */
#define X86_CR4_PSE 0x0010 /* enable page size extensions */
#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
#define X86_CR4_MCE 0x0040 /* Machine check enable */
#define X86_CR4_PGE 0x0080 /* enable global pages */
#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
/*
* Save the cr4 feature set we're using (ie
......@@ -244,23 +248,7 @@ extern unsigned int mca_pentium_flag;
#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
#define INVALID_IO_BITMAP_OFFSET 0x8000
#ifndef CONFIG_X86_FXSR
#define i387_save_hard(x) \
__asm__("fnsave %0\n\tfwait": :"m" (x))
#define i387_restore_hard(x) \
__asm__("frstor %0": :"m" (x))
#define i387_hard_to_user(uaddr, x) \
__copy_to_user((uaddr), (x), sizeof(struct i387_hard_struct))
#define i387_user_to_hard(x, uaddr) \
__copy_from_user((x), (uaddr), sizeof(struct i387_hard_struct))
#define i387_set_cwd(x,v) do { (x).cwd = 0xffff0000 | (v); } while (0)
#define i387_set_swd(x,v) do { (x).swd = 0xffff0000 | (v); } while (0)
#define i387_set_twd(x,v) do { (x).twd = 0xffff0000 | (v); } while (0)
struct i387_hard_struct {
struct i387_fsave_struct {
long cwd;
long swd;
long twd;
......@@ -272,69 +260,22 @@ struct i387_hard_struct {
long status; /* software status information */
};
#else
/*
* has to be 128-bit aligned
*/
struct i387_hard_struct {
struct i387_fxsave_struct {
unsigned short cwd;
unsigned short swd;
unsigned short twd;
unsigned short fopcode;
unsigned int fip;
unsigned short fcs;
unsigned short __reserved_01;
unsigned int fdp;
unsigned short fds;
unsigned short __reserved_02;
unsigned int mxcsr;
unsigned int __reserved_03;
unsigned int st_space[32]; /* 8*16 bytes for each FP/MMX-reg = 128 bytes */
unsigned int xmm_space[22*4]; /* 22 cachelines for MMX2 registers */
unsigned long status;
unsigned short fop;
long fip;
long fcs;
long foo;
long fos;
long mxcsr;
long reserved;
long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
long padding[56];
} __attribute__ ((aligned (16)));
/*
* tag word conversion (thanks to Gabriel Paubert for noticing the
* subtle format difference and implementing these functions)
*
* there are several erratas wrt. the tag word in the i387, thus
* any software relying on it's value is questionable, but we
* definitely want to be as close as possible.
*/
static inline unsigned short fputag_KNIto387(unsigned char tb) {
unsigned short tw = tb;
tw = ((tw<<4) | tw) &0x0f0f; /* zzzz7654zzzz3210 */
tw = ((tw<<2) | tw) &0x3333; /* zz76zz54zz32zz10 */
tw = ((tw<<1) | tw) &0x5555; /* z7z6z5z4z3z2z1z0 */
return ~(tw*3);
}
static inline unsigned char fputag_387toKNI(unsigned short tw) {
tw = ~tw;
tw = (tw | (tw>>1)) & 0x5555; /* z7z6z5z4z3z2z1z0 */
tw = (tw | (tw>>1)) & 0x3333; /* zz76zz54zz32zz10 */
tw = (tw | (tw>>3)) & 0x0f0f; /* zzzz7654zzzz3210 */
return (tw|(tw>>4)) & 0x00ff; /* zzzzzzzz76543210 */
}
#define i387_set_cwd(x,v) do { (x).cwd = (short)(v); } while (0)
#define i387_set_swd(x,v) do { (x).swd = (short)(v); } while (0)
#define i387_set_twd(x,v) do { (x).twd = fputag_387toKNI(v); } while (0)
#define i387_save_hard(x) \
{ __asm__ __volatile__(".byte 0x0f, 0xae, 0x06": :"S" (&(x))); } while (0)
#define i387_restore_hard(x) \
do { __asm__ __volatile__(".byte 0x0f, 0xae, 0x4f, 0x00": :"D" (&(x))); } while(0)
extern int i387_hard_to_user ( struct _fpstate * user,
struct i387_hard_struct * hard);
extern int i387_user_to_hard (struct i387_hard_struct * hard,
struct _fpstate * user);
#endif
struct i387_soft_struct {
long cwd;
long swd;
......@@ -350,7 +291,8 @@ struct i387_soft_struct {
};
union i387_union {
struct i387_hard_struct hard;
struct i387_fsave_struct fsave;
struct i387_fxsave_struct fxsave;
struct i387_soft_struct soft;
};
......@@ -466,27 +408,6 @@ extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
extern void release_segments(struct mm_struct * mm);
extern void forget_segments(void);
/*
* FPU lazy state save handling..
*/
#define save_fpu(tsk) do { \
i387_save_hard(tsk->thread.i387); \
tsk->flags &= ~PF_USEDFPU; \
stts(); \
} while (0)
#define unlazy_fpu(tsk) do { \
if (tsk->flags & PF_USEDFPU) \
save_fpu(tsk); \
} while (0)
#define clear_fpu(tsk) do { \
if (tsk->flags & PF_USEDFPU) { \
tsk->flags &= ~PF_USEDFPU; \
stts(); \
} \
} while (0)
/*
* Return saved PC of a blocked thread.
*/
......
......@@ -46,6 +46,8 @@ struct pt_regs {
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
#define PTRACE_GETFPXREGS 18
#define PTRACE_SETFPXREGS 19
#ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
......
#ifndef _ASMi386_SIGCONTEXT_H
#define _ASMi386_SIGCONTEXT_H
#include <linux/config.h>
/*
* As documented in the iBCS2 standard..
*
* The first part of "struct _fpstate" is just the
* normal i387 hardware setup, the extra "status"
* word is used to save the coprocessor status word
* before entering the handler.
* The first part of "struct _fpstate" is just the normal i387
* hardware setup, the extra "status" word is used to save the
* coprocessor status word before entering the handler.
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*
* The FPU state data structure has had to grow to accomodate the
* extended FPU state required by the Streaming SIMD Extensions.
* There is no documented standard to accomplish this at the moment.
*/
struct _fpreg {
unsigned short significand[4];
unsigned short exponent;
};
struct _fpxreg {
unsigned short significand[4];
unsigned short exponent;
unsigned short padding[3];
};
struct _xmmreg {
unsigned long element[4];
};
struct _fpstate {
unsigned long cw,
sw,
tag,
ipoff,
cssel,
dataoff,
datasel;
/* Regular FPU environment */
unsigned long cw;
unsigned long sw;
unsigned long tag;
unsigned long ipoff;
unsigned long cssel;
unsigned long dataoff;
unsigned long datasel;
struct _fpreg _st[8];
unsigned long status;
#ifdef CONFIG_X86_FXSR
unsigned short status;
unsigned short magic; /* 0xffff = regular FPU data only */
/* FXSR FPU environment */
unsigned long _fxsr_env[6]; /* FXSR FPU env is ignored */
unsigned long mxcsr;
unsigned long _xmm[4*22];
#endif
unsigned long reserved;
struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
struct _xmmreg _xmm[8];
unsigned long padding[56];
};
#define X86_FXSR_MAGIC 0x0000
struct sigcontext {
unsigned short gs, __gsh;
unsigned short fs, __fsh;
......
......@@ -30,6 +30,18 @@
The minimum core file size is 3 pages, or 12288 bytes.
*/
/*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*
* Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
* interacting with the FXSR-format floating point environment. Floating
* point data can be accessed in the regular format in the usual manner,
* and both the standard and SIMD floating point data can be accessed via
* the new ptrace requests. In either case, changes to the FPU environment
* will be reflected in the task's state as expected.
*/
struct user_i387_struct {
long cwd;
long swd;
......@@ -41,6 +53,22 @@ struct user_i387_struct {
long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
};
struct user_fxsr_struct {
unsigned short cwd;
unsigned short swd;
unsigned short twd;
unsigned short fop;
long fip;
long fcs;
long foo;
long fos;
long mxcsr;
long reserved;
long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
long padding[56];
};
/*
* This is the old layout of "struct pt_regs", and
* is still the layout used by user mode (the new
......
......@@ -565,6 +565,7 @@ typedef struct elf64_shdr {
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_PRFPXREG 20
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
......
......@@ -20,6 +20,7 @@ struct elf_siginfo
typedef elf_greg_t greg_t;
typedef elf_gregset_t gregset_t;
typedef elf_fpregset_t fpregset_t;
typedef elf_fpxregset_t fpxregset_t;
#define NGREG ELF_NGREG
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment