From b409c9694eb5170a824bb1e646ae641a8d75030c Mon Sep 17 00:00:00 2001 From: dhewg Date: Wed, 8 Apr 2009 16:30:32 +0200 Subject: [PATCH] IPC to boot in-mem PPC ELF, with some test code. --- boot2.h | 4 +++- ipc.c | 4 ++++ ipc.h | 3 +++ main.c | 2 +- powerpc.c | 17 ++++++++++++++ powerpc.h | 5 +++- powerpc_elf.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++--- powerpc_elf.h | 7 +++--- 8 files changed, 97 insertions(+), 9 deletions(-) diff --git a/boot2.h b/boot2.h index 9cd394f..3742335 100644 --- a/boot2.h +++ b/boot2.h @@ -1,8 +1,10 @@ #ifndef __BOOT2_H__ #define __BOOT2_H__ -void boot2_ipc(volatile ipc_request *req); +#include "ipc.h" + int boot2_run(u32 tid_hi, u32 tid_lo); void boot2_init(); +void boot2_ipc(volatile ipc_request *req); #endif diff --git a/ipc.c b/ipc.c index 92ee395..8368352 100644 --- a/ipc.c +++ b/ipc.c @@ -10,6 +10,7 @@ #include "sdhc.h" #include "crypto.h" #include "boot2.h" +#include "powerpc.h" #include "panic.h" static volatile ipc_request in_queue[IPC_IN_SIZE] ALIGNED(32) MEM2_BSS; @@ -136,6 +137,9 @@ static int process_slow(volatile ipc_request *req) boot2_ipc(req); return 0; break; + case IPC_DEV_PPC: + powerpc_ipc(req); + break; default: gecko_printf("IPC: unknown SLOW request %02x-%04x\n", req->device, req->req); } diff --git a/ipc.h b/ipc.h index e4922a8..4b2d9f5 100644 --- a/ipc.h +++ b/ipc.h @@ -12,6 +12,7 @@ #define IPC_DEV_KEYS 0x03 #define IPC_DEV_AES 0x04 #define IPC_DEV_BOOT2 0x05 +#define IPC_DEV_PPC 0x06 #define IPC_SYS_PING 0x0000 #define IPC_SYS_JUMP 0x0001 @@ -56,6 +57,8 @@ #define IPC_BOOT2_RUN 0x0000 +#define IPC_PPC_BOOT 0x0000 + #define IPC_CODE (f,d,r) (((f)<<24)|((d)<<16)|(r)) #define IPC_IN_SIZE 32 diff --git a/main.c b/main.c index cf8fe01..278d8ed 100644 --- a/main.c +++ b/main.c @@ -222,7 +222,7 @@ void *_main(void *base) gecko_printf("Trying to boot:" PPC_BOOT_FILE "\n"); - res = powerpc_load_file(PPC_BOOT_FILE); + res = powerpc_boot_file(PPC_BOOT_FILE); if(res < 0) { gecko_printf("Failed to boot PPC: %d\n", res); gecko_printf("Continuing anyway\n"); diff --git a/powerpc.c b/powerpc.c index e73e1ed..758ddec 100644 --- a/powerpc.c +++ b/powerpc.c @@ -20,7 +20,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "types.h" +#include "memory.h" #include "powerpc.h" +#include "powerpc_elf.h" #include "hollywood.h" #include "utils.h" #include "start.h" @@ -73,3 +75,18 @@ void powerpc_reset() udelay(100000); set32(HW_EXICTRL, EXICTRL_ENABLE_EXI); } + +void powerpc_ipc(volatile ipc_request *req) +{ + switch (req->req) { + case IPC_PPC_BOOT: + dc_invalidaterange((void *) req->args[0], (u32) req->args[1]); + int res = powerpc_boot_mem((u8 *) req->args[0], (u32) req->args[1]); + if (res) + ipc_post(req->code, req->tag, 1, res); + break; + default: + gecko_printf("IPC: unknown SLOW PPC request %04X\n", req->req); + } +} + diff --git a/powerpc.h b/powerpc.h index 1ff9ec9..2683a74 100644 --- a/powerpc.h +++ b/powerpc.h @@ -1,9 +1,12 @@ #ifndef __POWERPC_H__ #define __POWERPC_H__ 1 -void ppc_boot_code(); +#include "ipc.h" + void powerpc_upload_stub(u32 entry); void powerpc_hang(); void powerpc_reset(); +void powerpc_ipc(volatile ipc_request *req); #endif + diff --git a/powerpc_elf.c b/powerpc_elf.c index 564de2f..82b22a1 100644 --- a/powerpc_elf.c +++ b/powerpc_elf.c @@ -16,7 +16,7 @@ static Elf32_Ehdr elfhdr; static Elf32_Phdr phdrs[PHDR_MAX]; static FIL fd; -int powerpc_load_file(const char *path) +int powerpc_boot_file(const char *path) { u32 read; FRESULT fres; @@ -49,7 +49,7 @@ int powerpc_load_file(const char *path) fres = f_lseek(&fd, elfhdr.e_phoff); if(fres != FR_OK) return -fres; - + fres = f_read(&fd, phdrs, sizeof(phdrs[0])*elfhdr.e_phnum, &read); if(fres != FR_OK) return -fres; @@ -67,7 +67,7 @@ int powerpc_load_file(const char *path) gecko_printf("Skipping PHDR of type %d\n",phdr->p_type); } else { void *dst = phdr->p_paddr; - + gecko_printf("LOAD 0x%x -> %p [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz); fres = f_lseek(&fd, phdr->p_offset); if(fres != FR_OK) @@ -90,3 +90,61 @@ int powerpc_load_file(const char *path) return 0; } + +int powerpc_boot_mem(const u8 *addr, u32 len) +{ + if (len < sizeof(Elf32_Ehdr)) + return -100; + + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) addr; + + if (memcmp("\x7F" "ELF\x01\x02\x01\x00\x00", ehdr->e_ident, 9)) { + gecko_printf("Invalid ELF header! 0x%02x 0x%02x 0x%02x 0x%02x\n", + ehdr->e_ident[0], ehdr->e_ident[1], + ehdr->e_ident[2], ehdr->e_ident[3]); + return -101; + } + + if (ehdr->e_phoff == 0 || ehdr->e_phnum == 0) { + gecko_printf("ELF has no program headers!\n"); + return -102; + } + + if (ehdr->e_phnum > PHDR_MAX) { + gecko_printf("ELF has too many (%d) program headers!\n", + elfhdr.e_phnum); + return -102; + } + + int count = ehdr->e_phnum; + if (len < ehdr->e_phoff + count * sizeof(Elf32_Phdr)) + return -103; + + Elf32_Phdr *phdr = (Elf32_Phdr *) &addr[ehdr->e_phoff]; + + // TODO: add more checks here + // - phdrs out of bounds? + // - loaded ELF overwrites itself? + + powerpc_hang(); + + while (count--) { + if (phdr->p_type != PT_LOAD) { + gecko_printf("Skipping PHDR of type %d\n", phdr->p_type); + } else { + gecko_printf("LOAD 0x%x -> %p [0x%x]\n", phdr->p_offset, phdr->p_paddr, phdr->p_filesz); + memcpy((void *) phdr->p_paddr, &addr[phdr->p_offset], + phdr->p_filesz); + } + phdr++; + } + + dc_flushall(); + + gecko_printf("ELF load done, booting PPC...\n"); + powerpc_upload_stub(ehdr->e_entry); + powerpc_reset(); + gecko_printf("PPC booted!\n"); + + return 0; +} diff --git a/powerpc_elf.h b/powerpc_elf.h index 656938f..8af6925 100644 --- a/powerpc_elf.h +++ b/powerpc_elf.h @@ -1,6 +1,7 @@ -#ifndef __POWERPC_H__ -#define __POWERPC_H__ 1 +#ifndef __POWERPC_ELF_H__ +#define __POWERPC_ELF_H__ 1 -int powerpc_load_file(const char *path); +int powerpc_boot_file(const char *path); +int powerpc_boot_mem(const u8 *addr, u32 len); #endif