模擬Linus Torvalds:從頭開始創建自己的操作系統(II)

歡迎閱讀有關如何創建我們自己的操作系統的另一篇文章,在本例中為NextDivel。

如果我們回到代碼 第一篇文章 在所有事情的最後,我們都應該想到這樣的事情:

下一級

如果這是正確的,我們可以繼續。 我將使用GitHub上的系統和結構(http://github.com/AdrianArroyoCalle/next-divel),因為這對我和您來說都比較舒適。 如您所見,文本是基本文本,沒有吸引力。 看起來似乎與眾不同。 但是俗話說,要嚐嚐顏色,在我們的操作系統中就會有顏色。 我們將要輸入的第一個顏色將是定義VGA卡的顏色,它們是0:

  1. 藍色
  2. 綠色
  3. 青色
  4. 羅霍
  5. 品紅
  6. 棕色
  7. 淺灰色
  8. 深灰色
  9. 淺藍色
  10. 淺綠色
  11. 青色清除
  12. 紅燈
  13. 淺洋紅色
  14. 淺褐色
  15. 布蘭科

我們將在標頭中定義這些顏色,以使其更方便使用,並可能在將來成為系統API的一部分。 因此,我們在NextDivel include中創建了文件ND_Colors.hpp。

#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");

如果我們按照以下步驟操作,我們將獲得此結果

下一級

由於我們已經創建了這些功能,我們可以開始製作小型GUI,例如每次出現不可恢復的錯誤時都會顯示的內核崩潰。 像這樣:

下一級

而這個小小的GUI我們僅通過以下功能實現了它:

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條評論,留下您的評論

發表您的評論

您的電子郵件地址將不會被發表。 必填字段標有 *

*

*

  1. 負責數據:MiguelÁngelGatón
  2. 數據用途:控制垃圾郵件,註釋管理。
  3. 合法性:您的同意
  4. 數據通訊:除非有法律義務,否則不會將數據傳達給第三方。
  5. 數據存儲:Occentus Networks(EU)託管的數據庫
  6. 權利:您可以隨時限制,恢復和刪除您的信息。

  1.   F3NIX 他說:

    優秀的朋友,繼續這樣下去,我正在毀掉我的頭盔來理解 C++ 代碼。

    問候。

  2.   熊貓人 他說:

    這些東西都很棒。 再次引起了我對處理器底層性能的好奇。
    也許如果我有時間我會開始玩下一個潛水。
    自從我發送文章以來已經有一段時間了。 這已經是必要的了

  3.   喬恩·洞穴 他說:

    好吧,就是這樣。

  4.   米格爾 他說:

    我長期以來一直想知道如何製作一個操作系統。

    等待你的下一篇文章。 問候

  5.   朱利亞諾 他說:

    好朋友!
    我只是有一個問題,有人可以給我發送這個例子的 C 文件嗎?
    它總是在終端中給我錯誤