1. 程式人生 > 其它 >linux中部署自己的系統核心

linux中部署自己的系統核心

1、計算機是如何將系統起起來的?-- PC機的引導流程

PC機BIOS韌體是固化在PC機主機板上的ROM晶片中,斷電也能儲存,PC機上電後的第一條指令就是在BIOS韌體中,它負責檢測和初始化CPU、記憶體和主機板平臺,然後載入引導裝置(大概率是硬碟)中的第一個扇區資料,到0x7c00地址開始的記憶體空間,再跳轉到0x7c00處執行指令。這裡是GRUB載入程式。

GRUB:GNU GRUB(GRand Unified Bootloader簡稱“GRUB”)是一個來自GNU專案的多作業系統啟動程式。GRUB是多啟動規範的實現,它允許使用者可以在計算機內同時擁有多個作業系統,並在計算機啟動時選擇希望執行的作業系統。GRUB可用於選擇作業系統分割槽上的不同核心,也可用於向這些核心傳遞啟動引數。

參考:百度百科

2、Hello OS引導彙編程式碼

為什麼不能直接用C?

C 作為通用的高階語言,不能直接操作特定的硬體,而且 C 語言的函式呼叫、函式傳參,都需要用棧。
棧,資料滿足後進先出的特性,它由CPU特定的暫存器指向,所以需要先用匯編程式碼處理好C語言的工作環境

;彭東 @ 2021.01.09
MBT_HDR_FLAGS EQU 0x00010003
MBT_HDR_MAGIC EQU 0x1BADB002 ;多引導協議頭魔數
MBT_HDR2_MAGIC EQU 0xe85250d6 ;第二版多引導協議頭魔數
global _start ;匯出_start符號
extern main ;匯入外部的main函式符號
[section .start.text] ;定義.start.text程式碼節
[bits 32] ;彙編成32位程式碼
_start:
jmp _entry
ALIGN 8
mbt_hdr:
dd MBT_HDR_MAGIC
dd MBT_HDR_FLAGS
dd -(MBT_HDR_MAGIC+MBT_HDR_FLAGS)
dd mbt_hdr
dd _start
dd 0
dd 0
dd _entry
;以上是GRUB所需要的頭
ALIGN 8
mbt2_hdr:
DD MBT_HDR2_MAGIC
DD 0
DD mbt2_hdr_end - mbt2_hdr
DD -(MBT_HDR2_MAGIC + 0 + (mbt2_hdr_end - mbt2_hdr))
DW 2, 0
DD 24
DD mbt2_hdr
DD _start
DD 0
DD 0
DW 3, 0
DD 12
DD _entry
DD 0
DW 0, 0
DD 8
mbt2_hdr_end:
;以上是GRUB2所需要的頭
;包含兩個頭是為了同時相容GRUB、GRUB2
ALIGN 8
_entry:
;關中斷
cli
;關不可遮蔽中斷
in al, 0x70
or al, 0x80
out 0x70,al
;重新載入GDT
lgdt [GDT_PTR]
jmp dword 0x8 :_32bits_mode
_32bits_mode:
;下面初始化C語言可能會用到的暫存器
mov ax, 0x10
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
xor edi,edi
xor esi,esi
xor ebp,ebp
xor esp,esp
;初始化棧,C語言需要棧才能工作
mov esp,0x9000
;呼叫C語言函式main
call main
;讓CPU停止執行指令
halt_step:
halt
jmp halt_step
GDT_START:
knull_dsc: dq 0
kcode_dsc: dq 0x00cf9e000000ffff
kdata_dsc: dq 0x00cf92000000ffff
k16cd_dsc: dq 0x00009e000000ffff
k16da_dsc: dq 0x000092000000ffff
GDT_END:
GDT_PTR:
GDTLEN dw GDT_END-GDT_START-1
GDTBASE dd GDT_START
  1. 程式碼 1~40 行,用匯編定義的 GRUB 的多引導協議頭,其實就是一定格式的資料,我們的 Hello OS 是用 GRUB 引導的,當然要遵循 GRUB 的多引導協議標準,讓 GRUB 能識別我們的 Hello OS。之所以有兩個引導頭,是為了相容 GRUB1 和 GRUB2。
  2. 程式碼 44~52 行,關掉中斷,設定 CPU 的工作模式
  3. 程式碼 54~73 行,初始化 CPU 的暫存器和 C 語言的執行環境。
  4. 程式碼 78~87 行,GDT_START 開始的,是 CPU 工作模式所需要的資料

Hello OS 的主函式

#include "vgastr.h"
void main()
{
    printf("Hello OS!");
    return;
}

注意:這裡的printf不是應用程式庫中的printf,是需要自己實現的

具體實現如下:

void _strwrite(char* string)
{
    char* p_strdst = (char*)(0xb8000);//指向視訊記憶體的開始位置
    while (*string)
    {

        *p_strdst = *string++;
        p_strdst += 2;
    }
    return;
}

void printf(char* fmt, ...)
{
    _strwrite(fmt);
    return;
}

顯示卡的字元模式的工作細節:

它把螢幕分成 24 行,每行 80 個字元,把這(24*80)個位置對映到以 0xb8000 地址開始的記憶體中,每兩個位元組對應一個字元,其中一個位元組是字元的 ASCII 碼,另一個位元組為字元的顏色值。如下圖所示:

因此在上述顯示printf的程式碼中要從0xb8000 開始寫,p_strdst 每次+2跳過字元的顏色空間的原因

編譯

  • 連結器-map選項
LDFLAGS		= -s -static -T hello.lds -n **-Map** HelloOS.map 
OJCYFLAGS	= -S -O binary

該選項將使得在連結過程中,生成連結佈局檔案,通過該檔案可知HelloOS的記憶體對映佈局
編譯HelloOS時生成的map檔案如下圖所示:

安裝HelloOS

將HelloOS作為一個作業系統啟動項供grub啟動,因此需要能夠在PC啟動時進入grub引導選單,並選擇啟動HelloOS
為了能夠每次啟動時進入grub引導選單,需要進行如下設定

  • 修改/etc/default/grub

a. 註釋掉HIDDEN所在的2行
b. 將GRUB_TIMEOUT設定為30(使用預設值10其實也可以)
c. 將GRUB_CMDLINE_LINUX_DEFAUL設定為text
參考

執行如下命令,更新grub配置

sudo update-grub
  • 增加HelloOS啟動選項
    修改/boot/grub/grub.cfg,增加HelloOS啟動項
menuentry 'HelloOS' {
    insmod part_msdos
    insmod ext2
    set root='hd0,msdos5' #注意boot目錄掛載的分割槽,這是我機器上的情況
    multiboot2 /boot/HelloOS.bin
    boot
}

PS:
使用df /boot 檢視/boot分割槽情況

  • 把HelloOS.bin檔案複製到/boot/目錄下

重啟虛擬機器,便可看到HelloOS啟動項


選擇該啟動項,即可啟動HelloOS