寒假OS学习第二天
今天准备完成的事情:
- 跟着教程完成字符模式下的显卡驱动
- 看操作系统概念,理论知识不能落下来!!
- 认真学习multiboot规范
- 认真学习makefile的进阶语法
Hurlex学习笔记——字符模式下的显卡驱动
32位最多能寻址到4G
4G的地址空间里面分给一部分给了其他外设
在PC上显示文字需要显示器和显卡
显卡负责提供内容
显卡有自己的存储区域,叫做VRAM
访问显存需要地址
显卡有两种模式:文本模式和图形模式
显卡在文本模式的显示规则
显卡会内置一套关于基本英文字符的显示。
在PC上工作的显卡在加电初始化后都会自动初始化到80*25
的文本模式
文本模式的显存:0xB8000~0xBFFFF
,有2000个字符
显卡会周期性地读取这里的数据并且将其按照顺序显示,每两个字节表示屏幕上的一个字符
这两个字节的前一个是字符的ASCII码,后一个是控制字符颜色和属性的控制信息
bit | 7 | 6:4 | 3:0 |
---|---|---|---|
1:闪烁,0:不闪烁 | 背景色 | 前景色 |
背景色:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
黑 | 蓝 | 绿 | 青 | 红 | 粉 | 棕 | 灰白 |
前景色:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
黑 | 蓝 | 绿 | 青 | 红 | 粉 | 棕 | 灰白 | 灰 | 亮蓝 | 亮绿 | 亮青 | 亮红 | 亮粉 | 黄 | 亮白 |
显卡除了显示内容的存储单位外还有部分的显示控制单元
使用特殊的in/out指令读写
将0x3D4作为内部寄存器的索引
端口读写函数
使用端口读写函数进行端口操作
// 端口写一个字节
inline void
outb (uint16_t port, uint8_t val)
{
asm volatile (
"outb %1, %0"
: // no output
:"dN"(port),
"a"(val) // 执行前先将val传递给eax
);
}
// 端口读一个字节
inline uint8_t
inb(uint16_t port)
{
uint8_t res;
asm volatile (
"inb %1, %0"
: "=a"(res)
: "dN"(port)
);
return res;
}
// 端口读一个字
inline uint16_t
intw(uint16_t port)
{
uint16_t res;
asm volatile(
"inw %1, %0"
: "=a"(res)
: "dN"(port)
);
return res;
}
- 此处使用了C语言的内联汇编
- 'a’表示eax,'dN’表示edx,限定数字范围0~255
屏幕操作函数
先定义颜色枚举
typedef
enum real_color
{
rc_black = 0,
rc_blue,
rc_green,
rc_cyan,
rc_red,
rc_magenta,
rc_brown,
rc_light_grey,
// 背景色只有8种
rc_dark_grey,
rc_light_blue,
rc_light_green,
rc_light_cyan,
rc_light_red,
rc_light_magenta,
rc_light_brown,
rc_white
// 前景色16种
}real_color_t;
然后定义屏幕操作函数
定义如下常量与如下变量
static uint16_t *const video_memory = (uint16_t *)0xB8000;
static const uint16_t screen_width = 80;
static const uint16_t screen_hight = 25;
static const uint16_t screen_size = 2000; // 80*25
static const uint8_t cursor_low = 14;
static const uint8_t cursor_high = 15;
static const uint8_t tab_len = 8;
static uint16_t video_post_port = 0x3D4;
static uint16_t video_set_port = 0x3D5;
static uint8_t cursor_x = 0;
static uint8_t cursor_y = 0;
定义如下宏
#define attribute_byte_raw(BACK, FORE) ((BACK << 4) | (FORE & 0x0F))
#define attribute_byte(BACK, FORE) (attribute_byte_raw(BACK, FORE) << 8)
主要要实现的有:
- 光标移动函数
- 屏幕滚动函数
- 字符输出函数
static void
move_cursor()
{
uint16_t curLtn = cursor_y * screen_width + cursor_x;
outb(video_post_port, cursor_high);
outb(video_set_port, curLtn >> 8);
outb(video_post_port, cursor_low);
outb(video_set_port, curLtn);
}
static void
scroll()
{
uint16_t blank = 0x20 | attribute_byte(rc_black, rc_white);
if (cursor_y >= screen_hight)
{
int i = 0;
int cpy_siz = screen_size - screen_width;
while (i < cpy_siz)
{
video_memory[i] = video_memory[i + screen_width];
i += 1;
}
while (i < screen_size)
video_memory[i ++] = blank;
cursor_y = screen_hight - 1;
}
}
// 清屏
void console_clear()
{
uint16_t blank = 0x20 | attribute_byte(rc_black, rc_white);
int i = 0;
while (i < screen_size)
video_memory[i ++] = blank;
cursor_x = cursor_y = 0;
move_cursor();
}
// 屏幕输出一个带颜色的字
void console_putc_color(char c, real_color_t back, real_color_t fore)
{
switch (c)
{
case 0x08: // backspace
cursor_x --; break;
case '\t': // tab
cursor_x = (cursor_x + tab_len) & ~(tab_len - 1); // % tablen
break;
case '\r':
cursor_x = 0; break;
case '\n':
cursor_x = 0; cursor_y ++; break;
default:
{
if (c >= ' ')
{
video_memory[cursor_y * screen_width + cursor_x] =
c | attribute_byte(back, fore);
cursor_x += 1;
}
}
}
if (cursor_x >= screen_width)
{
cursor_x = 0;
cursor_y ++;
}
scroll();
move_cursor();
}
其他函数均可以借助这些函数完成
// 屏幕打印一串以0结尾的字符串
void console_write(char *cstr)
{
while (*cstr)
console_putc_color(*cstr ++, rc_black, rc_white);
}
// 屏幕打印带颜色的字符串
void console_write_color(char *cstr, real_color_t back, real_color_t fore)
{
while (*cstr)
console_putc_color(*cstr ++, back, fore);
}
修改入口函数
int kern_entry()
{
console_clear();
int i = -1, j = -1;
while (++ i < 0x08)
{
j = -1;
while (++ j < 0x010)
console_write_color("HelloWorld", i, j);
}
return 0;
}
得到的效果如图
![[OS_1.png]]
操作系统概念学习笔记
https://blog.csdn.net/weixin_45206746/article/details/113036174
multiboot规范
https://blog.csdn.net/weixin_45206746/article/details/113065721
makefile解读
https://blog.csdn.net/weixin_45206746/article/details/113065944