操作系统开发:切换到32位模式会破坏我的代码

时间:2018-03-24 19:03:00

标签: assembly x86 nasm 32-bit osdev

编辑:当我将BITS 32之后的所有内容移动到disk_double_error时,我的问题解决了,但是现在它仍然被打破,是的,它会显示消息但是当我点击Y时它只是重新启动/重新启动系统可能是什么原因?

(sry for bad english)您好我正在尝试编写一个简单的操作系统只是为了好玩我制作了我的bootloader并且我显示了一些消息并读取了磁盘但是当涉及到切换到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函数在pm下打印东西,但我仍然没有使用

nasm -fbin bootload.asm -o bootload.bin

编译引导程序

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

这是代码:

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 

1 个答案:

答案 0 :(得分:0)

我将忽略在没有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代码。

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