我正在用汇编程序编写一个小内核。我在 QEMU 中运行它,并遇到一些错误的问题。现在我想用dbg调试内核。所以我像这样组装它:
$ nasm -g -f elf -o myos.elf myos.asm
$ objcopy --only-keep-debug myos.elf myos.sym
$ objcopy -O binary myos.elf myos.bin
Run Code Online (Sandbox Code Playgroud)
然后我在 QEMU 中运行它:
$ qemu-system-i386 -s -S myos.bin
Run Code Online (Sandbox Code Playgroud)
然后我与 gdb 连接:
$ gdb
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
symbol-file myos.sym
Reading symbols from /home/sven/Projekte/myos/myos.sym...done.
Run Code Online (Sandbox Code Playgroud)
welcome我的内核中有一个指向字符串的标签。在测试时,我尝试查看该字符串,结果如下:
(gdb) x/32b welcome
0x1e <welcome>: 0x00 0xf0 0xa5 0xfe 0x00 0xf0 0x87 0xe9
0x26: 0x00 0xf0 0x6e 0xc9 0x00 0xf0 0x6e 0xc9
0x2e: 0x00 0xf0 …Run Code Online (Sandbox Code Playgroud) 我想通过将 CPU 标志压入堆栈来读取它们,然后将它们弹出到寄存器中,如下所示:
uint32_t getEflags() {
uint32_t eflags;
asm ("pushf");
asm ("pop %eax");
asm ("mov %%eax, %0" : "=r"(eflags));
return eflags;
}
Run Code Online (Sandbox Code Playgroud)
现在我发现这是一个错误,因为Pushf只压入 EFLAGS 的低 16 位,然后我将它们弹出到 32 位寄存器中(我需要Pushfd)。
这意味着我弹出的内容基本上比最初推送的要多 - 返回这里时我的堆栈会发生什么情况?
有没有一种快速可靠的方法可以找出内存中 Multiboot 1 启动信息的总大小?
\n\n只是为了澄清:我不是在询问 EBX 寄存器中的值所指向的结构的大小,而是在询问内存中所有信息的总大小。
\n\n我目前正在开发 x86 Multiboot 1 兼容内核。该标准不保证 GRUB 将在何处放置此信息或其总大小。标准规定:
\n\n\n\n\n“Multiboot信息结构及其相关子结构可以由引导加载程序放置在内存中的任何位置(当然,为内核和引导模块保留的内存除外)。这是操作系统\xe2\x80\x99的责任以避免覆盖该内存,直到使用完毕为止。”
\n
实际上,这似乎总是在最低 1MB 内存中加载。\n到目前为止,在启动期间,我使用最低 1MB 的标识映射来初始化启动分页结构,以确保可以访问多重启动信息。找出这个结构的位置很简单,但我还没有找到任何关于找到准确尺寸的信息。(最好不要走遍整个结构)。
\n首先:这个问题是关于IA-32(x86)架构的。
我有一个关于旧版(非 PSE、非 PAE)寻呼的问题。在传统分页中,我们有一个包含 1024 个条目的页目录,每个条目都指向一个页表。每个页表包含 1024 个条目(这些是页),每个条目都指向一个 4096 字节对齐的物理地址。
同时,每个页目录项和页表项都保存一些标志,并且它们都有一个“U”标志(位#2):如果设置了该标志,则该页可以由用户(ring3)和用户(ring3)访问。主管(ring0);但是,如果未设置此标志,则只有管理程序 (ring0) 可以访问它。该标志通常称为“用户/管理员位”。
问题:如果我想让ring0和ring3页都在同一个页表中,该怎么办?我可以为页表中的条目设置适当的权限,但是相应的页目录条目应该指定什么权限呢?
例如:我设置了第一个页表(虚拟地址范围:0x00000000 - 0x003FFFFF)来映射物理地址范围0x00000000 - 0x003FFFFF(这涵盖了4兆字节)。第一个兆字节 (0x00000000 - 0x000FFFFF) 只能由管理员 (ring0) 访问,因此,“用户/管理员位”被清除。以下 3 MB (0x00100000 - 0x003FFFFF) 应可由用户 (ring3) 和管理员 (ring0) 访问,因此,设置“用户/管理员位”。
该页表由第一个页目录项指向。但是该页目录条目的“用户/管理员位”应该被清除(仅管理员)还是设置(用户和管理员)?有什么不同?
尝试在测试引导加载程序上实现硬件中断。例外正在工作(因此发现它是 GPF)。当尝试时sti,会发生 GPF。这是我的主要代码:
cli
lgdt [gdt_desc]
lidt [idt_desc]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:bit_32
bit_32:
[bits 32]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, 0x8000
mov esp, eax
mov ebp, esp
sti ; exception raised
Run Code Online (Sandbox Code Playgroud)
这就是我的 GDT 的样子:
start_gdt:
null:
dd 0x0
dd 0x0
code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 01000000b
db 0x0
data:
dw 0xffff …Run Code Online (Sandbox Code Playgroud) 使用 初始化并将 GDT 加载到 GDTR 后lgdt,以后如何更新 GDT?
如果我使用sgdt命令获取基地址,然后更新或添加条目,然后使用 重新加载它,我是否正确lgdt?还有其他方法吗?
或者我是否遗漏了一些东西,并且 GDT 永远不会“意味着”在初始化和加载后进行更新?
我在Linux工作,我有点困惑,我是否可以访问过程的PCB?如果是,那么我们可以访问它的哪些内容并将其打印到终端上,如果没有,那么为什么不呢?
谢谢回答 .....
我在文本模式下更新光标位置的函数有问题,函数定义和声明是
#include <sys/io.h>
signed int VGAx = 0,VGAy=0;
void setcursor()
{
uint16_t position = VGAx+VGAy*COLS;
outb(0x0f, 0x03d4);
outb((position<<8)>>8,0x03d5);
outb(0x0e,0x03d4);
outb(position>>8,0x03d5);
}
Run Code Online (Sandbox Code Playgroud)
和文件 sys/io.h
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm ("inb %0, %%al":"=rm"(value):"a"(port));
return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %%al, $0"::"rm"(value), "a"(port));
}
Run Code Online (Sandbox Code Playgroud)
使用该功能前光标有时闪烁下划线有时不出现而使用该功能后没有光标出现
这是运行的主要功能
#include <vga/vga.h>
int kmain(){
setcursor()
setbgcolor(BLACK);
clc();
setforecolor(BLUE);
terminal_write('h');
setcursor();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我尝试使用此功能
void enable_cursor() { …Run Code Online (Sandbox Code Playgroud) 当某些内核代码(Ring 0)对用户代码(Ring 3)例程进行"调用"时,我找不到任何关于标准CPU(即:x86)的真正含义的具体信息.
1)执行该例程时,CPU模式状态是否变为用户模式?
2)在用户级例程执行最后的'ret'指令后,由于尝试返回内核空间代码而引发异常?
我试图从C调用一些汇编代码。最近,我在将程序从x86切换到x86-64之前开始工作。我有以下代码:
__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg));
Run Code Online (Sandbox Code Playgroud)
哪里&idtreg是对结构的引用。用GCC进行编译会给我这个错误:
'lidt'的无效指令后缀
当我添加$令牌时:
__asm__ __volatile__("lidtl $(%0)" : : "r" (&idt_reg));
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
非法的立即寄存器操作数(%rax)
为什么会出现此问题,我该如何解决?