On Tue, 17 Jun 2014, BALATON Zoltan wrote:
From the test results it seems that Apple puts the stack after the image (and probably clears it or otherwise adds a mapping in the TLB for it so accessing it will not generate exceptions). How could this be implemented in OpenBIOS? I've tried to look at the code to find a good place but there seems to be different cases for different architectures and using preloaded kernel image seems to be an additional complication. Could the file-size stored in saved-program-state be used as a base to place the stack in call_elf? (this would need adding an additional parameter to it in the ppc/qemu case because accessing Forth from assembly is not something I'd try).
Or are my conclusions wrong or you have a better idea? (Also what about my other patches on the list? This place seemed abandoned for the last week.)
With the patch below I don't get DSI-s but it crashes in an ISI while trying to replace the sr registers. How could this possibly work on real hardware without getting any exceptions during replacing the vectors? Is there a way to preload the TLB with code addresses too so we can avoid the crash? How? (For data accessing it before calling the boot code is enough to preload translations but how to avoid ISI-s?)
Regards, BALATON Zoltan
diff --git a/openbios-devel/arch/ppc/qemu/init.c b/openbios-devel/arch/ppc/qemu/init.c index 8d5ef8e..2872c7b 100644 --- a/openbios-devel/arch/ppc/qemu/init.c +++ b/openbios-devel/arch/ppc/qemu/init.c @@ -594,12 +594,20 @@ static void go(void); static void go(void) { - ucell addr; + ucell addr, end;
feval("saved-program-state >sps.entry @"); addr = POP(); + feval("saved-program-state >sps.end @"); + end = POP();
- call_elf(0, 0, addr); + if (end) { + ofmem_claim(end, 64 * 1024, 0); + memset((void *)end, 0, 64 * 1024); + end += 64 * 1024; + } + + call_elf(0, 0, addr, end); }
static void kvm_of_init(void) diff --git a/openbios-devel/arch/ppc/qemu/kernel.h b/openbios-devel/arch/ppc/qemu/kernel.h index fe9be83..464aa14 100644 --- a/openbios-devel/arch/ppc/qemu/kernel.h +++ b/openbios-devel/arch/ppc/qemu/kernel.h @@ -22,7 +22,8 @@ extern void exit( int status ) __attribute__ ((noreturn)); /* start.S */ extern void flush_icache_range( char *start, char *stop ); extern char of_rtas_start[], of_rtas_end[]; -extern void call_elf( unsigned long arg1, unsigned long arg2, unsigned long elf_entry ); +extern void call_elf( unsigned long arg1, unsigned long arg2, + unsigned long elf_entry, unsigned long stack_addr );
/* methods.c */ extern void node_methods_init( const char *cpuname ); diff --git a/openbios-devel/arch/ppc/qemu/main.c b/openbios-devel/arch/ppc/qemu/main.c index 44b1666..ac45c6c 100644 --- a/openbios-devel/arch/ppc/qemu/main.c +++ b/openbios-devel/arch/ppc/qemu/main.c @@ -61,7 +61,7 @@ static void check_preloaded_kernel(void) ph = find_dev("/chosen"); set_property(ph, "bootargs", strdup(kernel_cmdline), strlen(kernel_cmdline) + 1); } - call_elf(initrd_image, initrd_size, kernel_image); + call_elf(initrd_image, initrd_size, kernel_image, 0); } }
diff --git a/openbios-devel/arch/ppc/qemu/start.S b/openbios-devel/arch/ppc/qemu/start.S index ae2fd53..2edf7ba 100644 --- a/openbios-devel/arch/ppc/qemu/start.S +++ b/openbios-devel/arch/ppc/qemu/start.S @@ -501,7 +501,7 @@ real_entry: saved_stack: DATA_LONG(0) .previous - /* void call_elf( arg1, arg2, entry ) */ + /* void call_elf( arg1, arg2, entry, stack_addr ) */ _GLOBAL(call_elf): mflr r0 PPC_STLU r1, -STACKFRAME_MINSIZE(r1) @@ -512,6 +512,13 @@ _GLOBAL(call_elf): mfsdr1 r1 addi r1, r1, -32768 /* - 32 KiB exception stack */ addis r1, r1, -1 /* - 64 KiB stack */ + cmpwi r6,0 + beq 1f + mr r1,r6 // use stack_addr if not NULL +1: LOAD_REG_IMMEDIATE(r8, __vectors) // access 0x1000 to preload TLB + li r9,0 + lwz r10,4096(r8) + stw r10,4096(r9) LOAD_REG_IMMEDIATE(r5, of_client_callback) // r5 = callback li r6,0 // r6 = address of client program arguments (unused) li r7,0 // r7 = length of client program arguments (unused) diff --git a/openbios-devel/forth/debugging/client.fs b/openbios-devel/forth/debugging/client.fs index f374404..f06d2d3 100644 --- a/openbios-devel/forth/debugging/client.fs +++ b/openbios-devel/forth/debugging/client.fs @@ -21,6 +21,7 @@ struct ( saved-program-state ) /n field >sps.entry /n field >sps.file-size /n field >sps.file-type + /n field >sps.end constant saved-program-state.size create saved-program-state saved-program-state.size allot
diff --git a/openbios-devel/libopenbios/aout_load.c b/openbios-devel/libopenbios/aout_load.c index e9d2002..01edb88 100644 --- a/openbios-devel/libopenbios/aout_load.c +++ b/openbios-devel/libopenbios/aout_load.c @@ -160,6 +160,8 @@ aout_load(struct sys_info *info, ihandle_t dev) PUSH(size); feval("saved-program-state >sps.file-size !"); feval("aout saved-program-state >sps.file-type !"); + PUSH(entry + size); + feval("saved-program-state >sps.end !");
feval("-1 state-valid !");
diff --git a/openbios-devel/libopenbios/bootcode_load.c b/openbios-devel/libopenbios/bootcode_load.c index 0fabf55..5c09c87 100644 --- a/openbios-devel/libopenbios/bootcode_load.c +++ b/openbios-devel/libopenbios/bootcode_load.c @@ -89,6 +89,8 @@ bootcode_load(ihandle_t dev) PUSH(size); feval("saved-program-state >sps.file-size !"); feval("bootcode saved-program-state >sps.file-type !"); + PUSH(bootcode); + feval("saved-program-state >sps.end !");
feval("-1 state-valid !");
diff --git a/openbios-devel/libopenbios/elf_load.c b/openbios-devel/libopenbios/elf_load.c index 9c7850e..236b893 100644 --- a/openbios-devel/libopenbios/elf_load.c +++ b/openbios-devel/libopenbios/elf_load.c @@ -478,6 +478,7 @@ elf_init_program(void) Elf_phdr *phdr; size_t size, total_size = 0; char *addr; + char *end = NULL; uintptr_t tmp;
/* TODO: manage ELF notes section */ @@ -519,6 +520,8 @@ elf_init_program(void)
memcpy(addr, base + phdr[i].p_offset, size);
+ if (addr + phdr[i].p_memsz > end) + end = addr + phdr[i].p_memsz; total_size += size;
#ifdef CONFIG_PPC @@ -532,6 +535,8 @@ elf_init_program(void) PUSH(total_size); feval("saved-program-state >sps.file-size !"); feval("elf saved-program-state >sps.file-type !"); + PUSH((ucell)end); + feval("saved-program-state >sps.end !");
feval("-1 state-valid !"); } diff --git a/openbios-devel/libopenbios/fcode_load.c b/openbios-devel/libopenbios/fcode_load.c index f4eb7bf..3f3fbbf 100644 --- a/openbios-devel/libopenbios/fcode_load.c +++ b/openbios-devel/libopenbios/fcode_load.c @@ -81,6 +81,8 @@ fcode_load(ihandle_t dev) PUSH(size); feval("saved-program-state >sps.file-size !"); feval("fcode saved-program-state >sps.file-type !"); + PUSH(start + size); + feval("saved-program-state >sps.end !");
feval("-1 state-valid !");
diff --git a/openbios-devel/libopenbios/forth_load.c b/openbios-devel/libopenbios/forth_load.c index c3a1929..403f1e5 100644 --- a/openbios-devel/libopenbios/forth_load.c +++ b/openbios-devel/libopenbios/forth_load.c @@ -69,6 +69,8 @@ int forth_load(ihandle_t dev) PUSH((ucell)forthsize); feval("saved-program-state >sps.file-size !"); feval("forth saved-program-state >sps.file-type !"); + PUSH(0); + feval("saved-program-state >sps.end !");
feval("-1 state-valid !");
diff --git a/openbios-devel/libopenbios/xcoff_load.c b/openbios-devel/libopenbios/xcoff_load.c index 0dcb28c..3eb8574 100644 --- a/openbios-devel/libopenbios/xcoff_load.c +++ b/openbios-devel/libopenbios/xcoff_load.c @@ -60,6 +60,7 @@ xcoff_init_program(void) uint32_t offset; size_t total_size = 0; int i; + ucell end = 0;
feval("0 state-valid !");
@@ -113,6 +114,8 @@ xcoff_init_program(void)
memcpy((char*)(uintptr_t)shdr->s_vaddr, base + shdr->s_scnptr, shdr->s_size); + if (shdr->s_vaddr + shdr->s_size > end) + end = shdr->s_vaddr + shdr->s_size; total_size += shdr->s_size; #ifdef CONFIG_PPC flush_icache_range((char*)(uintptr_t)shdr->s_vaddr, @@ -122,11 +125,15 @@ xcoff_init_program(void)
memcpy((char*)(uintptr_t)shdr->s_vaddr, base + shdr->s_scnptr, shdr->s_size); + if (shdr->s_vaddr + shdr->s_size > end) + end = shdr->s_vaddr + shdr->s_size; total_size += shdr->s_size;
} else if (strcmp(shdr->s_name, ".bss") == 0) {
memset((void *)(uintptr_t)shdr->s_vaddr, 0, shdr->s_size); + if (shdr->s_vaddr + shdr->s_size > end) + end = shdr->s_vaddr + shdr->s_size; total_size += shdr->s_size; } else { DPRINTF(" Skip '%s' section\n", shdr->s_name); @@ -142,6 +149,8 @@ xcoff_init_program(void) PUSH(total_size); feval("saved-program-state >sps.file-size !"); feval("xcoff saved-program-state >sps.file-type !"); + PUSH(end); + feval("saved-program-state >sps.end !");
feval("-1 state-valid !"); }