从零开始搭建环境编写操作系统 AT&T GCC (九)内存管理

  到了十分乏味而又至关重要的部分了,想要一个操作系统运行起来,同时处理不同的程序,就要使用内存管理。
  在开始之前,我们给Makefile中所有的gcc命令增加一个-fno-stack-protector,意思是不进行栈溢出检查,这是linux内核程序的一种防止栈溢出漏洞的机制,如果不加这一条指令,在使用栈的时候会发生__stack_chk_fail错误,具体详情百度 linux canary,这次我们做的东西跟linux半点关系都没有,所以就不赘述了。
  更正一下内存分布图
  这里写图片描述
把GDT放在0x80000处,这样GDT就一定够用了。GDT最大为64KB

gdt_size:   .word   31
gdt_base:   .long   0x80000 #定义GDT位置

一、内存管理的原理
  为了让操作系统能够统一的管理内存,所以需要让操作系统知道每一个内存地址的使用情况,是可用的,还是不可用的,并采用分页的形式将其管理起来。具体来说就是将内存按一定的大小分为多个页面,这里所说的大小不是唯一的,可根据多方面的条件来权衡,在这里我们将页面大小定义为4KB,也就是4096B(通常情况下也是这样的)。我们假设最大内存为4GB(实际可以更大),采用一个byte来记录4KB的内存是否已经分配出,于是我们需要
  0xffffffff÷0x1000=1048576 Bytes = 1024KB = 1MB,我们用0x100000~0x200000来存储这个表格。
  一个Byte记录了4KB的内存空间,当第0位置1时,说明内存被使用了,置0说明尚未使用。
  我们先把系统的框架完成,以后再来改进这些模块。
二、具体实现
  新建memmory文件夹,新建memmory.c和memmory.h,添加进入makefile文件。
  InitMMap()函数用于初始化系统内核所占用的内存,这部分内存永远为被使用,将InitMMap()加入main.c
  void AllocatePages(int pages,app_memmory_struct *app_memmory)这是内存分配函数,实现原理是遍历内存表,找到连续的pages页内存,然后分配给结构体app_memmory_struct,将内存分配情况输出到屏幕左上角,结构体定义和声明位于下方。
  void DeletePages(app_memmory_struct *app_memmory)//删除页面函数
  memmory.c

#include "memmory.h"
#include "../font/font.h"
char *mmap = (char *)(0x100000 - 0x8200);//内存位图位置0x100000~0x1fffff,减去段基址

void InitMMap()
{
    for (int i = 0; i < MMAP_END - MMAP_START + 1; i++)
    {
        if (i < MMAP_KERNEL)
        {
                //前5MB留给内核使用
                mmap[i] = MMAP_USED;
        }
        //剩下的内存为未使用
        else
        {
                mmap[i] = MMAP_FREE;
        }
    }
}

void AllocatePages(int pages,app_memmory_struct *app_memmory)//申请页面函数
{
    static unsigned int y;
    unsigned char succ = 0;
    unsigned int i,j;
    for (i = 0x500; i < MMAP_END - MMAP_START + 1; i++)
    {
        if (mmap[i] == MMAP_FREE)//空内存
        {
            for (j=1;j<pages;j++)
            {
                if(mmap[i+j] != MMAP_FREE)
                {

                    break;
                }
                if (j == (pages-1))//成功申请到
                {   
                    succ = 1;
                }
            }
            if (succ==1)//如果成功申请到,则赋值,修改MMAP,返回
            {

                app_memmory->start_page = i;
                app_memmory->end_page = i+j-1;
                for (unsigned int k=i;k<i+j;k++)
                {
                    mmap[k] = MMAP_USED;
                }
                printf(0,16*y,0xff0000,"i:%x,j:%x",app_memmory->start_page,app_memmory->end_page);
                y++;
                return;
            }
            else
            {
                i = i + j;
            }
        }
    }
    app_memmory->start_page = 0;
    app_memmory->start_page = 0;
    printf(0,16*y,0xff0000,"i:%x,j:%x",app_memmory->start_page,app_memmory->end_page);
    y++;

}
void DeletePages(app_memmory_struct *app_memmory)//删除页面函数
{
    for (int i = app_memmory->start_page;i<=app_memmory->end_page;i++)
    {
        mmap[i] = MMAP_FREE;
    }
}

  memmory.h

void InitMMap();
typedef struct{
    unsigned int start_page;
    unsigned int end_page;
} app_memmory_struct;

void AllocatePages(int pages,app_memmory_struct *app_memmory);//申请页面函数
void DeletePages(app_memmory_struct *app_memmory);//删除页面函数

#define MMAP_FREE   (0)//未使用
#define MMAP_USED   (1)//已使用
#define MMAP_START  (0x100000)//第一个表的位置
#define MMAP_END    (0x1fffff)//最后一个表的位置
#define MMAP_KERNEL (0x500)//5MB以下给kernel使用,初始化置1

  在main.c中写几个测试函数,一切正常。

三、改正一个小错误

  刚才在写程序的时候竟然栈满了,查了半天终于找到了原因:
  system.s最后改为如下
  现在我们把0x400000~0x200000作为内核的栈地址,共2MB,妥妥的够用。

start_protect:
.code32
    movw    $0x0010,   %ax
    movw    %ax,        %ds
    movw    %ax,        %ss   #暂时公用一个段选择子
    movl    $0x003f7e00,   %esp # 003f7e00 = 0x400000 - 0x8200,之前的值太小了
    call    SysMain

gdt_size:   .word   31
gdt_base:   .long   0x80000 #定义GDT位置

  现在内存使用情况如下:
  这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值