zoukankan      html  css  js  c++  java
  • 30天自制操作系统第九天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统

    qq交流群:122358078    ,更多学习中的问题、资料,群里分享

    environment:开发环境:ubuntu

    第九天的课程已学完,确实有点不想写这个笔记了,因为开学了,还要学习课业上的压力,转博了压力山大啊.

    这一天的课程最难的我感觉是后面的memory free的部分,这一部分有很多已经没有接触到的东西,所以感觉比较难.
    内存的管理在任何os中都是一个重要的问题.

    还是按照作者的书本上第九天的顺序的来做笔记吧:


           1:整理源文件部分,这一部分就没有什么了,把一个.c文件拆成多个.c文件工程大了,为了方便管理,方便各类函数的查找,必须要多个函数,能快速的定位所以与keyboard有关的函数放到keyboard中,与mouse有关的函数放到mouse中.

           2:这一部分是内存的容量检查,作者的思路,在学arm的时候,也用到了,就是向内存中写一个数,然后读出来,如果这个内在地址可用,那么读出来的数,肯定和写进去的数一样.但是作者在检查内存容量之前,讲了好多关于cache的东西,一开始以为没有用,后来才知,如果不关cahce,我们目的是想往内存中写的数,很有可能写到了cache中这样就会导致,不能正确的检测出这个内存地址是否真的存在.

           所以要先关了cache再检查内存的容量,因为386没有cache,先以后的cpu486及以上都有cache.所以要先判断cpu是不是i386,作者的思路是通过cpu中的eflags寄存器中的ac位,因为386的cpu还没有ac位这个标志位,所以向386cpu的efags的ac位写1是无效的,还是保持为0,通过这个方法,可以判断cpu是不是386.下面是伪代码.通过写出伪代码,可以更好的了解整个过程,而不会局限于一个细节

    unsigned int memtest(start ,end)
    {
        tmp=read_eflag();
        tmp|=acbit;
        write_elfag(tmp);
        tmp=read_eflag();
        if(tmp_ac_bit==1)
        {
         cpu=486higher;
        };
    
        if(cpu==486higher)
        {
         turn_off_cache(); //control cr0 register
        }
    
        size=get_memory_size(start,end);
    
        if(cpu==486higher)
        {
         turn_on_cache();
        }
        return size;//返回得到的memroy的值(byte为单位)
    }



    而get_memory_size()这个函数就用作者的方法搞定就行了,只是作者最后用汇编写了这部分的代码,因为作者认为编译器把他的代码给优化了,所以不得不用汇编写.但是实际上因为作者不了解c语言中还有一个强大的关键字,volatile.

    只要把这个关键字用上,编译器就不会对指向内存地址的变量进行优化了.

    当然,这一招是在学arm的时候学到的.

    所以get_memory_size()这个函数,就用下面的代码来实现就ok了

    unsigned int get_memory_size(start,end)
    {
     unsigned int i ,old;
     unsigned int pat0=0xaa55aa55,pat1=0x55aa55aa;
     volatile unsigned int *p;//注意这里的volatile关键字,
     for(i=start;i<end;i+=0x1000)
     {
      p=(unsigned int *)(i+0xffc);
      old=*p;
      *p=pat0;
      *p^=0xffffffff;
      if(*p!=pat1)
      {
       *p=old;
       break;
      }
     
     }
     return i;//i就是得到的memory size
    
    }
    

    上面的函数我做了一些简化,因为我觉得作者做了一些没用用的事


    当然在memtest,中需要用到读eflag,cr0,写eflag,cr0的函数,这个是用gcc内嵌汇编实现的



            3:这一部分就是作者一步一步发现c编译器如何优化了他的函数,而不得已只好用汇编写get_memory_size这个函数的过程,没有细看,能看懂汇编对于做顶层的人太重要了.

            4:这一天的第四部分,我觉得是最值得一看的,作者分析了两种内存管理的方法,
            第一种是用数组的方法,也介绍了如何实现内在的allocate and free,数组中的每一个字节都和一个具体的地址对应了,而且每一个
    memory block的大小也是固定的.有点想是分段的机制.因为这个管理内存的这个表太大了,而且在alocate and free时候要用for对数组
    读写多次,非常耗时.但是这个方法是最简单的,非常好理解.
            第二种方法是用下面的个数据结构
    :

    sturct FREEINFO
    {
     unsigned int  addr;
     unsigend int  size;
    };
    struct MEMMAN
    {
     unsigned int frees;
     struct FREEINFO free[1000];
    };


    上面的数据结构,配合上 下面的四个函数,内存管理就搞定了

    void memman_init(struct MEMMAN *man);
    unsigned int memman_total(struct MEMMAN *man);
    unsigned int memman_alloc(struct MEMMAN *man):
    int memman_free(struct MEMMAN *man,unsigned int addr,unsigned int size);



    用struct数据结构抽象成对象,上面的四个函数抽象成对 对象的操作.oop的编程.
    四个函数有个共同的特点,传递的都是函数的指针,所以要对一个对象进行操作,指针是非常重要的,
    可以在这些函数内部改变对象的属性.传递指针的方法也使函数具有更好的封装性,高内聚,低耦合就是这个道理吧.

    当然作者对memman_free这个函数是写的非常清楚的,可是我还是只看到了一个半懂.后面再温故知新吧.

    下面上一张virtualbox启动运行的图片,u盘启动,我也试了.如果要从u盘启动,命令如下

    sudo -s
    make usb=1
    make copy
    make u
    make dd   //这一步是写os.img到u盘,会看到u盘灯闪
    好了,启动u盘做好了,have a try and enjoy !
    



  • 相关阅读:
    qemu进程页表和EPT的同步问题
    Linux进程虚拟地址空间管理2
    qemu-kvm内存虚拟化1
    LInux进程虚拟地址空间的管理
    Linux下的文件系统2
    LInux中的文件系统1
    Linux IPC之管道通信
    操作系统中的特权级检查
    Linux下的信号机制
    进程的挂起、阻塞和睡眠
  • 原文地址:https://www.cnblogs.com/riskyer/p/3306189.html
Copyright © 2011-2022 走看看