mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-05-21 12:07:46 +00:00
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
11
arch/m68knommu/kernel/Makefile
Normal file
11
arch/m68knommu/kernel/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Makefile for arch/m68knommu/kernel.
|
||||
#
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
|
||||
obj-y += dma.o entry.o init_task.o m68k_ksyms.o process.o ptrace.o semaphore.o \
|
||||
setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
|
||||
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_COMEMPCI) += comempci.o
|
||||
101
arch/m68knommu/kernel/asm-offsets.c
Normal file
101
arch/m68knommu/kernel/asm-offsets.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This program is used to generate definitions needed by
|
||||
* assembly language modules.
|
||||
*
|
||||
* We use the technique used in the OSF Mach kernel code:
|
||||
* generate asm statements containing #defines,
|
||||
* compile this file to assembler, and then extract the
|
||||
* #defines from the assembly-language output.
|
||||
*/
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
||||
#define BLANK() asm volatile("\n->" : : )
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* offsets into the task struct */
|
||||
DEFINE(TASK_STATE, offsetof(struct task_struct, state));
|
||||
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
|
||||
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
|
||||
DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
|
||||
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
|
||||
DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
|
||||
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
|
||||
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
|
||||
|
||||
/* offsets into the kernel_stat struct */
|
||||
DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
|
||||
|
||||
/* offsets into the irq_cpustat_t struct */
|
||||
DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
|
||||
|
||||
/* offsets into the thread struct */
|
||||
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
|
||||
DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
|
||||
DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
|
||||
DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
|
||||
DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
|
||||
DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
|
||||
DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
|
||||
DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
|
||||
DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
|
||||
|
||||
/* offsets into the pt_regs */
|
||||
DEFINE(PT_D0, offsetof(struct pt_regs, d0));
|
||||
DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
|
||||
DEFINE(PT_D1, offsetof(struct pt_regs, d1));
|
||||
DEFINE(PT_D2, offsetof(struct pt_regs, d2));
|
||||
DEFINE(PT_D3, offsetof(struct pt_regs, d3));
|
||||
DEFINE(PT_D4, offsetof(struct pt_regs, d4));
|
||||
DEFINE(PT_D5, offsetof(struct pt_regs, d5));
|
||||
DEFINE(PT_A0, offsetof(struct pt_regs, a0));
|
||||
DEFINE(PT_A1, offsetof(struct pt_regs, a1));
|
||||
DEFINE(PT_A2, offsetof(struct pt_regs, a2));
|
||||
DEFINE(PT_PC, offsetof(struct pt_regs, pc));
|
||||
DEFINE(PT_SR, offsetof(struct pt_regs, sr));
|
||||
|
||||
#ifdef CONFIG_COLDFIRE
|
||||
/* bitfields are a bit difficult */
|
||||
DEFINE(PT_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
|
||||
#else
|
||||
/* bitfields are a bit difficult */
|
||||
DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
|
||||
/* offsets into the irq_handler struct */
|
||||
DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
|
||||
DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
|
||||
DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
|
||||
#endif
|
||||
|
||||
/* offsets into the kernel_stat struct */
|
||||
DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
|
||||
|
||||
/* signal defines */
|
||||
DEFINE(SIGSEGV, SIGSEGV);
|
||||
DEFINE(SEGV_MAPERR, SEGV_MAPERR);
|
||||
DEFINE(SIGTRAP, SIGTRAP);
|
||||
DEFINE(TRAP_TRACE, TRAP_TRACE);
|
||||
|
||||
DEFINE(PT_PTRACED, PT_PTRACED);
|
||||
DEFINE(PT_DTRACE, PT_DTRACE);
|
||||
|
||||
DEFINE(THREAD_SIZE, THREAD_SIZE);
|
||||
|
||||
/* Offsets in thread_info structure */
|
||||
DEFINE(TI_TASK, offsetof(struct thread_info, task));
|
||||
DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
|
||||
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
|
||||
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
|
||||
|
||||
return 0;
|
||||
}
|
||||
989
arch/m68knommu/kernel/comempci.c
Normal file
989
arch/m68knommu/kernel/comempci.c
Normal file
@@ -0,0 +1,989 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* comemlite.c -- PCI access code for embedded CO-MEM Lite PCI controller.
|
||||
*
|
||||
* (C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com).
|
||||
* (C) Copyright 2000, Lineo (www.lineo.com)
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/coldfire.h>
|
||||
#include <asm/mcfsim.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/anchor.h>
|
||||
|
||||
#ifdef CONFIG_eLIA
|
||||
#include <asm/elia.h>
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Debug configuration defines. DEBUGRES sets debugging output for
|
||||
* the resource allocation phase. DEBUGPCI traces on pcibios_ function
|
||||
* calls, and DEBUGIO traces all accesses to devices on the PCI bus.
|
||||
*/
|
||||
/*#define DEBUGRES 1*/
|
||||
/*#define DEBUGPCI 1*/
|
||||
/*#define DEBUGIO 1*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* PCI markers for bus present and active slots.
|
||||
*/
|
||||
int pci_bus_is_present = 0;
|
||||
unsigned long pci_slotmask = 0;
|
||||
|
||||
/*
|
||||
* We may or may not need to swap the bytes of PCI bus tranfers.
|
||||
* The endianess is re-roder automatically by the CO-MEM, but it
|
||||
* will get the wrong byte order for a pure data stream.
|
||||
*/
|
||||
#define pci_byteswap 0
|
||||
|
||||
|
||||
/*
|
||||
* Resource tracking. The CO-MEM part creates a virtual address
|
||||
* space that all the PCI devices live in - it is not in any way
|
||||
* directly mapped into the ColdFire address space. So we can
|
||||
* really assign any resources we like to devices, as long as
|
||||
* they do not clash with other PCI devices.
|
||||
*/
|
||||
unsigned int pci_iobase = PCIBIOS_MIN_IO; /* Arbitrary start address */
|
||||
unsigned int pci_membase = PCIBIOS_MIN_MEM; /* Arbitrary start address */
|
||||
|
||||
#define PCI_MINIO 0x100 /* 256 byte minimum I/O */
|
||||
#define PCI_MINMEM 0x00010000 /* 64k minimum chunk */
|
||||
|
||||
/*
|
||||
* The CO-MEM's shared memory segment is visible inside the PCI
|
||||
* memory address space. We need to keep track of the address that
|
||||
* this is mapped at, to setup the bus masters pointers.
|
||||
*/
|
||||
unsigned int pci_shmemaddr;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_interrupt(int irq, void *id, struct pt_regs *fp);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Some platforms have custom ways of reseting the PCI bus.
|
||||
*/
|
||||
|
||||
void pci_resetbus(void)
|
||||
{
|
||||
#ifdef CONFIG_eLIA
|
||||
int i;
|
||||
|
||||
#ifdef DEBUGPCI
|
||||
printk(KERN_DEBUG "pci_resetbus()\n");
|
||||
#endif
|
||||
|
||||
*((volatile unsigned short *) (MCF_MBAR+MCFSIM_PADDR)) |= eLIA_PCIRESET;
|
||||
for (i = 0; (i < 1000); i++) {
|
||||
*((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) =
|
||||
(ppdata | eLIA_PCIRESET);
|
||||
}
|
||||
|
||||
|
||||
*((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = ppdata;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int pcibios_assign_resource_slot(int slot)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned char *ip;
|
||||
unsigned int idsel, addr, val, align, i;
|
||||
int bar;
|
||||
|
||||
#ifdef DEBUGPCI
|
||||
printk(KERN_INFO "pcibios_assign_resource_slot(slot=%x)\n", slot);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
idsel = COMEM_DA_ADDR(0x1 << (slot + 16));
|
||||
|
||||
/* Try to assign resource to each BAR */
|
||||
for (bar = 0; (bar < 6); bar++) {
|
||||
addr = COMEM_PCIBUS + PCI_BASE_ADDRESS_0 + (bar * 4);
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
|
||||
val = rp[LREG(addr)];
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "-----------------------------------"
|
||||
"-------------------------------------\n");
|
||||
printk(KERN_DEBUG "BAR[%d]: read=%08x ", bar, val);
|
||||
#endif
|
||||
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
|
||||
rp[LREG(addr)] = 0xffffffff;
|
||||
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
|
||||
val = rp[LREG(addr)];
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "write=%08x ", val);
|
||||
#endif
|
||||
if (val == 0) {
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Determine space required by BAR */
|
||||
/* FIXME: this should go backwords from 0x80000000... */
|
||||
for (i = 0; (i < 32); i++) {
|
||||
if ((0x1 << i) & (val & 0xfffffffc))
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "size=%08x(%d)\n", (0x1 << i), i);
|
||||
#endif
|
||||
i = 0x1 << i;
|
||||
|
||||
/* Assign a resource */
|
||||
if (val & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
if (i < PCI_MINIO)
|
||||
i = PCI_MINIO;
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "BAR[%d]: IO size=%08x iobase=%08x\n",
|
||||
bar, i, pci_iobase);
|
||||
#endif
|
||||
if (i > 0xffff) {
|
||||
/* Invalid size?? */
|
||||
val = 0 | PCI_BASE_ADDRESS_SPACE_IO;
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "BAR[%d]: too big for IO??\n", bar);
|
||||
#endif
|
||||
} else {
|
||||
/* Check for un-alignment */
|
||||
if ((align = pci_iobase % i))
|
||||
pci_iobase += (i - align);
|
||||
val = pci_iobase | PCI_BASE_ADDRESS_SPACE_IO;
|
||||
pci_iobase += i;
|
||||
}
|
||||
} else {
|
||||
if (i < PCI_MINMEM)
|
||||
i = PCI_MINMEM;
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "BAR[%d]: MEMORY size=%08x membase=%08x\n",
|
||||
bar, i, pci_membase);
|
||||
#endif
|
||||
/* Check for un-alignment */
|
||||
if ((align = pci_membase % i))
|
||||
pci_membase += (i - align);
|
||||
val = pci_membase | PCI_BASE_ADDRESS_SPACE_MEMORY;
|
||||
pci_membase += i;
|
||||
}
|
||||
|
||||
/* Write resource back into BAR register */
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
|
||||
rp[LREG(addr)] = val;
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "BAR[%d]: assigned bar=%08x\n", bar, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "-----------------------------------"
|
||||
"-------------------------------------\n");
|
||||
#endif
|
||||
|
||||
/* Assign IRQ if one is wanted... */
|
||||
ip = (volatile unsigned char *) (COMEM_BASE + COMEM_PCIBUS);
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
|
||||
|
||||
addr = (PCI_INTERRUPT_PIN & 0xfc) + (~PCI_INTERRUPT_PIN & 0x03);
|
||||
if (ip[addr]) {
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
|
||||
addr = (PCI_INTERRUPT_LINE & 0xfc)+(~PCI_INTERRUPT_LINE & 0x03);
|
||||
ip[addr] = 25;
|
||||
#ifdef DEBUGRES
|
||||
printk(KERN_DEBUG "IRQ LINE=25\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int pcibios_enable_slot(int slot)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned short *wp;
|
||||
unsigned int idsel, addr;
|
||||
unsigned short cmd;
|
||||
|
||||
#ifdef DEBUGPCI
|
||||
printk(KERN_DEBUG "pcibios_enbale_slot(slot=%x)\n", slot);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
wp = (volatile unsigned short *) COMEM_BASE;
|
||||
idsel = COMEM_DA_ADDR(0x1 << (slot + 16));
|
||||
|
||||
/* Get current command settings */
|
||||
addr = COMEM_PCIBUS + PCI_COMMAND;
|
||||
addr = (addr & ~0x3) + (~addr & 0x02);
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
|
||||
cmd = wp[WREG(addr)];
|
||||
/*val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);*/
|
||||
|
||||
/* Enable I/O and memory accesses to this device */
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
|
||||
cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
|
||||
wp[WREG(addr)] = cmd;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pcibios_assign_resources(void)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
unsigned long sel, id;
|
||||
int slot;
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
|
||||
/*
|
||||
* Do a quick scan of the PCI bus and see what is here.
|
||||
*/
|
||||
for (slot = COMEM_MINDEV; (slot <= COMEM_MAXDEV); slot++) {
|
||||
sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16));
|
||||
rp[LREG(COMEM_DAHBASE)] = sel;
|
||||
rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */
|
||||
id = rp[LREG(COMEM_PCIBUS)];
|
||||
if ((id != 0) && ((id & 0xffff0000) != (sel & 0xffff0000))) {
|
||||
printk(KERN_INFO "PCI: slot=%d id=%08x\n", slot, (int) id);
|
||||
pci_slotmask |= 0x1 << slot;
|
||||
pcibios_assign_resource_slot(slot);
|
||||
pcibios_enable_slot(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int pcibios_init(void)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
unsigned long sel, id;
|
||||
int slot;
|
||||
|
||||
#ifdef DEBUGPCI
|
||||
printk(KERN_DEBUG "pcibios_init()\n");
|
||||
#endif
|
||||
|
||||
pci_resetbus();
|
||||
|
||||
/*
|
||||
* Do some sort of basic check to see if the CO-MEM part
|
||||
* is present... This works ok, but I think we really need
|
||||
* something better...
|
||||
*/
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
if ((rp[LREG(COMEM_LBUSCFG)] & 0xff) != 0x50) {
|
||||
printk(KERN_INFO "PCI: no PCI bus present\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef COMEM_BRIDGEDEV
|
||||
/*
|
||||
* Setup the PCI bridge device first. It needs resources too,
|
||||
* so that bus masters can get to its shared memory.
|
||||
*/
|
||||
slot = COMEM_BRIDGEDEV;
|
||||
sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16));
|
||||
rp[LREG(COMEM_DAHBASE)] = sel;
|
||||
rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */
|
||||
id = rp[LREG(COMEM_PCIBUS)];
|
||||
if ((id == 0) || ((id & 0xffff0000) == (sel & 0xffff0000))) {
|
||||
printk(KERN_INFO "PCI: no PCI bus bridge present\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "PCI: bridge device at slot=%d id=%08x\n", slot, (int) id);
|
||||
pci_slotmask |= 0x1 << slot;
|
||||
pci_shmemaddr = pci_membase;
|
||||
pcibios_assign_resource_slot(slot);
|
||||
pcibios_enable_slot(slot);
|
||||
#endif
|
||||
|
||||
pci_bus_is_present = 1;
|
||||
|
||||
/* Get PCI irq for local vectoring */
|
||||
if (request_irq(COMEM_IRQ, pci_interrupt, 0, "PCI bridge", NULL)) {
|
||||
printk(KERN_WARNING "PCI: failed to acquire interrupt %d\n", COMEM_IRQ);
|
||||
} else {
|
||||
mcf_autovector(COMEM_IRQ);
|
||||
}
|
||||
|
||||
pcibios_assign_resources();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
char *pcibios_setup(char *option)
|
||||
{
|
||||
/* Nothing for us to handle. */
|
||||
return(option);
|
||||
}
|
||||
/*****************************************************************************/
|
||||
|
||||
void pcibios_fixup_bus(struct pci_bus *b)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int pcibios_enable_device(struct pci_dev *dev, int mask)
|
||||
{
|
||||
int slot;
|
||||
|
||||
slot = PCI_SLOT(dev->devfn);
|
||||
if ((dev->bus == 0) && (pci_slotmask & (1 << slot)))
|
||||
pcibios_enable_slot(slot);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *r, int resource)
|
||||
{
|
||||
printk(KERN_WARNING "%s(%d): no support for changing PCI resources...\n",
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Local routines to interrcept the standard I/O and vector handling
|
||||
* code. Don't include this 'till now - initialization code above needs
|
||||
* access to the real code too.
|
||||
*/
|
||||
#include <asm/mcfpci.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_outb(unsigned char val, unsigned int addr)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned char *bp;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_outb(val=%02x,addr=%x)\n", val, addr);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
bp = (volatile unsigned char *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);
|
||||
addr = (addr & ~0x3) + (~addr & 0x03);
|
||||
bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_outw(unsigned short val, unsigned int addr)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned short *sp;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_outw(val=%04x,addr=%x)\n", val, addr);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
sp = (volatile unsigned short *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);
|
||||
addr = (addr & ~0x3) + (~addr & 0x02);
|
||||
if (pci_byteswap)
|
||||
val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);
|
||||
sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_outl(unsigned int val, unsigned int addr)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned int *lp;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_outl(val=%08x,addr=%x)\n", val, addr);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
lp = (volatile unsigned int *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);
|
||||
|
||||
if (pci_byteswap)
|
||||
val = (val << 24) | ((val & 0x0000ff00) << 8) |
|
||||
((val & 0x00ff0000) >> 8) | (val >> 24);
|
||||
|
||||
lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned long pci_blmask[] = {
|
||||
0x000000e0,
|
||||
0x000000d0,
|
||||
0x000000b0,
|
||||
0x00000070
|
||||
};
|
||||
|
||||
unsigned char pci_inb(unsigned int addr)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned char *bp;
|
||||
unsigned long r;
|
||||
unsigned char val;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_inb(addr=%x)\n", addr);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
bp = (volatile unsigned char *) COMEM_BASE;
|
||||
|
||||
r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_blmask[(addr & 0x3)];
|
||||
rp[LREG(COMEM_DAHBASE)] = r;
|
||||
|
||||
addr = (addr & ~0x3) + (~addr & 0x3);
|
||||
val = bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned long pci_bwmask[] = {
|
||||
0x000000c0,
|
||||
0x000000c0,
|
||||
0x00000030,
|
||||
0x00000030
|
||||
};
|
||||
|
||||
unsigned short pci_inw(unsigned int addr)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned short *sp;
|
||||
unsigned long r;
|
||||
unsigned short val;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_inw(addr=%x)", addr);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_bwmask[(addr & 0x3)];
|
||||
rp[LREG(COMEM_DAHBASE)] = r;
|
||||
|
||||
sp = (volatile unsigned short *) COMEM_BASE;
|
||||
addr = (addr & ~0x3) + (~addr & 0x02);
|
||||
val = sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];
|
||||
if (pci_byteswap)
|
||||
val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "=%04x\n", val);
|
||||
#endif
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned int pci_inl(unsigned int addr)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned int *lp;
|
||||
unsigned int val;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_inl(addr=%x)", addr);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
lp = (volatile unsigned int *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(addr);
|
||||
val = lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];
|
||||
|
||||
if (pci_byteswap)
|
||||
val = (val << 24) | ((val & 0x0000ff00) << 8) |
|
||||
((val & 0x00ff0000) >> 8) | (val >> 24);
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "=%08x\n", val);
|
||||
#endif
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_outsb(void *addr, void *buf, int len)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned char *bp;
|
||||
unsigned char *dp = (unsigned char *) buf;
|
||||
unsigned int a = (unsigned int) addr;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_outsb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a);
|
||||
|
||||
a = (a & ~0x3) + (~a & 0x03);
|
||||
bp = (volatile unsigned char *)
|
||||
(COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
|
||||
|
||||
while (len--)
|
||||
*bp = *dp++;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_outsw(void *addr, void *buf, int len)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned short *wp;
|
||||
unsigned short w, *dp = (unsigned short *) buf;
|
||||
unsigned int a = (unsigned int) addr;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_outsw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a);
|
||||
|
||||
a = (a & ~0x3) + (~a & 0x2);
|
||||
wp = (volatile unsigned short *)
|
||||
(COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
|
||||
|
||||
while (len--) {
|
||||
w = *dp++;
|
||||
if (pci_byteswap)
|
||||
w = ((w & 0xff) << 8) | ((w >> 8) & 0xff);
|
||||
*wp = w;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_outsl(void *addr, void *buf, int len)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned long *lp;
|
||||
unsigned long l, *dp = (unsigned long *) buf;
|
||||
unsigned int a = (unsigned int) addr;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_outsl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a);
|
||||
|
||||
lp = (volatile unsigned long *)
|
||||
(COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
|
||||
|
||||
while (len--) {
|
||||
l = *dp++;
|
||||
if (pci_byteswap)
|
||||
l = (l << 24) | ((l & 0x0000ff00) << 8) |
|
||||
((l & 0x00ff0000) >> 8) | (l >> 24);
|
||||
*lp = l;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_insb(void *addr, void *buf, int len)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned char *bp;
|
||||
unsigned char *dp = (unsigned char *) buf;
|
||||
unsigned int a = (unsigned int) addr;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_insb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a);
|
||||
|
||||
a = (a & ~0x3) + (~a & 0x03);
|
||||
bp = (volatile unsigned char *)
|
||||
(COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
|
||||
|
||||
while (len--)
|
||||
*dp++ = *bp;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_insw(void *addr, void *buf, int len)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned short *wp;
|
||||
unsigned short w, *dp = (unsigned short *) buf;
|
||||
unsigned int a = (unsigned int) addr;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_insw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a);
|
||||
|
||||
a = (a & ~0x3) + (~a & 0x2);
|
||||
wp = (volatile unsigned short *)
|
||||
(COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
|
||||
|
||||
while (len--) {
|
||||
w = *wp;
|
||||
if (pci_byteswap)
|
||||
w = ((w & 0xff) << 8) | ((w >> 8) & 0xff);
|
||||
*dp++ = w;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_insl(void *addr, void *buf, int len)
|
||||
{
|
||||
volatile unsigned long *rp;
|
||||
volatile unsigned long *lp;
|
||||
unsigned long l, *dp = (unsigned long *) buf;
|
||||
unsigned int a = (unsigned int) addr;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_insl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
|
||||
#endif
|
||||
|
||||
rp = (volatile unsigned long *) COMEM_BASE;
|
||||
rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a);
|
||||
|
||||
lp = (volatile unsigned long *)
|
||||
(COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
|
||||
|
||||
while (len--) {
|
||||
l = *lp;
|
||||
if (pci_byteswap)
|
||||
l = (l << 24) | ((l & 0x0000ff00) << 8) |
|
||||
((l & 0x00ff0000) >> 8) | (l >> 24);
|
||||
*dp++ = l;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct pci_localirqlist {
|
||||
void (*handler)(int, void *, struct pt_regs *);
|
||||
const char *device;
|
||||
void *dev_id;
|
||||
};
|
||||
|
||||
struct pci_localirqlist pci_irqlist[COMEM_MAXPCI];
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int pci_request_irq(unsigned int irq,
|
||||
void (*handler)(int, void *, struct pt_regs *),
|
||||
unsigned long flags, const char *device, void *dev_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_request_irq(irq=%d,handler=%x,flags=%x,device=%s,"
|
||||
"dev_id=%x)\n", irq, (int) handler, (int) flags, device,
|
||||
(int) dev_id);
|
||||
#endif
|
||||
|
||||
/* Check if this interrupt handler is already lodged */
|
||||
for (i = 0; (i < COMEM_MAXPCI); i++) {
|
||||
if (pci_irqlist[i].handler == handler)
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Find a free spot to put this handler */
|
||||
for (i = 0; (i < COMEM_MAXPCI); i++) {
|
||||
if (pci_irqlist[i].handler == 0) {
|
||||
pci_irqlist[i].handler = handler;
|
||||
pci_irqlist[i].device = device;
|
||||
pci_irqlist[i].dev_id = dev_id;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Couldn't fit?? */
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_free_irq(unsigned int irq, void *dev_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_free_irq(irq=%d,dev_id=%x)\n", irq, (int) dev_id);
|
||||
#endif
|
||||
|
||||
if (dev_id == (void *) NULL)
|
||||
return;
|
||||
|
||||
/* Check if this interrupt handler is lodged */
|
||||
for (i = 0; (i < COMEM_MAXPCI); i++) {
|
||||
if (pci_irqlist[i].dev_id == dev_id) {
|
||||
pci_irqlist[i].handler = NULL;
|
||||
pci_irqlist[i].device = NULL;
|
||||
pci_irqlist[i].dev_id = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_interrupt(int irq, void *id, struct pt_regs *fp)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_interrupt(irq=%d,id=%x,fp=%x)\n", irq, (int) id, (int) fp);
|
||||
#endif
|
||||
|
||||
for (i = 0; (i < COMEM_MAXPCI); i++) {
|
||||
if (pci_irqlist[i].handler)
|
||||
(*pci_irqlist[i].handler)(irq,pci_irqlist[i].dev_id,fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* The shared memory region is broken up into contiguous 512 byte
|
||||
* regions for easy allocation... This is not an optimal solution
|
||||
* but it makes allocation and freeing regions really easy.
|
||||
*/
|
||||
|
||||
#define PCI_MEMSLOTSIZE 512
|
||||
#define PCI_MEMSLOTS (COMEM_SHMEMSIZE / PCI_MEMSLOTSIZE)
|
||||
|
||||
char pci_shmemmap[PCI_MEMSLOTS];
|
||||
|
||||
|
||||
void *pci_bmalloc(int size)
|
||||
{
|
||||
int i, j, nrslots;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_bmalloc(size=%d)\n", size);
|
||||
#endif
|
||||
|
||||
if (size <= 0)
|
||||
return((void *) NULL);
|
||||
|
||||
nrslots = (size - 1) / PCI_MEMSLOTSIZE;
|
||||
|
||||
for (i = 0; (i < (PCI_MEMSLOTS-nrslots)); i++) {
|
||||
if (pci_shmemmap[i] == 0) {
|
||||
for (j = i+1; (j < (i+nrslots)); j++) {
|
||||
if (pci_shmemmap[j])
|
||||
goto restart;
|
||||
}
|
||||
|
||||
for (j = i; (j <= i+nrslots); j++)
|
||||
pci_shmemmap[j] = 1;
|
||||
break;
|
||||
}
|
||||
restart:
|
||||
}
|
||||
|
||||
return((void *) (COMEM_BASE + COMEM_SHMEM + (i * PCI_MEMSLOTSIZE)));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_bmfree(void *mp, int size)
|
||||
{
|
||||
int i, j, nrslots;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_bmfree(mp=%x,size=%d)\n", (int) mp, size);
|
||||
#endif
|
||||
|
||||
nrslots = size / PCI_MEMSLOTSIZE;
|
||||
i = (((unsigned long) mp) - (COMEM_BASE + COMEM_SHMEM)) /
|
||||
PCI_MEMSLOTSIZE;
|
||||
|
||||
for (j = i; (j < (i+nrslots)); j++)
|
||||
pci_shmemmap[j] = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
unsigned long pci_virt_to_bus(volatile void *address)
|
||||
{
|
||||
unsigned long l;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_virt_to_bus(address=%x)", (int) address);
|
||||
#endif
|
||||
|
||||
l = ((unsigned long) address) - COMEM_BASE;
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "=%x\n", (int) (l+pci_shmemaddr));
|
||||
#endif
|
||||
return(l + pci_shmemaddr);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void *pci_bus_to_virt(unsigned long address)
|
||||
{
|
||||
unsigned long l;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_bus_to_virt(address=%x)", (int) address);
|
||||
#endif
|
||||
|
||||
l = address - pci_shmemaddr;
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "=%x\n", (int) (address + COMEM_BASE));
|
||||
#endif
|
||||
return((void *) (address + COMEM_BASE));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_bmcpyto(void *dst, void *src, int len)
|
||||
{
|
||||
unsigned long *dp, *sp, val;
|
||||
unsigned char *dcp, *scp;
|
||||
int i, j;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_bmcpyto(dst=%x,src=%x,len=%d)\n", (int)dst, (int)src, len);
|
||||
#endif
|
||||
|
||||
dp = (unsigned long *) dst;
|
||||
sp = (unsigned long *) src;
|
||||
i = len >> 2;
|
||||
|
||||
#if 0
|
||||
printk(KERN_INFO "DATA:");
|
||||
scp = (unsigned char *) sp;
|
||||
for (i = 0; (i < len); i++) {
|
||||
if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i);
|
||||
printk(KERN_INFO "%02x ", *scp++);
|
||||
}
|
||||
printk(KERN_INFO "\n");
|
||||
#endif
|
||||
|
||||
for (j = 0; (i >= 0); i--, j++) {
|
||||
val = *sp++;
|
||||
val = (val << 24) | ((val & 0x0000ff00) << 8) |
|
||||
((val & 0x00ff0000) >> 8) | (val >> 24);
|
||||
*dp++ = val;
|
||||
}
|
||||
|
||||
if (len & 0x3) {
|
||||
dcp = (unsigned char *) dp;
|
||||
scp = ((unsigned char *) sp) + 3;
|
||||
for (i = 0; (i < (len & 0x3)); i++)
|
||||
*dcp++ = *scp--;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_bmcpyfrom(void *dst, void *src, int len)
|
||||
{
|
||||
unsigned long *dp, *sp, val;
|
||||
unsigned char *dcp, *scp;
|
||||
int i;
|
||||
|
||||
#ifdef DEBUGIO
|
||||
printk(KERN_DEBUG "pci_bmcpyfrom(dst=%x,src=%x,len=%d)\n",(int)dst,(int)src,len);
|
||||
#endif
|
||||
|
||||
dp = (unsigned long *) dst;
|
||||
sp = (unsigned long *) src;
|
||||
i = len >> 2;
|
||||
|
||||
for (; (i >= 0); i--) {
|
||||
val = *sp++;
|
||||
val = (val << 24) | ((val & 0x0000ff00) << 8) |
|
||||
((val & 0x00ff0000) >> 8) | (val >> 24);
|
||||
*dp++ = val;
|
||||
}
|
||||
|
||||
if (len & 0x3) {
|
||||
dcp = ((unsigned char *) dp) + 3;
|
||||
scp = (unsigned char *) sp;
|
||||
for (i = 0; (i < (len & 0x3)); i++)
|
||||
*dcp++ = *scp--;
|
||||
}
|
||||
|
||||
#if 0
|
||||
printk(KERN_INFO "DATA:");
|
||||
dcp = (unsigned char *) dst;
|
||||
for (i = 0; (i < len); i++) {
|
||||
if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i);
|
||||
printk(KERN_INFO "%02x ", *dcp++);
|
||||
}
|
||||
printk(KERN_INFO "\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void *pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_addr)
|
||||
{
|
||||
void *mp;
|
||||
if ((mp = pci_bmalloc(size)) != NULL) {
|
||||
dma_addr = mp - (COMEM_BASE + COMEM_SHMEM);
|
||||
return(mp);
|
||||
}
|
||||
*dma_addr = (dma_addr_t) NULL;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, dma_addr_t dma_addr)
|
||||
{
|
||||
pci_bmfree(cpu_addr, size);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
36
arch/m68knommu/kernel/dma.c
Normal file
36
arch/m68knommu/kernel/dma.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Dynamic DMA mapping support.
|
||||
*
|
||||
* We never have any address translations to worry about, so this
|
||||
* is just alloc/free.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, int gfp)
|
||||
{
|
||||
void *ret;
|
||||
/* ignore region specifiers */
|
||||
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
|
||||
|
||||
if (dev == NULL || (*dev->dma_mask < 0xffffffff))
|
||||
gfp |= GFP_DMA;
|
||||
ret = (void *)__get_free_pages(gfp, get_order(size));
|
||||
|
||||
if (ret != NULL) {
|
||||
memset(ret, 0, size);
|
||||
*dma_handle = virt_to_phys(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dma_free_coherent(struct device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle)
|
||||
{
|
||||
free_pages((unsigned long)vaddr, get_order(size));
|
||||
}
|
||||
143
arch/m68knommu/kernel/entry.S
Normal file
143
arch/m68knommu/kernel/entry.S
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/entry.S
|
||||
*
|
||||
* Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
|
||||
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
|
||||
* Kenneth Albanowski <kjahds@kjahds.com>,
|
||||
* Copyright (C) 2000 Lineo Inc. (www.lineo.com)
|
||||
*
|
||||
* Based on:
|
||||
*
|
||||
* linux/arch/m68k/kernel/entry.S
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file README.legal in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Linux/m68k support by Hamish Macdonald
|
||||
*
|
||||
* 68060 fixes by Jesper Skov
|
||||
* ColdFire support by Greg Ungerer (gerg@snapgear.com)
|
||||
* 5307 fixes by David W. Miller
|
||||
* linux 2.4 support David McCullough <davidm@snapgear.com>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sys.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/entry.h>
|
||||
|
||||
.text
|
||||
|
||||
.globl buserr
|
||||
.globl trap
|
||||
.globl ret_from_exception
|
||||
.globl ret_from_signal
|
||||
.globl sys_fork
|
||||
.globl sys_clone
|
||||
.globl sys_vfork
|
||||
|
||||
ENTRY(buserr)
|
||||
SAVE_ALL
|
||||
moveq #-1,%d0
|
||||
movel %d0,%sp@(PT_ORIG_D0)
|
||||
movel %sp,%sp@- /* stack frame pointer argument */
|
||||
jsr buserr_c
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
|
||||
ENTRY(trap)
|
||||
SAVE_ALL
|
||||
moveq #-1,%d0
|
||||
movel %d0,%sp@(PT_ORIG_D0)
|
||||
movel %sp,%sp@- /* stack frame pointer argument */
|
||||
jsr trap_c
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
|
||||
#ifdef TRAP_DBG_INTERRUPT
|
||||
|
||||
.globl dbginterrupt
|
||||
ENTRY(dbginterrupt)
|
||||
SAVE_ALL
|
||||
moveq #-1,%d0
|
||||
movel %d0,%sp@(PT_ORIG_D0)
|
||||
movel %sp,%sp@- /* stack frame pointer argument */
|
||||
jsr dbginterrupt_c
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
#endif
|
||||
|
||||
ENTRY(reschedule)
|
||||
/* save top of frame */
|
||||
pea %sp@
|
||||
jbsr set_esp0
|
||||
addql #4,%sp
|
||||
pea ret_from_exception
|
||||
jmp schedule
|
||||
|
||||
ENTRY(ret_from_fork)
|
||||
movel %d1,%sp@-
|
||||
jsr schedule_tail
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
|
||||
ENTRY(sys_fork)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr m68k_fork
|
||||
addql #4,%sp
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
ENTRY(sys_vfork)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr m68k_vfork
|
||||
addql #4,%sp
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
ENTRY(sys_clone)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr m68k_clone
|
||||
addql #4,%sp
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
ENTRY(sys_sigsuspend)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr do_sigsuspend
|
||||
addql #4,%sp
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
ENTRY(sys_rt_sigsuspend)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr do_rt_sigsuspend
|
||||
addql #4,%sp
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
ENTRY(sys_sigreturn)
|
||||
SAVE_SWITCH_STACK
|
||||
jbsr do_sigreturn
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
ENTRY(sys_rt_sigreturn)
|
||||
SAVE_SWITCH_STACK
|
||||
jbsr do_rt_sigreturn
|
||||
RESTORE_SWITCH_STACK
|
||||
rts
|
||||
|
||||
43
arch/m68knommu/kernel/init_task.c
Normal file
43
arch/m68knommu/kernel/init_task.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/init_task.c
|
||||
*/
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/init_task.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mqueue.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct files_struct init_files = INIT_FILES;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
||||
EXPORT_SYMBOL(init_mm);
|
||||
|
||||
/*
|
||||
* Initial task structure.
|
||||
*
|
||||
* All other task structs will be allocated on slabs in fork.c
|
||||
*/
|
||||
__asm__(".align 4");
|
||||
struct task_struct init_task = INIT_TASK(init_task);
|
||||
|
||||
EXPORT_SYMBOL(init_task);
|
||||
|
||||
/*
|
||||
* Initial thread structure.
|
||||
*
|
||||
* We need to make sure that this is 8192-byte aligned due to the
|
||||
* way process stacks are handled. This is done by having a special
|
||||
* "init_task" linker map entry..
|
||||
*/
|
||||
union thread_union init_thread_union
|
||||
__attribute__((__section__(".data.init_task"))) =
|
||||
{ INIT_THREAD_INFO(init_task) };
|
||||
|
||||
104
arch/m68knommu/kernel/m68k_ksyms.c
Normal file
104
arch/m68knommu/kernel/m68k_ksyms.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/elfcore.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/config.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/current.h>
|
||||
|
||||
extern void dump_thread(struct pt_regs *, struct user *);
|
||||
extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
|
||||
|
||||
/* platform dependent support */
|
||||
|
||||
EXPORT_SYMBOL(__ioremap);
|
||||
EXPORT_SYMBOL(iounmap);
|
||||
EXPORT_SYMBOL(dump_fpu);
|
||||
EXPORT_SYMBOL(dump_thread);
|
||||
EXPORT_SYMBOL(strnlen);
|
||||
EXPORT_SYMBOL(strrchr);
|
||||
EXPORT_SYMBOL(strstr);
|
||||
EXPORT_SYMBOL(strchr);
|
||||
EXPORT_SYMBOL(strcat);
|
||||
EXPORT_SYMBOL(strlen);
|
||||
EXPORT_SYMBOL(strcmp);
|
||||
EXPORT_SYMBOL(strncmp);
|
||||
|
||||
EXPORT_SYMBOL(ip_fast_csum);
|
||||
|
||||
EXPORT_SYMBOL(mach_enable_irq);
|
||||
EXPORT_SYMBOL(mach_disable_irq);
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
/* Networking helper routines. */
|
||||
EXPORT_SYMBOL(csum_partial_copy);
|
||||
|
||||
/* The following are special because they're not called
|
||||
explicitly (the C compiler generates them). Fortunately,
|
||||
their interface isn't gonna change any time soon now, so
|
||||
it's OK to leave it out of version control. */
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(memcmp);
|
||||
EXPORT_SYMBOL(memscan);
|
||||
EXPORT_SYMBOL(memmove);
|
||||
|
||||
EXPORT_SYMBOL(__down_failed);
|
||||
EXPORT_SYMBOL(__down_failed_interruptible);
|
||||
EXPORT_SYMBOL(__down_failed_trylock);
|
||||
EXPORT_SYMBOL(__up_wakeup);
|
||||
|
||||
EXPORT_SYMBOL(get_wchan);
|
||||
|
||||
/*
|
||||
* libgcc functions - functions that are used internally by the
|
||||
* compiler... (prototypes are not correct though, but that
|
||||
* doesn't really matter since they're not versioned).
|
||||
*/
|
||||
extern void __ashldi3(void);
|
||||
extern void __ashrdi3(void);
|
||||
extern void __divsi3(void);
|
||||
extern void __lshrdi3(void);
|
||||
extern void __modsi3(void);
|
||||
extern void __muldi3(void);
|
||||
extern void __mulsi3(void);
|
||||
extern void __udivsi3(void);
|
||||
extern void __umodsi3(void);
|
||||
|
||||
/* gcc lib functions */
|
||||
EXPORT_SYMBOL(__ashldi3);
|
||||
EXPORT_SYMBOL(__ashrdi3);
|
||||
EXPORT_SYMBOL(__divsi3);
|
||||
EXPORT_SYMBOL(__lshrdi3);
|
||||
EXPORT_SYMBOL(__modsi3);
|
||||
EXPORT_SYMBOL(__muldi3);
|
||||
EXPORT_SYMBOL(__mulsi3);
|
||||
EXPORT_SYMBOL(__udivsi3);
|
||||
EXPORT_SYMBOL(__umodsi3);
|
||||
|
||||
EXPORT_SYMBOL(is_in_rom);
|
||||
|
||||
#ifdef CONFIG_COLDFIRE
|
||||
extern unsigned int *dma_device_address;
|
||||
extern unsigned long dma_base_addr, _ramend;
|
||||
EXPORT_SYMBOL(dma_base_addr);
|
||||
EXPORT_SYMBOL(dma_device_address);
|
||||
EXPORT_SYMBOL(_ramend);
|
||||
|
||||
extern asmlinkage void trap(void);
|
||||
extern void *_ramvec;
|
||||
EXPORT_SYMBOL(trap);
|
||||
EXPORT_SYMBOL(_ramvec);
|
||||
#endif /* CONFIG_COLDFIRE */
|
||||
128
arch/m68knommu/kernel/module.c
Normal file
128
arch/m68knommu/kernel/module.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(fmt...)
|
||||
#endif
|
||||
|
||||
void *module_alloc(unsigned long size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
return vmalloc(size);
|
||||
}
|
||||
|
||||
|
||||
/* Free memory returned from module_alloc */
|
||||
void module_free(struct module *mod, void *module_region)
|
||||
{
|
||||
vfree(module_region);
|
||||
/* FIXME: If module_region == mod->init_region, trim exception
|
||||
table entries. */
|
||||
}
|
||||
|
||||
/* We don't need anything special. */
|
||||
int module_frob_arch_sections(Elf_Ehdr *hdr,
|
||||
Elf_Shdr *sechdrs,
|
||||
char *secstrings,
|
||||
struct module *mod)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apply_relocate(Elf32_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
unsigned int i;
|
||||
Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
|
||||
Elf32_Sym *sym;
|
||||
uint32_t *location;
|
||||
|
||||
DEBUGP("Applying relocate section %u to %u\n", relsec,
|
||||
sechdrs[relsec].sh_info);
|
||||
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||
/* This is where to make the change */
|
||||
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
|
||||
+ rel[i].r_offset;
|
||||
/* This is the symbol it is referring to. Note that all
|
||||
undefined symbols have been resolved. */
|
||||
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
|
||||
+ ELF32_R_SYM(rel[i].r_info);
|
||||
|
||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||
case R_68K_32:
|
||||
/* We add the value into the location given */
|
||||
*location += sym->st_value;
|
||||
break;
|
||||
case R_68K_PC32:
|
||||
/* Add the value, subtract its postition */
|
||||
*location += sym->st_value - (uint32_t)location;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
|
||||
me->name, ELF32_R_TYPE(rel[i].r_info));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apply_relocate_add(Elf32_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
unsigned int i;
|
||||
Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
||||
Elf32_Sym *sym;
|
||||
uint32_t *location;
|
||||
|
||||
DEBUGP("Applying relocate_add section %u to %u\n", relsec,
|
||||
sechdrs[relsec].sh_info);
|
||||
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||
/* This is where to make the change */
|
||||
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
|
||||
+ rel[i].r_offset;
|
||||
/* This is the symbol it is referring to. Note that all
|
||||
undefined symbols have been resolved. */
|
||||
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
|
||||
+ ELF32_R_SYM(rel[i].r_info);
|
||||
|
||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||
case R_68K_32:
|
||||
/* We add the value into the location given */
|
||||
*location = rel[i].r_addend + sym->st_value;
|
||||
break;
|
||||
case R_68K_PC32:
|
||||
/* Add the value, subtract its postition */
|
||||
*location = rel[i].r_addend + sym->st_value - (uint32_t)location;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
|
||||
me->name, ELF32_R_TYPE(rel[i].r_info));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int module_finalize(const Elf_Ehdr *hdr,
|
||||
const Elf_Shdr *sechdrs,
|
||||
struct module *me)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void module_arch_cleanup(struct module *mod)
|
||||
{
|
||||
}
|
||||
442
arch/m68knommu/kernel/process.c
Normal file
442
arch/m68knommu/kernel/process.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/process.c
|
||||
*
|
||||
* Copyright (C) 1995 Hamish Macdonald
|
||||
*
|
||||
* 68060 fixes by Jesper Skov
|
||||
*
|
||||
* uClinux changes
|
||||
* Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of process handling..
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/a.out.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
asmlinkage void ret_from_fork(void);
|
||||
|
||||
|
||||
/*
|
||||
* The idle loop on an m68knommu..
|
||||
*/
|
||||
void default_idle(void)
|
||||
{
|
||||
while(1) {
|
||||
if (need_resched())
|
||||
__asm__("stop #0x2000" : : : "cc");
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
void (*idle)(void) = default_idle;
|
||||
|
||||
/*
|
||||
* The idle thread. There's no useful work to be
|
||||
* done, so just try to conserve power and have a
|
||||
* low exit latency (ie sit in a loop waiting for
|
||||
* somebody to say that they'd like to reschedule)
|
||||
*/
|
||||
void cpu_idle(void)
|
||||
{
|
||||
/* endless idle loop with no priority at all */
|
||||
idle();
|
||||
}
|
||||
|
||||
void machine_restart(char * __unused)
|
||||
{
|
||||
if (mach_reset)
|
||||
mach_reset();
|
||||
for (;;);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(machine_restart);
|
||||
|
||||
void machine_halt(void)
|
||||
{
|
||||
if (mach_halt)
|
||||
mach_halt();
|
||||
for (;;);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(machine_halt);
|
||||
|
||||
void machine_power_off(void)
|
||||
{
|
||||
if (mach_power_off)
|
||||
mach_power_off();
|
||||
for (;;);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(machine_power_off);
|
||||
|
||||
void show_regs(struct pt_regs * regs)
|
||||
{
|
||||
printk(KERN_NOTICE "\n");
|
||||
printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
|
||||
regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
|
||||
printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
|
||||
regs->orig_d0, regs->d0, regs->a2, regs->a1);
|
||||
printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n",
|
||||
regs->a0, regs->d5, regs->d4);
|
||||
printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n",
|
||||
regs->d3, regs->d2, regs->d1);
|
||||
if (!(regs->sr & PS_S))
|
||||
printk(KERN_NOTICE "USP: %08lx\n", rdusp());
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a kernel thread
|
||||
*/
|
||||
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||
{
|
||||
int retval;
|
||||
long clone_arg = flags | CLONE_VM;
|
||||
mm_segment_t fs;
|
||||
|
||||
fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movel %%sp, %%d2\n\t"
|
||||
"movel %5, %%d1\n\t"
|
||||
"movel %1, %%d0\n\t"
|
||||
"trap #0\n\t"
|
||||
"cmpl %%sp, %%d2\n\t"
|
||||
"jeq 1f\n\t"
|
||||
"movel %3, %%sp@-\n\t"
|
||||
"jsr %4@\n\t"
|
||||
"movel %2, %%d0\n\t"
|
||||
"trap #0\n"
|
||||
"1:\n\t"
|
||||
"movel %%d0, %0\n"
|
||||
: "=d" (retval)
|
||||
: "i" (__NR_clone),
|
||||
"i" (__NR_exit),
|
||||
"a" (arg),
|
||||
"a" (fn),
|
||||
"a" (clone_arg)
|
||||
: "cc", "%d0", "%d1", "%d2");
|
||||
|
||||
set_fs(fs);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
#ifdef CONFIG_FPU
|
||||
unsigned long zero = 0;
|
||||
#endif
|
||||
set_fs(USER_DS);
|
||||
current->thread.fs = __USER_DS;
|
||||
#ifdef CONFIG_FPU
|
||||
if (!FPU_IS_EMU)
|
||||
asm volatile (".chip 68k/68881\n\t"
|
||||
"frestore %0@\n\t"
|
||||
".chip 68k" : : "a" (&zero));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* "m68k_fork()".. By the time we get here, the
|
||||
* non-volatile registers have also been saved on the
|
||||
* stack. We do some ugly pointer stuff here.. (see
|
||||
* also copy_thread)
|
||||
*/
|
||||
|
||||
asmlinkage int m68k_fork(struct pt_regs *regs)
|
||||
{
|
||||
/* fork almost works, enough to trick you into looking elsewhere :-( */
|
||||
return(-EINVAL);
|
||||
}
|
||||
|
||||
asmlinkage int m68k_vfork(struct pt_regs *regs)
|
||||
{
|
||||
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
asmlinkage int m68k_clone(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long clone_flags;
|
||||
unsigned long newsp;
|
||||
|
||||
/* syscall2 puts clone_flags in d1 and usp in d2 */
|
||||
clone_flags = regs->d1;
|
||||
newsp = regs->d2;
|
||||
if (!newsp)
|
||||
newsp = rdusp();
|
||||
return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
int copy_thread(int nr, unsigned long clone_flags,
|
||||
unsigned long usp, unsigned long topstk,
|
||||
struct task_struct * p, struct pt_regs * regs)
|
||||
{
|
||||
struct pt_regs * childregs;
|
||||
struct switch_stack * childstack, *stack;
|
||||
unsigned long stack_offset, *retp;
|
||||
|
||||
stack_offset = THREAD_SIZE - sizeof(struct pt_regs);
|
||||
childregs = (struct pt_regs *) ((unsigned long) p->thread_info + stack_offset);
|
||||
|
||||
*childregs = *regs;
|
||||
childregs->d0 = 0;
|
||||
|
||||
retp = ((unsigned long *) regs);
|
||||
stack = ((struct switch_stack *) retp) - 1;
|
||||
|
||||
childstack = ((struct switch_stack *) childregs) - 1;
|
||||
*childstack = *stack;
|
||||
childstack->retpc = (unsigned long)ret_from_fork;
|
||||
|
||||
p->thread.usp = usp;
|
||||
p->thread.ksp = (unsigned long)childstack;
|
||||
/*
|
||||
* Must save the current SFC/DFC value, NOT the value when
|
||||
* the parent was last descheduled - RGH 10-08-96
|
||||
*/
|
||||
p->thread.fs = get_fs().seg;
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
if (!FPU_IS_EMU) {
|
||||
/* Copy the current fpu state */
|
||||
asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
|
||||
|
||||
if (p->thread.fpstate[0])
|
||||
asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
|
||||
"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
|
||||
: : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
|
||||
: "memory");
|
||||
/* Restore the state in case the fpu was busy */
|
||||
asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fill in the fpu structure for a core dump. */
|
||||
|
||||
int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
|
||||
{
|
||||
#ifdef CONFIG_FPU
|
||||
char fpustate[216];
|
||||
|
||||
if (FPU_IS_EMU) {
|
||||
int i;
|
||||
|
||||
memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
|
||||
memcpy(fpu->fpregs, current->thread.fp, 96);
|
||||
/* Convert internal fpu reg representation
|
||||
* into long double format
|
||||
*/
|
||||
for (i = 0; i < 24; i += 3)
|
||||
fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
|
||||
((fpu->fpregs[i] & 0x0000ffff) << 16);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* First dump the fpu context to avoid protocol violation. */
|
||||
asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
|
||||
if (!fpustate[0])
|
||||
return 0;
|
||||
|
||||
asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
|
||||
:: "m" (fpu->fpcntl[0])
|
||||
: "memory");
|
||||
asm volatile ("fmovemx %/fp0-%/fp7,%0"
|
||||
:: "m" (fpu->fpregs[0])
|
||||
: "memory");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill in the user structure for a core dump..
|
||||
*/
|
||||
void dump_thread(struct pt_regs * regs, struct user * dump)
|
||||
{
|
||||
struct switch_stack *sw;
|
||||
|
||||
/* changed the size calculations - should hopefully work better. lbt */
|
||||
dump->magic = CMAGIC;
|
||||
dump->start_code = 0;
|
||||
dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
|
||||
dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
|
||||
dump->u_dsize = ((unsigned long) (current->mm->brk +
|
||||
(PAGE_SIZE-1))) >> PAGE_SHIFT;
|
||||
dump->u_dsize -= dump->u_tsize;
|
||||
dump->u_ssize = 0;
|
||||
|
||||
if (dump->start_stack < TASK_SIZE)
|
||||
dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
|
||||
|
||||
dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
|
||||
sw = ((struct switch_stack *)regs) - 1;
|
||||
dump->regs.d1 = regs->d1;
|
||||
dump->regs.d2 = regs->d2;
|
||||
dump->regs.d3 = regs->d3;
|
||||
dump->regs.d4 = regs->d4;
|
||||
dump->regs.d5 = regs->d5;
|
||||
dump->regs.d6 = sw->d6;
|
||||
dump->regs.d7 = sw->d7;
|
||||
dump->regs.a0 = regs->a0;
|
||||
dump->regs.a1 = regs->a1;
|
||||
dump->regs.a2 = regs->a2;
|
||||
dump->regs.a3 = sw->a3;
|
||||
dump->regs.a4 = sw->a4;
|
||||
dump->regs.a5 = sw->a5;
|
||||
dump->regs.a6 = sw->a6;
|
||||
dump->regs.d0 = regs->d0;
|
||||
dump->regs.orig_d0 = regs->orig_d0;
|
||||
dump->regs.stkadj = regs->stkadj;
|
||||
dump->regs.sr = regs->sr;
|
||||
dump->regs.pc = regs->pc;
|
||||
dump->regs.fmtvec = (regs->format << 12) | regs->vector;
|
||||
/* dump floating point stuff */
|
||||
dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic dumping code. Used for panic and debug.
|
||||
*/
|
||||
void dump(struct pt_regs *fp)
|
||||
{
|
||||
unsigned long *sp;
|
||||
unsigned char *tp;
|
||||
int i;
|
||||
|
||||
printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
|
||||
printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
|
||||
|
||||
if (current->mm) {
|
||||
printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
|
||||
(int) current->mm->start_code,
|
||||
(int) current->mm->end_code,
|
||||
(int) current->mm->start_data,
|
||||
(int) current->mm->end_data,
|
||||
(int) current->mm->end_data,
|
||||
(int) current->mm->brk);
|
||||
printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
|
||||
(int) current->mm->start_stack,
|
||||
(int)(((unsigned long) current) + THREAD_SIZE));
|
||||
}
|
||||
|
||||
printk(KERN_EMERG "PC: %08lx\n", fp->pc);
|
||||
printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp);
|
||||
printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
|
||||
fp->d0, fp->d1, fp->d2, fp->d3);
|
||||
printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
|
||||
fp->d4, fp->d5, fp->a0, fp->a1);
|
||||
printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) rdusp(),
|
||||
(unsigned int) fp);
|
||||
|
||||
printk(KERN_EMERG "\nCODE:");
|
||||
tp = ((unsigned char *) fp->pc) - 0x20;
|
||||
for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
|
||||
if ((i % 0x10) == 0)
|
||||
printk(KERN_EMERG "\n%08x: ", (int) (tp + i));
|
||||
printk(KERN_EMERG "%08x ", (int) *sp++);
|
||||
}
|
||||
printk(KERN_EMERG "\n");
|
||||
|
||||
printk(KERN_EMERG "\nKERNEL STACK:");
|
||||
tp = ((unsigned char *) fp) - 0x40;
|
||||
for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
|
||||
if ((i % 0x10) == 0)
|
||||
printk(KERN_EMERG "\n%08x: ", (int) (tp + i));
|
||||
printk(KERN_EMERG "%08x ", (int) *sp++);
|
||||
}
|
||||
printk(KERN_EMERG "\n");
|
||||
printk(KERN_EMERG "\n");
|
||||
|
||||
printk(KERN_EMERG "\nUSER STACK:");
|
||||
tp = (unsigned char *) (rdusp() - 0x10);
|
||||
for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
|
||||
if ((i % 0x10) == 0)
|
||||
printk(KERN_EMERG "\n%08x: ", (int) (tp + i));
|
||||
printk(KERN_EMERG "%08x ", (int) *sp++);
|
||||
}
|
||||
printk(KERN_EMERG "\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_execve() executes a new program.
|
||||
*/
|
||||
asmlinkage int sys_execve(char *name, char **argv, char **envp)
|
||||
{
|
||||
int error;
|
||||
char * filename;
|
||||
struct pt_regs *regs = (struct pt_regs *) &name;
|
||||
|
||||
lock_kernel();
|
||||
filename = getname(name);
|
||||
error = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
goto out;
|
||||
error = do_execve(filename, argv, envp, regs);
|
||||
putname(filename);
|
||||
out:
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
unsigned long fp, pc;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
|
||||
stack_page = (unsigned long)p;
|
||||
fp = ((struct switch_stack *)p->thread.ksp)->a6;
|
||||
do {
|
||||
if (fp < stack_page+sizeof(struct thread_info) ||
|
||||
fp >= 8184+stack_page)
|
||||
return 0;
|
||||
pc = ((unsigned long *)fp)[1];
|
||||
if (!in_sched_functions(pc))
|
||||
return pc;
|
||||
fp = *(unsigned long *) fp;
|
||||
} while (count++ < 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return saved PC of a blocked thread.
|
||||
*/
|
||||
unsigned long thread_saved_pc(struct task_struct *tsk)
|
||||
{
|
||||
struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
|
||||
|
||||
/* Check whether the thread is blocked in resume() */
|
||||
if (in_sched_functions(sw->retpc))
|
||||
return ((unsigned long *)sw->a6)[1];
|
||||
else
|
||||
return sw->retpc;
|
||||
}
|
||||
|
||||
383
arch/m68knommu/kernel/ptrace.c
Normal file
383
arch/m68knommu/kernel/ptrace.c
Normal file
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/ptrace.c
|
||||
*
|
||||
* Copyright (C) 1994 by Hamish Macdonald
|
||||
* Taken from linux/kernel/ptrace.c and modified for M680x0.
|
||||
* linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file COPYING in the main directory of
|
||||
* this archive for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/config.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* does not yet catch signals sent when the child dies.
|
||||
* in exit.c or in signal.c.
|
||||
*/
|
||||
|
||||
/* determines which bits in the SR the user has access to. */
|
||||
/* 1 = access 0 = no access */
|
||||
#define SR_MASK 0x001f
|
||||
|
||||
/* sets the trace bits. */
|
||||
#define TRACE_BITS 0x8000
|
||||
|
||||
/* Find the stack offset for a register, relative to thread.esp0. */
|
||||
#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
|
||||
#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
|
||||
- sizeof(struct switch_stack))
|
||||
/* Mapping from PT_xxx to the stack offset at which the register is
|
||||
saved. Notice that usp has no stack-slot and needs to be treated
|
||||
specially (see get_reg/put_reg below). */
|
||||
static int regoff[] = {
|
||||
PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
|
||||
PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
|
||||
PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
|
||||
SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
|
||||
PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
|
||||
};
|
||||
|
||||
/*
|
||||
* Get contents of register REGNO in task TASK.
|
||||
*/
|
||||
static inline long get_reg(struct task_struct *task, int regno)
|
||||
{
|
||||
unsigned long *addr;
|
||||
|
||||
if (regno == PT_USP)
|
||||
addr = &task->thread.usp;
|
||||
else if (regno < sizeof(regoff)/sizeof(regoff[0]))
|
||||
addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
|
||||
else
|
||||
return 0;
|
||||
return *addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write contents of register REGNO in task TASK.
|
||||
*/
|
||||
static inline int put_reg(struct task_struct *task, int regno,
|
||||
unsigned long data)
|
||||
{
|
||||
unsigned long *addr;
|
||||
|
||||
if (regno == PT_USP)
|
||||
addr = &task->thread.usp;
|
||||
else if (regno < sizeof(regoff)/sizeof(regoff[0]))
|
||||
addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
|
||||
else
|
||||
return -1;
|
||||
*addr = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by kernel/ptrace.c when detaching..
|
||||
*
|
||||
* Make sure the single step bit is not set.
|
||||
*/
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
unsigned long tmp;
|
||||
/* make sure the single step bit is not set. */
|
||||
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
|
||||
put_reg(child, PT_SR, tmp);
|
||||
}
|
||||
|
||||
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
|
||||
{
|
||||
struct task_struct *child;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
ret = -EPERM;
|
||||
if (request == PTRACE_TRACEME) {
|
||||
/* are we already being traced? */
|
||||
if (current->ptrace & PT_PTRACED)
|
||||
goto out;
|
||||
/* set the ptrace bit in the process flags. */
|
||||
current->ptrace |= PT_PTRACED;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
ret = -ESRCH;
|
||||
read_lock(&tasklist_lock);
|
||||
child = find_task_by_pid(pid);
|
||||
if (child)
|
||||
get_task_struct(child);
|
||||
read_unlock(&tasklist_lock);
|
||||
if (!child)
|
||||
goto out;
|
||||
|
||||
ret = -EPERM;
|
||||
if (pid == 1) /* you may not mess with init */
|
||||
goto out_tsk;
|
||||
|
||||
if (request == PTRACE_ATTACH) {
|
||||
ret = ptrace_attach(child);
|
||||
goto out_tsk;
|
||||
}
|
||||
ret = ptrace_check_attach(child, request == PTRACE_KILL);
|
||||
if (ret < 0)
|
||||
goto out_tsk;
|
||||
|
||||
switch (request) {
|
||||
/* when I and D space are separate, these will need to be fixed. */
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA: {
|
||||
unsigned long tmp;
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||
ret = -EIO;
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp,(unsigned long *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read the word at location addr in the USER area. */
|
||||
case PTRACE_PEEKUSR: {
|
||||
unsigned long tmp;
|
||||
|
||||
ret = -EIO;
|
||||
if ((addr & 3) || addr < 0 ||
|
||||
addr > sizeof(struct user) - 3)
|
||||
break;
|
||||
|
||||
tmp = 0; /* Default return condition */
|
||||
addr = addr >> 2; /* temporary hack. */
|
||||
ret = -EIO;
|
||||
if (addr < 19) {
|
||||
tmp = get_reg(child, addr);
|
||||
if (addr == PT_SR)
|
||||
tmp >>= 16;
|
||||
} else if (addr >= 21 && addr < 49) {
|
||||
tmp = child->thread.fp[addr - 21];
|
||||
#ifdef CONFIG_M68KFPU_EMU
|
||||
/* Convert internal fpu reg representation
|
||||
* into long double format
|
||||
*/
|
||||
if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
|
||||
tmp = ((tmp & 0xffff0000) << 15) |
|
||||
((tmp & 0x0000ffff) << 16);
|
||||
#endif
|
||||
} else if (addr == 49) {
|
||||
tmp = child->mm->start_code;
|
||||
} else if (addr == 50) {
|
||||
tmp = child->mm->start_data;
|
||||
} else if (addr == 51) {
|
||||
tmp = child->mm->end_code;
|
||||
} else
|
||||
break;
|
||||
ret = put_user(tmp,(unsigned long *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* when I and D space are separate, this will have to be fixed. */
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
case PTRACE_POKEDATA:
|
||||
ret = 0;
|
||||
if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
|
||||
break;
|
||||
ret = -EIO;
|
||||
break;
|
||||
|
||||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
||||
ret = -EIO;
|
||||
if ((addr & 3) || addr < 0 ||
|
||||
addr > sizeof(struct user) - 3)
|
||||
break;
|
||||
|
||||
addr = addr >> 2; /* temporary hack. */
|
||||
|
||||
if (addr == PT_SR) {
|
||||
data &= SR_MASK;
|
||||
data <<= 16;
|
||||
data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
|
||||
}
|
||||
if (addr < 19) {
|
||||
if (put_reg(child, addr, data))
|
||||
break;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (addr >= 21 && addr < 48)
|
||||
{
|
||||
#ifdef CONFIG_M68KFPU_EMU
|
||||
/* Convert long double format
|
||||
* into internal fpu reg representation
|
||||
*/
|
||||
if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
|
||||
data = (unsigned long)data << 15;
|
||||
data = (data & 0xffff0000) |
|
||||
((data & 0x0000ffff) >> 1);
|
||||
}
|
||||
#endif
|
||||
child->thread.fp[addr - 21] = data;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
||||
case PTRACE_CONT: { /* restart after signal. */
|
||||
long tmp;
|
||||
|
||||
ret = -EIO;
|
||||
if ((unsigned long) data > _NSIG)
|
||||
break;
|
||||
if (request == PTRACE_SYSCALL)
|
||||
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
else
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
child->exit_code = data;
|
||||
/* make sure the single step bit is not set. */
|
||||
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
|
||||
put_reg(child, PT_SR, tmp);
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* make the child exit. Best I can do is send it a sigkill.
|
||||
* perhaps it should be put in the status that it wants to
|
||||
* exit.
|
||||
*/
|
||||
case PTRACE_KILL: {
|
||||
long tmp;
|
||||
|
||||
ret = 0;
|
||||
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
|
||||
break;
|
||||
child->exit_code = SIGKILL;
|
||||
/* make sure the single step bit is not set. */
|
||||
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
|
||||
put_reg(child, PT_SR, tmp);
|
||||
wake_up_process(child);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SINGLESTEP: { /* set the trap flag. */
|
||||
long tmp;
|
||||
|
||||
ret = -EIO;
|
||||
if ((unsigned long) data > _NSIG)
|
||||
break;
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
|
||||
put_reg(child, PT_SR, tmp);
|
||||
|
||||
child->exit_code = data;
|
||||
/* give it a chance to run. */
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_DETACH: /* detach a process that was attached. */
|
||||
ret = ptrace_detach(child, data);
|
||||
break;
|
||||
|
||||
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
|
||||
int i;
|
||||
unsigned long tmp;
|
||||
for (i = 0; i < 19; i++) {
|
||||
tmp = get_reg(child, i);
|
||||
if (i == PT_SR)
|
||||
tmp >>= 16;
|
||||
if (put_user(tmp, (unsigned long *) data)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
data += sizeof(long);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
|
||||
int i;
|
||||
unsigned long tmp;
|
||||
for (i = 0; i < 19; i++) {
|
||||
if (get_user(tmp, (unsigned long *) data)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (i == PT_SR) {
|
||||
tmp &= SR_MASK;
|
||||
tmp <<= 16;
|
||||
tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
|
||||
}
|
||||
put_reg(child, i, tmp);
|
||||
data += sizeof(long);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef PTRACE_GETFPREGS
|
||||
case PTRACE_GETFPREGS: { /* Get the child FPU state. */
|
||||
ret = 0;
|
||||
if (copy_to_user((void *)data, &child->thread.fp,
|
||||
sizeof(struct user_m68kfp_struct)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PTRACE_SETFPREGS
|
||||
case PTRACE_SETFPREGS: { /* Set the child FPU state. */
|
||||
ret = 0;
|
||||
if (copy_from_user(&child->thread.fp, (void *)data,
|
||||
sizeof(struct user_m68kfp_struct)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
out_tsk:
|
||||
put_task_struct(child);
|
||||
out:
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage void syscall_trace(void)
|
||||
{
|
||||
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
return;
|
||||
if (!(current->ptrace & PT_PTRACED))
|
||||
return;
|
||||
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
|
||||
? 0x80 : 0));
|
||||
/*
|
||||
* this isn't the same as continuing with a signal, but it will do
|
||||
* for normal use. strace only continues with a signal if the
|
||||
* stopping signal is not SIGTRAP. -brl
|
||||
*/
|
||||
if (current->exit_code) {
|
||||
send_sig(current->exit_code, current, 1);
|
||||
current->exit_code = 0;
|
||||
}
|
||||
}
|
||||
134
arch/m68knommu/kernel/semaphore.c
Normal file
134
arch/m68knommu/kernel/semaphore.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Generic semaphore code. Buyer beware. Do your own
|
||||
* specific changes in <asm/semaphore-helper.h>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/semaphore-helper.h>
|
||||
|
||||
#ifndef CONFIG_RMW_INSNS
|
||||
spinlock_t semaphore_wake_lock;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Semaphores are implemented using a two-way counter:
|
||||
* The "count" variable is decremented for each process
|
||||
* that tries to sleep, while the "waking" variable is
|
||||
* incremented when the "up()" code goes to wake up waiting
|
||||
* processes.
|
||||
*
|
||||
* Notably, the inline "up()" and "down()" functions can
|
||||
* efficiently test if they need to do any extra work (up
|
||||
* needs to do something only if count was negative before
|
||||
* the increment operation.
|
||||
*
|
||||
* waking_non_zero() (from asm/semaphore.h) must execute
|
||||
* atomically.
|
||||
*
|
||||
* When __up() is called, the count was negative before
|
||||
* incrementing it, and we need to wake up somebody.
|
||||
*
|
||||
* This routine adds one to the count of processes that need to
|
||||
* wake up and exit. ALL waiting processes actually wake up but
|
||||
* only the one that gets to the "waking" field first will gate
|
||||
* through and acquire the semaphore. The others will go back
|
||||
* to sleep.
|
||||
*
|
||||
* Note that these functions are only called when there is
|
||||
* contention on the lock, and as such all this is the
|
||||
* "non-critical" part of the whole semaphore business. The
|
||||
* critical part is the inline stuff in <asm/semaphore.h>
|
||||
* where we want to avoid any extra jumps and calls.
|
||||
*/
|
||||
void __up(struct semaphore *sem)
|
||||
{
|
||||
wake_one_more(sem);
|
||||
wake_up(&sem->wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the "down" function. Return zero for semaphore acquired,
|
||||
* return negative for signalled out of the function.
|
||||
*
|
||||
* If called from __down, the return is ignored and the wait loop is
|
||||
* not interruptible. This means that a task waiting on a semaphore
|
||||
* using "down()" cannot be killed until someone does an "up()" on
|
||||
* the semaphore.
|
||||
*
|
||||
* If called from __down_interruptible, the return value gets checked
|
||||
* upon return. If the return value is negative then the task continues
|
||||
* with the negative value in the return register (it can be tested by
|
||||
* the caller).
|
||||
*
|
||||
* Either form may be used in conjunction with "up()".
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define DOWN_HEAD(task_state) \
|
||||
\
|
||||
\
|
||||
current->state = (task_state); \
|
||||
add_wait_queue(&sem->wait, &wait); \
|
||||
\
|
||||
/* \
|
||||
* Ok, we're set up. sem->count is known to be less than zero \
|
||||
* so we must wait. \
|
||||
* \
|
||||
* We can let go the lock for purposes of waiting. \
|
||||
* We re-acquire it after awaking so as to protect \
|
||||
* all semaphore operations. \
|
||||
* \
|
||||
* If "up()" is called before we call waking_non_zero() then \
|
||||
* we will catch it right away. If it is called later then \
|
||||
* we will have to go through a wakeup cycle to catch it. \
|
||||
* \
|
||||
* Multiple waiters contend for the semaphore lock to see \
|
||||
* who gets to gate through and who has to wait some more. \
|
||||
*/ \
|
||||
for (;;) {
|
||||
|
||||
#define DOWN_TAIL(task_state) \
|
||||
current->state = (task_state); \
|
||||
} \
|
||||
current->state = TASK_RUNNING; \
|
||||
remove_wait_queue(&sem->wait, &wait);
|
||||
|
||||
void __sched __down(struct semaphore * sem)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
DOWN_HEAD(TASK_UNINTERRUPTIBLE)
|
||||
if (waking_non_zero(sem))
|
||||
break;
|
||||
schedule();
|
||||
DOWN_TAIL(TASK_UNINTERRUPTIBLE)
|
||||
}
|
||||
|
||||
int __sched __down_interruptible(struct semaphore * sem)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int ret = 0;
|
||||
|
||||
DOWN_HEAD(TASK_INTERRUPTIBLE)
|
||||
|
||||
ret = waking_non_zero_interruptible(sem, current);
|
||||
if (ret)
|
||||
{
|
||||
if (ret == 1)
|
||||
/* ret != 0 only if we get interrupted -arca */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
schedule();
|
||||
DOWN_TAIL(TASK_INTERRUPTIBLE)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __down_trylock(struct semaphore * sem)
|
||||
{
|
||||
return waking_non_zero_trylock(sem);
|
||||
}
|
||||
347
arch/m68knommu/kernel/setup.c
Normal file
347
arch/m68knommu/kernel/setup.c
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/setup.c
|
||||
*
|
||||
* Copyright (C) 1999-2004 Greg Ungerer (gerg@snapgear.com)
|
||||
* Copyright (C) 1998,1999 D. Jeff Dionne <jeff@lineo.ca>
|
||||
* Copyleft ()) 2000 James D. Schettine {james@telos-systems.com}
|
||||
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
|
||||
* Copyright (C) 1995 Hamish Macdonald
|
||||
* Copyright (C) 2000 Lineo Inc. (www.lineo.com)
|
||||
* Copyright (C) 2001 Lineo, Inc. <www.lineo.com>
|
||||
*
|
||||
* 68VZ328 Fixes/support Evan Stawnyczy <e@lineo.ca>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of system setup
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
#include <asm/pgtable.h>
|
||||
#endif
|
||||
|
||||
unsigned long rom_length;
|
||||
unsigned long memory_start;
|
||||
unsigned long memory_end;
|
||||
|
||||
char command_line[COMMAND_LINE_SIZE];
|
||||
|
||||
/* setup some dummy routines */
|
||||
static void dummy_waitbut(void)
|
||||
{
|
||||
}
|
||||
|
||||
void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) = NULL;
|
||||
void (*mach_tick)( void ) = NULL;
|
||||
/* machine dependent keyboard functions */
|
||||
int (*mach_keyb_init) (void) = NULL;
|
||||
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
|
||||
void (*mach_kbd_leds) (unsigned int) = NULL;
|
||||
/* machine dependent irq functions */
|
||||
void (*mach_init_IRQ) (void) = NULL;
|
||||
irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
|
||||
void (*mach_enable_irq) (unsigned int) = NULL;
|
||||
void (*mach_disable_irq) (unsigned int) = NULL;
|
||||
int (*mach_get_irq_list) (struct seq_file *, void *) = NULL;
|
||||
void (*mach_process_int) (int irq, struct pt_regs *fp) = NULL;
|
||||
void (*mach_trap_init) (void);
|
||||
/* machine dependent timer functions */
|
||||
unsigned long (*mach_gettimeoffset) (void) = NULL;
|
||||
void (*mach_gettod) (int*, int*, int*, int*, int*, int*) = NULL;
|
||||
int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
|
||||
int (*mach_set_clock_mmss) (unsigned long) = NULL;
|
||||
void (*mach_mksound)( unsigned int count, unsigned int ticks ) = NULL;
|
||||
void (*mach_reset)( void ) = NULL;
|
||||
void (*waitbut)(void) = dummy_waitbut;
|
||||
void (*mach_debug_init)(void) = NULL;
|
||||
void (*mach_halt)( void ) = NULL;
|
||||
void (*mach_power_off)( void ) = NULL;
|
||||
|
||||
|
||||
#ifdef CONFIG_M68000
|
||||
#define CPU "MC68000"
|
||||
#endif
|
||||
#ifdef CONFIG_M68328
|
||||
#define CPU "MC68328"
|
||||
#endif
|
||||
#ifdef CONFIG_M68EZ328
|
||||
#define CPU "MC68EZ328"
|
||||
#endif
|
||||
#ifdef CONFIG_M68VZ328
|
||||
#define CPU "MC68VZ328"
|
||||
#endif
|
||||
#ifdef CONFIG_M68332
|
||||
#define CPU "MC68332"
|
||||
#endif
|
||||
#ifdef CONFIG_M68360
|
||||
#define CPU "MC68360"
|
||||
#endif
|
||||
#if defined(CONFIG_M5206)
|
||||
#define CPU "COLDFIRE(m5206)"
|
||||
#endif
|
||||
#if defined(CONFIG_M5206e)
|
||||
#define CPU "COLDFIRE(m5206e)"
|
||||
#endif
|
||||
#if defined(CONFIG_M5249)
|
||||
#define CPU "COLDFIRE(m5249)"
|
||||
#endif
|
||||
#if defined(CONFIG_M527x)
|
||||
#define CPU "COLDFIRE(m5270/5271/5274/5275)"
|
||||
#endif
|
||||
#if defined(CONFIG_M5272)
|
||||
#define CPU "COLDFIRE(m5272)"
|
||||
#endif
|
||||
#if defined(CONFIG_M528x)
|
||||
#define CPU "COLDFIRE(m5280/5282)"
|
||||
#endif
|
||||
#if defined(CONFIG_M5307)
|
||||
#define CPU "COLDFIRE(m5307)"
|
||||
#endif
|
||||
#if defined(CONFIG_M5407)
|
||||
#define CPU "COLDFIRE(m5407)"
|
||||
#endif
|
||||
#ifndef CPU
|
||||
#define CPU "UNKOWN"
|
||||
#endif
|
||||
|
||||
/* (es) */
|
||||
/* note: why is this defined here? the must be a better place to put this */
|
||||
#if defined( CONFIG_TELOS) || defined( CONFIG_UCDIMM ) || defined( CONFIG_UCSIMM ) || defined(CONFIG_DRAGEN2) || (defined( CONFIG_PILOT ) && defined( CONFIG_M68328 ))
|
||||
#define CAT_ROMARRAY
|
||||
#endif
|
||||
/* (/es) */
|
||||
|
||||
extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
|
||||
extern int _ramstart, _ramend;
|
||||
|
||||
void setup_arch(char **cmdline_p)
|
||||
{
|
||||
int bootmap_size;
|
||||
|
||||
#if defined(CAT_ROMARRAY) && defined(DEBUG)
|
||||
extern int __data_rom_start;
|
||||
extern int __data_start;
|
||||
int *romarray = (int *)((int) &__data_rom_start +
|
||||
(int)&_edata - (int)&__data_start);
|
||||
#endif
|
||||
|
||||
memory_start = PAGE_ALIGN(_ramstart);
|
||||
memory_end = _ramend; /* by now the stack is part of the init task */
|
||||
|
||||
init_mm.start_code = (unsigned long) &_stext;
|
||||
init_mm.end_code = (unsigned long) &_etext;
|
||||
init_mm.end_data = (unsigned long) &_edata;
|
||||
init_mm.brk = (unsigned long) 0;
|
||||
|
||||
config_BSP(&command_line[0], sizeof(command_line));
|
||||
|
||||
printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU "\n");
|
||||
|
||||
#ifdef CONFIG_UCDIMM
|
||||
printk(KERN_INFO "uCdimm by Lineo, Inc. <www.lineo.com>\n");
|
||||
#endif
|
||||
#ifdef CONFIG_M68VZ328
|
||||
printk(KERN_INFO "M68VZ328 support by Evan Stawnyczy <e@lineo.ca>\n");
|
||||
#endif
|
||||
#ifdef CONFIG_COLDFIRE
|
||||
printk(KERN_INFO "COLDFIRE port done by Greg Ungerer, gerg@snapgear.com\n");
|
||||
#ifdef CONFIG_M5307
|
||||
printk(KERN_INFO "Modified for M5307 by Dave Miller, dmiller@intellistor.com\n");
|
||||
#endif
|
||||
#ifdef CONFIG_ELITE
|
||||
printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
|
||||
#endif
|
||||
#ifdef CONFIG_TELOS
|
||||
printk(KERN_INFO "Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n");
|
||||
#endif
|
||||
#endif
|
||||
printk(KERN_INFO "Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
|
||||
|
||||
#if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )
|
||||
printk(KERN_INFO "TRG SuperPilot FLASH card support <info@trgnet.com>\n");
|
||||
#endif
|
||||
|
||||
#if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 )
|
||||
printk(KERN_INFO "PalmV support by Lineo Inc. <jeff@uclinux.com>\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_M68EZ328ADS
|
||||
printk(KERN_INFO "M68EZ328ADS board support (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ALMA_ANS
|
||||
printk(KERN_INFO "Alma Electronics board support (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>\n");
|
||||
#endif
|
||||
#if defined (CONFIG_M68360)
|
||||
printk(KERN_INFO "QUICC port done by SED Systems <hamilton@sedsystems.ca>,\n");
|
||||
printk(KERN_INFO "based on 2.0.38 port by Lineo Inc. <mleslie@lineo.com>.\n");
|
||||
#endif
|
||||
#ifdef CONFIG_DRAGEN2
|
||||
printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
|
||||
"BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
|
||||
(int) &_sdata, (int) &_edata,
|
||||
(int) &_sbss, (int) &_ebss);
|
||||
printk(KERN_DEBUG "KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x "
|
||||
"STACK=0x%06x-0x%06x\n",
|
||||
#ifdef CAT_ROMARRAY
|
||||
(int) romarray, ((int) romarray) + romarray[2],
|
||||
#else
|
||||
(int) &_ebss, (int) memory_start,
|
||||
#endif
|
||||
(int) memory_start, (int) memory_end,
|
||||
(int) memory_end, (int) _ramend);
|
||||
#endif
|
||||
|
||||
/* Keep a copy of command line */
|
||||
*cmdline_p = &command_line[0];
|
||||
memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
|
||||
saved_command_line[COMMAND_LINE_SIZE-1] = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (strlen(*cmdline_p))
|
||||
printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
|
||||
conswitchp = &dummy_con;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Give all the memory to the bootmap allocator, tell it to put the
|
||||
* boot mem_map at the start of memory.
|
||||
*/
|
||||
bootmap_size = init_bootmem_node(
|
||||
NODE_DATA(0),
|
||||
memory_start >> PAGE_SHIFT, /* map goes here */
|
||||
PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */
|
||||
memory_end >> PAGE_SHIFT);
|
||||
/*
|
||||
* Free the usable memory, we have to make sure we do not free
|
||||
* the bootmem bitmap so we then reserve it after freeing it :-)
|
||||
*/
|
||||
free_bootmem(memory_start, memory_end - memory_start);
|
||||
reserve_bootmem(memory_start, bootmap_size);
|
||||
|
||||
/*
|
||||
* Get kmalloc into gear.
|
||||
*/
|
||||
paging_init();
|
||||
}
|
||||
|
||||
int get_cpuinfo(char * buffer)
|
||||
{
|
||||
char *cpu, *mmu, *fpu;
|
||||
u_long clockfreq;
|
||||
|
||||
cpu = CPU;
|
||||
mmu = "none";
|
||||
fpu = "none";
|
||||
|
||||
#ifdef CONFIG_COLDFIRE
|
||||
clockfreq = (loops_per_jiffy*HZ)*3;
|
||||
#else
|
||||
clockfreq = (loops_per_jiffy*HZ)*16;
|
||||
#endif
|
||||
|
||||
return(sprintf(buffer, "CPU:\t\t%s\n"
|
||||
"MMU:\t\t%s\n"
|
||||
"FPU:\t\t%s\n"
|
||||
"Clocking:\t%lu.%1luMHz\n"
|
||||
"BogoMips:\t%lu.%02lu\n"
|
||||
"Calibration:\t%lu loops\n",
|
||||
cpu, mmu, fpu,
|
||||
clockfreq/1000000,(clockfreq/100000)%10,
|
||||
(loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
|
||||
(loops_per_jiffy*HZ)));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Get CPU information for use by the procfs.
|
||||
*/
|
||||
|
||||
static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
{
|
||||
char *cpu, *mmu, *fpu;
|
||||
u_long clockfreq;
|
||||
|
||||
cpu = CPU;
|
||||
mmu = "none";
|
||||
fpu = "none";
|
||||
|
||||
#ifdef CONFIG_COLDFIRE
|
||||
clockfreq = (loops_per_jiffy*HZ)*3;
|
||||
#else
|
||||
clockfreq = (loops_per_jiffy*HZ)*16;
|
||||
#endif
|
||||
|
||||
seq_printf(m, "CPU:\t\t%s\n"
|
||||
"MMU:\t\t%s\n"
|
||||
"FPU:\t\t%s\n"
|
||||
"Clocking:\t%lu.%1luMHz\n"
|
||||
"BogoMips:\t%lu.%02lu\n"
|
||||
"Calibration:\t%lu loops\n",
|
||||
cpu, mmu, fpu,
|
||||
clockfreq/1000000,(clockfreq/100000)%10,
|
||||
(loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
|
||||
(loops_per_jiffy*HZ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *c_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL;
|
||||
}
|
||||
|
||||
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
return c_start(m, pos);
|
||||
}
|
||||
|
||||
static void c_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
}
|
||||
|
||||
struct seq_operations cpuinfo_op = {
|
||||
.start = c_start,
|
||||
.next = c_next,
|
||||
.stop = c_stop,
|
||||
.show = show_cpuinfo,
|
||||
};
|
||||
|
||||
void arch_gettod(int *year, int *mon, int *day, int *hour,
|
||||
int *min, int *sec)
|
||||
{
|
||||
if (mach_gettod)
|
||||
mach_gettod(year, mon, day, hour, min, sec);
|
||||
else
|
||||
*year = *mon = *day = *hour = *min = *sec = 0;
|
||||
}
|
||||
|
||||
788
arch/m68knommu/kernel/signal.c
Normal file
788
arch/m68knommu/kernel/signal.c
Normal file
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/signal.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Linux/m68k support by Hamish Macdonald
|
||||
*
|
||||
* 68060 fixes by Jesper Skov
|
||||
*
|
||||
* 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
|
||||
*
|
||||
* mathemu support by Roman Zippel
|
||||
* (Note: fpstate in the signal context is completely ignored for the emulator
|
||||
* and the internal floating point format is put on stack)
|
||||
*/
|
||||
|
||||
/*
|
||||
* ++roman (07/09/96): implemented signal stacks (specially for tosemu on
|
||||
* Atari :-) Current limitation: Only one sigstack can be active at one time.
|
||||
* If a second signal with SA_ONSTACK set arrives while working on a sigstack,
|
||||
* SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
|
||||
* signal handlers!
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/highuid.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/binfmts.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/ucontext.h>
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
|
||||
|
||||
/*
|
||||
* Atomically swap in the new signal mask, and wait for a signal.
|
||||
*/
|
||||
asmlinkage int do_sigsuspend(struct pt_regs *regs)
|
||||
{
|
||||
old_sigset_t mask = regs->d3;
|
||||
sigset_t saveset;
|
||||
|
||||
mask &= _BLOCKABLE;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
saveset = current->blocked;
|
||||
siginitset(¤t->blocked, mask);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
regs->d0 = -EINTR;
|
||||
while (1) {
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
if (do_signal(&saveset, regs))
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
do_rt_sigsuspend(struct pt_regs *regs)
|
||||
{
|
||||
sigset_t *unewset = (sigset_t *)regs->d1;
|
||||
size_t sigsetsize = (size_t)regs->d2;
|
||||
sigset_t saveset, newset;
|
||||
|
||||
/* XXX: Don't preclude handling different sized sigset_t's. */
|
||||
if (sigsetsize != sizeof(sigset_t))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&newset, unewset, sizeof(newset)))
|
||||
return -EFAULT;
|
||||
sigdelsetmask(&newset, ~_BLOCKABLE);
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
saveset = current->blocked;
|
||||
current->blocked = newset;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
regs->d0 = -EINTR;
|
||||
while (1) {
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
if (do_signal(&saveset, regs))
|
||||
return -EINTR;
|
||||
}
|
||||
}
|
||||
|
||||
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 (!access_ok(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);
|
||||
}
|
||||
|
||||
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
|
||||
|
||||
if (!ret && oact) {
|
||||
if (!access_ok(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_sigaltstack(const stack_t *uss, stack_t *uoss)
|
||||
{
|
||||
return do_sigaltstack(uss, uoss, rdusp());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do a signal return; undo the signal stack.
|
||||
*
|
||||
* Keep the return code on the stack quadword aligned!
|
||||
* That makes the cache flush below easier.
|
||||
*/
|
||||
|
||||
struct sigframe
|
||||
{
|
||||
char *pretcode;
|
||||
int sig;
|
||||
int code;
|
||||
struct sigcontext *psc;
|
||||
char retcode[8];
|
||||
unsigned long extramask[_NSIG_WORDS-1];
|
||||
struct sigcontext sc;
|
||||
};
|
||||
|
||||
struct rt_sigframe
|
||||
{
|
||||
char *pretcode;
|
||||
int sig;
|
||||
struct siginfo *pinfo;
|
||||
void *puc;
|
||||
char retcode[8];
|
||||
struct siginfo info;
|
||||
struct ucontext uc;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
|
||||
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
|
||||
|
||||
static inline int restore_fpu_state(struct sigcontext *sc)
|
||||
{
|
||||
int err = 1;
|
||||
|
||||
if (FPU_IS_EMU) {
|
||||
/* restore registers */
|
||||
memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
|
||||
memcpy(current->thread.fp, sc->sc_fpregs, 24);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sc->sc_fpstate[0]) {
|
||||
/* Verify the frame format. */
|
||||
if (sc->sc_fpstate[0] != fpu_version)
|
||||
goto out;
|
||||
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"fmovemx %0,%/fp0-%/fp1\n\t"
|
||||
"fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
|
||||
".chip 68k"
|
||||
: /* no outputs */
|
||||
: "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
|
||||
}
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"frestore %0\n\t"
|
||||
".chip 68k" : : "m" (*sc->sc_fpstate));
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#define FPCONTEXT_SIZE 216
|
||||
#define uc_fpstate uc_filler[0]
|
||||
#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
|
||||
#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
|
||||
|
||||
static inline int rt_restore_fpu_state(struct ucontext *uc)
|
||||
{
|
||||
unsigned char fpstate[FPCONTEXT_SIZE];
|
||||
int context_size = 0;
|
||||
fpregset_t fpregs;
|
||||
int err = 1;
|
||||
|
||||
if (FPU_IS_EMU) {
|
||||
/* restore fpu control register */
|
||||
if (__copy_from_user(current->thread.fpcntl,
|
||||
&uc->uc_mcontext.fpregs.f_pcr, 12))
|
||||
goto out;
|
||||
/* restore all other fpu register */
|
||||
if (__copy_from_user(current->thread.fp,
|
||||
uc->uc_mcontext.fpregs.f_fpregs, 96))
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
|
||||
goto out;
|
||||
if (fpstate[0]) {
|
||||
context_size = fpstate[1];
|
||||
|
||||
/* Verify the frame format. */
|
||||
if (fpstate[0] != fpu_version)
|
||||
goto out;
|
||||
if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
|
||||
sizeof(fpregs)))
|
||||
goto out;
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"fmovemx %0,%/fp0-%/fp7\n\t"
|
||||
"fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
|
||||
".chip 68k"
|
||||
: /* no outputs */
|
||||
: "m" (*fpregs.f_fpregs),
|
||||
"m" (fpregs.f_pcr));
|
||||
}
|
||||
if (context_size &&
|
||||
__copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
|
||||
context_size))
|
||||
goto out;
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"frestore %0\n\t"
|
||||
".chip 68k" : : "m" (*fpstate));
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
|
||||
int *pd0)
|
||||
{
|
||||
int formatvec;
|
||||
struct sigcontext context;
|
||||
int err = 0;
|
||||
|
||||
/* get previous context */
|
||||
if (copy_from_user(&context, usc, sizeof(context)))
|
||||
goto badframe;
|
||||
|
||||
/* restore passed registers */
|
||||
regs->d1 = context.sc_d1;
|
||||
regs->a0 = context.sc_a0;
|
||||
regs->a1 = context.sc_a1;
|
||||
regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
|
||||
regs->pc = context.sc_pc;
|
||||
regs->orig_d0 = -1; /* disable syscall checks */
|
||||
wrusp(context.sc_usp);
|
||||
formatvec = context.sc_formatvec;
|
||||
regs->format = formatvec >> 12;
|
||||
regs->vector = formatvec & 0xfff;
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
err = restore_fpu_state(&context);
|
||||
#endif
|
||||
|
||||
*pd0 = context.sc_d0;
|
||||
return err;
|
||||
|
||||
badframe:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
|
||||
struct ucontext *uc, int *pd0)
|
||||
{
|
||||
int temp;
|
||||
greg_t *gregs = uc->uc_mcontext.gregs;
|
||||
unsigned long usp;
|
||||
int err;
|
||||
|
||||
err = __get_user(temp, &uc->uc_mcontext.version);
|
||||
if (temp != MCONTEXT_VERSION)
|
||||
goto badframe;
|
||||
/* restore passed registers */
|
||||
err |= __get_user(regs->d0, &gregs[0]);
|
||||
err |= __get_user(regs->d1, &gregs[1]);
|
||||
err |= __get_user(regs->d2, &gregs[2]);
|
||||
err |= __get_user(regs->d3, &gregs[3]);
|
||||
err |= __get_user(regs->d4, &gregs[4]);
|
||||
err |= __get_user(regs->d5, &gregs[5]);
|
||||
err |= __get_user(sw->d6, &gregs[6]);
|
||||
err |= __get_user(sw->d7, &gregs[7]);
|
||||
err |= __get_user(regs->a0, &gregs[8]);
|
||||
err |= __get_user(regs->a1, &gregs[9]);
|
||||
err |= __get_user(regs->a2, &gregs[10]);
|
||||
err |= __get_user(sw->a3, &gregs[11]);
|
||||
err |= __get_user(sw->a4, &gregs[12]);
|
||||
err |= __get_user(sw->a5, &gregs[13]);
|
||||
err |= __get_user(sw->a6, &gregs[14]);
|
||||
err |= __get_user(usp, &gregs[15]);
|
||||
wrusp(usp);
|
||||
err |= __get_user(regs->pc, &gregs[16]);
|
||||
err |= __get_user(temp, &gregs[17]);
|
||||
regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
|
||||
regs->orig_d0 = -1; /* disable syscall checks */
|
||||
regs->format = temp >> 12;
|
||||
regs->vector = temp & 0xfff;
|
||||
|
||||
if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
|
||||
goto badframe;
|
||||
|
||||
*pd0 = regs->d0;
|
||||
return err;
|
||||
|
||||
badframe:
|
||||
return 1;
|
||||
}
|
||||
|
||||
asmlinkage int do_sigreturn(unsigned long __unused)
|
||||
{
|
||||
struct switch_stack *sw = (struct switch_stack *) &__unused;
|
||||
struct pt_regs *regs = (struct pt_regs *) (sw + 1);
|
||||
unsigned long usp = rdusp();
|
||||
struct sigframe *frame = (struct sigframe *)(usp - 4);
|
||||
sigset_t set;
|
||||
int d0;
|
||||
|
||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
|
||||
(_NSIG_WORDS > 1 &&
|
||||
__copy_from_user(&set.sig[1], &frame->extramask,
|
||||
sizeof(frame->extramask))))
|
||||
goto badframe;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
|
||||
goto badframe;
|
||||
return d0;
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage int do_rt_sigreturn(unsigned long __unused)
|
||||
{
|
||||
struct switch_stack *sw = (struct switch_stack *) &__unused;
|
||||
struct pt_regs *regs = (struct pt_regs *) (sw + 1);
|
||||
unsigned long usp = rdusp();
|
||||
struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
|
||||
sigset_t set;
|
||||
int d0;
|
||||
|
||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||
goto badframe;
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
|
||||
goto badframe;
|
||||
return d0;
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FPU
|
||||
/*
|
||||
* Set up a signal frame.
|
||||
*/
|
||||
|
||||
static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
|
||||
{
|
||||
if (FPU_IS_EMU) {
|
||||
/* save registers */
|
||||
memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
|
||||
memcpy(sc->sc_fpregs, current->thread.fp, 24);
|
||||
return;
|
||||
}
|
||||
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"fsave %0\n\t"
|
||||
".chip 68k"
|
||||
: : "m" (*sc->sc_fpstate) : "memory");
|
||||
|
||||
if (sc->sc_fpstate[0]) {
|
||||
fpu_version = sc->sc_fpstate[0];
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"fmovemx %/fp0-%/fp1,%0\n\t"
|
||||
"fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
|
||||
".chip 68k"
|
||||
: /* no outputs */
|
||||
: "m" (*sc->sc_fpregs),
|
||||
"m" (*sc->sc_fpcntl)
|
||||
: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
|
||||
{
|
||||
unsigned char fpstate[FPCONTEXT_SIZE];
|
||||
int context_size = 0;
|
||||
int err = 0;
|
||||
|
||||
if (FPU_IS_EMU) {
|
||||
/* save fpu control register */
|
||||
err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr,
|
||||
current->thread.fpcntl, 12);
|
||||
/* save all other fpu register */
|
||||
err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
|
||||
current->thread.fp, 96);
|
||||
return err;
|
||||
}
|
||||
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"fsave %0\n\t"
|
||||
".chip 68k"
|
||||
: : "m" (*fpstate) : "memory");
|
||||
|
||||
err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
|
||||
if (fpstate[0]) {
|
||||
fpregset_t fpregs;
|
||||
context_size = fpstate[1];
|
||||
fpu_version = fpstate[0];
|
||||
__asm__ volatile (".chip 68k/68881\n\t"
|
||||
"fmovemx %/fp0-%/fp7,%0\n\t"
|
||||
"fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
|
||||
".chip 68k"
|
||||
: /* no outputs */
|
||||
: "m" (*fpregs.f_fpregs),
|
||||
"m" (fpregs.f_pcr)
|
||||
: "memory");
|
||||
err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
|
||||
sizeof(fpregs));
|
||||
}
|
||||
if (context_size)
|
||||
err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
|
||||
context_size);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
|
||||
unsigned long mask)
|
||||
{
|
||||
sc->sc_mask = mask;
|
||||
sc->sc_usp = rdusp();
|
||||
sc->sc_d0 = regs->d0;
|
||||
sc->sc_d1 = regs->d1;
|
||||
sc->sc_a0 = regs->a0;
|
||||
sc->sc_a1 = regs->a1;
|
||||
sc->sc_sr = regs->sr;
|
||||
sc->sc_pc = regs->pc;
|
||||
sc->sc_formatvec = regs->format << 12 | regs->vector;
|
||||
#ifdef CONFIG_FPU
|
||||
save_fpu_state(sc, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
|
||||
{
|
||||
struct switch_stack *sw = (struct switch_stack *)regs - 1;
|
||||
greg_t *gregs = uc->uc_mcontext.gregs;
|
||||
int err = 0;
|
||||
|
||||
err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
|
||||
err |= __put_user(regs->d0, &gregs[0]);
|
||||
err |= __put_user(regs->d1, &gregs[1]);
|
||||
err |= __put_user(regs->d2, &gregs[2]);
|
||||
err |= __put_user(regs->d3, &gregs[3]);
|
||||
err |= __put_user(regs->d4, &gregs[4]);
|
||||
err |= __put_user(regs->d5, &gregs[5]);
|
||||
err |= __put_user(sw->d6, &gregs[6]);
|
||||
err |= __put_user(sw->d7, &gregs[7]);
|
||||
err |= __put_user(regs->a0, &gregs[8]);
|
||||
err |= __put_user(regs->a1, &gregs[9]);
|
||||
err |= __put_user(regs->a2, &gregs[10]);
|
||||
err |= __put_user(sw->a3, &gregs[11]);
|
||||
err |= __put_user(sw->a4, &gregs[12]);
|
||||
err |= __put_user(sw->a5, &gregs[13]);
|
||||
err |= __put_user(sw->a6, &gregs[14]);
|
||||
err |= __put_user(rdusp(), &gregs[15]);
|
||||
err |= __put_user(regs->pc, &gregs[16]);
|
||||
err |= __put_user(regs->sr, &gregs[17]);
|
||||
#ifdef CONFIG_FPU
|
||||
err |= rt_save_fpu_state(uc, regs);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void push_cache (unsigned long vaddr)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void *
|
||||
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
|
||||
{
|
||||
unsigned long usp;
|
||||
|
||||
/* Default to using normal stack. */
|
||||
usp = rdusp();
|
||||
|
||||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if (ka->sa.sa_flags & SA_ONSTACK) {
|
||||
if (!on_sig_stack(usp))
|
||||
usp = current->sas_ss_sp + current->sas_ss_size;
|
||||
}
|
||||
return (void *)((usp - frame_size) & -8UL);
|
||||
}
|
||||
|
||||
static void setup_frame (int sig, struct k_sigaction *ka,
|
||||
sigset_t *set, struct pt_regs *regs)
|
||||
{
|
||||
struct sigframe *frame;
|
||||
struct sigcontext context;
|
||||
int err = 0;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
err |= __put_user((current_thread_info()->exec_domain
|
||||
&& current_thread_info()->exec_domain->signal_invmap
|
||||
&& sig < 32
|
||||
? current_thread_info()->exec_domain->signal_invmap[sig]
|
||||
: sig),
|
||||
&frame->sig);
|
||||
|
||||
err |= __put_user(regs->vector, &frame->code);
|
||||
err |= __put_user(&frame->sc, &frame->psc);
|
||||
|
||||
if (_NSIG_WORDS > 1)
|
||||
err |= copy_to_user(frame->extramask, &set->sig[1],
|
||||
sizeof(frame->extramask));
|
||||
|
||||
setup_sigcontext(&context, regs, set->sig[0]);
|
||||
err |= copy_to_user (&frame->sc, &context, sizeof(context));
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
err |= __put_user(frame->retcode, &frame->pretcode);
|
||||
/* moveq #,d0; trap #0 */
|
||||
err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
|
||||
(long *)(frame->retcode));
|
||||
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
push_cache ((unsigned long) &frame->retcode);
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
wrusp ((unsigned long) frame);
|
||||
regs->pc = (unsigned long) ka->sa.sa_handler;
|
||||
|
||||
adjust_stack:
|
||||
/* Prepare to skip over the extra stuff in the exception frame. */
|
||||
if (regs->stkadj) {
|
||||
struct pt_regs *tregs =
|
||||
(struct pt_regs *)((ulong)regs + regs->stkadj);
|
||||
#if DEBUG
|
||||
printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
|
||||
#endif
|
||||
/* This must be copied with decreasing addresses to
|
||||
handle overlaps. */
|
||||
tregs->vector = 0;
|
||||
tregs->format = 0;
|
||||
tregs->pc = regs->pc;
|
||||
tregs->sr = regs->sr;
|
||||
}
|
||||
return;
|
||||
|
||||
give_sigsegv:
|
||||
force_sigsegv(sig, current);
|
||||
goto adjust_stack;
|
||||
}
|
||||
|
||||
static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
sigset_t *set, struct pt_regs *regs)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
int err = 0;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
err |= __put_user((current_thread_info()->exec_domain
|
||||
&& current_thread_info()->exec_domain->signal_invmap
|
||||
&& sig < 32
|
||||
? current_thread_info()->exec_domain->signal_invmap[sig]
|
||||
: sig),
|
||||
&frame->sig);
|
||||
err |= __put_user(&frame->info, &frame->pinfo);
|
||||
err |= __put_user(&frame->uc, &frame->puc);
|
||||
err |= copy_siginfo_to_user(&frame->info, info);
|
||||
|
||||
/* Create the ucontext. */
|
||||
err |= __put_user(0, &frame->uc.uc_flags);
|
||||
err |= __put_user(0, &frame->uc.uc_link);
|
||||
err |= __put_user((void *)current->sas_ss_sp,
|
||||
&frame->uc.uc_stack.ss_sp);
|
||||
err |= __put_user(sas_ss_flags(rdusp()),
|
||||
&frame->uc.uc_stack.ss_flags);
|
||||
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||
err |= rt_setup_ucontext(&frame->uc, regs);
|
||||
err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
err |= __put_user(frame->retcode, &frame->pretcode);
|
||||
/* moveq #,d0; notb d0; trap #0 */
|
||||
err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
|
||||
(long *)(frame->retcode + 0));
|
||||
err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
|
||||
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
push_cache ((unsigned long) &frame->retcode);
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
wrusp ((unsigned long) frame);
|
||||
regs->pc = (unsigned long) ka->sa.sa_handler;
|
||||
|
||||
adjust_stack:
|
||||
/* Prepare to skip over the extra stuff in the exception frame. */
|
||||
if (regs->stkadj) {
|
||||
struct pt_regs *tregs =
|
||||
(struct pt_regs *)((ulong)regs + regs->stkadj);
|
||||
#if DEBUG
|
||||
printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
|
||||
#endif
|
||||
/* This must be copied with decreasing addresses to
|
||||
handle overlaps. */
|
||||
tregs->vector = 0;
|
||||
tregs->format = 0;
|
||||
tregs->pc = regs->pc;
|
||||
tregs->sr = regs->sr;
|
||||
}
|
||||
return;
|
||||
|
||||
give_sigsegv:
|
||||
force_sigsegv(sig, current);
|
||||
goto adjust_stack;
|
||||
}
|
||||
|
||||
static inline void
|
||||
handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
|
||||
{
|
||||
switch (regs->d0) {
|
||||
case -ERESTARTNOHAND:
|
||||
if (!has_handler)
|
||||
goto do_restart;
|
||||
regs->d0 = -EINTR;
|
||||
break;
|
||||
|
||||
case -ERESTARTSYS:
|
||||
if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
|
||||
regs->d0 = -EINTR;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case -ERESTARTNOINTR:
|
||||
do_restart:
|
||||
regs->d0 = regs->orig_d0;
|
||||
regs->pc -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we're invoking a handler
|
||||
*/
|
||||
static void
|
||||
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
/* are we from a system call? */
|
||||
if (regs->orig_d0 >= 0)
|
||||
/* If so, check system call restarting.. */
|
||||
handle_restart(regs, ka, 1);
|
||||
|
||||
/* set up the stack frame */
|
||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||
setup_rt_frame(sig, ka, info, oldset, regs);
|
||||
else
|
||||
setup_frame(sig, ka, oldset, regs);
|
||||
|
||||
if (ka->sa.sa_flags & SA_ONESHOT)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
|
||||
if (!(ka->sa.sa_flags & SA_NODEFER)) {
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
|
||||
sigaddset(¤t->blocked,sig);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
||||
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
||||
* mistake.
|
||||
*/
|
||||
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
struct k_sigaction ka;
|
||||
siginfo_t info;
|
||||
int signr;
|
||||
|
||||
/*
|
||||
* We want the common case to go fast, which
|
||||
* is why we may in certain cases get here from
|
||||
* kernel mode. Just return without doing anything
|
||||
* if so.
|
||||
*/
|
||||
if (!user_mode(regs))
|
||||
return 1;
|
||||
|
||||
if (!oldset)
|
||||
oldset = ¤t->blocked;
|
||||
|
||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||
if (signr > 0) {
|
||||
/* Whee! Actually deliver the signal. */
|
||||
handle_signal(signr, &ka, &info, oldset, regs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Did we come from a system call? */
|
||||
if (regs->orig_d0 >= 0) {
|
||||
/* Restart the system call - no handlers present */
|
||||
if (regs->d0 == -ERESTARTNOHAND
|
||||
|| regs->d0 == -ERESTARTSYS
|
||||
|| regs->d0 == -ERESTARTNOINTR) {
|
||||
regs->d0 = regs->orig_d0;
|
||||
regs->pc -= 2;
|
||||
} else if (regs->d0 == -ERESTART_RESTARTBLOCK) {
|
||||
regs->d0 = __NR_restart_syscall;
|
||||
regs->pc -= 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
208
arch/m68knommu/kernel/sys_m68k.c
Normal file
208
arch/m68knommu/kernel/sys_m68k.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/sys_m68k.c
|
||||
*
|
||||
* This file contains various random system calls that
|
||||
* have a non-standard calling sequence on the Linux/m68k
|
||||
* platform.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/sem.h>
|
||||
#include <linux/msg.h>
|
||||
#include <linux/shm.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/cachectl.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/ipc.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/*
|
||||
* sys_pipe() is the normal C calling standard for creating
|
||||
* a pipe. It's not the way unix traditionally does this, though.
|
||||
*/
|
||||
asmlinkage int sys_pipe(unsigned long * fildes)
|
||||
{
|
||||
int fd[2];
|
||||
int error;
|
||||
|
||||
error = do_pipe(fd);
|
||||
if (!error) {
|
||||
if (copy_to_user(fildes, fd, 2*sizeof(int)))
|
||||
error = -EFAULT;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/* common code for old and new mmaps */
|
||||
static inline long do_mmap2(
|
||||
unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, unsigned long pgoff)
|
||||
{
|
||||
int error = -EBADF;
|
||||
struct file * file = NULL;
|
||||
|
||||
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
file = fget(fd);
|
||||
if (!file)
|
||||
goto out;
|
||||
}
|
||||
|
||||
down_write(¤t->mm->mmap_sem);
|
||||
error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
|
||||
if (file)
|
||||
fput(file);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, unsigned long pgoff)
|
||||
{
|
||||
return do_mmap2(addr, len, prot, flags, fd, pgoff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the select(nd, in, out, ex, tv) and mmap() system
|
||||
* calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
|
||||
* handle more than 4 system call parameters, so these system calls
|
||||
* used a memory block for parameter passing..
|
||||
*/
|
||||
|
||||
struct mmap_arg_struct {
|
||||
unsigned long addr;
|
||||
unsigned long len;
|
||||
unsigned long prot;
|
||||
unsigned long flags;
|
||||
unsigned long fd;
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
asmlinkage int old_mmap(struct mmap_arg_struct *arg)
|
||||
{
|
||||
struct mmap_arg_struct a;
|
||||
int error = -EFAULT;
|
||||
|
||||
if (copy_from_user(&a, arg, sizeof(a)))
|
||||
goto out;
|
||||
|
||||
error = -EINVAL;
|
||||
if (a.offset & ~PAGE_MASK)
|
||||
goto out;
|
||||
|
||||
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
|
||||
|
||||
error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
struct sel_arg_struct {
|
||||
unsigned long n;
|
||||
fd_set *inp, *outp, *exp;
|
||||
struct timeval *tvp;
|
||||
};
|
||||
|
||||
asmlinkage int old_select(struct sel_arg_struct *arg)
|
||||
{
|
||||
struct sel_arg_struct a;
|
||||
|
||||
if (copy_from_user(&a, arg, sizeof(a)))
|
||||
return -EFAULT;
|
||||
/* sys_select() does the appropriate kernel locking */
|
||||
return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_ipc() is the de-multiplexer for the SysV IPC calls..
|
||||
*
|
||||
* This is really horribly ugly.
|
||||
*/
|
||||
asmlinkage int sys_ipc (uint call, int first, int second,
|
||||
int third, void *ptr, long fifth)
|
||||
{
|
||||
int version;
|
||||
|
||||
version = call >> 16; /* hack for backward compatibility */
|
||||
call &= 0xffff;
|
||||
|
||||
if (call <= SEMCTL)
|
||||
switch (call) {
|
||||
case SEMOP:
|
||||
return sys_semop (first, (struct sembuf *)ptr, second);
|
||||
case SEMGET:
|
||||
return sys_semget (first, second, third);
|
||||
case SEMCTL: {
|
||||
union semun fourth;
|
||||
if (!ptr)
|
||||
return -EINVAL;
|
||||
if (get_user(fourth.__pad, (void **) ptr))
|
||||
return -EFAULT;
|
||||
return sys_semctl (first, second, third, fourth);
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (call <= MSGCTL)
|
||||
switch (call) {
|
||||
case MSGSND:
|
||||
return sys_msgsnd (first, (struct msgbuf *) ptr,
|
||||
second, third);
|
||||
case MSGRCV:
|
||||
switch (version) {
|
||||
case 0: {
|
||||
struct ipc_kludge tmp;
|
||||
if (!ptr)
|
||||
return -EINVAL;
|
||||
if (copy_from_user (&tmp,
|
||||
(struct ipc_kludge *)ptr,
|
||||
sizeof (tmp)))
|
||||
return -EFAULT;
|
||||
return sys_msgrcv (first, tmp.msgp, second,
|
||||
tmp.msgtyp, third);
|
||||
}
|
||||
default:
|
||||
return sys_msgrcv (first,
|
||||
(struct msgbuf *) ptr,
|
||||
second, fifth, third);
|
||||
}
|
||||
case MSGGET:
|
||||
return sys_msgget ((key_t) first, second);
|
||||
case MSGCTL:
|
||||
return sys_msgctl (first, second,
|
||||
(struct msqid_ds *) ptr);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* sys_cacheflush -- flush (part of) the processor cache. */
|
||||
asmlinkage int
|
||||
sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
|
||||
{
|
||||
flush_cache_all();
|
||||
return(0);
|
||||
}
|
||||
|
||||
asmlinkage int sys_getpagesize(void)
|
||||
{
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
308
arch/m68knommu/kernel/syscalltable.S
Normal file
308
arch/m68knommu/kernel/syscalltable.S
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/syscalltable.S
|
||||
*
|
||||
* Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
|
||||
*
|
||||
* Based on older entry.S files, the following copyrights apply:
|
||||
*
|
||||
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
|
||||
* Kenneth Albanowski <kjahds@kjahds.com>,
|
||||
* Copyright (C) 2000 Lineo Inc. (www.lineo.com)
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/sys.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
.text
|
||||
ALIGN
|
||||
ENTRY(sys_call_table)
|
||||
.long sys_ni_syscall /* 0 - old "setup()" system call*/
|
||||
.long sys_exit
|
||||
.long sys_fork
|
||||
.long sys_read
|
||||
.long sys_write
|
||||
.long sys_open /* 5 */
|
||||
.long sys_close
|
||||
.long sys_waitpid
|
||||
.long sys_creat
|
||||
.long sys_link
|
||||
.long sys_unlink /* 10 */
|
||||
.long sys_execve
|
||||
.long sys_chdir
|
||||
.long sys_time
|
||||
.long sys_mknod
|
||||
.long sys_chmod /* 15 */
|
||||
.long sys_chown16
|
||||
.long sys_ni_syscall /* old break syscall holder */
|
||||
.long sys_stat
|
||||
.long sys_lseek
|
||||
.long sys_getpid /* 20 */
|
||||
.long sys_mount
|
||||
.long sys_oldumount
|
||||
.long sys_setuid16
|
||||
.long sys_getuid16
|
||||
.long sys_stime /* 25 */
|
||||
.long sys_ptrace
|
||||
.long sys_alarm
|
||||
.long sys_fstat
|
||||
.long sys_pause
|
||||
.long sys_utime /* 30 */
|
||||
.long sys_ni_syscall /* old stty syscall holder */
|
||||
.long sys_ni_syscall /* old gtty syscall holder */
|
||||
.long sys_access
|
||||
.long sys_nice
|
||||
.long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
|
||||
.long sys_sync
|
||||
.long sys_kill
|
||||
.long sys_rename
|
||||
.long sys_mkdir
|
||||
.long sys_rmdir /* 40 */
|
||||
.long sys_dup
|
||||
.long sys_pipe
|
||||
.long sys_times
|
||||
.long sys_ni_syscall /* old prof syscall holder */
|
||||
.long sys_brk /* 45 */
|
||||
.long sys_setgid16
|
||||
.long sys_getgid16
|
||||
.long sys_signal
|
||||
.long sys_geteuid16
|
||||
.long sys_getegid16 /* 50 */
|
||||
.long sys_acct
|
||||
.long sys_umount /* recycled never used phys() */
|
||||
.long sys_ni_syscall /* old lock syscall holder */
|
||||
.long sys_ioctl
|
||||
.long sys_fcntl /* 55 */
|
||||
.long sys_ni_syscall /* old mpx syscall holder */
|
||||
.long sys_setpgid
|
||||
.long sys_ni_syscall /* old ulimit syscall holder */
|
||||
.long sys_ni_syscall
|
||||
.long sys_umask /* 60 */
|
||||
.long sys_chroot
|
||||
.long sys_ustat
|
||||
.long sys_dup2
|
||||
.long sys_getppid
|
||||
.long sys_getpgrp /* 65 */
|
||||
.long sys_setsid
|
||||
.long sys_sigaction
|
||||
.long sys_sgetmask
|
||||
.long sys_ssetmask
|
||||
.long sys_setreuid16 /* 70 */
|
||||
.long sys_setregid16
|
||||
.long sys_sigsuspend
|
||||
.long sys_sigpending
|
||||
.long sys_sethostname
|
||||
.long sys_setrlimit /* 75 */
|
||||
.long sys_old_getrlimit
|
||||
.long sys_getrusage
|
||||
.long sys_gettimeofday
|
||||
.long sys_settimeofday
|
||||
.long sys_getgroups16 /* 80 */
|
||||
.long sys_setgroups16
|
||||
.long old_select
|
||||
.long sys_symlink
|
||||
.long sys_lstat
|
||||
.long sys_readlink /* 85 */
|
||||
.long sys_uselib
|
||||
.long sys_ni_syscall /* sys_swapon */
|
||||
.long sys_reboot
|
||||
.long old_readdir
|
||||
.long old_mmap /* 90 */
|
||||
.long sys_munmap
|
||||
.long sys_truncate
|
||||
.long sys_ftruncate
|
||||
.long sys_fchmod
|
||||
.long sys_fchown16 /* 95 */
|
||||
.long sys_getpriority
|
||||
.long sys_setpriority
|
||||
.long sys_ni_syscall /* old profil syscall holder */
|
||||
.long sys_statfs
|
||||
.long sys_fstatfs /* 100 */
|
||||
.long sys_ni_syscall /* ioperm for i386 */
|
||||
.long sys_socketcall
|
||||
.long sys_syslog
|
||||
.long sys_setitimer
|
||||
.long sys_getitimer /* 105 */
|
||||
.long sys_newstat
|
||||
.long sys_newlstat
|
||||
.long sys_newfstat
|
||||
.long sys_ni_syscall
|
||||
.long sys_ni_syscall /* iopl for i386 */ /* 110 */
|
||||
.long sys_vhangup
|
||||
.long sys_ni_syscall /* obsolete idle() syscall */
|
||||
.long sys_ni_syscall /* vm86old for i386 */
|
||||
.long sys_wait4
|
||||
.long sys_ni_syscall /* 115 */ /* sys_swapoff */
|
||||
.long sys_sysinfo
|
||||
.long sys_ipc
|
||||
.long sys_fsync
|
||||
.long sys_sigreturn
|
||||
.long sys_clone /* 120 */
|
||||
.long sys_setdomainname
|
||||
.long sys_newuname
|
||||
.long sys_cacheflush /* modify_ldt for i386 */
|
||||
.long sys_adjtimex
|
||||
.long sys_ni_syscall /* 125 */ /* sys_mprotect */
|
||||
.long sys_sigprocmask
|
||||
.long sys_ni_syscall /* old "creat_module" */
|
||||
.long sys_init_module
|
||||
.long sys_delete_module
|
||||
.long sys_ni_syscall /* 130: old "get_kernel_syms" */
|
||||
.long sys_quotactl
|
||||
.long sys_getpgid
|
||||
.long sys_fchdir
|
||||
.long sys_bdflush
|
||||
.long sys_sysfs /* 135 */
|
||||
.long sys_personality
|
||||
.long sys_ni_syscall /* for afs_syscall */
|
||||
.long sys_setfsuid16
|
||||
.long sys_setfsgid16
|
||||
.long sys_llseek /* 140 */
|
||||
.long sys_getdents
|
||||
.long sys_select
|
||||
.long sys_flock
|
||||
.long sys_ni_syscall /* sys_msync */
|
||||
.long sys_readv /* 145 */
|
||||
.long sys_writev
|
||||
.long sys_getsid
|
||||
.long sys_fdatasync
|
||||
.long sys_sysctl
|
||||
.long sys_ni_syscall /* 150 */ /* sys_mlock */
|
||||
.long sys_ni_syscall /* sys_munlock */
|
||||
.long sys_ni_syscall /* sys_mlockall */
|
||||
.long sys_ni_syscall /* sys_munlockall */
|
||||
.long sys_sched_setparam
|
||||
.long sys_sched_getparam /* 155 */
|
||||
.long sys_sched_setscheduler
|
||||
.long sys_sched_getscheduler
|
||||
.long sys_sched_yield
|
||||
.long sys_sched_get_priority_max
|
||||
.long sys_sched_get_priority_min /* 160 */
|
||||
.long sys_sched_rr_get_interval
|
||||
.long sys_nanosleep
|
||||
.long sys_ni_syscall /* sys_mremap */
|
||||
.long sys_setresuid16
|
||||
.long sys_getresuid16 /* 165 */
|
||||
.long sys_getpagesize /* sys_getpagesize */
|
||||
.long sys_ni_syscall /* old "query_module" */
|
||||
.long sys_poll
|
||||
.long sys_ni_syscall /* sys_nfsservctl */
|
||||
.long sys_setresgid16 /* 170 */
|
||||
.long sys_getresgid16
|
||||
.long sys_prctl
|
||||
.long sys_rt_sigreturn
|
||||
.long sys_rt_sigaction
|
||||
.long sys_rt_sigprocmask /* 175 */
|
||||
.long sys_rt_sigpending
|
||||
.long sys_rt_sigtimedwait
|
||||
.long sys_rt_sigqueueinfo
|
||||
.long sys_rt_sigsuspend
|
||||
.long sys_pread64 /* 180 */
|
||||
.long sys_pwrite64
|
||||
.long sys_lchown16
|
||||
.long sys_getcwd
|
||||
.long sys_capget
|
||||
.long sys_capset /* 185 */
|
||||
.long sys_sigaltstack
|
||||
.long sys_sendfile
|
||||
.long sys_ni_syscall /* streams1 */
|
||||
.long sys_ni_syscall /* streams2 */
|
||||
.long sys_vfork /* 190 */
|
||||
.long sys_getrlimit
|
||||
.long sys_mmap2
|
||||
.long sys_truncate64
|
||||
.long sys_ftruncate64
|
||||
.long sys_stat64 /* 195 */
|
||||
.long sys_lstat64
|
||||
.long sys_fstat64
|
||||
.long sys_chown
|
||||
.long sys_getuid
|
||||
.long sys_getgid /* 200 */
|
||||
.long sys_geteuid
|
||||
.long sys_getegid
|
||||
.long sys_setreuid
|
||||
.long sys_setregid
|
||||
.long sys_getgroups /* 205 */
|
||||
.long sys_setgroups
|
||||
.long sys_fchown
|
||||
.long sys_setresuid
|
||||
.long sys_getresuid
|
||||
.long sys_setresgid /* 210 */
|
||||
.long sys_getresgid
|
||||
.long sys_lchown
|
||||
.long sys_setuid
|
||||
.long sys_setgid
|
||||
.long sys_setfsuid /* 215 */
|
||||
.long sys_setfsgid
|
||||
.long sys_pivot_root
|
||||
.long sys_ni_syscall
|
||||
.long sys_ni_syscall
|
||||
.long sys_getdents64 /* 220 */
|
||||
.long sys_gettid
|
||||
.long sys_tkill
|
||||
.long sys_setxattr
|
||||
.long sys_lsetxattr
|
||||
.long sys_fsetxattr /* 225 */
|
||||
.long sys_getxattr
|
||||
.long sys_lgetxattr
|
||||
.long sys_fgetxattr
|
||||
.long sys_listxattr
|
||||
.long sys_llistxattr /* 230 */
|
||||
.long sys_flistxattr
|
||||
.long sys_removexattr
|
||||
.long sys_lremovexattr
|
||||
.long sys_fremovexattr
|
||||
.long sys_futex /* 235 */
|
||||
.long sys_sendfile64
|
||||
.long sys_ni_syscall /* sys_mincore */
|
||||
.long sys_ni_syscall /* sys_madvise */
|
||||
.long sys_fcntl64
|
||||
.long sys_readahead /* 240 */
|
||||
.long sys_io_setup
|
||||
.long sys_io_destroy
|
||||
.long sys_io_getevents
|
||||
.long sys_io_submit
|
||||
.long sys_io_cancel /* 245 */
|
||||
.long sys_fadvise64
|
||||
.long sys_exit_group
|
||||
.long sys_lookup_dcookie
|
||||
.long sys_epoll_create
|
||||
.long sys_epoll_ctl /* 250 */
|
||||
.long sys_epoll_wait
|
||||
.long sys_ni_syscall /* sys_remap_file_pages */
|
||||
.long sys_set_tid_address
|
||||
.long sys_timer_create
|
||||
.long sys_timer_settime /* 255 */
|
||||
.long sys_timer_gettime
|
||||
.long sys_timer_getoverrun
|
||||
.long sys_timer_delete
|
||||
.long sys_clock_settime
|
||||
.long sys_clock_gettime /* 260 */
|
||||
.long sys_clock_getres
|
||||
.long sys_clock_nanosleep
|
||||
.long sys_statfs64
|
||||
.long sys_fstatfs64
|
||||
.long sys_tgkill /* 265 */
|
||||
.long sys_utimes
|
||||
.long sys_fadvise64_64
|
||||
.long sys_mbind
|
||||
.long sys_get_mempolicy
|
||||
.long sys_set_mempolicy /* 270 */
|
||||
.long sys_mq_open
|
||||
.long sys_mq_unlink
|
||||
.long sys_mq_timedsend
|
||||
.long sys_mq_timedreceive
|
||||
.long sys_mq_notify /* 275 */
|
||||
.long sys_mq_getsetattr
|
||||
.long sys_waitid
|
||||
.long sys_ni_syscall /* sys_setaltroot */
|
||||
.long sys_ni_syscall /* sys_add_key */
|
||||
.long sys_ni_syscall /* 280 */ /* sys_request_key */
|
||||
.long sys_ni_syscall /* sys_keyctl */
|
||||
|
||||
.rept NR_syscalls-(.-sys_call_table)/4
|
||||
.long sys_ni_syscall
|
||||
.endr
|
||||
|
||||
198
arch/m68knommu/kernel/time.c
Normal file
198
arch/m68knommu/kernel/time.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/time.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
|
||||
*
|
||||
* This file contains the m68k-specific time handling details.
|
||||
* Most of the stuff is located in the machine specific files.
|
||||
*
|
||||
* 1997-09-10 Updated NTP code according to technical memorandum Jan '96
|
||||
* "A Kernel Model for Precision Timekeeping" by Dave Mills
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define TICK_SIZE (tick_nsec / 1000)
|
||||
|
||||
u64 jiffies_64 = INITIAL_JIFFIES;
|
||||
|
||||
EXPORT_SYMBOL(jiffies_64);
|
||||
|
||||
extern unsigned long wall_jiffies;
|
||||
|
||||
|
||||
static inline int set_rtc_mmss(unsigned long nowtime)
|
||||
{
|
||||
if (mach_set_clock_mmss)
|
||||
return mach_set_clock_mmss (nowtime);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* timer_interrupt() needs to keep up the real-time clock,
|
||||
* as well as call the "do_timer()" routine every clocktick
|
||||
*/
|
||||
static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
|
||||
{
|
||||
/* last time the cmos clock got updated */
|
||||
static long last_rtc_update=0;
|
||||
|
||||
/* may need to kick the hardware timer */
|
||||
if (mach_tick)
|
||||
mach_tick();
|
||||
|
||||
write_seqlock(&xtime_lock);
|
||||
|
||||
do_timer(regs);
|
||||
#ifndef CONFIG_SMP
|
||||
update_process_times(user_mode(regs));
|
||||
#endif
|
||||
if (current->pid)
|
||||
profile_tick(CPU_PROFILING, regs);
|
||||
|
||||
/*
|
||||
* If we have an externally synchronized Linux clock, then update
|
||||
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
|
||||
* called as close as possible to 500 ms before the new second starts.
|
||||
*/
|
||||
if ((time_status & STA_UNSYNC) == 0 &&
|
||||
xtime.tv_sec > last_rtc_update + 660 &&
|
||||
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
|
||||
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
|
||||
if (set_rtc_mmss(xtime.tv_sec) == 0)
|
||||
last_rtc_update = xtime.tv_sec;
|
||||
else
|
||||
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
|
||||
}
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
/* use power LED as a heartbeat instead -- much more useful
|
||||
for debugging -- based on the version for PReP by Cort */
|
||||
/* acts like an actual heart beat -- ie thump-thump-pause... */
|
||||
if (mach_heartbeat) {
|
||||
static unsigned cnt = 0, period = 0, dist = 0;
|
||||
|
||||
if (cnt == 0 || cnt == dist)
|
||||
mach_heartbeat( 1 );
|
||||
else if (cnt == 7 || cnt == dist+7)
|
||||
mach_heartbeat( 0 );
|
||||
|
||||
if (++cnt > period) {
|
||||
cnt = 0;
|
||||
/* The hyperbolic function below modifies the heartbeat period
|
||||
* length in dependency of the current (5min) load. It goes
|
||||
* through the points f(0)=126, f(1)=86, f(5)=51,
|
||||
* f(inf)->30. */
|
||||
period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
|
||||
dist = period / 4;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_HEARTBEAT */
|
||||
|
||||
write_sequnlock(&xtime_lock);
|
||||
return(IRQ_HANDLED);
|
||||
}
|
||||
|
||||
void time_init(void)
|
||||
{
|
||||
unsigned int year, mon, day, hour, min, sec;
|
||||
|
||||
extern void arch_gettod(int *year, int *mon, int *day, int *hour,
|
||||
int *min, int *sec);
|
||||
|
||||
arch_gettod(&year, &mon, &day, &hour, &min, &sec);
|
||||
|
||||
if ((year += 1900) < 1970)
|
||||
year += 100;
|
||||
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
|
||||
xtime.tv_nsec = 0;
|
||||
wall_to_monotonic.tv_sec = -xtime.tv_sec;
|
||||
|
||||
mach_sched_init(timer_interrupt);
|
||||
}
|
||||
|
||||
/*
|
||||
* This version of gettimeofday has near microsecond resolution.
|
||||
*/
|
||||
void do_gettimeofday(struct timeval *tv)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long lost, seq;
|
||||
unsigned long usec, sec;
|
||||
|
||||
do {
|
||||
seq = read_seqbegin_irqsave(&xtime_lock, flags);
|
||||
usec = mach_gettimeoffset ? mach_gettimeoffset() : 0;
|
||||
lost = jiffies - wall_jiffies;
|
||||
if (lost)
|
||||
usec += lost * (1000000 / HZ);
|
||||
sec = xtime.tv_sec;
|
||||
usec += (xtime.tv_nsec / 1000);
|
||||
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
|
||||
|
||||
while (usec >= 1000000) {
|
||||
usec -= 1000000;
|
||||
sec++;
|
||||
}
|
||||
|
||||
tv->tv_sec = sec;
|
||||
tv->tv_usec = usec;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(do_gettimeofday);
|
||||
|
||||
int do_settimeofday(struct timespec *tv)
|
||||
{
|
||||
time_t wtm_sec, sec = tv->tv_sec;
|
||||
long wtm_nsec, nsec = tv->tv_nsec;
|
||||
|
||||
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
|
||||
return -EINVAL;
|
||||
|
||||
write_seqlock_irq(&xtime_lock);
|
||||
/*
|
||||
* This is revolting. We need to set the xtime.tv_usec
|
||||
* correctly. However, the value in this location is
|
||||
* is value at the last tick.
|
||||
* Discover what correction gettimeofday
|
||||
* would have done, and then undo it!
|
||||
*/
|
||||
if (mach_gettimeoffset)
|
||||
nsec -= (mach_gettimeoffset() * 1000);
|
||||
|
||||
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
|
||||
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
|
||||
|
||||
set_normalized_timespec(&xtime, sec, nsec);
|
||||
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
|
||||
|
||||
time_adjust = 0; /* stop active adjtime() */
|
||||
time_status |= STA_UNSYNC;
|
||||
time_maxerror = NTP_PHASE_LIMIT;
|
||||
time_esterror = NTP_PHASE_LIMIT;
|
||||
write_sequnlock_irq(&xtime_lock);
|
||||
clock_was_set();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scheduler clock - returns current time in nanosec units.
|
||||
*/
|
||||
unsigned long long sched_clock(void)
|
||||
{
|
||||
return (unsigned long long)jiffies * (1000000000 / HZ);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(do_settimeofday);
|
||||
320
arch/m68knommu/kernel/traps.c
Normal file
320
arch/m68knommu/kernel/traps.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* linux/arch/m68knommu/kernel/traps.c
|
||||
*
|
||||
* Copyright (C) 1993, 1994 by Hamish Macdonald
|
||||
*
|
||||
* 68040 fixes by Michael Rausch
|
||||
* 68040 fixes by Martin Apel
|
||||
* 68060 fixes by Roman Hodek
|
||||
* 68060 fixes by Jesper Skov
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sets up all exception vectors
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/a.out.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/siginfo.h>
|
||||
|
||||
static char *vec_names[] = {
|
||||
"RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
|
||||
"ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
|
||||
"PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
|
||||
"UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
|
||||
"FORMAT ERROR", "UNINITIALIZED INTERRUPT",
|
||||
"UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
|
||||
"UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
|
||||
"UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
|
||||
"UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
|
||||
"SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
|
||||
"LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
|
||||
"SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
|
||||
"TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
|
||||
"TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
|
||||
"TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
|
||||
"FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
|
||||
"FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
|
||||
"FPCP UNSUPPORTED OPERATION",
|
||||
"MMU CONFIGURATION ERROR"
|
||||
};
|
||||
|
||||
void __init trap_init(void)
|
||||
{
|
||||
if (mach_trap_init)
|
||||
mach_trap_init();
|
||||
}
|
||||
|
||||
void die_if_kernel(char *str, struct pt_regs *fp, int nr)
|
||||
{
|
||||
if (!(fp->sr & PS_S))
|
||||
return;
|
||||
|
||||
console_verbose();
|
||||
printk(KERN_EMERG "%s: %08x\n",str,nr);
|
||||
printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
|
||||
fp->pc, fp->sr, fp, fp->a2);
|
||||
printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
|
||||
fp->d0, fp->d1, fp->d2, fp->d3);
|
||||
printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
|
||||
fp->d4, fp->d5, fp->a0, fp->a1);
|
||||
|
||||
printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
|
||||
show_stack(NULL, (unsigned long *)fp);
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
asmlinkage void buserr_c(struct frame *fp)
|
||||
{
|
||||
/* Only set esp0 if coming from user mode */
|
||||
if (user_mode(&fp->ptregs))
|
||||
current->thread.esp0 = (unsigned long) fp;
|
||||
|
||||
#if DEBUG
|
||||
printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
|
||||
#endif
|
||||
|
||||
die_if_kernel("bad frame format",&fp->ptregs,0);
|
||||
#if DEBUG
|
||||
printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
|
||||
#endif
|
||||
force_sig(SIGSEGV, current);
|
||||
}
|
||||
|
||||
|
||||
int kstack_depth_to_print = 48;
|
||||
|
||||
void show_stack(struct task_struct *task, unsigned long *esp)
|
||||
{
|
||||
unsigned long *stack, *endstack, addr;
|
||||
extern char _start, _etext;
|
||||
int i;
|
||||
|
||||
if (esp == NULL)
|
||||
esp = (unsigned long *) &esp;
|
||||
|
||||
stack = esp;
|
||||
addr = (unsigned long) esp;
|
||||
endstack = (unsigned long *) PAGE_ALIGN(addr);
|
||||
|
||||
printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
|
||||
for (i = 0; i < kstack_depth_to_print; i++) {
|
||||
if (stack + 1 > endstack)
|
||||
break;
|
||||
if (i % 8 == 0)
|
||||
printk(KERN_EMERG "\n ");
|
||||
printk(KERN_EMERG " %08lx", *stack++);
|
||||
}
|
||||
|
||||
printk(KERN_EMERG "\nCall Trace:");
|
||||
i = 0;
|
||||
while (stack + 1 <= endstack) {
|
||||
addr = *stack++;
|
||||
/*
|
||||
* If the address is either in the text segment of the
|
||||
* kernel, or in the region which contains vmalloc'ed
|
||||
* memory, it *may* be the address of a calling
|
||||
* routine; if so, print it so that someone tracing
|
||||
* down the cause of the crash will be able to figure
|
||||
* out the call path that was taken.
|
||||
*/
|
||||
if (((addr >= (unsigned long) &_start) &&
|
||||
(addr <= (unsigned long) &_etext))) {
|
||||
if (i % 4 == 0)
|
||||
printk(KERN_EMERG "\n ");
|
||||
printk(KERN_EMERG " [<%08lx>]", addr);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
printk(KERN_EMERG "\n");
|
||||
}
|
||||
|
||||
void bad_super_trap(struct frame *fp)
|
||||
{
|
||||
console_verbose();
|
||||
if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0]))
|
||||
printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
|
||||
vec_names[(fp->ptregs.vector) >> 2],
|
||||
fp->ptregs.format);
|
||||
else
|
||||
printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
|
||||
(fp->ptregs.vector) >> 2,
|
||||
fp->ptregs.format);
|
||||
printk (KERN_WARNING "Current process id is %d\n", current->pid);
|
||||
die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
|
||||
}
|
||||
|
||||
asmlinkage void trap_c(struct frame *fp)
|
||||
{
|
||||
int sig;
|
||||
siginfo_t info;
|
||||
|
||||
if (fp->ptregs.sr & PS_S) {
|
||||
if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
|
||||
/* traced a trapping instruction */
|
||||
current->ptrace |= PT_DTRACE;
|
||||
} else
|
||||
bad_super_trap(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send the appropriate signal to the user program */
|
||||
switch ((fp->ptregs.vector) >> 2) {
|
||||
case VEC_ADDRERR:
|
||||
info.si_code = BUS_ADRALN;
|
||||
sig = SIGBUS;
|
||||
break;
|
||||
case VEC_ILLEGAL:
|
||||
case VEC_LINE10:
|
||||
case VEC_LINE11:
|
||||
info.si_code = ILL_ILLOPC;
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case VEC_PRIV:
|
||||
info.si_code = ILL_PRVOPC;
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case VEC_COPROC:
|
||||
info.si_code = ILL_COPROC;
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case VEC_TRAP1: /* gdbserver breakpoint */
|
||||
fp->ptregs.pc -= 2;
|
||||
info.si_code = TRAP_TRACE;
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
case VEC_TRAP2:
|
||||
case VEC_TRAP3:
|
||||
case VEC_TRAP4:
|
||||
case VEC_TRAP5:
|
||||
case VEC_TRAP6:
|
||||
case VEC_TRAP7:
|
||||
case VEC_TRAP8:
|
||||
case VEC_TRAP9:
|
||||
case VEC_TRAP10:
|
||||
case VEC_TRAP11:
|
||||
case VEC_TRAP12:
|
||||
case VEC_TRAP13:
|
||||
case VEC_TRAP14:
|
||||
info.si_code = ILL_ILLTRP;
|
||||
sig = SIGILL;
|
||||
break;
|
||||
case VEC_FPBRUC:
|
||||
case VEC_FPOE:
|
||||
case VEC_FPNAN:
|
||||
info.si_code = FPE_FLTINV;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_FPIR:
|
||||
info.si_code = FPE_FLTRES;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_FPDIVZ:
|
||||
info.si_code = FPE_FLTDIV;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_FPUNDER:
|
||||
info.si_code = FPE_FLTUND;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_FPOVER:
|
||||
info.si_code = FPE_FLTOVF;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_ZERODIV:
|
||||
info.si_code = FPE_INTDIV;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_CHK:
|
||||
case VEC_TRAP:
|
||||
info.si_code = FPE_INTOVF;
|
||||
sig = SIGFPE;
|
||||
break;
|
||||
case VEC_TRACE: /* ptrace single step */
|
||||
info.si_code = TRAP_TRACE;
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
case VEC_TRAP15: /* breakpoint */
|
||||
info.si_code = TRAP_BRKPT;
|
||||
sig = SIGTRAP;
|
||||
break;
|
||||
default:
|
||||
info.si_code = ILL_ILLOPC;
|
||||
sig = SIGILL;
|
||||
break;
|
||||
}
|
||||
info.si_signo = sig;
|
||||
info.si_errno = 0;
|
||||
switch (fp->ptregs.format) {
|
||||
default:
|
||||
info.si_addr = (void *) fp->ptregs.pc;
|
||||
break;
|
||||
case 2:
|
||||
info.si_addr = (void *) fp->un.fmt2.iaddr;
|
||||
break;
|
||||
case 7:
|
||||
info.si_addr = (void *) fp->un.fmt7.effaddr;
|
||||
break;
|
||||
case 9:
|
||||
info.si_addr = (void *) fp->un.fmt9.iaddr;
|
||||
break;
|
||||
case 10:
|
||||
info.si_addr = (void *) fp->un.fmta.daddr;
|
||||
break;
|
||||
case 11:
|
||||
info.si_addr = (void *) fp->un.fmtb.daddr;
|
||||
break;
|
||||
}
|
||||
force_sig_info (sig, &info, current);
|
||||
}
|
||||
|
||||
asmlinkage void set_esp0(unsigned long ssp)
|
||||
{
|
||||
current->thread.esp0 = ssp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The architecture-independent backtrace generator
|
||||
*/
|
||||
void dump_stack(void)
|
||||
{
|
||||
unsigned long stack;
|
||||
|
||||
show_stack(current, &stack);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_M68KFPU_EMU
|
||||
asmlinkage void fpemu_signal(int signal, int code, void *addr)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
info.si_signo = signal;
|
||||
info.si_errno = 0;
|
||||
info.si_code = code;
|
||||
info.si_addr = addr;
|
||||
force_sig_info(signal, &info, current);
|
||||
}
|
||||
#endif
|
||||
348
arch/m68knommu/kernel/vmlinux.lds.S
Normal file
348
arch/m68knommu/kernel/vmlinux.lds.S
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* vmlinux.lds.S -- master linker script for m68knommu arch
|
||||
*
|
||||
* (C) Copyright 2002-2004, Greg Ungerer <gerg@snapgear.com>
|
||||
*
|
||||
* This ends up looking compilcated, because of the number of
|
||||
* address variations for ram and rom/flash layouts. The real
|
||||
* work of the linker script is all at the end, and reasonably
|
||||
* strait forward.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
|
||||
/*
|
||||
* Original Palm pilot (same for Xcopilot).
|
||||
* There is really only a rom target for this.
|
||||
*/
|
||||
#ifdef CONFIG_PILOT3
|
||||
#define ROMVEC_START 0x10c00000
|
||||
#define ROMVEC_LENGTH 0x10400
|
||||
#define ROM_START 0x10c10400
|
||||
#define ROM_LENGTH 0xfec00
|
||||
#define ROM_END 0x10d00000
|
||||
#define RAMVEC_START 0x00000000
|
||||
#define RAMVEC_LENGTH 0x400
|
||||
#define RAM_START 0x10000400
|
||||
#define RAM_LENGTH 0xffc00
|
||||
#define RAM_END 0x10100000
|
||||
#define _ramend _ram_end_notused
|
||||
#define DATA_ADDR RAM_START
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Same setup on both the uCsimm and uCdimm.
|
||||
*/
|
||||
#if defined(CONFIG_UCSIMM) || defined(CONFIG_UCDIMM)
|
||||
#ifdef CONFIG_RAMKERNEL
|
||||
#define ROMVEC_START 0x10c10000
|
||||
#define ROMVEC_LENGTH 0x400
|
||||
#define ROM_START 0x10c10400
|
||||
#define ROM_LENGTH 0x1efc00
|
||||
#define ROM_END 0x10e00000
|
||||
#define RAMVEC_START 0x00000000
|
||||
#define RAMVEC_LENGTH 0x400
|
||||
#define RAM_START 0x00020400
|
||||
#define RAM_LENGTH 0x7dfc00
|
||||
#define RAM_END 0x00800000
|
||||
#endif
|
||||
#ifdef CONFIG_ROMKERNEL
|
||||
#define ROMVEC_START 0x10c10000
|
||||
#define ROMVEC_LENGTH 0x400
|
||||
#define ROM_START 0x10c10400
|
||||
#define ROM_LENGTH 0x1efc00
|
||||
#define ROM_END 0x10e00000
|
||||
#define RAMVEC_START 0x00000000
|
||||
#define RAMVEC_LENGTH 0x400
|
||||
#define RAM_START 0x00020000
|
||||
#define RAM_LENGTH 0x600000
|
||||
#define RAM_END 0x00800000
|
||||
#endif
|
||||
#ifdef CONFIG_HIMEMKERNEL
|
||||
#define ROMVEC_START 0x00600000
|
||||
#define ROMVEC_LENGTH 0x400
|
||||
#define ROM_START 0x00600400
|
||||
#define ROM_LENGTH 0x1efc00
|
||||
#define ROM_END 0x007f0000
|
||||
#define RAMVEC_START 0x00000000
|
||||
#define RAMVEC_LENGTH 0x400
|
||||
#define RAM_START 0x00020000
|
||||
#define RAM_LENGTH 0x5e0000
|
||||
#define RAM_END 0x00600000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRAGEN2
|
||||
#define RAM_START 0x10000
|
||||
#define RAM_LENGTH 0x7f0000
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UCQUICC
|
||||
#define ROMVEC_START 0x00000000
|
||||
#define ROMVEC_LENGTH 0x404
|
||||
#define ROM_START 0x00000404
|
||||
#define ROM_LENGTH 0x1ff6fc
|
||||
#define ROM_END 0x00200000
|
||||
#define RAMVEC_START 0x00200000
|
||||
#define RAMVEC_LENGTH 0x404
|
||||
#define RAM_START 0x00200404
|
||||
#define RAM_LENGTH 0x1ff6fc
|
||||
#define RAM_END 0x00400000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The standard Arnewsh 5206 board only has 1MiB of ram. Not normally
|
||||
* enough to be useful. Assume the user has fitted something larger,
|
||||
* at least 4MiB in size. No point in not letting the kernel completely
|
||||
* link, it will be obvious if it is too big when they go to load it.
|
||||
*/
|
||||
#if defined(CONFIG_ARN5206)
|
||||
#define RAM_START 0x10000
|
||||
#define RAM_LENGTH 0x3f0000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The Motorola 5206eLITE board only has 1MiB of static RAM.
|
||||
*/
|
||||
#if defined(CONFIG_ELITE)
|
||||
#define RAM_START 0x30020000
|
||||
#define RAM_END 0xe0000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All the Motorola eval boards have the same basic arrangement.
|
||||
* The end of RAM will vary depending on how much ram is fitted,
|
||||
* but this isn't important here, we assume at least 4MiB.
|
||||
*/
|
||||
#if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \
|
||||
defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \
|
||||
defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \
|
||||
defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB)
|
||||
#define RAM_START 0x20000
|
||||
#define RAM_LENGTH 0x3e0000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The senTec COBRA5272 board has nearly the same memory layout as
|
||||
* the M5272C3. We assume 16MiB ram.
|
||||
*/
|
||||
#if defined(CONFIG_COBRA5272)
|
||||
#define RAM_START 0x20000
|
||||
#define RAM_LENGTH 0xfe0000
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_M5282EVB)
|
||||
#define RAM_START 0x10000
|
||||
#define RAM_LENGTH 0x3f0000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The senTec COBRA5282 board has the same memory layout as the M5282EVB.
|
||||
*/
|
||||
#if defined(CONFIG_COBRA5282)
|
||||
#define RAM_START 0x10000
|
||||
#define RAM_LENGTH 0x3f0000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These flash boot boards use all of ram for operation. Again the
|
||||
* actual memory size is not important here, assume at least 4MiB.
|
||||
* They currently have no support for running in flash.
|
||||
*/
|
||||
#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
|
||||
defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
|
||||
defined(CONFIG_HW_FEITH)
|
||||
#define RAM_START 0x400
|
||||
#define RAM_LENGTH 0x3ffc00
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sneha Boards mimimun memmory
|
||||
* The end of RAM will vary depending on how much ram is fitted,
|
||||
* but this isn't important here, we assume at least 4MiB.
|
||||
*/
|
||||
#if defined(CONFIG_CPU16B)
|
||||
#define RAM_START 0x20000
|
||||
#define RAM_LENGTH 0x3e0000
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(CONFIG_RAMKERNEL)
|
||||
#define TEXT ram
|
||||
#define DATA ram
|
||||
#define INIT ram
|
||||
#define BSS ram
|
||||
#endif
|
||||
#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
|
||||
#define TEXT rom
|
||||
#define DATA ram
|
||||
#define INIT ram
|
||||
#define BSS ram
|
||||
#endif
|
||||
|
||||
#ifndef DATA_ADDR
|
||||
#define DATA_ADDR
|
||||
#endif
|
||||
|
||||
|
||||
OUTPUT_ARCH(m68k)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY {
|
||||
#ifdef RAMVEC_START
|
||||
ramvec : ORIGIN = RAMVEC_START, LENGTH = RAMVEC_LENGTH
|
||||
#endif
|
||||
ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
|
||||
#ifdef RAM_END
|
||||
eram : ORIGIN = RAM_END, LENGTH = 0
|
||||
#endif
|
||||
#ifdef ROM_START
|
||||
romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
|
||||
rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
|
||||
erom : ORIGIN = ROM_END, LENGTH = 0
|
||||
#endif
|
||||
}
|
||||
|
||||
jiffies = jiffies_64 + 4;
|
||||
|
||||
SECTIONS {
|
||||
|
||||
#ifdef ROMVEC_START
|
||||
. = ROMVEC_START ;
|
||||
.romvec : {
|
||||
__rom_start = . ;
|
||||
_romvec = .;
|
||||
*(.data.initvect)
|
||||
} > romvec
|
||||
#endif
|
||||
|
||||
.text : {
|
||||
_stext = . ;
|
||||
*(.text)
|
||||
SCHED_TEXT
|
||||
*(.text.lock)
|
||||
|
||||
. = ALIGN(16); /* Exception table */
|
||||
__start___ex_table = .;
|
||||
*(__ex_table)
|
||||
__stop___ex_table = .;
|
||||
|
||||
*(.rodata) *(.rodata.*)
|
||||
*(__vermagic) /* Kernel version magic */
|
||||
*(.rodata1)
|
||||
*(.rodata.str1.1)
|
||||
|
||||
/* Kernel symbol table: Normal symbols */
|
||||
. = ALIGN(4);
|
||||
__start___ksymtab = .;
|
||||
*(__ksymtab)
|
||||
__stop___ksymtab = .;
|
||||
|
||||
/* Kernel symbol table: GPL-only symbols */
|
||||
__start___ksymtab_gpl = .;
|
||||
*(__ksymtab_gpl)
|
||||
__stop___ksymtab_gpl = .;
|
||||
|
||||
/* Kernel symbol table: Normal symbols */
|
||||
__start___kcrctab = .;
|
||||
*(__kcrctab)
|
||||
__stop___kcrctab = .;
|
||||
|
||||
/* Kernel symbol table: GPL-only symbols */
|
||||
__start___kcrctab_gpl = .;
|
||||
*(__kcrctab_gpl)
|
||||
__stop___kcrctab_gpl = .;
|
||||
|
||||
/* Kernel symbol table: strings */
|
||||
*(__ksymtab_strings)
|
||||
|
||||
/* Built-in module parameters */
|
||||
__start___param = .;
|
||||
*(__param)
|
||||
__stop___param = .;
|
||||
|
||||
. = ALIGN(4) ;
|
||||
_etext = . ;
|
||||
} > TEXT
|
||||
|
||||
#ifdef ROM_END
|
||||
. = ROM_END ;
|
||||
.erom : {
|
||||
__rom_end = . ;
|
||||
} > erom
|
||||
#endif
|
||||
#ifdef RAMVEC_START
|
||||
. = RAMVEC_START ;
|
||||
.ramvec : {
|
||||
__ramvec = .;
|
||||
} > ramvec
|
||||
#endif
|
||||
|
||||
.data DATA_ADDR : {
|
||||
. = ALIGN(4);
|
||||
_sdata = . ;
|
||||
*(.data)
|
||||
. = ALIGN(8192) ;
|
||||
*(.data.init_task)
|
||||
_edata = . ;
|
||||
} > DATA
|
||||
|
||||
.init : {
|
||||
. = ALIGN(4096);
|
||||
__init_begin = .;
|
||||
_sinittext = .;
|
||||
*(.init.text)
|
||||
_einittext = .;
|
||||
*(.init.data)
|
||||
. = ALIGN(16);
|
||||
__setup_start = .;
|
||||
*(.init.setup)
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
*(.initcall1.init)
|
||||
*(.initcall2.init)
|
||||
*(.initcall3.init)
|
||||
*(.initcall4.init)
|
||||
*(.initcall5.init)
|
||||
*(.initcall6.init)
|
||||
*(.initcall7.init)
|
||||
__initcall_end = .;
|
||||
__con_initcall_start = .;
|
||||
*(.con_initcall.init)
|
||||
__con_initcall_end = .;
|
||||
__security_initcall_start = .;
|
||||
*(.security_initcall.init)
|
||||
__security_initcall_end = .;
|
||||
. = ALIGN(4);
|
||||
__initramfs_start = .;
|
||||
*(.init.ramfs)
|
||||
__initramfs_end = .;
|
||||
. = ALIGN(4096);
|
||||
__init_end = .;
|
||||
} > INIT
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.exit.text)
|
||||
*(.exit.data)
|
||||
*(.exitcall.exit)
|
||||
}
|
||||
|
||||
.bss : {
|
||||
. = ALIGN(4);
|
||||
_sbss = . ;
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
. = ALIGN(4) ;
|
||||
_ebss = . ;
|
||||
} > BSS
|
||||
|
||||
#ifdef RAM_END
|
||||
. = RAM_END ;
|
||||
.eram : {
|
||||
__ramend = . ;
|
||||
_ramend = . ;
|
||||
} > eram
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user