summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/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/sparc64/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/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile6
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c15
-rw-r--r--arch/sparc64/kernel/dtlb_miss.S10
-rw-r--r--arch/sparc64/kernel/ebus.c76
-rw-r--r--arch/sparc64/kernel/entry.S250
-rw-r--r--arch/sparc64/kernel/etrap.S8
-rw-r--r--arch/sparc64/kernel/ioctl32.c717
-rw-r--r--arch/sparc64/kernel/irq.c198
-rw-r--r--arch/sparc64/kernel/itlb_miss.S10
-rw-r--r--arch/sparc64/kernel/process.c80
-rw-r--r--arch/sparc64/kernel/psycho.c550
-rw-r--r--arch/sparc64/kernel/ptrace.c23
-rw-r--r--arch/sparc64/kernel/rtrap.S39
-rw-r--r--arch/sparc64/kernel/setup.c107
-rw-r--r--arch/sparc64/kernel/signal.c392
-rw-r--r--arch/sparc64/kernel/signal32.c505
-rw-r--r--arch/sparc64/kernel/smp.c8
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c22
-rw-r--r--arch/sparc64/kernel/sunos_ioctl32.c4
-rw-r--r--arch/sparc64/kernel/sys32.S315
-rw-r--r--arch/sparc64/kernel/sys_sparc.c157
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c701
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c158
-rw-r--r--arch/sparc64/kernel/systbls.S155
-rw-r--r--arch/sparc64/kernel/traps.c144
-rw-r--r--arch/sparc64/kernel/ttable.S21
-rw-r--r--arch/sparc64/kernel/unaligned.c380
-rw-r--r--arch/sparc64/kernel/winfixup.S71
28 files changed, 3484 insertions, 1638 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 2b07a0e15..7889c84a4 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $
+# $Id: Makefile,v 1.35 1997/09/20 21:48:58 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -71,8 +71,8 @@ check_asm: dummy
@rm -f tmp.[ci]
#$(CC) -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
- $(CC) -mmedlow -S -o check_asm.s check_asm.c
- $(HOSTCC) -o check_asm check_asm.s
+ $(CC) -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c
+ $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
@rm -f check_asm.s
# </hack>
./check_asm > asm_offsets.h
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index 98066a321..55ccbc203 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -57,11 +57,12 @@ static void set_brk(unsigned long start, unsigned long end)
* macros to write out all the necessary info.
*/
#define DUMP_WRITE(addr,nr) \
-while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
+while (file.f_op->write(&file,(char *)(addr),(nr),&file.f_pos) != (nr)) \
+ goto close_coredump
#define DUMP_SEEK(offset) \
if (file.f_op->llseek) { \
- if (file.f_op->llseek(inode,&file,(offset),0) != (offset)) \
+ if (file.f_op->llseek(&file,(offset),0) != (offset)) \
goto close_coredump; \
} else file.f_pos = (offset)
@@ -81,7 +82,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
struct dentry * dentry = NULL;
struct inode * inode = NULL;
struct file file;
- unsigned short fs;
+ mm_segment_t fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
unsigned long dump_start, dump_size;
@@ -256,7 +257,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
unsigned long p = bprm->p;
unsigned long fd_offset;
unsigned long rlim;
- int retval;
+int retval;
ex = *((struct exec *) bprm->buf); /* exec-header */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -285,8 +286,6 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
return retval;
/* OK, This is the point of no return */
- memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
-
current->mm->end_code = ex.a_text +
(current->mm->start_code = N_TXTADDR(ex));
current->mm->end_data = ex.a_data +
@@ -420,13 +419,13 @@ do_load_aout32_library(int fd)
/* Seek into the file */
if (file->f_op->llseek) {
- if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
+ if ((error = file->f_op->llseek(file, 0, 0)) != 0)
return -ENOEXEC;
} else
file->f_pos = 0;
set_fs(KERNEL_DS);
- error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex));
+ error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos);
set_fs(USER_DS);
if (error != sizeof(ex))
return -ENOEXEC;
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S
index 04efb1cec..4d71d967c 100644
--- a/arch/sparc64/kernel/dtlb_miss.S
+++ b/arch/sparc64/kernel/dtlb_miss.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $
+/* $Id: dtlb_miss.S,v 1.14 1997/10/14 01:48:28 davem Exp $
* dtlb_miss.S: Data TLB miss code, this is included directly
* into the trap table.
*
@@ -53,10 +53,10 @@
/*0x24*/ srlx %g1, 1, %g1 ! PTE offset
2:/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
- /*0x30*/ brlz,a,pt %g5, 1f ! Valid set?
- /*0x34*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x38*/ ba,a,pt %xcc, sparc64_dtlb_refbit_catch ! Nope...
-1:/*0x3c*/ retry ! Trap return
+ /*0x30*/ brgez,pn %g5, sparc64_dtlb_refbit_catch ! Valid set?
+ /*0x34*/ nop ! delay
+ /*0x38*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load
+ /*0x3c*/ retry ! Trap return
3: /* ICACHE line 3 */
/*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index f484cfef8..02faf4e3c 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $
+/* $Id: ebus.c,v 1.17 1998/01/10 18:26:13 ecd Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -17,8 +17,15 @@
#include <asm/oplib.h>
#include <asm/bpp.h>
+#undef PROM_DEBUG
#undef DEBUG_FILL_EBUS_DEV
+#ifdef PROM_DEBUG
+#define dprintf prom_printf
+#else
+#define dprintf printk
+#endif
+
struct linux_ebus *ebus_chain = 0;
extern void prom_ebus_ranges_init(struct linux_ebus *);
@@ -36,8 +43,12 @@ extern int sparcaudio_init(void);
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
+#ifdef CONFIG_OBP_FLASH
+extern int flash_init(void);
+#endif
-extern unsigned int psycho_irq_build(unsigned int full_ino);
+extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
+ unsigned int full_ino);
static inline unsigned long
ebus_alloc(unsigned long *memory_start, size_t size)
@@ -47,6 +58,7 @@ ebus_alloc(unsigned long *memory_start, size_t size)
*memory_start = (*memory_start + 7) & ~(7);
mem = *memory_start;
*memory_start += size;
+ memset((void *)mem, 0, size);
return mem;
}
@@ -79,19 +91,19 @@ __initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++)
- dev->irqs[i] = psycho_irq_build(irqs[i]);
+ dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
}
#ifdef DEBUG_FILL_EBUS_DEV
- printk("child '%s': address%s\n", dev->prom_name,
+ dprintf("child '%s': address%s\n", dev->prom_name,
dev->num_addrs > 1 ? "es" : "");
for (i = 0; i < dev->num_addrs; i++)
- printk(" %016lx\n", dev->base_address[i]);
+ dprintf(" %016lx\n", dev->base_address[i]);
if (dev->num_irqs) {
- printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
for (i = 0; i < dev->num_irqs; i++)
- printk(" %08x", dev->irqs[i]);
- printk("\n");
+ dprintf(" %08x", dev->irqs[i]);
+ dprintf("\n");
}
#endif
}
@@ -121,7 +133,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
for (i = 0; i < dev->num_addrs; i++) {
n = (regs[i].which_io - 0x10) >> 2;
- dev->base_address[i] = dev->parent->self->base_address[n];
+ dev->base_address[i] = dev->bus->self->base_address[n];
dev->base_address[i] += (unsigned long)regs[i].phys_addr;
}
@@ -131,19 +143,19 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++)
- dev->irqs[i] = psycho_irq_build(irqs[i]);
+ dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
}
#ifdef DEBUG_FILL_EBUS_DEV
- printk("'%s': address%s\n", dev->prom_name,
+ dprintf("'%s': address%s\n", dev->prom_name,
dev->num_addrs > 1 ? "es" : "");
for (i = 0; i < dev->num_addrs; i++)
- printk(" %016lx\n", dev->base_address[i]);
+ dprintf(" %016lx\n", dev->base_address[i]);
if (dev->num_irqs) {
- printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
for (i = 0; i < dev->num_irqs; i++)
- printk(" %08x", dev->irqs[i]);
- printk("\n");
+ dprintf(" %08x", dev->irqs[i]);
+ dprintf("\n");
}
#endif
if ((node = prom_getchild(node))) {
@@ -153,6 +165,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
child = dev->children;
child->next = 0;
child->parent = dev;
+ child->bus = dev->bus;
fill_ebus_child(node, child);
while ((node = prom_getsibling(node))) {
@@ -162,6 +175,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
child = child->next;
child->next = 0;
child->parent = dev;
+ child->bus = dev->bus;
fill_ebus_child(node, child);
}
}
@@ -195,6 +209,9 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
}
if (!pdev) {
printk("ebus: No EBus's found.\n");
+#ifdef PROM_DEBUG
+ dprintf("ebus: No EBus's found.\n");
+#endif
return memory_start;
}
@@ -206,7 +223,10 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
ebus->next = 0;
while (ebusnd) {
- printk("ebus%d:\n", num_ebus);
+ printk("ebus%d:", num_ebus);
+#ifdef PROM_DEBUG
+ dprintf("ebus%d:", num_ebus);
+#endif
prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
ebus->prom_node = ebusnd;
@@ -250,20 +270,34 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
addr += (u64)rp->parent_phys_hi << 32UL;
*base++ = (unsigned long)__va(addr);
+ printk(" %lx[%x]", (unsigned long)__va(addr),
+ regs[reg].size_lo);
+#ifdef PROM_DEBUG
+ dprintf(" %lx[%x]", (unsigned long)__va(addr),
+ regs[reg].size_lo);
+#endif
break;
}
}
+ printk("\n");
+#ifdef PROM_DEBUG
+ dprintf("\n");
+#endif
prom_ebus_ranges_init(ebus);
nd = prom_getchild(ebusnd);
+ if (!nd)
+ goto next_ebus;
+
ebus->devices = (struct linux_ebus_device *)
- ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
+ ebus_alloc(&memory_start,
+ sizeof(struct linux_ebus_device));
dev = ebus->devices;
dev->next = 0;
dev->children = 0;
- dev->parent = ebus;
+ dev->bus = ebus;
memory_start = fill_ebus_device(nd, dev, memory_start);
while ((nd = prom_getsibling(nd))) {
@@ -273,10 +307,11 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
dev = dev->next;
dev->next = 0;
dev->children = 0;
- dev->parent = ebus;
+ dev->bus = ebus;
memory_start = fill_ebus_device(nd, dev, memory_start);
}
+ next_ebus:
for (pdev = pdev->next; pdev; pdev = pdev->next) {
if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
(pdev->device == PCI_DEVICE_ID_SUN_EBUS))
@@ -313,6 +348,9 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
if (sparc_cpu_model == sun4u)
auxio_probe();
#endif
+#ifdef CONFIG_OBP_FLASH
+ flash_init();
+#endif
#ifdef __sparc_v9__
if (sparc_cpu_model == sun4u) {
extern void sun4u_start_timers(void);
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index a6e2d6da7..76f913ade 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.65 1997/08/29 15:51:29 jj Exp $
+/* $Id: entry.S,v 1.76 1998/01/05 17:00:13 jj Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -121,7 +121,7 @@ sparc64_itlb_refbit_catch:
.align 32
.globl do_fpdis
do_fpdis:
- ldx [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group
sethi %hi(TSTATE_PEF), %g4 ! IEU0
sethi %hi(FPDIS_OFF), %g3 ! IEU1
wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles
@@ -337,9 +337,28 @@ setcc:
retl
stx %o1, [%o0 + PT_V9_TSTATE]
+ .globl utrap, utrap_ill
+utrap: brz,pn %g1, etrap
+ nop
+ save %sp, -128, %sp
+ rdpr %tstate, %l6
+ rdpr %cwp, %l7
+ andn %l6, TSTATE_CWP, %l6
+ wrpr %l6, %l7, %tstate
+ rdpr %tpc, %l6
+ rdpr %tnpc, %l7
+ wrpr %g1, 0, %tnpc
+ done
+utrap_ill:
+ call bad_trap
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
#ifdef CONFIG_BLK_DEV_FD
.globl floppy_hardint
floppy_hardint:
+ wr %g0, (1 << 11), %clear_softint
sethi %hi(doing_pdma), %g1
ld [%g1 + %lo(doing_pdma)], %g2
brz,pn %g2, floppy_dosoftint
@@ -404,8 +423,9 @@ floppy_fifo_emptied:
sethi %hi(irq_action), %g1
or %g1, %lo(irq_action), %g1
ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq]
- ldx [%g3 + 0x10], %g4 ! action->mask
- st %g0, [%g4] ! SYSIO_ICLR_IDLE
+ ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr
+ ldx [%g4 + 0x18], %g4 ! bucket->iclr
+ stw %g0, [%g4] ! SYSIO_ICLR_IDLE
membar #Sync ! probably not needed...
retry
@@ -446,14 +466,52 @@ do_mna:
cmp %g3, 1
bgu,a,pn %icc, winfix_mna
rdpr %tpc, %g3
+ mov DMMU_SFAR, %g4
+ mov TLB_SFSR, %g5
sethi %hi(109f), %g7
+ ldxa [%g4] ASI_DMMU, %g4
+ ldxa [%g5] ASI_DMMU, %g5
ba,pt %xcc, etrap
109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
+ .globl do_lddfmna
+do_lddfmna:
+ mov DMMU_SFAR, %g4
+ mov TLB_SFSR, %g5
+ sethi %hi(109f), %g7
+ ldxa [%g4] ASI_DMMU, %g4
+ ldxa [%g5] ASI_DMMU, %g5
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call handle_lddfmna
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+ .globl do_stdfmna
+do_stdfmna:
+ mov DMMU_SFAR, %g4
+ mov TLB_SFSR, %g5
+ sethi %hi(109f), %g7
+ ldxa [%g4] ASI_DMMU, %g4
+ ldxa [%g5] ASI_DMMU, %g5
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call handle_stdfmna
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
.globl breakpoint_trap
breakpoint_trap:
call sparc_breakpoint
@@ -471,13 +529,13 @@ sunos_indir:
mov %o7, %l4
cmp %o0, NR_SYSCALLS
blu,a,pt %icc, 1f
- sll %o0, 0x3, %o0
+ sll %o0, 0x2, %o0
sethi %hi(sunos_nosys), %l6
b,pt %xcc, 2f
or %l6, %lo(sunos_nosys), %l6
1: sethi %hi(sunos_sys_table), %l7
or %l7, %lo(sunos_sys_table), %l7
- ldx [%l7 + %o0], %l6
+ lduw [%l7 + %o0], %l6
2: mov %o1, %o0
mov %o2, %o1
mov %o3, %o2
@@ -526,7 +584,9 @@ sunos_execv:
add %sp, STACK_BIAS + REGWIN_SZ, %o0
.globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
- .globl sys_sigsuspend, sys_sigreturn
+ .globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend
+ .globl sys_sigreturn, sys_rt_sigreturn
+ .globl sys32_sigreturn, sys32_rt_sigreturn
.globl sys32_execve, sys_ptrace
.align 32
sys_pipe: sethi %hi(sparc_pipe), %g1
@@ -546,42 +606,57 @@ sys32_execve: sethi %hi(sparc32_execve), %g1
add %sp, STACK_BIAS + REGWIN_SZ, %o0
jmpl %g1 + %lo(sparc32_execve), %g0
nop
-
- /* NOTE: %o0 has a correct value already */
-sys_sigpause: call do_sigpause
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
- ldx [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
- clr %l6
- call syscall_trace
+sys_memory_ordering:
+ sethi %hi(sparc_memory_ordering), %g1
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ jmpl %g1 + %lo(sparc_memory_ordering), %g0
nop
- ba,pt %xcc, rtrap
- clr %l6
-linux_sparc_ni_syscall:
- sethi %hi(sys_ni_syscall), %l7
- b,pt %xcc,syscall_is_too_hard
- or %l7, %lo(sys_ni_syscall), %l7
- nop
-
.align 32
-sys_sigsuspend: call do_sigsuspend
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ldx [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
- clr %l6
- call syscall_trace
- nop
-
- ba,pt %xcc, rtrap
- clr %l6
-
+sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_sigsuspend
+ add %o7, 1f-.-4, %o7
+ nop
+sys_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */
+ add %sp, STACK_BIAS + REGWIN_SZ, %o2
+ call do_rt_sigsuspend
+ add %o7, 1f-.-4, %o7
+ nop
+sys32_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */
+ srl %o0, 0, %o0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o2
+ call do_rt_sigsuspend32
+ add %o7, 1f-.-4, %o7
+ /* NOTE: %o0 has a correct value already */
+sys_sigpause: add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call do_sigpause
+ add %o7, 1f-.-4, %o7
+ nop
+sys_sigreturn: add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_sigreturn
+ add %o7, 1f-.-4, %o7
+ nop
+sys32_sigreturn:
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_sigreturn32
+ add %o7, 1f-.-4, %o7
+ nop
+sys_rt_sigreturn:
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_rt_sigreturn
+ add %o7, 1f-.-4, %o7
+ nop
+sys32_rt_sigreturn:
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_rt_sigreturn32
+ add %o7, 1f-.-4, %o7
+ nop
+sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ call do_ptrace
+ add %o7, 1f-.-4, %o7
+ nop
.align 32
-sys_sigreturn: call do_sigreturn
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ldx [%curptr + AOFF_task_flags], %l5
+1: ldx [%curptr + AOFF_task_flags], %l5
andcc %l5, 0x20, %g0
be,pt %icc, rtrap
clr %l6
@@ -591,19 +666,6 @@ sys_sigreturn: call do_sigreturn
ba,pt %xcc, rtrap
clr %l6
- .align 32
-sys_ptrace: call do_ptrace
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- ldx [%curptr + AOFF_task_flags], %l5
- andcc %l5, 0x20, %g0
- be,pt %icc, rtrap
- clr %l6
- call syscall_trace
- nop
-
- ba,pt %xcc, rtrap
- clr %l6
-
/* This is how fork() was meant to be done, 12 instruction entry.
*
* I questioned the following code briefly, let me clear things
@@ -648,42 +710,94 @@ ret_from_syscall:
b,pt %xcc, ret_sys_call
ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+linux_sparc_ni_syscall:
+ sethi %hi(sys_ni_syscall), %l7
+ b,pt %xcc, 4f
+ or %l7, %lo(sys_ni_syscall), %l7
+
+linux_syscall_trace32:
+ call syscall_trace
+ nop
+ srl %i0, 0, %o0
+ mov %i4, %o4
+ srl %i1, 0, %o1
+ srl %i2, 0, %o2
+ b,pt %xcc, 2f
+ srl %i3, 0, %o3
+
linux_syscall_trace:
- call syscall_trace
- nop
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
- mov %i3, %o3
- b,pt %xcc, 2f
- mov %i4, %o4
+ call syscall_trace
+ nop
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov %i3, %o3
+ b,pt %xcc, 2f
+ mov %i4, %o4
+
+
+ /* Linux 32-bit and SunOS system calls enter here... */
+ .align 32
+ .globl linux_sparc_syscall32
+linux_sparc_syscall32:
+ /* Direct access to user regs, must faster. */
+ cmp %g1, NR_SYSCALLS ! IEU1 Group
+ bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
+ srl %i0, 0, %o0 ! IEU0
+ sll %g1, 2, %l4 ! IEU0 Group
+#ifdef SYSCALL_TRACING
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call syscall_trace_entry
+ mov %g1, %o0
+ srl %i0, 0, %o0
+#endif
+ mov %i4, %o4 ! IEU1
+ lduw [%l7 + %l4], %l7 ! Load
+ srl %i1, 0, %o1 ! IEU0 Group
+ ldx [%curptr + AOFF_task_flags], %l0 ! Load
+
+ mov %i5, %o5 ! IEU1
+ srl %i2, 0, %o2 ! IEU0 Group
+ mov %i0, %l5 ! IEU1
+ andcc %l0, 0x20, %g0 ! IEU1 Group
+ bne,pn %icc, linux_syscall_trace32 ! CTI
+ srl %i3, 0, %o3 ! IEU0
+ call %l7 ! CTI Group brk forced
+ add %o7, 3f-.-4, %o7 ! IEU0
/* Linux native and SunOS system calls enter here... */
.align 32
- .globl linux_sparc_syscall, syscall_is_too_hard, ret_sys_call
+ .globl linux_sparc_syscall, ret_sys_call
linux_sparc_syscall:
/* Direct access to user regs, must faster. */
cmp %g1, NR_SYSCALLS ! IEU1 Group
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
mov %i0, %o0 ! IEU0
sll %g1, 2, %l4 ! IEU0 Group
+#ifdef SYSCALL_TRACING
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+ call syscall_trace_entry
+ mov %g1, %o0
+ mov %i0, %o0
+#endif
mov %i1, %o1 ! IEU1
lduw [%l7 + %l4], %l7 ! Load
-syscall_is_too_hard:
- mov %i2, %o2 ! IEU0 Group
- ldx [%curptr + AOFF_task_flags], %l5 ! Load
+4: mov %i2, %o2 ! IEU0 Group
+ ldx [%curptr + AOFF_task_flags], %l0 ! Load
- st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS]
mov %i3, %o3 ! IEU1
mov %i4, %o4 ! IEU0 Group
- andcc %l5, 0x20, %g0 ! IEU1 2 bubbles
+ andcc %l0, 0x20, %g0 ! IEU1 Group+1 bubble
bne,pn %icc, linux_syscall_trace ! CTI Group
mov %i0, %l5 ! IEU0
2: call %l7 ! CTI Group brk forced
mov %i5, %o5 ! IEU0
- stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
-
+3: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
ret_sys_call:
+#ifdef SYSCALL_TRACING
+ call syscall_trace_exit
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+#endif
ldx [%curptr + AOFF_task_flags], %l6
sra %o0, 0, %o0
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index e10480454..9e7c9e374 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.37 1997/08/21 09:13:18 davem Exp $
+/* $Id: etrap.S,v 1.39 1997/10/24 11:57:47 jj Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -79,11 +79,11 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group
andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
be,pn %icc, 6f ! CTI
st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store
- ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group
stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group
or %l4, %l0, %l4 ! IEU0 Group
ba,pt %xcc, 3f ! CTI
- st %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store
+ sth %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store
2: rd %fprs, %l0 ! Single Group+4bubbles
andcc %l0, FPRS_FEF, %g0 ! IEU1 Group
be,pn %icc, 6f ! CTI
@@ -107,7 +107,7 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group
5: membar #Sync ! Memory
6: wr %g0, 0x0, %fprs ! Single Group+4bubbles
wrpr %g0, 0x0, %tl ! Single Group+4bubbles
- mov %g1, %l1 ! IEU0 Group
+ andn %g1, PSTATE_MM, %l1 ! IEU0 Group
mov %g4, %l4 ! IEU1
mov %g5, %l5 ! IEU0 Group
mov %g7, %l2 ! IEU1
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index af88ca4b6..64465663d 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $
+/* $Id: ioctl32.c,v 1.26 1997/12/15 15:11:02 jj Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -19,11 +19,19 @@
#include <linux/md.h>
#include <linux/kd.h>
#include <linux/route.h>
+#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/vt.h>
#include <linux/fs.h>
#include <linux/fd.h>
#include <linux/if_ppp.h>
+#include <linux/mtio.h>
+
+#include <scsi/scsi.h>
+/* Ugly hack. */
+#undef __KERNEL__
+#include <scsi/scsi_ioctl.h>
+#define __KERNEL__
#include <asm/types.h>
#include <asm/uaccess.h>
@@ -44,7 +52,7 @@ extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long
static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
{
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
int err;
unsigned long val;
@@ -97,16 +105,24 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
struct ifconf ifc;
struct ifreq32 *ifr32;
struct ifreq *ifr;
- unsigned long old_fs;
+ mm_segment_t old_fs;
unsigned int i, j;
int err;
if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32)))
return -EFAULT;
- ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq);
- ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
- if (!ifc.ifc_buf) return -ENOMEM;
+ if(ifc32.ifcbuf == 0) {
+ ifc32.ifc_len = 0;
+ ifc.ifc_len = 0;
+ ifc.ifc_buf = NULL;
+ } else {
+ ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
+ sizeof (struct ifreq);
+ ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+ if (!ifc.ifc_buf)
+ return -ENOMEM;
+ }
ifr = ifc.ifc_req;
ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
@@ -137,14 +153,15 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
err = -EFAULT;
}
}
- kfree (ifc.ifc_buf);
+ if(ifc.ifc_buf != NULL)
+ kfree (ifc.ifc_buf);
return err;
}
static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
{
struct ifreq ifr;
- unsigned long old_fs;
+ mm_segment_t old_fs;
int err;
switch (cmd) {
@@ -183,7 +200,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCGIFMTU:
case SIOCGIFMEM:
case SIOCGIFHWADDR:
- case SIOGIFINDEX:
+ case SIOCGIFINDEX:
case SIOCGIFADDR:
case SIOCGIFBRDADDR:
case SIOCGIFDSTADDR:
@@ -250,16 +267,10 @@ static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
char devname[16];
u32 rtdev;
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
- if (get_user (r.rt_pad1, &(((struct rtentry32 *)A(arg))->rt_pad1)) ||
- copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) ||
+ if (copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) ||
__get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) ||
- __get_user (r.rt_pad2, &(((struct rtentry32 *)A(arg))->rt_pad2)) ||
- __get_user (r.rt_pad3, &(((struct rtentry32 *)A(arg))->rt_pad3)) ||
- __get_user (r.rt_tos, &(((struct rtentry32 *)A(arg))->rt_tos)) ||
- __get_user (r.rt_class, &(((struct rtentry32 *)A(arg))->rt_class)) ||
- __get_user (r.rt_pad4, &(((struct rtentry32 *)A(arg))->rt_pad4)) ||
__get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) ||
__get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) ||
__get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) ||
@@ -277,116 +288,6 @@ static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
return ret;
}
-struct nlmsghdr32 {
- u32 nlmsg_len; /* Length of message including header */
- u32 nlmsg_type; /* Message type */
- u32 nlmsg_seq; /* Sequence number */
- u32 nlmsg_pid; /* Sending process PID */
- unsigned char nlmsg_data[0];
-};
-
-struct in_rtmsg32 {
- struct in_addr rtmsg_prefix;
- struct in_addr rtmsg_gateway;
- unsigned rtmsg_flags;
- u32 rtmsg_mtu;
- u32 rtmsg_window;
- unsigned short rtmsg_rtt;
- short rtmsg_metric;
- unsigned char rtmsg_tos;
- unsigned char rtmsg_class;
- unsigned char rtmsg_prefixlen;
- unsigned char rtmsg_reserved;
- int rtmsg_ifindex;
-};
-
-struct in_ifmsg32 {
- struct sockaddr ifmsg_lladdr;
- struct in_addr ifmsg_prefix;
- struct in_addr ifmsg_brd;
- unsigned ifmsg_flags;
- u32 ifmsg_mtu;
- short ifmsg_metric;
- unsigned char ifmsg_prefixlen;
- unsigned char ifmsg_reserved;
- int ifmsg_index;
- char ifmsg_name[16];
-};
-
-static inline int rtmsg_ioctl(unsigned int fd, u32 arg)
-{
- struct {
- struct nlmsghdr n;
- union {
- struct in_rtmsg rt;
- struct in_ifmsg iff;
- struct in_rtctlmsg ctl;
- struct in_rtrulemsg rule;
- } u;
- } nn;
- char *p;
- int ret;
- unsigned long old_fs = get_fs();
-
- if (get_user (nn.n.nlmsg_len, &(((struct nlmsghdr32 *)A(arg))->nlmsg_len)) ||
- __get_user (nn.n.nlmsg_type, &(((struct nlmsghdr32 *)A(arg))->nlmsg_type)) ||
- __get_user (nn.n.nlmsg_seq, &(((struct nlmsghdr32 *)A(arg))->nlmsg_seq)) ||
- __get_user (nn.n.nlmsg_pid, &(((struct nlmsghdr32 *)A(arg))->nlmsg_pid)) ||
- __get_user (nn.n.nlmsg_data[0], &(((struct nlmsghdr32 *)A(arg))->nlmsg_data[0])))
- return -EFAULT;
- p = ((char *)(&nn.n)) + sizeof(struct nlmsghdr);
- arg += sizeof(struct nlmsghdr32);
- switch (nn.n.nlmsg_type) {
- case RTMSG_NEWRULE:
- case RTMSG_DELRULE:
- if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtrulemsg)
- - sizeof(struct in_rtmsg) + sizeof(struct in_rtmsg32))
- return -EINVAL;
- if (copy_from_user (p, (struct in_rtrulemsg *)A(arg), sizeof(struct in_rtrulemsg) - sizeof(struct in_rtmsg)))
- return -EFAULT;
- nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtrulemsg);
- p += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg);
- arg += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg);
- goto newroute;
- case RTMSG_NEWROUTE:
- case RTMSG_DELROUTE:
- if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtmsg))
- return -EINVAL;
- nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtmsg);
-newroute:
- if (copy_from_user (p, (struct in_rtmsg32 *)A(arg), 2*sizeof(struct in_addr) + sizeof(unsigned)) ||
- __get_user (((struct in_rtmsg *)p)->rtmsg_mtu, &((struct in_rtmsg32 *)A(arg))->rtmsg_mtu) ||
- __get_user (((struct in_rtmsg *)p)->rtmsg_window, &((struct in_rtmsg32 *)A(arg))->rtmsg_window) ||
- copy_from_user (&(((struct in_rtmsg *)p)->rtmsg_rtt), &((struct in_rtmsg32 *)A(arg))->rtmsg_rtt,
- 2 * sizeof(short) + 4 + sizeof(int)))
- return -EFAULT;
- break;
- case RTMSG_NEWDEVICE:
- case RTMSG_DELDEVICE:
- if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_ifmsg))
- return -EINVAL;
- nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_ifmsg);
- if (copy_from_user (p, (struct in_ifmsg32 *)A(arg),
- sizeof(struct sockaddr) + 2*sizeof(struct in_addr) + sizeof(unsigned)) ||
- __get_user (((struct in_ifmsg *)p)->ifmsg_mtu, &((struct in_ifmsg32 *)A(arg))->ifmsg_mtu) ||
- copy_from_user (&(((struct in_ifmsg *)p)->ifmsg_metric), &((struct in_ifmsg32 *)A(arg))->ifmsg_metric,
- sizeof(short) + 2 + sizeof(int) + 16))
- return -EFAULT;
- break;
- case RTMSG_CONTROL:
- if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtctlmsg))
- return -EINVAL;
- nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtctlmsg);
- if (copy_from_user (p, (struct in_rtctlmsg *)A(arg), sizeof(struct in_rtctlmsg)))
- return -EFAULT;
- break;
- }
- set_fs (KERNEL_DS);
- ret = sys_ioctl (fd, SIOCRTMSG, (long)&(nn.n));
- set_fs (old_fs);
- return ret;
-}
-
struct hd_geometry32 {
unsigned char heads;
unsigned char sectors;
@@ -396,7 +297,7 @@ struct hd_geometry32 {
static inline int hdio_getgeo(unsigned int fd, u32 arg)
{
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
struct hd_geometry geo;
int err;
@@ -428,7 +329,7 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg)
int ret;
char red[256], green[256], blue[256];
u32 r, g, b;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) ||
__get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) ||
@@ -480,7 +381,7 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
char image[128], mask[128];
u32 r, g, b;
u32 m, i;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) ||
__get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) ||
@@ -516,7 +417,7 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
{
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
unsigned long kval;
unsigned int *uvp;
int error;
@@ -533,6 +434,328 @@ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
return error;
}
+struct floppy_struct32 {
+ unsigned int size;
+ unsigned int sect;
+ unsigned int head;
+ unsigned int track;
+ unsigned int stretch;
+ unsigned char gap;
+ unsigned char rate;
+ unsigned char spec1;
+ unsigned char fmt_gap;
+ const __kernel_caddr_t32 name;
+};
+
+struct floppy_drive_params32 {
+ char cmos;
+ u32 max_dtr;
+ u32 hlt;
+ u32 hut;
+ u32 srt;
+ u32 spinup;
+ u32 spindown;
+ unsigned char spindown_offset;
+ unsigned char select_delay;
+ unsigned char rps;
+ unsigned char tracks;
+ u32 timeout;
+ unsigned char interleave_sect;
+ struct floppy_max_errors max_errors;
+ char flags;
+ char read_track;
+ short autodetect[8];
+ int checkfreq;
+ int native_format;
+};
+
+struct floppy_drive_struct32 {
+ signed char flags;
+ u32 spinup_date;
+ u32 select_date;
+ u32 first_read_date;
+ short probed_format;
+ short track;
+ short maxblock;
+ short maxtrack;
+ int generation;
+ int keep_data;
+ int fd_ref;
+ int fd_device;
+ int last_checked;
+ __kernel_caddr_t32 dmabuf;
+ int bufblocks;
+};
+
+struct floppy_fdc_state32 {
+ int spec1;
+ int spec2;
+ int dtr;
+ unsigned char version;
+ unsigned char dor;
+ u32 address;
+ unsigned int rawcmd:2;
+ unsigned int reset:1;
+ unsigned int need_configure:1;
+ unsigned int perp_mode:2;
+ unsigned int has_fifo:1;
+ unsigned int driver_version;
+ unsigned char track[4];
+};
+
+struct floppy_write_errors32 {
+ unsigned int write_errors;
+ u32 first_error_sector;
+ int first_error_generation;
+ u32 last_error_sector;
+ int last_error_generation;
+ unsigned int badness;
+};
+
+#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32)
+#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32)
+#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32)
+#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32)
+#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32)
+#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32)
+#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32)
+#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32)
+#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32)
+
+static struct {
+ unsigned int cmd32;
+ unsigned int cmd;
+} fd_ioctl_trans_table[] = {
+ { FDSETPRM32, FDSETPRM },
+ { FDDEFPRM32, FDDEFPRM },
+ { FDGETPRM32, FDGETPRM },
+ { FDSETDRVPRM32, FDSETDRVPRM },
+ { FDGETDRVPRM32, FDGETDRVPRM },
+ { FDGETDRVSTAT32, FDGETDRVSTAT },
+ { FDPOLLDRVSTAT32, FDPOLLDRVSTAT },
+ { FDGETFDCSTAT32, FDGETFDCSTAT },
+ { FDWERRORGET32, FDWERRORGET }
+};
+
+#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0]))
+
+static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ mm_segment_t old_fs = get_fs();
+ void *karg;
+ unsigned int kcmd = 0;
+ int i, err;
+
+ for (i = 0; i < NR_FD_IOCTL_TRANS; i++)
+ if (cmd == fd_ioctl_trans_table[i].cmd32) {
+ kcmd = fd_ioctl_trans_table[i].cmd;
+ break;
+ }
+ if (!kcmd)
+ return -EINVAL;
+
+ switch (cmd) {
+ case FDSETPRM32:
+ case FDDEFPRM32:
+ case FDGETPRM32:
+ {
+ struct floppy_struct *f;
+
+ f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_struct));
+ if (!karg)
+ return -ENOMEM;
+ if (cmd == FDGETPRM32)
+ break;
+ if (__get_user(f->size, &((struct floppy_struct32 *)A(arg))->size) ||
+ __get_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) ||
+ __get_user(f->head, &((struct floppy_struct32 *)A(arg))->head) ||
+ __get_user(f->track, &((struct floppy_struct32 *)A(arg))->track) ||
+ __get_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) ||
+ __get_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) ||
+ __get_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) ||
+ __get_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) ||
+ __get_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) ||
+ __get_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ case FDSETDRVPRM32:
+ case FDGETDRVPRM32:
+ {
+ struct floppy_drive_params *f;
+
+ f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_params));
+ if (!karg)
+ return -ENOMEM;
+ if (cmd == FDGETDRVPRM32)
+ break;
+ if (__get_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) ||
+ __get_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) ||
+ __get_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) ||
+ __get_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) ||
+ __get_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) ||
+ __get_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) ||
+ __get_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) ||
+ __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) ||
+ __get_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) ||
+ __get_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) ||
+ __get_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) ||
+ __get_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) ||
+ __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) ||
+ __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)A(arg))->max_errors, sizeof(f->max_errors)) ||
+ __get_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) ||
+ __get_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) ||
+ __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)A(arg))->autodetect, sizeof(f->autodetect)) ||
+ __get_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) ||
+ __get_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ case FDGETDRVSTAT32:
+ case FDPOLLDRVSTAT32:
+ karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_struct));
+ if (!karg)
+ return -ENOMEM;
+ break;
+ case FDGETFDCSTAT32:
+ karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_fdc_state));
+ if (!karg)
+ return -ENOMEM;
+ break;
+ case FDWERRORGET32:
+ karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_write_errors));
+ if (!karg)
+ return -ENOMEM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+ set_fs (old_fs);
+ if (err) {
+ kfree(karg);
+ return err;
+ }
+ switch (cmd) {
+ case FDGETPRM32:
+ {
+ struct floppy_struct *f = karg;
+
+ if (__put_user(f->size, &((struct floppy_struct32 *)A(arg))->size) ||
+ __put_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) ||
+ __put_user(f->head, &((struct floppy_struct32 *)A(arg))->head) ||
+ __put_user(f->track, &((struct floppy_struct32 *)A(arg))->track) ||
+ __put_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) ||
+ __put_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) ||
+ __put_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) ||
+ __put_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) ||
+ __put_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) ||
+ __put_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ case FDGETDRVPRM32:
+ {
+ struct floppy_drive_params *f = karg;
+
+ if (__put_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) ||
+ __put_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) ||
+ __put_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) ||
+ __put_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) ||
+ __put_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) ||
+ __put_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) ||
+ __put_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) ||
+ __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) ||
+ __put_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) ||
+ __put_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) ||
+ __put_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) ||
+ __put_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) ||
+ __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) ||
+ __copy_to_user(&((struct floppy_drive_params32 *)A(arg))->max_errors, &f->max_errors, sizeof(f->max_errors)) ||
+ __put_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) ||
+ __put_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) ||
+ __copy_to_user(((struct floppy_drive_params32 *)A(arg))->autodetect, f->autodetect, sizeof(f->autodetect)) ||
+ __put_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) ||
+ __put_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ case FDGETDRVSTAT32:
+ case FDPOLLDRVSTAT32:
+ {
+ struct floppy_drive_struct *f = karg;
+
+ if (__put_user(f->flags, &((struct floppy_drive_struct32 *)A(arg))->flags) ||
+ __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)A(arg))->spinup_date) ||
+ __put_user(f->select_date, &((struct floppy_drive_struct32 *)A(arg))->select_date) ||
+ __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)A(arg))->first_read_date) ||
+ __put_user(f->probed_format, &((struct floppy_drive_struct32 *)A(arg))->probed_format) ||
+ __put_user(f->track, &((struct floppy_drive_struct32 *)A(arg))->track) ||
+ __put_user(f->maxblock, &((struct floppy_drive_struct32 *)A(arg))->maxblock) ||
+ __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)A(arg))->maxtrack) ||
+ __put_user(f->generation, &((struct floppy_drive_struct32 *)A(arg))->generation) ||
+ __put_user(f->keep_data, &((struct floppy_drive_struct32 *)A(arg))->keep_data) ||
+ __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)A(arg))->fd_ref) ||
+ __put_user(f->fd_device, &((struct floppy_drive_struct32 *)A(arg))->fd_device) ||
+ __put_user(f->last_checked, &((struct floppy_drive_struct32 *)A(arg))->last_checked) ||
+ __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)A(arg))->dmabuf) ||
+ __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)A(arg))->bufblocks)) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ case FDGETFDCSTAT32:
+ {
+ struct floppy_fdc_state *f = karg;
+
+ if (__put_user(f->spec1, &((struct floppy_fdc_state32 *)A(arg))->spec1) ||
+ __put_user(f->spec2, &((struct floppy_fdc_state32 *)A(arg))->spec2) ||
+ __put_user(f->dtr, &((struct floppy_fdc_state32 *)A(arg))->dtr) ||
+ __put_user(f->version, &((struct floppy_fdc_state32 *)A(arg))->version) ||
+ __put_user(f->dor, &((struct floppy_fdc_state32 *)A(arg))->dor) ||
+ __put_user(f->address, &((struct floppy_fdc_state32 *)A(arg))->address) ||
+ __copy_to_user((char *)&((struct floppy_fdc_state32 *)A(arg))->address
+ + sizeof(((struct floppy_fdc_state32 *)A(arg))->address),
+ (char *)&f->address + sizeof(f->address), sizeof(int)) ||
+ __put_user(f->driver_version, &((struct floppy_fdc_state32 *)A(arg))->driver_version) ||
+ __copy_to_user(((struct floppy_fdc_state32 *)A(arg))->track, f->track, sizeof(f->track))) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ case FDWERRORGET32:
+ {
+ struct floppy_write_errors *f = karg;
+
+ if (__put_user(f->write_errors, &((struct floppy_write_errors32 *)A(arg))->write_errors) ||
+ __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)A(arg))->first_error_sector) ||
+ __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)A(arg))->first_error_generation) ||
+ __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)A(arg))->last_error_sector) ||
+ __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)A(arg))->last_error_generation) ||
+ __put_user(f->badness, &((struct floppy_write_errors32 *)A(arg))->badness)) {
+ kfree(karg);
+ return -EFAULT;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ kfree(karg);
+ return 0;
+}
+
struct ppp_option_data32 {
__kernel_caddr_t32 ptr;
__u32 length;
@@ -540,14 +763,28 @@ struct ppp_option_data32 {
};
#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32)
-static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+struct ppp_idle32 {
+ __kernel_time_t32 xmit_idle;
+ __kernel_time_t32 recv_idle;
+};
+#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
+
+static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
{
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
struct ppp_option_data32 data32;
struct ppp_option_data data;
- int err;
+ struct ppp_idle32 idle32;
+ struct ppp_idle idle;
+ unsigned int kcmd;
+ void *karg;
+ int err = 0;
switch (cmd) {
+ case PPPIOCGIDLE32:
+ kcmd = PPPIOCGIDLE;
+ karg = &idle;
+ break;
case PPPIOCSCOMPRESS32:
if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32)))
return -EFAULT;
@@ -555,33 +792,163 @@ static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
if (!data.ptr)
return -ENOMEM;
if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) {
- err = -EFAULT;
- goto out;
+ kfree(data.ptr);
+ return -EFAULT;
}
data.length = data32.length;
data.transmit = data32.transmit;
+ kcmd = PPPIOCSCOMPRESS;
+ karg = &data;
break;
default:
printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
(int)fd, (unsigned int)cmd, (unsigned int)arg);
return -EINVAL;
}
- old_fs = get_fs();
set_fs (KERNEL_DS);
- err = sys_ioctl (fd, cmd, (unsigned long)&data);
+ err = sys_ioctl (fd, kcmd, (unsigned long)karg);
set_fs (old_fs);
- if (err)
- goto out;
switch (cmd) {
+ case PPPIOCGIDLE32:
+ if (err)
+ return err;
+ idle32.xmit_idle = idle.xmit_idle;
+ idle32.recv_idle = idle.recv_idle;
+ if (copy_to_user((struct ppp_idle32 *)A(arg), &idle32, sizeof(struct ppp_idle32)))
+ return -EFAULT;
+ break;
case PPPIOCSCOMPRESS32:
+ kfree(data.ptr);
+ break;
default:
break;
}
-out:
- kfree(data.ptr);
return err;
}
+
+struct mtget32 {
+ __u32 mt_type;
+ __u32 mt_resid;
+ __u32 mt_dsreg;
+ __u32 mt_gstat;
+ __u32 mt_erreg;
+ __kernel_daddr_t32 mt_fileno;
+ __kernel_daddr_t32 mt_blkno;
+};
+#define MTIOCGET32 _IOR('m', 2, struct mtget32)
+
+struct mtpos32 {
+ __u32 mt_blkno;
+};
+#define MTIOCPOS32 _IOR('m', 3, struct mtpos32)
+
+struct mtconfiginfo32 {
+ __u32 mt_type;
+ __u32 ifc_type;
+ __u16 irqnr;
+ __u16 dmanr;
+ __u16 port;
+ __u32 debug;
+ __u32 have_dens:1;
+ __u32 have_bsf:1;
+ __u32 have_fsr:1;
+ __u32 have_bsr:1;
+ __u32 have_eod:1;
+ __u32 have_seek:1;
+ __u32 have_tell:1;
+ __u32 have_ras1:1;
+ __u32 have_ras2:1;
+ __u32 have_ras3:1;
+ __u32 have_qfa:1;
+ __u32 pad1:5;
+ char reserved[10];
+};
+#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32)
+#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32)
+
+static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ mm_segment_t old_fs = get_fs();
+ struct mtconfiginfo info;
+ struct mtget get;
+ struct mtpos pos;
+ unsigned long kcmd;
+ void *karg;
+ int err = 0;
+
+ switch(cmd) {
+ case MTIOCPOS32:
+ kcmd = MTIOCPOS;
+ karg = &pos;
+ break;
+ case MTIOCGET32:
+ kcmd = MTIOCGET;
+ karg = &get;
+ break;
+ case MTIOCGETCONFIG32:
+ kcmd = MTIOCGETCONFIG;
+ karg = &info;
+ break;
+ case MTIOCSETCONFIG32:
+ kcmd = MTIOCSETCONFIG;
+ karg = &info;
+ if (__get_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) ||
+ __get_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) ||
+ __get_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) ||
+ __get_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) ||
+ __get_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) ||
+ __get_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) ||
+ __copy_from_user((char *)&info.debug + sizeof(info.debug),
+ (char *)&((struct mtconfiginfo32 *)A(arg))->debug
+ + sizeof(((struct mtconfiginfo32 *)A(arg))->debug),
+ sizeof(__u32)))
+ return -EFAULT;
+ break;
+ default:
+ printk("mt_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, (unsigned int)arg);
+ return -EINVAL;
+ }
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, kcmd, (unsigned long)karg);
+ set_fs (old_fs);
+ if (err)
+ return err;
+ switch (cmd) {
+ case MTIOCPOS32:
+ if (__put_user(pos.mt_blkno, &((struct mtpos32 *)A(arg))->mt_blkno))
+ return -EFAULT;
+ break;
+ case MTIOCGET32:
+ if (__put_user(get.mt_type, &((struct mtget32 *)A(arg))->mt_type) ||
+ __put_user(get.mt_resid, &((struct mtget32 *)A(arg))->mt_resid) ||
+ __put_user(get.mt_dsreg, &((struct mtget32 *)A(arg))->mt_dsreg) ||
+ __put_user(get.mt_gstat, &((struct mtget32 *)A(arg))->mt_gstat) ||
+ __put_user(get.mt_erreg, &((struct mtget32 *)A(arg))->mt_erreg) ||
+ __put_user(get.mt_fileno, &((struct mtget32 *)A(arg))->mt_fileno) ||
+ __put_user(get.mt_blkno, &((struct mtget32 *)A(arg))->mt_blkno))
+ return -EFAULT;
+ break;
+ case MTIOCGETCONFIG32:
+ if (__put_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) ||
+ __put_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) ||
+ __put_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) ||
+ __put_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) ||
+ __put_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) ||
+ __put_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) ||
+ __copy_to_user((char *)&((struct mtconfiginfo32 *)A(arg))->debug
+ + sizeof(((struct mtconfiginfo32 *)A(arg))->debug),
+ (char *)&info.debug + sizeof(info.debug), sizeof(__u32)))
+ return -EFAULT;
+ break;
+ case MTIOCSETCONFIG32:
+ break;
+ }
+ return 0;
+}
+
+
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
struct file * filp;
@@ -617,7 +984,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSIFHWADDR:
case SIOCADDMULTI:
case SIOCDELMULTI:
- case SIOGIFINDEX:
+ case SIOCGIFINDEX:
case SIOCGIFMAP:
case SIOCSIFMAP:
case SIOCGIFADDR:
@@ -628,6 +995,8 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSIFDSTADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
+ case SIOCSIFPFLAGS:
+ case SIOCGIFPFLAGS:
case SIOCGPPPSTATS:
case SIOCGPPPCSTATS:
case SIOCGPPPVER:
@@ -639,10 +1008,12 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = routing_ioctl(fd, cmd, arg);
goto out;
- case SIOCRTMSG:
- error = rtmsg_ioctl(fd, arg);
+ case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and
+ * the user would have seen just an -EINVAL anyways.
+ */
+ error = -EINVAL;
goto out;
-
+
case HDIO_GETGEO:
error = hdio_getgeo(fd, arg);
goto out;
@@ -671,6 +1042,30 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = hdio_ioctl_trans(fd, cmd, arg);
goto out;
+ case FDSETPRM32:
+ case FDDEFPRM32:
+ case FDGETPRM32:
+ case FDSETDRVPRM32:
+ case FDGETDRVPRM32:
+ case FDGETDRVSTAT32:
+ case FDPOLLDRVSTAT32:
+ case FDGETFDCSTAT32:
+ case FDWERRORGET32:
+ error = fd_ioctl_trans(fd, cmd, (unsigned long)arg);
+ goto out;
+
+ case PPPIOCGIDLE32:
+ case PPPIOCSCOMPRESS32:
+ error = ppp_ioctl_trans(fd, cmd, arg);
+ goto out;
+
+ case MTIOCGET32:
+ case MTIOCPOS32:
+ case MTIOCGETCONFIG32:
+ case MTIOCSETCONFIG32:
+ error = mt_ioctl_trans(fd, cmd, arg);
+ goto out;
+
/* List here exlicitly which ioctl's are known to have
* compatable types passed or none at all...
*/
@@ -751,13 +1146,22 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case BLKROGET:
/* 0x02 -- Floppy ioctls */
+ case FDMSGON:
+ case FDMSGOFF:
case FDSETEMSGTRESH:
case FDFLUSH:
+ case FDWERRORCLR:
case FDSETMAXERRS:
case FDGETMAXERRS:
case FDGETDRVTYP:
case FDEJECT:
- /* XXX The rest need struct floppy_* translations. */
+ case FDCLRPRM:
+ case FDFMTBEG:
+ case FDFMTEND:
+ case FDRESET:
+ case FDTWADDLE:
+ case FDFMTTRK:
+ case FDRAWCMD:
/* 0x12 */
case BLKRRPART:
@@ -807,6 +1211,15 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case KIOCSRATE:
case KIOCGRATE:
+ /* Big S */
+ case SCSI_IOCTL_GET_IDLUN:
+ case SCSI_IOCTL_DOORLOCK:
+ case SCSI_IOCTL_DOORUNLOCK:
+ case SCSI_IOCTL_TEST_UNIT_READY:
+ case SCSI_IOCTL_TAGGED_ENABLE:
+ case SCSI_IOCTL_TAGGED_DISABLE:
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+
/* Big V */
case VT_SETMODE:
case VT_GETMODE:
@@ -829,6 +1242,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case RTCGET:
case RTCSET:
+ /* Little m */
+ case MTIOCTOP:
+
/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
* embedded pointers in the arg which we'd need to clean up...
*/
@@ -860,9 +1276,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SIOCSARP:
case SIOCGARP:
case SIOCDARP:
+#if 0 /* XXX No longer exist in new routing code. XXX */
case OLD_SIOCSARP:
case OLD_SIOCGARP:
case OLD_SIOCDARP:
+#endif
case SIOCSRARP:
case SIOCGRARP:
case SIOCDRARP:
@@ -887,14 +1305,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case PPPIOCSNPMODE:
case PPPIOCGDEBUG:
case PPPIOCSDEBUG:
- case PPPIOCGIDLE:
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
- case PPPIOCSCOMPRESS32:
- error = ppp_ioctl (fd, cmd, (unsigned long)arg);
- goto out;
-
default:
printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
(int)fd, (unsigned int)cmd, (unsigned int)arg);
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 6f4c9dfdf..a84fe8eaa 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.39 1997/08/31 03:11:18 davem Exp $
+/* $Id: irq.c,v 1.47 1998/01/10 18:26:17 ecd Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -57,6 +57,7 @@ struct ino_bucket {
unsigned int ino;
unsigned int *imap;
unsigned int *iclr;
+ unsigned char *imap_refcnt;
};
#define INO_HASHSZ (NUM_HARD_IVECS >> 2)
@@ -114,9 +115,15 @@ int get_irq_list(char *buf)
}
#if 0
#ifdef CONFIG_PCI
- len += sprintf(buf + len, "ISTAT: PCI[%016lx] OBIO[%016lx]\n",
- psycho_root->psycho_regs->pci_istate,
- psycho_root->psycho_regs->obio_istate);
+ {
+ struct linux_psycho *p;
+ for (p = psycho_root; p; p = p->next)
+ len += sprintf(buf + len,
+ "ISTAT[%d]: PCI[%016lx] OBIO[%016lx]\n",
+ p->index,
+ p->psycho_regs->pci_istate,
+ p->psycho_regs->obio_istate);
+ }
#endif
#endif
return len;
@@ -229,10 +236,10 @@ unsigned char psycho_ino_to_pil[] = {
13, /* Audio Record */
14, /* Audio Playback */
15, /* PowerFail */
- 12, /* Keyboard/Mouse/Serial */
+ 9, /* Keyboard/Mouse/Serial */
11, /* Floppy */
2, /* Spare Hardware */
- 12, /* Keyboard */
+ 9, /* Keyboard */
4, /* Mouse */
12, /* Serial */
10, /* Timer 0 */
@@ -411,7 +418,7 @@ static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
offset += ((unsigned long)pregs);
*imap = ((unsigned int *)offset) + 1;
*iclr = (unsigned int *)
- (((unsigned long)pregs) + psycho_imap_offset(irq));
+ (((unsigned long)pregs) + psycho_iclr_offset(irq));
return;
}
#endif
@@ -449,10 +456,17 @@ static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup,
unsigned int **imap, unsigned int **iclr,
unsigned int irq)
{
- struct linux_psycho *psycho = psycho_root;
- struct psycho_regs *pregs = psycho->psycho_regs;
+ struct linux_psycho *psycho;
+ struct psycho_regs *pregs;
unsigned long addr, imoff;
+ psycho = psycho_by_index((irq & PCI_IRQ_BUSNO) >> PCI_IRQ_BUSNO_SHFT);
+ if (!psycho) {
+ printk("get_irq_translations: BAD PSYCHO BUSNO[%x]\n", irq);
+ panic("Bad PSYCHO IRQ frobnication...");
+ }
+ pregs = psycho->psycho_regs;
+
addr = (unsigned long) &pregs->imap_a_slot0;
imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT;
addr = addr + imoff;
@@ -515,7 +529,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
unsigned long flags;
unsigned int *imap, *iclr;
void *bus_id = NULL;
- int ivindex, ivindex_fixup, cpu_irq = -1;
+ int ivindex, ivindex_fixup, cpu_irq = -1, pending;
if(!handler)
return -EINVAL;
@@ -605,7 +619,10 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
return -ENOMEM;
}
+ pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
ivector_to_mask[ivindex] = (1 << cpu_irq);
+ if(pending)
+ ivector_to_mask[ivindex] |= 0x80000000;
if(dcookie) {
dcookie->ret_ino = ivindex;
@@ -625,6 +642,11 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
*(cpu_irq + irq_action) = action;
enable_irq(ivindex);
+
+ /* We ate the IVEC already, this makes sure it does not get lost. */
+ if(pending)
+ set_softint(1 << cpu_irq);
+
restore_flags(flags);
#ifdef __SMP__
if(irqs_have_been_distributed)
@@ -638,6 +660,7 @@ void free_irq(unsigned int irq, void *dev_id)
struct irqaction *action;
struct irqaction *tmp = NULL;
unsigned long flags;
+ unsigned int *imap = NULL;
unsigned int cpu_irq;
int ivindex = -1;
@@ -685,8 +708,8 @@ void free_irq(unsigned int irq, void *dev_id)
if(action->flags & SA_IMAP_MASKED) {
struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
- unsigned int *imap = bucket->imap;
+ imap = bucket->imap;
if(imap != NULL) {
ivindex = bucket->ino;
ivector_to_mask[ivindex] = 0;
@@ -696,8 +719,27 @@ void free_irq(unsigned int irq, void *dev_id)
}
kfree(action);
- if(ivindex != -1)
- disable_irq(ivindex);
+
+ if(ivindex != -1) {
+ struct ino_bucket *bp;
+ int i, count = 0;
+
+ /* The trick is that we can't turn the thing off when there
+ * are potentially other sub-irq level references.
+ */
+ if(imap != NULL) {
+ for(i = 0; i < INO_HASHSZ; i++) {
+ bp = ino_hash[i];
+ while(bp) {
+ if(bp->imap == imap)
+ count++;
+ bp = bp->next;
+ }
+ }
+ }
+ if(count < 2)
+ disable_irq(ivindex);
+ }
restore_flags(flags);
}
@@ -863,12 +905,21 @@ void synchronize_irq(void)
void report_spurious_ivec(struct pt_regs *regs)
{
extern unsigned long ivec_spurious_cookie;
- static int times = 0;
+#if 0
printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
ivec_spurious_cookie, regs->tpc);
- if(times++ > 1)
- prom_halt();
+#endif
+
+ /* We can actually see this on Ultra/PCI PCI cards, which are bridges
+ * to other devices. Here a single IMAP enabled potentially multiple
+ * unique interrupt sources (which each do have a unique ICLR register.
+ *
+ * So what we do is just register that the IVEC arrived, when registered
+ * for real the request_irq() code will check the high bit and signal
+ * a local CPU interrupt for it.
+ */
+ ivector_to_mask[ivec_spurious_cookie] |= (0x80000000);
}
void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
@@ -899,6 +950,7 @@ void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
void handler_irq(int irq, struct pt_regs *regs)
{
+ struct ino_bucket *bucket = NULL;
struct irqaction *action;
int cpu = smp_processor_id();
@@ -911,20 +963,19 @@ void handler_irq(int irq, struct pt_regs *regs)
unexpected_irq(irq, 0, regs);
} else {
do {
- struct ino_bucket *bucket = NULL;
- unsigned int ino = 0;
+ unsigned long *swmask = NULL;
if(action->flags & SA_IMAP_MASKED) {
bucket = (struct ino_bucket *)action->mask;
- ino = bucket->ino;
- if(!(ivector_to_mask[ino] & 0x80000000))
+ swmask = &ivector_to_mask[bucket->ino];
+ if(!(*swmask & 0x80000000))
continue;
}
action->handler(irq, action->dev_id, regs);
- if(bucket) {
- ivector_to_mask[ino] &= ~(0x80000000);
+ if(swmask) {
+ *swmask &= ~(0x80000000);
*(bucket->iclr) = SYSIO_ICLR_IDLE;
}
} while((action = action->next) != NULL);
@@ -938,12 +989,14 @@ extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs);
void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
{
struct irqaction *action = *(irq + irq_action);
+ struct ino_bucket *bucket;
int cpu = smp_processor_id();
irq_enter(cpu, irq);
+ bucket = (struct ino_bucket *)action->mask;
floppy_interrupt(irq, dev_cookie, regs);
- if(action->flags & SA_IMAP_MASKED)
- *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
+ ivector_to_mask[bucket->ino] &= ~(0x80000000);
+ *(bucket->iclr) = SYSIO_ICLR_IDLE;
irq_exit(cpu, irq);
}
#endif
@@ -975,28 +1028,60 @@ static void install_fast_irq(unsigned int cpu_irq,
int request_fast_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char *name)
+ unsigned long irqflags, const char *name, void *dev_id)
{
struct irqaction *action;
+ struct devid_cookie *dcookie = NULL;
+ struct ino_bucket *bucket = NULL;
unsigned long flags;
- unsigned int cpu_irq, *imap, *iclr;
- int ivindex = -1;
-
- /* XXX This really is not the way to do it, the "right way"
- * XXX is to have drivers set SA_SBUS or something like that
- * XXX in irqflags and we base our decision here on whether
- * XXX that flag bit is set or not.
- *
- * In this case nobody can have a fast interrupt at the level
- * where TICK interrupts live.
- */
- if(irq == 14)
- return -EINVAL;
- cpu_irq = sysio_ino_to_pil[irq];
+ unsigned int *imap, *iclr;
+ void *bus_id = NULL;
+ int ivindex, ivindex_fixup, cpu_irq = -1;
if(!handler)
return -EINVAL;
- imap = sysio_irq_to_imap(irq);
+
+ imap = iclr = NULL;
+ ivindex_fixup = 0;
+#ifdef CONFIG_PCI
+ if(PCI_IRQ_P(irq)) {
+ pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
+ } else
+#endif
+ if(irqflags & SA_DCOOKIE) {
+ if(!dev_id) {
+ printk("request_fast_irq: SA_DCOOKIE but dev_id is NULL!\n");
+ panic("Bogus irq registry.");
+ }
+ dcookie = dev_id;
+ dev_id = dcookie->real_dev_id;
+ cpu_irq = dcookie->pil;
+ imap = dcookie->imap;
+ iclr = dcookie->iclr;
+ bus_id = dcookie->bus_cookie;
+ get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+ &iclr, bus_id, irqflags, irq);
+ } else {
+ /* XXX NOTE: This code is maintained for compatability until I can
+ * XXX verify that all drivers sparc64 will use are updated
+ * XXX to use the new IRQ registry dcookie interface. -DaveM
+ */
+ if(irq == 14)
+ cpu_irq = irq;
+ else
+ cpu_irq = sysio_ino_to_pil[irq];
+ imap = sysio_irq_to_imap(irq);
+ if(!imap) {
+ printk("request_irq: BAD, null imap for old style "
+ "irq registry IRQ[%x].\n", irq);
+ panic("Bad IRQ registery...");
+ }
+ iclr = sysio_imap_to_iclr(imap);
+ }
+
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ ivindex += ivindex_fixup;
+
action = *(cpu_irq + irq_action);
if(action) {
if(action->flags & SA_SHIRQ)
@@ -1023,28 +1108,35 @@ int request_fast_irq(unsigned int irq,
}
install_fast_irq(cpu_irq, handler);
- if(imap) {
- ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
- ivector_to_mask[ivindex] = (1 << cpu_irq);
- iclr = sysio_imap_to_iclr(imap);
- action->mask = (unsigned long) iclr;
- irqflags |= SA_IMAP_MASKED;
- add_ino_hash(ivindex, imap, iclr, irqflags);
- } else
- action->mask = 0;
+ bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+ if(!bucket) {
+ kfree(action);
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+
+ ivector_to_mask[ivindex] = (1 << cpu_irq);
+
+ if(dcookie) {
+ dcookie->ret_ino = ivindex;
+ dcookie->ret_pil = cpu_irq;
+ }
+ action->mask = (unsigned long) bucket;
action->handler = handler;
- action->flags = irqflags;
+ action->flags = irqflags | SA_IMAP_MASKED;
action->dev_id = NULL;
action->name = name;
action->next = NULL;
*(cpu_irq + irq_action) = action;
-
- if(ivindex != -1)
- enable_irq(ivindex);
+ enable_irq(ivindex);
restore_flags(flags);
+#ifdef __SMP__
+ if(irqs_have_been_distributed)
+ distribute_irqs();
+#endif
return 0;
}
diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S
index 61233125c..9317587a7 100644
--- a/arch/sparc64/kernel/itlb_miss.S
+++ b/arch/sparc64/kernel/itlb_miss.S
@@ -1,4 +1,4 @@
-/* $Id: itlb_miss.S,v 1.10 1997/03/26 12:24:18 davem Exp $
+/* $Id: itlb_miss.S,v 1.11 1997/10/14 01:48:25 davem Exp $
* itlb_miss.S: Instruction TLB miss code, this is included directly
* into the trap table.
*
@@ -23,10 +23,10 @@
/*0x24*/ srlx %g1, 1, %g1 ! PTE offset
/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
2:/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
- /*0x30*/ brlz,a,pt %g5, 1f ! Valid set?
- /*0x34*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
- /*0x38*/ ba,a,pt %xcc, sparc64_itlb_refbit_catch ! Nope...
-1:/*0x3c*/ retry ! Trap return
+ /*0x30*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set?
+ /*0x34*/ nop ! delay
+ /*0x38*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
+ /*0x3c*/ retry ! Trap return
3: /* ICACHE line 3 */
/*0x40*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 35d4d606d..4e5ead982 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,9 +1,9 @@
-/* $Id: process.c,v 1.42 1997/08/19 14:17:55 jj Exp $
+/* $Id: process.c,v 1.50 1998/01/09 16:39:33 jj Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
/*
@@ -39,6 +39,8 @@
#include <asm/elf.h>
#include <asm/fpumacro.h>
+/* #define VERBOSE_SHOWREGS */
+
#define PGTCACHE_HIGH_WATER 50
#define PGTCACHE_LOW_WATER 25
@@ -98,7 +100,7 @@ asmlinkage int cpu_idle(void)
}
barrier();
current->counter = -100;
- if(resched_needed())
+ if(need_resched)
schedule();
barrier();
}
@@ -166,7 +168,7 @@ static void show_regwindow32(struct pt_regs *regs)
{
struct reg_window32 *rw;
struct reg_window32 r_w;
- unsigned long old_fs;
+ mm_segment_t old_fs;
__asm__ __volatile__ ("flushw");
rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]);
@@ -192,7 +194,7 @@ static void show_regwindow(struct pt_regs *regs)
{
struct reg_window *rw;
struct reg_window r_w;
- unsigned long old_fs;
+ mm_segment_t old_fs;
if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) {
__asm__ __volatile__ ("flushw");
@@ -311,8 +313,30 @@ void __show_regs(struct pt_regs * regs)
#endif
}
+#ifdef VERBOSE_SHOWREGS
+static void idump_from_user (unsigned int *pc)
+{
+ int i;
+ int code;
+
+ if((((unsigned long) pc) & 3))
+ return;
+
+ pc -= 3;
+ for(i = -3; i < 6; i++) {
+ get_user(code, pc);
+ printk("%c%08x%c",i?' ':'<',code,i?' ':'>');
+ pc++;
+ }
+ printk("\n");
+}
+#endif
+
void show_regs(struct pt_regs *regs)
{
+#ifdef VERBOSE_SHOWREGS
+ extern long etrap, etraptl1;
+#endif
__show_regs(regs);
#ifdef __SMP__
{
@@ -321,6 +345,17 @@ void show_regs(struct pt_regs *regs)
smp_report_regs();
}
#endif
+
+#ifdef VERBOSE_SHOWREGS
+ if (regs->tpc >= &etrap && regs->tpc < &etraptl1 &&
+ regs->u_regs[14] >= (long)current - PAGE_SIZE &&
+ regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) {
+ printk ("*********parent**********\n");
+ __show_regs((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ));
+ idump_from_user(((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ))->tpc);
+ printk ("*********endpar**********\n");
+ }
+#endif
}
void show_regs32(struct pt_regs32 *regs)
@@ -352,29 +387,35 @@ void show_thread(struct thread_struct *tss)
printk("sig_address: 0x%016lx\n", tss->sig_address);
printk("sig_desc: 0x%016lx\n", tss->sig_desc);
printk("ksp: 0x%016lx\n", tss->ksp);
- printk("kpc: 0x%016lx\n", tss->kpc);
-
- for (i = 0; i < NSWINS; i++) {
- if (!tss->rwbuf_stkptrs[i])
- continue;
- printk("reg_window[%d]:\n", i);
- printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]);
+ printk("kpc: 0x%08x\n", tss->kpc);
+
+ if (tss->w_saved) {
+ for (i = 0; i < NSWINS; i++) {
+ if (!tss->rwbuf_stkptrs[i])
+ continue;
+ printk("reg_window[%d]:\n", i);
+ printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]);
+ }
+ printk("w_saved: 0x%04x\n", tss->w_saved);
}
- printk("w_saved: 0x%08lx\n", tss->w_saved);
printk("sstk_info.stack: 0x%016lx\n",
(unsigned long)tss->sstk_info.the_stack);
printk("sstk_info.status: 0x%016lx\n",
(unsigned long)tss->sstk_info.cur_status);
printk("flags: 0x%08x\n", tss->flags);
- printk("current_ds: 0x%016lx\n", tss->current_ds);
-
- /* XXX missing: core_exec */
+ printk("current_ds: 0x%016lx\n", tss->current_ds.seg);
}
/* Free current thread data structures etc.. */
void exit_thread(void)
{
+ if (current->tss.utraps) {
+ if (current->tss.utraps[0] < 2)
+ kfree (current->tss.utraps);
+ else
+ current->tss.utraps[0]--;
+ }
}
void flush_thread(void)
@@ -540,9 +581,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
#ifdef __SMP__
- p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8;
+ p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_smpfork)) - 0x8;
#else
- p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+ p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_syscall)) - 0x8;
#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
@@ -569,6 +610,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
return -EFAULT;
p->tss.kregs->u_regs[UREG_FP] = csp;
}
+ if (p->tss.utraps)
+ p->tss.utraps[0]++;
}
/* Set the return value for the child. */
@@ -595,7 +638,6 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->regs.y = regs->y;
/* fuck me plenty */
memcpy(&dump->regs.regs[0], &regs->u_regs[1], (sizeof(unsigned long) * 15));
- dump->uexec = current->tss.core_exec;
dump->u_tsize = (((unsigned long) current->mm->end_code) -
((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
index 8aa1c342b..b3b403e33 100644
--- a/arch/sparc64/kernel/psycho.c
+++ b/arch/sparc64/kernel/psycho.c
@@ -1,7 +1,8 @@
-/* $Id: psycho.c,v 1.22 1997/08/31 03:51:40 davem Exp $
+/* $Id: psycho.c,v 1.31 1998/01/10 18:26:15 ecd Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/config.h>
@@ -11,6 +12,16 @@
#include <asm/ebus.h>
#include <asm/sbus.h> /* for sanity check... */
+#undef PROM_DEBUG
+#undef FIXUP_REGS_DEBUG
+#undef FIXUP_IRQ_DEBUG
+
+#ifdef PROM_DEBUG
+#define dprintf prom_printf
+#else
+#define dprintf printk
+#endif
+
#ifndef CONFIG_PCI
int pcibios_present(void)
@@ -49,6 +60,28 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
#include <asm/uaccess.h>
struct linux_psycho *psycho_root = NULL;
+struct linux_psycho **psycho_index_map;
+int linux_num_psycho = 0;
+static struct linux_pbm_info *bus2pbm[256];
+
+static int pbm_read_config_byte(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char *value);
+static int pbm_read_config_word(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short *value);
+static int pbm_read_config_dword(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int *value);
+static int pbm_write_config_byte(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char value);
+static int pbm_write_config_word(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short value);
+static int pbm_write_config_dword(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int value);
/* This is used to make the scan_bus in the generic PCI code be
* a nop, as we need to control the actual bus probing sequence.
@@ -69,10 +102,22 @@ static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
unsigned long control, i;
unsigned long *iopte;
+ /*
+ * Invalidate TLB Entries.
+ */
+ control = psycho->psycho_regs->iommu_control;
+ control |= IOMMU_CTRL_DENAB;
+ psycho->psycho_regs->iommu_control = control;
+ for(i = 0; i < 16; i++) {
+ psycho->psycho_regs->iommu_data[i] = 0;
+ }
+ control &= ~(IOMMU_CTRL_DENAB);
+ psycho->psycho_regs->iommu_control = control;
+
memory_start = (tsbbase + ((32 * 1024) * 8));
iopte = (unsigned long *)tsbbase;
- for(i = 0; i < (65536 / 2); i++) {
+ for(i = 0; i < (32 * 1024); i++) {
*iopte = (IOPTE_VALID | IOPTE_64K |
IOPTE_CACHE | IOPTE_WRITE);
*iopte |= (i << 16);
@@ -94,21 +139,26 @@ extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
{
struct linux_prom64_registers pr_regs[3];
+ struct linux_psycho *psycho;
char namebuf[128];
u32 portid;
int node;
printk("PSYCHO: Probing for controllers.\n");
+#ifdef PROM_DEBUG
+ dprintf("PSYCHO: Probing for controllers.\n");
+#endif
memory_start = long_align(memory_start);
node = prom_getchild(prom_root_node);
while((node = prom_searchsiblings(node, "pci")) != 0) {
- struct linux_psycho *psycho = (struct linux_psycho *)memory_start;
struct linux_psycho *search;
struct linux_pbm_info *pbm = NULL;
u32 busrange[2];
int err, is_pbm_a;
+ psycho = (struct linux_psycho *)memory_start;
+
portid = prom_getintdefault(node, "upa-portid", 0xff);
for(search = psycho_root; search; search = search->next) {
if(search->upa_portid == portid) {
@@ -123,7 +173,8 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
}
}
- memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+ memory_start = long_align(memory_start +
+ sizeof(struct linux_psycho));
memset(psycho, 0, sizeof(*psycho));
@@ -131,8 +182,12 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
psycho_root = psycho;
psycho->upa_portid = portid;
+ psycho->index = linux_num_psycho++;
- /* Map in PSYCHO register set and report the presence of this PSYCHO. */
+ /*
+ * Map in PSYCHO register set and report the presence
+ * of this PSYCHO.
+ */
err = prom_getproperty(node, "reg",
(char *)&pr_regs[0], sizeof(pr_regs));
if(err == 0 || err == -1) {
@@ -141,7 +196,10 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
prom_halt();
}
- /* Third REG in property is base of entire PSYCHO register space. */
+ /*
+ * Third REG in property is base of entire PSYCHO
+ * register space.
+ */
psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
NULL, sizeof(struct psycho_regs),
"PSYCHO Registers",
@@ -154,12 +212,19 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
printk("PSYCHO: Found controller, main regs at %p\n",
psycho->psycho_regs);
-#if 0
- printk("PSYCHO: Interrupt retry [%016lx]\n",
- psycho->psycho_regs->irq_retry);
+#ifdef PROM_DEBUG
+ dprintf("PSYCHO: Found controller, main regs at %p\n",
+ psycho->psycho_regs);
#endif
+
psycho->psycho_regs->irq_retry = 0xff;
+#if 0
+ psycho->psycho_regs->ecc_control |= 1;
+ psycho->psycho_regs->sbuf_a_control = 0;
+ psycho->psycho_regs->sbuf_b_control = 0;
+#endif
+
/* Now map in PCI config space for entire PSYCHO. */
psycho->pci_config_space =
sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
@@ -172,7 +237,12 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
}
/* Report some more info. */
- printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space);
+ printk("PSYCHO: PCI config space at %p\n",
+ psycho->pci_config_space);
+#ifdef PROM_DEBUG
+ dprintf("PSYCHO: PCI config space at %p\n",
+ psycho->pci_config_space);
+#endif
memory_start = psycho_iommu_init(psycho, memory_start);
@@ -223,6 +293,13 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
prom_halt();
}
+ psycho_index_map = (struct linux_psycho **)long_align(memory_start);
+ memory_start = long_align(memory_start + linux_num_psycho
+ * sizeof(struct linux_psycho *));
+
+ for (psycho = psycho_root; psycho; psycho = psycho->next)
+ psycho_index_map[psycho->index] = psycho;
+
return memory_start;
}
@@ -361,18 +438,118 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void)
return pci_init_alloc(sizeof(struct pcidev_cookie));
}
+
+static void
+pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
+{
+ unsigned int devfn, l, class;
+ unsigned char hdr_type = 0;
+
+ for (devfn = 0; devfn < 0xff; ++devfn) {
+ if (PCI_FUNC(devfn) == 0) {
+ pbm_read_config_byte(pbm, bus, devfn,
+ PCI_HEADER_TYPE, &hdr_type);
+ } else if (!(hdr_type & 0x80)) {
+ /* not a multi-function device */
+ continue;
+ }
+
+ /* Check if there is anything here. */
+ pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l);
+ if (l == 0xffffffff || l == 0x00000000) {
+ hdr_type = 0;
+ continue;
+ }
+
+ /* See if this is a bridge device. */
+ pbm_read_config_dword(pbm, bus, devfn,
+ PCI_CLASS_REVISION, &class);
+
+ if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+ unsigned int buses;
+
+ pbm_read_config_dword(pbm, bus, devfn,
+ PCI_PRIMARY_BUS, &buses);
+
+ /*
+ * First reconfigure everything underneath the bridge.
+ */
+ pbm_reconfigure_bridges(pbm, (buses >> 8) & 0xff);
+
+ /*
+ * Unconfigure this bridges bus numbers,
+ * pci_scan_bus() will fix this up properly.
+ */
+ buses &= 0xff000000;
+ pbm_write_config_dword(pbm, bus, devfn,
+ PCI_PRIMARY_BUS, buses);
+ }
+ }
+}
+
+static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
+{
+ unsigned int nbus;
+
+ /*
+ * First, reconfigure all bridge devices underneath this pbm.
+ */
+ pbm_reconfigure_bridges(pbm, pbm->pci_first_busno);
+
+ /*
+ * Now reconfigure the pbm to it's new bus number and set up
+ * our bus2pbm mapping for this pbm.
+ */
+ nbus = pbm->pci_last_busno - pbm->pci_first_busno;
+
+ pbm_write_config_byte(pbm, pbm->pci_first_busno, 0, 0x40, bus);
+
+ pbm->pci_first_busno = bus;
+ pbm_write_config_byte(pbm, bus, 0, 0x41, 0xff);
+
+ do {
+ bus2pbm[bus++] = pbm;
+ } while (nbus--);
+}
+
+
static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
{
+ static struct pci_bus *pchain = NULL;
struct pci_bus *pbus = &pbm->pci_bus;
+ static unsigned char busno = 0;
/* PSYCHO PBM's include child PCI bridges in bus-range property,
* but we don't scan each of those ourselves, Linux generic PCI
* probing code will find child bridges and link them into this
* pbm's root PCI device hierarchy.
*/
- pbus->number = pbm->pci_first_busno;
+
+ pbus->number = pbus->secondary = busno;
pbus->sysdata = pbm;
+
+ pbm_fixup_busno(pbm, busno);
+
pbus->subordinate = pci_scan_bus(pbus, mstart);
+
+ /*
+ * Set the maximum subordinate bus of this pbm.
+ */
+ pbm->pci_last_busno = pbus->subordinate;
+ pbm_write_config_byte(pbm, busno, 0, 0x41, pbm->pci_last_busno);
+
+ busno = pbus->subordinate + 1;
+
+ /*
+ * Fixup the chain of primary PCI busses.
+ */
+ if (pchain) {
+ pchain->next = &pbm->pci_bus;
+ pchain = pchain->next;
+ } else {
+ pchain = &pci_root;
+ memcpy(pchain, &pbm->pci_bus, sizeof(pci_root));
+ }
}
static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
@@ -433,8 +610,6 @@ static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
pdev_cookie_fillin(pbm, pdev);
}
-/* #define RECORD_ASSIGNMENTS_DEBUG */
-
/* Walk PROM device tree under PBM, looking for 'assigned-address'
* properties, and recording them in pci_vma's linked in via
* PBM->assignments.
@@ -534,8 +709,6 @@ static void record_assignments(struct linux_pbm_info *pbm)
assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
}
-/* #define FIXUP_REGS_DEBUG */
-
static void fixup_regs(struct pci_dev *pdev,
struct linux_pbm_info *pbm,
struct linux_prom_pci_registers *pregs,
@@ -556,12 +729,14 @@ static void fixup_regs(struct pci_dev *pdev,
if(bustype == 0) {
/* Config space cookie, nothing to do. */
if(preg != 0)
- prom_printf("fixup_doit: strange, config space not 0\n");
+ printk("%s: strange, config space not 0\n",
+ __FUNCTION__);
continue;
} else if(bustype == 3) {
/* XXX add support for this... */
- prom_printf("fixup_doit: Warning, ignoring 64-bit PCI "
- "memory space, tell DaveM.\n");
+ printk("%s: Warning, ignoring 64-bit PCI memory space, "
+ "tell Eddie C. Dost (ecd@skynet.be).\n",
+ __FUNCTION__);
continue;
}
bsreg = (pregs[preg].phys_hi & 0xff);
@@ -574,8 +749,13 @@ static void fixup_regs(struct pci_dev *pdev,
if((bsreg < PCI_BASE_ADDRESS_0) ||
(bsreg > (PCI_BASE_ADDRESS_5 + 4)) ||
(bsreg & 3)) {
- prom_printf("fixup_doit: Warning, ignoring bogus basereg [%x]\n",
- bsreg);
+ printk("%s: [%04x:%04x]: "
+ "Warning, ignoring bogus basereg [%x]\n",
+ __FUNCTION__, pdev->vendor, pdev->device, bsreg);
+ printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n",
+ pregs[preg].phys_hi, pregs[preg].phys_mid,
+ pregs[preg].phys_lo, pregs[preg].size_hi,
+ pregs[preg].size_lo);
continue;
}
@@ -740,22 +920,22 @@ static void fixup_regs(struct pci_dev *pdev,
pdev->devfn,
PCI_COMMAND, &l);
#ifdef FIXUP_REGS_DEBUG
- prom_printf("[");
+ dprintf("[");
#endif
if(IO_seen) {
#ifdef FIXUP_REGS_DEBUG
- prom_printf("IO ");
+ dprintf("IO ");
#endif
l |= PCI_COMMAND_IO;
}
if(MEM_seen) {
#ifdef FIXUP_REGS_DEBUG
- prom_printf("MEM");
+ dprintf("MEM");
#endif
l |= PCI_COMMAND_MEMORY;
}
#ifdef FIXUP_REGS_DEBUG
- prom_printf("]");
+ dprintf("]");
#endif
pcibios_write_config_dword(pdev->bus->number,
pdev->devfn,
@@ -763,7 +943,7 @@ static void fixup_regs(struct pci_dev *pdev,
}
#ifdef FIXUP_REGS_DEBUG
- prom_printf("REG_FIXUP[%s]: ", pci_strdev(pdev->vendor, pdev->device));
+ dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device);
for(preg = 0; preg < 6; preg++) {
if(pdev->base_address[preg] != 0)
prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]);
@@ -814,7 +994,7 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
}
/* Exported for EBUS probing layer. */
-unsigned int psycho_irq_build(unsigned int full_ino)
+unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino)
{
unsigned long imap_off, ign, ino;
@@ -906,11 +1086,9 @@ unsigned int psycho_irq_build(unsigned int full_ino)
}
imap_off -= imap_offset(imap_a_slot0);
- return pci_irq_encode(imap_off, 0 /* XXX */, ign, ino);
+ return pci_irq_encode(imap_off, pbm->parent->index, ign, ino);
}
-/* #define FIXUP_IRQ_DEBUG */
-
static void fixup_irq(struct pci_dev *pdev,
struct linux_pbm_info *pbm,
int node)
@@ -920,24 +1098,30 @@ static void fixup_irq(struct pci_dev *pdev,
int err;
#ifdef FIXUP_IRQ_DEBUG
- printk("fixup_irq[%s:%s]: ",
- pci_strvendor(pdev->vendor),
- pci_strdev(pdev->vendor, pdev->device));
+ dprintf("fixup_irq[%04x:%04x]: ", pdev->vendor, pdev->device);
#endif
err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
if(err == 0 || err == -1) {
- prom_printf("fixup_irq: No interrupts property for dev[%s:%s]\n",
- pci_strvendor(pdev->vendor),
- pci_strdev(pdev->vendor, pdev->device));
+ prom_printf("fixup_irq: No interrupts property for dev[%04x:%04x]\n",
+ pdev->vendor, pdev->device);
prom_halt();
}
/* See if fully specified already (ie. for onboard devices like hme) */
if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
- pdev->irq = psycho_irq_build(prom_irq);
+ pdev->irq = psycho_irq_build(pbm, prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
+#endif
+ /* See if onboard device interrupt (i.e. bit 5 set) */
+ } else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) {
+ pdev->irq = psycho_irq_build(pbm,
+ (pbm->parent->upa_portid << 6)
+ | prom_irq);
#ifdef FIXUP_IRQ_DEBUG
- printk("fully specified prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
+ dprintf("partially specified prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
#endif
} else {
unsigned int bus, slot, line;
@@ -952,20 +1136,25 @@ static void fixup_irq(struct pci_dev *pdev,
if(pbm == &pbm->parent->pbm_A)
slot = (pdev->devfn >> 3) - 1;
else
- slot = ((pdev->devfn >> 3) >> 1) - 1;
+ slot = (pdev->devfn >> 3) - 2;
} else {
/* Underneath a bridge, use slot number of parent
* bridge.
*/
- slot = (pdev->bus->self->devfn >> 3) - 1;
+ if(pbm == &pbm->parent->pbm_A)
+ slot = (pdev->bus->self->devfn >> 3) - 1;
+ else
+ slot = (pdev->bus->self->devfn >> 3) - 2;
/* Use low slot number bits of child as IRQ line. */
- line = ((pdev->devfn >> 3) & 3);
+ line = (line + ((pdev->devfn >> 3) - 4)) % 4;
}
slot = (slot << 2);
- pdev->irq = psycho_irq_build((((portid << 6) & PSYCHO_IMAP_IGN) |
- (bus | slot | line)));
+ pdev->irq = psycho_irq_build(pbm,
+ (((portid << 6) & PSYCHO_IMAP_IGN)
+ | (bus | slot | line)));
+
#ifdef FIXUP_IRQ_DEBUG
do {
unsigned char iline, ipin;
@@ -978,15 +1167,24 @@ static void fixup_irq(struct pci_dev *pdev,
pdev->devfn,
PCI_INTERRUPT_LINE,
&iline);
- printk("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] "
- "iline[%x] ipin[%x] prom_irq[%x]",
- portid, bus>>4, slot>>2, line, pdev->irq,
- iline, ipin, prom_irq);
+ dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] "
+ "iline[%x] ipin[%x] prom_irq[%x]",
+ portid, bus>>4, slot>>2, line, pdev->irq,
+ iline, ipin, prom_irq);
} while(0);
#endif
}
+
+ /*
+ * Write the INO to config space PCI_INTERRUPT_LINE.
+ */
+ (void)pcibios_write_config_byte(pdev->bus->number,
+ pdev->devfn,
+ PCI_INTERRUPT_LINE,
+ pdev->irq & PCI_IRQ_INO);
+
#ifdef FIXUP_IRQ_DEBUG
- printk("\n");
+ dprintf("\n");
#endif
}
@@ -1093,15 +1291,11 @@ static void psycho_final_fixup(struct linux_psycho *psycho)
/* Second, fixup base address registers and IRQ lines... */
fixup_addr_irq(&psycho->pbm_A);
fixup_addr_irq(&psycho->pbm_B);
-
-#if 0
- prom_halt();
-#endif
}
unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
{
- struct linux_psycho *psycho = psycho_root;
+ struct linux_psycho *psycho;
pci_probe_enable = 1;
@@ -1117,11 +1311,13 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end
* XXX apps that need to get at PCI configuration space.
*/
- /* Probe busses under PBM A. */
- pbm_probe(&psycho->pbm_A, &memory_start);
+ for (psycho = psycho_root; psycho; psycho = psycho->next) {
+ /* Probe busses under PBM B. */
+ pbm_probe(&psycho->pbm_B, &memory_start);
- /* Probe busses under PBM B. */
- pbm_probe(&psycho->pbm_B, &memory_start);
+ /* Probe busses under PBM A. */
+ pbm_probe(&psycho->pbm_A, &memory_start);
+ }
pci_init_alloc_init(&memory_start);
@@ -1130,15 +1326,17 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end
* sysdata with a pointer to the PBM (for pci_bus's) or
* a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
*/
- fill_in_pbm_cookies(&psycho->pbm_A);
- fill_in_pbm_cookies(&psycho->pbm_B);
+ for (psycho = psycho_root; psycho; psycho = psycho->next) {
+ fill_in_pbm_cookies(&psycho->pbm_A);
+ fill_in_pbm_cookies(&psycho->pbm_B);
- /* See what OBP has taken care of already. */
- record_assignments(&psycho->pbm_A);
- record_assignments(&psycho->pbm_B);
+ /* See what OBP has taken care of already. */
+ record_assignments(&psycho->pbm_A);
+ record_assignments(&psycho->pbm_B);
- /* Now, fix it all up. */
- psycho_final_fixup(psycho);
+ /* Now, fix it all up. */
+ psycho_final_fixup(psycho);
+ }
pci_init_alloc_fini();
@@ -1153,113 +1351,124 @@ volatile int pci_poke_faulted = 0;
* XXX space exists, on Ultra we can have many of them, especially with
* XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
*/
-static char *pci_mkaddr(unsigned char bus, unsigned char device_fn,
- unsigned char where)
+static void *
+pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus,
+ unsigned char devfn, unsigned char where)
{
- unsigned long ret = (unsigned long) psycho_root->pci_config_space;
+ unsigned long ret;
+
+ if (!pbm)
+ return NULL;
+
+ ret = (unsigned long) pbm->parent->pci_config_space;
ret |= (1 << 24);
- ret |= ((bus & 0xff) << 16);
- ret |= ((device_fn & 0xff) << 8);
- ret |= (where & 0xfc);
- return (unsigned char *)ret;
+ ret |= (bus << 16);
+ ret |= (devfn << 8);
+ ret |= where;
+
+ return (void *)ret;
}
-static inline int out_of_range(unsigned char bus, unsigned char device_fn)
+static inline int
+out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn)
{
- return ((bus == 0 && PCI_SLOT(device_fn) > 4) ||
- (bus == 1 && PCI_SLOT(device_fn) > 6) ||
+ return (((pbm == &pbm->parent->pbm_B) && PCI_SLOT(devfn) > 4) ||
+ ((pbm == &pbm->parent->pbm_A) && PCI_SLOT(devfn) > 6) ||
(pci_probe_enable == 0));
}
-int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned char *value)
+static int
+pbm_read_config_byte(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char *value)
{
- unsigned char *addr = pci_mkaddr(bus, device_fn, where);
- unsigned int word, trapped;
+ unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where);
+ unsigned int trapped;
+ unsigned char byte;
*value = 0xff;
- if(out_of_range(bus, device_fn))
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (out_of_range(pbm, bus, devfn))
return PCIBIOS_SUCCESSFUL;
pci_poke_in_progress = 1;
pci_poke_faulted = 0;
__asm__ __volatile__("membar #Sync\n\t"
- "lduwa [%1] %2, %0\n\t"
+ "lduba [%1] %2, %0\n\t"
"membar #Sync"
- : "=r" (word)
+ : "=r" (byte)
: "r" (addr), "i" (ASI_PL));
pci_poke_in_progress = 0;
trapped = pci_poke_faulted;
pci_poke_faulted = 0;
- if(!trapped) {
- switch(where & 3) {
- case 0:
- *value = word & 0xff;
- break;
- case 1:
- *value = (word >> 8) & 0xff;
- break;
- case 2:
- *value = (word >> 16) & 0xff;
- break;
- case 3:
- *value = (word >> 24) & 0xff;
- break;
- };
- }
+ if(!trapped)
+ *value = byte;
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned short *value)
+static int
+pbm_read_config_word(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short *value)
{
- unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
- unsigned int word, trapped;
+ unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where);
+ unsigned int trapped;
+ unsigned short word;
*value = 0xffff;
- if(out_of_range(bus, device_fn))
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (out_of_range(pbm, bus, devfn))
return PCIBIOS_SUCCESSFUL;
+ if (where & 0x01) {
+ printk("pcibios_read_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
pci_poke_in_progress = 1;
pci_poke_faulted = 0;
__asm__ __volatile__("membar #Sync\n\t"
- "lduwa [%1] %2, %0\n\t"
+ "lduha [%1] %2, %0\n\t"
"membar #Sync"
: "=r" (word)
: "r" (addr), "i" (ASI_PL));
pci_poke_in_progress = 0;
trapped = pci_poke_faulted;
pci_poke_faulted = 0;
- if(!trapped) {
- switch(where & 3) {
- case 0:
- *value = word & 0xffff;
- break;
- case 2:
- *value = (word >> 16) & 0xffff;
- break;
- default:
- printk("pcibios_read_config_word: misaligned "
- "reg [%x]\n", where);
- break;
- };
- }
+ if(!trapped)
+ *value = word;
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned int *value)
+static int
+pbm_read_config_dword(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int *value)
{
- unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+ unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where);
unsigned int word, trapped;
*value = 0xffffffff;
- if(out_of_range(bus, device_fn))
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x03) {
+ printk("pcibios_read_config_dword: misaligned reg [%x]\n",
+ where);
return PCIBIOS_SUCCESSFUL;
+ }
pci_poke_in_progress = 1;
pci_poke_faulted = 0;
@@ -1276,12 +1485,17 @@ int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned char value)
+static int
+pbm_write_config_byte(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char value)
{
- unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+ unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where);
- if(out_of_range(bus, device_fn))
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (out_of_range(pbm, bus, devfn))
return PCIBIOS_SUCCESSFUL;
pci_poke_in_progress = 1;
@@ -1299,14 +1513,25 @@ int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned short value)
+static int
+pbm_write_config_word(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short value)
{
- unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+ unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where);
- if(out_of_range(bus, device_fn))
+ if (!addr)
return PCIBIOS_SUCCESSFUL;
+ if (out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x01) {
+ printk("pcibios_write_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
pci_poke_in_progress = 1;
__asm__ __volatile__("membar #Sync\n\t"
"stha %0, [%1] %2\n\t"
@@ -1317,14 +1542,25 @@ int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
return PCIBIOS_SUCCESSFUL;
}
-int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned int value)
+static int
+pbm_write_config_dword(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int value)
{
- unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+ unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where);
- if(out_of_range(bus, device_fn))
+ if (!addr)
return PCIBIOS_SUCCESSFUL;
+ if (out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x03) {
+ printk("pcibios_write_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
pci_poke_in_progress = 1;
__asm__ __volatile__("membar #Sync\n\t"
"stwa %0, [%1] %2\n\t"
@@ -1335,6 +1571,42 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
return PCIBIOS_SUCCESSFUL;
}
+int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char *value)
+{
+ return pbm_read_config_byte(bus2pbm[bus], bus, devfn, where, value);
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short *value)
+{
+ return pbm_read_config_word(bus2pbm[bus], bus, devfn, where, value);
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int *value)
+{
+ return pbm_read_config_dword(bus2pbm[bus], bus, devfn, where, value);
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char value)
+{
+ return pbm_write_config_byte(bus2pbm[bus], bus, devfn, where, value);
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short value)
+{
+ return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value);
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int value)
+{
+ return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value);
+}
+
asmlinkage int sys_pciconfig_read(unsigned long bus,
unsigned long dfn,
unsigned long off,
@@ -1346,19 +1618,22 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
unsigned int uint;
int err = 0;
+ if(!suser())
+ return -EPERM;
+
lock_kernel();
switch(len) {
case 1:
pcibios_read_config_byte(bus, dfn, off, &ubyte);
- put_user(ubyte, buf);
+ put_user(ubyte, (unsigned char *)buf);
break;
case 2:
pcibios_read_config_word(bus, dfn, off, &ushort);
- put_user(ushort, buf);
+ put_user(ushort, (unsigned short *)buf);
break;
case 4:
pcibios_read_config_dword(bus, dfn, off, &uint);
- put_user(uint, buf);
+ put_user(uint, (unsigned int *)buf);
break;
default:
@@ -1381,6 +1656,9 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
unsigned int uint;
int err = 0;
+ if(!suser())
+ return -EPERM;
+
lock_kernel();
switch(len) {
case 1:
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 3df35ef14..9174e7e45 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -309,12 +309,14 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
}
if(offset >= 16 && offset < 784) {
offset -= 16; offset >>= 2;
- pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
+ if (t->w_saved)
+ pt_os_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset), addr);
return;
}
if(offset >= 784 && offset < 832) {
offset -= 784; offset >>= 2;
- pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
+ if (t->w_saved)
+ pt_os_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset), addr);
return;
}
switch(offset) {
@@ -399,12 +401,14 @@ static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
goto failure;
if(offset >= 16 && offset < 784) {
offset -= 16; offset >>= 2;
- *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
+ if (t->w_saved)
+ *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
goto success;
}
if(offset >= 784 && offset < 832) {
offset -= 784; offset >>= 2;
- *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
+ if (t->w_saved)
+ *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
goto success;
}
switch(offset) {
@@ -964,7 +968,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
addr = 1;
case PTRACE_CONT: { /* restart after signal. */
- if (data > NSIG) {
+ if (data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
}
@@ -1016,7 +1020,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;
}
@@ -1063,10 +1067,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/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index a3ac093f3..685182473 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.33 1997/08/21 09:13:22 davem Exp $
+/* $Id: rtrap.S,v 1.37 1997/12/11 15:14:54 jj Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -55,11 +55,11 @@ rtrap: sethi %hi(bh_active), %l2
ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48
1: membar #Sync
ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr
-rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
- mov %g6, %l6
+ mov %g6, %o5
ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4
ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5
ldx [%sp + PTREGS_OFF + PT_V9_G6], %g6
@@ -88,10 +88,10 @@ rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
wrpr %o2, %g0, %tnpc
mov PRIMARY_CONTEXT, %l7
brnz,pn %l3, kern_rtt
- mov SECONDARY_CONTEXT, %l5
+ mov SECONDARY_CONTEXT, %o4
stxa %l0, [%l7] ASI_DMMU
- stxa %l0, [%l5] ASI_DMMU
- flush %l6
+ stxa %l0, [%o4] ASI_DMMU
+ flush %o5
rdpr %wstate, %l1
rdpr %otherwin, %l2
@@ -106,30 +106,25 @@ rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
retry
kern_rtt: restore
retry
-to_user: lduw [%g6 + AOFF_task_processor], %o0
- mov 1, %o1
- sethi %hi(need_resched), %l0
+to_user: sethi %hi(need_resched), %l0
ldx [%l0 + %lo(need_resched)], %l0
- sllx %o1, %o0, %o1
wrpr %l7, PSTATE_IE, %pstate
- andcc %o1, %l0, %g0
- be,pt %xcc, check_signal
- ldx [%g6 + AOFF_task_signal], %l0
+ orcc %g0, %l0, %g0
+ be,a,pt %xcc, check_signal
+ lduw [%g6 + AOFF_task_sigpending], %l0
call schedule
nop
- ldx [%g6 + AOFF_task_signal], %l0
- nop
-check_signal: ldx [%g6 + AOFF_task_blocked], %o0
- ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
- andncc %l0, %o0, %g0
- be,pt %xcc, check_user_wins
- ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ lduw [%g6 + AOFF_task_sigpending], %l0
+check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2
+ brz,a,pt %l0, check_user_wins
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ clr %o0
mov %l5, %o2
mov %l6, %o3
call do_signal
add %sp, STACK_BIAS + REGWIN_SZ, %o1
- ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %l6
check_user_wins:brz,pt %o2, 1f
sethi %hi(TSTATE_PEF), %o3
@@ -142,7 +137,7 @@ check_user_wins:brz,pt %o2, 1f
be,a,pt %icc, rt_continue
andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF
ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3
- ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2
wr %g0, FPRS_FEF, %fprs
wr %o3, 0, %gsr
andcc %l2, SPARC_FLAG_USEDFPUL, %g0
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 147c6e55d..932addbb4 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.12 1997/08/28 02:23:19 ecd Exp $
+/* $Id: setup.c,v 1.18 1997/12/18 02:43:00 ecd Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -37,6 +37,10 @@
#include <asm/idprom.h>
#include <asm/head.h>
+#ifdef CONFIG_IP_PNP
+#include <net/ipconfig.h>
+#endif
+
struct screen_info screen_info = {
0, 0, /* orig-x, orig-y */
{ 0, 0, }, /* unused */
@@ -236,20 +240,35 @@ extern int root_mountflags;
char saved_command_line[256];
char reboot_command[256];
-#ifdef CONFIG_ROOT_NFS
-extern char nfs_root_addrs[];
-#endif
-
unsigned long phys_base;
static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
+#if 0
+#include <linux/console.h>
+
+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
+};
+#endif
+
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
+ extern int serial_console; /* in console.c, of course */
unsigned long lowest_paddr;
int total, i;
+#if 0
+ register_console(&prom_console);
+#endif
+
/* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
@@ -330,62 +349,58 @@ __initfunc(void setup_arch(char **cmdline_p,
init_task.mm->context = (unsigned long) NO_CONTEXT;
init_task.tss.kregs = &fake_swapper_regs;
-#ifdef CONFIG_ROOT_NFS
- if (!*nfs_root_addrs) {
+#ifdef CONFIG_IP_PNP
+ if (!ic_set_manually) {
int chosen = prom_finddevice ("/chosen");
u32 cl, sv, gw;
- char *p = nfs_root_addrs;
cl = prom_getintdefault (chosen, "client-ip", 0);
sv = prom_getintdefault (chosen, "server-ip", 0);
gw = prom_getintdefault (chosen, "gateway-ip", 0);
if (cl && sv) {
- strcpy (p, in_ntoa (cl));
- p += strlen (p);
- *p++ = ':';
- strcpy (p, in_ntoa (sv));
- p += strlen (p);
- *p++ = ':';
- if (gw) {
- strcpy (p, in_ntoa (gw));
- p += strlen (p);
- }
- strcpy (p, "::::none");
+ ic_myaddr = cl;
+ ic_servaddr = sv;
+ if (gw)
+ ic_gateway = gw;
+ ic_bootp_flag = ic_rarp_flag = 0;
}
}
#endif
#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's 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();
- }
+ switch (console_fb) {
+ case 0: /* Let's 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: "
+ "input %d, output %d\n",
+ idev, odev);
+ 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
+ break;
+ case 1: /* Force one of the framebuffers as console */
+ serial_console = 0;
+ break;
+ case 2: /* Force ttya as console */
+ serial_console = 1;
+ break;
+ case 3: /* Force ttyb as console */
+ serial_console = 2;
+ break;
}
+ *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
+#else
+ serial_console = 0;
+#endif
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 87241f8e3..94bf90398 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $
+/* $Id: signal.c,v 1.27 1997/12/15 15:04:44 jj Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -26,15 +26,14 @@
#include <asm/fpumacro.h>
#include <asm/uctx.h>
#include <asm/smp_lock.h>
+#include <asm/siginfo.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);
-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... */
@@ -61,8 +60,20 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
if((pc | npc) & 3)
goto do_sigsegv;
if(regs->u_regs[UREG_I1]) {
- __get_user(current->blocked, &ucp->uc_sigmask);
- current->blocked &= _BLOCKABLE;
+ sigset_t set;
+
+ if (_NSIG_WORDS == 1) {
+ if (__get_user(set.sig[0], &ucp->uc_sigmask.sig[0]))
+ goto do_sigsegv;
+ } else {
+ if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t)))
+ goto do_sigsegv;
+ }
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
}
regs->tpc = pc;
regs->tnpc = npc;
@@ -132,7 +143,11 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
- __put_user(current->blocked, &ucp->uc_sigmask);
+ if (_NSIG_WORDS == 1)
+ __put_user(current->blocked.sig[0], (unsigned long *)&ucp->uc_sigmask);
+ else
+ __copy_to_user(&ucp->uc_sigmask, &current->blocked, sizeof(sigset_t));
+
__put_user(regs->tstate, &((*grp)[MC_TSTATE]));
__put_user(regs->tpc, &((*grp)[MC_PC]));
__put_user(regs->tnpc, &((*grp)[MC_NPC]));
@@ -198,31 +213,45 @@ struct new_signal_frame {
__siginfo_t info;
__siginfo_fpu_t * fpu_save;
unsigned int insns [2];
+ unsigned long extramask[_NSIG_WORDS-1];
+ __siginfo_fpu_t fpu_state;
+};
+
+struct rt_signal_frame {
+ struct sparc_stackf ss;
+ siginfo_t info;
+ struct pt_regs regs;
+ sigset_t mask;
+ __siginfo_fpu_t * fpu_save;
+ unsigned int insns [2];
__siginfo_fpu_t fpu_state;
};
/* Align macros */
#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
+#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
/*
* 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;
#ifdef CONFIG_SPARC32_COMPAT
if (current->tss.flags & SPARC_FLAG_32BIT) {
- extern asmlinkage void _sigpause32_common(unsigned int,
+ extern asmlinkage void _sigpause32_common(old_sigset_t32,
struct pt_regs *);
_sigpause32_common(set, regs);
return;
}
#endif
+ 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->tpc = regs->tnpc;
@@ -242,7 +271,7 @@ asmlinkage void _sigpause_common(unsigned int set, struct pt_regs *regs)
*/
regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
regs->u_regs[UREG_I0] = EINTR;
- if (do_signal(mask, regs, 0, 0))
+ if (do_signal(&saveset, regs, 0, 0))
return;
}
}
@@ -257,6 +286,50 @@ 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->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ regs->u_regs[UREG_I0] = EINVAL;
+ return;
+ }
+ if (copy_from_user(&set, uset, sizeof(set))) {
+ regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ 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->tpc = regs->tnpc;
+ regs->tnpc += 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->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
+ 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)
@@ -282,47 +355,100 @@ void do_sigreturn(struct pt_regs *regs)
struct new_signal_frame *sf;
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t *fpu_save;
- unsigned long mask;
+ sigset_t set;
-#ifdef CONFIG_SPARC32_COMPAT
- if (current->tss.flags & SPARC_FLAG_32BIT) {
- extern asmlinkage void do_sigreturn32(struct pt_regs *);
- return do_sigreturn32(regs);
- }
-#endif
synchronize_user_stack ();
sf = (struct new_signal_frame *)
(regs->u_regs [UREG_FP] + STACK_BIAS);
/* 1. Make sure we are not getting garbage from the user */
- if (verify_area (VERIFY_READ, sf, sizeof (*sf)))
+ if (((unsigned long) sf) & 3)
goto segv;
+ if (get_user(tpc, &sf->info.si_regs.tpc) ||
+ __get_user(tnpc, &sf->info.si_regs.tnpc) ||
+ ((tpc | tnpc) & 3))
+ goto segv;
+
+ regs->tpc = tpc;
+ regs->tnpc = tnpc;
+
+ /* 2. Restore the state */
+ if (__get_user(regs->y, &sf->info.si_regs.y) ||
+ __get_user(tstate, &sf->info.si_regs.tstate) ||
+ copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs)))
+ goto segv;
+
+ /* User can only change condition codes in %tstate. */
+ regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate |= (tstate & TSTATE_ICC);
+
+ if (__get_user(fpu_save, &sf->fpu_save))
+ goto segv;
+ if (fpu_save)
+ restore_fpu_state(regs, &sf->fpu_state);
+ if (__get_user(set.sig[0], &sf->info.si_mask) ||
+ (_NSIG_WORDS > 1 &&
+ __copy_from_user(&set.sig[1], &sf->extramask,
+ sizeof(sf->extramask))))
+ goto segv;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ return;
+segv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+void do_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_signal_frame *sf;
+ unsigned long tpc, tnpc, tstate;
+ __siginfo_fpu_t *fpu_save;
+ sigset_t set;
+
+ synchronize_user_stack ();
+ sf = (struct rt_signal_frame *)
+ (regs->u_regs [UREG_FP] + STACK_BIAS);
+
+ /* 1. Make sure we are not getting garbage from the user */
if (((unsigned long) sf) & 3)
goto segv;
- get_user(tpc, &sf->info.si_regs.tpc);
- __get_user(tnpc, &sf->info.si_regs.tnpc);
- if ((tpc | tnpc) & 3)
+ if (get_user(tpc, &sf->regs.tpc) ||
+ __get_user(tnpc, &sf->regs.tnpc) ||
+ ((tpc | tnpc) & 3))
goto segv;
regs->tpc = tpc;
regs->tnpc = tnpc;
/* 2. Restore the state */
- __get_user(regs->y, &sf->info.si_regs.y);
- __get_user(tstate, &sf->info.si_regs.tstate);
- copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
+ if (__get_user(regs->y, &sf->regs.y) ||
+ __get_user(tstate, &sf->regs.tstate) ||
+ copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs)))
+ goto segv;
/* User can only change condition codes in %tstate. */
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= (tstate & TSTATE_ICC);
- __get_user(fpu_save, &sf->fpu_save);
+ if (__get_user(fpu_save, &sf->fpu_save))
+ goto segv;
if (fpu_save)
restore_fpu_state(regs, &sf->fpu_state);
- __get_user(mask, &sf->info.si_mask);
- current->blocked = mask & _BLOCKABLE;
+
+ if (__copy_from_user(&set, &sf->mask, sizeof(sigset_t)))
+ goto segv;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
return;
segv:
lock_kernel();
@@ -364,8 +490,8 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
}
static inline void
-new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
- int signo, unsigned long oldmask)
+new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
struct new_signal_frame *sf;
int sigframe_size;
@@ -398,33 +524,122 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
__put_user(0, &sf->fpu_save);
}
- __put_user(oldmask, &sf->info.si_mask);
+ __put_user(oldset->sig[0], &sf->info.si_mask);
+ if (_NSIG_WORDS > 1)
+ __copy_to_user(sf->extramask, &oldset->sig[1], sizeof(sf->extramask));
copy_in_user((u64 *)sf,
(u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
sizeof(struct reg_window));
- /* 3. return to kernel instructions */
- __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
- __put_user(0x91d02011, &sf->insns[1]); /* t 0x11 */
+ /* 3. signal handler back-trampoline and parameters */
+ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
+ regs->u_regs[UREG_I0] = signo;
+ regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+
+ /* 5. signal handler */
+ regs->tpc = (unsigned long) ka->sa.sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+
+ /* 4. return to kernel instructions */
+ if (ka->ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ else {
+ /* Flush instruction space. */
+ unsigned long address = ((unsigned long)&(sf->insns[0]));
+ pgd_t *pgdp = pgd_offset(current->mm, address);
+ pmd_t *pmdp = pmd_offset(pgdp, address);
+ pte_t *ptep = pte_offset(pmdp, address);
+
+ regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */
+
+ if(pte_present(*ptep)) {
+ unsigned long page = pte_page(*ptep);
+
+ __asm__ __volatile__("
+ membar #StoreStore
+ flush %0 + %1"
+ : : "r" (page), "r" (address & (PAGE_SIZE - 1))
+ : "memory");
+ }
+ }
+ return;
+
+sigill:
+ lock_kernel();
+ do_exit(SIGILL);
+}
+
+static inline void
+setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset, siginfo_t *info)
+{
+ struct rt_signal_frame *sf;
+ int sigframe_size;
+
+ /* 1. Make sure everything is clean */
+ synchronize_user_stack();
+ sigframe_size = RT_ALIGNEDSZ;
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
+ sigframe_size -= sizeof(__siginfo_fpu_t);
- /* 4. signal handler back-trampoline and parameters */
+ sf = (struct rt_signal_frame *)
+ (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size);
+
+ if (invalid_frame_pointer (sf, sigframe_size))
+ goto sigill;
+
+ if (current->tss.w_saved != 0) {
+ printk ("%s[%d]: Invalid user stack frame for "
+ "signal delivery.\n", current->comm, current->pid);
+ goto sigill;
+ }
+
+ /* 2. Save the current process state */
+ copy_to_user(&sf->regs, regs, sizeof (*regs));
+
+ if (current->tss.flags & SPARC_FLAG_USEDFPU) {
+ save_fpu_state(regs, &sf->fpu_state);
+ __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ } else {
+ __put_user(0, &sf->fpu_save);
+ }
+
+ copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
+
+ copy_in_user((u64 *)sf,
+ (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
+ sizeof(struct reg_window));
+
+ copy_to_user(&sf->info, info, sizeof(siginfo_t));
+
+ /* 3. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
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->tpc = (unsigned long) sa->sa_handler;
+ regs->tpc = (unsigned long) ka->sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
- /* Flush instruction space. */
- {
+ /* 4. return to kernel instructions */
+ if (ka->ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ else {
+ /* Flush instruction space. */
unsigned long address = ((unsigned long)&(sf->insns[0]));
pgd_t *pgdp = pgd_offset(current->mm, address);
pmd_t *pmdp = pmd_offset(pgdp, address);
pte_t *ptep = pte_offset(pmdp, address);
+ regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+ __put_user(0x82102065, &sf->insns[0]); /* mov __NR_rt_sigreturn, %g1 */
+ __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */
+
if(pte_present(*ptep)) {
unsigned long page = pte_page(*ptep);
@@ -442,15 +657,21 @@ sigill:
do_exit(SIGILL);
}
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs *regs)
+static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
+ siginfo_t *info,
+ sigset_t *oldset, struct pt_regs *regs)
{
- new_setup_frame(sa, regs, signr, oldmask);
- if(sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if(!(sa->sa_flags & SA_NOMASK)) {
+ if(ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(ka, regs, signr, oldset, info);
+ else
+ new_setup_frame(ka, regs, signr, oldset);
+ 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);
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
}
}
@@ -479,28 +700,30 @@ 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,
- unsigned long orig_i0, int restart_syscall)
+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;
+ siginfo_t info;
+ struct k_sigaction *ka;
+
+ if (!oldset)
+ oldset = &current->blocked;
#ifdef CONFIG_SPARC32_COMPAT
if (current->tss.flags & SPARC_FLAG_32BIT) {
- extern asmlinkage int do_signal32(unsigned long, struct pt_regs *,
+ extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *,
unsigned long, int);
- return do_signal32(oldmask, regs, orig_i0, restart_syscall);
+ return do_signal32(oldset, regs, orig_i0, restart_syscall);
}
#endif
- while ((signr = current->signal & mask) != 0) {
- signr = ffz(~signr);
-
+ for (;;) {
spin_lock_irq(&current->sigmask_lock);
- current->signal &= ~(1 << signr);
+ signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr) break;
- sa = current->sig->action + signr;
- signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
@@ -511,15 +734,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;
@@ -532,7 +766,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) {
@@ -548,7 +784,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- 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();
@@ -559,7 +795,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
@@ -569,20 +805,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);
-
- current->flags |= PF_SIGNALED;
-
lock_kernel();
- do_exit(signr);
- unlock_kernel();
+ sigaddset(&current->signal, signr);
+ current->flags |= PF_SIGNALED;
+ do_exit(exit_code);
+ /* NOT REACHED */
}
}
if(restart_syscall)
- syscall_restart(orig_i0, regs, sa);
- handle_signal(signr, sa, oldmask, regs);
+ syscall_restart(orig_i0, regs, &ka->sa);
+ handle_signal(signr, ka, &info, oldset, regs);
return 1;
}
if(restart_syscall &&
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 16cec2a72..8ca15c80b 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.30 1997/08/29 15:51:33 jj Exp $
+/* $Id: signal32.c,v 1.34 1997/12/15 15:04:49 jj Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -26,14 +26,12 @@
#include <asm/fpumacro.h>
#include <asm/smp_lock.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);
-asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
+asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs,
unsigned long orig_o0, int ret_from_syscall);
/* This turned off for production... */
@@ -60,6 +58,7 @@ struct signal_sframe32 {
/* struct sigcontext32 * */ u32 sig_scptr;
int sig_address;
struct sigcontext32 sig_context;
+ unsigned extramask[_NSIG_WORDS32 - 1];
};
/*
@@ -72,24 +71,89 @@ struct new_signal_frame32 {
__siginfo32_t info;
/* __siginfo_fpu32_t * */ u32 fpu_save;
unsigned int insns [2];
+ unsigned extramask[_NSIG_WORDS32 - 1];
+ __siginfo_fpu_t fpu_state;
+};
+
+struct rt_signal_frame32 {
+ struct sparc_stackf32 ss;
+ siginfo_t32 info;
+ struct pt_regs32 regs;
+ sigset_t32 mask;
+ /* __siginfo_fpu32_t * */ u32 fpu_save;
+ unsigned int insns [2];
__siginfo_fpu_t fpu_state;
};
/* Align macros */
#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe32) + 7) & (~7)))
#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7)))
+#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7)))
/*
* atomically swap in the new signal mask, and wait for a signal.
* This is really tricky on the Sparc, watch out...
*/
-asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
+asmlinkage void _sigpause32_common(old_sigset_t32 set, struct pt_regs *regs)
{
- unsigned int mask;
+ sigset_t saveset;
+
+ set &= _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ siginitset(&current->blocked, set);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 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->tstate |= TSTATE_ICARRY;
+ regs->u_regs[UREG_I0] = EINTR;
+ if (do_signal32(&saveset, regs, 0, 0))
+ return;
+ }
+}
+asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *regs)
+{
+ sigset_t oldset, set;
+ sigset_t32 set32;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (((__kernel_size_t32)sigsetsize) != sizeof(sigset_t)) {
+ regs->tstate |= TSTATE_ICARRY;
+ regs->u_regs[UREG_I0] = EINVAL;
+ return;
+ }
+ if (copy_from_user(&set32, (void *)(long)uset, sizeof(set32))) {
+ regs->tstate |= TSTATE_ICARRY;
+ regs->u_regs[UREG_I0] = EFAULT;
+ return;
+ }
+ switch (_NSIG_WORDS) {
+ case 4: set.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32);
+ case 3: set.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32);
+ case 2: set.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32);
+ case 1: set.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32);
+ }
+ sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
- mask = current->blocked;
- current->blocked = set & _BLOCKABLE;
+ oldset = current->blocked;
+ current->blocked = set;
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
regs->tpc = regs->tnpc;
@@ -109,7 +173,7 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs)
*/
regs->tstate |= TSTATE_ICARRY;
regs->u_regs[UREG_I0] = EINTR;
- if (do_signal32(mask, regs, 0, 0))
+ if (do_signal32(&oldset, regs, 0, 0))
return;
}
}
@@ -134,7 +198,9 @@ void do_new_sigreturn32(struct pt_regs *regs)
{
struct new_signal_frame32 *sf;
unsigned int psr;
- unsigned pc, npc, fpu_save, mask;
+ unsigned pc, npc, fpu_save;
+ sigset_t set;
+ unsigned seta[_NSIG_WORDS32];
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
@@ -177,16 +243,23 @@ void do_new_sigreturn32(struct pt_regs *regs)
regs->tstate &= ~(TSTATE_ICC);
regs->tstate |= psr_to_tstate_icc(psr);
-#if 0
- if (psr & PSR_EF)
- regs->tstate |= TSTATE_PEF;
-#endif
-
__get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
restore_fpu_state32(regs, &sf->fpu_state);
- __get_user(mask, &sf->info.si_mask);
- current->blocked = mask & _BLOCKABLE;
+ if (__get_user(seta[0], &sf->info.si_mask) ||
+ copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned)))
+ goto segv;
+ switch (_NSIG_WORDS) {
+ case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
+ case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);
+ case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
+ case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
+ }
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
return;
segv:
lock_kernel();
@@ -197,7 +270,8 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
{
struct sigcontext32 *scptr;
unsigned pc, npc, psr;
- unsigned long mask;
+ sigset_t set;
+ unsigned seta[_NSIG_WORDS32];
synchronize_user_stack();
if (current->tss.new_signal)
@@ -216,8 +290,22 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
if((pc | npc) & 3)
goto segv; /* Nice try. */
- __get_user(mask, &scptr->sigc_mask);
- current->blocked = (mask & _BLOCKABLE);
+ if (__get_user(seta[0], &scptr->sigc_mask) ||
+ /* Note that scptr + 1 points to extramask */
+ copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)))
+ goto segv;
+ switch (_NSIG_WORDS) {
+ case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
+ case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);
+ case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
+ case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
+ }
+ 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;
regs->tpc = pc;
@@ -236,6 +324,78 @@ segv:
do_exit (SIGSEGV);
}
+asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
+{
+ struct rt_signal_frame32 *sf;
+ unsigned int psr;
+ unsigned pc, npc, fpu_save;
+ sigset_t set;
+ sigset_t32 seta;
+
+ synchronize_user_stack();
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
+ sf = (struct rt_signal_frame32 *) regs->u_regs [UREG_FP];
+
+ /* 1. Make sure we are not getting garbage from the user */
+ if (verify_area (VERIFY_READ, sf, sizeof (*sf)) ||
+ (((unsigned long) sf) & 3))
+ goto segv;
+
+ get_user(pc, &sf->regs.pc);
+ __get_user(npc, &sf->regs.npc);
+
+ if ((pc | npc) & 3)
+ goto segv;
+
+ regs->tpc = pc;
+ regs->tnpc = npc;
+
+ /* 2. Restore the state */
+ __get_user(regs->y, &sf->regs.y);
+ __get_user(psr, &sf->regs.psr);
+
+ __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
+ __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
+ __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
+ __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
+ __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
+ __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
+ __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
+ __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
+ __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
+ __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
+ __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
+ __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
+ __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
+ __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
+ __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
+
+ /* User can only change condition codes in %tstate. */
+ regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate |= psr_to_tstate_icc(psr);
+
+ __get_user(fpu_save, &sf->fpu_save);
+ if (fpu_save)
+ restore_fpu_state32(regs, &sf->fpu_state);
+ if (copy_from_user(&seta, &sf->mask, sizeof(sigset_t32)))
+ goto segv;
+ switch (_NSIG_WORDS) {
+ case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
+ case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
+ case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32);
+ case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
+ }
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ return;
+segv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
/* Checks if the fp is valid */
static int invalid_frame_pointer(void *fp, int fplen)
{
@@ -246,10 +406,12 @@ static int invalid_frame_pointer(void *fp, int fplen)
static void
setup_frame32(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)
{
struct signal_sframe32 *sframep;
struct sigcontext32 *sc;
+ unsigned seta[_NSIG_WORDS32];
+
#if 0
int window = 0;
#endif
@@ -278,7 +440,19 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
/* 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);
+
+ switch (_NSIG_WORDS) {
+ case 4: seta[7] = (oldset->sig[3] >> 32);
+ seta[6] = oldset->sig[3];
+ case 3: seta[5] = (oldset->sig[2] >> 32);
+ seta[4] = oldset->sig[2];
+ case 2: seta[3] = (oldset->sig[1] >> 32);
+ seta[2] = oldset->sig[1];
+ case 1: seta[1] = (oldset->sig[0] >> 32);
+ seta[0] = oldset->sig[0];
+ }
+ __put_user(seta[0], &sc->sigc_mask);
+ __copy_to_user(sframep->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned));
__put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
__put_user(pc, &sc->sigc_pc);
__put_user(npc, &sc->sigc_npc);
@@ -346,13 +520,14 @@ static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
regs->tstate &= ~TSTATE_PEF;
}
-static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
- int signo, unsigned long oldmask)
+static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+ int signo, sigset_t *oldset)
{
struct new_signal_frame32 *sf;
int sigframe_size;
u32 psr;
int i;
+ unsigned seta[_NSIG_WORDS32];
/* 1. Make sure everything is clean */
synchronize_user_stack();
@@ -397,33 +572,47 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs,
__put_user(0, &sf->fpu_save);
}
- __put_user(oldmask, &sf->info.si_mask);
+ switch (_NSIG_WORDS) {
+ case 4: seta[7] = (oldset->sig[3] >> 32);
+ seta[6] = oldset->sig[3];
+ case 3: seta[5] = (oldset->sig[2] >> 32);
+ seta[4] = oldset->sig[2];
+ case 2: seta[3] = (oldset->sig[1] >> 32);
+ seta[2] = oldset->sig[1];
+ case 1: seta[1] = (oldset->sig[0] >> 32);
+ seta[0] = oldset->sig[0];
+ }
+ __put_user(seta[0], &sf->info.si_mask);
+ __copy_to_user(sf->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned));
copy_in_user((u32 *)sf,
(u32 *)(regs->u_regs[UREG_FP]),
sizeof(struct reg_window32));
- /* 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->tpc = (unsigned long) sa->sa_handler;
+ /* 4. signal handler */
+ regs->tpc = (unsigned long) ka->sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
- /* Flush instruction space. */
- {
+ /* 5. return to kernel instructions */
+ if (ka->ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ else {
+ /* Flush instruction space. */
unsigned long address = ((unsigned long)&(sf->insns[0]));
pgd_t *pgdp = pgd_offset(current->mm, address);
pmd_t *pmdp = pmd_offset(pgdp, address);
pte_t *ptep = pte_offset(pmdp, address);
+ 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 */
+
if(pte_present(*ptep)) {
unsigned long page = pte_page(*ptep);
@@ -444,7 +633,7 @@ sigill:
/* Setup a Solaris stack frame */
static inline void
setup_svr4_frame32(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;
@@ -452,6 +641,7 @@ setup_svr4_frame32(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;
#if 0
int window = 0;
#endif
@@ -485,8 +675,15 @@ setup_svr4_frame32(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[0] >> 32);
+ if (_NSIG_WORDS >= 2) {
+ setv.sigbits[2] = oldset->sig[1];
+ setv.sigbits[3] = (oldset->sig[1] >> 32);
+ __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ } else
+ __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
+
/* Store registers */
__put_user(regs->tpc, &((*gr) [SVR4_PC]));
__put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
@@ -572,11 +769,12 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
{
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
+ svr4_sigset_t setv;
int i;
synchronize_user_stack();
if (current->tss.w_saved){
- printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+ printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
lock_kernel();
do_exit (SIGSEGV);
}
@@ -586,9 +784,15 @@ 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[0] >> 32);
+ if (_NSIG_WORDS >= 2) {
+ setv.sigbits[2] = current->blocked.sig[1];
+ setv.sigbits[3] = (current->blocked.sig[1] >> 32);
+ __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+ } else
+ __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
/* Store registers */
__put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
@@ -622,6 +826,8 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
struct thread_struct *tp = &current->tss;
svr4_gregset_t *gr;
u32 pc, npc, psr;
+ sigset_t set;
+ svr4_sigset_t setv;
int i;
/* Fixme: restore windows, or is this already taken care of in
@@ -630,7 +836,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
flush_user_windows();
if (tp->w_saved){
- printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved);
+ printk ("Uh oh, w_saved is: 0x%x\n", tp->w_saved);
goto sigsegv;
}
if (((unsigned long) c) & 3){
@@ -654,8 +860,16 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
/* Retrieve information from passed ucontext */
/* note that nPC is ored a 1, this is used to inform entry.S */
/* that we don't want it to mess with our PC and nPC */
- __get_user(current->blocked, &c->sigmask.sigbits [0]);
- current->blocked &= _BLOCKABLE;
+ if (copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t)))
+ goto sigsegv;
+ set.sig[0] = setv.sigbits[0] | (((long)setv.sigbits[1]) << 32);
+ if (_NSIG_WORDS >= 2)
+ set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32);
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
regs->tpc = pc;
regs->tnpc = npc | 1;
__get_user(regs->y, &((*gr) [SVR4_Y]));
@@ -678,23 +892,137 @@ sigsegv:
do_exit(SIGSEGV);
}
-static inline void handle_signal32(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs *regs,
+static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+ unsigned long signr, sigset_t *oldset,
+ siginfo_t *info)
+{
+ struct rt_signal_frame32 *sf;
+ int sigframe_size;
+ u32 psr;
+ int i;
+ sigset_t32 seta;
+
+ /* 1. Make sure everything is clean */
+ synchronize_user_stack();
+ sigframe_size = RT_ALIGNEDSZ;
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
+ sigframe_size -= sizeof(__siginfo_fpu_t);
+
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
+ sf = (struct rt_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
+
+ if (invalid_frame_pointer (sf, sigframe_size)) {
+#ifdef DEBUG_SIGNALS
+ printk("rt_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n",
+ current->comm, current->pid, sf, sigframe_size);
+#endif
+ goto sigill;
+ }
+
+ if (current->tss.w_saved != 0) {
+#ifdef DEBUG_SIGNALS
+ printk ("%s[%d]: Invalid user stack frame for "
+ "signal delivery.\n", current->comm, current->pid);
+#endif
+ goto sigill;
+ }
+
+ /* 2. Save the current process state */
+ put_user(regs->tpc, &sf->regs.pc);
+ __put_user(regs->tnpc, &sf->regs.npc);
+ __put_user(regs->y, &sf->regs.y);
+ psr = tstate_to_psr (regs->tstate);
+ if(current->tss.flags & SPARC_FLAG_USEDFPU)
+ psr |= PSR_EF;
+ __put_user(psr, &sf->regs.psr);
+ for (i = 0; i < 16; i++)
+ __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+
+ if (psr & PSR_EF) {
+ save_fpu_state32(regs, &sf->fpu_state);
+ __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ } else {
+ __put_user(0, &sf->fpu_save);
+ }
+
+ switch (_NSIG_WORDS) {
+ case 4: seta.sig[7] = (oldset->sig[3] >> 32);
+ seta.sig[6] = oldset->sig[3];
+ case 3: seta.sig[5] = (oldset->sig[2] >> 32);
+ seta.sig[4] = oldset->sig[2];
+ case 2: seta.sig[3] = (oldset->sig[1] >> 32);
+ seta.sig[2] = oldset->sig[1];
+ case 1: seta.sig[1] = (oldset->sig[0] >> 32);
+ seta.sig[0] = oldset->sig[0];
+ }
+ __copy_to_user(&sf->mask, &seta, sizeof(sigset_t));
+
+ copy_in_user((u32 *)sf,
+ (u32 *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+
+ /* 3. signal handler back-trampoline and parameters */
+ regs->u_regs[UREG_FP] = (unsigned long) sf;
+ regs->u_regs[UREG_I0] = signr;
+ regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+
+ /* 4. signal handler */
+ regs->tpc = (unsigned long) ka->sa.sa_handler;
+ regs->tnpc = (regs->tpc + 4);
+
+ /* 5. return to kernel instructions */
+ if (ka->ka_restorer)
+ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
+ else {
+ /* Flush instruction space. */
+ unsigned long address = ((unsigned long)&(sf->insns[0]));
+ pgd_t *pgdp = pgd_offset(current->mm, address);
+ pmd_t *pmdp = pmd_offset(pgdp, address);
+ pte_t *ptep = pte_offset(pmdp, address);
+
+ 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 */
+
+ if(pte_present(*ptep)) {
+ unsigned long page = pte_page(*ptep);
+
+ __asm__ __volatile__("
+ membar #StoreStore
+ flush %0 + %1"
+ : : "r" (page), "r" (address & (PAGE_SIZE - 1))
+ : "memory");
+ }
+ }
+ return;
+
+sigill:
+ lock_kernel();
+ do_exit(SIGILL);
+}
+
+static inline void handle_signal32(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_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask);
+ setup_svr4_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset);
else {
- if (current->tss.new_signal)
- new_setup_frame32(sa, regs, signr, oldmask);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame32(ka, regs, signr, oldset, info);
+ else if (current->tss.new_signal)
+ new_setup_frame32(ka, regs, signr, oldset);
else
- setup_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask);
+ setup_frame32(&ka->sa, regs->tpc, regs->tnpc, 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);
}
}
@@ -723,22 +1051,22 @@ static inline void syscall_restart32(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_signal32(unsigned long oldmask, struct pt_regs * regs,
+asmlinkage int do_signal32(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);
-
+ for (;;) {
spin_lock_irq(&current->sigmask_lock);
- current->signal &= ~(1 << signr);
+ signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr) break;
- sa = current->sig->action + signr;
- signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
@@ -749,15 +1077,26 @@ asmlinkage int do_signal32(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;
@@ -770,7 +1109,9 @@ asmlinkage int do_signal32(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) {
@@ -786,7 +1127,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- 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();
@@ -797,7 +1138,7 @@ asmlinkage int do_signal32(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
@@ -807,20 +1148,16 @@ asmlinkage int do_signal32(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);
-
- current->flags |= PF_SIGNALED;
-
lock_kernel();
- do_exit(signr);
- unlock_kernel();
+ sigaddset(&current->signal, signr);
+ current->flags |= PF_SIGNALED;
+ do_exit(exit_code);
+ /* NOT REACHED */
}
}
if(restart_syscall)
- syscall_restart32(orig_i0, regs, sa);
- handle_signal32(signr, sa, oldmask, regs, svr4_signal);
+ syscall_restart32(orig_i0, regs, &ka->sa);
+ handle_signal32(signr, ka, &info, oldset, regs, svr4_signal);
return 1;
}
if(restart_syscall &&
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 8dd471be6..932534c05 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -3,6 +3,7 @@
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tasks.h>
@@ -23,6 +24,7 @@
#include <asm/spinlock.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#include <asm/uaccess.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -346,7 +348,7 @@ static void smp_cross_call_avoidance(struct mm_struct *mm)
spin_lock(&scheduler_lock);
get_new_mmu_context(mm, &tlb_context_cache);
mm->cpu_vm_mask = (1UL << smp_processor_id());
- if(current->tss.current_ds) {
+ if(segment_eq(current->tss.current_ds,USER_DS)) {
u32 ctx = mm->context & 0x1fff;
current->tss.ctx = ctx;
@@ -473,6 +475,7 @@ void smp_penguin_jailcell(void)
static inline void sparc64_do_profile(unsigned long pc)
{
+#ifdef CONFIG_PROFILE
if(prof_buffer && current->pid) {
extern int _stext;
@@ -483,6 +486,7 @@ static inline void sparc64_do_profile(unsigned long pc)
pc = prof_len - 1;
atomic_inc((atomic_t *)&prof_buffer[pc]);
}
+#endif
}
static unsigned long real_tick_offset, current_tick_offset;
@@ -510,7 +514,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
update_one_process(current, 1, user, !user);
if(--current->counter < 0) {
current->counter = 0;
- resched_force();
+ need_resched = 1;
}
if(user) {
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index c1ceacc3f..b776ea06e 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,10 +1,12 @@
-/* $Id: sparc64_ksyms.c,v 1.21 1997/09/03 12:29:07 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.27 1997/11/19 07:57:46 jj Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 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>
@@ -12,6 +14,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/in6.h>
+#include <linux/pci.h>
#include <asm/oplib.h>
#include <asm/delay.h>
@@ -30,10 +33,14 @@
#include <asm/user.h>
#include <asm/uaccess.h>
#include <asm/checksum.h>
+#include <asm/fpumacro.h>
#ifdef CONFIG_SBUS
#include <asm/sbus.h>
#include <asm/dma.h>
#endif
+#ifdef CONFIG_PCI
+#include <asm/ebus.h>
+#endif
#include <asm/a.out.h>
#include <asm/svr4.h>
@@ -43,6 +50,7 @@ struct poll {
short revents;
};
+extern void die_if_kernel(char *str, struct pt_regs *regs);
extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
@@ -68,6 +76,7 @@ extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
+extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
@@ -123,6 +132,10 @@ EXPORT_SYMBOL(mmu_release_scsi_sgl);
EXPORT_SYMBOL(SBus_chain);
EXPORT_SYMBOL(dma_chain);
#endif
+#if CONFIG_PCI
+EXPORT_SYMBOL(ebus_chain);
+EXPORT_SYMBOL(pci_devices);
+#endif
/* Solaris/SunOS binary compatibility */
EXPORT_SYMBOL(_sigpause_common);
@@ -131,6 +144,9 @@ EXPORT_SYMBOL(sunos_mmap);
/* Should really be in linux/kernel/ksyms.c */
EXPORT_SYMBOL(dump_thread);
+/* math-emu wants this */
+EXPORT_SYMBOL(die_if_kernel);
+
/* prom symbols */
EXPORT_SYMBOL(idprom);
EXPORT_SYMBOL(prom_root_node);
@@ -190,6 +206,10 @@ EXPORT_SYMBOL(sys_ioctl);
EXPORT_SYMBOL(sys32_ioctl);
#endif
+#ifdef CONFIG_MATHEMU_MODULE
+EXPORT_SYMBOL(handle_mathemu);
+#endif
+
/* Special internal versions of library functions. */
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c
index bb991dee6..d94a7c6d6 100644
--- a/arch/sparc64/kernel/sunos_ioctl32.c
+++ b/arch/sparc64/kernel/sunos_ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl32.c,v 1.4 1997/07/17 02:20:43 davem Exp $
+/* $Id: sunos_ioctl32.c,v 1.5 1997/09/18 10:37:57 rth Exp $
* sunos_ioctl32.c: SunOS ioctl compatability on sparc64.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -100,7 +100,7 @@ asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
goto out;
if(cmd == TIOCSETD) {
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
int *p, ntty = N_TTY;
int tmp;
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index 37c541755..6fb6f739b 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.3 1997/08/22 20:11:47 davem Exp $
+/* $Id: sys32.S,v 1.4 1997/09/09 17:13:29 jj Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -8,8 +8,7 @@
.text
.align 32
- .globl sys32_mmap, sys32_mprotect, sys32_munmap, sys32_msync
- .globl sys32_mlock, sys32_munlock, sys32_mremap, sparc32_brk
+ .globl sys32_mmap
sys32_mmap:
srl %o0, 0, %o0 ! IEU0 Group
sethi %hi(0xffffffff), %g2 ! IEU1
@@ -22,153 +21,15 @@ sys32_mmap:
and %o5, %g2, %o5 ! IEU0 Group
call sys_mmap ! CTI Group brk forced
mov %g1, %o7 ! IEU0 Group (regdep)
-sys32_mprotect:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- srl %o2, 0, %o2
- call sys_mprotect
- mov %g1, %o7
-sys32_munmap:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_munmap
- mov %g1, %o7
-sparc32_brk:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_brk
- mov %g1, %o7
-sys32_msync:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_msync
- mov %g1, %o7
-sys32_mlock:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_mlock
- mov %g1, %o7
-sys32_munlock:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_munlock
- mov %g1, %o7
-sys32_mremap:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- srl %o2, 0, %o2
- srl %o3, 0, %o3
- call sys_mremap
- mov %g1, %o7
.align 32
- .globl sys32_read, sys32_write, sys32_open, sys32_access
- .globl sys32_chdir, sys32_lseek, sys32_llseek, sys32_poll
- .globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink
- .globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate
- .globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat
- .globl sys32_mkdir, sys32_mknod, sys32_ustat
-sys32_read:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_read
- mov %g1, %o7
-sys32_write:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_write
- mov %g1, %o7
-sys32_open:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_open
- mov %g1, %o7
-sys32_access:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_access
- mov %g1, %o7
-sys32_chdir:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_chdir
- mov %g1, %o7
+ .globl sys32_lseek
+ .globl sys32_chmod, sys32_chown, sys32_mknod
sys32_lseek:
sra %o1, 0, %o1
mov %o7, %g1
call sys_lseek
mov %g1, %o7
-sys32_llseek:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- srl %o3, 0, %o3
- call sys_llseek
- mov %g1, %o7
-sys32_poll:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_poll
- mov %g1, %o7
-sys32_readlink:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_readlink
- mov %g1, %o7
-sys32_unlink:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_unlink
- mov %g1, %o7
-sys32_rmdir:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_rmdir
- mov %g1, %o7
-sys32_symlink:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_symlink
- mov %g1, %o7
-sys32_link:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_link
- mov %g1, %o7
-sys32_rename:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_rename
- mov %g1, %o7
- nop
-sys32_truncate:
- srl %o0, 0, %o0
- mov %o7, %g1
- srl %o1, 0, %o1
- call sys_truncate
- mov %g1, %o7
-sys32_ftruncate:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_ftruncate
- mov %g1, %o7
-sys32_chroot:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_chroot
- mov %g1, %o7
sys32_chmod:
sll %o1, 16, %o1
mov %o7, %g1
@@ -185,16 +46,6 @@ sys32_chown:
srl %o2, 16, %o2
call sys_chown
mov %g1, %o7
-sys32_creat:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_creat
- mov %g1, %o7
-sys32_mkdir:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_mkdir
- mov %g1, %o7
sys32_mknod:
sll %o2, 16, %o2
mov %o7, %g1
@@ -202,50 +53,9 @@ sys32_mknod:
srl %o2, 16, %o2
call sys_mknod
mov %g1, %o7
-sys32_ustat:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_ustat
- mov %g1, %o7
.align 32
- .globl sys32_bind, sys32_accept, sys32_connect, sys32_getsockname
- .globl sys32_getpeername, sys32_send, sys32_sendto, sys32_recv
- .globl sys32_recvfrom, sys32_setsockopt, sys32_getsockopt
-sys32_bind:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_bind
- mov %g1, %o7
-sys32_accept:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_accept
- mov %g1, %o7
-sys32_connect:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_connect
- mov %g1, %o7
-sys32_getsockname:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_getsockname
- mov %g1, %o7
-sys32_getpeername:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_getpeername
- mov %g1, %o7
-sys32_send:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_send
- mov %g1, %o7
+ .globl sys32_sendto, sys32_recvfrom, sys32_getsockopt
sys32_sendto:
srl %o1, 0, %o1
mov %o7, %g1
@@ -253,12 +63,6 @@ sys32_sendto:
srl %o4, 0, %o4
call sys_sendto
mov %g1, %o7
-sys32_recv:
- srl %o1, 0, %o1
- mov %o7, %g1
- srl %o2, 0, %o2
- call sys_recv
- mov %g1, %o7
sys32_recvfrom:
srl %o1, 0, %o1
mov %o7, %g1
@@ -267,11 +71,6 @@ sys32_recvfrom:
srl %o5, 0, %o5
call sys_recvfrom
mov %g1, %o7
-sys32_setsockopt:
- srl %o3, 0, %o3
- mov %o7, %g1
- call sys_setsockopt
- mov %g1, %o7
sys32_getsockopt:
srl %o3, 0, %o3
mov %o7, %g1
@@ -279,111 +78,9 @@ sys32_getsockopt:
call sys_setsockopt
mov %g1, %o7
- .globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog
- .globl sys32_personality, sys32_waitpid
- .globl sys32_sched_setscheduler
- .globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal
- .globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname
- .globl sys32_sethostname, sys32_gethostname, sys32_setdomainname
- .globl sys32_time, sys32_swapoff, sys32_swapon
- .globl sys32_create_module, sys32_init_module, sys32_delete_module
+ .globl sys32_bdflush
sys32_bdflush:
sra %o1, 0, %o1
mov %o7, %g1
call sys_bdflush
mov %g1, %o7
-sys32_uselib:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_uselib
- mov %g1, %o7
-sys32_umount:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_umount
- mov %g1, %o7
-sys32_syslog:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_syslog
- mov %g1, %o7
-sys32_personality:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_personality
- mov %g1, %o7
-sys32_waitpid:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_waitpid
- mov %g1, %o7
-sys32_sched_setscheduler:
- srl %o2, 0, %o2
- mov %o7, %g1
- call sys_sched_setscheduler
- mov %g1, %o7
-sys32_sched_setparam:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_sched_setparam
- mov %g1, %o7
-sys32_sched_getparam:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_sched_getparam
- mov %g1, %o7
-sys32_signal:
- srl %o1, 0, %o1
- mov %o7, %g1
- call sys_signal
- mov %g1, %o7
-sys32_reboot:
- srl %o3, 0, %o3
- mov %o7, %g1
- call sys_reboot
- mov %g1, %o7
-sys32_acct:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_acct
- mov %g1, %o7
-sys32_newuname:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_newuname
- mov %g1, %o7
-sys32_olduname:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_olduname
- mov %g1, %o7
-sys32_sethostname:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_sethostname
- mov %g1, %o7
-sys32_gethostname:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_gethostname
- mov %g1, %o7
-sys32_setdomainname:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_setdomainname
- mov %g1, %o7
-sys32_time:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_time
- mov %g1, %o7
-sys32_swapoff:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_swapoff
- mov %g1, %o7
-sys32_swapon:
- srl %o0, 0, %o0
- mov %o7, %g1
- call sys_swapon
- mov %g1, %o7
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 0ec6de167..e0e69abd9 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.5 1997/09/03 12:29:05 jj Exp $
+/* $Id: sys_sparc.c,v 1.9 1997/12/11 15:15:44 jj Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -16,11 +16,14 @@
#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>
+#include <linux/malloc.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
+#include <asm/utrap.h>
/* XXX Make this per-binary type, this way we can detect the type of
* XXX a binary. Every Sparc executable calls this very early on.
@@ -219,39 +222,16 @@ sparc_breakpoint (struct pt_regs *regs)
extern void check_pending(int signum);
-asmlinkage int
-sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
+asmlinkage int sys_getdomainname(char *name, int len)
{
- struct sigaction new_sa, *p;
+ int nlen = strlen(system_utsname.domainname);
- if(signum < 0) {
- current->tss.new_signal = 1;
- signum = -signum;
- }
- if (signum<1 || signum>32)
- return -EINVAL;
- p = signum - 1 + current->sig->action;
- if (action) {
- 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) {
- int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
- if (err)
- return err;
- }
- }
- if (oldaction) {
- if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- return -EFAULT;
- }
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- *p = new_sa;
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
- }
+ 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;
}
@@ -272,3 +252,116 @@ asmlinkage int solaris_syscall(struct pt_regs *regs)
unlock_kernel();
return 0;
}
+
+asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, utrap_handler_t new_d,
+ utrap_handler_t *old_p, utrap_handler_t *old_d)
+{
+ if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
+ return -EINVAL;
+ if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
+ if (old_p) {
+ if (!current->tss.utraps)
+ put_user_ret(NULL, old_p, -EFAULT);
+ else
+ put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
+ }
+ if (old_d)
+ put_user_ret(NULL, old_d, -EFAULT);
+ return 0;
+ }
+ lock_kernel();
+ if (!current->tss.utraps) {
+ current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
+ if (!current->tss.utraps) return -ENOMEM;
+ current->tss.utraps[0] = 1;
+ memset(current->tss.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
+ } else {
+ if ((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] > 1) {
+ long *p = current->tss.utraps;
+
+ current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
+ if (!current->tss.utraps) {
+ current->tss.utraps = p;
+ return -ENOMEM;
+ }
+ p[0]--;
+ current->tss.utraps[0] = 1;
+ memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
+ }
+ }
+ if (old_p)
+ put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
+ if (old_d)
+ put_user_ret(NULL, old_d, -EFAULT);
+ current->tss.utraps[type] = (long)new_p;
+ unlock_kernel();
+ return 0;
+}
+
+long sparc_memory_ordering(unsigned long model, struct pt_regs *regs)
+{
+ if (model >= 3)
+ return -EINVAL;
+ regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14);
+ return 0;
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t 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;
+ __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;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ 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);
+ }
+
+ 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;
+}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 81640c8e6..66993ebcb 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.55 1997/09/04 01:54:51 davem Exp $
+/* $Id: sys_sparc32.c,v 1.71 1997/12/11 15:15:11 jj Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -28,6 +28,7 @@
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
#include <linux/ncp_fs.h>
#include <linux/quota.h>
#include <linux/file.h>
@@ -39,6 +40,7 @@
#include <linux/nfsd/syscall.h>
#include <linux/module.h>
#include <linux/poll.h>
+#include <linux/personality.h>
#include <asm/types.h>
#include <asm/ipc.h>
@@ -253,7 +255,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
case SEMCTL: {
union semun fourth;
void *pad;
- unsigned long old_fs;
+ mm_segment_t old_fs;
struct semid_ds s;
err = -EINVAL;
@@ -336,7 +338,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
err = -EFAULT;
}
if (!err) {
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
err = sys_msgsnd (first, p, second, third);
set_fs (old_fs);
@@ -348,7 +350,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
case MSGRCV:
{
struct msgbuf *p;
- unsigned long old_fs;
+ mm_segment_t old_fs;
long msgtyp = fifth;
if (!version) {
@@ -398,7 +400,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
case MSGCTL:
{
struct msqid_ds m;
- unsigned long old_fs;
+ mm_segment_t old_fs;
switch (second) {
case IPC_INFO:
@@ -482,7 +484,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
case SHMCTL:
{
struct shmid_ds s;
- unsigned long old_fs;
+ mm_segment_t old_fs;
switch (second) {
case IPC_INFO:
@@ -590,7 +592,7 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
case F_SETLKW:
{
struct flock f;
- unsigned long old_fs;
+ mm_segment_t old_fs;
long ret;
if(get_flock(&f, (struct flock32 *)A(arg)))
@@ -625,7 +627,7 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
int cmds = cmd >> SUBCMDSHIFT;
int err;
struct dqblk d;
- unsigned long old_fs;
+ mm_segment_t old_fs;
char *spec;
switch (cmds) {
@@ -685,7 +687,7 @@ asmlinkage int sys32_statfs(u32 path, u32 buf)
{
int ret;
struct statfs s;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
char *pth;
pth = getname32 (path);
@@ -707,7 +709,7 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
{
int ret;
struct statfs s;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_fstatfs(fd, &s);
@@ -723,7 +725,7 @@ asmlinkage int sys32_utime(u32 filename, u32 times)
{
struct utimbuf32 { __kernel_time_t32 actime, modtime; };
struct utimbuf t;
- unsigned long old_fs;
+ mm_segment_t old_fs;
int ret;
char *filenam;
@@ -746,14 +748,15 @@ asmlinkage int sys32_utime(u32 filename, u32 times)
struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
-typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
+typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
-static long do_readv_writev32(int type, struct inode *inode, struct file *file,
+static long do_readv_writev32(int type, struct file *file,
const struct iovec32 *vector, u32 count)
{
unsigned long tot_len;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov=iovstack, *ivp;
+ struct inode *inode;
long retval, i;
IO_fn_t fn;
@@ -789,6 +792,7 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file,
i--;
}
+ inode = file->f_dentry->d_inode;
retval = locks_verify_area((type == VERIFY_READ) ?
FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
inode, file, file->f_pos, tot_len);
@@ -828,7 +832,7 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file,
len = ivp->iov_len;
ivp++;
count--;
- nr = fn(inode, file, base, len);
+ nr = fn(file, base, len, &file->f_pos);
if (nr < 0) {
if (retval)
break;
@@ -847,69 +851,53 @@ static long do_readv_writev32(int type, struct inode *inode, struct file *file,
asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
{
struct file *file;
- struct dentry *dentry;
- struct inode *inode;
- long err = -EBADF;
+ long ret = -EBADF;
lock_kernel();
- if(fd >= NR_OPEN)
- goto out;
-
- file = current->files->fd[fd];
+ file = fget(fd);
if(!file)
- goto out;
+ goto bad_file;
if(!(file->f_mode & 1))
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
- err = do_readv_writev32(VERIFY_WRITE, inode, file,
+ ret = do_readv_writev32(VERIFY_WRITE, file,
(struct iovec32 *)A(vector), count);
+ if (ret > 0)
+ current->io_usage += ret;
+
out:
+ fput(file);
+bad_file:
unlock_kernel();
- return err;
+ return ret;
}
asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
{
- int error = -EBADF;
struct file *file;
- struct dentry *dentry;
- struct inode *inode;
+ int ret = -EBADF;
lock_kernel();
- if(fd >= NR_OPEN)
- goto out;
-
- file = current->files->fd[fd];
+ file = fget(fd);
if(!file)
- goto out;
+ goto bad_file;
if(!(file->f_mode & 2))
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
- down(&inode->i_sem);
- error = do_readv_writev32(VERIFY_READ, inode, file,
+ down(&file->f_dentry->d_inode->i_sem);
+ ret = do_readv_writev32(VERIFY_READ, file,
(struct iovec32 *)A(vector), count);
- up(&inode->i_sem);
+ up(&file->f_dentry->d_inode->i_sem);
+ if (ret > 0)
+ current->io_usage += ret;
+
out:
+ fput(file);
+bad_file:
unlock_kernel();
- return error;
+ return ret;
}
/* readdir & getdents */
@@ -951,8 +939,6 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
{
int error = -EBADF;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct readdir_callback32 buf;
lock_kernel();
@@ -963,14 +949,6 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
if(!file)
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
buf.count = 0;
buf.dirent = (struct old_linux_dirent32 *)A(dirent);
@@ -978,7 +956,7 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
if (!file->f_op || !file->f_op->readdir)
goto out;
- error = file->f_op->readdir(inode, file, &buf, fillonedir);
+ error = file->f_op->readdir(file, &buf, fillonedir);
if (error < 0)
goto out;
error = buf.count;
@@ -1028,8 +1006,6 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
{
struct file * file;
- struct dentry * dentry;
- struct inode *inode;
struct linux_dirent32 * lastdirent;
struct getdents_callback32 buf;
int error = -EBADF;
@@ -1042,14 +1018,6 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
if(!file)
goto out;
- dentry = file->f_dentry;
- if(!dentry)
- goto out;
-
- inode = dentry->d_inode;
- if(!inode)
- goto out;
-
buf.current_dir = (struct linux_dirent32 *) A(dirent);
buf.previous = NULL;
buf.count = count;
@@ -1059,7 +1027,7 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
if (!file->f_op || !file->f_op->readdir)
goto out;
- error = file->f_op->readdir(inode, file, &buf, filldir);
+ error = file->f_op->readdir(file, &buf, filldir);
if (error < 0)
goto out;
lastdirent = buf.previous;
@@ -1088,7 +1056,7 @@ get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x)
if (ufdset) {
unsigned long odd;
- if (verify_area(VERIFY_WRITE, ufdset, nn*sizeof(u32)))
+ if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
return -EFAULT;
odd = n & 1UL;
@@ -1104,12 +1072,12 @@ get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x)
if (odd)
__get_user(*fdset, ufdset);
} else {
- /* Tricky, must clear full unsigned long in the kernel
- fdset at the end, this makes sure that actually
- happens. */
+ /* Tricky, must clear full unsigned long in the
+ * kernel fdset at the end, this makes sure that
+ * actually happens.
+ */
memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
}
-
return 0;
}
@@ -1168,7 +1136,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x)
goto out;
if (n > KFDS_NR)
n = KFDS_NR;
-
+
nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
if ((ret = get_fd_set32(nn, fds->in, inp)) ||
(ret = get_fd_set32(nn, fds->out, outp)) ||
@@ -1196,7 +1164,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x)
goto out;
if (!ret) {
ret = -ERESTARTNOHAND;
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
goto out;
ret = 0;
}
@@ -1237,7 +1205,7 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
int ret;
struct stat s;
char *filenam;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
filenam = getname32 (filename);
ret = PTR_ERR(filenam);
@@ -1259,7 +1227,7 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
int ret;
struct stat s;
char *filenam;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
filenam = getname32 (filename);
ret = PTR_ERR(filenam);
@@ -1280,7 +1248,7 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
{
int ret;
struct stat s;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_newfstat(fd, &s);
@@ -1290,29 +1258,11 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
return ret;
}
-extern asmlinkage int sys_sysfs(int option, ...);
+extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
-asmlinkage int sys32_sysfs(int option, ...)
+asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
{
- va_list args;
- unsigned int x;
- int ret = -EINVAL;
-
- va_start(args, option);
- switch (option) {
- case 1:
- ret = sys_sysfs(option, (const char *)A(va_arg(args, u32)));
- break;
- case 2:
- x = va_arg(args, unsigned int);
- ret = sys_sysfs(option, x, (char *)A(va_arg(args, u32)));
- break;
- case 3:
- ret = sys_sysfs(option);
- break;
- }
- va_end(args);
- return ret;
+ return sys_sysfs(option, arg1, arg2);
}
struct ncp_mount_data32 {
@@ -1347,17 +1297,7 @@ static void *do_ncp_super_data_conv(void *raw_data)
struct smb_mount_data32 {
int version;
- unsigned int fd;
__kernel_uid_t32 mounted_uid;
- struct sockaddr_in addr;
- char server_name[17];
- char client_name[17];
- char service[64];
- char root_path[64];
- char username[64];
- char password[64];
- char domain[64];
- unsigned short max_xmit;
__kernel_uid_t32 uid;
__kernel_gid_t32 gid;
__kernel_mode_t32 file_mode;
@@ -1434,7 +1374,7 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
(void *)A(data));
} else {
unsigned long dev_page, dir_page, data_page;
- int old_fs;
+ mm_segment_t old_fs;
err = copy_mount_stuff_to_kernel((const void *)A(dev_name), &dev_page);
if(err)
@@ -1527,7 +1467,7 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32
struct rusage r;
int ret;
unsigned int status;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
@@ -1558,7 +1498,7 @@ asmlinkage int sys32_sysinfo(u32 info)
{
struct sysinfo s;
int ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_sysinfo(&s);
@@ -1589,7 +1529,7 @@ asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
{
struct timespec t;
int ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_sched_rr_get_interval(pid, &t);
@@ -1606,7 +1546,7 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
{
struct timespec t;
int ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) ||
__get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec)))
@@ -1622,34 +1562,235 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
return ret;
}
-extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
+extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset);
asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
{
- sigset_t s;
+ old_sigset_t s;
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
- if (set && get_user (s, (sigset_t32 *)A(set))) return -EFAULT;
+ if (set && get_user (s, (old_sigset_t32 *)A(set))) return -EFAULT;
set_fs (KERNEL_DS);
ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
set_fs (old_fs);
- if (oset && put_user (s, (sigset_t32 *)A(oset))) return -EFAULT;
- return ret;
+ if (ret) return ret;
+ if (oset && put_user (s, (old_sigset_t32 *)A(oset))) return -EFAULT;
+ return 0;
}
-extern asmlinkage int sys_sigpending(sigset_t *set);
+extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);
-asmlinkage int sys32_sigpending(u32 set)
+asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t32 sigsetsize)
{
sigset_t s;
+ sigset_t32 s32;
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
+
+ if (set) {
+ if (copy_from_user (&s32, (sigset_t32 *)A(set), 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);
+ }
+ }
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sigsetsize);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (oset) {
+ switch (_NSIG_WORDS) {
+ case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+ case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+ case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+ case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+ }
+ if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+extern asmlinkage int sys_sigpending(old_sigset_t *set);
+
+asmlinkage int sys32_sigpending(u32 set)
+{
+ old_sigset_t s;
+ int ret;
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_sigpending(&s);
set_fs (old_fs);
- if (put_user (s, (sigset_t32 *)A(set))) return -EFAULT;
+ if (put_user (s, (old_sigset_t32 *)A(set))) return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
+
+asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize)
+{
+ sigset_t s;
+ sigset_t32 s32;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigpending(&s, sigsetsize);
+ set_fs (old_fs);
+ if (!ret) {
+ switch (_NSIG_WORDS) {
+ case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+ case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+ case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+ case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+ }
+ if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+siginfo_t32 *
+siginfo64to32(siginfo_t32 *d, siginfo_t *s)
+{
+ memset (&d, 0, sizeof(siginfo_t32));
+ d->si_signo = s->si_signo;
+ d->si_errno = s->si_errno;
+ d->si_code = s->si_code;
+ if (s->si_signo >= SIGRTMIN) {
+ d->si_pid = s->si_pid;
+ d->si_uid = s->si_uid;
+ /* XXX: Ouch, how to find this out??? */
+ d->si_int = s->si_int;
+ } else switch (s->si_signo) {
+ /* XXX: What about POSIX1.b timers */
+ case SIGCHLD:
+ d->si_pid = s->si_pid;
+ d->si_status = s->si_status;
+ d->si_utime = s->si_utime;
+ d->si_stime = s->si_stime;
+ break;
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ d->si_addr = (long)(s->si_addr);
+ /* XXX: Do we need to translate this from sparc64 to sparc32 traps? */
+ d->si_trapno = s->si_trapno;
+ break;
+ case SIGPOLL:
+ d->si_band = s->si_band;
+ d->si_fd = s->si_fd;
+ break;
+ default:
+ d->si_pid = s->si_pid;
+ d->si_uid = s->si_uid;
+ break;
+ }
+ return d;
+}
+
+siginfo_t *
+siginfo32to64(siginfo_t *d, siginfo_t32 *s)
+{
+ d->si_signo = s->si_signo;
+ d->si_errno = s->si_errno;
+ d->si_code = s->si_code;
+ if (s->si_signo >= SIGRTMIN) {
+ d->si_pid = s->si_pid;
+ d->si_uid = s->si_uid;
+ /* XXX: Ouch, how to find this out??? */
+ d->si_int = s->si_int;
+ } else switch (s->si_signo) {
+ /* XXX: What about POSIX1.b timers */
+ case SIGCHLD:
+ d->si_pid = s->si_pid;
+ d->si_status = s->si_status;
+ d->si_utime = s->si_utime;
+ d->si_stime = s->si_stime;
+ break;
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ d->si_addr = (void *)A(s->si_addr);
+ /* XXX: Do we need to translate this from sparc32 to sparc64 traps? */
+ d->si_trapno = s->si_trapno;
+ break;
+ case SIGPOLL:
+ d->si_band = s->si_band;
+ d->si_fd = s->si_fd;
+ break;
+ default:
+ d->si_pid = s->si_pid;
+ d->si_uid = s->si_uid;
+ break;
+ }
+ return d;
+}
+
+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(u32 uthese, u32 uinfo,
+ u32 uts, __kernel_size_t32 sigsetsize)
+{
+ sigset_t s;
+ sigset_t32 s32;
+ struct timespec t;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+ siginfo_t info;
+ siginfo_t32 info32;
+
+ if (copy_from_user (&s32, (sigset_t32 *)A(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);
+ }
+ if (uts) {
+ if (get_user (t.tv_sec, &(((struct timespec32 *)A(uts))->tv_sec)) ||
+ __get_user (t.tv_nsec, &(((struct timespec32 *)A(uts))->tv_nsec)))
+ return -EFAULT;
+ }
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
+ set_fs (old_fs);
+ if (ret >= 0 && uinfo) {
+ if (copy_to_user ((siginfo_t32 *)A(uinfo), siginfo64to32(&info32, &info), sizeof(siginfo_t32)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+extern asmlinkage int
+sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
+
+asmlinkage int
+sys32_rt_sigqueueinfo(int pid, int sig, u32 uinfo)
+{
+ siginfo_t info;
+ siginfo_t32 info32;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (copy_from_user (&info32, (siginfo_t32 *)A(uinfo), sizeof(siginfo_t32)))
+ return -EFAULT;
+ /* XXX: Is this correct? */
+ siginfo32to64(&info, &info32);
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigqueueinfo(pid, sig, &info);
+ set_fs (old_fs);
return ret;
}
@@ -1684,7 +1825,7 @@ asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
{
uid_t a, b, c;
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_getresuid(&a, &b, &c);
@@ -1696,6 +1837,49 @@ asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
return ret;
}
+extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid);
+
+asmlinkage int sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid)
+{
+ gid_t srgid, segid;
+
+ srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
+ segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
+ return sys_setregid(srgid, segid);
+}
+
+extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+
+asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid,
+ __kernel_gid_t32 egid,
+ __kernel_gid_t32 sgid)
+{
+ gid_t srgid, segid, ssgid;
+
+ srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
+ segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
+ ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
+ return sys_setresgid(srgid, segid, ssgid);
+}
+
+extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
+
+asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid)
+{
+ gid_t a, b, c;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getresgid(&a, &b, &c);
+ set_fs (old_fs);
+ if (put_user (a, (__kernel_gid_t32 *)A(rgid)) ||
+ put_user (b, (__kernel_gid_t32 *)A(egid)) ||
+ put_user (c, (__kernel_gid_t32 *)A(sgid)))
+ return -EFAULT;
+ return ret;
+}
+
struct tms32 {
__kernel_clock_t32 tms_utime;
__kernel_clock_t32 tms_stime;
@@ -1709,7 +1893,7 @@ asmlinkage long sys32_times(u32 tbuf)
{
struct tms t;
long ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_times(tbuf ? &t : NULL);
@@ -1729,7 +1913,7 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
{
gid_t gl[NGROUPS];
int ret, i;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_getgroups(gidsetsize, gl);
@@ -1747,7 +1931,7 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
{
gid_t gl[NGROUPS];
int ret, i;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
if ((unsigned) gidsetsize > NGROUPS)
return -EINVAL;
@@ -1774,7 +1958,7 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
{
struct rlimit r;
int ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_getrlimit(resource, &r);
@@ -1792,7 +1976,7 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
{
struct rlimit r;
int ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
if (resource >= RLIM_NLIMITS) return -EINVAL;
if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
@@ -1814,7 +1998,7 @@ asmlinkage int sys32_getrusage(int who, u32 ru)
{
struct rusage r;
int ret;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_getrusage(who, &r);
@@ -1854,7 +2038,7 @@ asmlinkage int sys32_adjtimex(u32 txc_p)
{
struct timex t;
int ret;
- unsigned long old_fs = get_fs ();
+ mm_segment_t old_fs = get_fs ();
if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
__get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
@@ -2158,21 +2342,19 @@ static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
#undef AL
-extern asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen);
-extern asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen);
-extern asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen);
-extern asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len);
-extern asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len);
-extern asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len,
- unsigned flags);
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
+extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags);
extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
unsigned flags, u32 addr, int addr_len);
-extern asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size,
- unsigned flags);
+extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
unsigned flags, u32 addr, u32 addr_len);
-extern asmlinkage int sys32_setsockopt(int fd, int level, int optname,
- u32 optval, int optlen);
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
u32 optval, u32 optlen);
@@ -2199,31 +2381,31 @@ asmlinkage int sys32_socketcall(int call, u32 args)
case SYS_SOCKET:
return sys_socket(a0, a1, a[2]);
case SYS_BIND:
- return sys32_bind(a0, a1, a[2]);
+ return sys_bind(a0, (struct sockaddr *)A(a1), a[2]);
case SYS_CONNECT:
- return sys32_connect(a0, a1, a[2]);
+ return sys_connect(a0, (struct sockaddr *)A(a1), a[2]);
case SYS_LISTEN:
return sys_listen(a0, a1);
case SYS_ACCEPT:
- return sys32_accept(a0, a1, a[2]);
+ return sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
case SYS_GETSOCKNAME:
- return sys32_getsockname(a0, a1, a[2]);
+ return sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
case SYS_GETPEERNAME:
- return sys32_getpeername(a0, a1, a[2]);
+ return sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2]));
case SYS_SOCKETPAIR:
return sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
case SYS_SEND:
- return sys32_send(a0, a1, a[2], a[3]);
+ return sys_send(a0, (void *)A(a1), a[2], a[3]);
case SYS_SENDTO:
return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
case SYS_RECV:
- return sys32_recv(a0, a1, a[2], a[3]);
+ return sys_recv(a0, (void *)A(a1), a[2], a[3]);
case SYS_RECVFROM:
return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
case SYS_SHUTDOWN:
return sys_shutdown(a0,a1);
case SYS_SETSOCKOPT:
- return sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
+ return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
case SYS_GETSOCKOPT:
return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
case SYS_SENDMSG:
@@ -2236,51 +2418,88 @@ asmlinkage int sys32_socketcall(int call, u32 args)
extern void check_pending(int signum);
-asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
+asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact)
{
- struct sigaction32 new_sa, old_sa;
- struct sigaction *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 (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
+
+ if (act) {
+ old_sigset_t32 mask;
+
+ if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
+ __get_user((long)new_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(act))->sa_restorer))
return -EFAULT;
- if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL &&
- ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
- int err = verify_area(VERIFY_READ,
- (__sighandler_t)A(new_sa.sa_handler), 1);
- if (err)
- return err;
+ __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags);
+ __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask);
+ new_ka.ka_restorer = NULL;
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) ||
+ __put_user((long)old_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(oact))->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys32_rt_sigaction(int sig, u32 act, u32 oact,
+ u32 restorer, __kernel_size_t32 sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+ sigset_t32 set32;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t32))
+ return -EINVAL;
+
+ if (act) {
+ if (get_user((long)new_ka.sa.sa_handler, &((struct sigaction32 *)A(act))->sa_handler) ||
+ __copy_from_user(&set32, &((struct sigaction32 *)A(act))->sa_mask, sizeof(sigset_t32)))
+ return -EFAULT;
+ switch (_NSIG_WORDS) {
+ case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
+ case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
+ case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
+ case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
}
- }
- if (oldaction) {
- old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
- old_sa.sa_mask = (sigset_t32)(p->sa_mask);
- old_sa.sa_flags = (unsigned)(p->sa_flags);
- old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
- if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
- return -EFAULT;
- }
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
- p->sa_mask = (sigset_t)(new_sa.sa_mask);
- p->sa_flags = new_sa.sa_flags;
- p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
- }
- return 0;
+ __get_user(new_ka.sa.sa_flags, &((struct sigaction32 *)A(act))->sa_flags);
+ __get_user((long)new_ka.sa.sa_restorer, &((struct sigaction32 *)A(act))->sa_restorer);
+ new_ka.ka_restorer = (void *)(long)restorer;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ switch (_NSIG_WORDS) {
+ case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
+ case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
+ case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
+ case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
+ }
+ if (put_user((long)old_ka.sa.sa_handler, &((struct sigaction32 *)A(oact))->sa_handler) ||
+ __copy_to_user(&((struct sigaction32 *)A(oact))->sa_mask, &set32, sizeof(sigset_t32)))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &((struct sigaction32 *)A(oact))->sa_flags);
+ __put_user((long)old_ka.sa.sa_restorer, &((struct sigaction32 *)A(oact))->sa_restorer);
+ }
+
+ return ret;
}
+
/*
* count32() counts the number of arguments/envelopes
*/
@@ -2476,7 +2695,7 @@ extern asmlinkage int sys_query_module(const char *name_user, int which, char *b
asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv)
{
char *buff;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
size_t val;
int ret, i, j;
unsigned long *p;
@@ -2544,7 +2763,7 @@ qmsym_toshort:
if (!ret && val) {
char *strings = buff + ((unsigned long *)buff)[1];
j = *(p - 1) - ((unsigned long *)buff)[1];
- j = j + strlen (buff + j) + 1;
+ j = j + strlen (strings + j) + 1;
if (bufsize < j) {
bufsiz = 0;
goto qmsym_toshort;
@@ -2597,7 +2816,7 @@ asmlinkage int sys32_get_kernel_syms(u32 table)
{
int len, i;
struct kernel_sym *tbl;
- unsigned long old_fs;
+ mm_segment_t old_fs;
len = sys_get_kernel_syms(NULL);
if (!table) return len;
@@ -2858,7 +3077,7 @@ int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
union nfsctl_res32 *res32 = (union nfsctl_res32 *)A(u_resp);
struct nfsctl_arg *karg = NULL;
union nfsctl_res *kres = NULL;
- unsigned long oldfs;
+ mm_segment_t oldfs;
int err;
karg = kmalloc(sizeof(*karg), GFP_USER);
@@ -3003,7 +3222,7 @@ asmlinkage int sys32_utimes(u32 filename, u32 tvs)
{
char *kfilename;
struct timeval ktvs[2];
- unsigned long old_fs;
+ mm_segment_t old_fs;
int ret;
kfilename = getname32(filename);
@@ -3024,3 +3243,87 @@ asmlinkage int sys32_utimes(u32 filename, u32 tvs)
}
return ret;
}
+
+/* These are here just in case some old sparc32 binary calls it. */
+asmlinkage int sys32_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+/* PCI config space poking. */
+extern asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf);
+
+extern asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf);
+
+asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
+{
+ return sys_pciconfig_read((unsigned long) bus,
+ (unsigned long) dfn,
+ (unsigned long) off,
+ (unsigned long) len,
+ (unsigned char *)A(ubuf));
+}
+
+asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
+{
+ return sys_pciconfig_write((unsigned long) bus,
+ (unsigned long) dfn,
+ (unsigned long) off,
+ (unsigned long) len,
+ (unsigned char *)A(ubuf));
+}
+
+extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5);
+
+asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+{
+ return sys_prctl(option,
+ (unsigned long) arg2,
+ (unsigned long) arg3,
+ (unsigned long) arg4,
+ (unsigned long) arg5);
+}
+
+
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
+asmlinkage int sys32_newuname(struct new_utsname * name)
+{
+ int ret = sys_newuname(name);
+
+ if (current->personality == PER_LINUX32 && !ret) {
+ ret = copy_to_user(name->machine, "sparc\0\0", 8);
+ }
+ return ret;
+}
+
+extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
+ size_t count, loff_t pos);
+
+extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
+ size_t count, loff_t pos);
+
+typedef __kernel_ssize_t32 ssize_t32;
+
+asmlinkage ssize_t32 sys32_pread(unsigned int fd, u32 ubuf,
+ __kernel_size_t32 count, u32 pos)
+{
+ return sys_pread(fd, (char *) A(ubuf), count, pos);
+}
+
+asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf,
+ __kernel_size_t32 count, u32 pos)
+{
+ return sys_pwrite(fd, (char *) A(ubuf), count, pos);
+}
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index dc87c3095..4af388b99 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.3 1997/07/17 02:20:48 davem Exp $
+/* $Id: sys_sunos32.c,v 1.7 1997/12/11 15:15:19 jj Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -297,35 +297,28 @@ asmlinkage int 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 u32 sunos_sigblock(u32 blk_mask)
{
- unsigned long flags;
u32 old;
- lock_kernel();
- save_and_cli(flags);
- old = (u32) current->blocked;
- current->blocked |= (blk_mask & _BLOCKABLE);
- restore_flags(flags);
- unlock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
+ old = (u32) current->blocked.sig[0];
+ current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
+ spin_unlock_irq(&current->sigmask_lock);
return old;
}
asmlinkage u32 sunos_sigsetmask(u32 newmask)
{
- unsigned long flags;
u32 retval;
- lock_kernel();
- save_and_cli(flags);
- retval = (u32) current->blocked;
- current->blocked = (newmask & _BLOCKABLE);
- restore_flags(flags);
- unlock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
+ retval = (u32) current->blocked.sig[0];
+ current->blocked.sig[0] = (newmask & _BLOCKABLE);
+ spin_unlock_irq(&current->sigmask_lock);
return retval;
}
@@ -379,8 +372,6 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct sunos_dirent * lastdirent;
struct sunos_dirent_callback buf;
int error = -EBADF;
@@ -394,14 +385,6 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_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;
@@ -415,7 +398,7 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
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;
@@ -472,8 +455,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
int cnt, u32 u_basep)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
struct sunos_direntry * lastdirent;
struct sunos_direntry_callback buf;
int error = -EBADF;
@@ -488,14 +469,6 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
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;
@@ -509,7 +482,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
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;
@@ -1140,7 +1113,7 @@ asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
struct sparc_stackf32 *sp;
struct msqid_ds kds;
struct msgbuf *kmbuf;
- unsigned long old_fs = get_fs();
+ mm_segment_t old_fs = get_fs();
u32 arg5;
int rval;
@@ -1264,7 +1237,8 @@ extern asmlinkage int sys_shmget (key_t key, int size, int shmflg);
asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3)
{
struct shmid_ds ksds;
- unsigned long raddr, old_fs = get_fs();
+ unsigned long raddr;
+ mm_segment_t old_fs = get_fs();
int rval;
lock_kernel();
@@ -1328,20 +1302,20 @@ static inline int check_nonblock(int ret, int fd)
return ret;
}
-extern asmlinkage int sys32_read(unsigned int fd, u32 buf, int count);
-extern asmlinkage int sys32_write(unsigned int fd, u32 buf,int count);
-extern asmlinkage int sys32_recv(int fd, u32 ubuf, int size, unsigned flags);
-extern asmlinkage int sys32_send(int fd, u32 buff, int len, unsigned flags);
-extern asmlinkage int sys32_accept(int fd, u32 sa, u32 addrlen);
+extern asmlinkage int sys_read(unsigned int fd, char *buf, unsigned long count);
+extern asmlinkage int sys_write(unsigned int fd, char *buf, unsigned long count);
+extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
+extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags);
+extern asmlinkage int sys_accept(int fd, struct sockaddr *sa, int *addrlen);
extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count);
extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count);
-asmlinkage int sunos_read(unsigned int fd, u32 buf, int count)
+asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count)
{
int ret;
lock_kernel();
- ret = check_nonblock(sys32_read(fd, buf, count), fd);
+ ret = check_nonblock(sys_read(fd, (char *)A(buf), count), fd);
unlock_kernel();
return ret;
}
@@ -1356,12 +1330,12 @@ asmlinkage int sunos_readv(u32 fd, u32 vector, s32 count)
return ret;
}
-asmlinkage int sunos_write(unsigned int fd, u32 buf, int count)
+asmlinkage int sunos_write(unsigned int fd, u32 buf, u32 count)
{
int ret;
lock_kernel();
- ret = check_nonblock(sys32_write(fd, buf, count), fd);
+ ret = check_nonblock(sys_write(fd, (char *)A(buf), count), fd);
unlock_kernel();
return ret;
}
@@ -1381,7 +1355,7 @@ asmlinkage int sunos_recv(int fd, u32 ubuf, int size, unsigned flags)
int ret;
lock_kernel();
- ret = check_nonblock(sys32_recv(fd, ubuf, size, flags), fd);
+ ret = check_nonblock(sys_recv(fd, (void *)A(ubuf), size, flags), fd);
unlock_kernel();
return ret;
}
@@ -1391,7 +1365,7 @@ asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags)
int ret;
lock_kernel();
- ret = check_nonblock(sys32_send(fd, buff, len, flags), fd);
+ ret = check_nonblock(sys_send(fd, (void *)A(buff), len, flags), fd);
unlock_kernel();
return ret;
}
@@ -1401,78 +1375,48 @@ asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen)
int ret;
lock_kernel();
- ret = check_nonblock(sys32_accept(fd, sa, addrlen), fd);
+ ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa), (int *)A(addrlen)), fd);
unlock_kernel();
return ret;
}
#define SUNOS_SV_INTERRUPT 2
-extern void check_pending(int signum);
-
-asmlinkage int sunos_sigaction(int signum, u32 action, u32 oldaction)
+asmlinkage int sunos_sigaction (int sig, u32 act, u32 oact)
{
- struct sigaction32 new_sa, old_sa;
- struct sigaction *p;
- const int sigaction_size = sizeof (struct sigaction32) - sizeof (u32);
+ 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_t32 mask;
- if(action) {
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- memset(&new_sa, 0, sizeof(struct sigaction32));
- if(copy_from_user(&new_sa, (struct sigaction32 *)A(action),
- sigaction_size))
+ if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
+ __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags))
return -EFAULT;
- if (((__sighandler_t)A(new_sa.sa_handler) != SIG_DFL) &&
- (__sighandler_t)A(new_sa.sa_handler) != SIG_IGN) {
- if(verify_area(VERIFY_READ,
- (__sighandler_t)A(new_sa.sa_handler), 1))
- return -EFAULT;
- }
- new_sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+ __get_user(mask, &((struct old_sigaction32 *)A(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) {
- /* 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 ;-)
- */
- old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
- old_sa.sa_mask = (sigset_t32)(p->sa_mask);
- old_sa.sa_flags = (unsigned)(p->sa_flags);
-
- if (old_sa.sa_flags & SA_RESTART)
- old_sa.sa_flags &= ~SA_RESTART;
- else
- old_sa.sa_flags |= SUNOS_SV_INTERRUPT;
- if (copy_to_user((struct sigaction32 *)A(oldaction),
- &old_sa, sigaction_size))
- return -EFAULT;
- }
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
- if (action) {
- spin_lock_irq(&current->sig->siglock);
- p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
- p->sa_mask = (sigset_t)(new_sa.sa_mask);
- p->sa_flags = new_sa.sa_flags;
- p->sa_restorer = (void (*)(void))0;
- check_pending(signum);
- spin_unlock_irq(&current->sig->siglock);
+ if (!ret && oact) {
+ old_ka.sa.sa_flags ^= SUNOS_SV_INTERRUPT;
+ if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) ||
+ __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask);
}
- return 0;
-}
+ return ret;
+}
-extern asmlinkage int sys32_setsockopt(int fd, int level, int optname,
- u32 optval, int optlen);
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
u32 optval, u32 optlen);
@@ -1488,7 +1432,7 @@ asmlinkage int sunos_setsockopt(int fd, int level, int optname, u32 optval,
if (tr_opt >=2 && tr_opt <= 6)
tr_opt += 30;
}
- ret = sys32_setsockopt(fd, level, tr_opt, optval, optlen);
+ ret = sys_setsockopt(fd, level, tr_opt, (char *)A(optval), optlen);
unlock_kernel();
return ret;
}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index ec2c3c9b6..48ae0ecdf 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.24 1997/08/22 20:12:06 davem Exp $
+/* $Id: systbls.S,v 1.37 1997/12/24 17:27:31 ecd Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -17,58 +17,58 @@
.globl sys_call_table32
sys_call_table32:
-/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
-/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
-/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_chown, sparc_brk, sys_nis_syscall, sys32_lseek
/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
- .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
-/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
- .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
-/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
- .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
-/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
- .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause
+/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
+ .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall
+ .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+ .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve
+/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_nis_syscall
+/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
.word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
- .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+ .word sys_swapon, sys32_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
.word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
+ .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
- .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
-/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate
+/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
- .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
-/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
- .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+ .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
+/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_umount
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
+ .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
- .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
-/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
- .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
-/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
- .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*190*/ .word sys32_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
+/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
+ .word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
+ .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
/*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
- .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
-/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+/*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+ .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
- .word sys_aplib, sys_prctl
+/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+ .word sys_aplib
/* Now the 64-bit native Linux syscall table. */
@@ -81,23 +81,23 @@ sys_call_table:
/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
- .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall
+/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
+ .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
.word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
- .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall
/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
.word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
/*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
.word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
/*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
.word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
- .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/ .word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
+ .word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
.word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
@@ -105,29 +105,29 @@ sys_call_table:
/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
.word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
- .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
+/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
- .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*190*/ .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
.word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
.word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+/*230*/ .word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
- .word sys_aplib, sys_prctl
+ .word sys_aplib
/* Now the 32-bit SunOS syscall table. */
@@ -136,40 +136,40 @@ sys_call_table:
sunos_sys_table:
/*0*/ .word sunos_indir, sys_exit, sys_fork
.word sunos_read, sunos_write, sunos_open
- .word sys_close, sunos_wait4, sys32_creat
- .word sys32_link, sys32_unlink, sunos_execv
- .word sys32_chdir, sunos_nosys, sys32_mknod
+ .word sys_close, sunos_wait4, sys_creat
+ .word sys_link, sys_unlink, sunos_execv
+ .word sys_chdir, sunos_nosys, sys32_mknod
.word sys32_chmod, sys32_chown, sunos_brk
.word sunos_nosys, sys32_lseek, sunos_getpid
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_getuid, sunos_nosys, sys_ptrace
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sunos_nosys
- .word sys32_access, sunos_nosys, sunos_nosys
+ .word sys_access, sunos_nosys, sunos_nosys
.word sys_sync, sys_kill, sys32_newstat
.word sunos_nosys, sys32_newlstat, sys_dup
- .word sys_pipe, sunos_nosys, sys_profil
+ .word sys_pipe, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sunos_getgid
.word sunos_nosys, sunos_nosys
-/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys
- .word sunos_mctl, sunos_ioctl, sys32_reboot
- .word sunos_nosys, sys32_symlink, sys32_readlink
- .word sys32_execve, sys_umask, sys32_chroot
+/*50*/ .word sunos_nosys, sys_acct, sunos_nosys
+ .word sunos_mctl, sunos_ioctl, sys_reboot
+ .word sunos_nosys, sys_symlink, sys_readlink
+ .word sys32_execve, sys_umask, sys_chroot
.word sys32_newfstat, sunos_nosys, sys_getpagesize
- .word sys32_msync, sys_vfork, sunos_nosys
+ .word sys_msync, sys_vfork, sunos_nosys
.word sunos_nosys, sunos_sbrk, sunos_sstk
- .word sunos_mmap, sunos_vadvise, sys32_munmap
- .word sys32_mprotect, sunos_madvise, sys_vhangup
+ .word sunos_mmap, sunos_vadvise, sys_munmap
+ .word sys_mprotect, sunos_madvise, sys_vhangup
.word sunos_nosys, sunos_mincore, sys32_getgroups
.word sys32_setgroups, sys_getpgrp, sunos_setpgrp
- .word sys32_setitimer, sunos_nosys, sys32_swapon
- .word sys32_getitimer, sys32_gethostname, sys32_sethostname
+ .word sys32_setitimer, sunos_nosys, sys_swapon
+ .word sys32_getitimer, sys_gethostname, sys_sethostname
.word sunos_getdtablesize, sys_dup2, sunos_nop
.word sys32_fcntl, sunos_select, sunos_nop
.word sys_fsync, sys_setpriority, sys_socket
- .word sys32_connect, sunos_accept
+ .word sys_connect, sunos_accept
/*100*/ .word sys_getpriority, sunos_send, sunos_recv
- .word sunos_nosys, sys32_bind, sunos_setsockopt
+ .word sunos_nosys, sys_bind, sunos_setsockopt
.word sys_listen, sunos_nosys, sunos_sigaction
.word sunos_sigblock, sunos_sigsetmask, sys_sigpause
.word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
@@ -177,21 +177,21 @@ sunos_sys_table:
.word sunos_getsockopt, sunos_nosys, sunos_readv
.word sunos_writev, sys32_settimeofday, sys_fchown
.word sys_fchmod, sys32_recvfrom, sys32_setreuid
- .word sys_setregid, sys32_rename, sys32_truncate
- .word sys32_ftruncate, sys_flock, sunos_nosys
+ .word sys_setregid, sys_rename, sys_truncate
+ .word sys_ftruncate, sys_flock, sunos_nosys
.word sys32_sendto, sys_shutdown, sys_socketpair
- .word sys32_mkdir, sys32_rmdir, sys32_utimes
- .word sys_sigreturn, sunos_nosys, sys32_getpeername
+ .word sys_mkdir, sys_rmdir, sys32_utimes
+ .word sys32_sigreturn, sunos_nosys, sys_getpeername
.word sunos_gethostid, sunos_nosys, sys32_getrlimit
.word sys32_setrlimit, sunos_killpg, sunos_nosys
.word sunos_nosys, sunos_nosys
-/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys
- .word sys32_poll, sunos_nosys, sunos_nosys
+/*150*/ .word sys_getsockname, sunos_nosys, sunos_nosys
+ .word sys_poll, sunos_nosys, sunos_nosys
.word sunos_getdirentries, sys32_statfs, sys32_fstatfs
- .word sys32_umount, sunos_nosys, sunos_nosys
- .word sunos_getdomainname, sys32_setdomainname
+ .word sys_umount, sunos_nosys, sunos_nosys
+ .word sunos_getdomainname, sys_setdomainname
.word sunos_nosys, sys32_quotactl, sunos_nosys
- .word sunos_mount, sys32_ustat, sunos_semsys
+ .word sunos_mount, sys_ustat, sunos_semsys
.word sunos_nosys, sunos_shmsys, sunos_audit
.word sunos_nosys, sunos_getdents, sys_setsid
.word sys_fchdir, sunos_nosys, sunos_nosys
@@ -221,4 +221,3 @@ sunos_sys_table:
.word sunos_nosys, sunos_nosys
/*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sys_aplib
- .word sunos_nosys
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 1ffd43730..cde799d92 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $
+/* $Id: traps.c,v 1.44 1998/01/09 16:39:35 jj Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -26,9 +26,13 @@
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
/* #define SYSCALL_TRACING */
/* #define VERBOSE_SYSCALL_TRACING */
+/* #define DEBUG_FPU */
#ifdef SYSCALL_TRACING
#ifdef VERBOSE_SYSCALL_TRACING
@@ -125,8 +129,9 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
int i;
#endif
- if(strcmp(current->comm, "bash.sunos"))
- return;
+#if 0
+ if (!current->pid) return;
+#endif
printk("SYS[%s:%d]: PC(%016lx) <%3d> ",
current->comm, current->pid, regs->tpc, (int)g1);
#ifdef VERBOSE_SYSCALL_TRACING
@@ -141,12 +146,20 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
for(i = 0; i < sdp->num_args; i++) {
if(i)
printk(",");
- if(!sdp->arg_is_string[i])
- printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]);
- else {
- strncpy_from_user(scall_strbuf,
- (char *)regs->u_regs[UREG_I0 + i],
- 512);
+ if(!sdp->arg_is_string[i]) {
+ if (current->tss.flags & SPARC_FLAG_32BIT)
+ printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]);
+ else
+ printk("%016lx", regs->u_regs[UREG_I0 + i]);
+ } else {
+ if (current->tss.flags & SPARC_FLAG_32BIT)
+ strncpy_from_user(scall_strbuf,
+ (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff),
+ 512);
+ else
+ strncpy_from_user(scall_strbuf,
+ (char *)regs->u_regs[UREG_I0 + i],
+ 512);
printk("%s", scall_strbuf);
}
}
@@ -157,7 +170,9 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
{
- if(!strcmp(current->comm, "bash.sunos"))
+#if 0
+ if (current->pid)
+#endif
printk("ret[%016lx]\n", retval);
return retval;
}
@@ -192,6 +207,24 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl)
void data_access_exception (struct pt_regs *regs)
{
+ if (regs->tstate & TSTATE_PRIV) {
+ /* Test if this comes from uaccess places. */
+ unsigned long fixup, g2;
+
+ g2 = regs->u_regs[UREG_G2];
+ if ((fixup = search_exception_table (regs->tpc, &g2))) {
+ /* Ouch, somebody is trying ugly VM hole tricks on us... */
+#ifdef DEBUG_EXCEPTIONS
+ printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);
+ printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
+ "g2<%016lx>\n", regs->tpc, fixup, g2);
+#endif
+ regs->tpc = fixup;
+ regs->tnpc = regs->tpc + 4;
+ regs->u_regs[UREG_G2] = g2;
+ return;
+ }
+ }
send_sig(SIGSEGV, current, 1);
}
@@ -271,11 +304,46 @@ void do_fpe_common(struct pt_regs *regs)
void do_fpieee(struct pt_regs *regs)
{
+#ifdef DEBUG_FPU
+ struct fpustate *f = FPUSTATE;
+
+ printk("fpieee %016lx\n", f->fsr);
+#endif
do_fpe_common(regs);
}
+#ifdef CONFIG_MATHEMU_MODULE
+volatile int (*handle_mathemu)(struct pt_regs *, struct fpustate *) = NULL;
+#else
+extern int do_mathemu(struct pt_regs *, struct fpustate *);
+#endif
+
void do_fpother(struct pt_regs *regs)
{
+ struct fpustate *f = FPUSTATE;
+ int ret = 0;
+
+ switch ((f->fsr & 0x1c000)) {
+ case (2 << 14): /* unfinished_FPop */
+ case (3 << 14): /* unimplemented_FPop */
+#ifdef CONFIG_MATHEMU_MODULE
+#ifdef CONFIG_KERNELD
+ if (!handle_mathemu)
+ request_module("math-emu");
+#endif
+ if (handle_mathemu)
+ ret = handle_mathemu(regs, f);
+#else
+#ifdef CONFIG_MATHEMU
+ ret = do_mathemu(regs, f);
+#endif
+#endif
+ break;
+ }
+ if (ret) return;
+#ifdef DEBUG_FPU
+ printk("fpother %016lx\n", f->fsr);
+#endif
do_fpe_common(regs);
}
@@ -298,7 +366,7 @@ void instruction_dump (unsigned int *pc)
int i;
if((((unsigned long) pc) & 3))
- return;
+ return;
for(i = -3; i < 6; i++)
printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
@@ -332,33 +400,51 @@ void die_if_kernel(char *str, struct pt_regs *regs)
(rw->ins[6] + STACK_BIAS);
}
}
- printk("Instruction DUMP:");
- instruction_dump ((unsigned int *) regs->tpc);
+ if(regs->tstate & TSTATE_PRIV) {
+ printk("Instruction DUMP:");
+ instruction_dump ((unsigned int *) regs->tpc);
+ }
lock_kernel(); /* Or else! */
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
do_exit(SIGSEGV);
}
+extern int handle_popc(u32 insn, struct pt_regs *regs);
+extern int handle_ldq_stq(u32 insn, struct pt_regs *regs);
+
void do_illegal_instruction(struct pt_regs *regs)
{
unsigned long pc = regs->tpc;
unsigned long tstate = regs->tstate;
+ u32 insn;
if(tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs);
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ pc = (u32)pc;
+ if (get_user(insn, (u32 *)pc) != -EFAULT) {
+ if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
+ if (handle_popc(insn, regs))
+ return;
+ } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ {
+ if (handle_ldq_stq(insn, regs))
+ return;
+ }
+ }
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
}
-void mem_address_unaligned(struct pt_regs *regs)
+void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
{
if(regs->tstate & TSTATE_PRIV) {
extern void kernel_unaligned_trap(struct pt_regs *regs,
- unsigned int insn);
+ unsigned int insn,
+ unsigned long sfar, unsigned long sfsr);
- return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
+ return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr);
} else {
current->tss.sig_address = regs->tpc;
current->tss.sig_desc = SUBSIG_PRIVINST;
@@ -390,22 +476,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
send_sig(SIGILL, current, 1);
}
-/* XXX User may want to be allowed to do this. XXX */
-
-void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
- unsigned long tstate)
-{
- if(regs->tstate & TSTATE_PRIV) {
- printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
- regs->u_regs[UREG_RETPC]);
- die_if_kernel("BOGUS", regs);
- /* die_if_kernel("Kernel MNA access", regs); */
- }
- current->tss.sig_address = pc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
- send_sig(SIGBUS, current, 1);
-}
-
void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
@@ -463,21 +533,11 @@ void do_irq_tl1(struct pt_regs *regs)
die_if_kernel("TL1: IRQ Exception", regs);
}
-void do_lddfmna(struct pt_regs *regs)
-{
- die_if_kernel("TL0: LDDF Exception", regs);
-}
-
void do_lddfmna_tl1(struct pt_regs *regs)
{
die_if_kernel("TL1: LDDF Exception", regs);
}
-void do_stdfmna(struct pt_regs *regs)
-{
- die_if_kernel("TL0: STDF Exception", regs);
-}
-
void do_stdfmna_tl1(struct pt_regs *regs)
{
die_if_kernel("TL1: STDF Exception", regs);
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index bf00cb231..b22cf82f7 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.20 1997/08/29 15:51:39 jj Exp $
+/* $Id: ttable.S,v 1.22 1997/10/16 07:07:46 jj Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -33,8 +33,8 @@ tl0_resv031: BTRAP(0x31)
tl0_dae: TRAP(do_dae)
tl0_resv033: BTRAP(0x33)
tl0_mna: TRAP_NOSAVE(do_mna)
-tl0_lddfmna: TRAP(do_lddfmna)
-tl0_stdfmna: TRAP(do_stdfmna)
+tl0_lddfmna: TRAP_NOSAVE(do_lddfmna)
+tl0_stdfmna: TRAP_NOSAVE(do_stdfmna)
tl0_privact: TRAP(do_privact)
tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
@@ -106,10 +106,14 @@ tl0_netbsd: NETBSD_SYSCALL_TRAP
tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e)
tl0_resv10f: BTRAP(0x10f)
tl0_linux32: LINUX_32BIT_SYSCALL_TRAP
-tl0_linux64: LINUX_64BIT_SYSCALL_TRAP
-tl0_resv112: BTRAP(0x112) BTRAP(0x113) BTRAP(0x114) BTRAP(0x115) BTRAP(0x116)
-tl0_resv117: BTRAP(0x117) BTRAP(0x118) BTRAP(0x119) BTRAP(0x11a) BTRAP(0x11b)
-tl0_resv11c: BTRAP(0x11c) BTRAP(0x11d) BTRAP(0x11e) BTRAP(0x11f)
+tl0_oldlinux64: LINUX_64BIT_SYSCALL_TRAP
+tl0_resv112: TRAP_UTRAP(UT_TRAP_INSTRUCTION_18,0x112) TRAP_UTRAP(UT_TRAP_INSTRUCTION_19,0x113)
+tl0_resv114: TRAP_UTRAP(UT_TRAP_INSTRUCTION_20,0x114) TRAP_UTRAP(UT_TRAP_INSTRUCTION_21,0x115)
+tl0_resv116: TRAP_UTRAP(UT_TRAP_INSTRUCTION_22,0x116) TRAP_UTRAP(UT_TRAP_INSTRUCTION_23,0x117)
+tl0_resv118: TRAP_UTRAP(UT_TRAP_INSTRUCTION_24,0x118) TRAP_UTRAP(UT_TRAP_INSTRUCTION_25,0x119)
+tl0_resv11a: TRAP_UTRAP(UT_TRAP_INSTRUCTION_26,0x11a) TRAP_UTRAP(UT_TRAP_INSTRUCTION_27,0x11b)
+tl0_resv11c: TRAP_UTRAP(UT_TRAP_INSTRUCTION_28,0x11c) TRAP_UTRAP(UT_TRAP_INSTRUCTION_29,0x11d)
+tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f)
tl0_getcc: GETCC_TRAP
tl0_setcc: SETCC_TRAP
tl0_resv122: BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126)
@@ -127,7 +131,8 @@ tl0_resv155: BTRAP(0x155) BTRAP(0x156) BTRAP(0x157) BTRAP(0x158) BTRAP(0x159)
tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e)
tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163)
tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168)
-tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) BTRAP(0x16d)
+tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c)
+tl0_linux64: LINUX_64BIT_SYSCALL_TRAP
tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context)
tl0_resv170: BTRAP(0x170) BTRAP(0x171)
#ifdef CONFIG_EC_FLUSH_TRAP
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 3aea13953..1c433d793 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.4 1997/08/19 15:25:11 jj Exp $
+/* $Id: unaligned.c,v 1.8 1997/10/14 16:21:24 jj Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -17,6 +17,8 @@
#include <asm/uaccess.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <asm/fpumacro.h>
+#include <asm/bitops.h>
/* #define DEBUG_MNA */
@@ -24,8 +26,8 @@ enum direction {
load, /* ld, ldd, ldh, ldsh */
store, /* st, std, sth, stsh */
both, /* Swap, ldstub, cas, ... */
- fpload,
- fpstore,
+ fpld,
+ fpst,
invalid,
};
@@ -101,34 +103,52 @@ static inline long sign_extend_imm13(long imm)
return imm << 51 >> 51;
}
-static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
+static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
{
- struct reg_window *win;
-
+ unsigned long value;
+
if(reg < 16)
return (!reg ? 0 : regs->u_regs[reg]);
-
- /* Ho hum, the slightly complicated case. */
- win = (struct reg_window *) regs->u_regs[UREG_FP];
- return win->locals[reg - 16]; /* yes, I know what this does... */
+ if (regs->tstate & TSTATE_PRIV) {
+ struct reg_window *win;
+ win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+ value = win->locals[reg - 16];
+ } else if (current->tss.flags & SPARC_FLAG_32BIT) {
+ struct reg_window32 *win32;
+ win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+ get_user(value, &win32->locals[reg - 16]);
+ } else {
+ struct reg_window *win;
+ win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+ get_user(value, &win->locals[reg - 16]);
+ }
+ return value;
}
-static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
+static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
{
- struct reg_window *win;
-
if(reg < 16)
return &regs->u_regs[reg];
- win = (struct reg_window *) regs->u_regs[UREG_FP];
- return &win->locals[reg - 16];
+ if (regs->tstate & TSTATE_PRIV) {
+ struct reg_window *win;
+ win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+ return &win->locals[reg - 16];
+ } else if (current->tss.flags & SPARC_FLAG_32BIT) {
+ struct reg_window32 *win32;
+ win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+ return (unsigned long *)&win32->locals[reg - 16];
+ } else {
+ struct reg_window *win;
+ win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+ return &win->locals[reg - 16];
+ }
}
static inline unsigned long compute_effective_address(struct pt_regs *regs,
- unsigned int insn)
+ unsigned int insn, unsigned int rd)
{
unsigned int rs1 = (insn >> 14) & 0x1f;
unsigned int rs2 = insn & 0x1f;
- unsigned int rd = (insn >> 25) & 0x1f;
if(insn & 0x2000) {
maybe_flush_windows(rs1, 0, rd);
@@ -326,7 +346,7 @@ void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
unsigned long fixup = search_exception_table (regs->tpc, &g2);
if (!fixup) {
- unsigned long address = compute_effective_address(regs, insn);
+ unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f));
if(address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
} else
@@ -344,7 +364,7 @@ void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
regs->u_regs [UREG_G2] = g2;
}
-asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr)
{
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
@@ -365,7 +385,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
"g1", "g2", "g3", "g4", "g5", "g7", "cc");
} else {
- unsigned long addr = compute_effective_address(regs, insn);
+ unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f));
#ifdef DEBUG_MNA
printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n",
@@ -401,117 +421,243 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
unlock_kernel();
}
-#if 0 /* XXX: Implement user mna some day */
-static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
- enum direction dir)
-{
- unsigned int reg;
- int retval, check = (dir == load) ? VERIFY_READ : VERIFY_WRITE;
- int size = ((insn >> 19) & 3) == 3 ? 8 : 4;
-
- if((regs->pc | regs->npc) & 3)
- return 0;
+static char popc_helper[] = {
+0, 1, 1, 2, 1, 2, 2, 3,
+1, 2, 2, 3, 2, 3, 3, 4,
+};
- /* Must verify_area() in all the necessary places. */
-#define WINREG_ADDR(regnum) ((void *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))
- retval = 0;
- reg = (insn >> 25) & 0x1f;
- if(reg >= 16) {
- retval = verify_area(check, WINREG_ADDR(reg - 16), size);
- if(retval)
- return retval;
+int handle_popc(u32 insn, struct pt_regs *regs)
+{
+ u64 value;
+ int ret, i, rd = ((insn >> 25) & 0x1f);
+
+ if (insn & 0x2000) {
+ maybe_flush_windows(0, 0, rd);
+ value = sign_extend_imm13(insn);
+ } else {
+ maybe_flush_windows(0, insn & 0x1f, rd);
+ value = fetch_reg(insn & 0x1f, regs);
}
- reg = (insn >> 14) & 0x1f;
- if(reg >= 16) {
- retval = verify_area(check, WINREG_ADDR(reg - 16), size);
- if(retval)
- return retval;
+ for (ret = 0, i = 0; i < 16; i++) {
+ ret += popc_helper[value & 0xf];
+ value >>= 4;
}
- if(!(insn & 0x2000)) {
- reg = (insn & 0x1f);
- if(reg >= 16) {
- retval = verify_area(check, WINREG_ADDR(reg - 16), size);
- if(retval)
- return retval;
+ if(rd < 16) {
+ if (rd)
+ regs->u_regs[rd] = ret;
+ } else {
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ struct reg_window32 *win32;
+ win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+ put_user(ret, &win32->locals[rd - 16]);
+ } else {
+ struct reg_window *win;
+ win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+ get_user(ret, &win->locals[rd - 16]);
}
}
- return retval;
-#undef WINREG_ADDR
+ advance(regs);
+ return 1;
}
-void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault");
+extern void do_fpother(struct pt_regs *regs);
+extern void do_privact(struct pt_regs *regs);
+extern void data_access_exception(struct pt_regs *regs);
-void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
+int handle_ldq_stq(u32 insn, struct pt_regs *regs)
{
- current->tss.sig_address = regs->pc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
- send_sig(SIGBUS, current, 1);
+ unsigned long addr = compute_effective_address(regs, insn, 0);
+ int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
+ struct fpustate *f = FPUSTATE;
+ int asi = decode_asi(insn, regs);
+ int flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
+
+ f->fsr &= ~0x1c000;
+ if (freg & 3) {
+ f->fsr |= (6 << 14) /* invalid_fp_register */;
+ do_fpother(regs);
+ return 0;
+ }
+ if (insn & 0x200000) {
+ /* STQ */
+ u64 first = 0, second = 0;
+
+ if (current->tss.flags & flag) {
+ first = *(u64 *)&f->regs[freg];
+ second = *(u64 *)&f->regs[freg+2];
+ }
+ if (asi < 0x80) {
+ do_privact(regs);
+ return 1;
+ }
+ switch (asi) {
+ case ASI_P:
+ case ASI_S: break;
+ case ASI_PL:
+ case ASI_SL:
+ {
+ /* Need to convert endians */
+ u64 tmp = __swab64p(&first);
+
+ first = __swab64p(&second);
+ second = tmp;
+ break;
+ }
+ default:
+ data_access_exception(regs);
+ return 1;
+ }
+ if (put_user (first >> 32, (u32 *)addr) ||
+ __put_user ((u32)first, (u32 *)(addr + 4)) ||
+ __put_user (second >> 32, (u32 *)(addr + 8)) ||
+ __put_user ((u32)second, (u32 *)(addr + 12))) {
+ data_access_exception(regs);
+ return 1;
+ }
+ } else {
+ /* LDQ */
+ u32 first, second, third, fourth;
+
+ if (asi < 0x80) {
+ do_privact(regs);
+ return 1;
+ } else if (asi > ASI_SNFL) {
+ data_access_exception(regs);
+ return 1;
+ }
+ if (get_user (first, (u32 *)addr) ||
+ __get_user (second, (u32 *)(addr + 4)) ||
+ __get_user (third, (u32 *)(addr + 8)) ||
+ __get_user (fourth, (u32 *)(addr + 12))) {
+ if (asi & 0x2) /* NF */ {
+ first = 0; second = 0; third = 0; fourth = 0;
+ } else {
+ data_access_exception(regs);
+ return 1;
+ }
+ }
+ if (asi & 0x8) /* Little */ {
+ u32 tmp = le32_to_cpup(&first);
+
+ first = le32_to_cpup(&fourth);
+ fourth = tmp;
+ tmp = le32_to_cpup(&second);
+ second = le32_to_cpup(&third);
+ third = tmp;
+ }
+ regs->fprs |= FPRS_FEF;
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) {
+ current->tss.flags |= SPARC_FLAG_USEDFPU;
+ f->fsr = 0;
+ f->gsr = 0;
+ }
+ if (!(current->tss.flags & flag)) {
+ if (freg < 32)
+ memset(f->regs, 0, 32*sizeof(u32));
+ else
+ memset(f->regs+32, 0, 32*sizeof(u32));
+ }
+ f->regs[freg] = first;
+ f->regs[freg+1] = second;
+ f->regs[freg+2] = third;
+ f->regs[freg+3] = fourth;
+ current->tss.flags |= flag;
+ }
+ advance(regs);
+ return 1;
}
-asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
{
- enum direction dir;
-
- lock_kernel();
- if(!(current->tss.flags & SPARC_FLAG_UNALIGNED) ||
- (((insn >> 30) & 3) != 3))
- goto kill_user;
- dir = decode_direction(insn);
- if(!ok_for_user(regs, insn, dir)) {
- goto kill_user;
- } else {
- int size = decode_access_size(insn);
- unsigned long addr;
-
- if(floating_point_load_or_store_p(insn)) {
- printk("User FPU load/store unaligned unsupported.\n");
- goto kill_user;
+ unsigned long pc = regs->tpc;
+ unsigned long tstate = regs->tstate;
+ u32 insn;
+ u32 first, second;
+ u64 value;
+ u8 asi, freg;
+ int flag;
+ struct fpustate *f = FPUSTATE;
+
+ if(tstate & TSTATE_PRIV)
+ die_if_kernel("lddfmna from kernel", regs);
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ pc = (u32)pc;
+ if (get_user(insn, (u32 *)pc) != -EFAULT) {
+ asi = sfsr >> 16;
+ if (asi > ASI_SNFL)
+ goto daex;
+ if (get_user(first, (u32 *)sfar) ||
+ get_user(second, (u32 *)(sfar + 4))) {
+ if (asi & 0x2) /* NF */ {
+ first = 0; second = 0;
+ } else
+ goto daex;
}
-
- addr = compute_effective_address(regs, insn);
- switch(dir) {
- case load:
- do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
- size, (unsigned long *) addr,
- decode_signedness(insn),
- user_unaligned_trap_fault);
- break;
-
- case store:
- do_integer_store(((insn>>25)&0x1f), size,
- (unsigned long *) addr, regs,
- user_unaligned_trap_fault);
- break;
-
- case both:
- do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
- (unsigned long *) addr,
- user_unaligned_trap_fault);
- break;
-
- default:
- unaligned_panic("Impossible user unaligned trap.");
-
- __asm__ __volatile__ ("\n"
-"user_unaligned_trap_fault:\n\t"
- "mov %0, %%o0\n\t"
- "call user_mna_trap_fault\n\t"
- " mov %1, %%o1\n\t"
- :
- : "r" (regs), "r" (insn)
- : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
- "g1", "g2", "g3", "g4", "g5", "g7", "cc");
- goto out;
+ freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
+ value = (((u64)first) << 32) | second;
+ if (asi & 0x8) /* Little */
+ value = __swab64p(&value);
+ flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
+ regs->fprs |= FPRS_FEF;
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) {
+ current->tss.flags |= SPARC_FLAG_USEDFPU;
+ f->fsr = 0;
+ f->gsr = 0;
}
- advance(regs);
- goto out;
+ if (!(current->tss.flags & flag)) {
+ if (freg < 32)
+ memset(f->regs, 0, 32*sizeof(u32));
+ else
+ memset(f->regs+32, 0, 32*sizeof(u32));
+ }
+ *(u64 *)(f->regs + freg) = value;
+ current->tss.flags |= flag;
+ } else {
+daex: data_access_exception(regs);
+ return;
}
+ advance(regs);
+ return;
+}
-kill_user:
- current->tss.sig_address = regs->pc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
- send_sig(SIGBUS, current, 1);
-out:
- unlock_kernel();
+void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
+{
+ unsigned long pc = regs->tpc;
+ unsigned long tstate = regs->tstate;
+ u32 insn;
+ u64 value;
+ u8 asi, freg;
+ int flag;
+ struct fpustate *f = FPUSTATE;
+
+ if(tstate & TSTATE_PRIV)
+ die_if_kernel("stdfmna from kernel", regs);
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ pc = (u32)pc;
+ if (get_user(insn, (u32 *)pc) != -EFAULT) {
+ freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
+ asi = sfsr >> 16;
+ value = 0;
+ flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU;
+ if (asi > ASI_SNFL)
+ goto daex;
+ if (current->tss.flags & flag)
+ value = *(u64 *)&f->regs[freg];
+ switch (asi) {
+ case ASI_P:
+ case ASI_S: break;
+ case ASI_PL:
+ case ASI_SL:
+ value = __swab64p(&value); break;
+ default: goto daex;
+ }
+ if (put_user (value >> 32, (u32 *)sfar) ||
+ __put_user ((u32)value, (u32 *)(sfar + 4)))
+ goto daex;
+ } else {
+daex: data_access_exception(regs);
+ return;
+ }
+ advance(regs);
+ return;
}
-#endif
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index 0ebf92767..6e3f6193a 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $
+/* $Id: winfixup.S,v 1.22 1997/10/24 11:57:48 jj Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -48,6 +48,10 @@ fill_fixup:
* most things are where they need to be, we also have the address
* which triggered the fault handy as well.
*
+ * Also note that we must preserve %l5 and %l6. If the user was
+ * returning from a system call, we must make it look this way
+ * after we process the fill fault on the users stack.
+ *
* First, get into the window where the original restore was executed.
*/
@@ -65,15 +69,23 @@ fill_fixup:
rdpr %pstate, %l1 ! Prepare to change globals.
mov %g6, %o7 ! Get current.
- mov %g5, %l5 ! Fault address
- clr %l4 ! It was a load, not a store
+ andn %l1, PSTATE_MM, %l1 ! We want to be in RMO
+ srlx %g5, PAGE_SHIFT, %o1 ! Fault address
wrpr %g0, 0x0, %tl ! Out of trap levels.
wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
sethi %uhi(PAGE_OFFSET), %g4 ! Prepare page_offset global reg
mov %o7, %g6
- b,pt %xcc, window_scheisse_merge ! And merge.
+ sllx %g4, 32, %g4 ! and finish it...
+ clr %o2
- sllx %g4, 32, %g4 ! and finish it...
+ /* This is the same as below, except we handle this a bit special
+ * since we must preserve %l5 and %l6, see comment above.
+ */
+ sllx %o1, PAGE_SHIFT, %o1
+ call do_sparc64_fault
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ b,pt %xcc, rtrap
+ nop ! yes, nop is correct
/* Be very careful about usage of the alternate globals here.
* You cannot touch %g4/%g5 as that has the fault information
@@ -84,59 +96,59 @@ fill_fixup:
* do not touch %g7 or %g2 so we handle the two cases fine.
*/
spill_fixup:
- ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
andcc %g1, SPARC_FLAG_32BIT, %g0
- ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+
sll %g1, 3, %g3
add %g6, %g3, %g3
stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
sll %g1, 7, %g3
-
bne,pt %xcc, 1f
add %g6, %g3, %g3
stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+
stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-
stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+
stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
-
stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
b,pt %xcc, 2f
stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
1: stw %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+
stw %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04]
stw %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
stw %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c]
stw %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-
stw %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14]
stw %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
stw %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c]
stw %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+
stw %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24]
stw %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
stw %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c]
stw %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-
stw %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34]
stw %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
stw %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c]
2: add %g1, 1, %g1
- stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+
+ sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
rdpr %tstate, %g1
andcc %g1, TSTATE_PRIV, %g0
saved
-
and %g1, TSTATE_CWP, %g1
be,a,pn %xcc, window_scheisse_from_user_common
or %g4, 0x4, %g4 ! we know it was a write
@@ -146,7 +158,6 @@ window_scheisse_from_user_common:
sethi %hi(109f), %g7
ba,pt %xcc, etrap
109: or %g7, %lo(109b), %g7
-window_scheisse_merge:
srlx %l5, PAGE_SHIFT, %o1
and %l4, 0x4, %o2
@@ -173,10 +184,15 @@ fill_fixup_mna:
andcc %g1, TSTATE_PRIV, %g0
be,pt %xcc, window_mna_from_user_common
and %g1, TSTATE_CWP, %g1
+
+ /* Please, see fill_fixup commentary about why we must preserve
+ * %l5 and %l6 to preserve absolute correct semantics.
+ */
rdpr %wstate, %g2 ! Grab user mode wstate.
wrpr %g1, %cwp ! Get into the right window.
sll %g2, 3, %g2 ! NORMAL-->OTHER
wrpr %g0, 0x0, %canrestore ! Standard etrap stuff.
+
wrpr %g2, 0x0, %wstate ! This must be consistant.
wrpr %g0, 0x0, %otherwin ! We know this.
mov PRIMARY_CONTEXT, %g1 ! Change contexts...
@@ -185,23 +201,28 @@ fill_fixup_mna:
rdpr %pstate, %l1 ! Prepare to change globals.
mov %g4, %o5 ! Setup args for
mov %g5, %o4 ! final call to do_sparc64_fault.
+ andn %l1, PSTATE_MM, %l1 ! We want to be in RMO
+
mov %g6, %o7 ! Stash away current.
wrpr %g0, 0x0, %tl ! Out of trap levels.
wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg.
mov %o7, %g6 ! Get current back.
- b,pt %xcc, window_mna_merge ! And merge.
- sllx %g4, 32, %g4 ! Finish it.
+ sllx %g4, 32, %g4 ! Finish it.
+ call mem_address_unaligned
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ b,pt %xcc, rtrap
+ nop ! yes, the nop is correct
spill_fixup_mna:
- ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
andcc %g1, SPARC_FLAG_32BIT, %g0
- ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
sll %g1, 3, %g3
add %g6, %g3, %g3
stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
- sll %g1, 7, %g3
+ sll %g1, 7, %g3
bne,pt %xcc, 1f
add %g6, %g3, %g3
stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
@@ -209,8 +230,8 @@ spill_fixup_mna:
stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
- stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+ stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
@@ -218,8 +239,8 @@ spill_fixup_mna:
stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
- stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+ stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
b,pt %xcc, 2f
@@ -227,16 +248,15 @@ spill_fixup_mna:
1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+ std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
add %g1, 1, %g1
-2: stx %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
rdpr %tstate, %g1
- nop
andcc %g1, TSTATE_PRIV, %g0
saved
@@ -248,7 +268,6 @@ window_mna_from_user_common:
sethi %hi(109f), %g7
ba,pt %xcc, etrap
109: or %g7, %lo(109b), %g7
-window_mna_merge:
call mem_address_unaligned
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap