引导代码ycboot.cpp
#define YCORG 0
#define YCBIT 16
#include "ycos.h"
asm void print();
asm void read_sector();
#define setup_POS (ycboot_SIZE - 512)
asm void main()
{
xor ax,ax //加电时, BIOS执行: memcpy(0000:7c00h, &imgBuf[0], 512)
mov ds,ax
mov ax,DATA_POS / 16
mov es,ax
//memcpy(9000:0000h, &imgBuf[0], 512)
mov ecx,512 / 4
mov esi,7c00h
xor edi,edi
rep movsd
jmp DATA_POS / 16 : rd_boot //该语句使cs由0000h变为9000h
rd_boot: mov ax, cs //此时 cs = 9000h
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0xfff0 //设置堆栈为9000:fff0, 用于push call ret等语句
//清屏
mov dx, 1f4fh
mov bx, 0f10h
mov ax, 0600h
int 10h
//显示 Loading 信息
mov al, 0
mov bx, 0x0047
call print
//memcpy(9000:setup_POS, &imgBuf[setup_POS], ycboot_SIZE - setup_POS)
mov eax,setup_POS/512
mov edx, 0
mov di, cs
mov bx, setup_POS
mov cx, (ycboot_SIZE - setup_POS) / 512
call read_sector
//显示[setup_POS]处的字符
mov ax,0xb800
mov gs,ax
mov al, [setup_POS]
mov byte gs:[(80*0 + 78)*2 + 0], al
mov byte gs:[(80*0 + 78)*2 + 1], 0xcf
//判断是否读入了ycboot的setup_main()函数
cmp byte [setup_POS], 66h
jz mn_0
mov al, 1
mov bx, 0x0017
call print //ycboot未被读入, 显示错误信息
mn_0: jmp setup_POS //跳到&imgBuf[setup_POS]代码处的setup_main()函数
}
asm char msg1()
{
db "YCos is booting... - ycboot.cpp"
db "Reading Error! - ycboot.cpp "
}
asm void print()
{
mov dh, al //显示位置(dl,dh)
mov dl, 0
mov cx, 31 //字符串msg1的长度
mul cl
mov bp, msg1 //字符串msg1的地址
add bp, ax
mov ax, 1301h //显示功能号
int 0x10 //显示字符串
ret
}
asm void hd_pack() { db 16, 15 dup(0) }
asm void read_sector()
{
push eax
push edx
push si
mov si, hd_pack
mov [si + 2], cx //read cx sectors into buffer
mov [si + 4], bx //buffer offset
mov [si + 6], di //buffer segment
mov [si + 8], eax //dada sector pos low
mov [si + 12], edx //dada sector pos high
mov ah, 42h //read mode
mov dl, 80h //disk C
int 0x13
pop si
pop edx
pop eax
ret
}
#org(e820_POS) //内存信息的存放位置
asm void $() { db 0 }
#org(510)
asm void flag() { dw 0xaa55 }
int64 Ygdt[] = {0, 0x00cf9a000000ffff, 0x00cf92000000ffff};
GDT_PTR gdt_descr = { sizeof Ygdt, (char*)Ygdt + DATA_POS };
#org(setup_POS)
asm void setup_main()
{
//memcpy(1000:5000h, &imgBuf[ycboot_SIZE], ycker_SIZE)
mov eax, ycboot_SIZE / 512 //逻辑扇区 = edx*100000000h + eax
mov edx, 0
mov di, ycker_POS / 16 //数据被读到 di:bx
mov bx, 0 //每次最多读 10000h = 64k 字节数据 = 128个扇区
mov cx, 128 //读128个扇区 = 128 * 512 = 10000h
rf_000: call read_sector
add eax, 128 //调整磁盘逻辑扇区, 以备下次读取数据
adc edx, 0
add di, 1000h //调整缓冲区位置
cmp di, DATA_POS / 16 //检查数据是否被读完
jne rf_000 //数据未被读完, 再读一次
//将系统内存信息读到9000:[e820_POS]
xor ebx,ebx
mov [e820_POS],ebx
mov di, e820_POS + offsetof(e820map,map)
sm_00: mov eax, 0000e820h
mov ecx, 20
mov edx, 'SMAP'
int 15h
jc sm_01
cmp eax, 'SMAP'
jne sm_01
mov eax,[e820_POS]
cmp dword [e820_POS],32
jnl sm_01
inc dword [e820_POS]
add di, 20
cmp ebx, 0
jne sm_00
sm_01: lgdt cs:gdt_descr //装入全局段描述符
mov al,0xdf
out 0x60,al //打开A20
mov ax,0x0001
lmsw ax //进入保护模式
jmp dword KERNEL_CS : DATA_POS - ychead_SIZE //跳入 ychead.cpp
}
C/C++代码文件: ycboot.cpp
源代码分析
语句#define YCORG 0 定义生成代码的位置,定义它后不再使用默认的头文件
语句#define YCBIT 16 定义生成16位不带头部信息的执行代码。
asm void main()为程序入口函数
代码mov ecx,512 / 4; mov esi,7c00h; xor edi,edi; rep movsd将引导扇区中的512字节考到内存9000:0000处,相当于执行C代码: memcpy(0x90000,&imgBuf[0],512)。
语句 #org(510)使函数asm void flag() { dw 0xaa55 }处于第510字节的位置
语句:…
mov cx, (ycboot_SIZE - setup_POS) / 512
call read_sector
将ycboot.cpp的第512字节后的代码拷到内存9000:0200处
语句jmp setup_POS使程序跳到9000:0200(即asm void setup_main()函数)处
语句:
mov cx, 128 //读128个扇区 = 128 * 512 = 10000h
call read_sector
将ycker.cpp,ychead.cpp,ycfs.cpp,ycmm.cpp执行代码拷贝到内存ycker_POS(即1000:5000)处,相当于执行C语句memcpy(0x50000,&imgBuf[ycboot_SIZE],ycker_SIZE)
语句jmp dword KERNEL_CS : DATA_POS - ychead_SIZE使程序跳到0x90000-0x2000处,分析ycos.cpp语句
memcpy(&imgBuf[ycboot_SIZE + ycker_SIZE - ychead_SIZE],head_buf,head_len)可知,此处是ychead.cpp代码,故程序便进入ychead.cpp的main()函数。