[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