操作系统之内存管理

一、基础知识

1.1 存储单元和内存地址(物理地址)

在这里插入图片描述

1.2 逻辑地址、线性地址、物理地址

1.2.1 区别

  • 逻辑地址:我们程序员写代码时给出的地址叫逻辑地址,其中包含段选择子和偏移地址两部分。
  • 线性地址:通过分段机制,将逻辑地址转换后的地址,叫做线性地址。而这个线性地址是有个范围的,这个范围就叫做线性地址空间,32 位模式下,线性地址空间就是 4G。
  • 物理地址:就是真正在内存中的地址,它也是有范围的,叫做物理地址空间。那这个范围的大小,就取决于你的内存有多大了。
  • 虚拟地址:如果没有开启分页机制,那么线性地址就和物理地址是一一对应的,可以理解为相等。如果开启了分页机制,那么线性地址将被视为虚拟地址,这个虚拟地址将会通过分页机制的转换,最终转换成物理地址。

1.2.2 分段机制

CPU在保护模式下段寄存器(比如 ds、ss、cs)里存储的是段选择子,段选择子去全局描述符表中寻找段描述符,从中取出段基址。段基址取出来,再和偏移地址相加,就得到了物理地址。
在这里插入图片描述
在这里插入图片描述

高 22 位就表示它是代码段还是数据段

物理地址计算过程:
在这里插入图片描述
全局描述符表(gdt),是由操作系统把这个位置信息存储在一个叫 gdtr 的寄存器中。
在这里插入图片描述
gdtr 寄存器48 位的数据,其中0–15位记录段选择子的数量 ,16-47位记录全局描述符表在内存的起始位置。
Linux系统源码:

#存放gdtr 的寄存器中全局描述符表
lgdt    gdt_48
#描述gdtr 寄存器值数据结构
gdt_48:
   .word   0x800       ; gdt limit=2048, 256 GDT entries
   .word   512+gdt,0x9 ; gdt base = 0X9xxxx==0x90200 + gdt
#gdt 这个标签处,就是全局描述符表在内存中的真正数据了
gdt:
   .word   0,0,0,0     ; dummy

   .word   0x07FF      ; 8Mb - limit=2047 (2048*4096=8Mb)
   .word   0x0000      ; base address=0
   .word   0x9A00      ; code read/exec
   .word   0x00C0      ; granularity=4096, 386

   .word   0x07FF      ; 8Mb - limit=2047 (2048*4096=8Mb)
   .word   0x0000      ; base address=0
   .word   0x9200      ; data read/write
   .word   0x00C0      ; granularity=4096, 386

1.2.2 分页机制

没有开启分页机制时,由程序员给出的逻辑地址,需要先通过分段机制转换成物理地址。但在开启分页机制后,逻辑地址仍然要先通过分段机制进行转换,只不过转换后不再是最终的物理地址,而是线性地址,然后再通过一次分页机制转换,得到最终的物理地址。
在这里插入图片描述
比如我们的线性地址(已经经过了分段机制的转换)15M(0000000011_0100000000_000000000000)
CPU 在看到我们给出的内存地址后,首先把线性地址被拆分成高 10 位:中间 10 位:后 12 位

高 10 位负责在页目录表中找到一个页目录项
页目录项的值加上中间 10 位拼接后的地址去页表中去寻找一个页表项
页表项的值,再加上后 12 位偏移地址,就是最终的物理地址。

在这里插入图片描述

而这一切的操作,都由计算机的一个硬件叫内存管理单元( MMU),负责将虚拟地址转换为物理地址。

操作系统这个软件层,只需要提供好页目录表和页表即可,这种页表方案叫做二级页表,第一级叫页目录表 PDE,第二级叫页表 PTE。

linux-0.11 认为,总共可以使用的内存不会超过 16M:
1 个页目录表最多包含 1024 个页目录项(也就是 1024 个页表),1 个页表最多包含 1024 个页表项
(也就是 1024 个页),1 页为 4KB(因为有 12 位偏移地址),因此,16M 的地址空间可以用 1 个页目录表 
+ 4 个页表搞定。

在这里插入图片描述

p:是否存在
RW:读写权限
US: 用户或内核态

二、操作系统

2.1 模式的转换

操作系统刚启动的时候是16 位的实模式,之后转变为之后 32 位的保护模式
由于x86 的历史包袱问题,目前的CPU都是32或64位了,但是为了兼容历史包袱,操作系统需要写一段模式转换的代码。

2.1.1模式的区别:

实模式下:CPU 计算物理地址的方式,段基址左移四位,再加上偏移地址。
在这里插入图片描述
保护模式:1.ds寄存器里存储的值,在实模式下叫做段基址,在保护模式下叫段选择子。段选择子里存储着段描述符的索引。2.通过段描述符索引,可以从全局描述符表 gdt 中找到一个段描述符,段描述符里存储着段基址。3.段基址取出来,再和偏移地址相加,就得到了物理地址
在这里插入图片描述

2.1.1模式切换:

1.准备全局描述符,将全局描述符设置到gdtr 寄存器中。

lgdt    gdt_48 #全局描述符设置到gdtr 寄存器中

gdt_48:  #初始化全局描述符在内存中
    .word   0x800       ; gdt limit=2048, 256 GDT entries
    .word   512+gdt,0x9 ; gdt base = 0X9xxxx
gdt:
    .word   0,0,0,0     ; dummy

    .word   0x07FF      ; 8Mb - limit=2047 (2048*4096=8Mb)
    .word   0x0000      ; base address=0
    .word   0x9A00      ; code read/exec
    .word   0x00C0      ; granularity=4096, 386

    .word   0x07FF      ; 8Mb - limit=2047 (2048*4096=8Mb)
    .word   0x0000      ; base address=0
    .word   0x9200      ; data read/write
    .word   0x00C0      ; granularity=4096, 386

2.打开 A20 地址线,就是为了突破地址信号线 20 位的宽度,变成 32 位可用。

mov al,#0xD1        ; command write
out #0x64,al
mov al,#0xDF        ; A20 on
out #0x60,al

# CPU 到了 32 位时代之后,由于要考虑兼容性,还必须保持一个只能用 20 位地址线的模式,所以如果你不手
动开启的话,即使地址线已经有 32 位了,仍然会限制只能使用其中的 20 位。

3.将 cr0 这个寄存器的位 0 置 1,模式就从实模式切换到保护模式了。

mov ax,#0x0001  ; protected mode (PE) bit
lmsw ax      ; This is it;
jmpi 0,8     ; jmp offset 0 of segment 8 (cs)

在这里插入图片描述

2.2开启分页

如果开启分页机制,线性地址就需要经过分页机制转换成物理地址。
在这里插入图片描述
1.页表初始化

#1.将页目录表放在内存地址的最开头
_pg_dir:
_startup_32:
    mov eax,0x10
    mov ds,ax
    ...
#2.之后紧挨着这个页目录表,放置 4 个页表
.org 0x1000 pg0:
.org 0x2000 pg1:
.org 0x3000 pg2:
.org 0x4000 pg3:
.org 0x5000

setup_paging:
    ...
    mov eax,_pg_dir
    mov [eax],pg0+7
    mov [eax+4],pg1+7
    mov [eax+8],pg2+7
    mov [eax+12],pg3+7
    mov edi,pg3+4092
    mov eax,00fff007h
    std

在这里插入图片描述
2.设置cr3 寄存器页目录表在哪里

告诉 cr3 寄存器,0 地址处就是页目录表,再通过页目录表可以找到所有的页表,也就相当于 CPU 知道了分页机制的全貌了。

xor eax,eax
mov cr3,eax

3.开启分页机制
在这里插入图片描述

L3: stosd
    sub eax,00001000h
    jge L3
    popf
    xor eax,eax
    mov cr3,eax //设置cr3 寄存器页目录表在哪里
    mov eax,cr0
    or  eax,80000000h
    mov cr0,eax  //开启分页机制
    ret
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值