Добро пожаловать в еще один пост о том, как создать нашу собственную операционную систему, в данном случае NextDivel.
Если мы вернемся к коду первый пост в конце концов, мы должны были придумать что-то вроде этого:
Если это верно, мы можем продолжить. Я собираюсь использовать систему и структуру, которые есть у меня на GitHub (http://github.com/AdrianArroyoCalle/next-divel) так как мне и вам так удобнее. Как видите, это простой текст, он не выглядит привлекательным. Это может показаться чем-то необычным. Но как говорится, цвета по вкусу, а в нашей операционной системе цвета будут. Первыми цветами, которые мы сможем использовать, будут те, которые определяют карты VGA, а их 0:
- черный
- синий
- Зеленый
- Голубой
- Красный
- фуксин
- Коричневый
- светло-серый
- Темно-серый
- светло-голубой
- Светло-зеленый
- Голубой прозрачный
- Светло-красный
- Светло-пурпурный
- Светло-коричневый
- Белый
Мы собираемся определить эти цвета в заголовке, чтобы он был более удобным и, возможно, в будущем стал частью системного API. Итак, мы создаем файл ND_Colors.hpp во включении 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
В то же время мы собираемся определить новые функции для записи на экране более удобным способом (нет, мы еще не собираемся реализовывать 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;
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).
Чтобы проверить, работает ли этот код, мы собираемся изменить точку входа 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
И я пользуюсь этой возможностью, чтобы поблагодарить вас за отличный прием, который получил первый пост.
Отличный друг, хоть и убиваю свой шлем пониманием кода на c ++.
Привет.
эти предметы великолепны. Они еще раз возбудили мое любопытство по поводу низкой производительности процессоров.
может, если у меня будет время, начну играть со следующим дайвом.
Давно не присылаю статьи. уже нужен
Хорошо, вот так.
Я давно хотел узнать, как создать операционную систему.
Жду вашего следующего поста. Ура
Великолепный друг!
У меня только одна проблема, может ли кто-нибудь передать мне файл C этого примера?
Он всегда присылает мне ошибки в терминале