2009-06-01 15:26:42 +03:00
|
|
|
// Iris: micro-kernel for a capability-based operating system.
|
|
|
|
// mips/entry.S: Routines which are entered from user space.
|
|
|
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
|
|
|
//
|
|
|
|
// 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 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2012-09-26 20:03:36 +03:00
|
|
|
#define KERNEL_STACK_SIZE 0x1000
|
2009-05-11 01:28:12 +03:00
|
|
|
// The kernel stack.
|
|
|
|
.lcomm kernel_stack, KERNEL_STACK_SIZE
|
|
|
|
|
|
|
|
.globl run_idle
|
2009-05-26 01:42:47 +03:00
|
|
|
.globl directory
|
2009-05-11 01:28:12 +03:00
|
|
|
.set noat
|
2009-05-26 01:42:47 +03:00
|
|
|
.set noreorder
|
2009-05-11 01:28:12 +03:00
|
|
|
|
2009-05-25 01:31:35 +03:00
|
|
|
#define ARCH
|
|
|
|
#define ASM
|
2009-10-31 10:32:23 +02:00
|
|
|
#define __KERNEL__
|
2009-05-25 01:31:35 +03:00
|
|
|
#include "arch.hh"
|
2009-05-11 01:28:12 +03:00
|
|
|
|
|
|
|
addr_000:
|
2009-05-27 15:38:52 +03:00
|
|
|
#if 0
|
2009-05-11 01:28:12 +03:00
|
|
|
// TLB refill
|
2013-05-12 16:46:11 +03:00
|
|
|
lui $k0, 0x8000
|
|
|
|
lw $k1, 0x174($k0) // directory
|
2009-05-26 01:42:47 +03:00
|
|
|
mfc0 $k0, $CP0_ENTRY_HI
|
|
|
|
srl $k0, $k0, 19
|
2013-05-12 16:46:11 +03:00
|
|
|
and $k0, $k0, 0xffc
|
2009-05-26 01:42:47 +03:00
|
|
|
addu $k0, $k0, $k1
|
2009-06-01 02:12:54 +03:00
|
|
|
beq $zero, $k0, zero_refill
|
2009-05-26 01:42:47 +03:00
|
|
|
lw $k0, 0($k0)
|
|
|
|
mfc0 $k1, $CP0_ENTRY_HI
|
|
|
|
srl $k1, $k1, 10
|
2013-05-12 16:46:11 +03:00
|
|
|
and $k1, $k1, 0xff8
|
2009-05-26 01:42:47 +03:00
|
|
|
add $k0, $k0, $k1
|
|
|
|
lw $k1, 0($k0)
|
|
|
|
mtc0 $k1, $CP0_ENTRY_LO0
|
|
|
|
lw $k1, 4($k0)
|
|
|
|
mtc0 $k1, $CP0_ENTRY_LO1
|
2009-06-01 02:12:54 +03:00
|
|
|
1: tlbwr
|
2013-05-12 16:46:11 +03:00
|
|
|
move $k0, $zero
|
|
|
|
move $k1, $zero
|
2009-05-26 01:42:47 +03:00
|
|
|
eret
|
|
|
|
|
2009-06-01 02:12:54 +03:00
|
|
|
zero_refill:
|
2013-05-12 16:46:11 +03:00
|
|
|
mtc0 $zero, $CP0_ENTRY_LO0
|
2009-06-01 02:12:54 +03:00
|
|
|
b 1b
|
2013-05-12 16:46:11 +03:00
|
|
|
mtc0 $zero, $CP0_ENTRY_LO1
|
|
|
|
#else
|
|
|
|
// Slow refill: use C code (which calls kdebug etc)
|
|
|
|
move $k1, $ra
|
2009-05-14 21:31:47 +03:00
|
|
|
bal save_regs
|
2009-05-27 15:38:52 +03:00
|
|
|
nop
|
2009-05-11 01:28:12 +03:00
|
|
|
la $t9, tlb_refill
|
|
|
|
jr $t9
|
|
|
|
nop
|
2013-05-12 16:46:11 +03:00
|
|
|
#endif
|
2009-05-11 01:28:12 +03:00
|
|
|
.fill 0x100 - (. - addr_000)
|
|
|
|
addr_100:
|
|
|
|
// Cache error
|
2013-05-12 16:46:11 +03:00
|
|
|
move $k1, $ra
|
2009-05-14 21:31:47 +03:00
|
|
|
bal save_regs
|
2009-05-27 15:38:52 +03:00
|
|
|
nop
|
2009-05-11 01:28:12 +03:00
|
|
|
la $t9, cache_error
|
|
|
|
jr $t9
|
|
|
|
nop
|
2013-05-12 16:46:11 +03:00
|
|
|
.fill 0x180 - (. - addr_000) - 3 * 4
|
|
|
|
|
|
|
|
directory: // 0x174
|
|
|
|
.word 0
|
|
|
|
current: // 0x178
|
|
|
|
.word idle
|
|
|
|
// 0x17c
|
|
|
|
.word _gp
|
|
|
|
|
2009-05-11 01:28:12 +03:00
|
|
|
addr_180:
|
|
|
|
// General exception
|
2013-05-12 16:46:11 +03:00
|
|
|
move $k1, $ra
|
2009-05-14 21:31:47 +03:00
|
|
|
bal save_regs
|
2009-05-27 15:38:52 +03:00
|
|
|
nop
|
2009-05-11 01:28:12 +03:00
|
|
|
la $t9, exception
|
|
|
|
jr $t9
|
|
|
|
nop
|
2013-05-12 16:46:11 +03:00
|
|
|
// This is annoying; it must fill it up so addr_200 is right. For some
|
|
|
|
// reason .fill 0x200 - (. - addr_000) - 2 * 4 doesn't work here.
|
|
|
|
.fill 0x60
|
|
|
|
.word 0x00000012 // 1f8 EntryLo data for idle page.
|
2009-05-27 15:38:52 +03:00
|
|
|
.word 0x80000000 // 1fc A pointer to the current page.
|
2009-05-11 01:28:12 +03:00
|
|
|
addr_200:
|
|
|
|
// Interrupt
|
2013-05-12 16:46:11 +03:00
|
|
|
move $k1, $ra
|
2009-05-14 21:31:47 +03:00
|
|
|
bal save_regs
|
2009-05-27 15:38:52 +03:00
|
|
|
nop
|
2009-05-11 01:28:12 +03:00
|
|
|
la $t9, interrupt
|
|
|
|
jr $t9
|
|
|
|
nop
|
2013-05-12 16:46:11 +03:00
|
|
|
.fill 0x280 - (. - addr_000)
|
2009-05-11 01:28:12 +03:00
|
|
|
|
2009-05-27 15:38:52 +03:00
|
|
|
start_idle: // 280
|
2009-05-14 21:31:47 +03:00
|
|
|
// Wait for the next interrupt, then the first thread will be scheduled.
|
|
|
|
// It is impractical to try to call schedule, because for that the
|
|
|
|
// idle task would need to own capabilities.
|
|
|
|
1: wait
|
|
|
|
b 1b
|
|
|
|
nop
|
2009-05-11 01:28:12 +03:00
|
|
|
|
2009-05-19 00:18:23 +03:00
|
|
|
// TODO: save only fragile registers now, the rest on task switch.
|
2009-05-14 21:31:47 +03:00
|
|
|
kernel_exit:
|
2013-05-12 16:46:11 +03:00
|
|
|
move $k0, $v0
|
|
|
|
lui $k1, 0x8000
|
|
|
|
sw $v0, 0x178($k1) // current
|
|
|
|
lw $k1, SAVE_PC($k0)
|
|
|
|
mtc0 $k1, $CP0_EPC
|
|
|
|
lw $k1, SAVE_LO($k0)
|
|
|
|
mtlo $k1
|
|
|
|
lw $k1, SAVE_HI($k0)
|
|
|
|
mthi $k1
|
|
|
|
lw $v0, SAVE_V + 0 * 4($k0)
|
|
|
|
lw $v1, SAVE_V + 1 * 4($k0)
|
|
|
|
lw $a0, SAVE_A + 0 * 4($k0)
|
|
|
|
lw $a1, SAVE_A + 1 * 4($k0)
|
|
|
|
lw $a2, SAVE_A + 2 * 4($k0)
|
|
|
|
lw $a3, SAVE_A + 3 * 4($k0)
|
|
|
|
lw $t0, SAVE_T + 0 * 4($k0)
|
|
|
|
lw $t1, SAVE_T + 1 * 4($k0)
|
|
|
|
lw $t2, SAVE_T + 2 * 4($k0)
|
|
|
|
lw $t3, SAVE_T + 3 * 4($k0)
|
|
|
|
lw $t4, SAVE_T + 4 * 4($k0)
|
|
|
|
lw $t5, SAVE_T + 5 * 4($k0)
|
|
|
|
lw $t6, SAVE_T + 6 * 4($k0)
|
|
|
|
lw $t7, SAVE_T + 7 * 4($k0)
|
|
|
|
lw $t8, SAVE_T + 8 * 4($k0)
|
|
|
|
lw $t9, SAVE_T + 9 * 4($k0)
|
|
|
|
lw $s0, SAVE_S + 0 * 4($k0)
|
|
|
|
lw $s1, SAVE_S + 1 * 4($k0)
|
|
|
|
lw $s2, SAVE_S + 2 * 4($k0)
|
|
|
|
lw $s3, SAVE_S + 3 * 4($k0)
|
|
|
|
lw $s4, SAVE_S + 4 * 4($k0)
|
|
|
|
lw $s5, SAVE_S + 5 * 4($k0)
|
|
|
|
lw $s6, SAVE_S + 6 * 4($k0)
|
|
|
|
lw $s7, SAVE_S + 7 * 4($k0)
|
|
|
|
lw $fp, SAVE_FP($k0)
|
|
|
|
lw $at, SAVE_AT($k0)
|
|
|
|
lw $sp, SAVE_SP($k0)
|
|
|
|
lw $gp, SAVE_GP($k0)
|
|
|
|
lw $ra, SAVE_RA($k0)
|
2009-07-04 17:21:28 +03:00
|
|
|
#ifndef NDEBUG
|
2009-10-31 10:32:23 +02:00
|
|
|
// Exceptions were enabled in the kernel; set them to usermode setting again.
|
2013-05-12 16:46:11 +03:00
|
|
|
mfc0 $k1, $CP0_STATUS
|
|
|
|
ori $k1, $k1, 0xff13
|
|
|
|
mtc0 $k1, $CP0_STATUS
|
2009-07-04 17:21:28 +03:00
|
|
|
#endif
|
2013-05-12 16:46:11 +03:00
|
|
|
move $k0, $zero
|
|
|
|
move $k1, $zero
|
2009-05-14 21:31:47 +03:00
|
|
|
eret
|
2009-05-11 01:28:12 +03:00
|
|
|
|
2009-05-14 21:31:47 +03:00
|
|
|
save_regs:
|
2013-05-12 16:46:11 +03:00
|
|
|
lui $k0, 0x8000
|
|
|
|
lw $k0, 0x178($k0) // current
|
2009-05-22 23:48:49 +03:00
|
|
|
|
2013-05-12 16:46:11 +03:00
|
|
|
sw $k1, SAVE_RA($k0)
|
2009-05-19 00:18:23 +03:00
|
|
|
sw $gp, SAVE_GP($k0)
|
|
|
|
sw $sp, SAVE_SP($k0)
|
2013-05-12 16:46:11 +03:00
|
|
|
sw $at, SAVE_AT($k0)
|
2009-05-19 00:18:23 +03:00
|
|
|
sw $fp, SAVE_FP($k0)
|
2009-08-24 22:02:35 +03:00
|
|
|
sw $s7, SAVE_S + 7 * 4($k0)
|
2013-05-12 16:46:11 +03:00
|
|
|
sw $s6, SAVE_S + 6 * 4($k0)
|
|
|
|
sw $s5, SAVE_S + 5 * 4($k0)
|
|
|
|
sw $s4, SAVE_S + 4 * 4($k0)
|
|
|
|
sw $s3, SAVE_S + 3 * 4($k0)
|
|
|
|
sw $s2, SAVE_S + 2 * 4($k0)
|
|
|
|
sw $s1, SAVE_S + 1 * 4($k0)
|
|
|
|
sw $s0, SAVE_S + 0 * 4($k0)
|
|
|
|
sw $t9, SAVE_T + 9 * 4($k0)
|
|
|
|
sw $t8, SAVE_T + 8 * 4($k0)
|
|
|
|
sw $t7, SAVE_T + 7 * 4($k0)
|
|
|
|
sw $t6, SAVE_T + 6 * 4($k0)
|
|
|
|
sw $t5, SAVE_T + 5 * 4($k0)
|
|
|
|
sw $t4, SAVE_T + 4 * 4($k0)
|
|
|
|
sw $t3, SAVE_T + 3 * 4($k0)
|
|
|
|
sw $t2, SAVE_T + 2 * 4($k0)
|
|
|
|
sw $t1, SAVE_T + 1 * 4($k0)
|
|
|
|
sw $t0, SAVE_T + 0 * 4($k0)
|
|
|
|
sw $a3, SAVE_A + 3 * 4($k0)
|
|
|
|
sw $a2, SAVE_A + 2 * 4($k0)
|
|
|
|
sw $a1, SAVE_A + 1 * 4($k0)
|
|
|
|
sw $a0, SAVE_A + 0 * 4($k0)
|
|
|
|
sw $v1, SAVE_V + 1 * 4($k0)
|
|
|
|
sw $v0, SAVE_V + 0 * 4($k0)
|
|
|
|
mfhi $k1
|
|
|
|
sw $k1, SAVE_HI($k0)
|
|
|
|
mflo $k1
|
|
|
|
sw $k1, SAVE_LO($k0)
|
2009-05-25 01:31:35 +03:00
|
|
|
mfc0 $k1, $CP0_EPC
|
2009-05-19 00:18:23 +03:00
|
|
|
sw $k1, SAVE_PC($k0)
|
2009-05-11 01:28:12 +03:00
|
|
|
|
2009-07-04 17:21:28 +03:00
|
|
|
#ifndef NDEBUG
|
2009-07-23 13:06:32 +03:00
|
|
|
// Allow kernel bugs to set EPC and friends.
|
2009-07-04 17:21:28 +03:00
|
|
|
mfc0 $k0, $CP0_STATUS
|
2013-05-12 16:46:11 +03:00
|
|
|
lui $k1, 0x1000
|
2009-07-05 11:52:44 +03:00
|
|
|
and $k0, $k0, $k1
|
2009-07-04 17:21:28 +03:00
|
|
|
mtc0 $k0, $CP0_STATUS
|
|
|
|
#endif
|
|
|
|
|
2013-05-12 16:46:11 +03:00
|
|
|
lui $k0, 0x8000
|
|
|
|
lw $gp, 0x17c($k0)
|
|
|
|
la $sp, kernel_stack + KERNEL_STACK_SIZE
|
|
|
|
|
2009-05-14 21:31:47 +03:00
|
|
|
move $t9, $ra
|
|
|
|
la $ra, kernel_exit
|
|
|
|
jr $t9
|
2009-05-23 21:55:31 +03:00
|
|
|
nop
|