diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /arch/mips | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/mips')
119 files changed, 18532 insertions, 3554 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index baec00d70..c7ba5db9b 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -10,78 +10,166 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1994, 1995 by Waldorf Electronics, -# written by Ralf Baechle +# Copyright (C) 1994, 1995, 1996 by Ralf Baechle +# DECStation modifications by Paul M. Antoine, 1996 +# ACN MIPS board modifications by Robin Farine (Robin.Farine@info.unine.ch) +# and Didier Frick (dfrick@dial.eunet.ch), copyright (C) 1996 by ACN S.A. # -ifdef CONFIG_ELF_COMPILER ifdef CONFIG_CPU_LITTLE_ENDIAN -prefix = mipsel-linuxelf- +cross-target = mipsel-linux- +ifdef CONFIG_MIPS_ECOFF +oformat = ecoff-littlemips else -prefix = mips-linuxelf- +oformat = a.out-mips-little-linux endif else -ifdef CONFIG_CPU_LITTLE_ENDIAN -prefix = mipsel-linux- +cross-target = mips-linux- +ifdef CONFIG_MIPS_ECOFF +oformat = ecoff-bigmips else -prefix = mips-linux- +oformat = a.out-mips-big-linux +endif endif + +ifdef CONFIG_CROSS_COMPILE +CROSS_COMPILE := $(cross-target) +else +CROSS_COMPILE := endif -AS = $(prefix)as -LD = $(prefix)ld -LINKFLAGS = -N -Ttext 0x80000000 -#HOSTCC = gcc -CC = $(prefix)gcc -D__KERNEL__ -I$(TOPDIR)/include -CPP = $(CC) -E $(CFLAGS) -AR = $(prefix)ar -RANLIB = $(prefix)ranlib -STRIP = $(prefix)strip -NM = $(prefix)nm +LINKFLAGS = -N # -# The new ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC +# The GCC uses -G 0 -mabicalls -fpic as default. We don't need PIC # code in the kernel since it only slows down the whole thing. For the # old GCC these options are just the defaults. At some point we might -# make use of global pointer optimaztions. +# make use of global pointer optimizations. # -ifdef CONFIG_OBJECT_ELF -CFLAGS := $(CFLAGS) -G0 -mno-abicalls -fno-pic #-pipe -endif +# We also pass -G 0 to the linker to avoid generation of a .scommon section. +# +# The DECStation requires an ECOFF kernel for remote booting, other MIPS +# machines may also. We build an ELF kernel and them convert it into an +# ECOFF kernel. +# +CFLAGS += -G 0 -mno-abicalls -fno-pic +LINKFLAGS += -G 0 ifdef CONFIG_REMOTE_DEBUG CFLAGS := $(CFLAGS) -g endif +# +# CPU dependand compiler/assembler options for optimization. +# ifdef CONFIG_CPU_R3000 CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1 -ASFLAGS := $(ASFLAGS) -mcpu=r3000 -mips1 +SUBDIRS += arch/mips/mips1 +cpu-core = arch/mips/mips1/mips.o endif ifdef CONFIG_CPU_R6000 CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2 -ASFLAGS := $(ASFLAGS) -mcpu=r6000 -mips2 +SUBDIRS += arch/mips/mips2 +cpu-core = arch/mips/mips2/mips.o endif ifdef CONFIG_CPU_R4X00 -CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r4400 -mips2 -ASFLAGS := $(ASFLAGS) -mcpu=r4400 -mips2 +ifdef CONFIG_OPTIMIZE_R4600 +CFLAGS := $(CFLAGS) -mcpu=r4600 -mips3 +else +CFLAGS := $(CFLAGS) -mcpu=r4400 -mips3 endif -ifdef CONFIG_CPU_R4600 -CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r4600 -mips2 -ASFLAGS := $(ASFLAGS) -mcpu=r4600 -mips2 +SUBDIRS += arch/mips/mips3 +cpu-core = arch/mips/mips3/mips.o endif ifdef CONFIG_CPU_R8000 -CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r8000 -mips2 -ASFLAGS := $(ASFLAGS) -mcpu=r8000 -mips2 +CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +SUBDIRS += arch/mips/mips3 +cpu-core = arch/mips/mips3/mips.o endif ifdef CONFIG_CPU_R10000 -CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r8000 -mips2 -ASFLAGS := $(ASFLAGS) -mcpu=r8000 -mips2 +CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +SUBDIRS += arch/mips/mips3 +cpu-core = arch/mips/mips3/mips.o +endif + +# +# Board dependand options and extra files +# +ifdef CONFIG_ACER_PICA_61 +ARCHIVES += arch/mips/jazz/jazz.o +SUBDIRS += arch/mips/jazz +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif +ifdef CONFIG_ACN_MIPS_BOARD +ARCHIVES += arch/mips/acn/acn.o +SUBDIRS += arch/mips/acn +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif +ifdef CONFIG_MIPS_DECSTATION +ARCHIVES += arch/mips/dec/dec.o +SUBDIRS += arch/mips/dec +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 endif +ifdef CONFIG_DESKSTATION_RPC44 +ARCHIVES += arch/mips/deskstation/deskstation.o +SUBDIRS += arch/mips/deskstation +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif +ifdef CONFIG_DESKSTATION_TYNE +ARCHIVES += arch/mips/deskstation/deskstation.o +SUBDIRS += arch/mips/deskstation +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif +ifdef CONFIG_MIPS_MAGNUM_3000 +LINKFLAGS += -Ttext 0x80100000 +endif +ifdef CONFIG_MIPS_MAGNUM_4000 +ARCHIVES += arch/mips/jazz/jazz.o +SUBDIRS += arch/mips/jazz +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif +ifdef CONFIG_OLIVETTI_M700 +ARCHIVES += arch/mips/jazz/jazz.o +SUBDIRS += arch/mips/jazz +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif +ifdef CONFIG_SNI_RM200_PCI +ARCHIVES += arch/mips/sni/sni.o +SUBDIRS += arch/mips/sni +LINKSCRIPT += arch/mips/ld.script +LOADADDR += 0x80000000 +endif + +# +# Choosing incompatible machines durings configuration will result in +# error messages during linking +# +ifdef LINKSCRIPT +LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) +endif + +ifdef LOADADDR +LINKFLAGS += -Ttext $(word 1,$(LOADADDR)) +endif + +# +# The pipe options is bad for low-mem machines +# Uncomment this if you want this. Helps most on diskless +# Linux machines. +# +CFLAGS += #-pipe HEAD := arch/mips/kernel/head.o SUBDIRS := $(SUBDIRS) arch/mips/kernel arch/mips/mm arch/mips/lib -ARCHIVES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(ARCHIVES) +ARCHIVES := $(cpu-core) arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(ARCHIVES) LIBS := arch/mips/lib/lib.a $(LIBS) arch/mips/lib/lib.a MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot @@ -96,6 +184,7 @@ zdisk: vmlinux archclean: @$(MAKEBOOT) clean + $(MAKE) -C arch/$(ARCH)/kernel clean archdep: @$(MAKEBOOT) dep diff --git a/arch/mips/TODO b/arch/mips/TODO index 29afd71f7..c5df56d0c 100644 --- a/arch/mips/TODO +++ b/arch/mips/TODO @@ -1,10 +1,166 @@ - - Check the definitions for F_EXLCK and F_SHLCK in include/asm-mips/fcntl.h - for correctness and compatibility with MIPS ABI. - - Check the definitions for O_NDELAY in include/asm-mips/fcntl.h for - correctness and compatibility with MIPS ABI. - - What are the fields l_sysid and pad in struct flock supposed to contain? - Do we need to handle them in the kernel? - - Check the resource limits defines in asm-mips/resource.h - - Recheck struct stat in asm-mips/stat.h - - Use timestruc_t in struct stat in asm/stat.h instead of time_t - - cacheflush should check for illegal flags + - Kernel: + - fd_set_dma_addr() Virtuelle Adressen -> Bus adressen + - __pa() und __va() Makro Benutzer in include/asm-mips/ aendern + - The PICs in some RISC PC class machines are cascaded, in others not. + Yuck. If they're using PC crap part they should do it right ... + - Print a warning for R4600 V1.0 users; there is a problem with the + caches that isn't handled yet in the kernel. + - IP checksums overhaul. (Dave said he did for the SGI port) + - The networking related constants still aren't indentical with IRIX/ABI. + - Check the definitions for F_EXLCK and F_SHLCK in include/asm-mips/fcntl.h + for correctness and compatibility with MIPS ABI. + - Check the definitions for O_NDELAY in include/asm-mips/fcntl.h for + correctness and compatibility with MIPS ABI. + - What are the fields l_sysid and pad in struct flock supposed to contain? + Do we need to handle them in the kernel? + - Check the resource limits defines in asm-mips/resource.h + - Recheck struct stat in asm-mips/stat.h + - Use timestruc_t in struct stat in asm/stat.h instead of time_t + - asm-mips/termios.h is pretty hacked; it should be verified for ABI + conformance by someone who has the documentation. + - Cleanup include files. To many files include too many others. + - Fix asm-mips/elf.h. This is just good enough to make the thing compile. + - asm-mips/socket.h needs further fixes for ABI conformance. + - linux/types.h / asm-mips/types.h: FD_SETSIZE should be 1024, not 256. + 1024 is required by the ABI. + - asm-mips/socket.h: check the FIO* and SIO* defines. + - linux/sockios.h: The sockios aren't ABI compatible. + - For performance reasons the missing inline functions in asm-mips/string.h + should be implemented. + - For performance reasons the tlbflush code should be rewritten. + - Module support for the Sonic driver. + - From 1.3.17 on the kernel does no more compile with network support but + without procfs support included. + - /proc/cpuinfo should contain more information that just CPU model, + computer model and damn BogoMIPS. + - The sysmips(2) syscall needs to be tested. Some of the subcommands + are still missing. + - The whole kernel is junked with #if 0 ... #endif debug code. Cleanup. + - Use set_pte hook in page.h. It's the more effective and elegant way + than my solution which was just optimized just to better survives other + peoples kernel patches without rejects ... + - Build the machine vector in arch/mips/kernel/setup.c table using + constructors, not static initialization. + - Can the virtual address spaces of the kernel virtual memory and page + tables colide with each other? (Yes, when the kernel uses excessive + amounts of kernel virtual memory.) + - Test the memory protection with nuclear warheads model W-crashme ... + - die_if_kernel() should try to handle branch delay slots. + - Try to reduce dependencies between header files. + - Unroll some of the memset type assembler loops. + - Replace memcpy and friends by a highly optimized routine. Will probably + speed up scrolling by another 100 %. Certainly not required by the Acer, + but Magnum and Olivetti ... + - Hmm... Think that the i386 version of the kernel has a bug. It doesn't + set the carry flag for syscalls > NR_syscalls. Really unimportant. + - The size_t definitions in <linux/stddef.h> and <asm/types.h> are + incompatible. + - Cleanup the parameter passing to new execve-ed ELF/a.out executables. + - Cleanup drivers/char/keyboard.c and send it to Linus. + - No SMP support yet. + - Caches: + - sys_cacheflush should check for illegal flags + - The way cache flushing is being done in floppy.c is dangerous because + the flushing is actually a writeback invalidate. Could corrupt data. + - The kernel is very conservative about flushing the TLB/caches. Try + to eleminate flushing as far as possible. + - page colouring NEEDS to be implemented for R4000+ to circument the + page aliasing problem due to the stupid R4000 cache. There are + alternatives but they'd be dog slow. + - Allocate the swapper pgd dynamically. + - it is impossible to send signals >= 32 (send_sig() in kernel/exit.c) + - Which is the unit of RLIMIT_CPU? + - Eleminate invalid_pte_table. It contains only zeros just like + empty_zero_page. + - Writing to floppies doesn't work in 1.3.62. + - Cleanup the arch/mips/ directory structure. Split up kernel/ and mm/ + in cpu dependand and machine dependand directories. Do this also for + the configfile. + - FIXME: resume() assumes current == prev. + - The timer interrupt runs with interrupts disabled. This means that + sometimes interrupts are off for a long time. Use some other strategy + for the jiffies stuff. + - Scrollback in the VGA console is broken. + - Modify pte_alloc() the same way as for Intel. + - Binutils 2.7: + - 2.6 introduces a new machine instruction waiti for the 4010. Is this + the same machine instruction as wait for R4200/R4300i/R4600? At least + the opcodes are the sames. + - strip --remove-section= with no other options also removes the symbols. + - Shouldn't the binutils support an ulwu macro? + - uld, ulw generate bad code for the special case when both registers are + the same. + - MIPS support in gprof is missing. + - When explicitly giving an nonexistant entry point as -e <entry> point + during loading a shared lib, ld should complain. + - The assembler dies when the argument to .gpword is a extern symbol. + - This source breaks GAS in binutils 2.7: + .macro ins + .if (3 | 16) + .endif + .endm + + ins + - GNU libc 951215: + - There are lots of collisions between structures in the kernel header + files and the includes generated by the kernel. + - setjmp & friends fail for the 32 double register model of > MIPS3. + - R4400: + - Per once told me he found something he believes is a CPU bug. Ask him if + it's really a bug. + - R8000 in arch/mips/config.in: + - Can the R8000 do a TLB shutdown like the R4000 or is it like the R10000? + - Manpages: + - The sysmips(2) documentation needs to be completed. + - The cacheflush(2) and cachectl(2) documentation needs to be proof read + by a native speaker. + - Translate the manpages into as many foreign languages as possible. + - Send the corrected/translated manpages to the LDP/Andries Brouwer. + - GCC 2.7.2: + - The info files lack descriptions of some MIPS options like -mips4. + - The multilib support has no way to specify incompatible options + like -mabicalls and -fno-PIC. For such option pairs library compilation + is nonsense and breaks anyway. + - The following macros work but generate good code only for certain + data types. We only use get_unaligned() for accessing unaligned ints + and then GCC makes full score anyway ... + +#define get_unaligned(ptr) \ + ({ \ + struct __unal { \ + __typeof__(*(ptr)) __x __attribute__((packed)); \ + }; \ + \ + ((struct __unal *)(ptr))->__x; \ + }) + +#define put_unaligned(ptr,val) \ + ({ \ + struct __unal { \ + __typeof__(*(ptr)) __x __attribute__((packed)); \ + }; \ + \ + ((struct __unal *)(ptr))->__x = (val); \ + }) + +int +foo(int *p) +{ + return get_unaligned(p); +} + +int +bar(int *p, int var) +{ + put_unaligned(p, var); +} + +struct blah { + char x1 __attribute__((packed)); + int x2 __attribute__((packed)); +}; + +fasel(struct blah *p, int var) +{ + p->x2 = var; +} diff --git a/arch/mips/acn/Makefile b/arch/mips/acn/Makefile new file mode 100644 index 000000000..3821d7b62 --- /dev/null +++ b/arch/mips/acn/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the SNI specific part of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: sni.o +O_TARGET := sni.o +O_OBJS := hw-access.o int-handler.o reset.o setup.o + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/acn/reset.c b/arch/mips/acn/reset.c new file mode 100644 index 000000000..149fedd9d --- /dev/null +++ b/arch/mips/acn/reset.c @@ -0,0 +1,12 @@ +/* + * linux/arch/mips/sni/process.c + * + * Reset the ACN board. + */ +#include <asm/io.h> +#include <asm/system.h> + +void +acn_hard_reset_now(void) +{ +} diff --git a/arch/mips/acn/setup.c b/arch/mips/acn/setup.c new file mode 100644 index 000000000..5fe8731e5 --- /dev/null +++ b/arch/mips/acn/setup.c @@ -0,0 +1,26 @@ +/* + * Setup pointers to hardware dependand routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/ptrace.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/vector.h> + +extern void acn_hard_reset_now(void); + +void +sni_rm200_pci_setup(void) +{ + hard_reset_now = acn_hard_reset_now; +} diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index 93784137d..3a8698d34 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -8,12 +8,6 @@ # Copyright (C) 1995 by Ralf Baechle # -.c.s: - $(CC) $(CFLAGS) -S $< -.s.o: - $(AS) $(ASFLAGS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c $< .S.s: $(CPP) $(CFLAGS) $< -o $*.s .S.o: @@ -22,11 +16,22 @@ OBJS = milo.o a.out.o # +# Drop some uninteresting sections in the kernel. +# This is only relevant for ELF kernels but doesn't hurt a.out +# +drop-sections = .reginfo .mdebug +strip-flags = $(addprefix --remove-section=,$(drop-sections)) + +# # Fake compressed boot # -zImage: $(CONFIGURE) $(TOPDIR)/vmlinux - cp $(TOPDIR)/vmlinux $@ - $(STRIP) --discard-all $@ +zImage: $(CONFIGURE) mkboot $(TOPDIR)/vmlinux + $(OBJCOPY) $(strip-flags) $(TOPDIR)/vmlinux zImage.tmp + ./mkboot zImage.tmp zImage + rm -f zImage.tmp + +mkboot: mkboot.c + $(HOSTCC) -o $@ $^ zdisk: zImage mcopy -n zImage a:vmlinux @@ -35,13 +40,8 @@ dep: $(CPP) -M *.[cS] > .depend clean: - rm -f zImage + rm -f zImage zImage.tmp mkboot dummy: -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 228ee83bc..e613fece0 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -1,5 +1,5 @@ # -# linux/arch/i386/boot/compressed/Makefile +# linux/arch/mips/boot/compressed/Makefile # # create a compressed vmlinux image from the original vmlinux # @@ -11,12 +11,6 @@ OBJECTS = $(HEAD) inflate.o unzip.o misc.o CFLAGS = -O2 -DSTDC_HEADERS -.c.s: - $(CC) $(CFLAGS) -S $< -.s.o: - $(AS) $(ASFLAGS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c $< .S.s: $(CPP) $(CFLAGS) $< -o $*.s .S.o: diff --git a/arch/mips/boot/compressed/cache.S b/arch/mips/boot/compressed/cache.S index 8e7fff0c1..3e6a3d57d 100644 --- a/arch/mips/boot/compressed/cache.S +++ b/arch/mips/boot/compressed/cache.S @@ -18,9 +18,10 @@ #include <asm/asm.h> #include <asm/cachectl.h> #include <asm/mipsregs.h> -#include <asm/segment.h> +#include <asm/uaccess.h> -#ifdef __R4000__ +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) /* * Some bits in the config register @@ -28,6 +29,8 @@ #define CONFIG_IB (1<<5) #define CONFIG_DB (1<<4) +#define CACHEBLOCKS 32 + /* * Flush instruction/data caches * @@ -48,7 +51,7 @@ /* * Writeback data cache, even lines */ - li t1,CACHELINES-1 + li t1,CACHEBLOCKS-1 1: cache Index_Writeback_Inv_D,0(t0) cache Index_Writeback_Inv_D,32(t0) cache Index_Writeback_Inv_D,64(t0) @@ -76,7 +79,7 @@ mfc0 t1,CP0_CONFIG andi t1,CONFIG_IB bnez t1,do_icache - li t1,CACHELINES-1 + li t1,CACHEBLOCKS-1 1: cache Index_Writeback_Inv_D,16(t0) cache Index_Writeback_Inv_D,48(t0) cache Index_Writeback_Inv_D,80(t0) @@ -104,7 +107,7 @@ do_icache: andi t1,a2,ICACHE * Flush instruction cache, even lines */ lui t0,0x8000 - li t1,CACHELINES-1 + li t1,CACHEBLOCKS-1 1: cache Index_Invalidate_I,0(t0) cache Index_Invalidate_I,32(t0) cache Index_Invalidate_I,64(t0) @@ -132,7 +135,7 @@ do_icache: andi t1,a2,ICACHE mfc0 t1,CP0_CONFIG andi t1,CONFIG_DB bnez t1,done - li t1,CACHELINES-1 + li t1,CACHEBLOCKS-1 1: cache Index_Invalidate_I,16(t0) cache Index_Invalidate_I,48(t0) cache Index_Invalidate_I,80(t0) @@ -157,6 +160,6 @@ done: j ra nop END(sys_cacheflush) -#else /* !defined (__R4000__) */ +#else #error "No R3000 cacheflushing implemented yet!" -#endif /* !defined (__R4000__) */ +#endif diff --git a/arch/mips/boot/compressed/misc.c b/arch/mips/boot/compressed/misc.c index 1e3bb5f82..625a75cd0 100644 --- a/arch/mips/boot/compressed/misc.c +++ b/arch/mips/boot/compressed/misc.c @@ -12,7 +12,7 @@ #include "gzip.h" #include "lzw.h" -#include <asm/segment.h> +#include <asm/uaccess.h> /* * These are set up by the setup-routine at boot-time: diff --git a/arch/mips/boot/mkboot.c b/arch/mips/boot/mkboot.c new file mode 100644 index 000000000..c34332f99 --- /dev/null +++ b/arch/mips/boot/mkboot.c @@ -0,0 +1,660 @@ +/* + * Make a bootable image from a Linux/MIPS kernel. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + * + * This file is written in plain Kernighan & Ritchie C as it has to run + * on all crosscompile hosts no matter how braindead. This code might + * also become part of Milo. It's therefore important that we don't use + * seek because the Seek() call of the Magnum 4000 ARC BIOS is broken. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +/* + * Define this for verbose debugging output. + */ +#undef VERBOSE + +/* + * Don't use the host's elf.h - it might be using incompatible defines + */ + +#define EI_NIDENT 16 + +/* + * Basic ELF types. + */ +typedef unsigned short Elf32_Half; +typedef unsigned short Elf32_Section; +typedef unsigned int Elf32_Word; +typedef unsigned int Elf32_Addr; +typedef unsigned int Elf32_Off; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +/* + * ELF magic number + */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 /* File version byte index */ +#define EV_CURRENT 1 /* Current version */ + +/* + * Acceptable machine type in e_machine. + */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +/* + * The type of ELF file we accept. + */ +#define ET_EXEC 2 /* Executable file */ + +/* + * Definition of a single program header structure + */ +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +/* + * Legal values for p_type + */ +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_NUM 7 /* Number of defined types. */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +/* How to extract and insert information held in the st_info field. */ +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ +#define STB_GLOBAL 1 /* Global symbol */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ + +static unsigned int +get_Elf32_Half(unsigned char *p) +{ + return p[0] | (p[1] << 8); +} +#define get_Elf32_Section(p) get_Elf32_Half(p) + +static unsigned int +get_Elf32_Word(unsigned char *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} +#define get_Elf32_Addr(p) get_Elf32_Word(p) +#define get_Elf32_Off(p) get_Elf32_Word(p) + +static void +put_byte(p, x) + unsigned char *p; + unsigned char x; +{ + p[0] = x; +} + +static void +put_half(p, x) + unsigned char *p; + unsigned short x; +{ + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; +} + +static void +put_word(p, x) + unsigned char *p; + unsigned long x; +{ + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +/* + * Swap a program header in. + */ +static void +get_elfph(p, ph) + unsigned char *p; + Elf32_Phdr *ph; +{ + ph->p_type = get_Elf32_Word(p); + ph->p_offset = get_Elf32_Off(p + 4); + ph->p_vaddr = get_Elf32_Addr(p + 8); + ph->p_paddr = get_Elf32_Addr(p + 12); + ph->p_filesz = get_Elf32_Word(p + 16); + ph->p_memsz = get_Elf32_Word(p + 20); + ph->p_flags = get_Elf32_Word(p + 24); + ph->p_align = get_Elf32_Word(p + 28); +} + +/* + * Swap a section header in. + */ +static void +get_elfsh(p, sh) + unsigned char *p; + Elf32_Shdr *sh; +{ + sh->sh_name = get_Elf32_Word(p); + sh->sh_type = get_Elf32_Word(p + 4); + sh->sh_flags = get_Elf32_Word(p + 8); + sh->sh_addr = get_Elf32_Addr(p + 12); + sh->sh_offset = get_Elf32_Off(p + 16); + sh->sh_size = get_Elf32_Word(p + 20); + sh->sh_link = get_Elf32_Word(p + 24); + sh->sh_info = get_Elf32_Word(p + 28); + sh->sh_addralign = get_Elf32_Word(p + 32); + sh->sh_entsize = get_Elf32_Word(p + 36); +} + +/* + * Swap a section header in. + */ +static void +get_elfsym(p, sym) + unsigned char *p; + Elf32_Sym *sym; +{ + sym->st_name = get_Elf32_Word(p); + sym->st_value = get_Elf32_Addr(p + 4); + sym->st_size = get_Elf32_Word(p + 8); + sym->st_info = *(p + 12); + sym->st_other = *(p + 13); + sym->st_shndx = get_Elf32_Section(p + 14); +} + +/* + * The a.out magic number + */ +#define OMAGIC 0407 /* Code indicating object file or impure executable. */ +#define M_MIPS1 151 /* MIPS R3000/R3000 binary */ +#define M_MIPS2 152 /* MIPS R6000/R4000 binary */ + +/* + * Compute and return an a.out magic number. + */ +#define AOUT_INFO(magic, type, flags) \ + (((magic) & 0xffff) | \ + (((int)(type) & 0xff) << 16) | \ + (((flags) & 0xff) << 24)) + +/* + * a.out symbols + */ +#define N_UNDF 0 +#define N_ABS 2 +#define N_TEXT 4 +#define N_DATA 6 +#define N_BSS 8 +#define N_FN 15 +#define N_EXT 1 + +#define min(x,y) (((x)<(y))?(x):(y)) + +static void +do_read(fd, buf, size) + int fd; + char *buf; + ssize_t size; +{ + ssize_t rd; + + while(size != 0) { + rd = read(fd, buf, size); + if (rd == -1) { + perror("Can't read from file."); + exit(1); + } + size -= rd; + } +} + +static void +writepad(fd, size) + int fd; + size_t size; +{ + static void *zeropage = NULL; + ssize_t written; + + if (zeropage == NULL) { + zeropage = malloc(4096); + if (zeropage == NULL) { + fprintf(stderr, "Couldn't allocate zero buffer.\n"); + exit(1); + } + memset(zeropage, '\0', 4096); + } + while(size != 0) { + written = write(fd, zeropage, min(4096, size)); + if (written == -1) { + perror("Can't write to boot image"); + exit(1); + } + size -= written; + } +} + +static void +do_write(fd, buf, size) + int fd; + char *buf; + ssize_t size; +{ + ssize_t written; + + while(size != 0) { + written = write(fd, buf, size); + if (written == -1) { + perror("Can't write to boot image"); + exit(1); + } + size -= written; + } +} + +static int +usage(program_name) + char *program_name; +{ + fprintf(stderr, "Usage: %s infile outfile\n", program_name); + exit(0); +} + +int +main(argc, argv) + int argc; + char *argv[]; +{ + char *infile, *outfile; + struct stat ifstat; + off_t ifsize; + void *image; + int ifd, ofd, i, symtabix, strtabix; + Elf32_Ehdr eh; + Elf32_Phdr *ph; + Elf32_Shdr *sh; + unsigned long vaddr, entry, bss, kernel_entry, kernel_end; + unsigned char ahdr[32]; + Elf32_Sym sym; + int symnum; + char *symname; + + /* + * Verify some basic assuptions about type sizes made in this code + */ + if (sizeof(Elf32_Half) != 2) { + fprintf(stderr, "Fix mkboot: sizeof(Elf32_Half) != 2\n"); + exit(1); + } + if (sizeof(Elf32_Word) != 4) { + fprintf(stderr, "Fix mkboot: sizeof(Elf32_Word) != 4\n"); + exit(1); + } + if (sizeof(Elf32_Addr) != 4) { + fprintf(stderr, "Fix mkboot: sizeof(Elf32_Addr) != 4\n"); + exit(1); + } + + if (argc != 3) + usage(argv[0]); + + infile = argv[1]; + outfile = argv[2]; + + if (stat(infile, &ifstat) < 0) { + perror("Can't stat kernel image."); + exit(1); + } + + if (!S_ISREG(ifstat.st_mode)) { + fprintf(stderr, "Input file isn't a regular file.\n"); + exit(1); + } + ifsize = ifstat.st_size; + + image = malloc((size_t)ifsize); + if (image == NULL) { + fprintf(stderr, "Can't allocate memory to read file\n"); + exit(1); + } + + /* + * Read the entire input file in. + */ + ifd = open(infile, O_RDONLY); + if(ifd == 0) { + fprintf(stderr, "Can't open input file\n"); + exit(1); + } + do_read(ifd, image, ifsize); + close(ifd); + + /* + * Now swap the ELF header in. This is ugly but we the file + * we're reading might have different type sizes, byteorder + * or alignment than the host. + */ + memcpy(eh.e_ident, image, sizeof(eh.e_ident)); + if(memcmp(eh.e_ident, ELFMAG, SELFMAG)) { + fprintf(stderr, "Input file isn't a ELF file\n"); + exit(1); + } + if(eh.e_ident[EI_CLASS] != ELFCLASS32) { + fprintf(stderr, "Input file isn't a 32 bit ELF file\n"); + exit(1); + } + if(eh.e_ident[EI_DATA] != ELFDATA2LSB) { + fprintf(stderr, "Input file isn't a little endian ELF file\n"); + exit(1); + } + if(eh.e_ident[EI_VERSION] != EV_CURRENT) { + fprintf(stderr, "Input file isn't a version %d ELF file\n", + EV_CURRENT); + exit(1); + } + + /* + * Ok, so far the file looks ok. Now swap the rest of the header in + * and do some more paranoia checks. + */ + eh.e_type = get_Elf32_Half(image + 16); + eh.e_machine = get_Elf32_Half(image + 18); + eh.e_version = get_Elf32_Word(image + 20); + eh.e_entry = get_Elf32_Addr(image + 24); + eh.e_phoff = get_Elf32_Off(image + 28); + eh.e_shoff = get_Elf32_Off(image + 32); + eh.e_flags = get_Elf32_Word(image + 36); + eh.e_ehsize = get_Elf32_Half(image + 40); + eh.e_phentsize = get_Elf32_Half(image + 42); + eh.e_phnum = get_Elf32_Half(image + 44); + eh.e_shentsize = get_Elf32_Half(image + 46); + eh.e_shnum = get_Elf32_Half(image + 48); + eh.e_shstrndx = get_Elf32_Half(image + 50); + + if(eh.e_type != ET_EXEC) { + fprintf(stderr, "Input file isn't a executable.\n"); + exit(1); + } + if(eh.e_machine != EM_MIPS && eh.e_machine != EM_MIPS_RS4_BE) { + fprintf(stderr, "Input file isn't a MIPS executable.\n"); + exit(1); + } + + /* + * Now read the program headers ... + */ + ph = malloc(sizeof(Elf32_Phdr) * eh.e_phnum); + if (ph == NULL) { + fprintf(stderr, "No memory for program header table.\n"); + exit(1); + } + for(i = 0;i < eh.e_phnum; i++) + get_elfph(image + eh.e_phoff + i * 32, ph + i); + + /* + * ... and then the section headers. + */ + sh = malloc(sizeof(Elf32_Shdr) * eh.e_shnum); + if (sh == NULL) { + fprintf(stderr, "No memory for section header table.\n"); + exit(1); + } + for(i = 0;i < eh.e_shnum; i++) + get_elfsh(image + eh.e_shoff + (i * 40), sh + i); + + /* + * Find the symboltable and the stringtable in the file. + */ + for(i = 0;i < eh.e_shnum; i++) { + if (!strcmp (image + sh [eh.e_shstrndx].sh_offset + sh[i].sh_name, + ".symtab")) { + symtabix = i; + continue; + } + if (!strcmp (image + sh [eh.e_shstrndx].sh_offset + sh[i].sh_name, + ".strtab")) { + strtabix = i; + continue; + } + } + + if (symtabix == -1) { + fprintf(stderr, "The executable doesn't have a symbol table\n"); + exit(1); + } + if (strtabix == -1) { + fprintf(stderr, "The executable doesn't have a string table\n"); + exit(1); + } + + /* + * Dig for the two required symbols in the symbol table. + */ + symnum = sh[symtabix].sh_size / 16; + for(i = 0;i < symnum;i++) { + get_elfsym(image + sh[symtabix].sh_offset + (i * 16), &sym); + symname = image + sh[strtabix].sh_offset + sym.st_name; + if (ELF32_ST_BIND(sym.st_info) != STB_GLOBAL) + continue; + if (ELF32_ST_TYPE(sym.st_info) != STT_NOTYPE && + ELF32_ST_TYPE(sym.st_info) != STT_OBJECT && + ELF32_ST_TYPE(sym.st_info) != STT_FUNC) + continue; + if (strcmp("kernel_entry", symname) == 0) { + kernel_entry = sym.st_value; + continue; + } + if (strcmp("_end", symname) == 0) { + kernel_end = sym.st_value; + continue; + } + } + +#ifdef VERBOSE + /* + * And print what we will be loaded into memory. + */ + for(i = 0;i < eh.e_phnum; i++) { + if (ph[i].p_type != PT_LOAD) { + continue; + } + printf(" Offset: %08lx\n", ph[i].p_offset); + printf(" file size: %08lx\n", ph[i].p_filesz); + printf(" mem size: %08lx\n", ph[i].p_memsz); + printf(" Loading: %08lx - %08lx\n", + ph[i].p_vaddr, ph[i].p_vaddr + ph[i].p_filesz); + printf(" Zero mapping: %08lx - %08lx\n", + ph[i].p_vaddr + ph[i].p_filesz, + ph[i].p_vaddr + ph[i].p_memsz); + } +#endif + + /* + * Time to open the outputfile. + */ + ofd = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (ofd == -1) { + perror("Can't open boot image for output."); + exit(1); + } + + /* + * First compute the layout of the file. We need to do this + * first because we can't seek back to the beginning due to the + * broken Seek() call in the Magnum firmware. + */ + entry = vaddr = 0xffffffff; + bss = 0; + for(i = 0;i < eh.e_phnum; i++) { + if (ph[i].p_type != PT_LOAD) + continue; + if (vaddr == 0xffffffff) + entry = vaddr = ph[i].p_vaddr; + vaddr = ph[i].p_vaddr + ph[i].p_filesz; + bss = ph[i].p_memsz - ph[i].p_filesz; + } + + /* + * In the next step we construct the boot image. The boot file + * looks essentially like a dump of the loaded kernel with a + * minimal header. Because Milo supports already a.out image + * we simply dump the image in an a.out image ... First let's + * write the header. + */ + + /* + * Create and write the a.out header. + */ + put_word(ahdr, AOUT_INFO(OMAGIC, M_MIPS1, 0)); + put_word(ahdr + 4, vaddr - entry); /* text size */ + put_word(ahdr + 8, 0); /* data size */ + put_word(ahdr + 12, bss); /* bss size */ + put_word(ahdr + 16, 2 * 12); /* size of symbol table */ +// put_word(ahdr + 16, 0); /* size of symbol table */ + put_word(ahdr + 20, entry); /* base address */ + put_word(ahdr + 24, 0); /* size of text relocations */ + put_word(ahdr + 28, 0); /* size of data relocations */ + do_write(ofd, ahdr, 32); + + /* + * Write text and data segment combined into the a.out text segment + * and a zero length data segment into the file. + */ + vaddr = 0xffffffff; + bss = 0; + for(i = 0;i < eh.e_phnum; i++) { + if (ph[i].p_type != PT_LOAD) + continue; + if (vaddr == 0xffffffff) + vaddr = ph[i].p_vaddr; + writepad(ofd, ph[i].p_vaddr - vaddr); /* Write zero pad */ + do_write(ofd, image + ph[i].p_offset, ph[i].p_filesz); + vaddr = ph[i].p_vaddr + ph[i].p_filesz; + bss = ph[i].p_memsz - ph[i].p_filesz; + } + + /* + * Now write the symbol table. It has only two symbols, + * kernel_entry and _end which we need for booting. + */ + put_word(ahdr , 4); /* n_un.n_strx */ + put_byte(ahdr + 4, N_TEXT | N_EXT); /* n_type */ + put_byte(ahdr + 5, 0); /* n_other */ + put_half(ahdr + 6, 0); /* n_desc */ + put_word(ahdr + 8, kernel_entry); /* n_value */ + do_write(ofd, ahdr, 12); + + put_word(ahdr , 4 + 13); /* n_un.n_strx */ + put_byte(ahdr + 4, N_ABS | N_EXT); /* n_type */ + put_byte(ahdr + 5, 0); /* n_other */ + put_half(ahdr + 6, 0); /* n_desc */ + put_word(ahdr + 8, kernel_end); /* n_value */ + do_write(ofd, ahdr, 12); + + /* + * Now write stringtable size and the strings. + */ + put_word(ahdr, 4 + 20); + do_write(ofd, ahdr, 4); + do_write(ofd, "kernel_entry\0_end\0\0", 20); + + /* + * That's is all ... + */ + close(ofd); + +#ifdef VERBOSE + printf("Entry: %08lx\n", entry); + printf("Dumped image %08lx - %08lx\n", 0x80000000, vaddr); + printf("Extra bss at end: %08lx\n", bss); +#endif + + return 0; +} diff --git a/arch/mips/config.in b/arch/mips/config.in index 6ecc5e698..3dd4c00c0 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -2,313 +2,173 @@ # For a description of the syntax of this configuration file, # see the Configure script. # +mainmenu_name "Linux Kernel Configuration" -comment 'Machine setup' +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu -bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 y -bool 'Support for DECstation' CONFIG_DECSTATION n -bool 'Support for Deskstation RPC44' CONFIG_DESKSTATION_RPC44 n -bool 'Support for Deskstation Tyne' CONFIG_DESKSTATION_TYNE n -bool 'Support for Mips Magnum 3000' CONFIG_MIPS_MAGNUM_3000 n -bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 y -if [ "$CONFIG_ACER_PICA_61" = "y" -o \ - "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ - "$CONFIG_OLIVETTI_M700" = "y" ]; then - echo "#define CONFIG_MIPS_JAZZ" >> $CONFIG_H - echo "CONFIG_MIPS_JAZZ=y" >> $CONFIG - CONFIG_MIPS_JAZZ=y -fi - -comment 'CPU selection' +mainmenu_option next_comment +comment 'Machine selection' -bool 'Generate code for R3000' CONFIG_CPU_R3000 n -#bool 'Generate code for R6000' CONFIG_CPU_R6000 n -bool 'Generate code for R4x00' CONFIG_CPU_R4X00 y -bool 'Generate code for R4600' CONFIG_CPU_R4600 n -bool 'Generate code for R8000' CONFIG_CPU_R8000 n -bool 'Generate code for R10000' CONFIG_CPU_R10000 n -bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN y -bool 'Compile the kernel into the ELF object format' CONFIG_MIPS_ELF n -if [ "$CONFIG_MIPS_ELF" = "y" ]; then - bool 'Is your normal Linux/MIPS compiler the ELF compiler' CONFIG_ELF_COMPILER n +bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for ACN MIPS Board' CONFIG_ACN_MIPS_BOARD fi - -comment 'General setup' - -bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y -bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 n -if [ "$CONFIG_ST506" = "y" ]; then - comment 'Please see block/drivers/README.ide for help/info on IDE drives' - bool ' Use old (reliable) disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y - if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then - bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n - else - bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE n - fi - if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then - bool ' Include support for IDE CDROM (ATAPI)' CONFIG_BLK_DEV_IDECD n - fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for DECstation' CONFIG_MIPS_DECSTATION fi - -bool 'XT harddisk support' CONFIG_BLK_DEV_XD n -bool 'Networking support' CONFIG_NET y -bool 'System V IPC' CONFIG_SYSVIPC n -bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF n - -if [ "$CONFIG_NET" = "y" ]; then -comment 'Networking options' -bool 'TCP/IP networking' CONFIG_INET y -if [ "$CONFIG_INET" = "y" ]; then -bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD n -bool 'IP: multicasting' CONFIG_IP_MULTICAST n -bool 'IP: firewalling' CONFIG_IP_FIREWALL n -bool 'IP: accounting' CONFIG_IP_ACCT n -bool 'IP: tunneling' CONFIG_NET_IPIP n -if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_FIREWALL" = "y" ]; then - bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y - bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for Deskstation RPC44' CONFIG_DESKSTATION_RPC44 + bool 'Support for Deskstation Tyne' CONFIG_DESKSTATION_TYNE + bool 'Support for Mips Magnum 3000' CONFIG_MIPS_MAGNUM_3000 +fi +bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 +bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700 +if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ + "$CONFIG_OLIVETTI_M700" = "y" ]; then + define_bool CONFIG_VIDEO_G364 y fi -comment '(it is safe to leave these untouched)' -bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP n -bool 'IP: Reverse ARP' CONFIG_INET_RARP n -bool 'IP: Assume subnets are local' CONFIG_INET_SNARL y -bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n -bool 'IP: Drop source routed frames' CONFIG_IP_NOSR y +bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI +if [ "$CONFIG_DESKSTATION_RPC44" = "y" -o \ + "$CONFIG_DESKSTATION_TYNE" = "y" ]; then + define_bool CONFIG_MIPS_ARC y fi -bool 'The IPX protocol' CONFIG_IPX n -bool 'Appletalk DDP' CONFIG_ATALK n -bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n -if [ "$CONFIG_AX25" = "y" ]; then - bool 'Amateur Radio NET/ROM' CONFIG_NETROM n +if [ "$CONFIG_ACER_PICA_61" = "y" -o \ + "$CONFIG_OLIVETTI_M700" = "y" -o \ + "$CONFIG_MIPS_MAGNUM_4000" = "y" ]; then + define_bool CONFIG_MIPS_JAZZ y fi +if [ "$CONFIG_ACN_MIPS_BOARD" = "y" ]; then + define_bool CONFIG_SERIAL_ONLY_CONSOLE y + define_bool CONFIG_NO_SWAPPER y + define_bool CONFIG_CUSTOM_UART y + define_bool CONFIG_CUSTOM_TIMER y fi +endmenu -comment 'SCSI support' - -bool 'SCSI support?' CONFIG_SCSI n - -if [ "$CONFIG_SCSI" = "n" ]; then - -comment 'Skipping SCSI configuration options...' - -else - -comment 'SCSI support type (disk, tape, CDrom)' - -bool 'SCSI disk support' CONFIG_BLK_DEV_SD y -bool 'SCSI tape support' CONFIG_CHR_DEV_ST y -bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR y -bool 'SCSI generic support' CONFIG_CHR_DEV_SG n - -comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - -bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n - -comment 'SCSI low-level drivers' +mainmenu_option next_comment +comment 'CPU selection' -bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y -bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n -bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y -bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n -bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n -bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n -bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n -bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n -if [ "$CONFIG_PCI" = "y" ]; then - bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n +choice 'CPU type' \ + "R3000 CONFIG_CPU_R3000 \ + R6000 CONFIG_CPU_R6000 \ + R4x00 CONFIG_CPU_R4X00 \ + R8000 CONFIG_CPU_R8000 \ + R10000 CONFIG_CPU_R10000" R4x00 +if [ "$CONFIG_CPU_R3000" = "y" -o \ + "$CONFIG_CPU_R6000" = "y" -o \ + "$CONFIG_CPU_R4X00" = "y" -o \ + "$CONFIG_CPU_R8000" = "y" ]; then + define_bool CONFIG_TLB_SHUTDOWN y fi -bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n -bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n -bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n -bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n -bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n -bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n -bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n -#bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n -#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n +if [ "$CONFIG_CPU_R4X00" = "y" ]; then + bool "Optimize for R4600 only" CONFIG_OPTIMIZE_R4600 fi +endmenu +mainmenu_option next_comment +comment 'General setup' +define_bool CONFIG_BINFMT_ELF y +define_bool CONFIG_BINFMT_AOUT n +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA +fi +if [ "$CONFIG_MIPS_DECSTATION" = "y" ]; then + bool 'Compile the kernel into the ECOFF object format' CONFIG_ECOFF_KERNEL + comment 'Assuming little endian code required.' + define_bool CONFIG_CPU_LITTLE_ENDIAN y +else + define_bool CONFIG_ELF_KERNEL y + bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN +fi +bool 'Networking support' CONFIG_NET +bool 'Limit memory to low 16MB' CONFIG_MAX_16M +bool 'PCI bios support' CONFIG_PCI +#if [ "$CONFIG_PCI" = "y" ]; then +# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE +# fi +#fi +bool 'System V IPC' CONFIG_SYSVIPC +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD +fi +endmenu + +source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then - -comment 'Network device support' - -bool 'Network device support?' CONFIG_NETDEVICES y -if [ "$CONFIG_NETDEVICES" = "n" ]; then - -comment 'Skipping network driver configuration options...' - -else -bool 'Dummy net driver support' CONFIG_DUMMY y -bool 'SLIP (serial line) support' CONFIG_SLIP n -if [ "$CONFIG_SLIP" = "y" ]; then - bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y - bool ' 16 channels instead of 4' SL_SLIP_LOTS n -fi -bool 'PPP (point-to-point) support' CONFIG_PPP n -if [ "$CONFIG_PPP" = "y" ]; then - bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n -fi -if [ "$CONFIG_AX25" = "y" ]; then - bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y -fi -bool 'PLIP (parallel port) support' CONFIG_PLIP n -bool 'EQL (serial line load balancing) support' CONFIG_EQUALIZER n -bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n -bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n -bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n -if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then - bool 'WD80*3 support' CONFIG_WD80x3 n - bool 'SMC Ultra support' CONFIG_ULTRA n -fi -bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n -bool '3COM cards' CONFIG_NET_VENDOR_3COM n -if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then - bool '3c501 support' CONFIG_EL1 n - bool '3c503 support' CONFIG_EL2 n - if [ "$CONFIG_NET_ALPHA" = "y" ]; then - bool '3c505 support' CONFIG_ELPLUS n - bool '3c507 support' CONFIG_EL16 n - fi - bool '3c509/3c579 support' CONFIG_EL3 n -fi -bool 'Other ISA cards' CONFIG_NET_ISA n -if [ "$CONFIG_NET_ISA" = "y" ]; then - bool 'Arcnet support' CONFIG_ARCNET n - bool 'Cabletron E21xx support' CONFIG_E2100 n - bool 'DEPCA support' CONFIG_DEPCA n - bool 'EtherWorks 3 support' CONFIG_EWRK3 n - if [ "$CONFIG_NET_ALPHA" = "y" ]; then - bool 'AT1700 support' CONFIG_AT1700 n -# bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n - bool 'EtherExpress support' CONFIG_EEXPRESS n - bool 'NI5210 support' CONFIG_NI52 n - bool 'NI6510 support' CONFIG_NI65 n - bool 'WaveLAN support' CONFIG_WAVELAN n - fi - bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n - bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n - bool 'NE2000/NE1000 support' CONFIG_NE2000 y - if [ "$CONFIG_AX25" = "y" ]; then - bool 'Ottawa PI and PI/2 support' CONFIG_PI y - fi - bool 'SK_G16 support' CONFIG_SK_G16 n -fi -bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n -if [ "$CONFIG_NET_EISA" = "y" ]; then - if [ "$CONFIG_NET_ALPHA" = "y" ]; then - bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n - fi - bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n -# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n -# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n -# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n -# bool 'Zenith Z-Note support' CONFIG_ZNET n + source net/Config.in fi -if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then - bool 'MIPS JAZZ onboard SONIC ethernet support' CONFIG_MIPS_JAZZ_SONIC y -fi +mainmenu_option next_comment +comment 'SCSI support' -bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n -if [ "$CONFIG_NET_POCKET" = "y" ]; then - bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n - bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n - bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n -# bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n -# bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n -# bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n -fi -bool 'Token Ring driver support' CONFIG_TR n -if [ "$CONFIG_TR" = "y" ]; then - bool 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR y -fi -fi +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in fi +endmenu -comment 'CD-ROM drivers' +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' -bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n -bool 'Mitsumi CDROM driver support' CONFIG_MCD n -bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n -if [ "$CONFIG_SBPCD" = "y" ]; then - bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n - if [ "$CONFIG_SBPCD2" = "y" ]; then - bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n - if [ "$CONFIG_SBPCD3" = "y" ]; then - bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n - fi + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in fi + endmenu fi -comment 'Filesystems' +mainmenu_option next_comment +comment 'ISDN subsystem' -bool 'Standard (minix) fs support' CONFIG_MINIX_FS n -bool 'Extended fs support' CONFIG_EXT_FS n -bool 'Second extended fs support' CONFIG_EXT2_FS y -bool 'xiafs filesystem support' CONFIG_XIA_FS n -bool 'msdos fs support' CONFIG_MSDOS_FS n -if [ "$CONFIG_MSDOS_FS" = "y" ]; then -#bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n -comment 'Umsdos is not supported in 1.3.0: wait for 1.3.1' -fi -bool '/proc filesystem support' CONFIG_PROC_FS n -if [ "$CONFIG_INET" = "y" ]; then -bool 'NFS filesystem support' CONFIG_NFS_FS n +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in fi -if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then - bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y -else - bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n -fi -bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n -bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n +endmenu -comment 'character devices' +mainmenu_option next_comment +comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' -bool 'Parallel printer support' CONFIG_PRINTER y -bool 'Standard serial device support' CONFIG_SERIAL y -bool 'Cyclades async mux support' CONFIG_CYCLADES n -bool 'Logitech busmouse support' CONFIG_BUSMOUSE n -bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n -if [ "$CONFIG_PSMOUSE" = "y" ]; then -bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE n +bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in fi -bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n -bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n - -bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n -if [ "$CONFIG_QIC02_TAPE" = "y" ]; then -bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF n -if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then +endmenu -comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!' - -else +source fs/Config.in -comment '>>> Setting runtime QIC-02 configuration is done with qic02conf' -comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/' - -fi -fi - -bool 'QIC-117 tape support' CONFIG_FTAPE n -if [ "$CONFIG_FTAPE" = "y" ]; then -int ' number of ftape buffers' NR_FTAPE_BUFFERS 3 -fi +source drivers/char/Config.in +mainmenu_option next_comment comment 'Sound' -bool 'Sound card support' CONFIG_SOUND n +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu +mainmenu_option next_comment comment 'Kernel hacking' -bool 'Remote kernel debugging support' CONFIG_REMOTE_DEBUG n -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n -bool 'Kernel profiling support' CONFIG_PROFILE n +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +#bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG +bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi -if [ "$CONFIG_SCSI" = "y" ]; then -bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y -fi +bool 'Cross compilation' CONFIG_CROSS_COMPILE +endmenu diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile new file mode 100644 index 000000000..92fc4a1ff --- /dev/null +++ b/arch/mips/dec/Makefile @@ -0,0 +1,24 @@ +# +# Makefile for the DECstation family specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: dec.o +O_TARGET := dec.o +O_OBJS := boot.o int-handler.o decstation.o hw-access.o setup.o + +boot.o: boot.S + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/dec/boot.S b/arch/mips/dec/boot.S new file mode 100644 index 000000000..587c43623 --- /dev/null +++ b/arch/mips/dec/boot.S @@ -0,0 +1,92 @@ +/* + * arch/mips/dec/boot.S + * + * Copyright (C) 1995, 1996 Paul M. Antoine + * + * Written by Ralf Baechle and Andreas Busse, modified for DECStation + * support by Paul Antoine. + * + * NOTE: There are references to R4X00 code in here, because there is an + * upgrade module for Personal DECStations with such a CPU! + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/fpregdef.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/bootinfo.h> + +/* + * dec_entry: Called by the boot PROM loader to do DECStation setup, prior + * to calling dec_setup() to fill in the boot_info structure. + * + * This code should also go in the boot loader for loading off + * floppy and HD... in addition to the tags code in dec_setup(). + * + * FIXME: arrange for this code only to be linked in when building a + * kernel image to be booted via tftp from the boot prom?? + */ + .text + .globl dec_entry +dec_entry: + /* Save the address of the REX call vector for later + * use in printing debug messages. + */ + sw a3,pmax_rex_base + sw a2,rex_prom_magic + la a0,dec_signon + jal pmax_printf + nop + + /* Now set up the bootinfo with things that + * should be loaded by the boot loader, except that + * for the moment we're booting using tftp. + */ + jal dec_setup + nop +/* + * Now we need to move exception vector handler routines that appear + * in head.S down to the right addresses, 'cos the DECStation loads + * kernels at 0x80030000... <sigh> + */ + +/* + * First move the TLB refill code down to offset 0x000, at addr 0x80000000 + */ + la t0,except_vec0 # begining of exception code + la t1,except_vec1 # end of exception code + la t2,0x80000000 # where the code should live + lw t3,(t0) # get first word +1: sw t3,(t2) # put it where it should go + addiu t0,4 # increment both pointers + addiu t2,4 + lw t3,(t0) # will be in the delay slot + bne t0,t1,1b +/* + * Now move the General Exception code down to offset 0x080 at 0x80000000 + */ + la t0,except_vec3 # begining of general exception code + la t1,end_except # end of general exception code + la t2,0x80000080 # where the code should live + lw t3,(t0) # get first word +1: sw t3,(t2) + addiu t0,4 + addiu t2,4 + lw t3,(t0) + bne t0,t1,1b + + la a0,dec_launch # say where we are going + jal pmax_printf + nop + + la t0,mach_mem_upper # get upper memory bound + lw a0,(t0) + j kernel_entry + nop + + .data + .align 2 +dec_signon: .ascii "\n\nLinux/MIPS DECStation Boot\n"; + .asciiz "Copyright (C) Paul M. Antoine 1995, 1996 and others, 1994, 1995, 1996\n\n"; +dec_launch: .asciiz "Setup complete, launching kernel...\n"; diff --git a/arch/mips/dec/decstation.S b/arch/mips/dec/decstation.S new file mode 100644 index 000000000..8c5f97764 --- /dev/null +++ b/arch/mips/dec/decstation.S @@ -0,0 +1,382 @@ +/* + * arch/mips/kernel/decstation.S + * + * Copyright (C) 1995, 1996 Paul M. Antoine + * + * Written by Ralf Baechle and Andreas Busse, modified for DECStation + * support by Paul Antoine. + * + * NOTE: There are references to R4X00 code in here, because I believe + * that there is an upgrade module for Personal DECStations with + * such CPU's! + * + * FIXME: still plenty to do in this file, as much of the code towards + * the end hasn't been modified to suit the DECStation's interrupts. + * (Paul, you need to fix this file to comply with NAPS. Won't be + * too hard - Ralf) + */ +#include <asm/asm.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/decstation.h> +#include <asm/stackframe.h> +#include <asm/bootinfo.h> + +/* + * dec_entry: Called at boot in head.S to do DECStation setup, and to + * fill in the boot_info structure. + */ + .text + .globl dec_entry +dec_entry: + /* Save the address of the REX call vector for later + * use in printing debug messages. + */ + sw a3,pmax_rex_base + la a0,dec_signon + jal pmax_printf + nop + /* Now set up the bootinfo structure with things that + * should be loaded by the boot loader, except that + * for the moment we're booting using tftp. + */ + la t0,boot_info + li t1,0x40 # 64 TLB entries +/* + * FIXME: Ideally, all DEC workstations should be supported, so here we + * should put some clevernesses to determine machine type and CPU + * type. Needs a hierarchy of DEC machine types. Perhaps Machine + * AND Model fields in bootinfo structure? + */ + sw t1,OFFSET_BOOTINFO_TLB_ENTRIES(t0) + li t1,MACH_DECSTATION # Machine type + sw t1,(t0) + li t1,CPU_R3000A # CPU type + sw t1,OFFSET_BOOTINFO_CPUTYPE(t0) +/* + * FIXME: the following should find the memory size from the boot PROM + */ + li t1,0x80000000 # Lower memory bound + sw t1,OFFSET_BOOTINFO_MEMLOWER(t0) + li t1,0x88000000 # Upper memory bound (8MB) + sw t1,OFFSET_BOOTINFO_MEMUPPER(t0) +/* + * FIXME: the following should determine the cache size a la the method + * used in MACH. For now we just guess - PMA. + */ + li t1,0x100000 # 64K icache + sw t1,OFFSET_BOOTINFO_ICACHE_SIZE(t0) + li t1,0x100000 # 64K dcache + sw t1,OFFSET_BOOTINFO_DCACHE_SIZE(t0) + +/* + * FIXME: template for other bootinfo fields that probably need filling in... + * + li t1,0x80000000 + sw t1,OFFSET_BOOTINFO_(t0) +*/ + +/* + * Now we need to move exception vector handler routines that appear + * in head.S down to the right addresses, 'cos the DECStation loads + * kernels at 0x80030000... <sigh> + */ + +/* + * First move the TLB refill code down to offset 0x000, at addr 0x80000000 + */ + la t0,except_vec0 # begining of TLB exception code + la t1,except_vec1 # end of TLB exception code + la t2,0x80000000 # where the code should live + lw t3,(t0) # get first word +1: sw t3,(t2) # put it where it should go + addiu t0,4 # increment both pointers + addiu t2,4 + lw t3,(t0) # will be in the delay slot + bne t0,t1,1b + +/* + * Now move the General Exception code down to offset 0x080 at 0x80000000 + */ + la t0,except_vec3 # begining of general exception code + la t1,kernel_entry # end of general exception code + la t2,0x80000080 # where the code should live + lw t3,(t0) # get first word +1: sw t3,(t2) + addiu t0,4 + addiu t2,4 + lw t3,(t0) + bne t0,t1,1b + +/* + * FIXME: Don't forget to set the gp regster... why do I need this? + */ + la gp,_gp + la a0,dec_launch # say where we are going + jal pmax_printf + nop + j kernel_entry + nop + + .data + .align 2 +dec_signon: .ascii "\n\nLinux/MIPS DECStation Boot\n"; + .asciiz "Copyright (C) Paul M. Antoine 1995, 1996 and others, 1994, 1995, 1996\n\n"; +dec_launch: .asciiz "Launching kernel...\n"; + .text + .set noreorder +/* + * decstation_handle_int: Interrupt handler for Personal DECStation 5000/2x + * + * FIXME: this is *extremely* experimental, though it is probably o.k. for + * most DECStation models. + */ + NESTED(decstation_handle_int, FR_SIZE, ra) + .set noat + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + CLI + .set at + + /* + * Get pending interrupts + */ + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + andi t0,0xff00 # isolate pending bits +/* + * FIXME: The following branch was: + * beqz t0,spurious_interrupt + * + * ...but the wonders of ecoff cause the gas assembler (ver 2.5.1 ) + * to complain: + * + * "Can not represent relocation in this object file format"... + * + * hence this hack to branch foward a bit, and then jump <sigh> + * Perhaps a later version of gas will cope? - Paul + * (No, this is impossible in COFF as well as in ELF. - Ralf) + */ + beqz t0,3f; + sll t0,16 # delay slot + + /* + * Find irq with highest priority + * FIXME: This is slow + */ + la t1,ll_vectors +1: bltz t0,2f # found pending irq + sll t0,1 + b 1b + subu t1,PTRSIZE # delay slot + + /* + * Do the low-level stuff + */ + .set reorder +2: LOAD_L t0,(t1) + jr t0 + .set noreorder + END(decstation_handle_int) + +/* + * FIXME: The hack mentioned above. + */ +3: j spurious_interrupt + nop + +/* + * FIXME: the rest of this is pretty suspect, as it's straight from + * jazz.S... and I really haven't altered it at all - Paul + */ + +/* + * Used for keyboard driver's fake_keyboard_interrupt() + * (Paul, even for i386 this is no longer being used -- Ralf) + */ +ll_sw0: li s1,~IE_SW0 + mfc0 t0,CP0_CAUSE + and t0,s1 + mtc0 t0,CP0_CAUSE + PRINT("sw0 received...\n") + li t1,1 + b call_real + li t3,PTRSIZE # delay slot, re-map to irq level 1 + +ll_sw1: li s1,~IE_SW1 + PANIC("Unimplemented sw1 handler") + +loc_no_irq: PANIC("Unimplemented loc_no_irq handler") +loc_sound: PANIC("Unimplemented loc_sound handler") +loc_video: PANIC("Unimplemented loc_video handler") +loc_scsi: PANIC("Unimplemented loc_scsi handler") + +/* + * Ethernet interrupt, remapped to level 15 + * NOTE: Due to a bug somewhere in the kernel I was not able + * to figure out, the PRINT() is necessary. Without this, + * I get a "gfp called nonatomically from interrupt 00000000". + * Only god knows why... Tell me if you find the reason! + * (You were fouled by the caches and this is the wrong file for this + * comment - Ralf) + * Andy, 6/16/95 + */ +loc_ethernet: PANIC("Unimplemented loc_ethernet\n") + +/* + * Keyboard interrupt, remapped to level 1 + */ +loc_keyboard: PANIC("Unimplemented loc_keyboard\n") + +loc_mouse: PANIC("Unimplemented loc_mouse handler") + +/* + * Serial port 1 IRQ, remapped to level 3 + */ +loc_serial1: PANIC("Unimplemented loc_serial handler") + +/* + * Serial port 2 IRQ, remapped to level 4 + */ +loc_serial2: PANIC("Unimplemented loc_serial handler") + +/* + * Parallel port IRQ, remapped to level 5 + */ +loc_parallel: PANIC("Unimplemented loc_parallel handler") + +/* + * Floppy IRQ, remapped to level 6 + */ +loc_floppy: PANIC("Unimplemented loc_floppy handler") + +/* + * Now call the real handler + */ +loc_call: lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + la t0,IRQ_vectors # delay slot + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + /* + * Temporarily disable interrupt source + */ +/* lhu t2,JAZZ_IO_IRQ_ENABLE +*/ + addu t0,t3 # make ptr to IRQ handler + LOAD_L t0,(t0) + and t2,s1 # delay slot +/* sh t2,JAZZ_IO_IRQ_ENABLE */ + jalr t0 # call IRQ handler + nor s1,zero,s1 # delay slot + + /* + * Reenable interrupt + */ +/* lhu t2,JAZZ_IO_IRQ_ENABLE */ + lw t1,%lo(intr_count)(s3) # delay slot + or t2,s1 +/* sh t2,JAZZ_IO_IRQ_ENABLE */ + + subu t1,1 + jr v0 + sw t1,%lo(intr_count)(s3) + +ll_tc3: PANIC("Unimplemented tc3 interrupt handler") + +ll_fpu: PANIC("Unimplemented fpu interrupt handler") + +ll_io_error: PANIC("Unimplemented I/O write timeout interrupt handler") + +ll_rtc: PANIC("Unimplemented RTC interrupt handler") + +/* + * Timer IRQ + * We remap the timer irq to be more similar to a IBM compatible + */ +ll_timer: PANIC("Timer interrupt!\n"); +/* + * CPU count/compare IRQ (unused) + */ +ll_reset: li a0,0 + jal pmax_halt + li a1,0 # delay slot + +/* + * Now call the real handler + */ +call_real: lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + la t0,IRQ_vectors # delay slot + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + /* + * temporarily disable interrupt + */ + mfc0 t2,CP0_STATUS + and t2,s1 + + addu t0,t3 + LOAD_L t0,(t0) + mtc0 t2,CP0_STATUS # delay slot + jalr t0 + nor s1,zero,s1 # delay slot + + /* + * reenable interrupt + */ + mfc0 t2,CP0_STATUS + or t2,s1 + mtc0 t2,CP0_STATUS + + lw t2,%lo(intr_count)(s3) + subu t2,1 + + jr v0 + sw t2,%lo(intr_count)(s3) # delay slot + +/* + * Just for debugging... load a0 with address of the point inside the + * framebuffer at which you want to draw a line of 16x32 pixels. + * Maxine's framebuffer starts at 0xaa000000. + */ + .set reorder + LEAF(drawline) + li t1,0xffffffff # set all pixels on + li t2,0x10 # we will write 16 words +1: sw t1,(a0) # write the first word + addiu a0,a0,4 # move our framebuffer pointer + addiu t2,t2,-1 # one less to do + bnez t2,1b # finished? + jr ra + END(drawline) + +/* + * FIXME: I have begun to alter this table to reflect Personal DECStation + * (i.e. Maxine) interrupts... Paul. + */ + .data + PTR ll_sw0 # SW0 + PTR ll_sw1 # SW1 + PTR ll_timer # Periodic interrupt + PTR ll_rtc # RTC periodic interrupt + PTR ll_io_error # Timeout on I/O writes + PTR ll_tc3 # TC slot 3, motherboard + PTR ll_reset # Halt keycode (CTRL+ALT+ENTER) +ll_vectors: PTR ll_fpu # FPU + +local_vector: PTR loc_no_irq + PTR loc_parallel + PTR loc_floppy + PTR loc_sound + PTR loc_video + PTR loc_ethernet + PTR loc_scsi + PTR loc_keyboard + PTR loc_mouse + PTR loc_serial1 + PTR loc_serial2 diff --git a/arch/mips/dec/decstation.c b/arch/mips/dec/decstation.c new file mode 100644 index 000000000..f52a1510b --- /dev/null +++ b/arch/mips/dec/decstation.c @@ -0,0 +1,201 @@ +/* + * arch/mips/dec/decstation.c + * + * Copyright (C) 1996 Paul M. Antoine + * + * Written by Paul Antoine. + * + * FIXME: still plenty to do in this file, as we don't yet fully fill + * the boot info structure with DEC-specific tags. Also still + * too specific to the Person Decstattion 5000/2x!! + */ + +#include <asm/segment.h> +#include <asm/dec/decstation.h> +#include <asm/dec/maxine.h> /* FIXME: what about other decstations? */ +#include <asm/bootinfo.h> + +/* + * dec_setup: Called at boot from dec_entry() in boot.S to do + * DECStation-specific setup, and to fill in the kernel argument + * tags. + * + * FIXME: I'm not sure all DEC workstations are correctly supported. This + * code may not need to be here when booting off floppy or HD?? + */ + +unsigned long mach_mem_upper = 0; +unsigned long mach_mem_lower = 0; +unsigned long mips_dcache_size = 0; +unsigned long mips_icache_size = 0; +unsigned long rex_prom_magic; /* from boot.S */ +unsigned long dec_get_memory_size(void); + +void dec_setup(void) +{ + unsigned long int mem_mask = 0; + unsigned long tag_data_dummy, dec_sysid; + unsigned char dec_cpunum, dec_systype, dec_firmrev, dec_etc; + extern const char *linux_banner; + + pmax_printf("%s\n", linux_banner); + /* First we need the memory upper bound before we can add tag entries... */ + mach_mem_lower = 0x80000000L; + mach_mem_upper = mach_mem_lower + dec_get_memory_size(); + + /* First tag is always memory upper limit, right Stoned?? */ + (void)bi_TagAdd(tag_memupper, ULONGSIZE, &mach_mem_upper); + + /* We're obviously one of the DEC machines */ + tag_data_dummy = MACH_GROUP_DEC; + (void)bi_TagAdd(tag_machgroup, ULONGSIZE, &tag_data_dummy); + + /* Now let's try to figure out what type of DECStation we are */ + pmax_printf("System id is: "); + if ((dec_sysid = pmax_getsysid()) != 0) + pmax_printf("%x\n", dec_sysid); + else + pmax_printf("unknown\n"); + + dec_cpunum = (dec_sysid & 0xff000000) >> 24; + dec_systype = (dec_sysid & 0xff0000) >> 16; + dec_firmrev = (dec_sysid & 0xff00) >> 8; + dec_etc = dec_sysid & 0xff; + + /* + * FIXME: for now use the PROM to determine the CPU type - should + * probably just get the CPU to tell us. + */ + pmax_printf("System has an "); + switch(dec_cpunum) + { + case 0x82: + { + pmax_printf("R3000 CPU\n"); + tag_data_dummy = CPU_R3000A; + break; + } + case 0x84: + { + pmax_printf("R4000 CPU\n"); + /* FIXME: assume a plain R4000PC for now */ + tag_data_dummy = CPU_R4000PC; + break; + } + default: + { + pmax_printf("unknown CPU, code is %x\n", dec_cpunum); + /* FIXME: assume an R2000 for now */ + tag_data_dummy = CPU_R2000; + break; + } + } + /* Add the CPU type */ + (void)bi_TagAdd(tag_cputype, ULONGSIZE, &tag_data_dummy); + + pmax_printf("System has firmware type: "); + if (dec_firmrev == 2) + pmax_printf("TCF0\n"); + else + pmax_printf("TCF1\n"); + + pmax_printf("This DECStation is a: "); + switch(dec_systype) { + case 1: /* DS2100/3100 Pmax */ + pmax_printf("DS2100/3100\n"); + tag_data_dummy = MACH_DECSTATION; + break; + case 2: /* DS5000 3max */ + pmax_printf("DS5000\n"); + tag_data_dummy = MACH_DECSTATION; + break; + case 3: /* DS5000/100 3min */ + pmax_printf("DS5000/1x0\n"); + tag_data_dummy = MACH_DECSTATION; + break; + case 7: /* Personal DS5000/2x */ + pmax_printf("Personal DS5000/2x\n"); + tag_data_dummy = MACH_DECSTATION; + break; + default: + pmax_printf("unknown, id is: %x\n", dec_systype); + tag_data_dummy = MACH_UNKNOWN; + break; + } + + /* Add the machine type */ + (void)bi_TagAdd(tag_machtype, ULONGSIZE, &tag_data_dummy); + + /* Add the number of tlb entries */ + tag_data_dummy = 64; + (void)bi_TagAdd(tag_tlb_entries, ULONGSIZE, &tag_data_dummy); + + /* + * Add the instruction cache size + * FIXME: should determine this somehow + */ + tag_data_dummy = 0x100000; /* set it to 64K for now */ + (void)bi_TagAdd(tag_icache_size, ULONGSIZE, &tag_data_dummy); + mips_icache_size = tag_data_dummy; + + /* + * Add the data cache size + * FIXME: should determine this somehow + */ + tag_data_dummy = 0x100000; /* set it to 64K for now */ + (void)bi_TagAdd(tag_dcache_size, ULONGSIZE, &tag_data_dummy); + mips_dcache_size = tag_data_dummy; + + /* FIXME: should determine vram_base properly */ + tag_data_dummy = 0xa8000000; + (void)bi_TagAdd(tag_vram_base, ULONGSIZE, &tag_data_dummy); + + /* FIXME: dummy drive info tag */ + tag_data_dummy = 0; + (void)bi_TagAdd(tag_drive_info, ULONGSIZE, &tag_data_dummy); + + /* FIXME: do we need a dummy tag at the end? */ + tag_data_dummy = 0; + (void)bi_TagAdd(tag_dummy, 0, &tag_data_dummy); + + pmax_printf("Added tags\n"); +} /* dec_setup */ + +unsigned long dec_get_memory_size() +{ + int i, bitmap_size; + unsigned long mem_size = 0; + struct pmax_bitmap { + int pagesize; + unsigned char bitmap[64*1024*1024 - 4]; + } *bm; + + /* some free 64k */ + bm = (struct pmax_bitmap *)0x8002f000; + bitmap_size = pmax_getbitmap(bm); + + pmax_printf("Page size is: %x\n", bm->pagesize); + pmax_printf("Bitmap size is: %d bytes\n", bitmap_size); + + for (i = 0; i < bitmap_size; i++) + { + /* FIXME: very simplistically only add full sets of pages */ + if (bm->bitmap[i] == 0xff) + mem_size += (8 * bm->pagesize); + } + pmax_printf("Main memory size is: %d KB\n", (mem_size / 1024)); + return(mem_size); +} /* dec_get_memory_size */ + +unsigned char maxine_rtc_read_data(unsigned long addr) +{ + char *rtc = (char *)(PMAX_RTC_BASE); + return(rtc[addr * 4]); +} /* maxine_rtc_read_data */ + +void maxine_rtc_write_data(unsigned char data, unsigned long addr) +{ + char *rtc = (char *)(PMAX_RTC_BASE); + rtc[addr * 4] = data; +} /* maxine_rtc_read_data */ + diff --git a/arch/mips/dec/hw-access.c b/arch/mips/dec/hw-access.c new file mode 100644 index 000000000..31a8aabef --- /dev/null +++ b/arch/mips/dec/hw-access.c @@ -0,0 +1,26 @@ +/* + * DECstation specific hardware access code. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Paul Antoine + */ +#include <linux/linkage.h> +#include <linux/types.h> +#include <asm/mc146818rtc.h> +#include <asm/vector.h> + +asmlinkage void decstation_handle_int(void); +extern unsigned char maxine_rtc_read_data(unsigned long); +extern void maxine_rtc_write_data(unsigned char, unsigned long); + +/* + * FIXME: Don't have any of the goo required to access fd etc. + */ +struct feature decstation_feature = { + 0,0,0,0,0,0,0,0,0,0,0,0,0, + maxine_rtc_read_data, + maxine_rtc_write_data +}; diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S new file mode 100644 index 000000000..6692d657b --- /dev/null +++ b/arch/mips/dec/int-handler.S @@ -0,0 +1,273 @@ +/* + * arch/mips/dec/int-handler.S + * + * Copyright (C) 1995, 1996 Paul M. Antoine + * + * Written by Ralf Baechle and Andreas Busse, modified for DECStation + * support by Paul Antoine. + * + * NOTE: There are references to R4X00 code in here, because there is an + * upgrade module for Personal DECStations with such a CPU! + * + * FIXME: still plenty to do in this file, as much of the code hasn't been + * modified to suit the DECStation's interrupts. + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/fpregdef.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/bootinfo.h> + + .text + .set noreorder +/* + * decstation_handle_int: Interrupt handler for Personal DECStation 5000/2x + * + * FIXME: this is *extremely* experimental, though it is probably o.k. for + * most DECStation models. + */ + NESTED(decstation_handle_int, FR_SIZE, ra) + .set noat + SAVE_ALL + CLI + .set at + + /* + * Get pending interrupts + */ + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + andi t0,0xff00 # isolate pending bits +/* + * FIXME: The following branch was: + * beqz t0,spurious_interrupt + * + * ...but the wonders of ecoff cause the gas assembler (ver 2.5.1 ) + * to complain: + * + * "Can not represent relocation in this object file format"... + * + * hence this hack to branch foward a bit, and then jump <sigh> + * Perhaps a later version of gas will cope? - Paul + */ + beqz t0,3f; + sll t0,16 # delay slot + + /* + * Find irq with highest priority + * FIXME: This is slow + */ + la t1,ll_vectors +1: bltz t0,2f # found pending irq + sll t0,1 + b 1b + subu t1,PTRSIZE # delay slot + + /* + * Do the low-level stuff + */ +2: lw t0,(t1) + jr t0 + nop # delay slot + END(decstation_handle_int) + +/* + * FIXME: The hack mentioned above. + */ +3: j spurious_interrupt + nop + +/* + * FIXME: the rest of this is pretty suspect, as it's straight from + * jazz.S... and I really haven't altered it at all - Paul + */ + +/* + * Used for keyboard driver's fake_keyboard_interrupt() + * (Paul, even for i386 this is no longer being used -- Ralf) + */ +ll_sw0: li s1,~IE_SW0 + mfc0 t0,CP0_CAUSE + and t0,s1 + mtc0 t0,CP0_CAUSE + PRINT("sw0 received...\n") + li t1,1 + b call_real + li t3,PTRSIZE # delay slot, re-map to irq level 1 + +ll_sw1: li s1,~IE_SW1 + PANIC("Unimplemented sw1 handler") + +loc_no_irq: PANIC("Unimplemented loc_no_irq handler") +loc_sound: PANIC("Unimplemented loc_sound handler") +loc_video: PANIC("Unimplemented loc_video handler") +loc_scsi: PANIC("Unimplemented loc_scsi handler") + +/* + * Ethernet interrupt, remapped to level 15 + * NOTE: Due to a bug somewhere in the kernel I was not able + * to figure out, the PRINT() is necessary. Without this, + * I get a "gfp called nonatomically from interrupt 00000000". + * Only god knows why... Tell me if you find the reason! + * Andy, 6/16/95 + */ +loc_ethernet: PANIC("Unimplemented loc_ethernet\n") + +/* + * Keyboard interrupt, remapped to level 1 + */ +loc_keyboard: PANIC("Unimplemented loc_keyboard\n") + +loc_mouse: PANIC("Unimplemented loc_mouse handler") + +/* + * Serial port 1 IRQ, remapped to level 3 + */ +loc_serial1: PANIC("Unimplemented loc_serial handler") + +/* + * Serial port 2 IRQ, remapped to level 4 + */ +loc_serial2: PANIC("Unimplemented loc_serial handler") + +/* + * Parallel port IRQ, remapped to level 5 + */ +loc_parallel: PANIC("Unimplemented loc_parallel handler") + +/* + * Floppy IRQ, remapped to level 6 + */ +loc_floppy: PANIC("Unimplemented loc_floppy handler") + +/* + * Now call the real handler + */ +loc_call: lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + la t0,IRQ_vectors # delay slot + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + /* + * Temporarily disable interrupt source + */ +/* lhu t2,JAZZ_IO_IRQ_ENABLE +*/ + addu t0,t3 # make ptr to IRQ handler + lw t0,(t0) + and t2,s1 # delay slot +/* sh t2,JAZZ_IO_IRQ_ENABLE */ + jalr t0 # call IRQ handler + nor s1,zero,s1 # delay slot + + /* + * Reenable interrupt + */ +/* lhu t2,JAZZ_IO_IRQ_ENABLE */ + lw t1,%lo(intr_count)(s3) # delay slot + or t2,s1 +/* sh t2,JAZZ_IO_IRQ_ENABLE */ + + subu t1,1 + jr v0 + sw t1,%lo(intr_count)(s3) + +ll_tc3: PANIC("Unimplemented tc3 interrupt handler") + +ll_fpu: PANIC("Unimplemented fpu interrupt handler") + +ll_io_error: PANIC("Unimplemented I/O write timeout interrupt handler") + +ll_rtc: PANIC("Unimplemented RTC interrupt handler") + +/* + * Timer IRQ + * We remap the timer irq to be more similar to a IBM compatible + */ +ll_timer: PANIC("Timer interrupt!\n"); +/* + * CPU count/compare IRQ (unused) + */ +ll_reset: li a0,0 + jal pmax_halt + li a1,0 # delay slot + +/* + * Now call the real handler + */ +call_real: lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + la t0,IRQ_vectors # delay slot + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + /* + * temporarily disable interrupt + */ + mfc0 t2,CP0_STATUS + and t2,s1 + + addu t0,t3 + lw t0,(t0) + mtc0 t2,CP0_STATUS # delay slot + jalr t0 + nor s1,zero,s1 # delay slot + + /* + * reenable interrupt + */ + mfc0 t2,CP0_STATUS + or t2,s1 + mtc0 t2,CP0_STATUS + + lw t2,%lo(intr_count)(s3) + subu t2,1 + + jr v0 + sw t2,%lo(intr_count)(s3) # delay slot + +/* + * Just for debugging... load a0 with address of the point inside the + * framebuffer at which you want to draw a line of 16x32 pixels. + * Maxine's framebuffer starts at 0xaa000000. + */ + .set reorder + LEAF(drawline) + li t1,0xffffffff # set all pixels on + li t2,0x10 # we will write 16 words +1: sw t1,(a0) # write the first word + addiu a0,a0,4 # move our framebuffer pointer + addiu t2,t2,-1 # one less to do + bnez t2,1b # finished? + jr ra + END(drawline) + +/* + * FIXME: I have begun to alter this table to reflect Personal DECStation + * (i.e. Maxine) interrupts... Paul. + */ + .data + PTR ll_sw0 # SW0 + PTR ll_sw1 # SW1 + PTR ll_timer # Periodic interrupt + PTR ll_rtc # RTC periodic interrupt + PTR ll_io_error # Timeout on I/O writes + PTR ll_tc3 # TC slot 3, motherboard + PTR ll_reset # Halt keycode (CTRL+ALT+ENTER) +ll_vectors: PTR ll_fpu # FPU + +local_vector: PTR loc_no_irq + PTR loc_parallel + PTR loc_floppy + PTR loc_sound + PTR loc_video + PTR loc_ethernet + PTR loc_scsi + PTR loc_keyboard + PTR loc_mouse + PTR loc_serial1 + PTR loc_serial2 diff --git a/arch/mips/dec/ld.script b/arch/mips/dec/ld.script new file mode 100644 index 000000000..f0cf33fc4 --- /dev/null +++ b/arch/mips/dec/ld.script @@ -0,0 +1,47 @@ +OUTPUT_FORMAT("ecoff-littlemips") +OUTPUT_ARCH(mips) +ENTRY(dec_entry) +SECTIONS +{ + /* This is probably a little simplistic, and is based on work by + * Chris Fraser of Softway Pty Ltd as used in his port of Vsta to + * the DECStation - Paul M. Antoine 21/1/96. + */ + . = 0x80030000; + .text : + { + *(.text) + . = ALIGN(0x10); + _etext = .; + __etext = .; + } + .lit8 : { + *(.lit8) + } + .lit4 : { + *(.lit4) + } + . = ALIGN(0x1000); + .data : + { + *(.data .rdata .rodata) + _edata = .; + __edata = .; + } + __bss_start = ALIGN(16) + 0x8000; + .sbss : + { + *(.sbss) + *(.scommon) + } + .bss : + { + *(.bss) + *(COMMON) + _end = ALIGN(4) ; + __end = ALIGN(4) ; + } + .reginfo : { + *(.reginfo) + } +} diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c new file mode 100644 index 000000000..5037fbaae --- /dev/null +++ b/arch/mips/dec/setup.c @@ -0,0 +1,41 @@ +/* + * Setup pointers to hardware dependand routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/ptrace.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/vector.h> + +extern struct feature decstation_feature; + +static void +dec_irq_setup(void) +{ + /* FIXME: should set up the clock as per above? */ + pmax_printf("Please write the IRQ setup code for the DECStation!\n"); +} + +void (*board_time_init)(struct irqaction *irq); + +static void dec_time_init(struct irqaction *irq) +{ + pmax_printf("Please write the time init code for the DECStation!\n"); +} + +void +decstation_setup(void) +{ + irq_setup = dec_irq_setup; + board_time_init = dec_time_init; + /* FIXME: Setup fd_cacheflush */ + feature = &decstation_feature; /* FIXME: Will go away */ +} diff --git a/arch/mips/defconfig b/arch/mips/defconfig new file mode 100644 index 000000000..bb3635c25 --- /dev/null +++ b/arch/mips/defconfig @@ -0,0 +1,241 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Machine selection +# +CONFIG_ACER_PICA_61=y +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_OLIVETTI_M700 is not set +CONFIG_SNI_RM200_PCI=y +CONFIG_MIPS_JAZZ=y + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R6000 is not set +CONFIG_CPU_R4X00=y +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +CONFIG_TLB_SHUTDOWN=y +# CONFIG_OPTIMIZE_R4600 is not set + +# +# General setup +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_ELF_KERNEL=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_NET=y +# CONFIG_MAX_16M is not set +# CONFIG_SYSVIPC is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Floppy, IDE, and other block devices +# +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_IDEDISK is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set +CONFIG_INET=y +# CONFIG_IP_FORWARD is not set +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ACCT is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_INET_PCTCP is not set +# CONFIG_INET_RARP is not set +# CONFIG_NO_PATH_MTU_DISCOVERY is not set +CONFIG_IP_NOSR=y +CONFIG_SKB_LARGE=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_AX25 is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DTC3280 is not set +CONFIG_SCSI_EATA_DMA=y +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_LANCE=y +CONFIG_LANCE32=y +# CONFIG_NET_VENDOR_SMC is not set +CONFIG_NET_ISA=y +# CONFIG_E2100 is not set +# CONFIG_DEPCA is not set +# CONFIG_EWRK3 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HPLAN is not set +# CONFIG_HP100 is not set +# CONFIG_NE2000 is not set +# CONFIG_NI52 is not set +# CONFIG_NI65 is not set +# CONFIG_SK_G16 is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_SLIP is not set +# CONFIG_TR is not set +CONFIG_MIPS_JAZZ_SONIC=y + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +# CONFIG_EXT_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_XIA_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_UMSDOS_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_RNFS_BOOTP=y +# CONFIG_RNFS_RARP is not set +# CONFIG_SMB_FS is not set +CONFIG_ISO9660_FS=y +# CONFIG_HPFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_UFS_FS is not set + +# +# Character devices +# +CONFIG_SERIAL=y +# CONFIG_DIGI is not set +# CONFIG_CYCLADES is not set +# CONFIG_STALDRV is not set +# CONFIG_RISCOM8 is not set +# CONFIG_PRINTER is not set +# CONFIG_MOUSE is not set +# CONFIG_UMISC is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_FTAPE is not set +# CONFIG_APM is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +# CONFIG_PROFILE is not set +CONFIG_CROSS_COMPILE=y diff --git a/arch/mips/deskstation/Makefile b/arch/mips/deskstation/Makefile new file mode 100644 index 000000000..8e1b6bb13 --- /dev/null +++ b/arch/mips/deskstation/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the Deskstation family specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: deskstation.o +O_TARGET := deskstation.o +O_OBJS := hw-access.o int-handler.o setup.o + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/deskstation/hw-access.c b/arch/mips/deskstation/hw-access.c new file mode 100644 index 000000000..2d79e6f77 --- /dev/null +++ b/arch/mips/deskstation/hw-access.c @@ -0,0 +1,198 @@ +/* + * Low-level hardware access stuff for Deskstation rPC44/Tyne + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <linux/config.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/types.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mc146818rtc.h> +#include <asm/vector.h> + +extern int FLOPPY_IRQ; +extern int FLOPPY_DMA; + +/* + * How to access the FDC's registers. + */ +static unsigned char +fd_inb(unsigned int port) +{ + return inb_p(port); +} + +static void +fd_outb(unsigned char value, unsigned int port) +{ + outb_p(value, port); +} + +/* + * How to access the floppy DMA functions. + */ +static void +fd_enable_dma(void) +{ + enable_dma(FLOPPY_DMA); +} + +static void +fd_disable_dma(void) +{ + disable_dma(FLOPPY_DMA); +} + +static int +fd_request_dma(void) +{ + return request_dma(FLOPPY_DMA, "floppy"); +} + +static void +fd_free_dma(void) +{ + free_dma(FLOPPY_DMA); +} + +static void +fd_clear_dma_ff(void) +{ + clear_dma_ff(FLOPPY_DMA); +} + +static void +fd_set_dma_mode(char mode) +{ + set_dma_mode(FLOPPY_DMA, mode); +} + +static void +fd_set_dma_addr(unsigned int addr) +{ + set_dma_addr(FLOPPY_DMA, addr); +} + +static void +fd_set_dma_count(unsigned int count) +{ + set_dma_count(FLOPPY_DMA, count); +} + +static int +fd_get_dma_residue(void) +{ + return get_dma_residue(FLOPPY_DMA); +} + +static void +fd_enable_irq(void) +{ + enable_irq(FLOPPY_IRQ); +} + +static void +fd_disable_irq(void) +{ + disable_irq(FLOPPY_IRQ); +} + +void +deskstation_fd_cacheflush(const void *addr, size_t size) +{ + cacheflush(addr, size, CF_DCACHE|CF_ALL); +} + +/* + * RTC stuff (This is a guess on how Deskstation handles this ...) + */ +static unsigned char +rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void +rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +/* + * KLUDGE + */ +static unsigned long +vdma_alloc(unsigned long paddr, unsigned long size) +{ + return 0; +} + +#ifdef CONFIG_DESKSTATION_TYNE +struct feature deskstation_tyne_feature = { + /* + * How to access the floppy controller's ports + */ + fd_inb, + fd_outb, + /* + * How to access the floppy DMA functions. + */ + fd_enable_dma, + fd_disable_dma, + fd_request_dma, + fd_free_dma, + fd_clear_dma_ff, + fd_set_dma_mode, + fd_set_dma_addr, + fd_set_dma_count, + fd_get_dma_residue, + fd_enable_irq, + fd_disable_irq, + /* + * How to access the RTC functions. + */ + rtc_read_data, + rtc_write_data +}; +#endif + +#ifdef CONFIG_DESKSTATION_RPC44 +struct feature deskstation_rpc44_feature = { + /* + * How to access the floppy controller's ports + */ + fd_inb, + fd_outb, + /* + * How to access the floppy DMA functions. + */ + fd_enable_dma, + fd_disable_dma, + fd_request_dma, + fd_free_dma, + fd_clear_dma_ff, + fd_set_dma_mode, + fd_set_dma_addr, + fd_set_dma_count, + fd_get_dma_residue, + fd_enable_irq, + fd_disable_irq, + /* + * How to access the RTC functions. + */ + rtc_read_data, + rtc_write_data +}; +#endif diff --git a/arch/mips/kernel/tyne.S b/arch/mips/deskstation/int-handler.S index 912f6d414..a52df711f 100644 --- a/arch/mips/kernel/tyne.S +++ b/arch/mips/deskstation/int-handler.S @@ -1,114 +1,120 @@ /* - * arch/mips/kernel/tyne.S + * Deskstation rPC44/Tyne specific interrupt handler code * - * Deskstation Tyne specific Assembler code - * - * Copyright (C) 1994, 1995 Waldorf Electronics - * written by Ralf Baechle and Andreas Busse + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle */ #include <asm/asm.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> +#include <asm/regdef.h> #include <asm/stackframe.h> -/* - * Deskstation Tyne interrupt handler - */ +#error "FIXME - PORT_BASE is defined to port_base which breaks this file" + .text .set noreorder .set noat .align 5 - NESTED(deskstation_tyne_handle_int, FR_SIZE, sp) + NESTED(deskstation_handle_int, FR_SIZE, sp) SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) CLI .set at lui s0,%hi(PORT_BASE) - li t1,0x0f - sb t1,%lo(PORT_BASE+0x20)(s0) # poll command - lb t1,%lo(PORT_BASE+0x20)(s0) # read result - li s1,1 - bgtz t1,Lpoll_second - andi t1,t1,7 + li a0,0x0f + sb a0,%lo(PORT_BASE+0x20)(s0) # poll command + lb a0,%lo(PORT_BASE+0x20)(s0) # read result + bgtz a0,poll_second + andi a0,7 + beq a0,2,poll_second # cascade? + li s1,1 # delay slot /* * Acknowledge first pic */ lb t2,%lo(PORT_BASE+0x21)(s0) lui s4,%hi(cache_21) lb t0,%lo(cache_21)(s4) - sllv s1,s1,t1 - or t0,t0,s1 + sllv s1,s1,a0 + or t0,s1 sb t0,%lo(cache_21)(s4) sb t0,%lo(PORT_BASE+0x21)(s0) lui s3,%hi(intr_count) - lw t0,%lo(intr_count)(s3) + lw s7,%lo(intr_count)(s3) li t2,0x20 sb t2,%lo(PORT_BASE+0x20)(s0) /* * Now call the real handler */ la t3,IRQ_vectors - sll t2,t1,2 - addu t3,t3,t2 - lw t3,(t3) - addiu t0,t0,1 + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,s7,1 jalr t3 - sw t0,%lo(intr_count)(s3) # delay slot - lw t0,%lo(intr_count)(s3) + sw t0,%lo(intr_count)(s3) + sw s7,%lo(intr_count)(s3) /* * Unblock first pic */ lbu t1,%lo(PORT_BASE+0x21)(s0) lb t1,%lo(cache_21)(s4) - subu t0,t0,1 - sw t0,%lo(intr_count)(s3) nor s1,zero,s1 - and t1,t1,s1 + and t1,s1 sb t1,%lo(cache_21)(s4) jr v0 sb t1,%lo(PORT_BASE+0x21)(s0) # delay slot + /* + * Cascade interrupt from second PIC + */ .align 5 -Lpoll_second: li t1,0x0f - sb t1,%lo(PORT_BASE+0xa0)(s0) # poll command - lb t1,%lo(PORT_BASE+0xa0)(s0) # read result - lui s4,%hi(cache_A1) - bgtz t1,spurious_interrupt - andi t1,t1,7 +poll_second: li a0,0x0f + sb a0,%lo(PORT_BASE+0xa0)(s0) # poll command + lb a0,%lo(PORT_BASE+0xa0)(s0) # read result + bgtz a0,3f + andi a0,7 /* * Acknowledge second pic */ lbu t2,%lo(PORT_BASE+0xa1)(s0) + lui s4,%hi(cache_A1) lb t3,%lo(cache_A1)(s4) - sllv s1,s1,t1 - or t3,t3,s1 + sllv s1,s1,a0 + or t3,s1 sb t3,%lo(cache_A1)(s4) sb t3,%lo(PORT_BASE+0xa1)(s0) li t3,0x20 sb t3,%lo(PORT_BASE+0xa0)(s0) lui s3,%hi(intr_count) - lw t0,%lo(intr_count)(s3) + lw s7,%lo(intr_count)(s3) sb t3,%lo(PORT_BASE+0x20)(s0) /* * Now call the real handler */ - la t0,IRQ_vectors - sll t2,t1,2 - addu t0,t0,t2 - lw t0,32(t0) - addiu t0,t0,1 - jalr t0 - sw t0,%lo(intr_count)(s3) # delay slot - lw t0,%lo(intr_count)(s3) + la t3,IRQ_vectors + addiu a0,8 + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,s7,1 + jalr t3 + sw t0,%lo(intr_count)(s3) # delay slot + sw s7,%lo(intr_count)(s3) /* * Unblock second pic */ lb t1,%lo(PORT_BASE+0xa1)(s0) lb t1,%lo(cache_A1)(s4) - subu t0,t0,1 - lw t0,%lo(intr_count)(s3) + subu t0,1 nor s1,zero,s1 and t1,t1,s1 sb t1,%lo(cache_A1)(s4) jr v0 sb t1,%lo(PORT_BASE+0xa1)(s0) # delay slot - END(deskstation_tyne_handle_int) + +/* + * "Jump extender" to reach spurious_interrupt + */ +3: j spurious_interrupt + nop # delay slot + END(deskstation_handle_int) diff --git a/arch/mips/deskstation/setup.c b/arch/mips/deskstation/setup.c new file mode 100644 index 000000000..fedab9c84 --- /dev/null +++ b/arch/mips/deskstation/setup.c @@ -0,0 +1,141 @@ +/* + * Setup pointers to hardware dependand routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/ptrace.h> +#include <linux/config.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mipsregs.h> +#include <asm/processor.h> +#include <asm/vector.h> + +/* + * Initial irq handlers. + */ +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; + +extern asmlinkage void deskstation_handle_int(void); +extern asmlinkage void deskstation_fd_cacheflush(const void *addr, size_t size); +extern struct feature deskstation_tyne_feature; +extern struct feature deskstation_rpc44_feature; + +#ifdef CONFIG_DESKSTATION_TYNE +unsigned long mips_dma_cache_size = 0; +unsigned long mips_dma_cache_base = KSEG0; + +static void +tyne_irq_setup(void) +{ + set_except_vector(0, deskstation_handle_int); + request_region(0x20,0x20, "pic1"); + request_region(0xa0,0x20, "pic2"); + setup_x86_irq(2, &irq2); +} +#endif + +#ifdef CONFIG_DESKSTATION_RPC44 +static void +rpc44_irq_setup(void) +{ + /* + * For the moment just steal the TYNE support. In the + * future, we need to consider merging the two -- imp + */ + set_except_vector(0, deskstation_handle_int); + request_region(0x20,0x20, "pic1"); + request_region(0xa0,0x20, "pic2"); + setup_x86_irq(2, &irq2); + set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); +} +#endif + +void (*board_time_init)(struct irqaction *irq); + +static void deskstation_time_init(struct irqaction *irq) +{ + /* set the clock to 100 Hz */ + outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + setup_x86_irq(0, irq); +} + +void +deskstation_setup(void) +{ + tag *atag; + + /* + * We just check if a tag_screen_info can be gathered + * in setup_arch(), if yes we don't proceed futher... + */ + atag = bi_TagFind(tag_screen_info); + if (!atag) { + /* + * If no, we try to find the tag_arc_displayinfo which is + * always created by Milo for an ARC box (for now Milo only + * works on ARC boxes :) -Stoned. + */ + atag = bi_TagFind(tag_arcdisplayinfo); + if (atag) { + screen_info.orig_x = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x; + screen_info.orig_y = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y; + screen_info.orig_video_cols = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns; + screen_info.orig_video_lines = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines; + } + } + + switch(mips_machtype) { +#ifdef CONFIG_DESKSTATION_TYNE + case MACH_DESKSTATION_TYNE: + atag = bi_TagFind(tag_dma_cache_size); + memcpy(&mips_dma_cache_size, TAGVALPTR(atag), atag->size); + + atag = bi_TagFind(tag_dma_cache_base); + memcpy(&mips_dma_cache_base, TAGVALPTR(atag), atag->size); + + irq_setup = tyne_irq_setup; + feature = &deskstation_tyne_feature; // Will go away + port_base = PORT_BASE_TYNE; + isa_slot_offset = 0xe3000000; + break; +#endif +#ifdef CONFIG_DESKSTATION_RPC44 + case MACH_DESKSTATION_RPC44: + irq_setup = rpc44_irq_setup; + mips_memory_upper = KSEG0 + (32 << 20); /* xxx fixme imp */ + feature = &deskstation_rpc44_feature; // Will go away + port_base = PORT_BASE_RPC44; + isa_slot_offset = 0xa0000000; + break; +#endif + } + board_time_init = deskstation_time_init; + fd_cacheflush = deskstation_fd_cacheflush; + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x70,0x10,"rtc"); + + if (mips_machtype == MACH_DESKSTATION_RPC44) + EISA_bus = 1; +} diff --git a/arch/mips/doc/pagetables.txt b/arch/mips/doc/pagetables.txt new file mode 100644 index 000000000..3d900a194 --- /dev/null +++ b/arch/mips/doc/pagetables.txt @@ -0,0 +1,87 @@ +Format and handling of Linux/MIPS pagetables +============================================ + +This file describes the MIPS specific parts of the Linux pagetable handling. + +Opposed to other architecures like i386 or m68k architecture all MIPS +CPUs only implement the TLB itself and a small set of functions to +maintain it as hardware. The actual maintenance of the TLB's contents +is implemented in software only. + +The TLB has a relativly small number of entries. This limits the +maximum address space that can mapped by the TLB using 4kb pages and +without consideration of wired entries to a maximum of 512kb for the +R1000, 384kb for the R4000/4400 and 256kb for the R2000/R3000. This +actual size of mappable space is even smaller due to the wired entries. + +Especially for processes with a huge working set of pages it is therefore +important to make the process of reloading entries into the TLB as +efficient as possible. This means: + + - Choosing a data structure that can be handled as efficient as + possible. + - The implementation of the low level pagefault handling has to be + implemented in a efficient way. + +The Linux kernel itself implements three level page tables as a tree +structure. Linux implementations that don't need three levels of page +tables can fold one level of the page tables so that effectivly a two +level page table remains. The exact size and content of the entries +is upto the implementation. + +Opposed to this the MIPS hardware architecture implies by the data +provided in the c0_context/c0_xcontext registers a simple array of +4 byte elements (for R2000/R3000/R6000) or 8 byte elements (for the +other 64bit members of the CPU family). + +The page tables are mapped to the address TLBMAP (which is usually +defined as 0xe4000000 in <asm/mipsconfig.h). The page which contains +the root of the page table of the current process, the "page directory" +and is therefore mapped at (TLBMAP + (TLBMAP >> (12-2))) (this is the +value of the define TLB_ROOT which is defined as 0xe4390000). That +way the kernel itself can access the page tables as a tree structure +while the exception handlers can work with maxiumum efficiency accessing +the page tables as simple array. + +The tlb refill handler itself is very simple. For the R4x00 family it +has just 14 instruction, for the R4600 and derivatives it can be +optimized to 12 instruction, even further for the R10000. This +exception handler is very simple and fast and therefore doesn't any +checking for errors or special cases. + +It can therefore happen that the entry that is attempted to be reloaded +isn't mapped via the pagetables thus resulting in a double tlb refill +exception. Due to the EXL flag set in c0_status this exception goes +through the general exception vector and from there to handle_tlbl. +Handle_tlbl is a more complex exception handler that is - compared +to the first handler - complex and called far less often. It features +handling of special cases and some error checking for debugging. This +second handler still doesn't reenable interrupts, change to the kernel +stack or save registers to be as efficient as possible. Therefore +only the two registers k0/k1 are available for use. All this is only +done when do_page_fault() in arch/mips/mm/fault.c is called. For the +normal case this handler just reloads the entry mapping the pte table +which again contains the entries to be loaded in the tlb. Since the +original fault address has been lost this exception handler cannot +complete the job. So it just returns to the main program which after +taking another exception via the first tlb refill handler reloads the +originally missing entry into the TLB and continues normal execution. + +Another special in the Linux/MIPS page handling is the handling of +pages in non-existant branches of the page tables. To avoid that +the exception handlers have to handle this special case the kernel +maps these ptes (page table entries) to invalid_pte_table. This is a +4kb page full of invalid entries. On an attempted access to such an +invalid page the kernel then reloads - eventuall via a double fault +this invalid entry into the tlb. The CPU then takes a tlb invalid +exception resulting in a call to do_page_fault() which usually will +take the apropriate measures like sending SIGSEGV. + +Downsides of this implementation are it's complexity and the faster +handling of the majority of exceptions is bought at the expense of +having to handle page aliasing problems with the page tables (which +are accessed at TLBMAP and in KSEG1) itself. This is done using +uncached accesses which are especially on older machines with slow +memory subsystems painfully slow. The implementation is done this +way because for the original hardware which Linux/MIPS was intended for +had a blindingly fast memory interface. diff --git a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile new file mode 100644 index 000000000..3ee478fee --- /dev/null +++ b/arch/mips/jazz/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for the Jazz family specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: jazz.o +O_TARGET := jazz.o +O_OBJS := hw-access.o int-handler.o jazzdma.o setup.o + +ifdef CONFIG_VIDEO_G364 +O_OBJS += g364.o +endif + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/jazz/g364.c b/arch/mips/jazz/g364.c new file mode 100644 index 000000000..87d66e24c --- /dev/null +++ b/arch/mips/jazz/g364.c @@ -0,0 +1,415 @@ +/* + * linux/drivers/char/g364.c + * + * Copyright (C) 1996 Wayne Hodgen + * + * Based on and using chunks of Jay Estabrooks tga.c + * + * This module exports the console io support for Inmos's G364 controller + * used in Mips Magnums and clones. Based on the hardware desc for the + * Olivetti M700-10 ie. an Inmos G364 based card in a dedicated video slot, + * 2MB dual ported VRAM with a 64 bit data path, 256 color lookup table, + * palette of 16.7M and a user definable 64x64 hardware cursor. + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/kd.h> +#include <linux/malloc.h> +#include <linux/major.h> +#include <linux/mm.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/types.h> + +#include "../../../drivers/char/kbd_kern.h" +#include "../../../drivers/char/vt_kern.h" +#include "../../../drivers/char/consolemap.h" +#include "../../../drivers/char/selection.h" +#include "../../../drivers/char/console_struct.h" + +extern void register_console(void (*proc)(const char *)); +extern void console_print(const char *); +unsigned video_res_x; + +/* + * Various defines for the G364 + */ +#define G364_MEM_BASE 0xe0800000 +#define G364_PORT_BASE 0xe0200000 +#define ID_REG 0xe0200000 /* Read only */ +#define BOOT_REG 0xe0280000 +#define TIMING_REG 0xe0280108 /* to 0x080170 - DON'T TOUCH! */ +#define MASK_REG 0xe0280200 +#define CTLA_REG 0xe0280300 +#define CURS_TOGGLE 0x800000 +#define BIT_PER_PIX 0x700000 /* bits 22 to 20 of Control A */ +#define DELAY_SAMPLE 0x080000 +#define PORT_INTER 0x040000 +#define PIX_PIPE_DEL 0x030000 /* bits 17 and 16 of Control A */ +#define PIX_PIPE_DEL2 0x008000 /* same as above - don't ask me why */ +#define TR_CYCLE_TOG 0x004000 +#define VRAM_ADR_INC 0x003000 /* bits 13 and 12 of Control A */ +#define BLANK_OFF 0x000800 +#define FORCE_BLANK 0x000400 +#define BLK_FUN_SWTCH 0x000200 +#define BLANK_IO 0x000100 +#define BLANK_LEVEL 0x000080 +#define A_VID_FORM 0x000040 +#define D_SYNC_FORM 0x000020 +#define FRAME_FLY_PAT 0x000010 +#define OP_MODE 0x000008 +#define INTL_STAND 0x000004 +#define SCRN_FORM 0x000002 +#define ENABLE_VTG 0x000001 +#define TOP_REG 0xe0280400 +#define CURS_PAL_REG 0xe0280508 /* to 0x080518 */ +#define CHKSUM_REG 0xe0280600 /* to 0x080610 - unused */ +#define CURS_POS_REG 0xe0280638 +#define CLR_PAL_REG 0xe0280800 /* to 0x080ff8 */ +#define CURS_PAT_REG 0xe0281000 /* to 0x081ff8 */ +#define MON_ID_REG 0xe0300000 /* unused */ +#define RESET_REG 0xe0380000 /* Write only */ + +/* + * built-in font management constants + * + * NOTE: the built-in font is 8x16, and the video resolution + * is either 1280x1024 @ 60Hz or 1024x768 @ 60 or 78Hz. + */ +#define FONTSIZE_X 8 /* 8 pixels wide */ +#define FONTSIZE_Y 16 /* 16 pixels high */ + +unsigned char g364_font[] = { +#include "g364.fnt" +}; + +u32 g364_cursor[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0xffff0000,0,0,0,0xffff0000,0,0,0,0xffff0000,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +#ifdef CONFIG_REMOTE_DEBUG +/* #define DEBUG_G364 */ + +extern int putDebugChar(char c); + +void +putDebugString(char *d_str) +{ + while (*d_str != '\0') { + putDebugChar(*d_str); + d_str++; + } + if (*--d_str != '\n') + putDebugChar('\n'); +} +#endif + +void g364_clear_screen(void); + +int cursor_initialised=0; + +unsigned long +con_type_init(unsigned long kmem_start, const char **display_desc) +{ + can_do_color = 1; + + /* + * fake the screen memory with some CPU memory + */ + video_mem_base = kmem_start; + kmem_start += video_screen_size; + video_mem_term = kmem_start; + video_type = VIDEO_TYPE_MIPS_G364; + video_res_x = video_num_columns * FONTSIZE_X; + + *display_desc = "G364"; + + return kmem_start; +} + +void +__set_origin(unsigned short offset) +{ + /* + * should not be called, but if so, do nothing... + */ +} + +/* + * Hide the cursor from view, during blanking, usually... + */ +void +hide_cursor(void) +{ +/* *(unsigned int *) CTLA_REG &= ~CURS_TOGGLE; */ +} + +void +init_g364_cursor(void) +{ + volatile unsigned int *ptr = (unsigned int *) CURS_PAL_REG; + + *ptr |= 0x00ffffff; + ptr[2] |= 0x00ffffff; + ptr[4] |= 0x00ffffff; + + memcpy((unsigned int *)CURS_PAT_REG, &g364_cursor, 1024); + cursor_initialised = 1; +} + +/* + * Set the cursor on. + */ +void +set_cursor(int currcons) +{ +/* + if (!cursor_initialised) + init_g364_cursor(); + + if (console_blanked) + return; + + *(unsigned int *) CTLA_REG |= CURS_TOGGLE; +*/ +} + +/* + * NOTE: get_scrmem() and set_scrmem() are here only because + * the VGA version of set_scrmem() has some direct VGA references. + */ +void +get_scrmem(int currcons) +{ + memcpyw((unsigned short *)vc_scrbuf[currcons], + (unsigned short *)origin, video_screen_size); + origin = video_mem_start = (unsigned long)vc_scrbuf[currcons]; + scr_end = video_mem_end = video_mem_start + video_screen_size; + pos = origin + y*video_size_row + (x<<1); +} + +void +set_scrmem(int currcons, long offset) +{ + if (video_mem_term - video_mem_base < offset + video_screen_size) + offset = 0; /* strange ... */ + memcpyw((unsigned short *)(video_mem_base + offset), + (unsigned short *) origin, video_screen_size); + video_mem_start = video_mem_base; + video_mem_end = video_mem_term; + origin = video_mem_base + offset; + scr_end = origin + video_screen_size; + pos = origin + y*video_size_row + (x<<1); +} + +/* + * Fill out later + */ +void +set_palette(void) +{ + int i, j; + volatile unsigned int *ptr = (volatile unsigned int *) CLR_PAL_REG; + + for (i = 0; i < 16; i++,ptr+=2) { + j = color_table[i]; + *ptr = ((default_red[j] << 16) | + (default_grn[j] << 8) | + (default_blu[j])); + } +} + +/* + * NOTE: + * this is here, and not in console.c, because the VGA version + * tests the controller type to see if color can be done. We *KNOW* + * that we can do color on the G364. + * + */ + +int +set_get_cmap(unsigned char * arg, int set) +{ + int i; + + for (i=0; i<16; i++) { + if (set) { + if (!access_ok(VERIFY_READ, (void *)arg, 16*3)) goto fault; + if (__get_user(default_red[i], arg++)) goto fault; + if (__get_user(default_grn[i], arg++)) goto fault; + if (__get_user(default_blu[i], arg++)) goto fault; + } else { + if (!access_ok(VERIFY_WRITE, (void *)arg, 16*3)) goto fault; + if (__put_user(default_red[i], arg++)) goto fault; + if (__put_user(default_grn[i], arg++)) goto fault; + if (__put_user(default_blu[i], arg++)) goto fault; + } + } + if (set) { + for (i=0; i<MAX_NR_CONSOLES; i++) + if (vc_cons_allocated(i)) { + int j, k ; + for (j=k=0; j<16; j++) { + vc_cons[i].d->vc_palette[k++] = default_red[j]; + vc_cons[i].d->vc_palette[k++] = default_grn[j]; + vc_cons[i].d->vc_palette[k++] = default_blu[j]; + } + } + set_palette() ; + } + + return 0; + +fault: + return -EFAULT; +} + +/* + * Adjust the screen to fit a font of a certain height + * + * Returns < 0 for error, 0 if nothing changed, and the number + * of lines on the adjusted console if changed. + * + * for now, we only support the built-in font... + */ +int +con_adjust_height(unsigned long fontheight) +{ + return -EINVAL; +} + +/* + * PIO_FONT support. + * + * for now, we will use/allow *only* our built-in font... + */ +int +set_get_font(char * arg, int set, int ch512) +{ + return -EINVAL; +} + +/* + * print a character to a graphics console. + */ +void +g364_blitc(unsigned short charattr, unsigned long addr) +{ + int row, col, temp; + register unsigned long long *dst, *font_row; + register int i; + char c; + + /* + * calculate (row,col) from addr and video_mem_base + */ + temp = (addr - video_mem_base) >> 1; + col = temp % 128; + row = (temp - col) / 128; + + /* + * calculate destination address + */ + dst = (unsigned long long *) ( G364_MEM_BASE + + ( row * video_res_x * FONTSIZE_Y ) + + ( col * FONTSIZE_X ) ); + + c = charattr & 0x00ff; + if (c == 0x20) { + for (i=0; i < FONTSIZE_Y; i++, dst += video_num_columns) + *dst = 0x00000000; + } else { + font_row = (unsigned long long *) &g364_font[(c << 7)]; + for (i=0; i < FONTSIZE_Y; i++, font_row++, dst += video_num_columns) + *dst = *font_row; + } +} + +/* + * print a character to a graphics console. Colour version, slower! + */ +void +g364_blitc_colour(unsigned short charattr, unsigned long addr) +{ + int row, col, temp, c, attrib; + register unsigned int fgmask, bgmask; + register unsigned long long *dst, *font_row; + register int i, stride; + + c = charattr & 0x00ff; + attrib = (charattr >> 8) & 0x00ff; + + /* + * extract foreground and background indices + * NOTE: we always treat blink/underline bits as color for now... + */ + fgmask = attrib & 0x0f; + bgmask = (attrib >> 4) & 0x0f; + + /* i = (c & 0xff) << 7; NOTE: assumption of 128 bytes per character bitmap */ + + /* + * calculate (row,col) from addr and video_mem_base + */ + temp = (addr - video_mem_base) >> 1; + col = temp % 128; + row = (temp - col) / 128; + stride = video_res_x / 8; + + /* + * calculate destination address + */ + dst = (unsigned long long *) ( G364_MEM_BASE + + ( row * video_res_x * FONTSIZE_Y ) + + ( col * FONTSIZE_X ) ); + + font_row = (unsigned long long *) &g364_font[((c & 0xff) << 7)]; + + for (i=0; i < FONTSIZE_Y; i++, font_row++, dst += stride) { + *dst = *font_row; + } +} + +/* + * dummy routines for the VESA blanking code, which is VGA only, + * so we don't have to carry that stuff around for the G364... + */ +void +vesa_powerdown(void) +{ +} + +void +vesa_blank(void) +{ +} + +void +vesa_unblank(void) +{ +} + +void +set_vesa_blanking(const unsigned long arg) +{ +} diff --git a/arch/mips/jazz/g364.fnt b/arch/mips/jazz/g364.fnt new file mode 100644 index 000000000..fd4890f03 --- /dev/null +++ b/arch/mips/jazz/g364.fnt @@ -0,0 +1,4097 @@ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x00,0x07,0x07,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x00,0x07,0x07,0x07, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x07,0x07,0x07,0x00,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x07,0x07,0x07,0x00,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x00,0x07,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x07,0x00, +0x07,0x07,0x07,0x07,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x07, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x07,0x07,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x00,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x00,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x07, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x07, +0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x07, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x07, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00, +0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07, +0x07,0x07,0x07,0x00,0x07,0x00,0x07,0x07, +0x07,0x07,0x07,0x07,0x00,0x07,0x00,0x07, +0x07,0x07,0x07,0x00,0x07,0x00,0x07,0x07, +0x07,0x07,0x07,0x07,0x00,0x07,0x00,0x07, +0x07,0x07,0x07,0x00,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07, +0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x07,0x00,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x07, +0x07,0x07,0x07,0x00,0x07,0x07,0x07,0x07, +0x07,0x00,0x07,0x07,0x07,0x00,0x07,0x07, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x00,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x00,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x07, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x07, +0x07,0x00,0x07,0x00,0x00,0x07,0x00,0x07, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x07, +0x00,0x07,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x07,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07, +0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x07, +0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x00,0x07,0x07,0x07, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x07, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x07, +0x07,0x07,0x07,0x00,0x07,0x07,0x07,0x07, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x07,0x07,0x07,0x07,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x00,0x07,0x00,0x00,0x00, +0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00, +0x07,0x07,0x07,0x00,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00, +0x07,0x07,0x00,0x07,0x00,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x07,0x07,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x07, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x07,0x07,0x00,0x07,0x07, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x07,0x00,0x00,0x00, +0x07,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00, +0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x00,0x00,0x00, +0x07,0x07,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00, +0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0 diff --git a/arch/mips/jazz/hw-access.c b/arch/mips/jazz/hw-access.c new file mode 100644 index 000000000..112941275 --- /dev/null +++ b/arch/mips/jazz/hw-access.c @@ -0,0 +1,147 @@ +/* + * Low-level hardware access stuff for Jazz family machines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996 by Ralf Baechle + */ +#include <linux/delay.h> +#include <linux/linkage.h> +#include <linux/types.h> +#include <asm/addrspace.h> +#include <asm/cache.h> +#include <asm/vector.h> +#include <asm/jazz.h> +#include <asm/jazzdma.h> +#include <asm/mc146818rtc.h> + +static unsigned char +fd_inb(unsigned int port) +{ + unsigned char c; + + c = *(volatile unsigned char *) port; + udelay(1); + + return c; +} + +static void +fd_outb(unsigned char value, unsigned int port) +{ + *(volatile unsigned char *) port = value; +} + +/* + * How to access the floppy DMA functions. + */ +static void +fd_enable_dma(void) +{ + vdma_enable(JAZZ_FLOPPY_DMA); +} + +static void +fd_disable_dma(void) +{ + vdma_disable(JAZZ_FLOPPY_DMA); +} + +static int +fd_request_dma(void) +{ + return 0; +} + +static void +fd_free_dma(void) +{ +} + +static void +fd_clear_dma_ff(void) +{ +} + +static void +fd_set_dma_mode(char mode) +{ + vdma_set_mode(JAZZ_FLOPPY_DMA, mode); +} + +static void +fd_set_dma_addr(unsigned int a) +{ + vdma_set_addr(JAZZ_FLOPPY_DMA, vdma_phys2log(PHYSADDR(a))); +} + +static void +fd_set_dma_count(unsigned int count) +{ + vdma_set_count(JAZZ_FLOPPY_DMA, count); +} + +static int +fd_get_dma_residue(void) +{ + return vdma_get_residue(JAZZ_FLOPPY_DMA); +} + +static void +fd_enable_irq(void) +{ +} + +static void +fd_disable_irq(void) +{ +} + +void +jazz_fd_cacheflush(const void *addr, size_t size) +{ + cacheflush((unsigned long)addr, size, CF_DCACHE|CF_ALL); +} + +static unsigned char +rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return *(char *)JAZZ_RTC_BASE; +} + +static void +rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + *(char *)JAZZ_RTC_BASE = data; +} + +struct feature jazz_feature = { + /* + * How to access the floppy controller's ports + */ + fd_inb, + fd_outb, + /* + * How to access the floppy DMA functions. + */ + fd_enable_dma, + fd_disable_dma, + fd_request_dma, + fd_free_dma, + fd_clear_dma_ff, + fd_set_dma_mode, + fd_set_dma_addr, + fd_set_dma_count, + fd_get_dma_residue, + fd_enable_irq, + fd_disable_irq, + /* + * How to access the RTC functions. + */ + rtc_read_data, + rtc_write_data +}; diff --git a/arch/mips/jazz/int-handler.S b/arch/mips/jazz/int-handler.S new file mode 100644 index 000000000..03c999124 --- /dev/null +++ b/arch/mips/jazz/int-handler.S @@ -0,0 +1,389 @@ +/* + * arch/mips/jazz/pica.S + * + * Copyright (C) 1995, 1996 by Ralf Baechle and Andreas Busse + * + * Jazz family specific stuff + * + * To do: On Jazz machines we remap some non-ISA interrupts to ISA + * interrupts. These interrupts should use their own vectors. + * Squeeze the last cycles out of the handlers. Only a dead + * cycle is a good cycle. + */ +#include <asm/asm.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/jazz.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +/* + * jazz_handle_int: Interrupt handler for the ACER Pica-61 boards + */ + .set noreorder + + NESTED(jazz_handle_int, FR_SIZE, ra) + .set noat + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + CLI + .set at + + /* + * Get pending interrupts + */ + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t1,CP0_STATUS # get enabled interrupts + and t0,t1 # isolate allowed ones + andi t0,0xff00 # isolate pending bits + beqz t0,3f + sll t0,16 # delay slot + + /* + * Find irq with highest priority + * FIXME: This is slow - use binary search + */ + la t1,ll_vectors +1: bltz t0,2f # found pending irq + sll t0,1 + b 1b + subu t1,PTRSIZE # delay slot + + /* + * Do the low-level stuff + */ +2: lw t0,(t1) + jr t0 + nop # delay slot + END(jazz_handle_int) + +ll_sw0: li s1,~IE_SW0 + mfc0 t0,CP0_CAUSE + and t0,s1 + mtc0 t0,CP0_CAUSE + PANIC("Unimplemented sw0 handler") + +ll_sw1: li s1,~IE_SW1 + mfc0 t0,CP0_CAUSE + and t0,s1 + mtc0 t0,CP0_CAUSE + PANIC("Unimplemented sw1 handler") + +ll_local_dma: li s1,~IE_IRQ0 + PANIC("Unimplemented local_dma handler") + +ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE +#if PTRSIZE == 8 /* True 64 bit kernel */ + dsll t0,1 +#endif + .set reorder + LONG_L t0,local_vector(t0) + jr t0 + .set noreorder + +/* + * The braindead PICA hardware gives us no way to distinguish if we really + * received interrupt 7 from the (E)ISA bus or if we just received an + * interrupt with no findable cause. This sometimes happens with braindead + * cards. Oh well - for all the Jazz boxes slots are more or less just + * whistles and bells and we're aware of the problem. + */ +ll_isa_irq: lw a0,JAZZ_EISA_IRQ_ACK + lui s0,%hi(PORT_BASE_JAZZ) + li s1,1 + andi t0,a0,8 # which pic? + bnez t0,ack_second + andi a0,7 # delay slot + + /* + * Acknowledge first pic + */ + lb t2,%lo(PORT_BASE_JAZZ)+0x21(s0) + lui s4,%hi(cache_21) + lb t0,%lo(cache_21)(s4) + sllv s1,s1,a0 + or t0,s1 + sb t0,%lo(cache_21)(s4) + sb t0,%lo(PORT_BASE_JAZZ)+0x21(s0) + lui s3,%hi(intr_count) + lw t0,%lo(intr_count)(s3) + li t2,0x20 + sb t2,%lo(PORT_BASE_JAZZ)+0x20(s0) + /* + * Now call the real handler + */ + la t3,IRQ_vectors + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,1 + jalr t3 + sw t0,%lo(intr_count)(s3) # delay slot + lw t0,%lo(intr_count)(s3) + /* + * Unblock first pic + */ + lbu a0,%lo(PORT_BASE_JAZZ)+0x21(s0) + lb a0,%lo(cache_21)(s4) + subu t0,1 + sw t0,%lo(intr_count)(s3) + nor s1,zero,s1 + and a0,s1 + sb a0,%lo(cache_21)(s4) + jr v0 + sb a0,%lo(PORT_BASE_JAZZ)+0x21(s0) # delay slot + + .align 5 +ack_second: /* + * Acknowledge second pic + */ + lbu t2,%lo(PORT_BASE_JAZZ)+0xa1(s0) + lui s4,%hi(cache_A1) + lb t3,%lo(cache_A1)(s4) + sllv s1,s1,a0 + or t3,s1 + sb t3,%lo(cache_A1)(s4) + sb t3,%lo(PORT_BASE_JAZZ)+0xa1(s0) + li t3,0x20 + sb t3,%lo(PORT_BASE_JAZZ)+0xa0(s0) + lui s3,%hi(intr_count) + lw t0,%lo(intr_count)(s3) + sb t3,%lo(PORT_BASE_JAZZ)+0x20(s0) + /* + * Now call the real handler + */ + la t3,IRQ_vectors + addiu a0,8 + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,1 + jalr t3 + sw t0,%lo(intr_count)(s3) # delay slot + + lw t0,%lo(intr_count)(s3) + /* + * Unblock second pic + */ + lb a0,%lo(PORT_BASE_JAZZ)+0xa1(s0) + lb a0,%lo(cache_A1)(s4) + subu t0,1 + sw t0,%lo(intr_count)(s3) + nor s1,zero,s1 + and a0,s1 + sb a0,%lo(cache_A1)(s4) + jr v0 + sb a0,%lo(PORT_BASE_JAZZ)+0xa1(s0) # delay slot + +/* + * Hmm... This is not just a plain PC clone so the question is + * which devices on Jazz machines can generate an (E)ISA NMI? + * (Writing to nonexistant memory?) + */ +ll_isa_nmi: li s1,~IE_IRQ3 + PANIC("Unimplemented isa_nmi handler") + +/* + * Timer IRQ - remapped to be more similar to an IBM compatible. + * + * The timer interrupt is handled specially to insure that the jiffies + * variable is updated at all times. Specifically, the timer interrupt is + * just like the complete handlers except that it is invoked with interrupts + * disabled and should never re-enable them. If other interrupts were + * allowed to be processed while the timer interrupt is active, then the + * other interrupts would have to avoid using the jiffies variable for delay + * and interval timing operations to avoid hanging the system. + */ +ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read + li s1,~IE_IRQ4 + + lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + li a0,0 + jal do_IRQ + move a1,sp # delay slot + + mfc0 t0,CP0_STATUS # disable interrupts again + ori t0,1 + xori t0,1 + mtc0 t0,CP0_STATUS + + lw t2,%lo(intr_count)(s3) + subu t2,1 + + j ret_from_sys_call + sw t2,%lo(intr_count)(s3) # delay slot + +/* + * CPU count/compare IRQ (unused) + */ +ll_count: j return + mtc0 zero,CP0_COMPARE + +#if 0 +/* + * Call the handler for the interrupt + * (Currently unused) + */ +call_real: lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + la t0,IRQ_vectors + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + /* + * temporarily disable interrupt + */ + mfc0 t2,CP0_STATUS + and t2,s1 + + addu t0,t3 + lw t0,(t0) + mtc0 t2,CP0_STATUS # delay slot + jalr t0 + nor s1,zero,s1 # delay slot + + /* + * reenable interrupt + */ + mfc0 t2,CP0_STATUS + or t2,s1 + mtc0 t2,CP0_STATUS + + lw t2,%lo(intr_count)(s3) + subu t2,1 + + jr v0 + sw t2,%lo(intr_count)(s3) +#endif + + .data + PTR ll_sw0 # SW0 + PTR ll_sw1 # SW1 + PTR ll_local_dma # Local DMA + PTR ll_local_dev # Local devices + PTR ll_isa_irq # ISA IRQ + PTR ll_isa_nmi # ISA NMI + PTR ll_timer # Timer +ll_vectors: PTR ll_count # Count/Compare IRQ + + /* + * Interrupt handlers for local devices. + */ + .text +loc_no_irq: PANIC("Unimplemented loc_no_irq handler") +/* + * Parallel port IRQ, remapped to level 5 + */ +loc_parallel: li s1,~JAZZ_IE_PARALLEL + li a0,JAZZ_PARALLEL_IRQ + b loc_call + li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot + +/* + * Floppy IRQ, remapped to level 6 + */ +loc_floppy: li s1,~JAZZ_IE_FLOPPY + li a0,JAZZ_FLOPPY_IRQ + b loc_call + li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot + +/* + * Sound? What sound hardware (whistle) ??? + */ +loc_sound: PANIC("Unimplemented loc_sound handler") +loc_video: PANIC("Unimplemented loc_video handler") + +/* + * Ethernet interrupt handler, remapped to level 13 + */ +loc_ethernet: li s1,~JAZZ_IE_ETHERNET + li a0,JAZZ_ETHERNET_IRQ + b loc_call + li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot + +loc_scsi: PANIC("Unimplemented loc_scsi handler") + +/* + * Keyboard interrupt handler + */ +loc_keyboard: li s1,~JAZZ_IE_KEYBOARD + li a0,JAZZ_KEYBOARD_IRQ + b loc_call + li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # re-map to irq level 1 + +loc_mouse: PANIC("Unimplemented loc_mouse handler") + +/* + * Serial port 1 IRQ, remapped to level 3 + */ +loc_serial1: li s1,~JAZZ_IE_SERIAL1 + li a0,JAZZ_SERIAL1_IRQ + b loc_call + li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot + +/* + * Serial port 2 IRQ, remapped to level 4 + */ +loc_serial2: li s1,~JAZZ_IE_SERIAL2 + li a0,JAZZ_SERIAL2_IRQ + b loc_call + li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot + +/* + * Call the interrupt handler for an interrupt generated by a + * local device. + */ +loc_call: lui s3,%hi(intr_count) + lw t2,%lo(intr_count)(s3) + la t0,IRQ_vectors # delay slot + addiu t2,1 + sw t2,%lo(intr_count)(s3) + + /* + * Temporarily disable interrupt source + */ + lhu t2,JAZZ_IO_IRQ_ENABLE + addu t0,t3 # make ptr to IRQ handler + lw t0,(t0) + and t2,s1 # delay slot + sh t2,JAZZ_IO_IRQ_ENABLE + jalr t0 # call IRQ handler + nor s1,zero,s1 # delay slot + + /* + * Reenable interrupt + */ + lhu t2,JAZZ_IO_IRQ_ENABLE + lw t1,%lo(intr_count)(s3) # delay slot + or t2,s1 + sh t2,JAZZ_IO_IRQ_ENABLE + + subu t1,1 + jr v0 + sw t1,%lo(intr_count)(s3) # delay slot + +/* + * "Jump extender" to reach spurious_interrupt + */ +3: j spurious_interrupt + nop # delay slot + +/* + * Vectors for interrupts generated by local devices + */ + .data +local_vector: PTR loc_no_irq + PTR loc_parallel + PTR loc_floppy + PTR loc_sound + PTR loc_video + PTR loc_ethernet + PTR loc_scsi + PTR loc_keyboard + PTR loc_mouse + PTR loc_serial1 + PTR loc_serial2 diff --git a/arch/mips/jazz/jazzdma.c b/arch/mips/jazz/jazzdma.c new file mode 100644 index 000000000..3663f33d8 --- /dev/null +++ b/arch/mips/jazz/jazzdma.c @@ -0,0 +1,515 @@ +/* + * arch/mips/jazz/jazzdma.c + * + * Mips Jazz DMA controller support + * Copyright (C) 1995, 1996 by Andreas Busse + * + * NOTE: Some of the argument checking could be removed when + * things have settled down. Also, instead of returning 0xffffffff + * on failure of vdma_alloc() one could leave page #0 unused + * and return the more usual NULL pointer as logical address. + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/mipsconfig.h> +#include <asm/jazz.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/dma.h> +#include <asm/jazzdma.h> + +/* + * Set this to one to enable additional vdma debug code. + */ +#define CONF_DEBUG_VDMA 0 + +static unsigned long vdma_pagetable_start = 0; +static unsigned long vdma_pagetable_end = 0; + +/* + * Debug stuff + */ +#define vdma_debug ((CONF_DEBUG_VDMA) ? debuglvl : 0) + +static int debuglvl = 3; + +/* + * Initialize the pagetable with a one-to-one mapping of + * the first 16 Mbytes of main memory and declare all + * entries to be unused. Using this method will at least + * allow some early device driver operations to work. + */ +static __inline__ void +vdma_pgtbl_init(void) +{ + int i; + unsigned long paddr = 0; + VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; + + for (i=0; i<VDMA_PGTBL_ENTRIES; i++) + { + pgtbl[i].frame = paddr; + pgtbl[i].owner = VDMA_PAGE_EMPTY; + paddr += VDMA_PAGESIZE; + } +} + +/* + * Initialize the Jazz R4030 dma controller + */ +unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end) +{ + /* + * Allocate 32k of memory for DMA page tables. + * This needs to be page aligned and should be + * uncached to avoid cache flushing after every + * update. + */ + vdma_pagetable_start = KSEG1ADDR((memory_start + 4095) & ~4095); + vdma_pagetable_end = vdma_pagetable_start + VDMA_PGTBL_SIZE; + cacheflush(vdma_pagetable_start, VDMA_PGTBL_SIZE, CF_DCACHE|CF_ALL); + + /* + * Clear the R4030 translation table + */ + vdma_pgtbl_init(); + + r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,PHYSADDR(vdma_pagetable_start)); + r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM,VDMA_PGTBL_SIZE); + r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); + + printk("VDMA: R4030 DMA pagetables initialized.\n"); + + return KSEG0ADDR(vdma_pagetable_end); +} + +/* + * Allocate DMA pagetables using a simple first-fit algorithm + */ +unsigned long vdma_alloc(unsigned long paddr, unsigned long size) +{ + VDMA_PGTBL_ENTRY *entry = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; + int first; + int last; + int pages; + unsigned int frame; + unsigned long laddr; + int i; + + /* check arguments */ + + if (paddr > 0x1fffffff) + { + if (vdma_debug) + printk("vdma_alloc: Invalid physical address: %08lx\n",paddr); + return VDMA_ERROR; /* invalid physical address */ + } + if (size > 0x400000 || size == 0) + { + if (vdma_debug) + printk("vdma_alloc: Invalid size: %08lx\n",size); + return VDMA_ERROR; /* invalid physical address */ + } + + /* + * Find free chunk + */ + pages = (size + 4095) >> 12; /* no. of pages to allocate */ + first = 0; + while (1) + { + while (entry[first].owner != VDMA_PAGE_EMPTY && + first < VDMA_PGTBL_ENTRIES) + first++; + if (first+pages > VDMA_PGTBL_ENTRIES) /* nothing free */ + return VDMA_ERROR; + + last = first+1; + while (entry[last].owner == VDMA_PAGE_EMPTY && last-first < pages) + last++; + + if (last-first == pages) + break; /* found */ + } + + /* + * Mark pages as allocated + */ + laddr = (first << 12) + (paddr & (VDMA_PAGESIZE-1)); + frame = paddr & ~(VDMA_PAGESIZE-1); + + for (i=first; i<last; i++) + { + entry[i].frame = frame; + entry[i].owner = laddr; + frame += VDMA_PAGESIZE; + } + + /* + * Update translation table and return logical start address + */ + r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); + + if (vdma_debug > 1) + printk("vdma_alloc: Allocated %d pages starting from %08lx\n", + pages,laddr); + + if (vdma_debug > 2) + { + printk("LADDR: "); + for (i=first; i<last; i++) + printk("%08x ",i<<12); + printk("\nPADDR: "); + for (i=first; i<last; i++) + printk("%08x ",entry[i].frame); + printk("\nOWNER: "); + for (i=first; i<last; i++) + printk("%08x ",entry[i].owner); + printk("\n"); + } + + return laddr; +} + +/* + * Free previously allocated dma translation pages + * Note that this does NOT change the translation table, + * it just marks the free'd pages as unused! + */ +int vdma_free(unsigned long laddr) +{ + VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; + int i; + + i = laddr >> 12; + + if (pgtbl[i].owner != laddr) + { + printk("vdma_free: trying to free other's dma pages, laddr=%8lx\n", + laddr); + return -1; + } + + while (pgtbl[i].owner == laddr && i < VDMA_PGTBL_ENTRIES) + { + pgtbl[i].owner = VDMA_PAGE_EMPTY; + i++; + } + + if (vdma_debug > 1) + printk("vdma_free: freed %ld pages starting from %08lx\n", + i-(laddr>>12),laddr); + + return 0; +} + +/* + * Map certain page(s) to another physical address. + * Caller must have allocated the page(s) before. + */ +int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size) +{ + VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; + int first, pages, npages; + + if (laddr > 0xffffff) + { + if (vdma_debug) + printk("vdma_map: Invalid logical address: %08lx\n",laddr); + return -EINVAL; /* invalid logical address */ + } + if (paddr > 0x1fffffff) + { + if (vdma_debug) + printk("vdma_map: Invalid physical address: %08lx\n",paddr); + return -EINVAL; /* invalid physical address */ + } + + npages = pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1; + first = laddr >> 12; + if (vdma_debug) + printk("vdma_remap: first=%x, pages=%x\n",first,pages); + if (first+pages > VDMA_PGTBL_ENTRIES) + { + if (vdma_debug) + printk("vdma_alloc: Invalid size: %08lx\n",size); + return -EINVAL; + } + + paddr &= ~(VDMA_PAGESIZE-1); + while (pages > 0 && first < VDMA_PGTBL_ENTRIES) + { + if (pgtbl[first].owner != laddr) + { + if (vdma_debug) + printk("Trying to remap other's pages.\n"); + return -EPERM; /* not owner */ + } + pgtbl[first].frame = paddr; + paddr += VDMA_PAGESIZE; + first++; + pages--; + } + + /* + * Update translation table + */ + r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); + + if (vdma_debug > 2) + { + int i; + pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1; + first = laddr >> 12; + printk("LADDR: "); + for (i=first; i<first+pages; i++) + printk("%08x ",i<<12); + printk("\nPADDR: "); + for (i=first; i<first+pages; i++) + printk("%08x ",pgtbl[i].frame); + printk("\nOWNER: "); + for (i=first; i<first+pages; i++) + printk("%08x ",pgtbl[i].owner); + printk("\n"); + } + + return 0; +} + +/* + * Translate a physical address to a logical address. + * This will return the logical address of the first + * match. + */ +unsigned long vdma_phys2log(unsigned long paddr) +{ + int i; + int frame; + VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; + + frame = paddr & ~(VDMA_PAGESIZE-1); + + for (i=0; i<VDMA_PGTBL_ENTRIES; i++) + { + if (pgtbl[i].frame == frame) + break; + } + + if (i == VDMA_PGTBL_ENTRIES) + return ~0UL; + + return (i<<12) + (paddr & (VDMA_PAGESIZE-1)); +} + +/* + * Translate a logical DMA address to a physical address + */ +unsigned long vdma_log2phys(unsigned long laddr) +{ + VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; + + return pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE-1)); +} + +/* + * Print DMA statistics + */ +void vdma_stats(void) +{ + int i; + + printk("vdma_stats: CONFIG: %08x\n", + r4030_read_reg32(JAZZ_R4030_CONFIG)); + printk("R4030 translation table base: %08x\n", + r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE)); + printk("R4030 translation table limit: %08x\n", + r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM)); + printk("vdma_stats: INV_ADDR: %08x\n", + r4030_read_reg32(JAZZ_R4030_INV_ADDR)); + printk("vdma_stats: R_FAIL_ADDR: %08x\n", + r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR)); + printk("vdma_stats: M_FAIL_ADDR: %08x\n", + r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR)); + printk("vdma_stats: IRQ_SOURCE: %08x\n", + r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE)); + printk("vdma_stats: I386_ERROR: %08x\n", + r4030_read_reg32(JAZZ_R4030_I386_ERROR)); + printk("vdma_chnl_modes: "); + for (i=0; i<8; i++) + printk("%04x ", + (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(i<<5))); + printk("\n"); + printk("vdma_chnl_enables: "); + for (i=0; i<8; i++) + printk("%04x ", + (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(i<<5))); + printk("\n"); +} + +/* + * DMA transfer functions + */ + +/* + * Enable a DMA channel. Also clear any error conditions. + */ +void vdma_enable(int channel) +{ + int status; + + if (vdma_debug) + printk("vdma_enable: channel %d\n",channel); + + /* + * Check error conditions first + */ + status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)); + if (status & 0x400) + printk("VDMA: Channel %d: Address error!\n",channel); + if (status & 0x200) + printk("VDMA: Channel %d: Memory error!\n",channel); + + /* + * Clear all interrupt flags + */ + r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), + R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR); + + /* + * Enable the desired channel + */ + r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), + r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) | + R4030_CHNL_ENABLE); +} + +/* + * Disable a DMA channel + */ +void vdma_disable(int channel) +{ + if (vdma_debug) + { + int status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)); + + printk("vdma_disable: channel %d\n",channel); + printk("VDMA: channel %d status: %04x (%s) mode: " + "%02x addr: %06x count: %06x\n", + channel,status,((status & 0x600) ? "ERROR" : "OK"), + (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5)), + (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5)), + (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5))); + } + + r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), + r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) & + ~R4030_CHNL_ENABLE); + + /* + * After disabling a DMA channel a remote bus register should be + * read to ensure that the current DMA acknowledge cycle is completed. + */ + *((volatile unsigned int *)JAZZ_DUMMY_DEVICE); +} + +/* + * Set DMA mode. This function accepts the mode values used + * to set a PC-style DMA controller. For the SCSI and FDC + * channels, we also set the default modes each time we're + * called. + * NOTE: The FAST and BURST dma modes are supported by the + * R4030 Rev. 2 and PICA chipsets only. I leave them disabled + * for now. + */ +void vdma_set_mode(int channel, int mode) +{ + if (vdma_debug) + printk("vdma_set_mode: channel %d, mode 0x%x\n", channel, mode); + + switch(channel) + { + case JAZZ_SCSI_DMA: /* scsi */ + r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5), +/* R4030_MODE_FAST | */ +/* R4030_MODE_BURST | */ + R4030_MODE_INTR_EN | + R4030_MODE_WIDTH_16 | + R4030_MODE_ATIME_80); + break; + + case JAZZ_FLOPPY_DMA: /* floppy */ + r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5), +/* R4030_MODE_FAST | */ +/* R4030_MODE_BURST | */ + R4030_MODE_INTR_EN | + R4030_MODE_WIDTH_8 | + R4030_MODE_ATIME_120); + break; + + case JAZZ_AUDIOL_DMA: + case JAZZ_AUDIOR_DMA: + printk("VDMA: Audio DMA not supported yet.\n"); + break; + + default: + printk("VDMA: vdma_set_mode() called with unsupported channel %d!\n", + channel); + } + + switch(mode) + { + case DMA_MODE_READ: + r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), + r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) & + ~R4030_CHNL_WRITE); + break; + + case DMA_MODE_WRITE: + r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), + r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) | + R4030_CHNL_WRITE); + break; + + default: + printk("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",mode); + } +} + +/* + * Set Transfer Address + */ +void vdma_set_addr(int channel, long addr) +{ + if (vdma_debug) + printk("vdma_set_addr: channel %d, addr %lx\n",channel,addr); + + r4030_write_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5),addr); +} + +/* + * Set Transfer Count + */ +void vdma_set_count(int channel, int count) +{ + if (vdma_debug) + printk("vdma_set_count: channel %d, count %08x\n",channel,(unsigned)count); + + r4030_write_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5),count); +} + +/* + * Get Residual + */ +int vdma_get_residue(int channel) +{ + int residual; + + residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5)); + + if (vdma_debug) + printk("vdma_get_residual: channel %d: residual=%d\n",channel,residual); + + return residual; +} diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c new file mode 100644 index 000000000..c5f5b1d77 --- /dev/null +++ b/arch/mips/jazz/setup.c @@ -0,0 +1,137 @@ +/* + * Setup pointers to hardware dependand routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/ptrace.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/jazz.h> +#include <asm/processor.h> +#include <asm/vector.h> +#include <asm/io.h> + +/* + * Initial irq handlers. + */ +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; + +extern asmlinkage void jazz_handle_int(void); +extern asmlinkage void jazz_fd_cacheflush(const void *addr, size_t size); +extern struct feature jazz_feature; +extern void (*ibe_board_handler)(struct pt_regs *regs); +extern void (*dbe_board_handler)(struct pt_regs *regs); + +static void +jazz_irq_setup(void) +{ + set_except_vector(0, jazz_handle_int); + r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, + JAZZ_IE_ETHERNET | + JAZZ_IE_SERIAL1 | + JAZZ_IE_SERIAL2 | + JAZZ_IE_PARALLEL | + JAZZ_IE_FLOPPY); + r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ + r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); /* clear error bits */ + set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); + request_region(0x20, 0x20, "pic1"); + request_region(0xa0, 0x20, "pic2"); + setup_x86_irq(2, &irq2); +} + +void (*board_time_init)(struct irqaction *irq); + +static void jazz_time_init(struct irqaction *irq) +{ + /* set the clock to 100 Hz */ + r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); + setup_x86_irq(0, irq); +} + +/* + * The ibe/dbe exceptions are signaled by onboard hardware and should get + * a board specific handlers to get maximum available information. Bus + * errors are always symptom of hardware malfunction or a kernel error. + * We should try to handle this case a bit more gracefully than just + * zapping the process ... + */ +static void jazz_be_board_handler(struct pt_regs *regs) +{ + u32 jazz_is, jazz_ia; + + /* + * Give some debugging aid ... + */ + jazz_is = r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE); + jazz_ia = r4030_read_reg32(JAZZ_R4030_INVAL_ADDR); + printk("Interrupt Source == %08x\n", jazz_is); + printk("Invalid Address Register == %08x\n", jazz_ia); + show_regs(regs); + + /* + * Assume it would be too dangerous to continue ... + */ + force_sig(SIGBUS, current); +} + +void +jazz_setup(void) +{ + tag *atag; + + /* + * we just check if a tag_screen_info can be gathered + * in setup_arch(), if yes we don't proceed futher... + */ + atag = bi_TagFind(tag_screen_info); + if (!atag) { + /* + * If no, we try to find the tag_arc_displayinfo which is + * always created by Milo for an ARC box (for now Milo only + * works on ARC boxes :) -Stoned. + */ + atag = bi_TagFind(tag_arcdisplayinfo); + if (atag) { + screen_info.orig_x = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x; + screen_info.orig_y = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y; + screen_info.orig_video_cols = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns; + screen_info.orig_video_lines = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines; + } + } + irq_setup = jazz_irq_setup; + board_time_init = jazz_time_init; + fd_cacheflush = jazz_fd_cacheflush; + feature = &jazz_feature; // Will go away + port_base = PORT_BASE_JAZZ; + isa_slot_offset = 0xe3000000; + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + /* The RTC is outside the port address space */ + + if (mips_machtype == MACH_MIPS_MAGNUM_4000 + && mips_machtype == MACH_OLIVETTI_M700) + EISA_bus = 1; + /* + * The Jazz hardware provides additional information for + * bus errors, so we use an special handler. + */ + ibe_board_handler = jazz_be_board_handler; + dbe_board_handler = jazz_be_board_handler; +} diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0086f60cf..b76c723b2 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -1,94 +1,51 @@ # -# Makefile for the linux kernel. +# Makefile for the Linux/MIPS kernel. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # -.c.s: - $(CC) $(CFLAGS) -S $< -.s.o: - $(AS) $(ASFLAGS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c $< .S.s: $(CPP) $(CFLAGS) $< -o $*.s .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = process.o signal.o entry.o traps.o irq.o ptrace.o vm86.o ioport.o \ - setup.o bios32.o tynedma.o - -include ../../../.config +all: kernel.o head.o +EXTRA_ASFLAGS = -mips3 -mcpu=r4000 +O_TARGET := kernel.o +O_OBJS := branch.o process.o signal.o entry.o traps.o irq.o ptrace.o vm86.o \ + ioport.o setup.o syscall.o sysmips.o time.o bios32.o ipc.o ksyms.o \ + unaligned.o tags.o # # Kernel debugging # - ifdef CONFIG_REMOTE_DEBUG -OBJS += gdb-low.o gdb-stub.o +O_OBJS += gdb-low.o gdb-stub.o endif # -# Board specific code +# Depending from some other kernel option # - -ifdef CONFIG_MIPS_JAZZ -OBJS += jazzdma.o -endif - -ifdef CONFIG_ACER_PICA_61 -OBJS += pica.o -endif - -ifdef CONFIG_DESKSTATION_TYNE -OBJS += tyne.o -endif - -ifdef CONFIG_MIPS_MAGNUM_4000 -OBJS += magnum4000.o +ifdef CONFIG_PROC_FS +O_OBJS += proc.o endif # -# CPU model specific code +# Since we add the same object files to O_OBJS for different configurations. +# O_OBJS might contain duplicate files. We correct this by filtering out +# duplicate files. Just to avoid users having to know about all the +# compatibility stuff between various boards and boards. # -ifdef CONFIG_CPU_R4X00 -OBJS += r4xx0.o -endif - -ifdef CONFIG_CPU_R4600 -OBJS += r4xx0.o -endif +O_OBJS := $(sort $(O_OBJS)) all: kernel.o head.o entry.o: entry.S - +exception.o: exception.S head.o: head.S -magnum4000.o: magnum4000.S - -pica.o: pica.S - -r4xx0.o: r4xx0.S - -tyne.o: tyne.S - -kernel.o: $(OBJS) - $(LD) -r -o kernel.o $(OBJS) - sync - -dep: - $(CPP) -M *.[cS] > .depend +clean: -modules: - -dummy: - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c new file mode 100644 index 000000000..32705b320 --- /dev/null +++ b/arch/mips/kernel/branch.c @@ -0,0 +1,193 @@ +/* + * Branch and jump emulation. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <asm/branch.h> +#include <asm/inst.h> +#include <asm/ptrace.h> +#include <asm/uaccess.h> + +/* + * Compute the return address and do emulate branch and instruction + * simulation, if required. + */ +int __compute_return_epc(struct pt_regs *regs) +{ + unsigned int *addr, bit, fcr31; + long epc; + union mips_instruction insn; + + epc = regs->cp0_epc; + if (epc & 3) { + printk("%s: unaligned epc - sending SIGBUS.\n", current->comm); + force_sig(SIGBUS, current); + return -EFAULT; + } + + /* + * Read the instruction + */ + addr = (unsigned int *) (unsigned long) epc; + if (__get_user(insn.word, addr)) { + force_sig(SIGSEGV, current); + return -EFAULT; + } + + regs->regs[0] = 0; + switch (insn.i_format.opcode) { + /* + * jr and jalr are in r_format format. + */ + case spec_op: + switch (insn.r_format.func) { + case jalr_op: + regs->regs[insn.r_format.rd] = epc + 8; + /* Fall through */ + case jr_op: + regs->cp0_epc = regs->regs[insn.r_format.rs]; + break; + } + break; + + /* + * This group contains: + * bltz_op, bgez_op, bltzl_op, bgezl_op, + * bltzal_op, bgezal_op, bltzall_op, bgezall_op. + */ + case bcond_op: + switch (insn.i_format.rt) { + case bltz_op: + case bltzl_op: + if (regs->regs[insn.i_format.rs] < 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bgez_op: + case bgezl_op: + if (regs->regs[insn.i_format.rs] >= 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bltzal_op: + case bltzall_op: + regs->regs[31] = epc + 8; + if (regs->regs[insn.i_format.rs] < 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bgezal_op: + case bgezall_op: + regs->regs[31] = epc + 8; + if (regs->regs[insn.i_format.rs] >= 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + } + break; + + /* + * These are unconditional and in j_format. + */ + case jal_op: + regs->regs[31] = regs->cp0_epc + 8; + case j_op: + epc += 4; + epc >>= 28; + epc <<= 28; + epc |= (insn.j_format.target << 2); + regs->cp0_epc = epc; + break; + + /* + * These are conditional and in i_format. + */ + case beq_op: + case beql_op: + if (regs->regs[insn.i_format.rs] == + regs->regs[insn.i_format.rt]) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bne_op: + case bnel_op: + if (regs->regs[insn.i_format.rs] != + regs->regs[insn.i_format.rt]) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case blez_op: /* not really i_format */ + case blezl_op: + /* rt field assumed to be zero */ + if (regs->regs[insn.i_format.rs] <= 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bgtz_op: + case bgtzl_op: + /* rt field assumed to be zero */ + if (regs->regs[insn.i_format.rs] > 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + /* + * And now the FPA/cp1 branch instructions. + */ + case cop1_op: + asm ("cfc1\t%0,$31":"=r" (fcr31)); + bit = (insn.i_format.rt >> 2); + bit += bit ? 24 : 23; + switch (insn.i_format.rt) { + case 0: /* bc1f */ + case 2: /* bc1fl */ + if (~fcr31 & (1 << bit)) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case 1: /* bc1t */ + case 3: /* bc1tl */ + if (fcr31 & (1 << bit)) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + } + break; + } + + return 0; +} diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 787e2bbf4..6072afae2 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -1,28 +1,31 @@ /* - * arch/mips/kernel/entry.S + * Low level exception handling * - * Copyright (C) 1994, 1995 Waldorf Electronics - * written by Ralf Baechle and Andreas Busse + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994, 1995 by Ralf Baechle */ /* * entry.S contains the system-call and fault low-level handling routines. * This also contains the timer-interrupt handler, as well as all interrupts - * and faults that can result in a task-switch. The ISA dependend TLB - * code is in arch/mips/kernel/tlb.S + * and faults that can result in a task-switch. The ISA dependent TLB + * code is in arch/mips/<ISA-level>/<cputype>.S */ - #include <linux/sys.h> #include <asm/asm.h> #include <asm/errno.h> -#include <asm/segment.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> -#include <asm/page.h> #include <asm/pgtable.h> #include <asm/stackframe.h> #include <asm/processor.h> +#include <asm/regdef.h> +#include <asm/fpregdef.h> +#include <asm/unistd.h> /* * These are offsets into the task-struct. @@ -36,6 +39,16 @@ flags = 20 errno = 24 exec_domain = 60 +#ifdef __SMP__ +#error "Fix this for SMP" +#else +#define current current_set +#endif + +/* + * Heia ... The %lo, %hi and %HI stuff is too strong for the ELF assembler + * and the ABI to cope with ... + */ .text .set noreorder .align 4 @@ -50,126 +63,16 @@ handle_bottom_half: jal do_bottom_half mtc0 t0,CP0_STATUS # delay slot mtc0 s3,CP0_STATUS # Restore old IRQ state - j 9f + b 9f sw s1,%lo(intr_count)(s0) # delay slot -reschedule: - lui ra,%hi(ret_from_sys_call) - j schedule - addiu ra,%lo(ret_from_sys_call) # delay slot - - .align 5 - NESTED(handle_sys, FR_SIZE, sp) - .set noat - SAVE_ALL - STI - .set at - /* - * Compute return address. We assume that syscalls never - * appear in delay slots. For the Linux/MIPS libc this - * assumption is always true. - */ - lw t3,FR_EPC(sp) - lw s1,FR_REG2(sp) - li t0,-ENOSYS - addiu t3,4 - sw t3,FR_EPC(sp) - li t2,NR_syscalls - bge s1,t2,ret_from_sys_call - sw t0,FR_REG2(sp) # delay slot - sll s1,PTRLOG - lw s1,sys_call_table(s1) - lw s0,current - - beqz s1,ret_from_sys_call - lw t0,flags(s0) # delay slot - sll t0,26 # PF_TRACESYS - bltz t0,1f - sw zero,errno(s0) # delay slot - -#if 0 - lw t0,FR_ORIG_REG2(sp) - beq t0,4,1f - nop - la t0,sys_call_names - lw t1,FR_ORIG_REG2(sp) - sll t1,2 - addu t0,t1 - lw a1,(t0) - PRINT("%s(") - lw a1,FR_REG4(sp) - lw a2,FR_REG5(sp) - lw a3,FR_REG6(sp) - PRINT("%08lx, %08lx, %08lx, ") - lw a1,FR_REG7(sp) - lw a2,FR_EPC(sp) - lw a3,FR_REG31(sp) - PRINT("%08lx) epc %08lx ra %08lx ") -1: -#endif - lw a0,FR_REG4(sp) - lw a1,FR_REG5(sp) - lw a2,FR_REG6(sp) - lw a3,FR_REG7(sp) - lw t0,FR_REG3(sp) - jalr s1 # do the real work - sw t0,PTRSIZE*4(sp) # delay slot - -#if 0 - lw t0,FR_ORIG_REG2(sp) - beq t0,4,1f - nop - sw v0,xxx - lw a1,xxx - PRINT("res %08lx\n") - lw v0,xxx - .data -xxx: .word 0 - .text -1: -#endif - - lw t0,errno(s0) - sw v0,FR_REG2(sp) # save return value - subu t0,zero,t0 - beqz t0,ret_from_sys_call +reschedule: jal schedule nop # delay slot - /* - * Fixme: should set error flag - */ - j ret_from_sys_call - sw t0,FR_REG2(sp) # delay slot - - .align 4 -1: jal syscall_trace - nop # delay slot - - lw a0,FR_REG4(sp) - lw a1,FR_REG5(sp) - lw a2,FR_REG6(sp) - lw a3,FR_REG7(sp) - lw t0,FR_REG3(sp) - jalr s1 # do the real work - sw t0,PTRSIZE*4(sp) # delay slot - - lw t0,errno(s0) - sw v0,FR_REG2(sp) - subu t0,zero,t0 # delay slot - beqz t0,1f - nop # delay slot - /* - * Fixme: should set error flag - */ -1: jal syscall_trace - sw t0,FR_REG2(sp) # delay slot - - .align 4 - .globl ret_from_sys_call -ret_from_sys_call: +EXPORT(ret_from_sys_call) lw t0,intr_count # bottom half bnez t0,return -9: - lw t0,bh_mask # delay slot + +9: lw t0,bh_mask # delay slot lw t1,bh_active # unused delay slot and t0,t1 bnez t0,handle_bottom_half @@ -187,15 +90,11 @@ ret_from_sys_call: lw s0,current lw t0,task - lw t1,state(s0) # state - beq s0,t0,return # task[0] cannot have signals - lw t0,counter(s0) # counter - bnez t1,reschedule # state == 0 ? lw a0,blocked(s0) + beq s0,t0,return # task[0] cannot have signals # save blocked in a0 for # signal handling - beqz t0,reschedule # counter == 0 ? - lw t0,signal(s0) + lw t0,signal(s0) # delay slot nor t1,zero,a0 and t1,t0,t1 beqz t1,return @@ -203,423 +102,225 @@ ret_from_sys_call: jal do_signal move a1,sp # delay slot - + .set noat - .globl return -return: RESTORE_ALL +EXPORT(return) + RESTORE_ALL ERET .set at - END(handle_sys) /* - * Beware: interrupt, fast_interrupt and bad_interrupt have unusal - * calling conventions! + * Beware: timer_interrupt, interrupt, fast_interrupt and bad_interrupt + * have unusual calling conventions to speedup the mess. * - * t1 - interrupt number + * a0 - interrupt number * s2 - destroyed * return values: * v0 - return routine + * + * The timer interrupt is handled specially to insure that the jiffies + * variable is updated at all times. Specifically, the timer interrupt is + * just like the complete handlers except that it is invoked with interrupts + * disabled and should never re-enable them. If other interrupts were + * allowed to be processed while the timer interrupt is active, then the + * other interrupts would have to avoid using the jiffies variable for delay + * and interval timing operations to avoid hanging the system. */ .text .set at .align 5 - NESTED(interrupt, FR_SIZE, sp) +NESTED(timer_interrupt, FR_SIZE, sp) + move s2,ra + jal do_IRQ + move a1,sp # delay slot + .set reorder + la v0,ret_from_sys_call + jr s2 + .set noreorder + END(timer_interrupt) + + .align 5 +NESTED(interrupt, FR_SIZE, sp) move s2,ra mfc0 t0,CP0_STATUS # enable IRQs ori t0,0x1f xori t0,0x1e mtc0 t0,CP0_STATUS - move a0,t1 jal do_IRQ move a1,sp # delay slot mfc0 t0,CP0_STATUS # disable IRQs ori t0,1 xori t0,1 + mtc0 t0,CP0_STATUS + .set reorder la v0,ret_from_sys_call jr s2 - mtc0 t0,CP0_STATUS # delay slot + .set noreorder END(interrupt) .align 5 - NESTED(fast_interrupt, FR_SIZE, sp) +NESTED(fast_interrupt, FR_SIZE, sp) + .set reorder move s2,ra - move a0,t1 jal do_fast_IRQ - move a1,sp # delay slot - lui v0,%hi(return) + la v0,return jr s2 - addiu v0,%lo(return) # delay slot + .set noreorder END(fast_interrupt) - LEAF(bad_interrupt) /* * Don't return & unblock the pic */ +LEAF(bad_interrupt) + .set reorder + lw t0,%lo(intr_count)(s3) + subu t0,1 + .set noreorder j return - nop + sw t0,%lo(intr_count)(s3) # delay slot END(bad_interrupt) - .align 5 - LEAF(spurious_interrupt) + .text + .align 5 +LEAF(spurious_interrupt) /* - * Nothing happened... (whistle) + * Someone tried to fool us by sending an interrupt but we + * couldn't find a cause for it. */ - lui t1,%hi(spurious_count) - lw t0,%lo(spurious_count)(t1) - la v0,return - addiu t0,1 - jr ra - sw t0,%lo(spurious_count)(t1) + lui t1,%hi(spurious_count) + lw t0,%lo(spurious_count)(t1) + la v0,return + addiu t0,1 + jr ra + sw t0,%lo(spurious_count)(t1) END(spurious_interrupt) - - /* - * Build a default exception handler for the other R4x00 exceptions + * Build a default exception handler for the exceptions that don't need + * special handlers. If you didn't know yet - I *like* playing games with + * the C preprocessor ... */ -#define BUILD_HANDLER(exception) \ +#define __BUILD_clear_none(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ +#define __BUILD_clear_sys(exception) \ + REG_S v0,FR_ORIG_REG2(sp); \ + REG_S a3,FR_ORIG_REG7(sp); +#define __BUILD_clear_fpe(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ \ + cfc1 a1,fcr31; \ + li a2,~(0x3f<<12); \ + and a2,a1; \ + ctc1 a2,fcr31; +#define __BUILD_clear_watch(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ \ + mtc0 zero,CP0_WATCHLO; \ + mtc0 zero,CP0_WATCHHI +#define __BUILD_clear_ade(exception) \ + REG_S sp,FR_ORIG_REG2(sp); /* sp < 0 */ \ + MFC0 t0,CP0_BADVADDR; \ + REG_S t0,FR_BADVADDR(sp); +#define __BUILD_silent(exception) +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) +#define fmt "Got %s at %08x.\n" +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) +#define fmt "Got %s at %016Lx.\n" +#endif +#define __BUILD_verbose(exception) \ + la a1,8f; \ + TEXT (#exception); \ + REG_L a2,FR_EPC(sp); \ + PRINT(fmt) +#define __BUILD_count(exception) \ + .set reorder; \ + lw t0,exception_count_##exception; \ + addiu t0,1; \ + sw t0,exception_count_##exception; \ + .set noreorder; \ + .data; \ +EXPORT(exception_count_##exception); \ + .word 0; \ + .text; +#define BUILD_HANDLER(exception,handler,clear,verbose) \ + .text; \ .align 5; \ NESTED(handle_##exception, FR_SIZE, sp); \ .set noat; \ SAVE_ALL; \ + __BUILD_clear_##clear(exception); \ STI; \ .set at; \ - la a1,8f; \ - TEXT (#exception); \ - lw a2,FR_EPC(sp); \ - PRINT("Got %s at %08x.\n"); \ - li a0,0; \ - li t0,-1; /* not a sys call */ \ - sw t0,FR_ORIG_REG2(sp); \ - jal do_##exception; \ + __BUILD_##verbose(exception); \ + REG_S sp,FR_ORIG_REG2(sp); /* not a sys call */ \ + jal do_##handler; \ move a0,sp; /* delay slot */ \ j ret_from_sys_call; \ nop; /* delay slot */ \ END(handle_##exception) - BUILD_HANDLER(adel) - BUILD_HANDLER(ades) - BUILD_HANDLER(ibe) - BUILD_HANDLER(dbe) - BUILD_HANDLER(ov) - BUILD_HANDLER(fpe) - BUILD_HANDLER(bp) - BUILD_HANDLER(tr) - BUILD_HANDLER(ri) - BUILD_HANDLER(cpu) - BUILD_HANDLER(vcei) - BUILD_HANDLER(vced) - BUILD_HANDLER(watch) - BUILD_HANDLER(reserved) - + BUILD_HANDLER(adel,ade,ade,silent) /* #4 */ + BUILD_HANDLER(ades,ade,ade,silent) /* #5 */ + BUILD_HANDLER(ibe,ibe,none,verbose) /* #6 */ + BUILD_HANDLER(dbe,dbe,none,verbose) /* #7 */ + BUILD_HANDLER(sys,sys,none,silent) /* #8 */ + BUILD_HANDLER(bp,bp,none,silent) /* #9 */ + BUILD_HANDLER(ri,ri,none,silent) /* #10 */ + BUILD_HANDLER(cpu,cpu,none,silent) /* #11 */ + BUILD_HANDLER(ov,ov,none,silent) /* #12 */ + BUILD_HANDLER(tr,tr,none,silent) /* #13 */ + BUILD_HANDLER(vcei,vcei,none,verbose) /* #14 */ + BUILD_HANDLER(fpe,fpe,fpe,silent) /* #15 */ + BUILD_HANDLER(watch,watch,watch,verbose) /* #23 */ + BUILD_HANDLER(vced,vced,none,verbose) /* #31 */ + BUILD_HANDLER(reserved,reserved,none,verbose) /* others */ /* * Exception handler table with 32 entries. * This might be extended to handle software exceptions */ .bss - .align 2 - EXPORT(exception_handlers) - .fill 32,4,0 + .align PTRLOG +EXPORT(exception_handlers) + .fill 32,PTRSIZE,0 + +/* + * Interrupt handler table with 16 entries. + */ +EXPORT(IRQ_vectors) + .fill 16,PTRSIZE,0 /* * Table of syscalls */ .data - EXPORT(sys_call_table) - PTR sys_setup /* 0 */ - PTR sys_exit - PTR sys_fork - PTR sys_read - PTR sys_write - PTR sys_open /* 5 */ - PTR sys_close - PTR sys_waitpid - PTR sys_creat - PTR sys_link - PTR sys_unlink /* 10 */ - PTR sys_execve - PTR sys_chdir - PTR sys_time - PTR sys_mknod - PTR sys_chmod /* 15 */ - PTR sys_chown - PTR sys_break - PTR sys_stat - PTR sys_lseek - PTR sys_getpid /* 20 */ - PTR sys_mount - PTR sys_umount - PTR sys_setuid - PTR sys_getuid - PTR sys_stime /* 25 */ - PTR sys_ptrace - PTR sys_alarm - PTR sys_fstat - PTR sys_pause - PTR sys_utime /* 30 */ - PTR sys_stty - PTR sys_gtty - PTR sys_access - PTR sys_nice - PTR sys_ftime /* 35 */ - PTR sys_sync - PTR sys_kill - PTR sys_rename - PTR sys_mkdir - PTR sys_rmdir /* 40 */ - PTR sys_dup - PTR sys_pipe - PTR sys_times - PTR sys_prof - PTR sys_brk /* 45 */ - PTR sys_setgid - PTR sys_getgid - PTR sys_signal - PTR sys_geteuid - PTR sys_getegid /* 50 */ - PTR sys_acct - PTR sys_phys - PTR sys_lock - PTR sys_ioctl - PTR sys_fcntl /* 55 */ - PTR sys_mpx - PTR sys_setpgid - PTR sys_ulimit - PTR sys_olduname - PTR sys_umask /* 60 */ - PTR sys_chroot - PTR sys_ustat - PTR sys_dup2 - PTR sys_getppid - PTR sys_getpgrp /* 65 */ - PTR sys_setsid - PTR sys_sigaction - PTR sys_sgetmask - PTR sys_ssetmask - PTR sys_setreuid /* 70 */ - PTR sys_setregid - PTR sys_sigsuspend - PTR sys_sigpending - PTR sys_sethostname - PTR sys_setrlimit /* 75 */ - PTR sys_getrlimit - PTR sys_getrusage - PTR sys_gettimeofday - PTR sys_settimeofday - PTR sys_getgroups /* 80 */ - PTR sys_setgroups - PTR sys_select - PTR sys_symlink - PTR sys_lstat - PTR sys_readlink /* 85 */ - PTR sys_uselib - PTR sys_swapon - PTR sys_reboot - PTR old_readdir - PTR sys_mmap /* 90 */ - PTR sys_munmap - PTR sys_truncate - PTR sys_ftruncate - PTR sys_fchmod - PTR sys_fchown /* 95 */ - PTR sys_getpriority - PTR sys_setpriority - PTR sys_profil - PTR sys_statfs - PTR sys_fstatfs /* 100 */ - PTR sys_ioperm - PTR sys_socketcall - PTR sys_syslog - PTR sys_setitimer - PTR sys_getitimer /* 105 */ - PTR sys_newstat - PTR sys_newlstat - PTR sys_newfstat - PTR sys_uname - PTR sys_iopl /* 110 */ - PTR sys_vhangup - PTR sys_idle - PTR sys_vm86 - PTR sys_wait4 - PTR sys_swapoff /* 115 */ - PTR sys_sysinfo - PTR sys_ipc - PTR sys_fsync - PTR sys_sigreturn - PTR sys_clone /* 120 */ - PTR sys_setdomainname - PTR sys_newuname - PTR 0 #sys_modify_ldt - PTR sys_adjtimex - PTR sys_mprotect /* 125 */ - PTR sys_sigprocmask - PTR sys_create_module - PTR sys_init_module - PTR sys_delete_module - PTR sys_get_kernel_syms /* 130 */ - PTR sys_quotactl - PTR sys_getpgid - PTR sys_fchdir - PTR sys_bdflush - PTR sys_sysfs /* 135 */ - PTR sys_personality - PTR 0 /* for afs_syscall */ - PTR sys_setfsuid - PTR sys_setfsgid - PTR sys_llseek /* 140 */ - PTR sys_getdents - PTR sys_select - PTR sys_flock - .space (NR_syscalls-140)*4 + .align PTRLOG +EXPORT(sys_call_table) + /* + * Reserved space for all the SVR4, SVR, BSD43 and POSIX + * flavoured syscalls. + */ + .space (__NR_Linux)*PTRSIZE - .bss - EXPORT(IRQ_vectors) - .fill 16,4,0 + /* + * Linux flavoured syscalls. + */ +#define SYS(call, narg) PTR call +#include "syscalls.h" - .text -sys_call_names: - TTABLE ("setup") - TTABLE ("exit") - TTABLE ("fork") - TTABLE ("read") - TTABLE ("write") - TTABLE ("open") - TTABLE ("close") - TTABLE ("waitpid") - TTABLE ("creat") - TTABLE ("link") - TTABLE ("unlink") - TTABLE ("execve") - TTABLE ("chdir") - TTABLE ("time") - TTABLE ("mknod") - TTABLE ("chmod") - TTABLE ("chown") - TTABLE ("break") - TTABLE ("stat") - TTABLE ("lseek") - TTABLE ("getpid") - TTABLE ("mount") - TTABLE ("umount") - TTABLE ("setuid") - TTABLE ("getuid") - TTABLE ("stime") - TTABLE ("ptrace") - TTABLE ("alarm") - TTABLE ("fstat") - TTABLE ("pause") - TTABLE ("utime") - TTABLE ("stty") - TTABLE ("gtty") - TTABLE ("access") - TTABLE ("nice") - TTABLE ("ftime") - TTABLE ("sync") - TTABLE ("kill") - TTABLE ("rename") - TTABLE ("mkdir") - TTABLE ("rmdir") - TTABLE ("dup") - TTABLE ("pipe") - TTABLE ("times") - TTABLE ("prof") - TTABLE ("brk") - TTABLE ("setgid") - TTABLE ("getgid") - TTABLE ("signal") - TTABLE ("geteuid") - TTABLE ("getegid") - TTABLE ("acct") - TTABLE ("phys") - TTABLE ("lock") - TTABLE ("ioctl") - TTABLE ("fcntl") - TTABLE ("mpx") - TTABLE ("setpgid") - TTABLE ("ulimit") - TTABLE ("olduname") - TTABLE ("umask") - TTABLE ("chroot") - TTABLE ("ustat") - TTABLE ("dup2") - TTABLE ("getppid") - TTABLE ("getpgrp") - TTABLE ("setsid") - TTABLE ("sigaction") - TTABLE ("sgetmask") - TTABLE ("ssetmask") - TTABLE ("setreuid") - TTABLE ("setregid") - TTABLE ("sigsuspend") - TTABLE ("sigpending") - TTABLE ("sethostname") - TTABLE ("setrlimit") - TTABLE ("getrlimit") - TTABLE ("getrusage") - TTABLE ("gettimeofday") - TTABLE ("settimeofday") - TTABLE ("getgroups") - TTABLE ("setgroups") - TTABLE ("select") - TTABLE ("symlink") - TTABLE ("lstat") - TTABLE ("readlink") - TTABLE ("uselib") - TTABLE ("swapon") - TTABLE ("reboot") - TTABLE ("readdir") - TTABLE ("mmap") - TTABLE ("munmap") - TTABLE ("truncate") - TTABLE ("ftruncate") - TTABLE ("fchmod") - TTABLE ("fchown") - TTABLE ("getpriority") - TTABLE ("setpriority") - TTABLE ("profil") - TTABLE ("statfs") - TTABLE ("fstatfs") - TTABLE ("ioperm") - TTABLE ("socketcall") - TTABLE ("syslog") - TTABLE ("setitimer") - TTABLE ("getitimer") - TTABLE ("newstat") - TTABLE ("newlstat") - TTABLE ("newfstat") - TTABLE ("uname") - TTABLE ("iopl") - TTABLE ("vhangup") - TTABLE ("idle") - TTABLE ("vm86") - TTABLE ("wait4") - TTABLE ("swapoff") - TTABLE ("sysinfo") - TTABLE ("ipc") - TTABLE ("fsync") - TTABLE ("sigreturn") - TTABLE ("clone") - TTABLE ("setdomainname") - TTABLE ("newuname") - TTABLE ("modify_ldt (unused)") - TTABLE ("adjtimex") - TTABLE ("mprotect") - TTABLE ("sigprocmask") - TTABLE ("create_module") - TTABLE ("init_module") - TTABLE ("delete_module") - TTABLE ("get_kernel_syms") - TTABLE ("quotactl") - TTABLE ("getpgid") - TTABLE ("fchdir") - TTABLE ("bdflush") - TTABLE ("sysfs") - TTABLE ("personality") - TTABLE ("afs_syscall") /* for afs_syscall */ - TTABLE ("setfsuid") - TTABLE ("setfsgid") - TTABLE ("llseek") - TTABLE ("sys_getdents") - TTABLE ("sys_select") - TTABLE ("sys_flock") +/* + * Number of arguments of each syscall + * FIXME: This table contains huge empty areas wasting memory. + */ +EXPORT(sys_narg_table) + /* + * Reserved space for all the SVR4, SVR, BSD43 and POSIX + * flavoured syscalls. + */ + .space (__NR_Linux) + + /* + * Linux flavoured syscalls. + */ +#undef SYS +#define SYS(call, narg) .byte narg +#include "syscalls.h" diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S index ea775e732..9b948a845 100644 --- a/arch/mips/kernel/gdb-low.S +++ b/arch/mips/kernel/gdb-low.S @@ -9,9 +9,9 @@ #include <linux/sys.h> #include <asm/asm.h> -#include <asm/segment.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> +#include <asm/regdef.h> #include <asm/stackframe.h> #include <asm/gdb-stub.h> diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 7708feac0..9a3240152 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -68,10 +68,10 @@ #include <linux/signal.h> #include <linux/kernel.h> +#include <asm/addrspace.h> #include <asm/asm.h> #include <asm/mipsregs.h> -#include <asm/segment.h> -#include <asm/cachectl.h> +#include <asm/cache.h> #include <asm/system.h> #include <asm/gdb-stub.h> @@ -407,7 +407,7 @@ static int hexToInt(char **ptr, int *intValue) } /* - * This function does all command procesing for interfacing to gdb. It + * This function does all command processing for interfacing to gdb. It * returns 1 if you should skip the instruction at the trap address, 0 * otherwise. */ @@ -605,7 +605,7 @@ void handle_exception (struct gdb_regs *regs) * NB: We flush both caches, just to be sure... */ - sys_cacheflush((void *)KSEG0,KSEG1-KSEG0,BCACHE); + cacheflush((void *)KSEG0, KSEG1-KSEG0, CF_BCACHE|CF_ALL); return; /* NOTREACHED */ break; diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index a2cb43de3..82de12ff5 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -1,16 +1,30 @@ /* * arch/mips/kernel/head.S * - * Copyright (C) 1994, 1995 Waldorf Electronics + * Copyright (C) 1994, 1995 Waldorf Electronics, 1996 Paul M. Antoine * Written by Ralf Baechle and Andreas Busse + * Modified for DECStation and hence R3000 support by Paul M. Antoine + * Additional R3000 support by Didier Frick <dfrick@dial.eunet.ch> + * for ACN S.A, Copyright (C) 1996 by ACN S.A * * Head.S contains the MIPS exception handler and startup code. + * + * FIXME: Note that the #ifdef's for R4X00 assume R3000 is the #else + * case, which is a little naughty. We also do NOT need the + * dec_entry goo at the begining of all this - PMA + * FIXME: This #ifdef stuff is ugly and I should move the tlb/exception + * handler code out into some other file - Ralf + * Take the zillions of (_MIPS_ISA == _MIPS_ISA_MIPSx) as a temporary + * solution. I know how they look ... */ +#include <linux/config.h> /* For the DECstation hacks */ #include <linux/tasks.h> +#include <asm/addrspace.h> #include <asm/asm.h> -#include <asm/segment.h> -#include <asm/cachectl.h> +#include <asm/processor.h> +#include <asm/regdef.h> +#include <asm/cache.h> #include <asm/mipsregs.h> #include <asm/mipsconfig.h> #include <asm/stackframe.h> @@ -18,14 +32,33 @@ #define PAGE_SIZE 0x1000 +/* + * FIXME: I still think the following should be in an include file (see + * also the reference in arch/mips/mips1/r3000.S - PMA + */ +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) +#define MODE_GLOBAL 0x0100 /* shared for all processes */ +#define MODE_ALIAS 0x00e0 +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) #define MODE_GLOBAL 0x0001 /* shared for all processes */ #define MODE_ALIAS 0x0016 /* uncachable */ +#endif - .text - .set mips3 /* + * The two symbols begin_except and end_except mark the range that is copied + * to KSEG0 on startup. + */ +EXPORT(begin_except) + .text +/* * This is space for the interrupt handlers. - * They are located at virtual address KSEG[01] (physical 0x0) + * After trap_init() they are located at virtual address KSEG0. + * + * For some machine where the kernel doesn't get directly loaded to KSEG0 + * the exceptionhandler get copied to KSEG0. They therefore must be + * relocatable code. */ /* * TLB refill, EXL == 0 @@ -33,6 +66,17 @@ .set noreorder .set noat LEAF(except_vec0) +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + mfc0 k1,CP0_CONTEXT + nop + lw k0,(k1) # May cause another exception + mfc0 k1,CP0_EPC # Get the return address + srl k0,12 # Convert to EntryLo format + mtc0 k0,CP0_ENTRYLO0 +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) + .set mips3 dmfc0 k1,CP0_CONTEXT dsra k1,1 lwu k0,(k1) # May cause another exception @@ -41,37 +85,103 @@ dsrl k1,6 # Convert to EntryLo format dmtc0 k0,CP0_ENTRYLO0 dmtc0 k1,CP0_ENTRYLO1 +#endif +#ifndef CONFIG_OPTIMIZE_R4600 nop # Needed for R4[04]00 pipeline +#endif tlbwr nop # Needed for R4[04]00 pipeline nop +#ifndef CONFIG_OPTIMIZE_R4600 nop +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + jr k1 + rfe +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) eret /* - * Workaround for R4000 bug. For explanation see MIPS - * docs. Note that this that obscure that it wont almost - * never happen. Well, but Mips writes about it's bugs. + * Partial workaround for R4000 bug. For explanation see + * MIPS docs. Note that this that obscure that it wont + * almost never happen. Well, but Mips writes about it's bugs. */ nop eret +#endif END(except_vec0) +/******************************************************************************/ + /* * XTLB refill, EXL == 0 - * Should never be reached + * Should never be reached on R4000. */ .org except_vec0+0x80 - LEAF(except_vec1) - PANIC("XTLB Refill exception.\n") -1: j 1b + NESTED(except_vec1, 0, sp) + .set noat + /* + * Register saving is delayed as long as we don't know + * which registers really need to be saved. + */ +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + mfc0 k1,CP0_CONTEXT nop + lw k0,(k1) # May cause another exception + mfc0 k1,CP0_EPC # Get the return address + srl k0,12 # Convert to EntryLo format + mtc0 k0,CP0_ENTRYLO0 +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) + mfc0 k1,CP0_CONTEXT + dsra k1,1 + lwu k0,(k1) # May cause another exception + lwu k1,4(k1) + dsrl k0,6 # Convert to EntryLo format + dsrl k1,6 # Convert to EntryLo format + dmtc0 k0,CP0_ENTRYLO0 + dmtc0 k1,CP0_ENTRYLO1 +#endif + nop # Needed for R4[04]00 pipeline + tlbwr + nop # Needed for R4[04]00 pipeline + nop +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + jr k1 + rfe +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) + nop + eret +#endif + /* + * Partial workaround for R4000 bug. For explanation see + * MIPS docs. Note that this that obscure that it wont + * almost never happen. Well, but Mips writes about it's bugs. + */ + nop + eret END(except_vec1) +/******************************************************************************/ + /* * Cache Error */ .org except_vec1+0x80 LEAF(except_vec2) +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) + /* + * On the R3000, this is the "Uncached TLB Miss" handler. + */ + j except_vec0 + nop +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS5) /* * Famous last words: unreached */ @@ -79,8 +189,11 @@ PRINT("Cache error exception: c0_errorepc == %08x\n") 1: j 1b nop +#endif END(except_vec2) +/******************************************************************************/ + /* * General exception vector. */ @@ -90,6 +203,8 @@ /* * Register saving is delayed as long as we don't know * which registers really need to be saved. + * Except for k1 which MUST be preserved to allow + * nested TLB refill exceptions on the R3000. */ mfc0 k1,CP0_CAUSE la k0,exception_handlers @@ -107,46 +222,89 @@ END(except_vec3) .set at +EXPORT(end_except) + /******************************************************************************/ /* * Kernel entry */ .set noreorder + NESTED(kernel_entry, 16, sp) /* + * The following two symbols are used for kernel profiling. + */ + EXPORT(stext) + EXPORT(_stext) + + /* + * Initialize the global pointer, if required. + */ + LOAD_GP + + /* + * First setup stack for kernel and init + */ + la sp,init_user_stack+(KERNEL_STACK_SIZE-4*SZREG) + la t0,init_kernel_stack+(KERNEL_STACK_SIZE) + LONG_S t0,kernelsp + + /* * Clear BSS first so that there are no surprises... */ la t0,_edata la t1,_end - sw zero,(t0) -1: addiu t0,4 + sb zero,(t0) +1: addiu t0,1 +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) + /* + * Paul, this clears one word too much - Ralf + */ + bne t0,t1,1b +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS3) || \ + (_MIPS_ISA == _MIPS_ISA_MIPS4) bnel t0,t1,1b - sw zero,(t0) +#endif + sb zero,(t0) # delay slot + + /* + * Get the memory upper limit the bootloader passed to us + * in a0 + */ + sw a0,mips_memory_upper + + /* + * Get the very one tags we need early in the boot process + */ + jal bi_EarlySnarf + nop /* * Initialize low level part of memory management + * First flush the TLB to make sure that we don't get a + * TLB shutdown during wire_mappings. */ jal tlbflush +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + nop +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) mtc0 zero,CP0_WIRED # delay slot +#endif jal wire_mappings nop - jal tlbflush - nop - - /* - * Stack for kernel and init - */ - la sp,init_user_stack+PAGE_SIZE-24 - la t0,init_kernel_stack+PAGE_SIZE - sw t0,kernelsp /* * Disable coprocessors */ mfc0 t0,CP0_STATUS - li t1,~(ST0_CU0|ST0_CU1|ST0_CU2|ST0_CU3) + li t1,~(ST0_CU1|ST0_CU2|ST0_CU3) and t0,t1 + li t1,ST0_CU0 + or t0,ST0_CU0 mtc0 t0,CP0_STATUS 1: jal start_kernel @@ -167,13 +325,18 @@ * Get base address of map0 table for the * the board we're running on */ - la t0,boot_info - lw t1,OFFSET_BOOTINFO_MACHTYPE(t0) - la t0,map0table - sll t1,PTRLOG # machtype used as index + lw t1,mips_machgroup # mips_machgroup is set by + # bi_EarlySnarf() + la t0,map0table + sll t1,PTRLOG # machgroup used as index addu t0,t1 - lw t0,(t0) # get base address - + lw t1,mips_machtype # mips_machtype is set by + # bi_EarlySnarf() + lw t0,(t0) # load table @ for the group + sll t1,PTRLOG # machtype used as index + addu t0,t1 + lw t0,(t0) # load table @ for the box + nop /* * Get number of wired TLB entries and * loop over selected map0 table. @@ -182,18 +345,33 @@ move t2,zero # TLB entry counter addiu t3,t1,1 # wire one additional entry beqz t1,2f # null, exit +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + nop +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) mtc0 t3,CP0_WIRED # delay slot +#endif addiu t0,8 1: lw t4,24(t0) # PageMask ld t5,0(t0) # entryHi ld t6,8(t0) # entryLo0 +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) ld t7,16(t0) # entryLo1 +#endif addiu t2,1 # increment ctr mtc0 t2,CP0_INDEX # set TLB entry +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + nop + mtc0 t5,CP0_ENTRYHI + nop + mtc0 t6,CP0_ENTRYLO0 +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) mtc0 t4,CP0_PAGEMASK dmtc0 t5,CP0_ENTRYHI dmtc0 t6,CP0_ENTRYLO0 dmtc0 t7,CP0_ENTRYLO1 +#endif addiu t0,32 bne t1,t2,1b # next TLB entry tlbwi # delay slot @@ -202,21 +380,40 @@ * We use only 4k pages. Therefore the PageMask register * is expected to be setup for 4k pages. */ -2: li t0,PM_4K +2: +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) + li t0,PM_4K mtc0 t0,CP0_PAGEMASK +#endif /* * Now map the pagetables */ mtc0 zero,CP0_INDEX la t0,TLB_ROOT +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + mtc0 t0,CP0_ENTRYHI + nop +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) dmtc0 t0,CP0_ENTRYHI +#endif la t0,swapper_pg_dir-KSEG1 +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + srl t0,12 +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) srl t0,6 +#endif ori t0,(MODE_ALIAS|MODE_GLOBAL) # uncachable, dirty, valid +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + mtc0 t0,CP0_ENTRYLO0 +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) dmtc0 t0,CP0_ENTRYLO0 li t0,MODE_GLOBAL dmtc0 t0,CP0_ENTRYLO1 +#endif nop tlbwi # delayed @@ -227,54 +424,18 @@ * NEVER be changed. */ li t0,TLBMAP +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + srl t0,1 # this is a guess! + mtc0 t0,CP0_CONTEXT +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) dsll t0,1 dmtc0 t0,CP0_CONTEXT +#endif jr ra # delay slot nop END(wire_mappings) -/* - * Just for debugging... - */ - .set noreorder - LEAF(beep) - lw t0,beepflag - nop - bnez t0,1f - lbu t0,0xe2000061 - xori t0,3 - sb t0,0xe2000061 - li t0,1 - sw t0,beepflag -1: jr ra - nop - END(beep) - - .bss -beepflag: .word 0 - .text - -/* - * Compute kernel code checksum to check kernel code against corruption - */ - LEAF(csum) - jal sys_cacheflush - move t8,ra # delay slot - li t0,KSEG1 - la t1,final - li t2,KSEG1 - or t0,t2 - or t1,t2 - move v0,zero -1: lw t2,(t0) - addiu t0,4 - bne t0,t1,1b - xor v0,t2 - jr t8 - nop - END(csum) -final: - .data /* * Build an entry for table of wired entries @@ -292,6 +453,11 @@ final: * following by EntryHi/EntryLo pairs and page mask. * Since everything must be quad-aligned (8) we insert * some dummy zeros. + * + * Keep in mind that the PFN does not depend on the page size in the + * TLB page mask register. See milo's lib/dumptlb.c for how to decode + * and encode these entries. Don't see the same routine in the linux + * kernel distribution, since it is older and unreliable. */ /* @@ -299,25 +465,56 @@ final: * Add your own stuff here but don't forget to define your * target system in bootinfo.h */ +/* First indirection level on the 'group' */ +map0table: PTR map0table_unknown # machgroup = unknown + PTR map0table_jazz # machgroup = JAZZ + PTR map0table_dec # machgroup = DEC + PTR map0table_arc # machgroup = ARC + PTR map0table_sni_rm # machgroup = SNI_RM + PTR map0table_acn # machgroup = ACN + .word 0 # pad + +/* table for group 'unknown' */ +map0table_unknown: PTR map0_dummy # machtype = unknown + .word 0 # pad + +/* table for group 'Jazz' */ +map0table_jazz: PTR map0_pica61 # Acer Pica-61 + PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030) + PTR map0_magnum4000 # Olivetti M700 (*same* table) + .word 0 # pad -map0table: PTR map0_dummy # machtype = unknown - PTR map0_rpc # Deskstation rPC44 +/* table for group 'Dec' */ +map0table_dec: PTR map0_dummy # DEC Personal DECStation 5000/2x (for now) + .word 0 # pad + +/* table for group 'ARC' */ +map0table_arc: PTR map0_rpc # Deskstation rPC44 PTR map0_tyne # Deskstation Tyne - PTR map0_pica61 # Acer Pica-61 - PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030) +/* table for group 'SNI_RM' */ +map0table_sni_rm: PTR map0_sni_rm200_pci # SNI RM200 PCI + .word 0 + +/* table for group 'ACN' */ +map0table_acn: PTR map0_dummy # ACN mips board + .word 0 + +/* dummy table */ map0_dummy: .word 0 # 0 entries .align 3 /* - * Initial mappings for Deskstation rPC boards. - * RB: Untested goodie - I don't have such a board. + * Deskstation rpc44 mappings. This machine has its EISA bus at physical + * address 0xa0000000 which we map for 32M, but that doesn't match EISA + * spec. Not sure what to do about this. Its I/O ports are memory mapped + * at physical memory location 0xb0000000. */ map0_rpc: .word 2 # no. of wired TLB entries .word 0 # pad for alignment -MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache -MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space +MAPDATA(0xffffffffe0000000, 0x02800017, 0x00000011, PM_16M) # ISA Memory space +MAPDATA(0xffffffffe2000000, 0x02c00017, 0x00000011, PM_64K) # ISA I/O Space /* * Initial mappings for Deskstation Tyne boards. @@ -325,23 +522,18 @@ MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memor map0_tyne: .word 2 # no. of wired TLB entries .word 0 # pad for alignment -MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache +MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000011, PM_1M) # VESA DMA cache MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space /* * Initial mapping for ACER PICA-61 boards. - * FIXME: These are rather preliminary since many drivers, such as serial, - * parallel, scsi and ethernet need some changes to distinguish between "local" - * (built-in) and "optional" (ISA/PCI) I/O hardware. Local video ram is mapped - * to the same location as the bios maps it to. Console driver has been changed - * accordingly (new video type: VIDEO_TYPE_PICA_S3). * FIXME: Remove or merge some of the mappings. */ map0_pica61: .word 7 # no. wired TLB entries .word 0 # dummy -MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # Local I/O space -MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # Interrupt source register +MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000011, PM_64K) # Local I/O space +MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000011, PM_4K) # Interrupt source register MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # Local video control MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # Extended video control MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # Local video memory (BIOS mapping) @@ -350,23 +542,27 @@ MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # PCR (???) /* * Initial mapping for Mips Magnum 4000PC systems. - * Do you believe me now that the Acer and Mips boxes are nearly the same ? :-) * FIXME: Remove or merge some of the mappings. */ - map0_magnum4000: .word 8 # no. wired TLB entries .word 0 # dummy -MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000001, 0x7e000) # 0 -MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, 0x1e000) # 1 local I/O -MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, 0) # 2 IRQ source -MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, 0x1fe000) # 3 local video ctrl -MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, 0x1fe000) # 4 ext. video ctrl -MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, 0x7fe000) # 5 local video mem. -MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, 0x1ffe000) # 6 ISA I/O and mem. -MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, 0) # 7 PCR +MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000011, PM_256K) # 0 +MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000011, PM_64K) # 1 local I/O +MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000011, PM_4K) # 2 IRQ source +MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # 3 local video ctrl +MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # 4 ext. video ctrl +MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # 5 local video mem. +MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # 6 ISA I/O and mem. +MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # 7 PCR +/* + * The RM200 doesn't need any wired entries. + */ +map0_sni_rm200_pci: + .word 0 # no. wired TLB entries + .word 0 # dummy .text @@ -374,35 +570,19 @@ MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, 0) # 7 PCR .globl swapper_pg_dir swapper_pg_dir = . + (KSEG1-KSEG0) -/* - * The page tables are initialized to only 4MB here - the final page - * tables are set up later depending on memory size. - */ .org 0x2000 - EXPORT(pg0) - - .org 0x3000 EXPORT(empty_bad_page) - .org 0x4000 + .org 0x3000 EXPORT(empty_bad_page_table) - .org 0x5000 + .org 0x4000 EXPORT(empty_zero_page) - .org 0x6000 + .org 0x5000 EXPORT(invalid_pte_table) - .org 0x7000 - -/* - * floppy_track_buffer is used to buffer one track of floppy data: it - * has to be separate from the tmp_floppy area, as otherwise a single- - * sector read/write can mess it up. It can contain one full cylinder (sic) of - * data (36*2*512 bytes). - */ - EXPORT(floppy_track_buffer) - .fill 512*2*36,1,0 + .org 0x6000 EXPORT(cache_error_buffer) .fill 32*4,1,0 diff --git a/arch/mips/kernel/ipc.c b/arch/mips/kernel/ipc.c new file mode 100644 index 000000000..336965acf --- /dev/null +++ b/arch/mips/kernel/ipc.c @@ -0,0 +1,109 @@ +/* + * linux/arch/mips/kernel/ipc.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/MIPS + * platform. + */ +#include <linux/config.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/sem.h> +#include <linux/msg.h> +#include <linux/shm.h> + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. FIXME: Get rid of this wrapper. + */ +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +{ +#ifdef CONFIG_SYSVIPC + int version; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + int err; + if (!ptr) + return -EINVAL; + if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) + return err; + get_from_user(fourth.__pad, ptr); + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + int err; + if (!ptr) + return -EINVAL; + if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) + return err; + memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp)); + return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + } + case 1: default: + return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + case 0: default: { + ulong raddr; + int err; + if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) + return err; + err = sys_shmat (first, (char *) ptr, second, &raddr); + if (err) + return err; + put_user (raddr, (ulong *) third); + return 0; + } + case 1: /* iBCS2 emulator entry point */ + if (get_fs() != get_ds()) + return -EINVAL; + return sys_shmat (first, (char *) ptr, second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, (struct shmid_ds *) ptr); + default: + return -EINVAL; + } + return -EINVAL; +#else /* CONFIG_SYSVIPC */ + return -ENOSYS; +#endif /* CONFIG_SYSVIPC */ +} diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 608a0b431..a6f257c88 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -8,125 +8,120 @@ * instead of just grabbing them. Thus setups with different IRQ numbers * shouldn't result in any weird surprises, and installing new handlers * should be easier. - */ - -/* - * IRQ's are in fact implemented a bit like signal handlers for the kernel. - * Naturally it's not a 1:1 relation, but there are similarities. - */ - -/* - * Mips support by Ralf Baechle and Andreas Busse * - * The Deskstation Tyne is almost completely like an IBM compatible PC with - * another type of microprocessor. Therefore this code is almost completely - * the same. More work needs to be done to support Acer PICA and other - * machines. + * Mips support by Ralf Baechle and Andreas Busse */ - -#include <linux/ptrace.h> #include <linux/errno.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/types.h> #include <linux/interrupt.h> +#include <linux/ioport.h> #include <linux/timex.h> +#include <linux/malloc.h> +#include <linux/random.h> #include <asm/bitops.h> #include <asm/bootinfo.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/mipsregs.h> #include <asm/jazz.h> +#include <asm/mipsregs.h> #include <asm/system.h> +#include <asm/vector.h> unsigned char cache_21 = 0xff; unsigned char cache_A1 = 0xff; unsigned long spurious_count = 0; -void disable_irq(unsigned int irq_nr) +/* + * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and + * PCI devices. Other onboard hardware needs specific routines. + */ +static inline void mask_irq(unsigned int irq_nr) { - unsigned long flags; unsigned char mask; mask = 1 << (irq_nr & 7); - save_flags(flags); if (irq_nr < 8) { - cli(); cache_21 |= mask; outb(cache_21,0x21); - restore_flags(flags); - return; + } else { + cache_A1 |= mask; + outb(cache_A1,0xA1); } - cli(); - cache_A1 |= mask; - outb(cache_A1,0xA1); - restore_flags(flags); } -void enable_irq(unsigned int irq_nr) +static inline void unmask_irq(unsigned int irq_nr) { - unsigned long flags; unsigned char mask; mask = ~(1 << (irq_nr & 7)); - save_flags(flags); if (irq_nr < 8) { - cli(); cache_21 &= mask; outb(cache_21,0x21); - restore_flags(flags); - return; + } else { + cache_A1 &= mask; + outb(cache_A1,0xA1); } +} + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_flags(flags); cli(); - cache_A1 &= mask; - outb(cache_A1,0xA1); + mask_irq(irq_nr); + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + save_flags(flags); + cli(); + unmask_irq(irq_nr); restore_flags(flags); } /* - * Pointers to the low-level handlers: first the general ones, then the - * fast ones, then the bad ones. + * Low-level interrupt handlers: first the timer interrupt, then the + * general, then the fast and finally the bad interrupt handler. */ +extern void timer_interrupt(void); extern void interrupt(void); extern void fast_interrupt(void); extern void bad_interrupt(void); -/* - * Initial irq handlers. - */ -struct irqaction { - void (*handler)(int, struct pt_regs *); - unsigned long flags; - unsigned long mask; - const char *name; -}; - -static struct irqaction irq_action[16] = { - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, - { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL } +static struct irqaction *irq_action[16] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; int get_irq_list(char *buf) { int i, len = 0; - struct irqaction * action = irq_action; + struct irqaction * action; - for (i = 0 ; i < 16 ; i++, action++) { - if (!action->handler) + for (i = 0 ; i < 16 ; i++) { + action = irq_action[i]; + if (!action) continue; - len += sprintf(buf+len, "%2d: %8d %c %s\n", + len += sprintf(buf+len, "%2d: %8u %c %s", i, kstat.interrupts[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, "\n"); } return len; } @@ -140,14 +135,17 @@ int get_irq_list(char *buf) */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { - struct irqaction * action = irq + irq_action; -#if 0 -if (irq > 0) { - printk("in do_IRQ with irq=%d\n",irq); -} -#endif + struct irqaction * action = *(irq + irq_action); + int do_random = 0; + kstat.interrupts[irq]++; - action->handler(irq, regs); + while (action) { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); } /* @@ -157,129 +155,159 @@ if (irq > 0) { */ asmlinkage void do_fast_IRQ(int irq) { - struct irqaction * action = irq + irq_action; + struct irqaction * action = *(irq + irq_action); + int do_random = 0; kstat.interrupts[irq]++; - action->handler(irq, NULL); + while (action) { + do_random |= action->flags; + action->handler(irq, action->dev_id, NULL); + action = action->next; + } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); } -#define SA_PROBE SA_ONESHOT +/* + * Used only for setup of PC style interrupts and therefore still + * called setup_x86_irq. Later on I'll provide a machine specific + * function with similar purpose. Idea is to put all interrupts + * in a single table and differenciate them just by number. + */ +int setup_x86_irq(int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); -int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *), - unsigned long irqflags, const char * devname) + save_flags(flags); + cli(); + *p = new; + + if (!shared) { + if (new->flags & SA_INTERRUPT) + set_int_vector(irq,fast_interrupt); + else + if (irq == 0) + set_int_vector(irq,timer_interrupt); + else + set_int_vector(irq,interrupt); + unmask_irq(irq); + } + restore_flags(flags); + return 0; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) { + int retval; struct irqaction * action; - unsigned long flags; if (irq > 15) return -EINVAL; - action = irq + irq_action; - if (action->handler) - return -EBUSY; if (!handler) return -EINVAL; - save_flags(flags); - cli(); + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + action->handler = handler; action->flags = irqflags; action->mask = 0; action->name = devname; - if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */ - /* - * FIXME: Does the SA_INTERRUPT flag make any sense on MIPS??? - */ - if (action->flags & SA_INTERRUPT) - set_int_vector(irq,fast_interrupt); - else - set_int_vector(irq,interrupt); - } - if (irq < 8) { - cache_21 &= ~(1<<irq); - outb(cache_21,0x21); - } else { - cache_21 &= ~(1<<2); - cache_A1 &= ~(1<<(irq-8)); - outb(cache_21,0x21); - outb(cache_A1,0xA1); - } - restore_flags(flags); - return 0; -} + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_x86_irq(irq, action); -void free_irq(unsigned int irq) + if (retval) + kfree(action); + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) { - struct irqaction * action = irq + irq_action; + struct irqaction * action, **p; unsigned long flags; if (irq > 15) { printk("Trying to free IRQ%d\n",irq); return; } - if (!action->handler) { - printk("Trying to free free IRQ%d\n",irq); + for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (!irq[irq_action]) { + mask_irq(irq); + set_int_vector(irq, bad_interrupt); + } + restore_flags(flags); + kfree(action); return; } - save_flags(flags); - cli(); - if (irq < 8) { - cache_21 |= 1 << irq; - outb(cache_21,0x21); - } else { - cache_A1 |= 1 << (irq-8); - outb(cache_A1,0xA1); - } - set_int_vector(irq,bad_interrupt); - action->handler = NULL; - action->flags = 0; - action->mask = 0; - action->name = NULL; - restore_flags(flags); + printk("Trying to free free IRQ%d\n",irq); } -static void no_action(int cpl, struct pt_regs * regs) { } - -unsigned int probe_irq_on (void) +unsigned long probe_irq_on (void) { unsigned int i, irqs = 0, irqmask; unsigned long delay; - /* first, snaffle up any unassigned irqs */ + /* first, enable any unassigned irqs */ for (i = 15; i > 0; i--) { - if (!request_irq(i, no_action, SA_PROBE, "probe")) { + if (!irq_action[i]) { enable_irq(i); irqs |= (1 << i); } } /* wait for spurious interrupts to mask themselves out again */ - for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */ + for (delay = jiffies + HZ/10; delay > jiffies; ) + /* about 100ms delay */; /* now filter out any obviously spurious interrupts */ irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; - for (i = 15; i > 0; i--) { - if (irqs & (1 << i) & irqmask) { - irqs ^= (1 << i); - free_irq(i); - } - } -#ifdef DEBUG - printk("probe_irq_on: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask); -#endif - return irqs; + return irqs & ~irqmask; } -int probe_irq_off (unsigned int irqs) +int probe_irq_off (unsigned long irqs) { unsigned int i, irqmask; irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; - for (i = 15; i > 0; i--) { - if (irqs & (1 << i)) { - free_irq(i); - } - } #ifdef DEBUG - printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask); + printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask); #endif irqs &= irqmask; if (!irqs) @@ -294,41 +322,7 @@ void init_IRQ(void) { int i; - switch (boot_info.machtype) { - case MACH_MIPS_MAGNUM_4000: - case MACH_ACER_PICA_61: - r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, - JAZZ_IE_ETHERNET | - JAZZ_IE_SERIAL1 | - JAZZ_IE_SERIAL2 | - JAZZ_IE_PARALLEL | - JAZZ_IE_FLOPPY); - r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */ - set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ1); - /* set the clock to 100 Hz */ - r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); - break; - case MACH_DESKSTATION_TYNE: - /* set the clock to 100 Hz */ - outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(LATCH & 0xff , 0x40); /* LSB */ - outb(LATCH >> 8 , 0x40); /* MSB */ - - if (request_irq(2, no_action, SA_INTERRUPT, "cascade")) - printk("Unable to get IRQ2 for cascade\n"); - break; - default: - panic("Unknown machtype in init_IRQ"); - } - for (i = 0; i < 16 ; i++) set_int_vector(i, bad_interrupt); - - /* initialize the bottom half routines. */ - for (i = 0; i < 32; i++) { - bh_base[i].routine = NULL; - bh_base[i].data = NULL; - } - bh_active = 0; - intr_count = 0; + irq_setup(); } diff --git a/arch/mips/kernel/jazzdma.c b/arch/mips/kernel/jazzdma.c deleted file mode 100644 index 1d535e716..000000000 --- a/arch/mips/kernel/jazzdma.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * jazzdma.c - * - * Mips Jazz DMA controller support - * (C) 1995 Andreas Busse - * - * NOTE: Some of the argument checkings could be removed when - * things have settled down. Also, instead of returning 0xffffffff - * on failure of vdma_alloc() one could leave page #0 unused - * and return the more usual NULL pointer as logical address. - * - */ - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <asm/mipsregs.h> -#include <asm/mipsconfig.h> -#include <asm/jazz.h> -#include <asm/io.h> -#include <asm/segment.h> -#include <asm/dma.h> -#include <asm/jazzdma.h> - - -static unsigned long vdma_pagetable_start = 0; -static unsigned long vdma_pagetable_end = 0; - -/* - * Debug stuff - */ - -#define DEBUG_VDMA 0 -#define vdma_debug ((DEBUG_VDMA) ? debuglvl : 0) - -static int debuglvl = 3; - -/* - * Local prototypes - */ - -static void vdma_pgtbl_init(void); - - -/* - * Initialize the Jazz R4030 dma controller - */ - -unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end) -{ - - /* - * Allocate 32k of memory for DMA page tables. - * This needs to be page aligned and should be - * uncached to avoid cache flushing after every - * update. - */ - - vdma_pagetable_start = KSEG1ADDR((memory_start + 4095) & ~ 4095); - vdma_pagetable_end = vdma_pagetable_start + VDMA_PGTBL_SIZE; - - - /* - * Clear the R4030 translation table - */ - - vdma_pgtbl_init(); - - r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,PHYSADDR(vdma_pagetable_start)); - r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM,VDMA_PGTBL_SIZE); - r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); - - printk("VDMA: R4030 DMA pagetables initialized.\n"); - return(KSEG0ADDR(vdma_pagetable_end)); -} - -/* - * Allocate DMA pagetables using a simple first-fit algorithm - */ - -unsigned long vdma_alloc(unsigned long paddr, unsigned long size) -{ - VDMA_PGTBL_ENTRY *entry = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; - int first; - int last; - int pages; - unsigned int frame; - unsigned long laddr; - int i; - - /* check arguments */ - - if (paddr > 0x1fffffff) { - if (vdma_debug) - printk("vdma_alloc: Invalid physical address: %08lx\n",paddr); - return (VDMA_ERROR); /* invalid physical address */ - } - if (size > 0x400000 || size == 0) { - if (vdma_debug) - printk("vdma_alloc: Invalid size: %08lx\n",size); - return (VDMA_ERROR); /* invalid physical address */ - } - - /* find free chunk */ - - pages = (size + 4095) >> 12; /* no. of pages to allocate */ - first = 0; - while (1) { - while (entry[first].owner != VDMA_PAGE_EMPTY && first < VDMA_PGTBL_ENTRIES) - first++; - if (first+pages > VDMA_PGTBL_ENTRIES) /* nothing free */ - return (VDMA_ERROR); - - last = first+1; - while (entry[last].owner == VDMA_PAGE_EMPTY && last-first < pages) - last++; - - if (last-first == pages) - break; /* found */ - } - - /* mark pages as allocated */ - - laddr = (first << 12) + (paddr & (VDMA_PAGESIZE-1)); - frame = paddr & ~(VDMA_PAGESIZE-1); - - for (i=first; i<last; i++) { - entry[i].frame = frame; - entry[i].owner = laddr; - frame += VDMA_PAGESIZE; - } - - /* - * update translation table and - * return logical start address - */ - - r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); - - if (vdma_debug > 1) - printk("vdma_alloc: Allocated %d pages starting from %08lx\n", - pages,laddr); - - if (vdma_debug > 2) { - printk("LADDR: "); - for (i=first; i<last; i++) - printk("%08x ",i<<12); - printk("\nPADDR: "); - for (i=first; i<last; i++) - printk("%08x ",entry[i].frame); - printk("\nOWNER: "); - for (i=first; i<last; i++) - printk("%08x ",entry[i].owner); - printk("\n"); - } - - return(laddr); -} - - -/* - * Free previously allocated dma translation pages - * Note that this does NOT change the translation table, - * it just marks the free'd pages as unused! - */ - -int vdma_free(unsigned long laddr) -{ - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; - int i; - - i = laddr >> 12; - - if (pgtbl[i].owner != laddr) { - printk("vdma_free: trying to free other's dma pages, laddr=%8lx\n",laddr); - return -1; - } - - while (pgtbl[i].owner == laddr && i < VDMA_PGTBL_ENTRIES) { - pgtbl[i].owner = VDMA_PAGE_EMPTY; - i++; - } - - if (vdma_debug > 1) - printk("vdma_free: freed %ld pages starting from %08lx\n", - i-(laddr>>12),laddr); - - return 0; -} - -/* - * Map certain page(s) to another physical address. - * Caller must have allocated the page(s) before. - */ - -int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size) -{ - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; - int first; - int pages; - - if (laddr > 0xffffff) { - if (vdma_debug) - printk("vdma_map: Invalid logical address: %08lx\n",laddr); - return -EINVAL; /* invalid logical address */ - } - if (paddr > 0x1fffffff) { - if (vdma_debug) - printk("vdma_map: Invalid physical address: %08lx\n",paddr); - return -EINVAL; /* invalid physical address */ - } - - pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1; - first = laddr >> 12; - if (vdma_debug) - printk("vdma_remap: first=%x, pages=%x\n",first,pages); - if (first+pages > VDMA_PGTBL_ENTRIES) { - if (vdma_debug) - printk("vdma_alloc: Invalid size: %08lx\n",size); - return -EINVAL; - } - - paddr &= ~(VDMA_PAGESIZE-1); - while (pages > 0 && first < VDMA_PGTBL_ENTRIES) { - if (pgtbl[first].owner != laddr) { - if (vdma_debug) - printk("Trying to remap other's pages.\n"); - return -EPERM; /* not owner */ - } - pgtbl[first].frame = paddr; - paddr += VDMA_PAGESIZE; - first++; - pages--; - } - - /* update translation table */ - - r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); - - - if (vdma_debug > 2) { - int i; - pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1; - first = laddr >> 12; - printk("LADDR: "); - for (i=first; i<first+pages; i++) - printk("%08x ",i<<12); - printk("\nPADDR: "); - for (i=first; i<first+pages; i++) - printk("%08x ",pgtbl[i].frame); - printk("\nOWNER: "); - for (i=first; i<first+pages; i++) - printk("%08x ",pgtbl[i].owner); - printk("\n"); - } - - return 0; -} - -/* - * Translate a physical address to a logical address. - * This will return the logical address of the first - * match. - */ - -unsigned long vdma_phys2log(unsigned long paddr) -{ - int i; - int frame; - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; - - frame = paddr & ~(VDMA_PAGESIZE-1); - - for (i=0; i<VDMA_PGTBL_ENTRIES; i++) { - if (pgtbl[i].frame == frame) - break; - } - - if (i == VDMA_PGTBL_ENTRIES) - return(0xffffffff); - - return((i<<12) + (paddr & (VDMA_PAGESIZE-1))); -} - -/* - * Translate a logical DMA address to a physical address - */ -unsigned long vdma_log2phys(unsigned long laddr) -{ - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; - - return(pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE-1))); -} - - -/* - * initialize the pagetable with a one-to-one mapping of - * the first 16 Mbytes of main memory and declare all - * entries to be unused. Using this method will at least - * allow some early device driver operations to work. - */ - -static void vdma_pgtbl_init(void) -{ - int i; - unsigned long paddr = 0; - VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start; - - for (i=0; i<VDMA_PGTBL_ENTRIES; i++) { - pgtbl[i].frame = paddr; - pgtbl[i].owner = VDMA_PAGE_EMPTY; - paddr += VDMA_PAGESIZE; - } - -/* vdma_stats(); */ -} - -/* - * Print DMA statistics - */ - -void vdma_stats(void) -{ - int i; - - printk("vdma_stats: CONFIG: %08x\n", - r4030_read_reg32(JAZZ_R4030_CONFIG)); - printk("R4030 translation table base: %08x\n", - r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE)); - printk("R4030 translation table limit: %08x\n", - r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM)); - printk("vdma_stats: INV_ADDR: %08x\n", - r4030_read_reg32(JAZZ_R4030_INV_ADDR)); - printk("vdma_stats: R_FAIL_ADDR: %08x\n", - r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR)); - printk("vdma_stats: M_FAIL_ADDR: %08x\n", - r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR)); - printk("vdma_stats: IRQ_SOURCE: %08x\n", - r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE)); - printk("vdma_stats: I386_ERROR: %08x\n", - r4030_read_reg32(JAZZ_R4030_I386_ERROR)); - printk("vdma_chnl_modes: "); - for (i=0; i<8; i++) - printk("%04x ",(unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(i<<5))); - printk("\n"); - printk("vdma_chnl_enables: "); - for (i=0; i<8; i++) - printk("%04x ",(unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(i<<5))); - printk("\n"); -} - - -/* - * DMA transfer functions - */ - -/* - * Enable a DMA channel. Also clear any error conditions. - */ -void vdma_enable(int channel) -{ - int status; - - if (vdma_debug) - printk("vdma_enable: channel %d\n",channel); - - /* - * Check error conditions first - */ - status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)); - if (status & 0x400) - printk("VDMA: Channel %d: Address error!\n",channel); - if (status & 0x200) - printk("VDMA: Channel %d: Memory error!\n",channel); - - /* - * Clear all interrupt flags - */ - r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), - R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR); - - /* - * Enable the desired channel - */ - r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), - r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) | - R4030_CHNL_ENABLE); -} - -/* - * Disable a DMA channel - */ -void vdma_disable(int channel) -{ - if (vdma_debug) - { - int status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)); - - printk("vdma_disable: channel %d\n",channel); - printk("VDMA: channel %d status: %04x (%s) mode: %02x addr: %06x count: %06x\n", - channel,status,((status & 0x600) ? "ERROR" : "OK"), - (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5)), - (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5)), - (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5))); - } - - r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), - r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) & - ~R4030_CHNL_ENABLE); - - /* - * After disabling a DMA channel a remote bus register should be - * read to ensure that the current DMA acknowledge cycle is completed. - */ - - *((volatile unsigned int *)JAZZ_DUMMY_DEVICE); -} - -/* - * Set DMA mode. This function accepts the mode values used - * to set a PC-style DMA controller. For the SCSI and FDC - * channels, we also set the default modes each time we're - * called. - * NOTE: The FAST and BURST dma modes are supported by the - * R4030 Rev. 2 and PICA chipsets only. I leave them disabled - * for now. - */ -void vdma_set_mode(int channel, int mode) -{ - if (vdma_debug) - printk("vdma_set_mode: channel %d, mode 0x%x\n",channel,mode); - - switch(channel) - { - case JAZZ_SCSI_DMA: /* scsi */ - r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5), -/* R4030_MODE_FAST | */ -/* R4030_MODE_BURST | */ - R4030_MODE_INTR_EN | - R4030_MODE_WIDTH_16 | - R4030_MODE_ATIME_80); - break; - - case JAZZ_FLOPPY_DMA: /* floppy */ - r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5), -/* R4030_MODE_FAST | */ -/* R4030_MODE_BURST | */ - R4030_MODE_INTR_EN | - R4030_MODE_WIDTH_8 | - R4030_MODE_ATIME_120); - break; - - case JAZZ_AUDIOL_DMA: - case JAZZ_AUDIOR_DMA: - printk("VDMA: Audio DMA not supported yet.\n"); - break; - - default: - printk("VDMA: vdma_set_mode() called with unsupported channel %d!\n",channel); - } - - switch(mode) - { - case DMA_MODE_READ: - r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), - r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) & - ~R4030_CHNL_WRITE); - break; - - case DMA_MODE_WRITE: - r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5), - r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) | - R4030_CHNL_WRITE); - break; - - default: - printk("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",mode); - } -} - -/* - * Set Transfer Address - */ -void vdma_set_addr(int channel, long addr) -{ - if (vdma_debug) - printk("vdma_set_addr: channel %d, addr %lx\n",channel,addr); - - r4030_write_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5),addr); -} - -/* - * Set Transfer Count - */ -void vdma_set_count(int channel, int count) -{ - if (vdma_debug) - printk("vdma_set_count: channel %d, count %08x\n",channel,(unsigned)count); - - r4030_write_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5),count); -} - -/* - * Get Residual - */ -int vdma_get_residue(int channel) -{ - int residual; - - residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5)); - - if (vdma_debug) - printk("vdma_get_residual: channel %d: residual=%d\n",channel,residual); - - return(residual); -} - - -/* end of file jazzdma.h */ diff --git a/arch/mips/kernel/ksyms.c b/arch/mips/kernel/ksyms.c new file mode 100644 index 000000000..c80bf588a --- /dev/null +++ b/arch/mips/kernel/ksyms.c @@ -0,0 +1,40 @@ +/* + * Export MIPS-specific functions needed for loadable modules. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <linux/module.h> +#include <linux/mm.h> +#include <asm/cache.h> +#include <asm/dma.h> +#include <asm/floppy.h> +#include <asm/io.h> + +static struct symbol_table arch_symbol_table = { +#include <linux/symtab_begin.h> + X(EISA_bus), + /* + * String functions + */ + X(__generic_memset_b), + X(__generic_memset_dw), + /* + * Functions to control caches. + */ + X(cacheflush), + X(fd_cacheflush), + /* + * Base address of ports for Intel style I/O. + */ + X(port_base), +#include <linux/symtab_end.h> +}; + +void arch_syms_export(void) +{ + register_symtab(&arch_symbol_table); +} diff --git a/arch/mips/kernel/magnum4000.S b/arch/mips/kernel/magnum4000.S deleted file mode 100644 index 45e62d88d..000000000 --- a/arch/mips/kernel/magnum4000.S +++ /dev/null @@ -1,261 +0,0 @@ -/* - * arch/mips/kernel/magnum4000.S - * - * Copyright (C) 1995 Waldorf Electronics - * written by Ralf Baechle and Andreas Busse - */ -#include <asm/asm.h> -#include <asm/mipsregs.h> -#include <asm/jazz.h> -#include <asm/stackframe.h> - -/* - * mips_magnum_4000_handle_int: Interrupt handler for Mips Magnum 4000 - */ - .set noreorder - - NESTED(mips_magnum_4000_handle_int, FR_SIZE, ra) - .set noat - SAVE_ALL - CLI - .set at - - /* - * Get pending interrupts - */ - mfc0 t0,CP0_CAUSE # get pending interrupts - mfc0 t1,CP0_STATUS # get enabled interrupts - and t0,t1 # isolate allowed ones - andi t0,0xff00 # isolate pending bits - beqz t0,spurious_interrupt - sll t0,16 # delay slot - - /* - * Find irq with highest priority - * FIXME: This is slow - */ - la t1,ll_vectors -1: bltz t0,2f # found pending irq - sll t0,1 - b 1b - subu t1,PTRSIZE # delay slot - - /* - * Do the low-level stuff - */ -2: lw t0,(t1) - jr t0 - nop # delay slot - END(mips_magnum_4000_handle_int) - -/* - * Used for keyboard driver's fake_keyboard_interrupt() - */ -ll_sw0: li s1,~IE_SW0 - mfc0 t0,CP0_CAUSE - and t0,s1 - mtc0 t0,CP0_CAUSE - PRINT("sw0 received...\n") - li t1,1 - b call_real - li t3,PTRSIZE # delay slot, re-map to irq level 1 - -ll_sw1: li s1,~IE_SW1 - PANIC("Unimplemented sw1 handler") - -ll_local_dma: li s1,~IE_IRQ0 - PANIC("Unimplemented local_dma handler") - -ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE -#if __mips == 3 - dsll t0,1 - ld t0,local_vector(t0) -#else /* 32 bit */ - lw t0,local_vector(t0) -#endif - jr t0 - nop - - -loc_no_irq: PANIC("Unimplemented loc_no_irq handler") -loc_sound: PANIC("Unimplemented loc_sound handler") -loc_video: PANIC("Unimplemented loc_video handler") -loc_scsi: PANIC("Unimplemented loc_scsi handler") - -/* - * Keyboard interrupt handler - */ -loc_keyboard: li s1,~JAZZ_IE_KEYBOARD - li t1,JAZZ_KEYBOARD_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # delay slot - -/* - * Ethernet interrupt handler, remapped to level 2 - */ -loc_ethernet: /* PRINT ("ethernet IRQ\n"); */ - li s1,~JAZZ_IE_ETHERNET - li t1,JAZZ_ETHERNET_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot - - -loc_mouse: PANIC("Unimplemented loc_mouse handler") - -/* - * Serial port 1 IRQ, remapped to level 3 - */ -loc_serial1: li s1,~JAZZ_IE_SERIAL1 - li t1,JAZZ_SERIAL1_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot - -/* - * Serial port 2 IRQ, remapped to level 4 - */ -loc_serial2: li s1,~JAZZ_IE_SERIAL2 - li t1,JAZZ_SERIAL2_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot - -/* - * Parallel port IRQ, remapped to level 5 - */ -loc_parallel: li s1,~JAZZ_IE_PARALLEL - li t1,JAZZ_PARALLEL_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot - -/* - * Floppy IRQ, remapped to level 6 - */ -loc_floppy: li s1,~JAZZ_IE_FLOPPY - li t1,JAZZ_FLOPPY_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot - -/* - * Now call the real handler - */ -loc_call: lui s3,%hi(intr_count) - lw t2,%lo(intr_count)(s3) - la t0,IRQ_vectors # delay slot - addiu t2,1 - sw t2,%lo(intr_count)(s3) - - /* - * Temporarily disable interrupt source - */ - lhu t2,JAZZ_IO_IRQ_ENABLE - addu t0,t3 # make ptr to IRQ handler - lw t0,(t0) - and t2,s1 # delay slot - sh t2,JAZZ_IO_IRQ_ENABLE - jalr t0 # call IRQ handler - nor s1,zero,s1 # delay slot - - /* - * Reenable interrupt - */ - lhu t2,JAZZ_IO_IRQ_ENABLE - lw t1,%lo(intr_count)(s3) # delay slot - or t2,s1 - sh t2,JAZZ_IO_IRQ_ENABLE - - subu t1,1 - jr v0 - sw t1,%lo(intr_count)(s3) - -ll_eisa_irq: li s1,~IE_IRQ2 - PANIC("Unimplemented eisa_irq handler") - -ll_eisa_nmi: li s1,~IE_IRQ3 - PANIC("Unimplemented eisa_nmi handler") - -/* - * Timer IRQ - * We remap the timer irq to be more similar to a IBM compatible - */ -ll_timer: lw t0,JAZZ_TIMER_REGISTER # timer irq cleared on read - li s1,~IE_IRQ4 - li t1,0 - b call_real - li t3,0 # delay slot, re-map to irq level 0 - -/* - * CPU count/compare IRQ (unused) - */ -ll_count: j return - mtc0 zero,CP0_COMPARE - -/* - * Now call the real handler - */ -call_real: lui s3,%hi(intr_count) - lw t2,%lo(intr_count)(s3) - la t0,IRQ_vectors # delay slot - addiu t2,1 - sw t2,%lo(intr_count)(s3) - - /* - * temporarily disable interrupt - */ - mfc0 t2,CP0_STATUS - and t2,s1 - - addu t0,t3 - lw t0,(t0) - mtc0 t2,CP0_STATUS # delay slot - jalr t0 - nor s1,zero,s1 # delay slot - - /* - * reenable interrupt - */ - mfc0 t2,CP0_STATUS - or t2,s1 - mtc0 t2,CP0_STATUS - - lw t2,%lo(intr_count)(s3) - subu t2,1 - - jr v0 - sw t2,%lo(intr_count)(s3) - -/* - * Just for debugging... - */ - LEAF(drawline) - li t1,0xffffffff - li t2,0x100 -1: sw t1,(a0) - addiu a0,a0,4 - addiu t2,t2,-1 - bnez t2,1b - nop - jr ra - nop - END(drawline) - - - .data - PTR ll_sw0 # SW0 - PTR ll_sw1 # SW1 - PTR ll_local_dma # Local DMA - PTR ll_local_dev # Local devices - PTR ll_eisa_irq # EISA IRQ - PTR ll_eisa_nmi # EISA NMI - PTR ll_timer # Timer -ll_vectors: PTR ll_count # Count/Compare IRQ - -local_vector: PTR loc_no_irq - PTR loc_parallel - PTR loc_floppy - PTR loc_sound - PTR loc_video - PTR loc_ethernet - PTR loc_scsi - PTR loc_keyboard - PTR loc_mouse - PTR loc_serial1 - PTR loc_serial2 diff --git a/arch/mips/kernel/pica.S b/arch/mips/kernel/pica.S deleted file mode 100644 index 036aa3139..000000000 --- a/arch/mips/kernel/pica.S +++ /dev/null @@ -1,252 +0,0 @@ -/* - * arch/mips/kernel/pica.S - * - * Copyright (C) 1995 Waldorf Electronics - * written by Ralf Baechle and Andreas Busse - * - * Acer PICA 61 specific stuff - */ -#include <asm/asm.h> -#include <asm/mipsregs.h> -#include <asm/jazz.h> -#include <asm/pica.h> -#include <asm/stackframe.h> - -/* - * acer_pica_61_handle_int: Interrupt handler for the ACER Pica-61 boards - * FIXME: this is *very* experimental! - */ - .set noreorder - - NESTED(acer_pica_61_handle_int, FR_SIZE, ra) - .set noat - SAVE_ALL - CLI - .set at - - /* - * Get pending interrupts - */ - mfc0 t0,CP0_CAUSE # get pending interrupts - mfc0 t1,CP0_STATUS # get enabled interrupts - and t0,t1 # isolate allowed ones - andi t0,0xff00 # isolate pending bits - beqz t0,spurious_interrupt - sll t0,16 # delay slot - - /* - * Find irq with highest priority - * FIXME: This is slow - use binary search - */ - la t1,ll_vectors -1: bltz t0,2f # found pending irq - sll t0,1 - b 1b - subu t1,PTRSIZE # delay slot - - /* - * Do the low-level stuff - */ -2: lw t0,(t1) - jr t0 - nop # delay slot - END(acer_pica_61_handle_int) - -/* - * Used for keyboard driver's fake_keyboard_interrupt() - */ -ll_sw0: li s1,~IE_SW0 - mfc0 t0,CP0_CAUSE - and t0,s1 - mtc0 t0,CP0_CAUSE - PRINT("sw0 received...\n") - li t1,1 - b call_real - li t3,PTRSIZE # delay slot, re-map to irq level 1 - -ll_sw1: li s1,~IE_SW1 - PANIC("Unimplemented sw1 handler") - -ll_local_dma: li s1,~IE_IRQ0 - PANIC("Unimplemented local_dma handler") - -ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE -#if __mips == 3 - dsll t0,1 - ld t0,local_vector(t0) -#else /* 32 bit */ - lw t0,local_vector(t0) -#endif - jr t0 - nop - - -loc_no_irq: PANIC("Unimplemented loc_no_irq handler") -/* - * Parallel port IRQ, remapped to level 5 - */ -loc_parallel: li s1,~JAZZ_IE_PARALLEL - li t1,JAZZ_PARALLEL_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot - -/* - * Floppy IRQ, remapped to level 6 - */ -loc_floppy: li s1,~JAZZ_IE_FLOPPY - li t1,JAZZ_FLOPPY_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot - -/* - * Now call the real handler - */ -loc_call: lui s3,%hi(intr_count) - lw t2,%lo(intr_count)(s3) - la t0,IRQ_vectors # delay slot - addiu t2,1 - sw t2,%lo(intr_count)(s3) - - /* - * Temporarily disable interrupt source - */ - lhu t2,JAZZ_IO_IRQ_ENABLE - addu t0,t3 # make ptr to IRQ handler - lw t0,(t0) - and t2,s1 # delay slot - sh t2,JAZZ_IO_IRQ_ENABLE - jalr t0 # call IRQ handler - nor s1,zero,s1 # delay slot - - /* - * Reenable interrupt - */ - lhu t2,JAZZ_IO_IRQ_ENABLE - lw t1,%lo(intr_count)(s3) # delay slot - or t2,s1 - sh t2,JAZZ_IO_IRQ_ENABLE - - subu t1,1 - jr v0 - sw t1,%lo(intr_count)(s3) # delay slot - -ll_isa_irq: li s1,~IE_IRQ2 - PANIC("Unimplemented isa_irq handler") - -ll_isa_nmi: li s1,~IE_IRQ3 - PANIC("Unimplemented isa_nmi handler") - -/* - * Timer IRQ - * We remap the timer irq to be more similar to an IBM compatible - */ -ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read - li s1,~IE_IRQ4 - li t1,0 - b call_real - li t3,0 # delay slot, re-map to irq level 0 - -/* - * CPU count/compare IRQ (unused) - */ -ll_count: j return - mtc0 zero,CP0_COMPARE - -/* - * Now call the real handler - */ -call_real: lui s3,%hi(intr_count) - lw t2,%lo(intr_count)(s3) - la t0,IRQ_vectors - addiu t2,1 - sw t2,%lo(intr_count)(s3) - - /* - * temporarily disable interrupt - */ - mfc0 t2,CP0_STATUS - and t2,s1 - - addu t0,t3 - lw t0,(t0) - mtc0 t2,CP0_STATUS # delay slot - jalr t0 - nor s1,zero,s1 # delay slot - - /* - * reenable interrupt - */ - mfc0 t2,CP0_STATUS - or t2,s1 - mtc0 t2,CP0_STATUS - - lw t2,%lo(intr_count)(s3) - subu t2,1 - - jr v0 - sw t2,%lo(intr_count)(s3) - - .data - PTR ll_sw0 # SW0 - PTR ll_sw1 # SW1 - PTR ll_local_dma # Local DMA - PTR ll_local_dev # Local devices - PTR ll_isa_irq # ISA IRQ - PTR ll_isa_nmi # ISA NMI - PTR ll_timer # Timer -ll_vectors: PTR ll_count # Count/Compare IRQ - - -/* - * Sound? What sound hardware (whistle) ??? - */ -loc_sound: PANIC("Unimplemented loc_sound handler") -loc_video: PANIC("Unimplemented loc_video handler") - -/* - * Ethernet interrupt handler, remapped to level 2 - */ -loc_ethernet: li s1,~JAZZ_IE_ETHERNET - li t1,JAZZ_ETHERNET_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot - -loc_scsi: PANIC("Unimplemented loc_scsi handler") - -/* - * Keyboard interrupt handler - */ -loc_keyboard: li s1,~JAZZ_IE_KEYBOARD - li t1,JAZZ_KEYBOARD_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # re-map to irq level 1 - -loc_mouse: PANIC("Unimplemented loc_mouse handler") - -/* - * Serial port 1 IRQ, remapped to level 3 - */ -loc_serial1: li s1,~JAZZ_IE_SERIAL1 - li t1,JAZZ_SERIAL1_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot - -/* - * Serial port 2 IRQ, remapped to level 4 - */ -loc_serial2: li s1,~JAZZ_IE_SERIAL2 - li t1,JAZZ_SERIAL2_IRQ - b loc_call - li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot - -local_vector: PTR loc_no_irq - PTR loc_parallel - PTR loc_floppy - PTR loc_sound - PTR loc_video - PTR loc_ethernet - PTR loc_scsi - PTR loc_keyboard - PTR loc_mouse - PTR loc_serial1 - PTR loc_serial2 diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c new file mode 100644 index 000000000..0e2803dd3 --- /dev/null +++ b/arch/mips/kernel/proc.c @@ -0,0 +1,62 @@ +/* + * linux/arch/mips/kernel/proc.c + * + * Copyright (C) 1995, 1996 Ralf Baechle + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <asm/bootinfo.h> +#include <asm/mipsregs.h> + +unsigned long dflushes = 0; +unsigned long iflushes = 0; +unsigned long unaligned_instructions; + +/* + * BUFFER is PAGE_SIZE bytes long. + * + * Currently /proc/cpuinfo is being abused to print data about the + * number of date/instruction cacheflushes. + */ +int get_cpuinfo(char *buffer) +{ + const char *cpu_name[] = CPU_NAMES; + const char *mach_group_names[] = GROUP_NAMES; + const char *mach_unknown_names[] = GROUP_UNKNOWN_NAMES; + const char *mach_jazz_names[] = GROUP_JAZZ_NAMES; + const char *mach_dec_names[] = GROUP_DEC_NAMES; + const char *mach_arc_names[] = GROUP_ARC_NAMES; + const char *mach_sni_rm_names[] = GROUP_SNI_RM_NAMES; + const char **mach_group_to_name[] = { mach_unknown_names, mach_jazz_names, + mach_dec_names, mach_arc_names, mach_sni_rm_names}; + unsigned int version = read_32bit_cp0_register(CP0_PRID); + int len; + + len = sprintf(buffer, "cpu\t\t\t: MIPS\n"); + len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n", + cpu_name[mips_cputype <= CPU_LAST ? + mips_cputype : + CPU_UNKNOWN], + (version >> 4) & 0x0f, + version & 0x0f); + len += sprintf(buffer + len, "system type\t\t: %s %s\n", + mach_group_names[mips_machgroup], + mach_group_to_name[mips_machgroup][mips_machtype]); + len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n", + (loops_per_sec + 2500) / 500000, + ((loops_per_sec + 2500) / 5000) % 100); +#if defined (__MIPSEB__) + len += sprintf(buffer + len, "byteorder\t\t: big endian\n"); +#endif +#if defined (__MIPSEL__) + len += sprintf(buffer + len, "byteorder\t\t: little endian\n"); +#endif + len += sprintf(buffer + len, "D-cache flushes\t\t: %lu\n", + dflushes); + len += sprintf(buffer + len, "I-cache flushes\t\t: %lu\n", + iflushes); + len += sprintf(buffer + len, "unaligned accesses\t: %lu\n", + unaligned_instructions); + + return len; +} diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index dd69c3208..2ce906ea4 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -2,13 +2,13 @@ * linux/arch/mips/kernel/process.c * * Copyright (C) 1995 Ralf Baechle - * written by Ralf Baechle - */ - -/* - * This file handles the architecture-dependent parts of process handling.. + * + * Modified for R3000/DECStation support by Paul M. Antoine 1995, 1996 + * + * This file handles the architecture-dependent parts of initialization, + * though it does not yet currently fully support the DECStation, + * or R3000 - PMA. */ - #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -17,13 +17,16 @@ #include <linux/unistd.h> #include <linux/ptrace.h> #include <linux/malloc.h> -#include <linux/ldt.h> +#include <linux/mman.h> +#include <linux/sys.h> #include <linux/user.h> #include <linux/a.out.h> #include <asm/bootinfo.h> -#include <asm/segment.h> +#include <asm/cache.h> +#include <asm/uaccess.h> #include <asm/pgtable.h> +#include <asm/sgidefs.h> #include <asm/system.h> #include <asm/mipsregs.h> #include <asm/processor.h> @@ -32,185 +35,111 @@ asmlinkage void ret_from_sys_call(void); -asmlinkage int sys_pipe(unsigned long * fildes) -{ - int fd[2]; - int error; - - error = verify_area(VERIFY_WRITE,fildes,8); - if (error) - return error; - error = do_pipe(fd); - if (error) - return error; - put_fs_long(fd[0],0+fildes); - put_fs_long(fd[1],1+fildes); - return 0; -} - -asmlinkage int sys_idle(void) -{ - if (current->pid != 0) - return -EPERM; - - /* endless idle loop with no priority at all */ - current->counter = -100; - for (;;) { - /* - * R4[26]00 have wait, R4[04]00 don't. - */ - if (wait_available && !need_resched) - __asm__(".set\tmips3\n\t" - "wait\n\t" - ".set\tmips0\n\t"); - schedule(); - } -} - -/* - * This routine reboots the machine by asking the keyboard - * controller to pulse the reset-line low. We try that for a while, - * and if it doesn't work, we do some other stupid things. - * Should be ok for Deskstation Tynes. Reseting others needs to be - * investigated... - */ -static inline void kb_wait(void) -{ - int i; - - for (i=0; i<0x10000; i++) - if ((inb_p(0x64) & 0x02) == 0) - break; -} - /* - * Hard reset for Deskstation Tyne - * No hint how this works on Pica boards. + * Free current thread data structures etc.. */ -void hard_reset_now(void) -{ - int i, j; - - sti(); - for (;;) { - for (i=0; i<100; i++) { - kb_wait(); - for(j = 0; j < 100000 ; j++) - /* nothing */; - outb(0xfe,0x64); /* pulse reset low */ - } - } -} - -void show_regs(struct pt_regs * regs) +void exit_thread(void) { /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, regs->reg1, regs->reg2, regs->reg3, - regs->reg4, regs->reg5, regs->reg6, regs->reg7); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg8, regs->reg9, regs->reg10, regs->reg11, - regs->reg12, regs->reg13, regs->reg14, regs->reg15); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg16, regs->reg17, regs->reg18, regs->reg19, - regs->reg20, regs->reg21, regs->reg22, regs->reg23); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - regs->reg24, regs->reg25, regs->reg28, regs->reg29, - regs->reg30, regs->reg31); - - /* - * Saved cp0 registers + * Nothing to do */ - printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n", - regs->cp0_epc, regs->cp0_status, regs->cp0_cause); } -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) +void flush_thread(void) { /* * Nothing to do */ } -void flush_thread(void) +void release_thread(struct task_struct *dead_task) { /* * Nothing to do */ } - + void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - struct task_struct * p, struct pt_regs * regs) + struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; + long childksp; + childksp = p->kernel_stack_page + KERNEL_STACK_SIZE - 8; /* * set up new TSS */ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; *childregs = *regs; - childregs->reg2 = 0; - regs->reg2 = p->pid; - childregs->reg29 = usp; - p->tss.ksp = (p->kernel_stack_page + PAGE_SIZE - 8); - p->tss.reg29 = (unsigned long) childregs; /* new sp */ - p->tss.reg31 = (unsigned long) ret_from_sys_call; + childregs->regs[2] = (__register_t) 0; /* Child gets zero as return value */ + childregs->regs[7] = (__register_t) 0; /* Clear error flag */ + regs->regs[2] = (__register_t) p->pid; + if (childregs->cp0_status & ST0_CU0) + childregs->regs[29] = (__register_t) childksp; + else + childregs->regs[29] = (__register_t) usp; + p->tss.ksp = childksp; + p->tss.reg29 = (__register_t)(long) childregs; /* new sp */ + p->tss.reg31 = (__register_t) ret_from_sys_call; + + /* + * Copy thread specific flags. + */ + p->tss.mflags = p->tss.mflags; /* * New tasks loose permission to use the fpu. This accelerates context * switching for most programs since they don't use the fpu. */ +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) p->tss.cp0_status = read_32bit_cp0_register(CP0_STATUS) & - ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU|ST0_ERL|ST0_EXL); + ~(ST0_CU3|ST0_CU2|ST0_CU1); +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) + p->tss.cp0_status = read_32bit_cp0_register(CP0_STATUS) & + ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU|ST0_ERL|ST0_EXL); +#endif childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1); } /* - * fill in the user structure for a core dump.. + * Do necessary setup to start up a newly executed thread. */ -void dump_thread(struct pt_regs * regs, struct user * dump) +extern void (*switch_to_user_mode)(struct pt_regs *regs); + +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) { + set_fs(USER_DS); + regs->cp0_epc = (__register_t) pc; /* - * To do... + * New thread loses kernel privileges. */ + switch_to_user_mode(regs); + regs->regs[29] = (__register_t) sp; + regs->regs[31] = 0; } -asmlinkage int sys_fork(struct pt_regs regs) -{ - return do_fork(COPYVM | SIGCHLD, regs.reg29, ®s); -} - -asmlinkage int sys_clone(struct pt_regs regs) +/* + * fill in the fpu structure for a core dump.. + * + * Actually this is "int dump_fpu (struct pt_regs * regs, struct user *fpu)" + */ +int dump_fpu (int shutup_the_gcc_warning_about_elf_fpregset_t) { - unsigned long clone_flags; - unsigned long newsp; + int fpvalid = 0; + /* + * To do... + */ - newsp = regs.reg4; - clone_flags = regs.reg5; - if (!newsp) - newsp = regs.reg29; - if (newsp == regs.reg29) - clone_flags |= COPYVM; - return do_fork(clone_flags, newsp, ®s); + return fpvalid; } /* - * sys_execve() executes a new program. + * fill in the user structure for a core dump.. */ -asmlinkage int sys_execve(struct pt_regs regs) +void dump_thread(struct pt_regs * regs, struct user * dump) { - int error; - char * filename; - - error = getname((char *) regs.reg4, &filename); - if (error) - return error; - error = do_execve(filename, (char **) regs.reg5, (char **) regs.reg6, ®s); - putname(filename); - return error; + /* + * To do... + */ } diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 6f35ceb67..93fae9961 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -1,7 +1,12 @@ -/* ptrace.c */ -/* By Ross Biro 1/23/92 */ -/* edited by Linus Torvalds */ - +/* + * Ptrace(2) syscall for MIPS. Based on arch/i386/kernel/ptrace.c. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996 by Ralf Baechle. + */ #include <linux/head.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -10,11 +15,10 @@ #include <linux/ptrace.h> #include <linux/user.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/system.h> -#if 0 /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -24,9 +28,6 @@ /* 1 = access 0 = no access */ #define FLAG_MASK 0x00044dd5 -/* set's the trap flag. */ -#define TRAP_FLAG 0x100 - /* * this is the number to subtract from the top of the stack. To find * the local frame. @@ -34,7 +35,8 @@ #define MAGICNUMBER 68 /* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) +static inline struct task_struct * +get_task(int pid) { int i; @@ -46,16 +48,15 @@ static inline struct task_struct * get_task(int pid) } /* - * this routine will get a word off of the processes privileged stack. - * the offset is how far from the base addr as stored in the TSS. - * this routine assumes that all the privileged stacks are in our - * data space. + * This routine will get a word off of the processes privileged stack. + * The offset is how far from the base addr as stored in the TSS. */ -static inline int get_stack_long(struct task_struct *task, int offset) +static inline int +get_stack_long(struct task_struct *task, int offset) { unsigned char *stack; - stack = (unsigned char *)task->tss.esp0; + stack = (unsigned char *)(unsigned long)task->tss.reg29; stack += offset; return (*((int *)stack)); } @@ -66,12 +67,13 @@ static inline int get_stack_long(struct task_struct *task, int offset) * this routine assumes that all the privileged stacks are in our * data space. */ -static inline int put_stack_long(struct task_struct *task, int offset, +static inline int +put_stack_long(struct task_struct *task, int offset, unsigned long data) { unsigned char * stack; - stack = (unsigned char *) task->tss.esp0; + stack = (unsigned char *)(unsigned long)task->tss.reg29; stack += offset; *(unsigned long *) stack = data; return 0; @@ -83,16 +85,19 @@ static inline int put_stack_long(struct task_struct *task, int offset, * and that it is in the task area before calling this: this routine does * no checking. */ -static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr) +static unsigned long +get_long(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr) { pgd_t * pgdir; + pmd_t * pgmiddle; pte_t * pgtable; unsigned long page; repeat: - pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr); + pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(vma, addr, 0); + do_no_page(tsk, vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -100,14 +105,23 @@ repeat: pgd_clear(pgdir); return 0; } - pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir)); + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return 0; + } + pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(vma, addr, 0); + do_no_page(tsk, vma, addr, 0); goto repeat; } - page = pte_page(*pgtable); /* this is a hack for non-kernel-mapped video buffers and similar */ - if (page >= high_memory) + if (MAP_NR(page) < max_mapnr) return 0; page += addr & ~PAGE_MASK; return *(unsigned long *) page; @@ -122,17 +136,19 @@ repeat: * Now keeps R/W state of page so that a text page stays readonly * even if a debugger scribbles breakpoints into it. -M.U- */ -static void put_long(struct vm_area_struct * vma, unsigned long addr, - unsigned long data) +static void +put_long(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr, unsigned long data) { pgd_t *pgdir; + pmd_t *pgmiddle; pte_t *pgtable; unsigned long page; repeat: - pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr); + pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(vma, addr, 1); + do_no_page(tsk, vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -140,33 +156,47 @@ repeat: pgd_clear(pgdir); return; } - pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir)); + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return; + } + pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(vma, addr, 1); + do_no_page(tsk, vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(vma, addr, 1); + do_wp_page(tsk, vma, addr, 1); goto repeat; } -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (page < high_memory) { - page += addr & ~PAGE_MASK; - *(unsigned long *) page = data; - } -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ - *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot)); - invalidate(); + /* + * This is a hack for non-kernel-mapped video buffers and similar + */ + if (page >= high_memory) + *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; + /* + * We're bypassing pagetables, so we have to set the dirty bit + * ourselves. This should also re-instate whatever read-only mode + * there was before + */ + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb(); } -static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr) +static struct vm_area_struct * +find_extend_vma(struct task_struct * tsk, unsigned long addr) { struct vm_area_struct * vma; addr &= PAGE_MASK; - vma = find_vma(tsk, addr); + vma = find_vma(tsk->mm, addr); if (!vma) return NULL; if (vma->vm_start <= addr) @@ -184,8 +214,9 @@ static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigne * This routine checks the page boundaries, and that the offset is * within the task area. It then calls get_long() to read a long. */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) +static int +read_long(struct task_struct * tsk, unsigned long addr, + unsigned long * result) { struct vm_area_struct * vma = find_extend_vma(tsk, addr); @@ -200,8 +231,8 @@ static int read_long(struct task_struct * tsk, unsigned long addr, if (!vma_high || vma_high->vm_start != vma->vm_end) return -EIO; } - low = get_long(vma, addr & ~(sizeof(long)-1)); - high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); + high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); switch (addr & (sizeof(long)-1)) { case 1: low >>= 8; @@ -218,7 +249,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr, } *result = low; } else - *result = get_long(vma, addr); + *result = get_long(tsk, vma, addr); return 0; } @@ -226,8 +257,9 @@ static int read_long(struct task_struct * tsk, unsigned long addr, * This routine checks the page boundaries, and that the offset is * within the task area. It then calls put_long() to write a long. */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) +static int +write_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) { struct vm_area_struct * vma = find_extend_vma(tsk, addr); @@ -242,8 +274,8 @@ static int write_long(struct task_struct * tsk, unsigned long addr, if (!vma_high || vma_high->vm_start != vma->vm_end) return -EIO; } - low = get_long(vma, addr & ~(sizeof(long)-1)); - high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); + high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); switch (addr & (sizeof(long)-1)) { case 0: /* shouldn't happen, but safety first */ low = data; @@ -267,23 +299,18 @@ static int write_long(struct task_struct * tsk, unsigned long addr, high |= data >> 8; break; } - put_long(vma, addr & ~(sizeof(long)-1),low); - put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); + put_long(tsk, vma, addr & ~(sizeof(long)-1),low); + put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); } else - put_long(vma, addr, data); + put_long(tsk, vma, addr, data); return 0; } -#endif -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +asmlinkage int +sys_ptrace(long request, long pid, long addr, long data) { -#if 1 - return -ENOSYS; -#else struct task_struct *child; struct user * dummy; - int i; - dummy = NULL; @@ -304,8 +331,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) return -EPERM; if ((!child->dumpable || (current->uid != child->euid) || + (current->uid != child->suid) || (current->uid != child->uid) || (current->gid != child->egid) || + (current->gid != child->sgid) || (current->gid != child->gid)) && !suser()) return -EPERM; /* the same process cannot be attached many times */ @@ -330,7 +359,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) return -ESRCH; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; @@ -341,22 +369,21 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) return res; res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); if (!res) - put_fs_long(tmp,(unsigned long *) data); + put_user(tmp, (unsigned long *)data); return res; } - /* read the word at location addr in the USER area. */ +#if 0 + /* + * Read the word at location addr in the USER area. + */ case PTRACE_PEEKUSR: { unsigned long tmp; int res; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if (addr < 0 || addr > sizeof(struct user) - 3) return -EIO; - res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); - if (res) - return res; tmp = 0; /* Default return condition */ if(addr < 17*sizeof(long)) { addr = addr >> 2; /* temporary hack. */ @@ -366,23 +393,23 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) addr == FS || addr == GS || addr == CS || addr == SS) tmp &= 0xffff; - }; - if(addr >= (long) &dummy->u_debugreg[0] && - addr <= (long) &dummy->u_debugreg[7]){ - addr -= (long) &dummy->u_debugreg[0]; - addr = addr >> 2; - tmp = child->debugreg[addr]; - }; - put_fs_long(tmp,(unsigned long *) data); + } + put_user(tmp, (unsigned long *)data); return 0; } - - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ +#endif + /* + * Write the word at location addr. + */ + case PTRACE_POKETEXT: case PTRACE_POKEDATA: return write_long(child,addr,data); - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + /* + * Write the word at location addr in the user area. + */ + case PTRACE_POKEUSR: +#if 0 if ((addr & 3) || addr < 0 || addr > sizeof(struct user) - 3) return -EIO; @@ -404,112 +431,79 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) } /* Do not allow the user to set the debug register for kernel address space */ - if(addr < 17){ + if(addr < 17) { if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data)) return -EIO; return 0; - }; - - /* We need to be very careful here. We implicitly - want to modify a portion of the task_struct, and we - have to be selective about what portions we allow someone - to modify. */ - - addr = addr << 2; /* Convert back again */ - if(addr >= (long) &dummy->u_debugreg[0] && - addr <= (long) &dummy->u_debugreg[7]){ - - if(addr == (long) &dummy->u_debugreg[4]) return -EIO; - if(addr == (long) &dummy->u_debugreg[5]) return -EIO; - if(addr < (long) &dummy->u_debugreg[4] && - ((unsigned long) data) >= 0xbffffffd) return -EIO; - - if(addr == (long) &dummy->u_debugreg[7]) { - data &= ~DR_CONTROL_RESERVED; - for(i=0; i<4; i++) - if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) - return -EIO; - }; - - addr -= (long) &dummy->u_debugreg; - addr = addr >> 2; - child->debugreg[addr] = data; - return 0; - }; + } + return -EIO; +#endif - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + /* + * Continue and stop at next (return from) syscall. + */ + case PTRACE_SYSCALL: case PTRACE_CONT: { /* restart after signal. */ - long tmp; - - if ((unsigned long) data > NSIG) + if ((unsigned long) data > _NSIG) return -EIO; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; else child->flags &= ~PF_TRACESYS; child->exit_code = data; - child->state = TASK_RUNNING; - /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + wake_up_process(child); return 0; } -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ + /* + * Make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ case PTRACE_KILL: { - long tmp; - - child->state = TASK_RUNNING; + if (child->state == TASK_ZOMBIE) /* already dead */ + return 0; + wake_up_process(child); child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); return 0; } case PTRACE_SINGLESTEP: { /* set the trap flag. */ - long tmp; + /* + * Not supported yet. + */ + return -ENOSYS; if ((unsigned long) data > NSIG) return -EIO; - child->flags &= ~PF_TRACESYS; - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); - child->state = TASK_RUNNING; + wake_up_process(child); child->exit_code = data; - /* give it a chance to run. */ + /* + * give it a chance to run. + */ return 0; } case PTRACE_DETACH: { /* detach a process that was attached. */ - long tmp; - if ((unsigned long) data > NSIG) return -EIO; child->flags &= ~(PF_PTRACED|PF_TRACESYS); - child->state = TASK_RUNNING; + wake_up_process(child); child->exit_code = data; REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); - /* make sure the single step bit is not set. */ - tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; - put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); return 0; } default: return -EIO; } -#endif } -asmlinkage void syscall_trace(void) +asmlinkage void +syscall_trace(void) { if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index f5037fbd7..30304abda 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -2,10 +2,12 @@ * linux/arch/mips/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1995 Ralf Baechle + * Copyright (C) 1995, 1996 Ralf Baechle + * Copyright (C) 1996 Stoned Elipot */ - +#include <linux/config.h> #include <linux/errno.h> +#include <linux/ioport.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> @@ -14,15 +16,20 @@ #include <linux/unistd.h> #include <linux/ptrace.h> #include <linux/malloc.h> -#include <linux/ldt.h> #include <linux/user.h> +#include <linux/utsname.h> #include <linux/a.out.h> #include <linux/tty.h> +#ifdef CONFIG_BLK_DEV_RAM +#include <linux/blk.h> +#endif #include <asm/asm.h> #include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/io.h> #include <asm/vector.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/stackframe.h> #include <asm/system.h> @@ -31,177 +38,256 @@ */ struct feature *feature; -#ifdef CONFIG_ACER_PICA_61 -void acer_pica_61_handle_int(void); -struct feature acer_pica_61_feature = { - acer_pica_61_handle_int -}; -#endif -#ifdef CONFIG_DECSTATION -void decstation_handle_handle_int(void); -struct feature decstation_feature = { - decstation_handle_handle_int -}; -#endif -#ifdef CONFIG_DESKSTATION_RPC44 -void deskstation_rpc44_handle_int(void); -struct feature deskstation_rpc44_feature = { - deskstation_rpc44_handle_int -}; -#endif -#ifdef CONFIG_DESKSTATION_TYNE -void deskstation_tyne_handle_int(void); -struct feature deskstation_tyne_feature = { - deskstation_tyne_handle_int -}; -#endif -#ifdef CONFIG_MIPS_MAGNUM_4000 -void mips_magnum_4000_handle_int(void); -struct feature mips_magnum_4000_feature = { - mips_magnum_4000_handle_int -}; -#endif +/* + * What to do to keep the caches consistent with memory + * We don't use the normal cacheflush routine to keep Tyne caches happier. + */ +void (*fd_cacheflush)(const void *addr, size_t size); /* - * Tell us the machine setup.. + * Not all of the MIPS CPUs have the "wait" instruction available. This + * is set to true if it is available. The wait instruction stops the + * pipeline and reduces the power consumption of the CPU very much. */ -char wait_available; /* set if the "wait" instruction available */ +char wait_available; /* - * Bus types .. + * There are several bus types available for MIPS machines. "RISC PC" + * type machines have ISA, EISA or PCI available, some DECstations have + * Turbochannel, SGI has GIO, there are lots of VME boxes ... + * This flag is set if a EISA slots are available. */ int EISA_bus = 0; /* - * Setup options + * Do a hardware reset. */ -struct drive_info_struct drive_info; -struct screen_info screen_info = SCREEN_INFO; +void (*hard_reset_now)(void); + +/* + * Milo passes some information to the kernel that looks like as if it + * had been returned by a Intel PC BIOS. Milo doesn't fill the passed + * drive_info and Linux can find out about this anyway, so I'm going to + * remove this sometime. screen_info contains information about the + * resolution of the text screen. For VGA graphics based machine this + * information is being use to continue the screen output just below + * the BIOS printed text and with the same text resolution. + */ +struct drive_info_struct drive_info = DEFAULT_DRIVE_INFO; +struct screen_info screen_info = DEFAULT_SCREEN_INFO; + +/* + * setup informations + * + * These are intialized so they are in the .data section + */ +unsigned long mips_memory_upper = KSEG0; /* this is set by kernel_entry() */ +unsigned long mips_cputype = CPU_UNKNOWN; +unsigned long mips_machtype = MACH_UNKNOWN; /* this is set by bi_EarlySnarf() */ +unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; /* this is set by bi_EarlySnarf() */ +unsigned long mips_tlb_entries = 48; /* this is set by bi_EarlySnarf() */ +unsigned long mips_vram_base = KSEG0; -unsigned char aux_device_present; -extern int ramdisk_size; extern int root_mountflags; extern int _end; extern char empty_zero_page[PAGE_SIZE]; /* - * Initialise this structure so that it will be placed in the - * .data section of the object file - */ -struct bootinfo boot_info = BOOT_INFO; - -/* * This is set up by the setup-routine at boot-time */ #define PARAM empty_zero_page -#if 0 -#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC)) -#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF)) -#endif +#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) +#define INITRD_START (*(unsigned long *) (PARAM+0x218)) +#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) static char command_line[CL_SIZE] = { 0, }; + char saved_command_line[CL_SIZE]; -#if 0 /* - * Code for easy access to new style bootinfo - * - * Parameter: tag -- taglist entry - * - * returns : (tag *) -- pointer to taglist entry, NULL for not found + * The board specific setup routine sets irq_setup to point to a board + * specific setup routine. */ -tag * -bi_TagFind(enum bi_tag tag) +void (*irq_setup)(void); + +static void default_irq_setup(void) { - /* TBD */ - return 0; + panic("Unknown machtype in init_IRQ"); } -/* - * Only for taglist creators (bootloaders) - * - * Parameter: tag -- (enum bi_tag) taglist entry - * - * returns : 1 -- success - * 0 -- failure - */ -int -bi_TagAdd(enum bi_tag tag, unsigned long size, void *tagdata) +static void default_fd_cacheflush(const void *addr, size_t size) { - /* TBD */ - return 0; } -#endif /* 0 */ -void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +static asmlinkage void +default_cacheflush(unsigned long addr, unsigned long nbytes, unsigned int flags) { - unsigned long memory_start, memory_end; + /* + * Someone didn't set his cacheflush() handler ... + */ + panic("default_cacheflush() called.\n"); +} +asmlinkage void (*cacheflush)(unsigned long addr, unsigned long nbytes, unsigned int flags) = default_cacheflush; - switch(boot_info.machtype) - { -#ifdef CONFIG_ACER_PICA_61 - case MACH_ACER_PICA_61: - feature = &acer_pica_61_feature; +static __inline__ void +cpu_init(void) +{ + asmlinkage void handle_reserved(void); + void mips1_cpu_init(void); + void mips2_cpu_init(void); + void mips3_cpu_init(void); + void mips4_cpu_init(void); + int i; + + /* + * Setup default vectors + */ + for (i=0;i<=31;i++) + set_except_vector(i, handle_reserved); + + switch(mips_cputype) { +#ifdef CONFIG_CPU_R3000 + case CPU_R2000: case CPU_R3000: case CPU_R3000A: case CPU_R3041: + case CPU_R3051: case CPU_R3052: case CPU_R3081: case CPU_R3081E: + mips1_cpu_init(); + break; +#endif +#ifdef CONFIG_CPU_R6000 + case CPU_R6000: case CPU_R6000A: + mips2_cpu_init(); break; #endif -#ifdef CONFIG_DECSTATION - case MACH_DECSTATION: - feature = &decstation_feature; +#ifdef CONFIG_CPU_R4X00 + case CPU_R4000MC: case CPU_R4400MC: case CPU_R4000SC: + case CPU_R4400SC: case CPU_R4000PC: case CPU_R4400PC: + case CPU_R4200: case CPU_R4300: /* case CPU_R4640: */ + case CPU_R4600: case CPU_R4700: + mips3_cpu_init(); break; #endif -#ifdef CONFIG_DESKSTATION_RPC - case MACH_DESKSTATION_RPC: - feature = &deskstation_rpc44_feature; +#ifdef CONFIG_CPU_R8000 + case CPU_R8000: case CPU_R5000: + printk("Detected unsupported CPU type %s.\n", + cpu_names[mips_cputype]); + panic("Can't handle CPU"); break; #endif -#ifdef CONFIG_DESKSTATION_TYNE - case MACH_DESKSTATION_TYNE: - feature = &deskstation_tyne_feature; +#ifdef CONFIG_CPU_R10000 + case CPU_R10000: + mips4_cpu_init(); +#endif + case CPU_UNKNOWN: + default: + panic("Unknown or unsupported CPU type"); + } +} + +void setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) +{ + unsigned long memory_end; + tag* atag; + void decstation_setup(void); + void deskstation_setup(void); + void jazz_setup(void); + void sni_rm200_pci_setup(void); + + /* Perhaps a lot of tags are not getting 'snarfed' - */ + /* please help yourself */ + + atag = bi_TagFind(tag_cputype); + memcpy(&mips_cputype, TAGVALPTR(atag), atag->size); + + cpu_init(); + + atag = bi_TagFind(tag_vram_base); + memcpy(&mips_vram_base, TAGVALPTR(atag), atag->size); + + irq_setup = default_irq_setup; + fd_cacheflush = default_fd_cacheflush; + + switch(mips_machgroup) + { +#ifdef CONFIG_MIPS_DECSTATION + case MACH_GROUP_DEC: + decstation_setup(); break; #endif -#ifdef CONFIG_MIPS_MAGNUM_4000 - case MACH_MIPS_MAGNUM_4000: - feature = &mips_magnum_4000_feature; +#if defined(CONFIG_MIPS_ARC) +/* Perhaps arch/mips/deskstation should be renommed arch/mips/arc. + * For now CONFIG_MIPS_ARC means DeskStation. -Stoned. + */ + case MACH_GROUP_ARC: + deskstation_setup(); + break; +#endif +#ifdef CONFIG_MIPS_JAZZ + case MACH_GROUP_JAZZ: + jazz_setup(); + break; +#endif +#ifdef CONFIG_SNI_RM200_PCI + case MACH_GROUP_SNI_RM: + sni_rm200_pci_setup(); break; #endif default: panic("Unsupported architecture"); } -#if 0 - ROOT_DEV = ORIG_ROOT_DEV; -#else - ROOT_DEV = 0x021c; /* fd0H1440 */ -/* ROOT_DEV = 0x0101; */ /* ram */ -/* ROOT_DEV = 0x00ff; */ /* NFS */ + atag = bi_TagFind(tag_drive_info); + memcpy(&drive_info, TAGVALPTR(atag), atag->size); + + memory_end = mips_memory_upper; + /* + * Due to prefetching and similar mechanism the CPU sometimes + * generates addresses beyond the end of memory. We leave the size + * of one cache line at the end of memory unused to make shure we + * don't catch this type of bus errors. + */ + memory_end -= 32; + memory_end &= PAGE_MASK; + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif - memcpy(&drive_info, &boot_info.drive_info, sizeof(drive_info)); -#if 0 - aux_device_present = AUX_DEVICE_INFO; +#ifdef CONFIG_MAX_16M + /* + * There is a quite large number of different PC chipset based boards + * available and so I include this option here just in case ... + */ + if (memory_end > PAGE_OFFSET + 16*1024*1024) + memory_end = PAGE_OFFSET + 16*1024*1024; #endif - memory_end = boot_info.memupper; - memory_end &= PAGE_MASK; - ramdisk_size = boot_info.ramdisk_size; - if (boot_info.mount_root_rdonly) - root_mountflags |= MS_RDONLY; - memory_start = (unsigned long) &_end; - memory_start += (ramdisk_size << 10); + atag= bi_TagFind(tag_screen_info); + if (atag) + memcpy(&screen_info, TAGVALPTR(atag), atag->size); + + atag = bi_TagFind(tag_command_line); + if (atag) + memcpy(&command_line, TAGVALPTR(atag), atag->size); + printk("Command line: '%s'\n", command_line); + + memcpy(saved_command_line, command_line, CL_SIZE); + saved_command_line[CL_SIZE-1] = '\0'; *cmdline_p = command_line; - *memory_start_p = memory_start; + *memory_start_p = (unsigned long) &_end; *memory_end_p = memory_end; -#if 0 - /* - * Check that struct pt_regs is defined properly - * (Should be optimized away, but gcc 2.6.3 is too bad..) - */ - if (FR_SIZE != sizeof(struct pt_regs) || - FR_SIZE & 7) - { - panic("Check_definition_of_struct_pt_regs\n"); +#ifdef CONFIG_BLK_DEV_INITRD + if (LOADER_TYPE) { + initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; + initrd_end = initrd_start+INITRD_SIZE; + if (initrd_end > memory_end) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,memory_end); + initrd_start = 0; + } } #endif } diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index ea00551a9..b744823b1 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -2,8 +2,8 @@ * linux/arch/mips/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1994, 1995, 1996 Ralf Baechle */ - #include <linux/sched.h> #include <linux/mm.h> #include <linux/kernel.h> @@ -13,158 +13,305 @@ #include <linux/ptrace.h> #include <linux/unistd.h> -#include <asm/segment.h> -#include <asm/cachectl.h> +#include <asm/asm.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/cache.h> +#include <asm/mipsconfig.h> +#include <asm/sgidefs.h> + +/* + * Linux/MIPS misstreats the SA_NOMASK flag for signal handlers. + * Actually this is a bug in libc that was made visible by the POSIX.1 + * changes in Linux/MIPS 2.0.1. To keep old binaries alive enable + * this define but note that this is just a hack with sideeffects, not a + * perfect compatibility mode. This will go away, so rebuild your + * executables with libc 960709 or newer. + */ +#define CONF_NOMASK_BUG_COMPAT #define _S(nr) (1<<((nr)-1)) #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); + +asmlinkage void (*save_fp_context)(struct sigcontext *sc); +extern asmlinkage void (*restore_fp_context)(struct sigcontext *sc); + +asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) +{ + k_sigset_t new_set, old_set = current->blocked; + + if (set) { + if (!access_ok(VERIFY_READ, set, sizeof(sigset_t))) + return -EFAULT; + + __get_user(new_set, to_k_sigset_t(set)); + new_set &= _BLOCKABLE; + + switch (how) { + case SIG_BLOCK: + current->blocked |= new_set; + break; + case SIG_UNBLOCK: + current->blocked &= ~new_set; + break; + case SIG_SETMASK: + current->blocked = new_set; + break; + /* + * SGI goodie: Just set the low 32 bits of 'blocked' even + * for 128 bit sigset_t. + */ + case SIG_SETMASK32: + current->blocked = new_set; + break; + default: + return -EINVAL; + } + } + if (oset) { + if(!access_ok(VERIFY_WRITE, oset, sizeof(sigset_t))) + return -EFAULT; + __put_user(old_set, &oset->__sigbits[0]); + __put_user(0, &oset->__sigbits[1]); + __put_user(0, &oset->__sigbits[2]); + __put_user(0, &oset->__sigbits[3]); + } + + return 0; +} /* - * atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) +asmlinkage int sys_sigsuspend(struct pt_regs *regs) { - unsigned long mask; - struct pt_regs * regs = (struct pt_regs *) &restart; + unsigned int mask; + sigset_t *uset; + k_sigset_t kset; mask = current->blocked; - current->blocked = set & _BLOCKABLE; - regs->reg2 = -EINTR; + uset = (sigset_t *)(long) regs->regs[4]; + if (!access_ok(VERIFY_READ, uset, sizeof(sigset_t))) + return -EFAULT; + + __get_user(kset, to_k_sigset_t(uset)); + + current->blocked = kset & _BLOCKABLE; + regs->regs[2] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask,regs)) + if (do_signal(mask, regs)) return -EINTR; } + + return -EINTR; } -/* - * This sets regs->reg29 even though we don't actually use sigstacks yet.. - */ -asmlinkage int sys_sigreturn(unsigned long __unused) +asmlinkage int sys_sigreturn(struct pt_regs *regs) { - struct sigcontext_struct context; - struct pt_regs * regs; + struct sigcontext *context; + int i; - regs = (struct pt_regs *) &__unused; - if (verify_area(VERIFY_READ, (void *) regs->reg29, sizeof(context))) + /* + * We don't support fixing ADEL/ADES exceptions for signal stack frames. + * No big loss - who doesn't care about the alignment of this stack + * really deserves to loose. + */ + context = (struct sigcontext *)(long) regs->regs[29]; + if (!access_ok(VERIFY_READ, context, sizeof(struct sigcontext)) || + (regs->regs[29] & (SZREG - 1))) goto badframe; - memcpy_fromfs(&context,(void *) regs->reg29, sizeof(context)); - current->blocked = context.oldmask & _BLOCKABLE; - regs->reg1 = context.sc_at; - regs->reg2 = context.sc_v0; - regs->reg3 = context.sc_v1; - regs->reg4 = context.sc_a0; - regs->reg5 = context.sc_a1; - regs->reg6 = context.sc_a2; - regs->reg7 = context.sc_a3; - regs->reg8 = context.sc_t0; - regs->reg9 = context.sc_t1; - regs->reg10 = context.sc_t2; - regs->reg11 = context.sc_t3; - regs->reg12 = context.sc_t4; - regs->reg13 = context.sc_t5; - regs->reg14 = context.sc_t6; - regs->reg15 = context.sc_t7; - regs->reg16 = context.sc_s0; - regs->reg17 = context.sc_s1; - regs->reg18 = context.sc_s2; - regs->reg19 = context.sc_s3; - regs->reg20 = context.sc_s4; - regs->reg21 = context.sc_s5; - regs->reg22 = context.sc_s6; - regs->reg23 = context.sc_s7; - regs->reg24 = context.sc_t8; - regs->reg25 = context.sc_t9; + + current->blocked = context->sc_sigset.__sigbits[0] & _BLOCKABLE; + regs->cp0_epc = context->sc_pc; +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + for(i = 31;i >= 0;i--) + __get_user(regs->regs[i], &context->sc_regs[i]); +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) /* - * Skip k0/k1 + * We only allow user processes in 64bit mode (n32, 64 bit ABI) to + * restore the upper half of registers. */ - regs->reg28 = context.sc_gp; - regs->reg29 = context.sc_sp; - regs->reg30 = context.sc_fp; - regs->reg31 = context.sc_ra; - regs->cp0_epc = context.sc_epc; - regs->cp0_cause = context.sc_cause; + if (read_32bit_cp0_register(CP0_STATUS) & ST0_UX) + for(i = 31;i >= 0;i--) + __get_user(regs->regs[i], &context->sc_regs[i]); + else + for(i = 31;i >= 0;i--) { + __get_user(regs->regs[i], &context->sc_regs[i]); + regs->regs[i] = (int) regs->regs[i]; + } +#endif + __get_user(regs->hi, &context->sc_mdhi); + __get_user(regs->lo, &context->sc_mdlo); + restore_fp_context(context); /* - * disable syscall checks + * Disable syscall checks */ regs->orig_reg2 = -1; - return regs->orig_reg2; + + /* + * Don't let your children do this ... + */ + asm( "move\t$29,%0\n\t" + "j\tret_from_sys_call" + :/* no outputs */ + :"r" (regs)); + /* Unreached */ + badframe: do_exit(SIGSEGV); } /* * Set up a signal frame... + * + * This routine is somewhat complicated by the fact that if the kernel may be + * entered by an exception other than a system call; e.g. a bus error or other + * "bad" exception. If this is the case, then *all* the context on the kernel + * stack frame must be saved. + * + * For a large number of exceptions, the stack frame format is the same + * as that which will be created when the process traps back to the kernel + * when finished executing the signal handler. In this case, nothing + * must be done. This information is saved on the user stack and restored + * when the signal handler is returned. + * + * The signal handler will be called with ra pointing to code1 (see below) and + * signal number and pointer to the saved sigcontext as the two parameters. + * + * usp -> [unused] ; first free word on stack + * arg save space ; 16/32 bytes arg. save space + * code1 (addiu sp,#1-offset) ; pop stackframe + * code2 (li v0,__NR_sigreturn) ; syscall number + * code3 (syscall) ; do sigreturn(2) + * #1| $0, at, v0, v1, a0, a1, a2, a3 ; All integer registers + * | t0, t1, t2, t3, t4, t5, t6, t7 ; $0, k0 and k1 are placeholders + * | s0, s1, s2, s3, s4, s5, s6, s7 + * | k0, k1, t8, t9, gp, sp, fp, ra; + * | epc ; old program counter + * | cause ; CP0 cause register + * | oldmask */ -static void setup_frame(struct sigaction * sa, unsigned long ** fp, - unsigned long pc, struct pt_regs *regs, + +struct sc { + unsigned long ass[4]; + unsigned int code[4]; + struct sigcontext scc; +}; +#define scc_offset ((size_t)&((struct sc *)0)->scc) + +static void setup_frame(struct sigaction * sa, struct pt_regs *regs, int signr, unsigned long oldmask) { - unsigned long * frame; + struct sc *frame; + struct sigcontext *sc; + int i; + + frame = (struct sc *) (long) regs->regs[29]; + frame--; - frame = *fp; - frame -= 32; - if (verify_area(VERIFY_WRITE,frame,21*4)) - do_exit(SIGSEGV); - /* - * set up the "normal" stack seen by the signal handler - */ - put_fs_long(regs->reg1 , frame ); - put_fs_long(regs->reg2 , frame+ 1); - put_fs_long(regs->reg3 , frame+ 2); - put_fs_long(regs->reg4 , frame+ 3); - put_fs_long(regs->reg5 , frame+ 4); - put_fs_long(regs->reg6 , frame+ 5); - put_fs_long(regs->reg7 , frame+ 6); - put_fs_long(regs->reg8 , frame+ 7); - put_fs_long(regs->reg9 , frame+ 8); - put_fs_long(regs->reg10, frame+ 9); - put_fs_long(regs->reg11, frame+10); - put_fs_long(regs->reg12, frame+11); - put_fs_long(regs->reg13, frame+12); - put_fs_long(regs->reg14, frame+13); - put_fs_long(regs->reg15, frame+14); - put_fs_long(regs->reg16, frame+15); - put_fs_long(regs->reg17, frame+16); - put_fs_long(regs->reg18, frame+17); - put_fs_long(regs->reg19, frame+18); - put_fs_long(regs->reg20, frame+19); - put_fs_long(regs->reg21, frame+20); - put_fs_long(regs->reg22, frame+21); - put_fs_long(regs->reg23, frame+22); - put_fs_long(regs->reg24, frame+23); - put_fs_long(regs->reg25, frame+24); /* - * Don't copy k0/k1 + * We realign the stack to an adequate boundary for the architecture. + * The assignment to sc had to be moved over the if to prevent + * GCC from throwing warnings. */ - put_fs_long(regs->reg28, frame+25); - put_fs_long(regs->reg29, frame+26); - put_fs_long(regs->reg30, frame+27); - put_fs_long(regs->reg31, frame+28); - put_fs_long(pc , frame+29); - put_fs_long(oldmask , frame+30); + frame = (struct sc *)((unsigned long)frame & ALMASK); + sc = &frame->scc; + if (!access_ok(VERIFY_WRITE, frame, sizeof (struct sc))) { + do_exit(SIGSEGV); + return; + } + /* - * set up the return code... + * Set up the return code ... * * .set noreorder - * .set noat - * syscall + * addiu sp,24 * li v0,__NR_sigreturn - * .set at + * syscall * .set reorder */ - put_fs_long(0x24020077, frame+31); /* li $2,119 */ - put_fs_long(0x000000c0, frame+32); /* syscall */ - *fp = frame; + __put_user(0x27bd0000 + scc_offset, &frame->code[0]); + __put_user(0x24020000 + __NR_sigreturn, &frame->code[1]); + __put_user(0x0000000c, &frame->code[2]); + + /* + * Flush caches so that the instructions will be correctly executed. + */ + cacheflush((unsigned long)frame->code, sizeof (frame->code), + CF_BCACHE|CF_ALL); + /* - * Flush caches so the instructions will be correctly executed. + * Set up the "normal" sigcontext */ - sys_cacheflush(frame, 32*4, BCACHE); + sc->sc_pc = regs->cp0_epc; /* Program counter */ + sc->sc_status = regs->cp0_status; /* Status register */ + for(i = 31;i >= 0;i--) + __put_user(regs->regs[i], &sc->sc_regs[i]); + save_fp_context(sc); + __put_user(regs->hi, &sc->sc_mdhi); + __put_user(regs->lo, &sc->sc_mdlo); + __put_user(regs->cp0_cause, &sc->sc_cause); + __put_user((regs->cp0_status & ST0_CU0) != 0, &sc->sc_ownedfp); + __put_user(oldmask, &sc->sc_sigset.__sigbits[0]); + __put_user(0, &sc->sc_sigset.__sigbits[1]); + __put_user(0, &sc->sc_sigset.__sigbits[2]); + __put_user(0, &sc->sc_sigset.__sigbits[3]); + + regs->regs[4] = signr; /* Args for handler */ + regs->regs[5] = (long) frame; /* Ptr to sigcontext */ + regs->regs[29] = (unsigned long) frame; /* Stack pointer */ + regs->regs[31] = (unsigned long) frame->code; /* Return address */ + regs->cp0_epc = regs->regs[25] /* "return" to the first handler */ + = (unsigned long) sa->sa_handler; +} + +/* + * OK, we're invoking a handler + */ +static inline void +handle_signal(unsigned long signr, struct sigaction *sa, + unsigned long oldmask, struct pt_regs * regs) +{ + /* are we from a failed system call? */ + if (regs->orig_reg2 >= 0 && regs->regs[7]) { + /* If so, check system call restarting.. */ + switch (regs->regs[2]) { + case ERESTARTNOHAND: + regs->regs[2] = EINTR; + break; + + case ERESTARTSYS: + if (!(sa->sa_flags & SA_RESTART)) { + regs->regs[2] = EINTR; + break; + } + /* fallthrough */ + case ERESTARTNOINTR: + regs->regs[7] = regs->orig_reg7; + regs->cp0_epc -= 8; + } + } + + /* set up the stack frame */ + setup_frame(sa, regs, signr, oldmask); + + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; +#ifdef CONF_NOMASK_BUG_COMPAT + current->blocked |= *to_k_sigset_t(&sa->sa_mask); +#else + if (!(sa->sa_flags & SA_NOMASK)) + current->blocked |= (*to_k_sigset_t(&sa->sa_mask) | + _S(signr)) & _BLOCKABLE; +#endif } /* @@ -179,16 +326,13 @@ static void setup_frame(struct sigaction * sa, unsigned long ** fp, asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) { unsigned long mask = ~current->blocked; - unsigned long handler_signal = 0; - unsigned long *frame = NULL; - unsigned long pc = 0; unsigned long signr; struct sigaction * sa; while ((signr = current->signal & mask)) { signr = ffz(~signr); clear_bit(signr, ¤t->signal); - sa = current->sigaction + signr; + sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; @@ -204,7 +348,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) current->signal |= _S(signr); continue; } - sa = current->sigaction + signr - 1; + sa = current->sig->action + signr - 1; } if (sa->sa_handler == SIG_IGN) { if (signr != SIGCHLD) @@ -221,19 +365,23 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & SA_NOCLDSTOP)) notify_parent(current); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) signr |= 0x80; @@ -241,55 +389,33 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) /* fall through */ default: current->signal |= _S(signr & 0x7f); + current->flags |= PF_SIGNALED; do_exit(signr); } } - /* - * OK, we're invoking a handler - */ - if (regs->orig_reg2 >= 0) { - if (regs->reg2 == -ERESTARTNOHAND || - (regs->reg2 == -ERESTARTSYS && - !(sa->sa_flags & SA_RESTART))) - regs->reg2 = -EINTR; - } - handler_signal |= 1 << (signr-1); - mask &= ~sa->sa_mask; + handle_signal(signr, sa, oldmask, regs); + return 1; } - if (regs->orig_reg2 >= 0 && - (regs->reg2 == -ERESTARTNOHAND || - regs->reg2 == -ERESTARTSYS || - regs->reg2 == -ERESTARTNOINTR)) { - regs->reg2 = regs->orig_reg2; - regs->cp0_epc -= 4; - } - if (!handler_signal) /* no handler will be called - return 0 */ - return 0; - pc = regs->cp0_epc; - frame = (unsigned long *) regs->reg29; - signr = 1; - sa = current->sigaction; - for (mask = 1 ; mask ; sa++,signr++,mask += mask) { - if (mask > handler_signal) - break; - if (!(mask & handler_signal)) - continue; - setup_frame(sa,&frame,pc,regs,signr,oldmask); - pc = (unsigned long) sa->sa_handler; - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - /* - * force a kernel-mode page-in of the signal - * handler to reduce races - */ - __asm__("lw\t$0,(%0)" - : /* no output */ - :"r" ((char *) pc)); - current->blocked |= sa->sa_mask; - oldmask |= sa->sa_mask; + + /* Did we come from a system call? */ + if (regs->orig_reg2 >= 0) { + /* Restart the system call - no handlers present */ + if (regs->regs[2] == -ERESTARTNOHAND || + regs->regs[2] == -ERESTARTSYS || + regs->regs[2] == -ERESTARTNOINTR) { + regs->regs[2] = regs->orig_reg2; + regs->cp0_epc -= 8; + } } - regs->reg29 = (unsigned long) frame; - regs->cp0_epc = pc; /* "return" to the first handler */ + return 0; +} - return 1; +/* + * The signal(2) syscall is no longer available in the kernel + * because GNU libc doesn't use it. Maybe I'll add it back to the + * kernel for the binary compatibility stuff. + */ +asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler) +{ + return -ENOSYS; } diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c new file mode 100644 index 000000000..144a3c905 --- /dev/null +++ b/arch/mips/kernel/syscall.c @@ -0,0 +1,280 @@ +/* + * MIPS specific syscall handling functions and syscalls + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996 by Ralf Baechle + * + * TODO: Implement the compatibility syscalls. + * Don't waste that much memory for empty entries in the syscall + * table. + */ +#undef CONF_PRINT_SYSCALLS + +#include <linux/linkage.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/sched.h> +#include <linux/unistd.h> +#include <asm/branch.h> +#include <asm/ptrace.h> +#include <asm/uaccess.h> +#include <asm/signal.h> + +extern asmlinkage void syscall_trace(void); +typedef asmlinkage int (*syscall_t)(void *a0,...); +extern asmlinkage int do_syscalls(struct pt_regs *regs, syscall_t fun, + int narg); +extern syscall_t sys_call_table[]; +extern unsigned char sys_narg_table[]; + +/* + * The pipe syscall has a unusual calling convention. We return the two + * filedescriptors in the result registers v0/v1. The syscall wrapper + * from libc places these results in the array to which the argument of + * pipe points to. This is like other MIPS operating systems and unlike + * Linux/i386 where the kernel itself places the results in the file + * descriptor array itself. This calling convention also has the advantage + * of lower overhead because we don't need to call verify_area. + */ +asmlinkage int sys_pipe(struct pt_regs *regs) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (error) + return error; + regs->regs[3] = fd[1]; + return fd[0]; +} + +asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, + int flags, int fd, off_t offset) +{ + struct file * file = NULL; + + if (!(flags & MAP_ANONYMOUS)) { + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + return do_mmap(file, addr, len, prot, flags, offset); +} + +asmlinkage int sys_idle(void) +{ + if (current->pid != 0) + return -EPERM; + + /* endless idle loop with no priority at all */ + current->counter = -100; + for (;;) { + /* + * Not all MIPS R-series CPUs have the wait instruction. + * FIXME: We should save power by reducing the clock where + * possible. + */ + if (wait_available && !need_resched) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0\n\t"); + schedule(); + } +} + +#if 0 +/* + * RISC/os compatible SysV flavoured fork(2) syscall. + * + * This call has a different calling sequence: + * child return value: pid of parent, secondary result = 1. + * parent return value: pid of child, secondary result value = 0. + * error: errno, secondary result = 0. + */ +asmlinkage int sys_sysv_fork(struct pt_regs *regs) +{ + int pid; + + pid = do_fork(SIGCHLD, regs->regs[29], regs); + if (pid == 0) { /* child */ + regs->regs[3] = 1; + return current->p_pptr->pid; + } /* parent or error */ + + regs->regs[3] = 0; + return pid; +} +#endif + +/* + * Normal Linux fork(2) syscall + */ +asmlinkage int sys_fork(struct pt_regs *regs) +{ + return do_fork(SIGCHLD, regs->regs[29], regs); +} + +asmlinkage int sys_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + clone_flags = regs->regs[4]; + newsp = regs->regs[5]; + if (!newsp) + newsp = regs->regs[29]; + return do_fork(clone_flags, newsp, regs); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(struct pt_regs *regs) +{ + int error; + char * filename; + + error = getname((char *) (long)regs->regs[4], &filename); + if (error) + return error; + error = do_execve(filename, (char **) (long)regs->regs[5], + (char **) (long)regs->regs[6], regs); + putname(filename); + + return error; +} + +/* + * Do the indirect syscall syscall. + */ +asmlinkage int sys_syscall(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + unsigned long a6) +{ + syscall_t syscall; + + if (a0 > __NR_Linux + __NR_Linux_syscalls) + return -ENOSYS; + + syscall = sys_call_table[a0]; + /* + * Prevent stack overflow by recursive + * syscall(__NR_syscall, __NR_syscall,...); + */ + if (syscall == (syscall_t) sys_syscall) + return -EINVAL; + + if (syscall == NULL) + return -ENOSYS; + + return syscall((void *)a0, a1, a2, a3, a4, a5, a6); +} + +/* + * If we ever come here the user sp is bad. Zap the process right away. + * Due to the bad stack signaling wouldn't work. + */ +asmlinkage void bad_stack(void) +{ + do_exit(SIGSEGV); +} + +#ifdef CONF_PRINT_SYSCALLS +#define SYS(fun, narg) #fun, +static char *sfnames[] = { +#include "syscalls.h" +}; +#endif + +asmlinkage void do_sys(struct pt_regs *regs) +{ + unsigned long syscallnr, usp; + syscall_t syscall; + int errno, narg; + + /* Skip syscall instruction */ + if (delay_slot(regs)) { + /* + * By convention "li v0,<syscallno>" is always preceeding + * the syscall instruction. So if we're in a delay slot + * userland is screwed up. + */ + force_sig(SIGILL, current); + return; + } + regs->cp0_epc += 4; + + syscallnr = regs->regs[2]; + if (syscallnr > (__NR_Linux + __NR_Linux_syscalls)) + goto illegal_syscall; + syscall = sys_call_table[syscallnr]; + +#ifdef CONF_PRINT_SYSCALLS + printk("do_sys(): %s()", sfnames[syscallnr - __NR_Linux]); +#endif + narg = sys_narg_table[syscallnr]; + if (narg > 4) { + /* + * Verify that we can safely get the additional parameters + * from the user stack. + */ + usp = regs->regs[29]; + if (usp & 3) { + printk("unaligned usp\n"); + do_exit(SIGBUS); + return; + } + + if (!access_ok(VERIFY_READ, (void *) (usp + 16), + (narg - 4) * sizeof(unsigned long))) { + errno = -EFAULT; + goto syscall_error; + } + } + + if ((current->flags & PF_TRACESYS) == 0) { + errno = do_syscalls(regs, syscall, narg); + if (errno < 0) + goto syscall_error; + + regs->regs[2] = errno; + regs->regs[7] = 0; + } else { + syscall_trace(); + + errno = do_syscalls(regs, syscall, narg); + if (errno < 0) { + regs->regs[2] = -errno; + regs->regs[7] = 1; + } else { + regs->regs[2] = errno; + regs->regs[7] = 0; + } + + syscall_trace(); + } +#ifdef CONF_PRINT_SYSCALLS + printk(" returning: normal\n"); +#endif + return; + +syscall_error: + regs->regs[2] = -errno; + regs->regs[7] = 1; +#ifdef CONF_PRINT_SYSCALLS + printk(" returning: syscall_error, errno=%d\n", -errno); +#endif + return; + +illegal_syscall: + regs->regs[2] = ENOSYS; + regs->regs[7] = 1; +#ifdef CONF_PRINT_SYSCALLS + printk(" returning: illegal_syscall\n"); +#endif + return; +} diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h new file mode 100644 index 000000000..6a398c92d --- /dev/null +++ b/arch/mips/kernel/syscalls.h @@ -0,0 +1,205 @@ +/* + * List of Linux/MIPS syscalls. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996 by Ralf Baechle + */ + +/* + * This file is being included twice - once to build a list of all + * syscalls and once to build a table of how many arguments each syscall + * accepts. Syscalls that receive a pointer to the saved registers are + * marked as having zero arguments. + * + * The binary compatibility calls are still missing in this list. + */ +SYS(sys_syscall, 7) /* 4000 */ +SYS(sys_exit, 1) +SYS(sys_fork, 0) +SYS(sys_read, 3) +SYS(sys_write, 3) +SYS(sys_open, 3) /* 4005 */ +SYS(sys_close, 3) +SYS(sys_waitpid, 3) +SYS(sys_creat, 2) +SYS(sys_link, 2) +SYS(sys_unlink, 1) /* 4010 */ +SYS(sys_execve, 0) +SYS(sys_chdir, 1) +SYS(sys_time, 1) +SYS(sys_mknod, 3) +SYS(sys_chmod, 2) /* 4015 */ +SYS(sys_chown, 3) +SYS(sys_break, 0) +SYS(sys_stat, 2) +SYS(sys_lseek, 3) +SYS(sys_getpid, 0) /* 4020 */ +SYS(sys_mount, 5) +SYS(sys_umount, 1) +SYS(sys_setuid, 1) +SYS(sys_getuid, 0) +SYS(sys_stime, 1) /* 4025 */ +SYS(sys_ptrace, 4) +SYS(sys_alarm, 1) +SYS(sys_fstat, 2) +SYS(sys_pause, 0) +SYS(sys_utime, 2) /* 4030 */ +SYS(sys_stty, 0) +SYS(sys_gtty, 0) +SYS(sys_access, 2) +SYS(sys_nice, 1) +SYS(sys_ftime, 0) /* 4035 */ +SYS(sys_sync, 0) +SYS(sys_kill, 2) +SYS(sys_rename, 2) +SYS(sys_mkdir, 2) +SYS(sys_rmdir, 1) /* 4040 */ +SYS(sys_dup, 1) +SYS(sys_pipe, 0) +SYS(sys_times, 1) +SYS(sys_prof, 0) +SYS(sys_brk, 1) /* 4045 */ +SYS(sys_setgid, 1) +SYS(sys_getgid, 0) +SYS(sys_signal, 2) +SYS(sys_geteuid, 0) +SYS(sys_getegid, 0) /* 4050 */ +SYS(sys_acct, 0) +SYS(sys_phys, 0) +SYS(sys_lock, 0) +SYS(sys_ioctl, 3) +SYS(sys_fcntl, 3) /* 4055 */ +SYS(sys_mpx, 2) +SYS(sys_setpgid, 2) +SYS(sys_ulimit, 0) +SYS(sys_olduname, 1) +SYS(sys_umask, 1) /* 4060 */ +SYS(sys_chroot, 1) +SYS(sys_ustat, 2) +SYS(sys_dup2, 2) +SYS(sys_getppid, 0) +SYS(sys_getpgrp, 0) /* 4065 */ +SYS(sys_setsid, 0) +SYS(sys_sigaction, 3) +SYS(sys_sgetmask, 0) +SYS(sys_ssetmask, 1) +SYS(sys_setreuid, 2) /* 4070 */ +SYS(sys_setregid, 2) +SYS(sys_sigsuspend, 0) +SYS(sys_sigpending, 1) +SYS(sys_sethostname, 2) +SYS(sys_setrlimit, 2) /* 4075 */ +SYS(sys_getrlimit, 2) +SYS(sys_getrusage, 2) +SYS(sys_gettimeofday, 2) +SYS(sys_settimeofday, 2) +SYS(sys_getgroups, 2) /* 4080 */ +SYS(sys_setgroups, 2) +SYS(sys_ni_syscall, 0) /* old_select */ +SYS(sys_symlink, 2) +SYS(sys_lstat, 2) +SYS(sys_readlink, 3) /* 4085 */ +SYS(sys_uselib, 1) +SYS(sys_swapon, 2) +SYS(sys_reboot, 3) +SYS(old_readdir, 3) +SYS(sys_mmap, 6) /* 4090 */ +SYS(sys_munmap, 2) +SYS(sys_truncate, 2) +SYS(sys_ftruncate, 2) +SYS(sys_fchmod, 2) +SYS(sys_fchown, 3) /* 4095 */ +SYS(sys_getpriority, 2) +SYS(sys_setpriority, 3) +SYS(sys_profil, 0) +SYS(sys_statfs, 2) +SYS(sys_fstatfs, 2) /* 4100 */ +SYS(sys_ioperm, 3) +SYS(sys_socketcall, 2) +SYS(sys_syslog, 3) +SYS(sys_setitimer, 3) +SYS(sys_getitimer, 2) /* 4105 */ +SYS(sys_newstat, 2) +SYS(sys_newlstat, 2) +SYS(sys_newfstat, 2) +SYS(sys_uname, 1) +SYS(sys_iopl, 0) /* Well, actually 17 args ... */ /* 4110 */ +SYS(sys_vhangup, 0) +SYS(sys_idle, 0) +SYS(sys_vm86, 1) +SYS(sys_wait4, 4) +SYS(sys_swapoff, 1) /* 4115 */ +SYS(sys_sysinfo, 1) +SYS(sys_ipc, 6) +SYS(sys_fsync, 1) +SYS(sys_sigreturn, 0) +SYS(sys_clone, 0) /* 4120 */ +SYS(sys_setdomainname, 2) +SYS(sys_newuname, 1) +SYS(sys_ni_syscall, 0) /* sys_modify_ldt */ +SYS(sys_adjtimex, 1) +SYS(sys_mprotect, 3) /* 4125 */ +SYS(sys_sigprocmask, 3) +SYS(sys_create_module, 2) +SYS(sys_init_module, 5) +SYS(sys_delete_module, 1) +SYS(sys_get_kernel_syms, 1) /* 4130 */ +SYS(sys_quotactl, 0) +SYS(sys_getpgid, 1) +SYS(sys_fchdir, 1) +SYS(sys_bdflush, 2) +SYS(sys_sysfs, 3) /* 4135 */ +SYS(sys_personality, 1) +SYS(sys_ni_syscall, 0) /* for afs_syscall */ +SYS(sys_setfsuid, 1) +SYS(sys_setfsgid, 1) +SYS(sys_llseek, 5) /* 4140 */ +SYS(sys_getdents, 3) +SYS(sys_select, 5) +SYS(sys_flock, 2) +SYS(sys_msync, 3) +SYS(sys_readv, 3) /* 4145 */ +SYS(sys_writev, 3) +SYS(sys_cacheflush, 3) +SYS(sys_cachectl, 3) +SYS(sys_sysmips, 4) +SYS(sys_setup, 0) /* 4150 */ +SYS(sys_getsid, 1) +SYS(sys_fdatasync, 0) +SYS(sys_sysctl, 1) +SYS(sys_mlock, 2) +SYS(sys_munlock, 2) /* 4155 */ +SYS(sys_mlockall, 1) +SYS(sys_munlockall, 0) +SYS(sys_sched_setparam,2) +SYS(sys_sched_getparam,2) +SYS(sys_sched_setscheduler,3) /* 4160 */ +SYS(sys_sched_getscheduler,1) +SYS(sys_sched_yield,0) +SYS(sys_sched_get_priority_max,1) +SYS(sys_sched_get_priority_min,1) +SYS(sys_sched_rr_get_interval,2) /* 4165 */ +SYS(sys_nanosleep,2) +SYS(sys_mremap,4) +SYS(sys_accept, 3) +SYS(sys_bind, 3) +SYS(sys_connect, 3) /* 4170 */ +SYS(sys_getpeername, 3) +SYS(sys_getsockname, 3) +SYS(sys_getsockopt, 5) +SYS(sys_listen, 2) +SYS(sys_recv, 4) /* 4175 */ +SYS(sys_recvfrom, 6) +SYS(sys_recvmsg, 3) +SYS(sys_send, 4) +SYS(sys_sendmsg, 3) +SYS(sys_sendto, 6) /* 4180 */ +SYS(sys_setsockopt, 5) +SYS(sys_shutdown, 2) +SYS(sys_socket, 3) +SYS(sys_socketpair, 4) +SYS(sys_setresuid, 3) /* 4185 */ +SYS(sys_getresuid, 3) diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c new file mode 100644 index 000000000..d15aaa4dd --- /dev/null +++ b/arch/mips/kernel/sysmips.c @@ -0,0 +1,113 @@ +/* + * MIPS specific syscalls + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995 by Ralf Baechle + */ +#include <linux/errno.h> +#include <linux/linkage.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/utsname.h> + +#include <asm/cachectl.h> +#include <asm/cache.h> +#include <asm/ipc.h> +#include <asm/uaccess.h> +#include <asm/sysmips.h> + +static inline size_t +strnlen_user(const char *s, size_t count) +{ + return strnlen(s, count); +} + +asmlinkage int +sys_sysmips(int cmd, int arg1, int arg2, int arg3) +{ + int *p; + char *name; + int flags, tmp, len, retval; + + switch(cmd) + { + case SETNAME: + if (!suser()) + return -EPERM; + name = (char *) arg1; + len = strnlen_user(name, retval); + if (len < 0) + retval = len; + break; + if (len == 0 || len > __NEW_UTS_LEN) + retval = -EINVAL; + break; + copy_from_user(system_utsname.nodename, name, len); + system_utsname.nodename[len] = '\0'; + return 0; + + case MIPS_ATOMIC_SET: + /* This is broken in case of page faults and SMP ... + Risc/OS fauls after maximum 20 tries with EAGAIN. */ + p = (int *) arg1; + retval = verify_area(VERIFY_WRITE, p, sizeof(*p)); + if (retval) + return retval; + save_flags(flags); + cli(); + retval = *p; + *p = arg2; + restore_flags(flags); + break; + + case MIPS_FIXADE: + tmp = current->tss.mflags & ~3; + current->tss.mflags = tmp | (arg1 & 3); + retval = 0; + break; + + case FLUSH_CACHE: + cacheflush(0, ~0, CF_BCACHE|CF_ALL); + break; + + case MIPS_RDNVRAM: + retval = -EIO; + break; + + default: + retval = -EINVAL; + break; + } + + return retval; +} + +asmlinkage int +sys_cacheflush(void *addr, int nbytes, int cache) +{ + unsigned int rw; + int ok; + + if ((cache & ~(DCACHE | ICACHE)) != 0) + return -EINVAL; + rw = (cache & DCACHE) ? VERIFY_WRITE : VERIFY_READ; + if (!access_ok(rw, addr, nbytes)) + return -EFAULT; + + cacheflush((unsigned long)addr, (unsigned long)nbytes, cache|CF_ALL); + + return 0; +} + +/* + * No implemented yet ... + */ +asmlinkage int +sys_cachectl(char *addr, int nbytes, int op) +{ + return -ENOSYS; +} diff --git a/arch/mips/kernel/tags.c b/arch/mips/kernel/tags.c new file mode 100644 index 000000000..4bf480c54 --- /dev/null +++ b/arch/mips/kernel/tags.c @@ -0,0 +1,70 @@ +/* + * linux/arch/mips/kernel/tags.c + * + * Copyright (C) 1996 Stoned Elipot + */ +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <asm/bootinfo.h> + +/* + * Parse the tags present in upper memory to find out + * a pecular one. + * + * Parameter: type - tag type to find + * + * returns : NULL - failure + * !NULL - pointer on the tag structure found + */ +tag * +bi_TagFind(enum bi_tag type) +{ + tag* t = (tag*)(mips_memory_upper - sizeof(tag)); + + while((t->tag != tag_dummy) && (t->tag != type)) + t = (tag*)(NEXTTAGPTR(t)); + + if (t->tag == tag_dummy) /* tag not found */ + return (tag*)NULL; + + return t; +} + +/* + * Snarf from the tag list in memory end some tags needed + * before the kernel reachs setup_arch() + * + * add yours here if you want to, but *beware*: the kernel var + * that will hold the values you want to snarf have to be + * in .data section of the kernel, so initialized in to whatever + * value in the kernel's sources. + */ +void bi_EarlySnarf(void) +{ + tag* atag; + + /* for wire_mappings() */ + atag = bi_TagFind(tag_machgroup); + if (atag) + memcpy(&mips_machgroup, TAGVALPTR(atag), atag->size); + else + /* useless for boxes without text video mode but....*/ + panic("machine group not specified by bootloader"); + + atag = bi_TagFind(tag_machtype); + if (atag) + memcpy(&mips_machtype, TAGVALPTR(atag), atag->size); + else + /* useless for boxes without text video mode but....*/ + panic("machine type not specified by bootloader"); + + /* for tlbflush() */ + atag = bi_TagFind(tag_tlb_entries); + if (atag) + memcpy(&mips_tlb_entries, TAGVALPTR(atag), atag->size); + else + /* useless for boxes without text video mode but....*/ + panic("number of TLB entries not specified by bootloader"); + return; +} diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c new file mode 100644 index 000000000..2dd1d54ee --- /dev/null +++ b/arch/mips/kernel/time.c @@ -0,0 +1,292 @@ +/* + * linux/arch/mips/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the time handling details for PC-style clocks as + * found in some MIPS systems. + */ +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> + +#include <asm/bootinfo.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <linux/mc146818rtc.h> +#include <linux/timex.h> + +/* This function must be called with interrupts disabled + * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs + * + * However, the pc-audio speaker driver changes the divisor so that + * it gets interrupted rather more often - it loads 64 into the + * counter rather than 11932! This has an adverse impact on + * do_gettimeoffset() -- it stops working! What is also not + * good is that the interval that our timer function gets called + * is no longer 10.0002 ms, but 9.9767 ms. To get around this + * would require using a different timing source. Maybe someone + * could use the RTC - I know that this can interrupt at frequencies + * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix + * it so that at startup, the timer code in sched.c would select + * using either the RTC or the 8253 timer. The decision would be + * based on whether there was any other device around that needed + * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz, + * and then do some jiggery to have a version of do_timer that + * advanced the clock by 1/1024 s. Every time that reached over 1/100 + * of a second, then do all the old code. If the time was kept correct + * then do_gettimeoffset could just return 0 - there is no low order + * divider that can be accessed. + * + * Ideally, you would be able to use the RTC for the speaker driver, + * but it appears that the speaker driver really needs interrupt more + * often than every 120 us or so. + * + * Anyway, this needs more thought.... pjsg (1993-08-28) + * + * If you are really that interested, you should be reading + * comp.protocols.time.ntp! + */ + +#define TICK_SIZE tick + +static unsigned long do_slow_gettimeoffset(void) +{ + int count; + unsigned long offset = 0; + + /* timer count may underflow right here */ + outb_p(0x00, 0x43); /* latch the count ASAP */ + count = inb_p(0x40); /* read the latched count */ + count |= inb(0x40) << 8; + /* we know probability of underflow is always MUCH less than 1% */ + if (count > (LATCH - LATCH/100)) { + /* check for pending timer interrupt */ + outb_p(0x0a, 0x20); + if (inb(0x20) & 1) + offset = TICK_SIZE; + } + count = ((LATCH-1) - count) * TICK_SIZE; + count = (count + LATCH/2) / LATCH; + return offset + count; +} + +static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_flags(flags); + cli(); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + restore_flags(flags); +} + +void do_settimeofday(struct timeval *tv) +{ + cli(); + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= do_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; + sti(); +} + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else + retval = -1; + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and crystal) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +/* last time the cmos clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 500000 - (tick >> 1) && + xtime.tv_usec < 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + /* As we return to user mode fire off the other CPU schedulers.. this is + basically because we don't yet share IRQ's around. This message is + rigged to be safe on the 386 - basically it's a hack, so don't look + closely for now.. */ + smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL}; + +void (*board_time_init)(struct irqaction *irq); + +void time_init(void) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } +#if 0 /* the IBM way */ + if ((year += 1900) < 1970) + year += 100; +#else + /* true for all MIPS machines? */ + year += 1980; +#endif + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + + /* FIXME: If we have the CPU hardware time counters, use them */ + board_time_init(&irq0); +} diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 36e8a31e8..0fb16f1a5 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1,39 +1,27 @@ /* - * arch/mips/kernel/traps.c + * arch/mips/kernel/traps.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - */ - -/* - * 'traps.c' handles hardware traps and faults after we have saved some - * state in 'asm.s'. Currently mostly a debugging-aid, will be extended - * to mainly kill the offending process (probably by giving it a signal, - * but possibly by killing it outright if necessary). * - * FIXME: This is the place for a fpu emulator. + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle + * Copyright (C) 1994, 1995, 1996 by Paul M. Antoine */ -#include <linux/head.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/config.h> -#include <linux/timer.h> #include <linux/mm.h> +#include <asm/branch.h> +#include <asm/cache.h> +#include <asm/jazz.h> #include <asm/vector.h> -#include <asm/page.h> #include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/segment.h> #include <asm/io.h> -#include <asm/mipsregs.h> #include <asm/bootinfo.h> +#include <asm/sgidefs.h> +#include <asm/uaccess.h> +#include <asm/watch.h> + +#undef CONF_DEBUG_EXCEPTIONS static inline void console_verbose(void) { @@ -63,20 +51,15 @@ extern asmlinkage void handle_ri(void); extern asmlinkage void handle_cpu(void); extern asmlinkage void handle_ov(void); extern asmlinkage void handle_tr(void); -extern asmlinkage void handle_vcei(void); extern asmlinkage void handle_fpe(void); -extern asmlinkage void handle_vced(void); extern asmlinkage void handle_watch(void); -extern asmlinkage void handle_reserved(void); -static char *cpu_names[] = CPU_NAMES; +char *cpu_names[] = CPU_NAMES; -/* - * Fix address errors. This is slow, so try not to use it. This is - * disabled by default, anyway. - */ -int fix_ade_enabled = 0; -unsigned long page_colour_mask; +unsigned int watch_available = 0; + +void (*ibe_board_handler)(struct pt_regs *regs); +void (*dbe_board_handler)(struct pt_regs *regs); int kstack_depth_to_print = 24; @@ -86,6 +69,10 @@ int kstack_depth_to_print = 24; */ #define MODULE_RANGE (8*1024*1024) +/* + * This routine abuses get_user()/put_user() to reference pointers + * with at least a bit of error checking ... + */ void die_if_kernel(char * str, struct pt_regs * regs, long err) { int i; @@ -93,11 +80,23 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err) u32 *sp, *pc, addr, module_start, module_end; extern char start_kernel, _etext; - if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0) + /* + * Just return if in user mode. + */ +#if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) + if (!((regs)->cp0_status & 0x4)) return; +#endif +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) + if (!(regs->cp0_status & 0x18)) + return; +#endif - sp = (u32 *)regs->reg29; - pc = (u32 *)regs->cp0_epc; + /* + * Yes, these double casts are required ... + */ + sp = (u32 *)(unsigned long)regs->regs[29]; + pc = (u32 *)(unsigned long)regs->cp0_epc; console_verbose(); printk("%s: %08lx\n", str, err ); @@ -105,11 +104,6 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err) show_regs(regs); /* - * Some goodies... - */ - printk("Int : %ld\n", regs->interrupt); - - /* * Dump the stack */ if (STACK_MAGIC != *(u32 *)current->kernel_stack_page) @@ -119,20 +113,30 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err) for(i=0;i<5;i++) printk("%08x ", *sp++); stack = (int *) sp; + for(i=0; i < kstack_depth_to_print; i++) { + unsigned int stackdata; + if (((u32) stack & (PAGE_SIZE -1)) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); - printk("%08lx ", get_user_long(stack++)); + if (get_user(stackdata, stack++) < 0) { + printk("(Bad stack address)"); + break; + } + printk("%08x ", stackdata); } printk("\nCall Trace: "); stack = (int *)sp; i = 1; module_start = VMALLOC_START; module_end = module_start + MODULE_RANGE; - while (((u32)stack & (PAGE_SIZE -1)) != 0) { - addr = get_user_long(stack++); + while (((unsigned long)stack & (PAGE_SIZE -1)) != 0) { + if (get_user(addr, stack++) < 0) { + printk("(Bad address)\n"); + break; + } /* * If the address is either in the text segment of the * kernel, or in the region which contains vmalloc'ed @@ -152,123 +156,128 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err) } printk("\nCode : "); - for(i=0;i<5;i++) - printk("%08x ", *pc++); - printk("\n"); + if ((KSEGX(pc) == KSEG0 || KSEGX(pc) == KSEG1) && + (((unsigned long) pc & 3) == 0)) + { + for(i=0;i<5;i++) + printk("%08x ", *pc++); + printk("\n"); + } + else + printk("(Bad address in epc)\n"); do_exit(SIGSEGV); } -static void -fix_ade(struct pt_regs *regs, int write) +static void default_be_board_handler(struct pt_regs *regs) { - printk("Received address error (ade%c)\n", write ? 's' : 'l'); - panic("Fixing address errors not implemented yet"); + /* + * Assume it would be too dangerous to continue ... + */ + force_sig(SIGBUS, current); } -void do_adel(struct pt_regs *regs) +void do_ibe(struct pt_regs *regs) { - unsigned long pc = regs->cp0_epc; - int i; - - if(fix_ade_enabled) - { - fix_ade(regs, 0); - return; - } -#if 0 - for(i=0; i<NR_TASKS;i++) - if(task[i] && task[i]->pid >= 2) - { - printk("Process %d\n", task[i]->pid); - dump_list_process(task[i], pc); - } -#endif - show_regs(regs); -while(1); - dump_tlb_nonwired(); - send_sig(SIGSEGV, current, 1); + ibe_board_handler(regs); } -void do_ades(struct pt_regs *regs) +void do_dbe(struct pt_regs *regs) { - unsigned long pc = regs->cp0_epc; - int i; - - if(fix_ade_enabled) - { - fix_ade(regs, 1); - return; - } -while(1); - for(i=0; i<NR_TASKS;i++) - if(task[i] && task[i]->pid >= 2) - { - printk("Process %d\n", task[i]->pid); - dump_list_process(task[i], pc); - } - show_regs(regs); - dump_tlb_nonwired(); - send_sig(SIGSEGV, current, 1); + dbe_board_handler(regs); } -/* - * The ibe/dbe exceptions are signaled by onboard hardware and should get - * a board specific handlers to get maximum available information. Bus - * errors are always symptom of hardware malfunction or a kernel error. - * - * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong. - * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe) - * are bus errors and therefor should send a SIGBUS! (Andy) - */ -void do_ibe(struct pt_regs *regs) +void do_ov(struct pt_regs *regs) { -while(1); - send_sig(SIGBUS, current, 1); +#ifdef CONF_DEBUG_EXCEPTIONS + show_regs(regs); +#endif + if (compute_return_epc(regs)) + return; + force_sig(SIGFPE, current); } -void do_dbe(struct pt_regs *regs) +void do_fpe(struct pt_regs *regs, unsigned int fcr31) { -while(1); - send_sig(SIGBUS, current, 1); +#ifdef CONF_DEBUG_EXCEPTIONS + show_regs(regs); +#endif + if (compute_return_epc(regs)) + return; + force_sig(SIGFPE, current); } -void do_ov(struct pt_regs *regs) +static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) { -while(1); - send_sig(SIGFPE, current, 1); + unsigned int *addr; + + addr = (unsigned int *) (unsigned long) regs->cp0_epc; + if (regs->cp0_cause & CAUSEF_BD) + addr += 4; + + if (get_user(*opcode, addr)) { + force_sig(SIGSEGV, current); + return -EFAULT; + } + + return 0; } -void do_fpe(struct pt_regs *regs) +static __inline__ void +do_bp_and_tr(struct pt_regs *regs, char *exc, unsigned int trapcode) { -while(1); - send_sig(SIGFPE, current, 1); + /* + * (A quick test says that IRIX 5.3 sends SIGTRAP for all break + * insns, even for break codes that indicate arithmetic failures. + * Wiered ...) + */ + force_sig(SIGTRAP, current); +#ifdef CONF_DEBUG_EXCEPTIONS + show_regs(regs); +#endif + if (compute_return_epc(regs)) + return; } void do_bp(struct pt_regs *regs) { -while(1); - send_sig(SIGILL, current, 1); + unsigned int opcode, bcode; + + /* + * There is the ancient bug in the MIPS assemblers that the break + * code starts left to bit 16 instead to bit 6 in the opcode. + * Gas is bug-compatible ... + */ + if (get_insn_opcode(regs, &opcode)) + return; + bcode = ((opcode >> 16) & ((1 << 20) - 1)); + + do_bp_and_tr(regs, "bp", bcode); } void do_tr(struct pt_regs *regs) { -while(1); - send_sig(SIGILL, current, 1); + unsigned int opcode, bcode; + + if (get_insn_opcode(regs, &opcode)) + return; + bcode = ((opcode >> 6) & ((1 << 20) - 1)); + + do_bp_and_tr(regs, "tr", bcode); } +/* + * TODO: add emulation of higher ISAs' instruction. In particular + * interest in MUL, MAD MADU has been expressed such that R4640/R4650 + * code can be run on other MIPS CPUs. + */ void do_ri(struct pt_regs *regs) { - int i; - - for(i=0; i<NR_TASKS;i++) - if(task[i] && task[i]->pid >= 2) - { - printk("Process %d\n", task[i]->pid); - dump_list_process(task[i], 0x7ffff000); - } +#ifdef CONF_DEBUG_EXCEPTIONS show_regs(regs); -while(1); - send_sig(SIGILL, current, 1); +#endif + if (compute_return_epc(regs)) + return; + force_sig(SIGILL, current); } void do_cpu(struct pt_regs *regs) @@ -276,53 +285,40 @@ void do_cpu(struct pt_regs *regs) unsigned int cpid; cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; - switch(cpid) - { - case 1: + if (cpid == 1) { regs->cp0_status |= ST0_CU1; - break; - case 3: - /* - * This is a guess how to handle MIPS IV - - * I don't have a manual. - */ - if((boot_info.cputype == CPU_R8000) || - (boot_info.cputype == CPU_R10000)) - { - regs->cp0_status |= ST0_CU3; - break; - } - case 0: - /* - * CPU for cp0 can only happen in user mode - */ - case 2: - send_sig(SIGILL, current, 1); - break; + return; } + + force_sig(SIGILL, current); } void do_vcei(struct pt_regs *regs) { /* - * Only possible on R4[04]00[SM]C. No handler because - * I don't have such a cpu. + * Only possible on R4[04]00[SM]C. No handler because I don't have + * such a cpu. Theory says this exception doesn't happen. */ - panic("Caught VCEI exception - can't handle yet\n"); + panic("Caught VCEI exception - should not happen"); } void do_vced(struct pt_regs *regs) { /* - * Only possible on R4[04]00[SM]C. No handler because - * I don't have such a cpu. + * Only possible on R4[04]00[SM]C. No handler because I don't have + * such a cpu. Theory says this exception doesn't happen. */ - panic("Caught VCED exception - can't handle yet\n"); + panic("Caught VCE exception - should not happen"); } void do_watch(struct pt_regs *regs) { - panic("Caught WATCH exception - can't handle yet\n"); + /* + * We use the watch exception where available to detect stack + * overflows. + */ + show_regs(regs); + panic("Caught WATCH exception - probably caused by stack overflow."); } void do_reserved(struct pt_regs *regs) @@ -332,46 +328,56 @@ void do_reserved(struct pt_regs *regs) * Most probably caused by a new unknown cpu type or * after another deadly hard/software error. */ - panic("Caught reserved exception - can't handle.\n"); + panic("Caught reserved exception - should not happen."); } -void trap_init(void) +static void watch_init(unsigned long cputype) { - unsigned long i; - - if(boot_info.machtype == MACH_MIPS_MAGNUM_4000) - EISA_bus = 1; + switch(cputype) { + case CPU_R10000: + case CPU_R4000MC: + case CPU_R4400MC: + case CPU_R4000SC: + case CPU_R4400SC: + case CPU_R4000PC: + case CPU_R4400PC: + case CPU_R4200: + /* case CPU_R4300: */ + set_except_vector(23, handle_watch); + watch_available = 1; + break; + } +} +void trap_init(void) +{ /* - * Setup default vectors + * Only some CPUs have the watch exception. */ - for (i=0;i<=31;i++) - set_except_vector(i, handle_reserved); + watch_init(mips_cputype); /* * Handling the following exceptions depends mostly of the cpu type */ - switch(boot_info.cputype) { - case CPU_R4000MC: - case CPU_R4400MC: - case CPU_R4000SC: - case CPU_R4400SC: + switch(mips_cputype) { + case CPU_R10000: /* - * Handlers not implemented yet. If should every be used - * it's a bug in the Linux/MIPS kernel, anyway. + * The R10000 is in most aspects similar to the R4400. It + * should get some special optimizations. */ - set_except_vector(14, handle_vcei); - set_except_vector(31, handle_vced); - case CPU_R4000PC: - case CPU_R4400PC: - case CPU_R4200: - /* case CPU_R4300: */ + write_32bit_cp0_register(CP0_FRAMEMASK, 0); + set_cp0_status(ST0_XX, ST0_XX); /* - * Use watch exception to trap on access to address zero + * The R10k might even work for Linux/MIPS - but we're paranoid + * and refuse to run until this is tested on real silicon */ - set_except_vector(23, handle_watch); - watch_set(KSEG0, 3); - case CPU_R4600: + panic("CPU too expensive - making holiday in the ANDES!"); + break; + + case CPU_R4000MC: case CPU_R4400MC: case CPU_R4000SC: + case CPU_R4400SC: case CPU_R4000PC: case CPU_R4400PC: + case CPU_R4200: /*case CPU_R4300: case CPU_R4640: */ + case CPU_R4600: case CPU_R4700: set_except_vector(1, handle_mod); set_except_vector(2, handle_tlbl); set_except_vector(3, handle_tlbs); @@ -392,47 +398,64 @@ void trap_init(void) set_except_vector(12, handle_ov); set_except_vector(13, handle_tr); set_except_vector(15, handle_fpe); + break; + case CPU_R6000: case CPU_R6000A: +#if 0 + /* The R6000 is the only R-series CPU that features a machine + * check exception (similar to the R4000 cache error) and + * unaligned ldc1/sdc1 exception. The handlers have not been + * written yet. Well, anyway there is no R6000 machine on the + * current list of targets for Linux/MIPS. + */ + set_except_vector(14, handle_mc); + set_except_vector(15, handle_ndc); +#endif + case CPU_R2000: case CPU_R3000: case CPU_R3000A: case CPU_R3041: + case CPU_R3051: case CPU_R3052: case CPU_R3081: case CPU_R3081E: + /* + * Clear BEV, we are ready to handle exceptions using + * the in-RAM dispatchers. This will not be useful on all + * machines, but it can't hurt (the worst that can happen is + * that BEV is already 0). + */ + set_cp0_status(ST0_BEV,0); + + /* + * Actually don't know about these, but let's guess - PMA + */ + set_except_vector(1, handle_mod); + set_except_vector(2, handle_tlbl); + set_except_vector(3, handle_tlbs); + set_except_vector(4, handle_adel); + set_except_vector(5, handle_ades); /* - * Compute mask for page_colour(). This is based on the - * size of the data cache. Does the size of the icache - * need to be accounted for? + * The Data Bus Error/ Instruction Bus Errors are signaled + * by external hardware. Therefore these two expection have + * board specific handlers. */ - i = read_32bit_cp0_register(CP0_CONFIG); - i = (i >> 26) & 7; - page_colour_mask = 1 << (12 + i); + set_except_vector(6, handle_ibe); + set_except_vector(7, handle_dbe); + ibe_board_handler = default_be_board_handler; + dbe_board_handler = default_be_board_handler; + + set_except_vector(8, handle_sys); + set_except_vector(9, handle_bp); + set_except_vector(10, handle_ri); + set_except_vector(11, handle_cpu); + set_except_vector(12, handle_ov); + set_except_vector(13, handle_tr); + set_except_vector(15, handle_fpe); break; - case CPU_R2000: - case CPU_R3000: - case CPU_R3000A: - case CPU_R3041: - case CPU_R3051: - case CPU_R3052: - case CPU_R3081: - case CPU_R3081E: - case CPU_R6000: - case CPU_R6000A: - case CPU_R8000: + + case CPU_R8000: case CPU_R5000: printk("Detected unsupported CPU type %s.\n", - cpu_names[boot_info.cputype]); - panic("Can't handle CPU\n"); + cpu_names[mips_cputype]); + panic("Can't handle CPU"); break; - /* - * The R10000 is in most aspects similar to the R4400. It however - * should get some special optimizations. - */ - case CPU_R10000: - write_32bit_cp0_register(CP0_FRAMEMASK, 0); - panic("CPU too expensive - making holiday in the ANDES!"); - break; case CPU_UNKNOWN: default: - panic("Unknown CPU type"); + panic("Unsupported CPU type"); } - - /* - * The interrupt handler depends most of the board type. - */ - set_except_vector(0, feature->handle_int); } diff --git a/arch/mips/kernel/tynedma.c b/arch/mips/kernel/tynedma.c deleted file mode 100644 index 04846cddd..000000000 --- a/arch/mips/kernel/tynedma.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Tiny Tyne DMA buffer allocator - * - * Copyright (C) 1995 Ralf Baechle - */ -#include <linux/autoconf.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <asm/bootinfo.h> - -#ifdef CONFIG_DESKSTATION_TYNE - -static unsigned long allocated; - -/* - * Not very sophisticated, but should suffice for now... - */ -unsigned long deskstation_tyne_dma_alloc(size_t size) -{ - unsigned long ret = allocated; - allocated += size; - if (allocated > boot_info.dma_cache_size) - ret = -1; - return ret; -} - -void deskstation_tyne_dma_init(void) -{ - if (boot_info.machtype != MACH_DESKSTATION_TYNE) - return; - allocated = 0; - printk ("Deskstation Tyne DMA (%luk) buffer initialized.\n", - boot_info.dma_cache_size >> 10); -} - -#endif /* CONFIG_DESKSTATION_TYNE */ diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c new file mode 100644 index 000000000..8bf2ad9b7 --- /dev/null +++ b/arch/mips/kernel/unaligned.c @@ -0,0 +1,457 @@ +/* + * Handle unaligned accesses by emulation. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + * + * This file contains exception handler for address error exception with the + * special capability to execute faulting instructions in software. The + * handler does not try to handle the case when the program counter points + * to an address not aligned to a word boundary. + * + * Putting data to unaligned addresses is a bad practice even on Intel where + * only the performance is affected. Much worse is that such code is non- + * portable. Due to several programs that die on MIPS due to alignment + * problems I decieded to implement this handler anyway though I originally + * didn't intend to do this at all for user code. + * + * For now I enable fixing of address errors by default to make life easier. + * I however intend to disable this somewhen in the future when the alignment + * problems with user programs have been fixed. For programmers this is the + * right way to go. + * + * Fixing address errors is a per process option. The option is inherited + * across fork(2) and execve(2) calls. If you really want to use the + * option in your user programs - I discourage the use of the software + * emulation strongly - use the following code in your userland stuff: + * + * #include <sys/sysmips.h> + * + * ... + * sysmips(MIPS_FIXADE, x); + * ... + * + * The parameter x is 0 for disabeling software emulation. Set bit 0 for + * enabeling software emulation and bit 1 for enabeling printing debug + * messages into syslog to aid finding address errors in programs. + * + * The logging feature is an addition over RISC/os and IRIX where only the + * values 0 and 1 are acceptable values for x. I'll probably remove this + * hack later on. + * + * Below a little program to play around with this feature. + * + * #include <stdio.h> + * #include <asm/sysmips.h> + * + * struct foo { + * unsigned char bar[8]; + * }; + * + * main(int argc, char *argv[]) + * { + * struct foo x = {0, 1, 2, 3, 4, 5, 6, 7}; + * unsigned int *p = (unsigned int *) (x.bar + 3); + * int i; + * + * if (argc > 1) + * sysmips(MIPS_FIXADE, atoi(argv[1])); + * + * printf("*p = %08lx\n", *p); + * + * *p = 0xdeadface; + * + * for(i = 0; i <= 7; i++) + * printf("%02x ", x.bar[i]); + * printf("\n"); + * } + * + * Until I've written the code to handle branch delay slots it may happen + * that the kernel receives an ades/adel instruction from an insn in a + * branch delay slot but is unable to handle this case. The kernel knows + * this fact and therefore will kill the process. For most code you can + * fix this temporarily by compiling with flags -fno-delayed-branch -Wa,-O0. + * + * Coprozessor loads are not supported; I think this case is unimportant + * in the practice. + * + * TODO: Handle ndc (attempted store to doubleword in uncached memory) + * exception for the R6000. + * A store crossing a page boundary might be executed only partially. + * Undo the partial store in this case. + */ +#include <linux/mm.h> +#include <linux/signal.h> +#include <asm/branch.h> +#include <asm/byteorder.h> +#include <asm/inst.h> +#include <asm/uaccess.h> + +#undef CONF_NO_UNALIGNED_KERNEL_ACCESS +#undef CONF_LOG_UNALIGNED_ACCESSES + +#define STR(x) __STR(x) +#define __STR(x) #x + +/* + * User code may only access USEG; kernel code may access the + * entire address space. + */ +#define check_axs(p,a,s) \ + if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0) \ + goto sigbus; + +static __inline__ void +emulate_load_store_insn(struct pt_regs *regs, unsigned long addr, unsigned long pc) +{ + union mips_instruction insn; + __register_t value; + + regs->regs[0] = 0; + /* + * This load never faults. + */ + __get_user(insn.word, (unsigned int *)pc); + + switch (insn.i_format.opcode) { + /* + * These are instructions that a compiler doesn't generate. We + * can assume therefore that the code is MIPS-aware and + * really buggy. Emulating these instructions would break the + * semantics anyway. + */ + case ll_op: + case lld_op: + case sc_op: + case scd_op: + + /* + * For these instructions the only way to create an address + * error is an attempted access to kernel/supervisor address + * space. + */ + case ldl_op: + case ldr_op: + case lwl_op: + case lwr_op: + case sdl_op: + case sdr_op: + case swl_op: + case swr_op: + case lb_op: + case lbu_op: + case sb_op: + goto sigbus; + + /* + * The remaining opcodes are the ones that are really of interrest. + */ + case lh_op: + check_axs(pc, addr, 2); + __asm__( + ".set\tnoat\n" +#ifdef __BIG_ENDIAN + "1:\tlb\t%0,0(%1)\n" + "2:\tlbu\t$1,1(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tlb\t%0,1(%1)\n" + "2:\tlbu\t$1,0(%1)\n\t" +#endif + "sll\t%0,0x8\n\t" + "or\t%0,$1\n\t" + ".set\tat\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + :"=&r" (value) + :"r" (addr), "i" (&&fault) + :"$1"); + regs->regs[insn.i_format.rt] = value; + return; + + case lw_op: + check_axs(pc, addr, 4); + __asm__( +#ifdef __BIG_ENDIAN + "1:\tlwl\t%0,(%1)\n" + "2:\tlwr\t%0,3(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tlwl\t%0,3(%1)\n" + "2:\tlwr\t%0,(%1)\n\t" +#endif + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + :"=&r" (value) + :"r" (addr), "i" (&&fault)); + regs->regs[insn.i_format.rt] = value; + return; + + case lhu_op: + check_axs(pc, addr, 2); + __asm__( + ".set\tnoat\n" +#ifdef __BIG_ENDIAN + "1:\tlbu\t%0,0(%1)\n" + "2:\tlbu\t$1,1(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tlbu\t%0,1(%1)\n" + "2:\tlbu\t$1,0(%1)\n\t" +#endif + "sll\t%0,0x8\n\t" + "or\t%0,$1\n\t" + ".set\tat\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + :"=&r" (value) + :"r" (addr), "i" (&&fault) + :"$1"); + regs->regs[insn.i_format.rt] = value; + return; + + case lwu_op: + check_axs(pc, addr, 4); + __asm__( +#ifdef __BIG_ENDIAN + "1:\tlwl\t%0,(%1)\n" + "2:\tlwr\t%0,3(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tlwl\t%0,3(%1)\n" + "2:\tlwr\t%0,(%1)\n\t" +#endif + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + :"=&r" (value) + :"r" (addr), "i" (&&fault)); + value &= 0xffffffff; + regs->regs[insn.i_format.rt] = value; + return; + + case ld_op: + check_axs(pc, addr, 8); + __asm__( + ".set\tmips3\n" +#ifdef __BIG_ENDIAN + "1:\tldl\t%0,(%1)\n" + "2:\tldr\t%0,7(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tldl\t%0,7(%1)\n" + "2:\tldr\t%0,(%1)\n\t" +#endif + ".set\tmips0\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + :"=&r" (value) + :"r" (addr), "i" (&&fault)); + regs->regs[insn.i_format.rt] = value; + return; + + case sh_op: + check_axs(pc, addr, 2); + value = regs->regs[insn.i_format.rt]; + __asm__( +#ifdef __BIG_ENDIAN + ".set\tnoat\n" + "1:\tsb\t%0,1(%1)\n\t" + "srl\t$1,%0,0x8\n" + "2:\tsb\t$1,0(%1)\n\t" + ".set\tat\n\t" +#endif +#ifdef __LITTLE_ENDIAN + ".set\tnoat\n" + "1:\tsb\t%0,0(%1)\n\t" + "srl\t$1,%0,0x8\n" + "2:\tsb\t$1,1(%1)\n\t" + ".set\tat\n\t" +#endif + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + : /* no outputs */ + :"r" (value), "r" (addr), "i" (&&fault) + :"$1"); + return; + + case sw_op: + check_axs(pc, addr, 4); + value = regs->regs[insn.i_format.rt]; + __asm__( +#ifdef __BIG_ENDIAN + "1:\tswl\t%0,(%1)\n" + "2:\tswr\t%0,3(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tswl\t%0,3(%1)\n" + "2:\tswr\t%0,(%1)\n\t" +#endif + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + : /* no outputs */ + :"r" (value), "r" (addr), "i" (&&fault)); + return; + + case sd_op: + check_axs(pc, addr, 8); + value = regs->regs[insn.i_format.rt]; + __asm__( + ".set\tmips3\n" +#ifdef __BIG_ENDIAN + "1:\tsdl\t%0,(%1)\n" + "2:\tsdr\t%0,7(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tsdl\t%0,7(%1)\n" + "2:\tsdr\t%0,(%1)\n\t" +#endif + ".set\tmips0\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%2\n\t" + STR(PTR)"\t2b,%2\n\t" + ".text" + : /* no outputs */ + :"r" (value), "r" (addr), "i" (&&fault)); + return; + + case lwc1_op: + case ldc1_op: + case swc1_op: + case sdc1_op: + /* + * I herewith declare: this does not happen. So send SIGBUS. + */ + goto sigbus; + + case lwc2_op: + case ldc2_op: + case swc2_op: + case sdc2_op: + /* + * These are the coprozessor 2 load/stores. The current + * implementations don't use cp2 and cp2 should always be + * disabled in c0_status. So send SIGILL. + * (No longer true: The Sony Praystation uses cp2 for + * 3D matrix operations. Dunno if that thingy has a MMU ...) + */ + default: + /* + * Pheeee... We encountered an yet unknown instruction ... + */ + force_sig(SIGILL, current); + } + return; + +fault: + send_sig(SIGSEGV, current, 1); + return; +sigbus: + send_sig(SIGBUS, current, 1); + return; +} + +unsigned long unaligned_instructions; + +static __inline__ void +fix_ade(struct pt_regs *regs, unsigned long pc) +{ + /* + * Did we catch a fault trying to load an instruction? + */ + if (regs->cp0_badvaddr == pc) { + /* + * Phee... Either the code is severly messed up or the + * process tried to activate some MIPS16 code. + */ + force_sig(SIGBUS, current); + } + + /* + * Ok, this wasn't a failed instruction load. The CPU was capable of + * reading the instruction and faulted after this. So we don't need + * to verify_area the address of the instrucion. We still don't + * know whether the address used was legal and therefore need to do + * verify_area(). The CPU already did the checking for legal + * instructions for us, so we don't need to do this. + */ + emulate_load_store_insn(regs, regs->cp0_badvaddr, pc); + unaligned_instructions++; +} + +#define kernel_address(x) ((long)(x) < 0) + +asmlinkage void +do_ade(struct pt_regs *regs) +{ + __register_t pc = regs->cp0_epc; + __register_t badvaddr __attribute__ ((unused)) = regs->cp0_badvaddr; + char *adels; + + adels = (((regs->cp0_cause & CAUSEF_EXCCODE) >> + CAUSEB_EXCCODE) == 4) ? "adel" : "ades"; + +#ifdef CONF_NO_UNALIGNED_KERNEL_ACCESS + /* + * In an ideal world there are no unaligned accesses by the kernel. + * So be a bit noisy ... + */ + if (kernel_address(badvaddr) && !user_mode(regs)) { + show_regs(regs); +#ifdef __mips64 + panic("Caught %s exception in kernel mode accessing %016Lx.", + adels, badvaddr); +#else + panic("Caught %s exception in kernel mode accessing %08lx.", + adels, badvaddr); +#endif + } +#endif /* CONF_NO_UNALIGNED_KERNEL_ACCESS */ + +#ifdef CONF_LOG_UNALIGNED_ACCESSES + if (current->tss.mflags & MF_LOGADE) { + __register_t logpc = pc; + if (regs->cp0_cause & CAUSEF_BD) + logpc += 4; +#ifdef __mips64 + printk(KERN_DEBUG + "Caught %s in '%s' at 0x%016Lx accessing 0x%016Lx.\n", + adels, current->comm, logpc, regs->cp0_badvaddr); +#else + printk(KERN_DEBUG + "Caught %s in '%s' at 0x%08lx accessing 0x%08lx.\n", + adels, current->comm, logpc, regs->cp0_badvaddr); +#endif + } +#endif /* CONF_LOG_UNALIGNED_ACCESSES */ + + if (compute_return_epc(regs)) + return; + if(current->tss.mflags & MF_FIXADE) { + pc += ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); + fix_ade(regs, pc); + return; + } + +#ifdef CONF_DEBUG_EXCEPTIONS + show_regs(regs); +#endif + + force_sig(SIGBUS, current); +} diff --git a/arch/mips/kernel/vm86.c b/arch/mips/kernel/vm86.c index 454b35fe0..53627201a 100644 --- a/arch/mips/kernel/vm86.c +++ b/arch/mips/kernel/vm86.c @@ -1,12 +1,13 @@ /* - * arch/mips/vm86.c + * arch/mips/kernel/vm86.c * - * Copyright (C) 1994 Waldorf GMBH, + * Copyright (C) 1994, 1996 Waldorf GMBH, * written by Ralf Baechle */ #include <linux/linkage.h> #include <linux/errno.h> -#include <linux/vm86.h> + +struct vm86_struct; asmlinkage int sys_vm86(struct vm86_struct * v86) { diff --git a/arch/mips/ld.script b/arch/mips/ld.script new file mode 100644 index 000000000..debe96282 --- /dev/null +++ b/arch/mips/ld.script @@ -0,0 +1,107 @@ +OUTPUT_FORMAT("elf32-littlemips") +/* OUTPUT_FORMAT("a.out-mips-little-linux") */ +OUTPUT_ARCH(mips) +ENTRY(kernel_entry) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x80000000; + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0 + .text : + { + _ftext = . ; + *(.text) + *(.rodata) + *(.rodata1) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0 + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = .; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + . = .; + .data : + { + _fdata = . ; + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + _gp = . + 0x8000; + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + *(.sbss) + *(.scommon) + } + _end = . ; + PROVIDE (end = .); + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 56279fb3e..ac3cf45ad 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -1,33 +1,25 @@ # # Makefile for MIPS-specific library files.. # +# Some of these routines are just left over debugging trash of ancient +# times when I just could make my Tyne beep and so ... +# +# ...and for when I need to get the DECStation to use the boot prom to +# do things... Paul M. Antoine. +# -.c.s: - $(CC) $(CFLAGS) -S $< -.s.o: - $(AS) $(ASFLAGS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c $< .S.s: $(CPP) $(CFLAGS) $< -o $*.s .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = dump_tlb.o tinycon.o watch.o - -include ../../../.config - -lib.a: $(OBJS) - $(AR) rcs lib.a $(OBJS) - sync - -dep: - $(CPP) -M *.[cS] > .depend - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend +L_TARGET = lib.a +L_OBJS = beep.o bitags.o checksum.o csum.o dump_tlb.o io.o memmove.o \ + strncpy_user.o strlen_user.o watch.o +ifdef CONFIG_MIPS_DECSTATION +L_OBJS += pmaxcon.o pmaxio.o +else +L_OBJS += tinycon.o endif +include $(TOPDIR)/Rules.make diff --git a/arch/mips/lib/bcopy.c b/arch/mips/lib/bcopy.c new file mode 100644 index 000000000..4afd557bf --- /dev/null +++ b/arch/mips/lib/bcopy.c @@ -0,0 +1,20 @@ +/* + * arch/mips/lib/bcopy.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1994, 1995, 1996 by Ralf Baechle + * + * bcopy() only exists here such that it doesn't get compiled into + * lib/strings.o. Though it's more efficient ... + */ +#include <linux/string.h> + +char * bcopy(const char *src, char *dest, size_t count) +{ + __memcpy(dest, src, count); + + return dest; +} diff --git a/arch/mips/lib/beep.S b/arch/mips/lib/beep.S new file mode 100644 index 000000000..e74a63c0e --- /dev/null +++ b/arch/mips/lib/beep.S @@ -0,0 +1,21 @@ +#include <asm/asm.h> +#include <asm/regdef.h> + +/* + * Just for debugging... + */ + LEAF(beep) + lw t0,beepflag + bnez t0,1f + lbu t0,0xb4000061 + xori t0,3 + sb t0,0xb4000061 + li t0,1 + sw t0,beepflag +1: jr ra + END(beep) + + .bss +beepflag: .word 0 + .text + diff --git a/arch/mips/lib/bitags.c b/arch/mips/lib/bitags.c new file mode 100644 index 000000000..4427c4195 --- /dev/null +++ b/arch/mips/lib/bitags.c @@ -0,0 +1,161 @@ +/* + * milo/bitags.c -- handles the tags passed to the kernel + * + * Copyright (C) 1995 by Stoned Elipot <Stoned.Elipot@fnet.fr> + * written by Stoned Elipot from an original idea of + * Ralf Baechle <ralf@waldorf-gmbh.de> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for more + */ +#include <stdio.h> +#include <asm/bootinfo.h> + +static unsigned int debuglevel = 0; + +extern unsigned long mach_mem_upper; /* from milo.c */ +extern unsigned long mach_mem_lower; /* from milo.c */ + +static unsigned long next_tag = (unsigned long)NULL; + +/* + * Create a tag + * + * Parameters: tag - tag type to create + * size - tag's data size + * tagdata - pointer on tag's data + * + * returns : 0 - success + * 1 - failure + */ +int +bi_TagAdd(enum bi_tag type, unsigned long size, void *data) +{ + tag t; + unsigned long addr; + + t.tag = type; + t.size = size; + if (next_tag == (unsigned long)NULL) /* HuHo... first tag to create */ + { + if (mach_mem_upper != (unsigned long)NULL) /* RAM detection code had run */ + { + next_tag = mach_mem_upper; + } + else + /* RAM dectection code had not run, let's hope the + * tag we are creating is a memupper one, else fail + * ...miserably, hopelessly, lonely + */ + { + if (type != tag_memupper) + { + return 1; + } + else + { + /* + * saved, it's a memupper tag: put it's value in + * mach_mem_upper so launch() can pass it to the kernel + * in a0 and well we're going to create a tag anyway... + */ + next_tag = *(unsigned long*)data; + memcpy((void*)&mach_mem_upper, data, size); + } + } + } + addr = next_tag - (sizeof(tag)); + if (debuglevel >=2) + { + printk("bi_TagAdd: adding tag struct at %08x, tag: %d, size: %08x\r\n", addr, t.tag, t.size); + } + memcpy((void*)addr, (void*)&t, (size_t)(sizeof(tag))); + if (size != 0) + { + addr = addr - size; + if (debuglevel >=2) + { + printk("bi_TagAdd: adding tag value at %08x\r\n", addr); + } + memcpy((void*)addr, data, (size_t)(t.size)); + } + next_tag = addr; + return 0; +} + +/* + * Create tags from a "null-terminated" array of tag + * (tag type of the tag_def struct in array must be 'dummy') + * + * Parameter: taglist - tag array pointer + * + * returns : 0 - success + * 1 - failure + */ +int +bi_TagAddList(tag_def* taglist) +{ + int ret_val = 0; + for(; (taglist->t.tag != tag_dummy) && (!ret_val); taglist++) + { + /* + * we assume this tag is present in the default taglist + * for the machine we're running on + */ + if (taglist->t.tag == tag_memlower) + { + mach_mem_lower = (unsigned long)(*((unsigned long*)taglist->d)); +/* ajouter detection de memupper pour simplifier le code de bi_TagAdd: soit mach_mem_upper + a ete initialise par <machine_ident>() soit est initialise par le pre;ier tag de la list + par default pour la machine */ + } + ret_val = bi_TagAdd(taglist->t.tag, taglist->t.size, taglist->d); + } + return ret_val; +} + +/* + * Parse the tags present in upper memory to find out + * a pecular one. + * + * Parameter: type - tag type to find + * + * returns : NULL - failure + * !NULL - pointer on the tag structure found + * + * Note: Just a 'prototype', the kernel's one is in + * arch/mips/kernel/setup.c + */ +/* tag* */ +/* bi_TagFind(enum bi_tag type) */ +/* { */ +/* tag* t; */ +/* t = (tag*)(mach_mem_upper - sizeof(tag)); */ +/* while((t->tag != tag_dummy) && (t->tag != type)) */ +/* t = (tag*)(NEXTTAGPTR(t)); */ +/* if (t->tag == tag_dummy) */ +/* { */ +/* return (tag*)NULL; */ +/* } */ +/* return t; */ +/* } */ + + +/* + * Make a listing of tags available in memory: debug helper. + */ +/* void */ +/* bi_TagWalk(void) */ +/* { */ +/* tag* t; */ +/* int i=0; */ +/* t = (tag*)(mach_mem_upper - sizeof(tag)); */ +/* while(t->tag != tag_dummy) */ +/* { */ +/* printk("tag #02%dm addr: %08x, type %d, size %u\n\r", i, (void*)t, t->tag, t->size); */ +/* t = (tag*)(NEXTTAGPTR(t)); */ +/* i++; */ +/* } */ +/* return; */ +/* } */ + diff --git a/arch/mips/lib/checksum.c b/arch/mips/lib/checksum.c new file mode 100644 index 000000000..0e04ac5e8 --- /dev/null +++ b/arch/mips/lib/checksum.c @@ -0,0 +1,158 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * MIPS specific IP/TCP/UDP checksumming routines + * + * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de> + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <net/checksum.h> +#include <asm/string.h> + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ + unsigned long scratch1; + unsigned long scratch2; + + /* + * This is for 32-bit MIPS processors. + */ + __asm__(" + .set noreorder + .set noat + andi $1,%4,2 # Check alignment + beqz $1,2f # Branch if ok + nop # delay slot + subu $1,%3,2 # Alignment uses up two bytes + bgez $1,1f # Jump if we had at least two bytes + move %3,$1 # delay slot + j 4f + addiu %3,2 # delay slot; len was < 2. Deal with it + +1: lhu %2,(%4) + addiu %4,2 + addu %0,%2 + sltu $1,%0,%2 + addu %0,$1 + +2: srl %1,%3,5 + beqz %1,2f + sll %1,%1,5 # delay slot + + addu %1,%4 +1: lw %2,0(%4) + addu %4,32 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-28(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-24(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-20(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-16(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-12(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-8(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + lw %2,-4(%4) + addu %0,$1 + addu %0,%2 + sltu $1,%0,%2 + + bne %4,%1,1b + addu %0,$1 # delay slot + +2: andi %1,%3,0x1c + beqz %1,4f + addu %1,%4 # delay slot +3: lw %2,0(%4) + addu %4,4 + addu %0,%2 + sltu $1,%0,%2 + bne %4,%1,3b + addu %0,$1 # delay slot + +4: andi $1,%3,3 + beqz $1,7f + andi $1,%3,2 # delay slot + beqz $1,5f + move %2,$0 # delay slot + lhu %2,(%4) + addiu %4,2 # delay slot + +5: andi $1,%3,1 + beqz $1,6f + nop # delay slot + lbu %1,(%4) + sll %2,16\n\t" +#ifdef __MIPSEB__ + "sll %1,8\n\t" +#endif + "or %2,%1 +6: addu %0,%2 + sltu $1,%0,%2 + addu %0,$1 +7: .set at + .set reorder" + : "=r"(sum), + "=&r" (scratch1), + "=&r" (scratch2), + "=r" (len), + "=r" (buff) + : "0"(sum), "3"(len), "4"(buff) + : "$1"); + + return sum; +} + +/* + * copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy(const char *src, char *dst, + int len, unsigned int sum) +{ + /* + * It's 2:30 am and I don't feel like doing it right ... + * This is lots slower than the real thing (tm) + * + * XXX This may nuke the kernel for unaligned src addresses!!! + * (Due to software address error fixing no longer true, but + * seems to happen very rarely only anyway.) + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} diff --git a/arch/mips/lib/csum.S b/arch/mips/lib/csum.S new file mode 100644 index 000000000..08224e86b --- /dev/null +++ b/arch/mips/lib/csum.S @@ -0,0 +1,25 @@ +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/regdef.h> + +/* + * Compute kernel code checksum to check kernel code against corruption + * (Ancient debugging trash ...) + */ + LEAF(csum) + LONG_L t0,cacheflush + move t8,ra + jalr t0 + li t0,KSEG1 + la t1,final + li t2,KSEG1 + or t0,t2 + or t1,t2 + move v0,zero +1: lw t2,(t0) + addiu t0,4 + bne t0,t1,1b + xor v0,t2 + jr t8 + nop + END(csum) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index f730b9fce..e7082e1ac 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -4,16 +4,20 @@ * Copyright (C) 1994, 1995 by Waldorf Electronics, * written by Ralf Baechle. */ - #include <linux/kernel.h> +#include <linux/mm.h> #include <linux/sched.h> #include <linux/string.h> #include <asm/bootinfo.h> -#include <asm/cachectl.h> +#include <asm/cache.h> +#include <asm/mipsconfig.h> #include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> -static void +void dump_tlb(int first, int last) { int i; @@ -61,21 +65,20 @@ dump_tlb(int first, int last) void dump_tlb_all(void) { - dump_tlb(0, boot_info.tlb_entries - 1); + dump_tlb(0, mips_tlb_entries - 1); } void -dump_tlb_nonwired(void) +dump_tlb_wired(void) { - dump_tlb(read_32bit_cp0_register(CP0_WIRED), boot_info.tlb_entries - 1); + dump_tlb(0, read_32bit_cp0_register(CP0_WIRED)); } -#include <linux/kernel.h> -#include <linux/mm.h> - -#include <asm/mipsconfig.h> -#include <asm/page.h> -#include <asm/pgtable.h> +void +dump_tlb_nonwired(void) +{ + dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_tlb_entries - 1); +} void dump_list_process(struct task_struct *t, void *address) @@ -86,15 +89,15 @@ dump_list_process(struct task_struct *t, void *address) unsigned int addr; addr = (unsigned int) address; - printk("Addr == %08x\n", addr); - printk("tasks->tss.pg_dir == %08x\n", - (unsigned int) t->tss.pg_dir); + printk("Addr == %08x\n", addr); + printk("tasks->tss.pg_dir == %08x\n", (unsigned int) t->tss.pg_dir); + printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd); - page_dir = pgd_offset(t, 0); + page_dir = pgd_offset(t->mm, 0); printk("page_dir == %08x\n", (unsigned int) page_dir); - pgd = pgd_offset(t, addr); + pgd = pgd_offset(t->mm, addr); printk("pgd == %08x, ", (unsigned int) pgd); pmd = pmd_offset(pgd, addr); @@ -105,7 +108,6 @@ dump_list_process(struct task_struct *t, void *address) page = *pte; printk("page == %08x\n", (unsigned int) pte_val(page)); - } void @@ -125,8 +127,6 @@ dump_list_current(void *address) printk("%08x\n", *pt); } -#include <asm/segment.h> - unsigned int vtop(void *address) { @@ -135,8 +135,8 @@ vtop(void *address) pte_t *pte; unsigned int addr, paddr; - addr = (unsigned int) address; - pgd = pgd_offset(current, addr); + addr = (unsigned long) address; + pgd = pgd_offset(current->mm, addr); pmd = pmd_offset(pgd, addr); pte = pte_offset(pmd, addr); paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK; @@ -158,4 +158,3 @@ dump16(unsigned long *p) (unsigned long)p, (unsigned long)*p++); } } - diff --git a/arch/mips/lib/io.c b/arch/mips/lib/io.c new file mode 100644 index 000000000..c3c3f68d7 --- /dev/null +++ b/arch/mips/lib/io.c @@ -0,0 +1,24 @@ +/* + * include/asm-mips/string.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1994, 1995, 1996 by Ralf Baechle + * + * For now io.c contains only the definition of isa_slot_offset. The + * real io.S doesn't assemble due to a GAS bug. + */ + +/* + * port_base is the begin of the address space to which x86 style + * I/O ports are mapped. + */ +unsigned long port_base; + +/* + * isa_slot_offset is the address where E(ISA) busaddress 0 is is mapped + * for the processor. + */ +unsigned long isa_slot_offset; diff --git a/arch/mips/lib/memmove.c b/arch/mips/lib/memmove.c new file mode 100644 index 000000000..c3927ad49 --- /dev/null +++ b/arch/mips/lib/memmove.c @@ -0,0 +1,39 @@ +/* + * arch/mips/lib/memmove.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1994, 1995, 1996 by Ralf Baechle + * + * Less stupid implementation of memmove. + */ +#include <linux/string.h> + +void __memmove(void *dest, const void *src, size_t n) +{ + if (!n) + return; + + if (dest < src + || dest > src + n) + /* Copy forward */ + __memcpy(dest, src, n); + else + /* Copy backwards */ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n" + "1:\tlbu\t$1,-1(%1)\n\t" + "subu\t%1,1\n\t" + "sb\t$1,-1(%0)\n\t" + "subu\t%2,1\n\t" + "bnez\t%2,1b\n\t" + "subu\t%0,1\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=r" (dest), "=r" (src), "=r" (n) + : "0" (dest + n), "1" (src + n), "2" (n) + : "$1","memory" ); +} diff --git a/arch/mips/lib/pmaxcon.c b/arch/mips/lib/pmaxcon.c new file mode 100644 index 000000000..3b2cb1216 --- /dev/null +++ b/arch/mips/lib/pmaxcon.c @@ -0,0 +1,150 @@ +/* ---------------------------------------------------------------------- + * console.c + * + * Copyright (C) 1994 by Waldorf Electronic, + * written by Ralf Baechle and Andreas Busse + * Copyright (C) 1995 Paul M. Antoine (PMAX) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * ---------------------------------------------------------------------- */ +/* + * FIXME: This file is hacked to be hardwired for the Personal DECStation + * Only thought of as a debugging console output + */ + +#include <linux/tty.h> +#include <asm/bootinfo.h> + +static unsigned int size_x; +static unsigned int size_y; +static unsigned short cursor_x; +static unsigned short cursor_y; +static volatile unsigned short *vram_addr; +static int console_needs_init = 1; + +extern struct bootinfo boot_info; +extern struct screen_info screen_info; + +/* + * Here is the base address of the prom calls + */ +unsigned long pmax_rex_base = 0; + +/* ---------------------------------------------------------------------- + * init_console() + * ---------------------------------------------------------------------- */ + +void init_console(void) +{ + size_x = 80; + size_y = 50; + cursor_x = 0; + cursor_y = 0; + + vram_addr = (unsigned short *)0xe10b8000; + + console_needs_init = 0; +} + +void +set_size_x(unsigned int x) +{ + size_x = x; +} + +void +set_size_y(unsigned int y) +{ + size_y = y; +} + +void +set_vram(unsigned short *vram) +{ + vram_addr = vram; +} + +/* + * FIXME: Temporary hack - changed its name to avoid conflict in + * drivers/char/vga.c that shouldn't be there <sigh> PMA + */ +void +set_pmax_cursor(unsigned int x, unsigned int y) +{ + cursor_x = x; + cursor_y = y; +} + +void +print_char(unsigned int x, unsigned int y, unsigned char c) +{ + volatile unsigned short *caddr; + +/* caddr = vram_addr + (y * size_x) + x; + *caddr = (*caddr & 0xff00) | 0x0f00 | (unsigned short) c; +*/ + pmax_putch(c); +} + +static void +scroll(void) +{ + volatile unsigned short *caddr; + register int i; +/* + caddr = vram_addr; + for(i=0; i<size_x * (size_y-1); i++) + *(caddr++) = *(caddr + size_x); + + blank last line + + caddr = vram_addr + (size_x * (size_y-1)); + for(i=0; i<size_x; i++) + *(caddr++) = (*caddr & 0xff00) | (unsigned short) ' '; +*/ + pmax_putch('\n'); +} + +void print_string(const unsigned char *str) +{ + unsigned char c; + + if (console_needs_init) + init_console(); +/* + while((c = *str++)) + switch(c) + { + case '\n': + cursor_x = 0; + cursor_y++; + if(cursor_y == size_y) + { + scroll(); + cursor_y = size_y - 1; + } + break; + + default: + print_char(cursor_x, cursor_y, c); + cursor_x++; + if(cursor_x == size_x) + { + cursor_x = 0; + cursor_y++; + if(cursor_y == size_y) + { + scroll(); + cursor_y = size_y - 1; + } + } + break; + } +*/ + pmax_printf(str); + +} + +/* end of file */ diff --git a/arch/mips/lib/pmaxio.S b/arch/mips/lib/pmaxio.S new file mode 100644 index 000000000..97ee46a23 --- /dev/null +++ b/arch/mips/lib/pmaxio.S @@ -0,0 +1,78 @@ +#include <asm/regdef.h> +#include <asm/dec/decstation.h> + + .text + .set reorder +/* + * pmax_printf - call the PROM printf() function + */ + .globl pmax_printf +pmax_printf: + lw v0,pmax_rex_base + lw v0,REX_PRINTF(v0) + j v0 + +/* + * pmax_getchar - call the PROM getchar() function + */ + .globl pmax_getch +pmax_getch: + lw v0,pmax_rex_base + lw v0,REX_GETCHAR(v0) + j v0 + +/* + * pmax_putchar - call the PROM putchar() function + */ + .globl pmax_putch +pmax_putch: + lw v0,pmax_rex_base + lw v0,REX_PUTCHAR(v0) + j v0 + +/* + * pmax_callfn - call the PROM function + */ + .globl pmax_callfn +pmax_callfn: + lw v0,pmax_rex_base + addu v0,v0,a0 + lw v0,(v0) + j v0 + +/* + * pmax_getbitmap - call the PROM for memory bitmap function + */ + .globl pmax_getbitmap +pmax_getbitmap: + lw v0,pmax_rex_base + lw v0,REX_GETBITMAP(v0) + j v0 + +/* + * pmax_getgetenv - call the PROM to get environment variable + */ + .globl pmax_getenv +pmax_getenv: + lw v0,pmax_rex_base + lw v0,REX_GETENV(v0) + j v0 + +/* + * pmax_getsysid - call the PROM to get system id + */ + .globl pmax_getsysid +pmax_getsysid: + lw v0,pmax_rex_base + lw v0,REX_GETSYSID(v0) + j v0 + +/* + * pmax_halt - call the PROM halt() function + */ + .globl pmax_halt +pmax_halt: + lw v0,pmax_rex_base + lw v0,REX_HALT(v0) + j v0 + diff --git a/arch/mips/lib/strlen_user.S b/arch/mips/lib/strlen_user.S new file mode 100644 index 000000000..3ef8ed18d --- /dev/null +++ b/arch/mips/lib/strlen_user.S @@ -0,0 +1,33 @@ +/* + * arch/mips/lib/strlen_user.S + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1996 by Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/sgidefs.h> + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error + */ +LEAF(__strlen_user) + move v0,zero +1: lb t0,(a0) + LONG_ADDIU v0,1 + LONG_ADDIU a0,1 + bnez t0,1b + jr ra + END(strlen_user) + + .section __ex_table,"a" + PTR 1b,fault + .text + +fault: move v0,zero + jr ra diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S new file mode 100644 index 000000000..4230ffe6d --- /dev/null +++ b/arch/mips/lib/strncpy_user.S @@ -0,0 +1,48 @@ +/* + * arch/mips/lib/strncpy_user.S + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1996 by Ralf Baechle + */ +#include <linux/errno.h> + +#include <asm/asm.h> +#include <asm/regdef.h> + +/* + * Returns: -EFAULT if exception before terminator, N if the entire + * buffer filled, else strlen. + */ + +/* + * Ugly special case have to check: we might get passed a user space + * pointer which wraps into the kernel space ... + */ + +LEAF(__strncpy_from_user) + move v0,zero + move v1,a1 + .set noreorder +1: lbu t0,(v1) + LONG_ADDIU v1,1 + beqz t0,2f + sb t0,(a0) # delay slot + LONG_ADDIU v0,1 + bne v0,a2,1b + LONG_ADDIU a0,1 # delay slot + .set reorder +2: LONG_ADDU t0,a1,v0 + xor t0,a1 + bltz t0,fault + jr ra # return n + END(__strncpy_from_user) + +fault: li v0,-EFAULT + jr ra + + .section __ex_table,"a" + PTR 1b,fault + .text diff --git a/arch/mips/lib/tinycon.c b/arch/mips/lib/tinycon.c index 4410986d8..4b75dec20 100644 --- a/arch/mips/lib/tinycon.c +++ b/arch/mips/lib/tinycon.c @@ -1,5 +1,5 @@ -/* ---------------------------------------------------------------------- - * console.c +/* + * arch/mips/lib/console.c * * Copyright (C) 1994 by Waldorf Electronic, * written by Ralf Baechle and Andreas Busse @@ -7,10 +7,11 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. - * ---------------------------------------------------------------------- */ -/* + * * FIXME: This file is hacked to be hardwired for the Deskstation - * Only thought as a debugging console output + * Only thought as a debugging console output. It's as inefficient + * as a piece of code can be but probably a good piece of code to + * implement a preliminary console for a new target. */ #include <linux/tty.h> @@ -23,7 +24,6 @@ static unsigned short cursor_y; static volatile unsigned short *vram_addr; static int console_needs_init = 1; -extern struct bootinfo boot_info; extern struct screen_info screen_info; /* ---------------------------------------------------------------------- @@ -33,11 +33,13 @@ extern struct screen_info screen_info; void init_console(void) { size_x = 80; - size_y = 50; + // size_y = 50; + size_y = 25; cursor_x = 0; cursor_y = 0; - vram_addr = (unsigned short *)0xe10b8000; + // vram_addr = (unsigned short *)0xe10b8000; + vram_addr = (unsigned short *)0xb00b8000; console_needs_init = 0; } @@ -61,7 +63,7 @@ set_vram(unsigned short *vram) } void -set_cursor(unsigned int x, unsigned int y) +set_crsr(unsigned int x, unsigned int y) { cursor_x = x; cursor_y = y; @@ -129,5 +131,3 @@ void print_string(const unsigned char *str) break; } } - -/* end of file */ diff --git a/arch/mips/lib/watch.S b/arch/mips/lib/watch.S index 36b54d5c0..e460de6db 100644 --- a/arch/mips/lib/watch.S +++ b/arch/mips/lib/watch.S @@ -1,15 +1,16 @@ /* * Kernel debug stuff to use the Watch registers. - * Usefull to find stack overflows etc. + * Usefull to find stack overflows, dangeling pointers etc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995 Ralf Baechle + * Copyright (C) 1995, 1996 by Ralf Baechle */ #include <asm/asm.h> #include <asm/mipsregs.h> +#include <asm/regdef.h> .set noreorder /* @@ -19,30 +20,48 @@ * bit #0 to trap on store references * Results : none */ - LEAF(watch_set) + LEAF(__watch_set) li t0,0x80000000 subu a0,t0 ori a0,7 xori a0,7 or a0,a1 mtc0 a0,CP0_WATCHLO + sw a0,watch_savelo jr ra mtc0 zero,CP0_WATCHHI - END(watch_set) + END(__watch_set) /* - * The stuff below are just some kernel debugging gadgets. It will - * go away. + * Parameter: none + * Results : none */ + LEAF(__watch_clear) + jr ra + mtc0 zero,CP0_WATCHLO + END(__watch_clear) /* * Parameter: none * Results : none */ - LEAF(watch_clear) + LEAF(__watch_reenable) + lw t0,watch_savelo jr ra - mtc0 zero,CP0_WATCHLO - END(watch_clear) + mtc0 t0,CP0_WATCHLO + END(__watch_reenable) + +/* + * Saved value of the c0_watchlo register for watch_reenable() + */ + .data +watch_savelo: .word 0 + .text + +/* + * The stuff below are just some kernel debugging gadgets. It is only here + * because it had to be somewhere and will go away. + */ /* * Parameter: none @@ -75,28 +94,28 @@ * Parameter: none * Results : none */ - NESTED(print_sp, 24, sp) - .mask 0x80000000,16 - subu sp,24 - sw ra,16(sp) - move a1,sp + NESTED(print_sp, ((5*SZREG)+ALSZ)&ALMASK, sp) + .mask 0x80000000,4*SZREG + PTR_SUBU sp,((5*SZREG)+ALSZ)&ALMASK + REG_S ra,4*SZREG(sp) + move a1,sp PRINT("$sp == %08lx\n") - lw ra,16(sp) - jr ra - addiu sp,24 + REG_L ra,4*SZREG(sp) + jr ra + PTR_ADDU sp,((5*SZREG)+ALSZ)&ALMASK END(print_sp) /* * Parameter: none * Results : none */ - NESTED(print_st, 24, sp) - .mask 0x80000000,16 - subu sp,24 - sw ra,16(sp) - mfc0 a1,CP0_STATUS + NESTED(print_st, ((5*SZREG)+ALSZ)&ALMASK, sp) + .mask 0x80000000,4*SZREG + PTR_SUBU sp,((5*SZREG)+ALSZ)&ALMASK + REG_S ra,4*SZREG(sp) + mfc0 a1,CP0_STATUS PRINT("cp0_status == %08lx\n") - lw ra,16(sp) - jr ra - addiu sp,24 + REG_L ra,4*SZREG(sp) + jr ra + PTR_ADDU sp,((5*SZREG)+ALSZ)&ALMASK END(print_st) diff --git a/arch/mips/man/de/man2/cacheflush.2 b/arch/mips/man/de/man2/cacheflush.2 new file mode 100644 index 000000000..1085f6ecb --- /dev/null +++ b/arch/mips/man/de/man2/cacheflush.2 @@ -0,0 +1,77 @@ +.\" Geschrieben von Ralf Baechle (ralf@waldorf-gmbh.de), +.\" Copyright (c) 1994, 1995 Waldorf GMBH +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual 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 License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH CACHEFLUSH 2 "30 Juni 95" "Linux" "Systemaufrufe" +.SH NAME +cacheflush \- Befehls- und Datencaches l\(:oschen und zur\(:uckschreiben +.SH \(:UBERSICHT +.nf +.B #include <sys/cachectl.h> +.sp +.BI "int cacheflush(char *" addr ", int "nbytes ", int "cache ");" +.fi +.SH BESCHREIBUNG +.I Cacheflush +schreibt den als Argument angegebenen Benutzeradressbereich addr bis +(addr+nbytes-1) aus den Caches in den Speicher zur\(:uck und invalidiert +die betroffenen Cachelines anschlie\(ssend. Cache ist eine der +folgenden Konstanten: +.TP +.B ICACHE +Befehlscache invalidieren. +.TP +.B DCACHE +Den Datencache zur\(:uck in den Speicher schreiben und die betroffenen +Cachelines invalidieren. +.TP +.B BCACHE +Identisch mit +(\fIICACHE\fP|\fIDCACHE\fP). +.PP +.SH "R\(:UCKGABEWERT" +.B cacheflush +gibt 0 bei Erfolg oder -1 im Fehlerfall zur\(:uck. Beim Auftreten +von Fehlern, enth\(:alt +.I errno +die Fehlernummer. +.SH FEHLER +.TP +.B EINVAL +Der cache Parameter ist nicht +.IR ICACHE , +.IR DCACHE , +oder +.IR BCACHE . +.TP +.B EFAULT +Der Adressbereich addr bis (addr+nbytes-1) ist ganz oder teilweise nicht +adressierbar. +.PP +.SH FEHLER +Die aktuelle Implementation ignoriert die addr und nbytes Parameter. Statt +dessen wird immer der gesamte Cache geflusht. +.SH BEMERKUNGEN +Dieser Systemaufruf ist nur auf MIPS-basierten Systemen verf\(:ugbar. + +.SH "SIEHE" +\fBcachectl\fP(2). diff --git a/arch/mips/man/de/man2/syscall.2 b/arch/mips/man/de/man2/syscall.2 new file mode 100644 index 000000000..2d2345f9c --- /dev/null +++ b/arch/mips/man/de/man2/syscall.2 @@ -0,0 +1,60 @@ +.\" Copyright (c) 1995 by Ralf Baechle (ralf@waldorf-gmbh.de) +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual 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 License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH SYSCALL 2 "28 November 95" "Linux" "Systemaufrufe" +.SH NAME +syscall \- Indirekter Systemaufruf +.SH SYNOPSIS +.nf +.B #include <sys/syscall.h> +.sp +.BI "int syscall(unsigned int " syscallnr ", ...);" +.fi +.SH DESCRIPTION +.B syscall +ruft den durch +.B syscallnr +bezeichneten Systemaufruf indirekt auf. Die weiteren optionalen +Parameter werden an den indirekt aufgerufenen Systemaufruf uebergeben. +.B syscallnr +darf nicht SYS_syscall sein. +.PP +.SH "R\(:UCKGABEWERT" +.B syscall +gibt den R\(:uckgabewert des indirekt aufgerufenen Systemaufrufs zurueck, als +ob dieser direkt aufgerufen worden w\(:are. Beim Auftreten von Fehlern, +werden diese durch errno angezeigt. +.SH FEHLER +.TP +.B ENOSYS +syscallnr ist au\(sserhalb des erlaubten Wertebereiches oder der durch +syscallnr bezeichnete Systemaufruf wird durch das System nicht unterst\(:utzt. +.PP +Wegen weiterer m\(:oglicher Werte von errno siehe auch die Dokumentation des +Systemaufrufs syscallnr. +.SH BUGS +Syscall(2) ist ungetestet. +.SH NOTE +Dieser Systemaufruf ist nur auf MIPS basierten Systemen verf\(:ugbar. Die +anderen Linuxsysteme implementieren syscall(2) als Funktion in libc. +.SH "SIEHE AUCH" +Dokumentation des Systemaufrufs syscallnr. diff --git a/arch/mips/man/man2/cacheflush.2 b/arch/mips/man/man2/cacheflush.2 new file mode 100644 index 000000000..3d6778d92 --- /dev/null +++ b/arch/mips/man/man2/cacheflush.2 @@ -0,0 +1,67 @@ +.\" Written by Ralf Baechle (ralf@waldorf-gmbh.de), +.\" Copyright (c) 1994, 1995 Waldorf GMBH +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual 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 License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH CACHEFLUSH 2 "27 June 95" "Linux" "System calls" +.SH NAME +cacheflush \- flush contents of instruction and/or data cache +.SH SYNOPSIS +.nf +.B #include <sys/cachectl.h> +.sp +.BI "int cacheflush(char *" addr ", int "nbytes ", int "cache ");" +.fi +.SH DESCRIPTION +.B cacheflush +flushes contents of indicated cache(s) for user addresses in the range +addr to (addr+nbytes-1). Cache may be one of: +.TP +.B ICACHE +Flush the instruction cache. +.TP +.B DCACHE +Write back to memory and invalidate the affected valid cachelines. +.TP +.B BCACHE +Same as +.B (ICACHE|DCACHE). +.PP +.SH "RETURN VALUE" +.B cacheflush +returns 0 on success or -1 on error. If errors are detected, +errno will indicate the error. +.SH ERRORS +.TP +.B EINVAL +cache parameter is not one of ICACHE, DCACHE, or BCACHE. +.TP +.B EFAULT +Some or all of the address range addr to (addr+nbytes-1) is not accessible. +.PP +.SH BUGS +The current implementation ignores the addr and nbytes parameters. Therefore +always the whole cache is flushed. +.SH NOTE +This system call is only available on MIPS based systems. + +.SH "SEE ALSO" +.BR cachectl "(2)" diff --git a/arch/mips/man/man2/syscall.2 b/arch/mips/man/man2/syscall.2 new file mode 100644 index 000000000..86d7837db --- /dev/null +++ b/arch/mips/man/man2/syscall.2 @@ -0,0 +1,61 @@ +.\" Copyright (c) 1995 by Ralf Baechle (ralf@waldorf-gmbh.de) +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual 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 License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH SYSCALL 2 "28 November 95" "Linux" "System calls" +.SH NAME +syscall \- indirect syscall +.SH SYNOPSIS +.nf +.B #include <sys/syscall.h> +.sp +.BI "int syscall(unsigned int " syscallnr ", ...);" +.fi +.SH DESCRIPTION +.B syscall +does an indirect syscall. The parameter +.B syscallnr +is the number of the syscall. The other optional parameters are the +ones of the attempted syscall. +.B syscallnr +may no be SYS_syscall. +.PP +.SH "RETURN VALUE" +.B syscall +returns a return value as if the syscall indicated by +.B syscall +would have been called directly. If errors are detected, errno will indicate +the error. +.SH ERRORS +.TP +.B ENOSYS +syscallnr has no legal value or the syscall indicated by syscallnr is not +supported by the system. +.PP +For other values of errno see the documentation of the syscall indicated by +syscallnr. +.SH BUGS +Syscall(2) hasn't yet been tested. +.SH NOTE +This system call is only available on MIPS based systems. The other Linux +systems implement syscall(2) as library function in libc. +.SH "SEE ALSO" +Manpage of the syscall indicated by syscallnr. diff --git a/arch/mips/man/man8/hardware.8 b/arch/mips/man/man8/hardware.8 new file mode 100644 index 000000000..b19e2d4e0 --- /dev/null +++ b/arch/mips/man/man8/hardware.8 @@ -0,0 +1,97 @@ +.\" Copyright 1996 by Ralf Baechle (ralf@uni-koblenz.de) +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual 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 License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH HARDWARE 8 "29 May 96" "Linux" "Supported hardware" + +.SH ABSTRACT +This file contains information about the status of hardware support +of the various ports of Linux/MIPS. + +.TP +.B "Acer PICA 61" + Supported; the onboard S3 graphics is fully supported in the + text mode as well as the parallel port and the floppy (buggy). There + are no drivers available yet for the onboard Ethernet interface and + SCSI controller. However 35c03 Ethernet cards are working in PIO mode + after disabeling the shared memory detection code, IDE harddisk and + CD ROM have been successfully tested as well as NE2000 Ethernet cards + and the DPT PM2041W ISA SCSI hostadapter (drivers EATA-DMA and + EATA-PIO). In general all drivers that do PIO via ports are supposed + to work. +.TP +.B "Mips Magnum 4000" + Same status as Acer PICA 61; additionally the serial interface is + supported. The current console driver for the standard G364 video + is however just a quick hack of \"better than nothing\" quality, + very unreliable and causes many crashes. It's as well very slow. + A replacement driver is in development. +.TP +.B "Olivetti M700" + Same status like Mips Magnum but the serial interface isn't + supported yet due to a smell, not yet know hardware difference + (different crystal clock for the serial interface) to the Magnum. +.TP +.B "Mips Magnum 3000" + This port hasn't been started yet but demand is relativly high. + So chances for this are still good. + +.TP +.B "SNI RM 200" + Current status is that the ARC bootloader Milo is now also working + on the unusually bahaving SNI ARC BIOS 4.05 (which is supposed to + be the current version as of this writing); the kernel itself + supports the builtin VGA card and floppy controller. It boots via + an ISA NE2000 card from NFS; ISA DPT hostadapters have also + successfully been tested. Other SNI hardware isn't supported yet. + +.TP +.B "Deskstation Tyne" + This R4600 based machine was the original targets for +.IR "Linux/MIPS" ; + the port has stalled due to a defective motherboard. The code + hasn't been tested for over a year; if it's working at all only + console and PIO via ports based drivers are working. + +.TP +.B "Deskstation rPC44" + (Warner could you please write something apropriate here?) + +.TP +.B "SGI" + There is currently no port to SGI hardware; a port is about to + start. Due to the resources SGI is willing to invest in this + project this port will probably advance rather fast and help to + improve Linux/MIPS in general so stay tuned. According to SGI + also support of SMP machines is planned. + +.TP +.B "DECstation" + This port is currently experimental; it involves not only the + port to a new, not PC-like hardware but also to the R3000 + CPU. + Current status is that the kernel initializes and reaches the + BogoMIPS (TM) performance test where it locks up. +.SH NOTES + I urge all the developers to send me updates to this file as soon + new configurations have been tested. +.SH BUGS + Like every documentation this file is determined to be outdated. diff --git a/arch/mips/mips1/Makefile b/arch/mips/mips1/Makefile new file mode 100644 index 000000000..3e9f13037 --- /dev/null +++ b/arch/mips/mips1/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the MIPS I specific parts of the Linux/MIPS kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: mips.o +EXTRA_ASFLAGS = -mips1 -mcpu=r3000 +O_TARGET := mips.o +O_OBJS := cache.o cpu.o memcpy.o memset.o r3000.o pagetables.o showregs.o + fp-context.o + +r3000.o: r3000.S + +fp-context.o: fp-context.S + +cache.o: cache.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/mips1/cache.S b/arch/mips/mips1/cache.S new file mode 100644 index 000000000..788a567e8 --- /dev/null +++ b/arch/mips/mips1/cache.S @@ -0,0 +1,162 @@ +# R3000 cache routines lifted from IDT documentation +# by Ruud Riem-Viis. Adapted for linux by Didier Frick +# (dfrick@dial.eunet.ch) + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/processor.h> +#include <asm/regdef.h> +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/mipsconfig.h> +#include <asm/stackframe.h> +#include <asm/bootinfo.h> + +#define MINCACHE 0x00200 /* minimum cache size 512 */ +#define MAXCACHE 0x04000 /* maximum cache size 16K */ + +/* + * Figure out the size of the I- and D-caches, using the diagnostic isolate + * swap features. The cache size is left in an environment variable because + * the system will want to know it later. + * Flush the cache so that it is in a known state. + */ +NESTED(cache_init,8,ra) + subu sp, sp, 24 # keep sp aligned on 8 words + sw ra, 20(sp) # push return address on stack + sw s0, 16(sp) # save s0 on stack + mfc0 s0, CP0_STATUS # save sr + mtc0 zero, CP0_STATUS + nop + .set reorder + jal cache_size + sw v0, mips_dcache_size + li v0, ST0_CE # swap caches + .set noreorder + mtc0 v0, CP0_STATUS + nop + jal cache_size + nop + sw v0, mips_icache_size + mtc0 zero, CP0_STATUS # swap back caches + nop + mtc0 s0, CP0_STATUS # restore sr + nop + .set reorder + jal cache_flush + lw s0, 16(sp) # restore s0 + lw ra, 20(sp) + addu sp, sp, 24 + j ra + nop +END(cache_init) + +LEAF(cache_size) + .set noreorder + mfc0 t0, CP0_STATUS # save current SR + nop + and t0, ~ST0_SR # do not clear parity error bit + or v0, t0, ST0_DE # isolate cache + mtc0 v0, CP0_STATUS + nop + + move v0, zero + li v1, 0xa5a5a5a5 + nop + sw v1, KSEG0 # try to write in cache + lw t1, KSEG0 # try to read from cache + nop + mfc0 t2, CP0_STATUS + nop + .set reorder + and t2, (1<<19) + bne t2, zero, 3f # cache miss, must be no cache + bne v1, t1, 3f # data not equal -> no cache + +/* + * Clear cache boundries to known state. + */ + li v0, MINCACHE +1: + sw zero, KSEG0(v0) + sll v0, 1 + ble v0, MAXCACHE, 1b + + li v0, -1 + sw v0, KSEG0(zero) # store marker in cache + li v0, MINCACHE # MIN cache size +2: + lw v1, KSEG0(v0) # look for marker + bne v1, zero, 3f # found marker + sll v0, 1 # cache size * 2 + ble v0, MAXCACHE, 2b # keep looking + move v0, zero # must be no cache + .set noreorder +3: + mtc0 t0, CP0_STATUS # restore sr + nop + j ra + nop + .set reorder +END(cache_size) + +LEAF(cache_flush) + lw t1, mips_icache_size + lw t2, mips_dcache_size + .set noreorder + mfc0 t3, CP0_STATUS # save sr + nop + and t3, ~ST0_SR # do not clear PE + beq t1, zero, check_dcache # if no icache, check dcache + nop + li v0, ST0_DE | ST0_CE # isolate and swap + nop + mtc0 v0, CP0_STATUS + nop + li t0, KSEG0 + .set reorder + or t1, t0, t1 +1: + sb zero, 0(t0) + sb zero, 4(t0) + sb zero, 8(t0) + sb zero, 12(t0) + sb zero, 16(t0) + sb zero, 20(t0) + sb zero, 24(t0) + addu t0, 32 + sb zero, -4(t0) + bne t0, t1, 1b # continue until done + +check_dcache: + li v0, ST0_DE + nop + .set noreorder + mtc0 v0, CP0_STATUS + nop + beq t2, zero, flush_done # if no dcache, done + .set reorder + li t0, KSEG0 + or t1, t0, t2 +1: + sb zero, 0(t0) + sb zero, 4(t0) + sb zero, 8(t0) + sb zero, 12(t0) + sb zero, 16(t0) + sb zero, 20(t0) + sb zero, 24(t0) + addu t0, 32 + sb zero, -4(t0) + bne t0, t1, 1b # continue until done + + .set noreorder +flush_done: + mtc0 t3, CP0_STATUS # restore old sr + nop + j ra + nop + .set reorder +END(cache_flush) + + diff --git a/arch/mips/mips1/cpu.c b/arch/mips/mips1/cpu.c new file mode 100644 index 000000000..fd41ce15b --- /dev/null +++ b/arch/mips/mips1/cpu.c @@ -0,0 +1,91 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/sched.h> + +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/processor.h> + +extern asmlinkage void mips1_cacheflush(void *addr, int nbytes, unsigned int flags); + +void (*mips_cache_init)(void); + +static void +mips1_cache_init(void) +{ + cacheflush = mips1_cacheflush; +} + +void (*switch_to_user_mode)(struct pt_regs *regs); + +static void +mips1_switch_to_user_mode(struct pt_regs *regs) +{ + regs->cp0_status = regs->cp0_status | ST0_KUC; +} + +unsigned long (*thread_saved_pc)(struct thread_struct *t); + +/* + * Return saved PC of a blocked thread. + */ +static unsigned long mips1_thread_saved_pc(struct thread_struct *t) +{ + return ((unsigned long *)(unsigned long)t->reg29)[13]; +} + +unsigned long (*get_wchan)(struct task_struct *p); + +static unsigned long mips1_get_wchan(struct task_struct *p) +{ + /* + * This one depends on the frame size of schedule(). Do a + * "disass schedule" in gdb to find the frame size. Also, the + * code assumes that sleep_on() follows immediately after + * interruptible_sleep_on() and that add_timer() follows + * immediately after interruptible_sleep(). Ugly, isn't it? + * Maybe adding a wchan field to task_struct would be better, + * after all... + */ + unsigned long schedule_frame; + unsigned long pc; + + pc = thread_saved_pc(&p->tss); + if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { + schedule_frame = ((unsigned long *)(long)p->tss.reg30)[13]; + return ((unsigned long *)schedule_frame)[11]; + } + return pc; +} + +void (*pgd_init)(unsigned long page); +void (*copy_page)(unsigned long to, unsigned long from); +asmlinkage void (*restore_fp_context)(struct sigcontext *sc); +asmlinkage void (*save_fp_context)(struct sigcontext *sc); + +void +mips1_cpu_init(void) +{ + extern void mips1_cache_init(void); + extern void mips1_pgd_init(unsigned long page); + extern void mips1_clear_page(unsigned long page); + extern void mips1_copy_page(unsigned long to, unsigned long from); + extern asmlinkage void mips1_restore_fp_context(struct sigcontext *sc); + extern asmlinkage void mips1_save_fp_context(struct sigcontext *sc); + + mips_cache_init = mips1_cache_init; + pgd_init = mips1_pgd_init; + switch_to_user_mode = mips1_switch_to_user_mode; + thread_saved_pc = mips1_thread_saved_pc; + get_wchan = mips1_get_wchan; + clear_page = mips1_clear_page; + copy_page = mips1_copy_page; + restore_fp_context = mips1_restore_fp_context; + save_fp_context = mips1_save_fp_context; +} diff --git a/arch/mips/mips1/fp-context.S b/arch/mips/mips1/fp-context.S new file mode 100644 index 000000000..6ff3c6be3 --- /dev/null +++ b/arch/mips/mips1/fp-context.S @@ -0,0 +1,159 @@ +/* + * Save/restore floating point context for signal handlers. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/fpregdef.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/sigcontext.h> + +#define SWC1(r,m) \ +7: swc1 r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define SW(r,m) \ +7: sw r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define LWC1(r,m) \ +7: lwc1 r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define LW(r,m) \ +7: lw r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + + .set noreorder +/* + * Save floating point context + */ +LEAF(mips1_save_fp_context) + mfc0 t0,CP0_STATUS + sll t0,t0,2 + bgez t0,1f + nop # delay slot + cfc1 t0,fcr31 + /* + * Store the 16 odd double precision registers + */ + SWC1 ($f0,(SC_FPREGS+0)(a0)) + SWC1 ($f1,(SC_FPREGS+8)(a0)) + SWC1 ($f2,(SC_FPREGS+16)(a0)) + SWC1 ($f3,(SC_FPREGS+24)(a0)) + SWC1 ($f4,(SC_FPREGS+32)(a0)) + SWC1 ($f5,(SC_FPREGS+40)(a0)) + SWC1 ($f6,(SC_FPREGS+48)(a0)) + SWC1 ($f7,(SC_FPREGS+56)(a0)) + SWC1 ($f8,(SC_FPREGS+64)(a0)) + SWC1 ($f9,(SC_FPREGS+72)(a0)) + SWC1 ($f10,(SC_FPREGS+80)(a0)) + SWC1 ($f11,(SC_FPREGS+88)(a0)) + SWC1 ($f12,(SC_FPREGS+96)(a0)) + SWC1 ($f13,(SC_FPREGS+104)(a0)) + SWC1 ($f14,(SC_FPREGS+112)(a0)) + SWC1 ($f15,(SC_FPREGS+120)(a0)) + SWC1 ($f16,(SC_FPREGS+128)(a0)) + SWC1 ($f17,(SC_FPREGS+136)(a0)) + SWC1 ($f18,(SC_FPREGS+144)(a0)) + SWC1 ($f19,(SC_FPREGS+152)(a0)) + SWC1 ($f20,(SC_FPREGS+160)(a0)) + SWC1 ($f21,(SC_FPREGS+168)(a0)) + SWC1 ($f22,(SC_FPREGS+176)(a0)) + SWC1 ($f23,(SC_FPREGS+184)(a0)) + SWC1 ($f24,(SC_FPREGS+192)(a0)) + SWC1 ($f25,(SC_FPREGS+200)(a0)) + SWC1 ($f26,(SC_FPREGS+208)(a0)) + SWC1 ($f27,(SC_FPREGS+216)(a0)) + SWC1 ($f28,(SC_FPREGS+224)(a0)) + SWC1 ($f29,(SC_FPREGS+232)(a0)) + SWC1 ($f30,(SC_FPREGS+240)(a0)) + SWC1 ($f31,(SC_FPREGS+248)(a0)) + SW (t0,SC_FPC_CSR(a0)) + cfc1 t0,$0 # implementation/version + jr ra + .set nomacro + SW t0,SC_FPC_EIR(a0) # delay slot + .set macro + +1: jr ra + .set nomacro + nop # delay slot + .set macro + END(mips1_save_fp_context) + +/* + * Restore fpu state: + * - fp gp registers + * - cp1 status/control register + * + * We base the decission which registers to restore from the signal stack + * frame on the current content of c0_status, not on the content of the + * stack frame which might have been changed by the user. + */ +LEAF(mips1_restore_fp_context) + mfc0 t0,CP0_STATUS + sll t0,t0,2 + bgez t0,1f + nop # delay slot + bgez t0,1f + LW (t0,SC_FPC_CSR(a0)) # delay slot + /* + * Restore the 16 odd double precision registers only + * when enabled in the cp0 status register. + */ + LWC1 ($f0,(SC_FPREGS+0)(a0)) + LWC1 ($f1,(SC_FPREGS+8)(a0)) + LWC1 ($f2,(SC_FPREGS+16)(a0)) + LWC1 ($f3,(SC_FPREGS+24)(a0)) + LWC1 ($f4,(SC_FPREGS+32)(a0)) + LWC1 ($f5,(SC_FPREGS+40)(a0)) + LWC1 ($f6,(SC_FPREGS+48)(a0)) + LWC1 ($f7,(SC_FPREGS+56)(a0)) + LWC1 ($f8,(SC_FPREGS+64)(a0)) + LWC1 ($f9,(SC_FPREGS+72)(a0)) + LWC1 ($f10,(SC_FPREGS+80)(a0)) + LWC1 ($f11,(SC_FPREGS+88)(a0)) + LWC1 ($f12,(SC_FPREGS+96)(a0)) + LWC1 ($f13,(SC_FPREGS+104)(a0)) + LWC1 ($f14,(SC_FPREGS+112)(a0)) + LWC1 ($f15,(SC_FPREGS+120)(a0)) + LWC1 ($f16,(SC_FPREGS+128)(a0)) + LWC1 ($f17,(SC_FPREGS+136)(a0)) + LWC1 ($f18,(SC_FPREGS+144)(a0)) + LWC1 ($f19,(SC_FPREGS+152)(a0)) + LWC1 ($f20,(SC_FPREGS+160)(a0)) + LWC1 ($f21,(SC_FPREGS+168)(a0)) + LWC1 ($f22,(SC_FPREGS+176)(a0)) + LWC1 ($f23,(SC_FPREGS+184)(a0)) + LWC1 ($f24,(SC_FPREGS+192)(a0)) + LWC1 ($f25,(SC_FPREGS+200)(a0)) + LWC1 ($f26,(SC_FPREGS+208)(a0)) + LWC1 ($f27,(SC_FPREGS+216)(a0)) + LWC1 ($f28,(SC_FPREGS+224)(a0)) + LWC1 ($f29,(SC_FPREGS+232)(a0)) + LWC1 ($f30,(SC_FPREGS+240)(a0)) + LWC1 ($f31,(SC_FPREGS+248)(a0)) + jr ra + .set nomacro + ctc1 t0,fcr31 # delay slot + .set macro + +1: jr ra + .set nomacro + nop # delay slot + .set macro + END(mips1_restore_fp_context) diff --git a/arch/mips/mips1/memcpy.S b/arch/mips/mips1/memcpy.S new file mode 100644 index 000000000..9685fa8df --- /dev/null +++ b/arch/mips/mips1/memcpy.S @@ -0,0 +1,206 @@ +/* + * arch/mips/mips1/memcpy.S + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1996 by Ralf Baechle + * + * Less stupid memcpy/user_copy implementation for 32 bit MIPS CPUs. + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> + +#define BLOCK_SIZE 16 + +#define EX(addr,handler) \ + .section __ex_table,"a"; \ + PTR addr, handler; \ + .text +#define UEX(addr,handler) \ + EX(addr,handler); \ + EX(addr+4,handler) + + .set noreorder + .set noat + +/* ---------------------------------------------------------------------- */ + +/* + * Bad. We can't fix the alignment for both address parts. + * Align the source address and copy slowly ... + */ +not_even_the_same_alignment: + LONG_SUBU v1,zero,a1 + andi v1,a1,3 + sltu t0,v0,v1 + MOVN(v1,v0,t0) + beqz v1,align4 # -> finished + LONG_ADDU v1,a0 # delay slot +1: lb $1,(a1) + EX(1b, fault) + LONG_ADDIU a1,1 +2: sb $1,(a0) + EX(2b, fault) + LONG_ADDIU a0,1 + bne a0,v1,1b + LONG_SUBU v0,1 # delay slot + +/* + * Ok. We've fixed the alignment of the copy src for this case. + * Now let's copy in the usual BLOCK_SIZE byte blocks using unaligned + * stores. + * XXX Align the destination address. This is better if the __copy_user + * encounters an access fault because we never have to deal with an + * only partially modified destination word. + */ + ori v1,v0,BLOCK_SIZE-1 + xori v1,BLOCK_SIZE-1 + beqz v1,copy_left_over + nop # delay slot + LONG_SUBU v0,v1 + LONG_ADDU v1,a0 + +1: lw t0,(a1) # Can cause tlb fault + EX(1b, fault) +2: lw t1,4(a1) # Can cause tlb fault + EX(2b, fault) +2: lw t2,8(a1) # Can cause tlb fault + EX(2b, fault) +2: lw t3,12(a1) # Can cause tlb fault + EX(2b, fault) +2: usw t0,(a0) # Can cause tlb faults + UEX(2b, fault) +2: usw t1,4(a0) # Can cause tlb faults + UEX(2b, fault_plus_4) +2: usw t2,8(a0) # Can cause tlb faults + UEX(2b, fault_plus_8) +2: usw t3,12(a0) # Can cause tlb faults + UEX(2b, fault_plus_12) + LONG_ADDIU a0,BLOCK_SIZE + bne a0,v1,1b + LONG_ADDIU a1,BLOCK_SIZE # delay slot +9: + b copy_left_over # < BLOCK_SIZE bytes left + nop # delay slot + +/* ---------------------------------------------------------------------- */ + +not_w_aligned: +/* + * Ok, src or destination are not 8-byte aligned. + * Try to fix that. Do at least both addresses have the same alignment? + */ + xor t0,a0,a1 + andi t0,3 + bnez t0,not_even_the_same_alignment + nop # delay slot + +/* + * Ok, we can fix the alignment for both operands and go back to the + * fast path. We have to copy at least one byte, on average 3 bytes + * bytewise. + */ + LONG_SUBU v1,zero,a0 + andi v1,3 + sltu t0,v0,v1 + MOVN(v1,v0,t0) + beqz v1,align4 # -> finished + LONG_ADDU v1,a0 # delay slot +1: lb $1,(a1) + EX(1b, fault) + LONG_ADDIU a1,1 +2: sb $1,(a0) + EX(2b, fault) + LONG_ADDIU a0,1 + bne a0,v1,1b + LONG_SUBU v0,1 # delay slot + b align4 + nop # delay slot + +/* ---------------------------------------------------------------------- */ + +LEAF(__copy_user) + or t1,a0,a1 + andi t1,3 + bnez t1,not_w_aligned + move v0,a2 # delay slot + +align4: + ori v1,v0,BLOCK_SIZE-1 + xori v1,BLOCK_SIZE-1 + beqz v1,copy_left_over + nop # delay slot + LONG_SUBU v0,v1 + LONG_ADDU v1,a0 + +1: lw t0,(a1) # Can cause tlb fault + EX(1b, fault) +2: lw t1,4(a1) # Can cause tlb fault + EX(2b, fault) +2: lw t2,8(a1) # Can cause tlb fault + EX(2b, fault) +2: lw t3,12(a1) # Can cause tlb fault + EX(2b, fault) +2: sw t0,(a0) # Can cause tlb fault + EX(2b, fault) +2: sw t1,4(a0) # Can cause tlb fault + EX(2b, fault_plus_4) +2: sw t2,8(a0) # Can cause tlb fault + EX(2b, fault_plus_8) +2: sw t3,12(a0) # Can cause tlb fault + EX(2b, fault_plus_12) + LONG_ADDIU a0,BLOCK_SIZE + bne a0,v1,1b + LONG_ADDIU a1,BLOCK_SIZE # delay slot +9: + +/* + * XXX Tune me ... + */ +copy_left_over: + beqz v0,3f + nop # delay slot +1: lb $1,(a1) + EX(1b, fault) + LONG_ADDIU a1,1 +2: sb $1,(a0) + EX(2b, fault) + LONG_SUBU v0,1 + bnez v0,1b + LONG_ADDIU a0,1 +3: jr ra + nop # delay slot + + END(__copy_user) + .set at + .set reorder + +/* ---------------------------------------------------------------------- */ + +/* + * Access fault. The number of not copied bytes is in v0. We have to + * correct the number of the not copied bytes in v0 in case of a access + * fault in an unrolled loop, then return. + */ + +fault: jr ra +fault_plus_4: LONG_ADDIU v0,4 + jr ra +fault_plus_8: LONG_ADDIU v0,8 + jr ra +fault_plus_12: LONG_ADDIU v0,12 + jr ra + +/* ---------------------------------------------------------------------- */ + +/* + * For now we use __copy_user for __memcpy, too. This is effizient (one + * instruction penatly) and smaller but adds unwanted error checking we don't + * need. This hopefully doesn't cover any bugs. The memcpy() wrapper in + * <asm/string.h> takes care of the return value in a way GCC can optimize. + */ + .globl __memcpy +__memcpy = __copy_user diff --git a/arch/mips/mips1/memset.S b/arch/mips/mips1/memset.S new file mode 100644 index 000000000..5cfb5d9a7 --- /dev/null +++ b/arch/mips/mips1/memset.S @@ -0,0 +1,27 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + * + * Generic memset for all MIPS CPUs. + * This is time critical. Hear it crying "optimize me" ... + */ +#include <asm/asm.h> +#include <asm/regdef.h> + +LEAF(__generic_memset_b) +__generic_memset_dw = __generic_memset_b + .set noreorder + beqz a2,2f + LONG_ADDU a3,a0,a2 + .set reorder + LONG_SUBU a3,1 +1: sb a1,(a0) + .set noreorder + bne a0,a3,1b + LONG_ADDIU a0,1 + .set reorder +2: jr ra + END(__generic_memset_b) diff --git a/arch/mips/mips1/pagetables.c b/arch/mips/mips1/pagetables.c new file mode 100644 index 000000000..22419d1c9 --- /dev/null +++ b/arch/mips/mips1/pagetables.c @@ -0,0 +1,86 @@ +/* + * 32 bit MIPS specific page handling. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/mm.h> +#include <asm/cache.h> +#include <asm/mipsconfig.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +void (*pgd_init)(unsigned long page); + +/* + * Initialize new page directory with pointers to invalid ptes + */ +void mips1_pgd_init(unsigned long page) +{ + unsigned long dummy1, dummy2; + + /* + * The plain and boring version for the R3000. No cache flushing + * stuff is needed since the R3000 has physical caches. + */ + __asm__ __volatile__( + ".set\tnoreorder\n" + "1:\tsw\t%2,(%0)\n\t" + "sw\t%2,4(%0)\n\t" + "sw\t%2,8(%0)\n\t" + "sw\t%2,12(%0)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%2,20(%0)\n\t" + "sw\t%2,24(%0)\n\t" + "sw\t%2,28(%0)\n\t" + "subu\t%1,1\n\t" + "bnez\t%1,1b\n\t" + "addiu\t%0,32\n\t" + ".set\treorder" + :"=r" (dummy1), + "=r" (dummy2) + :"r" (((unsigned long) invalid_pte_table /* - PAGE_OFFSET */ ) | + _PAGE_TABLE), + "0" (page), + "1" (PAGE_SIZE/(sizeof(pmd_t)*8))); +} + +void (*clear_page)(unsigned long page) + +/* + * To do: cache magic ... + */ +void mips1_clear_page(unsigned long page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "addiu\t$1,%0,%2\n" + "1:\tsw\t$0,(%0)\n\t" + "sw\t$0,4(%0)\n\t" + "sw\t$0,8(%0)\n\t" + "sw\t$0,12(%0)\n\t" + "addiu\t%0,32\n\t" + "sw\t$0,-16(%0)\n\t" + "sw\t$0,-12(%0)\n\t" + "sw\t$0,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t$0,-4(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE) + :"$1","memory"); +} + +void (*copy_page)(unsigned long to, unsigned long from); + +void mips1_copy_page(unsigned long to, unsigned long from) +{ + memcpy((void *) to, + (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE); +} diff --git a/arch/mips/mips1/r3000.S b/arch/mips/mips1/r3000.S new file mode 100644 index 000000000..25529d9a0 --- /dev/null +++ b/arch/mips/mips1/r3000.S @@ -0,0 +1,1125 @@ +/* + * arch/mips/kernel/r3000.S + * + * Copyright (C) 1994, 1995 Waldorf Electronics, 1996 Paul M. Antoine + * Written by Ralf Baechle and Andreas Busse + * Modified for R3000 by Paul M. Antoine + * + * Additional R3000 support by Didier Frick <dfrick@dial.eunet.ch> + * for ACN S.A, Copyright (C) 1996 by ACN S.A + * + * This file contains most of the R3000/R3000A specific routines, which would + * probably work on the R2000 (if anyone's interested!). + * + * This code is evil magic. Read appendix f (coprocessor 0 hazards) of + * all R3000/MIPS manuals and think about that MIPS means "Microprocessor without + * Interlocked Pipeline Stages" before you even think about changing this code! + * + * Then remember that some bugs here are due to my not having completely + * converted the R4xx0 code to R3000 and that the R4xx0 CPU's are more + * forgiving than the R3000/A!! All that, and the fact that I'm not up to + * 'guru' level on R3000 - PMA. + * (Paul, I replaced all occurances of TLBMAPHI with %HI(TLBMAP) -- Ralf) + */ +#include <linux/config.h> + +#include <asm/asm.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/fpregdef.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +#ifdef __SMP__ +#error "Fix this for SMP!" +#else +#define current current_set +#endif + +/* + +FIXME: + - First of all, this really screams for a light version of SAVE_ALL + and RESTORE_ALL, saving and restoring only the context actually + needed in this case. I'm afraid it's necessary to save some context + on the stack because on the R3000 tlb exceptions can nest in some + cases where they wouldn't on the R4000. + + - The TLB handling code should be completely rewritten for the R3000 + because too many things are different from the R4000. + For instance, the CP0_CONTEXT register has a different format + and cannot be reused with the current setup. + I really had to do a fast hack to get it to work, but no time to do + it cleanly for now, sorry. + We also introduced a tlb_softindex variable to point to the next + TLB entry to write. This variable is incremented everytime we add a + new entry to the TLB. We did this because we felt that using the + CP0_RANDOM register could be unsafe in some cases (like trashing + the TLB entry for the handler's return address in user space). + It's very possible that we are wrong on this one, but we had so + much trouble with this TLB thing that we chose the safe side. +*/ + +#define CONF_DEBUG_TLB +#undef CONFIG_TLB_SHUTDOWN +#undef TLB_LOG + +MODE_ALIAS = 0x00e0 # cachable + + .text + .set mips1 + .set noreorder + + .align 5 + NESTED(handle_tlbl, FR_SIZE, sp) + .set noat + /* + * Check whether this is a refill or an invalid exception + */ + mfc0 k0,CP0_BADVADDR + nop + mfc0 k1,CP0_ENTRYHI + ori k0,0xfff # clear ASID... + xori k0,0xfff # in BadVAddr + andi k1,0xfc0 # get current ASID + or k0,k1 # make new entryhi + mfc0 k1,CP0_ENTRYHI + nop + mtc0 k0,CP0_ENTRYHI + nop # for pipeline + tlbp + nop # for pipeline + mfc0 k0,CP0_INDEX + nop + mtc0 k1,CP0_ENTRYHI # delay slot + bgez k0,invalid_tlbl # bad addr in c0_badvaddr + nop + + + mfc0 k0,CP0_BADVADDR + lui k1,0xe000 + subu k0,k0,k1 + bgez k0,1f + nop + j real_utlb + nop + +1: + + +#ifdef CONF_DEBUG_TLB + /* + * OK, this is a double fault. Let's see whether this is + * due to an invalid entry in the page_table. + */ + + lw k0, tlbl_lock + nop + bnez k0,1f + li k1,1 + la k0, tlbl_lock + sw k1,(k0) + + + mfc0 k0,CP0_BADVADDR + lui k1,58368 + srl k0,12 # get PFN? + sll k0,2 + addu k0,k1 + lw k1,(k0) + nop + andi k1,(_PAGE_PRESENT|_PAGE_ACCESSED) + bnez k1,reload_pgd_entries + nop # delay slot + +1: + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + + PRINT("Double fault caused by invalid entries in pgd:\n") + mfc0 a1,CP0_BADVADDR + nop + PRINT("Double fault address : %08lx\n") + mfc0 a1,CP0_EPC + nop + PRINT("c0_epc : %08lx\n") + jal show_regs + move a0,sp + jal dump_tlb_nonwired + nop + mfc0 a0,CP0_BADVADDR + jal dump_list_current + nop + .set noat + STI + .set at + PANIC("Corrupted pagedir") + .set noat + +reload_pgd_entries: +#endif /* CONF_DEBUG_TLB */ + + /* + * Load missing pair of entries from the pgd and return. + */ + + mfc0 k0,CP0_BADVADDR + nop + lui k1,58368 + + srl k0,12 + sll k0,2 + addu k0,k1 + lw k0,(k0) + nop + mtc0 k0,CP0_ENTRYLO0 + + la k0, tlb_softIndex + lw k1,(k0) + nop + mtc0 k1,CP0_INDEX + nop + addu k1,(1<<8) + andi k0,k1,(63<<8) + bnez k0, 1f + nop + li k1,(8<<8) +1: + la k0, tlb_softIndex + sw k1,(k0) + + + nop + nop + nop # for pipeline + tlbwi + nop # for pipeline + nop + nop + + +#ifdef CONF_DEBUG_TLB + la k0, tlbl_lock + sw zero,(k0) +#endif + mfc0 k0,CP0_EPC + nop + jr k0 + rfe + nop + + + /* + * Handle invalid exception + * + * There are two possible causes for an invalid (tlbl) + * exception: + * 1) pages with present bit set but the valid bit clear + * 2) nonexistant pages + * Case one needs fast handling, therefore don't save + * registers yet. + * + * k0 contains c0_index. + */ +invalid_tlbl: + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + +#ifdef TLB_LOG + PRINT ("tlbl: invalid\n"); + nop +#endif + /* + * Test present bit in entry + */ + lw s0,FR_BADVADDR(sp) + nop + srl s0,12 + sll s0,2 + lui k1,58368 + addu s0,k1 + + lw k1,(s0) + nop + andi k1,(_PAGE_PRESENT|_PAGE_READ) + xori k1,(_PAGE_PRESENT|_PAGE_READ) + bnez k1,nopage_tlbl + nop + /* + * Present and read bits are set -> set valid and accessed bits + */ + lw k1,(s0) # delay slot + nop + ori k1,(_PAGE_VALID|_PAGE_ACCESSED) + sw k1,(s0) + + mtc0 k1,CP0_ENTRYLO0 + nop + tlbwi + nop + nop + + j return + nop + + /* + * Page doesn't exist. Lots of work which is less important + * for speed needs to be done, so hand it all over to the + * kernel memory management routines. + */ +nopage_tlbl: +/* SAVE_ALL */ + REG_S sp,FR_ORIG_REG2(sp) */ +#ifdef TLB_LOG + PRINT ("nopage_tlbl\n"); + nop +#endif +#ifdef CONFIG_TLB_SHUTDOWN + mfc0 t0,CP0_INDEX + sll t0,4 + la t1,KSEG1 + or t0,t1 + mtc0 t0,CP0_ENTRYHI + mtc0 zero,CP0_ENTRYLO0 + nop + nop + tlbwi + nop + nop +#endif + + lw a2,FR_BADVADDR(sp) + li t1,-1 # not a sys call + sw t1,FR_ORIG_REG2(sp) + nop + STI + .set at + /* + * a0 (struct pt_regs *) regs + * a1 (unsigned long) 0 for read access + * a2 (unsigned long) faulting virtual address + */ + move a0,sp + jal do_page_fault + li a1,0 # delay slot + j ret_from_sys_call + nop # delay slot + END(handle_tlbl) + + .text + .align 5 + NESTED(handle_tlbs, FR_SIZE, sp) + .set noat + /* + * It is impossible that is a nested reload exception. + * Therefore this must be a invalid exception. + * Two possible cases: + * 1) Page exists but not dirty. + * 2) Page doesn't exist yet. Hand over to the kernel. + * + * Test whether present bit in entry is set + */ + /* used to be dmfc0 */ + +#ifdef CONF_DEBUG_TLB + + la k0,tlbs_lock + lw k1,(k0) + nop + beqz k1,3f + nop + .set noat + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + .set at + PRINT("Nested tlbs exception:\n") + mfc0 a1,CP0_BADVADDR + nop + PRINT("Virtual address : %08lx\n") + mfc0 a1,CP0_EPC + nop + PRINT("c0_epc : %08lx\n") + jal show_regs + move a0,sp + jal dump_tlb_nonwired + nop + mfc0 a0,CP0_BADVADDR + jal dump_list_current + nop + .set noat + STI + .set at + PANIC("Nested tlbs exception") + +3: + li k1,1 + sw k1,(k0) + +#endif + .set noat + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + .set at + + mfc0 s0,CP0_BADVADDR + + lui k1,58368 + srl s0,12 + sll s0,2 + addu s0,k1 + nop + lw k1,(s0) # may cause nested xcpt. + nop + move k0,s0 + + lw k1,FR_ENTRYHI(sp) + nop + mtc0 k1,CP0_ENTRYHI + nop + nop + tlbp # find faulting entry + nop + lw k1,(k0) + nop + andi k1,(_PAGE_PRESENT|_PAGE_WRITE) + xori k1,(_PAGE_PRESENT|_PAGE_WRITE) + bnez k1,nopage_tlbs + nop + /* + * Present and writable bits set: set accessed and dirty bits. + */ + lw k1,(k0) # delay slot + nop + ori k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \ + _PAGE_VALID|_PAGE_DIRTY) + sw k1,(k0) + /* + * Now reload the entry into the TLB + */ + mtc0 k1,CP0_ENTRYLO0 + nop + nop + nop # for pipeline + tlbwi + nop # for pipeline +#ifdef CONF_DEBUG_TLB + la k0,tlbs_lock + li k1,0 + sw k1,(k0) +#endif + j return + nop + + /* + * Page doesn't exist. Lots of work which is less important + * for speed needs to be done, so hand it all over to the + * kernel memory management routines. + */ +nowrite_mod: +nopage_tlbs: + +#ifdef CONFIG_TLB_SHUTDOWN + /* + * Remove entry so we don't need to care later + */ + mfc0 k0,CP0_INDEX + nop +#ifdef CONF_DEBUG_TLB + bgez k0,2f + nop + /* + * We got a tlbs exception but found no matching entry in + * the tlb. This should never happen. Paranoia makes us + * check it, though. + */ + .set noat +/* SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) */ + jal show_regs + move a0,sp + .set at + la a1,FR_BADVADDR(sp) + lw a1,(a1) + nop + PRINT("c0_badvaddr == %08lx\n") + nop + mfc0 a1,CP0_INDEX + nop + PRINT("c0_index == %08x\n") + nop + la a1,FR_ENTRYHI(sp) + lw a1,(a1) + nop + PRINT("c0_entryhi == %08x\n") + nop + jal dump_tlb_nonwired + nop + la a0,FR_BADVADDR(sp) + lw a0,(a0) + jal dump_list_current + nop + + .set noat + STI + .set at + PANIC("Tlbs or tlbm exception with no matching entry in tlb") +1: j 1b + nop +2: +#endif /* CONF_DEBUG_TLB */ + lui k1,0xa000 + sll k0,4 + or k0,k1 + xor k0,k1 + or k0,k1 # make it a KSEG1 address + mtc0 k0,CP0_ENTRYHI + nop + mtc0 zero,CP0_ENTRYLO0 + nop + nop + nop + tlbwi + nop +#endif /* CONFIG_TLB_SHUTDOWN */ + +#ifdef CONF_DEBUG_TLB + la k0,tlbs_lock + li k1,0 + sw k1,(k0) +#endif + .set noat +/* SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) */ + lw a2,FR_BADVADDR(sp) + li t1,-1 + sw t1,FR_ORIG_REG2(sp) # not a sys call + nop + STI + .set at + /* + * a0 (struct pt_regs *) regs + * a1 (unsigned long) 1 for write access + * a2 (unsigned long) faulting virtual address + */ + move a0,sp + jal do_page_fault + li a1,1 # delay slot + j ret_from_sys_call + nop # delay slot + END(handle_tlbs) + + .align 5 + NESTED(handle_mod, FR_SIZE, sp) + .set noat + /* + * Two possible cases: + * 1) Page is writable but not dirty -> set dirty and return + * 2) Page is not writable -> call C handler + */ + /* used to be dmfc0 */ + + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + + mfc0 s0,CP0_BADVADDR + nop + + srl s0,12 + sll s0,2 + lui k1,58368 + addu s0,k1 + lw k1,(s0) + nop + move k0,s0 + nop + + lw k1,FR_ENTRYHI(sp) + nop + mtc0 k1,CP0_ENTRYHI + nop + tlbp + nop + lw k1,(k0) + nop + andi k1,_PAGE_WRITE + beqz k1,nowrite_mod + nop + /* + * Present and writable bits set: set accessed and dirty bits. + */ + lw k1,(k0) # delay slot + nop + ori k1,(_PAGE_ACCESSED|_PAGE_DIRTY) + sw k1,(k0) + /* + * Now reload the entry into the tlb + */ + lw k0,(k0) + nop + mtc0 k0,CP0_ENTRYLO0 + nop + nop # for pipeline + nop + tlbwi + nop # for pipeline + j return + nop + END(handle_mod) + .set at + + .set reorder + LEAF(tlbflush) + + .set noreorder + + mfc0 t3,CP0_STATUS # disable interrupts... + nop + ori t4,t3,1 + xori t4,1 + mtc0 t4,CP0_STATUS + lw t1,mips_tlb_entries /* mips_tlb_enbtries is set */ + /* by bi_EarlySnarf() */ + mfc0 t0,CP0_ENTRYHI + nop + mtc0 zero,CP0_ENTRYLO0 + sll t1,t1,8 + li t2,KSEG1 + li t5,(7<<8) /* R3000 has 8 wired entries */ +1: + subu t1,(1<<8) + beq t1,t5,2f /* preserve wired entries */ + + sll t6,t1,4 + addu t6,t2 + mtc0 t6,CP0_ENTRYHI + nop + mtc0 t1,CP0_INDEX + nop + nop + nop + tlbwi + nop + b 1b + nop +2: + + mtc0 t0,CP0_ENTRYHI + nop + mtc0 t3,CP0_STATUS + nop + jr ra + nop + END(tlbflush) + +/* + * Flush a single entry from the TLB + * + * Parameters: a0 - unsigned long address + */ + .set noreorder + LEAF(tlbflush_page) + /* + * Step 1: Wipe out old TLB information. Not shure if + * we really need that step; call it paranoia ... + * In order to do that we need to disable interrupts. + */ + mfc0 t0,CP0_STATUS # interrupts off + nop + ori t1,t0,1 + xori t1,1 + mtc0 t1,CP0_STATUS + li t3,TLBMAP # then wait 3 cycles + ori t1,a0,0xfff # mask off low 12 bits + xori t1,0xfff + mfc0 t2,CP0_ENTRYHI # copy ASID into address + nop + andi t2,0xfc0 # ASID in bits 11-6 + or t2,t1 + mtc0 t2,CP0_ENTRYHI +/* FIXME: + shouldn't we save ENTRYHI before trashing it ? +*/ + + srl t4,a0,12 # wait again three cycles + sll t4,t4,PTRLOG + mtc0 zero,CP0_ENTRYLO0 + nop + tlbp # now query the TLB + addu t3,t4 # wait another three cycles + ori t3,0xffff + xori t3,0xffff + mfc0 t1,CP0_INDEX + nop + blez t1,1f # No old entry? + nop # delay slot + li t5, KSEG1 + sll t1,4 + addu t5,t1 + mtc0 t5,CP0_ENTRYHI + nop + nop + tlbwi + /* + * But there still might be a entry for the pgd ... + */ +1: mtc0 t3,CP0_ENTRYHI + nop # wait 3 cycles + nop + nop + tlbp # TLB lookup + nop + nop + mfc0 t1,CP0_INDEX # wait 3 cycles + nop + blez t1,1f # No old entry? + nop + li t5, KSEG1 + sll t1,4 + addu t5,t1 + mtc0 t5,CP0_ENTRYHI + nop + nop + tlbwi # gotcha ... + nop + nop + nop + +1: + mtc0 t0,CP0_STATUS + nop + jr ra + nop + + END(tlbflush_page) + + .set noreorder + LEAF(tlbload) + /* + address in a0 + pte in a1 + */ + + mfc0 t1,CP0_STATUS + nop + ori t0,t1,1 + xori t0,1 + mtc0 t0,CP0_STATUS + nop + mfc0 t0,CP0_ENTRYHI + nop + ori a0,0xfff + xori a0,0xfff + andi t2,t0,0xfc0 + or a0,t2 + mtc0 a0,CP0_ENTRYHI + nop + nop + mtc0 a1,CP0_ENTRYLO0 + + la t2, tlb_softIndex + lw t3,(t2) + nop + mtc0 t3, CP0_INDEX + nop + addu t3,(1<<8) + andi t2,t3,(63<<8) + bnez t2, 1f + nop + li t3,(8<<8) +1: + la t2, tlb_softIndex + sw t3,(t2) + + + nop + nop + nop + tlbwi + nop + nop + mtc0 t0,CP0_ENTRYHI + nop + mtc0 t1,CP0_STATUS + + jr ra + nop + + END(tlbload) + + + +/* + * Code necessary to switch tasks on an Linux/MIPS machine. + * FIXME: We don't need to disable interrupts anymore. + */ + .align 5 + LEAF(resume) + /* + * Current task's task_struct + */ + lui t5,%hi(current) + lw t0,%lo(current)(t5) + + /* + * Save status register + */ + mfc0 t1,CP0_STATUS + addu t0,a1 # Add tss offset + sw t1,TOFF_CP0_STATUS(t0) + +/* + li t2,ST0_CU0 + and t2,t1 + beqz t2,1f + nop + sw sp,TOFF_KSP(t0) +1: +*/ + /* + * Disable interrupts + */ +#ifndef __R3000__ + ori t2,t1,0x1f + xori t2,0x1e +#else + ori t2,t1,1 + xori t2,1 +#endif + mtc0 t2,CP0_STATUS + + /* + * Save non-scratch registers + * All other registers have been saved on the kernel stack + */ + sw s0,TOFF_REG16(t0) + sw s1,TOFF_REG17(t0) + sw s2,TOFF_REG18(t0) + sw s3,TOFF_REG19(t0) + sw s4,TOFF_REG20(t0) + sw s5,TOFF_REG21(t0) + sw s6,TOFF_REG22(t0) + sw s7,TOFF_REG23(t0) + sw gp,TOFF_REG28(t0) + sw sp,TOFF_REG29(t0) + sw fp,TOFF_REG30(t0) + + /* + * Save floating point state + */ + sll t2,t1,2 + bgez t2,2f + sw ra,TOFF_REG31(t0) # delay slot + sll t2,t1,5 + bgez t2,1f + swc1 $f0,(TOFF_FPU+0)(t0) # delay slot + /* + * Store the 16 odd double precision registers + */ + swc1 $f1,(TOFF_FPU+8)(t0) + swc1 $f3,(TOFF_FPU+24)(t0) + swc1 $f5,(TOFF_FPU+40)(t0) + swc1 $f7,(TOFF_FPU+56)(t0) + swc1 $f9,(TOFF_FPU+72)(t0) + swc1 $f11,(TOFF_FPU+88)(t0) + swc1 $f13,(TOFF_FPU+104)(t0) + swc1 $f15,(TOFF_FPU+120)(t0) + swc1 $f17,(TOFF_FPU+136)(t0) + swc1 $f19,(TOFF_FPU+152)(t0) + swc1 $f21,(TOFF_FPU+168)(t0) + swc1 $f23,(TOFF_FPU+184)(t0) + swc1 $f25,(TOFF_FPU+200)(t0) + swc1 $f27,(TOFF_FPU+216)(t0) + swc1 $f29,(TOFF_FPU+232)(t0) + swc1 $f31,(TOFF_FPU+248)(t0) + + /* + * Store the 16 even double precision registers + */ +1: cfc1 t1,fcr31 + swc1 $f2,(TOFF_FPU+16)(t0) + swc1 $f4,(TOFF_FPU+32)(t0) + swc1 $f6,(TOFF_FPU+48)(t0) + swc1 $f8,(TOFF_FPU+64)(t0) + swc1 $f10,(TOFF_FPU+80)(t0) + swc1 $f12,(TOFF_FPU+96)(t0) + swc1 $f14,(TOFF_FPU+112)(t0) + swc1 $f16,(TOFF_FPU+128)(t0) + swc1 $f18,(TOFF_FPU+144)(t0) + swc1 $f20,(TOFF_FPU+160)(t0) + swc1 $f22,(TOFF_FPU+176)(t0) + swc1 $f24,(TOFF_FPU+192)(t0) + swc1 $f26,(TOFF_FPU+208)(t0) + swc1 $f28,(TOFF_FPU+224)(t0) + swc1 $f30,(TOFF_FPU+240)(t0) + sw t1,(TOFF_FPU+256)(t0) + + /* + * Switch current task + */ +2: sw a0,%lo(current)(t5) + addu a0,a1 # Add tss offset + + /* + * Switch address space + */ + + /* + * (Choose new ASID for process) + * This isn't really required, but would speed up + * context switching. + */ + + /* + * Switch the root pointer + */ + lw t0,TOFF_PG_DIR(a0) # get PFN + li t1,TLB_ROOT + mtc0 t1,CP0_ENTRYHI + nop + mtc0 zero,CP0_INDEX + ori t0,MODE_ALIAS # want cachable, dirty, valid + mtc0 t0,CP0_ENTRYLO0 + nop + nop + nop + tlbwi # delay slot + nop + + /* + * Flush tlb + * (probably not needed, doesn't clobber a0-a3) + */ + jal tlbflush + nop + + lw a2,TOFF_CP0_STATUS(a0) + nop + + /* + * Restore fpu state: + * - cp0 status register bits + * - fp gp registers + * - cp1 status/control register + */ + ori t1,a2,1 # pipeline magic + xori t1,1 + mtc0 t1,CP0_STATUS + sll t0,a2,2 + bgez t0,2f + sll t0,a2,5 # delay slot + bgez t0,1f + nop + lwc1 $f0,(TOFF_FPU+0)(a0) # delay slot + /* + * Restore the 16 odd double precision registers only + * when enabled in the cp0 status register. + */ + lwc1 $f1,(TOFF_FPU+8)(a0) + lwc1 $f3,(TOFF_FPU+24)(a0) + lwc1 $f5,(TOFF_FPU+40)(a0) + lwc1 $f7,(TOFF_FPU+56)(a0) + lwc1 $f9,(TOFF_FPU+72)(a0) + lwc1 $f11,(TOFF_FPU+88)(a0) + lwc1 $f13,(TOFF_FPU+104)(a0) + lwc1 $f15,(TOFF_FPU+120)(a0) + lwc1 $f17,(TOFF_FPU+136)(a0) + lwc1 $f19,(TOFF_FPU+152)(a0) + lwc1 $f21,(TOFF_FPU+168)(a0) + lwc1 $f23,(TOFF_FPU+184)(a0) + lwc1 $f25,(TOFF_FPU+200)(a0) + lwc1 $f27,(TOFF_FPU+216)(a0) + lwc1 $f29,(TOFF_FPU+232)(a0) + lwc1 $f31,(TOFF_FPU+248)(a0) + + /* + * Restore the 16 even double precision registers + * when cp1 was enabled in the cp0 status register. + */ +1: lw t0,(TOFF_FPU+256)(a0) + lwc1 $f2,(TOFF_FPU+16)(a0) + lwc1 $f4,(TOFF_FPU+32)(a0) + lwc1 $f6,(TOFF_FPU+48)(a0) + lwc1 $f8,(TOFF_FPU+64)(a0) + lwc1 $f10,(TOFF_FPU+80)(a0) + lwc1 $f12,(TOFF_FPU+96)(a0) + lwc1 $f14,(TOFF_FPU+112)(a0) + lwc1 $f16,(TOFF_FPU+128)(a0) + lwc1 $f18,(TOFF_FPU+144)(a0) + lwc1 $f20,(TOFF_FPU+160)(a0) + lwc1 $f22,(TOFF_FPU+176)(a0) + lwc1 $f24,(TOFF_FPU+192)(a0) + lwc1 $f26,(TOFF_FPU+208)(a0) + lwc1 $f28,(TOFF_FPU+224)(a0) + lwc1 $f30,(TOFF_FPU+240)(a0) + ctc1 t0,fcr31 + + /* + * Restore non-scratch registers + */ +2: lw s0,TOFF_REG16(a0) + lw s1,TOFF_REG17(a0) + lw s2,TOFF_REG18(a0) + lw s3,TOFF_REG19(a0) + lw s4,TOFF_REG20(a0) + lw s5,TOFF_REG21(a0) + lw s6,TOFF_REG22(a0) + lw s7,TOFF_REG23(a0) + lw gp,TOFF_REG28(a0) + lw sp,TOFF_REG29(a0) + lw fp,TOFF_REG30(a0) + lw ra,TOFF_REG31(a0) + + /* + * Restore status register + */ + lw t0,TOFF_KSP(a0) + nop + sw t0,kernelsp + + mtc0 a2,CP0_STATUS # delay slot + jr ra + nop + END(resume) + + /* + * Load a new root pointer into the tlb + */ + .set noreorder + LEAF(load_pgd) + /* + * Switch the root pointer + */ + mfc0 t0,CP0_STATUS + nop + ori t1,t0,1 + xori t1,1 + mtc0 t1,CP0_STATUS + + ori a0,MODE_ALIAS + li t1,TLB_ROOT + mtc0 t1,CP0_ENTRYHI + nop + mtc0 zero,CP0_INDEX + nop + mtc0 a0,CP0_ENTRYLO0 + nop + nop + nop + tlbwi + nop + nop + mtc0 t0,CP0_STATUS + nop + jr ra + nop + END(load_pgd) + +/* + * Some bits in the config register + */ +#define CONFIG_DB (1<<4) +#define CONFIG_IB (1<<5) + +/* + * Flush instruction/data caches - FIXME: Don't know how to do this on R[236]000! + * (Actually most of this flushing stuff isn't needed for the R2000/R3000/R6000 + * since these CPUs have physical indexed caches unlike R4000 and better + * which have virtual indexed caches.) + * + * Parameters: a0 - starting address to flush + * a1 - size of area to be flushed + * a2 - which caches to be flushed + * + * FIXME: - ignores parameters in a0/a1 + * - doesn't know about second level caches + + */ + .set noreorder + LEAF(mips1_cacheflush) + +done: j cache_flush + nop + END(mips1_cacheflush) + +/* + * Invalidate virtual addresses. - FIXME: Don't know how on R[236]000 yet! + * (Flushing is relativly expensive; it isn't required at all if a + * particular machines' chipset keeps the external cache in a state that is + * consistent with memory -- Ralf) + * + * Parameters: a0 - starting address to flush + * a1 - size of area to be flushed + * + * FIXME: - ignores parameters in a0/a1 + * - doesn't know about second level caches + */ + .set noreorder + LEAF(fd_cacheflush) + jr ra + nop + END(fd_cacheflush) + +/* + * do_syscall calls the function in a1 with upto 7 arguments. If over + * four arguments are being requested, the additional arguments will + * be copied from the user stack pointed to by a0->reg29. + * + * a0 (struct pt_regs *) pointer to user registers + * a1 (syscall_t) pointer to syscall to do + * a2 (int) number of arguments to syscall + */ + .set reorder + .text +NESTED(do_syscalls, 32, sp) + subu sp,32 + sw ra,28(sp) + sll a2,a2,PTRLOG + lw t1,dst(a2) + move t2,a1 + lw t0,FR_REG29(a0) # get old user stack pointer + jalr t1 + +7: lw t1,24(t0) # parameter #7 from usp + sw t1,24(sp) +6: lw t1,20(t0) # parameter #6 from usp + sw t1,20(sp) +5: lw t1,16(t0) # parameter #5 from usp + sw t1,16(sp) +4: lw a3,FR_REG7(a0) # 4 args +3: lw a2,FR_REG6(a0) # 3 args +2: lw a1,FR_REG5(a0) # 2 args +1: lw a0,FR_REG4(a0) # delay slot + jalr t2 # 1 args + lw ra,28(sp) + addiu sp,32 + jr ra +0: jalr t2 # 0 args, just pass a0 + lw ra,28(sp) + addiu sp,32 + jr ra + END(do_syscalls) + + .rdata + .align PTRLOG +dst: PTR 0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b + + .section __ex_table,"a" + PTR 7b,bad_stack + PTR 6b,bad_stack + PTR 5b,bad_stack + + .data + + EXPORT(tlbl_lock) + .word 0 + +tlbs_lock: + .word 0 + + EXPORT(tlb_softIndex) + .word 0 diff --git a/arch/mips/mips1/showregs.c b/arch/mips/mips1/showregs.c new file mode 100644 index 000000000..0be6db80e --- /dev/null +++ b/arch/mips/mips1/showregs.c @@ -0,0 +1,32 @@ +/* + * linux/arch/mips/mips1/showregs.c + * + * Copyright (C) 1995, 1996 Ralf Baechle, Paul M. Antoine. + */ +#include <linux/kernel.h> +#include <linux/ptrace.h> + +void show_regs(struct pt_regs * regs) +{ + /* + * Saved main processor registers + */ + printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + 0, regs->regs[1], regs->regs[2], regs->regs[3], + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11], + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19], + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[24], regs->regs[25], regs->regs[28], regs->regs[29], + regs->regs[30], regs->regs[31]); + + /* + * Saved cp0 registers + */ + printk("epc : %08lx\nStatus: %08x\nCause : %08x\nBadVAdddr : %08x\n", + regs->cp0_epc, regs->cp0_status, regs->cp0_cause,regs->cp0_badvaddr); +} diff --git a/arch/mips/mips2/Makefile b/arch/mips/mips2/Makefile new file mode 100644 index 000000000..1d53d027c --- /dev/null +++ b/arch/mips/mips2/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the MIPS II specific parts of the Linux/MIPS kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: mips.o +EXTRA_ASFLAGS = -mips2 -mcpu=r6000 +O_TARGET := mips.o +O_OBJS := cpu.o pagetables.o showregs.o + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/mips2/README b/arch/mips/mips2/README new file mode 100644 index 000000000..c64808874 --- /dev/null +++ b/arch/mips/mips2/README @@ -0,0 +1,3 @@ +This directory contains the R6000 specific part. I (Ralf) tried to support +this CPU as good as possible without a machine and without detailed +documentation. So don't look to close on this part ... diff --git a/arch/mips/mips2/cpu.c b/arch/mips/mips2/cpu.c new file mode 100644 index 000000000..bcc021ee7 --- /dev/null +++ b/arch/mips/mips2/cpu.c @@ -0,0 +1,91 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/sched.h> + +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/processor.h> + +extern asmlinkage void mips2_cacheflush(void *addr, int nbytes, unsigned int flags); + +void (*mips_cache_init)(void); + +static void +mips2_cache_init(void) +{ + cacheflush = mips2_cacheflush; +} + +void (*switch_to_user_mode)(struct pt_regs *regs); + +static void +mips2_switch_to_user_mode(struct pt_regs *regs) +{ + regs->cp0_status = regs->cp0_status | ST0_KUC; +} + +unsigned long (*thread_saved_pc)(struct thread_struct *t); + +/* + * Return saved PC of a blocked thread. + */ +static unsigned long mips2_thread_saved_pc(struct thread_struct *t) +{ + return ((unsigned long *)(unsigned long)t->reg29)[13]; +} + +unsigned long (*get_wchan)(struct task_struct *p); + +static unsigned long mips2_get_wchan(struct task_struct *p) +{ + /* + * This one depends on the frame size of schedule(). Do a + * "disass schedule" in gdb to find the frame size. Also, the + * code assumes that sleep_on() follows immediately after + * interruptible_sleep_on() and that add_timer() follows + * immediately after interruptible_sleep(). Ugly, isn't it? + * Maybe adding a wchan field to task_struct would be better, + * after all... + */ + unsigned long schedule_frame; + unsigned long pc; + + pc = thread_saved_pc(&p->tss); + if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { + schedule_frame = ((unsigned long *)(long)p->tss.reg30)[13]; + return ((unsigned long *)schedule_frame)[11]; + } + return pc; +} + +void (*pgd_init)(unsigned long page); +void (*copy_page)(unsigned long to, unsigned long from); +asmlinkage void (*restore_fp_context)(struct sigcontext *sc); +asmlinkage void (*save_fp_context)(struct sigcontext *sc); + +void +mips2_cpu_init(void) +{ + extern void mips2_cache_init(void); + extern void mips2_pgd_init(unsigned long page); + extern void mips2_clear_page(unsigned long page); + extern void mips2_copy_page(unsigned long to, unsigned long from); + extern asmlinkage void mips2_restore_fp_context(struct sigcontext *sc); + extern asmlinkage void mips2_save_fp_context(struct sigcontext *sc); + + mips_cache_init = mips2_cache_init; + pgd_init = mips2_pgd_init; + switch_to_user_mode = mips2_switch_to_user_mode; + thread_saved_pc = mips2_thread_saved_pc; + get_wchan = mips2_get_wchan; + clear_page = mips2_clear_page; + copy_page = mips2_copy_page; + restore_fp_context = mips2_restore_fp_context; + save_fp_context = mips2_save_fp_context; +} diff --git a/arch/mips/mips2/fp-context.S b/arch/mips/mips2/fp-context.S new file mode 100644 index 000000000..fc11a7fed --- /dev/null +++ b/arch/mips/mips2/fp-context.S @@ -0,0 +1,124 @@ +/* + * Save/restore floating point context for signal handlers. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/fpregdef.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/sigcontext.h> + +#define SDC1(r,m) \ +7: sdc1 r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define SW(r,m) \ +7: sw r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define LDC1(r,m) \ +7: ldc1 r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define LW(r,m) \ +7: lw r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + + .set noreorder +/* + * Save floating point context + */ +LEAF(mips2_save_fp_context) + mfc0 t0,CP0_STATUS + sll t0,t0,2 + bgez t0,1f + nop # delay slot + cfc1 t1,fcr31 + /* + * Store the 16 double precision registers + */ + SDC1 ($f0,(SC_FPREGS+0)(a0)) + SDC1 ($f2,(SC_FPREGS+16)(a0)) + SDC1 ($f4,(SC_FPREGS+32)(a0)) + SDC1 ($f6,(SC_FPREGS+48)(a0)) + SDC1 ($f8,(SC_FPREGS+64)(a0)) + SDC1 ($f10,(SC_FPREGS+80)(a0)) + SDC1 ($f12,(SC_FPREGS+96)(a0)) + SDC1 ($f14,(SC_FPREGS+112)(a0)) + SDC1 ($f16,(SC_FPREGS+128)(a0)) + SDC1 ($f18,(SC_FPREGS+144)(a0)) + SDC1 ($f20,(SC_FPREGS+160)(a0)) + SDC1 ($f22,(SC_FPREGS+176)(a0)) + SDC1 ($f24,(SC_FPREGS+192)(a0)) + SDC1 ($f26,(SC_FPREGS+208)(a0)) + SDC1 ($f28,(SC_FPREGS+224)(a0)) + SDC1 ($f30,(SC_FPREGS+240)(a0)) + SW (t0,SC_FPC_CSR(a0)) + cfc1 t0,$0 # implementation/version + jr ra + .set nomacro + SW (t0,SC_FPC_EIR(a0)) # delay slot + .set macro + +1: jr ra + .set nomacro + nop # delay slot + .set macro + END(mips2_save_fp_context) + +/* + * Restore fpu state: + * - fp gp registers + * - cp1 status/control register + * + * We base the decission which registers to restore from the signal stack + * frame on the current content of c0_status, not on the content of the + * stack frame which might have been changed by the user. + */ +LEAF(mips2_restore_fp_context) + mfc0 t0,CP0_STATUS + sll t0,t0,2 + bgez t0,1f + LW t0,SC_FPC_CSR(a0) # delay slot + /* + * Restore the 16 double precision registers + */ + LDC1 ($f0,(SC_FPREGS+0)(a0)) + LDC1 ($f2,(SC_FPREGS+16)(a0)) + LDC1 ($f4,(SC_FPREGS+32)(a0)) + LDC1 ($f6,(SC_FPREGS+48)(a0)) + LDC1 ($f8,(SC_FPREGS+64)(a0)) + LDC1 ($f10,(SC_FPREGS+80)(a0)) + LDC1 ($f12,(SC_FPREGS+96)(a0)) + LDC1 ($f14,(SC_FPREGS+112)(a0)) + LDC1 ($f16,(SC_FPREGS+128)(a0)) + LDC1 ($f18,(SC_FPREGS+144)(a0)) + LDC1 ($f20,(SC_FPREGS+160)(a0)) + LDC1 ($f22,(SC_FPREGS+176)(a0)) + LDC1 ($f24,(SC_FPREGS+192)(a0)) + LDC1 ($f26,(SC_FPREGS+208)(a0)) + LDC1 ($f28,(SC_FPREGS+224)(a0)) + LDC1 ($f30,(SC_FPREGS+240)(a0)) + jr ra + .set nomacro + ctc1 t0,fcr31 # delay slot + .set macro + +1: jr ra + .set nomacro + nop # delay slot + .set macro + END(mips2_restore_fp_context) diff --git a/arch/mips/mips2/pagetables.c b/arch/mips/mips2/pagetables.c new file mode 100644 index 000000000..2c0061d39 --- /dev/null +++ b/arch/mips/mips2/pagetables.c @@ -0,0 +1,99 @@ +/* + * 32 bit MIPS specific page handling. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/mm.h> +#include <asm/cache.h> +#include <asm/mipsconfig.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +void (*pgd_init)(unsigned long page); + +/* + * Initialize new page directory with pointers to invalid ptes + */ +void mips2_pgd_init(unsigned long page) +{ + unsigned long dummy1, dummy2; + + /* + * This version is optimized for the R6000. We generate dirty lines + * in the datacache, overwrite these lines with zeros and then flush + * the cache. Sounds horribly complicated but is just a trick to + * avoid unnecessary loads of from memory and uncached stores which + * are very expensive. Not tested yet as the R6000 is a rare CPU only + * available in SGI machines and I don't have one. + */ + __asm__ __volatile__( + ".set\tnoreorder\n" + "1:\t" + "cache\t%5,(%0)\n\t" + "sw\t%2,(%0)\n\t" + "sw\t%2,4(%0)\n\t" + "sw\t%2,8(%0)\n\t" + "sw\t%2,12(%0)\n\t" + "cache\t%5,16(%0)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%2,20(%0)\n\t" + "sw\t%2,24(%0)\n\t" + "sw\t%2,28(%0)\n\t" + "subu\t%1,1\n\t" + "bnez\t%1,1b\n\t" + "addiu\t%0,32\n\t" + ".set\treorder" + :"=r" (dummy1), + "=r" (dummy2) + :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) | + _PAGE_TABLE), + "0" (page), + "1" (PAGE_SIZE/(sizeof(pmd_t)*8)), + "i" (Create_Dirty_Excl_D)); +#endif + /* + * Now force writeback to ashure values are in the RAM. + */ + cacheflush(page, PAGE_SIZE, CF_DCACHE|CF_PHYSICAL); +} + +void (*clear_page)(unsigned long page); + +/* + * To do: cache magic, maybe FPU for 64 accesses when clearing cache pages. + */ +void mips2_clear_page(unsigned long page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "addiu\t$1,%0,%2\n" + "1:\tsw\t$0,(%0)\n\t" + "sw\t$0,4(%0)\n\t" + "sw\t$0,8(%0)\n\t" + "sw\t$0,12(%0)\n\t" + "addiu\t%0,32\n\t" + "sw\t$0,-16(%0)\n\t" + "sw\t$0,-12(%0)\n\t" + "sw\t$0,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t$0,-4(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE) + :"$1","memory"); +} + +void (*copy_page)(unsigned long to, unsigned long from); + +void mips2_copy_page(unsigned long to, unsigned long from) +{ + memcpy((void *) to, + (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE); +} diff --git a/arch/mips/mips2/showregs.c b/arch/mips/mips2/showregs.c new file mode 100644 index 000000000..d207d231b --- /dev/null +++ b/arch/mips/mips2/showregs.c @@ -0,0 +1,32 @@ +/* + * linux/arch/mips/mips1/showregs.c + * + * Copyright (C) 1995, 1996 Ralf Baechle, Paul M. Antoine. + */ +#include <linux/kernel.h> +#include <linux/ptrace.h> + +void show_regs(struct pt_regs * regs) +{ + /* + * Saved main processor registers + */ + printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + 0, regs->regs[1], regs->regs[2], regs->regs[3], + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11], + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19], + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", + regs->regs[24], regs->regs[25], regs->regs[28], regs->regs[29], + regs->regs[30], regs->regs[31]); + + /* + * Saved cp0 registers + */ + printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", + regs->cp0_epc, regs->cp0_status, regs->cp0_cause); +} diff --git a/arch/mips/mips3/Makefile b/arch/mips/mips3/Makefile new file mode 100644 index 000000000..e0f6bcf29 --- /dev/null +++ b/arch/mips/mips3/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for the MIPS III specific parts of the Linux/MIPS kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: mips.o +EXTRA_ASFLAGS = -mips3 -mcpu=r4400 +O_TARGET := mips.o +O_OBJS := cache.o cpu.o fp-context.o memcpy.o memset.o r4xx0.o pagetables.o \ + showregs.o + +copy_user.o: copy_user.S +r4xx0.o: r4xx0.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/mips3/cache.c b/arch/mips/mips3/cache.c new file mode 100644 index 000000000..3fac95b75 --- /dev/null +++ b/arch/mips/mips3/cache.c @@ -0,0 +1,309 @@ +/* + * Cache maintenance for R4000/R4400/R4600 CPUs. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright 1996 by Ralf Baechle + * FIXME: Support for SC/MC version is missing. + */ +#include <linux/kernel.h> +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/system.h> + +#define STR(x) __STR(x) +#define __STR(x) #x + +unsigned long page_colour_mask; + +/* + * Size of the caches + * Line size of the caches + */ +unsigned int dcache_size, icache_size; +unsigned int dcache_line_size, icache_line_size; +unsigned long dcache_line_mask, icache_line_mask; + +/* + * Profiling counter + */ +extern unsigned int dflushes; +extern unsigned int iflushes; + +/* + * Pointers to code for particular CPU sub family. + */ +static void (*wb_inv_d_cache)(void); +static void (*inv_i_cache)(void); + +#define CACHELINES 512 /* number of cachelines (kludgy) */ + +extern inline void cache(unsigned int cacheop, unsigned long addr, + unsigned long offset, void *fault) +{ + __asm__ __volatile__ ( + "1:\tcache\t%0,%2+%1\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,%3\n\t" + ".text" + : /* no outputs */ + :"ri" (cacheop), + "o" (*(unsigned char *)addr), + "ri" (offset), + "ri" (fault)); +} + +/* + * Code for R4000 style primary caches. + * + * R4000 style caches are direct-mapped, virtual indexed and physical tagged. + * The size of cache line is either 16 or 32 bytes. + * SC/MC versions of the CPUs add support for an second level cache with + * upto 4mb configured as either joint or split I/D. These level two + * caches with direct support from CPU aren't yet supported. + */ + +static void r4000_wb_inv_d_cache(void) +{ + unsigned long addr = KSEG0; + int i; + + for (i=CACHELINES;i;i--) { + cache(Index_Writeback_Inv_D, addr, 0, &&fault); + addr += 32; + } + if (read_32bit_cp0_register(CP0_CONFIG) & CONFIG_DB) + return; + for (i=CACHELINES;i;i--) { + cache(Index_Writeback_Inv_D, addr, 16, &&fault); + addr += 32; + } +fault: +} + +static void r4000_inv_i_cache(void) +{ + unsigned long addr = KSEG0; + int i; + + for (i=CACHELINES;i;i--) { + cache(Index_Invalidate_I, addr, 0, &&fault); + addr += 32; + } + if (read_32bit_cp0_register(CP0_CONFIG) & CONFIG_IB) + return; + for (i=CACHELINES;i;i--) { + cache(Index_Invalidate_I, addr, 16, &&fault); + addr += 32; + } +fault: +} + +/* + * Code for R4600 style primary caches. + * + * R4600 has two way primary caches with 32 bytes line size. The way to + * flush is selected by bith 12 of the physical address given as argument + * to an Index_* cache operation. CPU supported second level caches are + * not available. + * + * R4600 v1.0 bug: Flush way 2, then way 1 of the instruction cache when + * using Index_Invalidate_I. IDT says this should work but is untested. + * If this should not work, we have to disable interrupts for the broken + * chips. The CPU might otherwise execute code from the wrong cache way + * during an interrupt. + */ +static void r4600_wb_inv_d_cache(void) +{ + unsigned long addr = KSEG0; + int i; + + for (i=CACHELINES;i;i-=2) { + cache(Index_Writeback_Inv_D, addr, 8192, &&fault); + cache(Index_Writeback_Inv_D, addr, 0, &&fault); + addr += 32; + } +fault: +} + +static void r4600_inv_i_cache(void) +{ + unsigned long addr = KSEG0; + int i; + + for (i=CACHELINES;i;i-=2) { + cache(Index_Invalidate_I, addr, 8192, &&fault); + cache(Index_Invalidate_I, addr, 0, &&fault); + addr += 32; + } +fault: +} + +/* + * Flush the cache of R4x00. + * + * R4600 v2.0 bug: "The CACHE instructions Hit_Writeback_Invalidate_D, + * Hit_Writeback_D, Hit_Invalidate_D and Create_Dirty_Exclusive_D will only + * operate correctly if the internal data cache refill buffer is empty. These + * CACHE instructions should be separated from any potential data cache miss + * by a load instruction to an uncached address to empty the response buffer." + * (Revision 2.0 device errata from IDT available on http://www.idt.com/ + * in .pdf format.) + * + * To do: Use Hit_Invalidate where possible to be more economic. + * Handle SC & MC versions. + * The decission to nuke the entire cache might be based on a better + * decission algorithem based on the real costs. + * Handle different cache sizes. + * Combine the R4000 and R4600 cases. + */ +extern inline void +flush_d_cache(unsigned long addr, unsigned long size) +{ + unsigned long end; + unsigned long a; + + dflushes++; + if (1 || size >= dcache_size) { + wb_inv_d_cache(); + return; + } + + /* + * Workaround for R4600 bug. Explanation see above. + */ + *(volatile unsigned long *)KSEG1; + + /* + * Ok, we only have to invalidate parts of the cache. + */ + a = addr & dcache_line_mask; + end = (addr + size) & dcache_line_mask; + while (1) { + cache(Hit_Writeback_Inv_D, a, 0, &&fault); + if (a == end) break; + a += dcache_line_size; + } +fault: + return; +} + +extern inline void +flush_i_cache(unsigned long addr, unsigned long size) +{ + unsigned long end; + unsigned long a; + + iflushes++; + if (1 || size >= icache_size) { + inv_i_cache(); + return; + } + + /* + * Ok, we only have to invalidate parts of the cache. + */ + a = addr & icache_line_mask; + end = (addr + size) & dcache_line_mask; + while (1) { + cache(Hit_Invalidate_I, a, 0, &&fault); + if (a == end) break; + a += icache_line_size; + } +fault: + return; +} + +asmlinkage void +mips3_cacheflush(unsigned long addr, unsigned long size, unsigned int flags) +{ + if (!(flags & CF_ALL)) + printk("mips3_cacheflush called without cachetype parameter\n"); + if (!(flags & CF_VIRTUAL)) + return; /* Nothing to do */ + if (flags & CF_DCACHE) + flush_d_cache(addr, size); + if (flags & CF_ICACHE) + flush_i_cache(addr, size); +} + +/* Going away. */ +asmlinkage void fd_cacheflush(unsigned long addr, unsigned long size) +{ + cacheflush(addr, size, CF_DCACHE|CF_VIRTUAL); +} + +void mips3_cache_init(void) +{ + extern asmlinkage void handle_vcei(void); + extern asmlinkage void handle_vced(void); + unsigned int c0_config = read_32bit_cp0_register(CP0_CONFIG); + + switch (mips_cputype) { + case CPU_R4000MC: case CPU_R4400MC: + case CPU_R4000SC: case CPU_R4400SC: + /* + * Handlers not implemented yet. + */ + set_except_vector(14, handle_vcei); + set_except_vector(31, handle_vced); + break; + default: + } + + /* + * Which CPU are we running on? There are different styles + * of primary caches in the MIPS R4xx0 CPUs. + */ + switch (mips_cputype) { + case CPU_R4000MC: case CPU_R4400MC: + case CPU_R4000SC: case CPU_R4400SC: + case CPU_R4000PC: case CPU_R4400PC: + inv_i_cache = r4000_inv_i_cache; + wb_inv_d_cache = r4000_wb_inv_d_cache; + break; + case CPU_R4600: case CPU_R4700: + inv_i_cache = r4600_inv_i_cache; + wb_inv_d_cache = r4600_wb_inv_d_cache; + break; + default: + panic("Don't know about cache type ..."); + } + cacheflush = mips3_cacheflush; + + /* + * Find the size of primary instruction and data caches. + * For most CPUs these sizes are the same. + */ + dcache_size = 1 << (12 + ((c0_config >> 6) & 7)); + icache_size = 1 << (12 + ((c0_config >> 9) & 7)); + page_colour_mask = (dcache_size - 1) & ~(PAGE_SIZE - 1); + + /* + * Cache line sizes + */ + dcache_line_size = (c0_config & CONFIG_DB) ? 32 : 16; + dcache_line_mask = ~(dcache_line_size - 1); + icache_line_size = (c0_config & CONFIG_IB) ? 32 : 16; + icache_line_mask = ~(icache_line_size - 1); + + printk("Primary D-cache size %dkb bytes, %d byte lines.\n", + dcache_size >> 10, dcache_line_size); + printk("Primary I-cache size %dkb bytes, %d byte lines.\n", + icache_size >> 10, icache_line_size); + + /* + * Second level cache. + * FIXME ... + */ + if (!(c0_config & CONFIG_SC)) { + printk("S-cache detected. This type of of cache is not " + "supported yet.\n"); + } +} diff --git a/arch/mips/mips3/cpu.c b/arch/mips/mips3/cpu.c new file mode 100644 index 000000000..cd8a293e5 --- /dev/null +++ b/arch/mips/mips3/cpu.c @@ -0,0 +1,96 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/sched.h> + +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/processor.h> +#include <asm/system.h> + +extern asmlinkage void mips3_cacheflush(unsigned long addr, unsigned long nbytes, unsigned int flags); + +void (*mips_cache_init)(void); +void (*switch_to_user_mode)(struct pt_regs *regs); + +static void +mips3_switch_to_user_mode(struct pt_regs *regs) +{ + regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU)) | KSU_USER; +} + +unsigned long (*thread_saved_pc)(struct thread_struct *t); + +/* + * Return saved PC of a blocked thread. + */ +static unsigned long mips3_thread_saved_pc(struct thread_struct *t) +{ + return ((unsigned long long *)(unsigned long)t->reg29)[11]; +} + +unsigned long (*get_wchan)(struct task_struct *p); + +static unsigned long mips3_get_wchan(struct task_struct *p) +{ + /* + * This one depends on the frame size of schedule(). Do a + * "disass schedule" in gdb to find the frame size. Also, the + * code assumes that sleep_on() follows immediately after + * interruptible_sleep_on() and that add_timer() follows + * immediately after interruptible_sleep(). Ugly, isn't it? + * Maybe adding a wchan field to task_struct would be better, + * after all... + */ + unsigned long schedule_frame; + unsigned long pc; + + pc = thread_saved_pc(&p->tss); + if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { + schedule_frame = ((unsigned long long *)(long)p->tss.reg30)[10]; + return (unsigned long)((unsigned long long *)schedule_frame)[9]; + } + return pc; +} + +void (*pgd_init)(unsigned long page); +void (*copy_page)(unsigned long to, unsigned long from); +asmlinkage void (*restore_fp_context)(struct sigcontext *sc); +asmlinkage void (*save_fp_context)(struct sigcontext *sc); + +void +mips3_cpu_init(void) +{ + extern void mips3_cache_init(void); + extern void mips3_pgd_init_32byte_lines(unsigned long page); + extern void mips3_pgd_init_16byte_lines(unsigned long page); + extern void mips3_clear_page_32byte_lines(unsigned long page); + extern void mips3_clear_page_16byte_lines(unsigned long page); + extern void mips3_copy_page_32byte_lines(unsigned long to, unsigned long from); + extern void mips3_copy_page_16byte_lines(unsigned long to, unsigned long from); + extern void mips3_copy_page(unsigned long to, unsigned long from); + extern asmlinkage void mips3_restore_fp_context(struct sigcontext *sc); + extern asmlinkage void mips3_save_fp_context(struct sigcontext *sc); + + mips_cache_init = mips3_cache_init; + if (read_32bit_cp0_register(CP0_CONFIG) & CONFIG_DB) { + pgd_init = mips3_pgd_init_32byte_lines; + clear_page = mips3_clear_page_32byte_lines; + copy_page = mips3_copy_page_32byte_lines; + } else { + pgd_init = mips3_pgd_init_16byte_lines; + clear_page = mips3_clear_page_16byte_lines; + copy_page = mips3_copy_page_16byte_lines; + } + switch_to_user_mode = mips3_switch_to_user_mode; + thread_saved_pc = mips3_thread_saved_pc; + get_wchan = mips3_get_wchan; + restore_fp_context = mips3_restore_fp_context; + save_fp_context = mips3_save_fp_context; +} diff --git a/arch/mips/mips3/fp-context.S b/arch/mips/mips3/fp-context.S new file mode 100644 index 000000000..5e04aa61f --- /dev/null +++ b/arch/mips/mips3/fp-context.S @@ -0,0 +1,170 @@ +/* + * Save/restore floating point context for signal handlers. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/fpregdef.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/sigcontext.h> + +#define SDC1(r,m) \ +7: sdc1 r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define SW(r,m) \ +7: sw r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define LDC1(r,m) \ +7: ldc1 r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + +#define LW(r,m) \ +7: lw r,m; \ + .section __ex_table,"a"; \ + PTR 7b,bad_stack; \ + .text + + .set noreorder +/* + * Save floating point context + */ +LEAF(mips3_save_fp_context) + mfc0 t1,CP0_STATUS + sll t2,t1,2 + bgez t2,2f + sll t2,t1,5 # delay slot + bgez t2,1f + cfc1 t1,fcr31 # delay slot + /* + * Store the 16 odd double precision registers + */ + SDC1 ($f1,(SC_FPREGS+8)(a0)) + SDC1 ($f3,(SC_FPREGS+24)(a0)) + SDC1 ($f5,(SC_FPREGS+40)(a0)) + SDC1 ($f7,(SC_FPREGS+56)(a0)) + SDC1 ($f9,(SC_FPREGS+72)(a0)) + SDC1 ($f11,(SC_FPREGS+88)(a0)) + SDC1 ($f13,(SC_FPREGS+104)(a0)) + SDC1 ($f15,(SC_FPREGS+120)(a0)) + SDC1 ($f17,(SC_FPREGS+136)(a0)) + SDC1 ($f19,(SC_FPREGS+152)(a0)) + SDC1 ($f21,(SC_FPREGS+168)(a0)) + SDC1 ($f23,(SC_FPREGS+184)(a0)) + SDC1 ($f25,(SC_FPREGS+200)(a0)) + SDC1 ($f27,(SC_FPREGS+216)(a0)) + SDC1 ($f29,(SC_FPREGS+232)(a0)) + SDC1 ($f31,(SC_FPREGS+248)(a0)) + + /* + * Store the 16 even double precision registers + */ +1: SDC1 ($f0,(SC_FPREGS+0)(a0)) + SDC1 ($f2,(SC_FPREGS+16)(a0)) + SDC1 ($f4,(SC_FPREGS+32)(a0)) + SDC1 ($f6,(SC_FPREGS+48)(a0)) + SDC1 ($f8,(SC_FPREGS+64)(a0)) + SDC1 ($f10,(SC_FPREGS+80)(a0)) + SDC1 ($f12,(SC_FPREGS+96)(a0)) + SDC1 ($f14,(SC_FPREGS+112)(a0)) + SDC1 ($f16,(SC_FPREGS+128)(a0)) + SDC1 ($f18,(SC_FPREGS+144)(a0)) + SDC1 ($f20,(SC_FPREGS+160)(a0)) + SDC1 ($f22,(SC_FPREGS+176)(a0)) + SDC1 ($f24,(SC_FPREGS+192)(a0)) + SDC1 ($f26,(SC_FPREGS+208)(a0)) + SDC1 ($f28,(SC_FPREGS+224)(a0)) + SDC1 ($f30,(SC_FPREGS+240)(a0)) + SW t1,SC_FPC_CSR(a0) + cfc1 t0,$0 # implementation/version + jr ra + .set nomacro + SW t1,SC_FPC_EIR(a0) # delay slot + .set macro + +2: jr ra + .set nomacro + nop # delay slot + .set macro + END(mips3_save_fp_context) + +/* + * Restore fpu state: + * - fp gp registers + * - cp1 status/control register + * + * We base the decission which registers to restore from the signal stack + * frame on the current content of c0_status, not on the content of the + * stack frame which might have been changed by the user. + */ +LEAF(mips3_restore_fp_context) + mfc0 t1,CP0_STATUS + sll t0,t1,2 + bgez t0,2f + sll t0,t1,5 # delay slot + bgez t0,1f + LW t0,SC_FPC_CSR(a0) # delay slot + /* + * Restore the 16 odd double precision registers only + * when enabled in the cp0 status register. + */ + LDC1 ($f1,(SC_FPREGS+8)(a0)) + LDC1 ($f3,(SC_FPREGS+24)(a0)) + LDC1 ($f5,(SC_FPREGS+40)(a0)) + LDC1 ($f7,(SC_FPREGS+56)(a0)) + LDC1 ($f9,(SC_FPREGS+72)(a0)) + LDC1 ($f11,(SC_FPREGS+88)(a0)) + LDC1 ($f13,(SC_FPREGS+104)(a0)) + LDC1 ($f15,(SC_FPREGS+120)(a0)) + LDC1 ($f17,(SC_FPREGS+136)(a0)) + LDC1 ($f19,(SC_FPREGS+152)(a0)) + LDC1 ($f21,(SC_FPREGS+168)(a0)) + LDC1 ($f23,(SC_FPREGS+184)(a0)) + LDC1 ($f25,(SC_FPREGS+200)(a0)) + LDC1 ($f27,(SC_FPREGS+216)(a0)) + LDC1 ($f29,(SC_FPREGS+232)(a0)) + LDC1 ($f31,(SC_FPREGS+248)(a0)) + + /* + * Restore the 16 even double precision registers + * when cp1 was enabled in the cp0 status register. + */ +1: LDC1 ($f0,(SC_FPREGS+0)(a0)) + LDC1 ($f2,(SC_FPREGS+16)(a0)) + LDC1 ($f4,(SC_FPREGS+32)(a0)) + LDC1 ($f6,(SC_FPREGS+48)(a0)) + LDC1 ($f8,(SC_FPREGS+64)(a0)) + LDC1 ($f10,(SC_FPREGS+80)(a0)) + LDC1 ($f12,(SC_FPREGS+96)(a0)) + LDC1 ($f14,(SC_FPREGS+112)(a0)) + LDC1 ($f16,(SC_FPREGS+128)(a0)) + LDC1 ($f18,(SC_FPREGS+144)(a0)) + LDC1 ($f20,(SC_FPREGS+160)(a0)) + LDC1 ($f22,(SC_FPREGS+176)(a0)) + LDC1 ($f24,(SC_FPREGS+192)(a0)) + LDC1 ($f26,(SC_FPREGS+208)(a0)) + LDC1 ($f28,(SC_FPREGS+224)(a0)) + LDC1 ($f30,(SC_FPREGS+240)(a0)) + jr ra + .set nomacro + ctc1 t0,fcr31 # delay slot + .set macro + +2: jr ra + .set nomacro + nop # delay slot + .set macro + END(mips3_restore_fp_context) + .set reorder diff --git a/arch/mips/mips3/memcpy.S b/arch/mips/mips3/memcpy.S new file mode 100644 index 000000000..6f03032a6 --- /dev/null +++ b/arch/mips/mips3/memcpy.S @@ -0,0 +1,185 @@ +/* + * arch/mips/mips3/memcpy.S + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1996 by Ralf Baechle + * + * Less stupid memcpy/user_copy implementation for 64 bit MIPS CPUs. + * Much faster than the old memcpy but definately work in progress. + * The list of tricks for a good memcpy is long ... + */ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> + +#define BLOCK_SIZE (SZREG*4) + +#define SWAP(x,y) \ + subu x,x,y; \ + addu y,x,y; \ + subu x,y,x + +#define EX(addr,handler) \ + .section __ex_table,"a"; \ + PTR addr, handler; \ + .text +#define UEX(addr,handler) \ + EX(addr,handler); \ + EX(addr+4,handler) + + .set noreorder + .set noat + +/* ---------------------------------------------------------------------- */ + +not_dw_aligned: +/* + * At least one address is missaligned. + * Let's see if we can fix the alignment. + */ + LONG_SUBU v1,zero,a0 + andi v1,SZREG-1 + sltu t0,v0,v1 + MOVN(v1,v0,t0) + beqz v1,still_not_aligned + LONG_ADDU v1,a0 # delay slot +1: lb $1,(a1) + EX(1b, fault) + LONG_ADDIU a1,1 +2: sb $1,(a0) + EX(2b, fault) + LONG_ADDIU a0,1 + bne a0,v1,1b + LONG_SUBU v0,1 # delay slot + +/* + * Ok, now the destination address is 8-byte aligned. + * Is the source also aligned? + */ + andi t0,a1,SZREG-1 + beqz t0,align8 # fine ... + +/* + * Bad. We could only fix the alignment of the destination address. + * Now let's copy in the usual BLOCK_SIZE byte blocks using unaligned + * load and aligned stores. + */ +still_not_aligned: + ori v1,v0,BLOCK_SIZE-1 # delay slot + xori v1,BLOCK_SIZE-1 + beqz v1,copy_left_over + nop # delay slot + LONG_SUBU v0,v1 + LONG_ADDU v1,a0 + +1: uld t0,(a1) + UEX(1b, fault) +2: uld t1,8(a1) + UEX(2b, fault) +2: uld t2,16(a1) + UEX(2b, fault) +2: uld t3,24(a1) + UEX(2b, fault) +2: sd t0,(a0) + EX(2b, fault) +2: sd t1,8(a0) + EX(2b, fault_plus_one_reg) +2: sd t2,16(a0) + EX(2b, fault_plus_two_reg) +2: sd t3,24(a0) + EX(2b, fault_plus_three_reg) + LONG_ADDIU a0,BLOCK_SIZE + bne a0,v1,1b + LONG_ADDIU a1,BLOCK_SIZE # delay slot +9: + b copy_left_over # < BLOCK_SIZE bytes left + nop # delay slot + +/* ---------------------------------------------------------------------- */ + +LEAF(__copy_user) + + or t1,a0,a1 + andi t1,SZREG-1 + bnez t1,not_dw_aligned + move v0,a2 # delay slot + +align8: + ori v1,v0,BLOCK_SIZE-1 + xori v1,BLOCK_SIZE-1 + beqz v1,copy_left_over + nop # delay slot + LONG_SUBU v0,v1 + LONG_ADDU v1,a0 + +1: ld t0,(a1) + EX(1b, fault) +2: ld t1,8(a1) + EX(2b, fault) +2: ld t2,16(a1) + EX(2b, fault) +2: ld t3,24(a1) + EX(2b, fault) +2: sd t0,(a0) + EX(2b, fault) +2: sd t1,8(a0) + EX(2b, fault_plus_one_reg) +2: sd t2,16(a0) + EX(2b, fault_plus_two_reg) +2: sd t3,24(a0) + EX(2b, fault_plus_three_reg) + LONG_ADDIU a0,BLOCK_SIZE + bne a0,v1,1b + LONG_ADDIU a1,BLOCK_SIZE # delay slot +9: + +/* + * We've got upto 31 bytes left to copy ... + */ +copy_left_over: + beqz v0,3f + nop # delay slot +1: lb $1,(a1) + EX(1b, fault) + LONG_ADDIU a1,1 +2: sb $1,(a0) + EX(2b, fault) + LONG_SUBU v0,1 + bnez v0,1b + LONG_ADDIU a0,1 +3: jr ra + nop # delay slot + + END(__copy_user) + .set at + .set reorder + +/* ---------------------------------------------------------------------- */ + +/* + * Access fault. The number of not copied bytes is in v0. We have to + * correct the number of the not copied bytes in v0 in case of a access + * fault in an unrolled loop, then return. + */ + +fault: jr ra +fault_plus_one_reg: LONG_ADDIU v0,SZREG + jr ra +fault_plus_two_reg: LONG_ADDIU v0,SZREG*2 + jr ra +fault_plus_three_reg: LONG_ADDIU v0,SZREG*3 + jr ra + +/* ---------------------------------------------------------------------- */ + +/* + * For now we use __copy_user for __memcpy, too. This is efficient (one + * instruction penatly) and smaller but adds unwanted error checking we don't + * need. This hopefully doesn't cover any bugs. The memcpy() wrapper in + * <asm/string.h> takes care of the return value in a way GCC can optimize. + */ + .globl __memcpy +__memcpy = __copy_user diff --git a/arch/mips/mips3/memset.c b/arch/mips/mips3/memset.c new file mode 100644 index 000000000..e92a0907f --- /dev/null +++ b/arch/mips/mips3/memset.c @@ -0,0 +1,82 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + * + * Less stupid memset for 64 bit MIPS CPUs. + */ +#include <linux/linkage.h> +#include <linux/string.h> + +static void __inline__ b_memset(void *s, unsigned long long c, size_t count) +{ + unsigned char *p = s; + + while(count--) + *(p++) = c; +} + +static void __inline__ dw_memset(void *s, unsigned long long c, size_t count) +{ + unsigned long long *p = s; + + count >>= 3; + while(count--) + *(p++) = c; +} + +asm( ".globl\t__generic_memset_b\n\t" + ".align\t2\n\t" + ".type\t__generic_memset_b,@function\n\t" + ".ent\t__generic_memset_b,0\n\t" + ".frame\t$29,0,$31\n" + "__generic_memset_b:\n\t" + "andi\t$5,0xff\n\t" + "dsll\t$2,$5,8\n\t" + "or\t$5,$2\n\t" + "dsll\t$2,$5,16\n\t" + "or\t$5,$2\n\t" + "dsll32\t$2,$5,0\n\t" + "or\t$5,$2\n\t" + ".end\t__generic_memset_b\n\t" + ".size\t__generic_memset_b,.-t__generic_memset_b"); + +/* + * Fill small area bytewise. For big areas fill the source bytewise + * until the pointer is doubleword aligned, then fill in doublewords. + * Fill the rest again in single bytes. + */ +void __generic_memset_dw(void *s, unsigned long long c, size_t count) +{ + unsigned long i; + + /* + * Fill small areas bytewise. + */ + if (count <= 16) { + b_memset(s, c, count); + return; + } + + /* + * Pad for 8 byte boundary + */ + i = 8 - ((unsigned long)s & 7); + b_memset(s, c, i); + s += i; + count -= i; + + /* + * Now start filling with aligned doublewords + */ + dw_memset(s, c, count); + s += (count | 7) ^ 7; + count &= 7; + + /* + * And do what ever is left over again with single bytes. + */ + b_memset(s, c, count); +} diff --git a/arch/mips/mips3/pagetables.c b/arch/mips/mips3/pagetables.c new file mode 100644 index 000000000..e8cb83d03 --- /dev/null +++ b/arch/mips/mips3/pagetables.c @@ -0,0 +1,297 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + * + * Functions that manipulate entire pages. + * + * Not nice to have all these functions in two versions for cpus with + * different cache line size but it seems to be by far the fastest thing + * to schedule the cache instructions immediately before the store + * instructions. For example using the clear_page() version for 16 byte + * lines on machine with 32 byte lines gives a measured penalty of + * ~1280 cycles per page. + */ +#include <linux/mm.h> +#include <asm/cache.h> +#include <asm/mipsconfig.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +extern unsigned int dflushes; + +/* + * Initialize new page directory with pointers to invalid ptes. + */ +void mips3_pgd_init_32byte_lines(unsigned long page) +{ + unsigned long dummy1, dummy2; + + /* + * We generate dirty lines in the datacache, overwrite them + * then writeback the cache. + */ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "dsll32\t$1,%2,0\n\t" + "dsrl32\t%2,$1,0\n\t" + "or\t%2,$1\n" + "1:\tcache\t%5,(%0)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%2,8(%0)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%2,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "cache\t%5,-32(%0)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%2,-24(%0)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t%0,%1,1b\n\t" + "sd\t%2,-8(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (dummy1), + "=&r" (dummy2) + :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) | + _PAGE_TABLE), + "0" (page), + "1" (page + PAGE_SIZE - 64), + "i" (Create_Dirty_Excl_D) + :"$1"); + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "1:\tcache\t%3,(%0)\n\t" + "bne\t%0,%1,1b\n\t" + "daddiu\t%0,32\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1) + :"0" (page), + "r" (page + PAGE_SIZE - 32), + "i" (Hit_Writeback_D)); + dflushes++; + +#if 0 + cacheflush(page, PAGE_SIZE, CF_DCACHE|CF_VIRTUAL); +#endif +} + +/* + * Initialize new page directory with pointers to invalid ptes + */ +void mips3_pgd_init_16byte_lines(unsigned long page) +{ + unsigned long dummy1, dummy2; + + /* + * We generate dirty lines in the datacache, overwrite them + * then writeback the cache. + */ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "dsll32\t$1,%2,0\n\t" + "dsrl32\t%2,$1,0\n\t" + "or\t%2,$1\n" + "1:\tcache\t%5,(%0)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%2,8(%0)\n\t" + "cache\t%5,16(%0)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%2,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "cache\t%5,-32(%0)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%2,-24(%0)\n\t" + "cache\t%5,-16(%0)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t%0,%1,1b\n\t" + "sd\t%2,-8(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (dummy1), + "=&r" (dummy2) + :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) | + _PAGE_TABLE), + "0" (page), + "1" (page + PAGE_SIZE - 64), + "i" (Create_Dirty_Excl_D) + :"$1"); + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "1:\tcache\t%3,(%0)\n\t" + "bne\t%0,%1,1b\n\t" + "daddiu\t%0,16\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1) + :"0" (page), + "r" (page + PAGE_SIZE - 16), + "i" (Hit_Writeback_D)); + dflushes++; + +#if 0 + cacheflush(page, PAGE_SIZE, CF_DCACHE|CF_VIRTUAL); +#endif +} + +/* + * Zero an entire page. + */ + +void (*clear_page)(unsigned long page); + +void mips3_clear_page_32byte_lines(unsigned long page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%2\n" + "1:\tcache\t%3,(%0)\n\t" + "sd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "cache\t%3,-32(%0)\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D) + :"$1","memory"); +} + +void mips3_clear_page_16byte_lines(unsigned long page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%2\n" + "1:\tcache\t%3,(%0)\n\t" + "sd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "cache\t%3,16(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "cache\t%3,-32(%0)\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "cache\t%3,-16(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D) + :"$1","memory"); +} + +/* + * This is still inefficient. We only can do better if we know the + * virtual address where the copy will be accessed. + */ +void (*copy_page)(unsigned long to, unsigned long from); + +void mips3_copy_page_32byte_lines(unsigned long to, unsigned long from) +{ + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%8\n" + "1:\tcache\t%9,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "ld\t%4,16(%1)\n\t" + "ld\t%5,24(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "sd\t%4,16(%0)\n\t" + "sd\t%5,24(%0)\n\t" + "cache\t%9,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "ld\t%4,-16(%1)\n\t" + "ld\t%5,-8(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "sd\t%4,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t%5,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + :"0" (to), "1" (from), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D)); +} + +void mips3_copy_page_16byte_lines(unsigned long to, unsigned long from) +{ + unsigned dummy1, dummy2; + unsigned long reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "cache\t%7,16(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "cache\t%7,-16(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2) + :"0" (to), "1" (from), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D)); +} diff --git a/arch/mips/kernel/r4xx0.S b/arch/mips/mips3/r4xx0.S index a68b32243..a282998ac 100644 --- a/arch/mips/kernel/r4xx0.S +++ b/arch/mips/mips3/r4xx0.S @@ -1,33 +1,61 @@ /* - * arch/mips/kernel/r4xx0.S + * arch/mips/mips3/r4xx0.S * - * Copyright (C) 1994, 1995 Waldorf Electronics - * Written by Ralf Baechle and Andreas Busse + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse * - * This file contains most of the R4xx0 specific routines. + * This file contains most of the R4xx0 specific routines. Due to the + * similarities this should hopefully also be fine for the R10000. For + * now we especially support the R10000 by not invalidating entries out of + * the TLB before calling the C handlers. * - * This code is evil magic. Read appendix f (coprozessor 0 hazards) of + * This code is evil magic. Read appendix F (coprocessor 0 hazards) of * all R4xx0 manuals and think about that MIPS means "Microprocessor without * Interlocked Pipeline Stages" before you even think about changing this code! + * + * CAVEATS: The R4000/R4400/R4600 manual say that the operation of a memory + * reference associated with a instruction immediately after a tlpb + * instruction is undefined. It seems that the R4600 v2.0 also + * failes to handle the case where a tlbp instruction follows a + * (mapped???) memory reference. In this case c0_index gets + * overwritten by some value which I suppose to be the entry + * mapping the associated instruction's memory reference. + * + * This needs a complete overhaul; it was written for a Linux kernel that + * handled it's page tables the old i386 way ... */ -#include <linux/autoconf.h> +#include <linux/config.h> #include <asm/asm.h> #include <asm/bootinfo.h> -#include <asm/cachectl.h> +#include <asm/cache.h> +#include <asm/fpregdef.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> -#include <asm/page.h> #include <asm/pgtable.h> #include <asm/processor.h> -#include <asm/mipsregs.h> -#include <asm/segment.h> +#include <asm/regdef.h> #include <asm/stackframe.h> +/* + * Use this to activate extra TLB error checking + */ +#define CONF_DEBUG_TLB + +/* + * Use this to activate extra TLB profiling code + * (not implemented yet) + */ +#undef CONF_PROFILE_TLB + +#ifdef __SMP__ +#error "Fix this for SMP" +#else +#define current current_set +#endif + MODE_ALIAS = 0x0016 # uncachable .text - .set mips3 .set noreorder .align 5 @@ -52,7 +80,9 @@ MODE_ALIAS = 0x0016 # uncachable nop # for R4[04]00 pipeline nop nop + nop tlbp + nop nop # for R4[04]00 pipeline nop mfc0 k0,CP0_INDEX @@ -65,7 +95,7 @@ MODE_ALIAS = 0x0016 # uncachable */ nop -#ifdef CONFIG_DEBUG_TLB +#ifdef CONF_DEBUG_TLB /* * OK, this is a double fault. Let's see whether this is * due to an invalid entry in the page_table. @@ -85,11 +115,16 @@ MODE_ALIAS = 0x0016 # uncachable .set at PRINT("Double fault caused by invalid entries in pgd:\n") dmfc0 a1,CP0_BADVADDR - PRINT("Double fault address : %08lx\n") + PRINT("Double fault address : %016Lx\n") dmfc0 a1,CP0_EPC - PRINT("c0_epc : %08lx\n") + PRINT("c0_epc : %016Lx\n") jal show_regs move a0,sp + jal dump_tlb_nonwired + nop + dmfc0 a0,CP0_BADVADDR + jal dump_list_current + nop .set noat STI .set at @@ -97,12 +132,13 @@ MODE_ALIAS = 0x0016 # uncachable .set noat reload_pgd_entries: -#endif /* CONFIG_DEBUG_TLB */ +#endif /* CONF_DEBUG_TLB */ /* * Load missing pair of entries from the pgd and return. */ dmfc0 k1,CP0_CONTEXT +// mfc0 k1,CP0_CONTEXT dsra k1,1 lwu k0,(k1) # Never causes nested exception lwu k1,4(k1) @@ -133,7 +169,9 @@ reload_pgd_entries: * * k0 contains c0_index. */ -invalid_tlbl: /* +invalid_tlbl: +#ifdef CONFIG_TLB_SHUTDOWN + /* * Remove entry so we don't need to care later * For sake of the R4000 V2.2 pipeline the tlbwi insn * has been moved down. Moving it around is juggling with @@ -145,13 +183,16 @@ invalid_tlbl: /* dmtc0 k0,CP0_ENTRYHI dmtc0 zero,CP0_ENTRYLO0 dmtc0 zero,CP0_ENTRYLO1 +#endif /* * Test present bit in entry */ dmfc0 k0,CP0_BADVADDR srl k0,12 sll k0,2 +#ifdef CONFIG_TLB_SHUTDOWN tlbwi # do not move! +#endif lui k1,%HI(TLBMAP) addu k0,k1 lw k1,(k0) @@ -172,11 +213,14 @@ invalid_tlbl: /* * kernel memory management routines. */ nopage_tlbl: SAVE_ALL + dmfc0 a2,CP0_BADVADDR STI + REG_S sp,FR_ORIG_REG2(sp) .set at /* * a0 (struct pt_regs *) regs * a1 (unsigned long) 0 for read access + * a2 (unsigned long) faulting virtual address */ move a0,sp jal do_page_fault @@ -204,7 +248,10 @@ nopage_tlbl: SAVE_ALL lui k1,%HI(TLBMAP) addu k0,k1 lw k1,(k0) + nop + nop tlbp # find faulting entry + nop andi k1,(_PAGE_PRESENT|_PAGE_WRITE) xori k1,(_PAGE_PRESENT|_PAGE_WRITE) bnez k1,nopage_tlbs @@ -239,35 +286,13 @@ nopage_tlbl: SAVE_ALL * kernel memory management routines. */ nopage_tlbs: -#if 0 - .set mips3 - SAVE_ALL - .set mips0 - PRINT("nopage_tlbs\n") - .set mips3 - RESTORE_ALL - .set mips3 - j 1f - nop -#endif nowrite_mod: -#if 0 - .set mips3 - SAVE_ALL - .set mips0 - PRINT("nopage_mod\n") - .set mips3 - RESTORE_ALL - .set mips3 - j 1f - nop -1: -#endif +#ifdef CONFIG_TLB_SHUTDOWN /* * Remove entry so we don't need to care later */ mfc0 k0,CP0_INDEX -#ifdef CONFIG_DEBUG_TLB +#ifdef CONF_DEBUG_TLB bgez k0,2f nop /* @@ -279,14 +304,12 @@ nowrite_mod: jal show_regs move a0,sp .set at - mfc0 a1,CP0_BADVADDR - PRINT("c0_badvaddr == %08lx\n") + dmfc0 a1,CP0_BADVADDR + PRINT("c0_badvaddr == %016Lx\n") mfc0 a1,CP0_INDEX PRINT("c0_index == %08x\n") - mfc0 a1,CP0_ENTRYHI - PRINT("c0_entryhi == %08x\n") - jal dump_tlb_nonwired - nop + dmfc0 a1,CP0_ENTRYHI + PRINT("c0_entryhi == %016Lx\n") .set noat STI .set at @@ -294,7 +317,7 @@ nowrite_mod: 1: j 1b nop 2: -#endif /* CONFIG_DEBUG_TLB */ +#endif /* CONF_DEBUG_TLB */ lui k1,0x0008 or k0,k1 dsll k0,13 @@ -306,13 +329,17 @@ nowrite_mod: nop nop tlbwi +#endif /* CONFIG_TLB_SHUTDOWN */ .set noat SAVE_ALL + dmfc0 a2,CP0_BADVADDR STI + REG_S sp,FR_ORIG_REG2(sp) .set at /* * a0 (struct pt_regs *) regs * a1 (unsigned long) 1 for write access + * a2 (unsigned long) faulting virtual address */ move a0,sp jal do_page_fault @@ -335,7 +362,10 @@ nowrite_mod: lui k1,%HI(TLBMAP) addu k0,k1 lw k1,(k0) + nop + nop tlbp # find faulting entry + nop andi k1,_PAGE_WRITE beqz k1,nowrite_mod /* @@ -366,12 +396,15 @@ nowrite_mod: END(handle_mod) .set at +/* + * Flush the complete TLB + */ .set noreorder LEAF(tlbflush) li t0,PM_4K mtc0 t0,CP0_PAGEMASK - la t0,boot_info - lw t0,OFFSET_BOOTINFO_TLB_ENTRIES(t0) + lw t0,mips_tlb_entries /* mips_tlb_enbtries is set */ + /* by bi_EarlySnarf() */ dmtc0 zero,CP0_ENTRYLO0 dmtc0 zero,CP0_ENTRYLO1 mfc0 t2,CP0_WIRED @@ -384,12 +417,67 @@ nowrite_mod: bne t2,t0,1b tlbwi # delay slot jr ra - nop + nop # delay slot END(tlbflush) +/* + * Flush a single entry from the TLB + * + * Parameters: a0 - unsigned long address + */ + .set noreorder + LEAF(tlbflush_page) + /* + * Step 1: Wipe out old TLB information. Not shure if + * we really need that step; call it paranoia ... + * In order to do that we need to disable interrupts. + */ + li t3,TLBMAP # then wait 3 cycles + ori t1,a0,0xfff # mask off low 12 bits + xori t1,0xfff + mfc0 t2,CP0_ENTRYHI # copy ASID into address + andi t2,0xff + or t2,t1 + mtc0 t2,CP0_ENTRYHI + srl t4,a0,12 # wait again three cycles + sll t4,t4,PTRLOG + dmtc0 zero,CP0_ENTRYLO0 + nop + tlbp # now query the TLB + nop + addu t3,t4 # wait another three cycles + ori t3,0xffff + xori t3,0xffff + mfc0 t1,CP0_INDEX + bltz t1,1f # No old entry? + dmtc0 zero,CP0_ENTRYLO1 + or t3,t1 # wait one cycle + tlbwi /* - * Code necessary to switch tasks on an Linux/MIPS machine. + * But there still might be an entry for the pgd ... */ +1: mtc0 t3,CP0_ENTRYHI + nop # wait 3 cycles + nop + nop + nop + tlbp # TLB lookup + nop + nop + nop + mfc0 t1,CP0_INDEX # wait 3 cycles + bltz t1,1f # No old entry? + nop + tlbwi # gotcha ... +1: jr ra + nop # delay slot + END(tlbflush_page) + +/* + * Code necessary to switch tasks on an Linux/MIPS machine. + * FIXME: We don't need to disable interrupts anymore. + * FIXME: Do some cache magic for faster loading/saving. + */ .align 5 LEAF(resume) /* @@ -416,24 +504,24 @@ nowrite_mod: * Save non-scratch registers * All other registers have been saved on the kernel stack */ - sw s0,TOFF_REG16(t0) - sw s1,TOFF_REG17(t0) - sw s2,TOFF_REG18(t0) - sw s3,TOFF_REG19(t0) - sw s4,TOFF_REG20(t0) - sw s5,TOFF_REG21(t0) - sw s6,TOFF_REG22(t0) - sw s7,TOFF_REG23(t0) - sw gp,TOFF_REG28(t0) - sw sp,TOFF_REG29(t0) - sw fp,TOFF_REG30(t0) + sd s0,TOFF_REG16(t0) + sd s1,TOFF_REG17(t0) + sd s2,TOFF_REG18(t0) + sd s3,TOFF_REG19(t0) + sd s4,TOFF_REG20(t0) + sd s5,TOFF_REG21(t0) + sd s6,TOFF_REG22(t0) + sd s7,TOFF_REG23(t0) + sd gp,TOFF_REG28(t0) + sd sp,TOFF_REG29(t0) + sd fp,TOFF_REG30(t0) /* * Save floating point state */ sll t2,t1,2 bgez t2,2f - sw ra,TOFF_REG31(t0) # delay slot + sd ra,TOFF_REG31(t0) # delay slot sll t2,t1,5 bgez t2,1f sdc1 $f0,(TOFF_FPU+0)(t0) # delay slot @@ -460,7 +548,7 @@ nowrite_mod: /* * Store the 16 even double precision registers */ -1: cfc1 t1,$31 +1: cfc1 t1,fcr31 sdc1 $f2,(TOFF_FPU+16)(t0) sdc1 $f4,(TOFF_FPU+32)(t0) sdc1 $f6,(TOFF_FPU+48)(t0) @@ -569,23 +657,23 @@ nowrite_mod: ldc1 $f26,(TOFF_FPU+208)(a0) ldc1 $f28,(TOFF_FPU+224)(a0) ldc1 $f30,(TOFF_FPU+240)(a0) - ctc1 t0,$31 + ctc1 t0,fcr31 /* * Restore non-scratch registers */ -2: lw s0,TOFF_REG16(a0) - lw s1,TOFF_REG17(a0) - lw s2,TOFF_REG18(a0) - lw s3,TOFF_REG19(a0) - lw s4,TOFF_REG20(a0) - lw s5,TOFF_REG21(a0) - lw s6,TOFF_REG22(a0) - lw s7,TOFF_REG23(a0) - lw gp,TOFF_REG28(a0) - lw sp,TOFF_REG29(a0) - lw fp,TOFF_REG30(a0) - lw ra,TOFF_REG31(a0) +2: ld s0,TOFF_REG16(a0) + ld s1,TOFF_REG17(a0) + ld s2,TOFF_REG18(a0) + ld s3,TOFF_REG19(a0) + ld s4,TOFF_REG20(a0) + ld s5,TOFF_REG21(a0) + ld s6,TOFF_REG22(a0) + ld s7,TOFF_REG23(a0) + ld gp,TOFF_REG28(a0) + ld sp,TOFF_REG29(a0) + ld fp,TOFF_REG30(a0) + ld ra,TOFF_REG31(a0) /* * Restore status register @@ -598,135 +686,156 @@ nowrite_mod: END(resume) /* - * Some bits in the config register + * Load a new root pointer into the tlb */ -#define CONFIG_DB (1<<4) -#define CONFIG_IB (1<<5) + .set noreorder + LEAF(load_pgd) + /* + * Switch the root pointer + */ + mfc0 t0,CP0_STATUS + ori t1,t0,1 + xori t1,1 + mtc0 t1,CP0_STATUS + srl a0,6 + ori a0,MODE_ALIAS + li t1,TLB_ROOT + mtc0 t1,CP0_ENTRYHI + mtc0 zero,CP0_INDEX + mtc0 a0,CP0_ENTRYLO0 + mtc0 zero,CP0_ENTRYLO1 + mtc0 t0,CP0_STATUS + jr ra + tlbwi # delay slot + END(load_pgd) /* - * Flush instruction/data caches + * do_syscall calls the function in a1 with upto 7 arguments. If over + * four arguments are being requested, the additional arguments will + * be copied from the user stack pointed to by a0->reg29. * - * Parameters: a0 - starting address to flush - * a1 - size of area to be flushed - * a2 - which caches to be flushed + * FIXME: This function will fail for syscalls with more than four + * arguments from kernelspace. * - * FIXME: - ignores parameters in a0/a1 - * - doesn't know about second level caches + * a0 (struct pt_regs *) pointer to user registers + * a1 (syscall_t) pointer to syscall to do + * a2 (int) number of arguments to syscall */ - .set noreorder - LEAF(sys_cacheflush) - andi t1,a2,DCACHE - beqz t1,do_icache - li t0,KSEG0 # delay slot - - /* - * Writeback data cache, even lines - */ - li t1,CACHELINES-1 -1: cache Index_Writeback_Inv_D,0(t0) - cache Index_Writeback_Inv_D,32(t0) - cache Index_Writeback_Inv_D,64(t0) - cache Index_Writeback_Inv_D,96(t0) - cache Index_Writeback_Inv_D,128(t0) - cache Index_Writeback_Inv_D,160(t0) - cache Index_Writeback_Inv_D,192(t0) - cache Index_Writeback_Inv_D,224(t0) - cache Index_Writeback_Inv_D,256(t0) - cache Index_Writeback_Inv_D,288(t0) - cache Index_Writeback_Inv_D,320(t0) - cache Index_Writeback_Inv_D,352(t0) - cache Index_Writeback_Inv_D,384(t0) - cache Index_Writeback_Inv_D,416(t0) - cache Index_Writeback_Inv_D,448(t0) - cache Index_Writeback_Inv_D,480(t0) - addiu t0,512 - bnez t1,1b - subu t1,1 - - /* - * Writeback data cache, odd lines - * Only needed for 16 byte line size - */ - mfc0 t1,CP0_CONFIG - andi t1,CONFIG_DB - bnez t1,do_icache - li t1,CACHELINES-1 -1: cache Index_Writeback_Inv_D,16(t0) - cache Index_Writeback_Inv_D,48(t0) - cache Index_Writeback_Inv_D,80(t0) - cache Index_Writeback_Inv_D,112(t0) - cache Index_Writeback_Inv_D,144(t0) - cache Index_Writeback_Inv_D,176(t0) - cache Index_Writeback_Inv_D,208(t0) - cache Index_Writeback_Inv_D,240(t0) - cache Index_Writeback_Inv_D,272(t0) - cache Index_Writeback_Inv_D,304(t0) - cache Index_Writeback_Inv_D,336(t0) - cache Index_Writeback_Inv_D,368(t0) - cache Index_Writeback_Inv_D,400(t0) - cache Index_Writeback_Inv_D,432(t0) - cache Index_Writeback_Inv_D,464(t0) - cache Index_Writeback_Inv_D,496(t0) - addiu t0,512 - bnez t1,1b - subu t1,1 - -do_icache: andi t1,a2,ICACHE - beqz t1,done - - /* - * Flush instruction cache, even lines - */ - lui t0,0x8000 - li t1,CACHELINES-1 -1: cache Index_Invalidate_I,0(t0) - cache Index_Invalidate_I,32(t0) - cache Index_Invalidate_I,64(t0) - cache Index_Invalidate_I,96(t0) - cache Index_Invalidate_I,128(t0) - cache Index_Invalidate_I,160(t0) - cache Index_Invalidate_I,192(t0) - cache Index_Invalidate_I,224(t0) - cache Index_Invalidate_I,256(t0) - cache Index_Invalidate_I,288(t0) - cache Index_Invalidate_I,320(t0) - cache Index_Invalidate_I,352(t0) - cache Index_Invalidate_I,384(t0) - cache Index_Invalidate_I,416(t0) - cache Index_Invalidate_I,448(t0) - cache Index_Invalidate_I,480(t0) - addiu t0,512 - bnez t1,1b - subu t1,1 - - /* - * Flush instruction cache, even lines - * Only needed for 16 byte line size - */ - mfc0 t1,CP0_CONFIG - andi t1,CONFIG_IB - bnez t1,done - li t1,CACHELINES-1 -1: cache Index_Invalidate_I,16(t0) - cache Index_Invalidate_I,48(t0) - cache Index_Invalidate_I,80(t0) - cache Index_Invalidate_I,112(t0) - cache Index_Invalidate_I,144(t0) - cache Index_Invalidate_I,176(t0) - cache Index_Invalidate_I,208(t0) - cache Index_Invalidate_I,240(t0) - cache Index_Invalidate_I,272(t0) - cache Index_Invalidate_I,304(t0) - cache Index_Invalidate_I,336(t0) - cache Index_Invalidate_I,368(t0) - cache Index_Invalidate_I,400(t0) - cache Index_Invalidate_I,432(t0) - cache Index_Invalidate_I,464(t0) - cache Index_Invalidate_I,496(t0) - addiu t0,512 - bnez t1,1b - subu t1,1 - -done: j ra - nop - END(sys_cacheflush) +#if defined (__MIPSEB__) && defined (__mips64) +#define bo 4 +#else +#define bo 0 +#endif + .set reorder + .text +NESTED(do_syscalls, 64, sp) + LONG_SUBU sp,64 + REG_S ra,56(sp) + dsll a2,a2,PTRLOG + lw t1,dst(a2) + move t2,a1 + REG_L t0,FR_REG29(a0) # get old user stack pointer + jalr t1 + +7: lw t1,24+bo(t0) # parameter #7 from usp + REG_S t1,SZREG*6(sp) +6: lw t1,20+bo(t0) # parameter #6 from usp + REG_S t1,SZREG*5(sp) +5: lw t1,16+bo(t0) # parameter #5 from usp + REG_S t1,SZREG*4(sp) + +4: lw a3,FR_REG7+bo(a0) # 4 args +3: lw a2,FR_REG6+bo(a0) # 3 args +2: lw a1,FR_REG5+bo(a0) # 2 args +1: lw a0,FR_REG4+bo(a0) # 1 args + jalr t2 + ld ra,56(sp) + addiu sp,64 + jr ra +0: jalr t2 # 0 args, just pass a0 + ld ra,56(sp) + LONG_ADDIU sp,64 + jr ra + END(do_syscalls) + + .rdata + .align PTRLOG +dst: PTR 0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b + + .section __ex_table,"a" + PTR 7b,bad_stack + PTR 6b,bad_stack + PTR 5b,bad_stack + .text + +#ifdef CONFIG_REVERSE + +/* + * Same as above but for processes running with reverse byte order. + * When exec(2)ing a file the system detects normal/reverse byteorder in + * an executable and + * - sets the appropriate vector for syscalls and other low level + * routines that depend of userspace byteorder. + * - set the reverse byteorder flag in c0_status + * - marks the process as reverse in the process table. + */ +#define REG_SWAP(r,t) \ + .set push; \ + .set noat; \ + sll $1,r,24; \ + andi t,r,0xff00; \ + sll t,$t,8; \ + or $1,t; \ + srl t,r,8; \ + andi t,$t,0xff00; \ + or $1,t; \ + srl r,r,24; \ + or $1,r; \ + .set pop + + .set reorder + .text +NESTED(do_syscalls_rev, 64, sp) + LONG_SUBU sp,64 + REG_S ra,56(sp) + dsll a2,a2,PTRLOG + lw t1,dst_rev(a2) + move t2,a1 + REG_L t0,FR_REG29(a0) # get old user stack pointer + jalr t1 + +7: lw t1,24+bo(t0) # parameter #7 from usp + REG_SWAP(t1,v0) # convert byteorder + REG_S t1,SZREG*6(sp) +6: lw t1,20+bo(t0) # parameter #6 from usp + REG_SWAP(t1,v0) # convert byteorder + REG_S t1,SZREG*5(sp) +5: lw t1,16+bo(t0) # parameter #5 from usp + REG_SWAP(t1,v0) # convert byteorder + REG_S t1,SZREG*4(sp) + +4: lw a3,FR_REG7+bo(a0) # 4 args +3: lw a2,FR_REG6+bo(a0) # 3 args +2: lw a1,FR_REG5+bo(a0) # 2 args +1: lw a0,FR_REG4+bo(a0) # 1 args + jalr t2 + ld ra,56(sp) + addiu sp,64 + jr ra +0: jalr t2 # 0 args, just pass a0 + ld ra,56(sp) + LONG_ADDIU sp,64 + jr ra + END(do_syscalls) + + .rdata + .align PTRLOG +dst_rev: PTR 0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b + + .section __ex_table,"a" + PTR 7b,bad_stack + PTR 6b,bad_stack + PTR 5b,bad_stack + .text + +#endif /* CONFIG_REVERSE */ diff --git a/arch/mips/mips3/showregs.c b/arch/mips/mips3/showregs.c new file mode 100644 index 000000000..651cb6a24 --- /dev/null +++ b/arch/mips/mips3/showregs.c @@ -0,0 +1,36 @@ +/* + * linux/arch/mips/mips3/showregs.c + * + * Copyright (C) 1995, 1996 Ralf Baechle + */ +#include <linux/kernel.h> +#include <linux/ptrace.h> + +void show_regs(struct pt_regs * regs) +{ + /* + * Saved main processor registers + */ + printk("$0 : %016Lx %016Lx %016Lx %016Lx\n", + 0ULL, regs->regs[1], regs->regs[2], regs->regs[3]); + printk("$4 : %016Lx %016Lx %016Lx %016Lx\n", + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %016Lx %016Lx %016Lx %016Lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); + printk("$12: %016Lx %016Lx %016Lx %016Lx\n", + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16: %016Lx %016Lx %016Lx %016Lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); + printk("$20: %016Lx %016Lx %016Lx %016Lx\n", + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24: %016Lx %016Lx\n", + regs->regs[24], regs->regs[25]); + printk("$28: %016Lx %016Lx %016Lx %016Lx\n", + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + + /* + * Saved cp0 registers + */ + printk("epc : %016Lx\nStatus: %08x\nCause : %08x\n", + regs->cp0_epc, regs->cp0_status, regs->cp0_cause); +} diff --git a/arch/mips/mips4/Makefile b/arch/mips/mips4/Makefile new file mode 100644 index 000000000..d5827861b --- /dev/null +++ b/arch/mips/mips4/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the MIPS IV specific parts of the Linux/MIPS kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: mips.o +EXTRA_ASFLAGS = -mips4 -mcpu=r8000 +O_TARGET := mips.o +O_OBJS := cpu.o pagetables.o showregs.o + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/mips4/README b/arch/mips/mips4/README new file mode 100644 index 000000000..22e90921b --- /dev/null +++ b/arch/mips/mips4/README @@ -0,0 +1,3 @@ +This directory contains the start of the R8000/R10000 specific part. I +tried to support this CPU as good as possible without a machine and +without detailed documentation. diff --git a/arch/mips/mips4/cpu.c b/arch/mips/mips4/cpu.c new file mode 100644 index 000000000..ef5a3f8db --- /dev/null +++ b/arch/mips/mips4/cpu.c @@ -0,0 +1,106 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/sched.h> + +#include <asm/cache.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/processor.h> + +extern asmlinkage void mips4_cacheflush(void *addr, int nbytes, unsigned int flags); + +unsigned long page_colour_mask; + +void (*mips_cache_init)(void); + +static void +mips4_cache_init(void) +{ + /* + * The R10000 is in most aspects similar to the R4400. It + * should get some special optimizations. + */ + write_32bit_cp0_register(CP0_FRAMEMASK, 0); + set_cp0_status(ST0_XX, ST0_XX); + /* + * Actually this mask stands for only 16k cache. This is + * correct since the R10000 has multiple ways in it's cache. + */ + page_colour_mask = 0x3000; + cacheflush = mips4_cacheflush; + /* + * The R10k might even work for Linux/MIPS - but we're paranoid + * and refuse to run until this is tested on real silicon + */ + panic("CPU too expensive - making holiday in the ANDES!"); +} + +void (*switch_to_user_mode)(struct pt_regs *regs); + +static void +mips4_switch_to_user_mode(struct pt_regs *regs) +{ + regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU)) | KSU_USER; +} + +unsigned long (*thread_saved_pc)(struct thread_struct *t); + +/* + * Return saved PC of a blocked thread. + * XXX This works only for 64 bit kernels. + */ +static unsigned long mips4_thread_saved_pc(struct thread_struct *t) +{ + return ((unsigned long long *)(unsigned long)t->reg29)[11]; +} + +unsigned long (*get_wchan)(struct task_struct *p); + +static unsigned long mips4_get_wchan(struct task_struct *p) +{ + /* + * This one depends on the frame size of schedule(). Do a + * "disass schedule" in gdb to find the frame size. Also, the + * code assumes that sleep_on() follows immediately after + * interruptible_sleep_on() and that add_timer() follows + * immediately after interruptible_sleep(). Ugly, isn't it? + * Maybe adding a wchan field to task_struct would be better, + * after all... + */ + unsigned long schedule_frame; + unsigned long pc; + + pc = thread_saved_pc(&p->tss); + if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { + schedule_frame = ((unsigned long long *)(long)p->tss.reg30)[10]; + return (unsigned long)((unsigned long long *)schedule_frame)[9]; + } + return pc; +} + +extern void mips4_clear_page(unsigned long page); +extern void mips4_copy_page(unsigned long to, unsigned long from); +asmlinkage void (*restore_fp_context)(struct sigcontext *sc); +asmlinkage void (*save_fp_context)(struct sigcontext *sc); + +void +mips4_cpu_init(void) +{ + extern void mips4_pgd_init(unsigned long page); + extern asmlinkage void mips4_restore_fp_context(struct sigcontext *sc); + extern asmlinkage void mips4_save_fp_context(struct sigcontext *sc); + + mips_cache_init = mips4_cache_init; + pgd_init = mips1_pgd_init; + switch_to_user_mode = mips4_switch_to_user_mode; + thread_saved_pc = mips4_thread_saved_pc; + get_wchan = mips4_get_wchan; + clear_page = mips4_clear_page; + restore_fp_context = mips4_restore_fp_context; + save_fp_context = mips4_save_fp_context; +} diff --git a/arch/mips/mips4/pagetables.c b/arch/mips/mips4/pagetables.c new file mode 100644 index 000000000..b1b86290a --- /dev/null +++ b/arch/mips/mips4/pagetables.c @@ -0,0 +1,122 @@ +/* + * 64 bit MIPS specific page handling. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 Ralf Baechle + */ +#include <linux/mm.h> +#include <asm/cache.h> +#include <asm/mipsconfig.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +void (*pgd_init)(unsigned long page); + +/* + * Initialize new page directory with pointers to invalid ptes + */ +void mips4_pgd_init(unsigned long page) +{ + unsigned long dummy1, dummy2; + + /* + * We generate dirty lines in the datacache, overwrite these lines + * with zeros and then flush the cache. Sounds horribly complicated + * but is just a trick to avoid unnecessary loads of from memory + * and uncached stores which are very expensive. + * FIXME: This is the same like the R4000 version. We could do some + * R10000 trickery using caching mode "uncached accelerated". + */ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "dsll32\t$1,%2,0\n\t" + "dsrl32\t%2,$1,0\n\t" + "or\t%2,$1\n" + "1:\t" + "cache\t%5,(%0)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%2,8(%0)\n\t" + "cache\t%5,16(%0)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%2,24(%0)\n\t" + "cache\t%5,32(%0)\n\t" + "sd\t%2,32(%0)\n\t" + "sd\t%2,40(%0)\n\t" + "cache\t%5,48(%0)\n\t" + "sd\t%2,48(%0)\n\t" + "sd\t%2,56(%0)\n\t" + "subu\t%1,1\n\t" + "bnez\t%1,1b\n\t" + "addiu\t%0,64\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=&r" (dummy1), + "=&r" (dummy2) + :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) | + _PAGE_TABLE), + "0" (page), + "1" (PAGE_SIZE/(sizeof(pmd_t)*16)), + "i" (Create_Dirty_Excl_D) + :"$1"); + /* + * Now force writeback to ashure values are in the RAM. + */ + cacheflush(page, PAGE_SIZE, CF_DCACHE|CF_VIRTUAL); +} + +void (*clear_page)(unsigned long page); + +/* + * To do: cache magic + */ +void mips4_clear_page(unsigned long page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%2\n" + "1:\tsd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE) + :"$1","memory"); +} + +void (*copy_page)(unsigned long to, unsigned long from); + +/* + * This is horribly inefficient ... + */ +void mips4_copy_page(unsigned long to, unsigned long from) +{ + /* + * Force writeback of old page to memory. We don't know the + * virtual address, so we have to flush the entire cache ... + */ + cacheflush(0, ~0, CF_DCACHE|CF_VIRTUAL); + sync_mem(); + memcpy((void *) to, + (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE); + /* + * Now writeback the page again if colour has changed. + */ + if (page_colour(from) != page_colour(to)) + cacheflush(0, ~0, CF_DCACHE|CF_VIRTUAL); +} diff --git a/arch/mips/mkdisk b/arch/mips/mkdisk deleted file mode 100644 index 468d34727..000000000 --- a/arch/mips/mkdisk +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -cp vmlinux vmlinux.tmp -mipsel-linux-strip -g -x vmlinux.tmp -mwrite -n vmlinux.tmp a:vmlinux -rm -f vmlinux.tmp diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 6ff21fafd..6f69a0ee6 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the linux mips-specific parts of the memory manager. +# Makefile for the Linux/MIPS-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -7,26 +7,7 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -.c.o: - $(CC) $(CFLAGS) -c $< -.s.o: - $(AS) -o $*.o $< -.c.s: - $(CC) $(CFLAGS) -S $< +O_TARGET := mm.o +O_OBJS := extable.o init.o fault.o stack.o -OBJS = fault.o init.o - -mm.o: $(OBJS) - $(LD) -r -o mm.o $(OBJS) - -modules: - -dep: - $(CPP) -M *.c > .depend - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif +include $(TOPDIR)/Rules.make diff --git a/arch/mips/mm/extable.c b/arch/mips/mm/extable.c new file mode 100644 index 000000000..c46568ab1 --- /dev/null +++ b/arch/mips/mm/extable.c @@ -0,0 +1,57 @@ +/* + * linux/arch/mips/mm/extable.c + */ +#include <linux/config.h> +#include <linux/module.h> +#include <asm/uaccess.h> + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline unsigned +search_one_table(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid->nextinsn; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +unsigned long search_exception_table(unsigned long addr) +{ + unsigned ret; +#ifdef CONFIG_MODULES + struct module *mp; +#endif + + /* Search the kernel's table first. */ + ret = search_one_table(__start___ex_table, + __stop___ex_table-1, addr); + if (ret) + return ret; + +#ifdef CONFIG_MODULES + for (mp = module_list; mp != NULL; mp = mp->next) { + if (mp->exceptinfo.start != NULL) { + ret = search_one_table(mp->exceptinfo.start, + mp->exceptinfo.stop-1, addr); + if (ret) + return ret; + } + } +#endif + + return 0; +} diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 9256025d9..f1462eff9 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -1,10 +1,8 @@ /* * arch/mips/mm/fault.c * - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * Ported to MIPS by Ralf Baechle + * Copyright (C) 1995, 1996 by Ralf Baechle */ -#include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/head.h> @@ -16,45 +14,47 @@ #include <linux/mman.h> #include <linux/mm.h> +#include <asm/cache.h> #include <asm/system.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/pgtable.h> extern void die_if_kernel(char *, struct pt_regs *, long); /* + * Macro for exception fixup code to access integer registers. + */ +#define dpf_reg(r) (regs->regs[r]) + +/* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate * routines. */ asmlinkage void -do_page_fault(struct pt_regs *regs, unsigned long writeaccess) +do_page_fault(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) { struct vm_area_struct * vma; - unsigned long address; - - /* get the address */ - __asm__(".set\tmips3\n\t" - "dmfc0\t%0,$8\n\t" - ".set\tmips0" - : "=r" (address)); + struct task_struct *tsk = current; + struct mm_struct *mm = tsk->mm; + unsigned long fixup; #if 0 - printk("do_page_fault() #1: %s %08lx (epc == %08lx)\n", + printk("do_page_fault() #1: %s %08lx (epc == %08lx, ra == %08lx)\n", writeaccess ? "writeaccess to" : "readaccess from", - address, regs->cp0_epc); + address, regs->cp0_epc, regs->regs[31]); #endif - vma = find_vma(current, address); + down(&mm->mmap_sem); + vma = find_vma(mm, address); if (!vma) goto bad_area; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) + if (expand_stack(vma, address)) goto bad_area; - vma->vm_offset -= vma->vm_start - (address & PAGE_MASK); - vma->vm_start = (address & PAGE_MASK); /* * Ok, we have a good vm_area for this memory access, so * we can handle it.. @@ -68,6 +68,8 @@ good_area: goto bad_area; } handle_mm_fault(vma, address, writeaccess); + up(&mm->mmap_sem); + return; /* @@ -75,18 +77,43 @@ good_area: * Fix it, but check if it's kernel or user first.. */ bad_area: + up(&mm->mmap_sem); + /* Did we have an exception handler installed? */ + + fixup = search_exception_table(regs->cp0_epc); + if (fixup) { + long new_epc; + new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); + printk("Taking exception at %lx (%lx)\n", + regs->cp0_epc, new_epc); + regs->cp0_epc = new_epc; + return; + } if (user_mode(regs)) { - current->tss.cp0_badvaddr = address; - current->tss.error_code = writeaccess; - send_sig(SIGSEGV, current, 1); + tsk->tss.cp0_badvaddr = address; + tsk->tss.error_code = writeaccess; +#if 1 + printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n" + "%08lx (epc == %08lx, ra == %08lx)\n", + tsk->comm, + writeaccess ? "writeaccess to" : "readaccess from", + address, + (unsigned long) regs->cp0_epc, + (unsigned long) regs->regs[31]); +#endif + force_sig(SIGSEGV, tsk); return; } /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ - printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx", - address); + printk(KERN_ALERT "Unable to handle kernel paging request at virtual " +#ifdef __mips64 + "address %08lx, epc == %08Lx\n", address, regs->cp0_epc); +#else + "address %08lx, epc == %016lx\n", address, regs->cp0_epc); +#endif die_if_kernel("Oops", regs, writeaccess); do_exit(SIGKILL); } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 37912e2d0..149349102 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -15,26 +15,29 @@ #include <linux/ptrace.h> #include <linux/mman.h> #include <linux/mm.h> +#include <linux/swap.h> +#ifdef CONFIG_BLK_DEV_INITRD +#include <linux/blk.h> +#endif -#include <asm/cachectl.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/dma.h> +#include <asm/jazzdma.h> #include <asm/vector.h> #include <asm/system.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/pgtable.h> +#include <asm/page.h> extern void deskstation_tyne_dma_init(void); -extern void scsi_mem_init(unsigned long); -extern void sound_mem_init(void); -extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); -extern char empty_zero_page[PAGE_SIZE]; - /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode + * for a process dying in kernel mode, possibly leaving an inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized @@ -48,9 +51,18 @@ pte_t * __bad_pagetable(void) extern char empty_bad_page_table[PAGE_SIZE]; unsigned long page; unsigned long dummy1, dummy2; +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) + unsigned long dummy3; +#endif - page = ((unsigned long)empty_bad_page_table) + (PT_OFFSET - PAGE_OFFSET); -#ifdef __R4000__ + page = (unsigned long) empty_bad_page_table; + page = page_to_ptp(page); + /* + * As long as we only save the low 32 bit of the 64 bit wide + * R4000 registers on interrupt we cannot use 64 bit memory accesses + * to the main memory. + */ +#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) /* * Use 64bit code even for Linux/MIPS 32bit on R4000 */ @@ -69,11 +81,12 @@ pte_t * __bad_pagetable(void) ".set\tat\n" ".set\treorder" :"=r" (dummy1), - "=r" (dummy2) - :"r" (pte_val(BAD_PAGE)), - "0" (page), - "1" (PAGE_SIZE/8)); -#else + "=r" (dummy2), + "=r" (dummy3) + :"0" (page), + "1" (PAGE_SIZE/8), + "2" (pte_val(BAD_PAGE))); +#else /* (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) */ __asm__ __volatile__( ".set\tnoreorder\n" "1:\tsw\t%2,(%0)\n\t" @@ -91,128 +104,37 @@ pte_t * __bad_pagetable(void) return (pte_t *)page; } -static inline void -__zeropage(unsigned long page) -{ - unsigned long dummy1, dummy2; - -#ifdef __R4000__ - /* - * Use 64bit code even for Linux/MIPS 32bit on R4000 - */ - __asm__ __volatile__( - ".set\tnoreorder\n" - ".set\tnoat\n\t" - ".set\tmips3\n" - "1:\tsd\t$0,(%0)\n\t" - "subu\t%1,1\n\t" - "bnez\t%1,1b\n\t" - "addiu\t%0,8\n\t" - ".set\tmips0\n\t" - ".set\tat\n" - ".set\treorder" - :"=r" (dummy1), - "=r" (dummy2) - :"0" (page), - "1" (PAGE_SIZE/8)); -#else - __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\tsw\t$0,(%0)\n\t" - "subu\t%1,1\n\t" - "bnez\t%1,1b\n\t" - "addiu\t%0,4\n\t" - ".set\treorder" - :"=r" (dummy1), - "=r" (dummy2) - :"0" (page), - "1" (PAGE_SIZE/4)); -#endif -} - -static inline void -zeropage(unsigned long page) -{ - sys_cacheflush((void *)page, PAGE_SIZE, BCACHE); - sync_mem(); - __zeropage(page + (PT_OFFSET - PAGE_OFFSET)); -} - pte_t __bad_page(void) { extern char empty_bad_page[PAGE_SIZE]; unsigned long page = (unsigned long)empty_bad_page; - zeropage(page); + clear_page(page_to_ptp(page)); + cacheflush(page, PAGE_SIZE, CF_DCACHE|CF_VIRTUAL); return pte_mkdirty(mk_pte(page, PAGE_SHARED)); } -unsigned long __zero_page(void) -{ - unsigned long page = (unsigned long) empty_zero_page; - - zeropage(page); - return page; -} - -/* - * This is horribly inefficient ... - */ -void __copy_page(unsigned long from, unsigned long to) -{ - /* - * Now copy page from uncached KSEG1 to KSEG0. The copy destination - * is in KSEG0 so that we keep stupid L2 caches happy. - */ - if(from == (unsigned long) empty_zero_page) - { - /* - * The page copied most is the COW empty_zero_page. Since we - * know it's contents we can avoid the writeback reading of - * the page. Speeds up the standard case alot. - */ - __zeropage(to); - } - else - { - /* - * Force writeback of old page to memory. We don't know the - * virtual address, so we have to flush the entire cache ... - */ - sys_cacheflush(0, ~0, DCACHE); - sync_mem(); - memcpy((void *) to, - (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE); - } - /* - * Now writeback the page again if colour has changed. - * Actually this does a Hit_Writeback, but due to an artifact in - * the R4xx0 implementation this should be slightly faster. - * Then sweep chipset controlled secondary caches and the ICACHE. - */ - if (page_colour(from) != page_colour(to)) - sys_cacheflush(0, ~0, DCACHE); - sys_cacheflush(0, ~0, ICACHE); -} - void show_mem(void) { - int i,free = 0,total = 0; + int i, free = 0, total = 0, reserved = 0; int shared = 0; printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - i = (high_memory - PAGE_OFFSET) >> PAGE_SHIFT; + i = max_mapnr; while (i-- > 0) { total++; - if (!mem_map[i]) + if (PageReserved(mem_map+i)) + reserved++; + else if (!mem_map[i].count) free++; else - shared += mem_map[i]-1; + shared += mem_map[i].count-1; } printk("%d pages of RAM\n", total); printk("%d free pages\n", free); + printk("%d reserved pages\n", reserved); printk("%d pages shared\n", shared); show_buffers(); #ifdef CONFIG_NET @@ -224,6 +146,7 @@ extern unsigned long free_area_init(unsigned long, unsigned long); unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) { + mips_cache_init(); pgd_init((unsigned long)swapper_pg_dir - (PT_OFFSET - PAGE_OFFSET)); return free_area_init(start_mem, end_mem); } @@ -235,41 +158,65 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) unsigned long tmp; extern int _etext; +#ifdef CONFIG_MIPS_JAZZ + if (mips_machgroup == MACH_GROUP_JAZZ) + start_mem = vdma_init(start_mem, end_mem); +#endif + end_mem &= PAGE_MASK; - high_memory = end_mem; + max_mapnr = MAP_NR(end_mem); + high_memory = (void *)end_mem; + + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); /* mark usable pages in the mem_map[] */ start_mem = PAGE_ALIGN(start_mem); - tmp = start_mem; - while (tmp < high_memory) { - mem_map[MAP_NR(tmp)] = 0; - tmp += PAGE_SIZE; - } + for(tmp = MAP_NR(start_mem);tmp < max_mapnr;tmp++) + clear_bit(PG_reserved, &mem_map[tmp].flags); + + /* + * For rPC44 we've reserved some memory too much. Free the memory + * from PAGE_SIZE to PAGE_OFFSET + 0xa0000 again. We don't free the + * lowest page where the exception handlers will reside. + */ + if (mips_machgroup == MACH_GROUP_ARC && + mips_machtype == MACH_DESKSTATION_RPC44) + for(tmp = MAP_NR(PAGE_OFFSET + PAGE_SIZE); + tmp < MAP_NR(PAGE_OFFSET + 0xa000); tmp++) + clear_bit(PG_reserved, &mem_map[tmp].flags); + #ifdef CONFIG_DESKSTATION_TYNE - deskstation_tyne_dma_init(); -#endif -#ifdef CONFIG_SCSI - scsi_mem_init(high_memory); + if (mips_machtype == MACH_DESKSTATION_TYNE) + deskstation_tyne_dma_init(); #endif -#ifdef CONFIG_SOUND - sound_mem_init(); -#endif - for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) { - if (mem_map[MAP_NR(tmp)]) { + for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) { + /* + * This is only for PC-style DMA. The onboard DMA + * of Jazz and Tyne machines is completly different and + * not handled via a flag in mem_map_t. + */ + if (tmp >= MAX_DMA_ADDRESS) + clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); + if (PageReserved(mem_map+MAP_NR(tmp))) { if (tmp < (unsigned long) &_etext) codepages++; else if (tmp < start_mem) datapages++; continue; } - mem_map[MAP_NR(tmp)] = 1; - free_page(tmp); + mem_map[MAP_NR(tmp)].count = 1; +#ifdef CONFIG_BLK_DEV_INITRD + if (!initrd_start || (tmp < initrd_start || tmp >= + initrd_end)) +#endif + free_page(tmp); } tmp = nr_free_pages << PAGE_SHIFT; printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n", tmp >> 10, - (high_memory - PAGE_OFFSET) >> 10, + max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10)); @@ -280,18 +227,18 @@ void si_meminfo(struct sysinfo *val) { int i; - i = high_memory >> PAGE_SHIFT; + i = MAP_NR(high_memory); val->totalram = 0; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = buffermem; while (i-- > 0) { - if (mem_map[i] & MAP_PAGE_RESERVED) + if (PageReserved(mem_map+i)) continue; val->totalram++; - if (!mem_map[i]) + if (!mem_map[i].count) continue; - val->sharedram += mem_map[i]-1; + val->sharedram += mem_map[i].count-1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; diff --git a/arch/mips/mm/stack.c b/arch/mips/mm/stack.c new file mode 100644 index 000000000..3a4dccd26 --- /dev/null +++ b/arch/mips/mm/stack.c @@ -0,0 +1,26 @@ +/* + * Kernel stack allocation/deallocation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + * + * (This is _bad_ if the free page pool is fragmented ...) + */ +#include <linux/sched.h> +#include <linux/mm.h> + +extern unsigned long alloc_kernel_stack(void) +{ + unsigned long stack; + stack = __get_free_pages(GFP_KERNEL, 1, 0); + + return stack; +} + +extern void free_kernel_stack(unsigned long stack) +{ + free_pages(stack, 1); +} diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile new file mode 100644 index 000000000..bfa8e2cad --- /dev/null +++ b/arch/mips/sni/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the SNI specific part of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +include ../../../.config + +all: sni.o +O_TARGET := sni.o +O_OBJS := hw-access.o int-handler.o reset.o setup.o + +ifdef CONFIG_PCI +O_OBJS += bios32.o +endif + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/sni/bios32.c b/arch/mips/sni/bios32.c new file mode 100644 index 000000000..366347902 --- /dev/null +++ b/arch/mips/sni/bios32.c @@ -0,0 +1,264 @@ +/* + * bios32.c - Fake PCI BIOS functions for RM200 C systems. Chainsawed + * from the Alpha version. + * + * Written by Ralf Baechle (ralf@gnu.ai.mit.edu) + * + * For more information, please consult + * + * PCI BIOS Specification Revision + * PCI Local Bus Specification + * PCI System Design Guide + * + * PCI Special Interest Group + * M/S HF3-15A + * 5200 N.E. Elam Young Parkway + * Hillsboro, Oregon 97124-6497 + * +1 (503) 696-2000 + * +1 (800) 433-5177 + * + * Manuals are $25 each or $50 for all three, plus $7 shipping + * within the United States, $35 abroad. + */ +#include <linux/config.h> + +#include <linux/kernel.h> +#include <linux/bios32.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/malloc.h> +#include <linux/mm.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/io.h> + +/* + * This is a table of the onboard PCI devices of the RM200 C + * onboard devices. + */ +static struct board { + unsigned short vendor; + unsigned short device_id; + unsigned int memory; + unsigned int io; + unsigned char irq; + unsigned char revision; + } boards[] = { + { + PCI_VENDOR_ID_NCR, + PCI_DEVICE_ID_NCR_53C810, + 0x1b000000, + 0x00000000, + 5, + 0x11 + }, + { + PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_LANCE, + 0x1b000100, + 0x17beffe0, + 6, + 0x16 + }, + { + PCI_VENDOR_ID_CIRRUS, + PCI_DEVICE_ID_CIRRUS_5434_8, + 0x18000000, + 0x00000000, + 4, + 0x8e + }, + { 0xffff, } +}; + +/* + * Given the vendor and device ids, find the n'th instance of that device + * in the system. + */ +int pcibios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct board *p; + + for (p = pci_devices; p->vendor != 0xffff; p++) { + if (p->vendor == vendor && p->device == device_id) { + if (curr == index) { + *devfn = p->devfn; + *bus = 0; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + + return PCIBIOS_DEVICE_NOT_FOUND; +} + +/* + * Given the class, find the n'th instance of that device + * in the system. + */ +int pcibios_find_class (unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class == class_code) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +int pcibios_present(void) +{ + return 1; +} + +unsigned long pcibios_init(unsigned long mem_start, + unsigned long mem_end) +{ + printk("SNI RM200 C BIOS32 fake implementation\n"); + + return mem_start; +} + +const char *pcibios_strerror (int error) +{ + static char buf[80]; + + switch (error) { + case PCIBIOS_SUCCESSFUL: + return "SUCCESSFUL"; + + case PCIBIOS_FUNC_NOT_SUPPORTED: + return "FUNC_NOT_SUPPORTED"; + + case PCIBIOS_BAD_VENDOR_ID: + return "SUCCESSFUL"; + + case PCIBIOS_DEVICE_NOT_FOUND: + return "DEVICE_NOT_FOUND"; + + case PCIBIOS_BAD_REGISTER_NUMBER: + return "BAD_REGISTER_NUMBER"; + + default: + sprintf (buf, "UNKNOWN RETURN 0x%x", error); + return buf; + } +} + +/* + * BIOS32-style PCI interface: + */ + +int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + *value = 0xff; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x00; + *value = conf_read(addr) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + *value = 0xffff; + + if (where & 0x1) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x08; + *value = conf_read(addr) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + *value = 0xffffffff; + if (where & 0x3) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + *value = conf_read(addr); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x00; + conf_write(addr, value << ((where & 3) * 8)); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x08; + conf_write(addr, value << ((where & 3) * 8)); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + conf_write(addr, value << ((where & 3) * 8)); + return PCIBIOS_SUCCESSFUL; +} diff --git a/arch/mips/sni/hw-access.c b/arch/mips/sni/hw-access.c new file mode 100644 index 000000000..42c69590a --- /dev/null +++ b/arch/mips/sni/hw-access.c @@ -0,0 +1,157 @@ +/* + * Low-level hardware access stuff for SNI RM200 PCI + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/types.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mc146818rtc.h> +#include <asm/vector.h> + +extern int FLOPPY_IRQ; +extern int FLOPPY_DMA; + +/* + * How to access the FDC's registers. + */ +static unsigned char +fd_inb(unsigned int port) +{ + return inb_p(port); +} + +static void +fd_outb(unsigned char value, unsigned int port) +{ + outb_p(value, port); +} + +/* + * How to access the floppy DMA functions. + */ +static void +fd_enable_dma(void) +{ + enable_dma(FLOPPY_DMA); +} + +static void +fd_disable_dma(void) +{ + disable_dma(FLOPPY_DMA); +} + +static int +fd_request_dma(void) +{ + return request_dma(FLOPPY_DMA, "floppy"); +} + +static void +fd_free_dma(void) +{ + free_dma(FLOPPY_DMA); +} + +static void +fd_clear_dma_ff(void) +{ + clear_dma_ff(FLOPPY_DMA); +} + +static void +fd_set_dma_mode(char mode) +{ + set_dma_mode(FLOPPY_DMA, mode); +} + +static void +fd_set_dma_addr(unsigned int addr) +{ + set_dma_addr(FLOPPY_DMA, addr); +} + +static void +fd_set_dma_count(unsigned int count) +{ + set_dma_count(FLOPPY_DMA, count); +} + +static int +fd_get_dma_residue(void) +{ + return get_dma_residue(FLOPPY_DMA); +} + +static void +fd_enable_irq(void) +{ + enable_irq(FLOPPY_IRQ); +} + +static void +fd_disable_irq(void) +{ + disable_irq(FLOPPY_IRQ); +} + +void +sni_fd_cacheflush(const void *addr, size_t size) +{ + cacheflush((unsigned long)addr, (unsigned long)size, CF_DCACHE|CF_ALL); +} + +/* + * RTC stuff (This is a guess on how the RM handles this ...) + */ +static unsigned char +rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void +rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +struct feature sni_rm200_pci_feature = { + /* + * How to access the floppy controller's ports + */ + fd_inb, + fd_outb, + /* + * How to access the floppy DMA functions. + */ + fd_enable_dma, + fd_disable_dma, + fd_request_dma, + fd_free_dma, + fd_clear_dma_ff, + fd_set_dma_mode, + fd_set_dma_addr, + fd_set_dma_count, + fd_get_dma_residue, + fd_enable_irq, + fd_disable_irq, + /* + * How to access the RTC functions. + */ + rtc_read_data, + rtc_write_data +}; diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S new file mode 100644 index 000000000..367c07d84 --- /dev/null +++ b/arch/mips/sni/int-handler.S @@ -0,0 +1,193 @@ +/* + * SNI RM200 PCI specific interrupt handler code. + * + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle + * + * This is a verbose copy of the Tyne/rPC44 interrupt handler. We + * don't share the code because the SNI machine has some extra interrupt + * features that want to be supported. + */ +#include <asm/asm.h> +#include <linux/config.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .text + .set noreorder + .set noat + .align 5 + NESTED(sni_rm200_pci_handle_int, FR_SIZE, sp) + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + CLI + .set at + lui s0,%hi(PORT_BASE_SNI) + li a0,0x0f + sb a0,%lo(PORT_BASE_SNI+0x20)(s0) # poll command + lb a0,%lo(PORT_BASE_SNI+0x20)(s0) # read result + bgtz a0,poll_second + andi a0,7 + beq a0,2,poll_second # cascade? + li s1,1 # delay slot + /* + * Acknowledge first pic + */ + lb t2,%lo(PORT_BASE_SNI+0x21)(s0) + lui s4,%hi(cache_21) + lb t0,%lo(cache_21)(s4) + sllv s1,s1,a0 + or t0,s1 + sb t0,%lo(cache_21)(s4) + sb t0,%lo(PORT_BASE_SNI+0x21)(s0) + lui s3,%hi(intr_count) + lw s7,%lo(intr_count)(s3) + li t2,0x20 + sb t2,%lo(PORT_BASE_SNI+0x20)(s0) + /* + * Now call the real handler + */ + la t3,IRQ_vectors + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,s7,1 + jalr t3 + sw t0,%lo(intr_count)(s3) + sw s7,%lo(intr_count)(s3) + /* + * Unblock first pic + */ + lbu t1,%lo(PORT_BASE_SNI+0x21)(s0) + lb t1,%lo(cache_21)(s4) + nor s1,zero,s1 + and t1,s1 + sb t1,%lo(cache_21)(s4) + jr v0 + sb t1,%lo(PORT_BASE_SNI+0x21)(s0) # delay slot + + /* + * Cascade interrupt from second PIC + */ + .align 5 +poll_second: li a0,0x0f + sb a0,%lo(PORT_BASE_SNI+0xa0)(s0) # poll command + lb a0,%lo(PORT_BASE_SNI+0xa0)(s0) # read result + bgtz a0,3f + andi a0,7 + /* + * Acknowledge second pic + */ + lbu t2,%lo(PORT_BASE_SNI+0xa1)(s0) + lui s4,%hi(cache_A1) + lb t3,%lo(cache_A1)(s4) + sllv s1,s1,a0 + or t3,s1 + sb t3,%lo(cache_A1)(s4) + sb t3,%lo(PORT_BASE_SNI+0xa1)(s0) + li t3,0x20 + sb t3,%lo(PORT_BASE_SNI+0xa0)(s0) + lui s3,%hi(intr_count) + lw s7,%lo(intr_count)(s3) + sb t3,%lo(PORT_BASE_SNI+0x20)(s0) + /* + * Now call the real handler + */ + la t3,IRQ_vectors + addiu a0,8 + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,s7,1 + jalr t3 + sw t0,%lo(intr_count)(s3) # delay slot + sw s7,%lo(intr_count)(s3) + /* + * Unblock second pic + */ + lb t1,%lo(PORT_BASE_SNI+0xa1)(s0) + lb t1,%lo(cache_A1)(s4) + subu t0,1 + nor s1,zero,s1 + and t1,t1,s1 + sb t1,%lo(cache_A1)(s4) + jr v0 + sb t1,%lo(PORT_BASE_SNI+0xa1)(s0) # delay slot + +/* + * FIXME: This is definatly wrong but I'll have to do it this way + * 'till I get more hardware info. + */ +#ifdef CONFIG_LANCE32 + +/* + * FIXME: detect this address + */ +#define LANCE_BASE 0xbb000100 + +/* Offsets from base I/O address. */ +#define LANCE_DATA 0x10 +#define LANCE_ADDR 0x12 +#define LANCE_RESET 0x14 +#define LANCE_BUS_IF 0x16 +#define LANCE_TOTAL_SIZE 0x18 + +/* + * ... check if we were interrupted by the Lance ... + */ +3: lh s0,LANCE_BASE+LANCE_ADDR + sh zero,LANCE_BASE+LANCE_ADDR + lh t1,LANCE_BASE+LANCE_DATA + andi t2,t1,0x80 + beqz t1,3f # no Lance interrupt? + mfc0 t0,CP0_STATUS # delay slot + ori t0,0x041f + xori t0,0x041e + mtc0 t0,CP0_STATUS + jal do_IRQ + li a0,10 # delay slot + sh s0,LANCE_BASE+LANCE_ADDR + mfc0 t0,CP0_STATUS + ori t0,0x0401 + xori t0,0x0001 + mtc0 t0,CP0_STATUS + j ret_from_sys_call + nop # delay slot + +#endif /* CONFIG_LANCE32 */ + +/* + * FIXME: This is definatly wrong but I'll have to do it this way + * 'till I get more hardware info. + */ +#ifdef CONFIG_SCSI_NCR53C8XX + +/* + * FIXME: detect this address + */ +#define NCR_BASE 0xb8000000 + +/* Offsets from base I/O address. */ +#define NCR_INTF 0x14 + +/* + * ... check if we were interrupted by the NCR ... + */ +3: lb t0,NCR_BASE+NCR_INTF + andi t0,7 + beqz t0,3f # no NCR interrupt? + nop # delay slot + jal do_fast_IRQ + li a0,5 # delay slot + j return + nop # delay slot + +#endif /* CONFIG_SCSI_NCR53C8XX */ + +/* + * "Jump extender" to reach spurious_interrupt + */ +3: j spurious_interrupt + nop # delay slot + END(sni_rm200_pci_handle_int) diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c new file mode 100644 index 000000000..9dd017a7c --- /dev/null +++ b/arch/mips/sni/reset.c @@ -0,0 +1,38 @@ +/* + * linux/arch/mips/sni/process.c + * + * Reset a SNI machine. + */ +#include <asm/io.h> +#include <asm/system.h> + +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. We try that for a while, + * and if it doesn't work, we do some other stupid things. + */ +static inline void +kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +void +sni_hard_reset_now(void) +{ + int i, j; + + sti(); + for (;;) { + for (i=0; i<100; i++) { + kb_wait(); + for(j = 0; j < 100000 ; j++) + /* nothing */; + outb_p(0xfe,0x64); /* pulse reset low */ + } + } +} diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c new file mode 100644 index 000000000..a4cc4a57f --- /dev/null +++ b/arch/mips/sni/setup.c @@ -0,0 +1,108 @@ +/* + * Setup pointers to hardware dependand routines. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + */ +#include <asm/ptrace.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/processor.h> +#include <asm/vector.h> + +/* + * Initial irq handlers. + */ +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; + +extern asmlinkage void sni_rm200_pci_handle_int(void); +extern asmlinkage void sni_fd_cacheflush(const void *addr, size_t size); +extern struct feature sni_rm200_pci_feature; +extern void sni_hard_reset_now(void); + +static void +sni_irq_setup(void) +{ + set_except_vector(0, sni_rm200_pci_handle_int); + request_region(0x20,0x20, "pic1"); + request_region(0xa0,0x20, "pic2"); + setup_x86_irq(2, &irq2); + /* + * IRQ0 seems to be the irq for PC style stuff. + * I don't know how to handle the debug button interrupt, so + * don't use this button yet or bad things happen ... + */ + set_cp0_status(ST0_IM, IE_IRQ0); +} + +void (*board_time_init)(struct irqaction *irq); + +static void sni_rm200_pci_time_init(struct irqaction *irq) +{ + /* set the clock to 100 Hz */ + outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + setup_x86_irq(0, irq); +} + +unsigned char aux_device_present; + +void +sni_rm200_pci_setup(void) +{ + tag *atag; + + /* + * We just check if a tag_screen_info can be gathered + * in setup_arch(), if yes we don't proceed futher... + */ + atag = bi_TagFind(tag_screen_info); + if (!atag) { + /* + * If no, we try to find the tag_arc_displayinfo which is + * always created by Milo for an ARC box (for now Milo only + * works on ARC boxes :) -Stoned. + */ + atag = bi_TagFind(tag_arcdisplayinfo); + if (atag) { + screen_info.orig_x = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x; + screen_info.orig_y = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y; + screen_info.orig_video_cols = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns; + screen_info.orig_video_lines = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines; + } + } + + irq_setup = sni_irq_setup; + fd_cacheflush = sni_fd_cacheflush; // Will go away + feature = &sni_rm200_pci_feature; + port_base = PORT_BASE_SNI; + isa_slot_offset = 0xb0000000; + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x70,0x10,"rtc"); + board_time_init = sni_rm200_pci_time_init; + + hard_reset_now = sni_hard_reset_now; + + if (mips_machtype == MACH_SNI_RM200_PCI) + EISA_bus = 1; + aux_device_present = 0xaa; +} |