Commit a0adf3b1 authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/sparc-2.6

into kernel.bkbits.net:/home/davem/sparc-2.6
parents 6ce8ea8a 39e8d677
...@@ -74,7 +74,7 @@ sys_call_table: ...@@ -74,7 +74,7 @@ sys_call_table:
/*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
/*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink
/*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid
/*280*/ .long sys_ni_syscall, sys_ni_syscall, sys_ni_syscall /*280*/ .long sys_ni_syscall, sys_ni_syscall, sys_ni_syscall
#ifdef CONFIG_SUNOS_EMUL #ifdef CONFIG_SUNOS_EMUL
......
...@@ -11,6 +11,16 @@ config DEBUG_STACK_USAGE ...@@ -11,6 +11,16 @@ config DEBUG_STACK_USAGE
This option will slow down process creation somewhat. This option will slow down process creation somewhat.
config KPROBES
bool "Kprobes"
depends on DEBUG_KERNEL
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
config DEBUG_DCFLUSH config DEBUG_DCFLUSH
bool "D-cache flush debugging" bool "D-cache flush debugging"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
......
# #
# Automatically generated make config: don't edit # Automatically generated make config: don't edit
# Linux kernel version: 2.6.9-rc1 # Linux kernel version: 2.6.9-rc1
# Fri Aug 27 17:37:00 2004 # Wed Sep 1 17:54:49 2004
# #
CONFIG_64BIT=y CONFIG_64BIT=y
CONFIG_MMU=y CONFIG_MMU=y
...@@ -35,6 +35,8 @@ CONFIG_IOSCHED_AS=y ...@@ -35,6 +35,8 @@ CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y CONFIG_IOSCHED_CFQ=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
# CONFIG_TINY_SHMEM is not set
# #
# Loadable module support # Loadable module support
...@@ -332,7 +334,8 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000 ...@@ -332,7 +334,8 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000
# CONFIG_AIC79XX_DEBUG_ENABLE is not set # CONFIG_AIC79XX_DEBUG_ENABLE is not set
CONFIG_AIC79XX_DEBUG_MASK=0 CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
# CONFIG_SCSI_MEGARAID is not set # CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA=y
CONFIG_SCSI_SATA_SVW=m CONFIG_SCSI_SATA_SVW=m
CONFIG_SCSI_ATA_PIIX=m CONFIG_SCSI_ATA_PIIX=m
...@@ -357,9 +360,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 ...@@ -357,9 +360,7 @@ CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
CONFIG_SCSI_IPR=m # CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_IPR_TRACE is not set
# CONFIG_SCSI_IPR_DUMP is not set
CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_ISP=m
CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC=y
CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y
...@@ -417,7 +418,6 @@ CONFIG_DM_ZERO=m ...@@ -417,7 +418,6 @@ CONFIG_DM_ZERO=m
# #
CONFIG_FUSION=m CONFIG_FUSION=m
CONFIG_FUSION_MAX_SGE=40 CONFIG_FUSION_MAX_SGE=40
CONFIG_FUSION_ISENSE=m
CONFIG_FUSION_CTL=m CONFIG_FUSION_CTL=m
CONFIG_FUSION_LAN=m CONFIG_FUSION_LAN=m
...@@ -1757,6 +1757,7 @@ CONFIG_MAGIC_SYSRQ=y ...@@ -1757,6 +1757,7 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_DEBUG_STACK_USAGE is not set
CONFIG_KPROBES=y
# CONFIG_DEBUG_DCFLUSH is not set # CONFIG_DEBUG_DCFLUSH is not set
# CONFIG_STACK_DEBUG is not set # CONFIG_STACK_DEBUG is not set
# CONFIG_DEBUG_BOOTMEM is not set # CONFIG_DEBUG_BOOTMEM is not set
......
...@@ -22,6 +22,7 @@ obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o ...@@ -22,6 +22,7 @@ obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
obj-$(CONFIG_KPROBES) += kprobes.o
ifdef CONFIG_SUNOS_EMUL ifdef CONFIG_SUNOS_EMUL
obj-y += sys_sunos32.o sunos_ioctl32.o obj-y += sys_sunos32.o sunos_ioctl32.o
......
...@@ -791,16 +791,24 @@ void handler_irq(int irq, struct pt_regs *regs) ...@@ -791,16 +791,24 @@ void handler_irq(int irq, struct pt_regs *regs)
#endif #endif
if ((flags & IBF_MULTI) == 0) { if ((flags & IBF_MULTI) == 0) {
struct irqaction *ap = bp->irq_info; struct irqaction *ap = bp->irq_info;
ap->handler(__irq(bp), ap->dev_id, regs); int ret;
random |= ap->flags & SA_SAMPLE_RANDOM;
ret = ap->handler(__irq(bp), ap->dev_id, regs);
if (ret == IRQ_HANDLED)
random |= ap->flags;
} else { } else {
void **vector = (void **)bp->irq_info; void **vector = (void **)bp->irq_info;
int ent; int ent;
for (ent = 0; ent < 4; ent++) { for (ent = 0; ent < 4; ent++) {
struct irqaction *ap = vector[ent]; struct irqaction *ap = vector[ent];
if (ap != NULL) { if (ap != NULL) {
ap->handler(__irq(bp), ap->dev_id, regs); int ret;
random |= ap->flags & SA_SAMPLE_RANDOM;
ret = ap->handler(__irq(bp),
ap->dev_id,
regs);
if (ret == IRQ_HANDLED)
random |= ap->flags;
} }
} }
} }
...@@ -813,8 +821,9 @@ void handler_irq(int irq, struct pt_regs *regs) ...@@ -813,8 +821,9 @@ void handler_irq(int irq, struct pt_regs *regs)
} }
#endif #endif
upa_writel(ICLR_IDLE, bp->iclr); upa_writel(ICLR_IDLE, bp->iclr);
/* Test and add entropy */ /* Test and add entropy */
if (random) if (random & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq); add_interrupt_randomness(irq);
} }
} else } else
......
/* arch/sparc64/kernel/kprobes.c
*
* Copyright (C) 2004 David S. Miller <davem@davemloft.net>
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <asm/kdebug.h>
#include <asm/signal.h>
/* We do not have hardware single-stepping, so in order
* to implement post handlers correctly we use two breakpoint
* instructions.
*
* 1) ta 0x70 --> 0x91d02070
* 2) ta 0x71 --> 0x91d02071
*
* When these are hit, control is transferred to kprobe_trap()
* below. The arg 'level' tells us which of the two traps occurred.
*
* Initially, the instruction at p->addr gets set to "ta 0x70"
* by code in register_kprobe() by setting that memory address
* to BREAKPOINT_INSTRUCTION. When this breakpoint is hit
* the following happens:
*
* 1) We run the pre-handler
* 2) We replace p->addr with the original opcode
* 3) We set the instruction at "regs->npc" to "ta 0x71"
* 4) We mark that we are waiting for the second breakpoint
* to hit and return from the trap.
*
* At this point we wait for the second breakpoint to hit.
* When it does:
*
* 1) We run the post-handler
* 2) We re-install "ta 0x70" at p->addr
* 3) We restore the opcode at the "ta 0x71" breakpoint
* 4) We reset our "waiting for "ta 0x71" state
* 5) We return from the trap
*
* We could use the trick used by the i386 kprobe code but I
* think that scheme has problems with exception tables. On i386
* they single-step over the original instruction stored at
* kprobe->insn. So they set the processor to single step, and
* set the program counter to kprobe->insn.
*
* But that explodes if the original opcode is a user space
* access instruction and that faults. It will go wrong because
* since the location of the instruction being executed is
* different from that recorded in the exception tables, the
* kernel will not find it and this will cause an erroneous
* kernel OOPS.
*/
void arch_prepare_kprobe(struct kprobe *p)
{
p->insn[0] = *p->addr;
p->insn[1] = 0xdeadbeef;
}
static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
u32 *insn2 = (u32 *) regs->tpc;
p->insn[1] = *insn2;
*insn2 = BREAKPOINT_INSTRUCTION_2;
flushi(insn2);
}
static void undo_singlestep(struct kprobe *p, struct pt_regs *regs)
{
u32 *insn2 = (u32 *) regs->tpc;
BUG_ON(p->insn[1] == 0xdeadbeef);
*insn2 = p->insn[1];
flushi(insn2);
p->insn[1] = 0xdeadbeef;
}
/* kprobe_status settings */
#define KPROBE_HIT_ACTIVE 0x00000001
#define KPROBE_HIT_SS 0x00000002
static struct kprobe *current_kprobe;
static unsigned int kprobe_status;
static int kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
void *addr = (void *) regs->tpc;
int ret = 0;
preempt_disable();
if (kprobe_running()) {
p = get_kprobe(addr);
if (p) {
*p->addr = p->opcode;
flushi(p->addr);
ret = 1;
} else {
p = current_kprobe;
if (p->break_handler && p->break_handler(p, regs))
goto ss_probe;
}
goto no_kprobe;
}
lock_kprobes();
p = get_kprobe(addr);
if (!p) {
unlock_kprobes();
if (*(u32 *)addr != BREAKPOINT_INSTRUCTION)
ret = 1;
goto no_kprobe;
}
kprobe_status = KPROBE_HIT_ACTIVE;
current_kprobe = p;
if (p->pre_handler(p, regs))
return 1;
ss_probe:
prepare_singlestep(p, regs);
kprobe_status = KPROBE_HIT_SS;
return 1;
no_kprobe:
preempt_enable_no_resched();
return ret;
}
static int post_kprobe_handler(struct pt_regs *regs)
{
u32 *insn_p = (u32 *) regs->tpc;
if (!kprobe_running() || (*insn_p != BREAKPOINT_INSTRUCTION_2))
return 0;
if (current_kprobe->post_handler)
current_kprobe->post_handler(current_kprobe, regs, 0);
undo_singlestep(current_kprobe, regs);
unlock_kprobes();
preempt_enable_no_resched();
return 1;
}
/* Interrupts disabled, kprobe_lock held. */
static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
if (current_kprobe->fault_handler
&& current_kprobe->fault_handler(current_kprobe, regs, trapnr))
return 1;
if (kprobe_status & KPROBE_HIT_SS) {
undo_singlestep(current_kprobe, regs);
unlock_kprobes();
preempt_enable_no_resched();
}
return 0;
}
/*
* Wrapper routine to for handling exceptions.
*/
int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
void *data)
{
struct die_args *args = (struct die_args *)data;
switch (val) {
case DIE_DEBUG:
if (kprobe_handler(args->regs))
return NOTIFY_OK;
break;
case DIE_DEBUG_2:
if (post_kprobe_handler(args->regs))
return NOTIFY_OK;
break;
case DIE_GPF:
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
return NOTIFY_OK;
break;
case DIE_PAGE_FAULT:
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
return NOTIFY_OK;
break;
default:
break;
}
return NOTIFY_BAD;
}
asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
{
BUG_ON(trap_level != 0x170 && trap_level != 0x171);
if (user_mode(regs)) {
local_irq_enable();
bad_trap(regs, trap_level);
return;
}
/* trap_level == 0x170 --> ta 0x70
* trap_level == 0x171 --> ta 0x71
*/
if (notify_die((trap_level == 0x170) ? DIE_DEBUG : DIE_DEBUG_2,
(trap_level == 0x170) ? "debug" : "debug_2",
regs, 0, trap_level, SIGTRAP) != NOTIFY_OK)
bad_trap(regs, trap_level);
}
/* Jprobes support. */
static struct pt_regs jprobe_saved_regs;
static struct sparc_stackf jprobe_saved_stack;
int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
memcpy(&jprobe_saved_regs, regs, sizeof(*regs));
/* Save a whole stack frame, this gets arguments
* pushed onto the stack after using up all the
* arg registers.
*/
memcpy(&jprobe_saved_stack,
(char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
sizeof(jprobe_saved_stack));
regs->tpc = (unsigned long) jp->entry;
regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
return 1;
}
void jprobe_return(void)
{
preempt_enable_no_resched();
__asm__ __volatile__(
".globl jprobe_return_trap_instruction\n"
"jprobe_return_trap_instruction:\n\t"
"ta 0x70");
}
extern void jprobe_return_trap_instruction(void);
int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
u32 *addr = (u32 *) regs->tpc;
if (addr == (u32 *) jprobe_return_trap_instruction) {
/* Restore old register state. Do pt_regs
* first so that UREG_FP is the original one for
* the stack frame restore.
*/
memcpy(regs, &jprobe_saved_regs, sizeof(*regs));
memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
&jprobe_saved_stack,
sizeof(jprobe_saved_stack));
return 1;
}
return 0;
}
...@@ -41,7 +41,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, ...@@ -41,7 +41,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
#else #else
/* List of all PCI controllers found in the system. */ /* List of all PCI controllers found in the system. */
spinlock_t pci_controller_lock = SPIN_LOCK_UNLOCKED;
struct pci_controller_info *pci_controller_root = NULL; struct pci_controller_info *pci_controller_root = NULL;
/* Each PCI controller found gets a unique index. */ /* Each PCI controller found gets a unique index. */
...@@ -298,12 +297,9 @@ static void __init pci_controller_probe(void) ...@@ -298,12 +297,9 @@ static void __init pci_controller_probe(void)
static void __init pci_scan_each_controller_bus(void) static void __init pci_scan_each_controller_bus(void)
{ {
struct pci_controller_info *p; struct pci_controller_info *p;
unsigned long flags;
spin_lock_irqsave(&pci_controller_lock, flags);
for (p = pci_controller_root; p; p = p->next) for (p = pci_controller_root; p; p = p->next)
p->scan_bus(p); p->scan_bus(p);
spin_unlock_irqrestore(&pci_controller_lock, flags);
} }
/* Reorder the pci_dev chain, so that onboard devices come first /* Reorder the pci_dev chain, so that onboard devices come first
......
...@@ -15,18 +15,13 @@ ...@@ -15,18 +15,13 @@
*/ */
void __init pci_fixup_host_bridge_self(struct pci_bus *pbus) void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *pdev;
walk = walk->next;
while (walk != &pbus->devices) {
struct pci_dev *pdev = pci_dev_b(walk);
list_for_each_entry(pdev, &pbus->devices, bus_list) {
if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) { if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) {
pbus->self = pdev; pbus->self = pdev;
return; return;
} }
walk = walk->next;
} }
prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n"); prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n");
...@@ -217,31 +212,18 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, ...@@ -217,31 +212,18 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm, struct pci_pbm_info *pbm,
int prom_node) int prom_node)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *pdev, *pdev_next;
struct pci_bus *this_pbus, *pbus_next;
/* This loop is coded like this because the cookie
* fillin routine can delete devices from the tree.
*/
walk = walk->next;
while (walk != &pbus->devices) {
struct pci_dev *pdev = pci_dev_b(walk);
struct list_head *walk_next = walk->next;
/* This must be _safe because the cookie fillin
routine can delete devices from the tree. */
list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list)
pdev_cookie_fillin(pbm, pdev, prom_node); pdev_cookie_fillin(pbm, pdev, prom_node);
walk = walk_next; list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) {
}
walk = &pbus->children;
walk = walk->next;
while (walk != &pbus->children) {
struct pci_bus *this_pbus = pci_bus_b(walk);
struct pcidev_cookie *pcp = this_pbus->self->sysdata; struct pcidev_cookie *pcp = this_pbus->self->sysdata;
struct list_head *walk_next = walk->next;
pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node); pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node);
walk = walk_next;
} }
} }
...@@ -431,14 +413,14 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm, ...@@ -431,14 +413,14 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
void __init pci_record_assignments(struct pci_pbm_info *pbm, void __init pci_record_assignments(struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *dev;
struct pci_bus *bus;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) list_for_each_entry(dev, &pbus->devices, bus_list)
pdev_record_assignments(pbm, pci_dev_b(walk)); pdev_record_assignments(pbm, dev);
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_record_assignments(pbm, bus);
pci_record_assignments(pbm, pci_bus_b(walk));
} }
/* Return non-zero if PDEV has implicit I/O resources even /* Return non-zero if PDEV has implicit I/O resources even
...@@ -549,14 +531,14 @@ static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, ...@@ -549,14 +531,14 @@ static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
void __init pci_assign_unassigned(struct pci_pbm_info *pbm, void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *dev;
struct pci_bus *bus;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) list_for_each_entry(dev, &pbus->devices, bus_list)
pdev_assign_unassigned(pbm, pci_dev_b(walk)); pdev_assign_unassigned(pbm, dev);
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_assign_unassigned(pbm, bus);
pci_assign_unassigned(pbm, pci_bus_b(walk));
} }
static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
...@@ -797,14 +779,14 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev) ...@@ -797,14 +779,14 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
void __init pci_fixup_irq(struct pci_pbm_info *pbm, void __init pci_fixup_irq(struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *dev;
struct pci_bus *bus;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) list_for_each_entry(dev, &pbus->devices, bus_list)
pdev_fixup_irq(pci_dev_b(walk)); pdev_fixup_irq(dev);
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_fixup_irq(pbm, bus);
pci_fixup_irq(pbm, pci_bus_b(walk));
} }
static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
...@@ -897,7 +879,7 @@ static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) ...@@ -897,7 +879,7 @@ static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk; struct pci_dev *pdev;
int all_are_66mhz; int all_are_66mhz;
u16 status; u16 status;
...@@ -906,11 +888,8 @@ void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, ...@@ -906,11 +888,8 @@ void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
goto out; goto out;
} }
walk = &pbus->devices;
all_are_66mhz = 1; all_are_66mhz = 1;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { list_for_each_entry(pdev, &pbus->devices, bus_list) {
struct pci_dev *pdev = pci_dev_b(walk);
pci_read_config_word(pdev, PCI_STATUS, &status); pci_read_config_word(pdev, PCI_STATUS, &status);
if (!(status & PCI_STATUS_66MHZ)) { if (!(status & PCI_STATUS_66MHZ)) {
all_are_66mhz = 0; all_are_66mhz = 0;
...@@ -929,17 +908,17 @@ void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, ...@@ -929,17 +908,17 @@ void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
void pci_setup_busmastering(struct pci_pbm_info *pbm, void pci_setup_busmastering(struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *dev;
struct pci_bus *bus;
int is_66mhz; int is_66mhz;
is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz; is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) list_for_each_entry(dev, &pbus->devices, bus_list)
pdev_setup_busmastering(pci_dev_b(walk), is_66mhz); pdev_setup_busmastering(dev, is_66mhz);
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_setup_busmastering(pbm, bus);
pci_setup_busmastering(pbm, pci_bus_b(walk));
} }
void pci_register_legacy_regions(struct resource *io_res, void pci_register_legacy_regions(struct resource *io_res,
...@@ -987,10 +966,10 @@ void pci_scan_for_target_abort(struct pci_controller_info *p, ...@@ -987,10 +966,10 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
struct pci_pbm_info *pbm, struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *pdev;
struct pci_bus *bus;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { list_for_each_entry(pdev, &pbus->devices, bus_list) {
struct pci_dev *pdev = pci_dev_b(walk);
u16 status, error_bits; u16 status, error_bits;
pci_read_config_word(pdev, PCI_STATUS, &status); pci_read_config_word(pdev, PCI_STATUS, &status);
...@@ -1005,19 +984,18 @@ void pci_scan_for_target_abort(struct pci_controller_info *p, ...@@ -1005,19 +984,18 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
} }
} }
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_scan_for_target_abort(p, pbm, bus);
pci_scan_for_target_abort(p, pbm, pci_bus_b(walk));
} }
void pci_scan_for_master_abort(struct pci_controller_info *p, void pci_scan_for_master_abort(struct pci_controller_info *p,
struct pci_pbm_info *pbm, struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *pdev;
struct pci_bus *bus;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { list_for_each_entry(pdev, &pbus->devices, bus_list) {
struct pci_dev *pdev = pci_dev_b(walk);
u16 status, error_bits; u16 status, error_bits;
pci_read_config_word(pdev, PCI_STATUS, &status); pci_read_config_word(pdev, PCI_STATUS, &status);
...@@ -1031,19 +1009,18 @@ void pci_scan_for_master_abort(struct pci_controller_info *p, ...@@ -1031,19 +1009,18 @@ void pci_scan_for_master_abort(struct pci_controller_info *p,
} }
} }
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_scan_for_master_abort(p, pbm, bus);
pci_scan_for_master_abort(p, pbm, pci_bus_b(walk));
} }
void pci_scan_for_parity_error(struct pci_controller_info *p, void pci_scan_for_parity_error(struct pci_controller_info *p,
struct pci_pbm_info *pbm, struct pci_pbm_info *pbm,
struct pci_bus *pbus) struct pci_bus *pbus)
{ {
struct list_head *walk = &pbus->devices; struct pci_dev *pdev;
struct pci_bus *bus;
for (walk = walk->next; walk != &pbus->devices; walk = walk->next) { list_for_each_entry(pdev, &pbus->devices, bus_list) {
struct pci_dev *pdev = pci_dev_b(walk);
u16 status, error_bits; u16 status, error_bits;
pci_read_config_word(pdev, PCI_STATUS, &status); pci_read_config_word(pdev, PCI_STATUS, &status);
...@@ -1058,7 +1035,6 @@ void pci_scan_for_parity_error(struct pci_controller_info *p, ...@@ -1058,7 +1035,6 @@ void pci_scan_for_parity_error(struct pci_controller_info *p,
} }
} }
walk = &pbus->children; list_for_each_entry(bus, &pbus->children, node)
for (walk = walk->next; walk != &pbus->children; walk = walk->next) pci_scan_for_parity_error(p, pbm, bus);
pci_scan_for_parity_error(p, pbm, pci_bus_b(walk));
} }
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/io.h> #include <asm/io.h>
extern spinlock_t pci_controller_lock;
extern struct pci_controller_info *pci_controller_root; extern struct pci_controller_info *pci_controller_root;
extern int pci_num_controllers; extern int pci_num_controllers;
......
...@@ -1487,22 +1487,18 @@ void __init psycho_init(int node, char *model_name) ...@@ -1487,22 +1487,18 @@ void __init psycho_init(int node, char *model_name)
struct linux_prom64_registers pr_regs[3]; struct linux_prom64_registers pr_regs[3];
struct pci_controller_info *p; struct pci_controller_info *p;
struct pci_iommu *iommu; struct pci_iommu *iommu;
unsigned long flags;
u32 upa_portid; u32 upa_portid;
int is_pbm_a, err; int is_pbm_a, err;
upa_portid = prom_getintdefault(node, "upa-portid", 0xff); upa_portid = prom_getintdefault(node, "upa-portid", 0xff);
spin_lock_irqsave(&pci_controller_lock, flags);
for(p = pci_controller_root; p; p = p->next) { for(p = pci_controller_root; p; p = p->next) {
if (p->pbm_A.portid == upa_portid) { if (p->pbm_A.portid == upa_portid) {
spin_unlock_irqrestore(&pci_controller_lock, flags);
is_pbm_a = (p->pbm_A.prom_node == 0); is_pbm_a = (p->pbm_A.prom_node == 0);
psycho_pbm_init(p, node, is_pbm_a); psycho_pbm_init(p, node, is_pbm_a);
return; return;
} }
} }
spin_unlock_irqrestore(&pci_controller_lock, flags);
p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p) { if (!p) {
...@@ -1518,10 +1514,8 @@ void __init psycho_init(int node, char *model_name) ...@@ -1518,10 +1514,8 @@ void __init psycho_init(int node, char *model_name)
memset(iommu, 0, sizeof(*iommu)); memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = p->pbm_B.iommu = iommu; p->pbm_A.iommu = p->pbm_B.iommu = iommu;
spin_lock_irqsave(&pci_controller_lock, flags);
p->next = pci_controller_root; p->next = pci_controller_root;
pci_controller_root = p; pci_controller_root = p;
spin_unlock_irqrestore(&pci_controller_lock, flags);
p->pbm_A.portid = upa_portid; p->pbm_A.portid = upa_portid;
p->pbm_B.portid = upa_portid; p->pbm_B.portid = upa_portid;
......
...@@ -1113,10 +1113,9 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource) ...@@ -1113,10 +1113,9 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource)
static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
{ {
struct list_head *walk = &sabre_bus->devices; struct pci_dev *pdev;
for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { list_for_each_entry(pdev, &sabre_bus->devices, bus_list) {
struct pci_dev *pdev = pci_dev_b(walk);
if (pdev->vendor == PCI_VENDOR_ID_SUN && if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
...@@ -1178,10 +1177,9 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm) ...@@ -1178,10 +1177,9 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm)
static void __init sabre_scan_bus(struct pci_controller_info *p) static void __init sabre_scan_bus(struct pci_controller_info *p)
{ {
static int once; static int once;
struct pci_bus *sabre_bus; struct pci_bus *sabre_bus, *pbus;
struct pci_pbm_info *pbm; struct pci_pbm_info *pbm;
struct pcidev_cookie *cookie; struct pcidev_cookie *cookie;
struct list_head *walk;
int sabres_scanned; int sabres_scanned;
/* The APB bridge speaks to the Sabre host PCI bridge /* The APB bridge speaks to the Sabre host PCI bridge
...@@ -1217,9 +1215,7 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) ...@@ -1217,9 +1215,7 @@ static void __init sabre_scan_bus(struct pci_controller_info *p)
sabres_scanned = 0; sabres_scanned = 0;
walk = &sabre_bus->children; list_for_each_entry(pbus, &sabre_bus->children, node) {
for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) {
struct pci_bus *pbus = pci_bus_b(walk);
if (pbus->number == p->pbm_A.pci_first_busno) { if (pbus->number == p->pbm_A.pci_first_busno) {
pbm = &p->pbm_A; pbm = &p->pbm_A;
...@@ -1554,7 +1550,6 @@ void __init sabre_init(int pnode, char *model_name) ...@@ -1554,7 +1550,6 @@ void __init sabre_init(int pnode, char *model_name)
struct linux_prom64_registers pr_regs[2]; struct linux_prom64_registers pr_regs[2];
struct pci_controller_info *p; struct pci_controller_info *p;
struct pci_iommu *iommu; struct pci_iommu *iommu;
unsigned long flags;
int tsbsize, err; int tsbsize, err;
u32 busrange[2]; u32 busrange[2];
u32 vdma[2]; u32 vdma[2];
...@@ -1602,10 +1597,8 @@ void __init sabre_init(int pnode, char *model_name) ...@@ -1602,10 +1597,8 @@ void __init sabre_init(int pnode, char *model_name)
upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);
spin_lock_irqsave(&pci_controller_lock, flags);
p->next = pci_controller_root; p->next = pci_controller_root;
pci_controller_root = p; pci_controller_root = p;
spin_unlock_irqrestore(&pci_controller_lock, flags);
p->pbm_A.portid = upa_portid; p->pbm_A.portid = upa_portid;
p->pbm_B.portid = upa_portid; p->pbm_B.portid = upa_portid;
......
...@@ -2081,13 +2081,11 @@ static void __init __schizo_init(int node, char *model_name, int chip_type) ...@@ -2081,13 +2081,11 @@ static void __init __schizo_init(int node, char *model_name, int chip_type)
{ {
struct pci_controller_info *p; struct pci_controller_info *p;
struct pci_iommu *iommu; struct pci_iommu *iommu;
unsigned long flags;
int is_pbm_a; int is_pbm_a;
u32 portid; u32 portid;
portid = prom_getintdefault(node, "portid", 0xff); portid = prom_getintdefault(node, "portid", 0xff);
spin_lock_irqsave(&pci_controller_lock, flags);
for(p = pci_controller_root; p; p = p->next) { for(p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm; struct pci_pbm_info *pbm;
...@@ -2099,13 +2097,11 @@ static void __init __schizo_init(int node, char *model_name, int chip_type) ...@@ -2099,13 +2097,11 @@ static void __init __schizo_init(int node, char *model_name, int chip_type)
&p->pbm_B); &p->pbm_B);
if (portid_compare(pbm->portid, portid, chip_type)) { if (portid_compare(pbm->portid, portid, chip_type)) {
spin_unlock_irqrestore(&pci_controller_lock, flags);
is_pbm_a = (p->pbm_A.prom_node == 0); is_pbm_a = (p->pbm_A.prom_node == 0);
schizo_pbm_init(p, node, portid, chip_type); schizo_pbm_init(p, node, portid, chip_type);
return; return;
} }
} }
spin_unlock_irqrestore(&pci_controller_lock, flags);
p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p) { if (!p) {
...@@ -2130,10 +2126,8 @@ static void __init __schizo_init(int node, char *model_name, int chip_type) ...@@ -2130,10 +2126,8 @@ static void __init __schizo_init(int node, char *model_name, int chip_type)
memset(iommu, 0, sizeof(*iommu)); memset(iommu, 0, sizeof(*iommu));
p->pbm_B.iommu = iommu; p->pbm_B.iommu = iommu;
spin_lock_irqsave(&pci_controller_lock, flags);
p->next = pci_controller_root; p->next = pci_controller_root;
pci_controller_root = p; pci_controller_root = p;
spin_unlock_irqrestore(&pci_controller_lock, flags);
p->index = pci_num_controllers++; p->index = pci_num_controllers++;
p->pbms_same_domain = 0; p->pbms_same_domain = 0;
......
...@@ -86,9 +86,62 @@ struct new_signal_frame32 { ...@@ -86,9 +86,62 @@ struct new_signal_frame32 {
__siginfo_fpu_t fpu_state; __siginfo_fpu_t fpu_state;
}; };
struct siginfo32 {
int si_signo;
int si_errno;
int si_code;
union {
int _pad[SI_PAD_SIZE32];
/* kill() */
struct {
compat_pid_t _pid; /* sender's pid */
unsigned int _uid; /* sender's uid */
} _kill;
/* POSIX.1b timers */
struct {
timer_t _tid; /* timer id */
int _overrun; /* overrun count */
sigval_t32 _sigval; /* same as below */
int _sys_private; /* not to be passed to user */
} _timer;
/* POSIX.1b signals */
struct {
compat_pid_t _pid; /* sender's pid */
unsigned int _uid; /* sender's uid */
sigval_t32 _sigval;
} _rt;
/* SIGCHLD */
struct {
compat_pid_t _pid; /* which child */
unsigned int _uid; /* sender's uid */
int _status; /* exit code */
compat_clock_t _utime;
compat_clock_t _stime;
struct compat_rusage _rusage;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
struct {
u32 _addr; /* faulting insn/memory ref. */
int _trapno;
} _sigfault;
/* SIGPOLL */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
};
struct rt_signal_frame32 { struct rt_signal_frame32 {
struct sparc_stackf32 ss; struct sparc_stackf32 ss;
siginfo_t32 info; struct siginfo32 info;
struct pt_regs32 regs; struct pt_regs32 regs;
compat_sigset_t mask; compat_sigset_t mask;
/* __siginfo_fpu32_t * */ u32 fpu_save; /* __siginfo_fpu32_t * */ u32 fpu_save;
...@@ -105,11 +158,11 @@ struct rt_signal_frame32 { ...@@ -105,11 +158,11 @@ struct rt_signal_frame32 {
#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7))) #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame32) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7)))
int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from)
{ {
int err; int err;
if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) if (!access_ok(VERIFY_WRITE, to, sizeof(struct siginfo32)))
return -EFAULT; return -EFAULT;
/* If you change siginfo_t structure, please be sure /* If you change siginfo_t structure, please be sure
...@@ -135,6 +188,8 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) ...@@ -135,6 +188,8 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from)
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
err |= put_compat_rusage(&from->si_rusage,
&to->si_rusage);
default: default:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
...@@ -155,6 +210,22 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from) ...@@ -155,6 +210,22 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from)
return err; return err;
} }
/* CAUTION: This is just a very minimalist implementation for the
* sake of compat_sys_rt_sigqueueinfo()
*/
int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from)
{
if (!access_ok(VERIFY_WRITE, from, sizeof(struct siginfo32)))
return -EFAULT;
if (copy_from_user(to, from, 3*sizeof(int)) ||
copy_from_user(to->_sifields._pad, from->_sifields._pad,
SI_PAD_SIZE))
return -EFAULT;
return 0;
}
/* /*
* atomically swap in the new signal mask, and wait for a signal. * atomically swap in the new signal mask, and wait for a signal.
* This is really tricky on the Sparc, watch out... * This is really tricky on the Sparc, watch out...
......
...@@ -1045,7 +1045,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, ...@@ -1045,7 +1045,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
} }
asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese,
siginfo_t32 __user *uinfo, struct siginfo32 __user *uinfo,
struct compat_timespec __user *uts, struct compat_timespec __user *uts,
compat_size_t sigsetsize) compat_size_t sigsetsize)
{ {
...@@ -1130,15 +1130,15 @@ asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, ...@@ -1130,15 +1130,15 @@ asmlinkage long sys32_rt_sigtimedwait(compat_sigset_t __user *uthese,
} }
asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
siginfo_t32 __user *uinfo) struct siginfo32 __user *uinfo)
{ {
siginfo_t info; siginfo_t info;
int ret; int ret;
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
if (copy_from_user (&info, uinfo, 3*sizeof(int)) || if (copy_siginfo_to_kernel32(&info, uinfo))
copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
return -EFAULT; return -EFAULT;
set_fs (KERNEL_DS); set_fs (KERNEL_DS);
ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
set_fs (old_fs); set_fs (old_fs);
...@@ -1736,3 +1736,23 @@ sys32_timer_create(u32 clock, struct sigevent32 __user *se32, ...@@ -1736,3 +1736,23 @@ sys32_timer_create(u32 clock, struct sigevent32 __user *se32,
return err; return err;
} }
asmlinkage long compat_sys_waitid(u32 which, u32 pid,
struct siginfo32 __user *uinfo, u32 options)
{
siginfo_t info;
long ret;
mm_segment_t old_fs = get_fs();
memset(&info, 0, sizeof(info));
set_fs (KERNEL_DS);
ret = sys_waitid((int)which, (compat_pid_t) pid,
(siginfo_t __user *) &info, (int) options);
set_fs (old_fs);
if (ret < 0 || info.si_signo == 0)
return ret;
BUG_ON(info.si_code & __SI_MASK);
info.si_code |= __SI_CHLD;
return copy_siginfo_to_user32(uinfo, &info);
}
...@@ -75,7 +75,7 @@ sys_call_table32: ...@@ -75,7 +75,7 @@ sys_call_table32:
/*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_timer_gettime, sys_timer_getoverrun /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy .word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
/*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink
.word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, sys_ni_syscall .word sys_mq_timedsend, sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid
/*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
...@@ -141,7 +141,7 @@ sys_call_table: ...@@ -141,7 +141,7 @@ sys_call_table:
/*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy
/*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink
.word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_ni_syscall .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid
/*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall /*280*/ .word sys_ni_syscall, sys_ni_syscall, sys_ni_syscall
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
......
...@@ -36,10 +36,24 @@ ...@@ -36,10 +36,24 @@
#include <asm/psrcompat.h> #include <asm/psrcompat.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/kdebug.h>
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
#include <linux/kmod.h> #include <linux/kmod.h>
#endif #endif
struct notifier_block *sparc64die_chain;
static spinlock_t die_notifier_lock = SPIN_LOCK_UNLOCKED;
int register_die_notifier(struct notifier_block *nb)
{
int err = 0;
unsigned long flags;
spin_lock_irqsave(&die_notifier_lock, flags);
err = notifier_chain_register(&sparc64die_chain, nb);
spin_unlock_irqrestore(&die_notifier_lock, flags);
return err;
}
/* When an irrecoverable trap occurs at tl > 0, the trap entry /* When an irrecoverable trap occurs at tl > 0, the trap entry
* code logs the trap state registers at every level in the trap * code logs the trap state registers at every level in the trap
* stack. It is found at (pt_regs + sizeof(pt_regs)) and the layout * stack. It is found at (pt_regs + sizeof(pt_regs)) and the layout
...@@ -71,11 +85,20 @@ static void dump_tl1_traplog(struct tl1_traplog *p) ...@@ -71,11 +85,20 @@ static void dump_tl1_traplog(struct tl1_traplog *p)
} }
} }
void bad_trap (struct pt_regs *regs, long lvl) void do_call_debug(struct pt_regs *regs)
{
notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT);
}
void bad_trap(struct pt_regs *regs, long lvl)
{ {
char buffer[32]; char buffer[32];
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "bad trap", regs,
0, lvl, SIGTRAP) == NOTIFY_OK)
return;
if (lvl < 0x100) { if (lvl < 0x100) {
sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl); sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
die_if_kernel(buffer, regs); die_if_kernel(buffer, regs);
...@@ -84,7 +107,7 @@ void bad_trap (struct pt_regs *regs, long lvl) ...@@ -84,7 +107,7 @@ void bad_trap (struct pt_regs *regs, long lvl)
lvl -= 0x100; lvl -= 0x100;
if (regs->tstate & TSTATE_PRIV) { if (regs->tstate & TSTATE_PRIV) {
sprintf(buffer, "Kernel bad sw trap %lx", lvl); sprintf(buffer, "Kernel bad sw trap %lx", lvl);
die_if_kernel (buffer, regs); die_if_kernel(buffer, regs);
} }
if (test_thread_flag(TIF_32BIT)) { if (test_thread_flag(TIF_32BIT)) {
regs->tpc &= 0xffffffff; regs->tpc &= 0xffffffff;
...@@ -98,10 +121,14 @@ void bad_trap (struct pt_regs *regs, long lvl) ...@@ -98,10 +121,14 @@ void bad_trap (struct pt_regs *regs, long lvl)
force_sig_info(SIGILL, &info, current); force_sig_info(SIGILL, &info, current);
} }
void bad_trap_tl1 (struct pt_regs *regs, long lvl) void bad_trap_tl1(struct pt_regs *regs, long lvl)
{ {
char buffer[32]; char buffer[32];
if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs,
0, lvl, SIGTRAP) == NOTIFY_OK)
return;
dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
sprintf (buffer, "Bad trap %lx at tl>0", lvl); sprintf (buffer, "Bad trap %lx at tl>0", lvl);
...@@ -121,6 +148,10 @@ void instruction_access_exception(struct pt_regs *regs, ...@@ -121,6 +148,10 @@ void instruction_access_exception(struct pt_regs *regs,
{ {
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "instruction access exception", regs,
0, 0x8, SIGTRAP) == NOTIFY_OK)
return;
if (regs->tstate & TSTATE_PRIV) { if (regs->tstate & TSTATE_PRIV) {
printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
sfsr, sfar); sfsr, sfar);
...@@ -141,15 +172,23 @@ void instruction_access_exception(struct pt_regs *regs, ...@@ -141,15 +172,23 @@ void instruction_access_exception(struct pt_regs *regs,
void instruction_access_exception_tl1(struct pt_regs *regs, void instruction_access_exception_tl1(struct pt_regs *regs,
unsigned long sfsr, unsigned long sfar) unsigned long sfsr, unsigned long sfar)
{ {
if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
0, 0x8, SIGTRAP) == NOTIFY_OK)
return;
dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
instruction_access_exception(regs, sfsr, sfar); instruction_access_exception(regs, sfsr, sfar);
} }
void data_access_exception (struct pt_regs *regs, void data_access_exception(struct pt_regs *regs,
unsigned long sfsr, unsigned long sfar) unsigned long sfsr, unsigned long sfar)
{ {
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "data access exception", regs,
0, 0x30, SIGTRAP) == NOTIFY_OK)
return;
if (regs->tstate & TSTATE_PRIV) { if (regs->tstate & TSTATE_PRIV) {
/* Test if this comes from uaccess places. */ /* Test if this comes from uaccess places. */
unsigned long fixup; unsigned long fixup;
...@@ -220,6 +259,10 @@ void do_iae(struct pt_regs *regs) ...@@ -220,6 +259,10 @@ void do_iae(struct pt_regs *regs)
spitfire_clean_and_reenable_l1_caches(); spitfire_clean_and_reenable_l1_caches();
if (notify_die(DIE_TRAP, "instruction access exception", regs,
0, 0x8, SIGTRAP) == NOTIFY_OK)
return;
info.si_signo = SIGBUS; info.si_signo = SIGBUS;
info.si_errno = 0; info.si_errno = 0;
info.si_code = BUS_OBJERR; info.si_code = BUS_OBJERR;
...@@ -230,6 +273,8 @@ void do_iae(struct pt_regs *regs) ...@@ -230,6 +273,8 @@ void do_iae(struct pt_regs *regs)
void do_dae(struct pt_regs *regs) void do_dae(struct pt_regs *regs)
{ {
siginfo_t info;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
spitfire_clean_and_reenable_l1_caches(); spitfire_clean_and_reenable_l1_caches();
...@@ -244,7 +289,18 @@ void do_dae(struct pt_regs *regs) ...@@ -244,7 +289,18 @@ void do_dae(struct pt_regs *regs)
return; return;
} }
#endif #endif
do_iae(regs); spitfire_clean_and_reenable_l1_caches();
if (notify_die(DIE_TRAP, "data access exception", regs,
0, 0x30, SIGTRAP) == NOTIFY_OK)
return;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_OBJERR;
info.si_addr = (void *)0;
info.si_trapno = 0;
force_sig_info(SIGBUS, &info, current);
} }
static char ecc_syndrome_table[] = { static char ecc_syndrome_table[] = {
...@@ -1638,6 +1694,10 @@ void do_fpe_common(struct pt_regs *regs) ...@@ -1638,6 +1694,10 @@ void do_fpe_common(struct pt_regs *regs)
void do_fpieee(struct pt_regs *regs) void do_fpieee(struct pt_regs *regs)
{ {
if (notify_die(DIE_TRAP, "fpu exception ieee", regs,
0, 0x24, SIGFPE) == NOTIFY_OK)
return;
do_fpe_common(regs); do_fpe_common(regs);
} }
...@@ -1648,6 +1708,10 @@ void do_fpother(struct pt_regs *regs) ...@@ -1648,6 +1708,10 @@ void do_fpother(struct pt_regs *regs)
struct fpustate *f = FPUSTATE; struct fpustate *f = FPUSTATE;
int ret = 0; int ret = 0;
if (notify_die(DIE_TRAP, "fpu exception other", regs,
0, 0x25, SIGFPE) == NOTIFY_OK)
return;
switch ((current_thread_info()->xfsr[0] & 0x1c000)) { switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
case (2 << 14): /* unfinished_FPop */ case (2 << 14): /* unfinished_FPop */
case (3 << 14): /* unimplemented_FPop */ case (3 << 14): /* unimplemented_FPop */
...@@ -1663,6 +1727,10 @@ void do_tof(struct pt_regs *regs) ...@@ -1663,6 +1727,10 @@ void do_tof(struct pt_regs *regs)
{ {
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "tagged arithmetic overflow", regs,
0, 0x26, SIGEMT) == NOTIFY_OK)
return;
if (regs->tstate & TSTATE_PRIV) if (regs->tstate & TSTATE_PRIV)
die_if_kernel("Penguin overflow trap from kernel mode", regs); die_if_kernel("Penguin overflow trap from kernel mode", regs);
if (test_thread_flag(TIF_32BIT)) { if (test_thread_flag(TIF_32BIT)) {
...@@ -1681,6 +1749,10 @@ void do_div0(struct pt_regs *regs) ...@@ -1681,6 +1749,10 @@ void do_div0(struct pt_regs *regs)
{ {
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "integer division by zero", regs,
0, 0x28, SIGFPE) == NOTIFY_OK)
return;
if (regs->tstate & TSTATE_PRIV) if (regs->tstate & TSTATE_PRIV)
die_if_kernel("TL0: Kernel divide by zero.", regs); die_if_kernel("TL0: Kernel divide by zero.", regs);
if (test_thread_flag(TIF_32BIT)) { if (test_thread_flag(TIF_32BIT)) {
...@@ -1786,6 +1858,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) ...@@ -1786,6 +1858,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
" \\__U_/\n"); " \\__U_/\n");
printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter); printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter);
notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV);
__asm__ __volatile__("flushw"); __asm__ __volatile__("flushw");
__show_regs(regs); __show_regs(regs);
if (regs->tstate & TSTATE_PRIV) { if (regs->tstate & TSTATE_PRIV) {
...@@ -1834,6 +1907,10 @@ void do_illegal_instruction(struct pt_regs *regs) ...@@ -1834,6 +1907,10 @@ void do_illegal_instruction(struct pt_regs *regs)
u32 insn; u32 insn;
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "illegal instruction", regs,
0, 0x10, SIGILL) == NOTIFY_OK)
return;
if (tstate & TSTATE_PRIV) if (tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs); die_if_kernel("Kernel illegal instruction", regs);
if (test_thread_flag(TIF_32BIT)) if (test_thread_flag(TIF_32BIT))
...@@ -1859,6 +1936,10 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo ...@@ -1859,6 +1936,10 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo
{ {
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "memory address unaligned", regs,
0, 0x34, SIGSEGV) == NOTIFY_OK)
return;
if (regs->tstate & TSTATE_PRIV) { if (regs->tstate & TSTATE_PRIV) {
extern void kernel_unaligned_trap(struct pt_regs *regs, extern void kernel_unaligned_trap(struct pt_regs *regs,
unsigned int insn, unsigned int insn,
...@@ -1881,6 +1962,10 @@ void do_privop(struct pt_regs *regs) ...@@ -1881,6 +1962,10 @@ void do_privop(struct pt_regs *regs)
{ {
siginfo_t info; siginfo_t info;
if (notify_die(DIE_TRAP, "privileged operation", regs,
0, 0x11, SIGILL) == NOTIFY_OK)
return;
if (test_thread_flag(TIF_32BIT)) { if (test_thread_flag(TIF_32BIT)) {
regs->tpc &= 0xffffffff; regs->tpc &= 0xffffffff;
regs->tnpc &= 0xffffffff; regs->tnpc &= 0xffffffff;
......
...@@ -158,7 +158,7 @@ tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) ...@@ -158,7 +158,7 @@ tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168)
tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c)
tl0_linux64: LINUX_64BIT_SYSCALL_TRAP tl0_linux64: LINUX_64BIT_SYSCALL_TRAP
tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context)
tl0_resv170: BTRAP(0x170) BTRAP(0x171) BTRAP(0x172) tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) BTRAP(0x172)
tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177)
tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <asm/asi.h> #include <asm/asi.h>
#include <asm/lsu.h> #include <asm/lsu.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/kdebug.h>
#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
...@@ -147,6 +148,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk, ...@@ -147,6 +148,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
(tsk->mm ? (unsigned long) tsk->mm->pgd : (tsk->mm ? (unsigned long) tsk->mm->pgd :
(unsigned long) tsk->active_mm->pgd)); (unsigned long) tsk->active_mm->pgd));
if (notify_die(DIE_GPF, "general protection fault", regs,
0, 0, SIGSEGV) == NOTIFY_OK)
return;
die_if_kernel("Oops", regs); die_if_kernel("Oops", regs);
} }
...@@ -318,8 +322,13 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs) ...@@ -318,8 +322,13 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
int si_code, fault_code; int si_code, fault_code;
unsigned long address; unsigned long address;
si_code = SEGV_MAPERR;
fault_code = get_thread_fault_code(); fault_code = get_thread_fault_code();
if (notify_die(DIE_PAGE_FAULT, "page_fault", regs,
fault_code, 0, SIGSEGV) == NOTIFY_OK)
return;
si_code = SEGV_MAPERR;
address = current_thread_info()->fault_address; address = current_thread_info()->fault_address;
if ((fault_code & FAULT_CODE_ITLB) && if ((fault_code & FAULT_CODE_ITLB) &&
......
...@@ -137,21 +137,34 @@ asmlinkage int solaris_brk(u32 brk) ...@@ -137,21 +137,34 @@ asmlinkage int solaris_brk(u32 brk)
return sunos_brk(brk); return sunos_brk(brk);
} }
#define set_utsfield(to, from, dotchop, countfrom) { \ static int __set_utsfield(char __user *to, int to_size,
char *p; \ const char *from, int from_size,
int i, len = (countfrom) ? \ int dotchop, int countfrom)
((sizeof(to) > sizeof(from) ? \ {
sizeof(from) : sizeof(to))) : sizeof(to); \ int len = countfrom ? (to_size > from_size ?
if (copy_to_user(to, from, len)) \ from_size : to_size) : to_size;
return -EFAULT; \ int off;
if (dotchop) \
for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \ if (copy_to_user(to, from, len))
else \ return -EFAULT;
i = len - 1; \
if (__put_user('\0', (char __user *)((to)+i))) \ if (dotchop) {
return -EFAULT; \ off = (strnchr(from, len, '.') - from);
} else{
off = len - 1;
}
if (__put_user('\0', to + off))
return -EFAULT;
return 0;
} }
#define set_utsfield(to, from, dotchop, countfrom) \
__set_utsfield((to), sizeof(to), \
(from), sizeof(from), \
(dotchop), (countfrom))
struct sol_uname { struct sol_uname {
char sysname[9]; char sysname[9];
char nodename[9]; char nodename[9];
...@@ -219,17 +232,20 @@ static char *serial(char *buffer) ...@@ -219,17 +232,20 @@ static char *serial(char *buffer)
asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
{ {
struct sol_uname __user *v = A(buf); struct sol_uname __user *v = A(buf);
int err;
switch (which) { switch (which) {
case 0: /* old uname */ case 0: /* old uname */
/* Let's cheat */ /* Let's cheat */
set_utsfield(v->sysname, "SunOS", 1, 0); err = set_utsfield(v->sysname, "SunOS", 1, 0);
down_read(&uts_sem); down_read(&uts_sem);
set_utsfield(v->nodename, system_utsname.nodename, 1, 1); err |= set_utsfield(v->nodename, system_utsname.nodename,
1, 1);
up_read(&uts_sem); up_read(&uts_sem);
set_utsfield(v->release, "2.6", 0, 0); err |= set_utsfield(v->release, "2.6", 0, 0);
set_utsfield(v->version, "Generic", 0, 0); err |= set_utsfield(v->version, "Generic", 0, 0);
set_utsfield(v->machine, machine(), 0, 0); err |= set_utsfield(v->machine, machine(), 0, 0);
return 0; return (err ? -EFAULT : 0);
case 2: /* ustat */ case 2: /* ustat */
return -ENOSYS; return -ENOSYS;
case 3: /* fusers */ case 3: /* fusers */
...@@ -242,15 +258,18 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) ...@@ -242,15 +258,18 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
asmlinkage int solaris_utsname(u32 buf) asmlinkage int solaris_utsname(u32 buf)
{ {
struct sol_utsname __user *v = A(buf); struct sol_utsname __user *v = A(buf);
int err;
/* Why should we not lie a bit? */ /* Why should we not lie a bit? */
down_read(&uts_sem); down_read(&uts_sem);
set_utsfield(v->sysname, "SunOS", 0, 0); err = set_utsfield(v->sysname, "SunOS", 0, 0);
set_utsfield(v->nodename, system_utsname.nodename, 1, 1); err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1);
set_utsfield(v->release, "5.6", 0, 0); err |= set_utsfield(v->release, "5.6", 0, 0);
set_utsfield(v->version, "Generic", 0, 0); err |= set_utsfield(v->version, "Generic", 0, 0);
set_utsfield(v->machine, machine(), 0, 0); err |= set_utsfield(v->machine, machine(), 0, 0);
up_read(&uts_sem); up_read(&uts_sem);
return 0;
return (err ? -EFAULT : 0);
} }
#define SI_SYSNAME 1 /* return name of operating system */ #define SI_SYSNAME 1 /* return name of operating system */
......
...@@ -290,11 +290,12 @@ ...@@ -290,11 +290,12 @@
#define __NR_io_cancel 271 #define __NR_io_cancel 271
#define __NR_io_getevents 272 #define __NR_io_getevents 272
#define __NR_mq_open 273 #define __NR_mq_open 273
#define __NR_mq_unlink (__NR_mq_open+1) #define __NR_mq_unlink 274
#define __NR_mq_timedsend (__NR_mq_open+2) #define __NR_mq_timedsend 275
#define __NR_mq_timedreceive (__NR_mq_open+3) #define __NR_mq_timedreceive 276
#define __NR_mq_notify (__NR_mq_open+4) #define __NR_mq_notify 277
#define __NR_mq_getsetattr (__NR_mq_open+5) #define __NR_mq_getsetattr 278
#define __NR_waitid 279
/* WARNING: You MAY NOT add syscall numbers larger than 282, since /* WARNING: You MAY NOT add syscall numbers larger than 282, since
* all of the syscall tables in the Sparc kernel are * all of the syscall tables in the Sparc kernel are
......
#ifndef _SPARC64_KDEBUG_H #ifndef _SPARC64_KDEBUG_H
#define _SPARC64_KDEBUG_H #define _SPARC64_KDEBUG_H
/* /* Nearly identical to x86_64/i386 code. */
* No kernel debugger on sparc64. Kept here because drivers/sbus/char/
* includes it for sparc32 sake. #include <linux/notifier.h>
struct pt_regs;
struct die_args {
struct pt_regs *regs;
const char *str;
long err;
int trapnr;
int signr;
};
/* Note - you should never unregister because that can race with NMIs.
* If you really want to do it first unregister - then synchronize_kernel
* - then free.
*/ */
int register_die_notifier(struct notifier_block *nb);
extern struct notifier_block *sparc64die_chain;
extern void bad_trap(struct pt_regs *, long);
/* Grossly misnamed. */
enum die_val {
DIE_OOPS = 1,
DIE_DEBUG, /* ta 0x70 */
DIE_DEBUG_2, /* ta 0x71 */
DIE_DIE,
DIE_TRAP,
DIE_TRAP_TL1,
DIE_GPF,
DIE_CALL,
DIE_PAGE_FAULT,
};
static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs,
long err, int trap, int sig)
{
struct die_args args = { .regs = regs,
.str = str,
.err = err,
.trapnr = trap,
.signr = sig };
return notifier_call_chain(&sparc64die_chain, val, &args);
}
#endif #endif
#ifndef _SPARC64_KPROBES_H
#define _SPARC64_KPROBES_H
#include <linux/config.h>
#include <linux/types.h>
typedef u32 kprobe_opcode_t;
#define BREAKPOINT_INSTRUCTION 0x91d02070 /* ta 0x70 */
#define BREAKPOINT_INSTRUCTION_2 0x91d02071 /* ta 0x71 */
#define MAX_INSN_SIZE 2
#ifdef CONFIG_KPROBES
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
#else /* !CONFIG_KPROBES */
static inline int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
{
return 0;
}
#endif
#endif /* _SPARC64_KPROBES_H */
...@@ -24,57 +24,8 @@ typedef union sigval32 { ...@@ -24,57 +24,8 @@ typedef union sigval32 {
u32 sival_ptr; u32 sival_ptr;
} sigval_t32; } sigval_t32;
typedef struct siginfo32 { struct siginfo32;
int si_signo;
int si_errno;
int si_code;
union {
int _pad[SI_PAD_SIZE32];
/* kill() */
struct {
compat_pid_t _pid; /* sender's pid */
unsigned int _uid; /* sender's uid */
} _kill;
/* POSIX.1b timers */
struct {
timer_t _tid; /* timer id */
int _overrun; /* overrun count */
sigval_t32 _sigval; /* same as below */
int _sys_private; /* not to be passed to user */
} _timer;
/* POSIX.1b signals */
struct {
compat_pid_t _pid; /* sender's pid */
unsigned int _uid; /* sender's uid */
sigval_t32 _sigval;
} _rt;
/* SIGCHLD */
struct {
compat_pid_t _pid; /* which child */
unsigned int _uid; /* sender's uid */
int _status; /* exit code */
compat_clock_t _utime;
compat_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
struct {
u32 _addr; /* faulting insn/memory ref. */
int _trapno;
} _sigfault;
/* SIGPOLL */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
} siginfo_t32;
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
...@@ -105,7 +56,8 @@ typedef struct sigevent32 { ...@@ -105,7 +56,8 @@ typedef struct sigevent32 {
} _sigev_un; } _sigev_un;
} sigevent_t32; } sigevent_t32;
extern int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from); extern int copy_siginfo_to_user32(struct siginfo32 __user *to, siginfo_t *from);
extern int copy_siginfo_to_kernel32(siginfo_t *to, struct siginfo32 __user *from);
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
......
...@@ -176,6 +176,12 @@ ...@@ -176,6 +176,12 @@
ba,pt %xcc, rtrap_clr_l6; \ ba,pt %xcc, rtrap_clr_l6; \
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]; stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC];
#ifdef CONFIG_KPROBES
#define KPROBES_TRAP(lvl) TRAP_IRQ(kprobe_trap, lvl)
#else
#define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
#endif
/* Before touching these macros, you owe it to yourself to go and /* Before touching these macros, you owe it to yourself to go and
* see how arch/sparc64/kernel/winfixup.S works... -DaveM * see how arch/sparc64/kernel/winfixup.S works... -DaveM
* *
......
...@@ -292,11 +292,13 @@ ...@@ -292,11 +292,13 @@
#define __NR_io_cancel 271 #define __NR_io_cancel 271
#define __NR_io_getevents 272 #define __NR_io_getevents 272
#define __NR_mq_open 273 #define __NR_mq_open 273
#define __NR_mq_unlink (__NR_mq_open+1) #define __NR_mq_unlink 274
#define __NR_mq_timedsend (__NR_mq_open+2) #define __NR_mq_timedsend 275
#define __NR_mq_timedreceive (__NR_mq_open+3) #define __NR_mq_timedreceive 276
#define __NR_mq_notify (__NR_mq_open+4) #define __NR_mq_notify 277
#define __NR_mq_getsetattr (__NR_mq_open+5) #define __NR_mq_getsetattr 278
#define __NR_waitid 279
/* WARNING: You MAY NOT add syscall numbers larger than 282, since /* WARNING: You MAY NOT add syscall numbers larger than 282, since
* all of the syscall tables in the Sparc kernel are * all of the syscall tables in the Sparc kernel are
* sized to have 283 entries (starting at zero). Therefore * sized to have 283 entries (starting at zero). Therefore
......
...@@ -88,7 +88,8 @@ int register_kprobe(struct kprobe *p) ...@@ -88,7 +88,8 @@ int register_kprobe(struct kprobe *p)
arch_prepare_kprobe(p); arch_prepare_kprobe(p);
p->opcode = *p->addr; p->opcode = *p->addr;
*p->addr = BREAKPOINT_INSTRUCTION; *p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range(p->addr, p->addr + sizeof(kprobe_opcode_t)); flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
out: out:
spin_unlock_irqrestore(&kprobe_lock, flags); spin_unlock_irqrestore(&kprobe_lock, flags);
return ret; return ret;
...@@ -100,7 +101,8 @@ void unregister_kprobe(struct kprobe *p) ...@@ -100,7 +101,8 @@ void unregister_kprobe(struct kprobe *p)
spin_lock_irqsave(&kprobe_lock, flags); spin_lock_irqsave(&kprobe_lock, flags);
*p->addr = p->opcode; *p->addr = p->opcode;
hlist_del(&p->hlist); hlist_del(&p->hlist);
flush_icache_range(p->addr, p->addr + sizeof(kprobe_opcode_t)); flush_icache_range((unsigned long) p->addr,
(unsigned long) p->addr + sizeof(kprobe_opcode_t));
spin_unlock_irqrestore(&kprobe_lock, flags); spin_unlock_irqrestore(&kprobe_lock, flags);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment