首页 > 解决方案 > 切换到保护模式后如何正确跳转到内核

问题描述

我目前正在开发一个简单的操作系统,我决定从头开始编写。在引导加载程序的第二阶段,当我切换到保护模式时,它在切换后立即卡住,并且模拟器(QEMU)重新启动。

这是引导加载程序阶段 1:

org 0x7C00

;SEGMENTS
;bootloadter stage 1: 0x0000:0x7C00
;bootloader stage 2: 0x07E0:0x0100
;public data segment: 0x08E0:0x0000
;gdt: 0x1000:0x0000
;idt: 0x1000:0x0200
;kernel: 0x2000:0x0000

init:
  ;sets up the temporary data segment
  xor ax,ax
  mov ds, ax

  ;set up the stack
  xor ax, ax
  mov ss, ax
  mov sp, 0x7C00

  <<save the drive number>>

  ;reset the drive
  call drive_reset

  ;loads IDT but does not load the idtr until we're in protected mode
  call load_idt

  ;loads GDT
  call load_gdt
  lgdt [0x9E]

  call load_stage2
  call _wait

  jmp 0x07E0:0x0100
  jmp $

load_data_segment:
  <<loads the shared data segment from disk>>
  ret

load_stage2:
  <<loads second stage from disk>>
  ret

print:
   <<print function>>

boot_failure:
  <<boot failure function (alerts the user and halts the system)>>

_wait:
  <<wait function (wait for the user to press a key)>>

reboot:
  <<reboot function>>

;loads the initial gdt table from sector 9 to 0x1000:0x0000 (512 byte)
load_gdt:
  mov si, 0x00
  call print
  mov ah, 0x2 ;subroutine
  mov al, 0x1 ;numbers of sectors to be read
  mov dl, [0xAA] ;drive number

  mov ch, 0 ;cylinder number
  mov dh, 0 ;head number
  mov cl, 9 ;start sector (the first sector has index 1)

  mov bx, 0x1000 ;segment
  mov es, bx
  mov bx, 0x0000 ;segment offset
  int 0x13 ;drive low level routines
  jc process_error
  call drive_reset
  call process_done
  ret

;loads the initial idt table from sector 10 to 0x1000:0x0200 (512 bytes)
load_idt:
  mov si, 0x10
  call print
  mov ah, 0x2 ;subroutine
  mov al, 0x4 ;numbers of sectors to be read
  mov dl, [0xAA] ;drive number

  mov ch, 0 ;cylinder number
  mov dh, 0 ;head number
  mov cl, 0xA ;start sector (the first sector has index 1)

  mov bx, 0x1000 ;segment
  mov es, bx
  mov bx, 0x200 ;segment offset (512 bytes), right after gdt
  int 0x13 ;drive low level routines
  jc process_error
  call drive_reset
  call process_done
  ret

process_done:
  <<print "[DONE]">>

process_error:
  <<print "[ERROR]" and halts the system>>

drive_reset:
  <<drive reset function>>

drive_number: db 0

times 510-($-$$) db 0x0
dw 0xAA55

引导加载程序阶段 2:

org 0x0100

;segment 0x07E0
;offset 0x0100

init:
  cli
  ;sets up the data segment
  mov ax, 0x08E0
  mov ds, ax

  ;sets up the stack
  mov ax, 0x07E0
  mov ss, ax
  mov sp, 0x0100
  sti

  ;loads the kernel
  mov si, 0x63 ;loading kernel...
  call print
  call load_kernel
  call process_done

  ;enable A20
  checkA20:
  mov si, 0x20 ;checking A20...
  call print
  call A20_test
  cmp ax, 1
  je A20_enabled_func
  jmp A20_disabled_func

  continue: ;return point from A20 procedures
  jmp enable_protected

_wait:
  mov si, 0xB7
  call print
  mov ah, 0
  int 0x16
  ret

A20_disabled_func:
  <<calls enable_A20 procedure and jumps to 'continue'>>

A20_enabled_func:
  <<print "ENABLED">>

print:
  <<print function>>

process_done:
  <<prints "[DONE]">>

process_error:
  <<prints "[ERROR]" and halts the system>>

A20_test:
  pushf
  push ds
  push es
  push di
  push si

  cli

  xor ax, ax
  mov es, ax
  mov di, 0x0500

  mov ax, 0xffff
  mov ds, ax
  mov si, 0x0510

  mov al, byte es:[di]
  push ax

  mov al, byte ds:[si]
  push ax

  mov byte es:[di], 0x00
  mov byte ds:[si], 0xFF

  cmp byte es:[di], 0xFF

  pop ax
  mov byte ds:[si], al

  pop ax
  mov byte es:[di], al

  mov ax, 0
  je A20_test_exit

  mov ax, 1

A20_test_exit:
  pop si
  pop di
  pop es
  pop ds
  popf
  ret

enable_A20:
  cli

  call a20wait
  mov al, 0xAD
  out 0x64, al

  call a20wait
  mov al, 0xD0
  out 0x64, al

  call a20wait2
  in al, 0x60
  push eax

  call a20wait
  mov al, 0xD1
  out 0x64, al

  call a20wait
  pop eax
  or al, 2
  out 0x60, al

  call a20wait
  mov al, 0xAE
  out 0x64, al

  call a20wait
  sti
  ret

a20wait:
  in al, 0x64
  test al, 2
  jnz a20wait
  ret

a20wait2:
  in al, 0x64
  test al, 1
  jz a20wait2
  ret

load_kernel:
  mov ah, 0x2 ;subroutine
  mov al, 0x1 ;numbers of sectors to be read
  mov dl, [0xAA] ;drive number

  mov ch, 0 ;cylinder number
  mov dh, 0 ;head number
  mov cl, 21 ;start sector (the first sector has index 1)

  mov bx, 0x2000 ;segment
  mov es, bx
  mov bx, 0x0 ;segment offset
  int 0x13 ;drive low level routines
  jc process_error
  ret

enable_protected:
  mov si, 0x43 ;switching to protected mode...
  call print
  call _wait

  mov eax, cr0
  or eax, 1
  mov cr0, eax ;--------HERE IS THE PROBLEM--------

  bits 32
  mov ax, 0x8
  mov cs, ax
  jmp 0x2000

times 2560-($-$$) db 0xAE

我在 x86 架构上使用 nasm 编译器和 qemu 作为模拟器。我感谢任何读过这篇文章而没有改变主意的人:D 我希望我可以发布所有内容,但该网站说它看起来像垃圾邮件......

标签: assemblyx86operating-systemqemuprotected-mode

解决方案


推荐阅读