【问题标题】:OS development : switching to 32bit mode breaks my code操作系统开发:切换到 32 位模式会破坏我的代码
【发布时间】:2018-09-03 06:06:13
【问题描述】:

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

(抱歉英语不好)您好,我正在尝试编写一个简单的操作系统,只是为了好玩没用 正常显示

`> `
`>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 中打印东西,但我仍然没有使用

p>
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 

【问题讨论】:

  • 你不能在保护模式下使用 BIOS 中断,语义改变了。 BIOS 为您设置了 IVT,但在保护模式下您需要和 IDT,现在代码大小为 32 位,段语义不再是 value*16
  • @MargaretBloom 如您所见,我在更改为 pm 后没有使用任何中断
  • 哇,对不起。阅读代码太多:)
  • 从 16 位代码中调用位于 BITS 32 指令之后的代码。我觉得不合适。
  • 代码审查:您不需要在设置esds 的第一个代码块周围使用pusha / popa。如果输入时ax 中的值值得保留(但AFAICT 你不使用它),你可以再次使用bx。用xor ax,ax 清零一个寄存器,而不是mov。此外,您设置了sp 而不是ss,所以您不知道您的堆栈在哪里。 IDK 如果它在这样做之后可能靠近您的代码或数据。如果你没有设置ss 并且movss 将中断延迟到NEXT 指令之后,那么禁用中断是没有意义的,所以你可以在没有cli / sti 的情况下自动设置ss:sp

标签: assembly x86 nasm osdev protected-mode


【解决方案1】:

我将忽略在没有 SS 的情况下设置 SP 的问题和其他问题。请参阅问题下方的 cmets,了解您可以采取哪些措施来清理代码。

您的主要问题是使用 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)。在mov cr0 , eax 之前放置一个cli 指令。如果在保护模式下发生第一次中断,则会导致三重故障并重新启动。

【讨论】:

    猜你喜欢
    • 2014-11-24
    • 2013-08-29
    • 2010-11-18
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 2015-09-26
    • 1970-01-01
    相关资源
    最近更新 更多