OS实战笔记(2)-- 利用grub启动一个最简单的Tiny System

本实验介绍了如何利用GRUB启动一个简单的TinySystem,该系统由汇编初始化C运行环境,输出欢迎信息。实验涉及GRUB配置、X86上电引导流程、汇编初始化栈、C语言输出字符。通过修改Ubuntu的GRUB配置文件,创建启动菜单,然后编写汇编代码创建C环境并跳转执行C函数,最终在显示器输出字符串。
摘要由CSDN通过智能技术生成

        本小节,做一个实验,利用grub来启动一个最简单的小系统,这个系统的功能非常简单,先使用汇编初始化好C语言的运行环境(主要是配置好栈),然后向显示器输出"Welcom to Tiny System!"这几个字符。

        注意,本小节笔记只是为了简单做实验的目的,其中有很多细节暂时还不会提及。在后续笔记中,会详细做解释。如果不清楚某些细节也可以跳过。

        实验环境: Oracle VM VirtualBox虚拟机运行ubuntu 16.04

        继续跟着LMOS大神学习,早日完成这个项目

X86上电引导Tiny System流程极简概述

        此流程仅为了Tiny System阐述,很多细节都不会说,仅列出对本实验理解所需的重要步骤,如果想要了解详细的流程,CSDN上有很多大神有详细分析,请自行搜索,感谢。

        1. X86上电后,CPU的程序计数器PC的值来自BIOS固件。BIOS负责初始化硬件设备如CPU,时钟,内存,基本外设等。

        2. BIOS加载可引导设备的GRUB到内存,并且跳转到GRUB程序

        3. GRUB运行后,加载硬盘分区中的Tiny System文件

        4. GRUB工作完成,跳转至Tiny System的入口地址运行

        5. Tiny System汇编部分代码初始化X86,关闭中断,创建C语言运行环境

        6. Tiny System汇编部分工作完成,跳转到C语言入口函数

        7. Tiny Sytem C语言部分将“Tiny System”输出到显示器上

        关于ubuntu下的grub配置文件详细说明,有兴趣的可参考这里:

Ubuntu下Grub配置详解_Alix_sz的博客-CSDN博客_grub配置1 Grub简介1.1 GNU GRUBGNU GRUB(简称“GRUB”)是一个来自GNU项目的启动引导程序. GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数.GNU GRUB的前身为Grand Unified Boo...https://blog.csdn.net/humanof/article/details/100726977

实验过程

ubuntu启动显示grub菜单

        由于ubuntu默认的grub配置不会显示菜单,我们需要先将其打开。网上有很多文章讲这个操作,本笔记仅简单描述,这里也给出一个参考链接

Ubuntu显示grub启动菜单以及修改默认启动项 - 哔哩哔哩安装了新内核后想换回之前的内核,但是发现系统启动默认就进入了新内核。可以通过两个方式解决,一是开启grub启动菜单,主动选择内核;二可以修改默认启动的内核。下面看看具体如何操作。1、修改配置grub的配置位于/etc/default/grub下,打开它会看到配置选项。修改前三项就可以实现我们想要的效果,修改这个文件需要管理员权限。GRUB_DEFAULT设置默认启动项,默认是0,编号规则如下:所以如果默认想启动高级选项下的第三个,就需要改为“1> 2”,引号必须加,>和2之间有空格。这样系统开机https://www.bilibili.com/read/cv14681162        修改/etc/default/grub

        sudo update-grub将配置更新

        重启ubuntu,应该就可以看到grub菜单了

        能显示grub菜单后,我们再进入后面的步骤

Tiny System汇编部分

        Tiny System汇编代码主要是为了创建好C语言运行环境,由于C语言编译后的函数,都需要栈来实现函数的调用和返回,因此汇编部分最核心的工作是将栈指针初始化好。

        关于X86汇编,目前不需要了解太多,这里给一篇参考,快速了解一下即可

X86汇编快速入门_鱼儿-1226的博客-CSDN博客_汇编x86本文描述基本的32位X86汇编语言的一个子集,其中涉及汇编语言的最核心部分,包括寄存器结构,数据表示,基本的操作指令(包括数据传送指令、逻辑计算指令、算数运算指令),以及函数的调用规则。个人认为:在理解了本文后,基本可以无障碍地阅读绝大部分标准X86汇编程序。当然,更复杂的指令请参阅Intel相关文档。1 寄存器.主要寄存器如下图所示:X86处理器中有8个32位的通用寄存器。由于历史的原因,EAX通常用于计算,ECX通常用于循环变量计数。ESP和EBP有专门用途,ESP指示栈指针(用于指示栈https://blog.csdn.net/qq_21743659/article/details/120786059         汇编部分还涉及一点X86 I/O端口的知识,可参考这里

X86架构IO端口表_xqhrs232的博客-CSDN博客原文地址::http://blog.chinaunix.net/uid-27717694-id-3920569.htmlRedhat 5 /proc/ioports 独立编址的IO0000-001f : dma10020-0021 : pic10040-0043 : timer00050-0053 : timer10060-0060 : keybhttps://blog.csdn.net/xqhrs232/article/details/51274390?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-51274390-blog-104090982.pc_relevant_default&spm=1001.2101.3001.4242.2&utm_relevant_index=3        启动部分汇编如下:

        

MULBOOT_HEADER_FLAGS EQU 0x00010003
MULBOOT_HEADER2_MAGIC EQU 0xE85250D6 ;GRUB2 multiboot magic

global _start 
extern main 
[section .start.text] 
[bits 32] 
_start:
jmp _entry
ALIGN 8
mbt2_hdr:
dd MULBOOT_HEADER2_MAGIC
dd 0 ;architecture 0 - i386
dd mbt2_hdr_end - mbt2_hdr ; header_length
dd -(MULBOOT_HEADER2_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:

ALIGN 8
_entry:
cli ;clear  interrupts
in al, 0x70 ;disable NMI
or al, 0x80
out 0x70,al
lgdt [GDT_PTR]
jmp dword 0x8 :_32bits_mode
_32bits_mode:
;initialize all registers needed by 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
;Initalize stack pointer register
mov esp,0x9000
call main
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

        目前这个汇编文件关键的功能在注释中给出。总体来说,汇编做的事情主要有:

        1. 定义grub mutliboot2 的header

        2. 关闭普通中断和NMI

        3. 创建C语言运行环境

        4. 跳转到C的main函数

        现在这个阶段也不用过于纠结不懂的地方。在后续笔记中会深入细节讲解。

Tiny SytemC语言部分

#define VGA_DIAPLAY_BUFFER      0xb8000

void vga_display_string(char *string)
{
        char *vga_buffer = (char *)VGA_DIAPLAY_BUFFER;
        while (*string != '\0') {
                *vga_buffer = *string++;
                vga_buffer += 2;//VGA buffer format: ASCII + Character color
        }
}

void main()
{
        vga_display_string("Welcome to Tiny System");
}

        C语言部分主要是向VGA字符模式下的buffer中写入字符串的ASCII码,显卡会将这块区域内的buffer显示到屏幕上。关于显卡的字符模式说明,参考这里

4. 字符模式下的显卡驱动 - 灰信网(软件开发博客聚合)4. 字符模式下的显卡驱动,灰信网,软件开发博客聚合,程序员专属的优秀博客文章阅读平台。icon-default.png?t=M5H6https://www.freesion.com/article/4263791592/

 Tiny System Makefile

MAKEFLAGS = -sR
MKDIR = mkdir
RMDIR = rmdir
CP = cp
CD = cd
DD = dd
RM = rm

ASM             = nasm
CC              = gcc
LD              = ld
OBJCOPY = objcopy

ASMBFLAGS       = -f elf -w-orphan-labels
CFLAGS          = -c -Os -std=c99 -m32 -Wall -Wshadow -W -Wconversion -Wno-sign-conversion  -fno-stack-protector -fomit-frame-pointer -fno-builtin -fno-common  -ffreestanding  -Wno-unused-parameter -Wunused-variable
LDFLAGS         = -s -static -T tiny_sys.lds -n -Map TinySystem.map
OJCYFLAGS       = -S -O binary

TINYSYSTEM_OBJS :=
TINYSYSTEM_OBJS += tiny_system_entry.o main.o
TINYSYSTEM_ELF = TinySystem.elf
TINYSYSTEM_BIN = TinySystem.bin

.PHONY : build clean all link bin

all: clean build link bin

clean:
        $(RM) -f *.o *.bin *.elf

build: $(TINYSYSTEM_OBJS)

link: $(TINYSYSTEM_ELF)
$(TINYSYSTEM_ELF): $(TINYSYSTEM_OBJS)
        $(LD) $(LDFLAGS) -o $@ $(TINYSYSTEM_OBJS)
bin: $(TINYSYSTEM_BIN)
$(TINYSYSTEM_BIN): $(TINYSYSTEM_ELF)
        $(OBJCOPY) $(OJCYFLAGS) $< $@

%.o : %.s
        $(ASM) $(ASMBFLAGS) -o $@ $<
%.o : %.c
        $(CC) $(CFLAGS) -o $@ $<

        运行make命令(Makefile请在“本小节代码”一节中去下载,或者自己手动写也可以),生成TinySystem.bin。

让Grub启动Tiny System

        修改grub.cfg添加启动项

        df /boot查看boot分区所使用的块设备,我的ubuntu系统输出如下

Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda5       65274444 11657876  50271112  19% /

        grub配置sda,要换成hd0,msdos,因此我们要在grub.cfg中插入下面的内容添加一个启动项菜单

menuentry 'TinySytem' {
        insmod part_msdos
        insmod ext2
        set root='hd0,msdos5'
        multiboot2 /boot/TinySystem.bin
        boot
}

        添加后,重启ubuntu,应该可以看到grub菜单多出一项

         选择TinySystem后,可以看到屏幕上输出了“Welcome to Tiny System!”

         各位如果按照这个笔记里的C语言main函数代码写,会发现字符不是红色的。这是留给各位自己去实现的一个功能,去看如何修改程序让字符颜色变化。

本小节代码

        https://gitee.com/vivo01/os_e/tree/master/TinySystem_1stDemoicon-default.png?t=M5H6https://gitee.com/vivo01/os_e/tree/master/TinySystem_1stDemo

        TinySystem_1stDemo

参考资料

        Grub Multiboot规范_加油小懒的博客-CSDN博客_grub multiboot

        [操作系统原理与实现]Multiboot与GRUB_cloudblaze的博客-CSDN博客_grub multiboot

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦枫Leonlew

希望这篇文章能帮到你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值