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的開發模式(倒計時時按下空格鍵)

2.使用tftp下載編譯好的skymixos.bin,並運行

那麼這個最簡單的OS,都包含些啥呢?

源文件倒很好理解,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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章