c++ - 调试三重故障
问题描述
我正在尝试操作系统开发教程(wyoos.org),但无法让中断工作。当我尝试在 Virtualbox 中运行我的操作系统时,我得到了三重故障,有时是在激活中断之后。我了解到这可能是因为我的全局描述符表设置不正确。我可能正试图跳入数据块。
我很确定当一个中断被触发并且我没有处理它时会发生这种情况,但我很难调试它。有人可以指出我正确的方向吗?
我的中断处理包括三个文件interruptstubs.s
,interrupts.h
和interrupts.cpp
#interruptstubs.s
.set IRQ_BASE, 0x20
.section .text
.extern _ZN16InterruptManager15HandleInterruptEhj
.global _ZN16IterruptManager26IgnoreInterruptRequestEv
.macro HandleException num
.global _ZN16InterruptManager16HandleException\num\()Ev
_ZN16InterruptManager16handleException\num\()Ev:
movb $\num, (interruptnumber)
jmp int_bottom
.endm
.macro HandleInterruptRequest num
.global _ZN16InterruptManager26HandleInterruptRequest\num\()Ev
_ZN16InterruptManager26handleInterruptRequest\num\()Ev:
movb $\num + IRQ_BASE, (interruptnumber)
jmp int_bottom
.endm
HandleInterruptRequest 0x00
HandleInterruptRequest 0x01
int_bottom:
pusha
pushl %ds
pushl %es
pushl %fs
pushl %gs
pushl %esp
push (interruptnumber)
call _ZN16InterruptManager15HandleInterruptEhj
# addl $5, %esp
movl %eax, %esp
popl %gs
popl %fs
popl %es
popl %ds
popa
_ZN16IterruptManager26IgnoreInterruptRequestEv:
iret
.data
interruptnumber: .byte 0
中断.h
#ifndef __INTERRUPTS_H
#define __INTERRUPTS_H
#include "types.h"
#include "port.h"
#include "gdt.h"
class InterruptManager {
public:
InterruptManager(GlobalDescriptorTable* gdt);
~InterruptManager();
static void Activate();
static uint32_t HandleInterrupt(uint8_t interruptNumber, uint32_t esp );
static void InterruptIgnore();
static void HandleInterruptRequest();
static void HandleInterruptRequest0x00();
static void HandleInterruptRequest0x01();
protected:
struct GateDescriptor {
uint16_t handlerAddressLowBits;
uint16_t gdt_codeSegmentSelector;
uint8_t reserved;
uint8_t access_rights;
uint16_t handlerAddressHighBits;
} __attribute__((packed));
static GateDescriptor interruptDescriptorTable[256];
struct InterruptDescriptorTablePointer
{
uint16_t size;
uint32_t base;
} __attribute__((packed));
static void SetInterruptDescriptorTableEntry(
uint8_t interruptNumber,
uint16_t codeSegmentSelectorOffset,
void (*handler)(),
uint8_t DescriptorPrivilegeLevel,
uint8_t DescriptorType);
Port8BitSlow picMasterCommand;
Port8BitSlow picMasterData;
Port8BitSlow picWorkerCommand;
Port8BitSlow picWorkerData;
};
#endif
中断.cpp
#ifndef __INTERRUPTS_H
#define __INTERRUPTS_H
#include "types.h"
#include "port.h"
#include "gdt.h"
class InterruptManager {
public:
InterruptManager(GlobalDescriptorTable* gdt);
~InterruptManager();
static void Activate();
static uint32_t HandleInterrupt(uint8_t interruptNumber, uint32_t esp );
static void InterruptIgnore();
static void HandleInterruptRequest();
static void HandleInterruptRequest0x00();
static void HandleInterruptRequest0x01();
protected:
struct GateDescriptor {
uint16_t handlerAddressLowBits;
uint16_t gdt_codeSegmentSelector;
uint8_t reserved;
uint8_t access_rights;
uint16_t handlerAddressHighBits;
} __attribute__((packed));
static GateDescriptor interruptDescriptorTable[256];
struct InterruptDescriptorTablePointer
{
uint16_t size;
uint32_t base;
} __attribute__((packed));
static void SetInterruptDescriptorTableEntry(
uint8_t interruptNumber,
uint16_t codeSegmentSelectorOffset,
void (*handler)(),
uint8_t DescriptorPrivilegeLevel,
uint8_t DescriptorType);
Port8BitSlow picMasterCommand;
Port8BitSlow picMasterData;
Port8BitSlow picWorkerCommand;
Port8BitSlow picWorkerData;
};
#endif
(v2_ordergroove-py27) ~/s/wyoos ❯❯❯ cat interrupts.cpp
#include "interrupts.h"
void printf(const char* str);
InterruptManager::GateDescriptor InterruptManager::interruptDescriptorTable[256];
void InterruptManager::SetInterruptDescriptorTableEntry(
uint8_t interruptNumber,
uint16_t codeSegmentSelectorOffset,
void (*handler)(),
uint8_t DescriptorPrivilegeLevel,
uint8_t descriptorType)
{
printf("\nGDT Entry Start\n");
interruptDescriptorTable[interruptNumber].handlerAddressLowBits = ((uint32_t)handler) & 0xFFFF;
interruptDescriptorTable[interruptNumber].handlerAddressHighBits = (((uint32_t)handler) >> 16) & 0xFFFF;
interruptDescriptorTable[interruptNumber].gdt_codeSegmentSelector = codeSegmentSelectorOffset;
const uint8_t IDT_DESC_PRESENT = 0x00;
interruptDescriptorTable[interruptNumber].access_rights = IDT_DESC_PRESENT | descriptorType | (DescriptorPrivilegeLevel << 5);
interruptDescriptorTable[interruptNumber].reserved = 0;
printf("\nGDT Entry End\n");
}
InterruptManager::InterruptManager(GlobalDescriptorTable* gdt)
: picMasterCommand(0x20),
picMasterData(0x21),
picWorkerCommand(0xA0),
picWorkerData(0xA1)
{
uint16_t CodeSegment = gdt->CodeSegmentSelector();
const uint8_t IDT_INTERRUPT_GATE = 0xE;
for(uint16_t i = 0; i < 256; i++) {
SetInterruptDescriptorTableEntry(i, CodeSegment, &InterruptIgnore, 0, IDT_INTERRUPT_GATE);
}
SetInterruptDescriptorTableEntry(0x20, CodeSegment, &HandleInterruptRequest0x00, 0, IDT_INTERRUPT_GATE);
SetInterruptDescriptorTableEntry(0x21, CodeSegment, &HandleInterruptRequest0x01, 0, IDT_INTERRUPT_GATE);
picMasterCommand.Write(0x11);
picWorkerCommand.Write(0x11);
picMasterData.Write(0x20);
picWorkerData.Write(0x20);
picMasterData.Write(0x04);
picWorkerData.Write(0x02);
picMasterData.Write(0x01);
picWorkerData.Write(0x01);
picMasterData.Write(0x00);
picWorkerData.Write(0x00);
InterruptDescriptorTablePointer idt;
idt.size = 256 * sizeof(GateDescriptor) - 1;
idt.base = (uint32_t)interruptDescriptorTable;
asm volatile("lidt %0" : : "m" (idt));
}
void InterruptManager::InterruptIgnore() {
}
void InterruptManager::HandleInterruptRequest0x01() {
printf("Handle 0x01");
}
void InterruptManager::HandleInterruptRequest0x00() {
printf("Handle 0x00");
}
InterruptManager::~InterruptManager()
{
}
void InterruptManager::Activate()
{
printf("\nStart activate\n");
asm("sti");
printf("Done activate\n");
}
uint32_t InterruptManager::HandleInterrupt(uint8_t interrupt, uint32_t esp)
{
printf("start handle interrupt");
//const char* debugString = " INTERRUPT";
char* foo = "INTERRUPT 0x00";
char* hex = "0123456789ABCDEF";
foo[12] = hex[(interrupt >> 4) & 0xF];
foo[13] = hex[interrupt & 0xF];
printf(foo);
return esp;
}
我的完整源代码可在https://github.com/munk/wyoos/tree/gdt-triple-fault获得
解决方案
推荐阅读
- nginx - 如何将 NGINX 反向代理到具有自签名证书的后端服务器?
- sql - SQLite - 从相同的 ID 获取 SUM
- javascript - .addField 值可以写入包含文件“名称”的数组吗?
- awk - 在bash中按指定的序列长度过滤掉FASTA文件
- c# - SimpleInjector 延迟反射
- excel - 如何在 Excel 数据透视图中绘制 90000 个点
- javascript - 如何减少我的 vuejs 网络应用程序的 app.js 大小?
- cgal - 查找源面和目标面之间的所有面
- php - Laravel 广播身份验证工作或用于网络保护或自定义保护
- node.js - (节点:3966)UnhandledPromiseRejectionWarning:错误:querySrv ECONNREFUSED