自己动手写操作系统(四)
程序员文章站
2024-03-24 11:51:16
...
今天主要接着(二)来看一下stage2.asm。stage2.asm的功能主要有下面几个:
=============================
1.将系统从实模式切换到保护模式
2.找到core.sys(就是kernel)的位置,并且将core.sys导入内存
3.跳转到core.sys的入口函数处
=============================
首先看一下代码流程
call GDT_INSTALL
GDT即全局描述符表。[span]在英特尔x86[span]系列处理器的80286[span]起,为了定义的特点使用不同的存储区,在程序执行期间,包括基地址,大小和访问权限,如可执行可写。这些内存区域被称为段(英特尔的术语)。内存中段所在的位置不需要写入特殊标记,段的信息(基地址、界限、属性等)保存通过段描述符表进行。GDT正是最重要的描述符表,进入保护模式,至少要准备GDT。GDT主要存放操作系统和各任务公用的描述符,如公用的数据和代码段描述符、各任务的TSS描述符和LDT描述符。每8个字节的条目在GDT是一个描述符。进入保护模式后我们会用到这个东东。
call ENABLE_PMODE
jmp GDT_CODE_DESC:STAGE3 ; far jump to fix CS
进入保护模式,然后跳转到StageE,可以看一下GDT_CODE_DESC就是之前我们定义在GDT中的段。
关键来看一下stage3中的处理:
STAGE3:
; set segment registers
cli
mov ax, GDT_DATA_DESC ; set data segments to data selectors (0x10)
mov ds, ax
mov ss, ax
mov es, ax
mov esp, 0x90000 ; stack begins from 0x90000
; map PDE and enable paging
;call ENABLE_PAGING ;asido中会在这里进行内存第1M的分页,但是这样做会导致进入kernel后内存分页比较麻烦,所以这里直接不做分页
; calculate memory size in Kb from in 16-bit returned BIOS
push DWORD [MemKBHigh]
push DWORD [MemKBLow]
call MEM16_TO_MEM32_SIZE
mov DWORD [MemorySize], eax
; calculate kernel size in sectors returned from in 16-bit FAT12 driver
push DWORD [KernelImgSizeHigh]
push DWORD [KernelImgSizeLow]
call KRNL_SIZE_TO_INT32
mov DWORD [KernelImgSize], eax
; load the kernel
push KERNEL_RMODE_BASE
call LOAD_ELF ;这里是从core.sys中查找到入口函数地址,然后存放到eax中
; and execute it!
cli
push DWORD KERNEL_PMODE_BASE ;core.sys的加载起始地址入栈,这些数据会作为参数传入入口函数
push DWORD [KernelImgSize]
push DWORD [MemorySize]
;we push gdt addr to main start
;push DWORD [LGDT_VAL]
;we push gdt addr to main end
call eax ;eax中存的就是入口函数地址,所以直接跳转。
add esp, 0x4
-Ttext $(ENTRYPOINT)来指定入口函数地址等,但都不是很方便。个人觉得还是这个上面介绍的方法比较方便。
从call eax开始,我们就进入了core的处理流程了(也就是大家常说的kernel)。后续主要的精力会先放在内存管理这块。主要也是因为性能优化关系较大的还是内存这块,哈哈~~~~。最关心的优先学~~。
谢谢