學(xué)習(xí)筆記
使用教材(配書源碼以及使用方法)
《一個(gè)64位操作系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)》
http://www.ituring.com.cn/book/2450
http://www.reibang.com/p/28f9713a9171
源碼結(jié)構(gòu)
- 配書代碼包 :第8章 \ 程序 \ 程序8-2
實(shí)驗(yàn)操作
1撩满、虛擬機(jī):生成boot.bin 棠绘、loader.bin以及kernel.bin 并復(fù)制到U盤
[anno@localhost 32MB-bootloader]$
sudo dd if=boot.bin of=/dev/sdb bs=512 count=1 conv=notrunc
[anno@localhost 物理平臺(tái)]$ cd kernel
[anno@localhost kernel]$ make
gcc -E head.S > head.s
as --64 -o head.o head.s
gcc -E entry.S > entry.s
as --64 -o entry.o entry.s
gcc -mcmodel=large -fno-builtin -m64 -c main.c
gcc -mcmodel=large -fno-builtin -m64 -c printk.c
gcc -mcmodel=large -fno-builtin -m64 -c trap.c
gcc -mcmodel=large -fno-builtin -m64 -c memory.c
gcc -mcmodel=large -fno-builtin -m64 -c interrupt.c
gcc -mcmodel=large -fno-builtin -m64 -c task.c
gcc -mcmodel=large -fno-builtin -m64 -c cpu.c
ld -b elf64-x86-64 -z muldefs -o system head.o entry.o main.o printk.o trap.o memory.o interrupt.o task.o cpu.o -T Kernel.lds
objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary system kernel.bin
根據(jù)自己使用的U盤网严,修改bootloader部分源碼的方法參見
[OS64][031]實(shí)驗(yàn)操作:程序7-3 移植到物理平臺(tái) U盤啟動(dòng)
http://www.reibang.com/p/a84b45ae3219
- 其實(shí)程序8-2與程序7-3使用的
bootloader
代碼是一致的胸墙,如果在程序7-3的實(shí)驗(yàn)中已經(jīng)按照自己的U盤規(guī)格制作好了boot.bin
猾骡、loader.bin
牢贸,可以直接拿來用了
2子漩、物理機(jī)器:插上U盤阿弃,顯示運(yùn)行畫面
源碼閱讀
get_cpuid 用于獲取處理器固件信息
CPUID
指令將通過EAX
寄存器輸入查詢的主功能號(hào)
,如果有需要缀雳,則再向ECX寄存器輸入查詢的子功能號(hào)渡嚣。
當(dāng)這條匯編指令執(zhí)行結(jié)束后,查詢的返回值
將保存在EAX肥印、EBX识椰、ECX和EDX寄存器
中
代碼清單8-4 第8章\程序\程序8-2\物理平臺(tái)\kernel\cpu.h
inline void get_cpuid(unsigned int Mop,
unsigned int Sop,
unsigned int * a,
unsigned int * b,
unsigned int * c,
unsigned int * d)
{
__asm__ __volatile__ ( "cpuid \n\t"
:"=a"(*a),"=b"(*b),"=c"(*c),"=d"(*d)
:"0"(Mop),"2"(Sop)
);
}
- 將
CPUID
匯編指令封裝成get_cpuid
函數(shù) -
Mop
和Sop
參數(shù)用于向CPUID
指令傳遞主功能號(hào)和子功能號(hào) - 將查詢的返回值保存到指針變量
a、b深碱、c和d
指向的內(nèi)存中
init_cpu() 中調(diào)用 get_cpuid(...)
void init_cpu(void)
{
int i,j;
unsigned int CpuFacName[4] = {0,0,0,0};
char FactoryName[17] = {0};
//vendor_string
get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
*(unsigned int*)&FactoryName[0] = CpuFacName[1];
*(unsigned int*)&FactoryName[4] = CpuFacName[3];
*(unsigned int*)&FactoryName[8] = CpuFacName[2];
FactoryName[12] = '\0';
color_printk(YELLOW,BLACK,"%s\t%#010x\t%#010x\t%#010x\n",FactoryName,CpuFacName[1],CpuFacName[3],CpuFacName[2]);
//brand_string
for(i = 0x80000002;i < 0x80000005;i++)
{
get_cpuid(i,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
*(unsigned int*)&FactoryName[0] = CpuFacName[0];
*(unsigned int*)&FactoryName[4] = CpuFacName[1];
*(unsigned int*)&FactoryName[8] = CpuFacName[2];
*(unsigned int*)&FactoryName[12] = CpuFacName[3];
FactoryName[16] = '\0';
color_printk(YELLOW,BLACK,"%s",FactoryName);
}
color_printk(YELLOW,BLACK,"\n");
//Version Informatin Type,Family,Model,and Stepping ID
get_cpuid(1,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
color_printk(YELLOW,BLACK,"Family Code:%#010x,Extended Family:%#010x,Model Number:%#010x,Extended Model:%#010x,Processor Type:%#010x,Stepping ID:%#010x\n",(CpuFacName[0] >> 8 & 0xf),(CpuFacName[0] >> 20 & 0xff),(CpuFacName[0] >> 4 & 0xf),(CpuFacName[0] >> 16 & 0xf),(CpuFacName[0] >> 12 & 0x3),(CpuFacName[0] & 0xf));
//get Linear/Physical Address size
get_cpuid(0x80000008,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
color_printk(YELLOW,BLACK,"Physical Address size:%08d,Linear Address size:%08d\n",(CpuFacName[0] & 0xff),(CpuFacName[0] >> 8 & 0xff));
//max cpuid operation code
get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
color_printk(WHITE,BLACK,"MAX Basic Operation Code :%#010x\t",CpuFacName[0]);
get_cpuid(0x80000000,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
color_printk(WHITE,BLACK,"MAX Extended Operation Code :%#010x\n",CpuFacName[0]);
}
功能號(hào) 0x00
獲取處理器的供應(yīng)商標(biāo)識(shí)
get_cpuid(0,0,&CpuFacName[0],&CpuFacName[1],&CpuFacName[2],&CpuFacName[3]);
傳入的功能號(hào)0x00
*(unsigned int*)&FactoryName[0] = CpuFacName[1];
其中 CpuFacName[1] = 0x756e6547 代表 "Genu"*(unsigned int*)&FactoryName[0]
先取FactoryName[0]的地址腹鹉,然后就是將 0x756e6547 填入FactoryName[0] FactoryName[1] FactoryName[2] FactoryName[3]
color_printk(YELLOW,BLACK,"%s\t%#010x\t%#010x\t%#010x\n",FactoryName,CpuFacName[1],CpuFacName[3],CpuFacName[2]);
其中%s
把 0x756e6547 看做字符串 Genu輸出,%#010x
直接輸出數(shù)值0x756e6547
功能號(hào)0x80002~0x80004
獲取處理器商標(biāo)信息
for(i = 0x80000002;i < 0x80000005;i++) { }
init_cpu() 在何處被調(diào)用 敷硅?
通常情況下功咒,這些數(shù)據(jù)(處理器固件信息),應(yīng)該最先被操作系統(tǒng)捕獲绞蹦,隨后操作系統(tǒng)再根據(jù)處理器的固件信息來確定處理器支持的功能力奋,以便進(jìn)一步初始化處理器。
因此幽七,將init_cpu
函數(shù)插入到系統(tǒng)異常處理功能的初始化函數(shù)( sys_vector_init();)之后會(huì)更妥當(dāng)一些
代碼清單8-6 第8章\程序\程序8-2\物理平臺(tái)\kernel\main.c
void Start_Kernel(void)
{
……
sys_vector_init();
init_cpu();
……
}
參考資料
[ATT匯編]程序舉例:xxx.S 編譯景殷、鏈接、運(yùn)行澡屡、調(diào)試 (CPUID命令 顯示處理器廠商信息)
http://www.reibang.com/p/91506500523a
[內(nèi)聯(lián)匯編]擴(kuò)展asm:格式猿挚、占位符、跳轉(zhuǎn)挪蹭、內(nèi)聯(lián)匯編宏函數(shù)
http://www.reibang.com/p/76fda24ee7f7