skymixos之"Hello Skymixos"

  学编程的童鞋门写的第一个程序估计都是"hello world"吧,那我们自己实现的os,第一个功能也是来个“Hello Skymixos”的功能!

  趁着清明节的这几天假期,开始鼓捣skymixos(这是个啥?就是笔者前文说的一个简单的类Linux系统)。既然是个OS,必然有运行的硬件平台,翻箱倒柜找了一圈,接口完整还能用的海思板子就剩下下图这个“老古董”了,没办法,就它了!

至于主机开发环境,好整!那台老旧的笔记本装个Ubuntu16.04也能跑的杠杠的!一看这配置就知道有年头了:
skymixos@skymixos-Latitude-E6400:~/work/skymixos$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Duo CPU     P8700  @ 2.53GHz
stepping        : 10
microcode       : 0xa0b
cpu MHz         : 797.401
cache size      : 3072 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fdiv_bug        : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts cpuid aperfmperf pni dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm pti tpr_shadow vnmi flexpriority dtherm ida
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit
bogomips        : 5050.20
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

processor       : 1
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Duo CPU     P8700  @ 2.53GHz
stepping        : 10
microcode       : 0xa0b
cpu MHz         : 797.401
cache size      : 3072 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fdiv_bug        : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts cpuid aperfmperf pni dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm pti tpr_shadow vnmi flexpriority dtherm ida
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit
bogomips        : 5050.20
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:
但这完全不影响咱开发啊,装个交叉工具链就可以编译程序了。交叉工具就直接用海思SDK包里的arm-hisiv400-linux,找到并安装这个工具应该不难。至于编辑代码编辑工具,vscode就不错!

  至于我们的目标是OS,必然不是从ARM上电后的第一条指令写起(后面可以把这方面的代码加上),而是将我们编译出来的skymixos.bin让u-boot去引导启动。我们当前最简单的目标就是u-boot启动引导OS后打印出一句“Hello Skymixos”(不是hello world哦),没有耐心的朋友估计不愿在看下去了,直接上现象再慢慢讲解怎么做到这一切的吧:

1.让目标板进入u-boot的开发模式(倒计时时按下空格键)

skymixos之

2.使用tftp下载编译好的skymixos.bin,并运行

skymixos之

那么这个最简单的OS,都包含些啥呢?

skymixos之

源文件倒很好理解,Makefile也不难理解,那这个skymixos.lds是干啥用的呢,平时编程也没用过?

要是小伙伴门学过韦东山老师的裸机开发应该就不会默认这个文件的作用,实在不知道,百度一下就明白了。

 

下面就来分析下这个最简陋的OS(甚至都不能称为OS)的程序都干了些啥事,上代码:

 .extern     main
.text
.global _start
_start:
    ldr sp, =0x84000000       /* 将栈设置在内存地址0x84000000处 */
    ldr lr, =halt_loop        /* 设置跳转返回的目标 */
    ldr pc, =main             /* 跳转到main标号处执行 */
halt_loop:
    b   halt_loop             /* 从main函数返回后将在此处死循环 */

我们在操作系统上编写App时都知道程序是从main函数开始执行的,那为啥是main而不是别的函数名呢?对于OS的基础程序不被其他程序调用执行,入口点又是哪呢?这时候连接脚本就发挥它的作用了。

skymixos.lds (Copy自u-boot中的u-boot.lds)
---------------------------------------------------------------------------
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
    . = 0x82000000;
    . = ALIGN(4);
    .text :
    {
        __text_start = .;
        head.o
        /*
        arch/arm/cpu/hi3518ev200/start.o (.text)
        arch/arm/cpu/hi3518ev200/lowlevel_init_svb.o (.text)
        drivers/ddr/ddr_training_impl.o (.text)
        drivers/ddr/ddr_training_ctl.o (.text)
        drivers/ddr/ddr_training_boot.o (.text)
        drivers/ddr/ddr_training_custom.o (.text)
        */
        __init_end = .;
        ASSERT(((__init_end - __text_start) < 0x4000), "init sections too big!");
        *(.text)
    }
    . = ALIGN(4);
    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
    . = ALIGN(4);
    .data : { *(.data) }
    . = ALIGN(4);
    .got : { *(.got) }
    __u_boot_cmd_start = .;
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;
    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss) }
    _end = .;
}

没错,skymixos.lds中将程序的入口点设置为_start,而head.S又放在了text段的最前面,也就是0x82000000这个地址处,因此当CPU从0x82000000这个地址执行时就从head.S的第一条指令开始执行了。head.S的功能也是相当简单,设置好栈地址后就跳转到main标号处执行了(终于回到我们熟悉的main函数了)

main.c
------------------------------------------------------------------
#include "serial_pl01x.h"


int main(void)
{		
	serial_init();
	serial_puts("+++ Hello Skymixos +++\n");

	return 0;
}

而我们的main函数也是一如既往的简单,初始化了串口后,通过串口打印出激动人心的“+++ Hello Skymixos +++”字符串,之后就返回,整个程序就进入无限循环中了。

剩下的几个文件(serial_pl01x.c, serial_pl01x.h platform.h)就很好理解了,实现了硬件串口相关的功能(从串口中输出一个字符,输入一个字符)

既然号称是个OS,那肯定要有我们常用的printf, scanf等这些格式化输入输出的功能,别急,下篇就将实现格式化输入输出的功能!!!!

完整的源码可以从阿里云的代码仓库中下载:[email protected]:luopinjing/skymixos.git

你可能感兴趣的:(Skymixos,嵌入式,编程语言)