我已经加载了一个包含256个条目的idt表,它们都指向类似的处理程序:
因此,当公共处理程序进入时,堆栈正确对齐并包含异常/中断号,错误代码(可能只是虚拟代码),eflags,cs和eip.
我的问题是关于从中断处理程序返回.我iret从堆栈中取出异常编号和错误代码后使用返回,但这不适用于异常nr 8; 如果我把错误代码留在堆栈上,那么它返回正常!
问题:
iret确定是否必须弹出错误代码?我想创建一个自包含的C函数来打印一个字符串.这将是操作系统的一部分,所以我无法使用stdio.h.如何创建一个函数来打印我传递给它的字符串而不使用stdio.h?我必须在汇编中写它吗?
我在许多ose(和一些引导程序)中看到,它们cli在从实模式切换到保护模式之前都禁用了interrupt().为什么我们需要这样做?
我的教授说,建议使用PIT而不是RTC来实现基于纪元的循环调度程序.他没有真正提到任何具体原因,我也想不出任何理由.有什么想法吗?
我有一个带有两个绝对符号的内核的链接描述文件:_kernel_start和_kernel_end.但是,我只收到链接器重定位错误_kernel_end:
In function `kernel::mem::mm::setup_memorymap':
/home/virtlink/kernel/src/mem/mm.rs:25:(.text._ZN3mem2mm15setup_memorymap):
relocation truncated to fit: R_X86_64_PC32 against symbol `_kernel_end'
defined in *ABS* section in ./kernel.bin
Run Code Online (Sandbox Code Playgroud)
这里有很多关于这个错误的问题,但我没有找到解决我特定问题的问题.
显然,这个:
_kernel_start = .;
Run Code Online (Sandbox Code Playgroud)
...被视为32位,而这:
. += KERNEL_BASE;
_kernel_end = . - KERNEL_BASE;
Run Code Online (Sandbox Code Playgroud)
...被视为64位.如果我将_kernel_end符号移动到. += KERNEL_BASE线上方,如下所示:
_kernel_end = .;
. += KERNEL_BASE;
Run Code Online (Sandbox Code Playgroud)
......然后再次运作.但我想_kernel_end在我的链接器脚本的末尾.
链接描述文件将引导代码放在内存开头,其余代码放在64位虚拟内存空间的上半部分.它看起来像这样:
OUTPUT_FORMAT(elf64-x86-64)
KERNEL_BASE = 0xFFFFFFFF80000000;
SECTIONS
{
/* Boot code at 1 MiB */
. = 1M;
_kernel_start = .;
.boot :
{
KEEP( *(.multiboot) …Run Code Online (Sandbox Code Playgroud) 在x86_64体系结构上,write!宏使用字符串参数按预期工作,但不使用整数.当使用整数参数时,我得到一个奇怪的循环(例如write!(writer, "Hello {}!", 123)产生无限的"Hello Hello Hello ...").在aarch64上,write!宏根本不起作用.
我使用以下命令构建libcore:
rustc -C opt-level=3 -Z no-landing-pads -C no-stack-check \
--crate-type rlib --target {arch}-unknown-linux-gnu lib.rs
Run Code Online (Sandbox Code Playgroud)
{arch}分别在哪里x86_64或aarch64.
我的代码使用相同的代码生成选项构建.libcore版本对应于我的编译器.有问题的代码在这里.你能说出问题的可能原因吗?
重要更新:
这是更精简的代码.libcore是在项目中构建的,因此一切都在掌控之中.上面的循环来自机器重启.代码完全适用于aarch64,但奇怪的是在x86_64上的Write :: write_fmt内崩溃.仔细检查我的启动程序集 - 似乎没有错误.
我已经开始了我的OS开发之旅.人们通常会大声说使用原始二进制而不是ELF(或其他结构化格式)是自定义操作系统中应用程序的常见错误.我可以说,因为ELF提供了额外的好处(存储元信息的地方,如符号表,.debug和.line).但是,让我们考虑内核二进制本身一分钟.它应该是结构化的(如ELF),如果是,为什么?否则写一个ELF加载器并在stage1加载器之后立即挤压它似乎是浪费.
AFAIK Linux内核是一个ELF文件,但我不知道原因.
最近,我开始在NASM和C中开发一个操作系统.我已经制作了一个启动加载程序,内核,文件系统等.到目前为止,我直接使用VGA文本模式来写入地址0x000B8000.所以,我决定切换到视频模式而不是文本模式.我选择了最大显示分辨率320x200,但后来我意识到有三个问题.首先,只有256种不同的颜色.其次,分辨率太小.第三,写入地址0x000A0000太慢了.我尝试做一些动画,但它非常迟钝,有时它会在下一帧之前等待超过一秒钟.
我在互联网上搜索了一些关于如何切换到更高分辨率的解释,例如1920x1080如何使用256*256*256颜色而不仅仅是256.我发现的一切都说很难使用更高的分辨率,因为你必须开发所有不同的驱动程序显卡类型和某些卡没有文档,所以我们必须使用逆向工程.
我真的想在我的操作系统中引入高分辨率图形.真的很难还是有简单的方法?关于如何解决这个问题的任何建议?
从技术上讲,UEFI提供了许多功能,这些功能是操作系统(如文件系统)的基础工作的一部分.在某种程度上,遗憾的是,在启动过程中,操作系统会丢弃并重新实现所有内容.
我想知道将多少功能操作系统作为简单的UEFI应用程序实现它.我在考虑图形用户界面和多任务处理.使用FAT32作为文件系统,UEFI应该可以用于很多目的,因此应该标识映射内存.它将构成一个非常精简和简单的操作系统,甚至可能无需安装.
问题是在完全成熟的操作系统的功能方面提供什么是可行的限制?有什么建议?
我正在尝试编写一个非常简单的内核用于学习目的.在阅读了大量有关x86架构中PIC和IRQ的文章后,我发现这IRQ1是键盘处理程序.我正在使用以下代码打印正在按下的键:
#include "port_io.h"
#define IDT_SIZE 256
#define PIC_1_CTRL 0x20
#define PIC_2_CTRL 0xA0
#define PIC_1_DATA 0x21
#define PIC_2_DATA 0xA1
void keyboard_handler();
void load_idt(void*);
struct idt_entry
{
unsigned short int offset_lowerbits;
unsigned short int selector;
unsigned char zero;
unsigned char flags;
unsigned short int offset_higherbits;
};
struct idt_pointer
{
unsigned short limit;
unsigned int base;
};
struct idt_entry idt_table[IDT_SIZE];
struct idt_pointer idt_ptr;
void load_idt_entry(char isr_number, unsigned long base, short int selector, char flags)
{
idt_table[isr_number].offset_lowerbits = base & 0xFFFF;
idt_table[isr_number].offset_higherbits …Run Code Online (Sandbox Code Playgroud)