Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1761008
  • 博文数量: 100
  • 博客积分: 10122
  • 博客等级: 上将
  • 技术积分: 4092
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-04 20:28
文章分类

全部博文(100)

文章存档

2010年(2)

2009年(28)

2008年(70)

我的朋友

分类:

2008-09-12 05:15:42

当拿到一块开发板,如果已经有类似uboot的具有下载功能的bootloader,那么可以尝试在移植操作系统前运行一些独立的小程序来测试硬件环境。
这里以 MEN 公司的 EM9 开发板为例,说明如何用 GNU GCC 工具链编译二进制程序直接在bootloader下运行。

EM9 开发板基于 freescale MPC8548 PowerPC SoC。在 MPC8548 的 Local Bus 上接了 16M bootflash 和 一片 128K FRAM, SDRAM 512M, PCI Bus 上接了一片 Altera EP2C20 FPGA。 EM9 预备了 MEN 公司的自己的 boot monitor MENMON, 功能类似 uboot ,支持 tftp 下载。

这里用到 MENMON 的两个命令, ndl(network download)  和 go。 ndl 支持tftp 下载根据传输的文件的文件名决定文件复制的位置,形如 FILENAME.DXY 的文件就会被复制到内存 0x200_00XY 的位置。 go 指令直接跳转到某个内存位置并开始执行这个位置的指令, 之后为了返回 MENMON, 必须调用 MENMON 提供的系统调用(这里和uboot不同, uboot 下只需要执行一个返回指令即可)。

为了编译,首先需要准备好 ppc-elf, ppc-linux 或者 ppc-eabi target 的 gcc 编译器,我使用我自己编译的 ppc-elf freestanding(without c lib) 编译器。

目录结构:

.
|-- Makefile.base
|-- Makefile.config -> Makefile.config.example
|-- Makefile.config.example
|-- hello
|   |-- Makefile
|   `-- hello.c
`-- libbase
    |-- Makefile
    |-- crt.c
    |-- io.c
    |-- io.h
    |-- syscall.c
    `-- syscall.h

File: ./Makefile.base
include $(FPTOP)/Makefile.config

LIBBASE_DIR=$(FPTOP)/libbase
BASELIB=$(LIBBASE_DIR)/libbase.a
CRTOBJ=$(LIBBASE_DIR)/crt.o
CFLAGS := $(CFLAGS) -I$(LIBBASE_DIR) -fno-builtin

all: $(NAME).bin tftp_upload

$(NAME).bin: $(NAME).elf
$(OBJCOPY) -O binary $< $@

$(NAME).elf: $(INOBJS) $(CRTLIB) $(BASELIB)
$(LD) $(LDFLAGS) $(LDFLAGS) -Ttext $(LOAD_ADDR) $(CRTOBJ) $(INOBJS) $(BASELIB) -o $@
$(STRIP) $@

tftp_upload: $(NAME).bin
[ ! -z "$(TFTP_DIR)" ] && cp "$(NAME).bin" "$(TFTP_DIR)/$(NAME)$(TFTP_POSTFIX)"

clean:
rm -f *.o *.bin *.elf "$(TFTP_DIR)/$(NAME)$(TFTP_POSTFIX)"

.PHONY: all clean tftp_upload
File: ./Makefile.config
AR=/home/hellwolf/dirs/apps/ycross/targets/ppc-elf_freestanding/bin/ppc-ycross-elf-ar
CC=/home/hellwolf/dirs/apps/ycross/targets/ppc-elf_freestanding/bin/ppc-ycross-elf-gcc
LD=/home/hellwolf/dirs/apps/ycross/targets/ppc-elf_freestanding/bin/ppc-ycross-elf-ld
STRIP=/home/hellwolf/dirs/apps/ycross/targets/ppc-elf_freestanding/bin/ppc-ycross-elf-strip
OBJCOPY=/home/hellwolf/dirs/apps/ycross/targets/ppc-elf_freestanding/bin/ppc-ycross-elf-objcopy
RANLIB=/home/hellwolf/dirs/apps/ycross/targets/ppc-elf_freestanding/bin/ppc-ycross-elf-ranlib
LOAD_ADDR=0x2000000
TFTP_DIR=/var/lib/tftpboot
TFTP_POSTFIX=.D00

File: ./libbase/Makefile
include ../Makefile.config

CFLAGS := $(CFLAGS) -fno-builtin
OBJS=\
syscall.o \
io.o

HEADFILES = \
syscall.h \
io.h

all: crt.o libbase.a

libbase.a: $(OBJS)
$(AR) cru $@ $(OBJS)
$(RANLIB) $@

crt.o: crt.c $(HEADFILES)

clean:
rm -f *.o *.a

.PHONY: all clean

libbase 是其他程序的基础支持库,其中 crt.c 包装了 main 函数:
#include "syscall.h"

void _start(void);
int main(void);

void _start(void){
main();
sys_return();
}
sys_return 来自 syscall.c:
#include "syscall.h"

/* System Call RETURN */
void sys_return(void) {
__asm__ __volatile__ (
"li %r10, 0x63\n\t"
"sc"
);
}

/* System Call OUT_CHR */
void sys_out_chr(char _c) {
register char c __asm__ ("r3") = _c;
(void)c;

__asm__ __volatile__ (
"li %r10, 0x20\n\t"
"sc"
);
}
这些 syscall 由 MENMON 提供。
io 库实现了简单的 printf 函数,这里就不贴出了。

File: ./hello/Makefile
FPTOP=..
NAME := hello
INOBJS := hello.o

include $(FPTOP)/Makefile.base
File ./hello/hello.c
#include "syscall.h"
#include "io.h"

int main(void) {
int i = 20;
char *s = "rocks";
printf("phigcsw %s %d\n", s, i);
return 0;
}

Makefile.base 中的关键部分就是,先编译所有目标文件,然后ld程序将这些目标文件和 crt.o(最先链接) 以及 libbase.a 链接在一起,成为 $(NAME).elf ELF 文件。 _start 为 ld 的默认入口,由 -Ttext 指定地址,这个地址必须是0x200_0000,如果我们将程序由MENMON载入到内存0x200_0000的话。
_start 函数先作一些初始化工作(如果有的话,这里为空), 然后调用用户的 main 函数,最后执行系统调用返回 MENMON。 如果是 uboot ,在 _start 最后 return 即可返回 uboot。
得到的 $(NAME).elf 文件不能直接载入到内存并且 go,必须由 objcopy转换 ELF格式为 RAW binary格式。
利用类似这样的框架,就可以方便的做硬件寄存器的存取测试,而不需要有操作系统的负担了。

阅读(2569) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~