如何在保护模式下执行间接远跳转/调用?首先我认为这样做是允许的:
jmp 0x10:eax;
Run Code Online (Sandbox Code Playgroud)
(不用担心段选择器..我的 GDT 的第二个条目是有效的代码段)
但是当nasm组装的时候,却出现了语法错误。查看Intel(指令集参考)手册的Book 2a,只能使用 来完成jmp ptr16:32,其中ptr16:32是立即值,或者使用 来完成jmp m16:32,其中 是m16:32包含48位跳转地址(16:32 )。
现在我尝试以这种方式对其进行编码:
mov dword[ds:jumpaddress_offset],eax
; or just dword[jumpaddress_offset],eax
mov word[ds:jumpaddress_sel],0x10;
; or just mov word[ds:jumpaddress_sel],0x10;
jmp dword far [dword ds:jumpaddress];
...
jumpaddress:
jumpaddress_sel dw 0
jumpaddress_offset dd 0
Run Code Online (Sandbox Code Playgroud)
它组装成功,但当我尝试运行它时,处理器出现一般保护故障并重新启动。我不知道发生了什么事。
我假设编码是这样的:
(例如我想使用间接跳转跳转到0x10:0x8010)
dw 0x10
dd 0x8010
Run Code Online (Sandbox Code Playgroud)
这可能有什么问题吗?难道48位内存值应该以小端编码吗?并且应该这样编码吗?
;0010 0000 8010
dd 0x10,0x80,0,0,0x10,0
Run Code Online (Sandbox Code Playgroud)
我还没有尝试做最后一项。
我知道还有其他一些类似的问题,无论是否是 StackOverflow。我为此研究了很多,但仍然没有找到单一的解决方案。我正在做一个操作系统作为一个副项目。我一直在做汇编,但现在我想加入 C 代码。为了测试,我制作了这个汇编代码文件(称为 test.asm):
[BITS 32]
GLOBAL _a
SECTION .text
_a:
jmp $
Run Code Online (Sandbox Code Playgroud)
然后我制作了这个 C 文件(称为 main.c):
extern void a(void);
int main(void)
{
a();
}
Run Code Online (Sandbox Code Playgroud)
为了链接,我使用了这个文件(称为 make.bat):
"C:\minGW\bin\gcc.exe" -ffreestanding -c -o c.o main.c
nasm -f coff -o asm.o test.asm
"C:\minGW\bin\ld.exe" -Ttext 0x100000 --oformat binary -o out.bin c.o asm.o
pause
Run Code Online (Sandbox Code Playgroud)
我一直在研究多年,但我仍在努力寻找答案。我希望这不会被标记为重复。我承认存在类似的问题,但都有不同的答案,没有一个对我有用。
问题:我做错了什么?
我正在尝试编写一个非常简单的MBR来开始学习如何编写MBR /内核.这是我到目前为止(从其他MBR的部分创建).我从使用nasm然后使用ld到链接的二进制文件与仅使用nasm两者有点不同,但这似乎不是问题.
我刚开始,jmp 0:continue但似乎跳转到0000:7c22(或001d单独使用nasm ...我相信我没有指定它开始于7c00)但我希望跳转到:7a22或:7a1d重新定位代码的地址.我尝试使用just jmp continue,然后在下面看到未注释,将堆栈指针添加到continue指针,推送它并返回.当我读到第一个扇区时,我得到的只是一个闪烁的光标.任何帮助表示赞赏.
; nasm+ld nasm comment
global _start
_start:
xor cx, cx ; 6631c9 31c9 Set segment registers to zero
mov es, cx ; 8ec1 8ec1
mov ds, cx ; 8ed9 8ed9
mov ss, cx ; 8ed1 8ed1
mov sp, 0x7A00 ; 66bc007a bc007a Stack
mov di, sp ; 6689e7 89e7 Bottom of relocation point
mov esi, _start ; be007c0000 66be00000000
cld …Run Code Online (Sandbox Code Playgroud) 我正在编写MBR并使用QEMU进行测试.
当将读取扇区用于内存(int 0x13, ah=0x02)时,该int指令似乎阻止了我的程序的执行,并且它继续挂起.我已经用各种打印语句对此进行了测试,以确认这是特定的指令阻塞.
什么可以使中断阻止?我认为这只能通过cli指令完成,即使这样也不会阻止int指令.
对于上下文,这是导致阻塞中断的代码read_sectors_16:
[bits 16]
[ORG 0x7C00]
jmp 0x000:start_16 ; ensure cs == 0x0000
reset_failure_str db 'error: boot disk reset', 13, 10, 0
read_failure_str db 'error: boot disk read', 13, 10, 0
boot_segaddr dw 0x7E00
read_attempt_str db 'read attempt', 13, 10, 0
end_read_attempt_str db 'end read attempt', 13, 10, 0
start_16:
;; Initialize segment registers
mov ax, cs
mov ds, ax
mov es, …Run Code Online (Sandbox Code Playgroud) 我正在开发一个简单的内核,并且一直在尝试实现一个键盘中断处理程序来摆脱端口轮询。我一直在-kernel模式下使用 QEMU (为了减少编译时间,因为使用生成 isogrub-mkrescue需要相当长的时间)并且它工作得很好,但是当我想切换到-cdrom模式时它突然开始崩溃。我不知道为什么。
最终我意识到,当它从 ISO 引导时,它还会在引导内核本身之前运行 GRUB 引导加载程序。我发现 GRUB 可能会将处理器切换到保护模式,这会导致问题。
问题:通常我会简单地初始化中断处理程序,每当我按下一个键时,它就会被处理。但是,当我使用 iso 运行内核并按下一个键时,虚拟机就崩溃了。这发生在 qemu 和 VMWare 中,所以我认为我的中断一定有问题。
请记住,只要我不使用 GRUB,代码就可以正常工作。
interrupts_init()(见下文)是main()内核函数中调用的第一件事。
本质上的问题是:有没有办法让它在保护模式下工作?.
我的内核的完整副本可以在我的GitHub 存储库中找到。一些相关文件:
lowlevel.asm:
section .text
global keyboard_handler_int
global load_idt
extern keyboard_handler
keyboard_handler_int:
pushad
cld
call keyboard_handler
popad
iretd
load_idt:
mov edx, [esp + 4]
lidt [edx]
sti
ret
Run Code Online (Sandbox Code Playgroud)
interrupts.c:
#include <assembly.h> // defines inb() and outb()
#define IDT_SIZE 256
#define …Run Code Online (Sandbox Code Playgroud) 我正在制作一个操作系统,并使用 Qemu 对其进行调试。我想要一种方法来读取一些指令末尾的内存的一些大块。怎么做?可以对 Qemu 说将 ram 复制到文件中吗?如果不是我能做什么?
我正在写自己的小操作系统。我已经完成启动,进入保护模式,一些文本打印以及与qemu的串行通信。我已经尝试添加中断两天了。我到处都在寻找,包括其他系统资源。不,我下面没有代码,qemu(我不知道为什么)关闭了。我包括geust errorsqemu。
这是我的主文件 kernel.cpp
__asm__ (".pushsection .text.start\r\n" \
"jmp main\r\n" \
".popsection\r\n");
#include <stdbool.h>
#include "utils/debug.h"
#include "drivers/display.h"
#include "drivers/serial.h"
#include "drivers/keyboard.h"
#include "drivers/pic.h"
#include "interrupt/interrupt.h"
void initDrivers(){
serial::init();
pic::init();
interrupt::init();
interrupt::enable();
terminal_initialize();
}
int main() {
initDrivers();
terminal_setcolor(VGA_COLOR_WHITE);
terminal_writestring("Hello!");
debug::println("after println");
bool alive = true;
while(alive) {
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
PIC驱动程序pic.cpp和pic.h
#include "pic.h"
#include <stddef.h>
#include <stdint.h>
#include "IO.h"
#include "../utils/debug.h"
/*
* IMR - Interrupt Mask Register
* IRR - Interrupt Request …Run Code Online (Sandbox Code Playgroud) 我已经很长一段时间没有使用 C 和汇编语言进行编程了(大约 2 年)。现在我决定重新开始,但我想做一些更复杂的事情。我考虑过创建一个简单的内核。现在我在网上找到了这个源代码:
启动.asm:
global loader
extern kernel_main
MAGIC equ 0xbad
FLAGS equ 0x3
CHECKSUM equ -(MAGIC+FLAGS)
section .text
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
loader:
call kernel_main
cli
quit:
hlt
jmp quit
Run Code Online (Sandbox Code Playgroud)
内核.c:
void print(char *text) {
char *memory = (char*)0xb8000;
while(*text) {
*memory++ = *text++;
*memory++ = 0x3;
}
}
void kernel_main() {
print("My cat sometimes smells like cafe. I love it.");
}
Run Code Online (Sandbox Code Playgroud)
链接器.ld:
ENTRY(loader)
SECTIONS {
. = 0x100000;
.text : { *(.text) …Run Code Online (Sandbox Code Playgroud) 我没有真正意义上的问题,但我会尽力澄清内容问题。假设我们有一个微内核(PC Intel x86;32 位保护模式),具有针对每个 CPU 异常工作的中断描述符表 (IDT)和中断服务例程 (ISR)。ISR 被成功调用,比如在出现Division by Zero异常的情况下。
global ir0
extern isr_handler
isr0:
cli
push 0x00 ; Dummy error code
push %1 ; Interrupt number
jmp isr_exc_handler
isr_exc_handler:
; Save the current processor state
pusha
mov ax, ds
push eax
mov ax, 0x10 ; Load kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; Push current stack pointer
mov eax, esp
push eax …Run Code Online (Sandbox Code Playgroud) 我有一个使用 UEFI 启动的小内核。我正在使用 QEMU 进行虚拟化。我想编写一个 xHCI 驱动程序来支持我的内核中的 USB 键盘。我很难找到简洁明了的信息。我在我的内核中“发现”了 xHCI。我有一个指向其 PCI 配置空间的指针。它支持 MSI-X。我想使用 MSI-X,但我无法理解它如何与 xHCI 和 USB 配合使用。
我的问题是,通常 osdev.org 提供的信息非常丰富,并且具有我需要实现某些功能的基础。就MSI-X而言,情况似乎并非如此。我很难将 osdev.org 上的所有信息与 MSI-X 功能联系起来。
基本上,我找到 MSI-X 表,然后在那里设置一些地址,告诉 xHCI PCI 设备写入该地址以触发中断。但是中断处理程序会在某个时刻被调用吗?我是否需要轮询该地址以确定是否发生中断?我本以为 MSI-X 表中的矢量控制字段可以让我设置中断矢量,但所有位都被保留。
编辑
我发现以下 stackoverflow 问答部分回答了我的问题:Question about Message Signaled Interrupts (MSI) on x86 LAPIC system。
所以基本上,数据寄存器的低字节包含要触发的向量,消息地址寄存器包含要触发的 LAPIC id。我还有一些问题。
为什么“消息地址寄存器包含固定顶部0xFEE”。
消息地址寄存器中的 RH、DM 和 XX 位是什么?
这如何与 LAPIC 配合使用?基本上,它是如何触发 LAPIC 中的中断的。这是 PCI 设备的一个特殊功能,允许它们在 LAPIC 中触发中断。或者只是 PCI 设备向 LAPIC 的内存映射寄存器写入一些触发中断的特定数据。因为通常 LAPIC 是从内核内部访问的,每个 LAPIC 的地址都相同。是来自 CPU 外部的某种处理器间中断吗?