gpt4 book ai didi

assembly - 如何在 NASM 程序集中进入 32 位保护模式?

转载 作者:行者123 更新时间:2023-12-04 11:37:04 35 4
gpt4 key购买 nike

我正在学习 x86 汇编,我正在尝试用 NASM 制作一个玩具操作系统,但我不明白一些事情。

我制作了一个成功引导我的内核的 bootstrap :

  • 从包含内核文件的软盘加载 14 个扇区;
  • 在这些标记为 kernel.feo 的扇区中搜索文件;
  • 将该文件加载到内存中的偏移量 0x2000 ;
  • 使用远跳转执行内核 jmp 0x2000:0x0000 .

  • 所以我的内核代码位于 0x2000:0在内存中。 CS可能因为使用了远跳而被正确设置。在这个内核代码中,我想进入 32 位保护模式,但我不确定 GDT 是如何工作的。当我在虚拟机上运行以下代码时 (QEMU) ,就是什么都不做。

    我想请你帮我进入32位保护模式!

    That said, you have the following problems:

    1. You assume the code is loaded at 0x7c00:0 due to the org 0, but that might not be the case. The only thing guaranteed is the physical address. You should use a far jump to your entry point so that CS is properly set.
    2. You are for some reason setting DS to 0x2000 so your code won't find any data at all. You should set DS to match CS, or use a CS override everywhere (not recommended).
    3. The protected mode code assumes zero-based segment, which in turn means it expects org 0x7c00 which of course conflicts with your setup. You should switch to org 0x7c00 and segments 0.
    4. The VGA text mode segment is at 0xb8000 not 0xb80000 (one less zero).
    5. You don't have the boot signature bytes 0x55 0xaa at the end of the boot sector.


    我在我的代码中更正了这些事情:
  • [org 0x0]更正为 [org 0x2000]和段设置为 0 ;
  • DS更正为 0而不是 0x2000 ,所以现在它与 CS 匹配;
  • VGA 文本模式段更正为 0xb8000 ;

  • 但是代码不能使用这些更正,它应该打印两个字符串但它什么也不做!

    请注意,此内核代码不应以引导签名 0x55 0xAA 结尾,因为它不是引导扇区。

    这是更正后的内核代码(不起作用):
    [bits 16]
    [org 0x2000]

    jmp 0:kernel_start

    gdt_start:

    gdt_null:
    dd 0x0
    dd 0x0

    gdt_code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10011010b
    db 11001111b
    db 0x0

    gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

    gdt_end:

    gdt_descriptor:
    dw gdt_end - gdt_start
    dd gdt_start

    CODE_SEG equ gdt_code - gdt_start
    DATA_SEG equ gdt_data - gdt_start

    print:
    mov ah, 14
    mov bh, 0
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp print
    .done:
    ret

    uzenet_real db 'uzenet16', 0
    uzenet_prot db 'uzenet32', 0

    kernel_start:
    mov ax, 0
    mov ss, ax
    mov sp, 0xFFFC

    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, uzenet_real
    call print

    cli
    lgdt[gdt_descriptor]
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp CODE_SEG:b32

    [bits 32]

    VIDEO_MEMORY equ 0xb8000
    WHITE_ON_BLACK equ 0x0f

    print32:
    pusha
    mov edx, VIDEO_MEMORY
    .loop:
    mov al, [ebx]
    mov ah, WHITE_ON_BLACK
    cmp al, 0
    je .done
    mov [edx], ax
    add ebx, 1
    add edx, 2
    jmp .loop
    .done:
    popa
    ret

    b32:
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    mov ebp, 0x90000
    mov esp, ebp

    mov ebx, uzenet_prot
    call print32

    jmp $

    最佳答案

    对操作系统进行编程是一项高级任务。您至少应该能够使用调试器来发现自己的错误并理解基本的东西。您可能需要重新考虑您是否具备这项工作的所有先决条件。

    也就是说,您有以下问题:

  • 您假设代码加载于 0x7c00:0由于 org 0 ,但情况可能并非如此。唯一保证的是物理地址。您应该使用远跳转到您的入口点,以便 CS已正确设置。
  • 您出于某种原因设置 DS0x2000所以你的代码根本找不到任何数据。您应该设置 DS匹配 CS ,或使用 CS到处覆盖(不推荐)。
  • 保护模式代码假定从零开始的段,这意味着它期望 org 0x7c00这当然与您的设置冲突。你应该切换到 org 0x7c00和段0 .
  • VGA 文本模式段位于 0xb8000不是 0xb80000 (减一零)。
  • 您没有启动签名字节 0x55 0xaa在引导扇区的末尾。

  • 固定代码:
    [bits 16]
    [org 0x7c00]

    jmp 0:kernel_start

    gdt_start:

    gdt_null:
    dd 0x0
    dd 0x0

    gdt_code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10011010b
    db 11001111b
    db 0x0

    gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

    gdt_end:

    gdt_descriptor:
    dw gdt_end - gdt_start
    dd gdt_start

    CODE_SEG equ gdt_code - gdt_start
    DATA_SEG equ gdt_data - gdt_start

    print:
    pusha
    mov ah, 14
    mov bh, 0
    .loop:
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp .loop
    .done:
    popa
    ret

    uzenet16 db 'uzenet16', 0
    uzenet32 db 'uzenet32', 0

    kernel_start:
    mov ax, 0
    mov ss, ax
    mov sp, 0xFFFC

    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, uzenet16
    call print

    cli
    lgdt[gdt_descriptor]
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp CODE_SEG:b32

    [bits 32]

    VIDEO_MEMORY equ 0xb8000
    WHITE_ON_BLACK equ 0x0f

    print32:
    pusha
    mov edx, VIDEO_MEMORY
    .loop:
    mov al, [ebx]
    mov ah, WHITE_ON_BLACK
    cmp al, 0
    je .done
    mov [edx], ax
    add ebx, 1
    add edx, 2
    jmp .loop
    .done:
    popa
    ret

    b32:
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    mov ebp, 0x2000
    mov esp, ebp

    mov ebx, uzenet32
    call print32

    jmp $

    [SECTION signature start=0x7dfe]
    dw 0AA55h

    您更新的问题似乎仍然对代码的加载位置感到困惑:您说 offset 0x2000再谈 Executes the kernel using a far jump jmp 0x2000:0x0000这当然是错误的,因为它在段中还有一个零,无论如何应该是零段远跳: jmp 0:0x2000 .除此之外,验证您的代码确实在正确的位置加载到内存中。学习使用调试器。

    这是一个小的引导扇区,它将上述代码从第二个扇区加载到地址 0x2000 .它工作正常,问题不在于 GDT 的东西,特别是如果你甚至没有打印出实模式消息(你也不清楚)。
    [bits 16]
    [org 0x7c00]
    mov ax, 0201h
    mov cx, 0002h
    mov dh, 0
    mov bx, 0
    mov es, bx
    mov bx, 2000h
    int 13h
    jmp 0:2000h

    [SECTION signature start=0x7dfe]
    dw 0AA55h

    关于assembly - 如何在 NASM 程序集中进入 32 位保护模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28645439/

    35 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com