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:
18
arch/m68k/kernel/Makefile
Normal file
18
arch/m68k/kernel/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
ifndef CONFIG_SUN3
|
||||
extra-y := head.o
|
||||
else
|
||||
extra-y := sun3-head.o
|
||||
endif
|
||||
extra-y += vmlinux.lds
|
||||
|
||||
obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \
|
||||
sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
|
||||
|
||||
obj-$(CONFIG_PCI) += bios32.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
|
||||
EXTRA_AFLAGS := -traditional
|
109
arch/m68k/kernel/asm-offsets.c
Normal file
109
arch/m68k/kernel/asm-offsets.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/amigahw.h>
|
||||
#include <linux/font.h>
|
||||
|
||||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
||||
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_WORK, offsetof(struct task_struct, thread.work));
|
||||
DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, thread.work.need_resched));
|
||||
DEFINE(TASK_SYSCALL_TRACE, offsetof(struct task_struct, thread.work.syscall_trace));
|
||||
DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, thread.work.sigpending));
|
||||
DEFINE(TASK_NOTIFY_RESUME, offsetof(struct task_struct, thread.work.notify_resume));
|
||||
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
|
||||
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
|
||||
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
|
||||
|
||||
/* 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));
|
||||
/* 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));
|
||||
|
||||
/* 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 bi_record struct */
|
||||
DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
|
||||
DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
|
||||
DEFINE(BIR_DATA, offsetof(struct bi_record, data));
|
||||
|
||||
/* offsets into font_desc (drivers/video/console/font.h) */
|
||||
DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
|
||||
DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
|
||||
DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
|
||||
DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
|
||||
DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
|
||||
DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
|
||||
|
||||
/* signal defines */
|
||||
DEFINE(SIGSEGV, SIGSEGV);
|
||||
DEFINE(SEGV_MAPERR, SEGV_MAPERR);
|
||||
DEFINE(SIGTRAP, SIGTRAP);
|
||||
DEFINE(TRAP_TRACE, TRAP_TRACE);
|
||||
|
||||
/* offsets into the custom struct */
|
||||
DEFINE(CUSTOMBASE, &custom);
|
||||
DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
|
||||
DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
|
||||
DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
|
||||
DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
|
||||
DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
|
||||
DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
|
||||
DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
|
||||
DEFINE(CIAABASE, &ciaa);
|
||||
DEFINE(CIABBASE, &ciab);
|
||||
DEFINE(C_PRA, offsetof(struct CIA, pra));
|
||||
DEFINE(ZTWOBASE, zTwoBase);
|
||||
|
||||
return 0;
|
||||
}
|
515
arch/m68k/kernel/bios32.c
Normal file
515
arch/m68k/kernel/bios32.c
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* bios32.c - PCI BIOS functions for m68k systems.
|
||||
*
|
||||
* Written by Wout Klaren.
|
||||
*
|
||||
* Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#if 0
|
||||
# define DBG_DEVS(args) printk args
|
||||
#else
|
||||
# define DBG_DEVS(args)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
/*
|
||||
* PCI support for Linux/m68k. Currently only the Hades is supported.
|
||||
*
|
||||
* The support for PCI bridges in the DEC Alpha version has
|
||||
* been removed in this version.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/pci.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define KB 1024
|
||||
#define MB (1024*KB)
|
||||
#define GB (1024*MB)
|
||||
|
||||
#define MAJOR_REV 0
|
||||
#define MINOR_REV 5
|
||||
|
||||
/*
|
||||
* Align VAL to ALIGN, which must be a power of two.
|
||||
*/
|
||||
|
||||
#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
/*
|
||||
* Offsets relative to the I/O and memory base addresses from where resources
|
||||
* are allocated.
|
||||
*/
|
||||
|
||||
#define IO_ALLOC_OFFSET 0x00004000
|
||||
#define MEM_ALLOC_OFFSET 0x04000000
|
||||
|
||||
/*
|
||||
* Declarations of hardware specific initialisation functions.
|
||||
*/
|
||||
|
||||
extern struct pci_bus_info *init_hades_pci(void);
|
||||
|
||||
/*
|
||||
* Bus info structure of the PCI bus. A pointer to this structure is
|
||||
* put in the sysdata member of the pci_bus structure.
|
||||
*/
|
||||
|
||||
static struct pci_bus_info *bus_info;
|
||||
|
||||
static int pci_modify = 1; /* If set, layout the PCI bus ourself. */
|
||||
static int skip_vga; /* If set do not modify base addresses
|
||||
of vga cards.*/
|
||||
static int disable_pci_burst; /* If set do not allow PCI bursts. */
|
||||
|
||||
static unsigned int io_base;
|
||||
static unsigned int mem_base;
|
||||
|
||||
/*
|
||||
* static void disable_dev(struct pci_dev *dev)
|
||||
*
|
||||
* Disable PCI device DEV so that it does not respond to I/O or memory
|
||||
* accesses.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* dev - device to disable.
|
||||
*/
|
||||
|
||||
static void __init disable_dev(struct pci_dev *dev)
|
||||
{
|
||||
unsigned short cmd;
|
||||
|
||||
if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
|
||||
(dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
|
||||
(dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
|
||||
cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
* static void layout_dev(struct pci_dev *dev)
|
||||
*
|
||||
* Layout memory and I/O for a device.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* device - device to layout memory and I/O for.
|
||||
*/
|
||||
|
||||
static void __init layout_dev(struct pci_dev *dev)
|
||||
{
|
||||
unsigned short cmd;
|
||||
unsigned int base, mask, size, reg;
|
||||
unsigned int alignto;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Skip video cards if requested.
|
||||
*/
|
||||
|
||||
if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
|
||||
(dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
|
||||
(dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
|
||||
for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
|
||||
{
|
||||
/*
|
||||
* Figure out how much space and of what type this
|
||||
* device wants.
|
||||
*/
|
||||
|
||||
pci_write_config_dword(dev, reg, 0xffffffff);
|
||||
pci_read_config_dword(dev, reg, &base);
|
||||
|
||||
if (!base)
|
||||
{
|
||||
/* this base-address register is unused */
|
||||
dev->resource[i].start = 0;
|
||||
dev->resource[i].end = 0;
|
||||
dev->resource[i].flags = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We've read the base address register back after
|
||||
* writing all ones and so now we must decode it.
|
||||
*/
|
||||
|
||||
if (base & PCI_BASE_ADDRESS_SPACE_IO)
|
||||
{
|
||||
/*
|
||||
* I/O space base address register.
|
||||
*/
|
||||
|
||||
cmd |= PCI_COMMAND_IO;
|
||||
|
||||
base &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
mask = (~base << 1) | 0x1;
|
||||
size = (mask & base) & 0xffffffff;
|
||||
|
||||
/*
|
||||
* Align to multiple of size of minimum base.
|
||||
*/
|
||||
|
||||
alignto = max_t(unsigned int, 0x040, size);
|
||||
base = ALIGN(io_base, alignto);
|
||||
io_base = base + size;
|
||||
pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO);
|
||||
|
||||
dev->resource[i].start = base;
|
||||
dev->resource[i].end = dev->resource[i].start + size - 1;
|
||||
dev->resource[i].flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
|
||||
|
||||
DBG_DEVS(("layout_dev: IO address: %lX\n", base));
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int type;
|
||||
|
||||
/*
|
||||
* Memory space base address register.
|
||||
*/
|
||||
|
||||
cmd |= PCI_COMMAND_MEMORY;
|
||||
type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
|
||||
base &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||
mask = (~base << 1) | 0x1;
|
||||
size = (mask & base) & 0xffffffff;
|
||||
switch (type)
|
||||
{
|
||||
case PCI_BASE_ADDRESS_MEM_TYPE_32:
|
||||
case PCI_BASE_ADDRESS_MEM_TYPE_64:
|
||||
break;
|
||||
|
||||
case PCI_BASE_ADDRESS_MEM_TYPE_1M:
|
||||
printk("bios32 WARNING: slot %d, function %d "
|
||||
"requests memory below 1MB---don't "
|
||||
"know how to do that.\n",
|
||||
PCI_SLOT(dev->devfn),
|
||||
PCI_FUNC(dev->devfn));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Align to multiple of size of minimum base.
|
||||
*/
|
||||
|
||||
alignto = max_t(unsigned int, 0x1000, size);
|
||||
base = ALIGN(mem_base, alignto);
|
||||
mem_base = base + size;
|
||||
pci_write_config_dword(dev, reg, base);
|
||||
|
||||
dev->resource[i].start = base;
|
||||
dev->resource[i].end = dev->resource[i].start + size - 1;
|
||||
dev->resource[i].flags = IORESOURCE_MEM;
|
||||
|
||||
if (type == PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
{
|
||||
/*
|
||||
* 64-bit address, set the highest 32 bits
|
||||
* to zero.
|
||||
*/
|
||||
|
||||
reg += 4;
|
||||
pci_write_config_dword(dev, reg, 0);
|
||||
|
||||
i++;
|
||||
dev->resource[i].start = 0;
|
||||
dev->resource[i].end = 0;
|
||||
dev->resource[i].flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable device:
|
||||
*/
|
||||
|
||||
if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
|
||||
dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
|
||||
dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
|
||||
dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
|
||||
{
|
||||
/*
|
||||
* All of these (may) have I/O scattered all around
|
||||
* and may not use i/o-base address registers at all.
|
||||
* So we just have to always enable I/O to these
|
||||
* devices.
|
||||
*/
|
||||
cmd |= PCI_COMMAND_IO;
|
||||
}
|
||||
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
|
||||
|
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32);
|
||||
|
||||
if (bus_info != NULL)
|
||||
bus_info->conf_device(dev); /* Machine dependent configuration. */
|
||||
|
||||
DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n",
|
||||
dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
|
||||
}
|
||||
|
||||
/*
|
||||
* static void layout_bus(struct pci_bus *bus)
|
||||
*
|
||||
* Layout memory and I/O for all devices on the given bus.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* bus - bus.
|
||||
*/
|
||||
|
||||
static void __init layout_bus(struct pci_bus *bus)
|
||||
{
|
||||
unsigned int bio, bmem;
|
||||
struct pci_dev *dev;
|
||||
|
||||
DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
|
||||
|
||||
if (!bus->devices && !bus->children)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Align the current bases on appropriate boundaries (4K for
|
||||
* IO and 1MB for memory).
|
||||
*/
|
||||
|
||||
bio = io_base = ALIGN(io_base, 4*KB);
|
||||
bmem = mem_base = ALIGN(mem_base, 1*MB);
|
||||
|
||||
/*
|
||||
* PCI devices might have been setup by a PCI BIOS emulation
|
||||
* running under TOS. In these cases there is a
|
||||
* window during which two devices may have an overlapping
|
||||
* address range. To avoid this causing trouble, we first
|
||||
* turn off the I/O and memory address decoders for all PCI
|
||||
* devices. They'll be re-enabled only once all address
|
||||
* decoders are programmed consistently.
|
||||
*/
|
||||
|
||||
DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number));
|
||||
|
||||
for (dev = bus->devices; dev; dev = dev->sibling)
|
||||
{
|
||||
if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
|
||||
(dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
|
||||
disable_dev(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space to each device:
|
||||
*/
|
||||
|
||||
DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
|
||||
|
||||
for (dev = bus->devices; dev; dev = dev->sibling)
|
||||
{
|
||||
if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
|
||||
(dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
|
||||
layout_dev(dev);
|
||||
}
|
||||
|
||||
DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
|
||||
}
|
||||
|
||||
/*
|
||||
* static void pcibios_fixup(void)
|
||||
*
|
||||
* Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is
|
||||
* true. This might be necessary because not every m68k machine with a PCI
|
||||
* bus has a PCI BIOS. This function should be called right after
|
||||
* pci_scan_bus() in pcibios_init().
|
||||
*/
|
||||
|
||||
static void __init pcibios_fixup(void)
|
||||
{
|
||||
if (pci_modify)
|
||||
{
|
||||
/*
|
||||
* Set base addresses for allocation of I/O and memory space.
|
||||
*/
|
||||
|
||||
io_base = bus_info->io_space.start + IO_ALLOC_OFFSET;
|
||||
mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET;
|
||||
|
||||
/*
|
||||
* Scan the tree, allocating PCI memory and I/O space.
|
||||
*/
|
||||
|
||||
layout_bus(pci_bus_b(pci_root.next));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix interrupt assignments, etc.
|
||||
*/
|
||||
|
||||
bus_info->fixup(pci_modify);
|
||||
}
|
||||
|
||||
/*
|
||||
* static void pcibios_claim_resources(struct pci_bus *bus)
|
||||
*
|
||||
* Claim all resources that are assigned to devices on the given bus.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* bus - bus.
|
||||
*/
|
||||
|
||||
static void __init pcibios_claim_resources(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
int i;
|
||||
|
||||
while (bus)
|
||||
{
|
||||
for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
|
||||
{
|
||||
for (i = 0; i < PCI_NUM_RESOURCES; i++)
|
||||
{
|
||||
struct resource *r = &dev->resource[i];
|
||||
struct resource *pr;
|
||||
struct pci_bus_info *bus_info = (struct pci_bus_info *) dev->sysdata;
|
||||
|
||||
if ((r->start == 0) || (r->parent != NULL))
|
||||
continue;
|
||||
#if 1
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
pr = &bus_info->io_space;
|
||||
else
|
||||
pr = &bus_info->mem_space;
|
||||
#else
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
pr = &ioport_resource;
|
||||
else
|
||||
pr = &iomem_resource;
|
||||
#endif
|
||||
if (request_resource(pr, r) < 0)
|
||||
{
|
||||
printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", i, dev->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->children)
|
||||
pcibios_claim_resources(bus->children);
|
||||
|
||||
bus = bus->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* int pcibios_assign_resource(struct pci_dev *dev, int i)
|
||||
*
|
||||
* Assign a new address to a PCI resource.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* dev - device.
|
||||
* i - resource.
|
||||
*
|
||||
* Result: 0 if successful.
|
||||
*/
|
||||
|
||||
int __init pcibios_assign_resource(struct pci_dev *dev, int i)
|
||||
{
|
||||
struct resource *r = &dev->resource[i];
|
||||
struct resource *pr = pci_find_parent_resource(dev, r);
|
||||
unsigned long size = r->end + 1;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
{
|
||||
if (size > 0x100)
|
||||
return -EFBIG;
|
||||
|
||||
if (allocate_resource(pr, r, size, bus_info->io_space.start +
|
||||
IO_ALLOC_OFFSET, bus_info->io_space.end, 1024))
|
||||
return -EBUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (allocate_resource(pr, r, size, bus_info->mem_space.start +
|
||||
MEM_ALLOC_OFFSET, bus_info->mem_space.end, size))
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (i < 6)
|
||||
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, r->start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
void *sysdata;
|
||||
|
||||
sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata;
|
||||
|
||||
for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
|
||||
dev->sysdata = sysdata;
|
||||
}
|
||||
|
||||
void __init pcibios_init(void)
|
||||
{
|
||||
printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
|
||||
|
||||
bus_info = NULL;
|
||||
#ifdef CONFIG_HADES
|
||||
if (MACH_IS_HADES)
|
||||
bus_info = init_hades_pci();
|
||||
#endif
|
||||
if (bus_info != NULL)
|
||||
{
|
||||
printk("PCI: Probing PCI hardware\n");
|
||||
pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info);
|
||||
pcibios_fixup();
|
||||
pcibios_claim_resources(pci_root);
|
||||
}
|
||||
else
|
||||
printk("PCI: No PCI bus detected\n");
|
||||
}
|
||||
|
||||
char * __init pcibios_setup(char *str)
|
||||
{
|
||||
if (!strcmp(str, "nomodify"))
|
||||
{
|
||||
pci_modify = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(str, "skipvga"))
|
||||
{
|
||||
skip_vga = 1;
|
||||
return NULL;
|
||||
}
|
||||
else if (!strcmp(str, "noburst"))
|
||||
{
|
||||
disable_pci_burst = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
712
arch/m68k/kernel/entry.S
Normal file
712
arch/m68k/kernel/entry.S
Normal file
@@ -0,0 +1,712 @@
|
||||
/* -*- mode: asm -*-
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* entry.S contains the system-call and fault low-level handling routines.
|
||||
* This also contains the timer-interrupt handler, as well as all interrupts
|
||||
* and faults that can result in a task-switch.
|
||||
*
|
||||
* NOTE: This code handles signal-recognition, which happens every time
|
||||
* after a timer-interrupt and after each system call.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
|
||||
* all pointers that used to be 'current' are now entry
|
||||
* number 0 in the 'current_set' list.
|
||||
*
|
||||
* 6/05/00 RZ: addedd writeback completion after return from sighandler
|
||||
* for 68040
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include <asm/offsets.h>
|
||||
|
||||
.globl system_call, buserr, trap
|
||||
.globl resume, ret_from_exception
|
||||
.globl ret_from_signal
|
||||
.globl inthandler, sys_call_table
|
||||
.globl sys_fork, sys_clone, sys_vfork
|
||||
.globl ret_from_interrupt, bad_interrupt
|
||||
|
||||
.text
|
||||
ENTRY(buserr)
|
||||
SAVE_ALL_INT
|
||||
GET_CURRENT(%d0)
|
||||
movel %sp,%sp@- | stack frame pointer argument
|
||||
bsrl buserr_c
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
|
||||
ENTRY(trap)
|
||||
SAVE_ALL_INT
|
||||
GET_CURRENT(%d0)
|
||||
movel %sp,%sp@- | stack frame pointer argument
|
||||
bsrl trap_c
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
|
||||
| After a fork we jump here directly from resume,
|
||||
| so that %d1 contains the previous task
|
||||
| schedule_tail now used regardless of CONFIG_SMP
|
||||
ENTRY(ret_from_fork)
|
||||
movel %d1,%sp@-
|
||||
jsr schedule_tail
|
||||
addql #4,%sp
|
||||
jra ret_from_exception
|
||||
|
||||
badsys:
|
||||
movel #-ENOSYS,%sp@(PT_D0)
|
||||
jra ret_from_exception
|
||||
|
||||
do_trace:
|
||||
movel #-ENOSYS,%sp@(PT_D0) | needed for strace
|
||||
subql #4,%sp
|
||||
SAVE_SWITCH_STACK
|
||||
jbsr syscall_trace
|
||||
RESTORE_SWITCH_STACK
|
||||
addql #4,%sp
|
||||
movel %sp@(PT_ORIG_D0),%d1
|
||||
movel #-ENOSYS,%d0
|
||||
cmpl #NR_syscalls,%d1
|
||||
jcc 1f
|
||||
jbsr @(sys_call_table,%d1:l:4)@(0)
|
||||
1: movel %d0,%sp@(PT_D0) | save the return value
|
||||
subql #4,%sp | dummy return address
|
||||
SAVE_SWITCH_STACK
|
||||
jbsr syscall_trace
|
||||
|
||||
ret_from_signal:
|
||||
RESTORE_SWITCH_STACK
|
||||
addql #4,%sp
|
||||
/* on 68040 complete pending writebacks if any */
|
||||
#ifdef CONFIG_M68040
|
||||
bfextu %sp@(PT_VECTOR){#0,#4},%d0
|
||||
subql #7,%d0 | bus error frame ?
|
||||
jbne 1f
|
||||
movel %sp,%sp@-
|
||||
jbsr berr_040cleanup
|
||||
addql #4,%sp
|
||||
1:
|
||||
#endif
|
||||
jra ret_from_exception
|
||||
|
||||
ENTRY(system_call)
|
||||
SAVE_ALL_SYS
|
||||
|
||||
GET_CURRENT(%d1)
|
||||
| save top of frame
|
||||
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
|
||||
|
||||
tstb %curptr@(TASK_SYSCALL_TRACE)
|
||||
jne do_trace
|
||||
cmpl #NR_syscalls,%d0
|
||||
jcc badsys
|
||||
jbsr @(sys_call_table,%d0:l:4)@(0)
|
||||
movel %d0,%sp@(PT_D0) | save the return value
|
||||
|
||||
|oriw #0x0700,%sr
|
||||
movel %curptr@(TASK_WORK),%d0
|
||||
jne syscall_exit_work
|
||||
1: RESTORE_ALL
|
||||
|
||||
syscall_exit_work:
|
||||
btst #5,%sp@(PT_SR) | check if returning to kernel
|
||||
bnes 1b | if so, skip resched, signals
|
||||
tstw %d0
|
||||
jeq do_signal_return
|
||||
tstb %d0
|
||||
jne do_delayed_trace
|
||||
|
||||
pea resume_userspace
|
||||
jmp schedule
|
||||
|
||||
ret_from_exception:
|
||||
btst #5,%sp@(PT_SR) | check if returning to kernel
|
||||
bnes 1f | if so, skip resched, signals
|
||||
| only allow interrupts when we are really the last one on the
|
||||
| kernel stack, otherwise stack overflow can occur during
|
||||
| heavy interrupt load
|
||||
andw #ALLOWINT,%sr
|
||||
|
||||
resume_userspace:
|
||||
movel %curptr@(TASK_WORK),%d0
|
||||
lsrl #8,%d0
|
||||
jne exit_work
|
||||
1: RESTORE_ALL
|
||||
|
||||
exit_work:
|
||||
| save top of frame
|
||||
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
|
||||
tstb %d0
|
||||
jeq do_signal_return
|
||||
|
||||
pea resume_userspace
|
||||
jmp schedule
|
||||
|
||||
do_signal_return:
|
||||
|andw #ALLOWINT,%sr
|
||||
subql #4,%sp | dummy return address
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
clrl %sp@-
|
||||
bsrl do_signal
|
||||
addql #8,%sp
|
||||
RESTORE_SWITCH_STACK
|
||||
addql #4,%sp
|
||||
jbra resume_userspace
|
||||
|
||||
do_delayed_trace:
|
||||
bclr #7,%sp@(PT_SR) | clear trace bit in SR
|
||||
pea 1 | send SIGTRAP
|
||||
movel %curptr,%sp@-
|
||||
pea LSIGTRAP
|
||||
jbsr send_sig
|
||||
addql #8,%sp
|
||||
addql #4,%sp
|
||||
jbra resume_userspace
|
||||
|
||||
|
||||
#if 0
|
||||
#ifdef CONFIG_AMIGA
|
||||
ami_inthandler:
|
||||
addql #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT
|
||||
SAVE_ALL_INT
|
||||
GET_CURRENT(%d0)
|
||||
|
||||
bfextu %sp@(PT_VECTOR){#4,#12},%d0
|
||||
movel %d0,%a0
|
||||
addql #1,%a0@(kstat+STAT_IRQ-VECOFF(VEC_SPUR))
|
||||
movel %a0@(autoirq_list-VECOFF(VEC_SPUR)),%a0
|
||||
|
||||
| amiga vector int handler get the req mask instead of irq vector
|
||||
lea CUSTOMBASE,%a1
|
||||
movew %a1@(C_INTREQR),%d0
|
||||
andw %a1@(C_INTENAR),%d0
|
||||
|
||||
| prepare stack (push frame pointer, dev_id & req mask)
|
||||
pea %sp@
|
||||
movel %a0@(IRQ_DEVID),%sp@-
|
||||
movel %d0,%sp@-
|
||||
pea %pc@(ret_from_interrupt:w)
|
||||
jbra @(IRQ_HANDLER,%a0)@(0)
|
||||
|
||||
ENTRY(nmi_handler)
|
||||
rte
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is the main interrupt handler, responsible for calling process_int()
|
||||
*/
|
||||
inthandler:
|
||||
SAVE_ALL_INT
|
||||
GET_CURRENT(%d0)
|
||||
addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2)
|
||||
| put exception # in d0
|
||||
bfextu %sp@(PT_VECTOR){#4,#10},%d0
|
||||
|
||||
movel %sp,%sp@-
|
||||
movel %d0,%sp@- | put vector # on stack
|
||||
#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
|
||||
btstb #4,0xff000000 | Q40 floppy needs very special treatment ...
|
||||
jbeq 1f
|
||||
btstb #3,0xff000004
|
||||
jbeq 1f
|
||||
jbsr floppy_hardint
|
||||
jbra 3f
|
||||
1:
|
||||
#endif
|
||||
jbsr process_int | process the IRQ
|
||||
3: addql #8,%sp | pop parameters off stack
|
||||
|
||||
ret_from_interrupt:
|
||||
subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2)
|
||||
jeq 1f
|
||||
2:
|
||||
RESTORE_ALL
|
||||
1:
|
||||
moveq #(~ALLOWINT>>8)&0xff,%d0
|
||||
andb %sp@(PT_SR),%d0
|
||||
jne 2b
|
||||
|
||||
/* check if we need to do software interrupts */
|
||||
tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING
|
||||
jeq ret_from_exception
|
||||
pea ret_from_exception
|
||||
jra do_softirq
|
||||
|
||||
|
||||
/* Handler for uninitialized and spurious interrupts */
|
||||
|
||||
bad_interrupt:
|
||||
addql #1,num_spurious
|
||||
rte
|
||||
|
||||
ENTRY(sys_fork)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr m68k_fork
|
||||
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_vfork)
|
||||
SAVE_SWITCH_STACK
|
||||
pea %sp@(SWITCH_STACK_SIZE)
|
||||
jbsr m68k_vfork
|
||||
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
|
||||
|
||||
resume:
|
||||
/*
|
||||
* Beware - when entering resume, prev (the current task) is
|
||||
* in a0, next (the new task) is in a1,so don't change these
|
||||
* registers until their contents are no longer needed.
|
||||
*/
|
||||
|
||||
/* save sr */
|
||||
movew %sr,%a0@(TASK_THREAD+THREAD_SR)
|
||||
|
||||
/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
|
||||
movec %sfc,%d0
|
||||
movew %d0,%a0@(TASK_THREAD+THREAD_FS)
|
||||
|
||||
/* save usp */
|
||||
/* it is better to use a movel here instead of a movew 8*) */
|
||||
movec %usp,%d0
|
||||
movel %d0,%a0@(TASK_THREAD+THREAD_USP)
|
||||
|
||||
/* save non-scratch registers on stack */
|
||||
SAVE_SWITCH_STACK
|
||||
|
||||
/* save current kernel stack pointer */
|
||||
movel %sp,%a0@(TASK_THREAD+THREAD_KSP)
|
||||
|
||||
/* save floating point context */
|
||||
#ifndef CONFIG_M68KFPU_EMU_ONLY
|
||||
#ifdef CONFIG_M68KFPU_EMU
|
||||
tstl m68k_fputype
|
||||
jeq 3f
|
||||
#endif
|
||||
fsave %a0@(TASK_THREAD+THREAD_FPSTATE)
|
||||
|
||||
#if defined(CONFIG_M68060)
|
||||
#if !defined(CPU_M68060_ONLY)
|
||||
btst #3,m68k_cputype+3
|
||||
beqs 1f
|
||||
#endif
|
||||
/* The 060 FPU keeps status in bits 15-8 of the first longword */
|
||||
tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2)
|
||||
jeq 3f
|
||||
#if !defined(CPU_M68060_ONLY)
|
||||
jra 2f
|
||||
#endif
|
||||
#endif /* CONFIG_M68060 */
|
||||
#if !defined(CPU_M68060_ONLY)
|
||||
1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE)
|
||||
jeq 3f
|
||||
#endif
|
||||
2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
|
||||
fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
|
||||
3:
|
||||
#endif /* CONFIG_M68KFPU_EMU_ONLY */
|
||||
/* Return previous task in %d1 */
|
||||
movel %curptr,%d1
|
||||
|
||||
/* switch to new task (a1 contains new task) */
|
||||
movel %a1,%curptr
|
||||
|
||||
/* restore floating point context */
|
||||
#ifndef CONFIG_M68KFPU_EMU_ONLY
|
||||
#ifdef CONFIG_M68KFPU_EMU
|
||||
tstl m68k_fputype
|
||||
jeq 4f
|
||||
#endif
|
||||
#if defined(CONFIG_M68060)
|
||||
#if !defined(CPU_M68060_ONLY)
|
||||
btst #3,m68k_cputype+3
|
||||
beqs 1f
|
||||
#endif
|
||||
/* The 060 FPU keeps status in bits 15-8 of the first longword */
|
||||
tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2)
|
||||
jeq 3f
|
||||
#if !defined(CPU_M68060_ONLY)
|
||||
jra 2f
|
||||
#endif
|
||||
#endif /* CONFIG_M68060 */
|
||||
#if !defined(CPU_M68060_ONLY)
|
||||
1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE)
|
||||
jeq 3f
|
||||
#endif
|
||||
2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
|
||||
fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
|
||||
3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
|
||||
4:
|
||||
#endif /* CONFIG_M68KFPU_EMU_ONLY */
|
||||
|
||||
/* restore the kernel stack pointer */
|
||||
movel %a1@(TASK_THREAD+THREAD_KSP),%sp
|
||||
|
||||
/* restore non-scratch registers */
|
||||
RESTORE_SWITCH_STACK
|
||||
|
||||
/* restore user stack pointer */
|
||||
movel %a1@(TASK_THREAD+THREAD_USP),%a0
|
||||
movel %a0,%usp
|
||||
|
||||
/* restore fs (sfc,%dfc) */
|
||||
movew %a1@(TASK_THREAD+THREAD_FS),%a0
|
||||
movec %a0,%sfc
|
||||
movec %a0,%dfc
|
||||
|
||||
/* restore status register */
|
||||
movew %a1@(TASK_THREAD+THREAD_SR),%sr
|
||||
|
||||
rts
|
||||
|
||||
.data
|
||||
ALIGN
|
||||
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_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 /* 110 */ /* iopl for i386 */
|
||||
.long sys_vhangup
|
||||
.long sys_ni_syscall /* obsolete idle() syscall */
|
||||
.long sys_ni_syscall /* vm86old for i386 */
|
||||
.long sys_wait4
|
||||
.long sys_swapoff /* 115 */
|
||||
.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_mprotect /* 125 */
|
||||
.long sys_sigprocmask
|
||||
.long sys_ni_syscall /* old "create_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_msync
|
||||
.long sys_readv /* 145 */
|
||||
.long sys_writev
|
||||
.long sys_getsid
|
||||
.long sys_fdatasync
|
||||
.long sys_sysctl
|
||||
.long sys_mlock /* 150 */
|
||||
.long sys_munlock
|
||||
.long sys_mlockall
|
||||
.long 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_mremap
|
||||
.long sys_setresuid16
|
||||
.long sys_getresuid16 /* 165 */
|
||||
.long sys_getpagesize
|
||||
.long sys_ni_syscall /* old sys_query_module */
|
||||
.long sys_poll
|
||||
.long 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_mincore
|
||||
.long 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_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 /* for sys_vserver */
|
||||
.long sys_add_key
|
||||
.long sys_request_key /* 280 */
|
||||
.long sys_keyctl
|
||||
|
3940
arch/m68k/kernel/head.S
Normal file
3940
arch/m68k/kernel/head.S
Normal file
File diff suppressed because it is too large
Load Diff
281
arch/m68k/kernel/ints.c
Normal file
281
arch/m68k/kernel/ints.c
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 07/03/96: Timer initialization, and thus mach_sched_init(),
|
||||
* removed from request_irq() and moved to init_time().
|
||||
* We should therefore consider renaming our add_isr() and
|
||||
* remove_isr() to request_irq() and free_irq()
|
||||
* respectively, so they are compliant with the other
|
||||
* architectures. /Jes
|
||||
* 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls.
|
||||
* Removed irq list support, if any machine needs an irq server
|
||||
* it must implement this itself (as it's already done), instead
|
||||
* only default handler are used with mach_default_handler.
|
||||
* request_irq got some flags different from other architectures:
|
||||
* - IRQ_FLG_REPLACE : Replace an existing handler (the default one
|
||||
* can be replaced without this flag)
|
||||
* - IRQ_FLG_LOCK : handler can't be replaced
|
||||
* There are other machine depending flags, see there
|
||||
* If you want to replace a default handler you should know what
|
||||
* you're doing, since it might handle different other irq sources
|
||||
* which must be served /Roman Zippel
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
#ifdef CONFIG_Q40
|
||||
#include <asm/q40ints.h>
|
||||
#endif
|
||||
|
||||
/* table for system interrupt handlers */
|
||||
static irq_handler_t irq_list[SYS_IRQS];
|
||||
|
||||
static const char *default_names[SYS_IRQS] = {
|
||||
[0] = "spurious int",
|
||||
[1] = "int1 handler",
|
||||
[2] = "int2 handler",
|
||||
[3] = "int3 handler",
|
||||
[4] = "int4 handler",
|
||||
[5] = "int5 handler",
|
||||
[6] = "int6 handler",
|
||||
[7] = "int7 handler"
|
||||
};
|
||||
|
||||
/* The number of spurious interrupts */
|
||||
volatile unsigned int num_spurious;
|
||||
|
||||
#define NUM_IRQ_NODES 100
|
||||
static irq_node_t nodes[NUM_IRQ_NODES];
|
||||
|
||||
static void dummy_enable_irq(unsigned int irq);
|
||||
static void dummy_disable_irq(unsigned int irq);
|
||||
static int dummy_request_irq(unsigned int irq,
|
||||
irqreturn_t (*handler) (int, void *, struct pt_regs *),
|
||||
unsigned long flags, const char *devname, void *dev_id);
|
||||
static void dummy_free_irq(unsigned int irq, void *dev_id);
|
||||
|
||||
void (*enable_irq) (unsigned int) = dummy_enable_irq;
|
||||
void (*disable_irq) (unsigned int) = dummy_disable_irq;
|
||||
|
||||
int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *),
|
||||
unsigned long, const char *, void *) = dummy_request_irq;
|
||||
void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
|
||||
|
||||
void init_irq_proc(void);
|
||||
|
||||
/*
|
||||
* void init_IRQ(void)
|
||||
*
|
||||
* Parameters: None
|
||||
*
|
||||
* Returns: Nothing
|
||||
*
|
||||
* This function should be called during kernel startup to initialize
|
||||
* the IRQ handling routines.
|
||||
*/
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SYS_IRQS; i++) {
|
||||
if (mach_default_handler)
|
||||
irq_list[i].handler = (*mach_default_handler)[i];
|
||||
irq_list[i].flags = 0;
|
||||
irq_list[i].dev_id = NULL;
|
||||
irq_list[i].devname = default_names[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_IRQ_NODES; i++)
|
||||
nodes[i].handler = NULL;
|
||||
|
||||
mach_init_IRQ ();
|
||||
}
|
||||
|
||||
irq_node_t *new_irq_node(void)
|
||||
{
|
||||
irq_node_t *node;
|
||||
short i;
|
||||
|
||||
for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
|
||||
if (!node->handler)
|
||||
return node;
|
||||
|
||||
printk ("new_irq_node: out of nodes\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We will keep these functions until I have convinced Linus to move
|
||||
* the declaration of them from include/linux/sched.h to
|
||||
* include/asm/irq.h.
|
||||
*/
|
||||
int request_irq(unsigned int irq,
|
||||
irqreturn_t (*handler) (int, void *, struct pt_regs *),
|
||||
unsigned long flags, const char *devname, void *dev_id)
|
||||
{
|
||||
return mach_request_irq(irq, handler, flags, devname, dev_id);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(request_irq);
|
||||
|
||||
void free_irq(unsigned int irq, void *dev_id)
|
||||
{
|
||||
mach_free_irq(irq, dev_id);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(free_irq);
|
||||
|
||||
int cpu_request_irq(unsigned int irq,
|
||||
irqreturn_t (*handler)(int, void *, struct pt_regs *),
|
||||
unsigned long flags, const char *devname, void *dev_id)
|
||||
{
|
||||
if (irq < IRQ1 || irq > IRQ7) {
|
||||
printk("%s: Incorrect IRQ %d from %s\n",
|
||||
__FUNCTION__, irq, devname);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
|
||||
if (irq_list[irq].flags & IRQ_FLG_LOCK) {
|
||||
printk("%s: IRQ %d from %s is not replaceable\n",
|
||||
__FUNCTION__, irq, irq_list[irq].devname);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!(flags & IRQ_FLG_REPLACE)) {
|
||||
printk("%s: %s can't replace IRQ %d from %s\n",
|
||||
__FUNCTION__, devname, irq, irq_list[irq].devname);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
irq_list[irq].handler = handler;
|
||||
irq_list[irq].flags = flags;
|
||||
irq_list[irq].dev_id = dev_id;
|
||||
irq_list[irq].devname = devname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpu_free_irq(unsigned int irq, void *dev_id)
|
||||
{
|
||||
if (irq < IRQ1 || irq > IRQ7) {
|
||||
printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (irq_list[irq].dev_id != dev_id)
|
||||
printk("%s: Removing probably wrong IRQ %d from %s\n",
|
||||
__FUNCTION__, irq, irq_list[irq].devname);
|
||||
|
||||
irq_list[irq].handler = (*mach_default_handler)[irq];
|
||||
irq_list[irq].flags = 0;
|
||||
irq_list[irq].dev_id = NULL;
|
||||
irq_list[irq].devname = default_names[irq];
|
||||
}
|
||||
|
||||
/*
|
||||
* Do we need these probe functions on the m68k?
|
||||
*
|
||||
* ... may be useful with ISA devices
|
||||
*/
|
||||
unsigned long probe_irq_on (void)
|
||||
{
|
||||
#ifdef CONFIG_Q40
|
||||
if (MACH_IS_Q40)
|
||||
return q40_probe_irq_on();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(probe_irq_on);
|
||||
|
||||
int probe_irq_off (unsigned long irqs)
|
||||
{
|
||||
#ifdef CONFIG_Q40
|
||||
if (MACH_IS_Q40)
|
||||
return q40_probe_irq_off(irqs);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(probe_irq_off);
|
||||
|
||||
static void dummy_enable_irq(unsigned int irq)
|
||||
{
|
||||
printk("calling uninitialized enable_irq()\n");
|
||||
}
|
||||
|
||||
static void dummy_disable_irq(unsigned int irq)
|
||||
{
|
||||
printk("calling uninitialized disable_irq()\n");
|
||||
}
|
||||
|
||||
static int dummy_request_irq(unsigned int irq,
|
||||
irqreturn_t (*handler) (int, void *, struct pt_regs *),
|
||||
unsigned long flags, const char *devname, void *dev_id)
|
||||
{
|
||||
printk("calling uninitialized request_irq()\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dummy_free_irq(unsigned int irq, void *dev_id)
|
||||
{
|
||||
printk("calling uninitialized disable_irq()\n");
|
||||
}
|
||||
|
||||
asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
|
||||
{
|
||||
if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
|
||||
vec -= VEC_SPUR;
|
||||
kstat_cpu(0).irqs[vec]++;
|
||||
irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
|
||||
} else {
|
||||
if (mach_process_int)
|
||||
mach_process_int(vec, fp);
|
||||
else
|
||||
panic("Can't process interrupt vector %ld\n", vec);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int show_interrupts(struct seq_file *p, void *v)
|
||||
{
|
||||
int i = *(loff_t *) v;
|
||||
|
||||
/* autovector interrupts */
|
||||
if (i < SYS_IRQS) {
|
||||
if (mach_default_handler) {
|
||||
seq_printf(p, "auto %2d: %10u ", i,
|
||||
i ? kstat_cpu(0).irqs[i] : num_spurious);
|
||||
seq_puts(p, " ");
|
||||
seq_printf(p, "%s\n", irq_list[i].devname);
|
||||
}
|
||||
} else if (i == SYS_IRQS)
|
||||
mach_get_irq_list(p, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_irq_proc(void)
|
||||
{
|
||||
/* Insert /proc/irq driver here */
|
||||
}
|
||||
|
88
arch/m68k/kernel/m68k_ksyms.c
Normal file
88
arch/m68k/kernel/m68k_ksyms.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#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>
|
||||
|
||||
asmlinkage long long __ashldi3 (long long, int);
|
||||
asmlinkage long long __ashrdi3 (long long, int);
|
||||
asmlinkage long long __lshrdi3 (long long, int);
|
||||
asmlinkage long long __muldi3 (long long, long long);
|
||||
extern char m68k_debug_device[];
|
||||
|
||||
extern void dump_thread(struct pt_regs *, struct user *);
|
||||
|
||||
/* platform dependent support */
|
||||
|
||||
EXPORT_SYMBOL(m68k_machtype);
|
||||
EXPORT_SYMBOL(m68k_cputype);
|
||||
EXPORT_SYMBOL(m68k_is040or060);
|
||||
EXPORT_SYMBOL(m68k_realnum_memory);
|
||||
EXPORT_SYMBOL(m68k_memory);
|
||||
#ifndef CONFIG_SUN3
|
||||
EXPORT_SYMBOL(cache_push);
|
||||
EXPORT_SYMBOL(cache_clear);
|
||||
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
|
||||
EXPORT_SYMBOL(mm_vtop);
|
||||
EXPORT_SYMBOL(mm_ptov);
|
||||
EXPORT_SYMBOL(mm_end_of_chunk);
|
||||
#else
|
||||
EXPORT_SYMBOL(m68k_memoffset);
|
||||
#endif /* !CONFIG_SINGLE_MEMORY_CHUNK */
|
||||
EXPORT_SYMBOL(__ioremap);
|
||||
EXPORT_SYMBOL(iounmap);
|
||||
EXPORT_SYMBOL(kernel_set_cachemode);
|
||||
#endif /* !CONFIG_SUN3 */
|
||||
EXPORT_SYMBOL(m68k_debug_device);
|
||||
EXPORT_SYMBOL(mach_hwclk);
|
||||
EXPORT_SYMBOL(mach_get_ss);
|
||||
EXPORT_SYMBOL(mach_get_rtc_pll);
|
||||
EXPORT_SYMBOL(mach_set_rtc_pll);
|
||||
#ifdef CONFIG_INPUT_M68K_BEEP_MODULE
|
||||
EXPORT_SYMBOL(mach_beep);
|
||||
#endif
|
||||
EXPORT_SYMBOL(dump_fpu);
|
||||
EXPORT_SYMBOL(dump_thread);
|
||||
EXPORT_SYMBOL(strnlen);
|
||||
EXPORT_SYMBOL(strrchr);
|
||||
EXPORT_SYMBOL(strstr);
|
||||
EXPORT_SYMBOL(strpbrk);
|
||||
EXPORT_SYMBOL(enable_irq);
|
||||
EXPORT_SYMBOL(disable_irq);
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
#ifdef CONFIG_VME
|
||||
EXPORT_SYMBOL(vme_brdtype);
|
||||
#endif
|
||||
|
||||
/* 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(__ashldi3);
|
||||
EXPORT_SYMBOL(__ashrdi3);
|
||||
EXPORT_SYMBOL(__lshrdi3);
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(memcmp);
|
||||
EXPORT_SYMBOL(memscan);
|
||||
EXPORT_SYMBOL(__muldi3);
|
||||
|
||||
EXPORT_SYMBOL(__down_failed);
|
||||
EXPORT_SYMBOL(__down_failed_interruptible);
|
||||
EXPORT_SYMBOL(__down_failed_trylock);
|
||||
EXPORT_SYMBOL(__up_wakeup);
|
||||
|
||||
EXPORT_SYMBOL(get_wchan);
|
128
arch/m68k/kernel/module.c
Normal file
128
arch/m68k/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)
|
||||
{
|
||||
}
|
405
arch/m68k/kernel/process.c
Normal file
405
arch/m68k/kernel/process.c
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* linux/arch/m68k/kernel/process.c
|
||||
*
|
||||
* Copyright (C) 1995 Hamish Macdonald
|
||||
*
|
||||
* 68060 fixes by Jesper Skov
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of process handling..
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.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/reboot.h>
|
||||
#include <linux/init_task.h>
|
||||
#include <linux/mqueue.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>
|
||||
|
||||
/*
|
||||
* Initial task/thread structure. Make this a per-architecture thing,
|
||||
* because different architectures tend to have different
|
||||
* alignment requirements and potentially different initial
|
||||
* setup.
|
||||
*/
|
||||
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);
|
||||
|
||||
union thread_union init_thread_union
|
||||
__attribute__((section(".data.init_task"), aligned(THREAD_SIZE)))
|
||||
= { INIT_THREAD_INFO(init_task) };
|
||||
|
||||
/* initial task structure */
|
||||
struct task_struct init_task = INIT_TASK(init_task);
|
||||
|
||||
EXPORT_SYMBOL(init_task);
|
||||
|
||||
asmlinkage void ret_from_fork(void);
|
||||
|
||||
|
||||
/*
|
||||
* Return saved PC from 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* The idle loop on an m68k..
|
||||
*/
|
||||
void default_idle(void)
|
||||
{
|
||||
if (!need_resched())
|
||||
#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
|
||||
/* block out HSYNC on the atari (falcon) */
|
||||
__asm__("stop #0x2200" : : : "cc");
|
||||
#else
|
||||
__asm__("stop #0x2000" : : : "cc");
|
||||
#endif
|
||||
}
|
||||
|
||||
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 */
|
||||
while (1) {
|
||||
while (!need_resched())
|
||||
idle();
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
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("\n");
|
||||
printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
|
||||
regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
|
||||
printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
|
||||
regs->orig_d0, regs->d0, regs->a2, regs->a1);
|
||||
printk("A0: %08lx D5: %08lx D4: %08lx\n",
|
||||
regs->a0, regs->d5, regs->d4);
|
||||
printk("D3: %08lx D2: %08lx D1: %08lx\n",
|
||||
regs->d3, regs->d2, regs->d1);
|
||||
if (!(regs->sr & PS_S))
|
||||
printk("USP: %08lx\n", rdusp());
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a kernel thread
|
||||
*/
|
||||
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||
{
|
||||
int pid;
|
||||
mm_segment_t fs;
|
||||
|
||||
fs = get_fs();
|
||||
set_fs (KERNEL_DS);
|
||||
|
||||
{
|
||||
register long retval __asm__ ("d0");
|
||||
register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
|
||||
|
||||
retval = __NR_clone;
|
||||
__asm__ __volatile__
|
||||
("clrl %%d2\n\t"
|
||||
"trap #0\n\t" /* Linux/m68k system call */
|
||||
"tstl %0\n\t" /* child or parent */
|
||||
"jne 1f\n\t" /* parent - jump */
|
||||
"lea %%sp@(%c7),%6\n\t" /* reload current */
|
||||
"movel %6@,%6\n\t"
|
||||
"movel %3,%%sp@-\n\t" /* push argument */
|
||||
"jsr %4@\n\t" /* call fn */
|
||||
"movel %0,%%d1\n\t" /* pass exit value */
|
||||
"movel %2,%%d0\n\t" /* exit */
|
||||
"trap #0\n"
|
||||
"1:"
|
||||
: "+d" (retval)
|
||||
: "i" (__NR_clone), "i" (__NR_exit),
|
||||
"r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
|
||||
"i" (-THREAD_SIZE)
|
||||
: "d2");
|
||||
|
||||
pid = retval;
|
||||
}
|
||||
|
||||
set_fs (fs);
|
||||
return pid;
|
||||
}
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
unsigned long zero = 0;
|
||||
set_fs(USER_DS);
|
||||
current->thread.fs = __USER_DS;
|
||||
if (!FPU_IS_EMU)
|
||||
asm volatile (".chip 68k/68881\n\t"
|
||||
"frestore %0@\n\t"
|
||||
".chip 68k" : : "a" (&zero));
|
||||
}
|
||||
|
||||
/*
|
||||
* "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)
|
||||
{
|
||||
return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
int *parent_tidptr, *child_tidptr;
|
||||
|
||||
/* syscall2 puts clone_flags in d1 and usp in d2 */
|
||||
clone_flags = regs->d1;
|
||||
newsp = regs->d2;
|
||||
parent_tidptr = (int *)regs->d3;
|
||||
child_tidptr = (int *)regs->d4;
|
||||
if (!newsp)
|
||||
newsp = rdusp();
|
||||
return do_fork(clone_flags, newsp, regs, 0,
|
||||
parent_tidptr, child_tidptr);
|
||||
}
|
||||
|
||||
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
|
||||
unsigned long unused,
|
||||
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;
|
||||
|
||||
if (!FPU_IS_EMU) {
|
||||
/* Copy the current fpu state */
|
||||
asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
|
||||
|
||||
if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
|
||||
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]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fill in the fpu structure for a core dump. */
|
||||
|
||||
int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *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 (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
|
||||
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");
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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->thread_info);
|
||||
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;
|
||||
}
|
393
arch/m68k/kernel/ptrace.c
Normal file
393
arch/m68k/kernel/ptrace.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* linux/arch/m68k/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[] = {
|
||||
[0] = PT_REG(d1),
|
||||
[1] = PT_REG(d2),
|
||||
[2] = PT_REG(d3),
|
||||
[3] = PT_REG(d4),
|
||||
[4] = PT_REG(d5),
|
||||
[5] = SW_REG(d6),
|
||||
[6] = SW_REG(d7),
|
||||
[7] = PT_REG(a0),
|
||||
[8] = PT_REG(a1),
|
||||
[9] = PT_REG(a2),
|
||||
[10] = SW_REG(a3),
|
||||
[11] = SW_REG(a4),
|
||||
[12] = SW_REG(a5),
|
||||
[13] = SW_REG(a6),
|
||||
[14] = PT_REG(d0),
|
||||
[15] = -1,
|
||||
[16] = PT_REG(orig_d0),
|
||||
[17] = PT_REG(sr),
|
||||
[18] = 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);
|
||||
child->thread.work.delayed_trace = 0;
|
||||
child->thread.work.syscall_trace = 0;
|
||||
}
|
||||
|
||||
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
|
||||
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) {
|
||||
child->thread.work.syscall_trace = ~0;
|
||||
} else {
|
||||
child->thread.work.syscall_trace = 0;
|
||||
}
|
||||
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);
|
||||
child->thread.work.delayed_trace = 0;
|
||||
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);
|
||||
child->thread.work.delayed_trace = 0;
|
||||
wake_up_process(child);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SINGLESTEP: { /* set the trap flag. */
|
||||
long tmp;
|
||||
|
||||
ret = -EIO;
|
||||
if ((unsigned long) data > _NSIG)
|
||||
break;
|
||||
child->thread.work.syscall_trace = 0;
|
||||
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
|
||||
put_reg(child, PT_SR, tmp);
|
||||
child->thread.work.delayed_trace = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
}
|
||||
out_tsk:
|
||||
put_task_struct(child);
|
||||
out:
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage void syscall_trace(void)
|
||||
{
|
||||
if (!current->thread.work.delayed_trace &&
|
||||
!current->thread.work.syscall_trace)
|
||||
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;
|
||||
}
|
||||
}
|
133
arch/m68k/kernel/semaphore.c
Normal file
133
arch/m68k/kernel/semaphore.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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/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);
|
||||
}
|
545
arch/m68k/kernel/setup.c
Normal file
545
arch/m68k/kernel/setup.c
Normal file
@@ -0,0 +1,545 @@
|
||||
/*
|
||||
* linux/arch/m68k/kernel/setup.c
|
||||
*
|
||||
* Copyright (C) 1995 Hamish Macdonald
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file handles the architecture-dependent parts of system setup
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/initrd.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/machdep.h>
|
||||
#ifdef CONFIG_AMIGA
|
||||
#include <asm/amigahw.h>
|
||||
#endif
|
||||
#ifdef CONFIG_ATARI
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atari_stram.h>
|
||||
#endif
|
||||
#ifdef CONFIG_SUN3X
|
||||
#include <asm/dvma.h>
|
||||
#endif
|
||||
|
||||
unsigned long m68k_machtype;
|
||||
unsigned long m68k_cputype;
|
||||
unsigned long m68k_fputype;
|
||||
unsigned long m68k_mmutype;
|
||||
#ifdef CONFIG_VME
|
||||
unsigned long vme_brdtype;
|
||||
#endif
|
||||
|
||||
int m68k_is040or060;
|
||||
|
||||
extern int end;
|
||||
extern unsigned long availmem;
|
||||
|
||||
int m68k_num_memory;
|
||||
int m68k_realnum_memory;
|
||||
unsigned long m68k_memoffset;
|
||||
struct mem_info m68k_memory[NUM_MEMINFO];
|
||||
|
||||
static struct mem_info m68k_ramdisk;
|
||||
|
||||
static char m68k_command_line[CL_SIZE];
|
||||
|
||||
char m68k_debug_device[6] = "";
|
||||
|
||||
void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
|
||||
/* machine dependent irq functions */
|
||||
void (*mach_init_IRQ) (void) __initdata = NULL;
|
||||
irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
|
||||
void (*mach_get_model) (char *model);
|
||||
int (*mach_get_hardware_list) (char *buffer);
|
||||
int (*mach_get_irq_list) (struct seq_file *, void *);
|
||||
irqreturn_t (*mach_process_int) (int, struct pt_regs *);
|
||||
/* machine dependent timer functions */
|
||||
unsigned long (*mach_gettimeoffset) (void);
|
||||
int (*mach_hwclk) (int, struct rtc_time*);
|
||||
int (*mach_set_clock_mmss) (unsigned long);
|
||||
unsigned int (*mach_get_ss)(void);
|
||||
int (*mach_get_rtc_pll)(struct rtc_pll_info *);
|
||||
int (*mach_set_rtc_pll)(struct rtc_pll_info *);
|
||||
void (*mach_reset)( void );
|
||||
void (*mach_halt)( void );
|
||||
void (*mach_power_off)( void );
|
||||
long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
|
||||
#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
|
||||
void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
void (*mach_heartbeat) (int);
|
||||
EXPORT_SYMBOL(mach_heartbeat);
|
||||
#endif
|
||||
#ifdef CONFIG_M68K_L2_CACHE
|
||||
void (*mach_l2_flush) (int);
|
||||
#endif
|
||||
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
|
||||
void (*mach_beep)(unsigned int, unsigned int);
|
||||
#endif
|
||||
#if defined(CONFIG_ISA) && defined(MULTI_ISA)
|
||||
int isa_type;
|
||||
int isa_sex;
|
||||
#endif
|
||||
|
||||
extern int amiga_parse_bootinfo(const struct bi_record *);
|
||||
extern int atari_parse_bootinfo(const struct bi_record *);
|
||||
extern int mac_parse_bootinfo(const struct bi_record *);
|
||||
extern int q40_parse_bootinfo(const struct bi_record *);
|
||||
extern int bvme6000_parse_bootinfo(const struct bi_record *);
|
||||
extern int mvme16x_parse_bootinfo(const struct bi_record *);
|
||||
extern int mvme147_parse_bootinfo(const struct bi_record *);
|
||||
extern int hp300_parse_bootinfo(const struct bi_record *);
|
||||
|
||||
extern void config_amiga(void);
|
||||
extern void config_atari(void);
|
||||
extern void config_mac(void);
|
||||
extern void config_sun3(void);
|
||||
extern void config_apollo(void);
|
||||
extern void config_mvme147(void);
|
||||
extern void config_mvme16x(void);
|
||||
extern void config_bvme6000(void);
|
||||
extern void config_hp300(void);
|
||||
extern void config_q40(void);
|
||||
extern void config_sun3x(void);
|
||||
|
||||
extern void mac_debugging_short (int, short);
|
||||
extern void mac_debugging_long (int, long);
|
||||
|
||||
#define MASK_256K 0xfffc0000
|
||||
|
||||
extern void paging_init(void);
|
||||
|
||||
static void __init m68k_parse_bootinfo(const struct bi_record *record)
|
||||
{
|
||||
while (record->tag != BI_LAST) {
|
||||
int unknown = 0;
|
||||
const unsigned long *data = record->data;
|
||||
switch (record->tag) {
|
||||
case BI_MACHTYPE:
|
||||
case BI_CPUTYPE:
|
||||
case BI_FPUTYPE:
|
||||
case BI_MMUTYPE:
|
||||
/* Already set up by head.S */
|
||||
break;
|
||||
|
||||
case BI_MEMCHUNK:
|
||||
if (m68k_num_memory < NUM_MEMINFO) {
|
||||
m68k_memory[m68k_num_memory].addr = data[0];
|
||||
m68k_memory[m68k_num_memory].size = data[1];
|
||||
m68k_num_memory++;
|
||||
} else
|
||||
printk("m68k_parse_bootinfo: too many memory chunks\n");
|
||||
break;
|
||||
|
||||
case BI_RAMDISK:
|
||||
m68k_ramdisk.addr = data[0];
|
||||
m68k_ramdisk.size = data[1];
|
||||
break;
|
||||
|
||||
case BI_COMMAND_LINE:
|
||||
strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (MACH_IS_AMIGA)
|
||||
unknown = amiga_parse_bootinfo(record);
|
||||
else if (MACH_IS_ATARI)
|
||||
unknown = atari_parse_bootinfo(record);
|
||||
else if (MACH_IS_MAC)
|
||||
unknown = mac_parse_bootinfo(record);
|
||||
else if (MACH_IS_Q40)
|
||||
unknown = q40_parse_bootinfo(record);
|
||||
else if (MACH_IS_BVME6000)
|
||||
unknown = bvme6000_parse_bootinfo(record);
|
||||
else if (MACH_IS_MVME16x)
|
||||
unknown = mvme16x_parse_bootinfo(record);
|
||||
else if (MACH_IS_MVME147)
|
||||
unknown = mvme147_parse_bootinfo(record);
|
||||
else if (MACH_IS_HP300)
|
||||
unknown = hp300_parse_bootinfo(record);
|
||||
else
|
||||
unknown = 1;
|
||||
}
|
||||
if (unknown)
|
||||
printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
|
||||
record->tag);
|
||||
record = (struct bi_record *)((unsigned long)record+record->size);
|
||||
}
|
||||
|
||||
m68k_realnum_memory = m68k_num_memory;
|
||||
#ifdef CONFIG_SINGLE_MEMORY_CHUNK
|
||||
if (m68k_num_memory > 1) {
|
||||
printk("Ignoring last %i chunks of physical memory\n",
|
||||
(m68k_num_memory - 1));
|
||||
m68k_num_memory = 1;
|
||||
}
|
||||
m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
extern int _etext, _edata, _end;
|
||||
#ifndef CONFIG_SUN3
|
||||
unsigned long endmem, startmem;
|
||||
#endif
|
||||
int i;
|
||||
char *p, *q;
|
||||
|
||||
/* The bootinfo is located right after the kernel bss */
|
||||
m68k_parse_bootinfo((const struct bi_record *)&_end);
|
||||
|
||||
if (CPU_IS_040)
|
||||
m68k_is040or060 = 4;
|
||||
else if (CPU_IS_060)
|
||||
m68k_is040or060 = 6;
|
||||
|
||||
/* FIXME: m68k_fputype is passed in by Penguin booter, which can
|
||||
* be confused by software FPU emulation. BEWARE.
|
||||
* We should really do our own FPU check at startup.
|
||||
* [what do we do with buggy 68LC040s? if we have problems
|
||||
* with them, we should add a test to check_bugs() below] */
|
||||
#ifndef CONFIG_M68KFPU_EMU_ONLY
|
||||
/* clear the fpu if we have one */
|
||||
if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
|
||||
volatile int zero = 0;
|
||||
asm __volatile__ ("frestore %0" : : "m" (zero));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (CPU_IS_060) {
|
||||
u32 pcr;
|
||||
|
||||
asm (".chip 68060; movec %%pcr,%0; .chip 68k"
|
||||
: "=d" (pcr));
|
||||
if (((pcr >> 8) & 0xff) <= 5) {
|
||||
printk("Enabling workaround for errata I14\n");
|
||||
asm (".chip 68060; movec %0,%%pcr; .chip 68k"
|
||||
: : "d" (pcr | 0x20));
|
||||
}
|
||||
}
|
||||
|
||||
init_mm.start_code = PAGE_OFFSET;
|
||||
init_mm.end_code = (unsigned long) &_etext;
|
||||
init_mm.end_data = (unsigned long) &_edata;
|
||||
init_mm.brk = (unsigned long) &_end;
|
||||
|
||||
*cmdline_p = m68k_command_line;
|
||||
memcpy(saved_command_line, *cmdline_p, CL_SIZE);
|
||||
|
||||
/* Parse the command line for arch-specific options.
|
||||
* For the m68k, this is currently only "debug=xxx" to enable printing
|
||||
* certain kernel messages to some machine-specific device.
|
||||
*/
|
||||
for( p = *cmdline_p; p && *p; ) {
|
||||
i = 0;
|
||||
if (!strncmp( p, "debug=", 6 )) {
|
||||
strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) );
|
||||
if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
|
||||
i = 1;
|
||||
}
|
||||
#ifdef CONFIG_ATARI
|
||||
/* This option must be parsed very early */
|
||||
if (!strncmp( p, "switches=", 9 )) {
|
||||
extern void atari_switches_setup( const char *, int );
|
||||
atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
|
||||
(q - (p+9)) : strlen(p+9) );
|
||||
i = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i) {
|
||||
/* option processed, delete it */
|
||||
if ((q = strchr( p, ' ' )))
|
||||
strcpy( p, q+1 );
|
||||
else
|
||||
*p = 0;
|
||||
} else {
|
||||
if ((p = strchr( p, ' ' ))) ++p;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m68k_machtype) {
|
||||
#ifdef CONFIG_AMIGA
|
||||
case MACH_AMIGA:
|
||||
config_amiga();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_ATARI
|
||||
case MACH_ATARI:
|
||||
config_atari();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_MAC
|
||||
case MACH_MAC:
|
||||
config_mac();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SUN3
|
||||
case MACH_SUN3:
|
||||
config_sun3();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_APOLLO
|
||||
case MACH_APOLLO:
|
||||
config_apollo();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_MVME147
|
||||
case MACH_MVME147:
|
||||
config_mvme147();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_MVME16x
|
||||
case MACH_MVME16x:
|
||||
config_mvme16x();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_BVME6000
|
||||
case MACH_BVME6000:
|
||||
config_bvme6000();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_HP300
|
||||
case MACH_HP300:
|
||||
config_hp300();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_Q40
|
||||
case MACH_Q40:
|
||||
config_q40();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SUN3X
|
||||
case MACH_SUN3X:
|
||||
config_sun3x();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
panic ("No configuration setup");
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SUN3
|
||||
startmem= m68k_memory[0].addr;
|
||||
endmem = startmem + m68k_memory[0].size;
|
||||
high_memory = (void *)PAGE_OFFSET;
|
||||
for (i = 0; i < m68k_num_memory; i++) {
|
||||
m68k_memory[i].size &= MASK_256K;
|
||||
if (m68k_memory[i].addr < startmem)
|
||||
startmem = m68k_memory[i].addr;
|
||||
if (m68k_memory[i].addr+m68k_memory[i].size > endmem)
|
||||
endmem = m68k_memory[i].addr+m68k_memory[i].size;
|
||||
high_memory += m68k_memory[i].size;
|
||||
}
|
||||
|
||||
availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT,
|
||||
startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT);
|
||||
|
||||
for (i = 0; i < m68k_num_memory; i++)
|
||||
free_bootmem(m68k_memory[i].addr, m68k_memory[i].size);
|
||||
|
||||
reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr);
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
if (m68k_ramdisk.size) {
|
||||
reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size);
|
||||
initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
|
||||
initrd_end = initrd_start + m68k_ramdisk.size;
|
||||
printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATARI
|
||||
if (MACH_IS_ATARI)
|
||||
atari_stram_reserve_pages((void *)availmem);
|
||||
#endif
|
||||
#ifdef CONFIG_SUN3X
|
||||
if (MACH_IS_SUN3X) {
|
||||
dvma_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !CONFIG_SUN3 */
|
||||
|
||||
paging_init();
|
||||
|
||||
/* set ISA defs early as possible */
|
||||
#if defined(CONFIG_ISA) && defined(MULTI_ISA)
|
||||
#if defined(CONFIG_Q40)
|
||||
if (MACH_IS_Q40) {
|
||||
isa_type = Q40_ISA;
|
||||
isa_sex = 0;
|
||||
}
|
||||
#elif defined(CONFIG_GG2)
|
||||
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){
|
||||
isa_type = GG2_ISA;
|
||||
isa_sex = 0;
|
||||
}
|
||||
#elif defined(CONFIG_AMIGA_PCMCIA)
|
||||
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){
|
||||
isa_type = AG_ISA;
|
||||
isa_sex = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
{
|
||||
const char *cpu, *mmu, *fpu;
|
||||
unsigned long clockfreq, clockfactor;
|
||||
|
||||
#define LOOP_CYCLES_68020 (8)
|
||||
#define LOOP_CYCLES_68030 (8)
|
||||
#define LOOP_CYCLES_68040 (3)
|
||||
#define LOOP_CYCLES_68060 (1)
|
||||
|
||||
if (CPU_IS_020) {
|
||||
cpu = "68020";
|
||||
clockfactor = LOOP_CYCLES_68020;
|
||||
} else if (CPU_IS_030) {
|
||||
cpu = "68030";
|
||||
clockfactor = LOOP_CYCLES_68030;
|
||||
} else if (CPU_IS_040) {
|
||||
cpu = "68040";
|
||||
clockfactor = LOOP_CYCLES_68040;
|
||||
} else if (CPU_IS_060) {
|
||||
cpu = "68060";
|
||||
clockfactor = LOOP_CYCLES_68060;
|
||||
} else {
|
||||
cpu = "680x0";
|
||||
clockfactor = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_M68KFPU_EMU_ONLY
|
||||
fpu="none(soft float)";
|
||||
#else
|
||||
if (m68k_fputype & FPU_68881)
|
||||
fpu = "68881";
|
||||
else if (m68k_fputype & FPU_68882)
|
||||
fpu = "68882";
|
||||
else if (m68k_fputype & FPU_68040)
|
||||
fpu = "68040";
|
||||
else if (m68k_fputype & FPU_68060)
|
||||
fpu = "68060";
|
||||
else if (m68k_fputype & FPU_SUNFPA)
|
||||
fpu = "Sun FPA";
|
||||
else
|
||||
fpu = "none";
|
||||
#endif
|
||||
|
||||
if (m68k_mmutype & MMU_68851)
|
||||
mmu = "68851";
|
||||
else if (m68k_mmutype & MMU_68030)
|
||||
mmu = "68030";
|
||||
else if (m68k_mmutype & MMU_68040)
|
||||
mmu = "68040";
|
||||
else if (m68k_mmutype & MMU_68060)
|
||||
mmu = "68060";
|
||||
else if (m68k_mmutype & MMU_SUN3)
|
||||
mmu = "Sun-3";
|
||||
else if (m68k_mmutype & MMU_APOLLO)
|
||||
mmu = "Apollo";
|
||||
else
|
||||
mmu = "unknown";
|
||||
|
||||
clockfreq = loops_per_jiffy*HZ*clockfactor;
|
||||
|
||||
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/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
|
||||
loops_per_jiffy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *c_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return *pos < 1 ? (void *)1 : NULL;
|
||||
}
|
||||
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
return NULL;
|
||||
}
|
||||
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,
|
||||
};
|
||||
|
||||
int get_hardware_list(char *buffer)
|
||||
{
|
||||
int len = 0;
|
||||
char model[80];
|
||||
unsigned long mem;
|
||||
int i;
|
||||
|
||||
if (mach_get_model)
|
||||
mach_get_model(model);
|
||||
else
|
||||
strcpy(model, "Unknown m68k");
|
||||
|
||||
len += sprintf(buffer+len, "Model:\t\t%s\n", model);
|
||||
for (mem = 0, i = 0; i < m68k_num_memory; i++)
|
||||
mem += m68k_memory[i].size;
|
||||
len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
|
||||
|
||||
if (mach_get_hardware_list)
|
||||
len += mach_get_hardware_list(buffer+len);
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
|
||||
void __init floppy_setup(char *str, int *ints)
|
||||
{
|
||||
if (mach_floppy_setup)
|
||||
mach_floppy_setup (str, ints);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void check_bugs(void)
|
||||
{
|
||||
#ifndef CONFIG_M68KFPU_EMU
|
||||
if (m68k_fputype == 0) {
|
||||
printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
|
||||
"WHICH IS REQUIRED BY LINUX/M68K ***\n" );
|
||||
printk( KERN_EMERG "Upgrade your hardware or join the FPU "
|
||||
"emulation project\n" );
|
||||
panic( "no FPU" );
|
||||
}
|
||||
#endif /* !CONFIG_M68KFPU_EMU */
|
||||
}
|
1025
arch/m68k/kernel/signal.c
Normal file
1025
arch/m68k/kernel/signal.c
Normal file
File diff suppressed because it is too large
Load Diff
104
arch/m68k/kernel/sun3-head.S
Normal file
104
arch/m68k/kernel/sun3-head.S
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/entry.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/contregs.h>
|
||||
#include <asm/sun3-head.h>
|
||||
|
||||
PSL_HIGHIPL = 0x2700
|
||||
NBSG = 0x20000
|
||||
ICACHE_ONLY = 0x00000009
|
||||
CACHES_OFF = 0x00000008 | actually a clear and disable --m
|
||||
#define MAS_STACK INT_STACK
|
||||
ROOT_TABLE_SIZE = 128
|
||||
PAGESIZE = 8192
|
||||
SUN3_INVALID_PMEG = 255
|
||||
.globl bootup_user_stack
|
||||
.globl bootup_kernel_stack
|
||||
.globl pg0
|
||||
.globl swapper_pg_dir
|
||||
.globl kernel_pmd_table
|
||||
.globl availmem
|
||||
.global m68k_pgtable_cachemode
|
||||
.global kpt
|
||||
| todo: all these should be in bss!
|
||||
swapper_pg_dir: .skip 0x2000
|
||||
pg0: .skip 0x2000
|
||||
kernel_pmd_table: .skip 0x2000
|
||||
|
||||
.globl kernel_pg_dir
|
||||
.equ kernel_pg_dir,kernel_pmd_table
|
||||
|
||||
.section .head
|
||||
ENTRY(_stext)
|
||||
ENTRY(_start)
|
||||
|
||||
/* Firstly, disable interrupts and set up function codes. */
|
||||
movew #PSL_HIGHIPL, %sr
|
||||
moveq #FC_CONTROL, %d0
|
||||
movec %d0, %sfc
|
||||
movec %d0, %dfc
|
||||
|
||||
/* Make sure we're in context zero. */
|
||||
moveq #0, %d0
|
||||
movsb %d0, AC_CONTEXT
|
||||
|
||||
/* map everything the bootloader left us into high memory, clean up the
|
||||
excess later */
|
||||
lea (AC_SEGMAP+0),%a0
|
||||
lea (AC_SEGMAP+KERNBASE),%a1
|
||||
1:
|
||||
movsb %a0@, %d1
|
||||
movsb %d1, %a1@
|
||||
cmpib #SUN3_INVALID_PMEG, %d1
|
||||
beq 2f
|
||||
addl #NBSG,%a0
|
||||
addl #NBSG,%a1
|
||||
jmp 1b
|
||||
|
||||
2:
|
||||
|
||||
/* Disable caches and jump to high code. */
|
||||
moveq #ICACHE_ONLY,%d0 | Cache disabled until we're ready to enable it
|
||||
movc %d0, %cacr | is this the right value? (yes --m)
|
||||
jmp 1f:l
|
||||
|
||||
/* Following code executes at high addresses (0xE000xxx). */
|
||||
1: lea init_task,%curptr | get initial thread...
|
||||
lea init_thread_union+THREAD_SIZE,%sp | ...and its stack.
|
||||
|
||||
/* copy bootinfo records from the loader to _end */
|
||||
lea _end, %a1
|
||||
lea BI_START, %a0
|
||||
/* number of longs to copy */
|
||||
movel %a0@, %d0
|
||||
1: addl #4, %a0
|
||||
movel %a0@, %a1@
|
||||
addl #4, %a1
|
||||
dbf %d0, 1b
|
||||
|
||||
/* Point MSP at an invalid page to trap if it's used. --m */
|
||||
movl #(PAGESIZE),%d0
|
||||
movc %d0,%msp
|
||||
moveq #-1,%d0
|
||||
movsb %d0,(AC_SEGMAP+0x0)
|
||||
|
||||
jbsr sun3_init
|
||||
|
||||
jbsr base_trap_init
|
||||
|
||||
jbsr start_kernel
|
||||
trap #15
|
||||
|
||||
.data
|
||||
.even
|
||||
kpt:
|
||||
.long 0
|
||||
availmem:
|
||||
.long 0
|
||||
| todo: remove next two. --m
|
||||
is_medusa:
|
||||
.long 0
|
||||
m68k_pgtable_cachemode:
|
||||
.long 0
|
||||
|
671
arch/m68k/kernel/sys_m68k.c
Normal file
671
arch/m68k/kernel/sys_m68k.c
Normal file
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
* linux/arch/m68k/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/page.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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct mmap_arg_struct64 {
|
||||
__u32 addr;
|
||||
__u32 len;
|
||||
__u32 prot;
|
||||
__u32 flags;
|
||||
__u64 offset; /* 64 bits */
|
||||
__u32 fd;
|
||||
};
|
||||
|
||||
asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg)
|
||||
{
|
||||
int error = -EFAULT;
|
||||
struct file * file = NULL;
|
||||
struct mmap_arg_struct64 a;
|
||||
unsigned long pgoff;
|
||||
|
||||
if (copy_from_user(&a, arg, sizeof(a)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((long)a.offset & ~PAGE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
pgoff = a.offset >> PAGE_SHIFT;
|
||||
if ((a.offset >> PAGE_SHIFT) != pgoff)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(a.flags & MAP_ANONYMOUS)) {
|
||||
error = -EBADF;
|
||||
file = fget(a.fd);
|
||||
if (!file)
|
||||
goto out;
|
||||
}
|
||||
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
|
||||
|
||||
down_write(¤t->mm->mmap_sem);
|
||||
error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
if (file)
|
||||
fput(file);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
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, ret;
|
||||
|
||||
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 -ENOSYS;
|
||||
}
|
||||
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 -ENOSYS;
|
||||
}
|
||||
if (call <= SHMCTL)
|
||||
switch (call) {
|
||||
case SHMAT:
|
||||
switch (version) {
|
||||
default: {
|
||||
ulong raddr;
|
||||
ret = do_shmat (first, (char *) ptr,
|
||||
second, &raddr);
|
||||
if (ret)
|
||||
return ret;
|
||||
return put_user (raddr, (ulong *) third);
|
||||
}
|
||||
}
|
||||
case SHMDT:
|
||||
return sys_shmdt ((char *)ptr);
|
||||
case SHMGET:
|
||||
return sys_shmget (first, second, third);
|
||||
case SHMCTL:
|
||||
return sys_shmctl (first, second,
|
||||
(struct shmid_ds *) ptr);
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Convert virtual (user) address VADDR to physical address PADDR */
|
||||
#define virt_to_phys_040(vaddr) \
|
||||
({ \
|
||||
unsigned long _mmusr, _paddr; \
|
||||
\
|
||||
__asm__ __volatile__ (".chip 68040\n\t" \
|
||||
"ptestr (%1)\n\t" \
|
||||
"movec %%mmusr,%0\n\t" \
|
||||
".chip 68k" \
|
||||
: "=r" (_mmusr) \
|
||||
: "a" (vaddr)); \
|
||||
_paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \
|
||||
_paddr; \
|
||||
})
|
||||
|
||||
static inline int
|
||||
cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
|
||||
{
|
||||
unsigned long paddr, i;
|
||||
|
||||
switch (scope)
|
||||
{
|
||||
case FLUSH_SCOPE_ALL:
|
||||
switch (cache)
|
||||
{
|
||||
case FLUSH_CACHE_DATA:
|
||||
/* This nop is needed for some broken versions of the 68040. */
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpusha %dc\n\t"
|
||||
".chip 68k");
|
||||
break;
|
||||
case FLUSH_CACHE_INSN:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpusha %ic\n\t"
|
||||
".chip 68k");
|
||||
break;
|
||||
default:
|
||||
case FLUSH_CACHE_BOTH:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpusha %bc\n\t"
|
||||
".chip 68k");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FLUSH_SCOPE_LINE:
|
||||
/* Find the physical address of the first mapped page in the
|
||||
address range. */
|
||||
if ((paddr = virt_to_phys_040(addr))) {
|
||||
paddr += addr & ~(PAGE_MASK | 15);
|
||||
len = (len + (addr & 15) + 15) >> 4;
|
||||
} else {
|
||||
unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
|
||||
|
||||
if (len <= tmp)
|
||||
return 0;
|
||||
addr += tmp;
|
||||
len -= tmp;
|
||||
tmp = PAGE_SIZE;
|
||||
for (;;)
|
||||
{
|
||||
if ((paddr = virt_to_phys_040(addr)))
|
||||
break;
|
||||
if (len <= tmp)
|
||||
return 0;
|
||||
addr += tmp;
|
||||
len -= tmp;
|
||||
}
|
||||
len = (len + 15) >> 4;
|
||||
}
|
||||
i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
|
||||
while (len--)
|
||||
{
|
||||
switch (cache)
|
||||
{
|
||||
case FLUSH_CACHE_DATA:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpushl %%dc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
case FLUSH_CACHE_INSN:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpushl %%ic,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
default:
|
||||
case FLUSH_CACHE_BOTH:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpushl %%bc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
}
|
||||
if (!--i && len)
|
||||
{
|
||||
/*
|
||||
* No need to page align here since it is done by
|
||||
* virt_to_phys_040().
|
||||
*/
|
||||
addr += PAGE_SIZE;
|
||||
i = PAGE_SIZE / 16;
|
||||
/* Recompute physical address when crossing a page
|
||||
boundary. */
|
||||
for (;;)
|
||||
{
|
||||
if ((paddr = virt_to_phys_040(addr)))
|
||||
break;
|
||||
if (len <= i)
|
||||
return 0;
|
||||
len -= i;
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
paddr += 16;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case FLUSH_SCOPE_PAGE:
|
||||
len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
|
||||
for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
|
||||
{
|
||||
if (!(paddr = virt_to_phys_040(addr)))
|
||||
continue;
|
||||
switch (cache)
|
||||
{
|
||||
case FLUSH_CACHE_DATA:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpushp %%dc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
case FLUSH_CACHE_INSN:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpushp %%ic,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
default:
|
||||
case FLUSH_CACHE_BOTH:
|
||||
__asm__ __volatile__ ("nop\n\t"
|
||||
".chip 68040\n\t"
|
||||
"cpushp %%bc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define virt_to_phys_060(vaddr) \
|
||||
({ \
|
||||
unsigned long paddr; \
|
||||
__asm__ __volatile__ (".chip 68060\n\t" \
|
||||
"plpar (%0)\n\t" \
|
||||
".chip 68k" \
|
||||
: "=a" (paddr) \
|
||||
: "0" (vaddr)); \
|
||||
(paddr); /* XXX */ \
|
||||
})
|
||||
|
||||
static inline int
|
||||
cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
|
||||
{
|
||||
unsigned long paddr, i;
|
||||
|
||||
/*
|
||||
* 68060 manual says:
|
||||
* cpush %dc : flush DC, remains valid (with our %cacr setup)
|
||||
* cpush %ic : invalidate IC
|
||||
* cpush %bc : flush DC + invalidate IC
|
||||
*/
|
||||
switch (scope)
|
||||
{
|
||||
case FLUSH_SCOPE_ALL:
|
||||
switch (cache)
|
||||
{
|
||||
case FLUSH_CACHE_DATA:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpusha %dc\n\t"
|
||||
".chip 68k");
|
||||
break;
|
||||
case FLUSH_CACHE_INSN:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpusha %ic\n\t"
|
||||
".chip 68k");
|
||||
break;
|
||||
default:
|
||||
case FLUSH_CACHE_BOTH:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpusha %bc\n\t"
|
||||
".chip 68k");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FLUSH_SCOPE_LINE:
|
||||
/* Find the physical address of the first mapped page in the
|
||||
address range. */
|
||||
len += addr & 15;
|
||||
addr &= -16;
|
||||
if (!(paddr = virt_to_phys_060(addr))) {
|
||||
unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
|
||||
|
||||
if (len <= tmp)
|
||||
return 0;
|
||||
addr += tmp;
|
||||
len -= tmp;
|
||||
tmp = PAGE_SIZE;
|
||||
for (;;)
|
||||
{
|
||||
if ((paddr = virt_to_phys_060(addr)))
|
||||
break;
|
||||
if (len <= tmp)
|
||||
return 0;
|
||||
addr += tmp;
|
||||
len -= tmp;
|
||||
}
|
||||
}
|
||||
len = (len + 15) >> 4;
|
||||
i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
|
||||
while (len--)
|
||||
{
|
||||
switch (cache)
|
||||
{
|
||||
case FLUSH_CACHE_DATA:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpushl %%dc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
case FLUSH_CACHE_INSN:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpushl %%ic,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
default:
|
||||
case FLUSH_CACHE_BOTH:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpushl %%bc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
}
|
||||
if (!--i && len)
|
||||
{
|
||||
|
||||
/*
|
||||
* We just want to jump to the first cache line
|
||||
* in the next page.
|
||||
*/
|
||||
addr += PAGE_SIZE;
|
||||
addr &= PAGE_MASK;
|
||||
|
||||
i = PAGE_SIZE / 16;
|
||||
/* Recompute physical address when crossing a page
|
||||
boundary. */
|
||||
for (;;)
|
||||
{
|
||||
if ((paddr = virt_to_phys_060(addr)))
|
||||
break;
|
||||
if (len <= i)
|
||||
return 0;
|
||||
len -= i;
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
paddr += 16;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case FLUSH_SCOPE_PAGE:
|
||||
len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
|
||||
addr &= PAGE_MASK; /* Workaround for bug in some
|
||||
revisions of the 68060 */
|
||||
for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
|
||||
{
|
||||
if (!(paddr = virt_to_phys_060(addr)))
|
||||
continue;
|
||||
switch (cache)
|
||||
{
|
||||
case FLUSH_CACHE_DATA:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpushp %%dc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
case FLUSH_CACHE_INSN:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpushp %%ic,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
default:
|
||||
case FLUSH_CACHE_BOTH:
|
||||
__asm__ __volatile__ (".chip 68060\n\t"
|
||||
"cpushp %%bc,(%0)\n\t"
|
||||
".chip 68k"
|
||||
: : "a" (paddr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sys_cacheflush -- flush (part of) the processor cache. */
|
||||
asmlinkage int
|
||||
sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
|
||||
{
|
||||
struct vm_area_struct *vma;
|
||||
int ret = -EINVAL;
|
||||
|
||||
lock_kernel();
|
||||
if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
|
||||
cache & ~FLUSH_CACHE_BOTH)
|
||||
goto out;
|
||||
|
||||
if (scope == FLUSH_SCOPE_ALL) {
|
||||
/* Only the superuser may explicitly flush the whole cache. */
|
||||
ret = -EPERM;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
goto out;
|
||||
} else {
|
||||
/*
|
||||
* Verify that the specified address region actually belongs
|
||||
* to this process.
|
||||
*/
|
||||
vma = find_vma (current->mm, addr);
|
||||
ret = -EINVAL;
|
||||
/* Check for overflow. */
|
||||
if (addr + len < addr)
|
||||
goto out;
|
||||
if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (CPU_IS_020_OR_030) {
|
||||
if (scope == FLUSH_SCOPE_LINE && len < 256) {
|
||||
unsigned long cacr;
|
||||
__asm__ ("movec %%cacr, %0" : "=r" (cacr));
|
||||
if (cache & FLUSH_CACHE_INSN)
|
||||
cacr |= 4;
|
||||
if (cache & FLUSH_CACHE_DATA)
|
||||
cacr |= 0x400;
|
||||
len >>= 2;
|
||||
while (len--) {
|
||||
__asm__ __volatile__ ("movec %1, %%caar\n\t"
|
||||
"movec %0, %%cacr"
|
||||
: /* no outputs */
|
||||
: "r" (cacr), "r" (addr));
|
||||
addr += 4;
|
||||
}
|
||||
} else {
|
||||
/* Flush the whole cache, even if page granularity requested. */
|
||||
unsigned long cacr;
|
||||
__asm__ ("movec %%cacr, %0" : "=r" (cacr));
|
||||
if (cache & FLUSH_CACHE_INSN)
|
||||
cacr |= 8;
|
||||
if (cache & FLUSH_CACHE_DATA)
|
||||
cacr |= 0x800;
|
||||
__asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
|
||||
}
|
||||
ret = 0;
|
||||
goto out;
|
||||
} else {
|
||||
/*
|
||||
* 040 or 060: don't blindly trust 'scope', someone could
|
||||
* try to flush a few megs of memory.
|
||||
*/
|
||||
|
||||
if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
|
||||
scope=FLUSH_SCOPE_PAGE;
|
||||
if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
|
||||
scope=FLUSH_SCOPE_ALL;
|
||||
if (CPU_IS_040) {
|
||||
ret = cache_flush_040 (addr, scope, cache, len);
|
||||
} else if (CPU_IS_060) {
|
||||
ret = cache_flush_060 (addr, scope, cache, len);
|
||||
}
|
||||
}
|
||||
out:
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage int sys_getpagesize(void)
|
||||
{
|
||||
return PAGE_SIZE;
|
||||
}
|
187
arch/m68k/kernel/time.c
Normal file
187
arch/m68k/kernel/time.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* linux/arch/m68k/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> /* CONFIG_HEARTBEAT */
|
||||
#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/rtc.h>
|
||||
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/profile.h>
|
||||
|
||||
u64 jiffies_64 = INITIAL_JIFFIES;
|
||||
|
||||
EXPORT_SYMBOL(jiffies_64);
|
||||
|
||||
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)
|
||||
{
|
||||
do_timer(regs);
|
||||
#ifndef CONFIG_SMP
|
||||
update_process_times(user_mode(regs));
|
||||
#endif
|
||||
profile_tick(CPU_PROFILING, regs);
|
||||
|
||||
#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 */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void time_init(void)
|
||||
{
|
||||
struct rtc_time time;
|
||||
|
||||
if (mach_hwclk) {
|
||||
mach_hwclk(0, &time);
|
||||
|
||||
if ((time.tm_year += 1900) < 1970)
|
||||
time.tm_year += 100;
|
||||
xtime.tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
|
||||
time.tm_hour, time.tm_min, time.tm_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;
|
||||
extern unsigned long wall_jiffies;
|
||||
unsigned long seq;
|
||||
unsigned long usec, sec, lost;
|
||||
unsigned long max_ntp_tick = tick_usec - tickadj;
|
||||
|
||||
do {
|
||||
seq = read_seqbegin_irqsave(&xtime_lock, flags);
|
||||
|
||||
usec = mach_gettimeoffset();
|
||||
lost = jiffies - wall_jiffies;
|
||||
|
||||
/*
|
||||
* If time_adjust is negative then NTP is slowing the clock
|
||||
* so make sure not to go into next possible interval.
|
||||
* Better to lose some accuracy than have time go backwards..
|
||||
*/
|
||||
if (unlikely(time_adjust < 0)) {
|
||||
usec = min(usec, max_ntp_tick);
|
||||
|
||||
if (lost)
|
||||
usec += lost * max_ntp_tick;
|
||||
}
|
||||
else if (unlikely(lost))
|
||||
usec += lost * tick_usec;
|
||||
|
||||
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;
|
||||
extern unsigned long wall_jiffies;
|
||||
|
||||
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_nsec
|
||||
* 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!
|
||||
*/
|
||||
nsec -= 1000 * (mach_gettimeoffset() +
|
||||
(jiffies - wall_jiffies) * (1000000 / HZ));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(do_settimeofday);
|
||||
|
||||
/*
|
||||
* Scheduler clock - returns current time in ns units.
|
||||
*/
|
||||
unsigned long long sched_clock(void)
|
||||
{
|
||||
return (unsigned long long)jiffies*(1000000000/HZ);
|
||||
}
|
||||
|
1227
arch/m68k/kernel/traps.c
Normal file
1227
arch/m68k/kernel/traps.c
Normal file
File diff suppressed because it is too large
Load Diff
95
arch/m68k/kernel/vmlinux-std.lds
Normal file
95
arch/m68k/kernel/vmlinux-std.lds
Normal file
@@ -0,0 +1,95 @@
|
||||
/* ld script to make m68k Linux kernel */
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
|
||||
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
|
||||
OUTPUT_ARCH(m68k)
|
||||
ENTRY(_start)
|
||||
jiffies = jiffies_64 + 4;
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1000;
|
||||
_text = .; /* Text and read-only data */
|
||||
.text : {
|
||||
*(.text)
|
||||
SCHED_TEXT
|
||||
*(.fixup)
|
||||
*(.gnu.warning)
|
||||
} :text = 0x4e75
|
||||
|
||||
. = ALIGN(16); /* Exception table */
|
||||
__start___ex_table = .;
|
||||
__ex_table : { *(__ex_table) }
|
||||
__stop___ex_table = .;
|
||||
|
||||
RODATA
|
||||
|
||||
_etext = .; /* End of text section */
|
||||
|
||||
.data : { /* Data */
|
||||
*(.data)
|
||||
CONSTRUCTORS
|
||||
}
|
||||
|
||||
.bss : { *(.bss) } /* BSS */
|
||||
|
||||
. = ALIGN(16);
|
||||
.data.cacheline_aligned : { *(.data.cacheline_aligned) } :data
|
||||
|
||||
_edata = .; /* End of data section */
|
||||
|
||||
/* will be freed after init */
|
||||
. = ALIGN(4096); /* Init code and data */
|
||||
__init_begin = .;
|
||||
.init.text : {
|
||||
_sinittext = .;
|
||||
*(.init.text)
|
||||
_einittext = .;
|
||||
}
|
||||
.init.data : { *(.init.data) }
|
||||
. = ALIGN(16);
|
||||
__setup_start = .;
|
||||
.init.setup : { *(.init.setup) }
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
.initcall.init : {
|
||||
*(.initcall1.init)
|
||||
*(.initcall2.init)
|
||||
*(.initcall3.init)
|
||||
*(.initcall4.init)
|
||||
*(.initcall5.init)
|
||||
*(.initcall6.init)
|
||||
*(.initcall7.init)
|
||||
}
|
||||
__initcall_end = .;
|
||||
__con_initcall_start = .;
|
||||
.con_initcall.init : { *(.con_initcall.init) }
|
||||
__con_initcall_end = .;
|
||||
SECURITY_INIT
|
||||
. = ALIGN(8192);
|
||||
__initramfs_start = .;
|
||||
.init.ramfs : { *(.init.ramfs) }
|
||||
__initramfs_end = .;
|
||||
. = ALIGN(8192);
|
||||
__init_end = .;
|
||||
|
||||
.data.init_task : { *(.data.init_task) } /* The initial task and kernel stack */
|
||||
|
||||
_end = . ;
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.exit.text)
|
||||
*(.exit.data)
|
||||
*(.exitcall.exit)
|
||||
}
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
95
arch/m68k/kernel/vmlinux-sun3.lds
Normal file
95
arch/m68k/kernel/vmlinux-sun3.lds
Normal file
@@ -0,0 +1,95 @@
|
||||
/* ld script to make m68k Linux kernel */
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
|
||||
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
|
||||
OUTPUT_ARCH(m68k)
|
||||
ENTRY(_start)
|
||||
jiffies = jiffies_64 + 4;
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xE004000;
|
||||
_text = .; /* Text and read-only data */
|
||||
.text : {
|
||||
*(.head)
|
||||
*(.text)
|
||||
SCHED_TEXT
|
||||
*(.fixup)
|
||||
*(.gnu.warning)
|
||||
} :text = 0x4e75
|
||||
RODATA
|
||||
|
||||
_etext = .; /* End of text section */
|
||||
|
||||
.data : { /* Data */
|
||||
*(.data)
|
||||
CONSTRUCTORS
|
||||
. = ALIGN(16); /* Exception table */
|
||||
__start___ex_table = .;
|
||||
*(__ex_table)
|
||||
__stop___ex_table = .;
|
||||
} :data
|
||||
/* End of data goes *here* so that freeing init code works properly. */
|
||||
_edata = .;
|
||||
|
||||
/* will be freed after init */
|
||||
. = ALIGN(8192); /* Init code and data */
|
||||
__init_begin = .;
|
||||
.init.text : {
|
||||
_sinittext = .;
|
||||
*(.init.text)
|
||||
_einittext = .;
|
||||
}
|
||||
.init.data : { *(.init.data) }
|
||||
. = ALIGN(16);
|
||||
__setup_start = .;
|
||||
.init.setup : { *(.init.setup) }
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
.initcall.init : {
|
||||
*(.initcall1.init)
|
||||
*(.initcall2.init)
|
||||
*(.initcall3.init)
|
||||
*(.initcall4.init)
|
||||
*(.initcall5.init)
|
||||
*(.initcall6.init)
|
||||
*(.initcall7.init)
|
||||
}
|
||||
__initcall_end = .;
|
||||
__con_initcall_start = .;
|
||||
.con_initcall.init : { *(.con_initcall.init) }
|
||||
__con_initcall_end = .;
|
||||
SECURITY_INIT
|
||||
. = ALIGN(8192);
|
||||
__initramfs_start = .;
|
||||
.init.ramfs : { *(.init.ramfs) }
|
||||
__initramfs_end = .;
|
||||
. = ALIGN(8192);
|
||||
__init_end = .;
|
||||
.init.task : { *(init_task) }
|
||||
|
||||
|
||||
.bss : { *(.bss) } /* BSS */
|
||||
|
||||
_end = . ;
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.exit.text)
|
||||
*(.exit.data)
|
||||
*(.exitcall.exit)
|
||||
}
|
||||
|
||||
.crap : {
|
||||
/* Stabs debugging sections. */
|
||||
*(.stab)
|
||||
*(.stabstr)
|
||||
*(.stab.excl)
|
||||
*(.stab.exclstr)
|
||||
*(.stab.index)
|
||||
*(.stab.indexstr)
|
||||
*(.comment)
|
||||
*(.note)
|
||||
}
|
||||
|
||||
}
|
11
arch/m68k/kernel/vmlinux.lds.S
Normal file
11
arch/m68k/kernel/vmlinux.lds.S
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <linux/config.h>
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FILEHDR PHDRS FLAGS (7);
|
||||
data PT_LOAD FLAGS (7);
|
||||
}
|
||||
#ifdef CONFIG_SUN3
|
||||
#include "vmlinux-sun3.lds"
|
||||
#else
|
||||
#include "vmlinux-std.lds"
|
||||
#endif
|
Reference in New Issue
Block a user