オペレーティングシステム-カーネル内の画面印刷(パート1)
1.画面印刷-C言語を使用して一連の印刷機能を設計し、その後のカーネル機能のさらなる開発に備えます。
カーネルの画面印刷モジュールには、
3つの異なる入口があります。screen。モジュールは、保護モードで画面にテキストを印刷する機能を提供します。このモジュールの具体的な実装は
、図に示すとおりです。設計する7つのインターフェイスがあり、最も重要です。関数の1つはvoidPrintChar(char c)です。文字列を出力する関数で、
下の図に示すように、上記の7つの関数インターフェイス間の関係を要約します。図に示すように、中心的な関数は上記の関数です。上の図で関係を得ることができます
2. void PrintChar(char c)関数の実装
最も重要な関数はvoidPrintChar(char c)であると結論付けることができるので、この関数を実現するには
1.関数の定義:画面に文字を印刷します
2.実装の原則:ビデオメモリの対応する位置に直接データを書き込みます
。上の図に示すように、データの書き込みの一部は4行のアセンブリ言語で実装できますが、前回の調査では、カーネル開発を実現するにはC言語である必要があります。その理由は、アセンブリ言語を使用して画面に文字列を印刷する方が簡単であり、アセンブリ命令が時々あるためです。アセンブリ言語で実装してから、C言語で呼び出す必要があります。
3.言語でのインラインアセンブリ-インラインアセンブリの構文形式の
コード例。
コード例から、関数はC言語で記述されていることがわかりますが、アセンブリ言語の埋め込みを実装するためにasmvolatileキーワードが使用されています。ここで注意する必要があります。 GCCコンパイラを使用しているため、インラインアセンブリにはAT&Tアセンブリ形式が使用されます(nasmアセンブリ形式とは異なります)。
3.スクリーン印刷の実現
1.最初にscreen.cファイルとscreen.hファイルを作成し、makefileに変更を加えます。同時に、コンパイル後、コンパイルしたファイルを後ろに保存する必要があるため、変更は次のようになります
。2.screen.hヘッダーファイルの実現
#ifndef SCREEN_H
#define SCREEN_H
#define SCREEN_WIDTH 80//定义的宽与高-横坐标与纵坐标
#define SCREEN_HEIGHT 25
typedef enum//颜色枚举类型的定义
{
SCREEN_GRAY = 0x07,
SCREEN_BLUE = 0x09,
SCREEN_GREEN = 0x0A,
SCREEN_RED = 0x0C,
SCREEN_YELLOW = 0x0E,
SCREEN_WHITE = 0x0F
} PrintColor;
//接口的声明
void ClearScreen();
int SetPrintPos(short w, short h);
void SetPrintColor(PrintColor c);
int PrintChar(char c);
int PrintString(const char* s);
int PrintIntDec(int n);
int PrintIntHex(unsigned int n);
#endif
3.screen.cの実装-intSetPrintPosおよびvoidSetPrintColor
static int gPosW = 0;
static int gPosH = 0;//全局变量的定义
static char gColor = SCREEN_WHITE;
int SetPrintPos(short w, short h)
{
int ret = 0;
if( ret = ((0 <= w) && (w <= SCREEN_WIDTH) && (0 <= h) && (h <= SCREEN_HEIGHT)) )
{
unsigned short bx = SCREEN_WIDTH * h + w;
gPosW = w;
gPosH = h;
asm volatile(
"movw %0, %%bx\n"
"movw $0x03D4, %%dx\n"
"movb $0x0E, %%al\n"
"outb %%al, %%dx\n"
"movw $0x03D5, %%dx\n"
"movb %%bh, %%al\n"
"outb %%al, %%dx\n"
"movw $0x03D4, %%dx\n"
"movb $0x0F, %%al\n"
"outb %%al, %%dx\n"
"movw $0x03D5, %%dx\n"
"movb %%bl, %%al\n"
"outb %%al, %%dx\n"
:
: "r"(bx)
: "ax", "bx", "dx"
);
}
return ret;
}
void SetPrintColor(PrintColor c)
{
gColor = c;
}
4.PrintChar関数の実装
int PrintChar(char c)
{
int ret = 0;
if( (c == '\n') || (c == '\r') )//需要注意这两个字符,当出现这俩个时换行,不进行打印
{
ret = SetPrintPos(0, gPosH + 1);//重新换行
}
else
{
int pw = gPosW;
int ph = gPosH;
if( (0 <= pw) && (pw <= SCREEN_WIDTH) && (0 <= ph) && (ph <= SCREEN_HEIGHT) )
{
int edi = (SCREEN_WIDTH * ph + pw) * 2;//位置的确定
char ah = gColor;//颜色的确定
char al = c;//具体打印的字符
//汇编的嵌入 l四个字节,b为一个字节,w为俩个字节
asm volatile(
"movl %0, %%edi\n"
"movb %1, %%ah\n"
"movb %2, %%al\n"
"movw %%ax, %%gs:(%%edi)"
"\n"
:
: "r"(edi), "r"(ah), "r"(al)
: "ax", "edi"
);
pw++;
if( pw == SCREEN_WIDTH )
{
pw = 0;
ph = ph + 1;
}
ret = 1;
}
SetPrintPos(pw, ph);
}
return ret;
}
32ビットの保護モードセレクターで実行されるため、loader.asmセットが必要
です。
実装の6.PrintStringを達成するには、変更する必要があります。0に達するまでのサイクルPrintChar呼び出しターミネーター
は、
実装のintPrintIntHexを達成します。 -パラメータnを対応する16進数の文字列に変換し、PrintStringを呼び出して変換された文字列を印刷します