Discussion:
standalone C program "Hello World" on qemu-system-mipsel
Leo Chen.
2011-07-02 06:13:03 UTC
Permalink
Hi, all

I am trying to run a standalone C program "Hello World" on qemu-system-mipsel,
but it failed to print the message via serial port.

What I have done now (step by step):
1. Successfully run a standalone C program "Hello World" on qemu-system-arm, by
following this guide:
http://balau82.wordpress.com/2010/02/14/simplest-bare-metal-program-for-arm/

2. Try to run the same standalone C program on qemu-system-mipsel, but
it failed.
I used GDB to trace the program, and I can make sure the program is
working fine, it just failed
to print the message via serial port, which mapped to address 0x3f8.

I know the qemu MIPS system emulator -m "mipssim" has a PC style
serial port (8250 UART).
And my code about operating the serial port is following the 8250 spec
(http://wiki.osdev.org/Serial_ports)

But now, I am stuck to make the 8250 serial port work, any suggestion
or sample codes will be appreciated.


Here is my compile/link/run commands, and the codes:

mips-linux-gnu-gcc -mips32 -EL -c startup.s -o obj/startup.o
mips-linux-gnu-gcc -mips32 -EL -static -Wall -Werror -g -msoft-float
-nostdlib -fno-exceptions -fno-builtin -nostartfiles -nodefaultlibs
-fno-stack-protector -c test.c -o obj/test.o
mips-linux-gnu-ld -mips32 -EL -T test.ld obj/startup.o obj/test.o -o
bin/test.elf
mips-linux-gnu-objcopy -O binary bin/test.elf bin/test.bin

qemu-system-mipsel -M mipssim -nographic -kernel bin/test.elf
or
qemu-system-mipsel -M malta -nographic -kernel bin/test.elf


file: test.ld
---------------
ENTRY(_Reset)
SECTIONS
{
. = 0x80100400;
.startup . : { obj/startup.o(.text) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
. = . + 0x1000; /* 4kB of stack memory */
stack_top = .;
}

file: startup.s
-----------------------
.text
.globl _Reset
_Reset:
lui $sp, %hi(stack_top)
addiu $sp, $sp, %lo(stack_top)
lui $t9, %hi(c_entry)
addiu $t9, %lo(c_entry)
jalr $t9
nop
hang:
b hang

file: test.c
---------------
void c_entry()
{
#if 1
init_serial();
print_uart0("Hello world!\n");
#endif
#if 0
*(char *)0x3f8 = 'H'; //this also failed too
#endif
}

#define UART0_BASE 0x3f8 /* 8250 COM1 */
void init_serial() {
volatile char * addr;
addr = (volatile char*)(UART0_BASE + 1);
*addr = 0x00;
addr = (volatile char*)(UART0_BASE + 3);
*addr = 0x80;
addr = (volatile char*)(UART0_BASE + 0);
*addr = 0x03;
addr = (volatile char*)(UART0_BASE + 1);
*addr = 0x00;
addr = (volatile char*)(UART0_BASE + 3);
*addr = 0x03;
addr = (volatile char*)(UART0_BASE + 2);
*addr = 0xc7;
addr = (volatile char*)(UART0_BASE + 4);
*addr = 0x0b;
}
int is_transmit_empty()
{
volatile char *addr = (volatile char *)(UART0_BASE + 5);
return *addr & 0x20;
}
void write_serial(char a)
{
while (is_transmit_empty() == 0);
volatile char *addr = (volatile char*)UART0_BASE;
*addr = a;
}
void print_uart0(const char *s)
{
while(*s != '\0') { /* Loop until end of string */
write_serial( *s );
s++; /* Next char */
}
}
Andreas Färber
2011-07-02 09:48:38 UTC
Permalink
Hi,
Post by Leo Chen.
qemu-system-mipsel -M mipssim -nographic -kernel bin/test.elf
or
qemu-system-mipsel -M malta -nographic -kernel bin/test.elf
The use of -kernel for a random ELF executable looks strange, even if
it happens to work on arm. Have you tried -bios instead?

Andreas
Leo Chen.
2011-07-03 15:00:02 UTC
Permalink
Hi, Andreas

Thanks for your reply.

I tried the -bios *.elf:
qemu-system-mipsel -M mipssim -nographic -bios bin/test.elf
The result is the same with -kernel *.elf: C program can work, but the
serial port still not working.

And I also tried the normal way: -kernel *.bin
mips-linux-gnu-objcopy -O binary bin/test.elf bin/test.bin
qemu-system-mipsel -M mipssim -nographic -kernel bin/test.bin
and get this failure message:
qemu: could not load kernel 'bin/test.bin'

I know the C programe is working by doing these:
step1:
add some useless code in my C entry:
void c_entry()
{
init_serial();
int a, b, c; //useless code, for remote GDB trace
a = 1;
b = 2;
c = a+b;
print_uart0("Hello world!\n");
}
step2:
using mips-linux-gdb to connect the qemu like this:
mips-linux-gnu-gdb
target remote localhost:1234
Then, I trace the code step by step, and get the correct
result "c=3";

So, I think the problem is I am driving the serial port in
a wrong way. I know there're some linux kernels working
fine on qemu-system-mipsel, maybe I should read these
kernel codes to see how to get the 8250 serial port work.
Hi,
Post by Leo Chen.
qemu-system-mipsel -M mipssim -nographic -kernel bin/test.elf
or
qemu-system-mipsel -M malta -nographic -kernel bin/test.elf
The use of -kernel for a random ELF executable looks strange, even if it
happens to work on arm. Have you tried -bios instead?
Andreas
Leo Chen

Loading...