// The kernel stack. .lcomm kernel_stack, KERNEL_STACK_SIZE .globl __start .globl run_idle .set noat .set noreorder #define EntryLo0 2 #define EntryLo1 3 #define EntryHi 10 #define Random 1 #define Index 0 #define PageMask 5 #define Wired 6 #define Config 16 #define Status 12 #define Cause 13 #define Compare 11 #define save_regs \ sw $k0, -0x180($zero) ;\ lw $k0, -0x184($zero) ;\ sw $at, 12($k0) ;\ sw $k1, 108($k0) ;\ lw $k1, -0x180($zero) ;\ sw $k1, 104($k0) ;\ sw $v0, 16($k0) ;\ sw $v1, 20($k0) ;\ sw $t0, 40($k0) ;\ sw $sp, 84($k0) ;\ sw $fp, 88($k0) ;\ sw $ra, 92($k0) ;\ lw $gp, -12($zero) ;\ la $sp, kernel_stack + KERNEL_STACK_SIZE ;\ move $a0, $k0 ;\ la $ra, kernel_exit ;\ bal save_args #define restore_regs \ lw $v0, 96($k0) ;\ lw $v1, 100($k0) ;\ mthi $v0 ;\ mtlo $v1 ;\ lw $v0, 16($k0) ;\ lw $v1, 20($k0) ;\ lw $a0, 24($k0) ;\ lw $a1, 28($k0) ;\ lw $a2, 32($k0) ;\ lw $a3, 36($k0) ;\ lw $t0, 40($k0) ;\ lw $t1, 44($k0) ;\ lw $t2, 48($k0) ;\ lw $t3, 52($k0) ;\ lw $t4, 56($k0) ;\ lw $t5, 60($k0) ;\ lw $t6, 64($k0) ;\ lw $t7, 68($k0) ;\ lw $t8, 72($k0) ;\ lw $t9, 76($k0) ;\ lw $gp, 80($k0) ;\ lw $sp, 84($k0) ;\ lw $fp, 88($k0) ;\ lw $ra, 92($k0) ;\ lw $at, 12($k0) ;\ lw $k1, 104($k0) ;\ sw $k1, -0x180($zero) ;\ lw $k1, 108($k0) ;\ sw $k0, -0x184($zero) ;\ lw $k0, -0x180($zero) addr_000: // TLB refill // TODO: this should probably be assembly-only for speed reasons li $a0, 0xffff0000 la $t9, panic jr $t9 save_regs mfc0 $a1, $EntryHi la $t9, tlb_refill jr $t9 nop .fill 0x100 - (. - addr_000) addr_100: // Cache error // TODO li $a0, 0xaaaa0000 la $t9, panic jr $t9 save_regs la $t9, cache_error jr $t9 nop .fill 0x180 - (. - addr_000) addr_180: // General exception // TODO li $a0, 0xaaff0000 la $t9, panic jr $t9 save_regs la $t9, exception jr $t9 nop .fill 0x200 - (. - addr_000) addr_200: // Interrupt // TODO li $a0, 0x0a0f0000 la $t9, panic jr $t9 save_regs la $t9, interrupt jr $t9 nop .fill 0x280 - (. - addr_000) // space for save_regs. .word 0 .word 0 start_idle: b . nop .word idle_page .word 0x80000000 // A pointer to the current page. __start: bal 1f nop .word _gp // For some reason the disassembler considers everything // after __start non-code until the next label. So I add a label. start_hack: 1: lw $gp, 0($ra) la $sp, kernel_stack + KERNEL_STACK_SIZE // Disable interrupts during bootstrap. mtc0 $zero, $Status // TODO: flush cache // Set kseg0 cachable. li $k0, 0x3 mtc0 $k0, $Config, 0 // Clear .bss la $a0, _edata la $a1, _end 1: sw $zero, 0($a0) bne $a1, $a0, 1b addu $a0, 4 // Set timer to a defined value mtc0 $zero, $Compare, 0 // Use the interrupt vector for interrupts li $k0, 1 << 23 mtc0 $k0, $Cause li $a0, 0xff0a0000 la $t9, panic jr $t9 // clear the tlb, hardwire page 0 to 0xffffffff // and soft-wire it to (0x294 << 20) + (0x290 << 10) // (for the idle task). // this address doesn't reach the tlb, so it can't trigger exceptions. mtc0 $zero, $PageMask mtc0 $zero, $EntryLo0 mtc0 $zero, $EntryLo1 li $t0, 0x80000000 // There are 32 tlb entries. addi $a0, $zero, 31 1: mtc0 $t0, $EntryHi mtc0 $a0, $Index tlbwi addiu $t0, $t0, 1 << 13 bgtz $a0, 1b addiu $a0, $a0, -1 la $t9, init jalr $t9 nop sw $gp, -12($zero) save_args: sw $a0, 24($k0) sw $a1, 28($k0) sw $a2, 32($k0) sw $a3, 36($k0) sw $t1, 44($k0) sw $t2, 48($k0) sw $t3, 52($k0) sw $t4, 56($k0) sw $t5, 60($k0) sw $t6, 64($k0) sw $t7, 68($k0) sw $t8, 72($k0) sw $t9, 76($k0) sw $gp, 80($k0) j $ra run_idle: move $k0, $a0 move $k1, $gp // Prepare enabling interrupts and switching to user mode. // The command is executed in the delay slot of the jump. li $t0, 0xff11 // Now it's acceptable to receive an exception. Jump to kuseg, // thereby generating a tlb_refill exception (which is handled). // The address is the virtual address where the idle task is. la $t9, ((0x294 << 20) + (0x290 << 10) + 0x288) jr $t9 mtc0 $t0, $Status kernel_exit: move $k0, $v0 restore_regs eret