两天 移植UCOSII到arm(代码+思路)-第一天

以下步骤均在ubuntu20.04下实现

如果要研究一个系统,首先要先让这个系统跑起来。所以我们的第一步是将这个系统移植到适当的平台上,大家也可以自行移植到自己手头上的开发板。

由于本人懒得弄开发板bootloader,加上调试也不太方便,就先在qemu上做实验。

先安装交叉编译链:

sudo apt-get install gcc-arm-linux-gnueabi

再安装qemu、gdb-multiarch:

sudo apt install qemu-system-arm

sudo apt install gdb-multiarch

基本上环境就搭建好了。现在下载μCOS-II源码。我的源码是直接在光盘拷贝出来的古董源码,2.52版本。

今天的任务就是先和平台无关的代码先编译出来。明天再把需要的代码补充完整。

在上图我们可以看到,只有3个文件的代码是和CPU相关的,别的都不相关。那我们今天就先把不相关的代码编译了

先新建三个文件夹,然后把文件薅进去:

.
├── arm9
│   ├── os_cpu_a.s
│   └── os_cpu_c.c
├── include
│   ├── includes.h
│   ├── os_cfg.h
│   ├── os_cpu.h
│   └── ucos_ii.h
└── ucosii
    ├── os_core.c
    ├── os_flag.c
    ├── os_mbox.c
    ├── os_mem.c
    ├── os_mutex.c
    ├── os_q.c
    ├── os_sem.c
    ├── os_task.c
    ├── os_time.c
    └── ucos_ii.c

这是我的布局,不一定要按照这样布局。我们可以看到,上图所有的文件都扔进去了。接下来是删代码。主要删的是 os_cpu_a.s、os_cpu_c.c、os_cpu.h的代码。为什么?因为他们和平台相关,一般文档会告诉你的。如果一个系统不告诉你这些,那他就不是一个拿来给你移植的系统。

接下来把这样

 删成这样:

 因为那些是内联汇编代码。既然是汇编,那就是肯定和平台相关。文件里的这些数据类型也可以改了,改成你所对应的平台的。

os_cpu_c.c这个文件就简单了,里面的所有的函数都像这样挖空就好:

 

 接下来就是 os_cpu_a.s。把;全部改成#,因为两个汇编器的注释的符号不一样。as的注释符号是#。接下来把

改成这样

具体的.global和.extern什么意思可以直接百度,修改这里主要也是因为汇编器识别的符号不同。 

接下来就是删汇编代码:

 一共四个函数,每一个都删成这样就OK

新的到时候再填充

删代码已经OK了,接下来是改一下includes.h,然后写一下makefile。如果你是用ide的话就不用写makefile了。makefile是指定这些文件怎么编译的,用ide的话全部把文件加进去就OK了。includes.h主要是把那些和库相关的都删了

我是把这样

改成这样

 

 因为那个pc.h也只是在x86平台上用的函数,有点像stm32的hal库,所以这里就用不上了。

接下来编译的时候就会发现有不少错误,因为没有那些头文件。但是这个系统用的头文件里面的函数的具体实现和平台无关,我们可以自己写,主要是memcpy和memset这两个函数。

接下来就是新建一个文件,写makfile。这个直接复制粘贴就好。makefile一般是拿一些通用模板来改的,不懂语法的就查一下就行,一般来说不用专门地学,像是脚本一样。还有链接脚本。我们暂时还不管内存布局,所以也是复制粘贴就好

CC      = arm-linux-gnueabi-gcc
LD      = arm-linux-gnueabi-ld
AR      = arm-linux-gnueabi-ar
OBJCOPY = arm-linux-gnueabi-objcopy
OBJDUMP = arm-linux-gnueabi-objdump

DIRS = arm9

objs := $(foreach dir,$(DIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c)))
objs += ucosii/ucos_ii.o
objs += $(foreach dir,$(DIRS),$(patsubst %.s,%.o,$(wildcard $(dir)/*.s)))

INCLUDEDIR 	:= $(shell pwd)/include
CFLAGS 	:= -Wall -O2 -o
CPPFLAGS   	:=  -I$(INCLUDEDIR) -g -c -fno-stack-protector
#-nostdinc 
ucos.bin : $(objs)
	@echo $(objs)
	$(LD) -g -Tucos.lds -o ucos.elf $^
	$(OBJCOPY) -O binary -S ucos.elf $@
	$(OBJDUMP) -D -m arm  ucos.elf > ucos.dis

%.o:%.c
	${CC} $(CPPFLAGS) $(CFLAGS) $@ $<

%.o:%.s
	${CC} $(CPPFLAGS) $(CFLAGS) $@ $<

clean:
	rm -f  ucos.bin ucos.elf ucos.dis $(objs)

make一下,接下来就是改错:

错误:

 把ucos_ii.c全部改成

接下来就是:

 我们其实可以看到,都编译完汇编了,就差链接了。说实在的今天的任务也算完成了。

但是我们可以进一步把elf和二进制文件搞出来。

elf是带了程序信息的,比如说加载位置、入口这些。bin文件需要直接烧录进内存,还要在内存布好局。elf布局就自由一点,但是要bootloader把他的布局搞好,因为他只是有信息,不代表他天生就OK,而且因为他多了信息,还不能直接烧录进去内存,不然CPU会以为多出来的信息也是指令。但是用QEMU的话,我们就不用bootloader,QEMU直接帮我们弄好,就像是天生就好了一样。

直接复制粘贴链接脚本:
命名为ucos.lds,想改名记得同时改makefile就行

SECTIONS {
	. = 0x00;
  	.text          :   { *(.text) }
	.rodata ALIGN(4) : {*(.rodata)} 
  	.data ALIGN(4) : { *(.data) }
  	.bss ALIGN(4)  : { *(.bss)  *(COMMON) }
}

make。接下来果然不出所料: 

 没有memset、memcpy,还有意料之外的__aeabi_uidiv。

工程目录下新建一个lib文件夹,我们自己给补上。

先解决__aeabi_uidiv,这个错误主要是arm芯片没有实现除法的硬件结构,因此需要采用软件去实现除法。我们就要先找到他的库文件。

去/usr搜索libgcc.a就行。一般库文件都在/usr下,.a文件则是和.o文件一样的东西。实现不重要,能拿来链接就行。一定要找对应的编译链的,别链接到别的CPU的代码上了。

复制放到lib下。然后新建一个文件:lib.c,现在布局如下:

.
├── arm9
│   ├── os_cpu_a.s
│   └── os_cpu_c.c
├── include
│   ├── includes.h
│   ├── os_cfg.h
│   ├── os_cpu.h
│   └── ucos_ii.h
├── lib
│   ├── lib.c
│   └── libgcc.a
├── makefile
├── ucosii
│   ├── os_core.c
│   ├── os_flag.c
│   ├── os_mbox.c
│   ├── os_mem.c
│   ├── os_mutex.c
│   ├── os_q.c
│   ├── os_sem.c
│   ├── os_task.c
│   ├── os_time.c
│   └── ucos_ii.c
└── ucos.lds

写代码

lib.c

#define NULL ((void*)0)

void * memset(void *dest, int set, unsigned int len)
{
	if (dest == NULL || len < 0)
	{
		return NULL;
	}
	char *pdest = (char *)dest;
	while (len-->0)
	{
		*pdest++ = set;
	}
	return dest;
}

void* memcpy(void* dest,const void* src, unsigned int num)
{
	void* ret = dest;
	if (dest == NULL)
	{
		return NULL;
	}
	if (src == NULL)
	{
		return NULL;
	}
	//有多少个字节执行多少次
	char* dest1,*src1;
	while (num--)
	{
		//一个字节一个字节进行赋值
		*dest1 = *src1;
		++dest1;
		++src1;
	}
	return ret;
}

makefile 文件里的DIRS = arm9后面加一个lib:DIRS = arm9 lib  

  $(LD) -g -Tucos.lds -o ucos.elf $^ 也要把lib/libgcc.a加上:

$(LD) -g -Tucos.lds -o ucos.elf $^ lib/libgcc.a

体会到没,makefile是管理文件怎么编译的。每次加点东西都要改一下它,因为编译的方法不同了。

又有一个错误,管上:

 lib.c末尾新起一行加上:

unsigned int raise (unsigned int signum)
{
	return 0;
}

再编译:

成功了!

目录下打开终端,运行

qemu-system-arm -M vexpress-a9 -nographic -kernel ucos.elf -S -s

再打开一个终端运行:

gdb-multiarch --tui ucos.elf -ex 'target remote localhost:1234'

回车,我们就可以看到进入了一个函数OSInitHookBegin (void)运行

由于我们还没设置入口,也没写移植的代码,所以暂时不能继续往下调试。

但是我们可以看到的是,调试平台已经搭建完了,我们是能够继续调试的。

明天再进行下一步了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值