c - 32 位 C 内核 - 渲染到 VGA 时奇怪的连续重绘

标签 c assembly kernel

我在为我用 C 编写的内核设置任何类型的功能时遇到问题。我已经完成了在 Assembly 中编写引导加载程序的步骤,然后将我的 C 内核编译并加载到内存中并运行

问题是,每当我尝试添加任何类型的主干(例如 VGA 图形类)以轻松组织方法以呈现到 VGA 内存时,我的内核就会崩溃,并且仿真会开始不断重绘自身,但我没有看不到与我试图渲染到 VGA 内存的任何相似之处。

我已经尝试通过许多不同的方式设置主干,通过遵循无数的在线教程,我满足于使用一种终端界面,如果它能开始工作的话。

我一直在将我的代码上传到 Bitbucket 存储库,其中包括我的 Makefile、程序集引导加载程序、程序集内核入口点和我所有的内核 C 源文件。我会将其公开并避免向其中提交任何内容,以便你们都可以引用它,直到我找到我正在寻找的答案。

Here是我的“操作系统”的 Bitbucket 存储库。

我在 Ubuntu 14.04 桌面 64 位上运行。如果您需要任何其他信息或资源来帮助您找到答案,请告诉我,我会进行修改。

提前感谢您的帮助和考虑。

编辑:

显然,将我的代码组织到 Bitbucket 存储库中进行显示是不受欢迎的,因此我将尝试向您详细说明我正在做的可能会导致问题的事情。

我的引导加载程序运行并将内核的 15 个扇区(15 * 512 字节)读取到内存中,尽管我的内核可能没有 15 个扇区的数据这似乎不会引起问题(除非它引起问题我不知道)。我将我的内核加载到地址偏移量 0x0500 之后,我将我的堆栈(在跳入我的内核之前)初始化为位于地址偏移量 0x9FBFF。

之后,我跳转到我的内核(实际上,我跳转到调用 C 内核主函数的汇编内核入口文件)。

当我的内核开始运行时,它会尝试使用我制作的一些主干文件将文本图形绘制到 VGA 内存地址 0xB80000。我可以做简单的事情,例如这行代码。

unsigned char* vidmem = (unsigned char*) 0xB80000;
*vidmem = 'X';

它工作正常,我可以在我的模拟器的左上角看到一个 X 以及引导加载程序中尚未被覆盖的其他图形。

当我尝试做更复杂的事情时,问题开始出现,例如调用其他试图将文本图形绘制到屏幕上不同列和行的后备骨源文件,存储打印到的最后一列和一行,处理滚动,打印整个字符串并考虑滚动和新行等。

我完全不明白为什么会发生这种情况,我对内存和汇编指令如何以可能导致问题的方式与计算机交互有中等到初级的理解。

再次强调,如能就此问题提供任何帮助,我们将不胜感激。

最佳答案

我看到的最明显的问题是您寻址 VGA 内存的逻辑不可靠。

您将指向视频内存的指针声明为 unsigned char *:

unsigned char* terminal_buffer;
...
static unsigned char* const VGA_MEMORY = (unsigned char*) 0xB8000;
...
terminal_buffer = VGA_MEMORY;

但是,您随后尝试将完整的 VGA 字符值写入每个位置,例如在 terminal_init() 中:

  const unsigned int index = r * VGA_WIDTH + c;
  terminal_buffer[index] = make_vga_entry(' ', terminal_color);

您没有将索引乘以 2,因此最终会将 VGA 条目的低 8 位(在本例中为 0x20)写入 VGA 缓冲区中的每个内存位置。当您开始向终端写入文本时,这会导致奇怪的结果,因为每隔一个字节最终都会被解释为属性对而不是字符!

值得庆幸的是,解决方案很简单:将 terminal_buffer 声明为 16 位元素的数组:

uint16_t *terminal_buffer = VGA_MEMORY;
^^^^^^^^

(附:我建议看一下 the OSDev article on VGA hardware 。)

关于c - 32 位 C 内核 - 渲染到 VGA 时奇怪的连续重绘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27747449/

相关文章:

c++ - 我在哪里可以找到世界上最快的 atof 实现?

c - libpng是否允许将整个图像读入内存

c - 为什么每次运行应用程序时都必须使用导出定义 LD_LIBRARY_PATH?

c - 直接将 double 结果分配给 int 时的精度损失/舍入差异

assembly - 关于初始化寄存器

assembly - MASM 列中的数组输出

linux - 内核keepalive是否自动触发?或者我必须从代​​码中触发它们吗?

linux - 内核模块 : hrtimer_start "Unknown Symbol in Module"

linux - Linux 中的中断延迟

c - 如何编辑字符数组的某些部分