从零开始操作系统-05:Memory

这一节主要主要是分页和内存管理。

所需要的文件在Github:https://github.com/yongkangluo/Ubuntu20.04OS/tree/main/Files/Lec5-Memory

1. 基础知识

多级页表:
在这里插入图片描述

在 x8086 里面使用的二级页表。其中第一级页表称作 PDE(Page Directiory)二级页表是 PTE(Page Table)在这里插入图片描述具体设置情况如图。

2. 内存布局

由于内核代码在0x10000,所以可以将内核代码重映射到高半区空间——0xC0000000。

而对于前 1 MiB 的代码,使用对等映射。
在这里插入图片描述

3. 实现
// boot.S
#define KPG_SIZE    6*4096 //一个PD,五个PT
.section .kpg
    .global _k_ptd
    _k_ptd:
        .skip KPG_SIZE, 0

//这里是将multiboot信息挪个位置
 movl $mb_info, 4(%esp)
 movl %ebx, (%esp) // ebx 基地址寄存器(base)
 call _save_multiboot_info

// 高半核初始化,将KPG的地址和大小入栈作为参数
movl $(KPG_SIZE), 4(%esp)
movl $(_k_ptd - 0xC0000000), (%esp) /* 将页表的基地址作为参数传递给初始化函数 */
call _hhk_init

/* 加载PTD基地址 */
movl (%esp), %eax
andl $0xfffff000, %eax //这里就是将低12位置置零
movl %eax, %cr3

movl %cr0, %eax
orl $0x80000000, %eax   /* 开启分页与地址转换 (CR0.PG=1, CR0.WP=1) */
movl %eax, %cr0
addl $16, %esp
/* 进入高半核! */
pushl $hhk_entry_

其中_hhk_init 收到 ptd 即 $(_k_ptd - 0xC0000000) 作为页目录的基地址。

// hhk.c
void _hhk_init(ptd_t* ptd, uint32_t kpg_size)
{

    // 初始化 kpg 全为0
    uint8_t* kpg = (uint8_t*)ptd;
    for (uint32_t i = 0; i < kpg_size; i++) {
        *(kpg + i) = 0;
    }

    _init_page(ptd);
    /*其中主要完成的工作就是将 1 Mib 之前的对等映射;
    将内核代码映射到高半区;
    */
}
// hhk.c
#define PT_ADDR(ptd, pt_index) ((ptd_t*)ptd + (pt_index + 1) * 1024) 
/* 因为是连续的,所以可以直接加和计算*/
#define SET_PDE(ptd, pde_index, pde) *((ptd_t*)ptd + pde_index) = pde;
#define SET_PTE(ptd, pt_index, pte_index, pte)                                 \
    *(PT_ADDR(ptd, pt_index) + pte_index) = pte;
#define sym_val(sym) (uintptr_t)(&sym)

_hhk_init 执行结束,并开启分页后,就进入了 hhk_entry_ 高半核代码:

// prologue.S
.section .text
    .global hhk_entry_
    hhk_entry_:
    /* 加载GDT */
    ...
		movl $mb_info, (%esp)
		   call _kernel_init
		   mov $0xffbffff0, %esp
		   call _kernel_post_init
		   subl $6, %esp
	...
    /* IDT 初始化各寄存器*/
    ...

其中 _kernel_init 主要做的是内存地图的初始化,并分配虚拟页和物理页之间的映射。还有一些初始化操作。

具体的实现映射关系在pmm.c 和 cmm.c 文件中,不赘述了。

注意细节:

  1. 利用 128k bitmap 用来标记物理页是否被指向;
  2. 跳过 0x0 页;
  3. 采用循环映射,即最后一个PDE指向第一个PDE。

方法主要跟着B站Up主做的,B站视频链接在:https://www.bilibili.com/video/BV1jL4y1s7X6/?spm_id_from=333.788&vd_source=72ce864f895f9fbf22b81450817f2875

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值