寒假OS学习第二天

寒假OS学习第二天

今天准备完成的事情:

  1. 跟着教程完成字符模式下的显卡驱动
  2. 看操作系统概念,理论知识不能落下来!!
  3. 认真学习multiboot规范
  4. 认真学习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;
}
  1. 此处使用了C语言的内联汇编
  2. '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)

主要要实现的有:

  1. 光标移动函数
  2. 屏幕滚动函数
  3. 字符输出函数
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

猜你喜欢

转载自blog.csdn.net/weixin_45206746/article/details/113078526