Q. lesson can be drawn from a small question, whether the following statement has Bug existence
after entering protected mode, using the stack segment at the selected site in the first to ss assignment, and then use the print, that there will exist Bug because the use of the function call, the function call using stack space required, but also -esp stack pointer register, and in the code here no assignment of registers esp. Esp need to register here to find out.
A. For the class code experiments
step here is to first find the address values decompiled at jump, and then set a breakpoint on a step by step bochs stepping it runs into the upcoming 5 call the command, then test the reg command to register addresses, it found that the address esp register is 0x00007c00, consistent with the top of the stack register address of the last chapter, the results of the program in line with expectations. Here there will be a question not of esp register address assignment, why in the 32 protected mode, but the value of esp register points to the top, you can experiment once again
to verify esp - experiment
[]!
Case run here , the same first address by decompiling look at Figure 1, and set a breakpoint register values and check esp at the breakpoint, and then stepping in jump value of, esp view register value, and finally into the the 32-bit protected mode address register esp view, esp found all registers are the same, so in the 32-bit protected mode does not have a gram esp register assignment.
stack segment at a. protected mode
1. specified spatial period, and define a descriptor
according to the definition of the position of the segment descriptor table selectors
3. initialize the segment register
stack pointer 4. initialize the
general definition of the stack segment B. (protected mode)
mainly the segment descriptor base address and the last chapter has been modified, and redefines a new code sections, as well as the specific definition of protected mode stack segment
%include "inc.asm"
org 0x9000
jmp CODE16_SEGMENT
[section .gdt]
; GDT definition
;
GDT_ENTRY : Descriptor 0, 0, 0
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32
VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32
DATA32_DESC : Descriptor 0, Data32SegLen - 1, DA_DR + DA_32
STACK32_DESC : Descriptor 0, TopOfStack32, DA_DRW + DA_32
; GDT end
GdtLen equ $ - GDT_ENTRY
GdtPtr:
dw GdtLen - 1
dd 0
; GDT Selector
Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector equ (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]
TopOfStack16 equ 0x7c00
[section .dat]
[bits 32]
DATA32_SEGMENT:
DTOS db "D.T.OS!", 0
DTOS_OFFSET equ DTOS - $$
HELLO_WORLD db "Hello World!", 0
HELLO_WORLD_OFFSET equ HELLO_WORLD - $$
Data32SegLen equ $ - DATA32_SEGMENT
[section .s16]
[bits 16]
CODE16_SEGMENT:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, TopOfStack16
; initialize GDT for 32 bits code segment
mov esi, CODE32_SEGMENT
mov edi, CODE32_DESC
call InitDescItem
mov esi, DATA32_SEGMENT
mov edi, DATA32_DESC
call InitDescItem
mov esi, STACK32_SEGMENT
mov edi, STACK32_DESC
call InitDescItem
; initialize GDT pointer struct
mov eax, 0
mov ax, ds
shl eax, 4
add eax, GDT_ENTRY
mov dword [GdtPtr + 2], eax
; 1. load GDT
lgdt [GdtPtr]
; 2. close interrupt
cli
; 3. open A20
in al, 0x92
or al, 00000010b
out 0x92, al
; 4. enter protect mode
mov eax, cr0
or eax, 0x01
mov cr0, eax
; 5. jump to 32 bits code
jmp dword Code32Selector : 0
; esi --> code segment label
; edi --> descriptor label
InitDescItem:
push eax
mov eax, 0
mov ax, cs
shl eax, 4
add eax, esi
mov word [edi + 2], ax
shr eax, 16
mov byte [edi + 4], al
mov byte [edi + 7], ah
pop eax
ret
[section .s32]
[bits 32]
CODE32_SEGMENT:
mov ax, VideoSelector
mov gs, ax
mov ax, Stack32Selector
mov ss, ax
mov eax, TopOfStack32
mov esp, eax
mov ax, Data32Selector
mov ds, ax
mov ebp, DTOS_OFFSET
mov bx, 0x0C
mov dh, 12
mov dl, 33
call PrintString
mov ebp, HELLO_WORLD_OFFSET
mov bx, 0x0C
mov dh, 13
mov dl, 31
call PrintString
jmp $
; ds:ebp --> string address
; bx --> attribute
; dx --> dh : row, dl : col
PrintString:
push ebp
push eax
push edi
push cx
push dx
print:
mov cl, [ds:ebp]
cmp cl, 0
je end
mov eax, 80
mul dh
add al, dl
shl eax, 1
mov edi, eax
mov ah, bl
mov al, cl
mov [gs:edi], ax
inc ebp
inc dl
jmp print
end:
pop dx
pop cx
pop edi
pop eax
pop ebp
ret
Code32SegLen equ $ - CODE32_SEGMENT
[section .gs]
[bits 32]
STACK32_SEGMENT:
times 1024 * 4 db 0
Stack32SegLen equ $ - STACK32_SEGMENT
TopOfStack32 equ Stack32SegLen - 1
make之后在bochs下的运行结果
现在通过实验对esp再次进行查看,首先再次通过反编译对跳转指令查看,然后设置断点并单步查看,并单步查看的寄存器地址的变化-ss段寄存器指向了定义的栈段,最后esp指向栈空间的限制处,最后打印处字符串,说明自定义的栈段空间被使用了
C.是否能从保护模式返回实模式?
a.80x86中的一个神秘限制
1.无法直接从32位代码段回到实模式
2.只能从16位代码段间接返回实模式
3.在返回前必须用合适的选择子对寄存器赋值
b.处理器中的设计简介
1.80286之后的处理器都提供兼容8086的实模式
2.然而,绝大多数处理器都运行于保护模式
3.因此,保护模式的运行效率至关重要
4.那么,处理器如何高效的访问内存中的段描述符?
Cache memory - solution for
a selected sub-set when a segment register.
1. The selecting sub-access memory descriptor
2. descriptor segment register is loaded into the cache memory
3. For information descriptor , directly from the cache memory
but a problem arises when the processor is running in real mode, cache memory segment register whether to use?
Here should be noted that - in real mode, the cache memory is still in operation, the segment base address is 32 bits, which is the value of the corresponding segment register is multiplied by 16, the real mode segment base address valid bit to 20 bits, segment limit fixed 0xFFFF (64K), the value of the attribute section is not provided, can continue to use the value of the protection provided
therefore, when the real mode from protected mode - to provide a suitable load descriptor related to the selected sub-segment register, so that the corresponding segment descriptor register which contains the cache block boundaries and properties suitable
real mode flow
Code
%include "inc.asm"
org 0x9000
jmp ENTRY_SEGMENT
[section .gdt]
; GDT definition
; 段基址, 段界限, 段属性
GDT_ENTRY : Descriptor 0, 0, 0
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32
VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32
DATA32_DESC : Descriptor 0, Data32SegLen - 1, DA_DR + DA_32
STACK32_DESC : Descriptor 0, TopOfStack32, DA_DRW + DA_32
CODE16_DESC : Descriptor 0, 0xFFFF, DA_C
UPDATE_DESC : Descriptor 0, 0xFFFF, DA_DRW
; GDT end
GdtLen equ $ - GDT_ENTRY
GdtPtr:
dw GdtLen - 1
dd 0
; GDT Selector
Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector equ (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ (0x0004 << 3) + SA_TIG + SA_RPL0
Code16Selector equ (0x0005 << 3) + SA_TIG + SA_RPL0
UpdateSelector equ (0x0006 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]
TopOfStack16 equ 0x7c00
[section .dat]
[bits 32]
DATA32_SEGMENT:
DTOS db "D.T.OS!", 0
DTOS_OFFSET equ DTOS - $$
HELLO_WORLD db "Hello World!", 0
HELLO_WORLD_OFFSET equ HELLO_WORLD - $$
Data32SegLen equ $ - DATA32_SEGMENT
[section .s16]
[bits 16]
ENTRY_SEGMENT:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, TopOfStack16
mov [BACK_TO_REAL_MODE + 3], ax
; initialize GDT for 32 bits code segment
mov esi, CODE32_SEGMENT
mov edi, CODE32_DESC
call InitDescItem
mov esi, DATA32_SEGMENT
mov edi, DATA32_DESC
call InitDescItem
mov esi, STACK32_SEGMENT
mov edi, STACK32_DESC
call InitDescItem
mov esi, CODE16_SEGMENT
mov edi, CODE16_DESC
call InitDescItem
; initialize GDT pointer struct
mov eax, 0
mov ax, ds
shl eax, 4
add eax, GDT_ENTRY
mov dword [GdtPtr + 2], eax
; 1. load GDT
lgdt [GdtPtr]
; 2. close interrupt
cli
; 3. open A20
in al, 0x92
or al, 00000010b
out 0x92, al
; 4. enter protect mode
mov eax, cr0
or eax, 0x01
mov cr0, eax
; 5. jump to 32 bits code
jmp dword Code32Selector : 0
BACK_ENTRY_SEGMENT:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, TopOfStack16
in al, 0x92
and al, 11111101b
out 0x92, al
sti
mov bp, HELLO_WORLD
mov cx, 12
mov dx, 0
mov ax, 0x1301
mov bx, 0x0007
int 0x10
jmp $
; esi --> code segment label
; edi --> descriptor label
InitDescItem:
push eax
mov eax, 0
mov ax, cs
shl eax, 4
add eax, esi
mov word [edi + 2], ax
shr eax, 16
mov byte [edi + 4], al
mov byte [edi + 7], ah
pop eax
ret
[section .s16]
[bits 16]
CODE16_SEGMENT:
mov ax, UpdateSelector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and al, 11111110b
mov cr0, eax
BACK_TO_REAL_MODE:
jmp 0 : BACK_ENTRY_SEGMENT
Code16SegLen equ $ - CODE16_SEGMENT
[section .s32]
[bits 32]
CODE32_SEGMENT:
mov ax, VideoSelector
mov gs, ax
mov ax, Stack32Selector
mov ss, ax
mov eax, TopOfStack32
mov esp, eax
mov ax, Data32Selector
mov ds, ax
mov ebp, DTOS_OFFSET
mov bx, 0x0C
mov dh, 12
mov dl, 33
call PrintString
mov ebp, HELLO_WORLD_OFFSET
mov bx, 0x0C
mov dh, 13
mov dl, 31
call PrintString
jmp Code16Selector : 0
; ds:ebp --> string address
; bx --> attribute
; dx --> dh : row, dl : col
PrintString:
push ebp
push eax
push edi
push cx
push dx
print:
mov cl, [ds:ebp]
cmp cl, 0
je end
mov eax, 80
mul dh
add al, dl
shl eax, 1
mov edi, eax
mov ah, bl
mov al, cl
mov [gs:edi], ax
inc ebp
inc dl
jmp print
end:
pop dx
pop cx
pop edi
pop eax
pop ebp
ret
Code32SegLen equ $ - CODE32_SEGMENT
[section .gs]
[bits 32]
STACK32_SEGMENT:
times 1024 * 4 db 0
Stack32SegLen equ $ - STACK32_SEGMENT
TopOfStack32 equ Stack32SegLen - 1
Run Results
Summary
when the stack segment 1. Definition protected mode segment selector must be set and stack pointer
2. The real mode from protected mode can be indirect jump
3. In real mode, it is still used in the data cache to do an effective judgment
4. modify the runtime instruction data can be dynamically determined by the behavior of the code