Эмуляция Линуса Торвальдса: создайте свою собственную операционную систему с нуля (II)

Добро пожаловать в еще один пост о том, как создать нашу собственную операционную систему, в данном случае NextDivel.

Если мы вернемся к коду первый пост в конце концов, мы должны были придумать что-то вроде этого:

NextDive-1

Если это верно, мы можем продолжить. Я собираюсь использовать систему и структуру, которые есть у меня на GitHub (http://github.com/AdrianArroyoCalle/next-divel) так как мне и вам так удобнее. Как видите, это простой текст, он не выглядит привлекательным. Это может показаться чем-то необычным. Но как говорится, цвета по вкусу, а в нашей операционной системе цвета будут. Первыми цветами, которые мы сможем использовать, будут те, которые определяют карты VGA, а их 0:

  1. черный
  2. синий
  3. Зеленый
  4. Голубой
  5. Красный
  6. фуксин
  7. Коричневый
  8. светло-серый
  9. Темно-серый
  10. светло-голубой
  11. Светло-зеленый
  12. Голубой прозрачный
  13. Светло-красный
  14. Светло-пурпурный
  15. Светло-коричневый
  16. Белый

Мы собираемся определить эти цвета в заголовке, чтобы он был более удобным и, возможно, в будущем стал частью системного 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");

И если мы будем следовать этим шагам, мы получим такой результат

NextDive-3

Благодаря этим функциям, которые мы создали, мы можем начать создавать небольшие графические интерфейсы пользователя, такие как паника ядра, которую мы будем показывать каждый раз, когда возникает неисправимая ошибка. Что-то вроде этого:

NextDive-4

И этот маленький графический интерфейс мы создали только с помощью следующих функций:

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

И я пользуюсь этой возможностью, чтобы поблагодарить вас за отличный прием, который получил первый пост.


Оставьте свой комментарий

Ваш электронный адрес не будет опубликован. Обязательные для заполнения поля помечены *

*

*

  1. Ответственный за данные: Мигель Анхель Гатон
  2. Назначение данных: контроль спама, управление комментариями.
  3. Легитимация: ваше согласие
  4. Передача данных: данные не будут переданы третьим лицам, кроме как по закону.
  5. Хранение данных: база данных, размещенная в Occentus Networks (ЕС)
  6. Права: в любое время вы можете ограничить, восстановить и удалить свою информацию.

  1.   f3niX сказал

    Отличный друг, хоть и убиваю свой шлем пониманием кода на c ++.

    Привет.

  2.   пандакрис сказал

    эти предметы великолепны. Они еще раз возбудили мое любопытство по поводу низкой производительности процессоров.
    может, если у меня будет время, начну играть со следующим дайвом.
    Давно не присылаю статьи. уже нужен

  3.   Джон Берроуз сказал

    Хорошо, вот так.

  4.   Мигель сказал

    Я давно хотел узнать, как создать операционную систему.

    Жду вашего следующего поста. Ура

  5.   Giuliano сказал

    Великолепный друг!
    У меня только одна проблема, может ли кто-нибудь передать мне файл C этого примера?
    Он всегда присылает мне ошибки в терминале