- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试获得一个简单的 Hello World!内核启动。每当我打开我的虚拟机时,我都会看到 GRUB 加载,选择我的操作系统,然后在屏幕上出现一个随机字符,并因三重故障而崩溃。我认为问题出在我的 VGA 部分。我怀疑问题出在我使用 C 指针的某个地方。 C 和指针都不是强项。具体来说,我怀疑涉及 put_char() 函数。有一些涉及指针的编译器问题。我究竟做错了什么?我该如何解决这个问题?
感谢您的帮助!
这是我的 VGA 部分的代码:
/*
This file will handle dealing with VGA stuff so I can print to the screen.
*/
#include <system.h>
/* this pointer will be set to the VGA access memory address */
unsigned short *text_ptr;
int attrib = 0x0F; // foreground and background color gets set in here.
int csr_x = 0; // cursor x position
int csr_y = 0; // cursor y position
int screen_width = 80; // width of the screen in columns
int screen_height = 25; // height of the screen in rows
void vga_initialize()
{
// set the text pointer to the proper location in memory
text_ptr = (unsigned short *) 0x0B8000;
clear_screen();
}
void set_text_color(unsigned char foreground_color, unsigned char background_color)
{
attrib = (background_color << 4) | (foreground_color & 0x0F);
}
void put_str(char *text)
{
// figure out the length of the string we'll be printing
char *my_text = text; // make a local copy of the pointer so the orinal's not overwritten.
int str_length;
for (str_length = 0; *my_text != '\0'; my_text++) // set the string lenght to 0; if the character at the pointer isn't zero; increment the pointer
{
str_length++; // increment the count
}
// for each character in the string
for (int i = 0; i < str_length; i++)
{
put_char(my_text[i]); // put the character on the screen
}
}
void put_char(char c)
{
unsigned short *index_ptr;
unsigned int my_attrib = attrib << 8;
if (c == 0x08) // backspace
{
if (csr_x != 0)
{
csr_x--;
}
}
else if (c == 0x09) // tab
{
csr_x = (csr_x + 8) & ~(8 - 1); // increment x but only to a point that will make it divisible by 8 (i dunno, lawl)
}
else if (c == '\r') // carriage return, move cursor to beginning of row
{
csr_x = 0;
}
else if (c == '\n') // newline
{
csr_x = 0;
csr_y++;
}
else if (c >= ' ') // any character greater than or equal to space is a printable character
{
// figure out where to put the character
index_ptr = text_ptr + (csr_y * screen_width + csr_x);
// put the character and it's attribute into memory, which will put it on the screen when it refreshes.
*index_ptr = c | my_attrib;
}
scroll();
move_csr();
}
void scroll()
{
unsigned short space_char = 0x20 | (attrib << 8);
// used to calculate the offsets needed when moving data around in the vga buffer memory
int temp_offset;
// screen's full, we need to scroll
if (csr_y >= screen_height)
{
// move everything up
temp_offset = csr_y - screen_height + 1; // offset for calculating the addresses to use in the vga memory
memcpy(text_ptr, text_ptr + temp_offset * screen_width, (screen_height - temp_offset) * screen_width * 2);
// set the chunk of memory that occupies the last line of text to spaces
memsetw(text_ptr + (screen_height - temp_offset) * screen_width, space_char, screen_width);
// adjust the position of the cursor
csr_y = screen_height - 1;
}
}
void move_csr()
{
unsigned char curr_pos = csr_y * screen_width + csr_x;
outportb(0x3D4, 14);
outportb(0x3D5, curr_pos >> 8);
outportb(0x3D4, 15);
outportb(0x3D5, curr_pos);
}
void clear_screen()
{
unsigned short space_char;
// i need to generate the ascii code? that represents a space of the proper background color
space_char = 0x20 | (attrib << 8);
// write spaces to the entire screen
for (int i = 0; i < screen_height; i++)
{
for (int j = 0; j < screen_width; j++)
{
memsetw(text_ptr + i * screen_width, space_char, 1);
}
}
// reset the cursors x and y position
csr_x = 0;
csr_y = 0;
move_csr(); // and reset the cursor in the hardware
}
我一直在学习各种教程,试图制作我自己的操作系统。到目前为止,我对 here 中描述的 GNU 工具链一直很满意。 .我正在使用带有工具链的 GNU 汇编程序,因为我遵循了说明,并没有考虑将 NASM 构建到其中。我宁愿学习另一种风格的 Assembly,也不愿重做工具链。 :-P 我一直在模拟我对 Bran's Kernel Development tutorial. 的尝试我试图将 C 代码和 GAS 代码保存在单独的文件中,因为我不喜欢教程将所有程序集集中到引导加载程序中的方式。我在 Windows 7 机器上制作它,但使用 Debian 进行编码。我在 Windows 上安装了 Oracle VirtualBox,并用它来模拟 Debian。然后,我使用我的开发工具设置了 Debian,并使用文本编辑器进行编码。
下面是我正在使用的所有代码的链接、崩溃的 VirtualBox 日志、我在 Debian 终端中用来构建代码的命令的日志文件、目标文件、二进制文件和我制作的 iso 文件。
http://wikisend.com/download/243118/POS_C3.zip
如果您想自己查看错误,那么您应该能够将 pos.iso 挂载到虚拟机上并运行它。它应该像宣传的那样崩溃。此时我已经为引导加载程序、内核主要函数、GDT 和 VGA 编写了代码。我在它们自己的 C 文件中有内存和 I/O 端口函数,GDT 的 GAS 也在它自己的文件中。
最佳答案
我看到的两个问题:
1) 您的 put_str()
函数访问了超出 text
字符串末尾的无效内存,这是未定义的行为:
void put_str(char *text)
{
char *my_text = text; // (1)
int str_length;
for (str_length = 0; *my_text != '\0'; my_text++) // (2)
{
str_length++; // increment the count
}
for (int i = 0; i < str_length; i++)
{
put_char(my_text[i]); // (3)
}
}
在这种情况下,您将 my_text
分配给 (1) 处字符串的开头,然后将其推进到 (2) 处字符串的结尾。然后,您继续从 (3) 处的字符串末尾对其进行索引,这会越界读取内存。您可能打算在 (3) 处编写 text[i]
而不是 my_text[i]
,或者您可能忘记重置 my_text = text;
在该循环之前(两者都会产生相同的结果)。您也可以用调用 strlen()
来替换整个第一个循环,但有一个更简单的解决方案:
void put_str(char *text)
{
while (*text != 0)
{
put_char(*text);
text++;
}
}
这将遍历字符串以查找 NUL 终止符并输出每个字符。无需先计算字符串长度,然后再次遍历字符串。
2) scroll()
函数内对 memcpy()
的调用具有未定义的行为,因为源和目标内存范围可以重叠:
memcpy(text_ptr, text_ptr + temp_offset * screen_width, (screen_height - temp_offset) * screen_width * 2);
这可能不会导致您看到的三重故障异常,但它可能导致数据以奇怪的方式被错误复制,具体取决于 memcpy()
在您的标准库中的实现方式。但由于这是未定义的行为,您必须为任何事情做好准备,包括从您的 Nose 里飞出的恶魔。
简单易行的解决方案是将其替换为调用 memmove()
相反,即使源和目标内存范围重叠,它也定义了行为:
memmove(text_ptr, text_ptr + temp_offset * screen_width, (screen_height - temp_offset) * screen_width * 2);
关于c - C 指针是否导致我的自制内核 VGA 部分出现三重错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25656536/
我正在尝试使用谷歌浏览器的 Trace Event Profiling Tool分析我正在运行的 Node.js 应用程序。选择点样本后,我可以在三种 View 之间进行选择: 自上而下(树) 自上而
对于一个可能是菜鸟的问题,我们深表歉意,但尽管在 SO 上研究了大量教程和其他问题,但仍找不到答案。 我想做的很简单:显示一个包含大量数据库存储字符串的 Android ListView。我所说的“很
我已经开始了一个新元素的工作,并决定给 Foundation 5 一个 bash,看看它是什么样的。在创建带有水平字段的表单时,我在文档中注意到的第一件事是它们使用大量 div 来设置样式。所以我在下
我有一个 Windows 窗体用户控件,其中包含一个使用 BeginInvoke 委托(delegate)调用从单独线程更新的第 3 方图像显示控件。 在繁重的 CPU 负载下,UI 会锁定。当我附加
我有一堆严重依赖dom元素的JS代码。我目前使用的测试解决方案依赖于 Selenium ,但 AFAIK 无法正确评估 js 错误(addScript 错误不会导致您的测试失败,而 getEval 会
我正在制作一款基于滚动 2D map /图 block 的游戏。每个图 block (存储为图 block [21][11] - 每个 map 总共 231 个图 block )最多可以包含 21 个
考虑到以下情况,我是前端初学者: 某个 HTML 页面应该包含一个沉重的图像(例如 - 动画 gif),但我不想强制客户缓慢地等待它完全下载才能享受一个漂亮的页面,而是我更愿意给他看一个轻量级图像(例
我正在设计一个小软件,其中包括: 在互联网上获取资源, 一些用户交互(资源的快速编辑), 一些处理。 我想使用许多资源(它们都列在列表中)来这样做。每个都独立于其他。由于编辑部分很累,我想让用户(可能
我想比较两个理论场景。为了问题的目的,我简化了案例。但基本上它是您典型的生产者消费者场景。 (我关注的是消费者)。 我有一个很大的Queue dataQueue我必须将其传输给多个客户端。 那么让我们
我有一个二元分类问题,标签 0 和 1(少数)存在巨大不平衡。由于测试集带有标签 1 的行太少,因此我将训练测试设置为至少 70-30 或 60-40,因此仍然有重要的观察结果。由于我没有过多地衡量准
我是一名优秀的程序员,十分优秀!