Assembly 如何在实模式下保存值并在受保护模式下访问它?

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; //

我得到了一个代码,它试图将VBE LFB地址传递到保护模式,但无法访问正确的值,我只是不知道在保护模式下获取真实模式保存值的正确方法 (我想这里没有问题)靴子

[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,那么值应该是相同的,您甚至不需要从堆栈中保存和恢复它。