summaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /arch/m68k/kernel
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r--arch/m68k/kernel/bios32.c50
-rw-r--r--arch/m68k/kernel/entry.S10
-rw-r--r--arch/m68k/kernel/head.S199
-rw-r--r--arch/m68k/kernel/ints.c3
-rw-r--r--arch/m68k/kernel/kgdb.c1194
-rw-r--r--arch/m68k/kernel/m68k_defs.h8
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c8
-rw-r--r--arch/m68k/kernel/process.c3
-rw-r--r--arch/m68k/kernel/ptrace.c7
-rw-r--r--arch/m68k/kernel/setup.c14
-rw-r--r--arch/m68k/kernel/signal.c400
-rw-r--r--arch/m68k/kernel/sys_m68k.c13
-rw-r--r--arch/m68k/kernel/time.c2
13 files changed, 1707 insertions, 204 deletions
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
index a1dc77f33..b1322261a 100644
--- a/arch/m68k/kernel/bios32.c
+++ b/arch/m68k/kernel/bios32.c
@@ -33,7 +33,6 @@
* been removed in this version.
*/
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/malloc.h>
#include <linux/mm.h>
@@ -49,7 +48,7 @@
#define GB (1024*MB)
#define MAJOR_REV 0
-#define MINOR_REV 0
+#define MINOR_REV 1
/*
* Base addresses of the PCI memory and I/O areas on the Hades.
@@ -264,12 +263,14 @@ __initfunc(static void disable_dev(struct pci_dev *dev))
#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
-__initfunc(static void layout_dev(struct pci_dev *dev))
+__initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_base,
+ unsigned long pci_io_base))
{
struct pci_bus *bus;
unsigned short cmd;
unsigned int base, mask, size, reg;
unsigned int alignto;
+ int i;
/*
* Skip video cards for the time being.
@@ -283,7 +284,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
bus = dev->bus;
pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
- for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4)
+ 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
@@ -297,6 +298,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
if (!base)
{
/* this base-address register is unused */
+ dev->base_address[i] = 0;
continue;
}
@@ -322,6 +324,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
io_base = base + size;
pcibios_write_config_dword(bus->number, dev->devfn,
reg, base | 0x1);
+ dev->base_address[i] = (pci_io_base + base) | 1;
DBG_DEVS(("layout_dev: IO address: %lX\n", base));
}
else
@@ -369,6 +372,7 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
mem_base = base + size;
pcibios_write_config_dword(bus->number, dev->devfn,
reg, base);
+ dev->base_address[i] = pci_mem_base + base;
}
}
@@ -396,7 +400,8 @@ __initfunc(static void layout_dev(struct pci_dev *dev))
bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
}
-__initfunc(static void layout_bus(struct pci_bus *bus))
+__initfunc(static void layout_bus(struct pci_bus *bus, unsigned long pci_mem_base,
+ unsigned long pci_io_base))
{
struct pci_dev *dev;
@@ -438,7 +443,7 @@ __initfunc(static void layout_bus(struct pci_bus *bus))
for (dev = bus->devices; dev; dev = dev->sibling)
{
if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
- layout_dev(dev);
+ layout_dev(dev, pci_mem_base, pci_io_base);
}
}
@@ -507,8 +512,7 @@ int pcibios_present(void)
return 0;
}
-__initfunc(unsigned long pcibios_init(unsigned long mem_start,
- unsigned long mem_end))
+__initfunc(void pcibios_init(void))
{
printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
@@ -516,7 +520,8 @@ __initfunc(unsigned long pcibios_init(unsigned long mem_start,
printk("...NOT modifying existing PCI configuration\n");
#endif
- return mem_start;
+ pci_mem_base = 0x80000000;
+ pci_io_base = 0xB0000000;
}
/*
@@ -555,26 +560,39 @@ __initfunc(static inline void hades_fixup(void))
}
}
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start,
- unsigned long mem_end))
+__initfunc(void pcibios_fixup(void))
{
#if PCI_MODIFY
+ unsigned long orig_mem_base, orig_io_base;
+
+ orig_mem_base = pci_mem_base;
+ orig_io_base = pci_io_base;
+ pci_mem_base = 0;
+ pci_io_base = 0;
+
/*
* Scan the tree, allocating PCI memory and I/O space.
*/
- layout_bus(&pci_root);
-#endif
+ layout_bus(&pci_root, orig_mem_base, orig_io_base);
- pci_mem_base = 0x80000000;
- pci_io_base = 0xB0000000;
+ pci_mem_base = orig_mem_base;
+ pci_io_base = orig_io_base;
+#endif
/*
* Now is the time to do all those dirty little deeds...
*/
hades_fixup();
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
- return mem_start;
+__initfunc(char *pcibios_setup(char *str))
+{
+ return str;
}
#endif /* CONFIG_PCI */
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 1c157c26a..eba9842cf 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -114,7 +114,7 @@ SYMBOL_NAME_LABEL(ret_from_exception)
| kernel stack, otherwise stack overflow can occur during
| heavy interupt load
andw #ALLOWINT,%sr
- tstl SYMBOL_NAME(need_resched)
+ tstl %curptr@(LTASK_NEEDRESCHED)
jne SYMBOL_NAME(reschedule)
cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
@@ -579,6 +579,14 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_pread) /* 180 */
.long SYMBOL_NAME(sys_pwrite)
.long SYMBOL_NAME(sys_lchown);
+ .long SYMBOL_NAME(sys_getcwd)
+ .long SYMBOL_NAME(sys_capget)
+ .long SYMBOL_NAME(sys_capset) /* 185 */
+ .long SYMBOL_NAME(sys_sigaltstack)
+ .long SYMBOL_NAME(sys_sendfile)
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+
.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 1f3795a7c..e98f39fa8 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -17,6 +17,7 @@
** 95/11/18 Richard Hirst: Added MVME166 support
** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
** Magnum- and FX-alternate ram
+** 98/04/25 Phil Blundell: added HP300 support
**
** 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
@@ -73,10 +74,25 @@
#include <asm/pgtable.h>
.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr)
+.globl SYMBOL_NAME(availmem)
.globl SYMBOL_NAME(m68k_pgtable_cachemode)
.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
+#if defined(CONFIG_MVME16x)
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+
+/*
+ * Added m68k_supervisor_cachemode for 68060 boards where some drivers
+ * need writethrough caching for supervisor accesses. Drivers known to
+ * be effected are 53c7xx.c and apricot.c (when used on VME boards).
+ * Richard Hirst.
+ */
+
+#ifdef CONFIG_060_WRITETHROUGH
+.globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#endif
+
D6B_0460 = 16 /* indicates 680[46]0 in d6 */
D6B_060 = 17 /* indicates 68060 in d6 */
D6F_040 = 1<<D6B_0460
@@ -146,12 +162,23 @@ TABLENR_16MB = 64 /* same for 16 MB */
#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
+#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
+#define is_not_hp300(lab) moveq &MACH_HP300,%d7 ; cmpl %d4,%d7; jne lab
#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
#define is_060(lab) btst &D6B_060,%d6; jne lab
#define is_not_060(lab) btst &D6B_060,%d6; jeq lab
+/* On the HP300 we use the on-board LEDs for debug output before
+ the console is running. Writing a 1 bit turns the corresponding LED
+ _off_ - on the 340 bit 7 is towards the back panel of the machine. */
+#ifdef CONFIG_HP300
+#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42:
+#else
+#define leds(x)
+#endif
+
.text
ENTRY(_stext)
/*
@@ -164,6 +191,7 @@ ENTRY(_stext)
.long MACH_AMIGA, AMIGA_BOOTI_VERSION
.long MACH_ATARI, ATARI_BOOTI_VERSION
.long MACH_MVME16x, MVME16x_BOOTI_VERSION
+ .long MACH_BVME6000, BVME6000_BOOTI_VERSION
.long 0
1: jra SYMBOL_NAME(_start)
@@ -224,6 +252,22 @@ ENTRY(_start)
movew %d6,%d0
movel %d0,%a0@ /* save cache mode for page tables */
+ /*
+ * If this is a 68060 board using drivers with cache coherency
+ * problems, then supervisor memory accesses need to be write-through
+ * also; otherwise, we want copyback.
+ */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+ is_not_060(Lset_norm)
+ jra 1f
+Lset_norm:
+ move.w #_PAGE_CACHE040,%d0
+1:
+ lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
+ movel %d0,%a0@
+#endif
+
/*
* raise interrupt level
*/
@@ -386,7 +430,12 @@ Lnotypetest:
movel %a3,%a0
movel %d5,%a1
- addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#if defined(CONFIG_060_WRITETHROUGH)
+ addw #_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+ addl m68k_supervisor_cachemode,%a1
+#else
+ addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#endif
movew #(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
movel #PAGESIZE,%d2
1: movel %a1,%a0@+
@@ -424,6 +473,9 @@ Lnotypetest:
* of %a2 are forgotten.
*/
Lnot040:
+
+ leds(0x4)
+
/*
* Do any machine specific page table initializations.
*/
@@ -615,6 +667,21 @@ Lspata68040:
Lnotatari:
#endif
+#ifdef CONFIG_HP300
+ is_not_hp300(Lnothp300)
+
+/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
+ by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early
+ termination page descriptor. The ROM mapping is needed because the LEDs
+ are mapped there too. */
+
+ movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
+ movel %d0,%a5@(0x78<<2)
+
+Lnothp300:
+
+#endif
+
#if defined(CONFIG_MVME16x)
is_not_mvme16x(Lnot16x)
@@ -639,6 +706,25 @@ Lnotatari:
Lnot16x:
#endif
+#if defined(CONFIG_BVME6000)
+ is_not_bvme6000(Lnotbvm)
+
+ /*
+ * On BVME6000 we have already created kernel page tables for
+ * 4MB of RAM at address 0, so now need to do a transparent
+ * mapping of the top of memory space. Make it 0.5GByte for now.
+ */
+
+ movel #0xe01f0000,%d2 /* logical address base */
+ orw #0xa040,%d2 /* add in magic bits */
+ .long 0x4e7b2005 /* movec d2,ittr1 */
+ .long 0x4e7b2007 /* movec d2,dttr1 */
+ .long 0x4e7b2004 /* movec d2,ittr0 */
+ .long 0x4e7b2006 /* movec d2,dttr0 */
+
+Lnotbvm:
+#endif
+
/*
* Setup a transparent mapping of the physical memory we are executing in.
*
@@ -647,6 +733,7 @@ Lnot16x:
*/
Lmapphys:
putc('J')
+ leds(0x8)
#ifdef CONFIG_AMIGA
is_not_amiga(Lmapphysnotamiga)
@@ -853,6 +940,80 @@ Lmapphysnot16x:
#endif
+#if defined(CONFIG_HP300)
+ is_not_hp300(Lmapphysnothp300)
+
+/*
+ * Physical RAM is at 0xff000000. We want to map the kernel at 0x00000000.
+ * In order to avoid disaster when we enable the MMU we need to make a
+ * transparent mapping of the RAM we're executing out of as well.
+ */
+ /*
+ * save physaddr of phys mem in register a3
+ */
+
+ .chip 68030
+ lea %pc@(Lmmu),%a3
+ movel %d5,%d0
+ andl #0xff000000,%d0 /* logical address base */
+ orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+ movel %d0,%a3@
+ pmove %a3@,%tt0
+ /* no limit, 4byte descriptors */
+ movel #0x80000002,%a3@
+ movel %a5,%a3@(4)
+ pmove %a3@,%srp
+ pmove %a3@,%crp
+ pflusha
+ /*
+ * enable,super root enable,4096 byte pages,7 bit root index,
+ * 7 bit pointer index, 6 bit page table index.
+ */
+ movel #0x82c07760,%a3@
+ pmove %a3@,%tc /* enable the MMU */
+ jmp 1f
+1:
+ .chip 68k
+
+ /*
+ * Fix up the custom register to point to the new location of the LEDs.
+ */
+ lea %pc@(Lcustom),%a1
+ movel #0xf0000000,%a1@
+
+ /*
+ * Energise the FPU and caches.
+ */
+ orl #0x64, 0xf05f400c
+
+Lmapphysnothp300:
+
+#endif
+
+#if defined(CONFIG_BVME6000)
+ is_not_bvme6000(Lmapphysnotbvm)
+ /*
+ * save physaddr of phys mem in register a3
+ */
+ moveq #'L',%d7
+ jbsr Lserial_putc
+
+ .word 0xf4d8 /* CINVA I/D */
+ .word 0xf518 /* pflusha */
+ .long 0x4e7bd807 /* movec a5,srp */
+ .long 0x4e7bd806 /* movec a5,urp */
+ movel #(TC_ENABLE+TC_PAGE4K),%d0
+ /*
+ * this value is also ok for the 68060, we don`t use the cache
+ * mode/protection defaults
+ */
+ .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
+ jra LdoneMMUenable /* branch to continuation of startup */
+
+Lmapphysnotbvm:
+
+#endif
+
LdoneMMUenable:
/*
@@ -861,6 +1022,7 @@ LdoneMMUenable:
*/
putc('M')
+ leds(0x10)
/*
* d5 contains physaddr of kernel start
@@ -917,6 +1079,7 @@ Lcache68060:
/* jump to the kernel start */
putr()
+ leds(0x55)
subl %a6,%a6 /* clear a6 for gdb */
jbsr SYMBOL_NAME(start_kernel)
@@ -998,6 +1161,11 @@ LMFP_UDR = 0xfffa2f
#endif
#endif
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A = 0xffb0000b
+BVME_SCC_DATA_A = 0xffb0000f
+#endif
+
/*
* Serial port output support.
*/
@@ -1062,6 +1230,17 @@ Lserial_init:
9:
rts
+#ifdef CONFIG_HP300
+/* Set LEDs to %d7 */
+ .even
+Lset_leds:
+ moveml %a0/%a1,%sp@-
+ movel %pc@(Lcustom),%a1
+ moveb %d7,%a1@(0x1ffff)
+ moveml %sp@+,%a0/%a1
+ rts
+#endif
+
/*
* Output character in d7 on serial port.
* d7 thrashed.
@@ -1073,6 +1252,16 @@ Lserial_putc:
jne 2f
moveb %d7,%sp@-
.long 0x4e4f0020
+ jra 9f
+2:
+#endif
+#ifdef CONFIG_BVME6000
+ cmpil #MACH_BVME6000,%d4
+ jne 2f
+1: btst #2,BVME_SCC_CTRL_A
+ jeq 1b
+ moveb %d7,BVME_SCC_DATA_A
+ jra 9f
2:
#endif
#ifdef CONFIG_AMIGA
@@ -1199,5 +1388,11 @@ SYMBOL_NAME_LABEL(availmem)
.long 0
SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
.long 0
+#ifdef CONFIG_060_WRITETHROUGH
+SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
+ .long 0
+#endif
+#if defined(CONFIG_MVME16x)
SYMBOL_NAME_LABEL(mvme_bdid_ptr)
.long 0
+#endif
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index a9109ab0a..20e39f17f 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -31,6 +31,7 @@
#include <linux/errno.h>
#include <linux/init.h>
+#include <asm/setup.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/traps.h>
@@ -212,7 +213,7 @@ static void dummy_free_irq(unsigned int irq, void *dev_id)
asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
{
- if (vec >= VEC_INT1 && vec <= VEC_INT7) {
+ if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
vec -= VEC_SPUR;
kstat.irqs[0][vec]++;
irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
diff --git a/arch/m68k/kernel/kgdb.c b/arch/m68k/kernel/kgdb.c
new file mode 100644
index 000000000..cdbd250cd
--- /dev/null
+++ b/arch/m68k/kernel/kgdb.c
@@ -0,0 +1,1194 @@
+/*
+ * arch/m68k/kernel/kgdb.c -- Stub for GDB remote debugging protocol
+ *
+ * Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ * Contributed by HP Systems
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ * Modified and extended for Linux/68k by Roman Hodek
+ *
+ * Send complaints, suggestions etc. to
+ * <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * Copyright (C) 1996-97 Roman Hodek
+ */
+
+/*
+ * kgdb usage notes:
+ * -----------------
+ *
+ * If you select CONFIG_KGDB in the configuration, the kernel will be built
+ * with different gccc flags: "-g" is added to get debug infos, and
+ * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
+ * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
+ * before compresion. Such a kernel will behave just as usually, except if
+ * given a "debug=<device>" command line option. (Only serial devices are
+ * allowed for <device>, i.e. no printers or the like; possible values are
+ * machine depedend and are the same as for the usual debug device, the one
+ * for logging kernel messages.) If that option is given and the device can be
+ * initialized, the kernel will connect to the remote gdb in trap_init(). The
+ * serial parameters are fixed to 8N1 and 9600bps, for easyness of
+ * implementation.
+ *
+ * Of course, you need a remote machine a suitable gdb there. I.e., it must
+ * have support for a m68k-linux target built in. If the remote machine
+ * doesn't run Linux/68k itself, you have to build a cross gdb. This is done
+ * by
+ * ./configure --target=m68k-linux
+ * in the gdb source directory. Until gdb comes with m68k-linux support by
+ * default, you have to apply some patches before. The remote debugging
+ * protocol itself is always built into gdb anyway, so you don't have to take
+ * special care about it.
+ *
+ * To start a debugging session, start that gdb with the debugging kernel
+ * image (the one with the symbols, vmlinux.debug) named on the command line.
+ * This file will be used by gdb to get symbol and debugging infos about the
+ * kernel. Next, select remote debug mode by
+ * target remote <device>
+ * where <device> is the name of the serial device over which the debugged
+ * machine is connected. Maybe you have to adjust the baud rate by
+ * set remotebaud <rate>
+ * or also other parameters with stty:
+ * shell stty ... </dev/...
+ * If the kernel to debug has already booted, it waited for gdb and now
+ * connects, and you'll see a breakpoint being reported. If the kernel isn't
+ * running yet, start it now. The order of gdb and the kernel doesn't matter.
+ * Another thing worth knowing about in the getting-started phase is how to
+ * debug the remote protocol itself. This is activated with
+ * set remotedebug 1
+ * gdb will then print out each packet sent or received. You'll also get some
+ * messages about the gdb stub on the console of the debugged machine.
+ *
+ * If all that works, you can use lots of the usual debugging techniques on
+ * the kernel, e.g. inspecting and changing variables/memory, setting
+ * breakpoints, single stepping and so on. It's also possible to interrupt the
+ * debugged kernel by pressing C-c in gdb. Have fun! :-)
+ *
+ * The gdb stub is entered (and thus the remote gdb gets control) in the
+ * following situations:
+ *
+ * - If breakpoint() is called. This is just after kgdb initialization, or if
+ * a breakpoint() call has been put somewhere into the kernel source.
+ * (Breakpoints can of course also be set the usual way in gdb.)
+ *
+ * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
+ * are entered. All the CPU exceptions are mapped to (more or less..., see
+ * the hard_trap_info array below) appropriate signal, which are reported
+ * to gdb. die_if_kernel() is usually called after some kind of access
+ * error and thus is reported as SIGSEGV.
+ *
+ * - When panic() is called. This is reported as SIGABRT.
+ *
+ * - If C-c is received over the serial line, which is treated as
+ * SIGINT.
+ *
+ * Of course, all these signals are just faked for gdb, since there is no
+ * signal concept as such for the kernel. It also isn't possible --obviously--
+ * to set signal handlers from inside gdb, or restart the kernel with a
+ * signal.
+ *
+ * Current limitations:
+ *
+ * - While the kernel is stopped, interrupts are disabled for safety reasons
+ * (i.e., variables not changing magically or the like). But this also
+ * means that the clock isn't running anymore, and that interrupts from the
+ * hardware may get lost/not be served in time. This can cause some device
+ * errors...
+ *
+ * - When single-stepping, only one instruction of the current thread is
+ * executed, but interrupts are allowed for that time and will be serviced
+ * if pending. Be prepared for that.
+ *
+ * - All debugging happens in kernel virtual address space. There's no way to
+ * access physical memory not mapped in kernel space, or to access user
+ * space. A way to work around this is using get_user_long & Co. in gdb
+ * expressions, but only for the current process.
+ *
+ * - Interrupting the kernel only works if interrupts are currently allowed,
+ * and the interrupt of the serial line isn't blocked by some other means
+ * (IPL too high, disabled, ...)
+ *
+ * - The gdb stub is currently not reentrant, i.e. errors that happen therein
+ * (e.g. accesing invalid memory) may not be caught correctly. This could
+ * be removed in future by introducing a stack of struct registers.
+ *
+ */
+
+/*
+ * To enable debugger support, two things need to happen. One, a
+ * call to kgdb_init() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * (Linux/68k note: Due to the current design, kgdb has to be initialized
+ * after traps and interrupts.)
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a TRAP #15 instruction.
+ *
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
+ * baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+
+#include <asm/setup.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/kgdb.h>
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#endif
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#endif
+
+
+#undef DEBUG
+
+/*
+ * global variable: register structure
+ */
+
+struct gdb_regs kgdb_registers;
+
+/*
+ * serial i/o functions
+ */
+
+static int (*serial_out)( unsigned char c );
+static unsigned char (*serial_in)( void );
+static unsigned char (*serial_intr)( void );
+
+#define putDebugChar(c) serial_out(c)
+#define getDebugChar() serial_in()
+
+
+/***************************** Prototypes *****************************/
+
+static int hex( unsigned char ch);
+static void getpacket( char *buffer);
+static void putpacket( char *buffer, int expect_ack);
+static inline unsigned long *get_vbr( void );
+static int protected_read( char *p, unsigned long *vbr );
+static int protected_write( char *p, char val, unsigned long *vbr );
+static unsigned char *mem2hex( char *mem, char *buf, int count, int
+ may_fault);
+static char *hex2mem( char *buf, char *mem, int count, int may_fault);
+static int computeSignal( int tt);
+static int hexToInt( char **ptr, int *intValue);
+extern asmlinkage void kgdb_intr( int intno, void *data, struct pt_regs *fp );
+static asmlinkage void handle_exception( void );
+static void show_gdbregs( void );
+#ifdef CONFIG_ATARI
+static int atari_mfp_out( unsigned char c );
+static unsigned char atari_mfp_in( void );
+static unsigned char atari_mfp_intr( void );
+static int atari_scc_out( unsigned char c );
+static unsigned char atari_scc_in( void );
+static unsigned char atari_scc_intr( void );
+#endif
+#ifdef CONFIG_AMIGA
+extern int amiga_ser_out( unsigned char c );
+extern unsigned char amiga_ser_in( void );
+#endif
+
+/************************* End of Prototypes **************************/
+
+
+int kgdb_initialized = 0; /* !0 means we've been initialized */
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+static const char hexchars[]="0123456789abcdef";
+/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
+static int remote_debug = 0;
+
+/* sizes (in bytes) of CPU stack frames */
+static int frame_sizes[16] = {
+ 8, 8, 12, 12, /* $0..$3 */
+ 16, 8, 8, 60, /* $4..$7 */
+ 8, 20, 32, 92, /* $8..$B */
+ 12, 4, 4, 4 /* $C..$F */
+};
+
+/*
+ * Convert ch from a hex digit to an int
+ */
+static int hex(unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ unsigned char ch;
+
+ do {
+ /*
+ * wait around for the start character,
+ * ignore all other characters
+ */
+ while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+ checksum = 0;
+ xmitcsum = -1;
+ count = 0;
+
+ /*
+ * now, read until a # or end of buffer is found
+ */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+
+ if (count >= BUFMAX)
+ continue;
+
+ buffer[count] = 0;
+#ifdef DEBUG
+ printk( "kgdb: received packet %s\n", buffer );
+#endif
+
+ if (ch == '#') {
+ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+ xmitcsum |= hex(getDebugChar() & 0x7f);
+
+ if (checksum != xmitcsum) {
+ if (remote_debug)
+ printk( "kgdb: bad checksum. count = 0x%x sent=0x%x "
+ "buf=%s\n", checksum, xmitcsum, buffer );
+ putDebugChar('-'); /* failed checksum */
+ }
+ else {
+ putDebugChar('+'); /* successful transfer */
+
+ /*
+ * if a sequence char is present,
+ * reply the sequence ID
+ */
+ if (buffer[2] == ':') {
+ putDebugChar(buffer[0]);
+ putDebugChar(buffer[1]);
+
+ /*
+ * remove sequence chars from buffer
+ */
+ count = strlen(buffer);
+ for (i=3; i <= count; i++)
+ buffer[i-3] = buffer[i];
+ }
+ }
+ }
+ }
+ while (checksum != xmitcsum);
+}
+
+/*
+ * send the packet in buffer.
+ */
+static void putpacket(char *buffer, int expect_ack)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch;
+
+ /*
+ * $<packet info>#<checksum>.
+ */
+
+#ifdef DEBUG
+ printk( "kgdb: sending packet %s\n", buffer );
+#endif
+ do {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count]) != 0) {
+ if (!(putDebugChar(ch)))
+ return;
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+
+ }
+ while (expect_ack && (getDebugChar() & 0x7f) != '+');
+}
+
+
+static inline unsigned long *get_vbr( void )
+
+{ unsigned long *vbr;
+
+ __asm__ __volatile__ ( "movec %/vbr,%0" : "=d" (vbr) : );
+ return( vbr );
+}
+
+static int protected_read( char *p, unsigned long *vbr )
+
+{ unsigned char val;
+ int rv;
+
+ __asm__ __volatile__
+ ( "movel %3@(8),%/a0\n\t"
+ "movel #Lberr1,%3@(8)\n\t"
+ "movel %/sp,%/a1\n\t"
+ "moveq #1,%1\n\t"
+ "moveb %2@,%0\n"
+ "nop \n\t"
+ "moveq #0,%1\n\t"
+ "Lberr1:\t"
+ "movel %/a1,%/sp\n\t"
+ "movel %/a0,%3@(8)"
+ : "=&d" (val), "=&r" (rv)
+ : "a" (p), "a" (vbr)
+ : "a0", "a1" );
+
+ return( rv ? -1 : val );
+}
+
+static int protected_write( char *p, char val, unsigned long *vbr )
+
+{ int rv;
+
+ __asm__ __volatile__
+ ( "movel %3@(8),%/a0\n\t"
+ "movel #Lberr2,%3@(8)\n\t"
+ "movel %/sp,%/a1\n\t"
+ "moveq #1,%0\n\t"
+ "moveb %2,%1@\n"
+ "nop \n\t"
+ "moveq #0,%0\n\t"
+ "Lberr2:\t"
+ "movel %/a1,%/sp\n\t"
+ "movel %/a0,%3@(8)"
+ : "=&r" (rv)
+ : "a" (p), "d" (val), "a" (vbr)
+ : "a0", "a1" );
+
+ return( rv );
+}
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+ int ch;
+ unsigned long *vbr = get_vbr();
+
+ for( ; count-- > 0; ++mem ) {
+ if ((ch = protected_read( mem, vbr )) < 0) {
+ /* bus error happened */
+ if (may_fault)
+ return 0;
+ else {
+ /* ignore, but print a warning */
+ printk( "Bus error on read from %p\n", mem );
+ ch = 0;
+ }
+ }
+ *buf++ = hexchars[(ch >> 4) & 0xf];
+ *buf++ = hexchars[ch & 0xf];
+ }
+
+ *buf = 0;
+
+ return buf;
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ */
+static char *hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+ int i;
+ unsigned char ch;
+ unsigned long *vbr = get_vbr();
+
+ for( i = 0; i < count; i++, mem++ ) {
+ ch = hex(*buf++) << 4;
+ ch |= hex(*buf++);
+ if (protected_write( mem, ch, vbr )) {
+ /* bus error happened */
+ if (may_fault)
+ return 0;
+ else
+ /* ignore, but print a warning */
+ printk( "Bus error on write to %p\n", mem );
+ }
+ }
+
+ return mem;
+}
+
+/*
+ * This table contains the mapping between SPARC hardware trap types, and
+ * signals, which are primarily what GDB understands. It also indicates
+ * which hardware traps we need to commandeer when initializing the stub.
+ */
+static struct hard_trap_info
+{
+ unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
+ unsigned char signo; /* Signal that we map this trap into */
+} hard_trap_info[] = {
+ { 1, SIGINT }, /* excep. 1 is used to fake SIGINT */
+ { VEC_BUSERR, SIGSEGV }, /* bus/access error */
+ { VEC_ADDRERR, SIGBUS }, /* address error */
+ { VEC_ILLEGAL, SIGILL }, /* illegal insn */
+ { VEC_ZERODIV, SIGFPE }, /* (integer) divison by zero */
+ { VEC_CHK, SIGILL }, /* CHK insn */
+ { VEC_TRAP, SIGFPE }, /* [F]TRAPcc insn */
+ { VEC_PRIV, SIGILL }, /* priviledge violation (cannot happen) */
+ { VEC_TRACE, SIGTRAP }, /* trace trap (single-stepping) */
+ { VEC_LINE10, SIGILL }, /* A-line insn */
+ { VEC_LINE11, SIGILL }, /* F-line insn */
+ { VEC_COPROC, SIGIOT }, /* coprocessor protocol error */
+ { VEC_FORMAT, SIGIOT }, /* frame format error */
+ { VEC_UNINT, SIGIOT }, /* uninitialized intr. (should not happen) */
+ { VEC_SYS, SIGILL }, /* TRAP #0 = system call (illegal in kernel) */
+ { VEC_TRAP1, SIGILL }, /* TRAP #1 */
+ { VEC_TRAP2, SIGILL }, /* TRAP #2 */
+ { VEC_TRAP3, SIGILL }, /* TRAP #3 */
+ { VEC_TRAP4, SIGILL }, /* TRAP #4 */
+ { VEC_TRAP5, SIGILL }, /* TRAP #5 */
+ { VEC_TRAP6, SIGILL }, /* TRAP #6 */
+ { VEC_TRAP7, SIGILL }, /* TRAP #7 */
+ { VEC_TRAP8, SIGILL }, /* TRAP #8 */
+ { VEC_TRAP9, SIGILL }, /* TRAP #9 */
+ { VEC_TRAP10, SIGILL }, /* TRAP #10 */
+ { VEC_TRAP11, SIGILL }, /* TRAP #11 */
+ { VEC_TRAP12, SIGILL }, /* TRAP #12 */
+ { VEC_TRAP13, SIGILL }, /* TRAP #13 */
+ { VEC_TRAP14, SIGABRT }, /* TRAP #14 (used by kgdb_abort) */
+ { VEC_TRAP15, SIGTRAP }, /* TRAP #15 (breakpoint) */
+ { VEC_FPBRUC, SIGFPE }, /* FPU */
+ { VEC_FPIR, SIGFPE }, /* FPU */
+ { VEC_FPDIVZ, SIGFPE }, /* FPU */
+ { VEC_FPUNDER, SIGFPE }, /* FPU */
+ { VEC_FPOE, SIGFPE }, /* FPU */
+ { VEC_FPOVER, SIGFPE }, /* FPU */
+ { VEC_FPNAN, SIGFPE }, /* FPU */
+ { VEC_FPUNSUP, SIGFPE }, /* FPU */
+ { VEC_UNIMPEA, SIGILL }, /* unimpl. effective address */
+ { VEC_UNIMPII, SIGILL }, /* unimpl. integer insn */
+
+ { 0, 0 } /* Must be last */
+};
+
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void kgdb_init(void)
+{
+ extern char m68k_debug_device[];
+
+ /* fake usage to avoid gcc warnings about unused stuff (they're used in
+ * assembler code) The local variables will be optimized away... */
+ void (*fake1)(void) = handle_exception;
+ int *fake2 = frame_sizes;
+ (void)fake1; (void)fake2;
+
+ /* We don't modify the real exception vectors here for the m68k.
+ * handle_exception() will be called from bad_kernel_trap() or
+ * die_if_kernel() as needed. */
+
+ /*
+ * Initialize the serial port (name in 'm68k_debug_device')
+ */
+
+ serial_in = NULL;
+ serial_out = NULL;
+ serial_intr = NULL;
+
+#ifdef CONFIG_ATARI
+ if (MACH_IS_ATARI) {
+ if (!strcmp( m68k_debug_device, "ser" )) {
+ /* defaults to ser2 for a Falcon and ser1 otherwise */
+ strcpy( m68k_debug_device,
+ ((atari_mch_cookie>>16) == ATARI_MCH_FALCON) ?
+ "ser2" : "ser1" );
+ }
+
+ if (!strcmp( m68k_debug_device, "ser1" )) {
+ /* ST-MFP Modem1 serial port init */
+ mfp.trn_stat &= ~0x01; /* disable TX */
+ mfp.rcv_stat &= ~0x01; /* disable RX */
+ mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */
+ mfp.tim_ct_cd &= 0x70; /* stop timer D */
+ mfp.tim_dt_d = 2; /* 9600 bps */
+ mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
+ mfp.trn_stat |= 0x01; /* enable TX */
+ mfp.rcv_stat |= 0x01; /* enable RX */
+
+ /* set function pointers */
+ serial_in = atari_mfp_in;
+ serial_out = atari_mfp_out;
+ serial_intr = atari_mfp_intr;
+
+ /* allocate interrupt */
+ request_irq( IRQ_MFP_RECFULL, kgdb_intr, IRQ_TYPE_FAST, "kgdb",
+ NULL );
+ }
+ else if (!strcmp( m68k_debug_device, "ser2" )) {
+ extern int atari_SCC_reset_done;
+
+ /* SCC Modem2 serial port init */
+ static unsigned char *p, scc_table[] = {
+ 9, 0xc0, /* Reset */
+ 4, 0x44, /* x16, 1 stopbit, no parity */
+ 3, 0xc0, /* receiver: 8 bpc */
+ 5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */
+ 2, 0x60, /* base int vector */
+ 9, 0x09, /* int enab, with status low */
+ 10, 0, /* NRZ */
+ 11, 0x50, /* use baud rate generator */
+ 12, 24, 13, 0, /* 9600 baud */
+ 14, 2, 14, 3, /* use master clock for BRG, enable */
+ 3, 0xc1, /* enable receiver */
+ 5, 0xea, /* enable transmitter */
+ 15, 0, /* no stat ints */
+ 1, 0x10, /* Rx int every char, other ints off */
+ 0
+ };
+
+ (void)scc.cha_b_ctrl; /* reset reg pointer */
+ MFPDELAY();
+ for( p = scc_table; *p != 0; ) {
+ scc.cha_b_ctrl = *p++;
+ MFPDELAY();
+ scc.cha_b_ctrl = *p++;
+ MFPDELAY();
+ if (p[-2] == 9)
+ udelay(40); /* extra delay after WR9 access */
+ }
+ /* avoid that atari_SCC.c resets the whole SCC again */
+ atari_SCC_reset_done = 1;
+
+ /* set function pointers */
+ serial_in = atari_scc_in;
+ serial_out = atari_scc_out;
+ serial_intr = atari_scc_intr;
+
+ /* allocate rx and spcond ints */
+ request_irq( IRQ_SCCB_RX, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL );
+ request_irq( IRQ_SCCB_SPCOND, kgdb_intr, IRQ_TYPE_FAST, "kgdb",
+ NULL );
+ }
+ }
+#endif
+
+#ifdef CONFIG_AMIGA
+ if (MACH_IS_AMIGA) {
+ /* always use built-in serial port, no init required */
+ serial_in = amiga_ser_in;
+ serial_out = amiga_ser_out;
+ }
+#endif
+
+#ifdef CONFIG_ATARI
+ if (!serial_in || !serial_out) {
+ if (*m68k_debug_device)
+ printk( "kgdb_init failed: no valid serial device!\n" );
+ else
+ printk( "kgdb not enabled\n" );
+ return;
+ }
+#endif
+
+ /*
+ * In case GDB is started before us, ack any packets
+ * (presumably "$?#xx") sitting there.
+ */
+
+ putDebugChar ('+');
+ kgdb_initialized = 1;
+ printk( KERN_INFO "kgdb initialized.\n" );
+}
+
+
+/*
+ * Convert the MIPS hardware trap type code to a unix signal number.
+ */
+static int computeSignal(int tt)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ if (ht->tt == tt)
+ return ht->signo;
+
+ return SIGHUP; /* default for things we don't know about */
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ while (**ptr)
+ {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+
+/*
+ * This assembler stuff copies a struct frame (passed as argument) into struct
+ * gdb_regs registers and then calls handle_exception. After return from
+ * there, register and the like are restored from 'registers', the stack is
+ * set up and execution is continued where registers->pc tells us.
+ */
+
+/* offsets in struct frame */
+#define FRAMEOFF_D1 "0" /* d1..d5 */
+#define FRAMEOFF_A0 "5*4" /* a0..a2 */
+#define FRAMEOFF_D0 "8*4"
+#define FRAMEOFF_SR "11*4"
+#define FRAMEOFF_PC "11*4+2"
+#define FRAMEOFF_VECTOR "12*4+2"
+
+/* offsets in struct gdb_regs */
+#define GDBOFF_D0 "0"
+#define GDBOFF_D1 "1*4"
+#define GDBOFF_D6 "6*4"
+#define GDBOFF_A0 "8*4"
+#define GDBOFF_A3 "11*4"
+#define GDBOFF_A7 "15*4"
+#define GDBOFF_VECTOR "16*4"
+#define GDBOFF_SR "16*4+2"
+#define GDBOFF_PC "17*4"
+#define GDBOFF_FP0 "18*4"
+#define GDBOFF_FPCTL "42*4"
+
+__asm__
+( " .globl " SYMBOL_NAME_STR(enter_kgdb) "\n"
+ SYMBOL_NAME_STR(enter_kgdb) ":\n"
+ /* return if not initialized */
+ " tstl "SYMBOL_NAME_STR(kgdb_initialized)"\n"
+ " bne 1f\n"
+ " rts \n"
+ "1: orw #0x700,%sr\n" /* disable interrupts while in stub */
+ " tstl %sp@+\n" /* pop off return address */
+ " movel %sp@+,%a0\n" /* get pointer to fp->ptregs (param) */
+ " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a1\n" /* destination */
+ /* copy d0-d5/a0-a1 into gdb_regs */
+ " movel %a0@("FRAMEOFF_D0"),%a1@("GDBOFF_D0")\n"
+ " moveml %a0@("FRAMEOFF_D1"),%d1-%d5\n"
+ " moveml %d1-%d5,%a1@("GDBOFF_D1")\n"
+ " moveml %a0@("FRAMEOFF_A0"),%d0-%d2\n"
+ " moveml %d0-%d2,%a1@("GDBOFF_A0")\n"
+ /* copy sr and pc */
+ " movel %a0@("FRAMEOFF_PC"),%a1@("GDBOFF_PC")\n"
+ " movew %a0@("FRAMEOFF_SR"),%a1@("GDBOFF_SR")\n"
+ /* copy format/vector word */
+ " movew %a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n"
+ /* save FPU regs */
+ " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n"
+ " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
+
+ /* set stack to CPU frame */
+ " addl #"FRAMEOFF_SR",%a0\n"
+ " movel %a0,%sp\n"
+ " movew %sp@(6),%d0\n"
+ " andl #0xf000,%d0\n"
+ " lsrl #8,%d0\n"
+ " lsrl #2,%d0\n" /* get frame format << 2 */
+ " lea "SYMBOL_NAME_STR(frame_sizes)",%a2\n"
+ " addl %a2@(%d0),%sp\n"
+ " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
+
+ /* call handle_exception() now that the stack is set up */
+ "Lcall_handle_excp:"
+ " jsr "SYMBOL_NAME_STR(handle_exception)"\n"
+
+ /* after return, first restore FPU registers */
+ " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */
+ " fmovemx %a0@("GDBOFF_FP0"),%fp0-%fp7\n"
+ " fmoveml %a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n"
+ /* set new stack pointer */
+ " movel %a0@("GDBOFF_A7"),%sp\n"
+ " clrw %sp@-\n" /* fake format $0 frame */
+ " movel %a0@("GDBOFF_PC"),%sp@-\n" /* new PC into frame */
+ " movew %a0@("GDBOFF_SR"),%sp@-\n" /* new SR into frame */
+ /* restore general registers */
+ " moveml %a0@("GDBOFF_D0"),%d0-%d7/%a0-%a6\n"
+ /* and jump to new PC */
+ " rte"
+ );
+
+
+/*
+ * This is the entry point for the serial interrupt handler. It calls the
+ * machine specific function pointer 'serial_intr' to get the char that
+ * interrupted. If that was C-c, the stub is entered as above, but based on
+ * just a struct intframe, not a struct frame.
+ */
+
+__asm__
+( SYMBOL_NAME_STR(kgdb_intr) ":\n"
+ /* return if not initialized */
+ " tstl "SYMBOL_NAME_STR(kgdb_initialized)"\n"
+ " bne 1f\n"
+ "2: rts \n"
+ "1: movel "SYMBOL_NAME_STR(serial_intr)",%a0\n"
+ " jsr (%a0)\n" /* get char from serial */
+ " cmpb #3,%d0\n" /* is it C-c ? */
+ " bne 2b\n" /* no -> just ignore */
+ " orw #0x700,%sr\n" /* disable interrupts */
+ " subql #1,"SYMBOL_NAME_STR(local_irq_count)"\n"
+ " movel %sp@(12),%sp\n" /* revert stack to where 'inthandler' set
+ * it up */
+ /* restore regs from frame */
+ " moveml %sp@+,%d1-%d5/%a0-%a2\n"
+ " movel %sp@+,%d0\n"
+ " addql #8,%sp\n" /* throw away orig_d0 and stkadj */
+ /* save them into 'registers' */
+ " moveml %d0-%d7/%a0-%a6,"SYMBOL_NAME_STR(kgdb_registers)"\n"
+ " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a1\n" /* destination */
+ /* copy sr and pc */
+ " movel %sp@(2),%a1@("GDBOFF_PC")\n"
+ " movew %sp@,%a1@("GDBOFF_SR")\n"
+ /* fake format 0 and vector 1 (translated to SIGINT) */
+ " movew #4,%a1@("GDBOFF_VECTOR")\n"
+ /* save FPU regs */
+ " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n"
+ " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
+ /* pop off the CPU stack frame */
+ " addql #8,%sp\n"
+ " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
+ /* proceed as in enter_kgdb */
+ " jbra Lcall_handle_excp\n"
+ );
+
+/*
+ * This function does all command processing for interfacing to gdb. It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+static asmlinkage void handle_exception( void )
+{
+ int trap; /* Trap type */
+ int sigval;
+ int addr;
+ int length;
+ char *ptr;
+
+ trap = kgdb_registers.vector >> 2;
+ sigval = computeSignal(trap);
+ /* clear upper half of vector/sr word */
+ kgdb_registers.vector = 0;
+ kgdb_registers.format = 0;
+
+#ifndef DEBUG
+ if (remote_debug) {
+#endif
+ printk("in handle_exception() trap=%d sigval=%d\n", trap, sigval );
+ show_gdbregs();
+#ifndef DEBUG
+ }
+#endif
+
+ /*
+ * reply to host that an exception has occurred
+ */
+ ptr = output_buffer;
+
+ /*
+ * Send trap type (converted to signal)
+ */
+ *ptr++ = 'T';
+ *ptr++ = hexchars[sigval >> 4];
+ *ptr++ = hexchars[sigval & 0xf];
+
+ /*
+ * Send Error PC
+ */
+ *ptr++ = hexchars[GDBREG_PC >> 4];
+ *ptr++ = hexchars[GDBREG_PC & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&kgdb_registers.pc, ptr, 4, 0);
+ *ptr++ = ';';
+
+ /*
+ * Send frame pointer
+ */
+ *ptr++ = hexchars[GDBREG_A6 >> 4];
+ *ptr++ = hexchars[GDBREG_A6 & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&kgdb_registers.regs[GDBREG_A6], ptr, 4, 0);
+ *ptr++ = ';';
+
+ /*
+ * Send stack pointer
+ */
+ *ptr++ = hexchars[GDBREG_SP >> 4];
+ *ptr++ = hexchars[GDBREG_SP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)&kgdb_registers.regs[GDBREG_SP], ptr, 4, 0);
+ *ptr++ = ';';
+
+ *ptr++ = 0;
+ putpacket(output_buffer,1); /* send it off... */
+
+ /*
+ * Wait for input from remote GDB
+ */
+ for(;;) {
+ output_buffer[0] = 0;
+ getpacket(input_buffer);
+
+ switch (input_buffer[0]) {
+ case '?':
+ output_buffer[0] = 'S';
+ output_buffer[1] = hexchars[sigval >> 4];
+ output_buffer[2] = hexchars[sigval & 0xf];
+ output_buffer[3] = 0;
+ break;
+
+ case 'd':
+ /* toggle debug flag */
+ remote_debug = !remote_debug;
+ break;
+
+ /*
+ * Return the value of the CPU registers
+ */
+ case 'g':
+ ptr = output_buffer;
+ ptr = mem2hex((char *)&kgdb_registers, ptr, NUMREGSBYTES, 0);
+ break;
+
+ /*
+ * set the value of the CPU registers - return OK
+ */
+ case 'G':
+ ptr = &input_buffer[1];
+ ptr = hex2mem(ptr, (char *)&kgdb_registers, NUMREGSBYTES, 0);
+ strcpy(output_buffer,"OK");
+ break;
+
+ /*
+ * Pn...=r... Write register n
+ */
+ case 'P':
+ ptr = &input_buffer[1];
+ if (hexToInt(&ptr, &addr) && *ptr++ == '=') {
+ if (addr >= 0 && addr <= GDBREG_PC)
+ hex2mem(ptr, (char *)&kgdb_registers.regs[addr], 4, 0);
+ else if (addr >= GDBREG_FP0 && addr <= GDBREG_FP7)
+ hex2mem(ptr, (char *)&kgdb_registers.fpregs[addr-GDBREG_FP0],
+ 12, 0);
+ else if (addr >= GDBREG_FPCR && addr <= GDBREG_FPIAR)
+ hex2mem(ptr, (char *)&kgdb_registers.fpcntl[addr-GDBREG_FPCR],
+ 4, 0);
+ }
+ else
+ strcpy(output_buffer,"E01");
+ break;
+
+ /*
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA
+ */
+ case 'm':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)) {
+ if (mem2hex((char *)addr, output_buffer, length, 1))
+ break;
+ strcpy (output_buffer, "E03");
+ } else
+ strcpy(output_buffer,"E01");
+ break;
+
+ /*
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+ */
+ case 'M':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ if (hex2mem(ptr, (char *)addr, length, 1))
+ strcpy(output_buffer, "OK");
+ else
+ strcpy(output_buffer, "E03");
+ }
+ else
+ strcpy(output_buffer, "E02");
+ break;
+
+ /*
+ * cAA..AA Continue at address AA..AA(optional)
+ * sAA..AA Step one instruction from AA..AA(optional)
+ */
+ case 'c':
+ case 's':
+ /* try to read optional parameter, pc unchanged if no parm */
+
+ ptr = &input_buffer[1];
+ if (hexToInt(&ptr, &addr))
+ kgdb_registers.pc = addr;
+
+ kgdb_registers.sr &= 0x7fff; /* clear Trace bit */
+ if (input_buffer[0] == 's')
+ kgdb_registers.sr |= 0x8000; /* set it if step command */
+
+ if (remote_debug)
+ printk( "cont; new PC=0x%08lx SR=0x%04x\n",
+ kgdb_registers.pc, kgdb_registers.sr );
+
+ /*
+ * Need to flush the instruction cache here, as we may
+ * have deposited a breakpoint, and the icache probably
+ * has no way of knowing that a data ref to some location
+ * may have changed something that is in the instruction
+ * cache.
+ */
+
+ if (m68k_is040or060)
+ __asm__ __volatile__
+ ( ".word 0xf4f8\n\t" /* CPUSHA I/D */
+ ".word 0xf498" /* CINVA I */
+ );
+ else
+ __asm__ __volatile__
+ ( "movec %/cacr,%/d0\n\t"
+ "oriw #0x0008,%/d0\n\t"
+ "movec %/d0,%/cacr"
+ : : : "d0" );
+
+ return;
+
+ /*
+ * kill the program means reset the machine
+ */
+ case 'k' :
+ case 'r':
+ if (mach_reset) {
+ /* reply OK before actual reset */
+ strcpy(output_buffer,"OK");
+ putpacket(output_buffer,0);
+ mach_reset();
+ }
+ else
+ strcpy(output_buffer,"E01");
+ break;
+
+ /*
+ * Set baud rate (bBB)
+ * FIXME: Needs to be written (in gdb, too...)
+ */
+ case 'b':
+ strcpy(output_buffer,"E01");
+ break;
+
+ } /* switch */
+
+ /*
+ * reply to the request
+ */
+
+ putpacket(output_buffer,1);
+
+ }
+}
+
+
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+static void show_gdbregs( void )
+{
+ printk( "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+ kgdb_registers.regs[0], kgdb_registers.regs[1],
+ kgdb_registers.regs[2], kgdb_registers.regs[3] );
+ printk( "d4: %08lx d5: %08lx d6: %08lx d7: %08lx\n",
+ kgdb_registers.regs[4], kgdb_registers.regs[5],
+ kgdb_registers.regs[6], kgdb_registers.regs[7] );
+ printk( "a0: %08lx a1: %08lx a2: %08lx a3: %08lx\n",
+ kgdb_registers.regs[8], kgdb_registers.regs[9],
+ kgdb_registers.regs[10], kgdb_registers.regs[11] );
+ printk( "a4: %08lx a5: %08lx a6: %08lx a7: %08lx\n",
+ kgdb_registers.regs[12], kgdb_registers.regs[13],
+ kgdb_registers.regs[14], kgdb_registers.regs[15] );
+ printk( "pc: %08lx sr: %04x\n", kgdb_registers.pc, kgdb_registers.sr );
+}
+
+
+/* -------------------- Atari serial I/O -------------------- */
+
+#ifdef CONFIG_ATARI
+
+static int atari_mfp_out( unsigned char c )
+
+{
+ while( !(mfp.trn_stat & 0x80) ) /* wait for tx buf empty */
+ barrier();
+ mfp.usart_dta = c;
+ return( 1 );
+}
+
+
+static unsigned char atari_mfp_in( void )
+
+{
+ while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
+ barrier();
+ return( mfp.usart_dta );
+}
+
+
+static unsigned char atari_mfp_intr( void )
+
+{
+ return( mfp.usart_dta );
+}
+
+
+static int atari_scc_out( unsigned char c )
+
+{
+ do {
+ MFPDELAY();
+ } while( !(scc.cha_b_ctrl & 0x04) ); /* wait for tx buf empty */
+ MFPDELAY();
+ scc.cha_b_data = c;
+ return( 1 );
+}
+
+
+static unsigned char atari_scc_in( void )
+
+{
+ do {
+ MFPDELAY();
+ } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+ MFPDELAY();
+ return( scc.cha_b_data );
+}
+
+
+static unsigned char atari_scc_intr( void )
+
+{ unsigned char c, stat;
+
+ MFPDELAY();
+ scc.cha_b_ctrl = 1; /* RR1 */
+ MFPDELAY();
+ stat = scc.cha_b_ctrl;
+ MFPDELAY();
+ c = scc.cha_b_data;
+ MFPDELAY();
+ if (stat & 0x30) {
+ scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */
+ MFPDELAY();
+ }
+ scc.cha_b_ctrl = 0x38; /* reset highest IUS */
+ MFPDELAY();
+ return( c );
+}
+
+#endif
diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h
new file mode 100644
index 000000000..992d390c7
--- /dev/null
+++ b/arch/m68k/kernel/m68k_defs.h
@@ -0,0 +1,8 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+
+#define TS_MAGICKEY 0x5a5a5a5a
+#define TS_TSS 478
+#define TS_ESP0 498
+#define TS_FPU 502
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 025e11c0f..ee73b3ff2 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/linkage.h>
#include <linux/sched.h>
@@ -8,7 +7,6 @@
#include <linux/elfcore.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <asm/setup.h>
#include <asm/machdep.h>
@@ -44,6 +42,8 @@ EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
@@ -60,7 +60,3 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index a6fbd5718..dac2bfcc8 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -66,13 +66,14 @@ asmlinkage int sys_idle(void)
current->priority = -100;
current->counter = -100;
for (;;){
- if (!need_resched)
+ if (!current->need_resched)
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
#else /* portable version */
__asm__("stop #0x2000" : : : "cc");
#endif /* machine compilation types */
+ check_pgt_cache();
run_task_queue(&tq_scheduler);
schedule();
}
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 4a2a95f4b..da91d32de 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -347,9 +347,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
+ unsigned long flags;
+
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
}
send_sig(SIGSTOP, child, 1);
ret = 0;
@@ -491,6 +495,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
case PTRACE_DETACH: { /* detach a process that was attached. */
+ unsigned long flags;
long tmp;
ret = -EIO;
@@ -499,9 +504,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
/* make sure the single step bit is not set. */
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index fccf8b4cf..6df005fb4 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -61,6 +61,8 @@ void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initd
int (*mach_keyb_init) (void) __initdata;
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
void (*mach_kbd_leds) (unsigned int) = NULL;
+/* machine dependent "kbd-reset" setup function */
+void (*kbd_reset_setup) (char *, int) __initdata = NULL;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata;
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
@@ -102,6 +104,8 @@ extern void config_mac(void);
extern void config_sun3(void);
extern void config_apollo(void);
extern void config_mvme16x(void);
+extern void config_bvme6000(void);
+extern void config_hp300(void);
#define MASK_256K 0xfffc0000
@@ -250,6 +254,16 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
config_mvme16x();
break;
#endif
+#ifdef CONFIG_BVME6000
+ case MACH_BVME6000:
+ config_bvme6000();
+ break;
+#endif
+#ifdef CONFIG_HP300
+ case MACH_HP300:
+ config_hp300();
+ break;
+#endif
default:
panic ("No configuration setup");
}
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 97809d382..03214a42f 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -147,6 +147,12 @@ sys_sigaction(int sig, const struct old_sigaction *act,
return ret;
}
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ return do_sigaltstack(uss, uoss, rdusp());
+}
+
/*
* Do a signal return; undo the signal stack.
@@ -177,31 +183,33 @@ struct rt_sigframe
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
-static inline void restore_fpu_state(struct sigcontext *sc)
+static inline int restore_fpu_state(struct sigcontext *sc)
{
+ int err = 1;
+
if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
/* Verify the frame format. */
if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
- goto badframe;
+ goto out;
if (CPU_IS_020_OR_030) {
if (m68k_fputype & FPU_68881 &&
!(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
- goto badframe;
+ goto out;
if (m68k_fputype & FPU_68882 &&
!(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
- goto badframe;
+ goto out;
} else if (CPU_IS_040) {
if (!(sc->sc_fpstate[1] == 0x00 ||
sc->sc_fpstate[1] == 0x28 ||
sc->sc_fpstate[1] == 0x60))
- goto badframe;
+ goto out;
} else if (CPU_IS_060) {
if (!(sc->sc_fpstate[3] == 0x00 ||
sc->sc_fpstate[3] == 0x60 ||
sc->sc_fpstate[3] == 0xe0))
- goto badframe;
+ goto out;
} else
- goto badframe;
+ goto out;
__asm__ volatile (".chip 68k/68881\n\t"
"fmovemx %0,%/fp0-%/fp1\n\t"
@@ -213,10 +221,10 @@ static inline void restore_fpu_state(struct sigcontext *sc)
__asm__ volatile (".chip 68k/68881\n\t"
"frestore %0\n\t"
".chip 68k" : : "m" (*sc->sc_fpstate));
- return;
+ err = 0;
-badframe:
- do_exit(SIGSEGV);
+out:
+ return err;
}
#define FPCONTEXT_SIZE 216
@@ -224,42 +232,43 @@ badframe:
#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
-static inline void rt_restore_fpu_state(struct ucontext *uc)
+static inline int rt_restore_fpu_state(struct ucontext *uc)
{
unsigned char fpstate[FPCONTEXT_SIZE];
int context_size = CPU_IS_060 ? 8 : 0;
fpregset_t fpregs;
+ int err = 1;
if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
- goto badframe;
+ goto out;
if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
if (!CPU_IS_060)
context_size = fpstate[1];
/* Verify the frame format. */
if (!CPU_IS_060 && (fpstate[0] != fpu_version))
- goto badframe;
+ goto out;
if (CPU_IS_020_OR_030) {
if (m68k_fputype & FPU_68881 &&
!(context_size == 0x18 || context_size == 0xb4))
- goto badframe;
+ goto out;
if (m68k_fputype & FPU_68882 &&
!(context_size == 0x38 || context_size == 0xd4))
- goto badframe;
+ goto out;
} else if (CPU_IS_040) {
if (!(context_size == 0x00 ||
context_size == 0x28 ||
context_size == 0x60))
- goto badframe;
+ goto out;
} else if (CPU_IS_060) {
if (!(fpstate[3] == 0x00 ||
fpstate[3] == 0x60 ||
fpstate[3] == 0xe0))
- goto badframe;
+ goto out;
} else
- goto badframe;
+ goto out;
if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
sizeof(fpregs)))
- goto badframe;
+ goto out;
__asm__ volatile (".chip 68k/68881\n\t"
"fmovemx %0,%/fp0-%/fp7\n\t"
"fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
@@ -271,21 +280,23 @@ static inline void rt_restore_fpu_state(struct ucontext *uc)
if (context_size &&
__copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
context_size))
- goto badframe;
+ goto out;
__asm__ volatile (".chip 68k/68881\n\t"
"frestore %0\n\t"
".chip 68k" : : "m" (*fpstate));
- return;
+ err = 0;
-badframe:
- do_exit(SIGSEGV);
+out:
+ return err;
}
static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
+ int *pd0)
{
int fsize, formatvec;
struct sigcontext context;
+ int err;
/* get previous context */
if (copy_from_user(&context, usc, sizeof(context)))
@@ -303,7 +314,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
regs->format = formatvec >> 12;
regs->vector = formatvec & 0xfff;
- restore_fpu_state(&context);
+ err = restore_fpu_state(&context);
fsize = frame_extra_sizes[regs->format];
if (fsize < 0) {
@@ -356,49 +367,55 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
goto badframe;
}
- return context.sc_d0;
+ *pd0 = context.sc_d0;
+ return err;
badframe:
- do_exit(SIGSEGV);
+ return 1;
}
static inline int
rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
- struct ucontext *uc)
+ struct ucontext *uc, int *pd0)
{
int fsize, temp;
greg_t *gregs = uc->uc_mcontext.gregs;
+ unsigned long usp;
+ int err;
- __get_user(temp, &uc->uc_mcontext.version);
+ err = __get_user(temp, &uc->uc_mcontext.version);
if (temp != MCONTEXT_VERSION)
goto badframe;
/* restore passed registers */
- __get_user(regs->d0, &gregs[0]);
- __get_user(regs->d1, &gregs[1]);
- __get_user(regs->d2, &gregs[2]);
- __get_user(regs->d3, &gregs[3]);
- __get_user(regs->d4, &gregs[4]);
- __get_user(regs->d5, &gregs[5]);
- __get_user(sw->d6, &gregs[6]);
- __get_user(sw->d7, &gregs[7]);
- __get_user(regs->a0, &gregs[8]);
- __get_user(regs->a1, &gregs[9]);
- __get_user(regs->a2, &gregs[10]);
- __get_user(sw->a3, &gregs[11]);
- __get_user(sw->a4, &gregs[12]);
- __get_user(sw->a5, &gregs[13]);
- __get_user(sw->a6, &gregs[14]);
- __get_user(temp, &gregs[15]);
- wrusp(temp);
- __get_user(regs->pc, &gregs[16]);
- __get_user(temp, &gregs[17]);
+ err |= __get_user(regs->d0, &gregs[0]);
+ err |= __get_user(regs->d1, &gregs[1]);
+ err |= __get_user(regs->d2, &gregs[2]);
+ err |= __get_user(regs->d3, &gregs[3]);
+ err |= __get_user(regs->d4, &gregs[4]);
+ err |= __get_user(regs->d5, &gregs[5]);
+ err |= __get_user(sw->d6, &gregs[6]);
+ err |= __get_user(sw->d7, &gregs[7]);
+ err |= __get_user(regs->a0, &gregs[8]);
+ err |= __get_user(regs->a1, &gregs[9]);
+ err |= __get_user(regs->a2, &gregs[10]);
+ err |= __get_user(sw->a3, &gregs[11]);
+ err |= __get_user(sw->a4, &gregs[12]);
+ err |= __get_user(sw->a5, &gregs[13]);
+ err |= __get_user(sw->a6, &gregs[14]);
+ err |= __get_user(usp, &gregs[15]);
+ wrusp(usp);
+ err |= __get_user(regs->pc, &gregs[16]);
+ err |= __get_user(temp, &gregs[17]);
regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
regs->orig_d0 = -1; /* disable syscall checks */
- __get_user(temp, &uc->uc_formatvec);
+ err |= __get_user(temp, &uc->uc_formatvec);
regs->format = temp >> 12;
regs->vector = temp & 0xfff;
- rt_restore_fpu_state(uc);
+ err |= rt_restore_fpu_state(uc);
+
+ if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
+ goto badframe;
fsize = frame_extra_sizes[regs->format];
if (fsize < 0) {
@@ -449,10 +466,11 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
goto badframe;
}
- return regs->d0;
+ *pd0 = regs->d0;
+ return err;
badframe:
- do_exit(SIGSEGV);
+ return 1;
}
asmlinkage int do_sigreturn(unsigned long __unused)
@@ -462,6 +480,7 @@ asmlinkage int do_sigreturn(unsigned long __unused)
unsigned long usp = rdusp();
struct sigframe *frame = (struct sigframe *)(usp - 24);
sigset_t set;
+ int d0;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -475,10 +494,13 @@ asmlinkage int do_sigreturn(unsigned long __unused)
current->blocked = set;
recalc_sigpending(current);
- return restore_sigcontext(regs, &frame->sc, frame + 1);
+ if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
+ goto badframe;
+ return d0;
badframe:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
+ return 0;
}
asmlinkage int do_rt_sigreturn(unsigned long __unused)
@@ -488,6 +510,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
unsigned long usp = rdusp();
struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
sigset_t set;
+ int d0;
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -498,10 +521,13 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
current->blocked = set;
recalc_sigpending(current);
- return rt_restore_ucontext(regs, sw, &frame->uc);
+ if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
+ goto badframe;
+ return d0;
badframe:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
+ return 0;
}
/*
@@ -535,17 +561,18 @@ static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
}
}
-static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
{
unsigned char fpstate[FPCONTEXT_SIZE];
int context_size = CPU_IS_060 ? 8 : 0;
+ int err = 0;
__asm__ volatile (".chip 68k/68881\n\t"
"fsave %0\n\t"
".chip 68k"
: : "m" (*fpstate) : "memory");
- __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
+ err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
fpregset_t fpregs;
if (!CPU_IS_060)
@@ -566,11 +593,13 @@ static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
: "m" (*fpregs.f_fpregs),
"m" (fpregs.f_pcr)
: "memory");
- copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs));
+ err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
+ sizeof(fpregs));
}
if (context_size)
- copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
- context_size);
+ err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
+ context_size);
+ return err;
}
static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
@@ -588,32 +617,34 @@ static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
save_fpu_state(sc, regs);
}
-static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
{
struct switch_stack *sw = (struct switch_stack *)regs - 1;
greg_t *gregs = uc->uc_mcontext.gregs;
-
- __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
- __put_user(regs->d0, &gregs[0]);
- __put_user(regs->d1, &gregs[1]);
- __put_user(regs->d2, &gregs[2]);
- __put_user(regs->d3, &gregs[3]);
- __put_user(regs->d4, &gregs[4]);
- __put_user(regs->d5, &gregs[5]);
- __put_user(sw->d6, &gregs[6]);
- __put_user(sw->d7, &gregs[7]);
- __put_user(regs->a0, &gregs[8]);
- __put_user(regs->a1, &gregs[9]);
- __put_user(regs->a2, &gregs[10]);
- __put_user(sw->a3, &gregs[11]);
- __put_user(sw->a4, &gregs[12]);
- __put_user(sw->a5, &gregs[13]);
- __put_user(sw->a6, &gregs[14]);
- __put_user(rdusp(), &gregs[15]);
- __put_user(regs->pc, &gregs[16]);
- __put_user(regs->sr, &gregs[17]);
- __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
- rt_save_fpu_state(uc, regs);
+ int err = 0;
+
+ err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+ err |= __put_user(regs->d0, &gregs[0]);
+ err |= __put_user(regs->d1, &gregs[1]);
+ err |= __put_user(regs->d2, &gregs[2]);
+ err |= __put_user(regs->d3, &gregs[3]);
+ err |= __put_user(regs->d4, &gregs[4]);
+ err |= __put_user(regs->d5, &gregs[5]);
+ err |= __put_user(sw->d6, &gregs[6]);
+ err |= __put_user(sw->d7, &gregs[7]);
+ err |= __put_user(regs->a0, &gregs[8]);
+ err |= __put_user(regs->a1, &gregs[9]);
+ err |= __put_user(regs->a2, &gregs[10]);
+ err |= __put_user(sw->a3, &gregs[11]);
+ err |= __put_user(sw->a4, &gregs[12]);
+ err |= __put_user(sw->a5, &gregs[13]);
+ err |= __put_user(sw->a6, &gregs[14]);
+ err |= __put_user(rdusp(), &gregs[15]);
+ err |= __put_user(regs->pc, &gregs[16]);
+ err |= __put_user(regs->sr, &gregs[17]);
+ err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+ err |= rt_save_fpu_state(uc, regs);
+ return err;
}
static inline void push_cache (unsigned long vaddr)
@@ -708,60 +739,72 @@ static inline void push_cache (unsigned long vaddr)
}
}
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+ unsigned long usp;
+
+ /* Default to using normal stack. */
+ usp = rdusp();
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (!on_sig_stack(usp))
+ usp = current->sas_ss_sp + current->sas_ss_size;
+ }
+ return (void *)((usp - frame_size) & -8UL);
+}
+
static void setup_frame (int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
struct sigframe *frame;
int fsize = frame_extra_sizes[regs->format];
struct sigcontext context;
+ int err = 0;
if (fsize < 0) {
#ifdef DEBUG
printk ("setup_frame: Unknown frame format %#x\n",
regs->format);
#endif
- goto segv_and_exit;
+ goto give_sigsegv;
}
- frame = (struct sigframe *)((rdusp() - sizeof(*frame) - fsize) & -8);
-
- if (!(current->flags & PF_ONSIGSTK) && (ka->sa.sa_flags & SA_ONSTACK)) {
- frame = (struct sigframe *)(((unsigned long)ka->sa.sa_restorer
- - sizeof(*frame) - fsize) & -8);
- current->flags |= PF_ONSIGSTK;
- }
+ frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
if (fsize) {
- if (copy_to_user (frame + 1, regs + 1, fsize))
- goto segv_and_exit;
+ err |= copy_to_user (frame + 1, regs + 1, fsize);
regs->stkadj = fsize;
}
- __put_user((current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : sig),
- &frame->sig);
+ err |= __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
- __put_user(regs->vector, &frame->code);
- __put_user(&frame->sc, &frame->psc);
+ err |= __put_user(regs->vector, &frame->code);
+ err |= __put_user(&frame->sc, &frame->psc);
if (_NSIG_WORDS > 1)
- copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
+ err |= copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
setup_sigcontext(&context, regs, set->sig[0]);
- if (copy_to_user (&frame->sc, &context, sizeof(context)))
- goto segv_and_exit;
+ err |= copy_to_user (&frame->sc, &context, sizeof(context));
/* Set up to return from userspace. */
- __put_user(frame->retcode, &frame->pretcode);
+ err |= __put_user(frame->retcode, &frame->pretcode);
/* addaw #20,sp */
- __put_user(0xdefc0014, (long *)(frame->retcode + 0));
+ err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0));
/* moveq #,d0; trap #0 */
- __put_user(0x70004e40 + (__NR_sigreturn << 16),
- (long *)(frame->retcode + 4));
+ err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
+ (long *)(frame->retcode + 4));
+
+ if (err)
+ goto give_sigsegv;
push_cache ((unsigned long) &frame->retcode);
@@ -791,8 +834,10 @@ static void setup_frame (int sig, struct k_sigaction *ka,
}
return;
-segv_and_exit:
- do_exit(SIGSEGV);
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
}
static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -800,48 +845,53 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
{
struct rt_sigframe *frame;
int fsize = frame_extra_sizes[regs->format];
+ int err = 0;
if (fsize < 0) {
#ifdef DEBUG
printk ("setup_frame: Unknown frame format %#x\n",
regs->format);
#endif
- goto segv_and_exit;
+ goto give_sigsegv;
}
- frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8);
-
- /* XXX: Check here if we need to switch stacks.. */
+ frame = get_sigframe(ka, regs, sizeof(*frame));
if (fsize) {
- if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize))
- goto segv_and_exit;
+ err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
regs->stkadj = fsize;
}
- __put_user((current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : sig),
- &frame->sig);
- __put_user(&frame->info, &frame->pinfo);
- __put_user(&frame->uc, &frame->puc);
- __copy_to_user(&frame->info, info, sizeof(*info));
-
- /* Clear all the bits of the ucontext we don't use. */
- clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
- rt_setup_ucontext(&frame->uc, regs);
- if (copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)))
- goto segv_and_exit;
+ err |= __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
+ err |= __put_user(&frame->info, &frame->pinfo);
+ err |= __put_user(&frame->uc, &frame->puc);
+ err |= __copy_to_user(&frame->info, info, sizeof(*info));
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user((void *)current->sas_ss_sp,
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(rdusp()),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= rt_setup_ucontext(&frame->uc, regs);
+ err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. */
- __put_user(frame->retcode, &frame->pretcode);
+ err |= __put_user(frame->retcode, &frame->pretcode);
/* movel #,d0; trap #0 */
- __put_user(0x203c, (short *)(frame->retcode + 0));
- __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
- __put_user(0x4e40, (short *)(frame->retcode + 6));
+ err |= __put_user(0x203c, (short *)(frame->retcode + 0));
+ err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
+ err |= __put_user(0x4e40, (short *)(frame->retcode + 6));
+
+ if (err)
+ goto give_sigsegv;
push_cache ((unsigned long) &frame->retcode);
@@ -871,8 +921,34 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
}
return;
-segv_and_exit:
- do_exit(SIGSEGV);
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+ switch (regs->d0) {
+ case -ERESTARTNOHAND:
+ if (!has_handler)
+ goto do_restart;
+ regs->d0 = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+ regs->d0 = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ do_restart:
+ regs->d0 = regs->orig_d0;
+ regs->pc -= 2;
+ break;
+ }
}
/*
@@ -883,24 +959,9 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
/* are we from a system call? */
- if (regs->orig_d0 >= 0) {
+ if (regs->orig_d0 >= 0)
/* If so, check system call restarting.. */
- switch (regs->d0) {
- case -ERESTARTNOHAND:
- regs->d0 = -EINTR;
- break;
-
- case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->d0 = -EINTR;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- regs->d0 = regs->orig_d0;
- regs->pc -= 2;
- }
- }
+ handle_restart(regs, ka, 1);
/* set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
@@ -952,13 +1013,14 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
/* Did we come from a system call? */
if (regs->orig_d0 >= 0) {
- /* Restart the system call */
- if (regs->d0 == -ERESTARTNOHAND ||
- regs->d0 == -ERESTARTSYS ||
- regs->d0 == -ERESTARTNOINTR) {
- regs->d0 = regs->orig_d0;
- regs->pc -= 2;
- }
+ /* Restart the system call the same way as
+ if the process were not traced. */
+ struct k_sigaction *ka =
+ &current->sig->action[signr-1];
+ int has_handler =
+ (ka->sa.sa_handler != SIG_IGN &&
+ ka->sa.sa_handler != SIG_DFL);
+ handle_restart(regs, ka, has_handler);
}
notify_parent(current, SIGCHLD);
schedule();
@@ -1052,15 +1114,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
}
/* Did we come from a system call? */
- if (regs->orig_d0 >= 0) {
+ if (regs->orig_d0 >= 0)
/* Restart the system call - no handlers present */
- if (regs->d0 == -ERESTARTNOHAND ||
- regs->d0 == -ERESTARTSYS ||
- regs->d0 == -ERESTARTNOINTR) {
- regs->d0 = regs->orig_d0;
- regs->pc -= 2;
- }
- }
+ handle_restart(regs, NULL, 0);
/* If we are about to discard some frame stuff we must copy
over the remaining frame. */
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 50d564134..75da52541 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -66,20 +66,25 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
struct file * file = NULL;
struct mmap_arg_struct a;
- lock_kernel();
- error = -EFAULT;
if (copy_from_user(&a, arg, sizeof(a)))
- goto out;
+ return -EFAULT;
+ down(&current->mm->mmap_sem);
+ lock_kernel();
if (!(a.flags & MAP_ANONYMOUS)) {
error = -EBADF;
- if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
+ file = fget(a.fd);
+ if (!file)
goto out;
}
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+ if (file)
+ fput(file);
out:
unlock_kernel();
+ up(&current->mm->mmap_sem);
return error;
}
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 51359f046..8f11a00d8 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -38,7 +38,7 @@ static inline void do_profile (unsigned long pc)
++prof_buffer[pc];
else
/*
- * Dont ignore out-of-bounds PC values silently,
+ * Don't ignore out-of-bounds PC values silently,
* put them into the last histogram slot, so if
* present, they will show up as a sharp peak.
*/