summaryrefslogtreecommitdiffstats
path: root/arch/mips64/lib
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
commit1d67e90f19a7acfd9a05dc59678e7d0c5090bd0d (patch)
tree357efc7b93f8f5102110d20d293f41360ec212fc /arch/mips64/lib
parentaea27b2e18d69af87e673972246e66657b4fa274 (diff)
Merge with Linux 2.3.21.
Diffstat (limited to 'arch/mips64/lib')
-rw-r--r--arch/mips64/lib/Makefile5
-rw-r--r--arch/mips64/lib/csum_partial.S2
-rw-r--r--arch/mips64/lib/csum_partial_copy.c2
-rw-r--r--arch/mips64/lib/dump_tlb.c125
-rw-r--r--arch/mips64/lib/floppy-no.c2
-rw-r--r--arch/mips64/lib/floppy-std.c2
-rw-r--r--arch/mips64/lib/ide-no.c2
-rw-r--r--arch/mips64/lib/ide-std.c2
-rw-r--r--arch/mips64/lib/kbd-no.c2
-rw-r--r--arch/mips64/lib/kbd-std.c2
-rw-r--r--arch/mips64/lib/memcpy.S12
-rw-r--r--arch/mips64/lib/memset.S6
-rw-r--r--arch/mips64/lib/rtc-no.c2
-rw-r--r--arch/mips64/lib/rtc-std.c2
-rw-r--r--arch/mips64/lib/strlen_user.S33
-rw-r--r--arch/mips64/lib/strncpy_user.S47
-rw-r--r--arch/mips64/lib/strnlen_user.S47
-rw-r--r--arch/mips64/lib/watch.S2
18 files changed, 194 insertions, 103 deletions
diff --git a/arch/mips64/lib/Makefile b/arch/mips64/lib/Makefile
index f916d7263..3e61ae79e 100644
--- a/arch/mips64/lib/Makefile
+++ b/arch/mips64/lib/Makefile
@@ -1,4 +1,4 @@
-# $Id$
+# $Id: Makefile,v 1.2 1999/11/19 20:35:22 ralf Exp $
#
# Makefile for MIPS-specific library files..
#
@@ -11,6 +11,7 @@
L_TARGET = lib.a
L_OBJS = csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \
floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \
- rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o watch.o
+ rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o \
+ strnlen_user.o watch.o
include $(TOPDIR)/Rules.make
diff --git a/arch/mips64/lib/csum_partial.S b/arch/mips64/lib/csum_partial.S
index 9d31bba49..27147065a 100644
--- a/arch/mips64/lib/csum_partial.S
+++ b/arch/mips64/lib/csum_partial.S
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: csum_partial.S,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/csum_partial_copy.c b/arch/mips64/lib/csum_partial_copy.c
index 235bdbfaa..9f08f405a 100644
--- a/arch/mips64/lib/csum_partial_copy.c
+++ b/arch/mips64/lib/csum_partial_copy.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: csum_partial_copy.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/dump_tlb.c b/arch/mips64/lib/dump_tlb.c
index 0d563cbb6..27d5bd45d 100644
--- a/arch/mips64/lib/dump_tlb.c
+++ b/arch/mips64/lib/dump_tlb.c
@@ -1,8 +1,8 @@
/*
* Dump R4x00 TLB for debugging purposes.
*
- * Copyright (C) 1994, 1995 by Waldorf Electronics,
- * written by Ralf Baechle.
+ * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
+ * Copyright (C) 1999 by Silicon Graphics, Inc.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -15,22 +15,18 @@
#include <asm/page.h>
#include <asm/pgtable.h>
-static char *region_map [] = {
- "u", "s", "k", "!"
-};
+#define mips_tlb_entries 48
void
dump_tlb(int first, int last)
{
int i;
- int wired;
- unsigned int pagemask, c0, c1, r;
- unsigned long long entryhi, entrylo0, entrylo1;
+ unsigned int pagemask, c0, c1, asid;
+ unsigned long entryhi, entrylo0, entrylo1;
- wired = read_32bit_cp0_register(CP0_WIRED);
- printk("Wired: %d", wired);
-
- for(i=first;i<last;i++)
+ asid = get_entryhi() & 0xff;
+
+ for(i=first;i<=last;i++)
{
write_32bit_cp0_register(CP0_INDEX, i);
__asm__ __volatile__(
@@ -42,30 +38,31 @@ dump_tlb(int first, int last)
".set\treorder\n\t"
".set\tmips0\n\t");
pagemask = read_32bit_cp0_register(CP0_PAGEMASK);
- entryhi = read_64bit_cp0_register(CP0_ENTRYHI);
- entrylo0 = read_64bit_cp0_register(CP0_ENTRYLO0);
- entrylo1 = read_64bit_cp0_register(CP0_ENTRYLO1);
+ entryhi = read_32bit_cp0_register(CP0_ENTRYHI);
+ entrylo0 = read_32bit_cp0_register(CP0_ENTRYLO0);
+ entrylo1 = read_32bit_cp0_register(CP0_ENTRYLO1);
- if((entrylo0|entrylo1) & 2)
- {
+ /* Unused entries have a virtual address of KSEG0. */
+ if ((entryhi & 0xffffe000) != 0x80000000
+ && (entryhi & 0xff) == asid) {
/*
* Only print entries in use
*/
- printk("\nIndex: %2d pgmask=%08x ", i, pagemask);
+ printk("Index: %2d pgmask=%08x ", i, pagemask);
- r = entryhi >> 62;
c0 = (entrylo0 >> 3) & 7;
c1 = (entrylo1 >> 3) & 7;
- printk("%s vpn2=%08Lx "
- "[pfn=%06Lx c=%d d=%d v=%d g=%Ld]"
- "[pfn=%06Lx c=%d d=%d v=%d g=%Ld]",
- region_map [r], (entryhi >> 13) & 0xffffffff,
- (entrylo0 >> 6) & 0xffffff, c0,
+ printk("va=%08lx asid=%08lx"
+ " [pa=%06lx c=%d d=%d v=%d g=%ld]"
+ " [pa=%06lx c=%d d=%d v=%d g=%ld]",
+ (entryhi & 0xffffe000),
+ entryhi & 0xff,
+ entrylo0 & PAGE_MASK, c0,
(entrylo0 & 4) ? 1 : 0,
(entrylo0 & 2) ? 1 : 0,
(entrylo0 & 1),
- (entrylo1 >> 6) & 0xffffff, c1,
+ entrylo1 & PAGE_MASK, c1,
(entrylo1 & 4) ? 1 : 0,
(entrylo1 & 2) ? 1 : 0,
(entrylo1 & 1));
@@ -73,6 +70,8 @@ dump_tlb(int first, int last)
}
}
printk("\n");
+
+ set_entryhi(asid);
}
void
@@ -84,9 +83,45 @@ dump_tlb_all(void)
void
dump_tlb_wired(void)
{
+ int wired;
+
+ wired = read_32bit_cp0_register(CP0_WIRED);
+ printk("Wired: %d", wired);
dump_tlb(0, read_32bit_cp0_register(CP0_WIRED));
}
+#define BARRIER \
+ __asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
+ "nop;nop;nop;nop;nop;nop;nop\n\t" \
+ ".set\treorder");
+
+void
+dump_tlb_addr(unsigned long addr)
+{
+ unsigned int flags, oldpid;
+ int index;
+
+ __save_and_cli(flags);
+ oldpid = get_entryhi() & 0xff;
+ BARRIER;
+ set_entryhi((addr & PAGE_MASK) | oldpid);
+ BARRIER;
+ tlb_probe();
+ BARRIER;
+ index = get_index();
+ set_entryhi(oldpid);
+ __restore_flags(flags);
+
+ if (index < 0) {
+ printk("No entry for address 0x%08lx in TLB\n", addr);
+ return;
+ }
+
+ printk("Entry %d maps address 0x%08lx\n", index, addr);
+ dump_tlb(index, index);
+}
+
void
dump_tlb_nonwired(void)
{
@@ -99,30 +134,39 @@ dump_list_process(struct task_struct *t, void *address)
pgd_t *page_dir, *pgd;
pmd_t *pmd;
pte_t *pte, page;
- unsigned long addr;
+ unsigned int addr;
+ unsigned long val;
- addr = (unsigned long) address;
+ addr = (unsigned int) address;
- printk("Addr == %08lx\n", addr);
- printk("tasks->thread.pg_dir == %08lx\n",
- (unsigned long) t->thread.pg_dir);
- printk("tasks->mm.pgd == %08lx\n",
- (unsigned long) t->mm->pgd);
+ printk("Addr == %08x\n", addr);
+ printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd);
page_dir = pgd_offset(t->mm, 0);
- printk("page_dir == %08lx\n", (unsigned long) page_dir);
+ printk("page_dir == %08x\n", (unsigned int) page_dir);
pgd = pgd_offset(t->mm, addr);
- printk("pgd == %08lx, ", (unsigned long) pgd);
+ printk("pgd == %08x, ", (unsigned int) pgd);
pmd = pmd_offset(pgd, addr);
- printk("pmd == %08lx, ", (unsigned long) pmd);
+ printk("pmd == %08x, ", (unsigned int) pmd);
pte = pte_offset(pmd, addr);
- printk("pte == %08lx, ", (unsigned long) pte);
+ printk("pte == %08x, ", (unsigned int) pte);
page = *pte;
- printk("page == %08lx\n", (unsigned long) pte_val(page));
+ printk("page == %08x\n", (unsigned int) pte_val(page));
+
+ val = pte_val(page);
+ if (val & _PAGE_PRESENT) printk("present ");
+ if (val & _PAGE_READ) printk("read ");
+ if (val & _PAGE_WRITE) printk("write ");
+ if (val & _PAGE_ACCESSED) printk("accessed ");
+ if (val & _PAGE_MODIFIED) printk("modified ");
+ if (val & _PAGE_R4KBUG) printk("r4kbug ");
+ if (val & _PAGE_GLOBAL) printk("global ");
+ if (val & _PAGE_VALID) printk("valid ");
+ printk("\n");
}
void
@@ -131,13 +175,13 @@ dump_list_current(void *address)
dump_list_process(current, address);
}
-unsigned long
+unsigned int
vtop(void *address)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
- unsigned long addr, paddr;
+ unsigned int addr, paddr;
addr = (unsigned long) address;
pgd = pgd_offset(current->mm, addr);
@@ -154,7 +198,8 @@ dump16(unsigned long *p)
{
int i;
- for(i=0; i<8; i++) {
+ for(i=0;i<8;i++)
+ {
printk("*%08lx == %08lx, ",
(unsigned long)p, (unsigned long)*p++);
printk("*%08lx == %08lx\n",
diff --git a/arch/mips64/lib/floppy-no.c b/arch/mips64/lib/floppy-no.c
index 45b174a03..f0cd72d28 100644
--- a/arch/mips64/lib/floppy-no.c
+++ b/arch/mips64/lib/floppy-no.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: floppy-no.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/floppy-std.c b/arch/mips64/lib/floppy-std.c
index 77d7298ae..88dbfdbc1 100644
--- a/arch/mips64/lib/floppy-std.c
+++ b/arch/mips64/lib/floppy-std.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: floppy-std.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/ide-no.c b/arch/mips64/lib/ide-no.c
index 6fdadc7df..7a7833db7 100644
--- a/arch/mips64/lib/ide-no.c
+++ b/arch/mips64/lib/ide-no.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: ide-no.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/ide-std.c b/arch/mips64/lib/ide-std.c
index 1538ffde9..f80f7d5ea 100644
--- a/arch/mips64/lib/ide-std.c
+++ b/arch/mips64/lib/ide-std.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: ide-std.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/kbd-no.c b/arch/mips64/lib/kbd-no.c
index 5da1be2b7..0120e9ba4 100644
--- a/arch/mips64/lib/kbd-no.c
+++ b/arch/mips64/lib/kbd-no.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: kbd-no.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/kbd-std.c b/arch/mips64/lib/kbd-std.c
index 1a1bbcbf7..a35a0c5c8 100644
--- a/arch/mips64/lib/kbd-std.c
+++ b/arch/mips64/lib/kbd-std.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: kbd-std.c,v 1.1 1999/08/21 21:43:01 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/memcpy.S b/arch/mips64/lib/memcpy.S
index 8efad1581..9f44b4b8b 100644
--- a/arch/mips64/lib/memcpy.S
+++ b/arch/mips64/lib/memcpy.S
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: memcpy.S,v 1.2 1999/10/19 20:51:51 ralf Exp $
*
* 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
@@ -93,7 +93,7 @@
.set noat
.align 5
-LEAF(memcpy) /* a0=dst a1=src a2=len */
+LEAF(xxmemcpy) /* a0=dst a1=src a2=len */
move v0, a0 /* return value */
__memcpy:
EXPORT(__copy_user)
@@ -365,7 +365,7 @@ u_end_bytes:
jr ra
move a2, zero
- END(memcpy)
+ END(xxmemcpy)
/* descending order, destination aligned */
#define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
@@ -406,14 +406,14 @@ u_end_bytes:
usw t3, (offset + 0x0c)(dst)
.align 5
-LEAF(memmove)
+LEAF(xxmemmove)
sltu ta0, a0, a1 # dst < src -> memcpy
- bnez ta0, memcpy
+ bnez ta0, xxmemcpy
daddu v0, a0, a2
sltu ta0, v0, a1 # dst + len < src -> non-
bnez ta0, __memcpy # overlapping, can use memcpy
move v0, a0 /* return value */
- END(memmove)
+ END(xxmemmove)
LEAF(__rmemcpy) /* a0=dst a1=src a2=len */
daddu a0, a2 # dst = dst + len
diff --git a/arch/mips64/lib/memset.S b/arch/mips64/lib/memset.S
index 25afb2c89..56dc72160 100644
--- a/arch/mips64/lib/memset.S
+++ b/arch/mips64/lib/memset.S
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: memset.S,v 1.2 1999/10/19 20:51:51 ralf Exp $
*
* 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
@@ -36,7 +36,7 @@
*/
.set noreorder
.align 5
-LEAF(memset)
+LEAF(xxmemset)
beqz a1, 1f
move v0, a0 /* result */
@@ -109,7 +109,7 @@ small_memset:
2: jr ra /* done */
move a2, zero
- END(memset)
+ END(xxmemset)
first_fixup:
jr ra
diff --git a/arch/mips64/lib/rtc-no.c b/arch/mips64/lib/rtc-no.c
index c471da824..808033648 100644
--- a/arch/mips64/lib/rtc-no.c
+++ b/arch/mips64/lib/rtc-no.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: rtc-no.c,v 1.1 1999/08/21 21:43:01 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/rtc-std.c b/arch/mips64/lib/rtc-std.c
index 7369db07d..a4a6ead81 100644
--- a/arch/mips64/lib/rtc-std.c
+++ b/arch/mips64/lib/rtc-std.c
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: rtc-std.c,v 1.1 1999/08/21 21:43:01 ralf Exp $
*
* 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
diff --git a/arch/mips64/lib/strlen_user.S b/arch/mips64/lib/strlen_user.S
index da37c0c2a..bb4347c02 100644
--- a/arch/mips64/lib/strlen_user.S
+++ b/arch/mips64/lib/strlen_user.S
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: strlen_user.S,v 1.2 1999/11/19 20:35:22 ralf Exp $
*
* 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
@@ -23,24 +23,23 @@
*
* Return 0 for error
*/
-LEAF(__strlen_user_nocheck_asm)
- LONG_L v0, THREAD_CURDS($28) # pointer ok?
- LONG_SUBU v0, zero, v0
- and v0, a0
- not v0
- beqz v0, fault
-EXPORT(__strlen_user_asm)
- move v0, a0
-1: EX(lb, t0, (v0), fault)
- LONG_ADDIU v0, 1
- bnez t0, 1b
- LONG_SUBU v0, a0
- jr ra
- END(__strlen_user_nocheck_asm)
+LEAF(__strlen_user_asm)
+ ld v0, THREAD_CURDS($28) # pointer ok?
+ and v0, a0
+ bltz v0, fault
+
+EXPORT(__strlen_user_nocheck_asm)
+ move v0, a0
+1: EX(lb, ta0, (v0), fault)
+ daddiu v0, 1
+ bnez ta0, 1b
+ dsubu v0, a0
+ jr ra
+ END(__strlen_user_asm)
.section __ex_table,"a"
PTR 1b, fault
.previous
-fault: move v0, zero
- jr ra
+fault: move v0, zero
+ jr ra
diff --git a/arch/mips64/lib/strncpy_user.S b/arch/mips64/lib/strncpy_user.S
index aad14c263..d30046cae 100644
--- a/arch/mips64/lib/strncpy_user.S
+++ b/arch/mips64/lib/strncpy_user.S
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: strncpy_user.S,v 1.2 1999/11/19 20:35:23 ralf Exp $
*
* 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
@@ -29,32 +29,31 @@
*/
LEAF(__strncpy_from_user_asm)
- LONG_L v0, THREAD_CURDS($28) # pointer ok?
- LONG_SUBU v0, zero, v0
- and v0, a1
- not v0
- beqz v0, fault
+ ld v0, THREAD_CURDS($28) # pointer ok?
+ and v0, a1
+ bltz v0, fault
+
EXPORT(__strncpy_from_user_nocheck_asm)
- move v0,zero
- move v1,a1
- .set noreorder
-1: EX(lbu, t0, (v1), fault)
- LONG_ADDIU v1,1
- beqz t0,2f
- sb t0,(a0)
- LONG_ADDIU v0,1
- bne v0,a2,1b
- LONG_ADDIU a0,1
- .set reorder
-2: LONG_ADDU t0,a1,v0
- xor t0,a1
- bltz t0,fault
- jr ra # return n
+ move v0, zero
+ move v1, a1
+ .set noreorder
+1: EX(lbu, ta0, (v1), fault)
+ daddiu v1, 1
+ beqz ta0, 2f
+ sb ta0, (a0)
+ daddiu v0, 1
+ bne v0, a2, 1b
+ daddiu a0, 1
+ .set reorder
+2: daddu ta0, a1, v0
+ xor ta0, a1
+ bltz ta0, fault
+ jr ra # return n
END(__strncpy_from_user_asm)
-fault: li v0, -EFAULT
- jr ra
+fault: li v0, -EFAULT
+ jr ra
.section __ex_table,"a"
- PTR 1b, fault
+ PTR 1b, fault
.previous
diff --git a/arch/mips64/lib/strnlen_user.S b/arch/mips64/lib/strnlen_user.S
new file mode 100644
index 000000000..9df7e5e87
--- /dev/null
+++ b/arch/mips64/lib/strnlen_user.S
@@ -0,0 +1,47 @@
+/* $Id: strnlen_user.S,v 1.1 1999/11/19 20:35:23 ralf Exp $
+ *
+ * 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, 1998, 1999 by Ralf Baechle
+ * Copyright (c) 1999 Silicon Graphics, Inc.
+ */
+#include <asm/asm.h>
+#include <asm/offset.h>
+#include <asm/regdef.h>
+#include <asm/sgidefs.h>
+
+#define EX(insn,reg,addr,handler) \
+9: insn reg, addr; \
+ .section __ex_table,"a"; \
+ PTR 9b, handler; \
+ .previous
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error, len on string but at max a1 otherwise
+ */
+LEAF(__strnlen_user_asm)
+ ld v0, THREAD_CURDS($28) # pointer ok?
+ and v0, ta0
+ bltz v0, fault
+
+EXPORT(__strnlen_user_nocheck_asm)
+ move v0, a0
+ daddu a1, a0 # stop pointer
+1: beq v0, a1, 1f # limit reached?
+ EX(lb, ta0, (v0), fault)
+ daddiu v0, 1
+ bnez ta0, 1b
+1: dsubu v0, a0
+ jr ra
+ END(__strnlen_user_asm)
+
+ .section __ex_table,"a"
+ PTR 1b, fault
+ .previous
+
+fault: move v0, zero
+ jr ra
diff --git a/arch/mips64/lib/watch.S b/arch/mips64/lib/watch.S
index ee9559522..3f3d18c6e 100644
--- a/arch/mips64/lib/watch.S
+++ b/arch/mips64/lib/watch.S
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: watch.S,v 1.1 1999/08/21 21:43:01 ralf Exp $
*
* 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