diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 12:04:58 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 12:04:58 +0100 |
commit | 008d0be72b2f160382c6e880765e96b64a050c65 (patch) | |
tree | 36f48a98a3815a408e2ce1693dd182af90f80305 /release/src/linux/linux/arch/mips/lib | |
parent | 611becfb8726c60cb060368541ad98191d4532f5 (diff) | |
download | tomato-008d0be72b2f160382c6e880765e96b64a050c65.tar.gz tomato-008d0be72b2f160382c6e880765e96b64a050c65.tar.bz2 |
imported original firmware WRT54GL_v4.30.11_11_US
Diffstat (limited to 'release/src/linux/linux/arch/mips/lib')
22 files changed, 2415 insertions, 0 deletions
diff --git a/release/src/linux/linux/arch/mips/lib/Makefile b/release/src/linux/linux/arch/mips/lib/Makefile new file mode 100644 index 00000000..64ba1f56 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for MIPS-specific library files.. +# + +USE_STANDARD_AS_RULE := true + +L_TARGET = lib.a + +obj-y += csum_partial.o csum_partial_copy.o \ + promlib.o rtc-std.o rtc-no.o memcpy.o \ + memset.o watch.o strlen_user.o \ + strncpy_user.o strnlen_user.o + +ifeq ($(CONFIG_CPU_R3000)$(CONFIG_CPU_TX39XX),y) + obj-y += r3k_dump_tlb.o +else + obj-y += dump_tlb.o +endif + +obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o +obj-$(subst m,y,$(CONFIG_IDE)) += ide-std.o ide-no.o # needed for ide module +obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o + +obj-$(CONFIG_MCOUNT) += mcount.o + +include $(TOPDIR)/Rules.make diff --git a/release/src/linux/linux/arch/mips/lib/csum_partial.S b/release/src/linux/linux/arch/mips/lib/csum_partial.S new file mode 100644 index 00000000..ef83e776 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/csum_partial.S @@ -0,0 +1,240 @@ +/* + * 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) 1998 Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/regdef.h> + +#define ADDC(sum,reg) \ + addu sum, reg; \ + sltu v1, sum, reg; \ + addu sum, v1 + +#define CSUM_BIGCHUNK(src, offset, sum, t0, t1, t2, t3) \ + lw t0, (offset + 0x00)(src); \ + lw t1, (offset + 0x04)(src); \ + lw t2, (offset + 0x08)(src); \ + lw t3, (offset + 0x0c)(src); \ + ADDC(sum, t0); \ + ADDC(sum, t1); \ + ADDC(sum, t2); \ + ADDC(sum, t3); \ + lw t0, (offset + 0x10)(src); \ + lw t1, (offset + 0x14)(src); \ + lw t2, (offset + 0x18)(src); \ + lw t3, (offset + 0x1c)(src); \ + ADDC(sum, t0); \ + ADDC(sum, t1); \ + ADDC(sum, t2); \ + ADDC(sum, t3); \ + +/* + * a0: source address + * a1: length of the area to checksum + * a2: partial checksum + */ + +#define src a0 +#define dest a1 +#define sum v0 + + .text + .set noreorder + +/* unknown src alignment and < 8 bytes to go */ +small_csumcpy: + move a1, t2 + + andi t0, a1, 4 + beqz t0, 1f + andi t0, a1, 2 + + /* Still a full word to go */ + ulw t1, (src) + addiu src, 4 + ADDC(sum, t1) + +1: move t1, zero + beqz t0, 1f + andi t0, a1, 1 + + /* Still a halfword to go */ + ulhu t1, (src) + addiu src, 2 + +1: beqz t0, 1f + sll t1, t1, 16 + + lbu t2, (src) + nop + +#ifdef __MIPSEB__ + sll t2, t2, 8 +#endif + or t1, t2 + +1: ADDC(sum, t1) + + /* fold checksum */ + sll v1, sum, 16 + addu sum, v1 + sltu v1, sum, v1 + srl sum, sum, 16 + addu sum, v1 + + /* odd buffer alignment? */ + beqz t7, 1f + nop + sll v1, sum, 8 + srl sum, sum, 8 + or sum, v1 + andi sum, 0xffff +1: + .set reorder + /* Add the passed partial csum. */ + ADDC(sum, a2) + jr ra + .set noreorder + +/* ------------------------------------------------------------------------- */ + + .align 5 +LEAF(csum_partial) + move sum, zero + move t7, zero + + sltiu t8, a1, 0x8 + bnez t8, small_csumcpy /* < 8 bytes to copy */ + move t2, a1 + + beqz a1, out + andi t7, src, 0x1 /* odd buffer? */ + +hword_align: + beqz t7, word_align + andi t8, src, 0x2 + + lbu t0, (src) + subu a1, a1, 0x1 +#ifdef __MIPSEL__ + sll t0, t0, 8 +#endif + ADDC(sum, t0) + addu src, src, 0x1 + andi t8, src, 0x2 + +word_align: + beqz t8, dword_align + sltiu t8, a1, 56 + + lhu t0, (src) + subu a1, a1, 0x2 + ADDC(sum, t0) + sltiu t8, a1, 56 + addu src, src, 0x2 + +dword_align: + bnez t8, do_end_words + move t8, a1 + + andi t8, src, 0x4 + beqz t8, qword_align + andi t8, src, 0x8 + + lw t0, 0x00(src) + subu a1, a1, 0x4 + ADDC(sum, t0) + addu src, src, 0x4 + andi t8, src, 0x8 + +qword_align: + beqz t8, oword_align + andi t8, src, 0x10 + + lw t0, 0x00(src) + lw t1, 0x04(src) + subu a1, a1, 0x8 + ADDC(sum, t0) + ADDC(sum, t1) + addu src, src, 0x8 + andi t8, src, 0x10 + +oword_align: + beqz t8, begin_movement + srl t8, a1, 0x7 + + lw t3, 0x08(src) + lw t4, 0x0c(src) + lw t0, 0x00(src) + lw t1, 0x04(src) + ADDC(sum, t3) + ADDC(sum, t4) + ADDC(sum, t0) + ADDC(sum, t1) + subu a1, a1, 0x10 + addu src, src, 0x10 + srl t8, a1, 0x7 + +begin_movement: + beqz t8, 1f + andi t2, a1, 0x40 + +move_128bytes: + CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4) + CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4) + CSUM_BIGCHUNK(src, 0x40, sum, t0, t1, t3, t4) + CSUM_BIGCHUNK(src, 0x60, sum, t0, t1, t3, t4) + subu t8, t8, 0x01 + bnez t8, move_128bytes + addu src, src, 0x80 + +1: + beqz t2, 1f + andi t2, a1, 0x20 + +move_64bytes: + CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4) + CSUM_BIGCHUNK(src, 0x20, sum, t0, t1, t3, t4) + addu src, src, 0x40 + +1: + beqz t2, do_end_words + andi t8, a1, 0x1c + +move_32bytes: + CSUM_BIGCHUNK(src, 0x00, sum, t0, t1, t3, t4) + andi t8, a1, 0x1c + addu src, src, 0x20 + +do_end_words: + beqz t8, maybe_end_cruft + srl t8, t8, 0x2 + +end_words: + lw t0, (src) + subu t8, t8, 0x1 + ADDC(sum, t0) + bnez t8, end_words + addu src, src, 0x4 + +maybe_end_cruft: + andi t2, a1, 0x3 + +small_memcpy: + j small_csumcpy; move a1, t2 + beqz t2, out + move a1, t2 + +end_bytes: + lb t0, (src) + subu a1, a1, 0x1 + bnez a2, end_bytes + addu src, src, 0x1 + +out: + jr ra + move v0, sum + END(csum_partial) diff --git a/release/src/linux/linux/arch/mips/lib/csum_partial_copy.c b/release/src/linux/linux/arch/mips/lib/csum_partial_copy.c new file mode 100644 index 00000000..7348cf23 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/csum_partial_copy.c @@ -0,0 +1,56 @@ +/* + * 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 <linux/types.h> +#include <asm/byteorder.h> +#include <asm/string.h> +#include <asm/uaccess.h> + +/* + * 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 real ... + * This is lots slower than the real thing (tm) + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len, sum); +} diff --git a/release/src/linux/linux/arch/mips/lib/dump_tlb.c b/release/src/linux/linux/arch/mips/lib/dump_tlb.c new file mode 100644 index 00000000..a3c4cc13 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/dump_tlb.c @@ -0,0 +1,231 @@ +/* + * Dump R4x00 TLB for debugging purposes. + * + * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. + * Copyright (C) 1999 by Silicon Graphics, Inc. + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/cachectl.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +static inline const char *msg2str(unsigned int mask) +{ + switch (mask) { + case PM_4K: return "4kb"; + case PM_16K: return "16kb"; + case PM_64K: return "64kb"; + case PM_256K: return "256kb"; +#ifndef CONFIG_CPU_VR41XX + case PM_1M: return "1Mb"; + case PM_4M: return "4Mb"; + case PM_16M: return "16Mb"; + case PM_64M: return "64Mb"; + case PM_256M: return "256Mb"; +#endif + } +} + +void dump_tlb(int first, int last) +{ + int i; + unsigned int pagemask, c0, c1, asid; + unsigned long long entrylo0, entrylo1; + unsigned long entryhi; + + asid = read_c0_entryhi() & 0xff; + + printk("\n"); + for(i=first;i<=last;i++) { + write_c0_index(i); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoreorder\n\t" + "nop;nop;nop;nop\n\t" + "tlbr\n\t" + "nop;nop;nop;nop\n\t" + ".set\treorder\n\t" + ".set\tmips0\n\t"); + pagemask = read_c0_pagemask(); + entryhi = read_c0_entryhi(); + entrylo0 = read_c0_entrylo0(); + entrylo1 = read_c0_entrylo1(); + + /* Unused entries have a virtual address in KSEG0. */ + if ((entryhi & 0xf0000000) != 0x80000000 + && (entryhi & 0xff) == asid) { + /* + * Only print entries in use + */ + printk("Index: %2d pgmask=%s ", i, msg2str(pagemask)); + + c0 = (entrylo0 >> 3) & 7; + c1 = (entrylo1 >> 3) & 7; + + printk("va=%08lx asid=%02lx\n", + (entryhi & 0xffffe000), (entryhi & 0xff)); + printk("\t\t\t[pa=%08Lx c=%d d=%d v=%d g=%Ld]\n", + (entrylo0 << 6) & PAGE_MASK, c0, + (entrylo0 & 4) ? 1 : 0, + (entrylo0 & 2) ? 1 : 0, + (entrylo0 & 1)); + printk("\t\t\t[pa=%08Lx c=%d d=%d v=%d g=%Ld]\n", + (entrylo1 << 6) & PAGE_MASK, c1, + (entrylo1 & 4) ? 1 : 0, + (entrylo1 & 2) ? 1 : 0, + (entrylo1 & 1)); + printk("\n"); + } + } + + write_c0_entryhi(asid); +} + +void dump_tlb_all(void) +{ + dump_tlb(0, mips_cpu.tlbsize - 1); +} + +void dump_tlb_wired(void) +{ + int wired; + + wired = read_c0_wired(); + printk("Wired: %d", wired); + dump_tlb(0, read_c0_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 = read_c0_entryhi() & 0xff; + BARRIER; + write_c0_entryhi((addr & PAGE_MASK) | oldpid); + BARRIER; + tlb_probe(); + BARRIER; + index = read_c0_index(); + write_c0_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) +{ + dump_tlb(read_c0_wired(), mips_cpu.tlbsize - 1); +} + +void +dump_list_process(struct task_struct *t, void *address) +{ + pgd_t *page_dir, *pgd; + pmd_t *pmd; + pte_t *pte, page; + unsigned int addr; + unsigned long val; + + addr = (unsigned int) address; + + printk("Addr == %08x\n", addr); + printk("task == %08p\n", t); + printk("task->mm == %08p\n", t->mm); + //printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd); + + if (addr > KSEG0) + page_dir = pgd_offset_k(0); + else + page_dir = pgd_offset(t->mm, 0); + printk("page_dir == %08x\n", (unsigned int) page_dir); + + if (addr > KSEG0) + pgd = pgd_offset_k(addr); + else + pgd = pgd_offset(t->mm, addr); + printk("pgd == %08x, ", (unsigned int) pgd); + + pmd = pmd_offset(pgd, addr); + printk("pmd == %08x, ", (unsigned int) pmd); + + pte = pte_offset(pmd, addr); + printk("pte == %08x, ", (unsigned int) pte); + + page = *pte; +#ifdef CONFIG_64BIT_PHYS_ADDR + printk("page == %08Lx\n", pte_val(page)); +#else + printk("page == %08lx\n", pte_val(page)); +#endif + + 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 +dump_list_current(void *address) +{ + dump_list_process(current, address); +} + +unsigned int +vtop(void *address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned int addr, paddr; + + 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; + paddr |= (addr & ~PAGE_MASK); + + return paddr; +} + +void +dump16(unsigned long *p) +{ + int i; + + for(i=0;i<8;i++) + { + printk("*%8p = %08lx, ", p, *p); p++; + printk("*%8p = %08lx\n", p, *p); p++; + } +} diff --git a/release/src/linux/linux/arch/mips/lib/floppy-no.c b/release/src/linux/linux/arch/mips/lib/floppy-no.c new file mode 100644 index 00000000..b87110e8 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/floppy-no.c @@ -0,0 +1,57 @@ +/* + * 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. + * + * Dummy file for machines without standard floppy drives. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <asm/floppy.h> + +/* + * How to access the FDC's registers. + */ +static void no_fd_dummy(void) +{ + panic("no_fd_dummy called - shouldn't happen"); +} + +static unsigned long no_fd_getfdaddr1(void) +{ + return (unsigned long)-1; /* No FDC nowhere ... */ +} + +static unsigned long no_fd_drive_type(unsigned long n) +{ + return 0; +} + +struct fd_ops no_fd_ops = { + /* + * How to access the floppy controller's ports + */ + (void *) no_fd_dummy, + (void *) no_fd_dummy, + /* + * How to access the floppy DMA functions. + */ + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + no_fd_getfdaddr1, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + no_fd_drive_type +}; diff --git a/release/src/linux/linux/arch/mips/lib/floppy-std.c b/release/src/linux/linux/arch/mips/lib/floppy-std.c new file mode 100644 index 00000000..8560138c --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/floppy-std.c @@ -0,0 +1,150 @@ +/* + * 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. + * + * Access the floppy hardware on PC style hardware + * + * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + */ +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <asm/bootinfo.h> +#include <asm/cachectl.h> +#include <asm/dma.h> +#include <asm/floppy.h> +#include <asm/keyboard.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mc146818rtc.h> +#include <asm/pgtable.h> + +/* + * How to access the FDC's registers. + */ +static unsigned char std_fd_inb(unsigned int port) +{ + return inb_p(port); +} + +static void std_fd_outb(unsigned char value, unsigned int port) +{ + outb_p(value, port); +} + +/* + * How to access the floppy DMA functions. + */ +static void std_fd_enable_dma(int channel) +{ + enable_dma(channel); +} + +static void std_fd_disable_dma(int channel) +{ + disable_dma(channel); +} + +static int std_fd_request_dma(int channel) +{ + return request_dma(channel, "floppy"); +} + +static void std_fd_free_dma(int channel) +{ + free_dma(channel); +} + +static void std_fd_clear_dma_ff(int channel) +{ + clear_dma_ff(channel); +} + +static void std_fd_set_dma_mode(int channel, char mode) +{ + set_dma_mode(channel, mode); +} + +static void std_fd_set_dma_addr(int channel, unsigned int addr) +{ + set_dma_addr(channel, addr); +} + +static void std_fd_set_dma_count(int channel, unsigned int count) +{ + set_dma_count(channel, count); +} + +static int std_fd_get_dma_residue(int channel) +{ + return get_dma_residue(channel); +} + +static void std_fd_enable_irq(int irq) +{ + enable_irq(irq); +} + +static void std_fd_disable_irq(int irq) +{ + disable_irq(irq); +} + +static unsigned long std_fd_getfdaddr1(void) +{ + return 0x3f0; +} + +static unsigned long std_fd_dma_mem_alloc(unsigned long size) +{ + unsigned long mem; + + mem = __get_dma_pages(GFP_KERNEL,get_order(size)); + + return mem; +} + +static void std_fd_dma_mem_free(unsigned long addr, unsigned long size) +{ + free_pages(addr, get_order(size)); +} + +static unsigned long std_fd_drive_type(unsigned long n) +{ + if (n == 0) + return 4; /* 3,5", 1.44mb */ + + return 0; +} + +struct fd_ops std_fd_ops = { + /* + * How to access the floppy controller's ports + */ + std_fd_inb, + std_fd_outb, + /* + * How to access the floppy DMA functions. + */ + std_fd_enable_dma, + std_fd_disable_dma, + std_fd_request_dma, + std_fd_free_dma, + std_fd_clear_dma_ff, + std_fd_set_dma_mode, + std_fd_set_dma_addr, + std_fd_set_dma_count, + std_fd_get_dma_residue, + std_fd_enable_irq, + std_fd_disable_irq, + std_fd_getfdaddr1, + std_fd_dma_mem_alloc, + std_fd_dma_mem_free, + std_fd_drive_type +}; diff --git a/release/src/linux/linux/arch/mips/lib/ide-no.c b/release/src/linux/linux/arch/mips/lib/ide-no.c new file mode 100644 index 00000000..0d78feb2 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/ide-no.c @@ -0,0 +1,70 @@ +/* + * 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. + * + * Stub IDE routines to keep Linux from crashing on machine which don't + * have IDE like the Indy. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + */ +#include <linux/hdreg.h> +#include <linux/kernel.h> +#include <linux/ide.h> +#include <asm/hdreg.h> +#include <asm/ptrace.h> + +static int no_ide_default_irq(ide_ioreg_t base) +{ + return 0; +} + +static ide_ioreg_t no_ide_default_io_base(int index) +{ + return 0; +} + +static void no_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ +} + +static int no_ide_request_irq(unsigned int irq, + void (*handler)(int,void *, struct pt_regs *), + unsigned long flags, const char *device, + void *dev_id) +{ + panic("no_no_ide_request_irq called - shouldn't happen"); +} + +static void no_ide_free_irq(unsigned int irq, void *dev_id) +{ + panic("no_ide_free_irq called - shouldn't happen"); +} + +static int no_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + panic("no_ide_check_region called - shouldn't happen"); +} + +static void no_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ + panic("no_ide_request_region called - shouldn't happen"); +} + +static void no_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + panic("no_ide_release_region called - shouldn't happen"); +} + +struct ide_ops no_ide_ops = { + &no_ide_default_irq, + &no_ide_default_io_base, + &no_ide_init_hwif_ports, + &no_ide_request_irq, + &no_ide_free_irq, + &no_ide_check_region, + &no_ide_request_region, + &no_ide_release_region +}; diff --git a/release/src/linux/linux/arch/mips/lib/ide-std.c b/release/src/linux/linux/arch/mips/lib/ide-std.c new file mode 100644 index 00000000..dd96e3e5 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/ide-std.c @@ -0,0 +1,137 @@ +/* + * 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. + * + * IDE routines for typical pc-like standard configurations. + * + * Copyright (C) 1998, 1999, 2001 by Ralf Baechle + */ +#include <linux/sched.h> +#include <linux/ide.h> +#include <linux/ioport.h> +#include <linux/hdreg.h> +#include <asm/ptrace.h> +#include <asm/hdreg.h> +#include <asm/io.h> +#include <asm/paccess.h> + +static int std_ide_default_irq(ide_ioreg_t base) +{ + switch (base) { + case 0x1f0: return 14; + case 0x170: return 15; + case 0x1e8: return 11; + case 0x168: return 10; + case 0x1e0: return 8; + case 0x160: return 12; + default: + return 0; + } +} + +static ide_ioreg_t std_ide_default_io_base(int index) +{ + switch (index) { + case 0: return 0x1f0; + case 1: return 0x170; + case 2: return 0x1e8; + case 3: return 0x168; + case 4: return 0x1e0; + case 5: return 0x160; + default: + return 0; + } +} + +static void std_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ + ide_ioreg_t reg = data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; + } + if (irq != NULL) + *irq = 0; + hw->io_ports[IDE_IRQ_OFFSET] = 0; +} + +static int std_ide_request_irq(unsigned int irq, + void (*handler)(int,void *, struct pt_regs *), + unsigned long flags, const char *device, + void *dev_id) +{ + return request_irq(irq, handler, flags, device, dev_id); +} + +static void std_ide_free_irq(unsigned int irq, void *dev_id) +{ + free_irq(irq, dev_id); +} + +static int std_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + int ret; + + if ((ret = check_region(from, extent))) + return ret; + + /* Standard IDE ports may not be accessible */ + switch (extent) { + case 1: { + u8 val; + ret = get_dbe(val, (u8 *)(mips_io_port_base + (unsigned long) from)); + break; + } + case 2: { + u16 val; + ret = get_dbe(val, (u16 *)(mips_io_port_base + (unsigned long) from)); + break; + } + case 4: { + u32 val; + ret = get_dbe(val, (u32 *)(mips_io_port_base + (unsigned long) from)); + break; + } + case 8: { + u64 val; + ret = get_dbe(val, (u64 *)(mips_io_port_base + (unsigned long) from)); + break; + } + default: + ret = -EFAULT; + break; + } + + return ret; +} + +static void std_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ + request_region(from, extent, name); +} + +static void std_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + release_region(from, extent); +} + +struct ide_ops std_ide_ops = { + &std_ide_default_irq, + &std_ide_default_io_base, + &std_ide_init_hwif_ports, + &std_ide_request_irq, + &std_ide_free_irq, + &std_ide_check_region, + &std_ide_request_region, + &std_ide_release_region +}; diff --git a/release/src/linux/linux/arch/mips/lib/kbd-no.c b/release/src/linux/linux/arch/mips/lib/kbd-no.c new file mode 100644 index 00000000..dcf3d0c4 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/kbd-no.c @@ -0,0 +1,62 @@ +/* + * 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. + * + * Stub keyboard and psaux routines to keep Linux from crashing on machines + * without a keyboard. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include <linux/sched.h> +#include <asm/keyboard.h> + +static void no_kbd_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int no_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static int no_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static void no_aux_free_irq(void) +{ +} + +static unsigned char no_kbd_read_input(void) +{ + return 0; +} + +static void no_kbd_write_output(unsigned char val) +{ +} + +static void no_kbd_write_command(unsigned char val) +{ +} + +static unsigned char no_kbd_read_status(void) +{ + return 0; +} + +struct kbd_ops no_kbd_ops = { + no_kbd_request_region, + no_kbd_request_irq, + + no_aux_request_irq, + no_aux_free_irq, + + no_kbd_read_input, + no_kbd_write_output, + no_kbd_write_command, + no_kbd_read_status +}; diff --git a/release/src/linux/linux/arch/mips/lib/kbd-std.c b/release/src/linux/linux/arch/mips/lib/kbd-std.c new file mode 100644 index 00000000..e1cba545 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/kbd-std.c @@ -0,0 +1,85 @@ +/* + * 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. + * + * Routines for standard PC style keyboards accessible via I/O ports. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + */ +#include <linux/config.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/pc_keyb.h> +#include <asm/keyboard.h> +#include <asm/io.h> + +#define KEYBOARD_IRQ 1 +#define AUX_IRQ 12 + +static void std_kbd_request_region(void) +{ +#ifdef CONFIG_MIPS_ITE8172 + request_region(0x14000060, 16, "keyboard"); +#else + request_region(0x60, 16, "keyboard"); +#endif +} + +static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); +} + +static int std_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(AUX_IRQ, handler, 0, "PS/2 Mouse", NULL); +} + +static void std_aux_free_irq(void) +{ + free_irq(AUX_IRQ, NULL); +} + +static unsigned char std_kbd_read_input(void) +{ + return inb(KBD_DATA_REG); +} + +static void std_kbd_write_output(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_DATA_REG); +} + +static void std_kbd_write_command(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_CNTL_REG); +} + +static unsigned char std_kbd_read_status(void) +{ + return inb(KBD_STATUS_REG); +} + +struct kbd_ops std_kbd_ops = { + std_kbd_request_region, + std_kbd_request_irq, + + std_aux_request_irq, + std_aux_free_irq, + + std_kbd_read_input, + std_kbd_write_output, + std_kbd_write_command, + std_kbd_read_status +}; diff --git a/release/src/linux/linux/arch/mips/lib/mcount.S b/release/src/linux/linux/arch/mips/lib/mcount.S new file mode 100644 index 00000000..5dcddfff --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/mcount.S @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2000 Silicon Graphics, Inc. + * + * Written by Ulf Carlsson (ulfc@engr.sgi.com) + * + * This file implements mcount(), which is used to collect profiling data. + * We provide several variants to accomodate different types of callers at + * the lowest possible overhead. + */ + +#include <asm/regdef.h> +#include <asm/asm.h> +#include <linux/config.h> + +.macro MCOUNT + .set push + .set noat + .set noreorder +#if defined(CONFIG_KERNPROF) || defined(CONFIG_KERNPROF_MODULE) + lw t9, (mcount_hook) + beqz t9, 1f + nop + subu sp, 16 + sw a0, 0(sp) + sw a1, 4(sp) + sw a2, 8(sp) + sw a3, 12(sp) + sw ra, 16(sp) + sw AT, 20(sp) + move a1, ra # mcount's parent (another gas bug -> ') + jalr t9 + move a0, AT # mcount's parent's parent + lw ra, 20(sp) + lw AT, 16(sp) + lw a3, 12(sp) + lw a2, 8(sp) + lw a1, 4(sp) + lw a0, 0(sp) + jr AT + addu sp, 24 +#endif +1: move t0, AT + move AT, ra + move ra, t0 + jr AT + addu sp, 8 # sp is adjusted by -8 when we are called + .set pop +.endm + + +/* + * This is the main variant and is called by C code. GCC's -pg option + * automatically instruments every C function with a call to this. + */ +FEXPORT(_mcount) + MCOUNT diff --git a/release/src/linux/linux/arch/mips/lib/memcpy.S b/release/src/linux/linux/arch/mips/lib/memcpy.S new file mode 100644 index 00000000..de093a94 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/memcpy.S @@ -0,0 +1,503 @@ +/* + * 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. + * + * Unified implementation of memcpy, memmove and the __copy_user backend. + * + * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc. + * Copyright (C) 2002 Broadcom, Inc. + * memcpy/copy_user author: Mark Vandevoorde + * + * Mnemonic names for arguments to memcpy/__copy_user + */ +#include <linux/config.h> +#include <asm/asm.h> +#include <asm/offset.h> +#include <asm/regdef.h> + +#define dst a0 +#define src a1 +#define len a2 + +/* + * Spec + * + * memcpy copies len bytes from src to dst and sets v0 to dst. + * It assumes that + * - src and dst don't overlap + * - src is readable + * - dst is writable + * memcpy uses the standard calling convention + * + * __copy_user copies up to len bytes from src to dst and sets a2 (len) to + * the number of uncopied bytes due to an exception caused by a read or write. + * __copy_user assumes that src and dst don't overlap, and that the call is + * implementing one of the following: + * copy_to_user + * - src is readable (no exceptions when reading src) + * copy_from_user + * - dst is writable (no exceptions when writing dst) + * __copy_user uses a non-standard calling convention; see + * include/asm-mips/uaccess.h + * + * When an exception happens on a load, the handler must + # ensure that all of the destination buffer is overwritten to prevent + * leaking information to user mode programs. + */ + +/* + * Implementation + */ + +/* + * The exception handler for loads requires that: + * 1- AT contain the address of the byte just past the end of the source + * of the copy, + * 2- src_entry <= src < AT, and + * 3- (dst - src) == (dst_entry - src_entry), + * The _entry suffix denotes values when __copy_user was called. + * + * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user + * (2) is met by incrementing src by the number of bytes copied + * (3) is met by not doing loads between a pair of increments of dst and src + * + * The exception handlers for stores adjust len (if necessary) and return. + * These handlers do not need to overwrite any data. + * + * For __rmemcpy and memmove an exception is always a kernel bug, therefore + * they're not protected. + */ + +#define EXC(inst_reg,addr,handler) \ +9: inst_reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +/* + * Only on the 64-bit kernel we can made use of 64-bit registers. + */ +#ifdef CONFIG_MIPS64 +#define USE_DOUBLE +#endif + +#ifdef USE_DOUBLE + +#define LOAD ld +#define LOADL ldl +#define LOADR ldr +#define STOREL sdl +#define STORER sdr +#define STORE sd +#define ADD daddu +#define SUB dsubu +#define SRL dsrl +#define SRA dsra +#define SLL dsll +#define SLLV dsllv +#define SRLV dsrlv +#define NBYTES 8 +#define LOG_NBYTES 3 + +/* + * As we are sharing code base with the mips32 tree (which use the o32 ABI + * register definitions). We need to redefine the register definitions from + * the n64 ABI register naming to the o32 ABI register naming. + */ +#undef t0 +#undef t1 +#undef t2 +#undef t3 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 + +#else + +#define LOAD lw +#define LOADL lwl +#define LOADR lwr +#define STOREL swl +#define STORER swr +#define STORE sw +#define ADD addu +#define SUB subu +#define SRL srl +#define SLL sll +#define SRA sra +#define SLLV sllv +#define SRLV srlv +#define NBYTES 4 +#define LOG_NBYTES 2 + +#endif /* USE_DOUBLE */ + +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define LDFIRST LOADR +#define LDREST LOADL +#define STFIRST STORER +#define STREST STOREL +#define SHIFT_DISCARD SLLV +#else +#define LDFIRST LOADL +#define LDREST LOADR +#define STFIRST STOREL +#define STREST STORER +#define SHIFT_DISCARD SRLV +#endif + +#define FIRST(unit) ((unit)*NBYTES) +#define REST(unit) (FIRST(unit)+NBYTES-1) +#define UNIT(unit) FIRST(unit) + +#define ADDRMASK (NBYTES-1) + + .text + .set noreorder + .set noat + +/* + * A combined memcpy/__copy_user + * __copy_user sets len to 0 for success; else to an upper bound of + * the number of uncopied bytes. + * memcpy sets v0 to dst. + */ + .align 5 +LEAF(memcpy) /* a0=dst a1=src a2=len */ + move v0, dst /* return value */ +__memcpy: +FEXPORT(__copy_user) + /* + * Note: dst & src may be unaligned, len may be 0 + * Temps + */ +#define rem t8 + + /* + * The "issue break"s below are very approximate. + * Issue delays for dcache fills will perturb the schedule, as will + * load queue full replay traps, etc. + * + * If len < NBYTES use byte operations. + */ + PREF( 0, 0(src) ) + PREF( 1, 0(dst) ) + sltu t2, len, NBYTES + and t1, dst, ADDRMASK + PREF( 0, 1*32(src) ) + PREF( 1, 1*32(dst) ) + bnez t2, copy_bytes_checklen + and t0, src, ADDRMASK + PREF( 0, 2*32(src) ) + PREF( 1, 2*32(dst) ) + bnez t1, dst_unaligned + nop + bnez t0, src_unaligned_dst_aligned + /* + * use delay slot for fall-through + * src and dst are aligned; need to compute rem + */ +both_aligned: + SRL t0, len, LOG_NBYTES+3 # +3 for 8 units/iter + beqz t0, cleanup_both_aligned # len < 8*NBYTES + and rem, len, (8*NBYTES-1) # rem = len % (8*NBYTES) + PREF( 0, 3*32(src) ) + PREF( 1, 3*32(dst) ) + .align 4 +1: +EXC( LOAD t0, UNIT(0)(src), l_exc) +EXC( LOAD t1, UNIT(1)(src), l_exc_copy) +EXC( LOAD t2, UNIT(2)(src), l_exc_copy) +EXC( LOAD t3, UNIT(3)(src), l_exc_copy) + SUB len, len, 8*NBYTES +EXC( LOAD t4, UNIT(4)(src), l_exc_copy) +EXC( LOAD t7, UNIT(5)(src), l_exc_copy) +EXC( STORE t0, UNIT(0)(dst), s_exc_p8u) +EXC( STORE t1, UNIT(1)(dst), s_exc_p7u) +EXC( LOAD t0, UNIT(6)(src), l_exc_copy) +EXC( LOAD t1, UNIT(7)(src), l_exc_copy) + ADD src, src, 8*NBYTES + ADD dst, dst, 8*NBYTES +EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u) +EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u) +EXC( STORE t4, UNIT(-4)(dst), s_exc_p4u) +EXC( STORE t7, UNIT(-3)(dst), s_exc_p3u) +EXC( STORE t0, UNIT(-2)(dst), s_exc_p2u) +EXC( STORE t1, UNIT(-1)(dst), s_exc_p1u) + PREF( 0, 8*32(src) ) + PREF( 1, 8*32(dst) ) + bne len, rem, 1b + nop + + /* + * len == rem == the number of bytes left to copy < 8*NBYTES + */ +cleanup_both_aligned: + beqz len, done + sltu t0, len, 4*NBYTES + bnez t0, less_than_4units + and rem, len, (NBYTES-1) # rem = len % NBYTES + /* + * len >= 4*NBYTES + */ +EXC( LOAD t0, UNIT(0)(src), l_exc) +EXC( LOAD t1, UNIT(1)(src), l_exc_copy) +EXC( LOAD t2, UNIT(2)(src), l_exc_copy) +EXC( LOAD t3, UNIT(3)(src), l_exc_copy) + SUB len, len, 4*NBYTES + ADD src, src, 4*NBYTES +EXC( STORE t0, UNIT(0)(dst), s_exc_p4u) +EXC( STORE t1, UNIT(1)(dst), s_exc_p3u) +EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) +EXC( STORE t3, UNIT(3)(dst), s_exc_p1u) + beqz len, done + ADD dst, dst, 4*NBYTES +less_than_4units: + /* + * rem = len % NBYTES + */ + beq rem, len, copy_bytes + nop +1: +EXC( LOAD t0, 0(src), l_exc) + ADD src, src, NBYTES + SUB len, len, NBYTES +EXC( STORE t0, 0(dst), s_exc_p1u) + bne rem, len, 1b + ADD dst, dst, NBYTES + + /* + * src and dst are aligned, need to copy rem bytes (rem < NBYTES) + * A loop would do only a byte at a time with possible branch + * mispredicts. Can't do an explicit LOAD dst,mask,or,STORE + * because can't assume read-access to dst. Instead, use + * STREST dst, which doesn't require read access to dst. + * + * This code should perform better than a simple loop on modern, + * wide-issue mips processors because the code has fewer branches and + * more instruction-level parallelism. + */ +#define bits t2 + beqz len, done + ADD t1, dst, len # t1 is just past last byte of dst + li bits, 8*NBYTES + SLL rem, len, 3 # rem = number of bits to keep +EXC( LOAD t0, 0(src), l_exc) + SUB bits, bits, rem # bits = number of bits to discard + SHIFT_DISCARD t0, t0, bits +EXC( STREST t0, -1(t1), s_exc) + jr ra + move len, zero +dst_unaligned: + /* + * dst is unaligned + * t0 = src & ADDRMASK + * t1 = dst & ADDRMASK; T1 > 0 + * len >= NBYTES + * + * Copy enough bytes to align dst + * Set match = (src and dst have same alignment) + */ +#define match rem +EXC( LDFIRST t3, FIRST(0)(src), l_exc) + ADD t2, zero, NBYTES +EXC( LDREST t3, REST(0)(src), l_exc_copy) + SUB t2, t2, t1 # t2 = number of bytes copied + xor match, t0, t1 +EXC( STFIRST t3, FIRST(0)(dst), s_exc) + beq len, t2, done + SUB len, len, t2 + ADD dst, dst, t2 + beqz match, both_aligned + ADD src, src, t2 + +src_unaligned_dst_aligned: + SRL t0, len, LOG_NBYTES+2 # +2 for 4 units/iter + PREF( 0, 3*32(src) ) + beqz t0, cleanup_src_unaligned + and rem, len, (4*NBYTES-1) # rem = len % 4*NBYTES + PREF( 1, 3*32(dst) ) +1: +/* + * Avoid consecutive LD*'s to the same register since some mips + * implementations can't issue them in the same cycle. + * It's OK to load FIRST(N+1) before REST(N) because the two addresses + * are to the same unit (unless src is aligned, but it's not). + */ +EXC( LDFIRST t0, FIRST(0)(src), l_exc) +EXC( LDFIRST t1, FIRST(1)(src), l_exc_copy) + SUB len, len, 4*NBYTES +EXC( LDREST t0, REST(0)(src), l_exc_copy) +EXC( LDREST t1, REST(1)(src), l_exc_copy) +EXC( LDFIRST t2, FIRST(2)(src), l_exc_copy) +EXC( LDFIRST t3, FIRST(3)(src), l_exc_copy) +EXC( LDREST t2, REST(2)(src), l_exc_copy) +EXC( LDREST t3, REST(3)(src), l_exc_copy) + PREF( 0, 9*32(src) ) # 0 is PREF_LOAD (not streamed) + ADD src, src, 4*NBYTES +#ifdef CONFIG_CPU_SB1 + nop # improves slotting +#endif +EXC( STORE t0, UNIT(0)(dst), s_exc_p4u) +EXC( STORE t1, UNIT(1)(dst), s_exc_p3u) +EXC( STORE t2, UNIT(2)(dst), s_exc_p2u) +EXC( STORE t3, UNIT(3)(dst), s_exc_p1u) + PREF( 1, 9*32(dst) ) # 1 is PREF_STORE (not streamed) + bne len, rem, 1b + ADD dst, dst, 4*NBYTES + +cleanup_src_unaligned: + beqz len, done + and rem, len, NBYTES-1 # rem = len % NBYTES + beq rem, len, copy_bytes +1: +EXC( LDFIRST t0, FIRST(0)(src), l_exc) +EXC( LDREST t0, REST(0)(src), l_exc_copy) + ADD src, src, NBYTES + SUB len, len, NBYTES +EXC( STORE t0, 0(dst), s_exc_p1u) + bne len, rem, 1b + ADD dst, dst, NBYTES + +copy_bytes_checklen: + beqz len, done + nop +copy_bytes: + /* 0 < len < NBYTES */ +#define COPY_BYTE(N) \ +EXC( lb t0, N(src), l_exc); \ + SUB len, len, 1; \ + beqz len, done; \ +EXC( sb t0, N(dst), s_exc_p1) + + COPY_BYTE(0) + COPY_BYTE(1) +#ifdef USE_DOUBLE + COPY_BYTE(2) + COPY_BYTE(3) + COPY_BYTE(4) + COPY_BYTE(5) +#endif +EXC( lb t0, NBYTES-2(src), l_exc) + SUB len, len, 1 + jr ra +EXC( sb t0, NBYTES-2(dst), s_exc_p1) +done: + jr ra + nop + END(memcpy) + +l_exc_copy: + /* + * Copy bytes from src until faulting load address (or until a + * lb faults) + * + * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28) + * may be more than a byte beyond the last address. + * Hence, the lb below may get an exception. + * + * Assumes src < THREAD_BUADDR($28) + */ + LOAD t0, THREAD_BUADDR($28) +1: +EXC( lb t1, 0(src), l_exc) + ADD src, src, 1 + sb t1, 0(dst) # can't fault -- we're copy_from_user + bne src, t0, 1b + ADD dst, dst, 1 +l_exc: + LOAD t0, THREAD_BUADDR($28) # t0 is just past last good address + nop + SUB len, AT, t0 # len number of uncopied bytes + /* + * Here's where we rely on src and dst being incremented in tandem, + * See (3) above. + * dst += (fault addr - src) to put dst at first byte to clear + */ + ADD dst, t0 # compute start address in a1 + SUB dst, src + /* + * Clear len bytes starting at dst. Can't call __bzero because it + * might modify len. An inefficient loop for these rare times... + */ + beqz len, done + SUB src, len, 1 +1: sb zero, 0(dst) + ADD dst, dst, 1 + bnez src, 1b + SUB src, src, 1 + jr ra + nop + + +#define SEXC(n) \ +s_exc_p ## n ## u: \ + jr ra; \ + ADD len, len, n*NBYTES + +SEXC(8) +SEXC(7) +SEXC(6) +SEXC(5) +SEXC(4) +SEXC(3) +SEXC(2) +SEXC(1) + +s_exc_p1: + jr ra + ADD len, len, 1 +s_exc: + jr ra + nop + + .align 5 +LEAF(memmove) + ADD t0, a0, a2 + ADD t1, a1, a2 + sltu t0, a1, t0 # dst + len <= src -> memcpy + sltu t1, a0, t1 # dst >= src + len -> memcpy + and t0, t1 + beqz t0, __memcpy + move v0, a0 /* return value */ + beqz a2, r_out + END(memmove) + + /* fall through to __rmemcpy */ +LEAF(__rmemcpy) /* a0=dst a1=src a2=len */ + sltu t0, a1, a0 + beqz t0, r_end_bytes_up # src >= dst + nop + ADD a0, a2 # dst = dst + len + ADD a1, a2 # src = src + len + +r_end_bytes: + lb t0, -1(a1) + SUB a2, a2, 0x1 + sb t0, -1(a0) + SUB a1, a1, 0x1 + bnez a2, r_end_bytes + SUB a0, a0, 0x1 + +r_out: + jr ra + move a2, zero + +r_end_bytes_up: + lb t0, (a1) + SUB a2, a2, 0x1 + sb t0, (a0) + ADD a1, a1, 0x1 + bnez a2, r_end_bytes_up + ADD a0, a0, 0x1 + + jr ra + move a2, zero + END(__rmemcpy) diff --git a/release/src/linux/linux/arch/mips/lib/memset.S b/release/src/linux/linux/arch/mips/lib/memset.S new file mode 100644 index 00000000..3371a153 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/memset.S @@ -0,0 +1,141 @@ +/* + * 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) 1998 by Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/offset.h> +#include <asm/regdef.h> + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +#define F_FILL64(dst, offset, val, fixup) \ + EX(sw, val, (offset + 0x00)(dst), fixup); \ + EX(sw, val, (offset + 0x04)(dst), fixup); \ + EX(sw, val, (offset + 0x08)(dst), fixup); \ + EX(sw, val, (offset + 0x0c)(dst), fixup); \ + EX(sw, val, (offset + 0x10)(dst), fixup); \ + EX(sw, val, (offset + 0x14)(dst), fixup); \ + EX(sw, val, (offset + 0x18)(dst), fixup); \ + EX(sw, val, (offset + 0x1c)(dst), fixup); \ + EX(sw, val, (offset + 0x20)(dst), fixup); \ + EX(sw, val, (offset + 0x24)(dst), fixup); \ + EX(sw, val, (offset + 0x28)(dst), fixup); \ + EX(sw, val, (offset + 0x2c)(dst), fixup); \ + EX(sw, val, (offset + 0x30)(dst), fixup); \ + EX(sw, val, (offset + 0x34)(dst), fixup); \ + EX(sw, val, (offset + 0x38)(dst), fixup); \ + EX(sw, val, (offset + 0x3c)(dst), fixup) + +/* + * memset(void *s, int c, size_t n) + * + * a0: start of area to clear + * a1: char to fill with + * a2: size of area to clear + */ + .set noreorder + .align 5 +LEAF(memset) + beqz a1, 1f + move v0, a0 /* result */ + + andi a1, 0xff /* spread fillword */ + sll t1, a1, 8 + or a1, t1 + sll t1, a1, 16 + or a1, t1 +1: + +EXPORT(__bzero) + sltiu t0, a2, 4 /* very small region? */ + bnez t0, small_memset + andi t0, a0, 3 /* aligned? */ + + beqz t0, 1f + subu t0, 4 /* alignment in bytes */ + +#ifdef __MIPSEB__ + EX(swl, a1, (a0), first_fixup) /* make word aligned */ +#endif +#ifdef __MIPSEL__ + EX(swr, a1, (a0), first_fixup) /* make word aligned */ +#endif + subu a0, t0 /* word align ptr */ + addu a2, t0 /* correct size */ + +1: ori t1, a2, 0x3f /* # of full blocks */ + xori t1, 0x3f + beqz t1, memset_partial /* no block to fill */ + andi t0, a2, 0x3c + + addu t1, a0 /* end address */ + .set reorder +1: addiu a0, 64 + F_FILL64(a0, -64, a1, fwd_fixup) + bne t1, a0, 1b + .set noreorder + +memset_partial: + PTR_LA t1, 2f /* where to start */ + subu t1, t0 + jr t1 + addu a0, t0 /* dest ptr */ + + .set push + .set noreorder + .set nomacro + F_FILL64(a0, -64, a1, partial_fixup) /* ... but first do wrds ... */ +2: .set pop + andi a2, 3 /* 0 <= n <= 3 to go */ + + beqz a2, 1f + addu a0, a2 /* What's left */ +#ifdef __MIPSEB__ + EX(swr, a1, -1(a0), last_fixup) +#endif +#ifdef __MIPSEL__ + EX(swl, a1, -1(a0), last_fixup) +#endif +1: jr ra + move a2, zero + +small_memset: + beqz a2, 2f + addu t1, a0, a2 + +1: addiu a0, 1 /* fill bytewise */ + bne t1, a0, 1b + sb a1, -1(a0) + +2: jr ra /* done */ + move a2, zero + END(memset) + +first_fixup: + jr ra + nop + +fwd_fixup: + lw t0, THREAD_BUADDR($28) + andi a2, 0x3f + addu a2, t1 + jr ra + subu a2, t0 + +partial_fixup: + lw t0, THREAD_BUADDR($28) + andi a2, 3 + addu a2, t1 + jr ra + subu a2, t0 + +last_fixup: + jr ra + andi v1, a2, 3 diff --git a/release/src/linux/linux/arch/mips/lib/promlib.c b/release/src/linux/linux/arch/mips/lib/promlib.c new file mode 100644 index 00000000..dddfe98b --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/promlib.c @@ -0,0 +1,24 @@ +#include <stdarg.h> +#include <linux/kernel.h> + +extern void prom_putchar(char); + +void prom_printf(char *fmt, ...) +{ + va_list args; + char ppbuf[1024]; + char *bptr; + + va_start(args, fmt); + vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while (*bptr != 0) { + if (*bptr == '\n') + prom_putchar('\r'); + + prom_putchar(*bptr++); + } + va_end(args); +} diff --git a/release/src/linux/linux/arch/mips/lib/r3k_dump_tlb.c b/release/src/linux/linux/arch/mips/lib/r3k_dump_tlb.c new file mode 100644 index 00000000..b6f08083 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/r3k_dump_tlb.c @@ -0,0 +1,187 @@ +/* + * Dump R3000 TLB for debugging purposes. + * + * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. + * Copyright (C) 1999 by Silicon Graphics, Inc. + * Copyright (C) 1999 by Harald Koerfgen + */ +#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/cpu.h> +#include <asm/mipsregs.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +extern int r3k_have_wired_reg; /* defined in tlb-r3k.c */ + +void +dump_tlb(int first, int last) +{ + int i; + unsigned int asid; + unsigned long entryhi, entrylo0; + + asid = read_c0_entryhi() & 0xfc0; + + for(i=first;i<=last;i++) + { + write_c0_index(i<<8); + __asm__ __volatile__( + ".set\tnoreorder\n\t" + "tlbr\n\t" + "nop\n\t" + ".set\treorder"); + entryhi = read_c0_entryhi(); + entrylo0 = read_c0_entrylo0(); + + /* Unused entries have a virtual address of KSEG0. */ + if ((entryhi & 0xffffe000) != 0x80000000 + && (entryhi & 0xfc0) == asid) { + /* + * Only print entries in use + */ + printk("Index: %2d ", i); + + printk("va=%08lx asid=%08lx" + " [pa=%06lx n=%d d=%d v=%d g=%d]", + (entryhi & 0xffffe000), + entryhi & 0xfc0, + entrylo0 & PAGE_MASK, + (entrylo0 & (1 << 11)) ? 1 : 0, + (entrylo0 & (1 << 10)) ? 1 : 0, + (entrylo0 & (1 << 9)) ? 1 : 0, + (entrylo0 & (1 << 8)) ? 1 : 0); + } + } + printk("\n"); + + write_c0_entryhi(asid); +} + +void +dump_tlb_all(void) +{ + dump_tlb(0, mips_cpu.tlbsize - 1); +} + +void +dump_tlb_wired(void) +{ + int wired = r3k_have_wired_reg ? read_c0_wired() : 8; + + printk("Wired: %d", wired); + dump_tlb(0, wired - 1); +} + +void +dump_tlb_addr(unsigned long addr) +{ + unsigned int flags, oldpid; + int index; + + __save_and_cli(flags); + oldpid = read_c0_entryhi() & 0xff; + write_c0_entryhi((addr & PAGE_MASK) | oldpid); + tlb_probe(); + index = read_c0_index(); + write_c0_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) +{ + int wired = r3k_have_wired_reg ? read_c0_wired() : 8; + dump_tlb(wired, mips_cpu.tlbsize - 1); +} + +void +dump_list_process(struct task_struct *t, void *address) +{ + pgd_t *page_dir, *pgd; + pmd_t *pmd; + pte_t *pte, page; + unsigned int addr; + unsigned long val; + + addr = (unsigned int) address; + + 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 == %08x\n", (unsigned int) page_dir); + + pgd = pgd_offset(t->mm, addr); + printk("pgd == %08x, ", (unsigned int) pgd); + + pmd = pmd_offset(pgd, addr); + printk("pmd == %08x, ", (unsigned int) pmd); + + pte = pte_offset(pmd, addr); + printk("pte == %08x, ", (unsigned int) pte); + + page = *pte; + 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_GLOBAL) printk("global "); + if (val & _PAGE_VALID) printk("valid "); + printk("\n"); +} + +void +dump_list_current(void *address) +{ + dump_list_process(current, address); +} + +unsigned int +vtop(void *address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned int addr, paddr; + + 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; + paddr |= (addr & ~PAGE_MASK); + + return paddr; +} + +void +dump16(unsigned long *p) +{ + int i; + + for(i=0;i<8;i++) + { + printk("*%08lx == %08lx, ", + (unsigned long)p, (unsigned long)*p++); + printk("*%08lx == %08lx\n", + (unsigned long)p, (unsigned long)*p++); + } +} diff --git a/release/src/linux/linux/arch/mips/lib/rtc-no.c b/release/src/linux/linux/arch/mips/lib/rtc-no.c new file mode 100644 index 00000000..a8f01eea --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/rtc-no.c @@ -0,0 +1,30 @@ +/* + * 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. + * + * Stub RTC routines to keep Linux from crashing on machine which don't + * have a RTC chip. + * + * Copyright (C) 1998, 2001 by Ralf Baechle + */ +#include <linux/kernel.h> +#include <linux/mc146818rtc.h> + +static unsigned int shouldnt_happen(void) +{ + static int called; + + if (!called) { + called = 1; + printk(KERN_DEBUG "RTC functions called - shouldn't happen\n"); + } + + return 0; +} + +struct rtc_ops no_rtc_ops = { + .rtc_read_data = (void *) &shouldnt_happen, + .rtc_write_data = (void *) &shouldnt_happen, + .rtc_bcd_mode = (void *) &shouldnt_happen +}; diff --git a/release/src/linux/linux/arch/mips/lib/rtc-std.c b/release/src/linux/linux/arch/mips/lib/rtc-std.c new file mode 100644 index 00000000..e36d02d2 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/rtc-std.c @@ -0,0 +1,34 @@ +/* + * 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. + * + * RTC routines for PC style attached Dallas chip. + * + * Copyright (C) 1998, 2001 by Ralf Baechle + */ +#include <linux/mc146818rtc.h> +#include <asm/io.h> + +static unsigned char std_rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void std_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +static int std_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops std_rtc_ops = { + &std_rtc_read_data, + &std_rtc_write_data, + &std_rtc_bcd_mode +}; diff --git a/release/src/linux/linux/arch/mips/lib/strlen_user.S b/release/src/linux/linux/arch/mips/lib/strlen_user.S new file mode 100644 index 00000000..e179f28c --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/strlen_user.S @@ -0,0 +1,40 @@ +/* + * 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 + */ +LEAF(__strlen_user_asm) + lw v0, THREAD_CURDS($28) # pointer ok? + and v0, a0 + bltz v0, fault + +FEXPORT(__strlen_user_nocheck_asm) + move v0, a0 +1: EX(lb, t0, (v0), fault) + addiu v0, 1 + bnez t0, 1b + subu v0, a0 + jr ra + END(__strlen_user_asm) + +fault: move v0, zero + jr ra diff --git a/release/src/linux/linux/arch/mips/lib/strncpy_user.S b/release/src/linux/linux/arch/mips/lib/strncpy_user.S new file mode 100644 index 00000000..3d91eb8e --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/strncpy_user.S @@ -0,0 +1,58 @@ +/* + * 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, 1999 by Ralf Baechle + */ +#include <linux/errno.h> +#include <asm/asm.h> +#include <asm/offset.h> +#include <asm/regdef.h> + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +/* + * 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. We don't deal with that. If + * it happens at most some bytes of the exceptions handlers will be copied. + */ + +LEAF(__strncpy_from_user_asm) + lw 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) + addiu v1, v1, 1 + beqz t0, 2f + sb t0, (a0) + addiu v0, 1 + bne v0, a2, 1b + addiu a0, 1 + .set reorder +2: addu t0, a1, v0 + xor t0, a1 + bltz t0, fault + jr ra # return n + END(__strncpy_from_user_asm) + +fault: li v0, -EFAULT + jr ra + + .section __ex_table,"a" + PTR 1b, fault + .previous diff --git a/release/src/linux/linux/arch/mips/lib/strnlen_user.S b/release/src/linux/linux/arch/mips/lib/strnlen_user.S new file mode 100644 index 00000000..83b77d04 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/strnlen_user.S @@ -0,0 +1,49 @@ +/* + * 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 of string but at max a1 otherwise + * + * Note: for performance reasons we deliberately accept that a user may + * make strlen_user and strnlen_user access the first few KSEG0 + * bytes. There's nothing secret there ... + */ +LEAF(__strnlen_user_asm) + lw v0, THREAD_CURDS($28) # pointer ok? + and v0, a0 + bltz v0, fault + +FEXPORT(__strnlen_user_nocheck_asm) + .type __strnlen_user_nocheck_asm,@function + move v0, a0 + addu a1, a0 # stop pointer + .set noreorder +1: beq v0, a1, 1f # limit reached? + addiu v0, 1 + .set reorder + EX(lb, t0, -1(v0), fault) + bnez t0, 1b +1: subu v0, a0 + jr ra + END(__strnlen_user_asm) + +fault: move v0, zero + jr ra diff --git a/release/src/linux/linux/arch/mips/lib/tinycon.c b/release/src/linux/linux/arch/mips/lib/tinycon.c new file mode 100644 index 00000000..5bf6ddd4 --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/tinycon.c @@ -0,0 +1,119 @@ + + +#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 screen_info screen_info; + +/* ---------------------------------------------------------------------- + * init_console() + * ---------------------------------------------------------------------- */ + +void init_console(void) +{ + size_x = 80; + size_y = 25; + cursor_x = 0; + cursor_y = 0; + + vram_addr = (unsigned short *)0xb00b8000; + + 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; +} + +void +set_crsr(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; +} + +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) ' '; +} + +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; + } +} + +/* end of file */ diff --git a/release/src/linux/linux/arch/mips/lib/watch.S b/release/src/linux/linux/arch/mips/lib/watch.S new file mode 100644 index 00000000..f42cf5da --- /dev/null +++ b/release/src/linux/linux/arch/mips/lib/watch.S @@ -0,0 +1,60 @@ +/* + * 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. + * + * Kernel debug stuff to use the Watch registers. + * Useful to find stack overflows, dangling pointers etc. + * + * Copyright (C) 1995, 1996, 1999 by Ralf Baechle + */ +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> + + .set noreorder +/* + * Parameter: a0 - logic address to watch + * Currently only KSEG0 addresses are allowed! + * a1 - set bit #1 to trap on load references + * bit #0 to trap on store references + * Results : none + */ + 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) + +/* + * Parameter: none + * Results : none + */ + LEAF(__watch_clear) + jr ra + mtc0 zero,CP0_WATCHLO + END(__watch_clear) + +/* + * Parameter: none + * Results : none + */ + LEAF(__watch_reenable) + lw t0,watch_savelo + jr ra + mtc0 t0,CP0_WATCHLO + END(__watch_reenable) + +/* + * Saved value of the c0_watchlo register for watch_reenable() + */ + .data +watch_savelo: .word 0 + .text |