[OpenBIOS] [RFC 3/3] ppc: RTAS WIP
Alexander Graf
agraf at csgraf.de
Fri Oct 15 00:38:44 CEST 2010
Am 15.10.2010 um 00:17 schrieb Andreas Färber <andreas.faerber at web.de>:
> Move RTAS code into an external binary blob.
> Implement the display-character token, add some debug output.
Oh nice :)
>
> The serial_putchar() calls are working now.
> Hangs on return of the first RTAS call though.
Aww :(
> ---
> 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);
Didn't you just set this to 0x41?
> + 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 at web.de>
> + */
This is missing a copyleft license.
> +
> +#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;
Phew - how is this done for the normal escc case? We should at least share the constants here.
> + 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 at 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)
Is the os guaranteed to give you r4 and r1 for free scribbling over?
> + stw r4, 8(r1)
> + mflr r0
> + stw r0, 4(r1)
> +
/* saving non-volatile registers */
> + stw r13, 8(r4)
I would recommend multiplying here:
stw r13, (3 * 4)(r4)
That makes it more readable.
> + 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
So rtas_interface gets the os given r3 as first parameter. Please make sure that struct is packed then.
> +
> + lwz r0, 4(r1)
> + mtlr r0
> + lwz r4, 8(r1)
> +// lwz r1, 0(r1)
> +
> + lwz r2, 84(r4)
> + mtcr r2
If the abi is similar to the normal C one, cr is volatile.
Alex
More information about the OpenBIOS
mailing list