Am 15.10.2010 um 00:17 schrieb Andreas Färber andreas.faerber@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@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@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