Emulowanie Linusa Torvaldsa: Stwórz swój własny system operacyjny od podstaw (II)

Witamy w kolejnym poście o tym, jak stworzyć własny system operacyjny, w tym przypadku NextDivel.

Jeśli wrócimy do kodu pierwszy post na koniec wszystkiego powinniśmy wymyślić coś takiego:

DalejDivel-1

Jeśli to prawda, możemy kontynuować. Użyję systemu i struktury, które mam na GitHubie (http://github.com/AdrianArroyoCalle/next-divel), ponieważ jest to wygodniejsze dla mnie i dla Ciebie. Jak widać tekst jest tekstem podstawowym, nie jest atrakcyjny. To może wydawać się czymś niezwykłym. Ale jak to się mówi, aby posmakować kolorów, aw naszym systemie operacyjnym będą kolory. Pierwsze kolory, które będziemy w stanie umieścić, będą tymi, które definiują karty VGA i jest ich 0:

  1. Czarny
  2. Azul
  3. Zielony
  4. Cyan
  5. Czerwony
  6. Magenta
  7. brązowy
  8. Jasnoszary
  9. Ciemny szary
  10. Jasnoniebieski
  11. Jasnozielony
  12. Cyjan przezroczysty
  13. Jasnoczerwony
  14. Jasnopurpurowy
  15. Jasny brąz
  16. Blanco

Zamierzamy zdefiniować te kolory w nagłówku, aby były bardziej przydatne i być może w przyszłości staną się częścią systemowego API. Więc tworzymy plik ND_Colors.hpp w dołączeniu NextDivel.

#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

Jednocześnie zamierzamy zdefiniować nowe funkcje do wygodniejszego pisania na ekranie (nie, nie zamierzamy jeszcze implementować printf, wiem, że tego chcesz). Utworzymy plik i jego nagłówek dla zestawu funkcji związanych z ekranem (ND_Screen.cpp i ND_Screen.hpp). W nich stworzymy funkcje do: zmiany koloru liter i tła, pisania fraz i liter, czyszczenia ekranu i poruszania się po ekranie. Nadal używamy ekranów VGA, ale teraz użyjemy kilku bajtów, które dadzą kolor. ND_Screen.cpp wyglądałby tak:

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

Nagłówek będzie bardzo prosty, więc nie zamieszczam go tutaj, ale podkreślam definicję typu ND_SIDE

typedef enum ND_SIDE{
ND_SIDE_BACKGROUND,
ND_SIDE_FOREGROUND
} ND_SIDE;

Wspomnij także, że używamy nagłówka ND_Types.hpp, nagłówek ten definiuje kilka podstawowych typów dla uint8_t, uint16_t itp. w oparciu o char i int. Właściwie ten nagłówek jest tym w standardzie C99 i tak naprawdę mój ND_Types.hpp to kopia/wklejenie pliku desde Linux, więc możesz je zamienić i nic by się nie stało (są tylko definicje, nie ma funkcji).

Aby sprawdzić, czy ten kod działa, zmodyfikujemy punkt wejścia 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 jeśli wykonamy te kroki, uzyskamy ten wynik

DalejDivel-3

Dzięki tym funkcjom, które stworzyliśmy, możemy zacząć tworzyć małe GUI, takie jak panika jądra, którą będziemy pokazywać za każdym razem, gdy wystąpi nieodwracalny błąd. Coś takiego:

DalejDivel-4

A ten mały GUI, który stworzyliśmy tylko z tymi funkcjami:

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 do tego post. Przypominam o instrukcji skompilowania systemu od 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

Korzystając z okazji, dziękuję za wspaniałe przyjęcie, jakie spotkało się z pierwszym postem.


Zostaw swój komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

*

*

  1. Odpowiedzialny za dane: Miguel Ángel Gatón
  2. Cel danych: kontrola spamu, zarządzanie komentarzami.
  3. Legitymacja: Twoja zgoda
  4. Przekazywanie danych: Dane nie będą przekazywane stronom trzecim, z wyjątkiem obowiązku prawnego.
  5. Przechowywanie danych: baza danych hostowana przez Occentus Networks (UE)
  6. Prawa: w dowolnym momencie możesz ograniczyć, odzyskać i usunąć swoje dane.

  1.   f3niX powiedział

    Znakomity przyjaciel, mimo to zabijam swój kask rozumiejąc kod w C ++.

    Pozdrowienia.

  2.   pandakrys powiedział

    te przedmioty są świetne. Po raz kolejny wzbudziły moją ciekawość niską wydajnością procesorów.
    może jak będę miał czas, zacznę bawić się next-divelem.
    Dawno nie wysłałem artykułu. już potrzebne

  3.   Jon nory powiedział

    W porządku, w ten sposób.

  4.   miguel powiedział

    Od dawna chciałem wiedzieć, jak zbudować system operacyjny.

    Czekam na twój następny post. Twoje zdrowie

  5.   juliański powiedział

    Świetny przyjaciel!
    Po prostu mam problem, czy ktoś może mi przekazać plik w C z tego przykładu?
    Zawsze wysyła mi błędy w terminalu