标签: osdev

使用 gdb 在 qemu 中调试时内存位置错误

我正在用汇编程序编写一个小内核。我在 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)

assembly gdb qemu osdev gdbserver

2
推荐指数
1
解决办法
2447
查看次数

使用“pushf”并弹出到 32 位寄存器是否会破坏堆栈?

我想通过将 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)。

这意味着我弹出的内容基本上比最初推送的要多 - 返回这里时我的堆栈会发生什么情况?

c assembly kernel osdev

2
推荐指数
1
解决办法
1175
查看次数

多重引导 1 引导信息总大小

有没有一种快速可靠的方法可以找出内存中 Multiboot 1 启动信息的总大小?

\n\n

只是为了澄清:我不是在询问 EBX 寄存器中的值所指向的结构的大小,而是在询问内存中所有信息的总大小。

\n\n

我目前正在开发 x86 Multiboot 1 兼容内核。该标准不保证 GRUB 将在何处放置此信息或其总大小。标准规定:

\n\n
\n

“Multiboot信息结构及其相关子结构可以由引导加载程序放置在内存中的任何位置(当然,为内核和引导模块保留的内存除外)。这是操作系统\xe2\x80\x99的责任以避免覆盖该内存,直到使用完毕为止。”

\n
\n\n

实际上,这似乎总是在最低 1MB 内存中加载。\n到目前为止,在启动​​期间,我使用最低 1MB 的标识映射来初始化启动分页结构,以确保可以访问多重启动信息。找出这个结构的位置很简单,但我还没有找到任何关于找到准确尺寸的信息。(最好不要走遍整个结构)。

\n

x86 kernel grub osdev multiboot

2
推荐指数
1
解决办法
267
查看次数

如何正确设置页目录项的权限?

首先:这个问题是关于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) 访问,因此,设置“用户/管理员位”。

该页表由第一个页目录项指向。但是该页目录条目的“用户/管理员位”应该被清除(仅管理员)还是设置(用户和管理员)?有什么不同?

memory paging x86 intel osdev

2
推荐指数
1
解决办法
900
查看次数

尝试“sti”时的一般保护错误

尝试在测试引导加载程序上实现硬件中断。例外正在工作(因此发现它是 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)

x86 qemu interrupt osdev bootloader

2
推荐指数
1
解决办法
1381
查看次数

初始加载后如何更新 GDT 条目?

使用 初始化并将 GDT 加载到 GDTR 后lgdt,以后如何更新 GDT?
如果我使用sgdt命令获取基地址,然后更新或添加条目,然后使用 重新加载它,我是否正确lgdt?还有其他方法吗?
或者我是否遗漏了一些东西,并且 GDT 永远不会“意味着”在初始化和加载后进行更新?

x86 operating-system osdev i386 gdt

2
推荐指数
1
解决办法
500
查看次数

在C中访问PCB的过程

我在Linux工作,我有点困惑,我是否可以访问过程的PCB?如果是,那么我们可以访问它的哪些内容并将其打印到终端上,如果没有,那么为什么不呢?

谢谢回答 .....

c linux osdev linux-kernel

1
推荐指数
1
解决办法
4865
查看次数

文本模式光标未出现在 qemu vga 模拟器中

我在文本模式下更新光标位置的函数有问题,函数定义和声明是

#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)

x86 gcc qemu inline-assembly osdev

1
推荐指数
1
解决办法
1220
查看次数

在Rings之间跳转时的处理器行为

当某些内核代码(Ring 0)对用户代码(Ring 3)例程进行"调用"时,我找不到任何关于标准CPU(即:x86)的真正含义的具体信息.

1)执行该例程时,CPU模式状态是否变为用户模式?

2)在用户级例程执行最后的'ret'指令后,由于尝试返回内核空间代码而引发异常?

x86 cpu-architecture osdev kernel-mode

1
推荐指数
1
解决办法
69
查看次数

GCC内联汇编错误:'lidt'的指令后缀无效

我试图从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)

为什么会出现此问题,我该如何解决?

assembly gcc x86-64 inline-assembly osdev

1
推荐指数
1
解决办法
141
查看次数