Index: arch/ppc32/loader/Makefile
===================================================================
--- arch/ppc32/loader/Makefile	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/Makefile	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -66,5 +66,5 @@
 
 image.boot: depend $(OBJECTS) kernel.o
-	$(LD) -no-check-sections -N -T _link.ld -Map map $(OBJECTS) kernel.o -o $@
+	$(LD) -no-check-sections -N -T _link.ld $(OBJECTS) kernel.o -o $@
 
 depend:
@@ -75,5 +75,5 @@
 
 kernel.o: $(KERNEL)
-	$(OBJCOPY) -I binary -O elf32-powerpc -B powerpc $(KERNEL) $@
+	$(OBJCOPY) -I binary -O elf32-powerpc -B powerpc --rename-section .data=.image $(KERNEL) $@
 
 %.o: %.S
Index: arch/ppc32/loader/_link.ld
===================================================================
--- arch/ppc32/loader/_link.ld	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/_link.ld	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -8,7 +8,7 @@
 
 SECTIONS {
-	.image 0x10000000: AT (0) { 
-		*(BOOTSTRAP)
-		*(REALMODE)
+	.boot 0x10000000: AT (0) { 
+		*(BOOTSTRAP);
+		*(REALMODE);
 		*(.text);
 		
@@ -22,3 +22,7 @@
 		*(COMMON); 		/* global variables */
 	}
+	
+	.image 0x10000000+SIZEOF(.boot): AT (SIZEOF(.boot)) SUBALIGN(4096) { 
+		*(.image);
+	}
 }
Index: arch/ppc32/loader/asm.S
===================================================================
--- arch/ppc32/loader/asm.S	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/asm.S	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -27,4 +27,5 @@
 #
 
+#include "asm.h"
 #include "regname.h"
 
@@ -36,197 +37,105 @@
 .text
 
-.global memsetb
-.global memcpy
-.global flush_instruction_cache
+.global halt
 .global jump_to_kernel
 
-memsetb:
-	rlwimi r5, r5, 8, 16, 23
-	rlwimi r5, r5, 16, 0, 15
-	
-	addi r14, r3, -4
-	
-	cmplwi 0, r4, 4
-	blt 7f
-	
-	stwu r5, 4(r14)
-	beqlr
-	
-	andi. r15, r14, 3
-	add r4, r15, r4
-	subf r14, r15, r14
-	srwi r15, r4, 2
-	mtctr r15
-	
-	bdz 6f
-	
-	1:
-		stwu r5, 4(r14)
-		bdnz 1b
-	
-	6:
-	
-	andi. r4, r4, 3
-	
-	7:
-	
-	cmpwi 0, r4, 0
-	beqlr
-	
-	mtctr r4
-	addi r6, r6, 3
-	
-	8:
-	
-	stbu r5, 1(r14)
-	bdnz 8b
-	
-	blr
-
-memcpy:
-	srwi. r7, r5, 3
-	addi r6, r3, -4
-	addi r4, r4, -4
-	beq	2f
-	
-	andi. r0, r6, 3
-	mtctr r7
-	bne 5f
-	
-	1:
-	
-	lwz r7, 4(r4)
-	lwzu r8, 8(r4)
-	stw r7, 4(r6)
-	stwu r8, 8(r6)
-	bdnz 1b
-	
-	andi. r5, r5, 7
-	
-	2:
-	
-	cmplwi 0, r5, 4
-	blt 3f
-	
-	lwzu r0, 4(r4)
-	addi r5, r5, -4
-	stwu r0, 4(r6)
-	
-	3:
-	
-	cmpwi 0, r5, 0
-	beqlr
-	mtctr r5
-	addi r4, r4, 3
-	addi r6, r6, 3
-	
-	4:
-	
-	lbzu r0, 1(r4)
-	stbu r0, 1(r6)
-	bdnz 4b
-	blr
-	
-	5:
-	
-	subfic r0, r0, 4
-	mtctr r0
-	
-	6:
-	
-	lbz r7, 4(r4)
-	addi r4, r4, 1
-	stb r7, 4(r6)
-	addi r6, r6, 1
-	bdnz 6b
-	subf r5, r0, r5
-	rlwinm. r7, r5, 32-3, 3, 31
-	beq 2b
-	mtctr r7
-	b 1b
-	
-flush_instruction_cache:
-
-	# Flush data cache
-	
-	lis r3, flush_buffer@h
-	ori r3, r3, flush_buffer@l
-	li r4, L1_CACHE_LINES
-	mtctr r4
-	
-	0:
-	
-	lwz r4, 0(r3)
-	addi r3, r3, L1_CACHE_BYTES
-	bdnz 0b
-	
-	# Invalidate instruction cache
-	
-	li r3, 0
-	ori	r3, r3, (hid0_ice | hid0_dce | hid0_icfi | hid0_dci)
-	mfspr r4, hid0
-	or r5, r4, r3
-	isync
-	mtspr hid0, r5
-	sync
-	isync
-	
-	# Enable instruction cache
-	
-	ori	r5, r4, hid0_ice
-	mtspr hid0, r5
-	sync
-	isync
-	blr
+halt:
+	b halt
 
 jump_to_kernel:
 	
-	# r3 = kernel_start (va)
-	# r4 = memmap (pa)
-	# r5 = real_mode (pa)
+	# r3 = memmap (pa)
+	# r4 = trans (pa)
+	# r5 = number of kernel pages
+	# r6 = real_mode (pa)
 	
-	mtspr srr0, r5
+	mtspr srr0, r6
 	
 	# jumps to real_mode
 	
-	mfmsr r5
-	lis r6, ~0@h
-	ori r6, r6, ~(msr_ir | msr_dr)@l
-	and r5, r5, r6
-	mtspr srr1, r5
+	mfmsr r31
+	lis r30, ~0@h
+	ori r30, r30, ~(msr_ir | msr_dr)@l
+	and r31, r31, r30
+	mtspr srr1, r31
 	rfi
 
 .section REALMODE
-.align 12
+.align PAGE_WIDTH
 .global real_mode
 
 real_mode:
-
+	
+	# copy kernel to proper location
+	#
+	# r4 = trans (pa)
+	# r5 = number of kernel pages
+	
+	li r31, PAGE_SIZE >> 3
+	li r30, 0
+	
+	page_copy:
+		
+		cmpwi r5, 0
+		beq copy_end
+		
+		# copy single page
+		
+		mtctr r31
+		lwz r29, 0(r4)
+		
+		copy_loop:
+			
+			lwz r28, 0(r29)
+			stw r28, 0(r30)
+			
+			addi r29, r29, 4
+			addi r30, r30, 4
+			
+			bdnz copy_loop
+		
+		subi r5, r5, 1
+		addi r4, r4, 4
+		b page_copy
+	
+	copy_end:
+		
 	# fill segment registers
 
-	li r5, 16
-	mtctr r5
-	li r5, 0
-	li r6, 0
+	li r31, 16
+	mtctr r31
+	li r31, 0
+	li r30, 0x2000
 	
 	seg_fill:
 	
-		mtsrin r6, r5
-		addis r5, r5, 0x1000    # move to next SR
-		addis r6, r6, 0x10      # add 256 MB, move to next SR
+		mtsrin r30, r31
+		
+		addis r31, r31, 0x1000    # add 256 MB
+		addi  r30, r30, 0x111     # move to next SR
 		
 		bdnz seg_fill
 	
-	# bootstrap kernel
+	# create identity mapping
+	
+	tlbia
+	
+	# start the kernel
 	#
-	# r3 = kernel_start (va)
-	# r4 = memmap (pa)       -> r10
+	# r3 = memmap (pa)
 	
-	mtspr srr0, r3
+	lis r31, KERNEL_START_ADDR@ha
+	addi r31, r31, KERNEL_START_ADDR@l
 	
-	mfmsr r5
-	ori r5, r5, (msr_ir | msr_dr)@l
-	mtspr srr1, r5
+	mtspr srr0, r31
 	
-	mr r10, r4
+	mfmsr r31
+	ori r31, r31, (msr_ir | msr_dr)@l
+	mtspr srr1, r31
+	
 	rfi
+
+.align PAGE_WIDTH
+.global trans
+trans:
+	.space (TRANS_SIZE * TRANS_ITEM_SIZE)
Index: arch/ppc32/loader/asm.h
===================================================================
--- arch/ppc32/loader/asm.h	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/asm.h	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -30,9 +30,21 @@
 #define __ASM_H__
 
-void flush_instruction_cache(void);
-void jump_to_kernel(void *code, void *memmap, void *real_mode) __attribute__((noreturn));
-void real_mode(void *code, void *memmap);
+#define PAGE_SIZE 4096
+#define PAGE_WIDTH 12
 
-#define memcpy(dst, src, cnt)  __builtin_memcpy((dst), (src), (cnt))
+#define TRANS_SIZE 1024
+#define TRANS_ITEM_SIZE 4
+
+#define KERNEL_START_ADDR 0x80002000
+
+#ifndef __ASM__
+
+extern void *trans[TRANS_SIZE];
+
+extern void halt();
+extern void jump_to_kernel(void *memmap, void *trans, unsigned int cnt, void *real_mode) __attribute__((noreturn));
+extern void real_mode();
 
 #endif
+
+#endif
Index: arch/ppc32/loader/main.c
===================================================================
--- arch/ppc32/loader/main.c	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/main.c	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -31,12 +31,19 @@
 #include "asm.h"
 
-#define KERNEL_PHYSICAL_ADDRESS 0x0000
-#define KERNEL_VIRTUAL_ADDRESS 0x80000000
-#define KERNEL_BOOT_OFFSET 0x2000
-#define KERNEL_START &_binary_____________kernel_kernel_bin_start
-#define KERNEL_END &_binary_____________kernel_kernel_bin_end
+#define KERNEL_START ((void *) &_binary_____________kernel_kernel_bin_start)
+#define KERNEL_END ((void *) &_binary_____________kernel_kernel_bin_end)
 #define KERNEL_SIZE ((unsigned int) KERNEL_END - (unsigned int) KERNEL_START)
 
 memmap_t memmap;
+
+
+static void check_align(const void *addr, const char *desc)
+{
+	if ((unsigned int) addr % PAGE_SIZE != 0) {
+		printf("Error: %s not on page boundary\n", desc);
+		halt();
+	}
+}
+
 
 void bootstrap(void)
@@ -44,6 +51,17 @@
 	printf("\nHelenOS PPC Bootloader\n");
 	
-	void *phys = ofw_translate(&start);
-	printf("loaded at %L (physical %L)\n", &start, phys);
+	check_align(KERNEL_START, "Kernel image");
+	check_align(&real_mode, "Bootstrap trampoline");
+	check_align(&trans, "Translation table");
+	
+	void *real_mode_pa = ofw_translate(&real_mode);
+	void *trans_pa = ofw_translate(&trans);
+	void *memmap_pa = ofw_translate(&memmap);
+	
+	printf("Memory statistics\n");
+	printf(" kernel image         at %L (size %d bytes)\n", KERNEL_START, KERNEL_SIZE);
+	printf(" memory map           at %L (physical %L)\n", &memmap, memmap_pa);
+	printf(" bootstrap trampoline at %L (physical %L)\n", &real_mode, real_mode_pa);
+	printf(" translation table    at %L (physical %L)\n", &trans, trans_pa);
 	
 	if (!ofw_memmap(&memmap)) {
@@ -51,23 +69,18 @@
 		halt();
 	}
-	printf("total memory %d MB\n", memmap.total >> 20);
+	printf("Total memory %d MB\n", memmap.total >> 20);
 	
-	if (ofw_map((void *) KERNEL_PHYSICAL_ADDRESS, (void *) KERNEL_VIRTUAL_ADDRESS, KERNEL_SIZE + KERNEL_BOOT_OFFSET, 0) != 0) {
-		printf("Unable to map kernel memory at %L (physical %L)\n", KERNEL_VIRTUAL_ADDRESS, KERNEL_PHYSICAL_ADDRESS);
-		halt();
+	unsigned int addr;
+	unsigned int pages;
+	for (addr = 0, pages = 0; addr < KERNEL_SIZE; addr += PAGE_SIZE, pages++) {
+		void *pa = ofw_translate(KERNEL_START + addr);
+		if ((unsigned int) pa < KERNEL_SIZE) {
+			printf("Error: Kernel image overlaps kernel physical area\n");
+			halt();
+		}
+		trans[addr >> PAGE_WIDTH] = pa;
 	}
-	printf("kernel memory mapped at %L (physical %L, size %d bytes)\n", KERNEL_VIRTUAL_ADDRESS, KERNEL_PHYSICAL_ADDRESS, KERNEL_SIZE);
-	// FIXME: relocate the kernel in real mode
-	memcpy((void *) KERNEL_VIRTUAL_ADDRESS, KERNEL_START, KERNEL_SIZE);
 	
-	// FIXME: proper hardware detection & mapping
-	ofw_map((void *) 0x84000000, (void *) 0xf0000000, 0x01000000, 0);
-	ofw_map((void *) 0x80816000, (void *) 0xf2000000, 0x00018000, 0);
-	
-	void *tramp = ofw_translate(&real_mode);
-	printf("bootstrap trampoline at %L (physical %L)\n", &real_mode, tramp);
 	printf("Booting the kernel...\n");
-	
-	flush_instruction_cache();
-	jump_to_kernel((void *) KERNEL_VIRTUAL_ADDRESS + KERNEL_BOOT_OFFSET, ofw_translate(&memmap), tramp);
+	jump_to_kernel(memmap_pa, trans_pa, pages, real_mode_pa);
 }
Index: arch/ppc32/loader/ofw.c
===================================================================
--- arch/ppc32/loader/ofw.c	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/ofw.c	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -28,4 +28,5 @@
  
 #include "ofw.h"
+#include "asm.h"
 #include "printf.h"
 
@@ -114,10 +115,4 @@
 
 
-void halt(void)
-{
-	ofw_call("exit", 0, 0);
-}
-
-
 void ofw_write(const char *str, const int len)
 {
@@ -132,10 +127,4 @@
 {
 	return (void *) ofw_call("call-method", 7, 1, "translate", ofw_mmu, virt, 0, 0, 0, 0);
-}
-
-
-int ofw_map(const void *phys, const void *virt, const int size, const int mode)
-{
-	return ofw_call("call-method", 6, 1, "map", ofw_mmu, mode, size, virt, phys);
 }
 
Index: arch/ppc32/loader/ofw.h
===================================================================
--- arch/ppc32/loader/ofw.h	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/ofw.h	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -54,10 +54,7 @@
 
 extern void init(void);
-extern void halt(void);
-
 extern void ofw_write(const char *str, const int len);
 
 extern void *ofw_translate(const void *virt);
-extern int ofw_map(const void *phys, const void *virt, const int size, const int mode);
 extern int ofw_memmap(memmap_t *map);
 
Index: arch/ppc32/loader/regname.h
===================================================================
--- arch/ppc32/loader/regname.h	(revision d89c554b30294aeff346a93549727d4ae8da166f)
+++ arch/ppc32/loader/regname.h	(revision 01cb2103560f14deeefc9e262f1da96c5ff69c16)
@@ -182,4 +182,5 @@
 #define ctr		9
 #define	dec		22
+#define	sdr1	25
 #define	srr0	26
 #define srr1	27
