/boot/trunk/arch/ppc32/loader/asm.S |
---|
26,6 → 26,7 |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
#include "asm.h" |
#include "regname.h" |
.data |
35,198 → 36,106 |
.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 |
halt: |
b halt |
addi r14, r3, -4 |
jump_to_kernel: |
cmplwi 0, r4, 4 |
blt 7f |
# r3 = memmap (pa) |
# r4 = trans (pa) |
# r5 = number of kernel pages |
# r6 = real_mode (pa) |
stwu r5, 4(r14) |
beqlr |
mtspr srr0, r6 |
andi. r15, r14, 3 |
add r4, r15, r4 |
subf r14, r15, r14 |
srwi r15, r4, 2 |
mtctr r15 |
# jumps to real_mode |
bdz 6f |
mfmsr r31 |
lis r30, ~0@h |
ori r30, r30, ~(msr_ir | msr_dr)@l |
and r31, r31, r30 |
mtspr srr1, r31 |
rfi |
1: |
stwu r5, 4(r14) |
bdnz 1b |
.section REALMODE |
.align PAGE_WIDTH |
.global real_mode |
6: |
real_mode: |
andi. r4, r4, 3 |
# copy kernel to proper location |
# |
# r4 = trans (pa) |
# r5 = number of kernel pages |
7: |
li r31, PAGE_SIZE >> 3 |
li r30, 0 |
cmpwi 0, r4, 0 |
beqlr |
page_copy: |
mtctr r4 |
addi r6, r6, 3 |
cmpwi r5, 0 |
beq copy_end |
8: |
# copy single page |
stbu r5, 1(r14) |
bdnz 8b |
mtctr r31 |
lwz r29, 0(r4) |
blr |
copy_loop: |
memcpy: |
srwi. r7, r5, 3 |
addi r6, r3, -4 |
addi r4, r4, -4 |
beq 2f |
lwz r28, 0(r29) |
stw r28, 0(r30) |
andi. r0, r6, 3 |
mtctr r7 |
bne 5f |
addi r29, r29, 4 |
addi r30, r30, 4 |
1: |
bdnz copy_loop |
lwz r7, 4(r4) |
lwzu r8, 8(r4) |
stw r7, 4(r6) |
stwu r8, 8(r6) |
bdnz 1b |
subi r5, r5, 1 |
addi r4, r4, 4 |
b page_copy |
andi. r5, r5, 7 |
copy_end: |
2: |
# fill segment registers |
cmplwi 0, r5, 4 |
blt 3f |
li r31, 16 |
mtctr r31 |
li r31, 0 |
li r30, 0x2000 |
lwzu r0, 4(r4) |
addi r5, r5, -4 |
stwu r0, 4(r6) |
seg_fill: |
3: |
mtsrin r30, r31 |
cmpwi 0, r5, 0 |
beqlr |
mtctr r5 |
addi r4, r4, 3 |
addi r6, r6, 3 |
addis r31, r31, 0x1000 # add 256 MB |
addi r30, r30, 0x111 # move to next SR |
4: |
bdnz seg_fill |
lbzu r0, 1(r4) |
stbu r0, 1(r6) |
bdnz 4b |
blr |
# create identity mapping |
5: |
tlbia |
subfic r0, r0, 4 |
mtctr r0 |
# start the kernel |
# |
# r3 = memmap (pa) |
6: |
lis r31, KERNEL_START_ADDR@ha |
addi r31, r31, KERNEL_START_ADDR@l |
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 |
mtspr srr0, r31 |
flush_instruction_cache: |
mfmsr r31 |
ori r31, r31, (msr_ir | msr_dr)@l |
mtspr srr1, r31 |
# 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 |
jump_to_kernel: |
# r3 = kernel_start (va) |
# r4 = memmap (pa) |
# r5 = real_mode (pa) |
mtspr srr0, r5 |
# 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 |
rfi |
.section REALMODE |
.align 12 |
.global real_mode |
real_mode: |
# fill segment registers |
li r5, 16 |
mtctr r5 |
li r5, 0 |
li r6, 0 |
seg_fill: |
mtsrin r6, r5 |
addis r5, r5, 0x1000 # move to next SR |
addis r6, r6, 0x10 # add 256 MB, move to next SR |
bdnz seg_fill |
# bootstrap kernel |
# |
# r3 = kernel_start (va) |
# r4 = memmap (pa) -> r10 |
mtspr srr0, r3 |
mfmsr r5 |
ori r5, r5, (msr_ir | msr_dr)@l |
mtspr srr1, r5 |
mr r10, r4 |
rfi |
.align PAGE_WIDTH |
.global trans |
trans: |
.space (TRANS_SIZE * TRANS_ITEM_SIZE) |
/boot/trunk/arch/ppc32/loader/ofw.h |
---|
53,12 → 53,9 |
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); |
#endif |
/boot/trunk/arch/ppc32/loader/regname.h |
---|
181,6 → 181,7 |
#define lr 8 |
#define ctr 9 |
#define dec 22 |
#define sdr1 25 |
#define srr0 26 |
#define srr1 27 |
#define sprg0 272 |
/boot/trunk/arch/ppc32/loader/main.c |
---|
30,44 → 30,57 |
#include "printf.h" |
#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) |
{ |
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)) { |
printf("Unable to get memory map\n"); |
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); |
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(); |
} |
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); |
trans[addr >> PAGE_WIDTH] = pa; |
} |
// 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); |
} |
/boot/trunk/arch/ppc32/loader/asm.h |
---|
29,10 → 29,22 |
#ifndef __ASM_H__ |
#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 |
/boot/trunk/arch/ppc32/loader/_link.ld |
---|
7,9 → 7,9 |
ENTRY(start) |
SECTIONS { |
.image 0x10000000: AT (0) { |
*(BOOTSTRAP) |
*(REALMODE) |
.boot 0x10000000: AT (0) { |
*(BOOTSTRAP); |
*(REALMODE); |
*(.text); |
*(.rodata); |
21,4 → 21,8 |
*(.bss); /* uninitialized static variables */ |
*(COMMON); /* global variables */ |
} |
.image 0x10000000+SIZEOF(.boot): AT (SIZEOF(.boot)) SUBALIGN(4096) { |
*(.image); |
} |
} |
/boot/trunk/arch/ppc32/loader/ofw.c |
---|
27,6 → 27,7 |
*/ |
#include "ofw.h" |
#include "asm.h" |
#include "printf.h" |
#define MAX_OFW_ARGS 10 |
113,12 → 114,6 |
} |
void halt(void) |
{ |
ofw_call("exit", 0, 0); |
} |
void ofw_write(const char *str, const int len) |
{ |
if (ofw_stdout == 0) |
134,12 → 129,6 |
} |
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); |
} |
int ofw_memmap(memmap_t *map) |
{ |
int i; |
/boot/trunk/arch/ppc32/loader/Makefile |
---|
65,7 → 65,7 |
-include Makefile.depend |
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: |
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null |
74,7 → 74,7 |
-rm -f $(OBJECTS) image.boot kernel.o Makefile.depend |
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 |
$(CC) $(DEFS) $(CFLAGS) -D__ASM__ -c $< -o $@ |