博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自制操作系统Antz day08——实现内核 (中) 扩展内核
阅读量:6329 次
发布时间:2019-06-22

本文共 4416 字,大约阅读时间需要 14 分钟。

  Antz系统更新地址: 

  Linux内核源码分析地址:

  Github地址: 

  在前几天的任务中,我们已经简单实现了MBR,直接操作显示器和硬盘操作来加载其他扇区的程序,如今已经可以进入保护模式了,并且编写了我们自己的内核程序,这个内核虽然什么也没有做,但还是成功被加载进内存了。接下来我们要将这个内核程序编写详细的内容了。

0. 切换堆栈和GDT

1 SELECTOR_KERNEL_CS    equ    8 2  3 extern    cstart 4 extern    gdt_ptr 5  6 [SECTION .bss] 7 StackSpace        resb    2 * 1024 8 StackTop:         9 10 [section .text]    11 global _start    12 13 _start:14     mov    esp, StackTop15     sgdt    [gdt_ptr]    16     call    cstart    17     lgdt    [gdt_ptr]    18     jmp    SELECTOR_KERNEL_CS:csinit19 csinit:        20     hlt

  这四行代码就可以完成切换堆栈和更换GDT任务了。StackTop定义在.bss段中,大小为2KB,操作GDT时用到了gdt_ptr和cstart分别时一个全局变量和全局函数,定义在c代码start.c中。

#include "type.h"#include "const.h"#include "protect.h"PUBLIC    void*    memcpy(void* pDst, void* pSrc, int iSize);PUBLIC void    disp_str(char * pszInfo);PUBLIC    t_8            gdt_ptr[6];     PUBLIC    DESCRIPTOR        gdt[GDT_SIZE]; PUBLIC void cstart(){    disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n-----\"cstart\" begins-----\n");    memcpy(    &gdt,                            (void*)(*((t_32*)(&gdt_ptr[2]))),           *((t_16*)(&gdt_ptr[0])) + 1                );    t_16* p_gdt_limit = (t_16*)(&gdt_ptr[0]);    t_32* p_gdt_base  = (t_32*)(&gdt_ptr[2]);    *p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;    *p_gdt_base  = (t_32)&gdt;}

 

  cstart()首先把位于Loader中的原GDT全部复制给新的GDT,然后把gdt_ptr中的内容换为新的GDT的基地址和界限。复制GDT用的是memepy,至于它的函数定义就不详细写了,这个是c中非常出名的一个函数了。

  当然还有一些类型,结构体和宏,这些可以放置在.h的头文件中。

  protect.h :

1 #ifndef    _TINIX_PROTECT_H_ 2 #define    _TINIX_PROTECT_H_ 3  4 typedef struct s_descriptor        /* 共 8 个字节 */ 5 { 6     t_16    limit_low;          7     t_16    base_low;  8     t_8    base_mid;      9     t_8    attr1;         10     t_8    limit_high_attr2; 11     t_8    base_high;         12 }DESCRIPTOR;13 14 #endif

  type.h :

1 #ifndef    _TINIX_TYPE_H_ 2 #define    _TINIX_TYPE_H_ 3  4  5 typedef    unsigned int        t_32; 6 typedef    unsigned short        t_16; 7 typedef    unsigned char        t_8; 8 typedef    int            t_bool; 9 10 11 #endif

  const.h :

1 #ifndef    _TINIX_CONST_H_ 2 #define    _TINIX_CONST_H_ 3  4  5 #define    PUBLIC      6 #define    PRIVATE    static     7  8 #define    GDT_SIZE    128 9 10 11 #endif

  接下来在linux下编译链接。

  nasm -f elf -o kernel.o kernel.asm

  nasm -f elf -o string.o string.asm

  gcc -c -o start.o start.c

  ld -s  -Ttext 0x30400 -o kernel.bin kernel.o string.o start.o

  将bin使用工具写入(day01或者dd) ,打开查看结果。

  可以看到cstart成功切换了堆栈与GDT。

 

1. Makefile

  随着代码量的增多,编译链接的命令也越来越多了,你可能之前没有接触过Makefile,但这是一个非常高效的东西,值得学习。

  Makefile 是和 make 命令一起配合使用的,很多大型项目的编译都是通过 Makefile 来组织的, 如果没有 Makefile, 那很多项目中各种库和代码之间的依赖关系不知会多复杂,Makefile的组织流程的能力如此之强, 不仅可以用来编译项目, 还可以用来组织我们平时的一些日常操作. 这个需要大家发挥自己的想象力.。

  Makefile基本语法如下:

1 target ... : prerequisites ...2     command3     ...
1 target ... : prerequisites ; command2     command3     ...

  target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

  prerequisites就是要生成那个target所需要的文件或是目标。

 

  command也就是make需要执行的命令。(任意的Shell命令)

 

  这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

 

  来举个例子:

1 # Makefile for boot 2  3 # Programs, flags, etc. 4 ASM        = nasm 5 ASMFLAGS    =  6  7 # This Program 8 TARGET        = boot.bin loader.bin 9 10 # All Phony Targets11 .PHONY : everything clean all12 13 # Default starting position14 everything : $(TARGET)15 16 clean :17     rm -f $(TARGET)18 19 all : clean everything20 21 boot.bin : boot.asm ./include/load.inc ./include/fat12hdr.inc22     $(ASM) $(ASMFLAGS) -o $@ $<23 24 loader.bin : loader.asm ./include/load.inc ./include/fat12hdr.inc ./include/pm.inc25     $(ASM) $(ASMFLAGS) -o $@ $<

  #是注释的意思, =用来定义变量 , ASM和ASMFLAGS就是两个变量,使用变量要用$(ASM)和$(ASMFLAGS) 。

  对于 target :  prerequistites 

          command 

  意思就是想要得到target就需要指向命令command。

  target依赖于prerequistites,当prerequistites中至少有一个文件比target文件新时,command才会执行。

  看看最后两行,要想得到loader.bin就需要执行命令:$(ASM) $(ASMFLAGS) -o $@ $<

  loader.bin依赖于loader.asm load.inc fat12hdr.inc pm.inc ,这些中只要有一个比target新,command就会执行。

  那么这里的command是什么意思呢?

1 $(ASM) $(ASMFLAGS) -o $@ $<

  $@  $< 其实就是target,prerequistites的第一个名字,所以这个命令等价于

1 nasm -o loader.bin loader.asm

  此外你可能还发现了在外的大标签,他们是动作名称,如everything,all,clean,它们用于make后面,比如make all ,make clean,然后就会执行相应的当作。

  对于Makefile我们目前只需要知道这些就可以了。

  对于Antz内核的编写将会暂时停止几天,最近准备看看Linux内核的相关知识。同步会更新在

 

转载地址:http://siboa.baihongyu.com/

你可能感兴趣的文章
oracle修改内存使用和性能调节,SGA
查看>>
SQL语言基础
查看>>
对事件处理的错误使用
查看>>
最大熵模型(二)朗格朗日函数
查看>>
深入了解setInterval方法
查看>>
html img Src base64 图片显示
查看>>
[Spring学习笔记 7 ] Spring中的数据库支持 RowMapper,JdbcDaoSupport 和 事务处理Transaction...
查看>>
FFMPEG中关于ts流的时长估计的实现(转)
查看>>
Java第三次作业
查看>>
【HDOJ 3652】B-number
查看>>
android代码混淆笔记
查看>>
Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction 并查集
查看>>
BMP文件的读取与显示
查看>>
Flash文字效果
查看>>
各种排序算法总结篇(高速/堆/希尔/归并)
查看>>
使用c#訪问Access数据库时,提示找不到可安装的 ISAM
查看>>
Highcharts X轴纵向显示
查看>>
windows 注册表讲解
查看>>
【算法】论平衡二叉树(AVL)的正确种植方法
查看>>
基于DDD的现代ASP.NET开发框架--ABP系列之1、ABP总体介绍
查看>>