开发单片类Unix操作系统-入门(1)

由于对试验文章“开发类似Microkernel的Unix OC-Scheduler”的负面评论,我决定在考虑一些评论的情况下重新开始系列文章。 现在,在实现了目标受众之后,我就可以将重点从同仁转移到真正需要它的人身上。

对上一篇文章的评论的回应。


备注1.调度程序太简单了。

自从上一篇文章发表以来,代码已发生了很大变化。 形成了一个完整的核,不再是微核。 支持初始ram磁盘(内核文件系统),支持虚拟内存(MMU)。 内核可以编写自定义程序。 有系统调用和clib库(stdio,字符串)。 因此,/ initrd / sh.elf外壳程序是一个独立的程序,由elf引导加载程序进行解析并作为进程运行。

Shell命令列表:exec <file.elf>,ps,kill,退出。 在这种情况下,可以从外壳本身启动外壳(演示多任务)。

注意2。视频教程的幕后内容太多了。

我决定突出显示我当前正在解释的文本。 他还面向需要澄清和最简单事物的初学者。 老实说,令我感到惊讶的是,没有编程经验的新人对如此复杂的话题感兴趣,尽管这是隐藏的罪恶,但我还是从这里开始。 我将偏见从解释操作系统转变为解释如何编写OC。

备注3.github的链接在哪里?

现在她了。 在YouTube上的视频说明中 (是的,我希望您不要忽略我的视频教程,至少要看一眼)。

备注4.我们应该从组装开始。

那就是我们要做的。

备注5.您不写任何东西,而只是评论。

是的,马上谈论一些大事是错误的。 现在,我们将从最简单的Hello world内核开始逐步进行操作。 视频教程可让您创建一个完整的世界图景,而github上的源代码将使您沉浸在细节中。

目录。


1.构建系统(make,gcc,gas)。 初始引导(多次引导)。 启动(qemu)。 C库(strcpy,memcpy,strext)。
2. C库(sprintf,strcpy,strcmp,strtok,va_list ...)。 以内核模式和用户应用程序模式构建库。
3.内核系统日志。 显存 输出到终端(kprintf,kpanic,kassert)。
4.动态内存,一堆(kmalloc,kfree)。
6.内存和中断处理的组织(GDT,IDT,PIC,系统调用)。 例外情况
5.虚拟内存(页面目录和页面表)。
6.过程。 策划人 多任务处理。 系统调用(kill,exit,ps)。
7.内核(initrd),elf及其内部文件系统。 系统调用(执行)。
8.字符设备驱动程序。 系统调用(ioctl,fopen,fread,fwrite)。 C库(fopen,fclose,fprintf,fscanf)。
9.将Shell作为内核的完整程序。
10.用户保护模式(ring3)。 任务状态段(tss)。

走吧 第1部分。构建系统并启动


在本文中,我将仅列出关键步骤 。 有关详细说明,请参阅本文的视频教程。

您需要Linux。 我们将收集优质旧货。 为了编译内核可执行文件,需要以下标志:

CC_FLAGS=-g -m32 -isystem $(IDIR) -I include -DKERNEL=1 -fno-stack-protector -Wall -Werror -fno-pie AS_FLAGS=-g --32 LD_FLAGS=-m elf_i386 

作为硬件模拟器,请在Linux上安装qemu模拟器。 我们将像这样运行内核:

 qemu-system-i386 -kernel ./bin/kernel.elf 

链接器也将需要一个小的脚本。 为了以正确的地址和正确的顺序加载节,这是必需的。 同样在其中,我们将指示入口点:

 OUTPUT_FORMAT(elf32-i386) ENTRY(start) SECTIONS { . = 0x100000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } } 

由于将根据多重引导规范加载内核,因此在代码部分的开头将需要标头:

 .code32 .text # multiboot spec .align 4 multiboot: .long 0x1BADB002 # magic .long 0x00 # flags .long -(0x1BADB002 + 0x00) # checksum. m+f+c should be zero 

建议您立即切换到自己的堆栈并设置全局描述符表。 定义我们自己的堆栈:

 .bss .fill 8192,1 # 8Kb stack: 

写一个入口点。 您可能会发现gnu汇编器语法不寻常。 我曾经也喜欢Intel语法,然后尝试了一下,深入研究Linux源代码,我完全为我自己喜欢AT&T语法,主要要记住的是它们具有相反的操作数。 其余的将很直观。

 start: cli movl $stack,%esp push %esp push %ebx /* address of struct multiboot_t */ call kernel_start /* should never return */ hlt 

这样就完成了样板代码。 有趣的开始。 现在我们可以用C语言编写代码。首先,我们将定义问候消息。

 char *hello = "Hello world!"; int screen_size = 80 * 25; 

接下来,我们编写入口点本身,汇编代码将控制权转移到该入口点:

 /* * Api - Kernel entry point */ extern void kernel_start(struct multiboot_t* multiboot, void* kstack) { char *video = (char*)0xB8000; char buff[screen_size + 1]; video[screen_size] = '\0'; memset(buff, ' ', screen_size); strext(video, buff, 0x7); strext(video, hello, 0x7); } 

在这里,我们仅在屏幕上显示消息。 原则上,您可以完全复制第一节课的代码,因为它是模板,并且永远不会更改。 为了在屏幕上显示某些内容,您只需将其直接写入视频存储器,并用属性符号补充每个字符。 为此,您将需要自己的C库,我们将根据需要编写自己的C库。 因此,控制过程将更加容易。 因此,例如,今天我们可以使用2个熟悉的函数(strcpy,memcpy)和我们自己的strext之一,以便在每个字符后插入属性字节。

结论


今天就这些了。 观看视频教程,尝试自己做。 如果无法解决问题,您可以在github上查看课程的源代码。 在视频教程说明中链接到github

文学作品



1.詹姆斯·莫洛伊(James Molloy)。 滚动自己的玩具UNIX克隆操作系统。
2.牙齿。 DOS,Windows,Unix的汇编器
3.卡拉什尼科夫。 汇编程序很简单!
4. Tanenbaum。 操作系统。 实施与开发。
5.罗伯特·洛夫(Robert Love)。 Linux内核 开发过程的描述。

Source: https://habr.com/ru/post/zh-CN466365/


All Articles