简体   繁体   English

从真实模式切换到保护模式后跳远

[英]Far jump after switching from real to protected mode

According to this tutorial it is sufficient to create a simple operating system with switching to protected mode as simple as the following code without the need for other well known actions such as enabling A20... 根据本教程 ,创建一个简单的操作系统就足够了,切换到保护模式就像下面的代码一样简单,无需其他众所周知的操作,如启用A20 ...

Anyway, I am newbie to this domain, I wrote the following code as they mentioned exactly with the modification inspired from this SO . 无论如何,我是这个领域的新手,我写了下面的代码,因为他们提到了这个SO的修改。

Code Structure: This simple operating system should load briefly as follows: 代码结构:这个简单的操作系统应简要加载如下:

  1. Load/read 15 sectors 加载/读取15个扇区
  2. Enable GDT 启用GDT
  3. Switch to protected mode (And print "Successfully landed in 32-bit Protected Mode"). 切换到保护模式(并打印“成功登陆32位保护模式”)。
  4. Load kernel and print "X" 加载内核并打印“X”

However the emulator is still rebooting. 但是,模拟器仍在重新启动。 Please find enclosed the entire code. 请查看随附的整个代码。

bootloader.asm bootloader.asm

[bits 16]
[org 0x7C00]

KERNEL_OFFSET equ 0x1000

xor ax, ax
mov ds, ax
mov es, ax
mov [BOOT_DRIVE], dl
mov ax, 0x07E0                  ; End of stack
cli
mov ss, ax
mov sp, 0x1200                  ; Size of Stack. By this, we assume that stack starts at 9000h
                            ; of size 1200h and ends at 7E00h to avoid being overwritten.
sti

call    load_kernel
call    switch_to_pm

jmp $

%include "src/functions/disk_load.asm"

load_kernel:
    mov bx, KERNEL_OFFSET   
    mov dh, 15
    mov dl, [BOOT_DRIVE]
    call    disk_load

    ret

; Global variables
BOOT_DRIVE  db 0
SECTORS     db 0
MSG_PROT_MODE   db "Successfully landed in 32-bit Protected Mode" , 0

%include "src/functions/gdt.asm"
%include "src/functions/switch_to_pm.asm"

[ bits 32]
; This is where we arrive after switching to and initialising protected mode.
BEGIN_PM:
    mov ebx , MSG_PROT_MODE
    call    print_string_pm     ; Use our 32 - bit print routine.


    ;call   KERNEL_OFFSET       ; Now jump to the address of our loaded
                    ; kernel code , assume the brace position ,
                    ; and cross your fingers. Here we go !

    jmp $           ; Hang.

%include "src/functions/writing_video_mode.asm"

; Bootsector padding
times 510-($-$$) db 0
dw 0xAA55

; 15 sector padding
times 15*256 dw 0xDADA

disk_load.asm disk_load.asm

disk_load:
    mov [SECTORS], dh
    mov ch, 0x00            ;C=0
    mov dh, 0x00            ;H=0
    mov cl, 0x02            ;S=2

next_group:
    mov di, 5                ;Max 5 tries

again: 
    mov ah, 0x02            ;Read sectors
    mov al, [SECTORS]
    int 0x13
    jc   maybe_retry
    sub [SECTORS], al ;Remaining sectors
    jz  ready
    mov cl, 0x01            ;Always sector 1
    xor dh, 1                ;Next head on diskette!
    jnz next_group
    inc ch                      ;Next cylinder
    jmp next_group

maybe_retry:
    mov ah, 0x00            ;Reset diskdrive
    int 0x13
    dec di
    jnz again
    jmp disk_error

ready:
    ret

disk_error:
    mov ah, 0x0e
    mov al, 'Y'
    int 0x10
    jmp $

DISK_ERROR_MSG db "Disk read error!", 0

gdt.asm gdt.asm

gdt_start:

    gdt_null:
        dd 0x0 ; ’ dd ’ means define double word ( i.e. 4 bytes )
        dd 0x0

    gdt_code:
        dw 0xffff
        dw 0x0
        db 0x0
        db 10011010b ; 1 st flags , type flags
        db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
        db 0x0

    gdt_data:
        dw 0xffff
        dw 0x0
        db 0x0
        db 10010010b ; 1 st flags , type flags
        db 11001111b ; 2 nd flags , Limit ( bits 16 -19)
        db 0x0

    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

switch_to_pm.asm switch_to_pm.asm

[ bits 16 ]

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

[ bits 32 ]

init_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 BEGIN_PM

And in order to make sure that we landed in the protected mode: 并且为了确保我们落入保护模式:

writing_video_mode.asm writing_video_mode.asm

[ bits 32]

VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

print_string_pm:
    push eax
    push ebx
    push edx
    mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem.

    print_string_pm_loop:
        mov al, [ebx]
        mov ah, WHITE_ON_BLACK
        cmp al, 0
        je print_string_pm_done
        mov [edx], ax
        add ebx, 1
        add edx, 2
        jmp print_string_pm_loop

    print_string_pm_done:
        pop edx 
        pop ebx 
        pop eax 
        ret

kernel.c kernel.c

void main () {
    char * video_memory = (char *) 0xb8000;
    *video_memory = 'X';
}

By the way, I am using this Makefile : 顺便说一下,我正在使用这个Makefile

all: bootloader.bin kernel.bin

bootloader.bin: src/bootloader.asm
    nasm src/bootloader.asm -f bin -o output/bootloader.bin

kernel.o: src/kernel/kernel.c
    gcc -ffreestanding -c src/kernel/kernel.c -o output/kernel.o -m32

kernel.bin: kernel.o
    ld -o output/kernel.bin -Ttext 0x1000 --oformat binary output/kernel.o -melf_i386

clean:
    rm -f output/*.* output/*

and in order to move it into the flash memory, I use these commands: 并且为了将其移动到闪存中,我使用以下命令:

cat output/bootloader.bin output/kernel.bin > os-image
sudo dd if=os-image of=/dev/sdb bs=512 conv=notrunc && sync

In order to run it, I am using qemu with this command: 为了运行它,我使用qemu与此命令:

qemu-system-i386 -hda /dev/sdb

Noting that /dev/sdb is my flash memory drive. 注意到/ dev / sdb是我的闪存驱动器。

Problem: Indeed, the code is landing into the protected mode (Ie Printing "Successfully landed in 32-bit Protected Mode") just when disabling/commenting the call KERNEL_OFFSET in the bootloader.asm . 问题:实际上,当禁用/注释bootloader.asmcall KERNEL_OFFSET时,代码将进入保护模式(即打印“成功登陆32位保护模式”)。 However when enabling this line it starts booting and rebooting. 但是,启用此行时,它将开始启动并重新启动。

I hope I have provided every needed information. 我希望我已经提供了所有必要的信息。 It seems for me that the far jump should not be done this way. 对我来说,远程跳跃不应该这样做。 Any comment is appreciated. 任何评论表示赞赏。

Just remove 只需删除

times 15*256 dw 0xDADA 时间15 * 256 dw 0xDADA

(btw, why DADA?) (顺便问一下,DADA为什么?)
then compile your kernel, after that 然后编译你的内核

cat output/bootloader.bin output/kernel.bin > os-image cat output / bootloader.bin output / kernel.bin> os-image

and somehow make your os image 8192 byte long (16 sectors, bootloader + 15). 并以某种方式使你的os图像长8192字节(16扇区,bootloader + 15)。 I'm not Linux/Unix fan (even can't use them), but I think dd command (something like dd if=dev\\zero of=temp_file count=(8192 - file actual size ) , and then cat os-image temp-file > os-image ) should do the job. 我不是Linux / Unix风扇(甚至不能使用它们),但我认为dd命令(类似于dd if = dev \\ zero of = temp_file count =(8192 - 文件实际大小 ,然后是cat os-image临时文件> os-image )应该完成这项工作。 I'm also not sure is this compilation command correct (only not sure). 我也不确定这个编译命令是否正确(只是不确定)。 I would remove "-melf_i386" from linker command, but idk, I have only used MinGW on Windows (it's only similar to GCC). 我会从链接器命令中删除“-melf_i386”,但是idk,我只在Windows上使用过MinGW(它只与GCC类似)。

Sorry for my bad English, I hope I helped. 对不起我的英语不好,我希望我帮忙。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM