昨天写的内核在屏幕上没有我们输出的东西,今天就来想办法显示点什么
文字的显示
要显示东西就涉及到显卡了,显卡有两种模式,文本模式和图形模式,现在基本都是图形模式用得多,但是我们这个就用文本模式了,毕竟不涉及ui啥的
文本的显示规则
显卡通电后就自动初始化了80\ * 25分辨率的文本模式,即一屏25行,一行80个字符
之前说过内存地址空间不是全部映射到主存的,有一部分映射到外部设备,0xB8000~0xBFFFF就是映射到显卡文本模式的显存的地址空间
从0xB8000开始,每两个字节对应屏幕上的一个字符,从第一行开始,字符在内存中的存储形式叫内码,第一个字符对应字符的ASCII码,第二个控制字符的颜色等等信息,每一位都有不同的含义,如下图: (图片来自教程)
除了显存之外,显卡还有一些控制单元,这些单元没有映射在cpu寻址的4GB空间里,需要使用in / out命令来读写,这部分寄存器的访问规则是:
- 通过0x3D4端口来设置寄存器索引,就是要访问哪一个寄存器
- 通过0x3D5端口来设置寄存器的值
端口读写函数
这些要用in / out命令访问的寄存器用c的代码显然是不行的,只能用汇编实现,这里选择在c里面内嵌汇编代码参考汇编语言和C语言混合编程和内联汇编
libs/common.c
1 |
|
include/common.h
1 |
|
头文件前面的那个ifndef和define是为了防止在不同的文件中include了同一个头文件会出现的重复定义错误
函数前面的inline是建议编译器把函数当成内联函数来编译,即在函数的调用处进行代码展开,而不是传统函数调用
颜色定义和屏幕操作函数
是颜色定义的枚举和一些屏幕控制函数的声明
include/console.h
1 |
|
drivers/console.c
定义一些变量,static修饰代表只在该文件内生效
1 | static uint16_t *video_memory = (uint16_t *)0xB8000; //显存的起始地址,每两个字节表示一个字符所以是16位 |
输入光标的移动
1 | //移动光标的位置 |
清屏操作
清屏就是把所有字符用黑底白字的空格填充,然后把光标移动到最前面就行了
1 | void console_clear() |
屏幕滚动
只需要将所有行内容往上移动一格,最后一行填充空格
1 | //屏幕的滚动 |
显示字符串
注意对换行符等等一些符号的处理
1 | // 屏幕输出一个字符带颜色 |
输出数字
做一下进制转换当字符串输出就行了
1 | / 屏幕输出一个十六进制的整型数 |
测试
修改一下init / entry.c
1 |
|
1 | make |
最终的成果