|
@@ -17,20 +17,37 @@ Offset_Tmp_Of_Kernel_File equ 0x7e00 ; 内核程序的临时转存空间
|
|
|
|
|
|
Memory_Struct_Buffer_Addr equ 0x7e00 ; 内核被转移到最终的内存空间后,原来的临时空间就作为内存结构数据的存储空间
|
|
|
|
|
|
-
|
|
|
+; ==== 临时的全局描述符表 =====
|
|
|
[SECTION gdt]
|
|
|
|
|
|
LABEL_GDT: dd 0,0
|
|
|
-LABEL_DESC_CODE32: dd 0x0000FFFF,0x00CF9A00
|
|
|
+LABEL_DESC_CODE32: dd 0x0000FFFF,0x00CF9A00 ; 代码段和数据段的段基地址都设置在0x00000000处, 把段限长设置为0xffffffff,可以索引32位地址空间
|
|
|
LABEL_DESC_DATA32: dd 0x0000FFFF,0x00CF9200
|
|
|
|
|
|
GdtLen equ $ - LABEL_GDT
|
|
|
+; GDTR寄存器是一个6B的结构,低2B保存GDT的长度, 高4B保存GDT的基地址
|
|
|
GdtPtr dw GdtLen - 1
|
|
|
dd LABEL_GDT
|
|
|
|
|
|
+; 这是两个段选择子,是段描述符在GDT表中的索引号
|
|
|
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
|
|
|
SelectorData32 equ LABEL_DESC_DATA32 - LABEL_GDT
|
|
|
|
|
|
+; === IA-32e模式的临时gdt表
|
|
|
+[SECTION gdt64]
|
|
|
+LABEL_GDT64: dq 0x0000000000000000
|
|
|
+LABEL_DESC_CODE64: dq 0x0020980000000000
|
|
|
+LABEL_DESC_DATA64: dq 0x0000920000000000
|
|
|
+
|
|
|
+GdtLen64 equ $ - LABEL_GDT64
|
|
|
+GdtPtr64 dw GdtLen64-1,
|
|
|
+ dd LABEL_GDT64
|
|
|
+
|
|
|
+SelectorCode64 equ LABEL_DESC_CODE64 - LABEL_GDT64
|
|
|
+SelectorData64 equ LABEL_DESC_DATA64 - LABEL_GDT64
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
[SECTION .s16] ;定义一个名为.s16的段
|
|
|
[BITS 16] ; 通知nasm,将要运行在16位宽的处理器上
|
|
@@ -349,7 +366,7 @@ Label_Get_Mem_OK:
|
|
|
mov ax, 0x1301
|
|
|
mov bx, 0x000f
|
|
|
mov dx, 0x0400 ; 在第5行显示
|
|
|
- mov cx, 39
|
|
|
+ mov cx, 38
|
|
|
push ax
|
|
|
mov ax, ds
|
|
|
mov es, ax
|
|
@@ -364,16 +381,290 @@ Label_Get_SVGA_Info:
|
|
|
mov ax, 0x1301
|
|
|
mov bx, 0x000f
|
|
|
mov dx, 0x0500 ; 在第6行显示
|
|
|
- mov cx, 30
|
|
|
+ mov cx, 34
|
|
|
push ax
|
|
|
mov ax, ds
|
|
|
mov es, ax
|
|
|
pop ax
|
|
|
- mov bp, Message_Start_Get_SVGA_Info
|
|
|
+ mov bp, Message_Start_Get_SVGA_VBE_Info
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+ ; 使用INT0x10的主功能号0x4F00获取SVGA VBE信息
|
|
|
+ ; For more information, please visit: https://longjin666.top/?p=1321
|
|
|
+ mov ax, 0x00
|
|
|
+ mov es, ax
|
|
|
+ mov di, 0x8000
|
|
|
+ mov ax, 0x4F00
|
|
|
int 0x10
|
|
|
|
|
|
+ cmp ax, 0x004F ; 获取成功
|
|
|
+ jz Label_Get_SVGA_VBE_Success
|
|
|
+
|
|
|
+Label_Get_SVGA_VBE_Failed:
|
|
|
+ ; 获取SVGA VBE信息失败
|
|
|
+ mov ax, 0x1301
|
|
|
+ mov bx, 0x008c
|
|
|
+ mov dx, 0x0600 ; 在第7行显示
|
|
|
+ mov cx, 33
|
|
|
+ push ax
|
|
|
+ mov ax, ds
|
|
|
+ mov es, ax
|
|
|
+ pop ax
|
|
|
+ mov bp, Message_Get_SVGA_VBE_Failed
|
|
|
+ int 0x10
|
|
|
jmp $
|
|
|
|
|
|
+Label_Get_SVGA_VBE_Success:
|
|
|
+ mov ax, 0x1301
|
|
|
+ mov bx, 0x000f
|
|
|
+ mov dx, 0x0600 ; 在第7行显示
|
|
|
+ mov cx, 38
|
|
|
+ push ax
|
|
|
+ mov ax, ds
|
|
|
+ mov es, ax
|
|
|
+ pop ax
|
|
|
+ mov bp, Message_Get_SVGA_VBE_Success
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+Label_Get_SVGA_Mode_Info:
|
|
|
+ ; ====== 获取SVGA mode信息 ======
|
|
|
+ mov ax, 0x1301
|
|
|
+ mov bx, 0x000f
|
|
|
+ mov dx, 0x0700 ; 在第8行显示
|
|
|
+ mov cx, 35
|
|
|
+ push ax
|
|
|
+ mov ax, ds
|
|
|
+ mov es, ax
|
|
|
+ pop ax
|
|
|
+ mov bp, Message_Start_Get_SVGA_Mode_Info
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+ mov ax, 0x00
|
|
|
+ mov es, ax
|
|
|
+ mov si, 0x800e ; 根据文档可知,偏移量0Eh处, DWORD pointer to list of supported VESA and OEM video modes
|
|
|
+ ;(list of words terminated with FFFFh)
|
|
|
+ mov esi, dword [es:si]
|
|
|
+ mov edi, 0x8200
|
|
|
+
|
|
|
+Label_SVGA_Mode_Info_Get:
|
|
|
+ mov cx, word [es:esi]
|
|
|
+
|
|
|
+
|
|
|
+; ===========显示SVGA mode的信息
|
|
|
+ ;push ax
|
|
|
+
|
|
|
+ ;mov ax, 0x00
|
|
|
+ ;mov al, ch
|
|
|
+ ;call Label_DispAL
|
|
|
+
|
|
|
+ ;mov ax, 0x00
|
|
|
+ ;mov al, cl
|
|
|
+ ;call Label_DispAL
|
|
|
+
|
|
|
+ ;pop ax
|
|
|
+;============
|
|
|
+
|
|
|
+ ; 判断是否获取完毕
|
|
|
+ cmp cx, 0xFFFF
|
|
|
+ jz Label_SVGA_Mode_Info_Finish
|
|
|
+
|
|
|
+ mov ax, 0x4f01 ; 使用4f01功能,获取SVGA的模式
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+ cmp ax, 0x004f ; 判断是否获取成功
|
|
|
+ jnz Label_SVGA_Mode_Info_Fail
|
|
|
+
|
|
|
+ add esi, 2
|
|
|
+ add edi, 0x100 ; 开辟一个 256-byte 的 buffer
|
|
|
+
|
|
|
+ jmp Label_SVGA_Mode_Info_Get
|
|
|
+
|
|
|
+Label_SVGA_Mode_Info_Fail:
|
|
|
+ ; === 获取信息失败 ===
|
|
|
+ mov ax, 0x1301
|
|
|
+ mov bx, 0x008c
|
|
|
+ mov dx, 0x0800 ; 在第9行显示
|
|
|
+ mov cx, 34
|
|
|
+ push ax
|
|
|
+ mov ax, ds
|
|
|
+ mov es, ax
|
|
|
+ pop ax
|
|
|
+ mov bp, Message_Get_SVGA_Mode_Failed
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+ jmp $
|
|
|
+
|
|
|
+Label_SVGA_Mode_Info_Finish:
|
|
|
+ ; === 成功获取SVGA mode信息 ===
|
|
|
+ mov ax, 0x1301
|
|
|
+ mov bx, 0x000f
|
|
|
+ mov dx, 0x0800 ; 在第9行显示
|
|
|
+ mov cx, 39
|
|
|
+ push ax
|
|
|
+ mov ax, ds
|
|
|
+ mov es, ax
|
|
|
+ pop ax
|
|
|
+ mov bp, Message_Get_SVGA_Mode_Success
|
|
|
+ int 0x10
|
|
|
+ jmp Label_Set_SVGA_Mode
|
|
|
+
|
|
|
+Label_SET_SVGA_Mode_VESA_VBE_FAIL:
|
|
|
+ ; 设置SVGA显示模式失败
|
|
|
+ mov ax, 0x1301
|
|
|
+ mov bx, 0x008c
|
|
|
+ mov dx, 0x0800 ; 在第10行显示
|
|
|
+ mov cx, 29
|
|
|
+ push ax
|
|
|
+ mov ax, ds
|
|
|
+ mov es, ax
|
|
|
+ pop ax
|
|
|
+ mov bp, Message_Set_SVGA_Mode_Failed
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+ jmp $
|
|
|
+
|
|
|
+
|
|
|
+Label_Set_SVGA_Mode:
|
|
|
+
|
|
|
+; ===== 设置SVGA芯片的显示模式(VESA VBE) ===
|
|
|
+ mov ax, 0x4f02 ; 使用int0x10 功能号AX=4f02设置SVGA芯片的显示模式
|
|
|
+ mov bx, 0x4180 ; 显示模式可以选择0x180(1440*900 32bit)或者0x143(800*600 32bit)
|
|
|
+ int 0x10
|
|
|
+
|
|
|
+ cmp ax, 0x004F
|
|
|
+ jnz Label_SET_SVGA_Mode_VESA_VBE_FAIL
|
|
|
+
|
|
|
+; ===== 初始化GDT表,切换到保护模式 =====
|
|
|
+
|
|
|
+ cli ; 关闭外部中断
|
|
|
+ db 0x66
|
|
|
+ lgdt [GdtPtr]
|
|
|
+
|
|
|
+ db 0x66
|
|
|
+ lidt [IDT_POINTER]
|
|
|
+
|
|
|
+ mov eax, cr0
|
|
|
+ or eax, 1 ; 启用保护模式
|
|
|
+ mov cr0, eax
|
|
|
+
|
|
|
+ ; 跳转到保护模式下的第一个程序
|
|
|
+ jmp dword SelectorCode32:GO_TO_TMP_Protect
|
|
|
+
|
|
|
+
|
|
|
+[SECTION .s32]
|
|
|
+[BITS 32]
|
|
|
+GO_TO_TMP_Protect:
|
|
|
+ ; ==== 切换到长模式 =====
|
|
|
+ mov ax, 0x10
|
|
|
+ mov ds, ax
|
|
|
+ mov es, ax
|
|
|
+ mov fs, ax
|
|
|
+ mov ss, ax
|
|
|
+ mov esp, 0x7e00 ; 将栈指针设置在实模式获取到的数据的基地址上
|
|
|
+
|
|
|
+ call support_long_mode ; 检测是否支持长模式
|
|
|
+
|
|
|
+ test eax, eax ; 将eax自身相与,检测是否为0(test指令不会把结果赋值回去eax)
|
|
|
+ jz no_support ; 不支持长模式
|
|
|
+
|
|
|
+ ; 初始化临时页表, 基地址设置为0x90000
|
|
|
+ ; 设置各级页表项的值(页表起始地址与页属性组成)
|
|
|
+ mov dword [0x90000], 0x91007
|
|
|
+ mov dword [0x90004], 0x00000
|
|
|
+ mov dword [0x90800], 0x91007
|
|
|
+ mov dword [0x90804], 0x00000
|
|
|
+
|
|
|
+ mov dword [0x91000], 0x92007
|
|
|
+ mov dword [0x91004], 0x00000
|
|
|
+
|
|
|
+ mov dword [0x92000], 0x000083
|
|
|
+ mov dword [0x92004], 0x000000
|
|
|
+
|
|
|
+ mov dword [0x92008], 0x200083
|
|
|
+ mov dword [0x9200c], 0x000000
|
|
|
+
|
|
|
+ mov dword [0x92010], 0x400083
|
|
|
+ mov dword [0x92014], 0x000000
|
|
|
+
|
|
|
+ mov dword [0x92018], 0x600083
|
|
|
+ mov dword [0x9201c], 0x000000
|
|
|
+
|
|
|
+ mov dword [0x92020], 0x800083
|
|
|
+ mov dword [0x92024], 0x000000
|
|
|
+
|
|
|
+ mov dword [0x92028], 0xa00083
|
|
|
+ mov dword [0x9202c], 0x000000
|
|
|
+
|
|
|
+ ; === 加载GDT ===
|
|
|
+ db 0x66
|
|
|
+ lgdt [GdtPtr64] ; 加载GDT
|
|
|
+ ; 把临时gdt的数据段加载到寄存器中(cs除外)
|
|
|
+ mov ax, 0x10
|
|
|
+ mov ds, ax
|
|
|
+ mov es, ax
|
|
|
+ mov fs, ax
|
|
|
+ mov gs, ax
|
|
|
+ mov ss, ax
|
|
|
+
|
|
|
+ mov esp, 0x7e00
|
|
|
+
|
|
|
+ ; ====== 开启物理地址扩展 =====
|
|
|
+ ; 通过bts指令,将cr4第5位置位,开启PAE
|
|
|
+ mov eax, cr4
|
|
|
+ bts eax, 5
|
|
|
+ mov cr4, eax
|
|
|
+
|
|
|
+ ; 将临时页目录的地址设置到CR3控制寄存器中
|
|
|
+ mov eax, 0x90000
|
|
|
+ mov cr3, eax
|
|
|
+
|
|
|
+ ; ==== 启用长模式 ===
|
|
|
+ ; 参见英特尔开发手册合集p4360 volume4, chapter2 2-60 Vol. 4
|
|
|
+ ; IA32_EFER寄存器的第8位是LME标志位,能启用IA-32e模式
|
|
|
+ mov ecx, 0xC0000080
|
|
|
+ rdmsr
|
|
|
+ bts eax, 8
|
|
|
+ wrmsr
|
|
|
+
|
|
|
+ ; === 开启分页机制 ===
|
|
|
+ mov eax, cr0
|
|
|
+ bts eax, 0 ; 再次开启保护模式
|
|
|
+ bts eax, 31 ; 开启分页管理机制
|
|
|
+ mov cr0, eax
|
|
|
+
|
|
|
+
|
|
|
+ ; === 通过此条远跳转指令,处理器跳转到内核文件进行执行,正式进入IA-32e模式
|
|
|
+
|
|
|
+ jmp SelectorCode64:Offset_Of_Kernel_File
|
|
|
+
|
|
|
+
|
|
|
+support_long_mode:
|
|
|
+ ; ===== 检测是否支持长模式 ====
|
|
|
+ mov eax, 0x80000000
|
|
|
+ cpuid ; cpuid指令返回的信息取决于eax的值。当前返回到eax中的是最大的输入参数值。 详见:英特尔开发人员手册卷2A Chapter3 (Page 304)
|
|
|
+ cmp eax, 0x80000001
|
|
|
+ setnb al ; 当cmp结果为不低于时,置位al
|
|
|
+ jb support_long_mode_done ; 当eax小于0x80000001时,跳转
|
|
|
+
|
|
|
+ mov eax, 0x80000001
|
|
|
+ cpuid ; 获取特定信息,参照开发人员手册卷2A p304
|
|
|
+
|
|
|
+ bt edx, 29 ; 将edx第29位的值移到CF上。该位指示了CPU是否支持IA-32e模式
|
|
|
+ ; Bit 29: Intel® 64 Architecture available if 1.
|
|
|
+ setc al ; 若支持则al置位
|
|
|
+
|
|
|
+support_long_mode_done:
|
|
|
+ movzx eax, al ; 将al,零扩展为32位赋值给eax
|
|
|
+ ret
|
|
|
+
|
|
|
+no_support:
|
|
|
+ ; 不支持长模式
|
|
|
+ jmp $
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+[SECTION .s16lib]
|
|
|
+[BITS 16]
|
|
|
; 从软盘读取一个扇区
|
|
|
; AX=待读取的磁盘起始扇区号
|
|
|
; CL=读入的扇区数量
|
|
@@ -471,24 +762,75 @@ Label_Even_2:
|
|
|
pop es
|
|
|
ret
|
|
|
|
|
|
+; ==== 显示AL中的信息 ===
|
|
|
+Label_DispAL:
|
|
|
+ push ecx
|
|
|
+ push edx
|
|
|
+ push edi
|
|
|
+
|
|
|
+ mov edi, [DisplayPosition]
|
|
|
+ mov ah, 0x0F
|
|
|
+ mov dl, al ; 为了先显示al的高4位,因此先将al暂存在dl中,然后把al往右移动4位
|
|
|
+ shr al, 4
|
|
|
+ mov ecx, 2 ; 计数为2
|
|
|
+
|
|
|
+.begin:
|
|
|
+ and al, 0x0F
|
|
|
+ cmp al, 9
|
|
|
+ ja .1 ; 大于9,跳转到.1
|
|
|
+ add al, '0'
|
|
|
+ jmp .2
|
|
|
+.1:
|
|
|
+ sub al, 0x0a
|
|
|
+ add al, 'A'
|
|
|
+.2:
|
|
|
+ ; 移动到显示内存中
|
|
|
+ mov [gs:edi], ax
|
|
|
+ add edi, 2
|
|
|
+
|
|
|
+ mov al, dl
|
|
|
+ loop .begin
|
|
|
+
|
|
|
+ mov [DisplayPosition], edi
|
|
|
+
|
|
|
+ pop edi
|
|
|
+ pop edx
|
|
|
+ pop ecx
|
|
|
|
|
|
+ ret
|
|
|
|
|
|
+; === 临时的中断描述符表 ===
|
|
|
+; 为临时的IDT开辟空间。
|
|
|
+; 由于模式切换过程中已经关闭了外部中断,只要确保模式切换过程中不产生异常,就不用完整的初始化IDT。甚至乎,只要没有异常产生,没有IDT也可以。
|
|
|
+IDT:
|
|
|
+ times 0x50 dq 0
|
|
|
+IDT_END:
|
|
|
|
|
|
+IDT_POINTER:
|
|
|
+ dw IDT_END - IDT - 1
|
|
|
+ dd IDT
|
|
|
|
|
|
-;====临时变量=====
|
|
|
+;==== 临时变量 =====
|
|
|
RootDirSizeForLoop dw RootDirSectors
|
|
|
SectorNo dw 0
|
|
|
Odd db 0
|
|
|
OffsetOfKernelFileCount dd Offset_Of_Kernel_File
|
|
|
|
|
|
+DisplayPosition dd 0
|
|
|
+
|
|
|
; 要显示的消息文本
|
|
|
Message_Start_Loader: db "[DragonOS] Start Loader"
|
|
|
Message_No_Loader: db "[ERROR] No Kernel Found."
|
|
|
Message_Kernel_Loaded: db "[INFO] Kernel loaded"
|
|
|
Message_Start_Get_Mem_Struct: db "[INFO] Try to get memory struct..."
|
|
|
Message_Get_Mem_Failed: db "[ERROR] Get memory struct failed."
|
|
|
-Message_Get_Mem_Success: db "[INFO] Successful to get memory struct."
|
|
|
-Message_Start_Get_SVGA_Info: db "[INFO] Try to get SVGA info..."
|
|
|
-
|
|
|
+Message_Get_Mem_Success: db "[INFO] Successfully got memory struct."
|
|
|
+Message_Start_Get_SVGA_VBE_Info: db "[INFO] Try to get SVGA VBE info..."
|
|
|
+Message_Get_SVGA_VBE_Failed: db "[ERROR] Get SVGA VBE info failed."
|
|
|
+Message_Get_SVGA_VBE_Success: db "[INFO] Successfully got SVGA VBE info."
|
|
|
+Message_Start_Get_SVGA_Mode_Info: db "[INFO] Try to get SVGA mode info..."
|
|
|
+Message_Get_SVGA_Mode_Failed: db "[ERROR] Get SVGA Mode info failed."
|
|
|
+Message_Get_SVGA_Mode_Success: db "[INFO] Successfully got SVGA Mode info."
|
|
|
+Message_Set_SVGA_Mode_Failed: db "[ERROR] Set SVGA Mode failed."
|
|
|
|
|
|
Kernel_FileName: db "KERNEL BIN", 0
|