SkyEye仿真平台下的操作系统实验- 准备篇(一)

29 篇文章 5 订阅
6 篇文章 1 订阅

目录

01.helloworld!

02.链接脚本

03.Arm汇编语言

04.汇编和C语言混合编程


《一步步写嵌入式操作系统》从零开始实现了操作系统leeos,并在SkyEye虚拟机中进行了实验验证。

leeos是一个简单的多任务操作系统,进程调度方式为时间片轮询。leeos使用伙伴算法实现了动态内存分配,支持romfs文件系统,支持运行elf格式的可执行文件。leeos提供了一个简单的驱动程序框架,和一个统一的异常与中断处理架构,并通过使用中断嵌套的方法提高了中断效率。leeos支持mmu,使用两级页表结构实现虚拟地址到物理地址的转换。以上涉及到的技术都在《一步步写嵌入式操作系统》中有详细讲解。

SkyEye,中文全称天目全数字实时仿真软件,是基于可视化建模的硬件行为级仿真平台,支持用户通过拖拽的方式对硬件进行行为级别的仿真和建模。

SkyEye目前支持主流的嵌入式硬件平台,可以运行主流的操作系统,此外还能适配国内自主研发的操作系统天脉。通过利用基于LLVM的动态二进制翻译技术,使虚拟处理器在典型的桌面计算机上运行速度可以达到2000MIPS以上。

使用SkyEye仿真平台可以快速搭建leeos操作系统的硬件环境,还可以从搭建的过程中了解到硬件系统的总体架构。操作系统与硬件之间是紧密交互的关系,学习在SkyEye仿真平台中搭建硬件环境和编写其上的操作系统,有助于更深入的了解操作系统运行的原理。

本系列文章将分为两个部分:“准备篇”和“实验篇”。“准备篇”用来阐述《一步步写嵌入式操作系统》在实现leeos操作系统过程中遇到的一些操作系统概念和编程知识。“实验篇”用来复现原书在SkyEye仿真环境下运行leeos的实验。

01.helloworld!

现在编写一个简单的串口测试代码,并在SkyEye中运行起来。

#define UFCON0  ((volatile unsigned int *)(0x50000020))void helloworld(void){  const char *p="helloworld!\n";  while(*p){    *UFCON0=*p++;  };  while(1); }

此代码假设串口FIFO寄存器地址为0x50000020,通过向此地址依次写入字符最终会在串口中打印出字符串"helloworld!\n"。

将上述代码保存为helloworld.c,并使用”arm-elf-gcc -O2 -c helloworld.c” 会生成”helloworld.o”文件。使用”arm-elf-ld -e helloworld -Ttext 0x0 helloworld.o -o helloworld”指定生成的helloworld可执行文件的入口为helloworld函数,此函数代替了main函数。在使用”arm-elf-objcopy -O binary helloworld helloworld.bin”将可执行elf文件所包含的机器码抽离出来生成”helloworld.bin”文件。

配置SkyEye启动文件”helloworld.skyeye”,在此配置文件中会指定运行的arm核心、需要在硬件仿真环境中运行的bin文件路径、bin文件的烧写地址等信息。再通过图形建模等工具生成一个硬件描述文件”helloworld.json”,此文件中描述了硬件的建模信息,如内存、处理器、中断控制器、定时器、串口等大小型号。也可以直接导入受支持的某个开发板的硬件描述json文件。最后将helloworld.bin、helloworld.json和helloworld.skyeye文件放在一个目录中,启动天目.exe,打开启动文件,即可在term中显示出”helloworld!\n”。SkyEye会将串口输出映射到term中显示。

上述实验是一个简单的过程描述,具体实验部分可见后续的《一步步写嵌入式操作系统》-实验篇。

02.链接脚本

通常我们使用gcc编译程序时并没有使用链接脚本,这是因为arm-elf-ld链接工具会使用内嵌到链接工具内部的默认脚本,可使用-verbose参数来查看。

当应用程序运行在操作系统之上时,往往不需要显式指定链接脚本,因为自己写的链接脚本可能与操作系统默认环境不符,导致运行出错。但是如果程序运行于操作系统之下,或者就是操作系统本身,编写一个链接脚本就显得十分重要了。下面是一个链接脚本的例子:

ENTRY(helloworld)SECTIONS{  . = 0x00000000;  .text :{     *(.text)  }  . = ALIGN(32);  .data :{     *(.data)  }  . = ALIGN(32);  .bss :{     *(.bss)  }}

此链接脚本使用了一个非常重要的命令-SECTIONS,用来描述输出文件的内存布局,定义了程序各段的输出位置。

在程序链接时使用-T参数即可使用连接脚本,例如:

arm-elf-ld -T helloworld.lds helloworld.o -o helloworld。

03.Arm汇编语言

arm寄存器有参与普通运算的r0-r12,保存堆栈地址的r13,保存程序返回值的r14,记录程序地址待r15。r13、r14、r15有对应的别名SP、LR、PC。还有一个保存程序运行状态的特殊寄存器CPSR。

在实际应用中操作系统是由汇编和c语言编写的。下面是一个arm汇编程序的例子:​​​​​​​

.arch armv4.global helloworld.equ REG_FIFO, 0x50000020.text.align 2helloworld:  ldr r1,=REG_FIFO  adr r0,.L0.L2:  ldrb r2,[r0], #0x1  str r2,[r1]  cmp r2,#0x0  bne .L2.L1:  b .L1.align 2.L0:  .ascii "2.3_helloworld\n\0"

上面的汇编程序涉及到了一些伪指令,其含义如下:

.arch:选择程序运行的体系架构。

.global:声明某个符号对链接器可见,例如上面的.global helloworld会声明helloworld函数全局可见。

.equ:相当于C语言中的宏定义。

.text:表示接下来的代码会归并到代码段中。

.align:代码对齐。与sparc和X86等架构不同的是,arm的.align后面的数字已幂的形式出现。例如.align 4,在sparc、X86架构中代表4字节对齐,而在arm中就是16字节对齐。

.ascii:用于在内存中定义字符串。

ldr、adr:常量装载、地址装载其实也是伪指令。

04.汇编和C语言混合编程

很少有操作系统会完全用汇编实现,绝大部分是汇编和C语言一起写成的。

要具体实现汇编语言和C语言之间的混合编程,就必须制订一套统一的标准,我们将这套共同遵守的标准称为过程调用标准(Procedure Call Standard),简称PCS。

ARM的PCS有很多版本,如Thumb过程调用标准TPCS、ARM过程调用标准APCS,ARM-Thumb之间相互调用是的过程调用标准ATPCS。目前最新的一套过程调用标准名为AAPCS(Procedure Call Standard for the ARM Architecture)。

例:​​​​​​​

printf.arch armv4.global _start.equ REG_FIFO, 0x50000020.text.align 2_start:  ldr r0,=REG_FIFO  adr r1,.L0  bl helloworld("hello world!");

上例中使用bl helloworld指令实现了汇编调用c语言的过程。在bl之前向r0和r1赋值,从而向helloworld函数传参。

以上涉及到的操作系统概念与嵌入式技术在《一步步写嵌入式操作系统》中有更详细的讲解,推荐阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值