OS 开发:切换到 32 位模式会破坏我的代码

OS development : switching to 32bit mode breaks my code

编辑:当我将 BITS 32 之后的所有内容移动到 disk_double_error 时,我的问题就解决了,但现在它仍然坏了,是的,它显示消息,但是当我点击 Y 时,它只是 restarts/reboots 系统什么可能是这个原因?

(对不起英语不好)你好我正在尝试写一个简单的 os 只是为了好玩我制作了我的引导加载程序并显示了一些消息并读取了磁盘但是当涉及到切换到 32 位保护时模式我做的所有事情都不起作用它正常显示

`> `
`>succesfully loaded  = if loaded succesfully > failed = if not `
`>Do you want to boot kernel mode Y/N       then gets input`
`>Booting in kernel mode = if Y   null = if no`

但是在我将 lgdt 和其他开关添加到 32 位之后它根本不显示任何东西所以我认为切换是以某种方式清除屏幕所以我尝试在下午用 print_string_pm 功能打印东西但仍然我什么都没用

nasm -fbin bootload.asm -o bootload.bin

编译bootloader

我的代码可能有什么问题请帮忙?

代码如下:

BITS 16
[ORG 0x7c00]
global _boot_start

_boot_start:

    cli
    mov bx,0x9000
    mov bp,bx
    mov sp,bx
    sti 

    pusha
    mov ax, 0x0000     
    mov ds, ax         
    mov es, ax
    popa

    mov [bootdev], dl


    mov bx, MSG_START       
    call print_string


    mov dl, [bootdev]             
    mov dh, 1             
    mov bx, 0x1000         
    call disk_load
    mov bx, MSG_YESNO
    call print_string

    call get_yes_no

    mov bx, MSG_BOOT_KERNEL
    call print_string



    lgdt [gdt_descriptor]

    mov eax , cr0 
    or eax , 0x1 
    mov cr0 , eax

    jmp CODE_SEG:pm

    BITS 32

    pm:


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

    mov ebp , 0x90000 
    mov esp , ebp

    call beg_pm

    beg_pm:

    mov ebx,MSG_BOOT_32
    call print_string_pm

    call KERNEL_OFFSET

    jmp $

;******************************************************************
print_string:       

.loop:
    mov al,[bx]
    cmp al,0
    je return
    push bx
    mov ah,0Eh

    int 10h
    pop bx
    inc bx
    jmp .loop

return:
    ret 

;******************************************************************
get_yes_no:
    pusha 
.loop:
    mov ah, 00h
    int 16h
    cmp ah, 15h
    je .yes
    cmp ah, 31h
    je .no
    jmp .loop
    ret
.no:
    mov bx, No
    call print_string
    mov ah, 00h
    int 13h 
    jmp $
.yes:   
    mov bx, Yes
    call print_string
    jmp .done
.done:
    popa
    ret 
;******************************************************************
disk_load:
    push dx
    mov ah, 02h    
    mov al, dh    
    mov ch, 0x00   
    mov dh, 0x00  
    mov cl, 0x02   
    int 0x13       
    pop dx
    jc disk_error 
    cmp dh, al 
    jne disk_error_double
    mov bx,MSG_LOAD_SUCC
    call print_string
    ret 

disk_error:
    mov bx,MSG_LOAD_FAIL 
    call print_string
    jmp $
disk_error_double:
    mov bx,MSG_LOAD_FAIL_C
    call print_string
    jmp $

;******************************************************************
print_string_pm :
    pusha
    mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem.
    .print_string_pm_loop :
    mov al , [ ebx ] ; Store the char at EBX in AL
    mov ah , WHITE_ON_BLACK ; Store the attributes in AH
    cmp al , 0 ; if (al == 0), at end of string , so
    je .print_string_pm_done ; jump to done
    mov [edx], ax ; Store char and attributes at current
    ; character cell.
    add ebx , 1 ; Increment EBX to the next char in string.
    add edx , 2 ; Move to next character cell in vid mem.
    jmp .print_string_pm_loop ; loop around to print the next char.
    .print_string_pm_done :
    popa
    ret 

; Global Descriptor table
; GDT
gdt_start :
gdt_null : ; the mandatory null descriptor
dd 0x0 ; 'dd ' means define double word ( i.e. 4 bytes )
dd 0x0
gdt_code : 
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10011010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
gdt_data : 
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10010010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
gdt_end : 

gdt_descriptor :
dw gdt_end - gdt_start - 1 
dd gdt_start 

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start   




MSG_START DB ">",13,10,0
MSG_LOAD_SUCC DB "> Succesfully loaded",13,10,0
MSG_LOAD_FAIL DB "> Failed to load Please try to restart the system",13,10,0
MSG_LOAD_FAIL_C DB "> Error while loading",13,10,0
MSG_YESNO DB "> Do you want to boot up in kernel mode Y/N :",0
MSG_BOOT_KERNEL DB 13,10,"> Booting in kernel mode",0
MSG_BOOT_32 DB "32 bit pm",13,10,0
Yes db "Y",0
No db "N",0
bootdev: db 0
KERNEL_OFFSET equ 0x1000 
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

times 510-($-$$) db 0
dw 0xaa55

这是我的内核代码:

int kmain()
{


    char* vm = 0xb8000;
    *vm = 'X';


}

和我的内核条目

[BITS 32]
[extern _kmain]

call _kmain 
jmp $

我使用以下几行来构建我的磁盘映像:

nasm -fbin bootload.asm -o bootload.bin
gcc -ffreestanding -c kernel.c -o kernel.o
nasm kernel_entry.asm -f elf -o k_entry.o
ld -T NUL -o kernel.tmp -Ttext 0x1000 k_entry.o kernel.o
objcopy -O binary -j .text  kernel.tmp kernel.bin
copy /b bootload.bin+kernel.bin os-image.bin 

我将忽略在没有 SS 的情况下设置 SP 的问题和其他问题。请参阅问题下的评论,了解您可以做些什么来清理代码。

您的主要问题是使用 bits 32 切换到 32 位指令编码。一旦您将编码设置为 32 位,之后的所有指令都将被编码为 32 位,直到您更改(使用 bits 16)。您可以做的最简单的事情是将标签 pm 的代码移动到超过所有 16 位代码的位置。移动所有这些行(删除原来的):

BITS 32

pm:

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

mov ebp , 0x90000 
mov esp , ebp

call beg_pm

beg_pm:

mov ebx,MSG_BOOT_32
call print_string_pm

call KERNEL_OFFSET

jmp $

到您拥有的 32 位代码的开头。这似乎是 print_string_pm 标签。所以当移动时它看起来像:

    [snip]
disk_error_double:
    mov bx,MSG_LOAD_FAIL_C
    call print_string
    jmp $

    BITS 32

    pm:

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

    mov ebp , 0x90000 
    mov esp , ebp

    call beg_pm

    beg_pm:

    mov ebx,MSG_BOOT_32
    call print_string_pm

    call KERNEL_OFFSET

    jmp $

;******************************************************************
print_string_pm :
    pusha

    [snip]

disk_error_double 的代码是 16 位代码的最后一个,print_string_pm 是 32 位代码的开头。我们只需将 pm 代码放在 disk_error_double 之后和 print_string_pm.

之前

在进入保护模式之前,您需要关闭中断,直到您设置中断描述符 Table (IDT)。在 mov cr0 , eax 之前放置一个 cli 指令。如果不这样做,将导致三重故障并在保护模式下发生第一个中断时重新启动。