Internet Info, s.r.o. Lupa Měšec Podnikatel Root Zdroják DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Programujeme OS: řídíme textový režim VGA

V minulém díle našeho seriálu o programování operačního systému jsme si ukázali, jak se dá vytvořit základ k jádru operačního systému - dnes si objasníme již nakousnuté VGA pro textový režim a také některé nejasnosti, jež se objevily v diskuzi článku ohledně zavaděče GRUB a linkovacího skriptu.

Tweetni to Twitter Jaggni to! Jagg Del.icio.us Delicious

Naše jádro je nyní schopno vypsat text „Ahoj svete !“, současná implementace funkce print () bohužel ale nestačí, pokud chceme, aby se náš text nacházel na jiné pozici, pokud ho budeme chtít obarvit, nebo třeba vypisovat na obrazovce litanie – pomůže nám s tím již zmiňované VGA.

Co je to vlastně VGA?

Je to počítačový standard definující techniku zobrazení – standard, dle kterého se řídí všechny grafické karty pro architekturu x86, jednoduše řečeno nám říká, jak „něco“ zobrazit na obrazovce pomocí grafického adaptéru z dnešního pohledu nejprimitivnějším způsobem.

A jak to funguje?

Každé zobrazovací grafické zařízení (grafická karta) operuje s blokem paměti, do kterého přistupuje jak operační systém (ten zpravidla do bloku zapisuje), tak samotné zařízení (čte z bloku data). My musíme jakožto programátoři obstarat zápis – proto je nutné pochopit, v jakém tvaru se mají nacházet data a kde vůbec …

Ještě před samotným vysvětlováním si musíme objasnit, že se bavíme o textovém režimu – to proto, že existuje ještě tzv. grafický a je mezi nimi značný rozdíl. Vycházejme tedy z názvu, textový je schopen vypisovat pouze text, přesněji znaky – každý znak se skládá z bodů (pixelů), ty jsou uloženy v zásobnících hardwaru.

Jednotlivé znaky mají přiřazené svoje číslo dle dalšího standardu ASCII. Identifikační číslo znaku je definováno 8 bity, což je 1 byte. Pro nás to znamená, že řetězec „Ahoj svete !“ zabral v paměti 12 bytů. Pro naše účely je tedy vhodnější textový režim, který je automaticky přednastavený. Naneštěstí pro větší zmatek existují i samotné submódy, tj. několik pro textový a několik pro grafický režim. Všechny se od sebe liší především rozlišením – schopností vykreslovat větší či menší počet znaků na obrazovce, ale také možností použít různou škálu barev.

Jednotlivé režimy se dají nastavit pomocí tzv. přerušení BIOSu a nebo pomocí specifické sekvence dat zapsané na vyhrazenou adresu v paměti. Přednastavený textový režim má parametry 80×25 znaků, kde každému lze přiřadit jednu z 16 barev, 8 možných barev jako pozadí a jako poslední zajímavou „vymoženost“ – blikání. Barvy změnit nemůžeme, přesto věřím, že si s nimi většina vystačí; Každá má vlastní číslo a to následovně:0: černá, 1: modrá, 2: zelená, 3: azurová, 4: červená, 5: fialová, 6: hnědá, 7: světle šedá, 8: tmavě šedá, 9: světle modrá, 10: světle zelená, 11: světle azurová, 12: světle červená, 13: světle fialová, 14: žlutá, 15: bílá. Nyní si definujeme jak vypadá struktura pro zápis jednoho znaku:

Grafický režim je takový, kde můžeme vykreslovat kterýkoliv bod na obrazovce dle své libosti. V podstatě se jedná jen o nastavení barvy na určitém místě v paměti. Pokud bychom chtěli vykreslovat znaky, musíme si je sami všechny definovat, pixel po pixelu a dále napsat funkce schopné je vykreslovat.

/* Struktura jedné datové buňky dle VGA standardu (16bitů) */
typedef struct {
    unsigned char c;        /* znak (8bitů) */
    unsigned font_color : 4;    /* barva znaku (4bity) */
    unsigned bg_color : 3;      /* barva pozadí (3bity) */
    unsigned blink : 1;     /* blikáme ? (1bit) */
} __attribute__ ((__packed__)) vga_cell_t;

Vidíme, že má dohromady 2 byty (16 bitů) – barva znaku je definovaná čtyřmi bity, což je celkem 16 kombinací (0 až 15), barva pozadí pouze 3 bity což dává 8 kombinací (dle vztahu 2^n, kde n je počet bitů). Zajisté jste si všimli podivného atributu struktury __attribute__ ((__packed__)) , ten je velmi důležitý, neboť říká kompilátoru, aby nevytvářel tzv. boundary alignment. Jsou to pro programátora neviditelné úseky paměti mezi proměnnými, které mají různou velikost. Často se tvoří při definici počtu bitů proměnných. Pokud přidáme tento atribut, je vše přesně tak, jak je vidno ze struktury – v budoucnu tento poznatek využijeme také.

Nyní přišel čas na varování – některé emulátory nebo virtualizační nástroje nedodržují tak základní standard jako je VGA na 100 %, týká se to hlavně zmíněné barvy pozadí, kdy je chybně definováno, že se jedná o 4bitovou proměnnou, tzn. blikání zde není podporováno (nesplnila by se podmínka celkové velikosti 16 bitů), naopak je zde více barev. Lze si tento problém snadno ověřit mezi reálným PC a příkladně Qemu (zde je implementace chybná).

Nyní už víme, jak vypadá jedna buňka, zapisující se do celého pole video paměti. Takovýchto buněk musí být v našem případě 80×25, pro informaci náš paměťový blok se rovná 4000 bytům, tj. 2000 za sebou jdoucích struktur vga_cell_t. Pořád tady píšu o nějakém bloku, teď konkrétněji .. jedná se o paměťový blok, který se nachází v naprosté většině případů na adrese 0×b8000 (hexadecimální), je namapován prostřednictvím BIOSu na RAM a mezi nimi probíhají naše data.

Poznámka: U starších nebo exotičtějších desek se můžeme setkat s jinou adresou, v tomto případě bychom na obrazovce neviděli vůbec nic. Naštěstí existuje způsob, jak lze zjistit tu správnou – to už ale není pro nás tak podstatné.

Implementace

Využijeme jednoduché matematiky a spočítáme si, na jaké adrese bychom zapisovali např. znak ‚Z‘, pokud by to mělo být na 3. řádku a 5. sloupci. Zde je vzor pro výpočet spolu s typováním na strukturu vga_cell_t definující jednu buňku.

vga_cell_t *cell = (vga_cell_t *) vga.vid_mem + (vga.cursor_y * VGA_RES_X) + vga.cursor_x;

Výpočet vypadá následovně: adresa = 0×b8000 + [(3–1) * 80] + (5–1)

Z výpočtu je tedy zjevné, že musíme od bodů souřadnic odečíst 1, protože se začíná od 0. Na tuto adresu zapíšeme 1 byte – znak a hned za něj přidáme atributy. Toto celé realizuje funkce put_char () nacházející se v ukázkovém kódu (odkaz na konci článku).

Nalezneme tam i několik dalších funkcí, ty už ale obstarávají vyšší záležitosti (výpis řetězců, apod). Nebyla zde zmíněna ještě jedna věc – tou je hardwarový kurzor, není ničím jiným, než to, co známe jako blikající podtržítko. V kódu je obsažena funkce, pro přesun kurzoru. Pokud se na ní podíváte blíže, uvidíte také outb () starající se o zápis 1 bytu na zvolený port (adresu). Tato funkce se nachází v souboru utils.c napsaném v jazyce C, ale využívá možnost použití inline assembleru (ten má ale přednastavenou odlišnou syntaxi od překladače NASM zvanou AT&T).Tímto vás nechci dezorientovat, ale ukázat, že to jde udělat i jinak – cílem tohoto seriálu není vytvořit dokonalé jádro (popř. operační systém), ale ukázat možné cesty vývoje.

Odpovědi na některé otázky z minulé diskuze

GRUB je zavaděč, který svým způsobem ulehčuje práci vývojářům jádra, proto je docela vhodný i pro nás – před spuštěním samotného jádra přepne režim procesoru na tzv. chráněný režim, což dovoluje použít např. stránkování, virtuální paměť nebo bezpečnější multitasking.

Přesněji GRUB nastaví automaticky GDT tabulku, na jednu stranu je to užitečné, na druhou nebezpečné… Další dotaz byl na téma linkovacích skriptů – proč je tam nějaké code = .; _code = .; __code = .; nebo *(.data) a *(.rodata)  – ld má v oblibě přidávat mezi klasické sekce ELFích binárek i další, pro náš účel je to to nevhodné a právě takto napsaný linkovací skript sjednotí daný typ sekce v jeden (nakonec jsou tedy opravdu jen 4) a nastolí pořádek a jednoduchost.

TIB2012

       

Na závěr

Dnes zde byla především teorie – ale jak se říká – „bez teorie není praxe“ – to platí i obráceně. Po dnešku už bychom měli být schopni vypisovat téměř cokoliv a myslím, že se to na začátek docela hodí – bez toho, že si uděláte výpisy to jednoduše někdy nejde. Archív s ukázkovým zdrojovým kódem se dá stáhnout na ZeXOS.org.

Příští díl se bude zabývat chráněným módem, nastavením GDT a IDT – o přerušení nouze nebude.

Tomáš Jędrzejek

Autor je studentem VŠB FEI a pracuje na několika projektech jako např. operační systém ZeX/OS nebo hra Tuxánci.

Školení: TCP/IP síť na Linuxu II

V tomto školení prohloubíte svoji znalost síťování na Linuxu a vyzkoušíte si pokročilejší techniky. Školení je určené mimojiné i pro správce poskytovatelských sítí.

  • Průřez technologiemi TCP/IP 
  • Stavba testovací sítě
  • Dynamický routing: OSPFv2 a OSPFv3
  • Bridging, proxy ARP, proxy NDP
  • Různé metody překladu adres
  • NAT traversal v praxi
  • Přepis paketů
  • Tunelování a VPN
  • Troubleshooting, situace z praxe

Podrobnější informace a přihláška 

Ohodnoťte jako ve škole:
Průměrná známka 2,74

Přehled názorů

Re: Programujeme OS: řídíme textový režim VGA
D.A. Tiger 28. 7. 2009 00:18
Nový
└ 
Re: Programujeme OS: řídíme textový režim VGA
backup 28. 7. 2009 01:27
Nový
 
└ 
OT / Necist
restore 28. 7. 2009 03:53
Nový
Panelák v paměti
Mim 28. 7. 2009 07:29
Nový
└ 
Re: Panelák v paměti
vtech 28. 7. 2009 08:10
Nový
 
└ 
Re: Panelák v paměti
Dominik 28. 7. 2009 09:30
Nový
 
 
├ 
Re: Panelák v paměti
Tomáš Jędrzejek 28. 7. 2009 10:05
Nový
 
 
└ 
Re: Panelák v paměti
alblaho 28. 7. 2009 10:59
Nový
Blikani
Mi. Chal. 28. 7. 2009 09:44
Nový
Jedna chybicka
peto 28. 7. 2009 09:50
Nový
└ 
Re: Jedna chybicka
Tomáš Jędrzejek 28. 7. 2009 10:02
Nový
 
└ 
Re: Jedna chybicka
peto 28. 7. 2009 10:33
Nový
 
 
└ 
Re: Jedna chybicka
skriatok.sotek 28. 7. 2009 16:16
Nový
VGA: Zmena palety
Ogar 28. 7. 2009 10:16
Nový
└ 
Re: VGA: Zmena palety
Jirka Kosek 28. 7. 2009 11:08
Nový
Cooo?!?
Biktop 28. 7. 2009 10:23
Nový
├ 
Re: Cooo?!?
Tom B 28. 7. 2009 10:47
Nový
│
└ 
Re: Cooo?!?
Biktop 28. 7. 2009 12:01
Nový
├ 
Re: Cooo?!?
KareII 28. 7. 2009 11:01
Nový
└ 
Re: Cooo?!?
Tomáš Jędrzejek 28. 7. 2009 12:26
Nový
 
└ 
Re: Cooo?!?
povinná 1. 8. 2009 21:52
Nový
bitfields
Ondrej SanTiago Zajicek 28. 7. 2009 11:28
Nový
├ 
Re: bitfields
Tomáš Jędrzejek 28. 7. 2009 12:21
Nový
│
└ 
Re: bitfields
Ondrej Santiago Zajicek 28. 7. 2009 14:31
Nový
│
 
└ 
Re: bitfields
Tomáš Jędrzejek 28. 7. 2009 15:19
Nový
│
 
 
└ 
Re: bitfields
Ondrej SanTiago Zajicek 28. 7. 2009 21:18
Nový
└ 
Re: bitfields
koroptev 29. 7. 2009 08:42
Nový
 
├ 
Re: bitfields
Ondrej SanTiago Zajicek 29. 7. 2009 11:41
Nový
 
└ 
Re: bitfields
Jirka P 29. 7. 2009 11:44
Nový
funkce putch
xavier 28. 7. 2009 18:27
Nový
Výpočet adresy znaku
Wladows 28. 7. 2009 22:23
Nový
├ 
Re: Výpočet adresy znaku
šachy 28. 7. 2009 23:34
Nový
└ 
Re: Výpočet adresy znaku
Tomáš Jędrzejek 28. 7. 2009 23:45
Nový
moderni OS nespoleha na BIOS ani VESA, nepouziva 16bit mode a je psan nad…
Ochrana proti…e prosím 29. 7. 2009 00:33
Nový
├ 
Re: moderni OS nespoleha na BIOS ani VESA, nepouziva 16bit mode a je psan nad…
Tomáš Jędrzejek 29. 7. 2009 10:27
Nový
└ 
Re: moderni OS nespoleha na BIOS ani VESA, nepouziva 16bit mode a je psan nad…
Biktop 29. 7. 2009 10:37
Nový
codeproject - clanek mesice
who cares 29. 7. 2009 06:10
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem