ARMV8上实现一个OS ---(2)从hello World!开始

        本章节,我们将使用qemu模拟一个cortex-a57的设备,并在上边输出一个hello类型的输出。开始之前,先了解一下AArch64的一些相关知识。更详细的内容可参照arm发布的手册。

AArch64的异常等级

在ARMV8的体系结构里,可执行程序都运行在一个特定的异常等级上。不同的异常等级有不同的权限。

ARMV8的异常等级

异常等级运行的典型程序
EL0普通的用户应用程序(APP)
EL1操作系统的内核(Kernel)
EL2虚拟化管理程序(Hypervisor.)
EL3安全监视程序(Secure monitor)

  

AArch64的寄存器

AArch64的寄存器分为以下几种:

1)通用寄存器

        包含了31个64位通用寄存器X0~X30,其中X29也被称为FP,X30也被称为LR

        W0~W30则分别表示X0~X30的低32位。(可能是为了兼容AArch32)

 2)特殊寄存器

XZR--这个寄存器的值一直是0,通常用于清零或者和0进行比较。

PC--程序计数器。

SP--栈指针寄存器,每个特权等级有单独的,方便进行等级切换。由PSTATE寄存器中的SP位决定使用哪个等级的SP.

ELR--异常链接寄存器,指示产生异常的地址。EL0的异常会陷入到内核中,因此没有EL0级别的ELR

3)系统寄存器 

        包含页表基地址寄存器、控制寄存器、定时器计数寄存器等等。这里不一一介绍,用到的时候再说。

构建基础工程

代码目录如下:

.
├── kernel                    //内核相关的代码
│   ├── arch                  //硬件架构相关代码
│   │   ├── aarch64           //aarch64相关的代码
│   │   │   └── boot.s        //aarch64启动阶段的代码
│   │   ├── CMakeLists.txt
│   │   └── include           //通用的头文件位置
│   │       ├── mem.h
│   │       └── reg_op.h
│   ├── CMakeLists.txt
│   └── include                //kernel总的头文件位置
│       └── type.h
└── vendor                     //板子相关的代码
    ├── board
    │   ├── CMakelists.txt
    │   ├── include            //通用头文件
    │   │   └── mem_addr.h
    │   ├── main.c             //函数入口
    │   └── qemu_a57           //板级---qemu_a57相关的内容
    │       ├── include
    │       │   └── mm.h       //内存地址的分布
    │       └── uart_pl011.c   //pl011的串口驱动
    ├── build_hfos.sh          //构建工程的脚本
    ├── cmake                  //cmake文件存放处
    │   ├── link.ld
    │   └── qemu_a57.cmake     //qemu_a57编译用的cmake文件
    ├── CMakeLists.txt
    ├── env_setup              //编译用的环境变量
    ├── include                //通用头文件的定义,不同板子需要实现
    │   └── uart.h
    └── run_hfos.sh            //编译完成后运行仿真的脚本

代码 

section ".text.boot"

.globl _start
_start:
    mrs	x0, mpidr_el1   //获取cpu num MPIDR_ELn Multiprocessor Affinity Register
    and	x0, x0,#0xFF    
    cbz x0, main_core    //等于0,跳转到main_core标签
    b slave_core        //不等于0,跳转到无限循环

//启动主核
main_core:
    //初始化BSS段
    adr	x0, bss_begin    
	adr	x1, bss_end
    cmp x0, x1            //比较是否相等
    b.eq set_sp           //相等则不进行清零
meminit:
    str xzr, [x0], #8     //进行清零操作
    cmp x0, x1
    b.ne meminit          //循环执行

    //给main函数设置栈地址,跳转到主函数运行
set_sp:
    mov sp, 0x60000000        //设置到一个有效的物理内存地址
    bl main
    b dead_loop


//死循环
dead_loop:
    b dead_loop

//不启动从核,让他自旋
slave_core:
    b dead_loop

main.c

#include "mem_addr.h"
#include "uart.h"

void delay(int cnt)
{
    while (cnt--) {
        ;
    } 
}


void main(void)
{
    uart_init();            //初始化一个串口,然后打印一些信息
    uart_send_string("  _      __  ____   _____ \n");
    uart_send_string(" | |    / _|/ __ \\ / ____|\n");
    uart_send_string(" | |__ | |_| |  | | (___  \n");
    uart_send_string(" | '_ \\|  _| |  | |\\___ \\ \n");
    uart_send_string(" | | | | | | |__| |____) |\n");
    uart_send_string(" |_| |_|_|  \\____/|_____/ \n");



    uart_send_string("Start with Hello world!\n");
    delay(1000000000);
    uart_send_string("Tomorrow will be better!\n");
    delay(1000000000);
    uart_send_string("hfOS go! go! go!\n");

    while (1) {
        ;
    }
}

其他信息

我们在mm.h中定义了如下的地址信息,并添加了一个pl011的串口驱动,那是如何确定串口芯片,内存地址等信息呢?

我们在run_hfOS.sh中的运行命令为

qemu-system-aarch64 -m 1024 -machine virt,gic-version=3,virtualization=on -cpu cortex-a57 -smp 4 -nographic -kernel ../build/out/bin/hfOS_qemu_a57.elf

 qemu会根据我们的命令生成对应的设备树,我们把设备树信息导出来就可以看到内存地址,驱动芯片等相关信息了。

调用如下的指令将此次使用的dtb文件导出来

qemu-system-aarch64 -m 1024 -machine virt,dumpdtb=dump.dtb,gic-version=3,virtualization=on -cpu cortex-a57 -smp 4 -nographic

然后使用dtc工具将dtb转换为dts文件

dtc -I dtb -O dts -o dump.dts dump.dtb

 打开后能看到如下信息,确定内存的起始位置是0x40000000,PL011的基地址是0x9000000

手册:

PL011手册地址

cortex系列编程手册       

 代码编译和运行

git clone https://gitee.com/genglufei/hfos.git
cd hfOS/day1_boot/hfOS/vendor
./build_hfos.sh qemu_a57
./run_hfos.sh

运行结果如下: 

下一章节我们将尝试为OS添加一个任务,并运行起来。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值