Emulazione di Linus Torvalds: crea il tuo sistema operativo da zero (II)

Benvenuti in un altro post su come creare il nostro sistema operativo, in questo caso NextDivel.

Se torniamo al codice di primo post alla fine di tutto avremmo dovuto inventare qualcosa del genere:

SuccessivoDivel-1

Se è corretto possiamo continuare. Userò il sistema e la struttura che ho su GitHub (http://github.com/AdrianArroyoCalle/next-divel) in quanto è più comodo per me e per te. Come puoi vedere il testo è un testo di base, non è attraente. Può sembrare qualcosa fuori dall'ordinario. Ma come dice il proverbio, per assaporare i colori, e nel nostro sistema operativo ci saranno i colori. I primi colori che potremo mettere saranno quelli che definiscono le schede VGA e sono 0:

  1. Nero
  2. blu
  3. Verde
  4. Ciano
  5. rosso
  6. Magenta
  7. marrone
  8. grigio chiaro
  9. grigio scuro
  10. Light Blue
  11. verde chiaro
  12. Ciano chiaro
  13. Rosso chiaro
  14. Magenta chiaro
  15. Marrone chiaro
  16. Bianco

Definiremo questi colori in un'intestazione per averlo più a portata di mano e forse in futuro diventerà parte dell'API di sistema. Quindi creiamo il file ND_Colors.hpp in NextDivel include.

#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

Allo stesso tempo definiremo nuove funzioni per scrivere sullo schermo in un modo più comodo (no, non implementeremo ancora printf, so che lo vuoi). Creeremo un file e la sua intestazione per una serie di funzioni relative allo schermo (ND_Screen.cpp e ND_Screen.hpp). In esse creeremo funzioni per: cambiare il colore delle lettere e dello sfondo, scrivere frasi e lettere, pulire lo schermo e spostarsi sullo schermo. Continuiamo a utilizzare gli schermi VGA ma ora useremo alcuni byte che daranno il colore. ND_Screen.cpp sarebbe simile a:

/**
* @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;
}

L'intestazione sarà molto semplice quindi non la includo qui, ma evidenzierò la definizione del tipo 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).

Per verificare se questo codice funziona, modificheremo il punto di ingresso C del kernel:

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");

E se seguiamo questi passaggi otterremmo questo risultato

SuccessivoDivel-3

Grazie a queste funzioni che abbiamo creato, possiamo iniziare a realizzare piccole GUI, come un kernel panic che mostreremo ogni volta che si verifica un errore irreversibile. Qualcosa come questo:

SuccessivoDivel-4

E questa piccola GUI l'abbiamo realizzata solo con queste funzioni:

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);
}

E fino a qui il post. Ti ricordo le istruzioni per compilare il sistema da 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

E colgo l'occasione per ringraziarvi per l'ottima accoglienza che ha avuto il primo post.


Lascia un tuo commento

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati con *

*

*

  1. Responsabile dei dati: Miguel Ángel Gatón
  2. Scopo dei dati: controllo SPAM, gestione commenti.
  3. Legittimazione: il tuo consenso
  4. Comunicazione dei dati: I dati non saranno oggetto di comunicazione a terzi se non per obbligo di legge.
  5. Archiviazione dati: database ospitato da Occentus Networks (UE)
  6. Diritti: in qualsiasi momento puoi limitare, recuperare ed eliminare le tue informazioni.

  1.   f3niX suddetto

    Eccellente amico, anche così sto uccidendo il mio casco comprendendo il codice in c ++.

    Saluti.

  2.   pandacris suddetto

    questi articoli sono fantastici. Ancora una volta hanno stuzzicato la mia curiosità per le prestazioni di basso livello dei processori.
    forse, se avrò tempo, inizierò a giocare con next-divel.
    Non invio un articolo da molto tempo. già necessario

  3.   Jon si nasconde suddetto

    Va bene, è così.

  4.   Miguel suddetto

    Desideravo da tempo sapere come costruire un sistema operativo.

    Aspettando il tuo prossimo post. Saluti

  5.   Giuliano suddetto

    Grande amico!
    Ho solo un problema, qualcuno può passarmi un file C di questo esempio?
    Mi invia sempre errori nel terminale