diff --git a/conf/mips.rmk b/conf/mips.rmk index 6ebd7d665..46b74d68f 100644 --- a/conf/mips.rmk +++ b/conf/mips.rmk @@ -140,4 +140,11 @@ pci_mod_SOURCES = bus/pci.c pci_mod_CFLAGS = $(COMMON_CFLAGS) pci_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For relocator.mod. +pkglib_MODULES += relocator.mod +relocator_mod_SOURCES = lib/$(target_cpu)/relocator.c lib/$(target_cpu)/relocator_asm.S +relocator_mod_CFLAGS = $(COMMON_CFLAGS) +relocator_mod_ASFLAGS = $(COMMON_ASFLAGS) +relocator_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/include/grub/mips/relocator.h b/include/grub/mips/relocator.h new file mode 100644 index 000000000..838ef832f --- /dev/null +++ b/include/grub/mips/relocator.h @@ -0,0 +1,39 @@ +/* + * 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 . + */ + +#ifndef GRUB_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 + +#include +#include + +struct grub_relocator32_state +{ + /* gpr[0] is ignored since it's hardwired to 0. */ + grub_uint32_t gpr[32]; + /* Register holding target $pc. */ + int jumpreg; +}; + +void *grub_relocator32_alloc (grub_size_t size); +grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, + struct grub_relocator32_state state); +void *grub_relocator32_realloc (void *relocator, grub_size_t size); +void grub_relocator32_free (void *relocator); + +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/kern/mips/qemu-mipssim/startup.S b/kern/mips/qemu-mipssim/startup.S index 19de4779d..36c5fabd7 100644 --- a/kern/mips/qemu-mipssim/startup.S +++ b/kern/mips/qemu-mipssim/startup.S @@ -49,7 +49,7 @@ bsscont: sb $0,0($t1) addiu $t1,$t1,1 sltu $t3,$t1,$t2 - bne $3, $0, bsscont + bne $t3, $t0, bsscont li $sp, GRUB_MACHINE_MEMORY_STACK_HIGH b grub_main \ No newline at end of file diff --git a/lib/mips/relocator.c b/lib/mips/relocator.c new file mode 100644 index 000000000..4ec7f6c08 --- /dev/null +++ b/lib/mips/relocator.c @@ -0,0 +1,102 @@ +/* + * 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 +#include + +#include + +/* Remark: doesn't work with source outside of 4G. + Use relocator64 in this case. + */ + +extern grub_uint8_t grub_relocator32_forward_start; +extern grub_uint8_t grub_relocator32_forward_end; +extern grub_uint8_t grub_relocator32_backward_start; +extern grub_uint8_t grub_relocator32_backward_end; + +#define REGW_SIZEOF (2 * sizeof (grub_uint32_t)) +#define JUMP_SIZEOF (sizeof (grub_uint32_t)) + +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator32_##x##_end \ + - &grub_relocator32_##x##_start) +#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ + + REGW_SIZEOF * (31 + 3) + JUMP_SIZEOF) +#define RELOCATOR_ALIGN 16 + +#define PREFIX(x) grub_relocator32_ ## x + +static void +write_reg (int regn, grub_uint32_t val, void **target) +{ + /* lui $r, (val+0x8000). */ + *(grub_uint32_t *) *target = ((0x3c00 | regn) << 16) | ((val + 0x8000) >> 16); + *target = ((grub_uint32_t *) *target) + 1; + /* addiu $r, $r, val. */ + *(grub_uint32_t *) *target = (((0x2400 | regn << 5 | regn) << 16) + | ((val + 0x8000) >> 16)); + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_jump (int regn, void **target) +{ + /* j $r. */ + *(grub_uint32_t *) *target = (regn<<21) | 0x8; + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_call_relocator_bw (void *ptr0, void *src, grub_uint32_t dest, + grub_size_t size, struct grub_relocator32_state state) +{ + void *ptr = ptr0; + int i; + write_reg (1, (grub_uint32_t) src, &ptr); + write_reg (2, dest, &ptr); + write_reg (3, size, &ptr); + grub_memcpy (ptr, &grub_relocator32_backward_start, + RELOCATOR_SRC_SIZEOF (backward)); + for (i = 1; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (state.jumpreg, &ptr); + ((void (*) ())ptr0) (); +} + +static void +write_call_relocator_fw (void *ptr0, void *src, grub_uint32_t dest, + grub_size_t size, struct grub_relocator32_state state) +{ + void *ptr = ptr0; + int i; + write_reg (1, (grub_uint32_t) src, &ptr); + write_reg (2, dest, &ptr); + write_reg (3, size, &ptr); + grub_memcpy (ptr, &grub_relocator32_forward_start, + RELOCATOR_SRC_SIZEOF (forward)); + for (i = 1; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (state.jumpreg, &ptr); + ((void (*) ())ptr0) (); +} + +#include "../relocator.c" diff --git a/lib/mips/relocator_asm.S b/lib/mips/relocator_asm.S new file mode 100644 index 000000000..607a46303 --- /dev/null +++ b/lib/mips/relocator_asm.S @@ -0,0 +1,50 @@ +/* + * 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 + +#ifdef BACKWARD +#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_backward_ ## x) +#else +#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_forward_ ## x) +#endif + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE (grub_relocator32_forward_start) +copycont1: + lb $4,0($1) + sb $4,0($2) + addiu $3, $3, 0xffff + subu $4,$3,$0 + bne $4, $0, copycont1 +VARIABLE (grub_relocator32_forward_end) + +VARIABLE (grub_relocator32_backward_start) + addu $2, $2, $3 + addu $1, $1, $3 + /* Backward movsl is implicitly off-by-one. compensate that. */ + addiu $2, $2, 0xffff + addiu $1, $1, 0xffff +copycont2: + lb $4,0($1) + sb $4,0($2) + addiu $3, 0xffff + subu $4,$3,$0 + bne $4, $0, copycont2 +VARIABLE (grub_relocator32_backward_end)