summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/sparc/kernel
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/entry.S60
-rw-r--r--arch/sparc/kernel/head.S15
-rw-r--r--arch/sparc/kernel/irq.c153
-rw-r--r--arch/sparc/kernel/muldiv.c43
-rw-r--r--arch/sparc/kernel/process.c6
-rw-r--r--arch/sparc/kernel/ptrace.c10
-rw-r--r--arch/sparc/kernel/rtrap.S28
-rw-r--r--arch/sparc/kernel/setup.c118
-rw-r--r--arch/sparc/kernel/signal.c329
-rw-r--r--arch/sparc/kernel/smp.c24
-rw-r--r--arch/sparc/kernel/sparc-stub.c41
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c4
-rw-r--r--arch/sparc/kernel/sun4d_irq.c483
-rw-r--r--arch/sparc/kernel/sun4m_irq.c8
-rw-r--r--arch/sparc/kernel/sunos_ioctl.c6
-rw-r--r--arch/sparc/kernel/sys_sparc.c103
-rw-r--r--arch/sparc/kernel/sys_sunos.c110
-rw-r--r--arch/sparc/kernel/systbls.S36
19 files changed, 1105 insertions, 476 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index d3307e463..7be8ddd3a 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $
+# $Id: Makefile,v 1.41 1997/11/19 15:11:59 jj Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -31,7 +31,7 @@ endif
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
-IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
+IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
process.o signal.o ioport.o setup.o idprom.o \
sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 59dd627b2..d82c098d5 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.138 1997/04/15 09:00:50 davem Exp $
+/* $Id: entry.S,v 1.142 1998/01/07 06:33:47 baccala Exp $
* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -92,8 +92,8 @@ C_LABEL(trap_low):
/* Load new kgdb register set. */
LOAD_KGDB_GLOBALS(sp)
LOAD_KGDB_INS(sp)
- LOAD_KGDB_SREGS(sp, l0, l2)
- wr %l0, 0x0, %y
+ LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
+ wr %l4, 0x0, %y
sethi %hi(in_trap_handler), %l4
ld [%lo(in_trap_handler) + %l4], %l5
@@ -108,7 +108,7 @@ C_LABEL(trap_low):
STORE_PT_INS(sp)
STORE_PT_GLOBALS(sp)
STORE_PT_YREG(sp, g2)
- STORE_PT_PRIV(sp, l1, l2, l3)
+ STORE_PT_PRIV(sp, l0, l1, l2)
RESTORE_ALL
@@ -283,7 +283,7 @@ bad_trap_handler:
*/
.align 4
- .globl real_irq_entry
+ .globl real_irq_entry, patch_handler_irq
real_irq_entry:
SAVE_ALL
@@ -299,6 +299,7 @@ real_irq_continue:
wr %g2, PSR_ET, %psr
WRITE_PAUSE
mov %l7, %o0 ! irq level
+patch_handler_irq:
call C_LABEL(handler_irq)
add %sp, REGWIN_SZ, %o1 ! pt_regs ptr
wr %l0, PSR_ET, %psr
@@ -1109,7 +1110,7 @@ C_LABEL(sys_ptrace):
call C_LABEL(do_ptrace)
add %sp, REGWIN_SZ, %o0
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1143,7 +1144,7 @@ C_LABEL(sys_sigpause):
call C_LABEL(do_sigpause)
add %sp, REGWIN_SZ, %o1
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1161,7 +1162,26 @@ C_LABEL(sys_sigsuspend):
call C_LABEL(do_sigsuspend)
add %sp, REGWIN_SZ, %o0
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be 1f
+ nop
+
+ call C_LABEL(syscall_trace)
+ nop
+
+1:
+ /* We are returning to a signal handler. */
+ RESTORE_ALL
+
+ .align 4
+ .globl C_LABEL(sys_rt_sigsuspend)
+C_LABEL(sys_rt_sigsuspend):
+ /* Note: %o0, %o1 already have correct value... */
+ call C_LABEL(do_rt_sigsuspend)
+ add %sp, REGWIN_SZ, %o2
+
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1179,7 +1199,7 @@ C_LABEL(sys_sigreturn):
call C_LABEL(do_sigreturn)
add %sp, REGWIN_SZ, %o0
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be 1f
nop
@@ -1193,6 +1213,24 @@ C_LABEL(sys_sigreturn):
*/
RESTORE_ALL
+ .align 4
+ .globl C_LABEL(sys_rt_sigreturn)
+C_LABEL(sys_rt_sigreturn):
+ call C_LABEL(do_rt_sigreturn)
+ add %sp, REGWIN_SZ, %o0
+
+ ld [%curptr + AOFF_task_flags], %l5
+ andcc %l5, 0x20, %g0
+ be 1f
+ nop
+
+ call C_LABEL(syscall_trace)
+ nop
+
+1:
+ /* We are returning to a signal handler. */
+ RESTORE_ALL
+
/* Now that we have a real sys_clone, sys_fork() is
* implemented in terms of it. Our _real_ implementation
* of SunOS vfork() will use sys_clone() instead.
@@ -1301,7 +1339,7 @@ syscall_is_too_hard:
mov %i1, %o1
mov %i2, %o2
- ld [%curptr + 0x14], %l5
+ ld [%curptr + AOFF_task_flags], %l5
mov %i3, %o3
andcc %l5, 0x20, %g0
mov %i4, %o4
@@ -1315,7 +1353,7 @@ syscall_is_too_hard:
.globl C_LABEL(ret_sys_call)
C_LABEL(ret_sys_call):
- ld [%curptr + 0x14], %l6
+ ld [%curptr + AOFF_task_flags], %l6
cmp %o0, -ENOIOCTLCMD
ld [%sp + REGWIN_SZ + PT_PSR], %g3
set PSR_C, %g2
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 5742453ff..2de97e92b 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.83 1997/08/28 11:10:39 jj Exp $
+/* $Id: head.S,v 1.84 1997/11/19 15:12:01 jj Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -843,7 +843,7 @@ got_prop:
cmp %l1, 'm' ! Test for sun4d, sun4e ?
be sun4m_init
cmp %l1, 'd' ! Let us see how the beast will die
- be sun4m_init
+ be sun4d_init
nop
/* Jump into mmu context zero. */
@@ -853,6 +853,17 @@ got_prop:
b sun4c_continue_boot
nop
+sun4d_init:
+ /* Need to patch call to handler_irq */
+ set C_LABEL(patch_handler_irq), %g4
+ set C_LABEL(sun4d_handler_irq), %g5
+ sethi %hi(0x40000000), %g3 ! call
+ sub %g5, %g4, %g5
+ srl %g5, 2, %g5
+ or %g5, %g3, %g5
+ st %g5, [%g4]
+ /* Fall through to sun4m_init */
+
sun4m_init:
/* XXX Fucking Cypress... */
lda [%g0] ASI_M_MMUREGS, %g5
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index b22f008a1..08c0be5c6 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.75 1997/05/08 20:57:37 davem Exp $
+/* $Id: irq.c,v 1.77 1997/11/19 15:33:05 jj Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -41,10 +41,6 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
-#ifdef __SMP_PROF__
-extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
-#endif
-
/*
* Dave Redman (djhr@tadpole.co.uk)
*
@@ -101,10 +97,10 @@ void (*set_irq_udt)(int);
*
*/
#define MAX_STATIC_ALLOC 4
-static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-static int static_irq_count = 0;
+struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+int static_irq_count = 0;
-static struct irqaction *irq_action[NR_IRQS+1] = {
+struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
@@ -114,6 +110,11 @@ int get_irq_list(char *buf)
int i, len = 0;
struct irqaction * action;
+ if (sparc_cpu_model == sun4d) {
+ extern int sun4d_get_irq_list(char *);
+
+ return sun4d_get_irq_list(buf);
+ }
for (i = 0 ; i < (NR_IRQS+1) ; i++) {
action = *(i + irq_action);
if (!action)
@@ -132,109 +133,6 @@ int get_irq_list(char *buf)
return len;
}
-#ifdef __SMP_PROF__
-
-static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
-
-extern unsigned int prof_multiplier[NR_CPUS];
-extern unsigned int prof_counter[NR_CPUS];
-
-int get_smp_prof_list(char *buf) {
- int i,j, len = 0;
- struct irqaction * action;
- unsigned long sum_spins = 0;
- unsigned long sum_spins_syscall = 0;
- unsigned long sum_spins_sys_idle = 0;
- unsigned long sum_smp_idle_count = 0;
- unsigned long sum_local_timer_ticks = 0;
-
- for (i=0;i<smp_num_cpus;i++) {
- int cpunum = cpu_logical_map[i];
- sum_spins+=smp_spins[cpunum];
- sum_spins_syscall+=smp_spins_syscall[cpunum];
- sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
- sum_smp_idle_count+=smp_idle_count[cpunum];
- sum_local_timer_ticks+=smp_local_timer_ticks[cpunum];
- }
-
- len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
- len += sprintf(buf+len," SUM ");
- for (i=0;i<smp_num_cpus;i++)
- len += sprintf(buf+len," P%1d ",cpu_logical_map[i]);
- len += sprintf(buf+len,"\n");
- for (i = 0 ; i < NR_IRQS ; i++) {
- action = *(i + irq_action);
- if (!action || !action->handler)
- continue;
- len += sprintf(buf+len, "%3d: %10d ",
- i, kstat.interrupts[i]);
- for (j=0;j<smp_num_cpus;j++)
- len+=sprintf(buf+len, "%10d ",
- int_count[cpu_logical_map[j]][i]);
- len += sprintf(buf+len, "%c %s",
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT) ? " +" : "",
- action->name);
- }
- len += sprintf(buf+len, "\n");
- }
- len+=sprintf(buf+len, "LCK: %10lu",
- sum_spins);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_spins[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," spins from int\n");
-
- len+=sprintf(buf+len, "LCK: %10lu",
- sum_spins_syscall);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_spins_syscall[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," spins from syscall\n");
-
- len+=sprintf(buf+len, "LCK: %10lu",
- sum_spins_sys_idle);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," spins from sysidle\n");
- len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
-
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_idle_count[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," idle ticks\n");
-
- len+=sprintf(buf+len,"TICK %10lu",sum_local_timer_ticks);
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10lu",smp_local_timer_ticks[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," local APIC timer ticks\n");
-
- len+=sprintf(buf+len,"MULT: ");
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10u",prof_multiplier[cpu_logical_map[i]]);
- len +=sprintf(buf+len," profiling multiplier\n");
-
- len+=sprintf(buf+len,"COUNT: ");
- for (i=0;i<smp_num_cpus;i++)
- len+=sprintf(buf+len," %10u",prof_counter[cpu_logical_map[i]]);
-
- len +=sprintf(buf+len," profiling counter\n");
-
- len+=sprintf(buf+len, "IPI: %10lu received\n",
- ipi_count);
-
- return len;
-}
-#endif
-
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action;
@@ -242,6 +140,11 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long flags;
unsigned int cpu_irq;
+ if (sparc_cpu_model == sun4d) {
+ extern void sun4d_free_irq(unsigned int, void *);
+
+ return sun4d_free_irq(irq, dev_id);
+ }
cpu_irq = irq & NR_IRQS;
action = *(cpu_irq + irq_action);
if (cpu_irq > 14) { /* 14 irq levels on the sparc */
@@ -531,29 +434,28 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
void handler_irq(int irq, struct pt_regs * regs)
{
struct irqaction * action;
- unsigned int cpu_irq = irq & NR_IRQS;
int cpu = smp_processor_id();
#ifdef __SMP__
extern void smp_irq_rotate(int cpu);
#endif
- disable_pil_irq(cpu_irq);
+ disable_pil_irq(irq);
#ifdef __SMP__
/* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
if(irq < 10)
smp_irq_rotate(cpu);
#endif
- irq_enter(cpu, cpu_irq, regs);
- action = *(cpu_irq + irq_action);
- kstat.interrupts[cpu_irq]++;
+ irq_enter(cpu, irq, regs);
+ action = *(irq + irq_action);
+ kstat.interrupts[irq]++;
do {
if (!action || !action->handler)
unexpected_irq(irq, 0, regs);
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
- irq_exit(cpu, cpu_irq);
- enable_pil_irq(cpu_irq);
+ irq_exit(cpu, irq);
+ enable_pil_irq(irq);
}
#ifdef CONFIG_BLK_DEV_FD
@@ -669,12 +571,22 @@ int request_irq(unsigned int irq,
unsigned long flags;
unsigned int cpu_irq;
+ if (sparc_cpu_model == sun4d) {
+ extern int sun4d_request_irq(unsigned int,
+ void (*)(int, void *, struct pt_regs *),
+ unsigned long, const char *, void *);
+ return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
+ }
cpu_irq = irq & NR_IRQS;
if(cpu_irq > 14)
return -EINVAL;
if (!handler)
return -EINVAL;
+
+ if (irqflags & SA_DCOOKIE)
+ dev_id = ((struct devid_cookie *)dev_id)->real_dev_id;
+
action = *(cpu_irq + irq_action);
if (action) {
if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
@@ -751,6 +663,7 @@ __initfunc(void init_IRQ(void))
{
extern void sun4c_init_IRQ( void );
extern void sun4m_init_IRQ( void );
+ extern void sun4d_init_IRQ( void );
switch(sparc_cpu_model) {
case sun4c:
@@ -760,6 +673,10 @@ __initfunc(void init_IRQ(void))
case sun4m:
sun4m_init_IRQ();
break;
+
+ case sun4d:
+ sun4d_init_IRQ();
+ break;
case ap1000:
#if CONFIG_AP1000
diff --git a/arch/sparc/kernel/muldiv.c b/arch/sparc/kernel/muldiv.c
index 6a193200b..b2cc64bb0 100644
--- a/arch/sparc/kernel/muldiv.c
+++ b/arch/sparc/kernel/muldiv.c
@@ -1,4 +1,4 @@
-/* $Id: muldiv.c,v 1.4 1997/04/11 00:42:08 davem Exp $
+/* $Id: muldiv.c,v 1.5 1997/12/15 20:07:20 ecd Exp $
* muldiv.c: Hardware multiply/division illegal instruction trap
* for sun4c/sun4 (which do not have those instructions)
*
@@ -69,18 +69,23 @@ static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
ret; \
})
-static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
+static inline int
+store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs)
{
struct reg_window *win;
- if(!reg)
- return NULL;
- else if(reg < 16)
- return &regs->u_regs[reg];
- win = (struct reg_window *) regs->u_regs[UREG_FP];
- return &win->locals[reg - 16];
+ if (!reg)
+ return 0;
+ if (reg < 16) {
+ regs->u_regs[reg] = result;
+ return 0;
+ } else {
+ /* need to use put_user() in this case: */
+ win = (struct reg_window *)regs->u_regs[UREG_FP];
+ return (put_user(result, &win->locals[reg - 16]));
+ }
}
-
+
extern void handle_hw_divzero (struct pt_regs *regs, unsigned long pc,
unsigned long npc, unsigned long psr);
@@ -90,7 +95,6 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
unsigned int insn;
int inst;
unsigned int rs1, rs2, rdv;
- unsigned long *rd;
if (!pc) return -1; /* This happens to often, I think */
if (get_user (insn, (unsigned int *)pc)) return -1;
@@ -109,7 +113,6 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
rs2 = fetch_reg(rs2, regs);
}
rs1 = fetch_reg(rs1, regs);
- rd = fetch_reg_addr(rdv, regs);
switch (inst) {
case 10: /* umul */
#ifdef DEBUG_MULDIV
@@ -127,9 +130,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x%08x\n", rs2, rs1);
#endif
- if (rd) {
- if (put_user (rs1, rd)) return -1;
- }
+ if (store_reg(rs1, rdv, regs))
+ return -1;
regs->y = rs2;
break;
case 11: /* smul */
@@ -148,9 +150,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x%08x\n", rs2, rs1);
#endif
- if (rd) {
- if (put_user (rs1, rd)) return -1;
- }
+ if (store_reg(rs1, rdv, regs))
+ return -1;
regs->y = rs2;
break;
case 14: /* udiv */
@@ -179,8 +180,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x\n", rs1);
#endif
- if (rd)
- if (put_user (rs1, rd)) return -1;
+ if (store_reg(rs1, rdv, regs))
+ return -1;
break;
case 15: /* sdiv */
#ifdef DEBUG_MULDIV
@@ -208,8 +209,8 @@ int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
#ifdef DEBUG_MULDIV
printk ("0x%x\n", rs1);
#endif
- if (rd)
- if (put_user (rs1, rd)) return -1;
+ if (store_reg(rs1, rdv, regs))
+ return -1;
break;
}
if (is_foocc (insn)) {
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index ff4a3f192..32feff3de 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.100 1997/08/10 04:49:23 davem Exp $
+/* $Id: process.c,v 1.102 1997/12/01 03:36:31 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -120,7 +120,7 @@ int cpu_idle(void *unused)
}
/* endless idle loop with no priority at all */
current->counter = -100;
- if(!smp_commenced || resched_needed())
+ if(!smp_commenced || need_resched)
schedule();
}
}
@@ -197,7 +197,9 @@ void show_regwindow(struct reg_window *rw)
rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}
+#ifdef __SMP__
static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
+#endif
void show_backtrace(void)
{
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 933a5acfa..635623fb3 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -799,7 +799,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
addr = 1;
case PTRACE_CONT: { /* restart after signal. */
- if ((unsigned long) data > NSIG) {
+ if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
}
@@ -851,7 +851,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */
- if ((unsigned long) data > NSIG) {
+ if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
}
@@ -898,9 +898,7 @@ asmlinkage void syscall_trace(void)
current->pid, current->exit_code);
#endif
if (current->exit_code) {
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= (1 << (current->exit_code - 1));
- spin_unlock_irq(&current->sigmask_lock);
+ send_sig (current->exit_code, current, 1);
+ current->exit_code = 0;
}
- current->exit_code = 0;
}
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S
index 8d46d487e..68f3dc9af 100644
--- a/arch/sparc/kernel/rtrap.S
+++ b/arch/sparc/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $
+/* $Id: rtrap.S,v 1.49 1997/12/14 23:24:24 ecd Exp $
* rtrap.S: Return from Sparc trap low-level code.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -65,27 +65,24 @@ C_LABEL(ret_trap_lockless_ipi):
wr %t_psr, 0x0, %psr
b ret_trap_kernel
- mov 1, %o0
+ nop
1:
- ld [%curptr + AOFF_task_processor], %o1
ld [%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
- sll %o0, %o1, %o0
-
- andcc %g2, %o0, %g0
+ orcc %g2, %g0, %g0
be signal_p
- nop
+ ld [%curptr + AOFF_task_sigpending], %g2
call C_LABEL(schedule)
nop
+ ld [%curptr + AOFF_task_sigpending], %g2
signal_p:
- ld [%curptr + AOFF_task_signal], %g2
- ld [%curptr + AOFF_task_blocked], %o0
- andncc %g2, %o0, %g0
- be,a ret_trap_continue
+ cmp %g2, 0
+ bz,a ret_trap_continue
ld [%sp + REGWIN_SZ + PT_PSR], %t_psr
+ clr %o0
mov %l5, %o2
mov %l6, %o3
call C_LABEL(do_signal)
@@ -110,7 +107,8 @@ ret_trap_continue:
call C_LABEL(try_to_clear_window_buffer)
add %sp, REGWIN_SZ, %o0
- b,a signal_p
+ b signal_p
+ ld [%curptr + AOFF_task_sigpending], %g2
ret_trap_nobufwins:
/* Load up the user's out registers so we can pull
@@ -179,7 +177,8 @@ ret_trap_unaligned_pc:
call C_LABEL(do_memaccess_unaligned)
nop
- b,a signal_p
+ b signal_p
+ ld [%curptr + AOFF_task_sigpending], %g2
ret_trap_kernel:
/* Will the rett land us in the invalid window? */
@@ -228,7 +227,8 @@ ret_trap_user_stack_is_bolixed:
call C_LABEL(window_ret_fault)
add %sp, REGWIN_SZ, %o0
- b,a signal_p
+ b signal_p
+ ld [%curptr + AOFF_task_sigpending], %g2
.globl C_LABEL(sun4c_rett_stackchk)
C_LABEL(sun4c_rett_stackchk):
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index a6b3f9e07..e53c343da 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.85 1997/05/27 06:45:54 davem Exp $
+/* $Id: setup.c,v 1.87 1997/12/18 02:42:42 ecd Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -25,6 +25,7 @@
#include <linux/blk.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/console.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -118,7 +119,9 @@ extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
unsigned int boot_flags;
#define BOOTME_DEBUG 0x1
#define BOOTME_SINGLE 0x2
-#define BOOTME_KGDB 0x4
+#define BOOTME_KGDBA 0x4
+#define BOOTME_KGDBB 0x8
+#define BOOTME_KGDB 0xc
#ifdef CONFIG_SUN_CONSOLE
extern char *console_fb_path;
@@ -188,15 +191,14 @@ __initfunc(static void boot_flags_init(char *commands))
process_switch(*commands++);
} else if (strlen(commands) >= 9
&& !strncmp(commands, "kgdb=tty", 8)) {
- boot_flags |= BOOTME_KGDB;
switch (commands[8]) {
#ifdef CONFIG_SUN_SERIAL
case 'a':
- rs_kgdb_hook(0);
+ boot_flags |= BOOTME_KGDBA;
prom_printf("KGDB: Using serial line /dev/ttya.\n");
break;
case 'b':
- rs_kgdb_hook(1);
+ boot_flags |= BOOTME_KGDBB;
prom_printf("KGDB: Using serial line /dev/ttyb.\n");
break;
#endif
@@ -207,7 +209,6 @@ __initfunc(static void boot_flags_init(char *commands))
#endif
default:
printk("KGDB: Unknown tty line.\n");
- boot_flags &= ~BOOTME_KGDB;
break;
}
commands += 9;
@@ -273,8 +274,6 @@ extern unsigned ramdisk_size;
extern int root_mountflags;
-extern void register_console(void (*proc)(const char *));
-
char saved_command_line[256];
char reboot_command[256];
enum sparc_cpu sparc_cpu_model;
@@ -283,6 +282,16 @@ struct tt_entry *sparc_ttable;
static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+static void prom_cons_write(struct console *con, const char *str, unsigned count)
+{
+ while (count--)
+ prom_printf("%c", *str++);
+}
+
+static struct console prom_console = {
+ "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
+};
+
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -335,7 +344,7 @@ __initfunc(void setup_arch(char **cmdline_p,
printk("SUN4U\n");
break;
case ap1000:
- register_console((void (*) (const char *))prom_printf);
+ register_console(&prom_console);
printk("AP1000\n");
packed = 1;
break;
@@ -345,16 +354,6 @@ __initfunc(void setup_arch(char **cmdline_p,
};
boot_flags_init(*cmdline_p);
- if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) &&
- ((*(short *)linux_dbvec) != -1)) {
- printk("Booted under KADB. Syncing trap table.\n");
- (*(linux_dbvec->teach_debugger))();
- }
- if((boot_flags & BOOTME_KGDB)) {
- set_debug_traps();
- prom_printf ("Breakpoint!\n");
- breakpoint();
- }
idprom_init();
load_mmu();
@@ -410,6 +409,56 @@ __initfunc(void setup_arch(char **cmdline_p,
}
not_relevant:
+#ifdef CONFIG_SUN_SERIAL
+ *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
+#endif
+ {
+ extern int serial_console; /* in console.c, of course */
+#if !CONFIG_SUN_SERIAL
+ serial_console = 0;
+#else
+ switch (console_fb) {
+ case 0: /* Let get our io devices from prom */
+ {
+ int idev = prom_query_input_device();
+ int odev = prom_query_output_device();
+ if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
+ serial_console = 0;
+ } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
+ serial_console = 1;
+ } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
+ serial_console = 2;
+ } else {
+ prom_printf("Inconsistent console\n");
+ prom_halt();
+ }
+ }
+ break;
+ case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
+ case 2: serial_console = 1; break; /* Force ttya as console */
+ case 3: serial_console = 2; break; /* Force ttyb as console */
+ }
+#endif
+ }
+
+ if ((boot_flags & BOOTME_KGDBA)) {
+ rs_kgdb_hook(0);
+ }
+ if ((boot_flags & BOOTME_KGDBB)) {
+ rs_kgdb_hook(1);
+ }
+
+ if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) &&
+ ((*(short *)linux_dbvec) != -1)) {
+ printk("Booted under KADB. Syncing trap table.\n");
+ (*(linux_dbvec->teach_debugger))();
+ }
+ if((boot_flags & BOOTME_KGDB)) {
+ set_debug_traps();
+ prom_printf ("Breakpoint!\n");
+ breakpoint();
+ }
+
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = to_kdev_t(root_dev);
@@ -443,37 +492,6 @@ not_relevant:
init_task.mm->context = (unsigned long) NO_CONTEXT;
init_task.tss.kregs = &fake_swapper_regs;
-#ifdef CONFIG_SUN_SERIAL
- *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
-#endif
- {
- extern int serial_console; /* in console.c, of course */
-#if !CONFIG_SUN_SERIAL
- serial_console = 0;
-#else
- switch (console_fb) {
- case 0: /* Let get our io devices from prom */
- {
- int idev = prom_query_input_device();
- int odev = prom_query_output_device();
- if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
- serial_console = 0;
- } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
- serial_console = 1;
- } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
- serial_console = 2;
- } else {
- prom_printf("Inconsistent console\n");
- prom_halt();
- }
- }
- break;
- case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
- case 2: serial_console = 1; break; /* Force ttya as console */
- case 3: serial_console = 2; break; /* Force ttyb as console */
- }
-#endif
- }
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index fbb5578fa..5c10faa81 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $
+/* $Id: signal.c,v 1.77 1997/12/22 03:06:32 ecd Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -24,9 +24,7 @@
#include <asm/svr4.h>
#include <asm/pgtable.h>
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
@@ -35,7 +33,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
void *fpqueue, unsigned long *fpqdepth);
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
unsigned long orig_o0, int ret_from_syscall);
/* This turned off for production... */
@@ -56,12 +54,13 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
* ---------------------------------- <-- New %sp
*/
struct signal_sframe {
- struct reg_window sig_window;
- int sig_num;
- int sig_code;
- struct sigcontext *sig_scptr;
- int sig_address;
- struct sigcontext sig_context;
+ struct reg_window sig_window;
+ int sig_num;
+ int sig_code;
+ struct sigcontext *sig_scptr;
+ int sig_address;
+ struct sigcontext sig_context;
+ unsigned int extramask[_NSIG_WORDS - 1];
};
/*
@@ -75,6 +74,7 @@ struct new_signal_frame {
__siginfo_t info;
__siginfo_fpu_t *fpu_save;
unsigned long insns [2] __attribute__ ((aligned (8)));
+ unsigned int extramask[_NSIG_WORDS - 1];
__siginfo_fpu_t fpu_state;
};
@@ -86,13 +86,15 @@ struct new_signal_frame {
* atomically swap in the new signal mask, and wait for a signal.
* This is really tricky on the Sparc, watch out...
*/
-asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
+asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs)
{
- unsigned long mask;
+ sigset_t saveset;
+ set &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock);
- mask = current->blocked;
- current->blocked = set & _BLOCKABLE;
+ saveset = current->blocked;
+ siginitset(&current->blocked, set);
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
regs->pc = regs->npc;
@@ -112,7 +114,7 @@ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
*/
regs->psr |= PSR_C;
regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(mask, regs, 0, 0))
+ if (do_signal(&saveset, regs, 0, 0))
return;
}
}
@@ -127,6 +129,52 @@ asmlinkage void do_sigsuspend (struct pt_regs *regs)
_sigpause_common(regs->u_regs[UREG_I0], regs);
}
+asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize,
+ struct pt_regs *regs)
+{
+ sigset_t oldset, set;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t)) {
+ regs->psr |= PSR_C;
+ regs->u_regs[UREG_I0] = EINVAL;
+ return;
+ }
+
+ if (copy_from_user(&set, uset, sizeof(set))) {
+ regs->psr |= PSR_C;
+ regs->u_regs[UREG_I0] = EFAULT;
+ return;
+ }
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ oldset = current->blocked;
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->pc = regs->npc;
+ regs->npc += 4;
+
+ /* Condition codes and return value where set here for sigpause,
+ * and so got used by setup_frame, which again causes sigreturn()
+ * to return -EINTR.
+ */
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ /*
+ * Return -EINTR and set condition code here,
+ * so the interrupted system call actually returns
+ * these.
+ */
+ regs->psr |= PSR_C;
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal(&oldset, regs, 0, 0))
+ return;
+ }
+}
static inline void
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
@@ -154,11 +202,12 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
(sizeof(unsigned long *)))*16));
}
-void do_new_sigreturn (struct pt_regs *regs)
+static inline void do_new_sigreturn (struct pt_regs *regs)
{
struct new_signal_frame *sf;
- unsigned long up_psr, pc, npc, mask;
-
+ unsigned long up_psr, pc, npc;
+ sigset_t set;
+
sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
/* 1. Make sure we are not getting garbage from the user */
@@ -173,7 +222,7 @@ void do_new_sigreturn (struct pt_regs *regs)
if ((pc | npc) & 3)
goto segv_and_exit;
-
+
/* 2. Restore the state */
up_psr = regs->psr;
copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
@@ -181,28 +230,36 @@ void do_new_sigreturn (struct pt_regs *regs)
/* User can only change condition codes and FPU enabling in %psr. */
regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
| (regs->psr & (PSR_ICC | PSR_EF));
-
+
if (sf->fpu_save)
restore_fpu_state(regs, sf->fpu_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
- __get_user(mask, &sf->info.si_mask);
- current->blocked = (mask & _BLOCKABLE);
+ if (__get_user(set.sig[0], &sf->info.si_mask) ||
+ copy_from_user(&set.sig[1], &sf->extramask,
+ (_NSIG_WORDS-1) * sizeof(unsigned int)))
+ goto segv_and_exit;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
return;
segv_and_exit:
/* Ugh, we need to grab master lock in these rare cases ;-( */
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
}
asmlinkage void do_sigreturn(struct pt_regs *regs)
{
struct sigcontext *scptr;
- unsigned long pc, npc, psr, mask;
+ unsigned long pc, npc, psr;
+ sigset_t set;
synchronize_user_stack();
@@ -225,8 +282,17 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
- __get_user(mask, &scptr->sigc_mask);
- current->blocked = (mask & _BLOCKABLE);
+ if (__get_user(set.sig[0], &scptr->sigc_mask) ||
+ /* Note that scptr + 1 points to extramask */
+ copy_from_user(&set.sig[1], scptr + 1,
+ (_NSIG_WORDS - 1) * sizeof(unsigned int)))
+ goto segv_and_exit;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
__get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack);
current->tss.sstk_info.cur_status &= 1;
@@ -248,11 +314,15 @@ segv_and_exit:
/* Ugh, we need to grab master lock in these rare cases ;-( */
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
+}
+
+asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
+{
+ printk("XXX: FIXME: write do_rt_sigreturn\n");
}
/* Checks if the fp is valid */
-int invalid_frame_pointer (void *fp, int fplen)
+static inline int invalid_frame_pointer (void *fp, int fplen)
{
if ((((unsigned long) fp) & 7) ||
!__access_ok((unsigned long)fp, fplen) ||
@@ -263,8 +333,9 @@ int invalid_frame_pointer (void *fp, int fplen)
return 0;
}
-static void setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
- struct pt_regs *regs, int signr, unsigned long oldmask)
+static inline void
+setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
+ struct pt_regs *regs, int signr, sigset_t *oldset)
{
struct signal_sframe *sframep;
struct sigcontext *sc;
@@ -291,7 +362,9 @@ static void setup_frame(struct sigaction *sa, unsigned long pc, unsigned long np
/* We've already made sure frame pointer isn't in kernel space... */
__put_user(old_status, &sc->sigc_onstack);
- __put_user(oldmask, &sc->sigc_mask);
+ __put_user(oldset->sig[0], &sc->sigc_mask);
+ __copy_to_user(sframep->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
__put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
__put_user(pc, &sc->sigc_pc);
__put_user(npc, &sc->sigc_npc);
@@ -334,7 +407,6 @@ sigill_and_return:
/* Ugh, we need to grab master lock in these rare cases ;-( */
lock_kernel();
do_exit(SIGILL);
- unlock_kernel();
}
@@ -369,8 +441,9 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
current->used_math = 0;
}
-static void new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
- int signo, unsigned long oldmask)
+static inline void
+new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
struct new_signal_frame *sf;
int sigframe_size;
@@ -403,39 +476,51 @@ static void new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
sf->fpu_save = NULL;
}
- __put_user(oldmask, &sf->info.si_mask);
+ __put_user(oldset->sig[0], &sf->info.si_mask);
+ __copy_to_user(sf->extramask, &oldset->sig[1],
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
sizeof (struct reg_window));
- /* 3. return to kernel instructions */
- __put_user(0x821020d8, &sf->insns [0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02010, &sf->insns [1]); /* t 0x10 */
-
- /* 4. signal handler back-trampoline and parameters */
+ /* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
regs->u_regs[UREG_I0] = signo;
regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
- regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
- /* 5. signal handler */
- regs->pc = (unsigned long) sa->sa_handler;
+ /* 4. signal handler */
+ regs->pc = (unsigned long) ka->sa.sa_handler;
regs->npc = (regs->pc + 4);
- /* Flush instruction space. */
- flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+ /* 5. return to kernel instructions */
+ if (ka->ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ else {
+ regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
+
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+
+ /* Flush instruction space. */
+ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+ }
return;
sigill_and_return:
lock_kernel();
do_exit(SIGILL);
- unlock_kernel();
}
+static inline void
+new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset, siginfo_t *info)
+{
+ printk("XXX: FIXME: new_setup_rt_frame unimplemented\n");
+}
/* Setup a Solaris stack frame */
static inline void
setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
- struct pt_regs *regs, int signr, unsigned long oldmask)
+ struct pt_regs *regs, int signr, sigset_t *oldset)
{
svr4_signal_frame_t *sfp;
svr4_gregset_t *gr;
@@ -443,6 +528,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
svr4_mcontext_t *mc;
svr4_gwindows_t *gw;
svr4_ucontext_t *uc;
+ svr4_sigset_t setv;
int window = 0;
synchronize_user_stack();
@@ -470,7 +556,14 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
* sc->sigc_onstack = old_status;
* anyways, it does not look like it is used for anything at all.
*/
- __put_user(oldmask, &uc->sigmask.sigbits [0]);
+ setv.sigbits[0] = oldset->sig[0];
+ setv.sigbits[1] = oldset->sig[1];
+ if (_NSIG_WORDS >= 4) {
+ setv.sigbits[2] = oldset->sig[2];
+ setv.sigbits[3] = oldset->sig[3];
+ __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ } else
+ __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
__put_user(regs->pc, &((*gr) [SVR4_PC]));
@@ -547,13 +640,13 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
sigill_and_return:
lock_kernel();
do_exit(SIGILL);
- unlock_kernel();
}
asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
{
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
+ svr4_sigset_t setv;
synchronize_user_stack();
@@ -566,9 +659,15 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
/* Setup convenience variables */
mc = &uc->mcontext;
gr = &mc->greg;
-
- /* We only have < 32 signals, fill the first slot only */
- __put_user(current->blocked, &uc->sigmask.sigbits [0]);
+
+ setv.sigbits[0] = current->blocked.sig[0];
+ setv.sigbits[1] = current->blocked.sig[1];
+ if (_NSIG_WORDS >= 4) {
+ setv.sigbits[2] = current->blocked.sig[2];
+ setv.sigbits[3] = current->blocked.sig[3];
+ __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ } else
+ __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
/* Store registers */
__put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
@@ -593,8 +692,6 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
sigsegv_and_return:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
- return -EFAULT;
}
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
@@ -602,7 +699,9 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
{
struct thread_struct *tp = &current->tss;
svr4_gregset_t *gr;
- unsigned long pc, npc, psr, mask;
+ unsigned long pc, npc, psr;
+ sigset_t set;
+ svr4_sigset_t setv;
/* Fixme: restore windows, or is this already taken care of in
* svr4_setup_frame when sync_user_windows is done?
@@ -633,8 +732,19 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
- __get_user(mask, &c->sigmask.sigbits [0]);
- current->blocked = (mask & _BLOCKABLE);
+ if (__copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t)))
+ goto sigsegv_and_return;
+ set.sig[0] = setv.sigbits[0];
+ set.sig[1] = setv.sigbits[1];
+ if (_NSIG_WORDS >= 4) {
+ set.sig[2] = setv.sigbits[2];
+ set.sig[3] = setv.sigbits[3];
+ }
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
regs->pc = pc;
regs->npc = npc | 1;
__get_user(regs->y, &((*gr) [SVR4_Y]));
@@ -650,27 +760,29 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
sigsegv_and_return:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
- return -EFAULT;
}
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs *regs,
- int svr4_signal)
+static inline void
+handle_signal(unsigned long signr, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
+ int svr4_signal)
{
- if(svr4_signal)
- setup_svr4_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
+ if (svr4_signal)
+ setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset);
else {
- if (current->tss.new_signal)
- new_setup_frame (sa, regs, signr, oldmask);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ new_setup_rt_frame(ka, regs, signr, oldset, info);
+ else if (current->tss.new_signal)
+ new_setup_frame (ka, regs, signr, oldset);
else
- setup_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
+ setup_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset);
}
- if(sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if(!(sa->sa_flags & SA_NOMASK)) {
+ if(ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+ if(!(ka->sa.sa_flags & SA_NOMASK)) {
spin_lock_irq(&current->sigmask_lock);
- current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked, signr);
spin_unlock_irq(&current->sigmask_lock);
}
}
@@ -699,22 +811,25 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
unsigned long orig_i0, int restart_syscall)
{
- unsigned long signr, mask = ~current->blocked;
- struct sigaction *sa;
+ unsigned long signr;
+ struct k_sigaction *ka;
+ siginfo_t info;
+
int svr4_signal = current->personality == PER_SVR4;
-
- while ((signr = current->signal & mask) != 0) {
- signr = ffz(~signr);
+ if (!oldset)
+ oldset = &current->blocked;
+
+ for (;;) {
spin_lock_irq(&current->sigmask_lock);
- current->signal &= ~(1 << signr);
+ signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sigmask_lock);
- sa = current->sig->action + signr;
- signr++;
+ if (!signr) break;
+
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
@@ -729,15 +844,26 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = 0;
if (signr == SIGSTOP)
continue;
- if (_S(signr) & current->blocked) {
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= _S(signr);
- spin_unlock_irq(&current->sigmask_lock);
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
continue;
}
- sa = current->sig->action + signr - 1;
}
- if(sa->sa_handler == SIG_IGN) {
+
+ ka = &current->sig->action[signr-1];
+
+ if(ka->sa.sa_handler == SIG_IGN) {
if(signr != SIGCHLD)
continue;
@@ -750,7 +876,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
;
continue;
}
- if(sa->sa_handler == SIG_DFL) {
+ if(ka->sa.sa_handler == SIG_DFL) {
+ unsigned long exit_code = signr;
+
if(current->pid == 1)
continue;
switch(signr) {
@@ -758,8 +886,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
continue;
case SIGTSTP: case SIGTTIN: case SIGTTOU:
- /* The operations performed by is_orphaned_pgrp()
- * are protected by the tasklist_lock.
+ /* The operations performed by
+ * is_orphaned_pgrp() are protected by
+ * the tasklist_lock.
*/
if (is_orphaned_pgrp(current->pgrp))
continue;
@@ -771,7 +900,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
/* notify_parent() is SMP safe */
- if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
@@ -782,7 +911,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
if(current->binfmt && current->binfmt->core_dump) {
lock_kernel();
if(current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
+ exit_code |= 0x80;
unlock_kernel();
}
#ifdef DEBUG_SIGNALS
@@ -792,20 +921,16 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
#endif
/* fall through */
default:
- spin_lock_irq(&current->sigmask_lock);
- current->signal |= _S(signr & 0x7f);
- spin_unlock_irq(&current->sigmask_lock);
-
+ lock_kernel();
+ sigaddset(&current->signal, signr);
current->flags |= PF_SIGNALED;
-
- lock_kernel(); /* 8-( */
- do_exit(signr);
- unlock_kernel();
+ do_exit(exit_code);
+ /* NOT REACHED */
}
}
if(restart_syscall)
- syscall_restart(orig_i0, regs, sa);
- handle_signal(signr, sa, oldmask, regs, svr4_signal);
+ syscall_restart(orig_i0, regs, &ka->sa);
+ handle_signal(signr, ka, &info, oldset, regs, svr4_signal);
return 1;
}
if(restart_syscall &&
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 17931fd55..15364d44f 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -3,6 +3,7 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h> /* for CONFIG_PROFILE */
#include <asm/head.h>
#include <linux/kernel.h>
@@ -66,16 +67,6 @@ volatile int cpu_logical_map[NR_CPUS];
struct klock_info klock_info = { KLOCK_CLEAR, 0 };
volatile unsigned long ipi_count;
-#ifdef __SMP_PROF__
-volatile unsigned long smp_spins[NR_CPUS]={0};
-volatile unsigned long smp_spins_syscall[NR_CPUS]={0};
-volatile unsigned long smp_spins_syscall_cur[NR_CPUS]={0};
-volatile unsigned long smp_spins_sys_idle[NR_CPUS]={0};
-volatile unsigned long smp_idle_count[1+NR_CPUS]={0,};
-#endif
-#if defined (__SMP_PROF__)
-volatile unsigned long smp_idle_map=0;
-#endif
volatile int smp_process_available=0;
@@ -558,7 +549,7 @@ void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
/* Reschedule call back. */
void smp_reschedule_irq(void)
{
- resched_force();
+ need_resched = 1;
}
/* Running cross calls. */
@@ -583,6 +574,8 @@ void smp_stop_cpu_irq(void)
/* Protects counters touched during level14 ticker */
spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_PROFILE
+
/* 32-bit Sparc specific profiling function. */
static inline void sparc_do_profile(unsigned long pc)
{
@@ -601,7 +594,7 @@ static inline void sparc_do_profile(unsigned long pc)
}
}
-volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]={0,};
+#endif
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
@@ -614,8 +607,10 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
int cpu = smp_processor_id();
clear_profile_irq(mid_xlate[cpu]);
+#ifdef CONFIG_PROFILE
if(!user_mode(regs))
sparc_do_profile(regs->pc);
+#endif
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
if(current->pid) {
@@ -623,7 +618,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
if(--current->counter < 0) {
current->counter = 0;
- resched_force();
+ need_resched = 1;
}
spin_lock(&ticker_lock);
@@ -639,9 +634,6 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
}
prof_counter[cpu] = prof_multiplier[cpu];
}
-#ifdef __SMP_PROF__
- smp_local_timer_ticks[cpu]++;
-#endif
}
extern unsigned int lvl14_resolution;
diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c
index 008e9c450..e259ffade 100644
--- a/arch/sparc/kernel/sparc-stub.c
+++ b/arch/sparc/kernel/sparc-stub.c
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.20 1997/01/06 06:52:31 davem Exp $
+/* $Id: sparc-stub.c,v 1.22 1998/01/07 06:33:48 baccala Exp $
* sparc-stub.c: KGDB support for the Linux kernel.
*
* Modifications to run under Linux
@@ -323,7 +323,23 @@ mem2hex(char *mem, char *buf, int count)
unsigned char ch;
while (count-- > 0) {
- ch = *mem++;
+ /* This assembler code is basically: ch = *mem++;
+ * except that we use the SPARC/Linux exception table
+ * mechanism (see how "fixup" works in kernel_mna_trap_fault)
+ * to arrange for a "return 0" upon a memory fault
+ */
+ __asm__(
+ "1: ldub [%0], %1
+ inc %0
+ .section .fixup,#alloc,#execinstr
+ .align 4
+ 2: retl
+ mov 0, %%o0
+ .section __ex_table, #alloc
+ .align 4
+ .word 1b, 2b
+ .text"
+ : "=r" (mem), "=r" (ch) : "0" (mem));
*buf++ = hexchars[ch >> 4];
*buf++ = hexchars[ch & 0xf];
}
@@ -345,7 +361,19 @@ hex2mem(char *buf, char *mem, int count)
ch = hex(*buf++) << 4;
ch |= hex(*buf++);
- *mem++ = ch;
+ /* Assembler code is *mem++ = ch; with return 0 on fault */
+ __asm__(
+ "1: stb %1, [%0]
+ inc %0
+ .section .fixup,#alloc,#execinstr
+ .align 4
+ 2: retl
+ mov 0, %%o0
+ .section __ex_table, #alloc
+ .align 4
+ .word 1b, 2b
+ .text"
+ : "=r" (mem) : "r" (ch) , "0" (mem));
}
return mem;
}
@@ -387,13 +415,18 @@ set_debug_traps(void)
/* In case GDB is started before us, ack any packets (presumably
* "$?#xx") sitting there.
+ *
+ * I've found this code causes more problems than it solves,
+ * so that's why it's commented out. GDB seems to work fine
+ * now starting either before or after the kernel -bwb
*/
-
+#if 0
while((c = getDebugChar()) != '$');
while((c = getDebugChar()) != '#');
c = getDebugChar(); /* eat first csum byte */
c = getDebugChar(); /* eat second csum byte */
putDebugChar('+'); /* ack it */
+#endif
initialized = 1; /* connect! */
restore_flags(flags);
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index cf4146c4a..df3eac300 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,10 +1,12 @@
-/* $Id: sparc_ksyms.c,v 1.60 1997/06/17 13:25:13 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.61 1997/11/19 07:57:44 jj Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*/
+/* Tell string.h we don't want memcpy etc. as cpp defines */
+#define EXPORT_SYMTAB_STROPS
#define PROMLIB_INTERNAL
#include <linux/config.h>
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
new file mode 100644
index 000000000..f22fe1495
--- /dev/null
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -0,0 +1,483 @@
+/* $Id: sun4d_irq.c,v 1.3 1997/12/22 16:09:15 jj Exp $
+ * arch/sparc/kernel/sun4d_irq.c:
+ * SS1000/SC2000 interrupt handling.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Heavily based on arch/sparc/kernel/irq.c.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/smp.h>
+#include <asm/vaddrs.h>
+#include <asm/timer.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/spinlock.h>
+#include <asm/sbus.h>
+#include <asm/sbi.h>
+
+struct sun4d_timer_regs *sun4d_timers;
+#define TIMER_IRQ 10
+
+#define MAX_STATIC_ALLOC 4
+extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+extern int static_irq_count;
+
+extern struct irqaction *irq_action[];
+
+struct sbus_action {
+ struct irqaction *action;
+ unsigned char lock;
+ unsigned char active;
+ unsigned char disabled;
+} *sbus_actions;
+
+static int pil_to_sbus[] = {
+ 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
+};
+
+static int nsbi;
+
+int sun4d_get_irq_list(char *buf)
+{
+ int i, j = 0, k = 0, len = 0, sbusl;
+ struct irqaction * action;
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ sbusl = pil_to_sbus[i];
+ if (!sbusl) {
+ action = *(i + irq_action);
+ if (!action)
+ continue;
+ } else {
+ for (j = 0; j < nsbi; j++) {
+ for (k = 0; k < 4; k++)
+ if ((action = sbus_actions [(j << 5) + (sbusl << 2) + k].action))
+ goto found_it;
+ }
+ continue;
+ }
+found_it: len += sprintf(buf+len, "%2d: %8d %c %s",
+ i, kstat.interrupts[i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ action = action->next;
+ for (;;) {
+ for (; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ if (!sbusl) break;
+ k++;
+ if (k < 4)
+ action = sbus_actions [(j << 5) + (sbusl << 2) + k].action;
+ else {
+ j++;
+ if (j == nsbi) break;
+ k = 0;
+ action = sbus_actions [(j << 5) + (sbusl << 2)].action;
+ }
+ }
+ len += sprintf(buf+len, "\n");
+ }
+ return len;
+}
+
+void sun4d_free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action, **actionp;
+ struct irqaction *tmp = NULL;
+ unsigned long flags;
+
+ if (irq < 15)
+ actionp = irq + irq_action;
+ else
+ actionp = &(sbus_actions[irq - (1 << 5)].action);
+ action = *actionp;
+ if (!action) {
+ printk("Trying to free free IRQ%d\n",irq);
+ return;
+ }
+ if (dev_id) {
+ for (; action; action = action->next) {
+ if (action->dev_id == dev_id)
+ break;
+ tmp = action;
+ }
+ if (!action) {
+ printk("Trying to free free shared IRQ%d\n",irq);
+ return;
+ }
+ } else if (action->flags & SA_SHIRQ) {
+ printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
+ return;
+ }
+ if (action->flags & SA_STATIC_ALLOC)
+ {
+ /* This interrupt is marked as specially allocated
+ * so it is a bad idea to free it.
+ */
+ printk("Attempt to free statically allocated IRQ%d (%s)\n",
+ irq, action->name);
+ return;
+ }
+
+ save_and_cli(flags);
+ if (action && tmp)
+ tmp->next = action->next;
+ else
+ *actionp = action->next;
+
+ kfree_s(action, sizeof(struct irqaction));
+
+ if (!(*actionp))
+ disable_irq(irq);
+
+ restore_flags(flags);
+}
+
+extern void unexpected_irq(int, void *, struct pt_regs *);
+
+void sun4d_handler_irq(int irq, struct pt_regs * regs)
+{
+ struct irqaction * action;
+ int cpu = smp_processor_id();
+ /* SBUS IRQ level (1 - 7) */
+ int sbusl = pil_to_sbus[irq];
+
+ /* FIXME: Is this necessary?? */
+ cc_get_ipen();
+
+ cc_set_iclr(1 << irq);
+
+ irq_enter(cpu, irq, regs);
+ kstat.interrupts[irq]++;
+ if (!sbusl) {
+ action = *(irq + irq_action);
+ if (!action)
+ unexpected_irq(irq, 0, regs);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ } else {
+ int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
+ int lock;
+ int sbino;
+ struct sbus_action *actionp;
+ unsigned mask, slot;
+ int sbil = (sbusl << 2);
+
+ bw_clear_intr_mask(sbusl, bus_mask);
+
+ /* Loop for each pending SBI */
+ for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1)
+ if (bus_mask & 1) {
+ mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
+ mask &= (0xf << sbil);
+ actionp = sbus_actions + (sbino << 5) + (sbil);
+ /* Loop for each pending SBI slot */
+ for (slot = (1 << sbil); mask; slot <<= 1, actionp++)
+ if (mask & slot) {
+ mask &= ~slot;
+ action = actionp->action;
+ __asm__ __volatile__ ("ldstub [%1 + 4], %0"
+ : "=r" (lock) : "r" (actionp));
+
+ if (!lock) {
+ if (!action)
+ unexpected_irq(irq, 0, regs);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ actionp->lock = 0;
+ } else
+ actionp->active = 1;
+ release_sbi(SBI2DEVID(sbino), slot);
+ }
+ }
+ }
+ irq_exit(cpu, irq);
+}
+
+int sun4d_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ struct irqaction *action, *tmp = NULL, **actionp;
+ unsigned long flags;
+ int sbusl;
+ unsigned int *ret = NULL;
+ struct linux_sbus_device *sdev = NULL;
+
+ if(irq > 14)
+ return -EINVAL;
+
+ if (!handler)
+ return -EINVAL;
+
+ if (irqflags & SA_DCOOKIE) {
+ struct devid_cookie *d = (struct devid_cookie *)dev_id;
+
+ dev_id = d->real_dev_id;
+ sdev = (struct linux_sbus_device *)d->bus_cookie;
+ ret = &d->ret_ino;
+ }
+
+ sbusl = pil_to_sbus[irq];
+ if (sbusl && !sdev) {
+ printk ("Attempt to register SBUS IRQ %d without DCOOKIE\n", irq);
+ return -EINVAL;
+ }
+ if (sbusl) {
+ actionp = &(sbus_actions[(sdev->my_bus->board << 5) +
+ (sbusl << 2) + sdev->slot].action);
+ *ret = ((sdev->my_bus->board + 1) << 5) +
+ (sbusl << 2) + sdev->slot;
+ } else
+ actionp = irq + irq_action;
+ action = *actionp;
+
+ if (action) {
+ if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+ for (tmp = action; tmp->next; tmp = tmp->next);
+ } else {
+ return -EBUSY;
+ }
+ if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+ printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
+ return -EBUSY;
+ }
+ action = NULL; /* Or else! */
+ }
+
+ save_and_cli(flags);
+
+ /* If this is flagged as statically allocated then we use our
+ * private struct which is never freed.
+ */
+ if (irqflags & SA_STATIC_ALLOC)
+ if (static_irq_count < MAX_STATIC_ALLOC)
+ action = &static_irqaction[static_irq_count++];
+ else
+ printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+
+ if (action == NULL)
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ GFP_KERNEL);
+
+ if (!action) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ if (tmp)
+ tmp->next = action;
+ else
+ *actionp = action;
+
+ if (ret) irq = *ret;
+
+ if (irq > NR_IRQS) {
+ struct sbus_action *s = sbus_actions + irq - (1 << 5);
+
+ if (s->disabled) {
+ s->disabled = 0;
+ s->active = 0;
+ s->lock = 0;
+ }
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void sun4d_disable_irq(unsigned int irq)
+{
+ struct sbus_action *s;
+
+ if (irq < NR_IRQS) {
+ /* FIXME */
+ printk ("Unable to disable IRQ %d\n", irq);
+ return;
+ }
+ s = sbus_actions + irq - (1 << 5);
+
+ if (s->disabled) return;
+ s->disabled = 1;
+ __asm__ __volatile__ ("
+1: ldstub [%0 + 4], %%g1
+ orcc %%g1, 0, %%g0
+ bne 1b"
+ : : "r" (s) : "g1", "cc");
+}
+
+static void sun4d_enable_irq(unsigned int irq)
+{
+ struct sbus_action *s;
+ struct irqaction *action;
+
+ if (irq < NR_IRQS)
+ /* FIXME */
+ return;
+ s = sbus_actions + irq - (1 << 5);
+
+ if (!s->disabled) return;
+ action = s->action;
+ s->disabled = 0;
+ while (s->active) {
+ s->active = 0;
+ while (action) {
+ /* FIXME: Hope no sbus intr handler uses regs */
+ action->handler(irq, action->dev_id, NULL);
+ action = action->next;
+ }
+ }
+ s->lock = 0;
+}
+
+#ifdef __SMP__
+
+/* +-------+-------------+-----------+------------------------------------+
+ * | bcast | devid | sid | levels mask |
+ * +-------+-------------+-----------+------------------------------------+
+ * 31 30 23 22 15 14 0
+ */
+#define IGEN_MESSAGE(bcast, devid, sid, levels) \
+ (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels))
+
+static void sun4d_send_ipi(int cpu, int level)
+{
+ cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1)));
+}
+
+static void sun4d_clear_ipi(int cpu, int level)
+{
+}
+
+static void sun4d_set_udt(int cpu)
+{
+}
+#endif
+
+static void sun4d_clear_clock_irq(void)
+{
+ volatile unsigned int clear_intr;
+ clear_intr = sun4d_timers->l10_timer_limit;
+}
+
+static void sun4d_clear_profile_irq(int cpu)
+{
+ bw_get_prof_limit(cpu);
+}
+
+static void sun4d_load_profile_irq(int cpu, unsigned int limit)
+{
+ bw_set_prof_limit(cpu, limit);
+}
+
+__initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)))
+{
+ int irq;
+ extern struct prom_cpuinfo linux_cpus[NCPUS];
+ int cpu;
+
+ /* Map the User Timer registers. */
+ sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0,
+ PAGE_SIZE, "user timer", 0xf, 0x0);
+
+ sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
+ master_l10_counter = &sun4d_timers->l10_cur_count;
+ master_l10_limit = &sun4d_timers->l10_timer_limit;
+
+ irq = request_irq(TIMER_IRQ,
+ counter_fn,
+ (SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", NULL);
+ if (irq) {
+ prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+ prom_halt();
+ }
+
+ /* Enable user timer free run for CPU 0 in BW */
+ /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
+
+ for(cpu = 0; cpu < NCPUS; cpu++)
+ sun4d_load_profile_irq(linux_cpus[cpu].mid, 0);
+}
+
+__initfunc(unsigned long sun4d_init_sbi_irq(unsigned long memory_start))
+{
+ struct linux_sbus *sbus;
+ struct sbus_action *s;
+ int i;
+ unsigned mask;
+
+ nsbi = 0;
+ for_each_sbus(sbus)
+ nsbi++;
+ memory_start = ((memory_start + 7) & ~7);
+ sbus_actions = (struct sbus_action *)memory_start;
+ memory_start += (nsbi * 8 * 4 * sizeof(struct sbus_action));
+ memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action)));
+ for (i = 0, s = sbus_actions; i < nsbi * 8 * 4; i++, s++) {
+ s->lock = 0xff;
+ s->disabled = 1;
+ }
+ for_each_sbus(sbus) {
+ /* Get rid of pending irqs from PROM */
+ mask = acquire_sbi(sbus->devid, 0xffffffff);
+ if (mask) {
+ printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
+ release_sbi(sbus->devid, mask);
+ }
+ }
+ return memory_start;
+}
+
+__initfunc(void sun4d_init_IRQ(void))
+{
+ __cli();
+
+ enable_irq = sun4d_enable_irq;
+ disable_irq = sun4d_disable_irq;
+ clear_clock_irq = sun4d_clear_clock_irq;
+ clear_profile_irq = sun4d_clear_profile_irq;
+ load_profile_irq = sun4d_load_profile_irq;
+ init_timers = sun4d_init_timers;
+#ifdef __SMP__
+ set_cpu_int = (void (*) (int, int))sun4d_send_ipi;
+ clear_cpu_int = (void (*) (int, int))sun4d_clear_ipi;
+ set_irq_udt = (void (*) (int))sun4d_set_udt;
+#endif
+ /* Cannot enable interrupts until OBP ticker is disabled. */
+}
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index d6420ec68..81db1a4ce 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -163,7 +163,8 @@ static void sun4m_enable_pil_irq(unsigned int pil)
sun4m_interrupts->clear = cpu_pil_to_imask[pil];
}
-void sun4m_send_ipi(int cpu, int level)
+#ifdef __SMP__
+static void sun4m_send_ipi(int cpu, int level)
{
unsigned long mask;
@@ -171,7 +172,7 @@ void sun4m_send_ipi(int cpu, int level)
sun4m_interrupts->cpu_intregs[cpu].set = mask;
}
-void sun4m_clear_ipi(int cpu, int level)
+static void sun4m_clear_ipi(int cpu, int level)
{
unsigned long mask;
@@ -179,10 +180,11 @@ void sun4m_clear_ipi(int cpu, int level)
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
}
-void sun4m_set_udt(int cpu)
+static void sun4m_set_udt(int cpu)
{
sun4m_interrupts->undirected_target = cpu;
}
+#endif
#define OBIO_INTR 0x20
#define TIMER_IRQ (OBIO_INTR | 10)
diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c
index cc0166a41..4f6b2accc 100644
--- a/arch/sparc/kernel/sunos_ioctl.c
+++ b/arch/sparc/kernel/sunos_ioctl.c
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.28 1997/02/15 01:17:05 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.29 1997/09/18 10:37:31 rth Exp $
* sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -45,8 +45,8 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
/* First handle an easy compat. case for tty ldisc. */
if(cmd == TIOCSETD) {
- int *p, ntty = N_TTY;
- int tmp, oldfs;
+ int *p, ntty = N_TTY, tmp;
+ mm_segment_t oldfs;
p = (int *) arg;
ret = -EFAULT;
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index d4044f88f..5b82aa8eb 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.35 1997/04/16 05:56:09 davem Exp $
+/* $Id: sys_sparc.c,v 1.38 1998/01/09 16:42:48 jj Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -17,6 +17,7 @@
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/utsname.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -248,53 +249,99 @@ sparc_breakpoint (struct pt_regs *regs)
unlock_kernel();
}
-extern void check_pending(int signum);
-
asmlinkage int
-sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
+sparc_sigaction (int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
{
- struct sigaction new_sa, *p;
+ struct k_sigaction new_ka, old_ka;
+ int ret;
- if(signum < 0) {
+ if (sig < 0) {
current->tss.new_signal = 1;
- signum = -signum;
+ sig = -sig;
}
- if(signum<1 || signum>32)
- return -EINVAL;
- p = signum - 1 + current->sig->action;
- if(action) {
- if(verify_area(VERIFY_READ,action,sizeof(struct sigaction)))
+ if (act) {
+ unsigned long mask;
+
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
return -EFAULT;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
- return -EFAULT;
- if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- if(verify_area(VERIFY_READ, new_sa.sa_handler, 1))
- return -EFAULT;
- }
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ new_ka.ka_restorer = NULL;
}
- if (oldaction) {
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
/* In the clone() case we could copy half consistant
* state to the user, however this could sleep and
* deadlock us if we held the signal lock on SMP. So for
* now I take the easy way out and do no locking.
*/
- if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- return -EFAULT;
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- *p = new_sa;
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
+ return ret;
+}
+
+asmlinkage int
+sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
+ void *restorer, size_t sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (act) {
+ new_ka.ka_restorer = restorer;
+ if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
+ return -EFAULT;
}
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+/* Just in case some old old binary calls this. */
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+asmlinkage int sys_getdomainname(char *name, int len)
+{
+ int nlen = strlen(system_utsname.domainname);
+
+ if (nlen < len)
+ len = nlen;
+ if(len > __NEW_UTS_LEN)
+ return -EFAULT;
+ if(copy_to_user(name, system_utsname.domainname, len))
+ return -EFAULT;
return 0;
}
+
#ifndef CONFIG_AP1000
/* only AP+ systems have sys_aplib */
asmlinkage int sys_aplib(void)
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index f60ecbe9c..29f00f6b8 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
+/* $Id: sys_sunos.c,v 1.83 1997/12/14 23:24:28 ecd Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -348,35 +348,28 @@ asmlinkage long sunos_getdtablesize(void)
{
return SUNOS_NR_OPEN;
}
-#define _S(nr) (1<<((nr)-1))
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask)
{
- unsigned long flags;
unsigned long old;
- lock_kernel();
- save_and_cli(flags);
- old = current->blocked;
- current->blocked |= (blk_mask & _BLOCKABLE);
- restore_flags(flags);
- unlock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
+ old = current->blocked.sig[0];
+ current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
+ spin_unlock_irq(&current->sigmask_lock);
return old;
}
asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask)
{
- unsigned long flags;
unsigned long retval;
- lock_kernel();
- save_and_cli(flags);
- retval = current->blocked;
- current->blocked = newmask & _BLOCKABLE;
- restore_flags(flags);
- unlock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
+ retval = current->blocked.sig[0];
+ current->blocked.sig[0] = (newmask & _BLOCKABLE);
+ spin_unlock_irq(&current->sigmask_lock);
return retval;
}
@@ -430,8 +423,6 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct sunos_dirent * lastdirent;
struct sunos_dirent_callback buf;
int error = -EBADF;
@@ -444,14 +435,6 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
if(!file)
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
@@ -464,7 +447,7 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
- error = file->f_op->readdir(inode, file, &buf, sunos_filldir);
+ error = file->f_op->readdir(file, &buf, sunos_filldir);
if (error < 0)
goto out;
lastdirent = buf.previous;
@@ -520,8 +503,6 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct sunos_direntry * lastdirent;
struct sunos_direntry_callback buf;
int error = -EBADF;
@@ -534,14 +515,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi
if(!file)
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
@@ -554,7 +527,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
- error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry);
+ error = file->f_op->readdir(file, &buf, sunos_filldirentry);
if (error < 0)
goto out;
lastdirent = buf.previous;
@@ -1254,58 +1227,47 @@ asmlinkage int sunos_accept(int fd, struct sockaddr *sa, int *addrlen)
#define SUNOS_SV_INTERRUPT 2
-extern void check_pending(int signum);
-
-asmlinkage int sunos_sigaction(int signum, const struct sigaction *action,
- struct sigaction *oldaction)
+asmlinkage int
+sunos_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
{
- struct sigaction new_sa, *p;
- const int sigaction_size = sizeof (struct sigaction) - sizeof (void *);
+ struct k_sigaction new_ka, old_ka;
+ int ret;
current->personality |= PER_BSD;
- if(signum < 1 || signum > 32)
- return -EINVAL;
- p = signum - 1 + current->sig->action;
+ if(act) {
+ old_sigset_t mask;
- if(action) {
- if(copy_from_user(&new_sa, action, sigaction_size))
- return -EFAULT;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- memset(&new_sa, 0, sizeof(struct sigaction));
- if(copy_from_user(&new_sa, action, sigaction_size))
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags))
return -EFAULT;
- if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
- if(verify_area(VERIFY_READ, new_sa.sa_handler, 1))
- return -EFAULT;
- }
- new_sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+ __get_user(mask, &act->sa_mask);
+ new_ka.sa.sa_restorer = NULL;
+ new_ka.ka_restorer = NULL;
+ siginitset(&new_ka.sa.sa_mask, mask);
+ new_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
}
- if (oldaction) {
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
/* In the clone() case we could copy half consistant
* state to the user, however this could sleep and
* deadlock us if we held the signal lock on SMP. So for
* now I take the easy way out and do no locking.
* But then again we don't support SunOS lwp's anyways ;-)
*/
- if (copy_to_user(oldaction, p, sigaction_size))
+ old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
return -EFAULT;
-
- if (oldaction->sa_flags & SA_RESTART)
- oldaction->sa_flags &= ~SA_RESTART;
- else
- oldaction->sa_flags |= SUNOS_SV_INTERRUPT;
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- *p = new_sa;
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
- }
- return 0;
+ return ret;
}
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 055b85b21..5ea64d2a4 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $
+/* $Id: systbls.S,v 1.68 1997/12/24 17:26:38 ecd Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -30,11 +30,11 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_setuid), C_LABEL(sys_getuid)
/*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_pause)
-/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty)
- .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime)
+/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
- .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil)
+ .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
.long C_LABEL(sys_signal), C_LABEL(sys_geteuid)
/*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall)
@@ -42,8 +42,8 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
.long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
.long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize)
- .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_pread)
+ .long C_LABEL(sys_pwrite), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap)
.long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups)
@@ -54,10 +54,10 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_rt_sigreturn)
+ .long C_LABEL(sys_rt_sigaction), C_LABEL(sys_rt_sigprocmask)
+ .long C_LABEL(sys_rt_sigpending), C_LABEL(sys_rt_sigtimedwait)
+ .long C_LABEL(sys_rt_sigqueueinfo), C_LABEL(sys_rt_sigsuspend)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
@@ -73,13 +73,13 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
- .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_prctl)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
/*150*/ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
.long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setdomainname)
+ .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
@@ -89,12 +89,12 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_query_module)
.long C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
- .long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
- .long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
+ .long C_LABEL(sys_personality), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
+ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
/*200*/ .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
.long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
- .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
+ .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
.long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
@@ -102,7 +102,7 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
.long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
.long C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid)
- .long C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time)
+ .long C_LABEL(sys_setfsgid), C_LABEL(sys_select), C_LABEL(sys_time)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
.long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
/* "We are the Knights of the Forest of Ni!!" */
@@ -125,7 +125,6 @@ C_LABEL(sys_call_table):
.long C_LABEL(sys_fdatasync)
.long C_LABEL(sys_nfsservctl)
/*255*/ .long C_LABEL(sys_aplib)
- .long C_LABEL(sys_prctl)
.long C_LABEL(sys_nis_syscall)
/* Now the SunOS syscall table. */
@@ -147,7 +146,7 @@ C_LABEL(sunos_sys_table):
.long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
.long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
- .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil)
+ .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
/*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys)
@@ -220,4 +219,3 @@ C_LABEL(sunos_sys_table):
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
/*250*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib)
- .long C_LABEL(sunos_nosys)