admin 管理员组文章数量: 1184232
疑问: CR3 与 PDE是不同的东西吗?
1 建立 4M的PDE 表
2 初始化第0个表项
3 打开页表
4 配置cr3 寄存器
5 配置cr4 寄存器
6 配置cr0 寄存器
注意 cr0 寄存器的打开页表必须是 在cr4 之后。否则报错
7定义二级页表 , 映射 80000000 地址。
cr4 寄存器的设置
cr0 寄存器的最高位 打开分页机制。
os.c 代码
#include "os.h"
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
//关于也表的宏定义
#define PDE_P (1<<0) //4M 的页必须为1
#define PDE_W (1<<1) //读写权限
#define PDE_U (1<<2) // superviser 模式
#define PDE_PS (1<<7) //一级页表必须为1
//定义要映射的地址
#define MAP_ADDR (0x80000000)
//定义一个用于 0x80000000 的映射的内存
//定义的一个4k大小的内存,存在与 0-4M 的物理内存
uint8_t map_phy_buffer[4096] __attribute__((aligned(4096))) = {0x36};
// 定义二级页表
static uint32_t page_table[1024] __attribute__((aligned(4096)))= {PDE_U};
//建立页表,数组中的每个元素都要4M 对其。
//只是初始化了第0个表项
uint32_t pg_dir[1024] __attribute__((aligned(4096))) = {
[0] = (0) |PDE_P| PDE_W |PDE_U |PDE_PS,
};
//定义二级页表的函数
void os_init(void){
// PDE_PS 默认是0
pg_dir[MAP_ADDR >> 22] = (uint32_t)page_table | PDE_P|PDE_W|PDE_U; // 将二级页表的地址副给一级页表
page_table[(MAP_ADDR >> 12) & 0x3ff] = (uint32_t)map_phy_buffer | PDE_P|PDE_W|PDE_U; // 设置二级页表到物理地址
};
// 1 直接定义的结构体数组,而不是先定义数组,在定义数组
// 2 __attribute__(aligned()) 是指的对于数组中的每一项的字节对其方式
// 3 base[31:24]:31:24 G:23 D/B:22 L:21 AVL:20-19 segment_limit:19-16 P:16-15 DPL :14-13 S:12 TYPE:11-8 base[23:16]:7-0
// 0000 0000 1 1 0 0 1111 1 00 1 1010 0000 0000
// base_addr[15:00]:31-16 segment_limit[15:00]:15-00
// 0000 0000 1111 1111
//这个表的内容应该在 栈段
struct {uint16_t limit_l,base_l,basehl_attr,base_limit;}gdt_table[256] __attribute__((aligned(8))) = {
[KERNEL_CODE_SEG/8] = {0xffff,0x0000,0x9a00,0x00cf},
[KERNEL_DATA_SEG/8] = {0xffff,0x0000,0x9200,0x00cf},
};start.s
#include "os.h"
// 声明本地以下符号是全局的,在其它源文件中可以访问
.global _start
//引用 C 函数+数组
.extern os_init,gdt_table,,pg_dir
// 指定以下的代码生成16位的机器指令,这样才能在启动时的实模式下运行
.code16
// 以下是代码区
.text
_start:
jmp $0, $offset // 用于设置cs寄存器, cs:ip 不支持这种语法
offset:
mov $0, %ax
mov %ax, %ds
mov %ax, %ss
mov %ax, %es
mov %ax, %gs
mov %ax, %fs
mov $offset, %esp // 设置了栈顶指针
read_self_all:
mov $0x7e00, %bx // 读取到内存的位置
mov $0x2, %cx // 读取的扇区数量
mov $0x240, %ax // AH:读磁盘, AL:读取的数量
mov $0x80, %dx // 读取第一块磁盘
int $0x13 // 13号中断
jc read_self_all // 读取出错就反复读取
cli //关中断
lgdt [gdt_desc] //设置GDT 表的起始位置
mov $1, %eax //设置cr0寄存器
lmsw %ax
jmp $KERNEL_CODE_SEG, $_start_32 //jump:cs:ip , 设置选择子
.org 0x1fe //从510的地方开始
.byte 0x55, 0xaa
// 这是第二个扇区的内容
.code32
.text
_start_32:
//设置32位下的数据段, 栈段
mov $KERNEL_DATA_SEG, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov $_start, %esp
//调用C 函数,初始化,二级页表
call os_init
//初始化cr3寄存器,设置页表地址
//pg_dir 在c语言中
mov $pg_dir, %eax
mov %eax, %cr3
//设置cr4 寄存器
// 是能 4M 对 4M
mov %cr4, %eax
orl $(1<<4), %eax
mov %eax, %cr4
//设置cr0 寄存器
mov %cr0, %eax
orl $(1<<31) , %eax // 设置的最高位
mov %eax, %cr0
jmp .
gdt_desc:
.word ((256*8)-1) //gdt 界限
.long gdt_table //gdt 地址
测试:
版权声明:本文标题:翻转页码的秘密:21章教程第二弹 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1771700913a3547580.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论