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:
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:
- Czarny
- Azul
- Zielony
- Cyan
- Czerwony
- Magenta
- brązowy
- Jasnoszary
- Ciemny szary
- Jasnoniebieski
- Jasnozielony
- Cyjan przezroczysty
- Jasnoczerwony
- Jasnopurpurowy
- Jasny brąz
- 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
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:
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.
Znakomity przyjaciel, mimo to zabijam swój kask rozumiejąc kod w C ++.
Pozdrowienia.
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
W porządku, w ten sposób.
Od dawna chciałem wiedzieć, jak zbudować system operacyjny.
Czekam na twój następny post. Twoje zdrowie
Ś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