JamesM's kernel development tutorials - 2. díl
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

JamesM's kernel development tutorials - 2. dílJamesM's kernel development tutorials - 2. díl

 
Hledat
Moderní platforma pro vytvoření vašeho nového webu – Wix.com.
Nyní už můžete mít web zdarma.
Vybavení pro Laser Game
Spuštěn Filmový magazín

JamesM's kernel development tutorials - 2. díl

Google       Google       18. 2. 2009       12 666×

Genesis
Překlad tutoriálů pro začínající OS vývojáře od Jamese Molloye (www.jamesmolloy.co.uk).

Reklama
Reklama

Chtěl bych poděkovat Jamesi Molloyovi, který mi dovolil jeho tutoriál(y) přeložit. Tuším, že se tak stanou vůbec prvními svého druhu na českém Internetu.

Kontakt na autora:

  • www.jamesmolloy.co.uk - autorův "internetový domov", najdete zde jednak tutoriály v originálním anglickém podání, jednak "Jimix" - jádro psané v C++
  • james<at>jamesmolloy.co.uk - emaily na tuto adresu pište prosím POUZE v angličtině

OK, přišel čas kódit! Ačkoli hlavní část jádra bude napsána v C, v určitých oblastech se bez assembleru zkrátka neobejdeme. Jedním z těchto případů je počáteční bootovací kód.

Tady ho máme:

;
; boot.s -- Startovní pozice jádra. Rovněž definuje multiboot hlavičku.
; Založeno na Bran's kernel development tutorial souboru start.asm
;

MBOOT_PAGE_ALIGN    equ 1<<0    ; Nahraje jádro a moduly na začátek stránky
MBOOT_MEM_INFO      equ 1<<1    ; Poskytne jádru informace o paměti
MBOOT_HEADER_MAGIC  equ 0x1BADB002 ; hodnota Multiboot Magic
; POZNÁMKA: Nepoužíváme MBOOT_AOUT_KLUDGE. To znamená, že nám GRUB 
; nepředá tabulku symbolů.
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)


[BITS 32]                       ; Všechny instrukce by měli být 32-bitové

[GLOBAL mboot]                  ; Zpřístupní 'mboot' z C.
[EXTERN code]                   ; Start '.text' sekce.
[EXTERN bss]                    ; Start .bss sekce.
[EXTERN end]                    ; Konec poslední načítané sekce.

mboot:
  dd  MBOOT_HEADER_MAGIC        ; GRUB bude hledat tuto hodnotu na
                                ; začátku každé stránky jádra
  dd  MBOOT_HEADER_FLAGS        ; Jak by měl GRUB nahrát váš soubor / nastavení
  dd  MBOOT_CHECKSUM            ; Zaručí, že jsou horní hodnoty správné.
   
  dd  mboot                     ; Pozice tohoto deskriptoru.
  dd  code                      ; Začátek sekce '.text' (kód).
  dd  bss                       ; Konec sekce '.data'.
  dd  end                       ; Konec jádra.
  dd  start                     ; Vstupní bod jádra (počáteční EIP).

[GLOBAL start]                  ; Vstupní bod jádra.
[EXTERN main]                   ; Vstupbní bod pro kód v C

start:
  push    ebx                   ; Předá pozici multiboot hlavičky

  ; Spuštění jádra:
  cli                         ; Zakáže přerušení.
  call main                   ; Zavolá naši funkci main().
  jmp $                       ; Vstoupíme do nekonečné smyčky, abychom zabránili
                              ; procesoru ve spouštění všelijakého bordelu nacházejícího se
                              ; v paměti za jádrem! 

Je tam vlastně jen pár řádků kódu:

push ebx
cli
call main
jmp $

To ostatní je multiboot hlavička.

Multiboot

GRUB předpokladá, že jádro dodržuje multiboot standard. Je to způsob, jakým může bootloader

  1. přesně zjistit, jaké prostředí bude jádro při zavádění potřebovat/požadovat
  2. poskytnout jádru informace o prostředí, které si pro něj připravil

Takže například pokud se bude vaše jádro potřebovat načíst ve specifickém VESA módu (což je mimochodem špatný nápad), informujete bootloader a on se už o to postará za vás.

Aby bylo jádro multiboot-kompatibilní, musíte do něj někam umístit multiboot hlavičku (přesněji, hlavička musí tvořit první 4KB jádra). Existuje NASM příkaz, který do kódu vloží potřebné konstanty - dd.

dd MBOOT_HEADER_MAGIC
dd MBOOT_HEADER_FLAGS
dd MBOOT_CHECKSUM
dd mboot
dd code
dd bss
dd end
dd start

Konstanty MBOOT_* jsme definovali na začátku.

MBOOT_HEADER_MAGIC
Magické číslo. Značí, že je jádro multiboot-kompatibilní.

MBOOT_HEADER_FLAGS
Pole příznaků. Požádáme GRUB o zarovnaní každé sekce jádra (MBOOT_PAGE_ALIGN) a informace o paměti (MBOOT_MEM_INFO). V některých tutoriálech je použito také MBOOT_AOUT_KLUDGE. Jelikož my používáme formát ELF, tento hack není potřeba a jeho přidání by zabránilo GRUBu v předání tabulky symbolů při startu.

MBOOT_CHECKSUM
Slouží k detekci chyb. Součet magic number, příznaků a této hodnoty musí být nula.

mboot
Adresa struktury, kterou právě píšeme.

code,bss,end,start
Tyto symboly definuje linker. Pomocí nich předáváme GRUBu pozici jednotlivých sekcí jádra.

Při startu GRUB do registru EBX uloží ukazatel na strukturu, ve které se nacházejí informací o prostředí, které pro nás připravil.

Zpátky ke kódu...

Bezprostředně po startu povíme CPU, aby přidal obsah EBX na stack (v EBX se nyní nachází ukazatel na multiboot informační strukturu), zakázal přerušení (CLI), zavolal naši main funkci (kterou jsme zatím nedefinovali) a vstoupil do nekonečné smyčky.

To všechno je sice moc pěkné, ale kód se neslinkuje. Nemáme definovanou main()!

Přidání trošky Céčkovského kódu

Propojování C a ASM je neuvěřitelně jednoduché. Stačí znát použitou "volací dohodu". GCC na architektuře x86 používá konvenci __cdecl:

  • Všechny parametry jsou funkci předávány přes stack.
  • Parametry jsou přidávány zprava doleva.
  • Návratová hodnota funkce se nachází v EAX.

...takže volání funkce:

d = func(a, b, c);

vypadá takto:

push [c]
push [b]
push [a]
call func
mov [d], eax

Nic na tom není! Jak můžete vidět v ASM kódu výše, to push ebx vlastně jen předává hodnotu EBX jako parametr funkci main().

C kód

// main.c -- definuje vstupní bod C kódu, provádí inicializaci
// JamesM's tutorials

int main(struct multiboot *mboot_ptr)
{
  // tady budeme volat všechny inicializační funkce
  return 0xDEADBABA;
}

Takhle tedy vypadá naše první funkce main(). Jak můžete vidět, funkci je předán jeden parametr - ukazatel na multiboot strukturu. Tu si definujeme později (nepotřebujeme ji definovat k úspěšné kompilaci!).

Vše, co funkce dělá, je navrácení konstanty - 0xDEADBABA. Ta je snad dost neobvyklá, abychom si ji všimli, až program za chvilku spustíme.

Kompilování, linkování a spuštění!

Teď, když jsme do našeho projektu přidali nový soubor, musíme ho přidat i do makefile. Tyto řádky:

SOURCES=boot.o
CFLAGS=

nahraďte za:

SOURCES=boot.o main.o
CFLAGS=-nostdlib -nostdinc -fno-builtin -fno-stack-protector

Musíme zastavit GCC, který se bude snažit přilinkovat linuxové C knihovny k našemu jádru - nebude to fungovat (zatím). K tomu slouží CFLAGS.

OK, teď byste měli být schopni zkompilovat, slinkovat a spustit vaše jádro!

cd src
make clean  # Ignorujte jakékoli chyby, které tu nastanou
make
cd ..
./update_image.sh
./run_bochs.sh  # Možná budete vyzvání k zadání root hesla

To by mělo spustit bochs. Pár sekund uvidíte GRUB, následně se spustí samotné jádro, které vlastně neudělá nic jiného, než zamrzne s hláškou "starting up...".

Jestliže si prohlédnete bochsout.txt, vespod byste měli uvidět něco podobného:

00074621500i[CPU  ] | EAX=deadbaba  EBX=0002d000  ECX=0001edd0 EDX=00000001
00074621500i[CPU  ] | ESP=00067ec8  EBP=00067ee0  ESI=00053c76 EDI=00053c77
00074621500i[CPU  ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
00074621500i[CPU  ] | SEG selector     base    limit G D
00074621500i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
00074621500i[CPU  ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00074621500i[CPU  ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00074621500i[CPU  ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00074621500i[CPU  ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00074621500i[CPU  ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00074621500i[CPU  ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00074621500i[CPU  ] | EIP=00100027 (00100027)
00074621500i[CPU  ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00074621500i[CPU  ] | CR3=0x00000000 CR4=0x00000000
00074621500i[CPU  ] >> jmp .+0xfffffffe (0x00100027) : EBFE

Všimli jste si hodnoty EAX? 0xDEADBABA - návratová hodnota main(). Gratuluji, už máte multiboot-kompatibilní "trampolínu", a tak vám nic nebrání začít psát na obrazovku!

Vzorový kód tutoriálu naleznete zde.

Zdroj: http://www.jamesmolloy.co.uk/tutorial_html/2.-Genesis.html

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

3 názory  —  3 nové  
Hlasování bylo ukončeno    
0 hlasů
Google
Autor obstojně ovládá PHP a C/C++, zajímají ho operační systémy, umělá inteligence, hry a počítačová bezpečnost. Miluje dobré jídlo, pití a dostatek spánku. Mezi jeho další koníčky patří psychologie, hra na klavír či létání.

Nové články

Reklama
Reklama
Obrázek ke článku NopCommerce – datová vrstva a přístup k datům – 2. díl

NopCommerce – datová vrstva a přístup k datům – 2. díl

V minulém článku jsme si představili platformu NopCommerce z globálního pohledu. V dnešním díle se již zaměříme na konkrétní část systému, a to datovou vrstvu. Představíme si základní stavební kameny systému v podobě doménových objektů. Ukážeme si, jakým způsobem rozšířit doménové objekty a jakým způsobem přistupuje NopCommerce k nastavení systému a modulů.

Obrázek ke článku Seznamte se s open source platformou NopCommerce – 1. díl

Seznamte se s open source platformou NopCommerce – 1. díl

Hledáte e-commerce řešení, které si dokážete přizpůsobit podle vašich požadavků? Chcete čistý a srozumitelný kód, se kterým bude radost pracovat? Prozkoumejte s námi možnosti open source projektu NopCommerce. Seriál programování pod NopCommerce vám pomůže překonat první kroky nejistoty a úspěšně zvládnout vývoj pod platformou NopCommerce.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032017 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý