Assembly 如何在实模式下保存值并在受保护模式下访问它?
我得到了一个代码,它试图将VBE LFB地址传递到保护模式,但无法访问正确的值,我只是不知道在保护模式下获取真实模式保存值的正确方法 (我想这里没有问题)靴子Assembly 如何在实模式下保存值并在受保护模式下访问它?,assembly,x86,nasm,protected,Assembly,X86,Nasm,Protected,我得到了一个代码,它试图将VBE LFB地址传递到保护模式,但无法访问正确的值,我只是不知道在保护模式下获取真实模式保存值的正确方法 (我想这里没有问题)靴子 [BITS 16] [ORG 0x7C00] setup_stack: xor ax, ax; // ax = 0 mov ds, ax; // ds = 0 mov es, ax; //
[BITS 16]
[ORG 0x7C00]
setup_stack:
xor ax, ax; // ax = 0
mov ds, ax; // ds = 0
mov es, ax; // es = ds
mov bx, 0x8000; // stack segment can be any usable memory
mov ss, bx; // stack start 0x80000
mov sp, ax; // stack final 0x8FFFF
cld; // clear direction flag
read_kernel:
mov ah, 00; // reset disk
int 13h; // disk interrupt
mov ax, 0x0000; // register ax [0000]:1000
mov bx, 0x1000; // register bx 0000:[1000]
mov ah, 0x2; // read sector instruction
mov al, 0x3; // sectors to read
mov ch, 0x0; // cylinder
mov cl, 0x2; // local to write
mov dh, 0x0; // head
int 0x13; // call the disk interupter
jmp 0x0000:0x1000; // Jump to kernel
cli; // clear interrupt flag
hlt; // halt
内核加载VBE,然后加载受保护模式kernel.s:
[BITS 16]
[ORG 0x1000]
jmp main_x16;
%include "sys/x16/data.s"; // the GDT table
%include "sys/x16/code/VBE.s" // 512+256 bytes so dont fit the boorloader
main_x16:
call VBE.enable; // its works and here i draw a pixel
call enter_x32; // enter in protected mode ( x32 bits )
enter_x32:
cli; // clear interrupts
lgdt [gdt_descriptor]; // load Global Descriptor Table
mov eax, cr0; // switch to protected mode
or eax, 0x1; // set PE ( Protection Enable ) bit in CR0
mov cr0, eax; // CR0 is a Control Register 0
jmp CODE_SEG:main_x32; // far jump to 32 bit instructions
[BITS 32]
main_x32:
mov eax, DATA_SEG
mov ds, eax;
mov es, eax;
mov ss, eax;
movzx esp, sp
pop edi; LFB address, the value from mode.framebuffer
mov al, 0x0F; the color of the pixel
mov [edi], al
jmp $;
据我所知,vbe在这里没有问题,我尽可能简化了表格:
[BITS 16]
VBE:
.signature db "VBE2"; // must be "VESA" to indicate valid VBE support
.version resw 1; // VBE version; high byte is major version, low byte is minor version
.oem resd 1; // segment:offset pointer to OEM
.capabilities resd 1; // bitfield that describes card capabilities
.video_modes resd 1; // segment:offset pointer to list of supported video modes
.video_memory resw 1; // amount of video memory in 64KB blocks
.rest_of_table resb 500 ;... and others values, this block got 512 bytes; and that line is just to simplify the code
.get_info:
mov ah, 4Fh; Super VGA support
mov al, 00h; Return Super VGA information
mov di, VBE; Pointer to buffer
int 0x10;
ret
.enable:
call VBE.get_info;
call mode.get_info;
call mode.set;
.draw:
;Assume first window is valid
mov ax, WORD [es:mode + 08h]
mov es, ax
;Example of how to change the window
mov ax, 4f05h
xor bx, bx
mov dx, 5 ;This is granularity units
int 10h
;here i can draw a pixel with no problem
mov edi, [mode.framebuffer]; framebuffer address
push edi; save edi for pm
add edi, 180054; pixel address
mov al,0x0F; the color of the pixel
mov [edi], al
ret
mode:
.attributes resw 1; // deprecated, only bit 7 should be of interest to you, and it indicates the mode supports a linear frame buffer.
.window_a resb 1; // deprecated
.window_b resb 1; // deprecated
.granularity resw 1; // deprecated; used while calculating bank numbers
.window_size resw 1;
.segment_a resw 1;
.segment_b resw 1;
.win_func_ptr resd 1; // deprecated; used to switch banks from protected mode without returning to real mode
.pitch resw 1; // number of bytes per horizontal line
.width resw 1; // width in pixels
.height resw 1; // height in pixels
.w_char resb 1; // unused...
.y_char resb 1; // ...
.planes resb 1;
.bpp resb 1; // bits per pixel in this mode
.banks resb 1; // deprecated; total number of banks in this mode
.memory_model resb 1;
.bank_size resb 1; // deprecated; size of a bank, almost always 64 KB but may be 16 KB...
.image_pages resb 1;
.reserved0 resb 1;
.red_mask resb 1;
.red_position resb 1;
.green_mask resb 1;
.green_position resb 1;
.blue_mask resb 1;
.blue_position resb 1;
.reserved_mask resb 1;
.reserved_position resb 1;
.direct_color_attributes resb 1;
.framebuffer resd 1; // physical address of the linear frame buffer; write here to draw to the screen
.off_screen_mem_off resd 1;
.off_screen_mem_size resw 1; // size of memory in the framebuffer but not being displayed on the screen
.reserved1 resb 206;
.get_info:
mov ax, 4F01h; Return mode information
mov cx, 0x101;[VBE_info.video_modes]; first mode
mov di, mode; Pointer to buffer
int 0x10;
ret
.set:
mov ah, 0
mov ax, 0x4F02
mov ebx, [VBE.video_modes]; estore de modes pointer at ebx to can access as a adress
mov bx, [ebx+8]; 8/2 = 4th mode in the mode array!!!!!!!
int 0x10
ret
系统在保护模式下不绘制像素,因此实际的edi
与保护模式下的不同。
我无法获取保存的
edi
,正确的方法是什么?回答标题问题:最简单的方法是将其保存在注册表中
否则,计算出在实模式下存储在内存中的线性地址,然后在保护模式下访问相同的线性地址
(或者干脆不修改
SS
,使基保持不变,或者更有效的方法是在GDT中使用SS
base=0的平面内存模型,并使用偏移量=该线性地址。例如,将ESP设置为指向在实模式下用于堆栈的相同线性/物理内存区域。)回答标题问题:最简单的方法是将其保存在注册表中
否则,计算出在实模式下存储在内存中的线性地址,然后在保护模式下访问相同的线性地址
(或者干脆不修改
SS
,使基保持不变,或者更有效的方法是在GDT中使用SS
base=0的平面内存模型,并使用偏移量=该线性地址。例如,将ESP设置为指向在实模式下用于堆栈的相同线性/物理内存区域。)您可以将实数模式地址转换为段:偏移量对,并将其转换为线性地址(我假设您在保护模式下不使用分页)。要将段:偏移量转换为线性地址,您可以取段值并将其左移4位(与乘以16相同),然后将偏移量添加到该值。因此,线性_地址=(分段)该计算中的线性地址可以在保护模式下使用。如果要使用保护模式,我建议查询VBE以获得使用LFB(线性帧缓冲区)的VESA视频模式因此,您可以访问视频ram,而无需切换存储组等。我很确定问题的当前形式不是。在重新加载段寄存器之前,更改为保护模式不会影响SS基址,如果SP=ESP,这应该可以正常工作。或者,如果您想继续使用相同的堆栈区域,请正确选择ESP。显然,正如Pete所说r表示这可能与堆栈有关。另一方面,在没有看到进入保护模式的代码的情况下-如果您在切换到保护模式时从未修改过EDI,则该值应相同,您甚至不需要从堆栈中保存和还原它。您可以将段:偏移对的实模式地址转换为li近地址(我假设您在保护模式下不使用分页)。要将段:偏移量转换为线性地址,您可以取段值并将其左移4位(与乘以16相同),然后将偏移量添加到该值。因此,线性地址=(分段该计算中的线性地址可以在保护模式下使用。如果要使用保护模式,我建议查询VBE以获得使用LFB(线性帧缓冲区)的VESA视频模式)因此,您可以访问视频ram,而无需切换存储组等。我很确定问题的当前形式不是。在重新加载段寄存器之前,更改为保护模式不会影响SS基址,如果SP=ESP,这应该可以正常工作。或者,如果您想继续使用相同的堆栈区域,请正确选择ESP。显然,正如Pete所说r说这可能与堆栈有关。另一方面,如果没有看到进入保护模式的代码,那么在切换到保护模式时,如果您从未修改过EDI,那么值应该是相同的,您甚至不需要从堆栈中保存和恢复它。