操作系统的完整代码——初始化代码ychead.cpp

#define YCORG  0x90000 - 0x2000
#include "ycio.cpp"

static_assert(YCORG == DATA_POS - ychead_SIZE, "YCORG Error!");
char kernel_stack[1024 * 2];

asm void main()
{
        mov     ax, KERNEL_DS
        mov     ds, ax
        mov     es, ax
        mov     ss, ax
        mov     fs, ax
        mov     gs, ax

        mov     esp, &kernel_stack + sizeof(kernel_stack)    //设置堆栈
        cli
        cld
        call    head_init
        jmp     KERNEL_POS              //跳入ycker.cpp的main()函数
}

void head_init()
{
    init_8259A();
    printk(0,80*1,0x17,"Initializing 8259A 8253 ...... ychead.cpp");
    init_8253();

    printk(0,80*2,0x5f,"Setting memory page ...... ychead.cpp");
    page_init();

    printk(1,80*3,0x2f,"Loading: ycker.cpp,ycfs.cpp,ycmm.cpp ... ychead.cpp");
    YCEXE *pKer = (YCEXE*)ycker_POS;            //ycboot.cpp把ycker.cpp读到此处
    YCEXE *pFs = (YCEXE*)(ycker_POS + pKer->length);              //ycfs.cpp代码
    YCEXE *pMm = (YCEXE*)(ycker_POS + pKer->length + pFs->length);//ycmm.cpp代码

    code_copy((byte*)KERNEL_POS, pKer);  //将ycker.cpp重定位拷贝到KERNEL_POS处
    code_copy((byte*)(KERNEL_POS + pKer->codelen), pFs);          //拷贝ycfs.cpp
    code_copy((byte*)(KERNEL_POS + pKer->codelen + pFs->codelen), pMm); //ycmm.cpp

    *(int*)(KERNEL_POS+DATA_POS+0) = pKer->codelen;  //ycfs.cpp的代码位置
    *(int*)(KERNEL_POS+DATA_POS+4) = pKer->codelen+pFs->codelen;//ycmm.cpp位置
    printk(1,80*4,0x3f,"Kernel has been loaded! - ychead.cpp");
}

void init_8259A()
{
    outb(0x20, 0x11);
    outb(0xA0, 0x11);
    outb(0x21, 0x20);
    outb(0xA1, 0x28);
    outb(0x21, 0x4);
    outb(0xA1, 0x2);
    outb(0x21, 0x1);
    outb(0xA1, 0x1);
    outb(0x21, 0xFF);
    outb(0xA1, 0xFF);
}

void init_8253()
{
    outb(0x43, 0x34);
    outb(0x40, 1193182/100);
    outb(0x40, (1193182/100) >> 8);
}

void page_init()
{
    e820map *pMem = (e820map*)(DATA_POS + e820_POS);
    e820map::e820entry *pRam = pMem->map; //系统内存信息由ycboot通过int 15h获得

    int ii,maxPos;
    for(maxPos=ii=0; ii<pMem->nr_map; ii++,pRam++) //计算可用内存最大位置maxPos
      {
        if(pRam->type != 1)   continue;
        if(maxPos < pRam->addr + pRam->size)  maxPos = pRam->addr + pRam->size;
      }

    unsigned int PDE_num = (maxPos + DIR_SIZE - 1) / DIR_SIZE; //计算页目录项数
    unsigned int PGT_endpos = PageTable_pos + PDE_num * PAGE_SIZE; //页表位置尾

    pRam = pMem->map;                                      //内存信息对象指针
    unsigned int phys_pos = 0;                             //物理内存地址计数
    unsigned int *pgDir = (unsigned int*)PageDir_POS;      //页目录首地址
    unsigned int *pgTable = (unsigned int*)PageTable_pos;  //页表首地址
    YMEM *maxHead = (YMEM*)freeMemLINK_POS;                //空闲内存链表首地址
    YMEM *phsHead = nullptr;                               //空闲内存链表头
    YMEM *pLink;

    #define PAGE_PRESENT   0x001
    #define PAGE_RW        0x002
    #define PAGE_USER      0x004
    int memflag,memAttr;
    for(memflag=ii=0; ii<PDE_num; ii++)
      {
        for(int jj=0; jj<1024; jj++)
          {
            while(pRam->type!=1 || phys_pos>=pRam->addr + pRam->size)  pRam++;

            if(phys_pos >= pRam->addr)  //内存可用
              {
                memAttr = PAGE_PRESENT | PAGE_RW | PAGE_USER;  //系统使用内存尾
                if(phys_pos < ycker_SIZE || (phys_pos>=freeMemLINK_POS &&
                                         phys_pos<PGT_endpos))  goto  sl_p_000;

                if(memflag == 0)
                  {
                    pLink = maxHead++;       //空闲内存链表指针
                    pLink->addr = phys_pos;  //设置空闲内存链表项代表的内存地址
                    yc_add_link(pLink,phsHead);  //空闲内存链表增加一项
                    memflag = 1;
                  }
              }
            else  //内存不可用
              {
                memAttr = PAGE_PRESENT;
                sl_p_000:
                if(memflag)  //当memflag!=0时, 结束空闲内存计数
                  {
                    pLink->size = phys_pos - pLink->addr;  //空闲链表内存大小
                    memflag = 0;
                  }
              }

            pgTable[jj] = phys_pos | memAttr; //页表项的内存物理地址和内存属性
            phys_pos += PAGE_SIZE;            //物理内存地址计数增加 1000h 字节
          }

        pgDir[ii] = (unsigned int)pgTable + (PAGE_PRESENT | PAGE_RW | PAGE_USER);
        if(KERNEL_POS / DIR_SIZE + ii < 1024)
                                pgDir[KERNEL_POS / DIR_SIZE + ii] = pgDir[ii];
        pgTable += 1024;
      }

    if(memflag)  pLink->size = phys_pos - pLink->addr;
    *(YMEM**)(DATA_POS + 8) = phsHead;   //空闲内存链表表头
    *(YMEM**)(DATA_POS + 12) = maxHead;  //可用内存链表最大地址

    asm
     {
        mov     eax, PageDir_POS  //页目录位置
        mov     cr3, eax          //设置页目录寄存器 cr3
        mov     eax, cr0          //读页目录状态寄存器 cr0
        or      eax, 80000000h    //内存分页状态位
        mov     cr0, eax          //内存分页功能被启动
     }
}

                      C/C++代码文件: ychead.cpp

源代码分析
    语句#define YCORG 0x90000 - 0x2000设置执行代码在内存中的位置
    语句static_assert(…)检查YCORG的值是否正确

    32位地址可访问4G字节内存,4G内存按下列方式被划分成1K个页表,1M个物理页框
            2^32字节 = 2^10 * 2^10 * 2^12字节 = 1024 * 1024 * 4196字节
                     = 1024页表 * 1024页框/页表 * 4096字节/页框
执行语句:
        mov eax, PageDir_POS
        mov cr3, eax
         ……
        后,
内存分页功能被启动,线性地址与物理地址可能不再相等,需进行转换。
如线性地址aa将按下列程序被转换为物理地址rr
    int ii = aa >> 22; //aa的第22-31位,第ii个页目录
    int jj = (aa >> 12) & 0x3ff; //aa的第12-21位,第jj个页表
    unsigned int pgDir = (unsigned int)PageDir_POS; //寄存器cr3中的页目录地址
    unsigned int pgTable = (unsigned int)(pgDir[ii] & ~0xfff); //页表地址
    unsigned int rr = (pgTable[jj] & ~0xfff) + (aa & 0xfff); //物理地址
语句jmp KERNEL_POS 使程序跳入ycker.cpp的main()函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值