diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index 2a3334a4f..91f705bb4 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -100,4 +100,11 @@ lsmmap_mod_SOURCES = commands/lsmmap.c
lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For relocator.mod.
+pkglib_MODULES += relocator.mod
+relocator_mod_SOURCES = lib/$(target_cpu)/relocator.c lib/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/powerpc/relocator.h b/include/grub/powerpc/relocator.h
new file mode 100644
index 000000000..c2780bbca
--- /dev/null
+++ b/include/grub/powerpc/relocator.h
@@ -0,0 +1,37 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2010 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
+#include
+
+#define GRUB_PPC_JUMP_REGISTER 31
+
+struct grub_relocator32_state
+{
+ grub_uint32_t gpr[32];
+};
+
+grub_err_t
+grub_relocator32_boot (struct grub_relocator *rel,
+ struct grub_relocator32_state state);
+
+#endif /* ! GRUB_RELOCATOR_CPU_HEADER */
diff --git a/kern/powerpc/cache.S b/kern/powerpc/cache.S
index da982afa0..d85e68d42 100644
--- a/kern/powerpc/cache.S
+++ b/kern/powerpc/cache.S
@@ -1,7 +1,7 @@
/* cache.S - Flush the processor cache for a specific region. */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2004,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2004,2007,2010 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
@@ -17,32 +17,10 @@
* along with GRUB. If not, see .
*/
-#define CACHE_LINE_BYTES 32
-
.text
.align 2
.globl grub_arch_sync_caches
grub_arch_sync_caches:
- /* `address' may not be CACHE_LINE_BYTES-aligned. */
- andi. 6, 3, CACHE_LINE_BYTES - 1 /* Find the misalignment. */
- add 4, 4, 6 /* Adjust `size' to compensate. */
-
- /* Force the dcache lines to memory. */
- li 5, 0
-1: dcbst 5, 3
- addi 5, 5, CACHE_LINE_BYTES
- cmpw 5, 4
- blt 1b
- sync /* Force all dcbsts to complete. */
-
- /* Invalidate the icache lines. */
- li 5, 0
-1: icbi 5, 3
- addi 5, 5, CACHE_LINE_BYTES
- cmpw 5, 4
- blt 1b
- sync /* Force all icbis to complete. */
- isync /* Discard partially executed instructions that were
- loaded from the invalid icache. */
+#include "cache_flush.S"
blr
diff --git a/kern/powerpc/cache_flush.S b/kern/powerpc/cache_flush.S
new file mode 100644
index 000000000..1410f78b1
--- /dev/null
+++ b/kern/powerpc/cache_flush.S
@@ -0,0 +1,43 @@
+/* cache.S - Flush the processor cache for a specific region. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2004,2007,2010 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 .
+ */
+
+#undef CACHE_LINE_BYTES
+#define CACHE_LINE_BYTES 32
+
+ /* `address' may not be CACHE_LINE_BYTES-aligned. */
+ andi. 6, 3, CACHE_LINE_BYTES - 1 /* Find the misalignment. */
+ add 4, 4, 6 /* Adjust `size' to compensate. */
+
+ /* Force the dcache lines to memory. */
+ li 5, 0
+1: dcbst 5, 3
+ addi 5, 5, CACHE_LINE_BYTES
+ cmpw 5, 4
+ blt 1b
+ sync /* Force all dcbsts to complete. */
+
+ /* Invalidate the icache lines. */
+ li 5, 0
+1: icbi 5, 3
+ addi 5, 5, CACHE_LINE_BYTES
+ cmpw 5, 4
+ blt 1b
+ sync /* Force all icbis to complete. */
+ isync /* Discard partially executed instructions that were
+ loaded from the invalid icache. */
diff --git a/lib/powerpc/relocator.c b/lib/powerpc/relocator.c
new file mode 100644
index 000000000..9f5fc1c7f
--- /dev/null
+++ b/lib/powerpc/relocator.c
@@ -0,0 +1,141 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2010 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
+
+#include
+#include
+
+extern grub_uint8_t grub_relocator_forward_start;
+extern grub_uint8_t grub_relocator_forward_end;
+extern grub_uint8_t grub_relocator_backward_start;
+extern grub_uint8_t grub_relocator_backward_end;
+
+#define REGW_SIZEOF (2 * sizeof (grub_uint32_t))
+#define JUMP_SIZEOF (sizeof (grub_uint32_t))
+
+#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \
+ - &grub_relocator_##x##_start)
+#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \
+ + REGW_SIZEOF * 3)
+grub_size_t grub_relocator_align = sizeof (grub_uint32_t);
+grub_size_t grub_relocator_forward_size;
+grub_size_t grub_relocator_backward_size;
+grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF;
+
+void
+grub_cpu_relocator_init (void)
+{
+ grub_relocator_forward_size = RELOCATOR_SIZEOF(forward);
+ grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
+}
+
+static void
+write_reg (int regn, grub_uint32_t val, void **target)
+{
+ /* lis r, val >> 16 */
+ *(grub_uint32_t *) *target =
+ ((0x3c00 | (regn << 5)) << 16) | (val >> 16);
+ *target = ((grub_uint32_t *) *target) + 1;
+ /* ori r, r, val & 0xffff. */
+ *(grub_uint32_t *) *target = (((0x6000 | regn << 5 | regn) << 16)
+ | (val & 0xffff));
+ *target = ((grub_uint32_t *) *target) + 1;
+}
+
+static void
+write_jump (void **target)
+{
+ /* blr. */
+ *(grub_uint32_t *) *target = 0x4e800020;
+ *target = ((grub_uint32_t *) *target) + 1;
+}
+
+void
+grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
+{
+ write_reg (GRUB_PPC_JUMP_REGISTER, addr, &rels);
+ write_jump (&rels);
+}
+
+void
+grub_cpu_relocator_backward (void *ptr0, void *src, void *dest,
+ grub_size_t size)
+{
+ void *ptr = ptr0;
+ write_reg (8, (grub_uint32_t) src, &ptr);
+ write_reg (9, (grub_uint32_t) dest, &ptr);
+ write_reg (10, (grub_uint32_t) size, &ptr);
+ grub_memcpy (ptr, &grub_relocator_backward_start,
+ RELOCATOR_SRC_SIZEOF (backward));
+}
+
+void
+grub_cpu_relocator_forward (void *ptr0, void *src, void *dest,
+ grub_size_t size)
+{
+ void *ptr = ptr0;
+ write_reg (8, (grub_uint32_t) src, &ptr);
+ write_reg (9, (grub_uint32_t) dest, &ptr);
+ write_reg (10, (grub_uint32_t) size, &ptr);
+ grub_memcpy (ptr, &grub_relocator_forward_start,
+ RELOCATOR_SRC_SIZEOF (forward));
+}
+
+grub_err_t
+grub_relocator32_boot (struct grub_relocator *rel,
+ struct grub_relocator32_state state)
+{
+ grub_addr_t target;
+ void *src, *ptr;
+ grub_err_t err;
+ grub_addr_t relst;
+ grub_size_t relsize;
+ grub_size_t stateset_size = 32 * REGW_SIZEOF + JUMP_SIZEOF;
+ unsigned i;
+
+ err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0,
+ (0xffffffff - stateset_size)
+ + 1, stateset_size,
+ sizeof (grub_uint32_t),
+ GRUB_RELOCATOR_PREFERENCE_NONE);
+ if (err)
+ return err;
+
+ ptr = src;
+ for (i = 0; i < 32; i++)
+ write_reg (i, state.gpr[i], &ptr);
+ write_jump (&ptr);
+
+ err = grub_relocator_prepare_relocs (rel, target, &relst, &relsize);
+ if (err)
+ return err;
+
+ grub_arch_sync_caches ((void *) relst, relsize);
+
+ ((void (*) (void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
diff --git a/lib/powerpc/relocator_asm.S b/lib/powerpc/relocator_asm.S
new file mode 100644
index 000000000..355e9c8b4
--- /dev/null
+++ b/lib/powerpc/relocator_asm.S
@@ -0,0 +1,60 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2010 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
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE (grub_relocator_forward_start)
+ mr 3, 9
+ mr 4, 10
+
+copycont1:
+ lbz 11,0(8)
+ stb 11,0(9)
+ addi 8, 8, 0x1
+ addi 9, 9, 0x1
+ addi 10, 10, -1
+ cmpwi 10, 0
+ bne copycont1
+
+#include "../../kern/powerpc/cache_flush.S"
+
+VARIABLE (grub_relocator_forward_end)
+
+VARIABLE (grub_relocator_backward_start)
+ mr 3, 9
+ mr 4, 10
+
+ add 9, 9, 10
+ add 8, 8, 10
+ /* Backward movsl is implicitly off-by-one. compensate that. */
+ addi 9, 9, -1
+ addi 8, 8, -1
+copycont2:
+ lbz 11,0(8)
+ stb 11,0(9)
+ addi 8, 8, -1
+ addi 9, 9, -1
+ addi 10, 10, -1
+ cmpwi 10, 0
+ bne copycont2
+
+#include "../../kern/powerpc/cache_flush.S"
+
+VARIABLE (grub_relocator_backward_end)