summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/kernel/signal.c32
-rw-r--r--arch/arm/kernel/signal.c37
-rw-r--r--arch/i386/Makefile4
-rw-r--r--arch/i386/config.in34
-rw-r--r--arch/i386/defconfig5
-rw-r--r--arch/i386/kernel/Makefile16
-rw-r--r--arch/i386/kernel/apic.c5
-rw-r--r--arch/i386/kernel/apm.c42
-rw-r--r--arch/i386/kernel/cpuid.c168
-rw-r--r--arch/i386/kernel/entry.S5
-rw-r--r--arch/i386/kernel/i8259.c3
-rw-r--r--arch/i386/kernel/msr.c274
-rw-r--r--arch/i386/kernel/process.c90
-rw-r--r--arch/i386/kernel/ptrace.c13
-rw-r--r--arch/i386/kernel/setup.c142
-rw-r--r--arch/i386/kernel/signal.c43
-rw-r--r--arch/i386/kernel/smp.c10
-rw-r--r--arch/i386/kernel/smpboot.c5
-rw-r--r--arch/i386/kernel/traps.c126
-rw-r--r--arch/i386/mm/fault.c22
-rw-r--r--arch/ia64/ia32/ia32_signal.c49
-rw-r--r--arch/ia64/kernel/signal.c39
-rw-r--r--arch/m68k/kernel/signal.c37
-rw-r--r--arch/mips/kernel/signal.c37
-rw-r--r--arch/mips/mm/fault.c25
-rw-r--r--arch/mips64/kernel/signal.c37
-rw-r--r--arch/mips64/mm/fault.c27
-rw-r--r--arch/ppc/kernel/signal.c35
-rw-r--r--arch/sh/kernel/signal.c37
-rw-r--r--arch/sparc/kernel/Makefile2
-rw-r--r--arch/sparc/kernel/signal.c34
-rw-r--r--arch/sparc64/defconfig7
-rw-r--r--arch/sparc64/kernel/Makefile6
-rw-r--r--arch/sparc64/kernel/ioctl32.c570
-rw-r--r--arch/sparc64/kernel/signal.c34
-rw-r--r--arch/sparc64/kernel/signal32.c26
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c6
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c93
-rw-r--r--arch/sparc64/mm/modutil.c4
39 files changed, 2020 insertions, 161 deletions
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index ff12b9e8d..1f70c98e6 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -36,6 +36,36 @@ asmlinkage int do_signal(sigset_t *, struct pt_regs *,
struct switch_stack *, unsigned long, unsigned long);
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ switch (from->si_code >> 16) {
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_addr, &to->si_addr);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* The OSF/1 sigprocmask calling sequence is different from the
* C sigprocmask() sequence..
@@ -489,7 +519,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
- err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
+ err |= copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 54d962790..15f8fb4cb 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -34,6 +34,41 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
extern int ptrace_cancel_bpt (struct task_struct *);
extern int ptrace_set_bpt (struct task_struct *);
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* atomically swap in the new signal mask, and wait for a signal.
*/
@@ -370,7 +405,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
- err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->info, info);
/* Clear all the bits of the ucontext we don't use. */
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 113a00fa6..755cc877a 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -49,6 +49,10 @@ ifdef CONFIG_M686
CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
endif
+ifdef CONFIG_M686FX
+CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
+endif
+
ifdef CONFIG_MK6
CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; fi)
endif
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 1208a6b82..a928efb33 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -18,13 +18,15 @@ endmenu
mainmenu_option next_comment
comment 'Processor type and features'
choice 'Processor family' \
- "386 CONFIG_M386 \
- 486/Cx486 CONFIG_M486 \
- 586/K5/5x86/6x86/6x86MX CONFIG_M586 \
- Pentium/TSC CONFIG_M586TSC \
- PPro/P-II/P-III CONFIG_M686 \
- K6/II/III CONFIG_MK6 \
- Athlon CONFIG_MK7" PPro
+ "386 CONFIG_M386 \
+ 486/Cx486 CONFIG_M486 \
+ 586/K5/5x86/6x86/6x86MX CONFIG_M586 \
+ Pentium/TSC CONFIG_M586TSC \
+ PPro/Pentium-II CONFIG_M686 \
+ Pentium-III CONFIG_M686FX \
+ K6/K6-II/K6-III CONFIG_MK6 \
+ Athlon CONFIG_MK7 \
+ Crusoe CONFIG_MCRUSOE" PPro
#
# Define implied options from the CPU selection here
#
@@ -60,6 +62,14 @@ if [ "$CONFIG_M686" = "y" ]; then
define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
+if [ "$CONFIG_M686FX" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_BYTES 32
+ define_bool CONFIG_X86_TSC y
+ define_bool CONFIG_X86_GOOD_APIC y
+ define_bool CONFIG_X86_PGE y
+ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+ define_bool CONFIG_X86_FX y
+fi
if [ "$CONFIG_MK6" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_BYTES 32
define_bool CONFIG_X86_ALIGNMENT_16 y
@@ -74,8 +84,14 @@ if [ "$CONFIG_MK7" = "y" ]; then
define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
+if [ "$CONFIG_MCRUSOE" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_BYTES 32
+ define_bool CONFIG_X86_TSC y
+fi
tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
+tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
choice 'High Memory Support' \
"off CONFIG_NOHIGHMEM \
@@ -89,7 +105,9 @@ if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
define_bool CONFIG_X86_PAE y
fi
-bool 'Math emulation' CONFIG_MATH_EMULATION
+if [ "$CONFIG_X86_FX" != "y" ]; then
+ bool 'Math emulation' CONFIG_MATH_EMULATION
+fi
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
bool 'Symmetric multi-processing support' CONFIG_SMP
if [ "$CONFIG_SMP" != "y" ]; then
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index e00ac753a..281a82cea 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -19,8 +19,10 @@ CONFIG_UID16=y
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
CONFIG_M686=y
+# CONFIG_M686FX is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
+# CONFIG_MCRUSOE is not set
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_CMPXCHG=y
@@ -32,6 +34,8 @@ CONFIG_X86_GOOD_APIC=y
CONFIG_X86_PGE=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
# CONFIG_MICROCODE is not set
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_CPUID is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
@@ -194,7 +198,6 @@ CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_IDEDMA_PCI_AUTO is not set
# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_PCI_EXPERIMENTAL is not set
# CONFIG_IDEDMA_PCI_WIP is not set
# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
# CONFIG_BLK_DEV_AEC62XX is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 56db72ef8..9e9b76848 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -40,6 +40,22 @@ else
endif
endif
+ifeq ($(CONFIG_X86_MSR),y)
+OX_OBJS += msr.o
+else
+ ifeq ($(CONFIG_X86_MSR),m)
+ MX_OBJS += msr.o
+ endif
+endif
+
+ifeq ($(CONFIG_X86_CPUID),y)
+OX_OBJS += cpuid.o
+else
+ ifeq ($(CONFIG_X86_CPUID),m)
+ MX_OBJS += cpuid.o
+ endif
+endif
+
ifeq ($(CONFIG_MICROCODE),y)
OX_OBJS += microcode.o
else
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index eab365e26..0a19bb758 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -128,6 +128,11 @@ void disable_local_APIC(void)
void __init sync_Arb_IDs(void)
{
+ /*
+ * Wait for idle.
+ */
+ apic_wait_icr_idle();
+
Dprintk("Synchronizing Arb IDs.\n");
apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG
| APIC_DM_INIT);
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index b1e0e8b7c..0b4517137 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -922,6 +922,10 @@ static int send_event(apm_event_t event, struct apm_user *sender)
case APM_USER_SUSPEND:
/* map all suspends to ACPI D3 */
if (pm_send_all(PM_SUSPEND, (void *)3)) {
+ if (event == APM_CRITICAL_SUSPEND) {
+ printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armagedon\n" );
+ return 0;
+ }
if (apm_bios_info.version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
return 0;
@@ -934,7 +938,6 @@ static int send_event(apm_event_t event, struct apm_user *sender)
break;
}
- queue_event(event, sender);
return 1;
}
@@ -964,6 +967,7 @@ static void check_events(void)
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
if (send_event(event, NULL)) {
+ queue_event(event, NULL);
if (standbys_pending <= 0)
standby();
}
@@ -980,17 +984,18 @@ static void check_events(void)
if (ignore_bounce)
break;
#endif
- /*
- * If we are already processing a SUSPEND,
- * then further SUSPEND events from the BIOS
- * will be ignored. We also return here to
- * cope with the fact that the Thinkpads keep
- * sending a SUSPEND event until something else
- * happens!
- */
+ /*
+ * If we are already processing a SUSPEND,
+ * then further SUSPEND events from the BIOS
+ * will be ignored. We also return here to
+ * cope with the fact that the Thinkpads keep
+ * sending a SUSPEND event until something else
+ * happens!
+ */
if (waiting_for_resume)
- return;
+ return;
if (send_event(event, NULL)) {
+ queue_event(event, NULL);
waiting_for_resume = 1;
if (suspends_pending <= 0)
(void) suspend();
@@ -1007,6 +1012,7 @@ static void check_events(void)
#endif
set_time();
send_event(event, NULL);
+ queue_event(event, NULL);
break;
case APM_CAPABILITY_CHANGE:
@@ -1020,6 +1026,7 @@ static void check_events(void)
break;
case APM_CRITICAL_SUSPEND:
+ send_event(event, NULL); /* We can only hope it worked; critical suspend may not fail */
(void) suspend();
break;
}
@@ -1056,6 +1063,7 @@ static void apm_event_handler(void)
static void apm_mainloop(void)
{
+ int timeout = HZ;
DECLARE_WAITQUEUE(wait, current);
if (smp_num_cpus > 1)
@@ -1065,7 +1073,10 @@ static void apm_mainloop(void)
current->state = TASK_INTERRUPTIBLE;
for (;;) {
/* Nothing to do, just sleep for the timeout */
- schedule_timeout(APM_CHECK_TIMEOUT);
+ timeout = 2*timeout;
+ if (timeout > APM_CHECK_TIMEOUT)
+ timeout = APM_CHECK_TIMEOUT;
+ schedule_timeout(timeout);
if (exit_kapmd)
break;
@@ -1080,13 +1091,16 @@ static void apm_mainloop(void)
continue;
if (apm_do_idle()) {
unsigned long start = jiffies;
- while (system_idle()) {
+ while ((!exit_kapmd) && system_idle()) {
apm_do_idle();
- if (jiffies - start > APM_CHECK_TIMEOUT)
- break;
+ if (jiffies - start > (5*APM_CHECK_TIMEOUT)) {
+ apm_event_handler();
+ start = jiffies;
+ }
}
apm_do_busy();
apm_event_handler();
+ timeout = 1;
}
#endif
}
diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
new file mode 100644
index 000000000..34c34d818
--- /dev/null
+++ b/arch/i386/kernel/cpuid.c
@@ -0,0 +1,168 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+
+/*
+ * cpuid.c
+ *
+ * x86 CPUID access device
+ *
+ * This device is accessed by lseek() to the appropriate CPUID level
+ * and then read in chunks of 16 bytes. A larger size means multiple
+ * reads of consecutive levels.
+ *
+ * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
+ * an SMP box will direct the access to CPU %d.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/major.h>
+
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+
+struct cpuid_command {
+ int cpu;
+ u32 reg;
+ u32 *data;
+};
+
+static void cpuid_smp_cpuid(void *cmd_block)
+{
+ struct cpuid_command *cmd = (struct cpuid_command *) cmd_block;
+
+ if ( cmd->cpu == smp_processor_id() )
+ cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]);
+}
+
+extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+{
+ struct cpuid_command cmd;
+
+ if ( cpu == smp_processor_id() ) {
+ cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
+ } else {
+ cmd->cpu = cpu;
+ cmd->reg = reg;
+ cmd->data = data;
+
+ smp_call_function(cpuid_smp_cpuid, (void *)cmd, 1, 1);
+ }
+}
+#else /* ! CONFIG_SMP */
+
+extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+{
+ cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
+}
+
+#endif /* ! CONFIG_SMP */
+
+static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+ default:
+ return -EINVAL; /* SEEK_END not supported */
+ }
+}
+
+static ssize_t cpuid_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ u32 *tmp = (u32 *)buf;
+ u32 data[4];
+ size_t rv;
+ u32 reg = *ppos;
+ int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if ( count % 16 )
+ return -EINVAL; /* Invalid chunk size */
+
+ for ( rv = 0 ; count ; count -= 16 ) {
+ do_cpuid(cpu, reg, data);
+ if ( copy_to_user(tmp,&data,16) )
+ return -EFAULT;
+ tmp += 4;
+ *ppos = reg++;
+ }
+
+ return ((char *)tmp) - buf;
+}
+
+static int cpuid_open(struct inode *inode, struct file *file)
+{
+ int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if ( !(cpu_online_map & (1UL << cpu)) )
+ return -ENXIO; /* No such CPU */
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int cpuid_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * File operations we support
+ */
+static struct file_operations cpuid_fops = {
+ llseek: cpuid_seek,
+ read: cpuid_read,
+ open: cpuid_open,
+ release: cpuid_release,
+};
+
+int __init cpuid_init(void)
+{
+ if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) {
+ printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n",
+ CPUID_MAJOR);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+void __exit cpuid_exit(void)
+{
+}
+
+module_init(cpuid_init);
+module_exit(cpuid_exit)
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
+MODULE_DESCRIPTION("x86 generic CPUID driver");
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 50887c15c..26f3d505d 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -413,6 +413,11 @@ 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*/
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index e88fa9022..fff171c24 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -390,10 +390,11 @@ void __init init_8259A(int auto_eoi)
static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
+ extern void math_error(void *);
outb(0,0xF0);
if (ignore_irq13 || !boot_cpu_data.hard_math)
return;
- math_error();
+ math_error((void *)regs->eip);
}
static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL };
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
new file mode 100644
index 000000000..2ab1ecf33
--- /dev/null
+++ b/arch/i386/kernel/msr.c
@@ -0,0 +1,274 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * msr.c
+ *
+ * x86 MSR access device
+ *
+ * This device is accessed by lseek() to the appropriate register number
+ * and then read/write in chunks of 8 bytes. A larger size means multiple
+ * reads or writes of the same register.
+ *
+ * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
+ * an SMP box will direct the access to CPU %d.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/major.h>
+
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
+{
+ int err = 0;
+
+ asm volatile(
+ "1: wrmsr\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: movl %4,%0\n"
+ " jmp 1b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,3b\n"
+ ".previous"
+ : "+r" (err)
+ : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO));
+
+ return err;
+}
+
+extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
+{
+ int err = 0;
+
+ asm volatile(
+ "1: rdmsr\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: movl %4,%0\n"
+ " jmp 1b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,3b\n"
+ ".previous"
+ : "+r" (err), "=a" (*eax), "=d" (*eax)
+ : "c" (reg), "i" (-EIO));
+
+ return err;
+}
+
+#ifdef CONFIG_SMP
+
+struct msr_command {
+ int cpu;
+ int err;
+ u32 reg;
+ u32 data[2];
+};
+
+static void msr_smp_wrmsr(void *cmd_block)
+{
+ struct msr_command *cmd = (struct msr_command *) cmd_block;
+
+ if ( cmd->cpu == smp_processor_id() )
+ cmd->err = wrmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
+}
+
+static void msr_smp_rdmsr(void *cmd_block)
+{
+ struct msr_command *cmd = (struct msr_command *) cmd_block;
+
+ if ( cmd->cpu == smp_processor_id() )
+ cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
+}
+
+extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+{
+ struct msr_command cmd;
+
+ if ( cpu == smp_processor_id() ) {
+ return wrmsr_eio(reg, eax, edx);
+ } else {
+ cmd.cpu = cpu;
+ cmd.reg = reg;
+ cmd.data[0] = eax;
+ cmd.data[1] = edx;
+
+ smp_call_function(msr_smp_wrmsr, (void *)cmd, 1, 1);
+ return cmd.err;
+ }
+}
+
+extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+{
+ struct msr_command cmd;
+
+ if ( cpu == smp_processor_id() ) {
+ return rdmsr_eio(reg, eax, edx);
+ } else {
+ cmd.cpu = cpu;
+ cmd.reg = reg;
+
+ smp_call_function(msr_smp_rdmsr, (void *)cmd, 1, 1);
+
+ *eax = cmd.data[0];
+ *edx = cmd.data[1];
+
+ return cmd.err;
+ }
+}
+
+#else /* ! CONFIG_SMP */
+
+extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+{
+ return wrmsr_eio(reg, eax, edx);
+}
+
+extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+{
+ return rdmsr_eio(reg, eax, edx);
+}
+
+#endif /* ! CONFIG_SMP */
+
+static loff_t msr_seek(struct file *file, loff_t offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return file->f_pos;
+ case 1:
+ file->f_pos += offset;
+ return file->f_pos;
+ default:
+ return -EINVAL; /* SEEK_END not supported */
+ }
+}
+
+static ssize_t msr_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ u32 *tmp = (u32 *)buf;
+ u32 data[2];
+ size_t rv;
+ u32 reg = *ppos;
+ int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int err;
+
+ if ( count % 8 )
+ return -EINVAL; /* Invalid chunk size */
+
+ for ( rv = 0 ; count ; count -= 8 ) {
+ err = do_rdmsr(cpu, reg, &data[0], &data[1]);
+ if ( err )
+ return err;
+ if ( copy_to_user(tmp,&data,8) )
+ return -EFAULT;
+ tmp += 2;
+ }
+
+ return ((char *)tmp) - buf;
+}
+
+static ssize_t msr_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ const u32 *tmp = (const u32 *)buf;
+ u32 data[2];
+ size_t rv;
+ u32 reg = *ppos;
+ int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+ int err;
+
+ if ( count % 8 )
+ return -EINVAL; /* Invalid chunk size */
+
+ for ( rv = 0 ; count ; count -= 8 ) {
+ if ( copy_from_user(&data,tmp,8) )
+ return -EFAULT;
+ err = do_wrmsr(cpu, reg, data[0], data[1]);
+ if ( err )
+ return err;
+ tmp += 2;
+ }
+
+ return ((char *)tmp) - buf;
+}
+
+static int msr_open(struct inode *inode, struct file *file)
+{
+ int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if ( !(cpu_online_map & (1UL << cpu)) ||
+ !((cpu_data)[cpu].x86_capability & X86_FEATURE_MSR) )
+ return -ENXIO; /* No such CPU */
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int msr_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * File operations we support
+ */
+static struct file_operations msr_fops = {
+ llseek: msr_seek,
+ read: msr_read,
+ write: msr_write,
+ open: msr_open,
+ release: msr_release,
+};
+
+int __init msr_init(void)
+{
+ if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
+ printk(KERN_ERR "msr: unable to get major %d for msr\n",
+ MSR_MAJOR);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+void __exit msr_exit(void)
+{
+}
+
+module_init(msr_init);
+module_exit(msr_exit)
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
+MODULE_DESCRIPTION("x86 generic MSR driver");
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 96eedb519..dddd807c8 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -2,6 +2,8 @@
* 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
*/
/*
@@ -469,6 +471,94 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
return;
}
+#ifdef CONFIG_X86_FX
+
+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.
*/
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index de9656150..01edbc37a 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -1,5 +1,6 @@
/* ptrace.c */
/* By Ross Biro 1/23/92 */
+/* FXSAVE/FXRSTOR support by Ingo Molnar and modifications by Goutham Rao */
/* edited by Linus Torvalds */
#include <linux/config.h> /* for CONFIG_MATH_EMULATION */
@@ -398,14 +399,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = 0;
if ( !child->used_math ) {
/* Simulate an empty FPU. */
- child->thread.i387.hard.cwd = 0xffff037f;
- child->thread.i387.hard.swd = 0xffff0000;
- child->thread.i387.hard.twd = 0xffffffff;
- }
+ 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
- __copy_to_user((void *)data, &child->thread.i387.hard, sizeof(struct user_i387_struct));
+ 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);
@@ -423,7 +424,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
#ifdef CONFIG_MATH_EMULATION
if ( boot_cpu_data.hard_math ) {
#endif
- __copy_from_user(&child->thread.i387.hard, (void *)data, sizeof(struct user_i387_struct));
+ 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);
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 358d9f917..3ea101d69 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -39,7 +39,8 @@
* 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
+ *
*/
/*
@@ -800,14 +801,30 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
#endif
+#ifdef CONFIG_X86_FX
+ 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)
{
unsigned int n, dummy, *v;
- /* Actually we must have cpuid or we could never have
- * figured out that this was AMD/Cyrix from the vendor info :-).
+ /*
+ * Actually we must have cpuid or we could never have
+ * figured out that this was AMD/Cyrix/Transmeta
+ * from the vendor info :-).
*/
cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
@@ -1196,6 +1213,86 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
sprintf( c->x86_model_id, "WinChip %s", name );
}
+static void __init transmeta_model(struct cpuinfo_x86 *c)
+{
+ unsigned int cap_mask, uk, max, dummy, n, ecx, edx;
+ unsigned int cms_rev1, cms_rev2;
+ unsigned int cpu_rev, cpu_freq, cpu_flags;
+ char cpu_info[65];
+
+ get_model_name(c); /* Same as AMD/Cyrix */
+
+ /* Print CMS and CPU revision */
+ cpuid(0x80860000, &max, &dummy, &dummy, &dummy);
+ if ( max >= 0x80860001 ) {
+ cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags);
+ printk("CPU: Processor revision %u.%u.%u.%u, %u MHz%s%s\n",
+ (cpu_rev >> 24) & 0xff,
+ (cpu_rev >> 16) & 0xff,
+ (cpu_rev >> 8) & 0xff,
+ cpu_rev & 0xff,
+ cpu_freq,
+ (cpu_flags & 1) ? " [recovery]" : "",
+ (cpu_flags & 2) ? " [longrun]" : "");
+ }
+ if ( max >= 0x80860002 ) {
+ cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy);
+ printk("CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n",
+ (cms_rev1 >> 24) & 0xff,
+ (cms_rev1 >> 16) & 0xff,
+ (cms_rev1 >> 8) & 0xff,
+ cms_rev1 & 0xff,
+ cms_rev2);
+ }
+ if ( max >= 0x80860006 ) {
+ cpuid(0x80860003,
+ (void *)&cpu_info[0],
+ (void *)&cpu_info[4],
+ (void *)&cpu_info[8],
+ (void *)&cpu_info[12]);
+ cpuid(0x80860004,
+ (void *)&cpu_info[16],
+ (void *)&cpu_info[20],
+ (void *)&cpu_info[24],
+ (void *)&cpu_info[28]);
+ cpuid(0x80860005,
+ (void *)&cpu_info[32],
+ (void *)&cpu_info[36],
+ (void *)&cpu_info[40],
+ (void *)&cpu_info[44]);
+ cpuid(0x80860006,
+ (void *)&cpu_info[48],
+ (void *)&cpu_info[52],
+ (void *)&cpu_info[56],
+ (void *)&cpu_info[60]);
+ cpu_info[64] = '\0';
+ printk("CPU: %s\n", cpu_info);
+ }
+
+ /* Unhide possibly hidden flags */
+ rdmsr(0x80860004, cap_mask, uk);
+ wrmsr(0x80860004, ~0, uk);
+ cpuid(0x00000001, &dummy, &dummy, &dummy, &c->x86_capability);
+ wrmsr(0x80860004, cap_mask, uk);
+
+
+ /* L1/L2 cache */
+ cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+
+ if (n >= 0x80000005) {
+ cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+ printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n",
+ ecx>>24, edx>>24);
+ c->x86_cache_size=(ecx>>24)+(edx>>24);
+ }
+ if (n >= 0x80000006) {
+ cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
+ printk("CPU: L2 Cache: %dK\n", ecx>>16);
+ c->x86_cache_size=(ecx>>16);
+ }
+}
+
+
void __init get_cpu_vendor(struct cpuinfo_x86 *c)
{
char *v = c->x86_vendor_id;
@@ -1214,6 +1311,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
c->x86_vendor = X86_VENDOR_NEXGEN;
else if (!strcmp(v, "RiseRiseRise"))
c->x86_vendor = X86_VENDOR_RISE;
+ else if (!strcmp(v, "GenuineTMx86"))
+ c->x86_vendor = X86_VENDOR_TRANSMETA;
else
c->x86_vendor = X86_VENDOR_UNKNOWN;
}
@@ -1263,6 +1362,9 @@ static struct cpu_model_info cpu_models[] __initdata = {
{ X86_VENDOR_RISE, 5,
{ "mP6", "mP6", NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
+ { X86_VENDOR_TRANSMETA, 5,
+ { NULL, NULL, NULL, "Crusoe", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
};
void __init identify_cpu(struct cpuinfo_x86 *c)
@@ -1275,6 +1377,16 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
get_cpu_vendor(c);
+ /* It should be possible for the user to override this. */
+ if(c->x86_capability&(1<<18)) {
+ /* Disable processor serial number */
+ unsigned long lo,hi;
+ rdmsr(0x119,lo,hi);
+ lo |= 0x200000;
+ wrmsr(0x119,lo,hi);
+ printk(KERN_INFO "CPU serial number disabled.\n");
+ }
+
switch (c->x86_vendor) {
case X86_VENDOR_UNKNOWN:
@@ -1296,16 +1408,6 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
return;
case X86_VENDOR_INTEL:
- if(c->x86_capability&(1<<18)) {
- /* Disable processor serial number on Intel Pentium III
- from code by Phil Karn */
- unsigned long lo,hi;
- rdmsr(0x119,lo,hi);
- lo |= 0x200000;
- wrmsr(0x119,lo,hi);
- printk(KERN_INFO "Pentium-III serial number disabled.\n");
- }
-
if (c->cpuid_level > 1) {
/* supports eax=2 call */
int edx, dummy;
@@ -1374,6 +1476,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
goto name_decoded;
break;
+
+ case X86_VENDOR_TRANSMETA:
+ transmeta_model(c);
+ return;
}
@@ -1412,7 +1518,7 @@ void __init dodgy_tsc(void)
static char *cpu_vendor_names[] __initdata = {
- "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise" };
+ "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
void __init print_cpu_info(struct cpuinfo_x86 *c)
@@ -1424,7 +1530,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
else if (c->cpuid_level >= 0)
vendor = c->x86_vendor_id;
- if (vendor)
+ if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
printk("%s ", vendor);
if (!c->x86_model_id[0])
@@ -1434,6 +1540,8 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
if (c->x86_mask || c->cpuid_level>=0)
printk(" stepping %02x\n", c->x86_mask);
+ else
+ printk("\n");
}
/*
@@ -1513,7 +1621,9 @@ int get_cpuinfo(char * buffer)
case X86_VENDOR_INTEL:
x86_cap_flags[16] = "pat";
+ x86_cap_flags[18] = "pn";
x86_cap_flags[24] = "fxsr";
+ x86_cap_flags[25] = "xmm";
break;
case X86_VENDOR_CENTAUR:
@@ -1522,7 +1632,7 @@ int get_cpuinfo(char * buffer)
break;
default:
- /* Unknown CPU manufacturer. Transmeta ? :-) */
+ /* Unknown CPU manufacturer or no special handling needed */
break;
}
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 4e813fac7..c35f5bae8 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -4,6 +4,8 @@
* 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
*/
#include <linux/config.h>
@@ -30,6 +32,41 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -155,7 +192,7 @@ static inline int restore_i387_hard(struct _fpstate *buf)
{
struct task_struct *tsk = current;
clear_fpu(tsk);
- return __copy_from_user(&tsk->thread.i387.hard, buf, sizeof(*buf));
+ return i387_user_to_hard(&tsk->thread.i387.hard, buf);
}
static inline int restore_i387(struct _fpstate *buf)
@@ -309,7 +346,7 @@ static inline int save_i387_hard(struct _fpstate * buf)
unlazy_fpu(tsk);
tsk->thread.i387.hard.status = tsk->thread.i387.hard.swd;
- if (__copy_to_user(buf, &tsk->thread.i387.hard, sizeof(*buf)))
+ if (i387_hard_to_user(buf, &tsk->thread.i387.hard))
return -1;
return 1;
}
@@ -491,7 +528,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
&frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
- err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->info, info);
if (err)
goto give_sigsegv;
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 94ba5c49f..e08418fe0 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -133,6 +133,11 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
unsigned int cfg;
/*
+ * Wait for idle.
+ */
+ apic_wait_icr_idle();
+
+ /*
* No need to touch the target chip field
*/
cfg = __prepare_ICR(shortcut, vector);
@@ -173,6 +178,11 @@ static inline void send_IPI_mask(int mask, int vector)
__cli();
/*
+ * Wait for idle.
+ */
+ apic_wait_icr_idle();
+
+ /*
* prepare target chip field
*/
cfg = __prepare_ICR2(mask);
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index ae84ff2b5..e0ae38b28 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -502,6 +502,11 @@ static inline void inquire_remote_apic(int apicid)
for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
printk("... APIC #%d %s: ", apicid, names[i]);
+ /*
+ * Wait for idle.
+ */
+ apic_wait_icr_idle();
+
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 7fb5ebc61..0df54449f 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -2,6 +2,7 @@
* linux/arch/i386/traps.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ * FXSAVE/FXRSTOR support by Ingo Molnar, OS exception support by Goutham Rao
*/
/*
@@ -82,6 +83,20 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
force_sig(signr, tsk); \
}
+#define DO_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+ siginfo_t info; \
+ tsk->thread.error_code = error_code; \
+ tsk->thread.trap_no = trapnr; \
+ die_if_no_fixup(str,regs,error_code); \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void *)siaddr; \
+ force_sig_info(signr, &info, tsk); \
+}
+
#define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
@@ -99,6 +114,28 @@ out: \
unlock_kernel(); \
}
+#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+ siginfo_t info; \
+ lock_kernel(); \
+ if (regs->eflags & VM_MASK) { \
+ if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \
+ goto out; \
+ /* else fall through */ \
+ } \
+ tsk->thread.error_code = error_code; \
+ tsk->thread.trap_no = trapnr; \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void *)siaddr; \
+ force_sig_info(signr, &info, tsk); \
+ die_if_kernel(str,regs,error_code); \
+out: \
+ unlock_kernel(); \
+}
+
void page_exception(void);
asmlinkage void divide_error(void);
@@ -120,6 +157,7 @@ asmlinkage void 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;
@@ -260,34 +298,29 @@ static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
}
}
-DO_VM86_ERROR( 0, SIGFPE, "divide error", divide_error, current)
+static inline unsigned long get_cr2(void)
+{
+ unsigned long address;
+
+ /* get the address */
+ __asm__("movl %%cr2,%0":"=r" (address));
+ return address;
+}
+
+DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, current, FPE_INTDIV, regs->eip)
DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current)
DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current)
DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds, current)
-DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current)
+DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, current, ILL_ILLOPN, regs->eip)
DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available, current)
DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, current)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, current, BUS_ADRALN, get_cr2())
DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
-/* I don't have documents for this but it does seem to cover the cache
- flush from user space exception some people get. */
-DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
-
-asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
-{
- 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.error_code = error_code;
- current->thread.trap_no = 19;
- force_sig(SIGSEGV, current);
-}
+DO_VM86_ERROR(19, SIGFPE, "XMM fault", xmm_fault, current)
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
@@ -485,6 +518,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
{
unsigned int condition;
struct task_struct *tsk = current;
+ siginfo_t info;
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
@@ -519,7 +553,11 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
/* Ok, finally something we can handle */
tsk->thread.trap_no = 1;
tsk->thread.error_code = error_code;
- force_sig(SIGTRAP, tsk);
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ info.si_addr = (void *)regs->eip;
+ force_sig_info(SIGTRAP, &info, tsk);
return;
debug_vm86:
@@ -544,9 +582,10 @@ clear_TF:
* the correct behaviour even in the presence of the asynchronous
* IRQ13 behaviour
*/
-void math_error(void)
+void math_error(void *eip)
{
struct task_struct * task;
+ siginfo_t info;
/*
* Save the info for the exception handler
@@ -556,13 +595,52 @@ void math_error(void)
save_fpu(task);
task->thread.trap_no = 16;
task->thread.error_code = 0;
- force_sig(SIGFPE, task);
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = __SI_FAULT;
+ info.si_addr = eip;
+ /*
+ * (~cwd & swd) will mask out exceptions that are not set to unmasked
+ * status. 0x3f is the exception bits in these regs, 0x200 is the
+ * C1 reg you need in case of a stack fault, 0x040 is the stack
+ * fault bit. We should only be taking one exception at a time,
+ * so if this combination doesn't produce any single exception,
+ * then we have a bad program that isn't syncronizing its FPU usage
+ * 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)) {
+ case 0x000:
+ default:
+ break;
+ case 0x001: /* Invalid Op */
+ case 0x040: /* Stack Fault */
+ case 0x240: /* Stack Fault | Direction */
+ 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_coprocessor_error(struct pt_regs * regs, long error_code)
{
ignore_irq13 = 1;
- math_error();
+ math_error((void *)regs->eip);
}
asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
@@ -586,7 +664,7 @@ asmlinkage void math_state_restore(struct pt_regs regs)
__asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */
if(current->used_math)
- __asm__("frstor %0": :"m" (current->thread.i387));
+ i387_restore_hard(current->thread.i387);
else
{
/*
@@ -829,6 +907,8 @@ 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_system_gate(SYSCALL_VECTOR,&system_call);
/*
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 697645988..b88c4a422 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -124,13 +124,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
unsigned long page;
unsigned long fixup;
int write;
- int si_code = SEGV_MAPERR;
+ siginfo_t info;
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
tsk = current;
mm = tsk->mm;
+ info.si_code = SEGV_MAPERR;
/*
* If we're in an interrupt or have no user
@@ -165,9 +166,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
* we can handle it..
*/
good_area:
+ info.si_code = SEGV_ACCERR;
write = 0;
- si_code = SEGV_ACCERR;
-
switch (error_code & 3) {
default: /* 3: write, present */
#ifdef TEST_VERIFY_AREA
@@ -225,14 +225,14 @@ bad_area:
/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
- struct siginfo si;
tsk->thread.cr2 = address;
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 14;
- si.si_signo = SIGSEGV;
- si.si_code = si_code;
- si.si_addr = (void*) address;
- force_sig_info(SIGSEGV, &si, tsk);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *)address;
+ force_sig_info(SIGSEGV, &info, tsk);
return;
}
@@ -309,7 +309,11 @@ do_sigbus:
tsk->thread.cr2 = address;
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 14;
- force_sig(SIGBUS, tsk);
+ info.si_code = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &info, tsk);
/* Kernel mode? Handle exceptions or die */
if (!(error_code & 4))
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index 83e6c9e61..e85af6ced 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -48,13 +48,58 @@ struct rt_sigframe_ia32
int sig;
int pinfo;
int puc;
- struct siginfo info;
+ siginfo_t32 info;
struct ucontext_ia32 uc;
struct _fpstate_ia32 fpstate;
char retcode[8];
};
static int
+copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
+{
+ int err;
+
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member.
+ This routine must convert siginfo from 64bit to 32bit as well
+ at the same time. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ if (from->si_code < 0)
+ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+ else {
+ switch (from->si_code >> 16) {
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_FAULT >> 16:
+ err |= __put_user((long)from->si_addr, &to->si_addr);
+ break;
+ case __SI_POLL >> 16:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ }
+ return err;
+}
+
+
+
+static int
setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate,
struct pt_regs *regs, unsigned long mask)
{
@@ -283,7 +328,7 @@ setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info,
&frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
- err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ err |= copy_siginfo_to_user32(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index a0cca9da7..25197c1d4 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -138,6 +138,43 @@ restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt)
return err;
}
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ case __SI_POLL >> 16:
+ err |= __put_user(from->si_addr, &to->si_addr);
+ err |= __put_user(from->si_imm, &to->si_imm);
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_pid, &to->si_pid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* When we get here, ((struct switch_stack *) pt - 1) is a
* switch_stack frame that has no defined value. Upon return, we
@@ -290,7 +327,7 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, st
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
- err = __copy_to_user(&frame->info, info, sizeof(siginfo_t));
+ err = copy_siginfo_to_user(&frame->info, info);
err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp);
err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size);
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index d795c71ad..d67617bea 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -189,6 +189,41 @@ struct rt_sigframe
};
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
static inline int restore_fpu_state(struct sigcontext *sc)
@@ -877,7 +912,7 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
&frame->sig);
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
- err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 81ff3173d..c145b3343 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -39,6 +39,41 @@ extern asmlinkage int restore_fp_context(struct sigcontext *sc);
extern asmlinkage void syscall_trace(void);
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -442,7 +477,7 @@ setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
}
/* Create siginfo. */
- err |= __copy_to_user(&frame->rs_info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->rs_info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->rs_uc.uc_flags);
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index e2d74fd11..6c9b46b82 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -1,10 +1,9 @@
-/* $Id: fault.c,v 1.15 2000/02/04 07:40:23 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
*/
#include <linux/signal.h>
#include <linux/sched.h>
@@ -47,9 +46,10 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
struct vm_area_struct * vma;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
- int si_code = SEGV_MAPERR;
unsigned long fixup;
+ siginfo_t info;
+ info.si_code = SEGV_MAPERR;
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
@@ -75,7 +75,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
* we can handle it..
*/
good_area:
- si_code = SEGV_ACCERR;
+ info.si_code = SEGV_ACCERR;
if (write) {
if (!(vma->vm_flags & VM_WRITE))
@@ -126,10 +126,11 @@ bad_area:
(unsigned long) regs->cp0_epc,
(unsigned long) regs->regs[31]);
#endif
- si.si_signo = SIGSEGV;
- si.si_code = si_code;
- si.si_addr = (void *) address;
- force_sig_info(SIGSEGV, &si, tsk);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *) address;
+ force_sig_info(SIGSEGV, &info, tsk);
return;
}
@@ -177,7 +178,11 @@ do_sigbus:
* or user mode.
*/
tsk->thread.cp0_badvaddr = address;
- force_sig(SIGBUS, tsk);
+ info.si_code = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *) address;
+ force_sig_info(SIGBUS, &info, tsk);
/* Kernel mode? Handle exceptions or die */
if (!user_mode(regs))
diff --git a/arch/mips64/kernel/signal.c b/arch/mips64/kernel/signal.c
index 9fad47ffe..d45f44b5a 100644
--- a/arch/mips64/kernel/signal.c
+++ b/arch/mips64/kernel/signal.c
@@ -40,6 +40,41 @@ extern asmlinkage int restore_fp_context(struct sigcontext *sc);
extern asmlinkage void syscall_trace(void);
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ err |= __put_user((long)from->si_addr, &to->si_addr);
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
static inline int store_fp_context(struct sigcontext *sc)
{
unsigned int fcr0;
@@ -468,7 +503,7 @@ setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
}
/* Create siginfo. */
- err |= __copy_to_user(&frame->rs_info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->rs_info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->rs_uc.uc_flags);
diff --git a/arch/mips64/mm/fault.c b/arch/mips64/mm/fault.c
index e31c82568..01ed01f79 100644
--- a/arch/mips64/mm/fault.c
+++ b/arch/mips64/mm/fault.c
@@ -1,11 +1,10 @@
-/* $Id: fault.c,v 1.7 2000/03/13 22:43:25 kanoj Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle
- * Copyright (C) 1999 by Silicon Graphics
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics, Inc.
*/
#include <linux/signal.h>
#include <linux/sched.h>
@@ -68,9 +67,10 @@ do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address)
struct vm_area_struct * vma;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
- int si_code = SEGV_MAPERR;
unsigned long fixup;
+ siginfo_t info;
+ info.si_code = SEGV_MAPERR;
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
@@ -96,7 +96,7 @@ do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address)
* we can handle it..
*/
good_area:
- si_code = SEGV_ACCERR;
+ info.si_code = SEGV_ACCERR;
if (write) {
if (!(vma->vm_flags & VM_WRITE))
@@ -147,10 +147,11 @@ bad_area:
(unsigned long) regs->cp0_epc,
(unsigned long) regs->regs[31]);
#endif
- si.si_signo = SIGSEGV;
- si.si_code = si_code;
- si.si_addr = (void *) address;
- force_sig_info(SIGSEGV, &si, tsk);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *) address;
+ force_sig_info(SIGSEGV, &info, tsk);
return;
}
@@ -198,7 +199,11 @@ do_sigbus:
* or user mode.
*/
tsk->thread.cp0_badvaddr = address;
- force_sig(SIGBUS, tsk);
+ info.si_code = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *) address;
+ force_sig_info(SIGBUS, &info, tsk);
/* Kernel mode? Handle exceptions or die */
if (!user_mode(regs))
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 1ca3a65f8..e5452fedb 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -58,6 +58,41 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs);
extern int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index 774359a1b..14ce2eae9 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -33,6 +33,41 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -424,7 +459,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
- err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ err |= copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index f63f542ba..e8524e430 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.54 2000/05/12 23:51:24 davem Exp $
+# $Id: Makefile,v 1.55 2000/05/23 23:09:08 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index e75d5d000..e807683ea 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -95,6 +95,38 @@ struct rt_signal_frame {
__siginfo_fpu_t fpu_state;
};
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ switch (from->si_code >> 16) {
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_pid, &to->si_pid);
+ break;
+ }
+ return err;
+ }
+}
+
/* Align macros */
#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7)))
#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
@@ -710,7 +742,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
sizeof (struct reg_window));
- err |= __copy_to_user(&sf->info, info, sizeof(siginfo_t));
+ err |= copy_siginfo_to_user(&sf->info, info);
if (err)
goto sigsegv;
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 135ee279e..2800d1bd5 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -201,6 +201,13 @@ CONFIG_BLK_DEV_IDE=y
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
# CONFIG_BLK_DEV_IDECS is not set
CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_IDETAPE=m
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index edb6b0571..df823619c 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -81,13 +81,11 @@ check_asm: dummy
@echo -e "# error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h
@echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
@echo "#include <linux/config.h>" > tmp.c
- @echo "#undef __SMP__" >> tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
$(CPP) $(CPPFLAGS) tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
- @echo "#undef __SMP__" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@@ -128,7 +126,7 @@ check_asm: dummy
$(SH) ./check_asm.sh thread tmp.i check_asm.c
@echo 'return 0; }' >> check_asm.c
@rm -f tmp.[ci]
- #$(CC) -D__SMP__ -o check_asm check_asm.c
+ #$(CC) -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
$(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
@@ -153,7 +151,7 @@ check_asm: dummy
$(SH) ./check_asm.sh thread tmp.i check_asm.c
@echo 'return 0; }' >> check_asm.c
@rm -f tmp.[ci]
- #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c
+ #$(CC) -DSPIN_LOCK_DEBUG -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
$(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 6c00ba2f6..9f5626b5b 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.90 2000/05/22 07:29:39 davem Exp $
+/* $Id: ioctl32.c,v 1.91 2000/05/23 05:25:44 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
@@ -2353,6 +2353,542 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
}
#endif
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+/* This really belongs in include/linux/drm.h -DaveM */
+#include "../../../drivers/char/drm/drm.h"
+
+typedef struct drm32_version {
+ int version_major; /* Major version */
+ int version_minor; /* Minor version */
+ int version_patchlevel;/* Patch level */
+ int name_len; /* Length of name buffer */
+ u32 name; /* Name of driver */
+ int date_len; /* Length of date buffer */
+ u32 date; /* User-space buffer to hold date */
+ int desc_len; /* Length of desc buffer */
+ u32 desc; /* User-space buffer to hold desc */
+} drm32_version_t;
+#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t)
+
+static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_version_t *uversion = (drm32_version_t *)arg;
+ char *name_ptr, *date_ptr, *desc_ptr;
+ u32 tmp1, tmp2, tmp3;
+ drm_version_t kversion;
+ mm_segment_t old_fs;
+ int ret;
+
+ memset(&kversion, 0, sizeof(kversion));
+ if (get_user(kversion.name_len, &uversion->name_len) ||
+ get_user(kversion.date_len, &uversion->date_len) ||
+ get_user(kversion.desc_len, &uversion->desc_len) ||
+ get_user(tmp1, &uversion->name) ||
+ get_user(tmp2, &uversion->date) ||
+ get_user(tmp3, &uversion->desc))
+ return -EFAULT;
+
+ name_ptr = (char *) A(tmp1);
+ date_ptr = (char *) A(tmp2);
+ desc_ptr = (char *) A(tmp3);
+
+ ret = -ENOMEM;
+ if (kversion.name_len && name_ptr) {
+ kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
+ if (!kversion.name)
+ goto out;
+ }
+ if (kversion.date_len && date_ptr) {
+ kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
+ if (!kversion.date)
+ goto out;
+ }
+ if (kversion.desc_len && desc_ptr) {
+ kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
+ if (!kversion.desc)
+ goto out;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
+ set_fs(old_fs);
+
+ if (!ret) {
+ if ((kversion.name &&
+ copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
+ (kversion.date &&
+ copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
+ (kversion.desc &&
+ copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
+ ret = -EFAULT;
+ if (put_user(kversion.version_major, &uversion->version_major) ||
+ put_user(kversion.version_minor, &uversion->version_minor) ||
+ put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
+ put_user(kversion.name_len, &uversion->name_len) ||
+ put_user(kversion.date_len, &uversion->date_len) ||
+ put_user(kversion.desc_len, &uversion->desc_len))
+ ret = -EFAULT;
+ }
+
+out:
+ if (kversion.name)
+ kfree(kversion.name);
+ if (kversion.date)
+ kfree(kversion.date);
+ if (kversion.desc)
+ kfree(kversion.desc);
+ return ret;
+}
+
+typedef struct drm32_unique {
+ size_t unique_len; /* Length of unique */
+ u32 unique; /* Unique name for driver instantiation */
+} drm32_unique_t;
+#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
+#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
+
+static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_unique_t *uarg = (drm32_unique_t *)arg;
+ drm_unique_t karg;
+ mm_segment_t old_fs;
+ char *uptr;
+ u32 tmp;
+ int ret;
+
+ if (get_user(karg.unique_len, &uarg->unique_len))
+ return -EFAULT;
+ karg.unique = NULL;
+
+ if (get_user(tmp, &uarg->unique))
+ return -EFAULT;
+
+ uptr = (char *) A(tmp);
+
+ if (uptr) {
+ karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
+ if (!karg.unique)
+ return -ENOMEM;
+ if (cmd == DRM32_IOCTL_SET_UNIQUE &&
+ copy_from_user(karg.unique, uptr, karg.unique_len)) {
+ kfree(karg.unique);
+ return -EFAULT;
+ }
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ if (cmd == DRM32_IOCTL_GET_UNIQUE)
+ ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
+ else
+ ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
+ set_fs(old_fs);
+
+ if (!ret) {
+ if (cmd == DRM32_IOCTL_GET_UNIQUE &&
+ copy_to_user(uptr, karg.unique, karg.unique_len))
+ ret = -EFAULT;
+ if (put_user(karg.unique_len, &uarg->unique_len))
+ ret = -EFAULT;
+ }
+
+ kfree(karg.unique);
+
+ return ret;
+}
+
+typedef struct drm32_map {
+ u32 offset; /* Requested physical address (0 for SAREA)*/
+ u32 size; /* Requested physical size (bytes) */
+ drm_map_type_t type; /* Type of memory to map */
+ drm_map_flags_t flags; /* Flags */
+ u32 handle; /* User-space: "Handle" to pass to mmap */
+ /* Kernel-space: kernel-virtual address */
+ int mtrr; /* MTRR slot used */
+ /* Private data */
+} drm32_map_t;
+#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t)
+
+static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_map_t *uarg = (drm32_map_t *) arg;
+ drm_map_t karg;
+ mm_segment_t old_fs;
+ u32 tmp;
+ int ret;
+
+ ret = get_user(karg.offset, &uarg->offset);
+ ret |= get_user(karg.size, &uarg->size);
+ ret |= get_user(karg.type, &uarg->type);
+ ret |= get_user(karg.flags, &uarg->flags);
+ ret |= get_user(tmp, &uarg->handle);
+ ret |= get_user(karg.mtrr, &uarg->mtrr);
+ if (ret)
+ return -EFAULT;
+
+ karg.handle = (void *) A(tmp);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
+ set_fs(old_fs);
+
+ if (!ret) {
+ ret = put_user(karg.offset, &uarg->offset);
+ ret |= put_user(karg.size, &uarg->size);
+ ret |= put_user(karg.type, &uarg->type);
+ ret |= put_user(karg.flags, &uarg->flags);
+ tmp = (u32) (long)karg.handle;
+ ret |= put_user(tmp, &uarg->handle);
+ ret |= put_user(karg.mtrr, &uarg->mtrr);
+ if (ret)
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+typedef struct drm32_buf_info {
+ int count; /* Entries in list */
+ u32 list; /* (drm_buf_desc_t *) */
+} drm32_buf_info_t;
+#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t)
+
+static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
+ drm_buf_desc_t *ulist;
+ drm_buf_info_t karg;
+ mm_segment_t old_fs;
+ int orig_count, ret;
+ u32 tmp;
+
+ if (get_user(karg.count, &uarg->count) ||
+ get_user(tmp, &uarg->list))
+ return -EFAULT;
+
+ ulist = (drm_buf_desc_t *) A(tmp);
+
+ orig_count = karg.count;
+
+ karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
+ if (!karg.list)
+ return -EFAULT;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
+ set_fs(old_fs);
+
+ if (!ret) {
+ if (karg.count <= orig_count &&
+ (copy_to_user(ulist, karg.list,
+ karg.count * sizeof(drm_buf_desc_t))))
+ ret = -EFAULT;
+ if (put_user(karg.count, &uarg->count))
+ ret = -EFAULT;
+ }
+
+ kfree(karg.list);
+
+ return ret;
+}
+
+typedef struct drm32_buf_free {
+ int count;
+ u32 list; /* (int *) */
+} drm32_buf_free_t;
+#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t)
+
+static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
+ drm_buf_free_t karg;
+ mm_segment_t old_fs;
+ int *ulist;
+ int ret;
+ u32 tmp;
+
+ if (get_user(karg.count, &uarg->count) ||
+ get_user(tmp, &uarg->list))
+ return -EFAULT;
+
+ ulist = (int *) A(tmp);
+
+ karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
+ if (!karg.list)
+ return -ENOMEM;
+
+ ret = -EFAULT;
+ if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
+ goto out;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
+ set_fs(old_fs);
+
+out:
+ kfree(karg.list);
+
+ return ret;
+}
+
+typedef struct drm32_buf_pub {
+ int idx; /* Index into master buflist */
+ int total; /* Buffer size */
+ int used; /* Amount of buffer in use (for DMA) */
+ u32 address; /* Address of buffer (void *) */
+} drm32_buf_pub_t;
+
+typedef struct drm32_buf_map {
+ int count; /* Length of buflist */
+ u32 virtual; /* Mmaped area in user-virtual (void *) */
+ u32 list; /* Buffer information (drm_buf_pub_t *) */
+} drm32_buf_map_t;
+#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t)
+
+static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
+ drm32_buf_pub_t *ulist;
+ drm_buf_map_t karg;
+ mm_segment_t old_fs;
+ int orig_count, ret, i;
+ u32 tmp1, tmp2;
+
+ if (get_user(karg.count, &uarg->count) ||
+ get_user(tmp1, &uarg->virtual) ||
+ get_user(tmp2, &uarg->list))
+ return -EFAULT;
+
+ karg.virtual = (void *) A(tmp1);
+ ulist = (drm32_buf_pub_t *) A(tmp2);
+
+ orig_count = karg.count;
+
+ karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
+ if (!karg.list)
+ return -ENOMEM;
+
+ ret = -EFAULT;
+ for (i = 0; i < karg.count; i++) {
+ if (get_user(karg.list[i].idx, &ulist[i].idx) ||
+ get_user(karg.list[i].total, &ulist[i].total) ||
+ get_user(karg.list[i].used, &ulist[i].used) ||
+ get_user(tmp1, &ulist[i].address))
+ goto out;
+
+ karg.list[i].address = (void *) A(tmp1);
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
+ set_fs(old_fs);
+
+ if (!ret) {
+ for (i = 0; i < orig_count; i++) {
+ tmp1 = (u32) (long) karg.list[i].address;
+ if (put_user(karg.list[i].idx, &ulist[i].idx) ||
+ put_user(karg.list[i].total, &ulist[i].total) ||
+ put_user(karg.list[i].used, &ulist[i].used) ||
+ put_user(tmp1, &ulist[i].address)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ if (put_user(karg.count, &uarg->count))
+ ret = -EFAULT;
+ }
+
+out:
+ kfree(karg.list);
+ return ret;
+}
+
+typedef struct drm32_dma {
+ /* Indices here refer to the offset into
+ buflist in drm_buf_get_t. */
+ int context; /* Context handle */
+ int send_count; /* Number of buffers to send */
+ u32 send_indices; /* List of handles to buffers (int *) */
+ u32 send_sizes; /* Lengths of data to send (int *) */
+ drm_dma_flags_t flags; /* Flags */
+ int request_count; /* Number of buffers requested */
+ int request_size; /* Desired size for buffers */
+ u32 request_indices; /* Buffer information (int *) */
+ u32 request_sizes; /* (int *) */
+ int granted_count; /* Number of buffers granted */
+} drm32_dma_t;
+#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t)
+
+/* RED PEN The DRM layer blindly dereferences the send/request
+ * indice/size arrays even though they are userland
+ * pointers. -DaveM
+ */
+static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_dma_t *uarg = (drm32_dma_t *) arg;
+ int *u_si, *u_ss, *u_ri, *u_rs;
+ drm_dma_t karg;
+ mm_segment_t old_fs;
+ int ret;
+ u32 tmp1, tmp2, tmp3, tmp4;
+
+ karg.send_indices = karg.send_sizes = NULL;
+ karg.request_indices = karg.request_sizes = NULL;
+
+ if (get_user(karg.context, &uarg->context) ||
+ get_user(karg.send_count, &uarg->send_count) ||
+ get_user(tmp1, &uarg->send_indices) ||
+ get_user(tmp2, &uarg->send_sizes) ||
+ get_user(karg.flags, &uarg->flags) ||
+ get_user(karg.request_count, &uarg->request_count) ||
+ get_user(karg.request_size, &uarg->request_size) ||
+ get_user(tmp3, &uarg->request_indices) ||
+ get_user(tmp4, &uarg->request_sizes) ||
+ get_user(karg.granted_count, &uarg->granted_count))
+ return -EFAULT;
+
+ u_si = (int *) A(tmp1);
+ u_ss = (int *) A(tmp2);
+ u_ri = (int *) A(tmp3);
+ u_rs = (int *) A(tmp4);
+
+ if (karg.send_count) {
+ karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+ karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+
+ ret = -ENOMEM;
+ if (!karg.send_indices || !karg.send_sizes)
+ goto out;
+
+ ret = -EFAULT;
+ if (copy_from_user(karg.send_indices, u_si,
+ (karg.send_count * sizeof(int))) ||
+ copy_from_user(karg.send_sizes, u_ss,
+ (karg.send_count * sizeof(int))))
+ goto out;
+ }
+
+ if (karg.request_count) {
+ karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+ karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+
+ ret = -ENOMEM;
+ if (!karg.request_indices || !karg.request_sizes)
+ goto out;
+
+ ret = -EFAULT;
+ if (copy_from_user(karg.request_indices, u_ri,
+ (karg.request_count * sizeof(int))) ||
+ copy_from_user(karg.request_sizes, u_rs,
+ (karg.request_count * sizeof(int))))
+ goto out;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
+ set_fs(old_fs);
+
+ if (!ret) {
+ if (put_user(karg.context, &uarg->context) ||
+ put_user(karg.send_count, &uarg->send_count) ||
+ put_user(karg.flags, &uarg->flags) ||
+ put_user(karg.request_count, &uarg->request_count) ||
+ put_user(karg.request_size, &uarg->request_size) ||
+ put_user(karg.granted_count, &uarg->granted_count))
+ ret = -EFAULT;
+
+ if (karg.send_count) {
+ if (copy_to_user(u_si, karg.send_indices,
+ (karg.send_count * sizeof(int))) ||
+ copy_to_user(u_ss, karg.send_sizes,
+ (karg.send_count * sizeof(int))))
+ ret = -EFAULT;
+ }
+ if (karg.request_count) {
+ if (copy_to_user(u_ri, karg.request_indices,
+ (karg.request_count * sizeof(int))) ||
+ copy_to_user(u_rs, karg.request_sizes,
+ (karg.request_count * sizeof(int))))
+ ret = -EFAULT;
+ }
+ }
+
+out:
+ if (karg.send_indices)
+ kfree(karg.send_indices);
+ if (karg.send_sizes)
+ kfree(karg.send_sizes);
+ if (karg.request_indices)
+ kfree(karg.request_indices);
+ if (karg.request_sizes)
+ kfree(karg.request_sizes);
+
+ return ret;
+}
+
+typedef struct drm32_ctx_res {
+ int count;
+ u32 contexts; /* (drm_ctx_t *) */
+} drm32_ctx_res_t;
+#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t)
+
+static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
+ drm_ctx_t *ulist;
+ drm_ctx_res_t karg;
+ mm_segment_t old_fs;
+ int orig_count, ret;
+ u32 tmp;
+
+ karg.contexts = NULL;
+ if (get_user(karg.count, &uarg->count) ||
+ get_user(tmp, &uarg->contexts))
+ return -EFAULT;
+
+ ulist = (drm_ctx_t *) A(tmp);
+
+ orig_count = karg.count;
+ if (karg.count && ulist) {
+ karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
+ if (!karg.contexts)
+ return -ENOMEM;
+ if (copy_from_user(karg.contexts, ulist,
+ (karg.count * sizeof(drm_ctx_t)))) {
+ kfree(karg.contexts);
+ return -EFAULT;
+ }
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
+ set_fs(old_fs);
+
+ if (!ret) {
+ if (orig_count) {
+ if (copy_to_user(ulist, karg.contexts,
+ (orig_count * sizeof(drm_ctx_t))))
+ ret = -EFAULT;
+ }
+ if (put_user(karg.count, &uarg->count))
+ ret = -EFAULT;
+ }
+
+ if (karg.contexts)
+ kfree(karg.contexts);
+
+ return ret;
+}
+
+#endif
+
static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
{
return -EINVAL;
@@ -2961,6 +3497,27 @@ COMPATIBLE_IOCTL(LV_SET_ACCESS)
COMPATIBLE_IOCTL(LV_SET_STATUS)
COMPATIBLE_IOCTL(LV_SET_ALLOCATION)
#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
+COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
+COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
+COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
+COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
+COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
+COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
+COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
+COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
+#endif /* DRM */
/* elevator */
COMPATIBLE_IOCTL(BLKELVGET)
COMPATIBLE_IOCTL(BLKELVSET)
@@ -3108,6 +3665,17 @@ HANDLE_IOCTL(LE_REMAP, do_lvm_ioctl)
HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
#endif /* LVM */
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
+HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
+HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
+HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
+HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
+HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
+HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
+#endif /* DRM */
IOCTL_TABLE_END
unsigned int ioctl32_hash_table[1024];
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index efd6a64d1..f893e7f3a 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -42,6 +42,38 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
/* #define DEBUG_SIGNALS_TRACE 1 */
/* #define DEBUG_SIGNALS_MAPS 1 */
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ switch (from->si_code >> 16) {
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ case __SI_FAULT >> 16:
+ case __SI_POLL >> 16:
+ err |= __put_user(from->si_trapno, &to->si_trapno);
+ default:
+ err |= __put_user(from->si_addr, &to->si_addr);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/* {set, get}context() needed for 64-bit SparcLinux userland. */
asmlinkage void sparc64_set_context(struct pt_regs *regs)
{
@@ -512,7 +544,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
sizeof(struct reg_window));
if (info)
- err |= copy_to_user(&sf->info, info, sizeof(siginfo_t));
+ err |= copy_siginfo_to_user(&sf->info, info);
else {
err |= __put_user(signo, &sf->info.si_signo);
err |= __put_user(SI_NOINFO, &sf->info.si_code);
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 1f5c03716..f908b0636 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -108,17 +108,21 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32)))
return -EFAULT;
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member.
+ This routine must convert siginfo from 64bit to 32bit as well
+ at the same time. */
err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user(from->si_code, &to->si_code);
+ err |= __put_user((short)from->si_code, &to->si_code);
if (from->si_code < 0)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else {
- int signo = from->si_signo;
- if (from->si_code == SI_USER || from->si_code == SI_KERNEL)
- signo = SIGRTMIN;
- switch (signo) {
- case SIGCHLD:
+ switch (from->si_code >> 16) {
+ case __SI_CHLD >> 16:
err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status);
@@ -126,16 +130,12 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
break;
- case SIGURG:
- case SIGIO:
- case SIGSEGV:
- case SIGILL:
- case SIGFPE:
- case SIGBUS:
- case SIGEMT:
+ case __SI_FAULT >> 16:
+ case __SI_POLL >> 16:
err |= __put_user(from->si_trapno, &to->si_trapno);
err |= __put_user((long)from->si_addr, &to->si_addr);
break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
}
}
return err;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 12a872447..942f37640 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.84 2000/05/09 17:40:14 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.85 2000/05/23 02:14:25 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -83,6 +83,7 @@ extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
extern long sparc32_open(const char * filename, int flags, int mode);
extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
extern int unregister_ioctl32_conversion(unsigned int cmd);
+extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
@@ -223,6 +224,9 @@ EXPORT_SYMBOL(pci_dma_supported);
EXPORT_SYMBOL(register_ioctl32_conversion);
EXPORT_SYMBOL(unregister_ioctl32_conversion);
+/* I/O device mmaping on Sparc64. */
+EXPORT_SYMBOL(io_remap_page_range);
+
/* Solaris/SunOS binary compatibility */
EXPORT_SYMBOL(_sigpause_common);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 12592b747..db6d2b4d0 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -2052,43 +2052,84 @@ asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize
return ret;
}
-extern asmlinkage int
-sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
- const struct timespec *uts, size_t sigsetsize);
-
asmlinkage int
sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
struct timespec32 *uts, __kernel_size_t32 sigsetsize)
{
- sigset_t s;
- sigset_t32 s32;
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs();
+ int ret, sig;
+ sigset_t these;
+ sigset_t32 these32;
+ struct timespec ts;
siginfo_t info;
-
- if (copy_from_user (&s32, uthese, sizeof(sigset_t32)))
+ long timeout = 0;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user (&these32, uthese, sizeof(sigset_t32)))
return -EFAULT;
+
switch (_NSIG_WORDS) {
- case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
- case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
- case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
- case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+ case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32);
+ case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32);
+ case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32);
+ case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32);
}
+
+ /*
+ * Invert the set of allowed signals to get those we
+ * want to block.
+ */
+ sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP));
+ signotset(&these);
+
if (uts) {
- ret = get_user (t.tv_sec, &uts->tv_sec);
- ret |= __get_user (t.tv_nsec, &uts->tv_nsec);
- if (ret)
- return -EFAULT;
+ if (get_user (ts.tv_sec, &uts->tv_sec) ||
+ get_user (ts.tv_nsec, &uts->tv_nsec))
+ return -EINVAL;
+ if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0
+ || ts.tv_sec < 0)
+ return -EINVAL;
}
- set_fs (KERNEL_DS);
- ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
- set_fs (old_fs);
- if (ret >= 0 && uinfo) {
- extern int copy_siginfo_to_user32(siginfo_t32 *, siginfo_t *);
- if (copy_siginfo_to_user32(uinfo, &info))
- ret = -EFAULT;
+
+ spin_lock_irq(&current->sigmask_lock);
+ sig = dequeue_signal(&these, &info);
+ if (!sig) {
+ /* None ready -- temporarily unblock those we're interested
+ in so that we'll be awakened when they arrive. */
+ sigset_t oldblocked = current->blocked;
+ sigandsets(&current->blocked, &current->blocked, &these);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ if (uts)
+ timeout = (timespec_to_jiffies(&ts)
+ + (ts.tv_sec || ts.tv_nsec));
+
+ current->state = TASK_INTERRUPTIBLE;
+ timeout = schedule_timeout(timeout);
+
+ spin_lock_irq(&current->sigmask_lock);
+ sig = dequeue_signal(&these, &info);
+ current->blocked = oldblocked;
+ recalc_sigpending(current);
}
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (sig) {
+ ret = sig;
+ if (uinfo) {
+ if (copy_siginfo_to_user32(uinfo, &info))
+ ret = -EFAULT;
+ }
+ } else {
+ ret = -EAGAIN;
+ if (timeout)
+ ret = -EINTR;
+ }
+
return ret;
}
diff --git a/arch/sparc64/mm/modutil.c b/arch/sparc64/mm/modutil.c
index 6d68d7468..8ae715c38 100644
--- a/arch/sparc64/mm/modutil.c
+++ b/arch/sparc64/mm/modutil.c
@@ -1,4 +1,4 @@
-/* $Id: modutil.c,v 1.4 1998/07/26 06:29:08 davem Exp $
+/* $Id: modutil.c,v 1.5 2000/05/23 23:09:08 davem Exp $
* arch/sparc64/mm/modutil.c
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -58,7 +58,7 @@ void * module_map (unsigned long size)
area->next = *p;
*p = area;
- if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) {
+ if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL)) {
vfree(addr);
return NULL;
}