Leo Chen.
2011-07-02 06:13:03 UTC
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 */
}
}
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 */
}
}