2019年7月6日 星期六

自製64位元作業系統06──進入保護模式

我們現在都還在bootloader裡面,之後,我們預計把之後會放在檔案系統中的核心讀取,並且放在記憶體1MB的地方。但是,目前我們只能讀取1MB以下的記憶體。今天,我們要開啟A20,並且進入32位元保護模式,讓我們之後更容易進行。
我們可以透過https://wiki.osdev.org/來得到許許多多的資料。
要進入保護模式,首先要先關閉中斷,直到我們自己製作一個中斷描述表,才能夠再開回來。關閉中斷,利用
cli
之後,我們可以利用許多方法開啟A20。其中,我們利用最簡便的方法開啟。
inb $0x92, %al
orb $2, %al
out %al, $0x92
再來就是GDT(全局描述表)了。它的功能就是描述每一段記憶體的開頭、大小、權限等等。我們的GDT有三個表項,分別是空、程式段、資料段。GDT的第一個一定要是空的。有關GDT內容的詳細敘述,可以參考Intel的手冊https://software.intel.com/sites/default/files/managed/a4/60/325384-sdm-vol-3abcd.pdf
在32位元保護模式中,GDT的大小是8Bytes(可以參考手冊中Figure 3-8)。我們的程式段和資料段都是由0x0起始,大小4GB。
GDT_NUL:
  .long 0
  .long 0
GDT_CODE32:
  .long 0x0000FFFF
  .long 0x00CF9A00
GDT_DATA32:
  .long 0x0000FFFF
  .long 0x00CF9200
GDTR:
  .word 24
  .long GDT_NUL+0x7C00
我們最後的GDTR這個區段,裡面是我們要存進GDTR暫存器的資料,首先是我們GDT的大小,再來是GDT的位置。我們打完這個區段以後,就利用
lgdt GDTR
將GDTR暫存器準備好。再來我們就要正式開啟保護模式了。設定CR0暫存器的最低位,就可以開啟保護模式。
movl %cr0, %eax
orl $1, %eax
movl %eax, %cr0
之後,利用一個ljmp指令,就可以改變cs暫存器,完全地進入保護模式。
ljmp $0x08, $(0x7c00+OS_PMODE)
OS_PMODE:
現在整個組合語言程式如下。
.code16
.section .text
# Init all the registers
xorw %ax, %ax
xorw %bx, %bx
xorw %cx, %cx
xorw %dx, %dx

movw $0x7c0, %ax
movw %ax, %es
movw %ax, %ds
movw %ax, %ss

# Reset Floppy (int 0x13, ah = 0x0, dl = 0 (first floppy))
movb $0, %ah
int $0x13

# Read Number 2 (CHS)
# (int 0x13, ah = 0x2, al = 1, ch = 0, cl = 2, dh = 0, dl = 0, ES:BX = 0x7E00)
movw $0x200, %bx
movb $0x2, %ah
movb $0x1, %al
movb $0x0, %ch
movb $0x2, %cl
movb $0x0, %dh
movb $0x0, %dl
int $0x13

jc error

jmp second_sector

error:
# Print Error
movw $ERROR_MSG, %bp
call print
jmp .

ERROR_MSG:
.asciz "READ FLOPPY ERROR"

# ====================================================================
# print function
# ====================================================================
# es:bp as Message position, zero-term string
print:
  # Get cursor position (Return dh = row, dl = column ...)
  movb $0x03, %ah
  movb $0, %bh
  int $0x10

  # Count String
  xorw %cx, %cx
  movw %bp, %si
  cnt:
  movb (%si), %ah
  cmpb $0, %ah
  je cnt_exit
  incw %si
  incw %cx
  jmp cnt
  cnt_exit:

  # Print
  # (ah = 0x13, al = 0x0, bh = 0, bl = 7, cx = strlen, dh:dl=row:column, es:bp=7c0:Message)
  movw $0x1300, %ax
  movw $0x7, %bx
  int $0x10

  # Move cursor to next line
  incb %dh
  xorb %dl, %dl
  movb $0, %bh
  movb $0x02, %ah
  int $0x10
  ret
#=====================================================================

#=====================================================================
# int 0xE820
# (eax = 0xe820) (ebx = 0) (es:di = smap) (ecx = buffer size = 0x200) (edx = smap)
#=====================================================================
getRam:
  movl $0xe820, %eax
  xorl %ebx, %ebx
  movw $0x400, %di
  movl $32, %ecx
  movl $0x534D4150, %edx
getRam_loop:
  int $0x15
  movl %eax, %edx
  movl $0xe820, %eax
  movl $32, %ecx
  addw $32, %di
  cmpl $0, %ebx
  jne getRam_loop
  ret
.org 0x1FE, 0x62
.byte 0x55
.byte 0xAA

second_sector:
# Print
movw $HELLO_MESSAGE, %bp
call print
call getRam

# Clear Interrupt Flag
cli

# A20
inb $0x92, %al
orb $2, %al
outb %al, $0x92

# LGDT
lgdt GDTR

# Enter Protected Mode
movl %cr0, %eax
orl $1, %eax
movl %eax, %cr0

ljmp $0x08, $(0x7c00+OS_PMODE)
OS_PMODE:

jmp .

HELLO_MESSAGE:
.asciz "Hello world!"
GDT_NUL:
  .long 0
  .long 0
GDT_CODE32:
  .long 0x0000FFFF
  .long 0x00CF9A00
GDT_DATA32:
  .long 0x0000FFFF
  .long 0x00CF9200
GDTR:
  .word 23
  .long GDT_NUL+0x7c00

.org 0x400, 0x62
# SuperBlock
.long 184 # s_inode_count
.long 1440 # s_blocks_count
.long 72 # s_r_blocks_count
.long 1411 # s_free_blocks_count
.long 174 # s_free_inodes_count
.long 1 # s_first_data_block
.long 0 # s_log_block_size
.long 0 # s_log_frag_size
.long 8192 # s_blocks_per_group
.long 8192 # s_frags_per_group
.long 184 # s_inodes_per_group
.long 0 # s_mtime
.long 0x5D0F7311 # s_wtime
.word 0 # s_mnt_count
.word 0x1e # s_max_mnt_count
.word 0xEF53 # s_magic
.word 1 # s_state
.word 1 # s_errors
.word 0 # s_minor_rev_level
.long 0x5D0F7311 # s_lastcheck
.long 0xed4e00 # s_checkinterval
.long 0 # s_creator_os
.long 1 # s_rev_level
.word 0 # s_def_resuid
.word 0 # s_def_resgid
.long 11
.word 128
.word 0
.long 0
.long 0
.long 0
.quad 0x52145214
.quad 0x52145214
.quad 0
.quad 0
.quad 0
.quad 0
.quad 0
.quad 0
.long 0

.org 0x800, 0x0
# Block Group Descriptor Table
.long 3
.long 4
.long 5
.word 1411
.word 174
.word 1
.word 0
.long
.long
.long

.org 0xC00, 0x0
# BLOCK BITMAP
.long 0x0FFFFFFF

.org 0x1000, 0x0
# INODE BITMAP
.word 0b1111111111
.org 0x1480, 0x0
# INODE TABLE
# Root directory
.word 0x41ED #i_mode
.word 0
.long 1024
.long 0
.long 0x5D0F7311
.long 0
.long 0
.word 0
.word 2
.long 2
.long 0
.long 0
# 15 blocks
.long 28
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0

.long 0
.long 0
.long 0
.long 0

.long 0
.long 0
.long 0
.org 0x7000, 0x0
.long 2
.word 12
.byte 1
.byte 2
.ascii "."

.long 2
.word 12
.byte 2
.byte 2
.ascii ".."




👉【幫我們一個忙!】👈

👋如果您喜歡這篇文章,請在下方按5個Like!
 ❤您的支持是我們最大的動力!

您只要登入帳號(Facebook、Google),在下方按5個Like,我們就會收到來自LikeCoin基金會的贊助。
您只需要支持我們,完全不會花到錢!