+ -
当前位置:首页 → 问答吧 → 如何使用汇编语言编写程序进入保护模式

如何使用汇编语言编写程序进入保护模式

时间:2009-11-17

来源:互联网

下面是一段演示进入保护模式的汇编代码, 可是我在我的机器上运行的时候老是失败, 还望高手指点一二。
另外, Window下面的应该程序可以自由地选择进入实/保护模式么???


;;;;;;;;;;;;;;;;;;;程序开始;;;;;;;;;;;;;;;;;;
;data struct

jump macro selector, offset
db 0eah
dw offset
dw selector
endm

;extrn DispStr:near
;extrn Exit:near
desp struc
segLimit dw 0; byte0, 1
segBaseLow dw 0; byte2, 3
segBaseMid db 0; byte4
segAttribute dw 0; byte5, 6
segBaseHigh db 0; byte7
desp ends

pgdt struc
segLimit dw 0ffffh; byte 0, 1
segBase dd 0; byte 2, 3, 4, 5
pgdt ends


;--------------------------------------------------------------------
; real mode data segment begin
;.data

.386p; if not p, lgdt is not defined
dseg segment use16 ;一定需要使用use16

; gdt segment begin
gdt label byte
DUMMY desp <>; 空描述符!!!
dataSegDesp desp <0ffffh,0h,0h,092h,> ; data segment is started with: 0x00000000h
dataSegSel = dataSegDesp - gdt ;dataSegSel的值为段描述符的偏移值,将其直接存放于ds中则其高!3位即为描述符索引了:)

codeSegDesp desp <0ffffh,,,098h,>
codeSegSel = codeSegDesp - gdt

extSegDesp desp <0ffffh,,88h,092h,> ; ext segment is started with: 0x00880000h
extSegSel = extSegDesp - gdt
gdtLen = $ - gdt
pgdtr pgdt <gdtLen-1, >
; gdt segment end

; pmode data segment begin
buffers db 256 dup('@')
bufferLen = $ - offset buffers

msg db "hello word"
msgLen = $ - offset msg
; pmode data segment end

bufferd db 256 dup('y')
bufferd2 db 256 dup('x')
dseg ends
; real mode data segment end

;--------------------------------------------------------------------
cseg segment use16
;.code
assume cs:cseg, ds:dseg

start:
MOV ax, dseg
MOV ds, ax

;prepare to jump to pmode
;1>. init gdtr
;2>. init code descriptor
;3>. init data descriptor
;4>. enable a20 address
;5>. set cr0
;6>. jump pmode

;1>. init gdtr
MOV bx, 16
MUL bx
ADD ax, offset gdt
ADC dx, 0
MOV WORD PTR pgdtr.segBase, ax
MOV WORD PTR pgdtr.segBase+2, dx

;2>. init code descriptor
MOV ax, cs
MUL bx
MOV codeSegDesp.segBaseLow, ax
MOV codeSegDesp.segBaseMid, dl
MOV codeSegDesp.segBaseHigh, dh

;3>. init data descriptor
MOV ax, ds
MUL bx
ADD ax, offset buffers
adc dx, 0
MOV dataSegDesp.segBaseLow, ax
MOV dataSegDesp.segBaseMid, dl
MOV dataSegDesp.segBaseHigh, dh
lgdt pgdtr

;4>. enable A20 address
cli
call enableA20

;5>. set cr0
MOV eax, cr0
or eax, 1
MOV cr0, eax

;6>. jump to pmode
;JMP pmode
jump <codeSegSel>,<offset pmode>

pmode:
MOV ax, dataSegSel
MOV ds, ax
MOV ax, extSegSel
MOV es, ax

;将数据段中常规内存口256个字节数据送到附加段中扩展内存中
cld
xor si,si
xor di,di
MOV si, offset buffers
MOV cx, bufferLen/4
repz movsd

;将附加段中扩展内存送到数据段常规内存buffer2中
cld
xor si,si
xor di,di
MOV si, offset bufferd
MOV cx, bufferLen/4
Copy4Bytes:
MOV eax, DWORD PTR es:[di]
MOV DWORD PTR DS:[si], eax
loop Copy4Bytes


MOV eax, cr0
and eax, 0fffffffeh
MOV cr0, eax
JMP rmode

rmode:
call disableA20
sti

MOV ax, dseg
MOV ds, ax

;在实模式下显示buffer2的内容, 看是否被buffers中的内容所替换
MOV cx, msgLen
MOV di, offset bufferd
call DispStr
call Exit

enableA20 proc
PUSH ax
in al, 92h
or al, 2
out 92h, al
POP ax
RET
enableA20 endp

disableA20 proc
PUSH ax
in al, 92h
and al, 0fdh
out 92h, al
POP ax
RET
disableA20 endp

;=============
;input1: cx - the length of the string
;input2: di - the begin address of the string
;output: nothing
DispStr proc
PUSH di
PUSH cx
PUSH ax
PUSH bx

MOV ah, 0eh
MOV bh, 0

PrintStrDisplay:
MOV al, [di]
int 10h
INC di
DEC cx
cmp cx, 0
JZ PrintStrDisplayEnd
JMP PrintStrDisplay


PrintStrDisplayEnd:
POP bx
POP ax
POP cx
POP di

RET
DispStr endp

;=============
;input: none
;output: al - exit code
Exit proc
MOV ah, 4ch
int 21h
Exit endp
cseg ends
END start

作者: zliu004   发布时间: 2009-11-17

你贴的代码是操作系统启动时从实模式跳转到保护模式的一个示例。你启动windows后,你就进入保护模式了,没法切换回实模式。

作者: li668xiao   发布时间: 2009-11-18

这种程序要在DOS环境下执行,Windows系统本身就是运行在保护模式下的,也不允许改变处理器的工作模式。

作者: cnzdgs   发布时间: 2009-11-18

A 装window 9x 系列,然后选择重启进入dos

B 用虚拟机直接安装dos

作者: mydo   发布时间: 2009-11-18

DOS下或者虚拟机。WIN本身就是保护模式下运行的。

作者: goodider   发布时间: 2009-11-19

從nt後就不允許進實模式了 你要進去幹嘛呢

作者: zhanzongru   发布时间: 2009-11-19

你的保护环境没有设置好:
1.先设置环境,both 16 bits and 32 bits,应为你的程序要从16 to 32 位跳转
 0xcf9a = 32 bits code segments
 0xcf92 = 32 bits data segments
 
 0x009a = 16 bits code segments
 0x0092 = 16 bits data segments.

 I really don't know what the meaning of your code following:
 codeSegDesp desp <0ffffh,,,098h,> 

2, 没有通知cpu 并更该相应的进入保护模式寄存期的标志位, 并且屏蔽所有的系统中断,以保证成功跳转。

example:

;SWITCH To PROTECTED MODE
LGDT [GDT_dscr]
MOV EAX, CR0 ;enablel flag (the Oth bit
OR AL, 0x01
MOV CR0, EAX
;<<processor now in protected mode>>
;JMP GDT_linear:protected_code;GDT_code:protected_code ; jmp instructio;n
JMP GDT_code:protected_code


good luck!

作者: miaomiao83   发布时间: 2009-11-23

环境变量设置部分:(测试成功过的,运行没有任何问题的)
;globle descriptor table
GDT_dscr:
dw GDT_end-GDT-1
dd GDT
GDT
nullsel equ $-GDT ; $->current location,so nullsel = 0h
 
GDT0
  dd 0
  dd 0
GDT_code equ $-GDT
GDT1 ;equals to code_gdt
  dw 0xFFFF ;protected mode code segment format
  dw 0x0000 ;0xcf9a
  db 0x00 ;dw 0x00
  db 10011010b ;10010010b ;0x92(data 16 bits 0f92 code 0f9a)
  db 11001111b ;0xcf 32 bits 0x0f 16 bits
  db 0x00
;GDT_code equ $-GDT ;equals 2 datasel

GDT_data equ $-GDT
GDT2 ;equals data_gdt
dw 0xFFFF ;protected mode data segment format
dw 0 ;0xcf92
db 0
db 10010010b ;10011010b ;0x9a ()
db 11001111b ;0xcf 16 bits
db 0x00
;GDT_data equ $-GDT ;equals videosel
videosel equ $-GDT ;GDT5
dw 3999 ; Limit 80*25*2-1
dw 0x8000 ; Base 0xb8000
db 0x0b
db 0x92 ; present,ring 0,data,expand-up,writable
db 0x00 ; byte granularity 16 bit
db 0x00

GDT_rcode equ $-GDT
GDT3 ;real mode code segment format
dw 0xFFFF ;0x0f9a
dw 0
db 0
db 10011010b;10010010b ;0x9a
db 00001111b;0x0f 16bits
db 0x00

GDT_rdata equ $-GDT
GDT4 ;real mode data segment format
dw 0xFFFF ;0x0f92
dw 0
db 0
db 10010010b ;0x92
db 00001111b ;0x00
db 0x00
GDT_end

作者: miaomiao83   发布时间: 2009-11-23

别忘记给分。
要更多资料说话。

作者: miaomiao83   发布时间: 2009-11-24

#6楼的朋友可以贴出完整的代码吗? 我使用你的代码都没法通过编译呀.

作者: zliu004   发布时间: 2009-11-24

我考,六楼的代码是nasm 编写的,你的源程序是MASM 编写的。当然便已无法通过了。
给你一个简单的例子(nasm)练练先:

test.asm (protected mode data ,code GDT only) final successful version 10-29-09 TAO ZHOU
org 0x7C00
use16
;****************************
; Realmode startup code.
;****************************

start:
  xor ax,ax
  mov ds,ax
  mov es,ax
  mov ss,ax
  mov sp,0x7C00

;*****************************
; Setting up, to enter pmode.
;*****************************
  cli
  lgdt [gdtr]
   
  mov eax, cr0
  or al,0x1
  mov cr0,eax
 
  jmp 0x10: protected

;*****************************
; Pmode.
;*****************************

use32
protected:
  mov ax,0x8
  mov ds,ax
  mov es,ax
  mov ss,ax
  mov esp,0x7C00
;*****************************
; Turn floppy off (if space).
;*****************************

  mov dx,3F2h
  mov al,0
  out dx,al

  lea esi,[msg0]  
  mov edi,0xB8000 + (80 * 3 + 4) * 2  
  mov ecx,28
  cld
  rep movsb

  jmp $
;*************************************
; GDT.
;*************************************

gdt: dw 0x0000, 0x0000, 0x0000, 0x0000
sys_data: dw 0xFFFF, 0x0000, 0x9200, 0x00CF
sys_code: dw 0xFFFF, 0x0000, 0x9800, 0x00CF
gdt_end:

gdtr: dw gdt_end - gdt - 1  
  dd gdt

;*************************************
; Data.
;*************************************

msg0 db " H E L L O W O R L D ! "

;*************************************
; Make program 510 byte's + 0xaa55
;*************************************
   
times 510- ($-start) db 0
dw 0xaa55


作者: miaomiao83   发布时间: 2009-11-26

http://www.upwardit.com/ShowSpecial.asp?SpecialID=1

作者: djd7726   发布时间: 2009-11-27

学习下。

作者: iqyely   发布时间: 2009-11-27

09年的帖子到现在没结贴 哇哈哈!

作者: znxllyuan   发布时间: 2011-01-07