Move RTAS code into an external binary blob. Implement the display-character token, add some debug output.
The serial_putchar() calls are working now. Hangs on return of the first RTAS call though. --- arch/ppc/build.xml | 26 ++++++++++++- arch/ppc/qemu/init.c | 7 +++- arch/ppc/qemu/kernel.h | 1 - arch/ppc/qemu/methods.c | 11 +++-- arch/ppc/qemu/rtas-ldscript | 47 +++++++++++++++++++++++ arch/ppc/qemu/rtas-tokens.c | 63 ++++++++++++++++++++++++++++++ arch/ppc/qemu/rtas.S | 88 +++++++++++++++++++++++++++++++++++++++++++ arch/ppc/qemu/start.S | 7 --- 8 files changed, 236 insertions(+), 14 deletions(-) create mode 100644 arch/ppc/qemu/rtas-ldscript create mode 100644 arch/ppc/qemu/rtas-tokens.c create mode 100644 arch/ppc/qemu/rtas.S
diff --git a/arch/ppc/build.xml b/arch/ppc/build.xml index 9778a43..f893abc 100644 --- a/arch/ppc/build.xml +++ b/arch/ppc/build.xml @@ -89,6 +89,22 @@ $(call quiet-command,$(CC) $$EXTRACFLAGS $(CFLAGS) $(INCLUDES) -c -o $@ $(SRCDIR)/arch/ppc/mol/kernel.c, " CC $(TARGET_DIR)$@")]]></rule> </executable>
+ + <executable name="target/include/qemu-rtas.h" target="target" condition="QEMU"> + <rule><![CDATA[ + $(call quiet-command,true, " GEN $(TARGET_DIR)$@") + @echo "static const char rtas_binary[] = {" > $@ + @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ + | sed 's/0x ,//g' >> $@ + @echo "};" >> $@]]></rule> + <external-object source="rtas-qemu.bin"/> + </executable> + + <executable name="target/arch/ppc/qemu/methods.o" target="target" condition="QEMU"> + <rule><![CDATA[ $(SRCDIR)/arch/ppc/qemu/methods.c $(ODIR)/target/include/qemu-rtas.h + $(call quiet-command,$(CC) $$EXTRACFLAGS $(CFLAGS) $(INCLUDES) -I$(SRCDIR)/arch/ppc -c -o $@ $(SRCDIR)/arch/ppc/qemu/methods.c, " CC $(TARGET_DIR)$@")]]></rule> + </executable> + <!-- END OF HACK ALERT -->
<library name="briq" target="target" type="static" condition="BRIQ"> @@ -123,7 +139,7 @@ <object source="qemu/init.c" flags="-I$(SRCDIR)/arch/ppc"/> <external-object source="target/arch/ppc/qemu/kernel.o"/> <object source="qemu/main.c" flags="-I$(SRCDIR)/arch/ppc"/> - <object source="qemu/methods.c" flags="-I$(SRCDIR)/arch/ppc"/> + <external-object source="target/arch/ppc/qemu/methods.o"/> <object source="qemu/vfd.c" flags="-I$(SRCDIR)/arch/ppc"/> <object source="qemu/console.c" flags="-I$(SRCDIR)/arch/ppc"/> </library> @@ -193,6 +209,14 @@ <external-object source="libgcc.a"/> </executable>
+ <executable name="rtas-qemu.bin" target="target" condition="QEMU"> + <rule> + $(call quiet-command,$(LD) --warn-common -N -T $(SRCDIR)/arch/$(ARCH)/qemu/rtas-ldscript -o $@ --whole-archive --pic-executable $^," LINK $(TARGET_DIR)$@")</rule> + <object source="qemu/rtas.S"/> + <object source="qemu/rtas-tokens.c" flags="-std=c99 -fpic -DPIC"/> + <external-object source="libgcc.a"/> + </executable> + <executable name="openbios-mol.elf" target="target" condition="MOL"> <rule> $(call quiet-command,$(LD) -g -Ttext=0x01e01000 -Bstatic $^ $(shell $(CC) -print-libgcc-file-name) -o $@.nostrip --whole-archive $^," LINK $(TARGET_DIR)$@") diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 2b0b891..6d72386 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -579,6 +579,10 @@ static void kvm_of_init(void) fword("finish-device"); }
+#ifdef CONFIG_RTAS +extern int rtas_size; +#endif + void arch_of_init( void ) { @@ -745,10 +749,11 @@ arch_of_init( void ) printk("Warning: No /rtas node\n"); else { unsigned long size = 0x1000; - while( size < (unsigned long)of_rtas_end - (unsigned long)of_rtas_start ) + while ( size < rtas_size ) size *= 2; set_property( ph, "rtas-size", (char*)&size, sizeof(size) ); set_int_property(ph, "rtas-version", 1); + set_int_property(ph, "display-character", 1); } #endif
diff --git a/arch/ppc/qemu/kernel.h b/arch/ppc/qemu/kernel.h index e8ae364..6ae928f 100644 --- a/arch/ppc/qemu/kernel.h +++ b/arch/ppc/qemu/kernel.h @@ -21,7 +21,6 @@ extern void exit( int status );
/* 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 );
/* methods.c */ diff --git a/arch/ppc/qemu/methods.c b/arch/ppc/qemu/methods.c index f27d532..00444a9 100644 --- a/arch/ppc/qemu/methods.c +++ b/arch/ppc/qemu/methods.c @@ -33,24 +33,27 @@ #ifdef CONFIG_RTAS DECLARE_NODE( rtas, INSTALL_OPEN, 0, "+/rtas" );
+#include "qemu-rtas.h" +#define RTAS_DATA_SIZE 0x1000 +const int rtas_size = RTAS_DATA_SIZE + sizeof(rtas_binary); + /* ( physbase -- rtas_callback ) */ static void rtas_instantiate( void ) { ucell physbase = POP(); - ucell s=0x1000, size = (ucell)of_rtas_end - (ucell)of_rtas_start; + ucell s=0x1000, size = RTAS_DATA_SIZE + sizeof(rtas_binary); unsigned long virt;
while( s < size ) s += 0x1000; virt = ofmem_claim_virt( 0, s, 0x1000 ); ofmem_map( physbase, virt, s, -1 ); - memcpy( (char*)virt, of_rtas_start, size ); + memcpy( (char*)virt + RTAS_DATA_SIZE, rtas_binary, rtas_size - RTAS_DATA_SIZE );
- printk("RTAS instantiated at %08x\n", physbase ); flush_icache_range( (char*)virt, (char*)virt + size );
- PUSH( physbase ); + PUSH( physbase + RTAS_DATA_SIZE ); }
NODE_METHODS( rtas ) = { diff --git a/arch/ppc/qemu/rtas-ldscript b/arch/ppc/qemu/rtas-ldscript new file mode 100644 index 0000000..f596eb7 --- /dev/null +++ b/arch/ppc/qemu/rtas-ldscript @@ -0,0 +1,47 @@ +OUTPUT_FORMAT(binary) +OUTPUT_ARCH(powerpc) + +SECTIONS +{ + _start = .; + + /*. = 0x1000;*/ + .rtasentry ALIGN(4096): { *(.rtasentry) } + + /* Normal sections */ + .text ALIGN(4096): { + *(.text) + *(.text.*) + } + + .rodata ALIGN(4096): { + _rodata = .; + *(.rodata) + *(.rodata.*) + *(.note.ELFBoot) + } + .data ALIGN(4096): { + _data = .; + *(.data) + *(.data.*) + _edata = .; + } + + .bss ALIGN(4096): { + _bss = .; + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + *(COMMON) + _ebss = .; + } + + . = ALIGN(4096); + _end = .; + + /* We discard .note sections other than .note.ELFBoot, + * because some versions of GCC generate useless ones. */ + + /DISCARD/ : { *(.comment*) *(.note.*) } +} diff --git a/arch/ppc/qemu/rtas-tokens.c b/arch/ppc/qemu/rtas-tokens.c new file mode 100644 index 0000000..f251716 --- /dev/null +++ b/arch/ppc/qemu/rtas-tokens.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 Andreas Färber andreas.faerber@web.de + */ + +#define RTAS_MAX_ARGS 10 + +typedef struct rtas_args { + unsigned long token; + long nargs; + long nret; + unsigned long args[RTAS_MAX_ARGS]; +} rtas_args_t; + +void rtas_interface(rtas_args_t*, void*); + +/* drivers/escc.h */ +#define IO_ESCC_OFFSET 0x00013000 +/* drivers/escc.c */ +#define CTRL(addr) (*(volatile unsigned char *)(addr)) +#define DATA(addr) (*(volatile unsigned char *)(addr + 16)) +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ + +/*static void uart_putchar(int port, unsigned char c) +{ + while (!(CTRL(port) & Tx_BUF_EMP)) + ; + DATA(port) = c; +}*/ + +/*void serial_putchar(char);*/ + +static void serial_putchar(char c) +{ + unsigned long addr = 0x80800000; + volatile unsigned char *serial_dev = (unsigned char *)addr + IO_ESCC_OFFSET + 0x20; + //uart_putchar((int)serial_dev, c); + volatile unsigned char * port = serial_dev; + while (!(CTRL(port) & Tx_BUF_EMP)) + ; + DATA(port) = c; +} + +enum { + DISPLAY_CHARACTER = 1, +}; + +void rtas_interface(rtas_args_t* params, void* privateData) +{ + switch (params->token) { + case DISPLAY_CHARACTER: { + serial_putchar((char)params->args[0]); + serial_putchar('x'); + params->args[params->nargs] = 0; + break; + } + default: + serial_putchar('.'); + params->args[params->nargs] = -1; + break; + } + serial_putchar('\r'); + serial_putchar('\n'); +} diff --git a/arch/ppc/qemu/rtas.S b/arch/ppc/qemu/rtas.S new file mode 100644 index 0000000..35037c4 --- /dev/null +++ b/arch/ppc/qemu/rtas.S @@ -0,0 +1,88 @@ +/* + * RTAS blob for QEMU + * Copyright (c) 2010 Andreas Färber andreas.faerber@web.de + */ + +#include "asm/asmdefs.h" + +/*.data +.space xxx, 0 */ + +.section .rtasentry,"ax" + /* real mode! */ +GLOBL(_entry): + /* + * r3 = arguments + * r4 = private memory + */ + stw r1, 0(r4) + stw r2, 4(r4) + + stwu r1, -12(r1) + stw r4, 8(r1) + mflr r0 + stw r0, 4(r1) + + stw r13, 8(r4) + stw r14, 12(r4) + stw r15, 16(r4) + stw r16, 20(r4) + stw r17, 24(r4) + stw r18, 28(r4) + stw r19, 32(r4) + stw r20, 36(r4) + stw r21, 40(r4) + stw r22, 44(r4) + stw r23, 48(r4) + stw r24, 52(r4) + stw r25, 56(r4) + stw r26, 60(r4) + stw r27, 64(r4) + stw r28, 68(r4) + stw r29, 72(r4) + stw r30, 76(r4) + stw r31, 80(r4) + + mfcr r2 + stw r2, 84(r4) + + bl rtas_interface + + lwz r0, 4(r1) + mtlr r0 + lwz r4, 8(r1) +// lwz r1, 0(r1) + + lwz r2, 84(r4) + mtcr r2 + + lwz r13, 8(r4) + lwz r14, 12(r4) + lwz r15, 16(r4) + lwz r16, 20(r4) + lwz r17, 24(r4) + lwz r18, 28(r4) + lwz r19, 32(r4) + lwz r20, 36(r4) + lwz r21, 40(r4) + lwz r22, 44(r4) + lwz r23, 48(r4) + lwz r24, 52(r4) + lwz r25, 56(r4) + lwz r26, 60(r4) + lwz r27, 64(r4) + lwz r28, 68(r4) + lwz r29, 72(r4) + lwz r30, 76(r4) + lwz r31, 80(r4) + + lwz r2, 4(r4) + lwz r1, 0(r4) + + blr + +/* libgcc.a */ +.globl __divide_error +__divide_error: +1: nop + b 1b diff --git a/arch/ppc/qemu/start.S b/arch/ppc/qemu/start.S index c995581..d9c61a7 100644 --- a/arch/ppc/qemu/start.S +++ b/arch/ppc/qemu/start.S @@ -522,13 +522,6 @@ GLOBL(of_client_callback):
blr
- /* rtas glue (must be reloctable) */ -GLOBL(of_rtas_start): - /* r3 = argument buffer, r4 = of_rtas_start */ - /* according to the CHRP standard, cr must be preserved (cr0/cr1 too?) */ - blr -GLOBL(of_rtas_end): -
#define CACHE_LINE_SIZE 32 #define LG_CACHE_LINE_SIZE 5