操作系统实现_05_基础显卡驱动
全部自己手写
#include <onix/console.h>
static u8 char_attr = 7; // 字符默认样式
static u16 space = 0x0720; // 带有样式的空格
struct CURSOR_REL {u8 x; u8 y} ; // 光标距离 当前屏幕的 x和y 单位为字符
// 得到当前显示器这一屏的开始的内存位置
static usize get_current_screen_mem_status(){
// 首先 获得当前显示器 距离 0xb800 多少个字符
// 高八位
out_8(CRT_ADDR_PORT, CRT_MEM_H_VALUE);
u8 h = in_8(CRT_DATA_PORT);
// 低8位
out_8(CRT_ADDR_PORT, CRT_MEM_L_VALUE);
u8 l = in_8(CRT_DATA_PORT);
u16 char_pos = (h << 8) | l;
// 累加 得到当前显示器的内存地址
usize mem_pos = char_pos << 1; // 一个字符 2字节
return CRT_MEM_START + mem_pos;
}
// 设置显示器当前屏需要展示的字符的内存位置 为新的一屏
static set_current_screen_mem_status(usize screen){
// 得到距离 crt开始的内存的距离
usize screen_rel = screen-CRT_MEM_START;
// 高八位字符设置
out_8(CRT_ADDR_PORT, CRT_MEM_H_VALUE);
out_8(CRT_DATA_PORT, (screen_rel >> 1) >> 8);
// 低8位
out_8(CRT_ADDR_PORT, CRT_MEM_L_VALUE);
out_8(CRT_DATA_PORT, (screen_rel >> 1));
}
// 得到当前光标在内存中的位置
static usize get_current_cursor_mem_status(){
// 首先 获得当前当前光标 距离 0xb800 多少个字符
// 高八位
out_8(CRT_ADDR_PORT, CRT_CURSOR_H_VALUE);
u8 h = in_8(CRT_DATA_PORT);
// 低8位
out_8(CRT_ADDR_PORT, CRT_CURSOR_L_VALUE);
u8 l = in_8(CRT_DATA_PORT);
u16 char_pos = (h << 8) | l;
// 累加 得到当前光标的内存地址
usize mem_pos = char_pos << 1; // 一个字符 2字节
return CRT_MEM_START + mem_pos;
}
// 设置光标的新的内存位置
static set_current_cursor_mem_status(usize cursor){
// 得到距离 crt开始的内存的距离
usize cursor_rel = cursor-CRT_MEM_START;
// 高八位字符设置
out_8(CRT_ADDR_PORT, CRT_CURSOR_H_VALUE);
out_8(CRT_DATA_PORT, (cursor_rel >> 1) >> 8);
// 低8位
out_8(CRT_ADDR_PORT, CRT_CURSOR_L_VALUE);
out_8(CRT_DATA_PORT, (cursor_rel >> 1));
}
// 得当当前距离屏幕的相对坐标
static struct CURSOR_REL get_current_cursor_x_and_y(){
// 获得当前 光标内存位置
usize cursor_mem_abs = get_current_cursor_mem_status();
// 获得当前显示器内存位置
usize screen_mem_abs = get_current_screen_mem_status();
// 当前光标距离当前屏幕首地址几个字符
usize char_count = (cursor_mem_abs - screen_mem_abs) >> 1;
u8 x = char_count % WIDTH;
u8 y = char_count / WIDTH;
struct CURSOR_REL tmp = {x,y};
return tmp;
}
// 向上滚动 count行
static scroll_up(usize* cursor_mem_abs_ptr){
usize count_bytes = (1 * 2 * 80 * 1);
// 当前屏幕的内存位置
usize screen_mem_abs = get_current_screen_mem_status();
// 新的内存屏幕的位置
usize new_screen_mem_abs_start = screen_mem_abs + count_bytes;
// 显存检测, 如果写入超过显存
if (*cursor_mem_abs_ptr >= CRT_MEM_END) {
// 把当前屏幕数据copy到 起始 位置
memcpy((u8*)CRT_MEM_START, (u8*)screen_mem_abs, (1 * 2 * WIDTH * HEIGHT));
// 清空现在当前屏幕, 内存之下所有的数据(!有问题, 用下面的循环)
// memset((u8*)CRT_MEM_START+(1 * 2 * WIDTH * HEIGHT), 0, CRT_MEM_END-(CRT_MEM_START+(1 * 2 * WIDTH * HEIGHT)));
// 结束位置
u8* e = (u8*)CRT_MEM_START + (1 * 2 * WIDTH * HEIGHT);
while (true){
if (e >= CRT_MEM_END) {
break;
}
*e = space;
e += 2;
}
// 设置 new_screen_mem_abs_start 为 新地址
new_screen_mem_abs_start = CRT_MEM_START + count_bytes;
// 光标也挪过去(cursor_mem_abs_ptr 是指针类型指针)
(*cursor_mem_abs_ptr) -= (screen_mem_abs - CRT_MEM_START);
}
// 设置屏幕
set_current_screen_mem_status(new_screen_mem_abs_start);
}
console_write(u8* buf, usize count){
// 当前光标内存位置
u8* cursor_mem_abs_ptr = (u8*)get_current_cursor_mem_status();
// 当前屏幕的内存位置
u8* screen_mem_abs_ptr = (u8*)get_current_screen_mem_status();
// 当前光标相对于屏幕坐标系
struct CURSOR_REL cursor_rel_xy = get_current_cursor_x_and_y();
for (usize i = 0; i < count; i++){
u8 ch = buf[i];
if (ch == '~'){
int f = 123;
}
switch (ch){
case EOS:
break;
case BEL:
break;
case BS:
// 如果光标内存位置==屏幕内存位置, 说明在开头
if (cursor_mem_abs_ptr == screen_mem_abs_ptr) {
break;
}
// 前一个字符的 内存位置
cursor_mem_abs_ptr -= 2;
// 修改为空字符
*cursor_mem_abs_ptr = space;
break;
case HT:
break;
case LF:
// 光标换行
cursor_mem_abs_ptr += (WIDTH << 1);
cursor_rel_xy.y += 1;
// 换行是否需要滚动
if(cursor_rel_xy.y >= HEIGHT) {
scroll_up(&cursor_mem_abs_ptr);
cursor_rel_xy.y -= 1;
}
goto in_cr;
break;
case VT:
break;
case FF:
goto in_cr;
break;
case CR:
// 使光标回到开始的位置
in_cr:
cursor_mem_abs_ptr -= (cursor_rel_xy.x << 1);
cursor_rel_xy.x = 0;
break;
case DEL:
// 直接替换当前字符为空白
*cursor_mem_abs_ptr = space;
break;
default:
cursor_rel_xy.x += 1;
// 如果需要换行
if(cursor_rel_xy.x >= WIDTH) {
cursor_rel_xy.x =0;
cursor_rel_xy.y += 1;
// 即将在下一行写入字符, 要保证下一行在 最大高度HEIGHT 之内
// cursor_rel_xy 内保存的是idx, 需要+1得到当前屏幕的行数 和HEIGHT 比较如果相等, 说明当前屏幕已经写满了
if(cursor_rel_xy.y >= HEIGHT) {
scroll_up(&cursor_mem_abs_ptr);
cursor_rel_xy.y -= 1;
}
}
// 替换字符和样式
*cursor_mem_abs_ptr = ch;
cursor_mem_abs_ptr += 1;
*cursor_mem_abs_ptr = char_attr;
cursor_mem_abs_ptr += 1;
break;
}
}
// // 如果最后一个字符显示完毕后刚好是屏幕的最后一个字符
// if(cursor_rel_xy.x >= WIDTH) {
// cursor_rel_xy.x =0;
// cursor_rel_xy.y += 1;
// // 即将在下一行写入字符, 要保证下一行在 最大高度HEIGHT 之内
// // cursor_rel_xy 内保存的是idx, 需要+1得到当前屏幕的行数 和HEIGHT 比较如果相等, 说明当前屏幕已经写满了
// if(cursor_rel_xy.y >= HEIGHT) {
// scroll_up(&cursor_mem_abs_ptr);
// cursor_rel_xy.y -= 1;
// }
// }
// 重新设置光标位置
set_current_cursor_mem_status((usize)cursor_mem_abs_ptr);
}
console_clear(){
// 整个显存内存区域改成 有样式的空格
usize crt_mem_start = CRT_MEM_START;
u8* crt_mem_start_ptr = (u8*)crt_mem_start;
for (usize i = 0; i < CRT_MEM_SIZE; i++){
*crt_mem_start_ptr = space;
crt_mem_start_ptr += 2;
}
// 光标重置到当前屏幕的第一个字符
set_current_cursor_mem_status(get_current_screen_mem_status());
}
console_init(){
test_console();
}
test_console(){
struct CURSOR_REL cursor_rel_xy = get_current_cursor_x_and_y();
int a = 0;
// 当前位置
usize screen_mem_abs = get_current_screen_mem_status();
// 设置从第二行开始显示 (2*80)表示一行的字节数量
usize screen = CRT_MEM_START + (2*80)*1;
set_current_screen_mem_status(screen);
// 当前位置
screen_mem_abs = get_current_screen_mem_status();
// 当前光标位置
usize cursor_mem_abs = get_current_cursor_mem_status();
// 设置新的光位置视在 第一行的 下标为3的字符, 当然, 这是不可见的, 因为 上面第一行已经不显示了
cursor_mem_abs = CRT_MEM_START + (1 * 2) * 3;
set_current_cursor_mem_status(cursor_mem_abs);
// 设置光标在第二行 下标为4的 字符处(这里屏幕中的第一行, 就是内存中的第二行)
cursor_mem_abs = CRT_MEM_START + (1 * 2) * 80 + (1 * 2) * 4;
set_current_cursor_mem_status(cursor_mem_abs);
// 得到当前光标的相对位置
struct CURSOR_REL cur = get_current_cursor_x_and_y();
console_clear();
char* message = "123456781234567812345672812345678123456781234567812345678123456781234567812345678\n";
for (usize i = 0; i < 49; i++){
console_write(message, strlen(message));
}
char* message1= "123456\n";
console_write(message1, strlen(message1));
console_write(message1, strlen(message1));
console_write(message1, strlen(message1));
cursor_rel_xy = get_current_cursor_x_and_y();
a = 0;
console_write(message1, strlen(message1));
cursor_rel_xy = get_current_cursor_x_and_y();
a = 0;
console_write(message1, strlen(message1));
console_write(message1, strlen(message1));
console_write(message1, strlen(message1));
console_write(message1, strlen(message1));
console_write(message1, strlen(message1));
char* message2= "12312312312312312312123123123123123123123123112312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312312323123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123112312312312312312312312312312312312312312323123123123123123123~\n";
console_write(message2, strlen(message2));
// screen_mem_abs = get_current_screen_mem_status();
// cursor_rel_xy = get_current_cursor_x_and_y();
// usize tmp = (6 * 2) + (24 * 80 * 2);
// set_current_cursor_mem_status(screen_mem_abs + tmp);
// char* message2= "1234567\n";
// console_write(message2, strlen(message2));
// console_write(message2, strlen(message2));
// console_write(message2, strlen(message2));
// console_write(message2, strlen(message2));
// console_write(message2, strlen(message2));
// console_write(message2, strlen(message2));
}