以上所用到的软件可以到官网下载,也可以去我网盘http://pan.baidu.com/s/1miuYGze
qemu重自带gdb server。
我是在windows 8上使用的qemu,按照和其它软件一样,双击安装就可以了,安装完成后可能需要手动将目录“C:\Program Files\qemu”添加到环境变量。这里需要用到的可执行文件“qemu-system-mipsel.exe”就在该目录中。
GDB远程调试套件包括Host端的gdb和Target端的gdbserver,对于gdb,宿主机上发行版本自带的(x64)PC版gdb是不能用的,它没有目标架构(MIPS)相关的调试支持。所以我们应该使用gdb的源码,针对MIPS平台编译一个(toolchain还是Host上的)特别的版本
./configure --target=mipsel-linux --prefix=/home/gdb/gdb-dest --program-prefix=mipsel-linux-
在windows上的命令窗口中运行如下命令启动qemu
qemu-system-mipsel -M mips -nographic -kernel bin/image.elf -gdb tcp::1234 -S
其中,-M mips指定machine为mips r4k platform。可以通过命令“qemu-system-mipsel -M ?”查看支持那些machine,用命令“qemu-system-mipsel -cpu ?”查看支持那些cpu。
-kernel后的bin/image.elf为本次调试对象,即运行在qemu上的可执行程序;
-gdb tcp:1234的作用是打开qemu中的gdbserver,并且使用tcp,端口为1234;
最后的一个参数“-S”的作用是qemu启动后立刻挂起gdbserver,等待客户端gdb的连接。
运行前面已经编译好的mipsel-linux-gdb,并用命令”target remote 192.168.3.102:1234”连接qemu中的gdbserver。
命令”target remote 192.168.3.102:1234“中的IP地址192.168.3.102为运行qemu的PC,端口1234为启动qemu时,传给qemu的gdbserver监听的端口。
编译源码时,在Makefile中加入了编译选项”-g“,所以符号表已经在可执行文件”bin/image.elf“中,那么使用命令”symbol-file”读取即可,如下
好,现在可以开始单步,打断点调试了
单步执行最开始那段汇编,源码如下
.text
.globl _start
_start:
b reset
nop
.org 0x180
/* General exception */
1: b 1b
nop
.align 4
reset:
/* Clear CP0_SR:BEV to 0 */
mfc0 $t0, $12
and $t0, 0xffbfffff
mtc0 $t0, $12
/* Setup stack address */
lui $sp, %hi(stack_top)
addiu $sp, $sp, %lo(stack_top)
lui $t9, %hi(main)
addiu $t9, %lo(main)
jalr $t9
nop
hang:
b hang
第一个单步,执行了一条汇编指令”mfc0 $t0, $12”,并提示自动切换到汇编模式
然后执行list命令,显示了当前上下文代码,可以看到其后的第二条汇编指令为”and $t0, 0xffbfffff”
第二个单步,执行了汇编指令”and $t0, 0xffbfffff”
第三个单步,执行了汇编指令”mtc0 $t0, $12”
在main函数处打个断点
注意右边为qemu中还没有打印helloworld,代码中13行打印helloworld,那么在15行再打个断点看看
这里只贴部分源码,完整的代码请移步到https://gitee.com/caogos/qemu_gdb_mips_hello
.text
.globl _start
_start:
b reset
nop
.org 0x180
/* General exception */
1: b 1b
nop
.align 4
reset:
/* Clear CP0_SR:BEV to 0 */
mfc0 $t0, $12
and $t0, 0xffbfffff
mtc0 $t0, $12
/* Setup stack address */
lui $sp, %hi(stack_top)
addiu $sp, $sp, %lo(stack_top)
lui $t9, %hi(main)
addiu $t9, %lo(main)
jalr $t9
nop
hang:
b hang
#include
#include
int main()
{
unsigned int tt = 0;
int i = 0;
// Test exception
//writel(0xffffffff, 0x12341234);
init_serial();
print_uart0("Hello world!\n");
for (i = 0 ; i < 10 ; i++) {
tt = read_c0_count();
}
// Never return
while(1);
return 0;
}
#ifndef __UART_H__
#define __UART_H__
//Define
#define UART0_BASE 0xB40003F8 /* 16550 COM1 */
// API
void init_serial(void);
void print_uart0(const char *s);
void putc(char a);
#endif
#include
#include
static int is_transmit_empty()
{
volatile char *addr = (volatile char *)(UART0_BASE + 5);
return *addr & 0x20;
}
void putc(char a)
{
volatile char *addr = (volatile char*)UART0_BASE;
while (is_transmit_empty() == 0);
*addr = a;
}
void print_uart0(const char *s)
{
while (*s != '\0') { /* Loop until end of string */
putc(*s);
s++; /* Next char */
}
}
void init_serial()
{
writeb(0xc1, UART0_BASE + 2);
writeb(0x03, UART0_BASE + 3);
writeb(0x03, UART0_BASE + 4);
writeb(0x60, UART0_BASE + 5);
writeb(0xb0, UART0_BASE + 6);
writeb(0x00, UART0_BASE + 7);
}
OBJDIR = obj/
BINDIR = bin/
DRVDIR = Drivers/
CROSS_COMPILE = mipsel-linux-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
AS = $(CROSS_COMPILE)as
AR = $(CROSS_COMPILE)ar
OBJCOPY = $(CROSS_COMPILE)objcopy
SYS_INC = include/
DRV_INC =Drivers/include/
INC_FLAGS += -I$(SYS_INC) -I$(DRV_INC)
CFLAGS += -mips32 -EL -Wall -g -fno-exceptions -fno-builtin -mno-abicalls -nostdinc -fno-stack-protector
LDFLAGS += -nostdlib -nostartfiles -nodefaultlibs -EL
ELF_IMAGE = $(BINDIR)image.elf
TARGET = $(BINDIR)image.bin
LINKER_SCRIPT = boot.ld
APP_OBJS += main.o
STARTUP_OBJ += start.o
DRIVER_OBJ += uart.o
OBJS = $(addprefix $(OBJDIR), $(STARTUP_OBJ) $(DRIVER_OBJ) $(APP_OBJS))
all: $(TARGET)
$(TARGET):$(OBJDIR) $(BINDIR) $(ELF_IMAGE)
$(OBJCOPY) -O binary $(ELF_IMAGE) $(TARGET)
$(ELF_IMAGE):$(OBJS)
$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) $(OBJS) -o $@
$(OBJDIR)start.o:start.S
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)main.o:main.c
$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $@
# Drivers
$(OBJDIR)uart.o:$(DRVDIR)uart.c
$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $@
$(OBJDIR):
mkdir -p $@
$(BINDIR):
mkdir -p $@
clean:
rm -rf obj bin
ENTRY(_start)
SECTIONS
{
. = 0x80000000;
.startup . : { obj/start.o(.text) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
. = . + 0x1000; /* 4kB of stack memory */
stack_top = .;
}
虽然源码中的串口基地址目前还不是龙芯1c的,但演示一个非常精简的,使用串口打印调试信息的例子,还是很有参考意义的。
使用命令“qemu-system-mipsel -cpu ?”查看支持的cpu型号,简单来说就是在命令后面跟一个问号,就会把支持的所以cpu型号打印出来。如下
D:\VmShare\rt-thread\bsp\ls1cdev>qemu-system-mipsel -cpu ?
MIPS '4Kc'
MIPS '4Km'
MIPS '4KEcR1'
MIPS '4KEmR1'
MIPS '4KEc'
MIPS '4KEm'
MIPS '24Kc'
MIPS '24KEc'
MIPS '24Kf'
MIPS '34Kf'
MIPS '74Kf'
MIPS 'M14K'
MIPS 'M14Kc'
MIPS 'P5600'
MIPS 'mips32r6-generic'
使用命令“qemu-system-mipsel -M ?”或“qemu-system-mipsel -machine ?”查看支持的Machine
D:\VmShare\qemu_gdb_rtt_ls1c\bsp\ls1cdev>qemu-system-mipsel -machine ?
Supported machines are:
ar7-amd MIPS AR7 with AMD flash
ar7 MIPS 4KEc / AR7 platform
fbox-4mb FBox 4 MiB flash (AR7 platform)
fbox-8mb FBox 8 MiB flash (AR7 platform)
malta MIPS Malta Core LV (default)
mips mips r4k platform
mipsel misp r4k platform (little endian)
mipssim MIPS MIPSsim platform
none empty machine
sinus-basic-3 Sinus DSL Basic 3 (AR7 platform)
sinus-basic-se Sinus DSL Basic SE (AR7 platform)
sinus-se Sinus DSL SE (AR7 platform)
speedport Speedport (AR7 platform)
tnetd7200 MIPS 4KEc / TNETD7200 platform
tnetd7300 MIPS 4KEc / TNETD7300 platform
D:\VmShare\qemu_gdb_rtt_ls1c\bsp\ls1cdev>qemu-system-mipsel -M ?
Supported machines are:
ar7-amd MIPS AR7 with AMD flash
ar7 MIPS 4KEc / AR7 platform
fbox-4mb FBox 4 MiB flash (AR7 platform)
fbox-8mb FBox 8 MiB flash (AR7 platform)
malta MIPS Malta Core LV (default)
mips mips r4k platform
mipsel misp r4k platform (little endian)
mipssim MIPS MIPSsim platform
none empty machine
sinus-basic-3 Sinus DSL Basic 3 (AR7 platform)
sinus-basic-se Sinus DSL Basic SE (AR7 platform)
sinus-se Sinus DSL SE (AR7 platform)
speedport Speedport (AR7 platform)
tnetd7200 MIPS 4KEc / TNETD7200 platform
tnetd7300 MIPS 4KEc / TNETD7300 platform
龙芯官方有最新的,支持龙芯1c的qemu,使用上和qemu官网下载的有点区别,网盘(本文前面有链接)中有个简要的说明文档,串口信息通过vncviewer查看,但目前我始终未能看到串口打印,有会的欢迎留言分享,谢谢!
http://ftp.loongnix.org/embed/ls1c/qemu-ls1c.tar.gz
http://ftp.loongnix.org/embed/ls1b/simulator/qemu.pdf
这是龙芯qemu配套说明文档中的部分截图。另外把测试时使用的命令也贴上,仅供参考
export PATH=$PATH:/home/develop/test/qemu-ls1c/qemu386/bin
qemu-system-mipsel -M ls1c -serial vc -kernel bin/image.elf -gdb tcp::1234 -S
target remote localhost:1234
symbol-file /mnt/hgfs/VmShare/qemu_gdb_mips_hello/bin/image.elf
vncview 127.0.0.1:5900