Emulace Linuse Torvaldse: Vytvořte si svůj vlastní operační systém od nuly (II)

Vítejte v dalším příspěvku o tom, jak vytvořit vlastní operační systém, v tomto případě NextDivel.

Pokud se vrátíme ke kódu první příspěvek na konci všeho jsme měli přijít s něčím takovým:

DalšíDivel-1

Pokud je to správné, můžeme pokračovat. Budu používat systém a strukturu, kterou mám na GitHubu (http://github.com/AdrianArroyoCalle/next-divel) protože je to pro mě i pro vás pohodlnější. Jak vidíte, text je základní text, není atraktivní. Může se to zdát jako něco neobvyklého. Ale jak se říká, ochutnat barvy a v našem operačním systému budou barvy. První barvy, které budeme moci dát, budou ty, které definují VGA karty a jsou 0:

  1. Černý
  2. Azul
  3. zelená
  4. Azurová
  5. Rojo
  6. Magenta
  7. Brown
  8. Světle šedá
  9. Tmavě šedá
  10. Světle modrá
  11. Světle zelená
  12. Azurová jasná
  13. Světle červená
  14. Světle purpurová
  15. Světle hnědá
  16. Blanco

Budeme definovat tyto barvy v záhlaví, abychom to měli praktičtější a možná se v budoucnu staneme součástí systémového API. Takže v souboru NextDivel vytvoříme soubor ND_Colors.hpp.

#ifndef ND_COLOR_HPP
#define ND_COLOR_HPP
typedef enum ND_Color{
ND_COLOR_BLACK = 0,
ND_COLOR_BLUE = 1,
ND_COLOR_GREEN = 2,
ND_COLOR_CYAN = 3,
ND_COLOR_RED = 4,
ND_COLOR_MAGENTA = 5,
ND_COLOR_BROWN = 6,
ND_COLOR_LIGHT_GREY = 7,
ND_COLOR_DARK_GREY = 8,
ND_COLOR_LIGHT_BLUE = 9,
ND_COLOR_LIGHT_GREEN = 10,
ND_COLOR_LIGHT_CYAN = 11,
ND_COLOR_LIGHT_RED = 12,
ND_COLOR_LIGHT_MAGENTA = 13,
ND_COLOR_LIGHT_BROWN = 14,
ND_COLOR_WHITE = 15
} ND_Color;
#endif

Zároveň budeme definovat nové funkce pro pohodlnější psaní na obrazovku (ne, zatím nebudeme implementovat printf, vím, že to chcete). Vytvoříme soubor a jeho záhlaví pro sadu funkcí souvisejících s obrazovkou (ND_Screen.cpp a ND_Screen.hpp). V nich vytvoříme funkce pro: změnu barvy písmen a pozadí, psaní vět a písmen, čištění obrazovky a pohyb po obrazovce. Pokračujeme v používání obrazovek VGA, ale nyní použijeme několik bajtů, které dají barvu. ND_Screen.cpp bude vypadat takto:

/**
* @file ND_Screen.cpp
* @author Adrián Arroyo Calle
* @brief Implements four easy functions for write strings directly
*/
#include <ND_Types.hpp>
#include <ND_Color.hpp>
#include <ND_Screen.hpp>
uint16_t *vidmem= (uint16_t *)0xB8000;
ND_Color backColour = ND_COLOR_BLACK;
ND_Color foreColour = ND_COLOR_WHITE;
uint8_t cursor_x = 0;
uint8_t cursor_y = 0;
/**
* @brief Gets the current color
* @param side The side to get the color
* */
ND_Color ND::Screen::GetColor(ND_SIDE side)
{
if(side==ND_SIDE_BACKGROUND){
return backColour;
}else{
return foreColour;
}
}
/**
* @brief Sets the color to a screen side
* @param side The side to set colour
* @param colour The new colour
* @see GetColor
* */
void ND::Screen::SetColor(ND_SIDE side, ND_Color colour)
{
if(side==ND_SIDE_BACKGROUND)
{
backColour=colour;
}else{
foreColour=colour;
}
}
/**
* @brief Puts the char on screen
* @param c The character to write
* */
void ND::Screen::PutChar(char c)
{
uint8_t attributeByte = (backColour << 4) | (foreColour & 0x0F);
uint16_t attribute = attributeByte << 8; uint16_t *location; if (c == 0x08 && cursor_x) { cursor_x--; }else if(c == '\r') { cursor_x=0; }else if(c == '\n') { cursor_x=0; cursor_y=1; } if(c >= ' ') /* Printable character */
{
location = vidmem + (cursor_y*80 + cursor_x);
*location = c | attribute;
cursor_x++;
}
if(cursor_x >= 80) /* New line, please*/
{
cursor_x = 0;
cursor_y++;
}
/* Scroll if needed*/
uint8_t attributeByte2 = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F);
uint16_t blank = 0x20 /* space */ | (attributeByte2 << 8); if(cursor_y >= 25)
{
int i;
for (i = 0*80; i < 24*80; i++)
{
vidmem[i] = vidmem[i+80];
}
// The last line should now be blank. Do this by writing
// 80 spaces to it.
for (i = 24*80; i < 25*80; i++)
{
vidmem[i] = blank;
}
// The cursor should now be on the last line.
cursor_y = 24;
}
}
/**
* @brief Puts a complete string to screen
* @param str The string to write
* */
void ND::Screen::PutString(const char* str)
{
int i=0;
while(str[i])
{
ND::Screen::PutChar(str[i++]);
}
}
/**
* @brief Cleans the screen with a color
* @param colour The colour to fill the screen
* */
void ND::Screen::Clear(ND_Color colour)
{
uint8_t attributeByte = (colour /*background*/ << 4) | (15 /*white - foreground*/ & 0x0F);
uint16_t blank = 0x20 /* space */ | (attributeByte << 8);
int i;
for (i = 0; i < 80*25; i++)
{
vidmem[i] = blank;
}
cursor_x = 0;
cursor_y = 0;
}
/**
* @brief Sets the cursor via software
* @param x The position of X
* @param y The position of y
* */
void ND::Screen::SetCursor(uint8_t x, uint8_t y)
{
cursor_x=x;
cursor_y=y;
}

Záhlaví bude velmi základní, takže jej sem nezahrnuji, ale zvýrazním definici typu ND_SIDE

typedef enum ND_SIDE{
ND_SIDE_BACKGROUND,
ND_SIDE_FOREGROUND
} ND_SIDE;

También mencionar que hacemos uso del header ND_Types.hpp, este header nos define unos tipos básicos para uint8_t, uint16_t, etc basado en los char y los int. Realmente este header es el en el estándar C99 y de hecho mi ND_Types.hpp es un copia/pega del archivo desde Linux, así que podeis intercambiarlos y no pasaría nada (solo hay definiciones, ninguna función).

Abychom otestovali, zda tento kód funguje, upravíme vstupní bod C jádra:

ND::Screen::Clear(ND_COLOR_WHITE);
ND::Screen::SetColor(ND_SIDE_BACKGROUND,ND_COLOR_WHITE);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("NextDivel\n");
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BLACK);
ND::Screen::PutString("Licensed under GNU GPL v2");

A pokud budeme postupovat podle těchto kroků, dosáhneme tohoto výsledku

DalšíDivel-3

Díky těmto funkcím, které jsme vytvořili, můžeme začít vytvářet malé GUI, například paniku jádra, kterou ukážeme pokaždé, když dojde k neodstranitelné chybě. Něco takového:

DalšíDivel-4

A toto malé GUI jsme zvládli pouze s těmito funkcemi:

void ND::Panic::Show(const char* error)
{
ND::Screen::Clear(ND_COLOR_RED);
ND::Screen::SetColor(ND_SIDE_BACKGROUND, ND_COLOR_WHITE);
ND::Screen::SetColor(ND_SIDE_FOREGROUND, ND_COLOR_RED);
ND::Screen::SetCursor(29,10); //(80-22)/2
ND::Screen::PutString("NextDivel Kernel Error\n");
ND::Screen::SetCursor(15,12);
ND::Screen::PutString(error);
}

A tady příspěvek. Připomínám vám pokyny ke kompilaci systému z 0:

git clone http://github.com/AdrianArroyoCalle/next-divel
cd next-divel
mkdir build && cd build
cmake ..
make
make DESTDIR=next install
chmod +x iso.sh
./iso.sh
qemu-system-i386 nextdivel.iso

A při této příležitosti vám děkuji za vynikající přijetí, které měl první příspěvek.


Zanechte svůj komentář

Vaše e-mailová adresa nebude zveřejněna. Povinné položky jsou označeny *

*

*

  1. Odpovědný za údaje: Miguel Ángel Gatón
  2. Účel údajů: Ovládací SPAM, správa komentářů.
  3. Legitimace: Váš souhlas
  4. Sdělování údajů: Údaje nebudou sděleny třetím osobám, s výjimkou zákonných povinností.
  5. Úložiště dat: Databáze hostovaná společností Occentus Networks (EU)
  6. Práva: Vaše údaje můžete kdykoli omezit, obnovit a odstranit.

  1.   f3niX řekl

    Výborný přítel, i tak zabíjím helmu tím, že rozumím kódu v c ++.

    Zdravím.

  2.   pandacriss řekl

    tyto položky jsou skvělé. znovu vzbudili mou zvědavost ohledně nízkoúrovňového výkonu procesorů.
    Možná, když budu mít čas, začnu hrát s next-divel.
    Dlouho jsem neposlal článek. již potřeba

  3.   Jon se hrabá řekl

    Dobře, tak to je.

  4.   Miguel řekl

    Dlouho jsem chtěl vědět, jak vybudovat operační systém.

    Čekání na váš další příspěvek. Na zdraví

  5.   Giuliano řekl

    Skvělý kamarád!
    Mám jen jeden problém, může mi někdo předat soubor C tohoto příkladu?
    Vždy mi pošle chyby v terminálu