äœæ¥äžãããŒããŠã§ã¢ãšã®ããªãäœã¬ãã«ã®çžäºäœçšã«å®æçã«å¯ŸåŠããå¿
èŠããããŸãã ãã®èšäºã§ã¯ã察å¿ããããã€ã¹ãã©ã€ããŒã®èå¥ãšèªã¿èŸŒã¿ã®ããã®PCIããã€ã¹ã®åãåãããã©ã®ããã«çºçãããã瀺ããããšæããŸãã
PCIããã€ã¹ãæäœããããã®æå°ããŒã¹ãšããŠããã«ãããŒã仿§ããµããŒãããã«ãŒãã«ã䜿çšããŸãã ããã«ãããç¬èªã®ããŒãã»ã¯ã¿ãŒãšããŒããŒãäœæããå¿
èŠããªããªããŸãã ããã«ããã®åé¡ã¯ãã§ã«ã€ã³ã¿ãŒãããã§ååã«åãäžããããŠããŸãã ããŒãããŒããŒã¯GRUBã«ãªããŸãã ä»®æ³ãã·ã³ãšå®ãã·ã³ã®äž¡æ¹ããèµ·åããã®ã䟿å©ãªã®ã§ããã©ãã·ã¥ãã©ã€ãããèµ·åããŸãã QEMUãä»®æ³ãã·ã³ãšããŠäœ¿çšããŸãã å®éã®ãã·ã³ã¯ãUSB-HDDããã®èµ·åããµããŒãããéåžžã®BIOSïŒUEFIã§ã¯ãªãïŒãæèŒãããã·ã³ã§ããå¿
èŠããããŸãïŒéåžžãã¬ã¬ã·ãŒUSBãµããŒããªãã·ã§ã³ããããŸãïŒã åäœããã«ã¯ãexpectãqemuãgrubã®åããã°ã©ã ãåããUbuntu Linuxãå¿
èŠã§ãïŒsudo apt-get installã³ãã³ãã䜿çšããŠç°¡åã«ã€ã³ã¹ããŒã«ã§ããŸãïŒã 䜿çšãããgccã¯32ãããã³ãŒããã³ã³ãã€ã«ããå¿
èŠããããŸãã
æåã®ã¹ããã-ãã«ãããŒã仿§ããµããŒãããã«ãŒãã«ã®äœæãæ€èšããŠãã ããã GRUBãããŒããŒãšããŠäœ¿çšããå Žåãã«ãŒãã«ã¯3ã€ã®ãã¡ã€ã«ããäœæãããŸãã
Kernel.c-ããã°ã©ã ã®ã³ãŒããšmainïŒïŒããã·ãŒãžã£ãå«ãã¡ã€ã³ãã¡ã€ã«ã
Loader.s -GRUBã®ãã«ãããŒãããããŒãå«ãŸããŠããŸãã
Linker.ldã¯ãã«ãŒãã«ãé
眮ãããã¢ãã¬ã¹ãå
·äœçã«ç€ºãldãªã³ã«ãŒã¹ã¯ãªããã§ãã
Linker.ldã³ã³ãã³ãïŒ
ENTRY (loader) SECTIONS { . = 0x00100000; .text ALIGN (0x1000) : { *(.text) } .rodata ALIGN (0x1000) : { *(.rodata*) } .data ALIGN (0x1000) : { *(.data) } .bss : { sbss = .; *(COMMON) *(.bss) ebss = .; } }
ãªã³ã«ã¹ã¯ãªããã¯ãæ¢ã«ã³ã³ãã€ã«ããããªããžã§ã¯ããã¡ã€ã«ããªã³ã¯ããæ¹æ³ã瀺ããŸãã æåã®è¡ã¯ãã³ã¢ã®ãšã³ããªãã€ã³ãããloaderããšããã©ãã«ã®ã¢ãã¬ã¹ã«ãªãããšã瀺ããŠããŸãã ããã«ã¹ã¯ãªããã§ã¯ãã¢ãã¬ã¹0x00100000ïŒ1MbïŒããå§ãŸãããã¹ãã»ã¯ã·ã§ã³ãé
眮ãããããšã瀺ãããŠããŸãã rodataãdataãããã³bssã»ã¯ã·ã§ã³ã¯0x1000ïŒ4KbïŒã«æããããããã¹ãã»ã¯ã·ã§ã³ã®åŸã«é
眮ãããŸãã
Loader.sã®å
容ïŒ
.global loader .set FLAGS, 0x0 .set MAGIC, 0x1BADB002 .set CHECKSUM, -(MAGIC + FLAGS) .align 4 .long MAGIC .long FLAGS .long CHECKSUM # reserve initial kernel stack space .set STACKSIZE, 0x4000 .lcomm stack, STACKSIZE .comm mbd, 4 .comm magic, 4 loader: movl $(stack + STACKSIZE), %esp movl %eax, magic movl %ebx, mbd call kmain cli hang: hlt jmp hang
ãã£ã¹ã¯ããã«ãŒãã«ã€ã¡ãŒãžãããŒãããåŸãGRUBã¯ãããŠã³ããŒããããã€ã¡ãŒãžã®æåã®8Kbã§çœ²å0x1BADB002ãæ¢ããŸãã 眲åã¯ãæåã®ãã«ãããŒãããããŒãã£ãŒã«ãã§ãã ã¿ã€ãã«èªäœã¯æ¬¡ã®ãšããã§ãã
ãªãã»ãã
| çš®é¡
| ãã£ãŒã«ãå
| ãæ³šæ
|
0
| u32
| éæ³
| å¿
èŠãª
|
4
| u32
| æ
| å¿
èŠãª
|
8
| u32
| ãã§ãã¯ãµã
| å¿
èŠãª
|
12
| u32
| header_addr
| ãã©ã°[16]ãèšå®ãããŠããå Žå
|
16
| u32
| load_addr
| ãã©ã°[16]ãèšå®ãããŠããå Žå
|
20
| u32
| load_end_addr
| ãã©ã°[16]ãèšå®ãããŠããå Žå
|
24
| u32
| bss_end_addr
| ãã©ã°[16]ãèšå®ãããŠããå Žå
|
28
| u32
| entry_addr
| ãã©ã°[16]ãèšå®ãããŠããå Žå
|
32
| u32
| mode_type
| ãã©ã°[2]ãèšå®ãããŠããå Žå
|
36
| u32
| å¹
| ãã©ã°[2]ãèšå®ãããŠããå Žå
|
40
| u32
| 身é·
| ãã©ã°[2]ãèšå®ãããŠããå Žå
|
44
| u32
| æ·±ã
| ãã©ã°[2]ãèšå®ãããŠããå Žå
|
ã¿ã€ãã«ã«ã¯ãå°ãªããšã3ã€ã®ãã£ãŒã«ãïŒããžãã¯ããã©ã°ããã§ãã¯ãµã ïŒãå«ããå¿
èŠããããŸãã ããžãã¯ãã£ãŒã«ãã¯çœ²åã§ãããäžèšã®ããã«ãåžžã«0x1BADB002ã§ãã ãã©ã°ãã£ãŒã«ãã«ã¯ãOSå¶åŸ¡ã®è»¢éæã®ãã·ã³ã®ç¶æ
ã«é¢ãã远å èŠä»¶ãå«ãŸããŠããŸãã ãã®ãã£ãŒã«ãã®å€ã«å¿ããŠããã«ãããŒãæ
å ±æ§é ã®ãã£ãŒã«ãã®ã»ããã倿Žãããå ŽåããããŸãã Multiboot Informationæ§é äœãžã®ãã€ã³ã¿ã«ã¯ãããŒããããã«ãŒãã«ãžã®å¶åŸ¡ã®è»¢éæã®EBXã¬ãžã¹ã¿ãå«ãŸããŠããŸãã ãã®äŸã§ã¯ããã©ã°ãã£ãŒã«ãã®å€ã¯0ã§ããããã«ãããŒãããããŒã¯3ã€ã®ãã£ãŒã«ãã®ã¿ã§æ§æãããŠããŸãã
ã«ãŒãã«ã«å¶åŸ¡ã転éããæç¹ã§ãããã»ããµã¯ããŒãžã³ã°ãç¡å¹ã«ãªã£ãŠããä¿è·ã¢ãŒãã§åäœããŸãã ããã€ã¹ã®å²ã蟌ã¿åŠçã¯ç¡å¹ã«ãªã£ãŠããŸãã GRUBã¯ããŒãå¯èœãªã«ãŒãã«ã®ã¹ã¿ãã¯ã圢æããŸãããããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãæåã«ãã¹ãããšã§ãã ãã®äŸã§ã¯ãã¹ã¿ãã¯ã®äžã«16KBãå²ãåœãŠãããŸãã æåŸã«å®è¡ãããã¢ã»ã³ãã©æã¯call kmainæã§ããããã¯ãå¶åŸ¡ãCã³ãŒããã€ãŸãvoid kmainïŒvoidïŒé¢æ°ã«è»¢éããŸãã
kernel.cã®å
容ïŒ
#include "printf.h" #include "screen.h" void kmain(void) { clear_screen(); printf(" -- Kernel started! -- \n"); }
ããã«ã¯ãŸã äœãé¢çœããã®ã¯ãããŸããã èªã¿èŸŒã¿ã®èгç¹ããã¯ãCã³ãŒãã®ãšã³ããªãã€ã³ãã®ã¿ã«ç¹å®ã®èŠçŽ ãååšããå¿
èŠããããŸããã€ã³ã¿ãŒãããã«ããprintf颿°ã®å®è£
ã衚瀺ãããããããã³putcharãclear_screenãªã©ã®ãããªã¡ã¢ãªãæäœããããã®ããã€ãã®é¢æ°ã远å ãããŸããã
次ã®ç°¡åãªã¡ã€ã¯ãã¡ã€ã«ã䜿çšããŠãã«ãŒãã«ãæ§ç¯ããŸãã
CC = gcc CFLAGS = -Wall -nostdlib -fno-builtin -nostartfiles -nodefaultlibs LD = ld OBJFILES = \ loader.o \ printf.o \ screen.o \ pci.o \ kernel.o start: all cp ./kernel.bin ./flash/boot/grub/ expect ./grub_install.exp qemu /dev/sdb all: kernel.bin .so: as -o $@ $< .co: $(CC) $(CFLAGS) -o $@ -c $< kernel.bin: $(OBJFILES) $(LD) -T linker.ld -o $@ $^ clean: rm $(OBJFILES) kernel.bin
ããã§ãããŠã³ããŒãã§ããã«ãŒãã«ãã§ããŸããã ãããæ¬åœã«ããŒããããããšã確èªããæãæ¥ãŸããã GRUBãUSBãã©ãã·ã¥ãã©ã€ãã«ã€ã³ã¹ããŒã«ããèµ·åæã«ã«ãŒãã«ãããŒãããããã«æç€ºããŸãã ãããè¡ãã«ã¯ãæ¬¡ã®æé ãå®è¡ããŸãã
1. USBãã©ãã·ã¥ãã©ã€ãã«ããŒãã£ã·ã§ã³ãäœæããGRUBããµããŒããããã¡ã€ã«ã·ã¹ãã ïŒãã®å Žåã¯FAT32ãã¡ã€ã«ã·ã¹ãã ïŒã«ãã©ãŒãããããŸãã Ubuntuãã³ãã«ã®Disk UtilityãŠãŒãã£ãªãã£ã䜿çšããŠãããŒãã£ã·ã§ã³ãäœæã§ããŸããã

2. USBãã©ãã·ã¥ãã©ã€ããããŠã³ããããã£ã¬ã¯ããª/ boot / grub /ãäœæããŸãã ãã¡ã€ã«stage1ãstage2ãfat_stage1_5ã/ usr / libã«ã³ããŒããŸãã ãã£ã¬ã¯ããª/ boot / grub /ã«ããã¹ããã¡ã€ã«menu.lstãäœæããŠæžã蟌ã¿ãŸã
timeout 5 default 0 title start_kernel root (hd0,0) kernel /boot/grub/kernel.bin
USBãã©ãã·ã¥ãã©ã€ãã«GRUBãã€ã³ã¹ããŒã«ããã«ã¯ãgrub_install.expãã¡ã€ã«ã®expectã¹ã¯ãªããã䜿çšããŸãã ãã®å
容ïŒ
log_user 0 spawn grub expect "grub> " send "root (hd1,0)\r" expect "grub> " send "setup (hd1)\r" expect "grub> " send "quit\r" exit 0
ç¹å®ã®ã±ãŒã¹ã§ã¯ãä»ã®ãã©ã€ãçªå·ãšããã€ã¹åãå¯èœã§ãã æçµçã«ãä»®æ³ãã·ã³ã®ã³ã³ãã€ã«ãšèµ·åã¯make startã³ãã³ãã§å®è¡ããå¿
èŠããããŸãã makefileããã®ãã®ã³ãã³ãã¯ãgrub_install.expã¹ã¯ãªããã䜿çšããŠãã©ãã·ã¥ãã©ã€ãã«GRUBãã€ã³ã¹ããŒã«ããããã°ã©ã ã§QEMUä»®æ³ãã·ã³ãèµ·åããŸãã ãã¹ãŠãå®éã®ãã©ãã·ã¥ãã©ã€ãããèªã¿èŸŒãŸãããããQEMUä»®æ³ãã·ã³ã ãã§ãªããå®éã®ã³ã³ãã¥ãŒã¿ãŒãããèµ·åã§ããŸãã
ããã°ã©ã ã§èµ·åãããQEMUä»®æ³ãã·ã³ã¯æ¬¡ã®ãšããã§ãã

ããã§ã¯ãã¡ã€ã³ã¿ã¹ã¯ã«åãæãããŸããã-ã³ã³ãã¥ãŒã¿ãŒã§å©çšå¯èœãªãã¹ãŠã®PCIããã€ã¹ããªã¹ãããŸãã PCIã¯ãã³ã³ãã¥ãŒã¿ãŒäžã®ããã€ã¹ãåããã¡ã€ã³ãã¹ã§ãã ãã¶ãŒããŒãã®ããç¥ãããŠããã¹ãããã«æ¿å
¥ãããåŸæ¥ã®ããã€ã¹ã«å ããŠããã¶ãŒããŒãèªäœã«é
ç·ãããããã€ã¹ïŒãããããªã³ããŒãããã€ã¹ïŒã ãã§ãªãã倿°ã®ã³ã³ãããŒã©ãŒïŒUSBãªã©ïŒããã³ä»ã®ãã¹ãžã®ããªããžïŒäŸïŒPCI-ISAããªããžïŒã ãããã£ãŠãPCIã¯ã³ã³ãã¥ãŒã¿ãŒäžã®ã¡ã€ã³ãã¹ã§ããããããããã¹ãŠã®ããã€ã¹ã®åãåãããéå§ãããŸãã
åPCIããã€ã¹ã¯ã256ãã€ãã®æ§é ïŒPCI Configuration SpaceïŒã«é¢é£ä»ããããŠããããã®èšå®ãé
眮ãããŠããŸãã ããã€ã¹ã®æ§æã¯ãæçµçã«ãã®æ§é ããã®ããŒã¿ã®æžã蟌ã¿ãšèªã¿åãã«ãªããŸãã ãã¹ãŠã®PCIããã€ã¹ã«ã€ããŠãããŒã¿ã®èªã¿åããšæžã蟌ã¿ã¯2ã€ã®å
¥åºåããŒããä»ããŠè¡ãããŸãã
0xcf8-PCIã¢ãã¬ã¹ãæžã蟌ãŸããæ§æããŒãã
0xcfc-æ§æããŒãã§æå®ãããPCIã¢ãã¬ã¹ã«ããŒã¿ãèªã¿æžãããããŒã¿ããŒãã
PCIæ§æã¹ããŒã¹ããããŒã¿ãèªã¿åãå Žåãããã€ã¹ã«é¢ããæ
å ±ãååŸããããã€ã¹ãžã®ããŒã¿ã®æžã蟌ã¿ãæ§æã§ããŸãã
PCIã¢ãã¬ã¹ã¯ã次ã®32ãããæ§é ã§ãã
ããã31
| ããã30ãã24
| ããã23ãã16
| ããã15-11
| ããã10-8
| ããã7-2
| ããã1-0
|
åžžã«1
| äºçŽæžã¿
| ã¿ã€ã€çªå·
| ããã€ã¹çªå·
| æ©èœçªå·
| ç»é²çªå·
| åžžã«0
|
ãã¹çªå·ãšããã€ã¹çªå·ã¯ãã³ã³ãã¥ãŒã¿ãŒäžã®ç©çããã€ã¹ãèå¥ããŸãã ç©çããã€ã¹ã«ã¯ãæ©èœçªå·ã§èå¥ãããããã€ãã®è«çããã€ã¹ãå«ãŸããå ŽåããããŸãïŒããšãã°ãWi-Fiã³ã³ãããŒã©ãŒãåãããããªãã£ããã£ã«ãŒãã«ã¯å°ãªããšã2ã€ã®æ©èœããããŸãïŒã
PCIæ§æã¹ããŒã¹ã¯ãæ¡ä»¶ä»ãã§4ãã€ãã®ã¬ãžã¹ã¿ã«åå²ãããŸãã ã¢ã¯ã»ã¹ãããŠããã¬ãžã¹ã¿çªå·ã¯ã32ãããPCIã¢ãã¬ã¹ã®2çªç®ãã7çªç®ã®ãããã«æ ŒçŽãããŸãã PCIããã€ã¹ãèšè¿°ããPCIæ§æã¹ããŒã¹æ§é ã®ãã£ãŒã«ãã¯ããã®ã¿ã€ãã«ãã£ãŠç°ãªããŸãã ãã ãããã¹ãŠã®ã¿ã€ãã®ããã€ã¹ã«ã€ããŠãæ§é ã®æåã®4ã€ã®ã¬ãžã¹ã¿ã«ã¯æ¬¡ã®ãã£ãŒã«ããå«ãŸããŸãã
ç»é²çªå·
| ããã31ãã24
| ããã23ãã16
| ããã15-8
| ããã7-0
|
0
| ããã€ã¹ID
| ãã³ããŒID
|
1
| ã¹ããŒã¿ã¹
| ã³ãã³ã
|
2
| ã¯ã©ã¹ã³ãŒã
| ãµãã¯ã©ã¹
| ããã°ã©ã IF
| ãªããžã§ã³ID
|
3
| ãã¹ã
| ããããŒã¿ã€ã
| ã¬ã€ãã³ã·ãŒã¿ã€ããŒ
| ãã£ãã·ã¥ã©ã€ã³ãµã€ãº
|
ã¯ã©ã¹ã³ãŒã -ããã€ã¹ãå®è¡ããæ©èœïŒãããã¯ãŒã¯ã¢ããã¿ãŒããããªã«ãŒããªã©ïŒã®èгç¹ããããã€ã¹ã®ã¿ã€ãïŒã¯ã©ã¹ïŒã説æããŸãã
ãã³ããŒID-ããã€ã¹ã¡ãŒã«ãŒã®èå¥åïŒäžçã®åããã€ã¹ã¡ãŒã«ãŒã¯ããããã®äžæã®èå¥åã1ã€ä»¥äžæã£ãŠããŸãïŒã ãããã®çªå·ã¯PCI SIGã«ãã£ãŠçºè¡ãããŸãã
ããã€ã¹ID-ããã€ã¹ã®äžæã®èå¥åïŒæå®ããããã³ããŒIDã«åºæïŒã ãããã®çªå·ã¯è£œé æ¥è
ã«ãã£ãŠæ±ºå®ãããŸãã
ãã£ãŒã«ãDeviceIDïŒDEVãšçç¥ïŒããã³VendorIDïŒVENãšçç¥ïŒã¯ããã®ããã€ã¹ã«å¯Ÿå¿ãããã©ã€ããŒã決å®ããŸãã ãã®ããã«ã远å ã®èå¥åRevisionIDïŒç¥ããŠREVïŒã䜿çšãããå ŽåããããŸãã ã€ãŸããWindowsã¯ãã³ã³ãã¥ãŒã¿ãŒã§æ°ããããã€ã¹ãæ€åºãããšãVENãDEVãããã³REVã®æ°åã䜿çšããŠãMicrosoftãµãŒããŒã䜿çšããŠãã£ã¹ã¯ãŸãã¯ã€ã³ã¿ãŒãããäžã§å¯Ÿå¿ãããã©ã€ããŒãæ€çŽ¢ããŸãã ãããã®çªå·ã¯ãããã€ã¹ãããŒãžã£ãŒã§ã確èªã§ããŸãã

ã³ã³ãã¥ãŒã¿ãŒã§äœ¿çšå¯èœãªPCIããã€ã¹ã®ãªã¹ããååŸããæãç°¡åãªæ¹æ³ãå®è£
ããã³ãŒããæ€èšããŠãã ããã
int ReadPCIDevHeader(u32 bus, u32 dev, u32 func, PCIDevHeader *p_pciDevice) { int i; if (p_pciDevice == 0) return 1; for (i = 0; i < sizeof(p_pciDevice->header)/sizeof(p_pciDevice->header[0]); i++) ReadConfig32(bus, dev, func, i, &p_pciDevice->header[i]); if (p_pciDevice->option.vendorID == 0x0000 || p_pciDevice->option.vendorID == 0xffff || p_pciDevice->option.deviceID == 0xffff) return 1; return 0; } void kmain(void) { int bus; int dev; clear_screen(); printf(" -- Kernel started! -- \n"); for (bus = 0; bus < PCI_MAX_BUSES; bus++) for (dev = 0; dev < PCI_MAX_DEVICES; dev++) { u32 func = 0; PCIDevHeader pci_device; if (ReadPCIDevHeader(bus, dev, func, &pci_device)) continue; PrintPCIDevHeader(bus, dev, func, &pci_device); if (pci_device.option.headerType & PCI_HEADERTYPE_MULTIFUNC) { for (func = 1; func < PCI_MAX_FUNCTIONS; func++) { if (ReadPCIDevHeader(bus, dev, func, &pci_device)) continue; PrintPCIDevHeader(bus, dev, func, &pci_device); } } } }
ãã®ã³ãŒãã§ã¯ããã¹çªå·ãšããã€ã¹çªå·ã¯ãèªã¿åããè¡ãããã¢ãã¬ã¹ã«å®å
šã«åæãããŠããŸãã ããããŒã¿ã€ããã£ãŒã«ãã«PCI_HEADERTYPE_MULTIFUNCãã©ã°ãå«ãŸããŠããå Žåããã®ç©çããã€ã¹ã¯ããã€ãã®è«çããã€ã¹ãå®è£
ããŸããæ§æããŒãã«æžã蟌ãŸããã¢ãã¬ã¹ã§PCIããã€ã¹ãæ€çŽ¢ããå Žåã颿°çªå·ãå埩åŠçããå¿
èŠããããŸãã VendorIDã®å€ãæ£ãããªãå Žåããã®ãã¹ã«ã¯ãã®çªå·ã®ããã€ã¹ã¯ãããŸããã Qemuã§ã¯ããã®ã³ãŒãã¯æ¬¡ã®çµæãåºåããŸãã

0x8086ã¯Intelã®VendorIDããŒããŠã§ã¢ã§ãã 0x7000ã®DeviceIDã¯ãPIIX3 PCI-to-ISA Bridgeããã€ã¹ã«å¯Ÿå¿ããŸãã çµæã®ãã©ãã·ã¥ãã©ã€ãããVmWare Workstation 9.0ã§èµ·åããŸãã PCIããã€ã¹ã®ãªã¹ãã¯éåžžã«é·ããªããæ¬¡ã®ããã«ãªããŸããã

ããã¯ãã·ã¹ãã å
ã®PCIããã€ã¹ã®æ€çŽ¢ãã©ã®ããã«èŠãããã§ãã ãã®ã¢ã¯ã·ã§ã³ã¯ãIBM PCã³ã³ãã¥ãŒã¿ãŒã§å®è¡ãããŠãããã¹ãŠã®ææ°ã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã§å®è¡ãããŸãã ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®æäœã«ãããæ¬¡ã®æé ã¯ããã©ã€ããŒãæ€çŽ¢ããèŠã€ãã£ãããã€ã¹ãæ§æããããšã§ããããã¯ãåããã€ã¹ã«å¯ŸããŠåå¥ã®æ¹æ³ã§æ¢ã«è¡ãããŠããŸãã