summaryrefslogtreecommitdiffstats
path: root/grub-core/boot/mips/startup_raw.S
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/boot/mips/startup_raw.S')
-rw-r--r--grub-core/boot/mips/startup_raw.S300
1 files changed, 300 insertions, 0 deletions
diff --git a/grub-core/boot/mips/startup_raw.S b/grub-core/boot/mips/startup_raw.S
new file mode 100644
index 0000000..6a81b37
--- /dev/null
+++ b/grub-core/boot/mips/startup_raw.S
@@ -0,0 +1,300 @@
+/* startup.S - Startup code for the MIPS. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB 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.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/offsets.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/kernel.h>
+#include <grub/offsets.h>
+#include <grub/mips/asm.h>
+
+#define BASE_ADDR 8
+
+.extern __bss_start
+.extern _end
+.extern _edata
+
+ .globl __start, _start, start
+ .set noreorder
+ .set nomacro
+__start:
+_start:
+start:
+
+ bal codestart
+ nop
+base:
+ .org GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE
+compressed_size:
+ .long 0
+ .org GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE
+uncompressed_size:
+ .long 0
+ .org GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR
+uncompressed_addr:
+ .long 0
+codestart:
+ /* Save our base. */
+ move $s0, $ra
+
+ /* Parse arguments. Has to be done before relocation.
+ So need to do it in asm. */
+#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS
+ lui $t0, %hi (((16 << 20) - 264 + 4) | 0x80000000)
+ lw $t1, %lo (((16 << 20) - 264 + 4) | 0x80000000) ($t0)
+
+ lui $t2, 0x1234
+ ori $t2, 0x5678
+
+ bne $t1, $t2, 1f
+ nop
+
+ lui $t0, %hi (((16 << 20) - 264) | 0x80000000)
+ b 2f
+ lw $s4, %lo (((16 << 20) - 264) | 0x80000000) ($t0)
+
+1:
+ li $s4, 0
+2:
+#endif
+
+#ifdef GRUB_MACHINE_MIPS_LOONGSON
+ move $s2, $zero
+ move $s3, $zero
+ move $s4, $zero
+ move $s5, $zero
+ move $s7, $zero
+
+ /* $a2 has the environment. */
+ addiu $t0, $zero, -0x10
+ and $t1, $a2, $t0
+ beq $t0, $t1, argfw
+ nop
+ move $t0, $a2
+argcont:
+ lw $t1, 0($t0)
+ beq $t1, $zero, argdone
+ nop
+#define DO_PARSE(str, reg) \
+ addiu $t2, $s0, (str-base);\
+ bal parsestr;\
+ nop ;\
+ beq $v0, $zero, 1f;\
+ nop ;\
+ b 2f;\
+ move reg, $v0; \
+1:
+#define DO_CHECKT1(str, val) \
+ move $t6, $t1 ;\
+ addiu $t7, $s0, (str - base);\
+ bal do_check ;\
+ li $t2, val
+
+ DO_PARSE (busclockstr, $s2)
+ DO_PARSE (cpuclockstr, $s3)
+ DO_PARSE (memsizestr, $s4)
+ DO_PARSE (highmemsizestr, $s5)
+ DO_CHECKT1 (pmon_yeeloong_verstr, GRUB_ARCH_MACHINE_YEELOONG)
+ DO_CHECKT1 (pmon_fuloong2f_verstr, GRUB_ARCH_MACHINE_FULOONG2F)
+2:
+ b argcont
+ addiu $t0, $t0, 4
+parsestr:
+ move $v0, $zero
+ move $t3, $t1
+3:
+ lb GRUB_ASM_T4, 0($t2)
+ lb GRUB_ASM_T5, 0($t3)
+ addiu $t2, $t2, 1
+ addiu $t3, $t3, 1
+ beq GRUB_ASM_T5, $zero, 1f
+ nop
+ beq GRUB_ASM_T5, GRUB_ASM_T4, 3b
+ nop
+ bne GRUB_ASM_T4, $zero, 1f
+ nop
+
+ addiu $t3, $t3, 0xffff
+digcont:
+ lb GRUB_ASM_T5, 0($t3)
+ /* Substract '0' from digit. */
+ addiu GRUB_ASM_T5, GRUB_ASM_T5, 0xffd0
+ bltz GRUB_ASM_T5, 1f
+ nop
+ addiu GRUB_ASM_T4, GRUB_ASM_T5, 0xfff7
+ bgtz GRUB_ASM_T4, 1f
+ nop
+ /* Multiply $v0 by 10 with bitshifts. */
+ sll $v0, $v0, 1
+ sll GRUB_ASM_T4, $v0, 2
+ addu $v0, $v0, GRUB_ASM_T4
+ addu $v0, $v0, GRUB_ASM_T5
+ addiu $t3, $t3, 1
+ b digcont
+ nop
+1:
+ jr $ra
+ nop
+busclockstr: .asciz "busclock="
+cpuclockstr: .asciz "cpuclock="
+memsizestr: .asciz "memsize="
+highmemsizestr: .asciz "highmemsize="
+machtype_yeeloong_str1: .asciz "machtype=8.9"
+machtype_yeeloong_str2: .asciz "machtype=lemote-yeeloong-"
+machtype_fuloong2f_str: .asciz "machtype=lemote-fuloong-2f"
+machtype_fuloong2e_str: .asciz "machtype=lemote-fuloong-2e"
+pmon_yeeloong_str: .asciz "PMON_VER=LM8"
+pmon_fuloong2f_str: .asciz "PMON_VER=LM6"
+pmon_yeeloong_verstr: .asciz "Version=LM8"
+pmon_fuloong2f_verstr: .asciz "Version=LM6"
+ .p2align 2
+
+argdone:
+ beq $a0, $zero, cmdlinedone
+ nop
+#define DO_CHECKA1(str, val) \
+ lw $t6, 0($a1) ;\
+ addiu $t7, $s0, (str - base);\
+ bal do_check ;\
+ li $t2, val
+ DO_CHECKA1 (machtype_yeeloong_str1, GRUB_ARCH_MACHINE_YEELOONG)
+ DO_CHECKA1 (machtype_yeeloong_str2, GRUB_ARCH_MACHINE_YEELOONG)
+ DO_CHECKA1 (pmon_yeeloong_str, GRUB_ARCH_MACHINE_YEELOONG)
+ DO_CHECKA1 (machtype_fuloong2f_str, GRUB_ARCH_MACHINE_FULOONG2F)
+ DO_CHECKA1 (machtype_fuloong2e_str, GRUB_ARCH_MACHINE_FULOONG2E)
+ DO_CHECKA1 (pmon_fuloong2f_str, GRUB_ARCH_MACHINE_FULOONG2F)
+ addiu $a0, $a0, -1
+ b argdone
+ addiu $a1, $a1, 4
+do_check:
+ lb GRUB_ASM_T4, 0($t7)
+ beq GRUB_ASM_T4, $zero, 1f
+ lb $t3, 0($t6)
+ bne $t3, GRUB_ASM_T4, 2f
+ addiu $t6, $t6, 1
+ b do_check
+ addiu $t7, $t7, 1
+1:
+ move $s7, $t2
+2:
+ jr $ra
+ nop
+argfw:
+ not $s7, $a2
+cmdlinedone:
+#endif
+#ifdef GRUB_MACHINE_ARC
+ lui $t0, %hi(_start - 256)
+ addiu $t0, $t0, %lo(_start - 256)
+ addiu $t3, $t0, 255
+ lw $t1, 0($a1)
+1:
+ bne $t0, $t3, 2f
+ lb $t2, 0($t1)
+ move $t2, $zero
+2:
+ sb $t2, 0($t0)
+ addiu $t0, $t0, 1
+ bnez $t2, 1b
+ addiu $t1, $t1, 1
+#endif
+ /* Copy the decompressor. */
+ lui $t1, %hi(base)
+ addiu $t1, $t1, %lo(base)
+ lui $t3, %hi(__bss_start)
+ addiu $t3, $t3, %lo(__bss_start)
+ move $t2, $s0
+
+1:
+ beq $t1, $t3, 2f
+ lb GRUB_ASM_T4, 0($t2)
+ sb GRUB_ASM_T4, 0($t1)
+ addiu $t1, $t1, 1
+ b 1b
+ addiu $t2, $t2, 1
+2:
+ /* Clean out its BSS. */
+ lui $t1, %hi(__bss_start)
+ addiu $t1, $t1, %lo(__bss_start)
+ lui $t2, %hi(_end)
+ addiu $t2, $t2, %lo(_end)
+1:
+ beq $t1, $t2, 2f
+ nop
+ sb $zero, 0($t1)
+ b 1b
+ addiu $t1, $t1, 1
+2:
+ lui $a0, %hi(base)
+ addiu $a0, $a0, %lo(base)
+ lui $a1, %hi(_end)
+ addiu $a1, %lo(_end)
+ subu $a1,$a1,$a0
+
+#include "../../kern/mips/cache_flush.S"
+
+ /* Decompress the payload. */
+ lui $a0, %hi(_edata)
+ addiu $a0, $a0, %lo(_edata)
+
+ lui $t0, %hi(base)
+ addiu $t0, $t0, %lo(base)
+ subu $a0, $a0, $t0
+ addu $a0, $a0, $s0
+
+ lw $a1, (GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR - BASE_ADDR)($s0)
+ lw $a2, (GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0)
+ lw $a3, (GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE - BASE_ADDR)($s0)
+ move $s1, $a1
+
+ /* $a0 contains source compressed address, $a1 is destination,
+ $a2 is compressed size, $a3 is uncompressed size.
+ */
+ move $s6, $a3
+
+ lui $t9, %hi(EXT_C(grub_decompress_core))
+ addiu $t9, $t9, %lo(EXT_C(grub_decompress_core))
+
+#ifdef GRUB_MACHINE_ARC
+ lui $sp, %hi(_start - 512)
+ jalr $t9
+ addiu $sp, $sp, %lo(_start - 512)
+#else
+ lui $sp, %hi(_start - 256)
+ jalr $t9
+ addiu $sp, $sp, %lo(_start - 256)
+#endif
+ move $a0, $s1
+ move $a1, $s6
+
+#include "../../kern/mips/cache_flush.S"
+
+ lui $t1, %hi(GRUB_MACHINE_LINK_ADDR)
+ addiu $t1, %lo(GRUB_MACHINE_LINK_ADDR)
+
+ jr $t1
+ nop
+ /* Ensure that .data section is created. In code we suppose that _edata
+ is first location not in decompressor image. Strictly speaking it's
+ _edata only when .data is present and _etext otherwise. But checking
+ for .data presence would cost more in code than it is to ensure that
+ .data is created.
+ */
+ .data
+ .long 0