221 lines
10 KiB
NASM
221 lines
10 KiB
NASM
|
||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
; loader.asm
|
||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
; Forrest Yu, 2005
|
||
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
[SECTION .text.s16]
|
||
ALIGN 16
|
||
[BITS 16]
|
||
|
||
%include "./boot/inc/load.inc"
|
||
|
||
global _start
|
||
_start:
|
||
jmp Main ; Start
|
||
|
||
%include "./boot/inc/fat12.inc"
|
||
%include "./boot/inc/pm.inc"
|
||
|
||
ALIGN 4
|
||
; GDT ------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
; 段基址 段界限 属性
|
||
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
|
||
LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 | DA_LIMIT_4K ; 0 ~ 4G
|
||
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_32 | DA_LIMIT_4K ; 0 ~ 4G
|
||
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW | DA_DPL3 ; 显存首地址
|
||
|
||
; 准备lgdt必要的数据结构 --------------------------------------------------------------------------------------------------------------------------------------------
|
||
GdtLen equ $ - LABEL_GDT
|
||
GdtPtr dw GdtLen - 1 ; gdt界限
|
||
dd LoaderSegPhyAddr + LABEL_GDT ; gdt基地址
|
||
|
||
; GDT 选择子 ----------------------------------------------------------------------------------
|
||
SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT
|
||
SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT
|
||
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3
|
||
|
||
Main: ; <--- 从这里开始 *************
|
||
mov ax, cs
|
||
mov ds, ax
|
||
mov es, ax
|
||
mov ss, ax
|
||
mov sp, BaseOfStack
|
||
|
||
mov cx, 02000h
|
||
mov ah, 01h
|
||
int 10h ; 隐藏光标
|
||
|
||
call LoadKernelFile
|
||
|
||
; 下面准备跳入保护模式 -------------------------------------------
|
||
|
||
; 加载 GDTR
|
||
lgdt [GdtPtr]
|
||
|
||
; 关中断
|
||
cli
|
||
|
||
; 打开地址线A20
|
||
in al, 92h
|
||
or al, 00000010b
|
||
out 92h, al
|
||
|
||
; 准备切换到保护模式
|
||
mov eax, cr0
|
||
or eax, 1
|
||
mov cr0, eax
|
||
|
||
; 真正进入保护模式
|
||
jmp dword SelectorFlatC:LABEL_PM_START
|
||
|
||
; 从此以后的代码在保护模式下执行 ----------------------------------------------------
|
||
; 32 位代码段. 由实模式跳入 ---------------------------------------------------------
|
||
[SECTION .text]
|
||
ALIGN 32
|
||
[BITS 32]
|
||
|
||
extern load_kernel
|
||
|
||
LABEL_PM_START:
|
||
mov ax, SelectorVideo
|
||
mov gs, ax
|
||
mov ax, SelectorFlatRW
|
||
mov ds, ax
|
||
mov es, ax
|
||
mov fs, ax
|
||
mov ss, ax
|
||
mov esp, TopOfStack
|
||
|
||
call SetupPaging; 启动分页机制,不过在这个实验大家可以不用管,就当是一个能够扩展访存范围的牛逼玩意
|
||
jmp SelectorFlatC:load_kernel
|
||
|
||
;***************************************************************
|
||
; 内存看上去是这样的:
|
||
; ┃ ┃
|
||
; ┃ . ┃
|
||
; ┃ . ┃
|
||
; ┃ . ┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||
; ┃■■■■■■Page Tables■■■■■■┃
|
||
; ┃■■■■■(大小由LOADER决定)■■■■┃
|
||
; 00101000h ┃■■■■■■■■■■■■■■■■■■┃ PageTblBase
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||
; 00100000h ┃■■■■Page Directory Table■■■■┃ PageDirBase <- 1M
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃□□□□□□□□□□□□□□□□□□┃
|
||
; F0000h ┃□□□□□□□System ROM□□□□□□┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃□□□□□□□□□□□□□□□□□□┃
|
||
; E0000h ┃□□□□Expansion of system ROM □□┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃□□□□□□□□□□□□□□□□□□┃
|
||
; C0000h ┃□□□Reserved for ROM expansion□□┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃□□□□□□□□□□□□□□□□□□┃ B8000h ← gs
|
||
; A0000h ┃□□□Display adapter reserved□□□┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃□□□□□□□□□□□□□□□□□□┃
|
||
; 9FC00h ┃□□extended BIOS data area (EBDA)□┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||
; 90000h ┃■■■■■■■LOADER.BIN■■■■■■┃ somewhere in LOADER ← esp
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||
; 80000h ┃■■■■■■■KERNEL.BIN■■■■■■┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||
; 30000h ┃■■■■■■■■KERNEL■■■■■■■┃ 30400h ← KERNEL 入口 (KernelEntryPointPhyAddr)
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃ ┃
|
||
; 7E00h ┃ F R E E ┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃■■■■■■■■■■■■■■■■■■┃
|
||
; 7C00h ┃■■■■■■BOOT SECTOR■■■■■■┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃ ┃
|
||
; 500h ┃ F R E E ┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃□□□□□□□□□□□□□□□□□□┃
|
||
; 400h ┃□□□□ROM BIOS parameter area □□┃
|
||
; ┣━━━━━━━━━━━━━━━━━━┫
|
||
; ┃◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇┃
|
||
; 0h ┃◇◇◇◇◇◇Int Vectors◇◇◇◇◇◇┃
|
||
; ┗━━━━━━━━━━━━━━━━━━┛ ← cs, ds, es, fs, ss
|
||
;
|
||
;
|
||
; ┏━━━┓ ┏━━━┓
|
||
; ┃■■■┃ 我们使用 ┃□□□┃ 不能使用的内存
|
||
; ┗━━━┛ ┗━━━┛
|
||
; ┏━━━┓ ┏━━━┓
|
||
; ┃ ┃ 未使用空间 ┃◇◇◇┃ 可以覆盖的内存
|
||
; ┗━━━┛ ┗━━━┛
|
||
;
|
||
; 注:KERNEL 的位置实际上是很灵活的,可以通过同时改变 LOAD.INC 中的 KernelEntryPointPhyAddr 和 MAKEFILE 中参数 -Ttext 的值来改变。
|
||
; 比如,如果把 KernelEntryPointPhyAddr 和 -Ttext 的值都改为 0x400400,则 KERNEL 就会被加载到内存 0x400000(4M) 处,入口在 0x400400。
|
||
;
|
||
|
||
; 启动分页机制 --------------------------------------------------------------
|
||
SetupPaging:
|
||
; 根据内存大小计算应初始化多少PDE以及多少页表
|
||
xor edx, edx
|
||
mov eax, 8000000h ; qemu虚拟机默认内存128MB,这里简化实现省去了实模式代码里中断向BIOS询问可用内存大小的步骤
|
||
mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小
|
||
div ebx
|
||
mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
|
||
test edx, edx
|
||
jz .no_remainder
|
||
inc ecx ; 如果余数不为 0 就需增加一个页表
|
||
.no_remainder:
|
||
push ecx ; 暂存页表个数
|
||
|
||
; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.
|
||
|
||
; 首先初始化页目录
|
||
mov ax, SelectorFlatRW
|
||
mov es, ax
|
||
mov edi, PageDirBase ; 此段首地址为 PageDirBase
|
||
xor eax, eax
|
||
mov eax, PageTblBase | PG_P | PG_USU | PG_RWW
|
||
.1:
|
||
stosd
|
||
add eax, 4096 ; 为了简化, 所有页表在内存中是连续的.
|
||
loop .1
|
||
|
||
; 再初始化所有页表
|
||
pop eax ; 页表个数
|
||
mov ebx, 1024 ; 每个页表 1024 个 PTE
|
||
mul ebx
|
||
mov ecx, eax ; PTE个数 = 页表个数 * 1024
|
||
mov edi, PageTblBase ; 此段首地址为 PageTblBase
|
||
xor eax, eax
|
||
mov eax, PG_P | PG_USU | PG_RWW
|
||
.2:
|
||
stosd
|
||
add eax, 4096 ; 每一页指向 4K 的空间
|
||
loop .2
|
||
|
||
mov eax, PageDirBase
|
||
mov cr3, eax
|
||
mov eax, cr0
|
||
or eax, 80000000h
|
||
mov cr0, eax
|
||
jmp short .3
|
||
.3:
|
||
nop
|
||
|
||
ret
|
||
; 分页机制启动完毕 ----------------------------------------------------------
|
||
|
||
|
||
; SECTION .data 之开始 ---------------------------------------------------------------------------------------------
|
||
[SECTION .data]
|
||
ALIGN 32
|
||
[BITS 32]
|
||
; 堆栈就在数据段的末尾
|
||
StackSpace: times 1000h db 0
|
||
TopOfStack equ $ ; 栈顶
|