代码拉取完成,页面将自动刷新
#include <print.h>
#include <stdarg.h>
// 光标位置
static U16 CursorPosX;
static U16 CursorPosY;
// 字体颜色
static U08 FontColor;
// 用于数值 0 ~ 15 转成对应的字符 '0' ~ 'F'
static const U08 IntToStr[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
// 获取 eflags 状态寄存器的 IF 位
#define EFLAGS_IF(eflags) ((eflags)&0x200)
/******************************************************************************
* 函数名称: E_RET SYS_SetCursorPos(U16 x, U16 y)
* 功能说明: 设置光标位置
* 输入参数: U16 x --横坐标
U16 y --纵坐标
* 输出参数: 无
* 函数返回: E_OK:成功; E_ERR:失败
* 其它说明: 无
******************************************************************************/
E_RET SYS_SetCursorPos(U16 x, U16 y)
{
U16 bx_c = 0;
U32 eflags_c = 0;
// 对传入的坐标进行合法性检查
if(x >= SCREEN_WIDTH || y >= SCREEN_WIDTH)
return E_ERR;
CursorPosX = x;
CursorPosY = y;
// 光标位置须按照 bx = (SCREEN_WIDTH * y + x) 公式转换一下放入 bx 寄存器中
bx_c = SCREEN_WIDTH * y + x;
// 获取 eflags 寄存器的值放到 eflags_c 变量中
asm volatile("pushf;popl %%eax":"=a"(eflags_c));
// 关闭外部中断
asm volatile("cli");
asm volatile(
// 设置光标高 8 位:先把数据 0x0E 写入端口 0x03D4,然后把 bh 写入端口 0x03D5
"movw %0, %%bx\n"
"movw $0x03D4, %%dx\n"
"movb $0x0E, %%al\n"
"outb %%al, %%dx\n"
"nop;nop;nop;nop;nop;"
"movw $0x03D5, %%dx\n"
"movb %%bh, %%al\n"
"outb %%al, %%dx\n"
"nop;nop;nop;nop;nop;"
// 设置光标低 8 位:先把数据 0x0F 写入端口 0x03D4,然后把 bl 写入端口 0x03D5
"movw $0x03D4, %%dx\n"
"movb $0x0F, %%al\n"
"outb %%al, %%dx\n"
"nop;nop;nop;nop;nop;"
"movw $0x03D5, %%dx\n"
"movb %%bl, %%al\n"
"outb %%al, %%dx\n"
"nop;nop;nop;nop;nop;"
:
: "b"(bx_c) // 相当于:bx = bx_c,等号左边是汇编中的寄存器 bx,等号右边是 C 代码中的变量
: "ax", "dx" // 告诉 gcc 编译器,ax,dx 寄存器被内嵌汇编使用,需要 gcc 自动添加保护和恢复操作(入栈和出栈)
// 明明 ax, bx, dx 三个寄存器都被使用了,为什么这里却只有 ax 和 dx 寄存器?
// "b"(bx_c) 中使用约束名 "b" 时 gcc 就已经自动对 bx 进行保护和恢复操作,所以这里就不需要重复了
);
// 若 bit9(IF 位) 为 1,则开启外部中断
if(EFLAGS_IF(eflags_c))
asm volatile("sti");
return E_OK;
}
/******************************************************************************
* 函数名称: void SetFontColor(E_FONT_COLOR color)
* 功能说明: 设置字体颜色
* 输入参数: E_FONT_COLOR color --字体颜色
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void SetFontColor(E_FONT_COLOR color)
{
FontColor = color;
}
/******************************************************************************
* 函数名称: static void PrintChar(U08 ch)
* 功能说明: 打印一个字符
* 输入参数: U08 ch --要打印的字符
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
static void PrintChar(U08 ch)
{
U32 edi_c = (SCREEN_WIDTH * CursorPosY + CursorPosX) * 2;
U08 ah_c = FontColor;
U08 al_c = ch;
// 每打印一个字符,光标都往后移动一个位置
CursorPosX++;
// 如果光标达到最大横坐标值了,则设置光标到下一行起始位置
if(CursorPosX >= SCREEN_WIDTH)
{
CursorPosX = 0;
CursorPosY++;
}
if('\n' == al_c || '\r' == al_c) // 遇到换行,则光标位置设置成下一行的起始位置处
{
CursorPosX = 0;
CursorPosY++;
}
else
{
// 打印一个字符
asm volatile(
"movl %0, %%edi\n" // edi:显存中的偏移量
"movb %1, %%ah\n" // 显示属性
"movb %2, %%al\n" // 要打印的字符
"movw %%ax, %%gs:(%%edi)" // 把显示数据放入显存
:
: "D"(edi_c), "r"(ah_c), "r"(al_c) // %0 替换成 edi_c,"D" 表示使用 edi 寄存器; %1 替换成 ah_c; %2 替换成 al_c;
: "ax"
);
}
// 更新光标位置
SYS_SetCursorPos(CursorPosX, CursorPosY);
}
/******************************************************************************
* 函数名称: static E_RET PrintString(U08 *str)
* 功能说明: 打印字符串
* 输入参数: U08 *str --要打印的字符串
* 输出参数: 无
* 函数返回: E_OK:成功; E_ERR:失败
* 其它说明: 无
******************************************************************************/
static E_RET PrintString(U08 const *str)
{
// 检查 *str 是否为空
if(NULL == str)
return E_ERR;
while(*str)
PrintChar(*str++);
return E_OK;
}
/******************************************************************************
* 函数名称: static void PrintIntDec(S32 num)
* 功能说明: 以十进制的方式打印一个整型数
* 输入参数: S32 num --要打印的整型数
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
static void PrintIntDec(S32 num)
{
// 如果 num 为负数,则先把负号 '-' 打印出来; num = -num: 取一个负数的绝对值
if(num < 0)
{
PrintChar('-');
num = -num;
}
if(num < 10) // 递归出口条件
PrintChar(IntToStr[num]);
else
{
PrintIntDec(num / 10);
PrintIntDec(num % 10);
}
}
/******************************************************************************
* 函数名称: static void PrintIntHex(U32 num)
* 功能说明: 以十六进制的方式打印一个无符号整型数
* 输入参数: U32 num --要打印的无符号整型数
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
static void PrintIntHex(U32 num)
{
U08 print[11] = { 0 }; // 初始化时必须清零,最大占 12 字节,比如 "0xFFFFFFFF\0"
U08 i = 0;
U08 tmp = 0;
print[0] = '0';
print[1] = 'x';
for(i = 9; i >= 2; i--)
{
tmp = num & 0xF;
num = num >> 4;
print[i] = IntToStr[tmp];
}
PrintString(print);
}
/******************************************************************************
* 函数名称: void ClearScreen(void)
* 功能说明: 清空屏幕
* 输入参数: 无
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void ClearScreen(void)
{
U32 i = 0;
U32 eflags_c = 0;
// 获取 eflags 寄存器的值放到 eflags_c 变量中
asm volatile("pushf;popl %%eax":"=a"(eflags_c));
// 关闭外部中断
asm volatile("cli");
SYS_SetCursorPos(0, 0);
for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++)
PrintChar(' ');
SYS_SetCursorPos(0, 0);
// 若 bit9(IF 位) 为 1,则开启外部中断
if(EFLAGS_IF(eflags_c))
asm volatile("sti");
}
/******************************************************************************
* 函数名称: E_RET printk(const char * fmt, ...)
* 功能说明: 通用打印
* 输入参数: const char * fmt --输出格式, 目前支持的格式:
%c: 字符
%s: 字符串
%x: 十六进制
%d: 十进制
... --可变参数
* 输出参数: 无
* 函数返回: E_OK:成功; E_ERR:失败
* 其它说明: 无
******************************************************************************/
E_RET printk(const char * fmt, ...)
{
va_list args;
U32 eflags_c = 0;
va_start(args, fmt);
// 获取 eflags 寄存器的值放到 eflags_c 变量中
asm volatile("pushf;popl %%eax":"=a"(eflags_c));
// 关闭外部中断
asm volatile("cli");
// 遍历字符串 fmt
for(; *fmt; ++fmt)
{
// 寻找格式转换字符 '%', 如果不是 '%', 则直接打印出来
if(*fmt != '%')
{
PrintChar(*fmt);
continue;
}
// 如果找到了 '%', 则取 '%' 后的第一个字符
++fmt;
switch (*fmt) // 根据 '%' 后的字符类型采取不同的打印接口
{
case 'c': // 字符
PrintChar((U08)va_arg(args, U32));
break;
case 's': // 字符串
PrintString(va_arg(args, U08 *));
break;
case 'x': // 十六进制
PrintIntHex(va_arg(args, U32));
break;
case 'd': // 十进制
PrintIntDec(va_arg(args, U32));
break;
default:
return E_ERR;
break;
}
}
// 若 bit9(IF 位) 为 1,则开启外部中断
if(EFLAGS_IF(eflags_c))
asm volatile("sti");
va_end(args);
return E_OK;
}
/******************************************************************************
* 函数名称: U32 SYS_print(U08* buf, U16 len)
* 功能说明: 打印
* 输入参数: U08* buf --要打印的 buf 首地址
U16 len --打印长度
* 输出参数: 无
* 函数返回: 成功打印的字符个数
* 其它说明: 无
******************************************************************************/
U32 SYS_print(U08* buf, U16 len)
{
U32 ret = 0;
U16 i = 0;
for(i = 0; i < len; i++)
{
PrintChar(buf[i]);
ret += 1;
}
return ret;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。