操作系统与网络实现 之四
来源:互联网 发布:tcp端口号范围 编辑:程序博客网 时间:2024/05/29 14:21
实模式与保护模式互相跳转
从这里开始我们就要告别实模式,实现保护模式了。
首先了解一些相关知识。
段描述符的具体格式
段描述符长8个字节64位。
重点说明:
空描述符: ; 这是保护模式要求保留的,第一个段必须是空段,空描述符的64位全是0
dd 0
dd 0
对于代码段字节5:
db 10011010b ; 0x9A 属性描述位,P=1,DPL=0,DT1=1,TYPE=A,指明此是代码段、可读可执行
对于数据段字节5:
db 10010010b ; 0x92 属性描述位,P=1,DPL=0,DT1=1,TYPE=2,指明此是数据段,可读可写
虚拟地址转换物理地址
简单的说:虚拟地址的偏移量+base=线性地址
在没有使用分布机制情况下,线性地址就是物理地址。
这里,我们没有使用分布机制。
改变kernelloader.asm,让它从实模式到保护模式显示一个字母,再返回实模式并显示hello。
新的kernelloader.asm
[BITS 16]
jmp main
gdt_entries equ 5 ;共有五个段描述符:null,os code32,os data32,os code16,os data16
showbase equ 8900h
pe equ 1 ;bit PE in CR0
null equ 0h
os_code32_sel equ 8h ;1,gdt,rpl=00
os_data32_sel equ 10h ;2,gdt,rpl=00
os_code16_sel equ 18h ;3,gdt,rpl=00
os_data16_sel equ 20h ;4,gdt,rpl=00
[SECTION .data]
ns db 0x48,0x65,0x6C,0x6C,0x6F,0x20,0x77,0x6F,0x72,0x6C,0x64,0x21, 'from ya' ;;hello world!from ya
gdt_table times (gdt_entries*8) db 0
pdescr times 6 db 0
end_32 dd 0
dw 0
hello: ;;hello子程序
push es
mov cx,19 ;;循环19次
mov bx,0 ;;从数组[0]开始
mov ah,0eh
next:
mov al,[ns+bx]
int 10h
inc bx
dec cx
jnz next ;;cx不为0则继续
pop es
ret
main:
mov ax,1000h
mov ds,ax
;打开 A 20 地址线
mov ax , 0x2401
int 0x15
mov word[end_32+0],end32
mov word[end_32+4],os_code16_sel ;point to 0018:end32
;[1]built up GDT table
cli
mov eax,gdt_table
;item 0:null descriptor,
mov dword[eax],0
mov dword[eax+4],0
add eax,8
;item 1,OS code32 descriptor,
;Base=00010000h,limit=0fh,G=1,D=1,type=a,dpl=0
mov word[eax],0000fh
mov word[eax+2],0
mov byte[eax+4],01h
mov byte[eax+5],09ah
mov byte[eax+6],0c0h
mov byte[eax+7],00h
add eax,8
;item 2,OS data32 descriptor
;Base=00010000h,Limit=0fffh,G=1,D=1,Type=2,DPL=0
mov word[eax],0fffh
mov word[eax+2],0000h
mov byte[eax+4],01h
mov byte[eax+5],092h
mov byte[eax+6],0c0h
mov byte[eax+7],00h
add eax,8
;item 3,OS code16 descriptor,
;Base=00010000h,limit=0ffffh,G=0,D=0,type=a,dpl=0
mov word[eax],0ffffh
mov word[eax+2],0
mov byte[eax+4],01h
mov byte[eax+5],09ah
mov byte[eax+6],00h
mov byte[eax+7],00h
add eax,8
;item 4,OS data16 descriptor
;Base=00010000h,Limit=0ffffh,G=0,D=1,Type=2,DPL=0
mov word[eax],0ffffh
mov word[eax+2],0000h
mov byte[eax+4],01h
mov byte[eax+5],092h
mov byte[eax+6],40h
mov byte[eax+7],00h
;[2]built false GDT descriptor
mov word[pdescr+0],(gdt_entries*8)
mov dword[pdescr+2],gdt_table+00010000h
lgdt [pdescr]
;[3]enter into protected mode
;刷新CR0
mov eax,cr0
or eax,pe
mov cr0,eax
jmp flush
flush:
mov ax,os_data32_sel
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov gs,ax
jmp dword os_code32_sel:start32
;[4]run in protected mode
start32:
cli
mov bx,showbase
dw 0ah ;mov ebx,0a8900h
mov di,bx ;es:edi=0010:000a8900=0b8900h
mov al,'A'
mov ah,34h
stosw
mov si,end_32
dw 00h ;mov esi,offset end_32
db 0ffh,2eh ;相当于jmp Fword Ptr [esi] ,jmp to 0018:end32
end32:
;[5]exit to dos
mov ax,os_data16_sel
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov gs,ax
cli
mov eax,cr0
and al,0feh
mov cr0,eax ;clear pe bit,exit of protected mode
mov cr3,eax
jmp realflush
realflush:
mov ax,01000h
mov ds,ax
mov es,ax
mov ss,ax
xor ax,ax
mov fs,ax
mov gs,ax
jmp 0x1000:real16
real16:
mov word[pdescr+0],0ffffh ;limit
mov dword[pdescr+2],0 ;basement
lidt [pdescr]
sti
mov ah,4ch
int 21h
call hello ;返回实模式后显示hello
jmp $
程序中
;打开 A 20 地址线
mov ax , 0x2401
int 0x15
......
;刷新CR0
mov eax,cr0
or eax,pe
mov cr0,eax
jmp flush
flush:
这些语句都是按要求必须这么做的,没什么可说的,大家按套路来就行。
目前kernelloader.bin大小为444字节,占据1个扇区,相应的boot程序中读取扇区的参数值应为1
在bochs中运行效果如下:
16位模式下与32位模式下的编译结果(机器码)是有区别的:
(16位下)mov bx,8900h 机器码为 BB0089
(32位下)mov ebx,68900h 机器码为 BB00890600
两个相差0600
(16位下)mov di,bx 机器码为 89DF
(32位下)mov edi,ebx 机器码为 89DF
两个相同
(16位下)mov si,end_32 机器码为 BE4500
(32位下)mov esi,end_32 机器码为 BE45000000
两个相差0000
(16位下)jmp fword ptr [esi] 机器码为 FF2e
为什么要研究机器码?因为我们程序是在16位模式下编译,但是我们中间这段程序又将要跳转到保护模式,但是在保护模式下运行16位程序显然会出错,怎么解决这个问题?
我们可以将16位模式下与32位模式指令中相差的部分补充上,那么以下的语句就可以理解了:
mov bx,showbase
dw 06h ;相当于mov ebx,68900h
mov di,bx ;es:edi=0010:00068900=0b8900h
mov al,'A' ;16位与32位相同
mov ah,34h ;16位与32位相同
stosw ;16位与32位相同
mov si,end_32
dw 00h ;mov esi,offset end_32
db 0ffh,2eh ;相当于jmp Fword Ptr [esi] ,jmp to 0018:end32
- 操作系统与网络实现 之四
- 操作系统与网络实现 之五
- 操作系统与网络实现 之二
- 操作系统与网络实现 之六
- 操作系统与网络实现 之三
- 操作系统与网络实现 之七
- 操作系统与网络实现 之八
- 操作系统与网络实现 之九
- 操作系统与网络实现 之十
- 操作系统与网络实现 之十一
- 操作系统与网络实现 之十二
- 操作系统与网络实现 之十三
- 操作系统与网络实现 之十四
- 操作系统与网络实现 之十五
- 操作系统与网络实现 之十六
- 操作系统与网络实现 之十七
- 操作系统与网络实现 之十八(甲)
- 操作系统与网络实现 之十八(乙)
- @Resource注解
- Linux系统安装后因为分区调节而出错:Grub
- 父表、子表、主键、外键的关系
- ios申请真机调试( xcode 5)详细解析
- OpenHW12手记--Qt网络服务(TCP UDP)的建立
- 操作系统与网络实现 之四
- SharePoint 2013 IT Professional-- Backup Web Application
- HIVE分析窗口函数:SUM,AVG,MIN,MAX
- 文章标题
- 组装电脑必看知识之处理器CPU参数的认识
- iframe的使用
- HDU1176 免费馅饼 DP
- [Leetcode] [Database] Second Highest Salary解题
- C/C++:结构体常见错误