代码之家  ›  专栏  ›  技术社区  ›  Programmer

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

  •  1
  • Programmer  · 技术社区  · 6 年前

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

    (sry代表蹩脚英语)您好,我正试图编写一个简单的操作系统,只是为了好玩,我制作了引导加载程序,显示了一些消息并读取了磁盘,但当切换到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\u string\u 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 回复  |  直到 5 年前
        1
  •  1
  •   Michael Petch    6 年前

    我将忽略设置无SS SP的问题和其他问题。请参阅问题下方的注释,以了解可以执行哪些操作来清理代码。

    您的主要问题是切换到32位指令编码 bits 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\u string\u pm 是32位代码的开头。我们只需将 项目经理 之后的代码 disk\u error\u double磁盘错误 和之前 print\u string\u pm


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