Сардэчна запрашаем у чарговы пост пра тое, як стварыць уласную аперацыйную сістэму, у дадзеным выпадку NextDivel.
Калі мы вернемся да кода першы пост напрыканцы ўсяго мы павінны былі прыдумаць нешта накшталт гэтага:
Калі гэта правільна, мы можам працягваць. Я збіраюся выкарыстаць сістэму і структуру, якія ёсць у мяне на GitHub (http://github.com/AdrianArroyoCalle/next-divel), так як гэта зручней і мне, і вам. Як бачыце, тэкст - асноўны тэкст, ён не прывабны. Гэта можа здацца чымсьці незвычайным. Але, як гаворыцца, каб паспрабаваць колеры, і ў нашай аперацыйнай сістэме будуць колеры. Першыя колеры, якія мы зможам паставіць, будуць тымі, якія вызначаюць карты VGA, а іх 0:
- Чорны
- Azul
- зялёны
- Блакітны
- Чырвоны
- Пурпурны
- карычневы
- Светла-шэры
- Цёмна-шэры
- Светла-блакітны
- Светла-зялёны
- Блакітна-чысты
- Светла-чырвоны
- Светла-пурпурны
- Светла карычневы
- Белы
Мы збіраемся вызначыць гэтыя колеры ў загалоўку, каб зрабіць яго больш зручным і, магчыма, у будучыні стаць часткай сістэмнага API. Такім чынам, мы ствараем файл ND_Colors.hpp у 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
У той жа час мы збіраемся вызначыць новыя функцыі для больш зручнага запісу на экране (не, мы пакуль не збіраемся рэалізоўваць printf, я ведаю, вы гэтага хочаце). Мы створым файл і загаловак для набору функцый, звязаных з экранам (ND_Screen.cpp і ND_Screen.hpp). У іх мы створым функцыі для: змены колеру літар і фону, напісання прапаноў і літар, ачысткі экрана і перамяшчэння па экране. Мы працягваем выкарыстоўваць VGA-экраны, але зараз мы будзем выкарыстоўваць некалькі байтаў, якія нададуць колер. ND_Screen.cpp будзе выглядаць так:
/**
* @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;
}
Загаловак будзе вельмі простым, таму я не ўключаю яго сюды, але вылучаю вызначэнне тыпу ND_SIDE
typedef enum ND_SIDE{
ND_SIDE_BACKGROUND,
ND_SIDE_FOREGROUND
} ND_SIDE;
Таксама згадаем, што мы выкарыстоўваем загаловак ND_Types.hpp, гэты загаловак вызначае некаторыя асноўныя тыпы для uint8_t, uint16_t і г.д. на аснове char і int. На самай справе гэты загаловак знаходзіцца ў стандарце C99, і на самой справе мой ND_Types.hpp - гэта копія / устаўка файла з Linux, таму вы можаце абменьвацца імі, і нічога не атрымаецца (ёсць толькі азначэнні, няма функцый).
Каб праверыць, ці працуе гэты код, мы збіраемся змяніць пункт уваходу ядра C:
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");
І калі мы будзем прытрымлівацца гэтых крокаў, мы атрымаем такі вынік
Дзякуючы гэтым функцыям, якія мы стварылі, мы можам пачаць рабіць невялікія графічныя інтэрфейсы, напрыклад, паніку ядра, якую мы будзем паказваць кожны раз, калі будзе непапраўная памылка. Нешта накшталт гэтага:
І гэты маленькі графічны інтэрфейс мы зрабілі толькі з такімі функцыямі:
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);
}
І да гэтага паведамлення. Я нагадваю вам інструкцыі па кампіляцыі сістэмы з 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
І карыстаюся выпадкам, каб падзякаваць вас за выдатны прыём, які быў зроблены ў першым паведамленні.
5 каментарыяў, пакіньце свой
Выдатны сябар, нават таму я забіваю свой шлем, разумеючы код на C ++.
Прывітанне.
гэтыя прадметы выдатныя. яны зноў выклікалі маё цікаўнасць да нізкай прадукцыйнасці працэсараў.
магчыма, калі ў мяне будзе час, я пачну гуляць з наступным дайвэлам.
Я даўно не дасылаў артыкул. ужо патрэбны
Добра, гэта шлях.
Я даўно хацеў ведаць, як пабудаваць аперацыйную сістэму.
Чакаю вашага наступнага допісу. На ўра
Вялікі сябар!
У мяне проста адна праблема, ці можа хто-небудзь перадаць мне файл C гэтага прыкладу?
Ён заўсёды пасылае мне памылкі ў тэрмінале