mn10300: add the MN10300/AM33 architecture to the kernel
David Howells [Fri, 8 Feb 2008 12:19:31 +0000 (04:19 -0800)]
Add architecture support for the MN10300/AM33 CPUs produced by MEI to the
kernel.

This patch also adds board support for the ASB2303 with the ASB2308 daughter
board, and the ASB2305.  The only processor supported is the MN103E010, which
is an AM33v2 core plus on-chip devices.

[akpm@linux-foundation.org: nuke cvs control strings]
Signed-off-by: Masakazu Urade <urade.masakazu@jp.panasonic.com>
Signed-off-by: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

234 files changed:
Documentation/mn10300/ABI.txt [new file with mode: 0644]
Documentation/mn10300/compartmentalisation.txt [new file with mode: 0644]
MAINTAINERS
arch/mn10300/Kconfig [new file with mode: 0644]
arch/mn10300/Kconfig.debug [new file with mode: 0644]
arch/mn10300/Makefile [new file with mode: 0644]
arch/mn10300/boot/.gitignore [new file with mode: 0644]
arch/mn10300/boot/Makefile [new file with mode: 0644]
arch/mn10300/boot/compressed/Makefile [new file with mode: 0644]
arch/mn10300/boot/compressed/head.S [new file with mode: 0644]
arch/mn10300/boot/compressed/misc.c [new file with mode: 0644]
arch/mn10300/boot/compressed/misc.h [new file with mode: 0644]
arch/mn10300/boot/compressed/vmlinux.lds [new file with mode: 0644]
arch/mn10300/boot/install.sh [new file with mode: 0644]
arch/mn10300/boot/tools/build.c [new file with mode: 0644]
arch/mn10300/configs/asb2303_defconfig [new file with mode: 0644]
arch/mn10300/kernel/Makefile [new file with mode: 0644]
arch/mn10300/kernel/asm-offsets.c [new file with mode: 0644]
arch/mn10300/kernel/entry.S [new file with mode: 0644]
arch/mn10300/kernel/fpu-low.S [new file with mode: 0644]
arch/mn10300/kernel/fpu.c [new file with mode: 0644]
arch/mn10300/kernel/gdb-cache.S [new file with mode: 0644]
arch/mn10300/kernel/gdb-io-serial-low.S [new file with mode: 0644]
arch/mn10300/kernel/gdb-io-serial.c [new file with mode: 0644]
arch/mn10300/kernel/gdb-io-ttysm-low.S [new file with mode: 0644]
arch/mn10300/kernel/gdb-io-ttysm.c [new file with mode: 0644]
arch/mn10300/kernel/gdb-low.S [new file with mode: 0644]
arch/mn10300/kernel/gdb-stub.c [new file with mode: 0644]
arch/mn10300/kernel/head.S [new file with mode: 0644]
arch/mn10300/kernel/init_task.c [new file with mode: 0644]
arch/mn10300/kernel/internal.h [new file with mode: 0644]
arch/mn10300/kernel/io.c [new file with mode: 0644]
arch/mn10300/kernel/irq.c [new file with mode: 0644]
arch/mn10300/kernel/kernel_execve.S [new file with mode: 0644]
arch/mn10300/kernel/kprobes.c [new file with mode: 0644]
arch/mn10300/kernel/kthread.S [new file with mode: 0644]
arch/mn10300/kernel/mn10300-debug.c [new file with mode: 0644]
arch/mn10300/kernel/mn10300-serial-low.S [new file with mode: 0644]
arch/mn10300/kernel/mn10300-serial.c [new file with mode: 0644]
arch/mn10300/kernel/mn10300-serial.h [new file with mode: 0644]
arch/mn10300/kernel/mn10300-watchdog-low.S [new file with mode: 0644]
arch/mn10300/kernel/mn10300-watchdog.c [new file with mode: 0644]
arch/mn10300/kernel/mn10300_ksyms.c [new file with mode: 0644]
arch/mn10300/kernel/module.c [new file with mode: 0644]
arch/mn10300/kernel/process.c [new file with mode: 0644]
arch/mn10300/kernel/profile-low.S [new file with mode: 0644]
arch/mn10300/kernel/profile.c [new file with mode: 0644]
arch/mn10300/kernel/ptrace.c [new file with mode: 0644]
arch/mn10300/kernel/rtc.c [new file with mode: 0644]
arch/mn10300/kernel/semaphore.c [new file with mode: 0644]
arch/mn10300/kernel/setup.c [new file with mode: 0644]
arch/mn10300/kernel/sigframe.h [new file with mode: 0644]
arch/mn10300/kernel/signal.c [new file with mode: 0644]
arch/mn10300/kernel/switch_to.S [new file with mode: 0644]
arch/mn10300/kernel/sys_mn10300.c [new file with mode: 0644]
arch/mn10300/kernel/time.c [new file with mode: 0644]
arch/mn10300/kernel/traps.c [new file with mode: 0644]
arch/mn10300/kernel/vmlinux.lds.S [new file with mode: 0644]
arch/mn10300/lib/Makefile [new file with mode: 0644]
arch/mn10300/lib/__ashldi3.S [new file with mode: 0644]
arch/mn10300/lib/__ashrdi3.S [new file with mode: 0644]
arch/mn10300/lib/__lshrdi3.S [new file with mode: 0644]
arch/mn10300/lib/ashrdi3.c [new file with mode: 0644]
arch/mn10300/lib/bitops.c [new file with mode: 0644]
arch/mn10300/lib/checksum.c [new file with mode: 0644]
arch/mn10300/lib/delay.c [new file with mode: 0644]
arch/mn10300/lib/do_csum.S [new file with mode: 0644]
arch/mn10300/lib/internal.h [new file with mode: 0644]
arch/mn10300/lib/lshrdi3.c [new file with mode: 0644]
arch/mn10300/lib/memcpy.S [new file with mode: 0644]
arch/mn10300/lib/memmove.S [new file with mode: 0644]
arch/mn10300/lib/memset.S [new file with mode: 0644]
arch/mn10300/lib/negdi2.c [new file with mode: 0644]
arch/mn10300/lib/usercopy.c [new file with mode: 0644]
arch/mn10300/mm/Makefile [new file with mode: 0644]
arch/mn10300/mm/cache-flush-mn10300.S [new file with mode: 0644]
arch/mn10300/mm/cache-mn10300.S [new file with mode: 0644]
arch/mn10300/mm/cache.c [new file with mode: 0644]
arch/mn10300/mm/dma-alloc.c [new file with mode: 0644]
arch/mn10300/mm/extable.c [new file with mode: 0644]
arch/mn10300/mm/fault.c [new file with mode: 0644]
arch/mn10300/mm/init.c [new file with mode: 0644]
arch/mn10300/mm/misalignment.c [new file with mode: 0644]
arch/mn10300/mm/mmu-context.c [new file with mode: 0644]
arch/mn10300/mm/pgtable.c [new file with mode: 0644]
arch/mn10300/mm/tlb-mn10300.S [new file with mode: 0644]
arch/mn10300/oprofile/Kconfig [new file with mode: 0644]
arch/mn10300/oprofile/Makefile [new file with mode: 0644]
arch/mn10300/oprofile/op_model_null.c [new file with mode: 0644]
arch/mn10300/proc-mn103e010/Makefile [new file with mode: 0644]
arch/mn10300/proc-mn103e010/proc-init.c [new file with mode: 0644]
arch/mn10300/unit-asb2303/Makefile [new file with mode: 0644]
arch/mn10300/unit-asb2303/leds.c [new file with mode: 0644]
arch/mn10300/unit-asb2303/smc91111.c [new file with mode: 0644]
arch/mn10300/unit-asb2303/unit-init.c [new file with mode: 0644]
arch/mn10300/unit-asb2305/Makefile [new file with mode: 0644]
arch/mn10300/unit-asb2305/leds.c [new file with mode: 0644]
arch/mn10300/unit-asb2305/pci-asb2305.c [new file with mode: 0644]
arch/mn10300/unit-asb2305/pci-asb2305.h [new file with mode: 0644]
arch/mn10300/unit-asb2305/pci-iomap.c [new file with mode: 0644]
arch/mn10300/unit-asb2305/pci-irq.c [new file with mode: 0644]
arch/mn10300/unit-asb2305/pci.c [new file with mode: 0644]
arch/mn10300/unit-asb2305/unit-init.c [new file with mode: 0644]
drivers/input/joystick/analog.c
drivers/net/Kconfig
drivers/net/smc91x.h
drivers/parport/Kconfig
drivers/pci/Makefile
drivers/video/console/Kconfig
include/asm-mn10300/.gitignore [new file with mode: 0644]
include/asm-mn10300/Kbuild [new file with mode: 0644]
include/asm-mn10300/atomic.h [new file with mode: 0644]
include/asm-mn10300/auxvec.h [new file with mode: 0644]
include/asm-mn10300/bitops.h [new file with mode: 0644]
include/asm-mn10300/bug.h [new file with mode: 0644]
include/asm-mn10300/bugs.h [new file with mode: 0644]
include/asm-mn10300/busctl-regs.h [new file with mode: 0644]
include/asm-mn10300/byteorder.h [new file with mode: 0644]
include/asm-mn10300/cache.h [new file with mode: 0644]
include/asm-mn10300/cacheflush.h [new file with mode: 0644]
include/asm-mn10300/checksum.h [new file with mode: 0644]
include/asm-mn10300/cpu-regs.h [new file with mode: 0644]
include/asm-mn10300/cputime.h [new file with mode: 0644]
include/asm-mn10300/current.h [new file with mode: 0644]
include/asm-mn10300/delay.h [new file with mode: 0644]
include/asm-mn10300/device.h [new file with mode: 0644]
include/asm-mn10300/div64.h [new file with mode: 0644]
include/asm-mn10300/dma-mapping.h [new file with mode: 0644]
include/asm-mn10300/dma.h [new file with mode: 0644]
include/asm-mn10300/dmactl-regs.h [new file with mode: 0644]
include/asm-mn10300/elf.h [new file with mode: 0644]
include/asm-mn10300/emergency-restart.h [new file with mode: 0644]
include/asm-mn10300/errno.h [new file with mode: 0644]
include/asm-mn10300/exceptions.h [new file with mode: 0644]
include/asm-mn10300/fb.h [new file with mode: 0644]
include/asm-mn10300/fcntl.h [new file with mode: 0644]
include/asm-mn10300/fpu.h [new file with mode: 0644]
include/asm-mn10300/frame.inc [new file with mode: 0644]
include/asm-mn10300/futex.h [new file with mode: 0644]
include/asm-mn10300/gdb-stub.h [new file with mode: 0644]
include/asm-mn10300/hardirq.h [new file with mode: 0644]
include/asm-mn10300/highmem.h [new file with mode: 0644]
include/asm-mn10300/hw_irq.h [new file with mode: 0644]
include/asm-mn10300/ide.h [new file with mode: 0644]
include/asm-mn10300/intctl-regs.h [new file with mode: 0644]
include/asm-mn10300/io.h [new file with mode: 0644]
include/asm-mn10300/ioctl.h [new file with mode: 0644]
include/asm-mn10300/ioctls.h [new file with mode: 0644]
include/asm-mn10300/ipc.h [new file with mode: 0644]
include/asm-mn10300/ipcbuf.h [new file with mode: 0644]
include/asm-mn10300/irq.h [new file with mode: 0644]
include/asm-mn10300/irq_regs.h [new file with mode: 0644]
include/asm-mn10300/kdebug.h [new file with mode: 0644]
include/asm-mn10300/kmap_types.h [new file with mode: 0644]
include/asm-mn10300/kprobes.h [new file with mode: 0644]
include/asm-mn10300/linkage.h [new file with mode: 0644]
include/asm-mn10300/local.h [new file with mode: 0644]
include/asm-mn10300/mc146818rtc.h [new file with mode: 0644]
include/asm-mn10300/mman.h [new file with mode: 0644]
include/asm-mn10300/mmu.h [new file with mode: 0644]
include/asm-mn10300/mmu_context.h [new file with mode: 0644]
include/asm-mn10300/module.h [new file with mode: 0644]
include/asm-mn10300/msgbuf.h [new file with mode: 0644]
include/asm-mn10300/mutex.h [new file with mode: 0644]
include/asm-mn10300/namei.h [new file with mode: 0644]
include/asm-mn10300/nmi.h [new file with mode: 0644]
include/asm-mn10300/page.h [new file with mode: 0644]
include/asm-mn10300/page_offset.h [new file with mode: 0644]
include/asm-mn10300/param.h [new file with mode: 0644]
include/asm-mn10300/pci.h [new file with mode: 0644]
include/asm-mn10300/percpu.h [new file with mode: 0644]
include/asm-mn10300/pgalloc.h [new file with mode: 0644]
include/asm-mn10300/pgtable.h [new file with mode: 0644]
include/asm-mn10300/pio-regs.h [new file with mode: 0644]
include/asm-mn10300/poll.h [new file with mode: 0644]
include/asm-mn10300/posix_types.h [new file with mode: 0644]
include/asm-mn10300/proc-mn103e010/cache.h [new file with mode: 0644]
include/asm-mn10300/proc-mn103e010/clock.h [new file with mode: 0644]
include/asm-mn10300/proc-mn103e010/irq.h [new file with mode: 0644]
include/asm-mn10300/proc-mn103e010/proc.h [new file with mode: 0644]
include/asm-mn10300/processor.h [new file with mode: 0644]
include/asm-mn10300/ptrace.h [new file with mode: 0644]
include/asm-mn10300/reset-regs.h [new file with mode: 0644]
include/asm-mn10300/resource.h [new file with mode: 0644]
include/asm-mn10300/rtc-regs.h [new file with mode: 0644]
include/asm-mn10300/rtc.h [new file with mode: 0644]
include/asm-mn10300/scatterlist.h [new file with mode: 0644]
include/asm-mn10300/sections.h [new file with mode: 0644]
include/asm-mn10300/semaphore.h [new file with mode: 0644]
include/asm-mn10300/sembuf.h [new file with mode: 0644]
include/asm-mn10300/serial-regs.h [new file with mode: 0644]
include/asm-mn10300/serial.h [new file with mode: 0644]
include/asm-mn10300/setup.h [new file with mode: 0644]
include/asm-mn10300/shmbuf.h [new file with mode: 0644]
include/asm-mn10300/shmparam.h [new file with mode: 0644]
include/asm-mn10300/sigcontext.h [new file with mode: 0644]
include/asm-mn10300/siginfo.h [new file with mode: 0644]
include/asm-mn10300/signal.h [new file with mode: 0644]
include/asm-mn10300/smp.h [new file with mode: 0644]
include/asm-mn10300/socket.h [new file with mode: 0644]
include/asm-mn10300/sockios.h [new file with mode: 0644]
include/asm-mn10300/spinlock.h [new file with mode: 0644]
include/asm-mn10300/stat.h [new file with mode: 0644]
include/asm-mn10300/statfs.h [new file with mode: 0644]
include/asm-mn10300/string.h [new file with mode: 0644]
include/asm-mn10300/system.h [new file with mode: 0644]
include/asm-mn10300/termbits.h [new file with mode: 0644]
include/asm-mn10300/termios.h [new file with mode: 0644]
include/asm-mn10300/thread_info.h [new file with mode: 0644]
include/asm-mn10300/timer-regs.h [new file with mode: 0644]
include/asm-mn10300/timex.h [new file with mode: 0644]
include/asm-mn10300/tlb.h [new file with mode: 0644]
include/asm-mn10300/tlbflush.h [new file with mode: 0644]
include/asm-mn10300/topology.h [new file with mode: 0644]
include/asm-mn10300/types.h [new file with mode: 0644]
include/asm-mn10300/uaccess.h [new file with mode: 0644]
include/asm-mn10300/ucontext.h [new file with mode: 0644]
include/asm-mn10300/unaligned.h [new file with mode: 0644]
include/asm-mn10300/unistd.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2303/clock.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2303/leds.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2303/serial.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2303/smc91111.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2303/timex.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2305/clock.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2305/leds.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2305/serial.h [new file with mode: 0644]
include/asm-mn10300/unit-asb2305/timex.h [new file with mode: 0644]
include/asm-mn10300/user.h [new file with mode: 0644]
include/asm-mn10300/vga.h [new file with mode: 0644]
include/asm-mn10300/xor.h [new file with mode: 0644]
include/linux/elf-em.h
include/linux/kernel.h
lib/Kconfig.debug

diff --git a/Documentation/mn10300/ABI.txt b/Documentation/mn10300/ABI.txt
new file mode 100644 (file)
index 0000000..1fef1f0
--- /dev/null
@@ -0,0 +1,149 @@
+                          =========================
+                          MN10300 FUNCTION CALL ABI
+                          =========================
+
+=======
+GENERAL
+=======
+
+The MN10300/AM33 kernel runs in little-endian mode; big-endian mode is not
+supported.
+
+The stack grows downwards, and should always be 32-bit aligned. There are
+separate stack pointer registers for userspace and the kernel.
+
+
+================
+ARGUMENT PASSING
+================
+
+The first two arguments (assuming up to 32-bits per argument) to a function are
+passed in the D0 and D1 registers respectively; all other arguments are passed
+on the stack.
+
+If 64-bit arguments are being passed, then they are never split between
+registers and the stack. If the first argument is a 64-bit value, it will be
+passed in D0:D1. If the first argument is not a 64-bit value, but the second
+is, the second will be passed entirely on the stack and D1 will be unused.
+
+Arguments smaller than 32-bits are not coelesced within a register or a stack
+word. For example, two byte-sized arguments will always be passed in separate
+registers or word-sized stack slots.
+
+
+=================
+CALLING FUNCTIONS
+=================
+
+The caller must allocate twelve bytes on the stack for the callee's use before
+it inserts a CALL instruction. The CALL instruction will write into the TOS
+word, but won't actually modify the stack pointer; similarly, the RET
+instruction reads from the TOS word of the stack, but doesn't move the stack
+pointer beyond it.
+
+
+       Stack:
+       |               |
+       |               |
+       |---------------| SP+20
+       | 4th Arg       |
+       |---------------| SP+16
+       | 3rd Arg       |
+       |---------------| SP+12
+       | D1 Save Slot  |
+       |---------------| SP+8
+       | D0 Save Slot  |
+       |---------------| SP+4
+       | Return Addr   |
+       |---------------| SP
+       |               |
+       |               |
+
+
+The caller must leave space on the stack (hence an allocation of twelve bytes)
+in which the callee may store the first two arguments.
+
+
+============
+RETURN VALUE
+============
+
+The return value is passed in D0 for an integer (or D0:D1 for a 64-bit value),
+or A0 for a pointer.
+
+If the return value is a value larger than 64-bits, or is a structure or an
+array, then a hidden first argument will be passed to the callee by the caller:
+this will point to a piece of memory large enough to hold the result of the
+function. In this case, the callee will return the value in that piece of
+memory, and no value will be returned in D0 or A0.
+
+
+===================
+REGISTER CLOBBERING
+===================
+
+The values in certain registers may be clobbered by the callee, and other
+values must be saved:
+
+       Clobber:        D0-D1, A0-A1, E0-E3
+       Save:           D2-D3, A2-A3, E4-E7, SP
+
+All other non-supervisor-only registers are clobberable (such as MDR, MCRL,
+MCRH).
+
+
+=================
+SPECIAL REGISTERS
+=================
+
+Certain ordinary registers may carry special usage for the compiler:
+
+       A3:     Frame pointer
+       E2:     TLS pointer
+
+
+==========
+KERNEL ABI
+==========
+
+The kernel may use a slightly different ABI internally.
+
+ (*) E2
+
+     If CONFIG_MN10300_CURRENT_IN_E2 is defined, then the current task pointer
+     will be kept in the E2 register, and that register will be marked
+     unavailable for the compiler to use as a scratch register.
+
+     Normally the kernel uses something like:
+
+       MOV     SP,An
+       AND     0xFFFFE000,An
+       MOV     (An),Rm         // Rm holds current
+       MOV     (yyy,Rm)        // Access current->yyy
+
+     To find the address of current; but since this option permits current to
+     be carried globally in an register, it can use:
+
+       MOV     (yyy,E2)        // Access current->yyy
+
+     instead.
+
+
+===============
+SYSTEM CALL ABI
+===============
+
+System calls are called with the following convention:
+
+       REGISTER        ENTRY                   EXIT
+       =============== ======================= =======================
+       D0              Syscall number          Return value
+       A0              1st syscall argument    Saved
+       D1              2nd syscall argument    Saved
+       A3              3rd syscall argument    Saved
+       A2              4th syscall argument    Saved
+       D3              5th syscall argument    Saved
+       D2              6th syscall argument    Saved
+
+All other registers are saved.  The layout is a consequence of the way the MOVM
+instruction stores registers onto the stack.
diff --git a/Documentation/mn10300/compartmentalisation.txt b/Documentation/mn10300/compartmentalisation.txt
new file mode 100644 (file)
index 0000000..8958b51
--- /dev/null
@@ -0,0 +1,60 @@
+                  =========================================
+                  PART-SPECIFIC SOURCE COMPARTMENTALISATION
+                  =========================================
+
+The sources for various parts are compartmentalised at two different levels:
+
+ (1) Processor level
+
+     The "processor level" is a CPU core plus the other on-silicon
+     peripherals.
+
+     Processor-specific header files are divided among directories in a similar
+     way to the CPU level:
+
+       (*) include/asm-mn10300/proc-mn103e010/
+
+           Support for the AM33v2 CPU core.
+
+     The appropriate processor is selected by a CONFIG_MN10300_PROC_YYYY option
+     from the "Processor support" choice menu in the arch/mn10300/Kconfig file.
+
+
+ (2) Unit level
+
+     The "unit level" is a processor plus all the external peripherals
+     controlled by that processor.
+
+     Unit-specific header files are divided among directories in a similar way
+     to the CPU level; not only that, but specific sources may also be
+     segregated into separate directories under the arch directory:
+
+       (*) include/asm-mn10300/unit-asb2303/
+       (*) arch/mn10300/unit-asb2303/
+
+           Support for the ASB2303 board with an ASB2308 daughter board.
+
+       (*) include/asm-mn10300/unit-asb2305/
+       (*) arch/mn10300/unit-asb2305/
+
+           Support for the ASB2305 board.
+
+     The appropriate processor is selected by a CONFIG_MN10300_UNIT_ZZZZ option
+     from the "Unit type" choice menu in the arch/mn10300/Kconfig file.
+
+
+============
+COMPILE TIME
+============
+
+When the kernel is compiled, symbolic links will be made in the asm header file
+directory for this arch:
+
+       include/asm-mn10300/proc => include/asm-mn10300/proc-YYYY/
+       include/asm-mn10300/unit => include/asm-mn10300/unit-ZZZZ/
+
+So that the header files contained in those directories can be accessed without
+lots of #ifdef-age.
+
+The appropriate arch/mn10300/unit-ZZZZ directory will also be entered by the
+compilation process; all other unit-specific directories will be ignored.
index 2cdb591..a7e6ef3 100644 (file)
@@ -2614,6 +2614,15 @@ L:       linux-kernel@vger.kernel.org
 W:     http://www.linux-mm.org
 S:     Maintained
 
+MEI MN10300/AM33 PORT
+P:     David Howells
+M:     dhowells@redhat.com
+P:     Koichi Yasutake
+M:     yasutake.koichi@jp.panasonic.com
+L:     linux-am33-list@redhat.com
+W:     ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
+S:     Maintained
+
 MEMORY TECHNOLOGY DEVICES (MTD)
 P:     David Woodhouse
 M:     dwmw2@infradead.org
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
new file mode 100644 (file)
index 0000000..eedc3a5
--- /dev/null
@@ -0,0 +1,381 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+mainmenu "Linux Kernel Configuration"
+
+config MN10300
+       def_bool y
+
+config AM33
+       def_bool y
+
+config MMU
+       def_bool y
+
+config HIGHMEM
+       def_bool n
+
+config NUMA
+       def_bool n
+
+config UID16
+       def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+       def_bool y
+
+config RWSEM_XCHGADD_ALGORITHM
+       bool
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       def_bool y
+
+config GENERIC_CALIBRATE_DELAY
+       def_bool y
+
+config GENERIC_FIND_NEXT_BIT
+       def_bool y
+
+config GENERIC_HWEIGHT
+       def_bool y
+
+config GENERIC_TIME
+       def_bool y
+
+config GENERIC_BUG
+       def_bool y
+
+config QUICKLIST
+       def_bool y
+
+config ARCH_HAS_ILOG2_U32
+       def_bool y
+
+config ARCH_SUPPORTS_AOUT
+       def_bool n
+
+# Use the generic interrupt handling code in kernel/irq/
+config GENERIC_HARDIRQS
+       def_bool y
+
+config HOTPLUG_CPU
+       def_bool n
+
+mainmenu "Matsushita MN10300/AM33 Kernel Configuration"
+
+source "init/Kconfig"
+
+
+menu "Matsushita MN10300 system setup"
+
+choice
+       prompt "Unit type"
+       default MN10300_UNIT_ASB2303
+       help
+         This option specifies board for which the kernel will be
+         compiled. It affects the external peripherals catered for.
+
+config MN10300_UNIT_ASB2303
+       bool "ASB2303"
+
+config MN10300_UNIT_ASB2305
+       bool "ASB2305"
+
+endchoice
+
+choice
+       prompt "Processor support"
+       default MN10300_PROC_MN103E010
+       help
+         This option specifies the processor for which the kernel will be
+         compiled. It affects the on-chip peripherals catered for.
+
+config MN10300_PROC_MN103E010
+       bool "MN103E010"
+       depends on MN10300_UNIT_ASB2303 || MN10300_UNIT_ASB2305
+       select MN10300_PROC_HAS_TTYSM0
+       select MN10300_PROC_HAS_TTYSM1
+       select MN10300_PROC_HAS_TTYSM2
+
+endchoice
+
+choice
+       prompt "Processor core support"
+       default MN10300_CPU_AM33V2
+       help
+         This option specifies the processor core for which the kernel will be
+         compiled. It affects the instruction set used.
+
+config MN10300_CPU_AM33V2
+       bool "AM33v2"
+
+endchoice
+
+config FPU
+       bool "FPU present"
+       default y
+       depends on MN10300_PROC_MN103E010
+
+choice
+       prompt "CPU Caching mode"
+       default MN10300_CACHE_WBACK
+       help
+         This option determines the caching mode for the kernel.
+
+         Write-Back caching mode involves the all reads and writes causing
+         the affected cacheline to be read into the cache first before being
+         operated upon. Memory is not then updated by a write until the cache
+         is filled and a cacheline needs to be displaced from the cache to
+         make room. Only at that point is it written back.
+
+         Write-Through caching only fetches cachelines from memory on a
+         read. Writes always get written directly to memory. If the affected
+         cacheline is also in cache, it will be updated too.
+
+         The final option is to turn of caching entirely.
+
+config MN10300_CACHE_WBACK
+       bool "Write-Back"
+
+config MN10300_CACHE_WTHRU
+       bool "Write-Through"
+
+config MN10300_CACHE_DISABLED
+       bool "Disabled"
+
+endchoice
+
+menu "Memory layout options"
+
+config KERNEL_RAM_BASE_ADDRESS
+       hex "Base address of kernel RAM"
+       default "0x90000000"
+
+config INTERRUPT_VECTOR_BASE
+       hex "Base address of vector table"
+       default "0x90000000"
+       help
+         The base address of the vector table will be programmed into
+          the TBR register. It must be on 16MiB address boundary.
+
+config KERNEL_TEXT_ADDRESS
+       hex "Base address of kernel"
+       default "0x90001000"
+
+config KERNEL_ZIMAGE_BASE_ADDRESS
+       hex "Base address of compressed vmlinux image"
+       default "0x90700000"
+
+endmenu
+
+config PREEMPT
+       bool "Preemptible Kernel"
+       help
+         This option reduces the latency of the kernel when reacting to
+         real-time or interactive events by allowing a low priority process to
+         be preempted even if it is in kernel mode executing a system call.
+         This allows applications to run more reliably even when the system is
+         under load.
+
+         Say Y here if you are building a kernel for a desktop, embedded
+         or real-time system.  Say N if you are unsure.
+
+config PREEMPT_BKL
+       bool "Preempt The Big Kernel Lock"
+       depends on PREEMPT
+       default y
+       help
+         This option reduces the latency of the kernel by making the
+         big kernel lock preemptible.
+
+         Say Y here if you are building a kernel for a desktop system.
+         Say N if you are unsure.
+
+config MN10300_CURRENT_IN_E2
+       bool "Hold current task address in E2 register"
+       default y
+       help
+         This option removes the E2/R2 register from the set available to gcc
+         for normal use and instead uses it to store the address of the
+         current process's task_struct whilst in the kernel.
+
+         This means the kernel doesn't need to calculate the address each time
+         "current" is used (take SP, AND with mask and dereference pointer
+         just to get the address), and instead can just use E2+offset
+         addressing each time.
+
+         This has no effect on userspace.
+
+config MN10300_USING_JTAG
+       bool "Using JTAG to debug kernel"
+       default y
+       help
+         This options indicates that JTAG will be used to debug the kernel. It
+         suppresses the use of certain hardware debugging features, such as
+         single-stepping, which are taken over completely by the JTAG unit.
+
+config MN10300_RTC
+       bool "Using MN10300 RTC"
+       depends on MN10300_PROC_MN103E010
+       default n
+       help
+
+         This option enables support for the RTC, thus enabling time to be
+         tracked, even when system is powered down. This is available on-chip
+         on the MN103E010.
+
+config MN10300_WD_TIMER
+       bool "Using MN10300 watchdog timer"
+       default y
+       help
+         This options indicates that the watchdog timer will be used.
+
+config PCI
+       bool "Use PCI"
+       depends on MN10300_UNIT_ASB2305
+       default y
+       help
+         Some systems (such as the ASB2305) have PCI onboard. If you have one
+         of these boards and you wish to use the PCI facilities, say Y here.
+
+         The PCI-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>, contains valuable
+         information about which PCI hardware does work under Linux and which
+         doesn't.
+
+source "drivers/pci/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+menu "MN10300 internal serial options"
+
+config MN10300_PROC_HAS_TTYSM0
+       bool
+       default n
+
+config MN10300_PROC_HAS_TTYSM1
+       bool
+       default n
+
+config MN10300_PROC_HAS_TTYSM2
+       bool
+       default n
+
+config MN10300_TTYSM
+       bool "Support for ttySM serial ports"
+       depends on MN10300
+       default y
+       select SERIAL_CORE
+       help
+         This option enables support for the on-chip serial ports that the
+         MN10300 has available.
+
+config MN10300_TTYSM_CONSOLE
+       bool "Support for console on ttySM serial ports"
+       depends on MN10300_TTYSM
+       select SERIAL_CORE_CONSOLE
+       help
+         This option enables support for a console on the on-chip serial ports
+         that the MN10300 has available.
+
+#
+# /dev/ttySM0
+#
+config MN10300_TTYSM0
+       bool "Enable SIF0 (/dev/ttySM0)"
+       depends on MN10300_TTYSM && MN10300_PROC_HAS_TTYSM0
+       help
+         Enable access to SIF0 through /dev/ttySM0 or gdb-stub
+
+choice
+       prompt "Select the timer to supply the clock for SIF0"
+       default MN10300_TTYSM0_TIMER8
+       depends on MN10300_TTYSM0
+
+config MN10300_TTYSM0_TIMER8
+       bool "Use timer 8 (16-bit)"
+
+config MN10300_TTYSM0_TIMER2
+       bool "Use timer 2 (8-bit)"
+
+endchoice
+
+#
+# /dev/ttySM1
+#
+config MN10300_TTYSM1
+       bool "Enable SIF1 (/dev/ttySM1)"
+       depends on MN10300_TTYSM && MN10300_PROC_HAS_TTYSM1
+       help
+         Enable access to SIF1 through /dev/ttySM1 or gdb-stub
+
+choice
+       prompt "Select the timer to supply the clock for SIF1"
+       default MN10300_TTYSM0_TIMER9
+       depends on MN10300_TTYSM1
+
+config MN10300_TTYSM1_TIMER9
+       bool "Use timer 9 (16-bit)"
+
+config MN10300_TTYSM1_TIMER3
+       bool "Use timer 3 (8-bit)"
+
+endchoice
+
+#
+# /dev/ttySM2
+#
+config MN10300_TTYSM2
+       bool "Enable SIF2 (/dev/ttySM2)"
+       depends on MN10300_TTYSM && MN10300_PROC_HAS_TTYSM2
+       help
+         Enable access to SIF2 through /dev/ttySM2 or gdb-stub
+
+choice
+       prompt "Select the timer to supply the clock for SIF2"
+       default MN10300_TTYSM0_TIMER10
+       depends on MN10300_TTYSM2
+
+config MN10300_TTYSM2_TIMER10
+       bool "Use timer 10 (16-bit)"
+
+endchoice
+
+config MN10300_TTYSM2_CTS
+       bool "Enable the use of the CTS line /dev/ttySM2"
+       depends on MN10300_TTYSM2
+
+endmenu
+
+source "mm/Kconfig"
+
+menu "Power management options"
+source kernel/power/Kconfig
+endmenu
+
+endmenu
+
+
+menu "Executable formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/mn10300/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+source "arch/mn10300/oprofile/Kconfig"
diff --git a/arch/mn10300/Kconfig.debug b/arch/mn10300/Kconfig.debug
new file mode 100644 (file)
index 0000000..524e338
--- /dev/null
@@ -0,0 +1,135 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+
+config DEBUG_DECOMPRESS_KERNEL
+       bool "Using serial port during decompressing kernel"
+       depends on DEBUG_KERNEL
+       default n
+       help
+         If you say Y here you will confirm the start and the end of
+         decompressing Linux seeing "Uncompressing Linux... " and
+         "Ok, booting the kernel.\n" on console.
+
+config KPROBES
+       bool "Kprobes"
+       depends on DEBUG_KERNEL
+       help
+         Kprobes allows you to trap at almost any kernel address and
+         execute a callback function.  register_kprobe() establishes
+         a probepoint and specifies the callback.  Kprobes is useful
+         for kernel debugging, non-intrusive instrumentation and testing.
+         If in doubt, say "N".
+
+config GDBSTUB
+       bool "Remote GDB kernel debugging"
+       depends on DEBUG_KERNEL
+       select DEBUG_INFO
+       select FRAME_POINTER
+       help
+         If you say Y here, it will be possible to remotely debug the kernel
+         using gdb. This enlarges your kernel ELF image disk size by several
+         megabytes and requires a machine with more than 16 MB, better 32 MB
+         RAM to avoid excessive linking time. This is only useful for kernel
+         hackers. If unsure, say N.
+
+config GDBSTUB_IMMEDIATE
+       bool "Break into GDB stub immediately"
+       depends on GDBSTUB
+       help
+         If you say Y here, GDB stub will break into the program as soon as
+         possible, leaving the program counter at the beginning of
+         start_kernel() in init/main.c.
+
+config GDB_CONSOLE
+       bool "Console output to GDB"
+       depends on GDBSTUB
+       help
+         If you are using GDB for remote debugging over a serial port and
+         would like kernel messages to be formatted into GDB $O packets so
+         that GDB prints them as program output, say 'Y'.
+
+config GDBSTUB_DEBUGGING
+       bool "Debug GDB stub by messages to serial port"
+       depends on GDBSTUB
+       help
+         This causes debugging messages to be displayed at various points
+         during execution of the GDB stub routines. Such messages will be
+         displayed on ttyS0 if that isn't the GDB stub's port, or ttySM0
+         otherwise.
+
+config GDBSTUB_DEBUG_ENTRY
+       bool "Debug GDB stub entry"
+       depends on GDBSTUB_DEBUGGING
+       help
+         This option causes information to be displayed about entry to or exit
+         from the main GDB stub routine.
+
+config GDBSTUB_DEBUG_PROTOCOL
+       bool "Debug GDB stub protocol"
+       depends on GDBSTUB_DEBUGGING
+       help
+         This option causes information to be displayed about the GDB remote
+         protocol messages generated exchanged with GDB.
+
+config GDBSTUB_DEBUG_IO
+       bool "Debug GDB stub I/O"
+       depends on GDBSTUB_DEBUGGING
+       help
+         This option causes information to be displayed about GDB stub's
+         low-level I/O.
+
+config GDBSTUB_DEBUG_BREAKPOINT
+       bool "Debug GDB stub breakpoint management"
+       depends on GDBSTUB_DEBUGGING
+       help
+         This option causes information to be displayed about GDB stub's
+         breakpoint management.
+
+choice
+       prompt "GDB stub port"
+       default GDBSTUB_TTYSM0
+       depends on GDBSTUB
+       help
+         Select the serial port used for GDB-stub.
+
+config GDBSTUB_ON_TTYSM0
+       bool "/dev/ttySM0 [SIF0]"
+       depends on MN10300_TTYSM0
+       select GDBSTUB_ON_TTYSMx
+
+config GDBSTUB_ON_TTYSM1
+       bool "/dev/ttySM1 [SIF1]"
+       depends on MN10300_TTYSM1
+       select GDBSTUB_ON_TTYSMx
+
+config GDBSTUB_ON_TTYSM2
+       bool "/dev/ttySM2 [SIF2]"
+       depends on MN10300_TTYSM2
+       select GDBSTUB_ON_TTYSMx
+
+config GDBSTUB_ON_TTYS0
+       bool "/dev/ttyS0"
+       select GDBSTUB_ON_TTYSx
+
+config GDBSTUB_ON_TTYS1
+       bool "/dev/ttyS1"
+       select GDBSTUB_ON_TTYSx
+
+endchoice
+
+config GDBSTUB_ON_TTYSMx
+       bool
+       depends on GDBSTUB_ON_TTYSM0 || GDBSTUB_ON_TTYSM1 || GDBSTUB_ON_TTYSM2
+       default y
+
+config GDBSTUB_ON_TTYSx
+       bool
+       depends on GDBSTUB_ON_TTYS0 || GDBSTUB_ON_TTYS1
+       default y
+
+endmenu
diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile
new file mode 100644 (file)
index 0000000..6673a28
--- /dev/null
@@ -0,0 +1,135 @@
+###############################################################################
+#
+# MN10300 Kernel makefile system specifications
+#
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Modified by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+
+KBUILD_DEFCONFIG := asb2303_defconfig
+
+CCSPECS        := $(shell $(CC) -v 2>&1 | grep "^Reading specs from " | head -1 | cut -c20-)
+CCDIR  := $(strip $(patsubst %/specs,%,$(CCSPECS)))
+KBUILD_CPPFLAGS += -nostdinc -I$(CCDIR)/include
+
+LDFLAGS                :=
+OBJCOPYFLAGS   := -O binary -R .note -R .comment -S
+#LDFLAGS_vmlinux := -Map linkmap.txt
+CHECKFLAGS     +=
+
+PROCESSOR      := unset
+UNIT           := unset
+
+KBUILD_CFLAGS  += -mam33 -mmem-funcs -DCPU=AM33
+KBUILD_AFLAGS  += -mam33 -DCPU=AM33
+
+ifeq ($(CONFIG_MN10300_CURRENT_IN_E2),y)
+KBUILD_CFLAGS  += -ffixed-e2 -fcall-saved-e5
+endif
+
+ifeq ($(CONFIG_MN10300_PROC_MN103E010),y)
+PROCESSOR      := mn103e010
+endif
+
+ifeq ($(CONFIG_MN10300_UNIT_ASB2303),y)
+UNIT           := asb2303
+endif
+ifeq ($(CONFIG_MN10300_UNIT_ASB2305),y)
+UNIT           := asb2305
+endif
+
+
+head-y         := arch/mn10300/kernel/head.o arch/mn10300/kernel/init_task.o
+
+core-y         += arch/mn10300/kernel/ arch/mn10300/mm/
+
+ifneq ($(PROCESSOR),unset)
+core-y         += arch/mn10300/proc-$(PROCESSOR)/
+endif
+ifneq ($(UNIT),unset)
+core-y         += arch/mn10300/unit-$(UNIT)/
+endif
+libs-y         += arch/mn10300/lib/
+
+drivers-$(CONFIG_OPROFILE)     += arch/mn10300/oprofile/
+
+boot := arch/mn10300/boot
+
+.PHONY: zImage
+
+KBUILD_IMAGE := $(boot)/zImage
+CLEAN_FILES += $(boot)/zImage
+CLEAN_FILES += $(boot)/compressed/vmlinux
+CLEAN_FILES += $(boot)/compressed/vmlinux.bin
+CLEAN_FILES += $(boot)/compressed/vmlinux.bin.gz
+
+zImage: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+all: zImage
+
+bootstrap:
+       $(Q)$(MAKEBOOT) bootstrap
+
+archclean:
+       $(Q)$(MAKE) $(clean)=arch/mn10300/proc-mn103e010
+       $(Q)$(MAKE) $(clean)=arch/mn10300/unit-asb2303
+       $(Q)$(MAKE) $(clean)=arch/mn10300/unit-asb2305
+
+define archhelp
+  echo  '* zImage        - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
+endef
+
+# If you make sure the .S files get compiled with debug info,
+# uncomment the following to disable optimisations
+# that are unhelpful whilst debugging.
+ifdef CONFIG_DEBUG_INFO
+#KBUILD_CFLAGS += -O1
+KBUILD_AFLAGS  += -Wa,--gdwarf2
+endif
+
+###################################################################################################
+#
+# juggle some symlinks in the MN10300 asm include dir
+#
+#      Update machine proc and unit symlinks if something which affects
+#      them changed.  We use .proc / .unit to indicate when they were
+#      updated last, otherwise make uses the target directory mtime.
+#
+###################################################################################################
+
+# processor specific definitions
+include/asm-mn10300/.proc: $(wildcard include/config/proc/*.h) include/config/auto.conf
+       @echo '  SYMLINK include/asm-mn10300/proc -> include/asm-mn10300/proc-$(PROCESSOR)'
+ifneq ($(KBUILD_SRC),)
+       $(Q)mkdir -p include/asm-mn10300
+       $(Q)ln -fsn $(srctree)/include/asm-mn10300/proc-$(PROCESSOR) include/asm-mn10300/proc
+else
+       $(Q)ln -fsn proc-$(PROCESSOR) include/asm-mn10300/proc
+endif
+       @touch $@
+
+CLEAN_FILES += include/asm-mn10300/proc include/asm-mn10300/.proc
+
+prepare: include/asm-mn10300/.proc
+
+# unit specific definitions
+include/asm-mn10300/.unit: $(wildcard include/config/unit/*.h) include/config/auto.conf
+       @echo '  SYMLINK include/asm-mn10300/unit -> include/asm-mn10300/unit-$(UNIT)'
+ifneq ($(KBUILD_SRC),)
+       $(Q)mkdir -p include/asm-mn10300
+       $(Q)ln -fsn $(srctree)/include/asm-mn10300/unit-$(UNIT) include/asm-mn10300/unit
+else
+       $(Q)ln -fsn unit-$(UNIT) include/asm-mn10300/unit
+endif
+       @touch $@
+
+CLEAN_FILES += include/asm-mn10300/unit include/asm-mn10300/.unit
+
+prepare: include/asm-mn10300/.unit
diff --git a/arch/mn10300/boot/.gitignore b/arch/mn10300/boot/.gitignore
new file mode 100644 (file)
index 0000000..b6718de
--- /dev/null
@@ -0,0 +1 @@
+zImage
diff --git a/arch/mn10300/boot/Makefile b/arch/mn10300/boot/Makefile
new file mode 100644 (file)
index 0000000..36c9caf
--- /dev/null
@@ -0,0 +1,28 @@
+# MN10300 kernel compressor and wrapper
+#
+# Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+
+targets                := vmlinux.bin zImage
+
+subdir-        := compressed
+
+# ---------------------------------------------------------------------------
+
+
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+       $(call if_changed,objcopy)
+       @echo 'Kernel: $@ is ready'
+
+$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
+       $(call if_changed,objcopy)
+
+$(obj)/compressed/vmlinux: FORCE
+       $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
diff --git a/arch/mn10300/boot/compressed/Makefile b/arch/mn10300/boot/compressed/Makefile
new file mode 100644 (file)
index 0000000..08a95e1
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Create a compressed vmlinux image from the original vmlinux
+#
+
+targets                := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+
+LDFLAGS_vmlinux := -Ttext $(CONFIG_KERNEL_ZIMAGE_BASE_ADDRESS) -e startup_32
+
+$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
+       $(call if_changed,ld)
+       @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-am33lin -T
+
+$(obj)/piggy.o: $(obj)/vmlinux.lds $(obj)/vmlinux.bin.gz FORCE
+       $(call if_changed,ld)
diff --git a/arch/mn10300/boot/compressed/head.S b/arch/mn10300/boot/compressed/head.S
new file mode 100644 (file)
index 0000000..502e1eb
--- /dev/null
@@ -0,0 +1,86 @@
+/* Boot entry point for a compressed MN10300 kernel
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+       .section        .text
+
+#define DEBUG
+
+#include <linux/linkage.h>
+#include <asm/cpu-regs.h>
+
+       .globl startup_32
+startup_32:
+       # first save off parameters from bootloader
+       mov     param_save_area,a0
+       mov     d0,(a0)
+       mov     d1,(4,a0)
+       mov     d2,(8,a0)
+
+       mov     sp,a3
+       mov     decomp_stack+0x2000-4,a0
+       mov     a0,sp
+
+       # invalidate and enable both of the caches
+       mov     CHCTR,a0
+       clr     d0
+       movhu   d0,(a0)                                 # turn off first
+       mov     CHCTR_ICINV|CHCTR_DCINV,d0
+       movhu   d0,(a0)
+       setlb
+       mov     (a0),d0
+       btst    CHCTR_ICBUSY|CHCTR_DCBUSY,d0            # wait till not busy
+       lne
+       mov     CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD,d0   # writethru dcache
+       movhu   d0,(a0)                                 # enable
+
+       # clear the BSS area
+       mov     __bss_start,a0
+       mov     _end,a1
+       clr     d0
+bssclear:
+       cmp     a1,a0
+       bge     bssclear_end
+       movbu   d0,(a0)
+       inc     a0
+       bra     bssclear
+bssclear_end:
+
+       # decompress the kernel
+       call    decompress_kernel[],0
+
+       # disable caches again
+       mov     CHCTR,a0
+       clr     d0
+       movhu   d0,(a0)
+       setlb
+       mov     (a0),d0
+       btst    CHCTR_ICBUSY|CHCTR_DCBUSY,d0            # wait till not busy
+       lne
+
+       mov     param_save_area,a0
+       mov     (a0),d0
+       mov     (4,a0),d1
+       mov     (8,a0),d2
+
+       mov     a3,sp
+       mov     CONFIG_KERNEL_TEXT_ADDRESS,a0
+       jmp     (a0)
+
+       .data
+       .align          4
+param_save_area:
+       .rept 3
+       .word           0
+       .endr
+
+       .section        .bss
+       .align          4
+decomp_stack:
+       .space          0x2000
diff --git a/arch/mn10300/boot/compressed/misc.c b/arch/mn10300/boot/compressed/misc.c
new file mode 100644 (file)
index 0000000..ded207e
--- /dev/null
@@ -0,0 +1,429 @@
+/* MN10300 Miscellaneous helper routines for kernel decompressor
+ *
+ * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Modified by David Howells (dhowells@redhat.com)
+ * - Derived from arch/x86/boot/compressed/misc_32.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/compiler.h>
+#include <asm/serial-regs.h>
+#include "misc.h"
+
+#ifndef CONFIG_GDBSTUB_ON_TTYSx
+/* display 'Uncompressing Linux... ' messages on ttyS0 or ttyS1 */
+#if 1  /* ttyS0 */
+#define CYG_DEV_BASE   0xA6FB0000
+#else   /* ttyS1 */
+#define CYG_DEV_BASE   0xA6FC0000
+#endif
+
+#define CYG_DEV_THR    (*((volatile __u8*)(CYG_DEV_BASE + 0x00)))
+#define CYG_DEV_MCR    (*((volatile __u8*)(CYG_DEV_BASE + 0x10)))
+#define SIO_MCR_DTR    0x01
+#define SIO_MCR_RTS    0x02
+#define CYG_DEV_LSR    (*((volatile __u8*)(CYG_DEV_BASE + 0x14)))
+#define SIO_LSR_THRE   0x20            /* transmitter holding register empty */
+#define SIO_LSR_TEMT   0x40            /* transmitter register empty */
+#define CYG_DEV_MSR    (*((volatile __u8*)(CYG_DEV_BASE + 0x18)))
+#define SIO_MSR_CTS    0x10            /* clear to send */
+#define SIO_MSR_DSR    0x20            /* data set ready */
+
+#define LSR_WAIT_FOR(STATE) \
+       do { while (!(CYG_DEV_LSR & SIO_LSR_##STATE)) {} } while (0)
+#define FLOWCTL_QUERY(LINE) \
+       ({ CYG_DEV_MSR & SIO_MSR_##LINE; })
+#define FLOWCTL_WAIT_FOR(LINE) \
+       do { while (!(CYG_DEV_MSR & SIO_MSR_##LINE)) {} } while (0)
+#define FLOWCTL_CLEAR(LINE) \
+       do { CYG_DEV_MCR &= ~SIO_MCR_##LINE; } while (0)
+#define FLOWCTL_SET(LINE) \
+       do { CYG_DEV_MCR |= SIO_MCR_##LINE; } while (0)
+#endif
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+
+static inline void *memset(const void *s, int c, size_t n)
+{
+       int i;
+       char *ss = (char *) s;
+
+       for (i = 0; i < n; i++)
+               ss[i] = c;
+       return (void *)s;
+}
+
+#define memzero(s, n) memset((s), 0, (n))
+
+static inline void *memcpy(void *__dest, const void *__src, size_t __n)
+{
+       int i;
+       const char *s = __src;
+       char *d = __dest;
+
+       for (i = 0; i < __n; i++)
+               d[i] = s[i];
+       return __dest;
+}
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000   /* Window size must be at least 32k, and a power of
+                        * two */
+
+static uch *inbuf;     /* input buffer */
+static uch window[WSIZE]; /* sliding window buffer */
+
+static unsigned insize;        /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to be processed in inbuf */
+static unsigned outcnt;        /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond, msg) { if (!(cond)) error(msg); }
+#  define Trace(x)     fprintf x
+#  define Tracev(x)    { if (verbose) fprintf x ; }
+#  define Tracevv(x)   { if (verbose > 1) fprintf x ; }
+#  define Tracec(c, x) { if (verbose && (c)) fprintf x ; }
+#  define Tracecv(c, x)        { if (verbose > 1 && (c)) fprintf x ; }
+#else
+#  define Assert(cond, msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c, x)
+#  define Tracecv(c, x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(const char *) __attribute__((noreturn));
+static void kputs(const char *);
+
+static inline unsigned char get_byte(void)
+{
+       unsigned char ch = inptr < insize ? inbuf[inptr++] : fill_inbuf();
+
+#if 0
+       char hex[3];
+       hex[0] = ((ch & 0x0f) > 9) ?
+               ((ch & 0x0f) + 'A' - 0xa) : ((ch & 0x0f) + '0');
+       hex[1] = ((ch >> 4) > 9) ?
+               ((ch >> 4) + 'A' - 0xa) : ((ch >> 4) + '0');
+       hex[2] = 0;
+       kputs(hex);
+#endif
+       return ch;
+}
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define EXT_MEM_K (*(unsigned short *)0x90002)
+#ifndef STANDARD_MEMORY_BIOS_CALL
+#define ALT_MEM_K (*(unsigned long *) 0x901e0)
+#endif
+#define SCREEN_INFO (*(struct screen_info *)0x90000)
+
+static long bytes_out;
+static uch *output_data;
+static unsigned long output_ptr;
+
+
+static void *malloc(int size);
+
+static inline void free(void *where)
+{      /* Don't care */
+}
+
+static unsigned long free_mem_ptr = (unsigned long) &end;
+static unsigned long free_mem_end_ptr = (unsigned long) &end + 0x90000;
+
+static inline void gzip_mark(void **ptr)
+{
+       kputs(".");
+       *ptr = (void *) free_mem_ptr;
+}
+
+static inline void gzip_release(void **ptr)
+{
+       free_mem_ptr = (unsigned long) *ptr;
+}
+
+#define INPLACE_MOVE_ROUTINE   0x1000
+#define LOW_BUFFER_START       0x2000
+#define LOW_BUFFER_END         0x90000
+#define LOW_BUFFER_SIZE                (LOW_BUFFER_END - LOW_BUFFER_START)
+#define HEAP_SIZE              0x3000
+static int high_loaded;
+static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
+
+static char *vidmem = (char *)0xb8000;
+static int lines, cols;
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+       void *p;
+
+       if (size < 0)
+               error("Malloc error\n");
+       if (!free_mem_ptr)
+               error("Memory error\n");
+
+       free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+       p = (void *) free_mem_ptr;
+       free_mem_ptr += size;
+
+       if (free_mem_ptr >= free_mem_end_ptr)
+               error("\nOut of memory\n");
+
+       return p;
+}
+
+static inline void scroll(void)
+{
+       int i;
+
+       memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
+       for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
+               vidmem[i] = ' ';
+}
+
+static inline void kputchar(unsigned char ch)
+{
+#ifdef CONFIG_MN10300_UNIT_ASB2305
+       while (SC0STR & SC01STR_TBF)
+               continue;
+
+       if (ch == 0x0a) {
+               SC0TXB = 0x0d;
+               while (SC0STR & SC01STR_TBF)
+                       continue;
+       }
+
+       SC0TXB = ch;
+
+#else
+       while (SC1STR & SC01STR_TBF)
+               continue;
+
+       if (ch == 0x0a) {
+               SC1TXB = 0x0d;
+               while (SC1STR & SC01STR_TBF)
+                       continue;
+       }
+
+       SC1TXB = ch;
+
+#endif
+}
+
+static void kputs(const char *s)
+{
+#ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL
+#ifndef CONFIG_GDBSTUB_ON_TTYSx
+       char ch;
+
+       FLOWCTL_SET(DTR);
+
+       while (*s) {
+               LSR_WAIT_FOR(THRE);
+
+               ch = *s++;
+               if (ch == 0x0a) {
+                       CYG_DEV_THR = 0x0d;
+                       LSR_WAIT_FOR(THRE);
+               }
+               CYG_DEV_THR = ch;
+       }
+
+       FLOWCTL_CLEAR(DTR);
+#else
+
+       for (; *s; s++)
+               kputchar(*s);
+
+#endif
+#endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf()
+{
+       if (insize != 0)
+               error("ran out of input data\n");
+
+       inbuf = input_data;
+       insize = input_len;
+       inptr = 1;
+       return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window_low(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+
+    in = window;
+    out = &output_data[output_ptr];
+    for (n = 0; n < outcnt; n++) {
+           ch = *out++ = *in++;
+           c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void flush_window_high(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in,  ch;
+    in = window;
+    for (n = 0; n < outcnt; n++) {
+       ch = *output_data++ = *in++;
+       if ((ulg) output_data == LOW_BUFFER_END)
+               output_data = high_buffer_start;
+       c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void flush_window(void)
+{
+       if (high_loaded)
+               flush_window_high();
+       else
+               flush_window_low();
+}
+
+static void error(const char *x)
+{
+       kputs("\n\n");
+       kputs(x);
+       kputs("\n\n -- System halted");
+
+       while (1)
+               /* Halt */;
+}
+
+#define STACK_SIZE (4096)
+
+long user_stack[STACK_SIZE];
+
+struct {
+       long *a;
+       short b;
+} stack_start = { &user_stack[STACK_SIZE], 0 };
+
+void setup_normal_output_buffer(void)
+{
+#ifdef STANDARD_MEMORY_BIOS_CALL
+       if (EXT_MEM_K < 1024)
+               error("Less than 2MB of memory.\n");
+#else
+       if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024)
+               error("Less than 2MB of memory.\n");
+#endif
+       output_data = (char *) 0x100000; /* Points to 1M */
+}
+
+struct moveparams {
+       uch *low_buffer_start;
+       int lcount;
+       uch *high_buffer_start;
+       int hcount;
+};
+
+void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+       high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE);
+#ifdef STANDARD_MEMORY_BIOS_CALL
+       if (EXT_MEM_K < (3 * 1024))
+               error("Less than 4MB of memory.\n");
+#else
+       if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024))
+               error("Less than 4MB of memory.\n");
+#endif
+       mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START;
+       high_loaded = 1;
+       free_mem_end_ptr = (long) high_buffer_start;
+       if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) {
+               high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE);
+               mv->hcount = 0; /* say: we need not to move high_buffer */
+       } else {
+               mv->hcount = -1;
+       }
+       mv->high_buffer_start = high_buffer_start;
+}
+
+void close_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+       mv->lcount = bytes_out;
+       if (bytes_out > LOW_BUFFER_SIZE) {
+               mv->lcount = LOW_BUFFER_SIZE;
+               if (mv->hcount)
+                       mv->hcount = bytes_out - LOW_BUFFER_SIZE;
+       } else {
+               mv->hcount = 0;
+       }
+}
+
+#undef DEBUGFLAG
+#ifdef DEBUGFLAG
+int debugflag;
+#endif
+
+int decompress_kernel(struct moveparams *mv)
+{
+#ifdef DEBUGFLAG
+       while (!debugflag)
+               barrier();
+#endif
+
+       output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS;
+
+       makecrc();
+       kputs("Uncompressing Linux... ");
+       gunzip();
+       kputs("Ok, booting the kernel.\n");
+       return 0;
+}
diff --git a/arch/mn10300/boot/compressed/misc.h b/arch/mn10300/boot/compressed/misc.h
new file mode 100644 (file)
index 0000000..da921cd
--- /dev/null
@@ -0,0 +1,18 @@
+/* Internal definitions for the MN10300 kernel decompressor
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+extern int end;
+
+/*
+ * vmlinux.lds
+ */
+extern char input_data[];
+extern int input_len;
diff --git a/arch/mn10300/boot/compressed/vmlinux.lds b/arch/mn10300/boot/compressed/vmlinux.lds
new file mode 100644 (file)
index 0000000..a084903
--- /dev/null
@@ -0,0 +1,9 @@
+SECTIONS
+{
+  .data : {
+       input_len = .;
+       LONG(input_data_end - input_data) input_data = .;
+       *(.data)
+       input_data_end = .;
+       }
+}
diff --git a/arch/mn10300/boot/install.sh b/arch/mn10300/boot/install.sh
new file mode 100644 (file)
index 0000000..072951c
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# arch/mn10300/boot/install -c.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# Licence.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install -c" script for i386 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install -c path (blank if root directory)
+#   $5 - boot rom file
+#
+
+# User may have a custom install -c script
+
+rm -fr $4/../usr/include/linux $4/../usr/include/asm
+install -c -m 0755 $2 $4/vmlinuz
+install -c -m 0755 $5 $4/boot.rom
+install -c -m 0755 -d $4/../usr/include/linux
+cd $TOPDIR/include/linux
+for i in `find . -maxdepth 1 -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux
+done
+install -c -m 0755 -d $4/../usr/include/linux/byteorder
+cd $TOPDIR/include/linux/byteorder
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux/byteorder
+done
+install -c -m 0755 -d $4/../usr/include/linux/lockd
+cd $TOPDIR/include/linux/lockd
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux/lockd
+done
+install -c -m 0755 -d $4/../usr/include/linux/netfilter_ipv4
+cd $TOPDIR/include/linux/netfilter_ipv4
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux/netfilter_ipv4
+done
+install -c -m 0755 -d $4/../usr/include/linux/nfsd
+cd $TOPDIR/include/linux/nfsd
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux/nfsd/$i
+done
+install -c -m 0755 -d $4/../usr/include/linux/raid
+cd $TOPDIR/include/linux/raid
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux/raid
+done
+install -c -m 0755 -d $4/../usr/include/linux/sunrpc
+cd $TOPDIR/include/linux/sunrpc
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/linux/sunrpc
+done
+install -c -m 0755 -d $4/../usr/include/asm
+cd $TOPDIR/include/asm
+for i in `find . -name '*.h' -print`; do
+  install -c -m 0644 $i $4/../usr/include/asm
+done
diff --git a/arch/mn10300/boot/tools/build.c b/arch/mn10300/boot/tools/build.c
new file mode 100644 (file)
index 0000000..4f552ea
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1997 Martin Mares
+ */
+
+/*
+ * This file builds a disk-image from three different files:
+ *
+ * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - setup: 8086 machine code, sets up system parm
+ * - system: 80386 code for actual system
+ *
+ * It does some checking that all files are of the correct type, and
+ * just writes the result to stdout, removing headers and padding to
+ * the right amount. It also writes some system data to stderr.
+ */
+
+/*
+ * Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
+ * Rewritten by Martin Mares, April 1997
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <asm/boot.h>
+
+#define DEFAULT_MAJOR_ROOT 0
+#define DEFAULT_MINOR_ROOT 0
+
+/* Minimal number of setup sectors (see also bootsect.S) */
+#define SETUP_SECTS 4
+
+uint8_t buf[1024];
+int fd;
+int is_big_kernel;
+
+__attribute__((noreturn))
+void die(const char *str, ...)
+{
+       va_list args;
+       va_start(args, str);
+       vfprintf(stderr, str, args);
+       fputc('\n', stderr);
+       exit(1);
+}
+
+void file_open(const char *name)
+{
+       fd = open(name, O_RDONLY, 0);
+       if (fd < 0)
+               die("Unable to open `%s': %m", name);
+}
+
+__attribute__((noreturn))
+void usage(void)
+{
+       die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+}
+
+int main(int argc, char **argv)
+{
+       unsigned int i, c, sz, setup_sectors;
+       uint32_t sys_size;
+       uint8_t major_root, minor_root;
+       struct stat sb;
+
+       if (argc > 2 && !strcmp(argv[1], "-b")) {
+               is_big_kernel = 1;
+               argc--, argv++;
+       }
+       if ((argc < 4) || (argc > 5))
+               usage();
+       if (argc > 4) {
+               if (!strcmp(argv[4], "CURRENT")) {
+                       if (stat("/", &sb)) {
+                               perror("/");
+                               die("Couldn't stat /");
+                       }
+                       major_root = major(sb.st_dev);
+                       minor_root = minor(sb.st_dev);
+               } else if (strcmp(argv[4], "FLOPPY")) {
+                       if (stat(argv[4], &sb)) {
+                               perror(argv[4]);
+                               die("Couldn't stat root device.");
+                       }
+                       major_root = major(sb.st_rdev);
+                       minor_root = minor(sb.st_rdev);
+               } else {
+                       major_root = 0;
+                       minor_root = 0;
+               }
+       } else {
+               major_root = DEFAULT_MAJOR_ROOT;
+               minor_root = DEFAULT_MINOR_ROOT;
+       }
+       fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
+
+       file_open(argv[1]);
+       i = read(fd, buf, sizeof(buf));
+       fprintf(stderr, "Boot sector %d bytes.\n", i);
+       if (i != 512)
+               die("Boot block must be exactly 512 bytes");
+       if (buf[510] != 0x55 || buf[511] != 0xaa)
+               die("Boot block hasn't got boot flag (0xAA55)");
+       buf[508] = minor_root;
+       buf[509] = major_root;
+       if (write(1, buf, 512) != 512)
+               die("Write call failed");
+       close(fd);
+
+       /* Copy the setup code */
+       file_open(argv[2]);
+       for (i = 0; (c = read(fd, buf, sizeof(buf))) > 0; i += c)
+               if (write(1, buf, c) != c)
+                       die("Write call failed");
+       if (c != 0)
+               die("read-error on `setup'");
+       close(fd);
+
+       /* Pad unused space with zeros */
+       setup_sectors = (i + 511) / 512;
+       /* for compatibility with ancient versions of LILO. */
+       if (setup_sectors < SETUP_SECTS)
+               setup_sectors = SETUP_SECTS;
+       fprintf(stderr, "Setup is %d bytes.\n", i);
+       memset(buf, 0, sizeof(buf));
+       while (i < setup_sectors * 512) {
+               c = setup_sectors * 512 - i;
+               if (c > sizeof(buf))
+                       c = sizeof(buf);
+               if (write(1, buf, c) != c)
+                       die("Write call failed");
+               i += c;
+       }
+
+       file_open(argv[3]);
+       if (fstat(fd, &sb))
+               die("Unable to stat `%s': %m", argv[3]);
+       sz = sb.st_size;
+       fprintf(stderr, "System is %d kB\n", sz / 1024);
+       sys_size = (sz + 15) / 16;
+       /* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
+       if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE))
+               die("System is too big. Try using %smodules.",
+                       is_big_kernel ? "" : "bzImage or ");
+       if (sys_size > 0xffff)
+               fprintf(stderr,
+                       "warning: kernel is too big for standalone boot "
+                       "from floppy\n");
+       while (sz > 0) {
+               int l, n;
+
+               l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
+               n = read(fd, buf, l);
+               if (n != l) {
+                       if (n < 0)
+                               die("Error reading %s: %m", argv[3]);
+                       else
+                               die("%s: Unexpected EOF", argv[3]);
+               }
+               if (write(1, buf, l) != l)
+                       die("Write failed");
+               sz -= l;
+       }
+       close(fd);
+
+       /* Write sizes to the bootsector */
+       if (lseek(1, 497, SEEK_SET) != 497)
+               die("Output: seek failed");
+       buf[0] = setup_sectors;
+       if (write(1, buf, 1) != 1)
+               die("Write of setup sector count failed");
+       if (lseek(1, 500, SEEK_SET) != 500)
+               die("Output: seek failed");
+       buf[0] = (sys_size & 0xff);
+       buf[1] = ((sys_size >> 8) & 0xff);
+       if (write(1, buf, 2) != 2)
+               die("Write of image length failed");
+
+       return 0;
+}
diff --git a/arch/mn10300/configs/asb2303_defconfig b/arch/mn10300/configs/asb2303_defconfig
new file mode 100644 (file)
index 0000000..0189a05
--- /dev/null
@@ -0,0 +1,555 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.24-rc2
+# Fri Nov 16 13:36:38 2007
+#
+CONFIG_MN10300=y
+CONFIG_AM33=y
+CONFIG_MMU=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_NUMA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_BUG=y
+CONFIG_QUICKLIST=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+# CONFIG_ARCH_SUPPORTS_AOUT is not set
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+# CONFIG_BLOCK is not set
+
+#
+# Matsushita MN10300 system setup
+#
+CONFIG_MN10300_UNIT_ASB2303=y
+# CONFIG_MN10300_UNIT_ASB2305 is not set
+CONFIG_MN10300_PROC_MN103E010=y
+CONFIG_MN10300_CPU_AM33V2=y
+CONFIG_FPU=y
+CONFIG_MN10300_CACHE_WBACK=y
+# CONFIG_MN10300_CACHE_WTHRU is not set
+# CONFIG_MN10300_CACHE_DISABLED is not set
+
+#
+# Memory layout options
+#
+CONFIG_KERNEL_RAM_BASE_ADDRESS=0x90000000
+CONFIG_INTERRUPT_VECTOR_BASE=0x90000000
+CONFIG_KERNEL_TEXT_ADDRESS=0x90001000
+CONFIG_KERNEL_ZIMAGE_BASE_ADDRESS=0x90700000
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+CONFIG_MN10300_CURRENT_IN_E2=y
+CONFIG_MN10300_USING_JTAG=y
+CONFIG_MN10300_RTC=y
+CONFIG_MN10300_WD_TIMER=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# MN10300 internal serial options
+#
+CONFIG_MN10300_PROC_HAS_TTYSM0=y
+CONFIG_MN10300_PROC_HAS_TTYSM1=y
+CONFIG_MN10300_PROC_HAS_TTYSM2=y
+CONFIG_MN10300_TTYSM=y
+CONFIG_MN10300_TTYSM_CONSOLE=y
+CONFIG_MN10300_TTYSM0=y
+CONFIG_MN10300_TTYSM0_TIMER8=y
+# CONFIG_MN10300_TTYSM0_TIMER2 is not set
+CONFIG_MN10300_TTYSM1=y
+CONFIG_MN10300_TTYSM1_TIMER9=y
+# CONFIG_MN10300_TTYSM1_TIMER3 is not set
+# CONFIG_MN10300_TTYSM2 is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Executable formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_CFI_I4=y
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_RTC=y
+# CONFIG_R3964 is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_RTC_CLASS is not set
+
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SAMPLES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile
new file mode 100644 (file)
index 0000000..ef07c95
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Makefile for the MN10300-specific core kernel code
+#
+extra-y := head.o init_task.o vmlinux.lds
+
+obj-y   := process.o semaphore.o signal.o entry.o fpu.o traps.o irq.o \
+          ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \
+          switch_to.o mn10300_ksyms.o kernel_execve.o
+
+obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o
+
+obj-$(CONFIG_FPU) += fpu-low.o
+
+obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \
+                              mn10300-debug.o
+obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-low.o
+obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o
+obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o
+
+ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y)
+obj-$(CONFIG_GDBSTUB) += gdb-cache.o
+endif
+
+obj-$(CONFIG_MN10300_RTC) += rtc.o
+obj-$(CONFIG_PROFILE) += profile.o profile-low.o
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..ee2d9f8
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/personality.h>
+#include <asm/ucontext.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/ptrace.h>
+#include "sigframe.h"
+#include "mn10300-serial.h"
+
+#define DEFINE(sym, val) \
+       asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->")
+
+#define OFFSET(sym, str, mem) \
+       DEFINE(sym, offsetof(struct str, mem));
+
+void foo(void)
+{
+       OFFSET(SIGCONTEXT_d0, sigcontext, d0);
+       OFFSET(SIGCONTEXT_d1, sigcontext, d1);
+       BLANK();
+
+       OFFSET(TI_task,                 thread_info, task);
+       OFFSET(TI_exec_domain,          thread_info, exec_domain);
+       OFFSET(TI_flags,                thread_info, flags);
+       OFFSET(TI_cpu,                  thread_info, cpu);
+       OFFSET(TI_preempt_count,        thread_info, preempt_count);
+       OFFSET(TI_addr_limit,           thread_info, addr_limit);
+       OFFSET(TI_restart_block,        thread_info, restart_block);
+       BLANK();
+
+       OFFSET(REG_D0,                  pt_regs, d0);
+       OFFSET(REG_D1,                  pt_regs, d1);
+       OFFSET(REG_D2,                  pt_regs, d2);
+       OFFSET(REG_D3,                  pt_regs, d3);
+       OFFSET(REG_A0,                  pt_regs, a0);
+       OFFSET(REG_A1,                  pt_regs, a1);
+       OFFSET(REG_A2,                  pt_regs, a2);
+       OFFSET(REG_A3,                  pt_regs, a3);
+       OFFSET(REG_E0,                  pt_regs, e0);
+       OFFSET(REG_E1,                  pt_regs, e1);
+       OFFSET(REG_E2,                  pt_regs, e2);
+       OFFSET(REG_E3,                  pt_regs, e3);
+       OFFSET(REG_E4,                  pt_regs, e4);
+       OFFSET(REG_E5,                  pt_regs, e5);
+       OFFSET(REG_E6,                  pt_regs, e6);
+       OFFSET(REG_E7,                  pt_regs, e7);
+       OFFSET(REG_SP,                  pt_regs, sp);
+       OFFSET(REG_EPSW,                pt_regs, epsw);
+       OFFSET(REG_PC,                  pt_regs, pc);
+       OFFSET(REG_LAR,                 pt_regs, lar);
+       OFFSET(REG_LIR,                 pt_regs, lir);
+       OFFSET(REG_MDR,                 pt_regs, mdr);
+       OFFSET(REG_MCVF,                pt_regs, mcvf);
+       OFFSET(REG_MCRL,                pt_regs, mcrl);
+       OFFSET(REG_MCRH,                pt_regs, mcrh);
+       OFFSET(REG_MDRQ,                pt_regs, mdrq);
+       OFFSET(REG_ORIG_D0,             pt_regs, orig_d0);
+       OFFSET(REG_NEXT,                pt_regs, next);
+       DEFINE(REG__END,                sizeof(struct pt_regs));
+       BLANK();
+
+       OFFSET(THREAD_UREGS,            thread_struct, uregs);
+       OFFSET(THREAD_PC,               thread_struct, pc);
+       OFFSET(THREAD_SP,               thread_struct, sp);
+       OFFSET(THREAD_A3,               thread_struct, a3);
+       OFFSET(THREAD_USP,              thread_struct, usp);
+       OFFSET(THREAD_FRAME,            thread_struct, __frame);
+       BLANK();
+
+       DEFINE(CLONE_VM_asm,            CLONE_VM);
+       DEFINE(CLONE_FS_asm,            CLONE_FS);
+       DEFINE(CLONE_FILES_asm,         CLONE_FILES);
+       DEFINE(CLONE_SIGHAND_asm,       CLONE_SIGHAND);
+       DEFINE(CLONE_UNTRACED_asm,      CLONE_UNTRACED);
+       DEFINE(SIGCHLD_asm,             SIGCHLD);
+       BLANK();
+
+       OFFSET(EXEC_DOMAIN_handler,     exec_domain, handler);
+       OFFSET(RT_SIGFRAME_sigcontext,  rt_sigframe, uc.uc_mcontext);
+
+       DEFINE(PAGE_SIZE_asm,           PAGE_SIZE);
+
+       OFFSET(__rx_buffer,             mn10300_serial_port, rx_buffer);
+       OFFSET(__rx_inp,                mn10300_serial_port, rx_inp);
+       OFFSET(__rx_outp,               mn10300_serial_port, rx_outp);
+       OFFSET(__tx_info_buffer,        mn10300_serial_port, uart.info);
+       OFFSET(__tx_xchar,              mn10300_serial_port, tx_xchar);
+       OFFSET(__tx_break,              mn10300_serial_port, tx_break);
+       OFFSET(__intr_flags,            mn10300_serial_port, intr_flags);
+       OFFSET(__rx_icr,                mn10300_serial_port, rx_icr);
+       OFFSET(__tx_icr,                mn10300_serial_port, tx_icr);
+       OFFSET(__tm_icr,                mn10300_serial_port, _tmicr);
+       OFFSET(__iobase,                mn10300_serial_port, _iobase);
+
+       DEFINE(__UART_XMIT_SIZE,        UART_XMIT_SIZE);
+       OFFSET(__xmit_buffer,           uart_info, xmit.buf);
+       OFFSET(__xmit_head,             uart_info, xmit.head);
+       OFFSET(__xmit_tail,             uart_info, xmit.tail);
+}
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
new file mode 100644 (file)
index 0000000..11de360
--- /dev/null
@@ -0,0 +1,721 @@
+###############################################################################
+#
+# MN10300 Exception and interrupt entry points
+#
+# Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Modified by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/thread_info.h>
+#include <asm/intctl-regs.h>
+#include <asm/busctl-regs.h>
+#include <asm/timer-regs.h>
+#include <asm/unit/leds.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/errno.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
+
+#ifdef CONFIG_PREEMPT
+#define preempt_stop           __cli
+#else
+#define preempt_stop
+#define resume_kernel          restore_all
+#endif
+
+       .macro __cli
+       and     ~EPSW_IM,epsw
+       or      EPSW_IE|MN10300_CLI_LEVEL,epsw
+       nop
+       nop
+       nop
+       .endm
+       .macro __sti
+       or      EPSW_IE|EPSW_IM_7,epsw
+       .endm
+
+
+       .am33_2
+
+###############################################################################
+#
+# the return path for a forked child
+# - on entry, D0 holds the address of the previous task to run
+#
+###############################################################################
+ENTRY(ret_from_fork)
+       call    schedule_tail[],0
+       GET_THREAD_INFO a2
+
+       # return 0 to indicate child process
+       clr     d0
+       mov     d0,(REG_D0,fp)
+       jmp     syscall_exit
+
+###############################################################################
+#
+# system call handler
+#
+###############################################################################
+ENTRY(system_call)
+       add     -4,sp
+       SAVE_ALL
+       mov     d0,(REG_ORIG_D0,fp)
+       GET_THREAD_INFO a2
+       cmp     nr_syscalls,d0
+       bcc     syscall_badsys
+       btst    _TIF_SYSCALL_TRACE,(TI_flags,a2)
+       bne     syscall_trace_entry
+syscall_call:
+       add     d0,d0,a1
+       add     a1,a1
+       mov     (REG_A0,fp),d0
+       mov     (sys_call_table,a1),a0
+       calls   (a0)
+       mov     d0,(REG_D0,fp)
+syscall_exit:
+       # make sure we don't miss an interrupt setting need_resched or
+       # sigpending between sampling and the rti
+       __cli
+       mov     (TI_flags,a2),d2
+       btst    _TIF_ALLWORK_MASK,d2
+       bne     syscall_exit_work
+restore_all:
+       RESTORE_ALL
+
+###############################################################################
+#
+# perform work that needs to be done immediately before resumption and syscall
+# tracing
+#
+###############################################################################
+       ALIGN
+syscall_exit_work:
+       btst    _TIF_SYSCALL_TRACE,d2
+       beq     work_pending
+       __sti                           # could let do_syscall_trace() call
+                                       # schedule() instead
+       mov     fp,d0
+       mov     1,d1
+       call    do_syscall_trace[],0    # do_syscall_trace(regs,entryexit)
+       jmp     resume_userspace
+
+       ALIGN
+work_pending:
+       btst    _TIF_NEED_RESCHED,d2
+       beq     work_notifysig
+
+work_resched:
+       call    schedule[],0
+
+       # make sure we don't miss an interrupt setting need_resched or
+       # sigpending between sampling and the rti
+       __cli
+
+       # is there any work to be done other than syscall tracing?
+       mov     (TI_flags,a2),d2
+       btst    _TIF_WORK_MASK,d2
+       beq     restore_all
+       btst    _TIF_NEED_RESCHED,d2
+       bne     work_resched
+
+       # deal with pending signals and notify-resume requests
+work_notifysig:
+       mov     fp,d0
+       mov     d2,d1
+       call    do_notify_resume[],0
+       jmp     resume_userspace
+
+       # perform syscall entry tracing
+syscall_trace_entry:
+       mov     -ENOSYS,d0
+       mov     d0,(REG_D0,fp)
+       mov     fp,d0
+       clr     d1
+       call    do_syscall_trace[],0
+       mov     (REG_ORIG_D0,fp),d0
+       mov     (REG_D1,fp),d1
+       cmp     nr_syscalls,d0
+       bcs     syscall_call
+       jmp     syscall_exit
+
+syscall_badsys:
+       mov     -ENOSYS,d0
+       mov     d0,(REG_D0,fp)
+       jmp     resume_userspace
+
+       # userspace resumption stub bypassing syscall exit tracing
+       .globl  ret_from_exception, ret_from_intr
+       ALIGN
+ret_from_exception:
+       preempt_stop
+ret_from_intr:
+       GET_THREAD_INFO a2
+       mov     (REG_EPSW,fp),d0        # need to deliver signals before
+                                       # returning to userspace
+       and     EPSW_nSL,d0
+       beq     resume_kernel           # returning to supervisor mode
+
+ENTRY(resume_userspace)
+       # make sure we don't miss an interrupt setting need_resched or
+       # sigpending between sampling and the rti
+       __cli
+
+       # is there any work to be done on int/exception return?
+       mov     (TI_flags,a2),d2
+       btst    _TIF_WORK_MASK,d2
+       bne     work_pending
+       jmp     restore_all
+
+#ifdef CONFIG_PREEMPT
+ENTRY(resume_kernel)
+       mov     (TI_preempt_count,a2),d0        # non-zero preempt_count ?
+       cmp     0,d0
+       bne     restore_all
+
+need_resched:
+       btst    _TIF_NEED_RESCHED,(TI_flags,a2)
+       beq     restore_all
+       mov     (REG_EPSW,fp),d0
+       and     EPSW_IM,d0
+       cmp     EPSW_IM_7,d0            # interrupts off (exception path) ?
+       beq     restore_all
+       call    preempt_schedule_irq[],0
+       jmp     need_resched
+#endif
+
+
+###############################################################################
+#
+# IRQ handler entry point
+# - intended to be entered at multiple priorities
+#
+###############################################################################
+ENTRY(irq_handler)
+       add     -4,sp
+       SAVE_ALL
+
+       # it's not a syscall
+       mov     0xffffffff,d0
+       mov     d0,(REG_ORIG_D0,fp)
+
+       mov     fp,d0
+       call    do_IRQ[],0                      # do_IRQ(regs)
+
+       jmp     ret_from_intr
+
+###############################################################################
+#
+# Monitor Signal handler entry point
+#
+###############################################################################
+ENTRY(monitor_signal)
+       movbu   (0xae000001),d1
+       cmp     1,d1
+       beq     monsignal
+       ret     [],0
+
+monsignal:
+       or      EPSW_NMID,epsw
+       mov     d0,a0
+       mov     a0,sp
+       mov     (REG_EPSW,fp),d1
+       and     ~EPSW_nSL,d1
+       mov     d1,(REG_EPSW,fp)
+       movm    (sp),[d2,d3,a2,a3,exreg0,exreg1,exother]
+       mov     (sp),a1
+       mov     a1,usp
+       movm    (sp),[other]
+       add     4,sp
+here:  jmp     0x8e000008-here+0x8e000008
+
+###############################################################################
+#
+# Double Fault handler entry point
+# - note that there will not be a stack, D0/A0 will hold EPSW/PC as were
+#
+###############################################################################
+       .section .bss
+       .balign THREAD_SIZE
+       .space  THREAD_SIZE
+__df_stack:
+       .previous
+
+ENTRY(double_fault)
+       mov     a0,(__df_stack-4)       # PC as was
+       mov     d0,(__df_stack-8)       # EPSW as was
+       mn10300_set_dbfleds             # display 'db-f' on the LEDs
+       mov     0xaa55aa55,d0
+       mov     d0,(__df_stack-12)      # no ORIG_D0
+       mov     sp,a0                   # save corrupted SP
+       mov     __df_stack-12,sp        # emergency supervisor stack
+       SAVE_ALL
+       mov     a0,(REG_A0,fp)          # save corrupted SP as A0 (which got
+                                       # clobbered by the CPU)
+       mov     fp,d0
+       calls   do_double_fault
+double_fault_loop:
+       bra     double_fault_loop
+
+###############################################################################
+#
+# Bus Error handler entry point
+# - handle external (async) bus errors separately
+#
+###############################################################################
+ENTRY(raw_bus_error)
+       add     -4,sp
+       mov     d0,(sp)
+       mov     (BCBERR),d0             # what
+       btst    BCBERR_BEMR_DMA,d0      # see if it was an external bus error
+       beq     __common_exception_aux  # it wasn't
+
+       SAVE_ALL
+       mov     (BCBEAR),d1             # destination of erroneous access
+
+       mov     (REG_ORIG_D0,fp),d2
+       mov     d2,(REG_D0,fp)
+       mov     -1,d2
+       mov     d2,(REG_ORIG_D0,fp)
+
+       add     -4,sp
+       mov     fp,(12,sp)              # frame pointer
+       call    io_bus_error[],0
+       jmp     restore_all
+
+###############################################################################
+#
+# Miscellaneous exception entry points
+#
+###############################################################################
+ENTRY(nmi_handler)
+       add     -4,sp
+       mov     d0,(sp)
+       mov     (TBR),d0
+       bra     __common_exception_nonmi
+
+ENTRY(__common_exception)
+       add     -4,sp
+       mov     d0,(sp)
+
+__common_exception_aux:
+       mov     (TBR),d0
+       and     ~EPSW_NMID,epsw         # turn NMIs back on if not NMI
+       or      EPSW_IE,epsw
+
+__common_exception_nonmi:
+       and     0x0000FFFF,d0           # turn the exception code into a vector
+                                       # table index
+
+       btst    0x00000007,d0
+       bne     1f
+       cmp     0x00000400,d0
+       bge     1f
+
+       SAVE_ALL                        # build the stack frame
+
+       mov     (REG_D0,fp),a2          # get the exception number
+       mov     (REG_ORIG_D0,fp),d0
+       mov     d0,(REG_D0,fp)
+       mov     -1,d0
+       mov     d0,(REG_ORIG_D0,fp)
+
+#ifdef CONFIG_GDBSTUB
+       btst    0x01,(gdbstub_busy)
+       beq     2f
+       and     ~EPSW_IE,epsw
+       mov     fp,d0
+       mov     a2,d1
+       call    gdbstub_exception[],0   # gdbstub itself caused an exception
+       bra     restore_all
+2:
+#endif
+
+       mov     fp,d0                   # arg 0: stacked register file
+       mov     a2,d1                   # arg 1: exception number
+       lsr     1,a2
+
+       mov     (exception_table,a2),a2
+       calls   (a2)
+       jmp     ret_from_exception
+
+1:     pi                              # BUG() equivalent
+
+###############################################################################
+#
+# Exception handler functions table
+#
+###############################################################################
+       .data
+ENTRY(exception_table)
+       .rept   0x400>>1
+        .long  uninitialised_exception
+       .endr
+       .previous
+
+###############################################################################
+#
+# Change an entry in the exception table
+# - D0 exception code, D1 handler
+#
+###############################################################################
+ENTRY(set_excp_vector)
+       lsr     1,d0
+       add     exception_table,d0
+       mov     d1,(d0)
+       mov     4,d1
+#if defined(CONFIG_MN10300_CACHE_WBACK)
+       jmp     mn10300_dcache_flush_inv_range2
+#else
+       ret     [],0
+#endif
+
+###############################################################################
+#
+# System call table
+#
+###############################################################################
+       .data
+ENTRY(sys_call_table)
+       .long sys_restart_syscall       /* 0 */
+       .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_lchown16
+       .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    /* old sys_olduname */
+       .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 */
+       .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    /* old sys_uname */
+       .long sys_ni_syscall    /* 110 - iopl */
+       .long sys_vhangup
+       .long sys_ni_syscall    /* old "idle" system call */
+       .long sys_ni_syscall    /* vm86old */
+       .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_ni_syscall    /* modify_ldt */
+       .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    /* reserved 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_ni_syscall    /* vm86 */
+       .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_chown16
+       .long sys_getcwd
+       .long sys_capget
+       .long sys_capset        /* 185 */
+       .long sys_sigaltstack
+       .long sys_sendfile
+       .long sys_ni_syscall    /* reserved for streams1 */
+       .long sys_ni_syscall    /* reserved for 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_lchown
+       .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_chown
+       .long sys_setuid
+       .long sys_setgid
+       .long sys_setfsuid      /* 215 */
+       .long sys_setfsgid
+       .long sys_pivot_root
+       .long sys_mincore
+       .long sys_madvise
+       .long sys_getdents64    /* 220 */
+       .long sys_fcntl64
+       .long sys_ni_syscall    /* reserved for TUX */
+       .long sys_ni_syscall
+       .long sys_gettid
+       .long sys_readahead     /* 225 */
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr
+       .long sys_getxattr
+       .long sys_lgetxattr     /* 230 */
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr
+       .long sys_flistxattr
+       .long sys_removexattr   /* 235 */
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_tkill
+       .long sys_sendfile64
+       .long sys_futex         /* 240 */
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_ni_syscall    /* sys_set_thread_area */
+       .long sys_ni_syscall    /* sys_get_thread_area */
+       .long sys_io_setup      /* 245 */
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit
+       .long sys_io_cancel
+       .long sys_fadvise64     /* 250 */
+       .long sys_ni_syscall
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl     /* 255 */
+       .long sys_epoll_wait
+       .long sys_remap_file_pages
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime         /* 260 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime         /* 265 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill                /* 270 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_ni_syscall    /* sys_vserver */
+       .long sys_mbind
+       .long sys_get_mempolicy         /* 275 */
+       .long sys_set_mempolicy
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive       /* 280 */
+       .long sys_mq_notify
+       .long sys_mq_getsetattr
+       .long sys_kexec_load
+       .long sys_waitid
+       .long sys_ni_syscall            /* 285 */ /* available */
+       .long sys_add_key
+       .long sys_request_key
+       .long sys_keyctl
+       .long sys_cacheflush
+       .long sys_ioprio_set            /* 290 */
+       .long sys_ioprio_get
+       .long sys_inotify_init
+       .long sys_inotify_add_watch
+       .long sys_inotify_rm_watch
+       .long sys_migrate_pages         /* 295 */
+       .long sys_openat
+       .long sys_mkdirat
+       .long sys_mknodat
+       .long sys_fchownat
+       .long sys_futimesat             /* 300 */
+       .long sys_fstatat64
+       .long sys_unlinkat
+       .long sys_renameat
+       .long sys_linkat
+       .long sys_symlinkat             /* 305 */
+       .long sys_readlinkat
+       .long sys_fchmodat
+       .long sys_faccessat
+       .long sys_pselect6
+       .long sys_ppoll                 /* 310 */
+       .long sys_unshare
+       .long sys_set_robust_list
+       .long sys_get_robust_list
+       .long sys_splice
+       .long sys_sync_file_range       /* 315 */
+       .long sys_tee
+       .long sys_vmsplice
+       .long sys_move_pages
+       .long sys_getcpu
+       .long sys_epoll_pwait           /* 320 */
+       .long sys_utimensat
+       .long sys_signalfd
+       .long sys_timerfd_create
+       .long sys_eventfd
+       .long sys_fallocate             /* 325 */
+       .long sys_timerfd_settime
+       .long sys_timerfd_gettime
+
+
+nr_syscalls=(.-sys_call_table)/4
diff --git a/arch/mn10300/kernel/fpu-low.S b/arch/mn10300/kernel/fpu-low.S
new file mode 100644 (file)
index 0000000..96cfd47
--- /dev/null
@@ -0,0 +1,197 @@
+/* MN10300 Low level FPU management operations
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <asm/cpu-regs.h>
+
+###############################################################################
+#
+# void fpu_init_state(void)
+# - initialise the FPU
+#
+###############################################################################
+       .globl  fpu_init_state
+       .type   fpu_init_state,@function
+fpu_init_state:
+       mov     epsw,d0
+       or      EPSW_FE,epsw
+
+#ifdef CONFIG_MN10300_PROC_MN103E010
+       nop
+       nop
+       nop
+#endif
+       fmov    0,fs0
+       fmov    fs0,fs1
+       fmov    fs0,fs2
+       fmov    fs0,fs3
+       fmov    fs0,fs4
+       fmov    fs0,fs5
+       fmov    fs0,fs6
+       fmov    fs0,fs7
+       fmov    fs0,fs8
+       fmov    fs0,fs9
+       fmov    fs0,fs10
+       fmov    fs0,fs11
+       fmov    fs0,fs12
+       fmov    fs0,fs13
+       fmov    fs0,fs14
+       fmov    fs0,fs15
+       fmov    fs0,fs16
+       fmov    fs0,fs17
+       fmov    fs0,fs18
+       fmov    fs0,fs19
+       fmov    fs0,fs20
+       fmov    fs0,fs21
+       fmov    fs0,fs22
+       fmov    fs0,fs23
+       fmov    fs0,fs24
+       fmov    fs0,fs25
+       fmov    fs0,fs26
+       fmov    fs0,fs27
+       fmov    fs0,fs28
+       fmov    fs0,fs29
+       fmov    fs0,fs30
+       fmov    fs0,fs31
+       fmov    FPCR_INIT,fpcr
+
+#ifdef CONFIG_MN10300_PROC_MN103E010
+       nop
+       nop
+       nop
+#endif
+       mov     d0,epsw
+       ret     [],0
+
+       .size   fpu_init_state,.-fpu_init_state
+
+###############################################################################
+#
+# void fpu_save(struct fpu_state_struct *)
+# - save the fpu state
+# - note that an FPU Operational exception might occur during this process
+#
+###############################################################################
+       .globl  fpu_save
+       .type   fpu_save,@function
+fpu_save:
+       mov     epsw,d1
+       or      EPSW_FE,epsw            /* enable the FPU so we can access it */
+
+#ifdef CONFIG_MN10300_PROC_MN103E010
+       nop
+       nop
+#endif
+       mov     d0,a0
+       fmov    fs0,(a0+)
+       fmov    fs1,(a0+)
+       fmov    fs2,(a0+)
+       fmov    fs3,(a0+)
+       fmov    fs4,(a0+)
+       fmov    fs5,(a0+)
+       fmov    fs6,(a0+)
+       fmov    fs7,(a0+)
+       fmov    fs8,(a0+)
+       fmov    fs9,(a0+)
+       fmov    fs10,(a0+)
+       fmov    fs11,(a0+)
+       fmov    fs12,(a0+)
+       fmov    fs13,(a0+)
+       fmov    fs14,(a0+)
+       fmov    fs15,(a0+)
+       fmov    fs16,(a0+)
+       fmov    fs17,(a0+)
+       fmov    fs18,(a0+)
+       fmov    fs19,(a0+)
+       fmov    fs20,(a0+)
+       fmov    fs21,(a0+)
+       fmov    fs22,(a0+)
+       fmov    fs23,(a0+)
+       fmov    fs24,(a0+)
+       fmov    fs25,(a0+)
+       fmov    fs26,(a0+)
+       fmov    fs27,(a0+)
+       fmov    fs28,(a0+)
+       fmov    fs29,(a0+)
+       fmov    fs30,(a0+)
+       fmov    fs31,(a0+)
+       fmov    fpcr,d0
+       mov     d0,(a0)
+#ifdef CONFIG_MN10300_PROC_MN103E010
+       nop
+       nop
+#endif
+
+       mov     d1,epsw
+       ret     [],0
+
+       .size   fpu_save,.-fpu_save
+
+###############################################################################
+#
+# void fpu_restore(struct fpu_state_struct *)
+# - restore the fpu state
+# - note that an FPU Operational exception might occur during this process
+#
+###############################################################################
+       .globl  fpu_restore
+       .type   fpu_restore,@function
+fpu_restore:
+       mov     epsw,d1
+       or      EPSW_FE,epsw            /* enable the FPU so we can access it */
+
+#ifdef CONFIG_MN10300_PROC_MN103E010
+       nop
+       nop
+#endif
+       mov     d0,a0
+       fmov    (a0+),fs0
+       fmov    (a0+),fs1
+       fmov    (a0+),fs2
+       fmov    (a0+),fs3
+       fmov    (a0+),fs4
+       fmov    (a0+),fs5
+       fmov    (a0+),fs6
+       fmov    (a0+),fs7
+       fmov    (a0+),fs8
+       fmov    (a0+),fs9
+       fmov    (a0+),fs10
+       fmov    (a0+),fs11
+       fmov    (a0+),fs12
+       fmov    (a0+),fs13
+       fmov    (a0+),fs14
+       fmov    (a0+),fs15
+       fmov    (a0+),fs16
+       fmov    (a0+),fs17
+       fmov    (a0+),fs18
+       fmov    (a0+),fs19
+       fmov    (a0+),fs20
+       fmov    (a0+),fs21
+       fmov    (a0+),fs22
+       fmov    (a0+),fs23
+       fmov    (a0+),fs24
+       fmov    (a0+),fs25
+       fmov    (a0+),fs26
+       fmov    (a0+),fs27
+       fmov    (a0+),fs28
+       fmov    (a0+),fs29
+       fmov    (a0+),fs30
+       fmov    (a0+),fs31
+       mov     (a0),d0
+       fmov    d0,fpcr
+#ifdef CONFIG_MN10300_PROC_MN103E010
+       nop
+       nop
+       nop
+#endif
+
+       mov     d1,epsw
+       ret     [],0
+
+       .size   fpu_restore,.-fpu_restore
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c
new file mode 100644 (file)
index 0000000..e705f25
--- /dev/null
@@ -0,0 +1,223 @@
+/* MN10300 FPU management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <asm/uaccess.h>
+#include <asm/fpu.h>
+#include <asm/elf.h>
+#include <asm/exceptions.h>
+
+struct task_struct *fpu_state_owner;
+
+/*
+ * handle an exception due to the FPU being disabled
+ */
+asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code)
+{
+       struct task_struct *tsk = current;
+
+       if (!user_mode(regs))
+               die_if_no_fixup("An FPU Disabled exception happened in"
+                               " kernel space\n",
+                               regs, code);
+
+#ifdef CONFIG_FPU
+       preempt_disable();
+
+       /* transfer the last process's FPU state to memory */
+       if (fpu_state_owner) {
+               fpu_save(&fpu_state_owner->thread.fpu_state);
+               fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
+       }
+
+       /* the current process now owns the FPU state */
+       fpu_state_owner = tsk;
+       regs->epsw |= EPSW_FE;
+
+       /* load the FPU with the current process's FPU state or invent a new
+        * clean one if the process doesn't have one */
+       if (is_using_fpu(tsk)) {
+               fpu_restore(&tsk->thread.fpu_state);
+       } else {
+               fpu_init_state();
+               set_using_fpu(tsk);
+       }
+
+       preempt_enable();
+#else
+       {
+               siginfo_t info;
+
+               info.si_signo = SIGFPE;
+               info.si_errno = 0;
+               info.si_addr = (void *) tsk->thread.uregs->pc;
+               info.si_code = FPE_FLTINV;
+
+               force_sig_info(SIGFPE, &info, tsk);
+       }
+#endif  /* CONFIG_FPU */
+}
+
+/*
+ * handle an FPU operational exception
+ * - there's a possibility that if the FPU is asynchronous, the signal might
+ *   be meant for a process other than the current one
+ */
+asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
+{
+       struct task_struct *tsk = fpu_state_owner;
+       siginfo_t info;
+
+       if (!user_mode(regs))
+               die_if_no_fixup("An FPU Operation exception happened in"
+                               " kernel space\n",
+                               regs, code);
+
+       if (!tsk)
+               die_if_no_fixup("An FPU Operation exception happened,"
+                               " but the FPU is not in use",
+                               regs, code);
+
+       info.si_signo = SIGFPE;
+       info.si_errno = 0;
+       info.si_addr = (void *) tsk->thread.uregs->pc;
+       info.si_code = FPE_FLTINV;
+
+#ifdef CONFIG_FPU
+       {
+               u32 fpcr;
+
+               /* get FPCR (we need to enable the FPU whilst we do this) */
+               asm volatile("  or      %1,epsw         \n"
+#ifdef CONFIG_MN10300_PROC_MN103E010
+                            "  nop                     \n"
+                            "  nop                     \n"
+                            "  nop                     \n"
+#endif
+                            "  fmov    fpcr,%0         \n"
+#ifdef CONFIG_MN10300_PROC_MN103E010
+                            "  nop                     \n"
+                            "  nop                     \n"
+                            "  nop                     \n"
+#endif
+                            "  and     %2,epsw         \n"
+                            : "=&d"(fpcr)
+                            : "i"(EPSW_FE), "i"(~EPSW_FE)
+                            );
+
+               if (fpcr & FPCR_EC_Z)
+                       info.si_code = FPE_FLTDIV;
+               else if (fpcr & FPCR_EC_O)
+                       info.si_code = FPE_FLTOVF;
+               else if (fpcr & FPCR_EC_U)
+                       info.si_code = FPE_FLTUND;
+               else if (fpcr & FPCR_EC_I)
+                       info.si_code = FPE_FLTRES;
+       }
+#endif
+
+       force_sig_info(SIGFPE, &info, tsk);
+}
+
+/*
+ * save the FPU state to a signal context
+ */
+int fpu_setup_sigcontext(struct fpucontext *fpucontext)
+{
+#ifdef CONFIG_FPU
+       struct task_struct *tsk = current;
+
+       if (!is_using_fpu(tsk))
+               return 0;
+
+       /* transfer the current FPU state to memory and cause fpu_init() to be
+        * triggered by the next attempted FPU operation by the current
+        * process.
+        */
+       preempt_disable();
+
+       if (fpu_state_owner == tsk) {
+               fpu_save(&tsk->thread.fpu_state);
+               fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
+               fpu_state_owner = NULL;
+       }
+
+       preempt_enable();
+
+       /* we no longer have a valid current FPU state */
+       clear_using_fpu(tsk);
+
+       /* transfer the saved FPU state onto the userspace stack */
+       if (copy_to_user(fpucontext,
+                        &tsk->thread.fpu_state,
+                        min(sizeof(struct fpu_state_struct),
+                            sizeof(struct fpucontext))))
+               return -1;
+
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+/*
+ * kill a process's FPU state during restoration after signal handling
+ */
+void fpu_kill_state(struct task_struct *tsk)
+{
+#ifdef CONFIG_FPU
+       /* disown anything left in the FPU */
+       preempt_disable();
+
+       if (fpu_state_owner == tsk) {
+               fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
+               fpu_state_owner = NULL;
+       }
+
+       preempt_enable();
+#endif
+       /* we no longer have a valid current FPU state */
+       clear_using_fpu(tsk);
+}
+
+/*
+ * restore the FPU state from a signal context
+ */
+int fpu_restore_sigcontext(struct fpucontext *fpucontext)
+{
+       struct task_struct *tsk = current;
+       int ret;
+
+       /* load up the old FPU state */
+       ret = copy_from_user(&tsk->thread.fpu_state,
+                            fpucontext,
+                            min(sizeof(struct fpu_state_struct),
+                                sizeof(struct fpucontext)));
+       if (!ret)
+               set_using_fpu(tsk);
+
+       return ret;
+}
+
+/*
+ * fill in the FPU structure for a core dump
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg)
+{
+       struct task_struct *tsk = current;
+       int fpvalid;
+
+       fpvalid = is_using_fpu(tsk);
+       if (fpvalid) {
+               unlazy_fpu(tsk);
+               memcpy(fpreg, &tsk->thread.fpu_state, sizeof(*fpreg));
+       }
+
+       return fpvalid;
+}
diff --git a/arch/mn10300/kernel/gdb-cache.S b/arch/mn10300/kernel/gdb-cache.S
new file mode 100644 (file)
index 0000000..1108bad
--- /dev/null
@@ -0,0 +1,105 @@
+###############################################################################
+#
+# MN10300 Low-level cache purging routines for gdbstub
+#
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/cache.h>
+#include <asm/cpu-regs.h>
+#include <asm/exceptions.h>
+#include <asm/frame.inc>
+#include <asm/serial-regs.h>
+
+       .text
+
+###############################################################################
+#
+# GDB stub cache purge
+#
+###############################################################################
+       .type   gdbstub_purge_cache,@function
+ENTRY(gdbstub_purge_cache)
+       #######################################################################
+       # read the addresses tagged in the cache's tag RAM and attempt to flush
+       # those addresses specifically
+       # - we rely on the hardware to filter out invalid tag entry addresses
+       mov     DCACHE_TAG(0,0),a0              # dcache tag RAM access address
+       mov     DCACHE_PURGE(0,0),a1            # dcache purge request address
+       mov     L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries
+
+mn10300_dcache_flush_loop:
+       mov     (a0),d0
+       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+       or      L1_CACHE_TAG_VALID,d0           # retain valid entries in the
+                                               # cache
+       mov     d0,(a1)                         # conditional purge
+
+mn10300_dcache_flush_skip:
+       add     L1_CACHE_BYTES,a0
+       add     L1_CACHE_BYTES,a1
+       add     -1,d1
+       bne     mn10300_dcache_flush_loop
+
+;;     # unconditionally flush and invalidate the dcache
+;;     mov     DCACHE_PURGE(0,0),a1            # dcache purge request address
+;;     mov     L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1     # total number of
+;;                                                     # entries
+;;
+;; gdbstub_purge_cache__dcache_loop:
+;;     mov     (a1),d0                         # unconditional purge
+;;
+;;     add     L1_CACHE_BYTES,a1
+;;     add     -1,d1
+;;     bne     gdbstub_purge_cache__dcache_loop
+
+       #######################################################################
+       # now invalidate the icache
+       mov     CHCTR,a0
+       movhu   (a0),a1
+
+       mov     epsw,d1
+       and     ~EPSW_IE,epsw
+       nop
+       nop
+
+       # disable the icache
+       and     ~CHCTR_ICEN,d0
+       movhu   d0,(a0)
+
+       # and wait for it to calm down
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # invalidate
+       or      CHCTR_ICINV,d0
+       movhu   d0,(a0)
+
+       # wait for the cache to finish
+       mov     CHCTR,a0
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # and reenable it
+       movhu   a1,(a0)
+       movhu   (a0),d0                 # read back to flush
+                                       # (SIGILLs all over without this)
+
+       mov     d1,epsw
+
+       ret     [],0
+
+       .size   gdbstub_purge_cache,.-gdbstub_purge_cache
diff --git a/arch/mn10300/kernel/gdb-io-serial-low.S b/arch/mn10300/kernel/gdb-io-serial-low.S
new file mode 100644 (file)
index 0000000..c68dcd0
--- /dev/null
@@ -0,0 +1,90 @@
+###############################################################################
+#
+# 16550 serial Rx interrupt handler for gdbstub I/O
+#
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/cpu-regs.h>
+#include <asm/thread_info.h>
+#include <asm/frame.inc>
+#include <asm/intctl-regs.h>
+#include <asm/unit/serial.h>
+
+       .text
+
+###############################################################################
+#
+# GDB stub serial receive interrupt entry point
+# - intended to run at interrupt priority 0
+#
+###############################################################################
+       .globl  gdbstub_io_rx_handler
+       .type   gdbstub_io_rx_handler,@function
+gdbstub_io_rx_handler:
+       movm    [d2,d3,a2,a3],(sp)
+
+#if 1
+       movbu   (GDBPORT_SERIAL_IIR),d2
+#endif
+
+       mov     (gdbstub_rx_inp),a3
+gdbstub_io_rx_more:
+       mov     a3,a2
+       add     2,a3
+       and     0x00000fff,a3
+       mov     (gdbstub_rx_outp),d3
+       cmp     a3,d3
+       beq     gdbstub_io_rx_overflow
+
+       movbu   (GDBPORT_SERIAL_LSR),d3
+       btst    UART_LSR_DR,d3
+       beq     gdbstub_io_rx_done
+       movbu   (GDBPORT_SERIAL_RX),d2
+       movbu   d3,(gdbstub_rx_buffer+1,a2)
+       movbu   d2,(gdbstub_rx_buffer,a2)
+       mov     a3,(gdbstub_rx_inp)
+       bra     gdbstub_io_rx_more
+
+gdbstub_io_rx_done:
+       mov     GxICR_DETECT,d2
+       movbu   d2,(XIRQxICR(GDBPORT_SERIAL_IRQ))       # ACK the interrupt
+       movhu   (XIRQxICR(GDBPORT_SERIAL_IRQ)),d2       # flush
+       movm    (sp),[d2,d3,a2,a3]
+       bset    0x01,(gdbstub_busy)
+       beq     gdbstub_io_rx_enter
+       rti
+
+gdbstub_io_rx_overflow:
+       bset    0x01,(gdbstub_rx_overflow)
+       bra     gdbstub_io_rx_done
+
+gdbstub_io_rx_enter:
+       or      EPSW_IE|EPSW_IM_1,epsw
+       add     -4,sp
+       SAVE_ALL
+
+       mov     0xffffffff,d0
+       mov     d0,(REG_ORIG_D0,fp)
+       mov     0x280,d1
+
+       mov     fp,d0
+       call    gdbstub_rx_irq[],0      # gdbstub_rx_irq(regs,excep)
+
+       and     ~EPSW_IE,epsw
+       bclr    0x01,(gdbstub_busy)
+
+       .globl gdbstub_return
+gdbstub_return:
+       RESTORE_ALL
+
+       .size   gdbstub_io_rx_handler,.-gdbstub_io_rx_handler
diff --git a/arch/mn10300/kernel/gdb-io-serial.c b/arch/mn10300/kernel/gdb-io-serial.c
new file mode 100644 (file)
index 0000000..9a6d4e8
--- /dev/null
@@ -0,0 +1,155 @@
+/* 16550 serial driver for gdbstub I/O
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/nmi.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/gdb-stub.h>
+#include <asm/exceptions.h>
+#include <asm/serial-regs.h>
+#include <asm/unit/serial.h>
+
+/*
+ * initialise the GDB stub
+ */
+void gdbstub_io_init(void)
+{
+       u16 tmp;
+
+       /* set up the serial port */
+       GDBPORT_SERIAL_LCR = UART_LCR_WLEN8; /* 1N8 */
+       GDBPORT_SERIAL_FCR = (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+                             UART_FCR_CLEAR_XMIT);
+
+       FLOWCTL_CLEAR(DTR);
+       FLOWCTL_SET(RTS);
+
+       gdbstub_io_set_baud(115200);
+
+       /* we want to get serial receive interrupts */
+       XIRQxICR(GDBPORT_SERIAL_IRQ) = 0;
+       tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
+
+       IVAR0 = EXCEP_IRQ_LEVEL0;
+       set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
+
+       XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST;
+       XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0;
+       tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
+
+       GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI;
+
+       /* permit level 0 IRQs to take place */
+       asm volatile(
+               "       and %0,epsw     \n"
+               "       or %1,epsw      \n"
+               :
+               : "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1)
+               );
+}
+
+/*
+ * set up the GDB stub serial port baud rate timers
+ */
+void gdbstub_io_set_baud(unsigned baud)
+{
+       unsigned value;
+       u8 lcr;
+
+       value = 18432000 / 16 / baud;
+
+       lcr = GDBPORT_SERIAL_LCR;
+       GDBPORT_SERIAL_LCR |= UART_LCR_DLAB;
+       GDBPORT_SERIAL_DLL = value & 0xff;
+       GDBPORT_SERIAL_DLM = (value >> 8) & 0xff;
+       GDBPORT_SERIAL_LCR = lcr;
+}
+
+/*
+ * wait for a character to come from the debugger
+ */
+int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
+{
+       unsigned ix;
+       u8 ch, st;
+
+       *_ch = 0xff;
+
+       if (gdbstub_rx_unget) {
+               *_ch = gdbstub_rx_unget;
+               gdbstub_rx_unget = 0;
+               return 0;
+       }
+
+ try_again:
+       /* pull chars out of the buffer */
+       ix = gdbstub_rx_outp;
+       if (ix == gdbstub_rx_inp) {
+               if (nonblock)
+                       return -EAGAIN;
+#ifdef CONFIG_MN10300_WD_TIMER
+               watchdog_alert_counter = 0;
+#endif /* CONFIG_MN10300_WD_TIMER */
+               goto try_again;
+       }
+
+       ch = gdbstub_rx_buffer[ix++];
+       st = gdbstub_rx_buffer[ix++];
+       gdbstub_rx_outp = ix & 0x00000fff;
+
+       if (st & UART_LSR_BI) {
+               gdbstub_proto("### GDB Rx Break Detected ###\n");
+               return -EINTR;
+       } else if (st & (UART_LSR_FE | UART_LSR_OE | UART_LSR_PE)) {
+               gdbstub_proto("### GDB Rx Error (st=%02x) ###\n", st);
+               return -EIO;
+       } else {
+               gdbstub_proto("### GDB Rx %02x (st=%02x) ###\n", ch, st);
+               *_ch = ch & 0x7f;
+               return 0;
+       }
+}
+
+/*
+ * send a character to the debugger
+ */
+void gdbstub_io_tx_char(unsigned char ch)
+{
+       FLOWCTL_SET(DTR);
+       LSR_WAIT_FOR(THRE);
+       /* FLOWCTL_WAIT_FOR(CTS); */
+
+       if (ch == 0x0a) {
+               GDBPORT_SERIAL_TX = 0x0d;
+               LSR_WAIT_FOR(THRE);
+               /* FLOWCTL_WAIT_FOR(CTS); */
+       }
+       GDBPORT_SERIAL_TX = ch;
+
+       FLOWCTL_CLEAR(DTR);
+}
+
+/*
+ * send a character to the debugger
+ */
+void gdbstub_io_tx_flush(void)
+{
+       LSR_WAIT_FOR(TEMT);
+       LSR_WAIT_FOR(THRE);
+       FLOWCTL_CLEAR(DTR);
+}
diff --git a/arch/mn10300/kernel/gdb-io-ttysm-low.S b/arch/mn10300/kernel/gdb-io-ttysm-low.S
new file mode 100644 (file)
index 0000000..677c787
--- /dev/null
@@ -0,0 +1,93 @@
+###############################################################################
+#
+# MN10300 On-chip serial Rx interrupt handler for GDB stub I/O
+#
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <asm/frame.inc>
+#include <asm/intctl-regs.h>
+#include <asm/unit/serial.h>
+#include "mn10300-serial.h"
+
+       .text
+
+###############################################################################
+#
+# GDB stub serial receive interrupt entry point
+# - intended to run at interrupt priority 0
+#
+###############################################################################
+       .globl  gdbstub_io_rx_handler
+       .type   gdbstub_io_rx_handler,@function
+gdbstub_io_rx_handler:
+       movm    [d2,d3,a2,a3],(sp)
+
+       mov     (gdbstub_rx_inp),a3
+gdbstub_io_rx_more:
+       mov     a3,a2
+       add     2,a3
+       and     PAGE_SIZE_asm-1,a3
+       mov     (gdbstub_rx_outp),d3
+       cmp     a3,d3
+       beq     gdbstub_io_rx_overflow
+
+       movbu   (SCgSTR),d3
+       btst    SC01STR_RBF,d3
+       beq     gdbstub_io_rx_done
+       movbu   (SCgRXB),d2
+       movbu   d3,(gdbstub_rx_buffer+1,a2)
+       movbu   d2,(gdbstub_rx_buffer,a2)
+       mov     a3,(gdbstub_rx_inp)
+       bra     gdbstub_io_rx_more
+
+gdbstub_io_rx_done:
+       mov     GxICR_DETECT,d2
+       movbu   d2,(GxICR(SCgRXIRQ))    # ACK the interrupt
+       movhu   (GxICR(SCgRXIRQ)),d2    # flush
+
+       movm    (sp),[d2,d3,a2,a3]
+       bset    0x01,(gdbstub_busy)
+       beq     gdbstub_io_rx_enter
+       rti
+
+gdbstub_io_rx_overflow:
+       bset    0x01,(gdbstub_rx_overflow)
+       bra     gdbstub_io_rx_done
+
+###############################################################################
+#
+# debugging interrupt - enter the GDB stub proper
+#
+###############################################################################
+gdbstub_io_rx_enter:
+       or      EPSW_IE|EPSW_IM_1,epsw
+       add     -4,sp
+       SAVE_ALL
+
+       mov     0xffffffff,d0
+       mov     d0,(REG_ORIG_D0,fp)
+       mov     0x280,d1
+
+       mov     fp,d0
+       call    gdbstub_rx_irq[],0      # gdbstub_io_rx_irq(regs,excep)
+
+       and     ~EPSW_IE,epsw
+       bclr    0x01,(gdbstub_busy)
+
+       .globl gdbstub_return
+gdbstub_return:
+       RESTORE_ALL
+
+       .size   gdbstub_io_rx_handler,.-gdbstub_io_rx_handler
diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c
new file mode 100644 (file)
index 0000000..c545159
--- /dev/null
@@ -0,0 +1,299 @@
+/* MN10300 On-chip serial driver for gdbstub I/O
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/gdb-stub.h>
+#include <asm/exceptions.h>
+#include <asm/unit/clock.h>
+#include "mn10300-serial.h"
+
+#if defined(CONFIG_GDBSTUB_ON_TTYSM0)
+struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif0;
+#elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
+struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif1;
+#else
+struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;
+#endif
+
+
+/*
+ * initialise the GDB stub I/O routines
+ */
+void __init gdbstub_io_init(void)
+{
+       uint16_t scxctr;
+       int tmp;
+
+       switch (gdbstub_port->clock_src) {
+       case MNSCx_CLOCK_SRC_IOCLK:
+               gdbstub_port->ioclk = MN10300_IOCLK;
+               break;
+
+#ifdef MN10300_IOBCLK
+       case MNSCx_CLOCK_SRC_IOBCLK:
+               gdbstub_port->ioclk = MN10300_IOBCLK;
+               break;
+#endif
+       default:
+               BUG();
+       }
+
+       /* set up the serial port */
+       gdbstub_io_set_baud(115200);
+
+       /* we want to get serial receive interrupts */
+       set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0);
+       set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0);
+       set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
+
+       *gdbstub_port->rx_icr |= GxICR_ENABLE;
+       tmp = *gdbstub_port->rx_icr;
+
+       /* enable the device */
+       scxctr = SC01CTR_CLN_8BIT;      /* 1N8 */
+       switch (gdbstub_port->div_timer) {
+       case MNSCx_DIV_TIMER_16BIT:
+               scxctr |= SC0CTR_CK_TM8UFLOW_8; /* == SC1CTR_CK_TM9UFLOW_8
+                                                  == SC2CTR_CK_TM10UFLOW_8 */
+               break;
+
+       case MNSCx_DIV_TIMER_8BIT:
+               scxctr |= SC0CTR_CK_TM2UFLOW_8;
+               break;
+       }
+
+       scxctr |= SC01CTR_TXE | SC01CTR_RXE;
+
+       *gdbstub_port->_control = scxctr;
+       tmp = *gdbstub_port->_control;
+
+       /* permit level 0 IRQs only */
+       asm volatile(
+               "       and %0,epsw     \n"
+               "       or %1,epsw      \n"
+               :
+               : "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1)
+               );
+}
+
+/*
+ * set up the GDB stub serial port baud rate timers
+ */
+void gdbstub_io_set_baud(unsigned baud)
+{
+       const unsigned bits = 10; /* 1 [start] + 8 [data] + 0 [parity] +
+                                  * 1 [stop] */
+       unsigned long ioclk = gdbstub_port->ioclk;
+       unsigned xdiv, tmp;
+       uint16_t tmxbr;
+       uint8_t tmxmd;
+
+       if (!baud) {
+               baud = 9600;
+       } else if (baud == 134) {
+               baud = 269;     /* 134 is really 134.5 */
+               xdiv = 2;
+       }
+
+try_alternative:
+       xdiv = 1;
+
+       switch (gdbstub_port->div_timer) {
+       case MNSCx_DIV_TIMER_16BIT:
+               tmxmd = TM8MD_SRC_IOCLK;
+               tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
+               if (tmp > 0 && tmp <= 65535)
+                       goto timer_okay;
+
+               tmxmd = TM8MD_SRC_IOCLK_8;
+               tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
+               if (tmp > 0 && tmp <= 65535)
+                       goto timer_okay;
+
+               tmxmd = TM8MD_SRC_IOCLK_32;
+               tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
+               if (tmp > 0 && tmp <= 65535)
+                       goto timer_okay;
+
+               break;
+
+       case MNSCx_DIV_TIMER_8BIT:
+               tmxmd = TM2MD_SRC_IOCLK;
+               tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
+               if (tmp > 0 && tmp <= 255)
+                       goto timer_okay;
+
+               tmxmd = TM2MD_SRC_IOCLK_8;
+               tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
+               if (tmp > 0 && tmp <= 255)
+                       goto timer_okay;
+
+               tmxmd = TM2MD_SRC_IOCLK_32;
+               tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
+               if (tmp > 0 && tmp <= 255)
+                       goto timer_okay;
+               break;
+       }
+
+       /* as a last resort, if the quotient is zero, default to 9600 bps */
+       baud = 9600;
+       goto try_alternative;
+
+timer_okay:
+       gdbstub_port->uart.timeout = (2 * bits * HZ) / baud;
+       gdbstub_port->uart.timeout += HZ / 50;
+
+       /* set the timer to produce the required baud rate */
+       switch (gdbstub_port->div_timer) {
+       case MNSCx_DIV_TIMER_16BIT:
+               *gdbstub_port->_tmxmd = 0;
+               *gdbstub_port->_tmxbr = tmxbr;
+               *gdbstub_port->_tmxmd = TM8MD_INIT_COUNTER;
+               *gdbstub_port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
+               break;
+
+       case MNSCx_DIV_TIMER_8BIT:
+               *gdbstub_port->_tmxmd = 0;
+               *(volatile u8 *) gdbstub_port->_tmxbr = (u8)tmxbr;
+               *gdbstub_port->_tmxmd = TM2MD_INIT_COUNTER;
+               *gdbstub_port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
+               break;
+       }
+}
+
+/*
+ * wait for a character to come from the debugger
+ */
+int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
+{
+       unsigned ix;
+       u8 ch, st;
+
+       *_ch = 0xff;
+
+       if (gdbstub_rx_unget) {
+               *_ch = gdbstub_rx_unget;
+               gdbstub_rx_unget = 0;
+               return 0;
+       }
+
+try_again:
+       /* pull chars out of the buffer */
+       ix = gdbstub_rx_outp;
+       if (ix == gdbstub_rx_inp) {
+               if (nonblock)
+                       return -EAGAIN;
+#ifdef CONFIG_MN10300_WD_TIMER
+               watchdog_alert_counter = 0;
+#endif /* CONFIG_MN10300_WD_TIMER */
+               goto try_again;
+       }
+
+       ch = gdbstub_rx_buffer[ix++];
+       st = gdbstub_rx_buffer[ix++];
+       gdbstub_rx_outp = ix & (PAGE_SIZE - 1);
+
+       st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |
+               SC01STR_OEF;
+
+       /* deal with what we've got
+        * - note that the UART doesn't do BREAK-detection for us
+        */
+       if (st & SC01STR_FEF && ch == 0) {
+               switch (gdbstub_port->rx_brk) {
+               case 0: gdbstub_port->rx_brk = 1;       goto try_again;
+               case 1: gdbstub_port->rx_brk = 2;       goto try_again;
+               case 2:
+                       gdbstub_port->rx_brk = 3;
+                       gdbstub_proto("### GDB MNSERIAL Rx Break Detected"
+                                     " ###\n");
+                       return -EINTR;
+               default:
+                       goto try_again;
+               }
+       } else if (st & SC01STR_FEF) {
+               if (gdbstub_port->rx_brk)
+                       goto try_again;
+
+               gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");
+               return -EIO;
+       } else if (st & SC01STR_OEF) {
+               if (gdbstub_port->rx_brk)
+                       goto try_again;
+
+               gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");
+               return -EIO;
+       } else if (st & SC01STR_PEF) {
+               if (gdbstub_port->rx_brk)
+                       goto try_again;
+
+               gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");
+               return -EIO;
+       } else {
+               /* look for the tail-end char on a break run */
+               if (gdbstub_port->rx_brk == 3) {
+                       switch (ch) {
+                       case 0xFF:
+                       case 0xFE:
+                       case 0xFC:
+                       case 0xF8:
+                       case 0xF0:
+                       case 0xE0:
+                       case 0xC0:
+                       case 0x80:
+                       case 0x00:
+                               gdbstub_port->rx_brk = 0;
+                               goto try_again;
+                       default:
+                               break;
+                       }
+               }
+
+               gdbstub_port->rx_brk = 0;
+               gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);
+               *_ch = ch & 0x7f;
+               return 0;
+       }
+}
+
+/*
+ * send a character to the debugger
+ */
+void gdbstub_io_tx_char(unsigned char ch)
+{
+       while (*gdbstub_port->_status & SC01STR_TBF)
+               continue;
+
+       if (ch == 0x0a) {
+               *(u8 *) gdbstub_port->_txb = 0x0d;
+               while (*gdbstub_port->_status & SC01STR_TBF)
+                       continue;
+       }
+
+       *(u8 *) gdbstub_port->_txb = ch;
+}
+
+/*
+ * flush the transmission buffers
+ */
+void gdbstub_io_tx_flush(void)
+{
+       while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
+               continue;
+}
diff --git a/arch/mn10300/kernel/gdb-low.S b/arch/mn10300/kernel/gdb-low.S
new file mode 100644 (file)
index 0000000..e272555
--- /dev/null
@@ -0,0 +1,115 @@
+###############################################################################
+#
+# MN10300 Low-level gdbstub routines
+#
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/cache.h>
+#include <asm/cpu-regs.h>
+#include <asm/exceptions.h>
+#include <asm/frame.inc>
+#include <asm/serial-regs.h>
+
+       .text
+
+###############################################################################
+#
+# GDB stub read memory with guard
+# - D0 holds the memory address to read
+# - D1 holds the address to store the byte into
+#
+###############################################################################
+       .globl gdbstub_read_byte_guard
+       .globl gdbstub_read_byte_cont
+ENTRY(gdbstub_read_byte)
+       mov     d0,a0
+       mov     d1,a1
+       clr     d0
+gdbstub_read_byte_guard:
+       movbu   (a0),d1
+gdbstub_read_byte_cont:
+       movbu   d1,(a1)
+       ret     [],0
+
+       .globl gdbstub_read_word_guard
+       .globl gdbstub_read_word_cont
+ENTRY(gdbstub_read_word)
+       mov     d0,a0
+       mov     d1,a1
+       clr     d0
+gdbstub_read_word_guard:
+       movhu   (a0),d1
+gdbstub_read_word_cont:
+       movhu   d1,(a1)
+       ret     [],0
+
+       .globl gdbstub_read_dword_guard
+       .globl gdbstub_read_dword_cont
+ENTRY(gdbstub_read_dword)
+       mov     d0,a0
+       mov     d1,a1
+       clr     d0
+gdbstub_read_dword_guard:
+       mov     (a0),d1
+gdbstub_read_dword_cont:
+       mov     d1,(a1)
+       ret     [],0
+
+###############################################################################
+#
+# GDB stub write memory with guard
+# - D0 holds the byte to store
+# - D1 holds the memory address to write
+#
+###############################################################################
+       .globl gdbstub_write_byte_guard
+       .globl gdbstub_write_byte_cont
+ENTRY(gdbstub_write_byte)
+       mov     d0,a0
+       mov     d1,a1
+       clr     d0
+gdbstub_write_byte_guard:
+       movbu   a0,(a1)
+gdbstub_write_byte_cont:
+       ret     [],0
+
+       .globl gdbstub_write_word_guard
+       .globl gdbstub_write_word_cont
+ENTRY(gdbstub_write_word)
+       mov     d0,a0
+       mov     d1,a1
+       clr     d0
+gdbstub_write_word_guard:
+       movhu   a0,(a1)
+gdbstub_write_word_cont:
+       ret     [],0
+
+       .globl gdbstub_write_dword_guard
+       .globl gdbstub_write_dword_cont
+ENTRY(gdbstub_write_dword)
+       mov     d0,a0
+       mov     d1,a1
+       clr     d0
+gdbstub_write_dword_guard:
+       mov     a0,(a1)
+gdbstub_write_dword_cont:
+       ret     [],0
+
+###############################################################################
+#
+# GDB stub BUG() trap
+#
+###############################################################################
+ENTRY(__gdbstub_bug_trap)
+       .byte   0xF7,0xF7       # don't use 0xFF as the JTAG unit preempts that
+       ret     [],0
diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c
new file mode 100644 (file)
index 0000000..21891c7
--- /dev/null
@@ -0,0 +1,1947 @@
+/* MN10300 GDB stub
+ *
+ * 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
+ * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ * Copyright (C) 1995 Andreas Busse
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Modified for Linux/mn10300 by David Howells <dhowells@redhat.com>
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  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 BREAK 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
+ *
+ *
+ *  ==============
+ *  MORE EXAMPLES:
+ *  ==============
+ *
+ *  For reference -- the following are the steps that one
+ *  company took (RidgeRun Inc) to get remote gdb debugging
+ *  going. In this scenario the host machine was a PC and the
+ *  target platform was a Galileo EVB64120A MIPS evaluation
+ *  board.
+ *
+ *  Step 1:
+ *  First download gdb-5.0.tar.gz from the internet.
+ *  and then build/install the package.
+ *
+ *  Example:
+ *    $ tar zxf gdb-5.0.tar.gz
+ *    $ cd gdb-5.0
+ *    $ ./configure --target=am33_2.0-linux-gnu
+ *    $ make
+ *    $ install
+ *    am33_2.0-linux-gnu-gdb
+ *
+ *  Step 2:
+ *  Configure linux for remote debugging and build it.
+ *
+ *  Example:
+ *    $ cd ~/linux
+ *    $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging>
+ *    $ make dep; make vmlinux
+ *
+ *  Step 3:
+ *  Download the kernel to the remote target and start
+ *  the kernel running. It will promptly halt and wait
+ *  for the host gdb session to connect. It does this
+ *  since the "Kernel Hacking" option has defined
+ *  CONFIG_REMOTE_DEBUG which in turn enables your calls
+ *  to:
+ *     set_debug_traps();
+ *     breakpoint();
+ *
+ *  Step 4:
+ *  Start the gdb session on the host.
+ *
+ *  Example:
+ *    $ am33_2.0-linux-gnu-gdb vmlinux
+ *    (gdb) set remotebaud 115200
+ *    (gdb) target remote /dev/ttyS1
+ *    ...at this point you are connected to
+ *       the remote target and can use gdb
+ *       in the normal fasion. Setting
+ *       breakpoints, single stepping,
+ *       printing variables, etc.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/gdb-stub.h>
+#include <asm/exceptions.h>
+#include <asm/cacheflush.h>
+#include <asm/serial-regs.h>
+#include <asm/busctl-regs.h>
+#include <asm/unit/leds.h>
+#include <asm/unit/serial.h>
+
+/* define to use F7F7 rather than FF which is subverted by JTAG debugger */
+#undef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static const char gdbstub_banner[] =
+       "Linux/MN10300 GDB Stub (c) RedHat 2007\n";
+
+u8     gdbstub_rx_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+u32    gdbstub_rx_inp;
+u32    gdbstub_rx_outp;
+u8     gdbstub_busy;
+u8     gdbstub_rx_overflow;
+u8     gdbstub_rx_unget;
+
+static u8      gdbstub_flush_caches;
+static char    input_buffer[BUFMAX];
+static char    output_buffer[BUFMAX];
+static char    trans_buffer[BUFMAX];
+
+static const char hexchars[] = "0123456789abcdef";
+
+struct gdbstub_bkpt {
+       u8      *addr;          /* address of breakpoint */
+       u8      len;            /* size of breakpoint */
+       u8      origbytes[7];   /* original bytes */
+};
+
+static struct gdbstub_bkpt gdbstub_bkpts[256];
+
+/*
+ * local prototypes
+ */
+static void getpacket(char *buffer);
+static int putpacket(char *buffer);
+static int computeSignal(enum exception_code excep);
+static int hex(unsigned char ch);
+static int hexToInt(char **ptr, int *intValue);
+static unsigned char *mem2hex(const void *mem, char *buf, int count,
+                             int may_fault);
+static const char *hex2mem(const char *buf, void *_mem, int count,
+                          int may_fault);
+
+/*
+ * 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;
+}
+
+#ifdef CONFIG_GDBSTUB_DEBUGGING
+
+void debug_to_serial(const char *p, int n)
+{
+       __debug_to_serial(p, n);
+       /* gdbstub_console_write(NULL, p, n); */
+}
+
+void gdbstub_printk(const char *fmt, ...)
+{
+       va_list args;
+       int len;
+
+       /* Emit the output into the temporary buffer */
+       va_start(args, fmt);
+       len = vsnprintf(trans_buffer, sizeof(trans_buffer), fmt, args);
+       va_end(args);
+       debug_to_serial(trans_buffer, len);
+}
+
+#endif
+
+static inline char *gdbstub_strcpy(char *dst, const char *src)
+{
+       int loop = 0;
+       while ((dst[loop] = src[loop]))
+              loop++;
+       return dst;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+       unsigned char checksum;
+       unsigned char xmitcsum;
+       unsigned char ch;
+       int count, i, ret, error;
+
+       for (;;) {
+               /*
+                * wait around for the start character,
+                * ignore all other characters
+                */
+               do {
+                       gdbstub_io_rx_char(&ch, 0);
+               } while (ch != '$');
+
+               checksum = 0;
+               xmitcsum = -1;
+               count = 0;
+               error = 0;
+
+               /*
+                * now, read until a # or end of buffer is found
+                */
+               while (count < BUFMAX) {
+                       ret = gdbstub_io_rx_char(&ch, 0);
+                       if (ret < 0)
+                               error = ret;
+
+                       if (ch == '#')
+                               break;
+                       checksum += ch;
+                       buffer[count] = ch;
+                       count++;
+               }
+
+               if (error == -EIO) {
+                       gdbstub_proto("### GDB Rx Error - Skipping packet"
+                                     " ###\n");
+                       gdbstub_proto("### GDB Tx NAK\n");
+                       gdbstub_io_tx_char('-');
+                       continue;
+               }
+
+               if (count >= BUFMAX || error)
+                       continue;
+
+               buffer[count] = 0;
+
+               /* read the checksum */
+               ret = gdbstub_io_rx_char(&ch, 0);
+               if (ret < 0)
+                       error = ret;
+               xmitcsum = hex(ch) << 4;
+
+               ret = gdbstub_io_rx_char(&ch, 0);
+               if (ret < 0)
+                       error = ret;
+               xmitcsum |= hex(ch);
+
+               if (error) {
+                       if (error == -EIO)
+                               gdbstub_io("### GDB Rx Error -"
+                                          " Skipping packet\n");
+                       gdbstub_io("### GDB Tx NAK\n");
+                       gdbstub_io_tx_char('-');
+                       continue;
+               }
+
+               /* check the checksum */
+               if (checksum != xmitcsum) {
+                       gdbstub_io("### GDB Tx NAK\n");
+                       gdbstub_io_tx_char('-');        /* failed checksum */
+                       continue;
+               }
+
+               gdbstub_proto("### GDB Rx '$%s#%02x' ###\n", buffer, checksum);
+               gdbstub_io("### GDB Tx ACK\n");
+               gdbstub_io_tx_char('+'); /* successful transfer */
+
+               /*
+                * if a sequence char is present,
+                * reply the sequence ID
+                */
+               if (buffer[2] == ':') {
+                       gdbstub_io_tx_char(buffer[0]);
+                       gdbstub_io_tx_char(buffer[1]);
+
+                       /*
+                        * remove sequence chars from buffer
+                        */
+                       count = 0;
+                       while (buffer[count])
+                               count++;
+                       for (i = 3; i <= count; i++)
+                               buffer[i - 3] = buffer[i];
+               }
+
+               break;
+       }
+}
+
+/*
+ * send the packet in buffer.
+ * - return 0 if successfully ACK'd
+ * - return 1 if abandoned due to new incoming packet
+ */
+static int putpacket(char *buffer)
+{
+       unsigned char checksum;
+       unsigned char ch;
+       int count;
+
+       /*
+        * $<packet info>#<checksum>.
+        */
+       gdbstub_proto("### GDB Tx $'%s'#?? ###\n", buffer);
+
+       do {
+               gdbstub_io_tx_char('$');
+               checksum = 0;
+               count = 0;
+
+               while ((ch = buffer[count]) != 0) {
+                       gdbstub_io_tx_char(ch);
+                       checksum += ch;
+                       count += 1;
+               }
+
+               gdbstub_io_tx_char('#');
+               gdbstub_io_tx_char(hexchars[checksum >> 4]);
+               gdbstub_io_tx_char(hexchars[checksum & 0xf]);
+
+       } while (gdbstub_io_rx_char(&ch, 0),
+                ch == '-' && (gdbstub_io("### GDB Rx NAK\n"), 0),
+                ch != '-' && ch != '+' &&
+                (gdbstub_io("### GDB Rx ??? %02x\n", ch), 0),
+                ch != '+' && ch != '$');
+
+       if (ch == '+') {
+               gdbstub_io("### GDB Rx ACK\n");
+               return 0;
+       }
+
+       gdbstub_io("### GDB Tx Abandoned\n");
+       gdbstub_rx_unget = ch;
+       return 1;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * We single-step by setting breakpoints. When an exception
+ * is handled, we need to restore the instructions hoisted
+ * when the breakpoints were set.
+ *
+ * This is where we save the original instructions.
+ */
+static struct gdb_bp_save {
+       u8      *addr;
+       u8      opcode[2];
+} step_bp[2];
+
+static const unsigned char gdbstub_insn_sizes[256] =
+{
+       /* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+       1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
+       2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */
+       1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */
+       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
+       0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1  /* f */
+};
+
+static int __gdbstub_mark_bp(u8 *addr, int ix)
+{
+       if (addr < (u8 *) 0x70000000UL)
+               return 0;
+       /* 70000000-7fffffff: vmalloc area */
+       if (addr < (u8 *) 0x80000000UL)
+               goto okay;
+       if (addr < (u8 *) 0x8c000000UL)
+               return 0;
+       /* 8c000000-93ffffff: SRAM, SDRAM */
+       if (addr < (u8 *) 0x94000000UL)
+               goto okay;
+       return 0;
+
+okay:
+       if (gdbstub_read_byte(addr + 0, &step_bp[ix].opcode[0]) < 0 ||
+           gdbstub_read_byte(addr + 1, &step_bp[ix].opcode[1]) < 0)
+               return 0;
+
+       step_bp[ix].addr = addr;
+       return 1;
+}
+
+static inline void __gdbstub_restore_bp(void)
+{
+#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+       if (step_bp[0].addr) {
+               gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0);
+               gdbstub_write_byte(step_bp[0].opcode[1], step_bp[0].addr + 1);
+       }
+       if (step_bp[1].addr) {
+               gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0);
+               gdbstub_write_byte(step_bp[1].opcode[1], step_bp[1].addr + 1);
+       }
+#else
+       if (step_bp[0].addr)
+               gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0);
+       if (step_bp[1].addr)
+               gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0);
+#endif
+
+       gdbstub_flush_caches = 1;
+
+       step_bp[0].addr         = NULL;
+       step_bp[0].opcode[0]    = 0;
+       step_bp[0].opcode[1]    = 0;
+       step_bp[1].addr         = NULL;
+       step_bp[1].opcode[0]    = 0;
+       step_bp[1].opcode[1]    = 0;
+}
+
+/*
+ * emulate single stepping by means of breakpoint instructions
+ */
+static int gdbstub_single_step(struct pt_regs *regs)
+{
+       unsigned size;
+       uint32_t x;
+       uint8_t cur, *pc, *sp;
+
+       step_bp[0].addr         = NULL;
+       step_bp[0].opcode[0]    = 0;
+       step_bp[0].opcode[1]    = 0;
+       step_bp[1].addr         = NULL;
+       step_bp[1].opcode[0]    = 0;
+       step_bp[1].opcode[1]    = 0;
+       x = 0;
+
+       pc = (u8 *) regs->pc;
+       sp = (u8 *) (regs + 1);
+       if (gdbstub_read_byte(pc, &cur) < 0)
+               return -EFAULT;
+
+       gdbstub_bkpt("Single Step from %p { %02x }\n", pc, cur);
+
+       gdbstub_flush_caches = 1;
+
+       size = gdbstub_insn_sizes[cur];
+       if (size > 0) {
+               if (!__gdbstub_mark_bp(pc + size, 0))
+                       goto fault;
+       } else {
+               switch (cur) {
+                       /* Bxx (d8,PC) */
+               case 0xc0:
+               case 0xc1:
+               case 0xc2:
+               case 0xc3:
+               case 0xc4:
+               case 0xc5:
+               case 0xc6:
+               case 0xc7:
+               case 0xc8:
+               case 0xc9:
+               case 0xca:
+                       if (gdbstub_read_byte(pc + 1, (u8 *) &x) < 0)
+                               goto fault;
+                       if (!__gdbstub_mark_bp(pc + 2, 0))
+                               goto fault;
+                       if ((x < 0 || x > 2) &&
+                           !__gdbstub_mark_bp(pc + (s8) x, 1))
+                               goto fault;
+                       break;
+
+                       /* LXX (d8,PC) */
+               case 0xd0:
+               case 0xd1:
+               case 0xd2:
+               case 0xd3:
+               case 0xd4:
+               case 0xd5:
+               case 0xd6:
+               case 0xd7:
+               case 0xd8:
+               case 0xd9:
+               case 0xda:
+                       if (!__gdbstub_mark_bp(pc + 1, 0))
+                               goto fault;
+                       if (regs->pc != regs->lar &&
+                           !__gdbstub_mark_bp((u8 *) regs->lar, 1))
+                               goto fault;
+                       break;
+
+                       /* SETLB - loads the next for bytes into the LIR
+                        * register */
+               case 0xdb:
+                       if (!__gdbstub_mark_bp(pc + 1, 0))
+                               goto fault;
+                       break;
+
+                       /* JMP (d16,PC) or CALL (d16,PC) */
+               case 0xcc:
+               case 0xcd:
+                       if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 ||
+                           gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0)
+                               goto fault;
+                       if (!__gdbstub_mark_bp(pc + (s16) x, 0))
+                               goto fault;
+                       break;
+
+                       /* JMP (d32,PC) or CALL (d32,PC) */
+               case 0xdc:
+               case 0xdd:
+                       if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 ||
+                           gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0 ||
+                           gdbstub_read_byte(pc + 3, ((u8 *) &x) + 2) < 0 ||
+                           gdbstub_read_byte(pc + 4, ((u8 *) &x) + 3) < 0)
+                               goto fault;
+                       if (!__gdbstub_mark_bp(pc + (s32) x, 0))
+                               goto fault;
+                       break;
+
+                       /* RETF */
+               case 0xde:
+                       if (!__gdbstub_mark_bp((u8 *) regs->mdr, 0))
+                               goto fault;
+                       break;
+
+                       /* RET */
+               case 0xdf:
+                       if (gdbstub_read_byte(pc + 2, (u8 *) &x) < 0)
+                               goto fault;
+                       sp += (s8)x;
+                       if (gdbstub_read_byte(sp + 0, ((u8 *) &x) + 0) < 0 ||
+                           gdbstub_read_byte(sp + 1, ((u8 *) &x) + 1) < 0 ||
+                           gdbstub_read_byte(sp + 2, ((u8 *) &x) + 2) < 0 ||
+                           gdbstub_read_byte(sp + 3, ((u8 *) &x) + 3) < 0)
+                               goto fault;
+                       if (!__gdbstub_mark_bp((u8 *) x, 0))
+                               goto fault;
+                       break;
+
+               case 0xf0:
+                       if (gdbstub_read_byte(pc + 1, &cur) < 0)
+                               goto fault;
+
+                       if (cur >= 0xf0 && cur <= 0xf7) {
+                               /* JMP (An) / CALLS (An) */
+                               switch (cur & 3) {
+                               case 0: x = regs->a0; break;
+                               case 1: x = regs->a1; break;
+                               case 2: x = regs->a2; break;
+                               case 3: x = regs->a3; break;
+                               }
+                               if (!__gdbstub_mark_bp((u8 *) x, 0))
+                                       goto fault;
+                       } else if (cur == 0xfc) {
+                               /* RETS */
+                               if (gdbstub_read_byte(
+                                           sp + 0, ((u8 *) &x) + 0) < 0 ||
+                                   gdbstub_read_byte(
+                                           sp + 1, ((u8 *) &x) + 1) < 0 ||
+                                   gdbstub_read_byte(
+                                           sp + 2, ((u8 *) &x) + 2) < 0 ||
+                                   gdbstub_read_byte(
+                                           sp + 3, ((u8 *) &x) + 3) < 0)
+                                       goto fault;
+                               if (!__gdbstub_mark_bp((u8 *) x, 0))
+                                       goto fault;
+                       } else if (cur == 0xfd) {
+                               /* RTI */
+                               if (gdbstub_read_byte(
+                                           sp + 4, ((u8 *) &x) + 0) < 0 ||
+                                   gdbstub_read_byte(
+                                           sp + 5, ((u8 *) &x) + 1) < 0 ||
+                                   gdbstub_read_byte(
+                                           sp + 6, ((u8 *) &x) + 2) < 0 ||
+                                   gdbstub_read_byte(
+                                           sp + 7, ((u8 *) &x) + 3) < 0)
+                                       goto fault;
+                               if (!__gdbstub_mark_bp((u8 *) x, 0))
+                                       goto fault;
+                       } else {
+                               if (!__gdbstub_mark_bp(pc + 2, 0))
+                                       goto fault;
+                       }
+
+                       break;
+
+                       /* potential 3-byte conditional branches */
+               case 0xf8:
+                       if (gdbstub_read_byte(pc + 1, &cur) < 0)
+                               goto fault;
+                       if (!__gdbstub_mark_bp(pc + 3, 0))
+                               goto fault;
+
+                       if (cur >= 0xe8 && cur <= 0xeb) {
+                               if (gdbstub_read_byte(
+                                           pc + 2, ((u8 *) &x) + 0) < 0)
+                                       goto fault;
+                               if ((x < 0 || x > 3) &&
+                                   !__gdbstub_mark_bp(pc + (s8) x, 1))
+                                       goto fault;
+                       }
+                       break;
+
+               case 0xfa:
+                       if (gdbstub_read_byte(pc + 1, &cur) < 0)
+                               goto fault;
+
+                       if (cur == 0xff) {
+                               /* CALLS (d16,PC) */
+                               if (gdbstub_read_byte(
+                                           pc + 2, ((u8 *) &x) + 0) < 0 ||
+                                   gdbstub_read_byte(
+                                           pc + 3, ((u8 *) &x) + 1) < 0)
+                                       goto fault;
+                               if (!__gdbstub_mark_bp(pc + (s16) x, 0))
+                                       goto fault;
+                       } else {
+                               if (!__gdbstub_mark_bp(pc + 4, 0))
+                                       goto fault;
+                       }
+                       break;
+
+               case 0xfc:
+                       if (gdbstub_read_byte(pc + 1, &cur) < 0)
+                               goto fault;
+                       if (cur == 0xff) {
+                               /* CALLS (d32,PC) */
+                               if (gdbstub_read_byte(
+                                           pc + 2, ((u8 *) &x) + 0) < 0 ||
+                                   gdbstub_read_byte(
+                                           pc + 3, ((u8 *) &x) + 1) < 0 ||
+                                   gdbstub_read_byte(
+                                           pc + 4, ((u8 *) &x) + 2) < 0 ||
+                                   gdbstub_read_byte(
+                                           pc + 5, ((u8 *) &x) + 3) < 0)
+                                       goto fault;
+                               if (!__gdbstub_mark_bp(
+                                           pc + (s32) x, 0))
+                                       goto fault;
+                       } else {
+                               if (!__gdbstub_mark_bp(
+                                           pc + 6, 0))
+                                       goto fault;
+                       }
+                       break;
+
+               }
+       }
+
+       gdbstub_bkpt("Step: %02x at %p; %02x at %p\n",
+                    step_bp[0].opcode[0], step_bp[0].addr,
+                    step_bp[1].opcode[0], step_bp[1].addr);
+
+       if (step_bp[0].addr) {
+#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+               if (gdbstub_write_byte(0xF7, step_bp[0].addr + 0) < 0 ||
+                   gdbstub_write_byte(0xF7, step_bp[0].addr + 1) < 0)
+                       goto fault;
+#else
+               if (gdbstub_write_byte(0xFF, step_bp[0].addr + 0) < 0)
+                       goto fault;
+#endif
+       }
+
+       if (step_bp[1].addr) {
+#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+               if (gdbstub_write_byte(0xF7, step_bp[1].addr + 0) < 0 ||
+                   gdbstub_write_byte(0xF7, step_bp[1].addr + 1) < 0)
+                       goto fault;
+#else
+               if (gdbstub_write_byte(0xFF, step_bp[1].addr + 0) < 0)
+                       goto fault;
+#endif
+       }
+
+       return 0;
+
+ fault:
+       /* uh-oh - silly address alert, try and restore things */
+       __gdbstub_restore_bp();
+       return -EFAULT;
+}
+
+#ifdef CONFIG_GDBSTUB_CONSOLE
+
+void gdbstub_console_write(struct console *con, const char *p, unsigned n)
+{
+       static const char gdbstub_cr[] = { 0x0d };
+       char outbuf[26];
+       int qty;
+       u8 busy;
+
+       busy = gdbstub_busy;
+       gdbstub_busy = 1;
+
+       outbuf[0] = 'O';
+
+       while (n > 0) {
+               qty = 1;
+
+               while (n > 0 && qty < 20) {
+                       mem2hex(p, outbuf + qty, 2, 0);
+                       qty += 2;
+                       if (*p == 0x0a) {
+                               mem2hex(gdbstub_cr, outbuf + qty, 2, 0);
+                               qty += 2;
+                       }
+                       p++;
+                       n--;
+               }
+
+               outbuf[qty] = 0;
+               putpacket(outbuf);
+       }
+
+       gdbstub_busy = busy;
+}
+
+static kdev_t gdbstub_console_dev(struct console *con)
+{
+       return MKDEV(1, 3); /* /dev/null */
+}
+
+static struct console gdbstub_console = {
+       .name   = "gdb",
+       .write  = gdbstub_console_write,
+       .device = gdbstub_console_dev,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+};
+
+#endif
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * - if successful, return a pointer to the last char put in buf (NUL)
+ * - in case of mem fault, return NULL
+ * may_fault is non-zero if we are reading from arbitrary memory, but is
+ * currently not used.
+ */
+static
+unsigned char *mem2hex(const void *_mem, char *buf, int count, int may_fault)
+{
+       const u8 *mem = _mem;
+       u8 ch[4];
+
+       if ((u32) mem & 1 && count >= 1) {
+               if (gdbstub_read_byte(mem, ch) != 0)
+                       return 0;
+               *buf++ = hexchars[ch[0] >> 4];
+               *buf++ = hexchars[ch[0] & 0xf];
+               mem++;
+               count--;
+       }
+
+       if ((u32) mem & 3 && count >= 2) {
+               if (gdbstub_read_word(mem, ch) != 0)
+                       return 0;
+               *buf++ = hexchars[ch[0] >> 4];
+               *buf++ = hexchars[ch[0] & 0xf];
+               *buf++ = hexchars[ch[1] >> 4];
+               *buf++ = hexchars[ch[1] & 0xf];
+               mem += 2;
+               count -= 2;
+       }
+
+       while (count >= 4) {
+               if (gdbstub_read_dword(mem, ch) != 0)
+                       return 0;
+               *buf++ = hexchars[ch[0] >> 4];
+               *buf++ = hexchars[ch[0] & 0xf];
+               *buf++ = hexchars[ch[1] >> 4];
+               *buf++ = hexchars[ch[1] & 0xf];
+               *buf++ = hexchars[ch[2] >> 4];
+               *buf++ = hexchars[ch[2] & 0xf];
+               *buf++ = hexchars[ch[3] >> 4];
+               *buf++ = hexchars[ch[3] & 0xf];
+               mem += 4;
+               count -= 4;
+       }
+
+       if (count >= 2) {
+               if (gdbstub_read_word(mem, ch) != 0)
+                       return 0;
+               *buf++ = hexchars[ch[0] >> 4];
+               *buf++ = hexchars[ch[0] & 0xf];
+               *buf++ = hexchars[ch[1] >> 4];
+               *buf++ = hexchars[ch[1] & 0xf];
+               mem += 2;
+               count -= 2;
+       }
+
+       if (count >= 1) {
+               if (gdbstub_read_byte(mem, ch) != 0)
+                       return 0;
+               *buf++ = hexchars[ch[0] >> 4];
+               *buf++ = hexchars[ch[0] & 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
+ * may_fault is non-zero if we are reading from arbitrary memory, but is
+ * currently not used.
+ */
+static
+const char *hex2mem(const char *buf, void *_mem, int count, int may_fault)
+{
+       u8 *mem = _mem;
+       union {
+               u32 val;
+               u8 b[4];
+       } ch;
+
+       if ((u32) mem & 1 && count >= 1) {
+               ch.b[0]  = hex(*buf++) << 4;
+               ch.b[0] |= hex(*buf++);
+               if (gdbstub_write_byte(ch.val, mem) != 0)
+                       return 0;
+               mem++;
+               count--;
+       }
+
+       if ((u32) mem & 3 && count >= 2) {
+               ch.b[0]  = hex(*buf++) << 4;
+               ch.b[0] |= hex(*buf++);
+               ch.b[1]  = hex(*buf++) << 4;
+               ch.b[1] |= hex(*buf++);
+               if (gdbstub_write_word(ch.val, mem) != 0)
+                       return 0;
+               mem += 2;
+               count -= 2;
+       }
+
+       while (count >= 4) {
+               ch.b[0]  = hex(*buf++) << 4;
+               ch.b[0] |= hex(*buf++);
+               ch.b[1]  = hex(*buf++) << 4;
+               ch.b[1] |= hex(*buf++);
+               ch.b[2]  = hex(*buf++) << 4;
+               ch.b[2] |= hex(*buf++);
+               ch.b[3]  = hex(*buf++) << 4;
+               ch.b[3] |= hex(*buf++);
+               if (gdbstub_write_dword(ch.val, mem) != 0)
+                       return 0;
+               mem += 4;
+               count -= 4;
+       }
+
+       if (count >= 2) {
+               ch.b[0]  = hex(*buf++) << 4;
+               ch.b[0] |= hex(*buf++);
+               ch.b[1]  = hex(*buf++) << 4;
+               ch.b[1] |= hex(*buf++);
+               if (gdbstub_write_word(ch.val, mem) != 0)
+                       return 0;
+               mem += 2;
+               count -= 2;
+       }
+
+       if (count >= 1) {
+               ch.b[0]  = hex(*buf++) << 4;
+               ch.b[0] |= hex(*buf++);
+               if (gdbstub_write_byte(ch.val, mem) != 0)
+                       return 0;
+       }
+
+       return buf;
+}
+
+/*
+ * This table contains the mapping between MN10300 exception codes, and
+ * signals, which are primarily what GDB understands.  It also indicates
+ * which hardware traps we need to commandeer when initializing the stub.
+ */
+static const struct excep_to_sig_map {
+       enum exception_code     excep;  /* MN10300 exception code */
+       unsigned char           signo;  /* Signal that we map this into */
+} excep_to_sig_map[] = {
+       { EXCEP_ITLBMISS,       SIGSEGV         },
+       { EXCEP_DTLBMISS,       SIGSEGV         },
+       { EXCEP_TRAP,           SIGTRAP         },
+       { EXCEP_ISTEP,          SIGTRAP         },
+       { EXCEP_IBREAK,         SIGTRAP         },
+       { EXCEP_OBREAK,         SIGTRAP         },
+       { EXCEP_UNIMPINS,       SIGILL          },
+       { EXCEP_UNIMPEXINS,     SIGILL          },
+       { EXCEP_MEMERR,         SIGSEGV         },
+       { EXCEP_MISALIGN,       SIGSEGV         },
+       { EXCEP_BUSERROR,       SIGBUS          },
+       { EXCEP_ILLINSACC,      SIGSEGV         },
+       { EXCEP_ILLDATACC,      SIGSEGV         },
+       { EXCEP_IOINSACC,       SIGSEGV         },
+       { EXCEP_PRIVINSACC,     SIGSEGV         },
+       { EXCEP_PRIVDATACC,     SIGSEGV         },
+       { EXCEP_FPU_DISABLED,   SIGFPE          },
+       { EXCEP_FPU_UNIMPINS,   SIGFPE          },
+       { EXCEP_FPU_OPERATION,  SIGFPE          },
+       { EXCEP_WDT,            SIGALRM         },
+       { EXCEP_NMI,            SIGQUIT         },
+       { EXCEP_IRQ_LEVEL0,     SIGINT          },
+       { EXCEP_IRQ_LEVEL1,     SIGINT          },
+       { EXCEP_IRQ_LEVEL2,     SIGINT          },
+       { EXCEP_IRQ_LEVEL3,     SIGINT          },
+       { EXCEP_IRQ_LEVEL4,     SIGINT          },
+       { EXCEP_IRQ_LEVEL5,     SIGINT          },
+       { EXCEP_IRQ_LEVEL6,     SIGINT          },
+       { 0, 0}
+};
+
+/*
+ * convert the MN10300 exception code into a UNIX signal number
+ */
+static int computeSignal(enum exception_code excep)
+{
+       const struct excep_to_sig_map *map;
+
+       for (map = excep_to_sig_map; map->signo; map++)
+               if (map->excep == excep)
+                       return map->signo;
+
+       return SIGHUP; /* default for things we don't know about */
+}
+
+static u32 gdbstub_fpcr, gdbstub_fpufs_array[32];
+
+/*
+ *
+ */
+static void gdbstub_store_fpu(void)
+{
+#ifdef CONFIG_FPU
+
+       asm volatile(
+               "or %2,epsw\n"
+#ifdef CONFIG_MN10300_PROC_MN103E010
+               "nop\n"
+               "nop\n"
+#endif
+               "mov %1, a1\n"
+               "fmov fs0,  (a1+)\n"
+               "fmov fs1,  (a1+)\n"
+               "fmov fs2,  (a1+)\n"
+               "fmov fs3,  (a1+)\n"
+               "fmov fs4,  (a1+)\n"
+               "fmov fs5,  (a1+)\n"
+               "fmov fs6,  (a1+)\n"
+               "fmov fs7,  (a1+)\n"
+               "fmov fs8,  (a1+)\n"
+               "fmov fs9,  (a1+)\n"
+               "fmov fs10, (a1+)\n"
+               "fmov fs11, (a1+)\n"
+               "fmov fs12, (a1+)\n"
+               "fmov fs13, (a1+)\n"
+               "fmov fs14, (a1+)\n"
+               "fmov fs15, (a1+)\n"
+               "fmov fs16, (a1+)\n"
+               "fmov fs17, (a1+)\n"
+               "fmov fs18, (a1+)\n"
+               "fmov fs19, (a1+)\n"
+               "fmov fs20, (a1+)\n"
+               "fmov fs21, (a1+)\n"
+               "fmov fs22, (a1+)\n"
+               "fmov fs23, (a1+)\n"
+               "fmov fs24, (a1+)\n"
+               "fmov fs25, (a1+)\n"
+               "fmov fs26, (a1+)\n"
+               "fmov fs27, (a1+)\n"
+               "fmov fs28, (a1+)\n"
+               "fmov fs29, (a1+)\n"
+               "fmov fs30, (a1+)\n"
+               "fmov fs31, (a1+)\n"
+               "fmov fpcr, %0\n"
+               : "=d"(gdbstub_fpcr)
+               : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE)
+               : "a1"
+               );
+#endif
+}
+
+/*
+ *
+ */
+static void gdbstub_load_fpu(void)
+{
+#ifdef CONFIG_FPU
+
+       asm volatile(
+               "or %1,epsw\n"
+#ifdef CONFIG_MN10300_PROC_MN103E010
+               "nop\n"
+               "nop\n"
+#endif
+               "mov %0, a1\n"
+               "fmov (a1+), fs0\n"
+               "fmov (a1+), fs1\n"
+               "fmov (a1+), fs2\n"
+               "fmov (a1+), fs3\n"
+               "fmov (a1+), fs4\n"
+               "fmov (a1+), fs5\n"
+               "fmov (a1+), fs6\n"
+               "fmov (a1+), fs7\n"
+               "fmov (a1+), fs8\n"
+               "fmov (a1+), fs9\n"
+               "fmov (a1+), fs10\n"
+               "fmov (a1+), fs11\n"
+               "fmov (a1+), fs12\n"
+               "fmov (a1+), fs13\n"
+               "fmov (a1+), fs14\n"
+               "fmov (a1+), fs15\n"
+               "fmov (a1+), fs16\n"
+               "fmov (a1+), fs17\n"
+               "fmov (a1+), fs18\n"
+               "fmov (a1+), fs19\n"
+               "fmov (a1+), fs20\n"
+               "fmov (a1+), fs21\n"
+               "fmov (a1+), fs22\n"
+               "fmov (a1+), fs23\n"
+               "fmov (a1+), fs24\n"
+               "fmov (a1+), fs25\n"
+               "fmov (a1+), fs26\n"
+               "fmov (a1+), fs27\n"
+               "fmov (a1+), fs28\n"
+               "fmov (a1+), fs29\n"
+               "fmov (a1+), fs30\n"
+               "fmov (a1+), fs31\n"
+               "fmov %2, fpcr\n"
+               :
+               : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE), "d"(gdbstub_fpcr)
+               : "a1"
+       );
+#endif
+}
+
+/*
+ * set a software breakpoint
+ */
+int gdbstub_set_breakpoint(u8 *addr, int len)
+{
+       int bkpt, loop, xloop;
+
+#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+       len = (len + 1) & ~1;
+#endif
+
+       gdbstub_bkpt("setbkpt(%p,%d)\n", addr, len);
+
+       for (bkpt = 255; bkpt >= 0; bkpt--)
+               if (!gdbstub_bkpts[bkpt].addr)
+                       break;
+       if (bkpt < 0)
+               return -ENOSPC;
+
+       for (loop = 0; loop < len; loop++)
+               if (gdbstub_read_byte(&addr[loop],
+                                     &gdbstub_bkpts[bkpt].origbytes[loop]
+                                     ) < 0)
+                       return -EFAULT;
+
+       gdbstub_flush_caches = 1;
+
+#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+       for (loop = 0; loop < len; loop++)
+               if (gdbstub_write_byte(0xF7, &addr[loop]) < 0)
+                       goto restore;
+#else
+       for (loop = 0; loop < len; loop++)
+               if (gdbstub_write_byte(0xFF, &addr[loop]) < 0)
+                       goto restore;
+#endif
+
+       gdbstub_bkpts[bkpt].addr = addr;
+       gdbstub_bkpts[bkpt].len = len;
+
+       gdbstub_bkpt("Set BKPT[%02x]: %p-%p {%02x%02x%02x%02x%02x%02x%02x}\n",
+                    bkpt,
+                    gdbstub_bkpts[bkpt].addr,
+                    gdbstub_bkpts[bkpt].addr + gdbstub_bkpts[bkpt].len - 1,
+                    gdbstub_bkpts[bkpt].origbytes[0],
+                    gdbstub_bkpts[bkpt].origbytes[1],
+                    gdbstub_bkpts[bkpt].origbytes[2],
+                    gdbstub_bkpts[bkpt].origbytes[3],
+                    gdbstub_bkpts[bkpt].origbytes[4],
+                    gdbstub_bkpts[bkpt].origbytes[5],
+                    gdbstub_bkpts[bkpt].origbytes[6]
+                    );
+
+       return 0;
+
+restore:
+       for (xloop = 0; xloop < loop; xloop++)
+               gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[xloop],
+                                  addr + xloop);
+       return -EFAULT;
+}
+
+/*
+ * clear a software breakpoint
+ */
+int gdbstub_clear_breakpoint(u8 *addr, int len)
+{
+       int bkpt, loop;
+
+#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
+       len = (len + 1) & ~1;
+#endif
+
+       gdbstub_bkpt("clearbkpt(%p,%d)\n", addr, len);
+
+       for (bkpt = 255; bkpt >= 0; bkpt--)
+               if (gdbstub_bkpts[bkpt].addr == addr &&
+                   gdbstub_bkpts[bkpt].len == len)
+                       break;
+       if (bkpt < 0)
+               return -ENOENT;
+
+       gdbstub_bkpts[bkpt].addr = NULL;
+
+       gdbstub_flush_caches = 1;
+
+       for (loop = 0; loop < len; loop++)
+               if (gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[loop],
+                                      addr + loop) < 0)
+                       return -EFAULT;
+
+       return 0;
+}
+
+/*
+ * This function does all command processing for interfacing to gdb
+ * - returns 1 if the exception should be skipped, 0 otherwise.
+ */
+static int gdbstub(struct pt_regs *regs, enum exception_code excep)
+{
+       unsigned long *stack;
+       unsigned long epsw, mdr;
+       uint32_t zero, ssp;
+       uint8_t broke;
+       char *ptr;
+       int sigval;
+       int addr;
+       int length;
+       int loop;
+
+       if (excep == EXCEP_FPU_DISABLED)
+               return 0;
+
+       gdbstub_flush_caches = 0;
+
+       mn10300_set_gdbleds(1);
+
+       asm volatile("mov mdr,%0" : "=d"(mdr));
+       asm volatile("mov epsw,%0" : "=d"(epsw));
+       asm volatile("mov %0,epsw"
+                    :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1));
+
+       gdbstub_store_fpu();
+
+#ifdef CONFIG_GDBSTUB_IMMEDIATE
+       /* skip the initial pause loop */
+       if (regs->pc == (unsigned long) __gdbstub_pause)
+               regs->pc = (unsigned long) start_kernel;
+#endif
+
+       /* if we were single stepping, restore the opcodes hoisted for the
+        * breakpoint[s] */
+       broke = 0;
+       if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) ||
+           (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc))
+               broke = 1;
+
+       __gdbstub_restore_bp();
+
+       if (gdbstub_rx_unget) {
+               sigval = SIGINT;
+               if (gdbstub_rx_unget != 3)
+                       goto packet_waiting;
+               gdbstub_rx_unget = 0;
+       }
+
+       stack = (unsigned long *) regs->sp;
+       sigval = broke ? SIGTRAP : computeSignal(excep);
+
+       /* send information about a BUG() */
+       if (!user_mode(regs) && excep == EXCEP_SYSCALL15) {
+               const struct bug_entry *bug;
+
+               bug = find_bug(regs->pc);
+               if (bug)
+                       goto found_bug;
+               length = snprintf(trans_buffer, sizeof(trans_buffer),
+                                 "BUG() at address %lx\n", regs->pc);
+               goto send_bug_pkt;
+
+       found_bug:
+               length = snprintf(trans_buffer, sizeof(trans_buffer),
+                                 "BUG() at address %lx (%s:%d)\n",
+                                 regs->pc, bug->file, bug->line);
+
+       send_bug_pkt:
+               ptr = output_buffer;
+               *ptr++ = 'O';
+               ptr = mem2hex(trans_buffer, ptr, length, 0);
+               *ptr = 0;
+               putpacket(output_buffer);
+
+               regs->pc -= 2;
+               sigval = SIGABRT;
+       } else if (regs->pc == (unsigned long) __gdbstub_bug_trap) {
+               regs->pc = regs->mdr;
+               sigval = SIGABRT;
+       }
+
+       /*
+        * send a message to the debugger's user saying what happened if it may
+        * not be clear cut (we can't map exceptions onto signals properly)
+        */
+       if (sigval != SIGINT && sigval != SIGTRAP && sigval != SIGILL) {
+               static const char title[] = "Excep ", tbcberr[] = "BCBERR ";
+               static const char crlf[] = "\r\n";
+               char hx;
+               u32 bcberr = BCBERR;
+
+               ptr = output_buffer;
+               *ptr++ = 'O';
+               ptr = mem2hex(title, ptr, sizeof(title) - 1, 0);
+
+               hx = hexchars[(excep & 0xf000) >> 12];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(excep & 0x0f00) >> 8];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(excep & 0x00f0) >> 4];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(excep & 0x000f)];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+
+               ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0);
+               *ptr = 0;
+               putpacket(output_buffer);       /* send it off... */
+
+               /* BCBERR */
+               ptr = output_buffer;
+               *ptr++ = 'O';
+               ptr = mem2hex(tbcberr, ptr, sizeof(tbcberr) - 1, 0);
+
+               hx = hexchars[(bcberr & 0xf0000000) >> 28];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x0f000000) >> 24];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x00f00000) >> 20];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x000f0000) >> 16];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x0000f000) >> 12];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x00000f00) >> 8];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x000000f0) >> 4];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+               hx = hexchars[(bcberr & 0x0000000f)];
+               *ptr++ = hexchars[hx >> 4];     *ptr++ = hexchars[hx & 0xf];
+
+               ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0);
+               *ptr = 0;
+               putpacket(output_buffer);       /* send it off... */
+       }
+
+       /*
+        * tell the debugger 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[GDB_REGID_PC >> 4];
+       *ptr++ = hexchars[GDB_REGID_PC & 0xf];
+       *ptr++ = ':';
+       ptr = mem2hex(&regs->pc, ptr, 4, 0);
+       *ptr++ = ';';
+
+       /*
+        * Send frame pointer
+        */
+       *ptr++ = hexchars[GDB_REGID_FP >> 4];
+       *ptr++ = hexchars[GDB_REGID_FP & 0xf];
+       *ptr++ = ':';
+       ptr = mem2hex(&regs->a3, ptr, 4, 0);
+       *ptr++ = ';';
+
+       /*
+        * Send stack pointer
+        */
+       ssp = (unsigned long) (regs + 1);
+       *ptr++ = hexchars[GDB_REGID_SP >> 4];
+       *ptr++ = hexchars[GDB_REGID_SP & 0xf];
+       *ptr++ = ':';
+       ptr = mem2hex(&ssp, ptr, 4, 0);
+       *ptr++ = ';';
+
+       *ptr++ = 0;
+       putpacket(output_buffer);       /* send it off... */
+
+packet_waiting:
+       /*
+        * Wait for input from remote GDB
+        */
+       while (1) {
+               output_buffer[0] = 0;
+               getpacket(input_buffer);
+
+               switch (input_buffer[0]) {
+                       /* request repeat of last signal number */
+               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 */
+                       break;
+
+                       /*
+                        * Return the value of the CPU registers
+                        */
+               case 'g':
+                       zero = 0;
+                       ssp = (u32) (regs + 1);
+                       ptr = output_buffer;
+                       ptr = mem2hex(&regs->d0, ptr, 4, 0);
+                       ptr = mem2hex(&regs->d1, ptr, 4, 0);
+                       ptr = mem2hex(&regs->d2, ptr, 4, 0);
+                       ptr = mem2hex(&regs->d3, ptr, 4, 0);
+                       ptr = mem2hex(&regs->a0, ptr, 4, 0);
+                       ptr = mem2hex(&regs->a1, ptr, 4, 0);
+                       ptr = mem2hex(&regs->a2, ptr, 4, 0);
+                       ptr = mem2hex(&regs->a3, ptr, 4, 0);
+
+                       ptr = mem2hex(&ssp, ptr, 4, 0);         /* 8 */
+                       ptr = mem2hex(&regs->pc, ptr, 4, 0);
+                       ptr = mem2hex(&regs->mdr, ptr, 4, 0);
+                       ptr = mem2hex(&regs->epsw, ptr, 4, 0);
+                       ptr = mem2hex(&regs->lir, ptr, 4, 0);
+                       ptr = mem2hex(&regs->lar, ptr, 4, 0);
+                       ptr = mem2hex(&regs->mdrq, ptr, 4, 0);
+
+                       ptr = mem2hex(&regs->e0, ptr, 4, 0);    /* 15 */
+                       ptr = mem2hex(&regs->e1, ptr, 4, 0);
+                       ptr = mem2hex(&regs->e2, ptr, 4, 0);
+                       ptr = mem2hex(&regs->e3, ptr, 4, 0);
+                       ptr = mem2hex(&regs->e4, ptr, 4, 0);
+                       ptr = mem2hex(&regs->e5, ptr, 4, 0);
+                       ptr = mem2hex(&regs->e6, ptr, 4, 0);
+                       ptr = mem2hex(&regs->e7, ptr, 4, 0);
+
+                       ptr = mem2hex(&ssp, ptr, 4, 0);
+                       ptr = mem2hex(&regs, ptr, 4, 0);
+                       ptr = mem2hex(&regs->sp, ptr, 4, 0);
+                       ptr = mem2hex(&regs->mcrh, ptr, 4, 0);  /* 26 */
+                       ptr = mem2hex(&regs->mcrl, ptr, 4, 0);
+                       ptr = mem2hex(&regs->mcvf, ptr, 4, 0);
+
+                       ptr = mem2hex(&gdbstub_fpcr, ptr, 4, 0); /* 29 - FPCR */
+                       ptr = mem2hex(&zero, ptr, 4, 0);
+                       ptr = mem2hex(&zero, ptr, 4, 0);
+                       for (loop = 0; loop < 32; loop++)
+                               ptr = mem2hex(&gdbstub_fpufs_array[loop],
+                                             ptr, 4, 0); /* 32 - FS0-31 */
+
+                       break;
+
+                       /*
+                        * set the value of the CPU registers - return OK
+                        */
+               case 'G':
+               {
+                       const char *ptr;
+
+                       ptr = &input_buffer[1];
+                       ptr = hex2mem(ptr, &regs->d0, 4, 0);
+                       ptr = hex2mem(ptr, &regs->d1, 4, 0);
+                       ptr = hex2mem(ptr, &regs->d2, 4, 0);
+                       ptr = hex2mem(ptr, &regs->d3, 4, 0);
+                       ptr = hex2mem(ptr, &regs->a0, 4, 0);
+                       ptr = hex2mem(ptr, &regs->a1, 4, 0);
+                       ptr = hex2mem(ptr, &regs->a2, 4, 0);
+                       ptr = hex2mem(ptr, &regs->a3, 4, 0);
+
+                       ptr = hex2mem(ptr, &ssp, 4, 0);         /* 8 */
+                       ptr = hex2mem(ptr, &regs->pc, 4, 0);
+                       ptr = hex2mem(ptr, &regs->mdr, 4, 0);
+                       ptr = hex2mem(ptr, &regs->epsw, 4, 0);
+                       ptr = hex2mem(ptr, &regs->lir, 4, 0);
+                       ptr = hex2mem(ptr, &regs->lar, 4, 0);
+                       ptr = hex2mem(ptr, &regs->mdrq, 4, 0);
+
+                       ptr = hex2mem(ptr, &regs->e0, 4, 0);    /* 15 */
+                       ptr = hex2mem(ptr, &regs->e1, 4, 0);
+                       ptr = hex2mem(ptr, &regs->e2, 4, 0);
+                       ptr = hex2mem(ptr, &regs->e3, 4, 0);
+                       ptr = hex2mem(ptr, &regs->e4, 4, 0);
+                       ptr = hex2mem(ptr, &regs->e5, 4, 0);
+                       ptr = hex2mem(ptr, &regs->e6, 4, 0);
+                       ptr = hex2mem(ptr, &regs->e7, 4, 0);
+
+                       ptr = hex2mem(ptr, &ssp, 4, 0);
+                       ptr = hex2mem(ptr, &zero, 4, 0);
+                       ptr = hex2mem(ptr, &regs->sp, 4, 0);
+                       ptr = hex2mem(ptr, &regs->mcrh, 4, 0);  /* 26 */
+                       ptr = hex2mem(ptr, &regs->mcrl, 4, 0);
+                       ptr = hex2mem(ptr, &regs->mcvf, 4, 0);
+
+                       ptr = hex2mem(ptr, &zero, 4, 0);        /* 29 - FPCR */
+                       ptr = hex2mem(ptr, &zero, 4, 0);
+                       ptr = hex2mem(ptr, &zero, 4, 0);
+                       for (loop = 0; loop < 32; loop++)     /* 32 - FS0-31 */
+                               ptr = hex2mem(ptr, &zero, 4, 0);
+
+#if 0
+                       /*
+                        * See if the stack pointer has moved. If so, then copy
+                        * the saved locals and ins to the new location.
+                        */
+                       unsigned long *newsp = (unsigned long *) registers[SP];
+                       if (sp != newsp)
+                               sp = memcpy(newsp, sp, 16 * 4);
+#endif
+
+                       gdbstub_strcpy(output_buffer, "OK");
+               }
+               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;
+                               gdbstub_strcpy(output_buffer, "E03");
+                       } else {
+                               gdbstub_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))
+                                       gdbstub_strcpy(output_buffer, "OK");
+                               else
+                                       gdbstub_strcpy(output_buffer, "E03");
+
+                               gdbstub_flush_caches = 1;
+                       } else {
+                               gdbstub_strcpy(output_buffer, "E02");
+                       }
+                       break;
+
+                       /*
+                        * cAA..AA    Continue at address AA..AA(optional)
+                        */
+               case 'c':
+                       /* try to read optional parameter, pc unchanged if no
+                        * parm */
+
+                       ptr = &input_buffer[1];
+                       if (hexToInt(&ptr, &addr))
+                               regs->pc = addr;
+                       goto done;
+
+                       /*
+                        * kill the program
+                        */
+               case 'k' :
+                       goto done;      /* just continue */
+
+                       /*
+                        * Reset the whole machine (FIXME: system dependent)
+                        */
+               case 'r':
+                       break;
+
+                       /*
+                        * Step to next instruction
+                        */
+               case 's':
+                       /*
+                        * using the T flag doesn't seem to perform single
+                        * stepping (it seems to wind up being caught by the
+                        * JTAG unit), so we have to use breakpoints and
+                        * continue instead.
+                        */
+                       if (gdbstub_single_step(regs) < 0)
+                               /* ignore any fault error for now */
+                               gdbstub_printk("unable to set single-step"
+                                              " bp\n");
+                       goto done;
+
+                       /*
+                        * Set baud rate (bBB)
+                        */
+               case 'b':
+                       do {
+                               int baudrate;
+
+                               ptr = &input_buffer[1];
+                               if (!hexToInt(&ptr, &baudrate)) {
+                                       gdbstub_strcpy(output_buffer, "B01");
+                                       break;
+                               }
+
+                               if (baudrate) {
+                                       /* ACK before changing speed */
+                                       putpacket("OK");
+                                       gdbstub_io_set_baud(baudrate);
+                               }
+                       } while (0);
+                       break;
+
+                       /*
+                        * Set breakpoint
+                        */
+               case 'Z':
+                       ptr = &input_buffer[1];
+
+                       if (!hexToInt(&ptr, &loop) || *ptr++ != ',' ||
+                           !hexToInt(&ptr, &addr) || *ptr++ != ',' ||
+                           !hexToInt(&ptr, &length)
+                           ) {
+                               gdbstub_strcpy(output_buffer, "E01");
+                               break;
+                       }
+
+                       /* only support software breakpoints */
+                       gdbstub_strcpy(output_buffer, "E03");
+                       if (loop != 0 ||
+                           length < 1 ||
+                           length > 7 ||
+                           (unsigned long) addr < 4096)
+                               break;
+
+                       if (gdbstub_set_breakpoint((u8 *) addr, length) < 0)
+                               break;
+
+                       gdbstub_strcpy(output_buffer, "OK");
+                       break;
+
+                       /*
+                        * Clear breakpoint
+                        */
+               case 'z':
+                       ptr = &input_buffer[1];
+
+                       if (!hexToInt(&ptr, &loop) || *ptr++ != ',' ||
+                           !hexToInt(&ptr, &addr) || *ptr++ != ',' ||
+                           !hexToInt(&ptr, &length)
+                           ) {
+                               gdbstub_strcpy(output_buffer, "E01");
+                               break;
+                       }
+
+                       /* only support software breakpoints */
+                       gdbstub_strcpy(output_buffer, "E03");
+                       if (loop != 0 ||
+                           length < 1 ||
+                           length > 7 ||
+                           (unsigned long) addr < 4096)
+                               break;
+
+                       if (gdbstub_clear_breakpoint((u8 *) addr, length) < 0)
+                               break;
+
+                       gdbstub_strcpy(output_buffer, "OK");
+                       break;
+
+               default:
+                       gdbstub_proto("### GDB Unsupported Cmd '%s'\n",
+                                     input_buffer);
+                       break;
+               }
+
+               /* reply to the request */
+               putpacket(output_buffer);
+       }
+
+done:
+       /*
+        * 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.
+        * NB: We flush both caches, just to be sure...
+        */
+       if (gdbstub_flush_caches)
+               gdbstub_purge_cache();
+
+       gdbstub_load_fpu();
+       mn10300_set_gdbleds(0);
+       if (excep == EXCEP_NMI)
+               NMICR = NMICR_NMIF;
+
+       touch_softlockup_watchdog();
+
+       local_irq_restore(epsw);
+       return 1;
+}
+
+/*
+ * handle event interception
+ */
+asmlinkage int gdbstub_intercept(struct pt_regs *regs,
+                                enum exception_code excep)
+{
+       static u8 notfirst = 1;
+       int ret;
+
+       if (gdbstub_busy)
+               gdbstub_printk("--> gdbstub reentered itself\n");
+       gdbstub_busy = 1;
+
+       if (notfirst) {
+               unsigned long mdr;
+               asm("mov mdr,%0" : "=d"(mdr));
+
+               gdbstub_entry(
+                       "--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n",
+                       regs, excep, mdr, regs->pc);
+
+               gdbstub_entry(
+                       "PC:  %08lx EPSW:  %08lx  SSP: %08lx mode: %s\n",
+                       regs->pc, regs->epsw, (unsigned long) &ret,
+                       user_mode(regs) ? "User" : "Super");
+               gdbstub_entry(
+                       "d0:  %08lx   d1:  %08lx   d2: %08lx   d3: %08lx\n",
+                       regs->d0, regs->d1, regs->d2, regs->d3);
+               gdbstub_entry(
+                       "a0:  %08lx   a1:  %08lx   a2: %08lx   a3: %08lx\n",
+                       regs->a0, regs->a1, regs->a2, regs->a3);
+               gdbstub_entry(
+                       "e0:  %08lx   e1:  %08lx   e2: %08lx   e3: %08lx\n",
+                       regs->e0, regs->e1, regs->e2, regs->e3);
+               gdbstub_entry(
+                       "e4:  %08lx   e5:  %08lx   e6: %08lx   e7: %08lx\n",
+                       regs->e4, regs->e5, regs->e6, regs->e7);
+               gdbstub_entry(
+                       "lar: %08lx   lir: %08lx  mdr: %08lx  usp: %08lx\n",
+                       regs->lar, regs->lir, regs->mdr, regs->sp);
+               gdbstub_entry(
+                       "cvf: %08lx   crl: %08lx  crh: %08lx  drq: %08lx\n",
+                       regs->mcvf, regs->mcrl, regs->mcrh, regs->mdrq);
+               gdbstub_entry(
+                       "threadinfo=%p task=%p)\n",
+                       current_thread_info(), current);
+       } else {
+               notfirst = 1;
+       }
+
+       ret = gdbstub(regs, excep);
+
+       gdbstub_entry("<-- gdbstub_intercept()\n");
+       gdbstub_busy = 0;
+       return ret;
+}
+
+/*
+ * handle the GDB stub itself causing an exception
+ */
+asmlinkage void gdbstub_exception(struct pt_regs *regs,
+                                 enum exception_code excep)
+{
+       unsigned long mdr;
+
+       asm("mov mdr,%0" : "=d"(mdr));
+       gdbstub_entry("--> gdbstub exception({%p},%04x) [MDR=%lx]\n",
+                     regs, excep, mdr);
+
+       while ((unsigned long) regs == 0xffffffff) {}
+
+       /* handle guarded memory accesses where we know it might fault */
+       if (regs->pc == (unsigned) gdbstub_read_byte_guard) {
+               regs->pc = (unsigned) gdbstub_read_byte_cont;
+               goto fault;
+       }
+
+       if (regs->pc == (unsigned) gdbstub_read_word_guard) {
+               regs->pc = (unsigned) gdbstub_read_word_cont;
+               goto fault;
+       }
+
+       if (regs->pc == (unsigned) gdbstub_read_dword_guard) {
+               regs->pc = (unsigned) gdbstub_read_dword_cont;
+               goto fault;
+       }
+
+       if (regs->pc == (unsigned) gdbstub_write_byte_guard) {
+               regs->pc = (unsigned) gdbstub_write_byte_cont;
+               goto fault;
+       }
+
+       if (regs->pc == (unsigned) gdbstub_write_word_guard) {
+               regs->pc = (unsigned) gdbstub_write_word_cont;
+               goto fault;
+       }
+
+       if (regs->pc == (unsigned) gdbstub_write_dword_guard) {
+               regs->pc = (unsigned) gdbstub_write_dword_cont;
+               goto fault;
+       }
+
+       gdbstub_printk("\n### GDB stub caused an exception ###\n");
+
+       /* something went horribly wrong */
+       console_verbose();
+       show_registers(regs);
+
+       panic("GDB Stub caused an unexpected exception - can't continue\n");
+
+       /* we caught an attempt by the stub to access silly memory */
+fault:
+       gdbstub_entry("<-- gdbstub exception() = EFAULT\n");
+       regs->d0 = -EFAULT;
+       return;
+}
+
+/*
+ * send an exit message to GDB
+ */
+void gdbstub_exit(int status)
+{
+       unsigned char checksum;
+       unsigned char ch;
+       int count;
+
+       gdbstub_busy = 1;
+       output_buffer[0] = 'W';
+       output_buffer[1] = hexchars[(status >> 4) & 0x0F];
+       output_buffer[2] = hexchars[status & 0x0F];
+       output_buffer[3] = 0;
+
+       gdbstub_io_tx_char('$');
+       checksum = 0;
+       count = 0;
+
+       while ((ch = output_buffer[count]) != 0) {
+               gdbstub_io_tx_char(ch);
+               checksum += ch;
+               count += 1;
+       }
+
+       gdbstub_io_tx_char('#');
+       gdbstub_io_tx_char(hexchars[checksum >> 4]);
+       gdbstub_io_tx_char(hexchars[checksum & 0xf]);
+
+       /* make sure the output is flushed, or else RedBoot might clobber it */
+       gdbstub_io_tx_flush();
+
+       gdbstub_busy = 0;
+}
+
+/*
+ * initialise the GDB stub
+ */
+asmlinkage void __init gdbstub_init(void)
+{
+#ifdef CONFIG_GDBSTUB_IMMEDIATE
+       unsigned char ch;
+       int ret;
+#endif
+
+       gdbstub_busy = 1;
+
+       printk(KERN_INFO "%s", gdbstub_banner);
+
+       gdbstub_io_init();
+
+       gdbstub_entry("--> gdbstub_init\n");
+
+       /* try to talk to GDB (or anyone insane enough to want to type GDB
+        * protocol by hand) */
+       gdbstub_io("### GDB Tx ACK\n");
+       gdbstub_io_tx_char('+'); /* 'hello world' */
+
+#ifdef CONFIG_GDBSTUB_IMMEDIATE
+       gdbstub_printk("GDB Stub waiting for packet\n");
+
+       /* in case GDB is started before us, ACK any packets that are already
+        * sitting there (presumably "$?#xx")
+        */
+       do { gdbstub_io_rx_char(&ch, 0); } while (ch != '$');
+       do { gdbstub_io_rx_char(&ch, 0); } while (ch != '#');
+       /* eat first csum byte */
+       do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0);
+       /* eat second csum byte */
+       do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0);
+
+       gdbstub_io("### GDB Tx NAK\n");
+       gdbstub_io_tx_char('-'); /* NAK it */
+
+#else
+       printk("GDB Stub ready\n");
+#endif
+
+       gdbstub_busy = 0;
+       gdbstub_entry("<-- gdbstub_init\n");
+}
+
+/*
+ * register the console at a more appropriate time
+ */
+#ifdef CONFIG_GDBSTUB_CONSOLE
+static int __init gdbstub_postinit(void)
+{
+       printk(KERN_NOTICE "registering console\n");
+       register_console(&gdbstub_console);
+       return 0;
+}
+
+__initcall(gdbstub_postinit);
+#endif
+
+/*
+ * handle character reception on GDB serial port
+ * - jump into the GDB stub if BREAK is detected on the serial line
+ */
+asmlinkage void gdbstub_rx_irq(struct pt_regs *regs, enum exception_code excep)
+{
+       char ch;
+       int ret;
+
+       gdbstub_entry("--> gdbstub_rx_irq\n");
+
+       do {
+               ret = gdbstub_io_rx_char(&ch, 1);
+               if (ret != -EIO && ret != -EAGAIN) {
+                       if (ret != -EINTR)
+                               gdbstub_rx_unget = ch;
+                       gdbstub(regs, excep);
+               }
+       } while (ret != -EAGAIN);
+
+       gdbstub_entry("<-- gdbstub_rx_irq\n");
+}
diff --git a/arch/mn10300/kernel/head.S b/arch/mn10300/kernel/head.S
new file mode 100644 (file)
index 0000000..606bd8c
--- /dev/null
@@ -0,0 +1,255 @@
+/* Boot entry point for MN10300 kernel
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <linux/serial_reg.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/frame.inc>
+#include <asm/param.h>
+#include <asm/unit/serial.h>
+
+       .section .text.head,"ax"
+
+###############################################################################
+#
+# bootloader entry point
+#
+###############################################################################
+       .globl  _start
+       .type   _start,@function
+_start:
+       # save commandline pointer
+       mov     d0,a3
+
+       # preload the PGD pointer register
+       mov     swapper_pg_dir,d0
+       mov     d0,(PTBR)
+
+       # turn on the TLBs
+       mov     MMUCTR_IIV|MMUCTR_DIV,d0
+       mov     d0,(MMUCTR)
+       mov     MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0
+       mov     d0,(MMUCTR)
+
+       # turn on AM33v2 exception handling mode and set the trap table base
+       movhu   (CPUP),d0
+       or      CPUP_EXM_AM33V2,d0
+       movhu   d0,(CPUP)
+       mov     CONFIG_INTERRUPT_VECTOR_BASE,d0
+       mov     d0,(TBR)
+
+       # invalidate and enable both of the caches
+       mov     CHCTR,a0
+       clr     d0
+       movhu   d0,(a0)                                 # turn off first
+       mov     CHCTR_ICINV|CHCTR_DCINV,d0
+       movhu   d0,(a0)
+       setlb
+       mov     (a0),d0
+       btst    CHCTR_ICBUSY|CHCTR_DCBUSY,d0            # wait till not busy
+       lne
+
+#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_WBACK
+#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC
+       mov     CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
+#else
+       mov     CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0
+#endif /* CACHE_DISABLED */
+#else
+       mov     CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
+#endif /* WBACK */
+       movhu   d0,(a0)                                 # enable
+#endif /* NOWRALLOC */
+
+       # turn on RTS on the debug serial port if applicable
+#ifdef CONFIG_MN10300_UNIT_ASB2305
+       bset    UART_MCR_RTS,(ASB2305_DEBUG_MCR)
+#endif
+
+       # clear the BSS area
+       mov     __bss_start,a0
+       mov     __bss_stop,a1
+       clr     d0
+bssclear:
+       cmp     a1,a0
+       bge     bssclear_end
+       mov     d0,(a0)
+       inc4    a0
+       bra     bssclear
+bssclear_end:
+
+       # retrieve the parameters (including command line) before we overwrite
+       # them
+       cmp     0xabadcafe,d1
+       bne     __no_parameters
+
+__copy_parameters:
+       mov     redboot_command_line,a0
+       mov     a0,a1
+       add     COMMAND_LINE_SIZE,a1
+1:
+       movbu   (a3),d0
+       inc     a3
+       movbu   d0,(a0)
+       inc     a0
+       cmp     a1,a0
+       blt     1b
+
+       mov     redboot_platform_name,a0
+       mov     a0,a1
+       add     COMMAND_LINE_SIZE,a1
+       mov     d2,a3
+1:
+       movbu   (a3),d0
+       inc     a3
+       movbu   d0,(a0)
+       inc     a0
+       cmp     a1,a0
+       blt     1b
+
+__no_parameters:
+
+       # set up the registers with recognisable rubbish in them
+       mov     init_thread_union+THREAD_SIZE-12,sp
+
+       mov     0xea01eaea,d0
+       mov     d0,(4,sp)               # EPSW save area
+       mov     0xea02eaea,d0
+       mov     d0,(8,sp)               # PC save area
+
+       mov     0xeb0060ed,d0
+       mov     d0,mdr
+       mov     0xeb0061ed,d0
+       mov     d0,mdrq
+       mov     0xeb0062ed,d0
+       mov     d0,mcrh
+       mov     0xeb0063ed,d0
+       mov     d0,mcrl
+       mov     0xeb0064ed,d0
+       mov     d0,mcvf
+       mov     0xed0065ed,a3
+       mov     a3,usp
+
+       mov     0xed00e0ed,e0
+       mov     0xed00e1ed,e1
+       mov     0xed00e2ed,e2
+       mov     0xed00e3ed,e3
+       mov     0xed00e4ed,e4
+       mov     0xed00e5ed,e5
+       mov     0xed00e6ed,e6
+       mov     0xed00e7ed,e7
+
+       mov     0xed00d0ed,d0
+       mov     0xed00d1ed,d1
+       mov     0xed00d2ed,d2
+       mov     0xed00d3ed,d3
+       mov     0xed00a0ed,a0
+       mov     0xed00a1ed,a1
+       mov     0xed00a2ed,a2
+       mov     0,a3
+
+       # set up the initial kernel stack
+       SAVE_ALL
+       mov     0xffffffff,d0
+       mov     d0,(REG_ORIG_D0,fp)
+
+       # put different recognisable rubbish in the regs
+       mov     0xfb0060ed,d0
+       mov     d0,mdr
+       mov     0xfb0061ed,d0
+       mov     d0,mdrq
+       mov     0xfb0062ed,d0
+       mov     d0,mcrh
+       mov     0xfb0063ed,d0
+       mov     d0,mcrl
+       mov     0xfb0064ed,d0
+       mov     d0,mcvf
+       mov     0xfd0065ed,a0
+       mov     a0,usp
+
+       mov     0xfd00e0ed,e0
+       mov     0xfd00e1ed,e1
+       mov     0xfd00e2ed,e2
+       mov     0xfd00e3ed,e3
+       mov     0xfd00e4ed,e4
+       mov     0xfd00e5ed,e5
+       mov     0xfd00e6ed,e6
+       mov     0xfd00e7ed,e7
+
+       mov     0xfd00d0ed,d0
+       mov     0xfd00d1ed,d1
+       mov     0xfd00d2ed,d2
+       mov     0xfd00d3ed,d3
+       mov     0xfd00a0ed,a0
+       mov     0xfd00a1ed,a1
+       mov     0xfd00a2ed,a2
+
+       # we may be holding current in E2
+#ifdef CONFIG_MN10300_CURRENT_IN_E2
+       mov     init_task,e2
+#endif
+
+       # initialise the processor and the unit
+       call    processor_init[],0
+       call    unit_init[],0
+
+#ifdef CONFIG_GDBSTUB
+       call    gdbstub_init[],0
+
+#ifdef CONFIG_GDBSTUB_IMMEDIATE
+       .globl  __gdbstub_pause
+__gdbstub_pause:
+       bra     __gdbstub_pause
+#endif
+#endif
+
+       jmp     start_kernel
+       .size   _start, _start-.
+ENTRY(__head_end)
+
+/*
+ * This is initialized to disallow all access to the low 2G region
+ * - the high 2G region is managed directly by the MMU
+ * - range 0x70000000-0x7C000000 are initialised for use by VMALLOC
+ */
+       .section .bss
+       .balign PAGE_SIZE
+ENTRY(swapper_pg_dir)
+        .space PTRS_PER_PGD*4
+
+/*
+ * The page tables are initialized to only 8MB here - the final page
+ * tables are set up later depending on memory size.
+ */
+
+       .balign PAGE_SIZE
+ENTRY(empty_zero_page)
+       .space PAGE_SIZE
+
+       .balign PAGE_SIZE
+ENTRY(empty_bad_page)
+       .space PAGE_SIZE
+
+       .balign PAGE_SIZE
+ENTRY(empty_bad_pte_table)
+       .space PAGE_SIZE
+
+       .balign PAGE_SIZE
+ENTRY(large_page_table)
+       .space PAGE_SIZE
+
+       .balign PAGE_SIZE
+ENTRY(kernel_vmalloc_ptes)
+       .space ((VMALLOC_END-VMALLOC_START)/PAGE_SIZE)*4
diff --git a/arch/mn10300/kernel/init_task.c b/arch/mn10300/kernel/init_task.c
new file mode 100644 (file)
index 0000000..39fe688
--- /dev/null
@@ -0,0 +1,45 @@
+/* MN10300 Initial task definitions
+ *
+ * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is THREAD_SIZE aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union
+       __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h
new file mode 100644 (file)
index 0000000..eee2eee
--- /dev/null
@@ -0,0 +1,20 @@
+/* Internal definitions for the arch part of the core kernel
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+/*
+ * kthread.S
+ */
+extern int kernel_thread_helper(int);
+
+/*
+ * entry.S
+ */
+extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
diff --git a/arch/mn10300/kernel/io.c b/arch/mn10300/kernel/io.c
new file mode 100644 (file)
index 0000000..e96fdf6
--- /dev/null
@@ -0,0 +1,30 @@
+/* MN10300 Misaligned multibyte-word I/O
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+/*
+ * output data from a potentially misaligned buffer
+ */
+void __outsl(unsigned long addr, const void *buffer, int count)
+{
+       const unsigned char *buf = buffer;
+       unsigned long val;
+
+       while (count--) {
+               memcpy(&val, buf, 4);
+               outl(val, addr);
+               buf += 4;
+       }
+}
+EXPORT_SYMBOL(__outsl);
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
new file mode 100644 (file)
index 0000000..761c434
--- /dev/null
@@ -0,0 +1,235 @@
+/* MN10300 Arch-specific interrupt handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <asm/setup.h>
+
+unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7;
+EXPORT_SYMBOL(__mn10300_irq_enabled_epsw);
+
+atomic_t irq_err_count;
+
+/*
+ * MN10300 INTC controller operations
+ */
+static void mn10300_cpupic_disable(unsigned int irq)
+{
+       u16 tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+       tmp = GxICR(irq);
+}
+
+static void mn10300_cpupic_enable(unsigned int irq)
+{
+       u16 tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
+       tmp = GxICR(irq);
+}
+
+static void mn10300_cpupic_ack(unsigned int irq)
+{
+       u16 tmp;
+       *(volatile u8 *) &GxICR(irq) = GxICR_DETECT;
+       tmp = GxICR(irq);
+}
+
+static void mn10300_cpupic_mask(unsigned int irq)
+{
+       u16 tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_LEVEL);
+       tmp = GxICR(irq);
+}
+
+static void mn10300_cpupic_mask_ack(unsigned int irq)
+{
+       u16 tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+       tmp = GxICR(irq);
+}
+
+static void mn10300_cpupic_unmask(unsigned int irq)
+{
+       u16 tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
+       tmp = GxICR(irq);
+}
+
+static void mn10300_cpupic_end(unsigned int irq)
+{
+       u16 tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
+       tmp = GxICR(irq);
+}
+
+static struct irq_chip mn10300_cpu_pic = {
+       .name           = "cpu",
+       .disable        = mn10300_cpupic_disable,
+       .enable         = mn10300_cpupic_enable,
+       .ack            = mn10300_cpupic_ack,
+       .mask           = mn10300_cpupic_mask,
+       .mask_ack       = mn10300_cpupic_mask_ack,
+       .unmask         = mn10300_cpupic_unmask,
+       .end            = mn10300_cpupic_end,
+};
+
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(int irq)
+{
+       printk(KERN_WARNING "unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/*
+ * change the level at which an IRQ executes
+ * - must not be called whilst interrupts are being processed!
+ */
+void set_intr_level(int irq, u16 level)
+{
+       u16 tmp;
+
+       if (in_interrupt())
+               BUG();
+
+       tmp = GxICR(irq);
+       GxICR(irq) = (tmp & GxICR_ENABLE) | level;
+       tmp = GxICR(irq);
+}
+
+/*
+ * mark an interrupt to be ACK'd after interrupt handlers have been run rather
+ * than before
+ * - see Documentation/mn10300/features.txt
+ */
+void set_intr_postackable(int irq)
+{
+       set_irq_handler(irq, handle_level_irq);
+}
+
+/*
+ * initialise the interrupt system
+ */
+void __init init_IRQ(void)
+{
+       int irq;
+
+       for (irq = 0; irq < NR_IRQS; irq++)
+               if (irq_desc[irq].chip == &no_irq_type)
+                       set_irq_chip_and_handler(irq, &mn10300_cpu_pic,
+                                                handle_edge_irq);
+       unit_init_IRQ();
+}
+
+/*
+ * handle normal device IRQs
+ */
+asmlinkage void do_IRQ(void)
+{
+       unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw;
+       int irq;
+
+       sp = current_stack_pointer();
+       if (sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN)
+               BUG();
+
+       /* make sure local_irq_enable() doesn't muck up the interrupt priority
+        * setting in EPSW */
+       old_irq_enabled_epsw = __mn10300_irq_enabled_epsw;
+       local_save_flags(epsw);
+       __mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw);
+       irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL;
+
+       __IRQ_STAT(smp_processor_id(), __irq_count)++;
+
+       irq_enter();
+
+       for (;;) {
+               /* ask the interrupt controller for the next IRQ to process
+                * - the result we get depends on EPSW.IM
+                */
+               irq = IAGR & IAGR_GN;
+               if (!irq)
+                       break;
+
+               local_irq_restore(irq_disabled_epsw);
+
+               generic_handle_irq(irq >> 2);
+
+               /* restore IRQ controls for IAGR access */
+               local_irq_restore(epsw);
+       }
+
+       __mn10300_irq_enabled_epsw = old_irq_enabled_epsw;
+
+       irq_exit();
+}
+
+/*
+ * Display interrupt management information through /proc/interrupts
+ */
+int show_interrupts(struct seq_file *p, void *v)
+{
+       int i = *(loff_t *) v, j, cpu;
+       struct irqaction *action;
+       unsigned long flags;
+
+       switch (i) {
+               /* display column title bar naming CPUs */
+       case 0:
+               seq_printf(p, "           ");
+               for (j = 0; j < NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "CPU%d       ", j);
+               seq_putc(p, '\n');
+               break;
+
+               /* display information rows, one per active CPU */
+       case 1 ... NR_IRQS - 1:
+               spin_lock_irqsave(&irq_desc[i].lock, flags);
+
+               action = irq_desc[i].action;
+               if (action) {
+                       seq_printf(p, "%3d: ", i);
+                       for_each_present_cpu(cpu)
+                               seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
+                       seq_printf(p, " %14s.%u", irq_desc[i].chip->name,
+                                  (GxICR(i) & GxICR_LEVEL) >>
+                                  GxICR_LEVEL_SHIFT);
+                       seq_printf(p, "  %s", action->name);
+
+                       for (action = action->next;
+                            action;
+                            action = action->next)
+                               seq_printf(p, ", %s", action->name);
+
+                       seq_putc(p, '\n');
+               }
+
+               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+               break;
+
+               /* polish off with NMI and error counters */
+       case NR_IRQS:
+               seq_printf(p, "NMI: ");
+               for (j = 0; j < NR_CPUS; j++)
+                       if (cpu_online(j))
+                               seq_printf(p, "%10u ", nmi_count(j));
+               seq_putc(p, '\n');
+
+               seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+               break;
+       }
+
+       return 0;
+}
diff --git a/arch/mn10300/kernel/kernel_execve.S b/arch/mn10300/kernel/kernel_execve.S
new file mode 100644 (file)
index 0000000..86039f1
--- /dev/null
@@ -0,0 +1,37 @@
+/* MN10300 In-kernel program execution
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+###############################################################################
+#
+# Do a system call from kernel instead of calling sys_execve so we end up with
+# proper pt_regs.
+#
+# int kernel_execve(const char *filename, char *const argv[],
+#                  char *const envp[])
+#
+# On entry: D0/D1/8(SP): arguments to function
+# On return: D0: syscall return.
+#
+###############################################################################
+       .globl          kernel_execve
+       .type           kernel_execve,@function
+kernel_execve:
+       mov             a3,a1
+       mov             d0,a0
+       mov             (12,sp),a3
+       mov             +__NR_execve,d0
+       syscall         0
+       mov             a1,a3
+       rets
+
+       .size           kernel_execve,.-kernel_execve
diff --git a/arch/mn10300/kernel/kprobes.c b/arch/mn10300/kernel/kprobes.c
new file mode 100644 (file)
index 0000000..dacafab
--- /dev/null
@@ -0,0 +1,653 @@
+/* MN10300 Kernel probes implementation
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/spinlock.h>
+#include <linux/preempt.h>
+#include <linux/kdebug.h>
+#include <asm/cacheflush.h>
+
+struct kretprobe_blackpoint kretprobe_blacklist[] = { { NULL, NULL } };
+const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
+
+/* kprobe_status settings */
+#define KPROBE_HIT_ACTIVE      0x00000001
+#define KPROBE_HIT_SS          0x00000002
+
+static struct kprobe *current_kprobe;
+static unsigned long current_kprobe_orig_pc;
+static unsigned long current_kprobe_next_pc;
+static int current_kprobe_ss_flags;
+static unsigned long kprobe_status;
+static kprobe_opcode_t current_kprobe_ss_buf[MAX_INSN_SIZE + 2];
+static unsigned long current_kprobe_bp_addr;
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+
+
+/* singlestep flag bits */
+#define SINGLESTEP_BRANCH 1
+#define SINGLESTEP_PCREL  2
+
+#define READ_BYTE(p, valp) \
+       do { *(u8 *)(valp) = *(u8 *)(p); } while (0)
+
+#define READ_WORD16(p, valp)                                   \
+       do {                                                    \
+               READ_BYTE((p), (valp));                         \
+               READ_BYTE((u8 *)(p) + 1, (u8 *)(valp) + 1);     \
+       } while (0)
+
+#define READ_WORD32(p, valp)                                   \
+       do {                                                    \
+               READ_BYTE((p), (valp));                         \
+               READ_BYTE((u8 *)(p) + 1, (u8 *)(valp) + 1);     \
+               READ_BYTE((u8 *)(p) + 2, (u8 *)(valp) + 2);     \
+               READ_BYTE((u8 *)(p) + 3, (u8 *)(valp) + 3);     \
+       } while (0)
+
+
+static const u8 mn10300_insn_sizes[256] =
+{
+       /* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+       1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
+       2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */
+       1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */
+       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
+       0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1  /* f */
+};
+
+#define LT (1 << 0)
+#define GT (1 << 1)
+#define GE (1 << 2)
+#define LE (1 << 3)
+#define CS (1 << 4)
+#define HI (1 << 5)
+#define CC (1 << 6)
+#define LS (1 << 7)
+#define EQ (1 << 8)
+#define NE (1 << 9)
+#define RA (1 << 10)
+#define VC (1 << 11)
+#define VS (1 << 12)
+#define NC (1 << 13)
+#define NS (1 << 14)
+
+static const u16 cond_table[] = {
+       /*  V  C  N  Z  */
+       /*  0  0  0  0  */ (NE | NC | CC | VC | GE | GT | HI),
+       /*  0  0  0  1  */ (EQ | NC | CC | VC | GE | LE | LS),
+       /*  0  0  1  0  */ (NE | NS | CC | VC | LT | LE | HI),
+       /*  0  0  1  1  */ (EQ | NS | CC | VC | LT | LE | LS),
+       /*  0  1  0  0  */ (NE | NC | CS | VC | GE | GT | LS),
+       /*  0  1  0  1  */ (EQ | NC | CS | VC | GE | LE | LS),
+       /*  0  1  1  0  */ (NE | NS | CS | VC | LT | LE | LS),
+       /*  0  1  1  1  */ (EQ | NS | CS | VC | LT | LE | LS),
+       /*  1  0  0  0  */ (NE | NC | CC | VS | LT | LE | HI),
+       /*  1  0  0  1  */ (EQ | NC | CC | VS | LT | LE | LS),
+       /*  1  0  1  0  */ (NE | NS | CC | VS | GE | GT | HI),
+       /*  1  0  1  1  */ (EQ | NS | CC | VS | GE | LE | LS),
+       /*  1  1  0  0  */ (NE | NC | CS | VS | LT | LE | LS),
+       /*  1  1  0  1  */ (EQ | NC | CS | VS | LT | LE | LS),
+       /*  1  1  1  0  */ (NE | NS | CS | VS | GE | GT | LS),
+       /*  1  1  1  1  */ (EQ | NS | CS | VS | GE | LE | LS),
+};
+
+/*
+ * Calculate what the PC will be after executing next instruction
+ */
+static unsigned find_nextpc(struct pt_regs *regs, int *flags)
+{
+       unsigned size;
+       s8  x8;
+       s16 x16;
+       s32 x32;
+       u8 opc, *pc, *sp, *next;
+
+       next = 0;
+       *flags = SINGLESTEP_PCREL;
+
+       pc = (u8 *) regs->pc;
+       sp = (u8 *) (regs + 1);
+       opc = *pc;
+
+       size = mn10300_insn_sizes[opc];
+       if (size > 0) {
+               next = pc + size;
+       } else {
+               switch (opc) {
+                       /* Bxx (d8,PC) */
+               case 0xc0 ... 0xca:
+                       x8 = 2;
+                       if (cond_table[regs->epsw & 0xf] & (1 << (opc & 0xf)))
+                               x8 = (s8)pc[1];
+                       next = pc + x8;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+
+                       /* JMP (d16,PC) or CALL (d16,PC) */
+               case 0xcc:
+               case 0xcd:
+                       READ_WORD16(pc + 1, &x16);
+                       next = pc + x16;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+
+                       /* JMP (d32,PC) or CALL (d32,PC) */
+               case 0xdc:
+               case 0xdd:
+                       READ_WORD32(pc + 1, &x32);
+                       next = pc + x32;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+
+                       /* RETF */
+               case 0xde:
+                       next = (u8 *)regs->mdr;
+                       *flags &= ~SINGLESTEP_PCREL;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+
+                       /* RET */
+               case 0xdf:
+                       sp += pc[2];
+                       READ_WORD32(sp, &x32);
+                       next = (u8 *)x32;
+                       *flags &= ~SINGLESTEP_PCREL;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+
+               case 0xf0:
+                       next = pc + 2;
+                       opc = pc[1];
+                       if (opc >= 0xf0 && opc <= 0xf7) {
+                               /* JMP (An) / CALLS (An) */
+                               switch (opc & 3) {
+                               case 0:
+                                       next = (u8 *)regs->a0;
+                                       break;
+                               case 1:
+                                       next = (u8 *)regs->a1;
+                                       break;
+                               case 2:
+                                       next = (u8 *)regs->a2;
+                                       break;
+                               case 3:
+                                       next = (u8 *)regs->a3;
+                                       break;
+                               }
+                               *flags &= ~SINGLESTEP_PCREL;
+                               *flags |= SINGLESTEP_BRANCH;
+                       } else if (opc == 0xfc) {
+                               /* RETS */
+                               READ_WORD32(sp, &x32);
+                               next = (u8 *)x32;
+                               *flags &= ~SINGLESTEP_PCREL;
+                               *flags |= SINGLESTEP_BRANCH;
+                       } else if (opc == 0xfd) {
+                               /* RTI */
+                               READ_WORD32(sp + 4, &x32);
+                               next = (u8 *)x32;
+                               *flags &= ~SINGLESTEP_PCREL;
+                               *flags |= SINGLESTEP_BRANCH;
+                       }
+                       break;
+
+                       /* potential 3-byte conditional branches */
+               case 0xf8:
+                       next = pc + 3;
+                       opc = pc[1];
+                       if (opc >= 0xe8 && opc <= 0xeb &&
+                           (cond_table[regs->epsw & 0xf] &
+                            (1 << ((opc & 0xf) + 3)))
+                           ) {
+                               READ_BYTE(pc+2, &x8);
+                               next = pc + x8;
+                               *flags |= SINGLESTEP_BRANCH;
+                       }
+                       break;
+
+               case 0xfa:
+                       if (pc[1] == 0xff) {
+                               /* CALLS (d16,PC) */
+                               READ_WORD16(pc + 2, &x16);
+                               next = pc + x16;
+                       } else
+                               next = pc + 4;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+
+               case 0xfc:
+                       x32 = 6;
+                       if (pc[1] == 0xff) {
+                               /* CALLS (d32,PC) */
+                               READ_WORD32(pc + 2, &x32);
+                       }
+                       next = pc + x32;
+                       *flags |= SINGLESTEP_BRANCH;
+                       break;
+                       /* LXX (d8,PC) */
+                       /* SETLB - loads the next four bytes into the LIR reg */
+               case 0xd0 ... 0xda:
+               case 0xdb:
+                       panic("Can't singlestep Lxx/SETLB\n");
+                       break;
+               }
+       }
+       return (unsigned)next;
+
+}
+
+/*
+ * set up out of place singlestep of some branching instructions
+ */
+static unsigned __kprobes singlestep_branch_setup(struct pt_regs *regs)
+{
+       u8 opc, *pc, *sp, *next;
+
+       next = NULL;
+       pc = (u8 *) regs->pc;
+       sp = (u8 *) (regs + 1);
+
+       switch (pc[0]) {
+       case 0xc0 ... 0xca:     /* Bxx (d8,PC) */
+       case 0xcc:              /* JMP (d16,PC) */
+       case 0xdc:              /* JMP (d32,PC) */
+       case 0xf8:              /* Bxx (d8,PC)  3-byte version */
+               /* don't really need to do anything except cause trap  */
+               next = pc;
+               break;
+
+       case 0xcd:              /* CALL (d16,PC) */
+               pc[1] = 5;
+               pc[2] = 0;
+               next = pc + 5;
+               break;
+
+       case 0xdd:              /* CALL (d32,PC) */
+               pc[1] = 7;
+               pc[2] = 0;
+               pc[3] = 0;
+               pc[4] = 0;
+               next = pc + 7;
+               break;
+
+       case 0xde:              /* RETF */
+               next = pc + 3;
+               regs->mdr = (unsigned) next;
+               break;
+
+       case 0xdf:              /* RET */
+               sp += pc[2];
+               next = pc + 3;
+               *(unsigned *)sp = (unsigned) next;
+               break;
+
+       case 0xf0:
+               next = pc + 2;
+               opc = pc[1];
+               if (opc >= 0xf0 && opc <= 0xf3) {
+                       /* CALLS (An) */
+                       /* use CALLS (d16,PC) to avoid mucking with An */
+                       pc[0] = 0xfa;
+                       pc[1] = 0xff;
+                       pc[2] = 4;
+                       pc[3] = 0;
+                       next = pc + 4;
+               } else if (opc >= 0xf4 && opc <= 0xf7) {
+                       /* JMP (An) */
+                       next = pc;
+               } else if (opc == 0xfc) {
+                       /* RETS */
+                       next = pc + 2;
+                       *(unsigned *) sp = (unsigned) next;
+               } else if (opc == 0xfd) {
+                       /* RTI */
+                       next = pc + 2;
+                       *(unsigned *)(sp + 4) = (unsigned) next;
+               }
+               break;
+
+       case 0xfa:      /* CALLS (d16,PC) */
+               pc[2] = 4;
+               pc[3] = 0;
+               next = pc + 4;
+               break;
+
+       case 0xfc:      /* CALLS (d32,PC) */
+               pc[2] = 6;
+               pc[3] = 0;
+               pc[4] = 0;
+               pc[5] = 0;
+               next = pc + 6;
+               break;
+
+       case 0xd0 ... 0xda:     /* LXX (d8,PC) */
+       case 0xdb:              /* SETLB */
+               panic("Can't singlestep Lxx/SETLB\n");
+       }
+
+       return (unsigned) next;
+}
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+       return 0;
+}
+
+void __kprobes arch_copy_kprobe(struct kprobe *p)
+{
+       memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+       *p->addr = BREAKPOINT_INSTRUCTION;
+       flush_icache_range((unsigned long) p->addr,
+                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+       mn10300_dcache_flush();
+       mn10300_icache_inv();
+}
+
+void arch_remove_kprobe(struct kprobe *p)
+{
+}
+
+static inline
+void __kprobes disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
+{
+       *p->addr = p->opcode;
+       regs->pc = (unsigned long) p->addr;
+       mn10300_dcache_flush();
+       mn10300_icache_inv();
+}
+
+static inline
+void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+       unsigned long nextpc;
+
+       current_kprobe_orig_pc = regs->pc;
+       memcpy(current_kprobe_ss_buf, &p->ainsn.insn[0], MAX_INSN_SIZE);
+       regs->pc = (unsigned long) current_kprobe_ss_buf;
+
+       nextpc = find_nextpc(regs, &current_kprobe_ss_flags);
+       if (current_kprobe_ss_flags & SINGLESTEP_PCREL)
+               current_kprobe_next_pc =
+                       current_kprobe_orig_pc + (nextpc - regs->pc);
+       else
+               current_kprobe_next_pc = nextpc;
+
+       /* branching instructions need special handling */
+       if (current_kprobe_ss_flags & SINGLESTEP_BRANCH)
+               nextpc = singlestep_branch_setup(regs);
+
+       current_kprobe_bp_addr = nextpc;
+
+       *(u8 *) nextpc = BREAKPOINT_INSTRUCTION;
+       mn10300_dcache_flush_range2((unsigned) current_kprobe_ss_buf,
+                                   sizeof(current_kprobe_ss_buf));
+       mn10300_icache_inv();
+}
+
+static inline int __kprobes kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p;
+       int ret = 0;
+       unsigned int *addr = (unsigned int *) regs->pc;
+
+       /* We're in an interrupt, but this is clear and BUG()-safe. */
+       preempt_disable();
+
+       /* Check we're not actually recursing */
+       if (kprobe_running()) {
+               /* We *are* holding lock here, so this is safe.
+                  Disarm the probe we just hit, and ignore it. */
+               p = get_kprobe(addr);
+               if (p) {
+                       disarm_kprobe(p, regs);
+                       ret = 1;
+               } else {
+                       p = current_kprobe;
+                       if (p->break_handler && p->break_handler(p, regs))
+                               goto ss_probe;
+               }
+               /* If it's not ours, can't be delete race, (we hold lock). */
+               goto no_kprobe;
+       }
+
+       p = get_kprobe(addr);
+       if (!p) {
+               if (*addr != BREAKPOINT_INSTRUCTION) {
+                       /* The breakpoint instruction was removed right after
+                        * we hit it.  Another cpu has removed either a
+                        * probepoint or a debugger breakpoint at this address.
+                        * In either case, no further handling of this
+                        * interrupt is appropriate.
+                        */
+                       ret = 1;
+               }
+               /* Not one of ours: let kernel handle it */
+               goto no_kprobe;
+       }
+
+       kprobe_status = KPROBE_HIT_ACTIVE;
+       current_kprobe = p;
+       if (p->pre_handler(p, regs)) {
+               /* handler has already set things up, so skip ss setup */
+               return 1;
+       }
+
+ss_probe:
+       prepare_singlestep(p, regs);
+       kprobe_status = KPROBE_HIT_SS;
+       return 1;
+
+no_kprobe:
+       preempt_enable_no_resched();
+       return ret;
+}
+
+/*
+ * Called after single-stepping.  p->addr is the address of the
+ * instruction whose first byte has been replaced by the "breakpoint"
+ * instruction.  To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction.  The address of this
+ * copy is p->ainsn.insn.
+ */
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
+{
+       /* we may need to fixup regs/stack after singlestepping a call insn */
+       if (current_kprobe_ss_flags & SINGLESTEP_BRANCH) {
+               regs->pc = current_kprobe_orig_pc;
+               switch (p->ainsn.insn[0]) {
+               case 0xcd:      /* CALL (d16,PC) */
+                       *(unsigned *) regs->sp = regs->mdr = regs->pc + 5;
+                       break;
+               case 0xdd:      /* CALL (d32,PC) */
+                       /* fixup mdr and return address on stack */
+                       *(unsigned *) regs->sp = regs->mdr = regs->pc + 7;
+                       break;
+               case 0xf0:
+                       if (p->ainsn.insn[1] >= 0xf0 &&
+                           p->ainsn.insn[1] <= 0xf3) {
+                               /* CALLS (An) */
+                               /* fixup MDR and return address on stack */
+                               regs->mdr = regs->pc + 2;
+                               *(unsigned *) regs->sp = regs->mdr;
+                       }
+                       break;
+
+               case 0xfa:      /* CALLS (d16,PC) */
+                       /* fixup MDR and return address on stack */
+                       *(unsigned *) regs->sp = regs->mdr = regs->pc + 4;
+                       break;
+
+               case 0xfc:      /* CALLS (d32,PC) */
+                       /* fixup MDR and return address on stack */
+                       *(unsigned *) regs->sp = regs->mdr = regs->pc + 6;
+                       break;
+               }
+       }
+
+       regs->pc = current_kprobe_next_pc;
+       current_kprobe_bp_addr = 0;
+}
+
+static inline int __kprobes post_kprobe_handler(struct pt_regs *regs)
+{
+       if (!kprobe_running())
+               return 0;
+
+       if (current_kprobe->post_handler)
+               current_kprobe->post_handler(current_kprobe, regs, 0);
+
+       resume_execution(current_kprobe, regs);
+       reset_current_kprobe();
+       preempt_enable_no_resched();
+       return 1;
+}
+
+/* Interrupts disabled, kprobe_lock held. */
+static inline
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       if (current_kprobe->fault_handler &&
+           current_kprobe->fault_handler(current_kprobe, regs, trapnr))
+               return 1;
+
+       if (kprobe_status & KPROBE_HIT_SS) {
+               resume_execution(current_kprobe, regs);
+               reset_current_kprobe();
+               preempt_enable_no_resched();
+       }
+       return 0;
+}
+
+/*
+ * Wrapper routine to for handling exceptions.
+ */
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+                                      unsigned long val, void *data)
+{
+       struct die_args *args = data;
+
+       switch (val) {
+       case DIE_BREAKPOINT:
+               if (current_kprobe_bp_addr != args->regs->pc) {
+                       if (kprobe_handler(args->regs))
+                               return NOTIFY_STOP;
+               } else {
+                       if (post_kprobe_handler(args->regs))
+                               return NOTIFY_STOP;
+               }
+               break;
+       case DIE_GPF:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+/* Jprobes support.  */
+static struct pt_regs jprobe_saved_regs;
+static struct pt_regs *jprobe_saved_regs_location;
+static kprobe_opcode_t jprobe_saved_stack[MAX_STACK_SIZE];
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+       jprobe_saved_regs_location = regs;
+       memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
+
+       /* Save a whole stack frame, this gets arguments
+        * pushed onto the stack after using up all the
+        * arg registers.
+        */
+       memcpy(&jprobe_saved_stack, regs + 1, sizeof(jprobe_saved_stack));
+
+       /* setup return addr to the jprobe handler routine */
+       regs->pc = (unsigned long) jp->entry;
+       return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+       void *orig_sp = jprobe_saved_regs_location + 1;
+
+       preempt_enable_no_resched();
+       asm volatile("          mov     %0,sp\n"
+                    ".globl    jprobe_return_bp_addr\n"
+                    "jprobe_return_bp_addr:\n\t"
+                    "          .byte   0xff\n"
+                    : : "d" (orig_sp));
+}
+
+extern void jprobe_return_bp_addr(void);
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       u8 *addr = (u8 *) regs->pc;
+
+       if (addr == (u8 *) jprobe_return_bp_addr) {
+               if (jprobe_saved_regs_location != regs) {
+                       printk(KERN_ERR"JPROBE:"
+                              " Current regs (%p) does not match saved regs"
+                              " (%p).\n",
+                              regs, jprobe_saved_regs_location);
+                       BUG();
+               }
+
+               /* Restore old register state.
+                */
+               memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
+
+               memcpy(regs + 1, &jprobe_saved_stack,
+                      sizeof(jprobe_saved_stack));
+               return 1;
+       }
+       return 0;
+}
+
+int __init arch_init_kprobes(void)
+{
+       return 0;
+}
diff --git a/arch/mn10300/kernel/kthread.S b/arch/mn10300/kernel/kthread.S
new file mode 100644 (file)
index 0000000..b5ae467
--- /dev/null
@@ -0,0 +1,31 @@
+/* MN10300 Kernel thread trampoline function
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+       .text
+
+###############################################################################
+#
+# kernel_thread_helper - trampoline for kernel_thread()
+#
+# On entry:
+#   A2 = address of function to call
+#   D2 = function argument
+#
+###############################################################################
+       .globl  kernel_thread_helper
+       .type   kernel_thread_helper,@function
+kernel_thread_helper:
+       mov     do_exit,d1
+       mov     d1,(sp)
+       mov     d1,mdr
+       mov     d2,d0
+       jmp     (a2)
+
+       .size   kernel_thread_helper,.-kernel_thread_helper
diff --git a/arch/mn10300/kernel/mn10300-debug.c b/arch/mn10300/kernel/mn10300-debug.c
new file mode 100644 (file)
index 0000000..bd81964
--- /dev/null
@@ -0,0 +1,58 @@
+/* Debugging stuff for the MN10300-based processors
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sched.h>
+#include <asm/serial-regs.h>
+
+#undef MN10300_CONSOLE_ON_SERIO
+
+/*
+ * write a string directly through one of the serial ports on-board the MN10300
+ */
+#ifdef MN10300_CONSOLE_ON_SERIO
+void debug_to_serial_mnser(const char *p, int n)
+{
+       char ch;
+
+       for (; n > 0; n--) {
+               ch = *p++;
+
+#if MN10300_CONSOLE_ON_SERIO == 0
+               while (SC0STR & (SC01STR_TBF)) continue;
+               SC0TXB = ch;
+               while (SC0STR & (SC01STR_TBF)) continue;
+               if (ch == 0x0a) {
+                       SC0TXB = 0x0d;
+                       while (SC0STR & (SC01STR_TBF)) continue;
+               }
+
+#elif MN10300_CONSOLE_ON_SERIO == 1
+               while (SC1STR & (SC01STR_TBF)) continue;
+               SC1TXB = ch;
+               while (SC1STR & (SC01STR_TBF)) continue;
+               if (ch == 0x0a) {
+                       SC1TXB = 0x0d;
+                       while (SC1STR & (SC01STR_TBF)) continue;
+               }
+
+#elif MN10300_CONSOLE_ON_SERIO == 2
+               while (SC2STR & (SC2STR_TBF)) continue;
+               SC2TXB = ch;
+               while (SC2STR & (SC2STR_TBF)) continue;
+               if (ch == 0x0a) {
+                       SC2TXB = 0x0d;
+                       while (SC2STR & (SC2STR_TBF)) continue;
+               }
+
+#endif
+       }
+}
+#endif
+
diff --git a/arch/mn10300/kernel/mn10300-serial-low.S b/arch/mn10300/kernel/mn10300-serial-low.S
new file mode 100644 (file)
index 0000000..ef3f4c1
--- /dev/null
@@ -0,0 +1,191 @@
+###############################################################################
+#
+# Virtual DMA driver for MN10300 serial ports
+#
+# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public Licence
+# as published by the Free Software Foundation; either version
+# 2 of the Licence, or (at your option) any later version.
+#
+###############################################################################
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/smp.h>
+#include <asm/cpu-regs.h>
+#include <asm/frame.inc>
+#include <asm/timer-regs.h>
+#include <asm/proc/cache.h>
+#include <asm/unit/timex.h>
+#include "mn10300-serial.h"
+
+#define        SCxCTR  0x00
+#define        SCxICR  0x04
+#define        SCxTXB  0x08
+#define        SCxRXB  0x09
+#define        SCxSTR  0x0c
+#define        SCxTIM  0x0d
+
+       .text
+
+###############################################################################
+#
+# serial port interrupt virtual DMA entry point
+# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
+#
+###############################################################################
+       .balign L1_CACHE_BYTES
+ENTRY(mn10300_serial_vdma_interrupt)
+       or      EPSW_IE,psw                     # permit overriding by
+                                               # debugging interrupts
+       movm    [d2,d3,a2,a3,exreg0],(sp)
+
+       movhu   (IAGR),a2                       # see if which interrupt is
+                                               # pending
+       and     IAGR_GN,a2
+       add     a2,a2
+       add     mn10300_serial_int_tbl,a2
+
+       mov     (a2+),a3
+       mov     (__iobase,a3),e2
+       mov     (a2),a2
+       jmp     (a2)
+
+###############################################################################
+#
+# serial port receive interrupt virtual DMA entry point
+# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
+# - stores data/status byte pairs in the ring buffer
+# - induces a scheduler tick timer interrupt when done, which we then subvert
+# on entry:
+#      A3      struct mn10300_serial_port *
+#      E2      I/O port base
+#
+###############################################################################
+ENTRY(mn10300_serial_vdma_rx_handler)
+       mov     (__rx_icr,a3),e3
+       mov     GxICR_DETECT,d2
+       movbu   d2,(e3)                         # ACK the interrupt
+       movhu   (e3),d2                         # flush
+
+       mov     (__rx_inp,a3),d3
+       mov     d3,a2
+       add     2,d3
+       and     MNSC_BUFFER_SIZE-1,d3
+       mov     (__rx_outp,a3),d2
+       cmp     d3,d2
+       beq     mnsc_vdma_rx_overflow
+
+       mov     (__rx_buffer,a3),d2
+       add     d2,a2
+       movhu   (SCxSTR,e2),d2
+       movbu   d2,(1,a2)
+       movbu   (SCxRXB,e2),d2
+       movbu   d2,(a2)
+       mov     d3,(__rx_inp,a3)
+       bset    MNSCx_RX_AVAIL,(__intr_flags,a3)
+
+mnsc_vdma_rx_done:
+       mov     (__tm_icr,a3),a2
+       mov     GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2
+       movhu   d2,(a2)                         # request a slow interrupt
+       movhu   (a2),d2                         # flush
+
+       movm    (sp),[d2,d3,a2,a3,exreg0]
+       rti
+
+mnsc_vdma_rx_overflow:
+       bset    MNSCx_RX_OVERF,(__intr_flags,a3)
+       bra     mnsc_vdma_rx_done
+
+###############################################################################
+#
+# serial port transmit interrupt virtual DMA entry point
+# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
+# - retrieves data bytes from the ring buffer and passes them to the serial port
+# - induces a scheduler tick timer interrupt when done, which we then subvert
+#      A3      struct mn10300_serial_port *
+#      E2      I/O port base
+#
+###############################################################################
+       .balign L1_CACHE_BYTES
+ENTRY(mn10300_serial_vdma_tx_handler)
+       mov     (__tx_icr,a3),e3
+       mov     GxICR_DETECT,d2
+       movbu   d2,(e3)                 # ACK the interrupt
+       movhu   (e3),d2                 # flush
+
+       btst    0x01,(__tx_break,a3)    # handle transmit break request
+       bne     mnsc_vdma_tx_break
+
+       movbu   (SCxSTR,e2),d2          # don't try and transmit a char if the
+                                       # buffer is not empty
+       btst    SC01STR_TBF,d2          # (may have tried to jumpstart)
+       bne     mnsc_vdma_tx_noint
+
+       movbu   (__tx_xchar,a3),d2      # handle hi-pri XON/XOFF
+       or      d2,d2
+       bne     mnsc_vdma_tx_xchar
+
+       mov     (__tx_info_buffer,a3),a2 # get the uart_info struct for Tx
+       mov     (__xmit_tail,a2),d3
+       mov     (__xmit_head,a2),d2
+       cmp     d3,d2
+       beq     mnsc_vdma_tx_empty
+
+       mov     (__xmit_buffer,a2),d2   # get a char from the buffer and
+                                       # transmit it
+       movbu   (d3,d2),d2
+       movbu   d2,(SCxTXB,e2)          # Tx
+
+       inc     d3                      # advance the buffer pointer
+       and     __UART_XMIT_SIZE-1,d3
+       mov     (__xmit_head,a2),d2
+       mov     d3,(__xmit_tail,a2)
+
+       sub     d3,d2                   # see if we've written everything
+       beq     mnsc_vdma_tx_empty
+
+       and     __UART_XMIT_SIZE-1,d2   # see if we just made a hole
+       cmp     __UART_XMIT_SIZE-2,d2
+       beq     mnsc_vdma_tx_made_hole
+
+mnsc_vdma_tx_done:
+       mov     (__tm_icr,a3),a2
+       mov     GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2
+       movhu   d2,(a2)                 # request a slow interrupt
+       movhu   (a2),d2                 # flush
+
+mnsc_vdma_tx_noint:
+       movm    (sp),[d2,d3,a2,a3,exreg0]
+       rti
+
+mnsc_vdma_tx_empty:
+       mov     +(GxICR_LEVEL_1|GxICR_DETECT),d2
+       movhu   d2,(e3)                 # disable the interrupt
+       movhu   (e3),d2                 # flush
+
+       bset    MNSCx_TX_EMPTY,(__intr_flags,a3)
+       bra     mnsc_vdma_tx_done
+
+mnsc_vdma_tx_break:
+       movhu   (SCxCTR,e2),d2          # turn on break mode
+       or      SC01CTR_BKE,d2
+       movhu   d2,(SCxCTR,e2)
+       mov     +(GxICR_LEVEL_1|GxICR_DETECT),d2
+       movhu   d2,(e3)                 # disable transmit interrupts on this
+                                       # channel
+       movhu   (e3),d2                 # flush
+       bra     mnsc_vdma_tx_noint
+
+mnsc_vdma_tx_xchar:
+       bclr    0xff,(__tx_xchar,a3)
+       movbu   d2,(SCxTXB,e2)
+       bra     mnsc_vdma_tx_done
+
+mnsc_vdma_tx_made_hole:
+       bset    MNSCx_TX_SPACE,(__intr_flags,a3)
+       bra     mnsc_vdma_tx_done
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c