文章目录
- 分段机制
- 分页机制
- 一级页表
- 二级页表
- 启用分页机制的过程
- 启用分页机制(二级页表)
- 详解
- 程序
- include.inc
- mbr.s
- loader.s
- 写入硬盘
- 启动bochs执行
分段机制
分页机制
一级页表
二级页表
启用分页机制的过程
1、准备好页目录项及页表
2、将页表地址写入控制寄存器cr3
3、寄存器cr0的PG位置1
1、
P:存在位,1表示存在于内存中,0表示不在内存中
RW:读写位,1表示可读可写,0表示可读不可写
US:访问权限位,1表示任意特权级都能访问该页,0表示特权级别为3不能访问该页
PWT:页级通写位,1表示通写方式(可提高访问效率),与高速缓存有关
PCD:页级高速缓存禁止位,1为启用高速缓存,0表示禁止高速缓存
A:访问位,1表示被CPU访问过,0表示未被CPU访问过
D:脏页位,1表示被修改过,0表示为被修改过,仅对页表项有效
PAT:页属性表位,能够在页面一级上设置内存属性,较为复杂,置0即可
G:全局位,1表示全局页,会在TLB中常驻,0表示不是全局页
AVL:操作系统可自行规定其用途
2、
cr3控制寄存器用于存储页表物理地址,所以cr3寄存器又称为页目录基址寄存器PDBR
使用mov指令在控制寄存器与通用寄存器互传数据:
mov cr[0~7], r32
mov r32, cr[0~7]
3、
将控制寄存器cr0的Page位置1,开启分页
启用分页机制(二级页表)
详解
低端3GB分配给用户空间,高端1GB分配给内核空间
第1个页目录项指向用户空间的起始位置
第769个页目录项指向内核空间的起始位置
页目录表在内存地址0x100000~0x100FFF处
第1个页表在内存地址0x101000~0x101FFF处,写入256个页表项指向低端1MB内存
第1、769个页目录项指向第1个页表
第1024个目录项指向页目录表
第770~1023个页目录项指向以内存地址0x102000为起始地址的254个页表
程序
include.inc
;--------- mbr & loader ---------
LBA_START_SECTOR equ 0x1
SECTOR_COUNT equ 0x4
LOADER_BASE_ADDR equ 0x7E0
LOADER_OFF_ADDR equ 0x0
LOADER_ADDR equ 0x7E00
ARDS_ADDR equ 0x1000
;--------- gdt ---------
DESC_G_4K equ 1_00000000000000000000000b
DESC_D_32 equ 1_0000000000000000000000b
DESC_L equ 0_000000000000000000000b
DESC_AVL equ 0_00000000000000000000b
DESC_LIMIT_CODE2 equ 1111_0000000000000000b
DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2 equ 0000_000000000000000b
DESC_P equ 1_000000000000000b
DESC_DPL_0 equ 00_0000000000000b
DESC_DPL_1 equ 01_0000000000000b
DESC_DPL_2 equ 10_0000000000000b
DESC_DPL_3 equ 11_0000000000000b
DESC_S_CODE equ 1_000000000000b
DESC_S_DATA equ DESC_S_CODE
DESC_S_sys equ 0_000000000000b
DESC_TYPE_CODE equ 1000_00000000b ;x=1,c=0,r=0,a=0 代码段是可执行的,非依从的,不可读的,已访问位a清0.
DESC_TYPE_DATA equ 0010_00000000b ;x=0,e=0,w=1,a=0 数据段是不可执行的,向上扩展的,可写的,已访问位a清0.
;code section
DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00
;data section
DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00
;video section
DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b
;-------------- paragraph selection ---------------
RPL0 equ 00b
RPL1 equ 01b
RPL2 equ 10b
RPL3 equ 11b
TI_GDT equ 000b
TI_LDT equ 100b
;-------------- loader & kernel --------------
PAGE_DIR_TABLE_POS equ 0x100000
;-------------- page tab --------------
PG_P equ 1b
PG_RW_R equ 00b
PG_RW_W equ 10b
PG_US_S equ 000b
PG_US_U equ 100b
mbr.s
;主引导程序
;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov ax, 0xB800
mov gs, ax
mov sp,0x7c00
; 清屏 利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
mov ax, 0x600
mov bx, 0x700
mov cx, 0 ; 左上角: (0, 0)
mov dx, 0x184f ; 右下角: (80,25),
; VGA文本模式中,一行只能容纳80个字符,共25行。
; 下标从0开始,所以0x18=24,0x4f=79
int 0x10 ; int 0x10
;;;;;;;;; 打印字符串 ;;;;;;;;;;;
mov cx, sx - msg
mov si, msg
mov di, 0
show_str:
mov byte al, [si]
mov byte ah, [sx]
mov word [gs:di], ax
inc si
add di, 2
loop show_str
jmp L0
msg db "enter mbr"
sx db 0x24
;;;;;;;;; 打字字符串结束 ;;;;;;;;;;;;;;;
L0:
push ds
push di
mov eax, LBA_START_SECTOR
push eax
mov ax, SECTOR_COUNT
push ax
mov ax, LOADER_BASE_ADDR
push ax
mov ax, LOADER_OFF_ADDR
push ax
call read_disk
add sp, 10
pop di
pop ds
jmp LOADER_ADDR
;;;;;;;;; read disk ;;;;;;;;;
; LBA: [bp+10]
; sector count: [bp+8]
; destination: sec=[bp+6], off=[bp+4]
read_disk:
push bp
mov bp, sp
;sector_count
mov dx,0x1f2
mov ax, [bp+8]
out dx, al
;sector_addr
mov dx, 0x1f3
mov ax, [bp+10]
out dx, al
mov dx, 0x1f4
mov al, ah
out dx, al
mov dx, 0x1f5
mov ax, [bp+12]
out dx, al
mov dx, 0x1f6
mov al, ah
and al, 0x0f
or al, 0xe0
out dx, al
;command_write
mov dx, 0x1f7
mov al, 0x20
out dx, al
disk_test:
nop ;give disk a moment
in al, dx
and al, 0x88 ;7: BUSY, 3: READY
cmp al, 0x08 ; (BUSY=0 & READY=1) or not?
jnz disk_test
;data_read:
mov ax, [bp+8]
mov dx, 256
mul dx
mov cx, ax
mov bx, [bp+4]
mov ax, [bp+6]
mov ds, ax
mov dx, 0x1f0
go_on_read:
in ax, dx
mov [bx], ax
add bx,2
loop go_on_read
mov sp, bp
pop bp
ret
;;;;;;;;; read disk ;;;;;;;;;
times 510-($-$$) db 0
db 0x55,0xaa
loader.s
%include "boot.inc"
section loader vstart=LOADER_ADDR
;;;;;;;;; 打印字符串 ;;;;;;;;;;;
mov cx, sx-msg1
mov si, msg1
mov di, 160
show_str:
mov byte al, [si]
mov byte ah, [sx]
mov word [gs:di], ax
inc si
add di, 2
loop show_str
jmp get_memoinfo
msg1 db "enter loader"
sx db 0x24
;;;;;;;;; 打字字符串结束 ;;;;;;;;;;;;;;;
;----- get memory information -----
get_memoinfo:
;----- get all: 0xE820
jmp_e820:
xor ebx, ebx
mov edx, 0x534d4150
mov di, ARDS_ADDR+2
ards_e820:
mov eax, 0x0000e820
mov ecx, 20
int 0x15
jc Error
add di, cx
inc word [ARDS_ADDR]
cmp ebx, 0
jnz ards_e820
show_memoinfo:
mov ax, 0xb800
mov gs, ax
mov cx, [ARDS_ADDR]
mov si, ARDS_ADDR+0x2
mov di, 320
loop_print:
push di
addr_info:
mov edx, [si]
mov di, memo_addr+22
call BtH
shr edx, 16
mov di, memo_addr+18
call BtH
mov edx, [si+4]
mov di, memo_addr+14
call BtH
shr edx, 16
mov di, memo_addr+10
call BtH
size_info:
mov edx, [si+8]
mov di, memo_size+22
call BtH
shr edx, 16
mov di, memo_size+18
call BtH
mov edx, [si+12]
mov di, memo_size+14
call BtH
shr edx, 16
mov di, memo_size+10
call BtH
type_info:
mov edx, [si+16]
mov di, memo_type+14
call BtH
shr edx, 16
mov di, memo_type+10
call BtH
pop di
push cx
push si
push di
mov cx, BtH_Table-memo_addr
mov ah, 0x24
mov si, memo_addr
info_print:
mov al, [si]
mov [gs:di], ax
inc si
add di, 0x2
loop info_print
pop di
add di, 160
pop si
add si, 20
pop cx
dec cx
cmp cx, 0
jne loop_print
jmp Jmp_there
memo_addr db "ADDR:0xxxxxxxxxxxxxxxxx. "
memo_size db "SIZE:0xxxxxxxxxxxxxxxxx. "
memo_type db "TYPE:0xxxxxxxxx."
BtH_Table db "0123456789ABCDEF"
;params: dx, di
BtH:
push ax
push bx
push edx
push di
mov bh, 0
mov bl, dl
and bl, 00001111b
mov al, [BtH_Table+bx]
mov [di], al
dec di
mov bl, dl
shr bl, 4
mov al, [BtH_Table+bx]
mov [di], al
dec di
mov bl, dh
and bl, 00001111b
mov al, [BtH_Table+bx]
mov [di], al
dec di
mov bl, dh
shr bl, 4
mov al, [BtH_Table+bx]
mov [di], al
pop di
pop edx
pop bx
pop ax
ret
Error:
;----- open A20 -----
Jmp_there:
in al, 0x92
or al, 00000010b
out 0x92, al
;----- load gdtr-----
lgdt [gdt_ptr]
;----- cr0 set -----
mov eax, cr0
or eax, 0x00000001
mov cr0, eax
;----- clear instruction pipeline -----
jmp dword SELECTOR_CODE:p_m_start
[bits 32]
p_m_start:
mov ax, SELECTOR_DATA
mov ds, ax
mov es, ax
mov ss, ax
mov esp, LOADER_ADDR
mov ax, SELECTOR_VIDEO
mov gs, ax
mov ecx, msg3-msg2
mov si, msg2
mov di, 1280
show_str2:
mov byte al, [si]
mov byte [gs:di], al
inc si
add di, 2
loop show_str2
pagination_mode:
call setup_page
sgdt [gdt_ptr]
mov eax, [gdt_ptr + 2]
or dword [eax + 0x18 + 4], 0xc0000000
add dword [gdt_ptr + 2], 0xc0000000
set_cr3:
mov eax, PAGE_DIR_TABLE_POS
mov cr3, eax
set_cr0_page:
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
reload_gdt:
lgdt [gdt_ptr]
mov ecx, GDT_BASE-msg3
mov si, msg3
mov di, 1440
show_str3:
mov byte al, [si]
mov byte [gs:di], al
inc si
add di, 2
loop show_str3
jmp $
;string
msg2 db "enter protect mode"
msg3 db "enable pagination mode"
;GDT_CREATE
GDT_BASE:
dd 0x00000000, 0x00000000
CODE_DESC:
dd 0x0000FFFF, DESC_CODE_HIGH4
DATA_DESC:
dd 0x0000FFFF, DESC_DATA_HIGH4
VIDEO_DESC:
dd 0x80000007, DESC_VIDEO_HIGH4
GDT_SIZE equ $ - GDT_BASE
GDT_LIMIT equ GDT_SIZE - 1
times 30 dq 0
;SELECTOR_SET
SELECTOR_CODE equ 0000000000001_000b + TI_GDT + RPL0
SELECTOR_DATA equ 0000000000010_000b + TI_GDT + RPL0
SELECTOR_VIDEO equ 0000000000011_000b + TI_GDT + RPL0
;GDT_pointer
gdt_ptr dw GDT_LIMIT
dd GDT_BASE
setup_page:
mov ecx, 1024
mov esi, 0
clear_page_dir:
mov dword [PAGE_DIR_TABLE_POS + 4*esi], 0
inc esi
loop clear_page_dir
create_pde:
mov eax, PAGE_DIR_TABLE_POS
add eax, 0x1000
mov ebx, eax
set_1_769_1024_PDE:
or eax, PG_US_U | PG_RW_W | PG_P
mov [PAGE_DIR_TABLE_POS + 0x0], eax
mov [PAGE_DIR_TABLE_POS + 0xc00], eax
sub eax, 0x1000
mov [PAGE_DIR_TABLE_POS + 0xffc], eax
mov ecx, 254
mov edx, PAGE_DIR_TABLE_POS
mov edi, 769
add eax, 0x2000
set_kernel_769~1022_PDE:
mov [edx + 4*edi], eax
inc edi
add eax, 0x1000
loop set_kernel_769~1022_PDE
set_0_PTE:
mov ecx, 256
mov edx, PAGE_DIR_TABLE_POS
add edx, 0x1000
mov edi, 0
and eax, 0x00000111
create_pte:
mov [edx + 4*edi], eax
inc edi
add eax, 0x1000
loop create_pte
ret
写入硬盘
nasm -I OS/include/ -o OS/boot/mbr.bin OS/boot/mbr.s
nasm -I OS/include/ -o OS/boot/loader.bin OS/boot/loader.s
dd if=OS/boot/mbr.bin of=bochs/hd60M.img bs=512 count=1 seek=0 conv=notrunc
dd if=OS/boot/loader.bin of=bochs/hd60M.img bs=512 count=4 seek=1 conv=notrunc
启动bochs执行
./bochs/bin/bochs -f bochs/boot.disk
页目录表详细信息: