summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/head.S
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/mips/kernel/head.S
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/mips/kernel/head.S')
-rw-r--r--arch/mips/kernel/head.S412
1 files changed, 412 insertions, 0 deletions
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
new file mode 100644
index 000000000..a2cb43de3
--- /dev/null
+++ b/arch/mips/kernel/head.S
@@ -0,0 +1,412 @@
+/*
+ * arch/mips/kernel/head.S
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ *
+ * Head.S contains the MIPS exception handler and startup code.
+ */
+#include <linux/tasks.h>
+
+#include <asm/asm.h>
+#include <asm/segment.h>
+#include <asm/cachectl.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/stackframe.h>
+#include <asm/bootinfo.h>
+
+#define PAGE_SIZE 0x1000
+
+#define MODE_GLOBAL 0x0001 /* shared for all processes */
+#define MODE_ALIAS 0x0016 /* uncachable */
+
+ .text
+ .set mips3
+/*
+ * This is space for the interrupt handlers.
+ * They are located at virtual address KSEG[01] (physical 0x0)
+ */
+ /*
+ * TLB refill, EXL == 0
+ */
+ .set noreorder
+ .set noat
+ LEAF(except_vec0)
+ dmfc0 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
+ nop # Needed for R4[04]00 pipeline
+ tlbwr
+ nop # Needed for R4[04]00 pipeline
+ nop
+ nop
+ 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.
+ */
+ nop
+ eret
+ END(except_vec0)
+
+ /*
+ * XTLB refill, EXL == 0
+ * Should never be reached
+ */
+ .org except_vec0+0x80
+ LEAF(except_vec1)
+ PANIC("XTLB Refill exception.\n")
+1: j 1b
+ nop
+ END(except_vec1)
+
+ /*
+ * Cache Error
+ */
+ .org except_vec1+0x80
+ LEAF(except_vec2)
+ /*
+ * Famous last words: unreached
+ */
+ mfc0 a1,CP0_ERROREPC
+ PRINT("Cache error exception: c0_errorepc == %08x\n")
+1: j 1b
+ nop
+ END(except_vec2)
+
+ /*
+ * General exception vector.
+ */
+ .org except_vec2+0x80
+ NESTED(except_vec3, 0, sp)
+ .set noat
+ /*
+ * Register saving is delayed as long as we don't know
+ * which registers really need to be saved.
+ */
+ mfc0 k1,CP0_CAUSE
+ la k0,exception_handlers
+ /*
+ * Next lines assumes that the used CPU type has max.
+ * 32 different types of exceptions. We might use this
+ * to implement software exceptions in the future.
+ */
+ andi k1,0x7c
+ addu k0,k1
+ lw k0,(k0)
+ NOP
+ jr k0
+ nop
+ END(except_vec3)
+ .set at
+
+/******************************************************************************/
+
+/*
+ * Kernel entry
+ */
+ .set noreorder
+ NESTED(kernel_entry, 16, sp)
+ /*
+ * Clear BSS first so that there are no surprises...
+ */
+ la t0,_edata
+ la t1,_end
+ sw zero,(t0)
+1: addiu t0,4
+ bnel t0,t1,1b
+ sw zero,(t0)
+
+ /*
+ * Initialize low level part of memory management
+ */
+ jal tlbflush
+ mtc0 zero,CP0_WIRED # delay slot
+ 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)
+ and t0,t1
+ mtc0 t0,CP0_STATUS
+
+1: jal start_kernel
+ nop # delay slot
+ /*
+ * Main should never return here, but
+ * just in case, we know what happens.
+ */
+ b 1b
+ nop # delay slot
+ END(kernel_entry)
+
+/*
+ * wire_mappings - used to map hardware registers
+ */
+ LEAF(wire_mappings)
+ /*
+ * 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
+ addu t0,t1
+ lw t0,(t0) # get base address
+
+ /*
+ * Get number of wired TLB entries and
+ * loop over selected map0 table.
+ */
+ lw t1,(t0) # number of wired TLB entries
+ move t2,zero # TLB entry counter
+ addiu t3,t1,1 # wire one additional entry
+ beqz t1,2f # null, exit
+ mtc0 t3,CP0_WIRED # delay slot
+ addiu t0,8
+1: lw t4,24(t0) # PageMask
+ ld t5,0(t0) # entryHi
+ ld t6,8(t0) # entryLo0
+ ld t7,16(t0) # entryLo1
+ addiu t2,1 # increment ctr
+ mtc0 t2,CP0_INDEX # set TLB entry
+ mtc0 t4,CP0_PAGEMASK
+ dmtc0 t5,CP0_ENTRYHI
+ dmtc0 t6,CP0_ENTRYLO0
+ dmtc0 t7,CP0_ENTRYLO1
+ addiu t0,32
+ bne t1,t2,1b # next TLB entry
+ tlbwi # delay slot
+
+ /*
+ * We use only 4k pages. Therefore the PageMask register
+ * is expected to be setup for 4k pages.
+ */
+2: li t0,PM_4K
+ mtc0 t0,CP0_PAGEMASK
+
+ /*
+ * Now map the pagetables
+ */
+ mtc0 zero,CP0_INDEX
+ la t0,TLB_ROOT
+ dmtc0 t0,CP0_ENTRYHI
+ la t0,swapper_pg_dir-KSEG1
+ srl t0,6
+ ori t0,(MODE_ALIAS|MODE_GLOBAL) # uncachable, dirty, valid
+ dmtc0 t0,CP0_ENTRYLO0
+ li t0,MODE_GLOBAL
+ dmtc0 t0,CP0_ENTRYLO1
+ nop
+ tlbwi # delayed
+
+ /*
+ * Load the context register with a value that allows
+ * it to be used as fast as possible in tlb exceptions.
+ * It is expected that this register's content will
+ * NEVER be changed.
+ */
+ li t0,TLBMAP
+ dsll t0,1
+ dmtc0 t0,CP0_CONTEXT
+ 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
+ */
+#define MAPDATA(q1,q2,q3,w1) \
+ .quad q1; \
+ .quad q2; \
+ .quad q3; \
+ .word w1; \
+ .word 0
+
+/*
+ * Initial mapping tables for supported Mips boards.
+ * First item is always the number of wired TLB entries,
+ * following by EntryHi/EntryLo pairs and page mask.
+ * Since everything must be quad-aligned (8) we insert
+ * some dummy zeros.
+ */
+
+/*
+ * Address table of mapping tables for supported Mips boards.
+ * Add your own stuff here but don't forget to define your
+ * target system in bootinfo.h
+ */
+
+map0table: PTR map0_dummy # machtype = unknown
+ PTR map0_rpc # Deskstation rPC44
+ PTR map0_tyne # Deskstation Tyne
+ PTR map0_pica61 # Acer Pica-61
+ PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030)
+
+map0_dummy: .word 0 # 0 entries
+
+ .align 3
+/*
+ * Initial mappings for Deskstation rPC boards.
+ * RB: Untested goodie - I don't have such a board.
+ */
+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
+
+/*
+ * Initial mappings for Deskstation Tyne boards.
+ */
+map0_tyne: .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
+
+/*
+ * 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(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)
+MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # ISA I/O and ISA memory space (both 16M)
+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
+
+
+ .text
+
+ .org 0x1000
+ .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
+ EXPORT(empty_bad_page_table)
+
+ .org 0x5000
+ EXPORT(empty_zero_page)
+
+ .org 0x6000
+ 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
+
+ EXPORT(cache_error_buffer)
+ .fill 32*4,1,0
+
+ .data
+ EXPORT(kernelsp)
+ PTR 0