From c5b4cd370ee3342d226cd0f4193f2c560f855b2d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 21 Sep 2010 10:14:08 +0200 Subject: [PATCH] asm part for mips decompressor --- grub-core/Makefile.core.def | 13 ++ grub-core/boot/mips/startup_raw.S | 186 +++++++++++++++++++++++++++++ grub-core/kern/mips/cache.S | 3 + grub-core/kern/mips/cache_flush.S | 4 +- grub-core/kern/mips/startup.S | 148 ++++------------------- grub-core/lib/mips/relocator_asm.S | 7 +- include/grub/offsets.h | 12 +- util/grub-mkimage.c | 51 ++++++-- 8 files changed, 278 insertions(+), 146 deletions(-) create mode 100644 grub-core/boot/mips/startup_raw.S diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2fca91430..3341cb678 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -275,6 +275,19 @@ image = { enable = i386_pc; }; +image = { + name = decompress; + mips = boot/mips/startup_raw.S; + common = lib/LzmaDec.c; + + mips_cppflags = '-DGRUB_MACHINE_LINK_ADDR=0x80200000'; + + objcopyflags = '-O binary'; + ldflags = '-lgcc -static-libgcc -Wl,-Ttext,0x80100000'; + cflags = '-static-libgcc'; + enable = mips; +}; + image = { name = fwstart; mips_yeeloong = boot/mips/yeeloong/fwstart.S; diff --git a/grub-core/boot/mips/startup_raw.S b/grub-core/boot/mips/startup_raw.S new file mode 100644 index 000000000..67dc2ec03 --- /dev/null +++ b/grub-core/boot/mips/startup_raw.S @@ -0,0 +1,186 @@ +/* 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 . + */ + +#include +#include +#include +#include + +#define BASE_ADDR 8 + +.extern __bss_start +.extern _end + + .globl __start, _start, start + .set noreorder + .set nomacro +__start: +_start: +start: + + bal codestart + nop +base: + . = _start + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE +compressed_size: + .long 0 + . = _start + GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE +uncompressed_size: + .long 0 +codestart: + /* Save our base. */ + move $s0, $ra + + /* Parse arguments. Has to be done before relocation. + So need to do it in asm. */ +#if 0 // def GRUB_MACHINE_MIPS_YEELOONG + move $s2, $zero + move $s3, $zero + move $s4, $zero + move $s5, $zero + + /* $a2 has the environment. */ + addiu $t0, $a2, 1 + beq $t0, $zero, argdone + 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;\ + beq $v0, $zero, 1f;\ + nop ;\ + b 2f;\ + move reg, $v0; +1: + DO_PARSE (busclockstr, $s2) + DO_PARSE (cpuclockstr, $s3) + DO_PARSE (memsizestr, $s4) + DO_PARSE (highmemsizestr, $s5) +2: + b argcont + addiu $t0, $t0, 4 +parsestr: + move $v0, $zero + move $t3, $t1 +3: + lb $t4, 0($t2) + lb $t5, 0($t3) + addiu $t2, $t2, 1 + addiu $t3, $t3, 1 + beq $t5, $zero, 1f + nop + beq $t5, $t4, 3b + nop + bne $t4, $zero, 1f + nop + + addiu $t3, $t3, 0xffff +digcont: + lb $t5, 0($t3) + /* Substract '0' from digit. */ + addiu $t5, $t5, 0xffd0 + bltz $t5, 1f + nop + addiu $t4, $t5, 0xfff7 + bgtz $t4, 1f + nop + /* Multiply $v0 by 10 with bitshifts. */ + sll $v0, $v0, 1 + sll $t4, $v0, 2 + addu $v0, $v0, $t4 + addu $v0, $v0, $t5 + addiu $t3, $t3, 1 + b digcont + nop +1: + jr $ra + nop +busclockstr: .asciiz "busclock=" +cpuclockstr: .asciiz "cpuclock=" +memsizestr: .asciiz "memsize=" +highmemsizestr: .asciiz "highmemsize=" + .p2align 2 +argdone: +#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 $t4, 0($t2) + sb $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: + + /* Decompress the payload. */ + lui $a0, %hi(__bss_start) + addiu $a0, $a0, %lo(__bss_start) + lui $t0, %hi(base) + addiu $t0, $t0, %lo(base) + subu $a0, $a0, $t0 + addu $a0, $a0, $s0 + + lui $a1, %hi(GRUB_MACHINE_LINK_ADDR) + addiu $a1, %lo(GRUB_MACHINE_LINK_ADDR) + lw $a2, (GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0) + lw $a3, (GRUB_KERNEL_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 $sp, %hi(_start) + + bal EXT_C(grub_decompress_core) + addiu $sp, $sp, %lo(_start) + + 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 diff --git a/grub-core/kern/mips/cache.S b/grub-core/kern/mips/cache.S index 2c35b6da2..02dc3355f 100644 --- a/grub-core/kern/mips/cache.S +++ b/grub-core/kern/mips/cache.S @@ -1,6 +1,9 @@ #include + .set nomacro + .set noreorder + FUNCTION (grub_cpu_flush_cache) FUNCTION (grub_arch_sync_caches) #include "cache_flush.S" diff --git a/grub-core/kern/mips/cache_flush.S b/grub-core/kern/mips/cache_flush.S index 5667ee7b4..11096c035 100644 --- a/grub-core/kern/mips/cache_flush.S +++ b/grub-core/kern/mips/cache_flush.S @@ -9,15 +9,15 @@ subu $t1, $t3, $t2 1: cache 1, 0($t0) - addiu $t0, $t0, 0x1 addiu $t1, $t1, 0xffff bne $t1, $zero, 1b + addiu $t0, $t0, 0x1 sync move $t0, $t2 subu $t1, $t3, $t2 2: cache 0, 0($t0) - addiu $t0, $t0, 0x1 addiu $t1, $t1, 0xffff bne $t1, $zero, 2b + addiu $t0, $t0, 0x1 sync diff --git a/grub-core/kern/mips/startup.S b/grub-core/kern/mips/startup.S index 6811353ea..1b27a5b1f 100644 --- a/grub-core/kern/mips/startup.S +++ b/grub-core/kern/mips/startup.S @@ -22,128 +22,19 @@ #include #include -#define BASE_ADDR 8 - -.extern __bss_start -.extern _end - +#define BASE_ADDR 8 + .globl __start, _start, start + .set noreorder + .set nomacro __start: _start: -start: - bal codestart -base: - . = _start + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE -compressed_size: - .long 0 - . = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE -total_module_size: - .long 0 - . = _start + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE -kernel_image_size: - .long 0 -codestart: - /* Save our base. */ - move $s0, $ra +start: +.extern __bss_start +.extern _end + bal cont + nop - /* Parse arguments. Has to be done before relocation. - So need to do it in asm. */ -#ifdef GRUB_MACHINE_MIPS_YEELOONG - move $s2, $zero - move $s3, $zero - move $s4, $zero - move $s5, $zero - - /* $a2 has the environment. */ - addiu $t0, $a2, 1 - beq $t0, $zero, argdone - move $t0, $a2 -argcont: - lw $t1, 0($t0) - beq $t1, $zero, argdone -#define DO_PARSE(str, reg) \ - addiu $t2, $s0, (str-base);\ - bal parsestr;\ - beq $v0, $zero, 1f;\ - move reg, $v0;\ - b 2f;\ -1: - DO_PARSE (busclockstr, $s2) - DO_PARSE (cpuclockstr, $s3) - DO_PARSE (memsizestr, $s4) - DO_PARSE (highmemsizestr, $s5) -2: - addiu $t0, $t0, 4 - b argcont -parsestr: - move $v0, $zero - move $t3, $t1 -3: - lb $t4, 0($t2) - lb $t5, 0($t3) - addiu $t2, $t2, 1 - addiu $t3, $t3, 1 - beq $t5, $zero, 1f - beq $t5, $t4, 3b - bne $t4, $zero, 1f - - addiu $t3, $t3, 0xffff -digcont: - lb $t5, 0($t3) - /* Substract '0' from digit. */ - addiu $t5, $t5, 0xffd0 - bltz $t5, 1f - addiu $t4, $t5, 0xfff7 - bgtz $t4, 1f - /* Multiply $v0 by 10 with bitshifts. */ - sll $v0, $v0, 1 - sll $t4, $v0, 2 - addu $v0, $v0, $t4 - addu $v0, $v0, $t5 - addiu $t3, $t3, 1 - b digcont -1: - jr $ra -busclockstr: .asciiz "busclock=" -cpuclockstr: .asciiz "cpuclock=" -memsizestr: .asciiz "memsize=" -highmemsizestr: .asciiz "highmemsize=" - .p2align 2 -argdone: -#endif - - /* Decompress the payload. */ - addiu $a0, $s0, GRUB_KERNEL_MACHINE_RAW_SIZE - BASE_ADDR - lui $a1, %hi(compressed) - addiu $a1, %lo(compressed) - lw $a2, (GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0) - move $s1, $a1 - - /* $a0 contains source compressed address, $a1 is destination, - $a2 is compressed size. FIXME: put LZMA here. Don't clober $s0, - $s1, $s2, $s3, $s4 and $s5. - On return $v0 contains uncompressed size. - */ - move $v0, $a2 -reloccont: - lb $t4, 0($a0) - sb $t4, 0($a1) - addiu $a1,$a1,1 - addiu $a0,$a0,1 - addiu $a2, 0xffff - bne $a2, $0, reloccont - - move $a0, $s1 - move $a1, $v0 - -#include "cache_flush.S" - - lui $t1, %hi(cont) - addiu $t1, %lo(cont) - - jr $t1 - . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE -compressed: . = _start + GRUB_KERNEL_MACHINE_PREFIX VARIABLE(grub_prefix) @@ -166,6 +57,8 @@ VARIABLE (grub_arch_highmemsize) .long 0 #endif cont: + /* Save our base. */ + move $s0, $ra #ifdef GRUB_MACHINE_MIPS_YEELOONG lui $t1, %hi(grub_arch_busclock) @@ -177,10 +70,8 @@ cont: #endif /* Move the modules out of BSS. */ - lui $t1, %hi(_start) - addiu $t1, %lo(_start) - lw $t2, (GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE - BASE_ADDR)($s0) - addu $t2, $t1, $t2 + lui $t2, %hi(_end) + addiu $t2, %lo(_end) lui $t1, %hi(_end) addiu $t1, %lo(_end) @@ -201,11 +92,11 @@ cont: modulesmovcont: lb $t4, 0($t2) sb $t4, 0($t1) - addiu $t1,$t1,0xffff - addiu $t2,$t2,0xffff - addiu $t3, 0xffff + addiu $t1, $t1, -1 + addiu $t3, $t3, -1 bne $t3, $0, modulesmovcont - + addiu $t2, $t2, -1 + /* Clean BSS. */ lui $t1, %hi(__bss_start) @@ -214,13 +105,14 @@ modulesmovcont: addiu $t2, %lo(_end) bsscont: sb $0,0($t1) - addiu $t1,$t1,1 - sltu $t3,$t1,$t2 + sltu $t3, $t1, $t2 bne $t3, $0, bsscont + addiu $t1, $t1, 1 li $sp, GRUB_MACHINE_MEMORY_STACK_HIGH lui $t1, %hi(grub_main) addiu $t1, %lo(grub_main) jr $t1 + nop diff --git a/grub-core/lib/mips/relocator_asm.S b/grub-core/lib/mips/relocator_asm.S index 3408b59e1..1d142a4f3 100644 --- a/grub-core/lib/mips/relocator_asm.S +++ b/grub-core/lib/mips/relocator_asm.S @@ -20,6 +20,9 @@ .p2align 4 /* force 16-byte alignment */ + .set noreorder + .set nomacro + VARIABLE (grub_relocator_forward_start) move $a0, $9 move $a1, $10 @@ -28,9 +31,9 @@ copycont1: lb $11,0($8) sb $11,0($9) addiu $8, $8, 1 - addiu $9, $9, 1 addiu $10, $10, -1 bne $10, $0, copycont1 + addiu $9, $9, 1 #include "../../kern/mips/cache_flush.S" @@ -49,9 +52,9 @@ copycont2: lb $11,0($8) sb $11,0($9) addiu $8, $8, -1 - addiu $9, $9, -1 addiu $10, $10, -1 bne $10, $0, copycont2 + addiu $9, $9, -1 #include "../../kern/mips/cache_flush.S" diff --git a/include/grub/offsets.h b/include/grub/offsets.h index 47eb6c9bd..8caa27c2f 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -102,13 +102,12 @@ #define GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN 32 -#define GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE 0x200 -#define GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE 0x8 -#define GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE 0xc -#define GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE 0x10 +#define GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE 0x8 +#define GRUB_KERNEL_MIPS_YEELOONG_UNCOMPRESSED_SIZE 0xc -#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE -#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE + 0x48 +#define GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE 0x08 +#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX 0x0c +#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END 0x54 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_EFI_PREFIX 0x8 @@ -158,6 +157,7 @@ #define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _TOTAL_MODULE_SIZE) #define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _KERNEL_IMAGE_SIZE) #define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _COMPRESSED_SIZE) +#define GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _UNCOMPRESSED_SIZE) #define GRUB_KERNEL_MACHINE_PREFIX GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _PREFIX) #define GRUB_KERNEL_MACHINE_PREFIX_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _PREFIX_END) diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index d798ad052..ee007a54b 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -248,13 +248,13 @@ struct image_target_desc image_targets[] = .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_YEELOONG_FLASH, - .flags = PLATFORM_FLAGS_NONE, + .flags = PLATFORM_FLAGS_LZMA, .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, - .raw_size = GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE, + .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, - .compressed_size = GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE, - .kernel_image_size = GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE, + .compressed_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, .install_dos_part = TARGET_NO_FIELD, @@ -268,13 +268,13 @@ struct image_target_desc image_targets[] = .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_YEELOONG_ELF, - .flags = PLATFORM_FLAGS_NONE, + .flags = PLATFORM_FLAGS_LZMA, .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, - .raw_size = GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE, + .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, - .compressed_size = GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE, - .kernel_image_size = GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE, + .compressed_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, .install_dos_part = TARGET_NO_FIELD, @@ -680,6 +680,41 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], = grub_host_to_target32 (-2); } + if (image_target->id == IMAGE_YEELOONG_FLASH + || image_target->id == IMAGE_YEELOONG_ELF) + { + char *full_img; + size_t full_size; + char *decompress_path, *decompress_img; + size_t decompress_size; + + decompress_path = grub_util_get_path (dir, "decompress.img"); + decompress_size = grub_util_get_image_size (decompress_path); + decompress_img = grub_util_read_image (decompress_path); + + *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE)) + = grub_host_to_target32 (core_size); + + *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_YEELOONG_UNCOMPRESSED_SIZE)) + = grub_host_to_target32 (kernel_size + total_module_size); + + full_size = core_size + decompress_size; + + full_img = xmalloc (full_size); + memset (full_img, 0, full_size); + + memcpy (full_img, decompress_img, decompress_size); + + memcpy (full_img + decompress_size, core_img, core_size); + + memset (full_img + decompress_size + core_size, 0, + full_size - (decompress_size + core_size)); + + free (core_img); + core_img = full_img; + core_size = full_size; + } + switch (image_target->id) { case IMAGE_I386_PC: