《操纵系统真象还原》第八章(1)——内存管理系统

打印 上一主题 下一主题

主题 1842|帖子 1842|积分 5526

前言

前两天北方大风,不太好去实行室,《真象还原》的学习有所搁置,这两天继承。
第八章标题内存管理系统,下面分5节。分别是makefile相关、实现assert断言、实现字符串操纵函数、位图相关、内存管理系统。我们的博客也分成这几部分。
贴一下我的第七章博客链接和本章参考的love6博客链接:
《操纵系统真象还原》第七章(1)——中断-CSDN博客
《操纵系统真象还原》第七章(2)——中断-CSDN博客
《操纵系统真象还原》第八章 ---- 初入内存管理系统 涉足MakeFile 了解摸谈一二_makefile内存管理-CSDN博客

makefile相关

简单来说makefile是一种脚本,由make指令实行。通过查验依赖文件的mtime是否比目标文件mtime新,决定是否实行makefile里的指令。
这部分内容在P358页,博客不再具体阐明,使用时多查阅即可。
根本语法
  1. 目标文件:依赖文件
  2. [Tab]命令
复制代码
跳转到目标处实行
实行完一个目标后就退出,不再实行背面的指令,格式如下
  1. make 目标名称
复制代码
伪目标
  1. .PHONY:伪目标名
复制代码
常见伪目标名称截图

自定义变量与系统变量
  1. 自定义变量定义的格式:变量名=值(字符串)
  2. 自定义变量引用的格式:$(变量名)
复制代码
系统变量表截图

隐含规则
反斜杠\是多行之间的连续符。井号#用来注释。
在缺少依赖文件时,make指令按照一些默认的习惯,用隐含的规则完善依赖文件。简单的说就是主动编译,根据源码文件.c、.cc、.C、.p生成目标文件.o。
主动化变量
一种能代表一类文件文件名的符号。


  •                                         @                            ,表现规则中的目标文件名聚集,如果存在多个目标文件,                                  @,表现规则中的目标文件名聚集,如果存在多个目标文件,                     @,表现规则中的目标文件名聚集,如果存在多个目标文件,@则表现其中每一个文件名。助记,’@’ 很像是at,aim at,表现对准目标。
  • $<,表现规则中依赖文件中的第1个文件。助记,‘<’很像是聚集的最左边,也就是第1个。
  •                                                              ,                                      表现规则中所有依赖文件的聚集,如果聚集中有重复的文件,                                  ^,表现规则中所有依赖文件的聚集,如果聚集中有重复的文件,                     ,表现规则中所有依赖文件的聚集,如果聚集中有重复的文件,会主动去重。助记,’’很像从上往下 罩的动作,能罩住很大的范围,所以称为聚集。
  • $?,表现规则中,所有比目标文件 mtime 更新的依赖文件聚集。助记,’?’表现疑问,make 最大的疑 问就是依赖文件的mtime是否比目标文件的mtime要新。
模式规则
就一句话,%用来匹配恣意多个非空字符。好比%.o代表所有以.o为结尾的文件,g%s.o是以字符g开头的所有以.o 为结尾的文件,make会拿这个字符串模式去文件系统上查找文件,默认为当前路径下。

实现assert断言

简单来说就是写一个debug程序,如果内核运行过程中出错,这个程序告诉我们哪个文件哪个函数哪行出了问题,把相关信息打印到屏幕上,帮助我们解决问题。下面直接给出代码。
interrupt.c

新增部分是两行宏定义和四个函数。关于这个罗列体还有四个函数的声明,看下面的interrupt.h。
  1. #define EFLAGS_IF 0x00000200   // 中断标志位IF,在EFLAGS寄存器中
  2. #define GET_EFLAGS_IF(EFLAGS_VAR) asm volatile ("pushfl ; popl %0" : "=g" (EFLAGS_VAR)) // 获取中断标志位IF
  3. /* 开启中断并返回开启中断之前的状态 */
  4. enum intr_status intr_enable(void) {
  5.    enum intr_status old_status;
  6.    if(INTR_ON == intr_get_status()) {
  7.       old_status= INTR_ON;        // 如果当前中断已经打开,则直接返回
  8.       return old_status;
  9.    }
  10.    else {
  11.       old_status = INTR_OFF;        // 如果当前中断关闭,则打开中断
  12.       asm volatile ("sti");        // 开中断
  13.       return old_status;
  14.    }
  15. }
  16. /* 关闭中断并返回在关闭中断之前的状态 */
  17. enum intr_status intr_disable(void) {
  18.    enum intr_status old_status;
  19.    if(INTR_OFF == intr_get_status()) {
  20.       old_status = INTR_OFF;        // 如果当前中断已经关闭,则直接返回
  21.       return old_status;
  22.    }
  23.    else {
  24.       old_status = INTR_ON;        // 如果当前中断打开,则关闭中断
  25.       asm volatile ("cli" : : : "memory");        // 关中断
  26.       return old_status;
  27.    }
  28. }
  29. /* 将中断状态设置为status */
  30. enum intr_status intr_set_status(enum intr_status status) {
  31.    return (status & INTR_ON) ? intr_enable() : intr_disable();
  32. }
  33. /* 获取当前中断状态 */
  34. enum intr_status intr_get_status(void) {
  35.    uint32_t eflags = 0;
  36.    GET_EFLAGS_IF(eflags);
  37.    return (eflags & EFLAGS_IF) ? INTR_ON : INTR_OFF;
  38. }
复制代码
interrupt.h

新增部分是一个罗列声明,四个函数声明,直接贴出完整代码
  1. #ifndef __KERNEL_INTERRUPT_H
  2. #define __KERNEL_INTERRUPT_H
  3. #include "stdint.h"
  4. typedef void* intr_handler;
  5. void idt_init(void);
  6. /* 定义中断的两种状态 */
  7. /*关于枚举体enum,第一项默认值0,后面每项默认+1*/
  8. enum intr_status {
  9.     INTR_OFF,        // 关中断
  10.     INTR_ON            // 开中断
  11. };
  12. enum intr_status intr_get_status(void);        // 获取中断状态
  13. enum intr_status intr_set_status(enum intr_status status);        // 设置中断状态
  14. enum intr_status intr_enable(void);            // 打开中断
  15. enum intr_status intr_disable(void);        // 关闭中断
  16. #endif
复制代码
debug.h

放在kernel文件夹下。主要内容是assert的声明和打印函数的声明,代码如下。
  1. #ifndef __KERNEL_DEBUG_H
  2. #define __KERNEL_DEBUG_H
  3. void panic_spin(char* filename, int line, const char* func, const char* condition);
  4. /* __VA_ARGS__代表若干个参数,对应前面的... */
  5. #define PANIC(...) panic_spin(__FILE__, __LINE__, __func__, __VA_ARGS__)
  6. #ifdef NDEBUG
  7. #define ASSERT(condition) ((void)0)
  8. #else
  9. #define ASSERT(condition) \
  10.     if (condition){} \
  11.     else { \
  12.         PANIC(#condition); \ /*关于#,学名字符串化宏,相当于宏定义了""字符串标号*/
  13.     }
  14. #endif /*结束__NDEBUG*/
  15. #endif /*结束__KERNEL_DEBUG_H*/
复制代码
debug.c

同样放在kernrl文件夹下,实现报错打印函数
  1. #include "debug.h"
  2. #include "print.h"
  3. #include "interrupt.h"
  4. /* 打印相关信息并悬停程序 */
  5. void panic_spin(char* filename, int line, const char* func, const char* condition){
  6.     intr_disable(); // 关闭中断
  7.     put_str("\n\n\n!!!kernel panic!!!\n");
  8.     put_str("filename:");put_str((char*)filename);put_str("\n");
  9.     put_str("line:0x"); put_int(line);put_str("\n");
  10.     put_str("function:");put_str((char*)func);put_str("\n");
  11.     put_str("condition:");put_str((char*)condition);put_str("\n");
  12.     while (1);
  13. }
复制代码
main.c

简单修改一下内核,用来测试assert
  1. #include "print.h"
  2. #include "init.h"
  3. #include "debug.h"
  4. int main(void){
  5.         put_str("HongBai's OS\n");
  6.         init_all();
  7.         asm volatile("sti");
  8.         ASSERT(1 == 2); // 断言失败,会调用panic_spin函数
  9.         while(1);
  10. }
复制代码
makefile

相当于是写脚本,目的是编译、毗连、写入之前的文件,整体cv的love6的博客,修改了路径。如果要cv下面的代码,记得修改路径。
  1. BUILD_DIR = ./build
  2. ENTRY_POINT = 0xc0001500
  3. AS = nasm
  4. CC = gcc
  5. LD = ld
  6. LIB = -I lib/ -I lib/kernel/ -I lib/user/ -I kernel/ -I device/
  7. ASFLAGS = -f elf
  8. CFLAGS = -Wall -m32 -fno-stack-protector $(LIB) -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes
  9. LDFLAGS =  -m elf_i386 -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_DIR)/kernel.map
  10. OBJS = $(BUILD_DIR)/main.o $(BUILD_DIR)/init.o $(BUILD_DIR)/interrupt.o \
  11.       $(BUILD_DIR)/timer.o $(BUILD_DIR)/kernel.o $(BUILD_DIR)/print.o \
  12.       $(BUILD_DIR)/debug.o
  13. ##############     c代码编译                             ###############
  14. $(BUILD_DIR)/main.o: kernel/main.c lib/kernel/print.h \
  15.         lib/kernel/stdint.h kernel/init.h
  16.         $(CC) $(CFLAGS) $< -o $@
  17. $(BUILD_DIR)/init.o: kernel/init.c kernel/init.h lib/kernel/print.h \
  18.         lib/kernel/stdint.h kernel/interrupt.h device/timer.h
  19.         $(CC) $(CFLAGS) $< -o $@
  20. $(BUILD_DIR)/interrupt.o: kernel/interrupt.c kernel/interrupt.h \
  21.         lib/kernel/stdint.h kernel/global.h kernel/io.h lib/kernel/print.h
  22.         $(CC) $(CFLAGS) $< -o $@
  23. $(BUILD_DIR)/timer.o: device/timer.c device/timer.h lib/kernel/stdint.h\
  24.         kernel/io.h lib/kernel/print.h
  25.         $(CC) $(CFLAGS) $< -o $@
  26. $(BUILD_DIR)/debug.o: kernel/debug.c kernel/debug.h \
  27.         lib/kernel/print.h lib/kernel/stdint.h kernel/interrupt.h
  28.         $(CC) $(CFLAGS) $< -o $@
  29. ##############    汇编代码编译    ###############
  30. $(BUILD_DIR)/kernel.o: kernel/kernel.S
  31.         $(AS) $(ASFLAGS) $< -o $@
  32. $(BUILD_DIR)/print.o: lib/kernel/print.S
  33.         $(AS) $(ASFLAGS) $< -o $@
  34. ##############    链接所有目标文件    #############
  35. $(BUILD_DIR)/kernel.bin: $(OBJS)
  36.         $(LD) $(LDFLAGS) $^ -o $@
  37. .PHONY : mk_dir hd clean all
  38. mk_dir:
  39.         if [ ! -d $(BUILD_DIR) ]; then mkdir $(BUILD_DIR); fi
  40. hd:
  41.         dd if=$(BUILD_DIR)/kernel.bin \
  42.            of=/home/hongbai/bochs/bin/c.img \
  43.            bs=512 count=200 seek=10 conv=notrunc
  44. clean:
  45.         cd $(BUILD_DIR) && rm -f  ./*
  46. build: $(BUILD_DIR)/kernel.bin
  47. all: mk_dir build hd
复制代码
测试

我们make all,效果如下

运行一下bochs

实现了99%功能,就是打印的有点歪,bug应该出现在print.S里,留待后续修改。

debug(无果)

先去研究了一下print.S,重写了一下换行回车部分代码
  1. ;关于换行符:我们按照习惯,把换行回车结合起来,实现日常敲下enter的效果,所以换行=换行+回车
  2. .is_line_feed:                        ;换行操作:光标挪到下一行行首
  3.         ;内联的回车逻辑
  4.         xor dx,dx
  5.         mov ax,bx
  6.         mov si,80
  7.         div si       
  8.         sub bx,dx
  9.         ;单独的换行逻辑
  10.         add bx,80                ;目前是本行行首,再加80就是下一行行首
  11.         cmp bx,2000                ;是否清屏
  12.         jl .set_cursor                ;bx<2000,即还在这一屏,就执行
  13. .is_backspace:                        ;退格操作:光标bx前移一个显存位置,待删除位置补空格字符
  14.         dec bx                        ;自减,前移到上一个坐标
  15.         shl bx,1                ;左移1位,等价于*2,坐标位置*2=实际字节偏移量
  16.         mov byte [gs:bx],0x20
  17.         inc bx
  18.         mov byte [gs:bx],0x07        ;上面三行代码等价于mov word [gs:bx],0x0720,即打印一个空格字符,属性是黑底白字。
  19.         shr bx,1                ;右移1位,将地址重新转化为坐标
  20.         jmp .set_cursor                ;将光标转移到新位置
复制代码
然而仍旧没解决问题

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表