int21h

Spouštění textových aplikací pod grafickým OS

Po delší době jsem si našel čas napsat (na dlouhou dobu zase jediný - a krátký) článek. Tentokrát se budeme více méně teoreticky věnovat tomu, jak spouštět textové aplikace pod grafickým operačním systémem, nebo nějakou nadstavbou. Následující článek není vůbec vyčerpávající a spíše by měl sloužit jen k počátečnímu zamyšlení. Vůbec bych se proto nezlobil, kdyby ho někdo jako spoluautor dopsal.

Minule jsme se naučili programovat multimediální aplikace a také základy pro operační systém. Pokud v něm budete využívat GUI (tedy okna, atd.), můžete si pro něj napsat aplikace, které poběží tak, aby zobrazovaly v souladu s OS (tedy předají data jemu přes nějaký ukazatel a teprve on je vykreslí, až to bude potřeba - sama aplikace si tedy kreslí do svého prostoru v RAM). Když spustíte cizí grafickou aplikaci (např. hru Doom) pro DOS, je nutné se smířit s tím, že pokud nebudete chtít odchytávat všechny její instrukce a zjišťovat, jak je emulovat (aby nezapisovala do VRAM; emulace vlastně spočívá v tom, že sice EXE soubor nahrajete, ale řízení mu nepředáte - namísto toho jej procházíte instrukci po instrukci a vykonáváte; popř. ještě můžete využívat DEBUG funkci CPU, nebo ochrany a práva přístupu, výjimky, atd.), a tím ji zpomalovat (cca. na 40% původní rychlosti), tak Vám aplikace Vaše rozlišení, zvuky, a všechno zruší a bude si přistupovat do VRAM a ke všemu sama (popř. přes ovladače na zvuk). Resp. se asi dnes těžko najde hra, která pixely poslušně vykresluje přes INT 10h. Emulace by sice byla možná, ale dost těžká (musíte znát všechny instrukce) a jak vidíte, ne vždy se to povede (Windows XP a DOSové aplikace s VESA, či stále ještě ne dokončený a pomalý DOSbox). Po ukončení aplikace musíte tedy obnovit znovu rozlišení a obsah VVRAM na adrese $a000, resp. u LFB, pokud ho používáte.

Dobře, to nejsou zrovna moc extra vyhlídky, ale co třeba taková textová aplikace? Ta je na tyto věci jednodušší. Ovšem jedná se jen o ty textové aplikace, které se moc nevrtají v registrech grafických karet (pokud to aplikace dělá, musíte ji zahrnout do prvního případu a celou emulovat, včetně registrů karty, čímž se z Vás stane DOSbox). Prostě něco na způsob: pomocí INT 10h s AX=3 nahodím textový režim a pak už kreslím jen přes MEM do $b800:0, popř. si ještě přepínám stránky. Je jasné, že nemusí být jednoduché takovou aplikaci najít, ale většina základních DOSových prográmků toto splňuje. Celý trik spočívá v tom, že se pověsíte na přerušení INT 10h a budete sledovat nastavování režimů (popř. i to přepínání stránek). Pokud se nějaká aplikace pokusí o změnu na textový režim, Vy toto neprovedete, ale vrátíte kladný výsledek operace. Aplikace by pak v ideálním případě měla kreslit pomocí MEM na 4 kB velké okno od adresy $b800:0. U Vás je vyžadováno běžet na pozadí (buď na časovači nebo s pomocí CPU multitaskingu) a v určitých intervalech si přečíst obsah textové VRAM. Pokud se od minule změnil, přišla Vaše chvíle ho vykreslit pomocí grafiky do nějakého okna. Stále si musíte hlídat, aby aplikace po svém spuštění nenahodila grafický režim, čímž by se z ní stal první případ (ovšem zase je nutné vědět, až ho aplikace shodí a přitom stále poběží, čímž se přepne do druhého). Vaše procedury by mohly vypadat nějak takto:

var	PuvodniVektor : pointer;
	VRAM,VRAM2 : array[0..24,0..79] of word;
	{je samozřejmě nutné počítat i s dalšími režimy, hlavně u VESA}
	TextovyRezim : boolean;
	Stranka : word;


{tuto funkci volat v určitých časových intervalech}
procedure VykresleniVRAM; far;
var x,y : longint;
begin
 Move(Ptr($b800,SizeOf(VRAM)*Stranka)^,VRAM,SizeOf(VRAM));
 for y := 0 to 24 do
  for x := 0 to 79 do
   if VRAM[y,x] <> VRAM2[y,x] then
   begin
    {tady vykreslit text pomocí pixelů do grafického okna}
   end;
end;


{pro rychlejší vykonání je vhodné to napsat jako ASM do další procedury}
procedure VymazVRAM;
begin
 FillChar(Ptr($b800,SizeOf(VRAM)*Stranka)^,SizeOf(VRAM),0);
end;


procedure ObsluhaINT10h; far; assembler;
asm
	cmp	ax,3		{nastavení textového video režimu}
	jne	@dalsi
	mov	TextovyRezim,true
	cmp	ax,127
	ja	@konec
	call	VymazVRAM
	{kdychom ošetřovali i VESA, tak musíme v AX vrátit $4f}
	ret
@dalsi:
	cmp	ah,5		{nastavení video stránky}
	jne	@puvodni
	xor	ah,ah
	mov	stranka,ax	{otázka je, zda je toto nutné emulovat: pokud si podle}
@konec:				{stránky jen nastaví karta offset, tuto pasáž zrušit!}
	ret
@puvodni:
	mov	TextovyRezim,false
	jmp	puvodnivektor
end;


procedure PoveseniINT10h;
begin
 GetIntVec($10,PuvodniVektor);
 SetIntVec($10,@ObsluhaINT10h);
end;


procedure ObnovaINT10h;
begin
 SetIntVec($10,PuvodniVektor);
end;


procedure SpusteniAplikace(Cesta : string);
begin
 PoveseniINT10;
 SwapVectors;
 Stranka := 0;
 Move(Ptr($b800,0)^,VRAM2,SizeOf(VRAM2));
 TextovyRezim := False;
 Exec(Cesta,'');
 _WaitUntilTerminate;
 SwapVectors;		{pokud napíšete Váš OS v assembleru, toto samozřejmě odpadá}
 ObnovaINT10h;
end;  

Příklad je psán pro snažší pochopení v Pascalu, ale je jasné, že ho nelze použít, protože Váš OS bude s největší pravděpodobností psán v assembleru, kde podobné funkce nenajdete. Navíc EXEC je DOSová funkce a nepodporuje multitasking.

Samozřejmě fór je v tom, že pokud má být Váš OS stále provozu schopný, musíte zachytávat i myš a klávesnici. U té klávesnice to není až takový problém (stačí nějak zařídit, abyste byli u u přerušení INT 9 jako první. Aplikace může ale Váš vektor přepsat. V tom případě musíte neustále kontrolovat, zda na INT 9 je ještě Váš původní vektor - a když ne, ten starý si zapsat a vložit tam svůj. No jo, ale co když ho aplikace obnoví a už nebude chtít, aby někdo volal tu její obsluhu? Jiným řešením by bylo neustále číst frontu kláves a být u nich tedy vždy první, a pokud se fronta změnila, klávesu si převzít (nebo ponechat v bufferu, pokud není určena nám)), ale co myš? Ano, můžeme se pověsit na vektor myši nebo číst přímo sériový port, čímž získáme jisté údaje, ale co když aplikace bude chtít číst myš také? Ta totiž předpokládá, že jsme v textovém režimu, zatímco my jedeme stále v grafickém... Ale prrr! Není potřeba se věšet. Nezapomínejte, že jedeme pod naším vlastním OS! Ten přeci využívá svůj vlastní ovladač, takže na INT 33h můžeme hodit něco, co bude emulovat ten DOSový, a tedy můžeme vracet souřadnice i pro textový režim (navíc jen v rámci okna!). Alespoň něco se nám podařilo vyřešit. Pak je tu zvuková karta. Pokud má mít program výhradní režim, bude vhodné ji vypnout, aby k ní mohl přistupovat sám. V opačném případě ho zase musíte plně emulovat, abyste to, co on domněle posílá na porty karty přes DMA, mohli zachytávat a mixovat do svých kanálů ručně.

To by byly DOSové aplikace. Nejjednodušší je samozřejmě nic takového neemulovat (což by byla škoda, neboť napsat si dneska OS je jednoduché, dát mu GUI sice složitější, ale stále zvládnutelné, nicméně OS musí mít to hlavní - využitelnost - a tu mu dodává spousta použitelných a hlavně zajímavých aplikací; k čemu je např. firmám dost dobrý OS Linux, i když zadarmo, když v něm ve většině případů nefunguje Corel Draw, ve kterém spousta lidí posílá grafické podklady?), nebo předat aplikaci plné řízení a naemulovat jen INT 33h a 21h, popř. další (XMS, EMS), které jsou potřeba. Aplikace může zlividovat tak maximálně obsah paměti RAM (ale na to jsou lidé z Windows zvyklí a pokud aplikace fungovala dobře pod DOSem, jistě poběží dobře i tady - alespoň po většinu času; to, že to občas shodí OS, bude malá daň za to, že půjde maximálně rychle a hlavně u her i se zvukem). Emulovat aplikace Windows je o něco jednodušší, protože ty už počítají s tím, že nad nimi "něco" jede a tedy využívají jakési GUI API (ale zase jsou tu DLL). A to je zatím všechno...

2006-12-06 | Martin Lux
Reklamy:
„Žití, to je největší umění na světě, neboť většina lidí pouze existuje.“ Oscar Wilde