如何加载IDT?
How to load IDT?
我正在写自己的小 os。我已经完成了启动、进入保护模式、一些文本打印和与 qemu 的串行通信。
两天多来我一直在尝试添加中断。我到处都在寻找,包括其他系统资源。不,我有下面的代码,qemu(我不知道为什么)关闭了。我包括来自 qemu 的 geust errors
。
这是我的主文件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;
}
PIC driver 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 Register
* ISR - In-Service Register or Interrupt Service Routine
*
*/
namespace pic {
static const uint16_t PIC1_PORT = 0x20; // I/O offset address for master PIC
static const uint16_t PIC2_PORT = 0xA0; // I/O offset address for slave PIC
static const uint16_t PIC1_SPORT = 0x21; // I/O offset address for master PIC data
static const uint16_t PIC2_SPORT = 0xA1; // I/O offset address for slave PIC data
static const uint8_t OCW3_READ_IRR = 0x0A; // OCW3 irq ready next CMD read
static const uint8_t OCW3_READ_ISR = 0x0B; // OCW3 irq service next CMD read
void init(){
outb(PIC1_PORT, 0x11); // Sending ICW1 to first PIC (starting initialization)
io_wait(); // Waiting for PIC to process
outb(PIC2_PORT, 0x11); // Sending ICW1 to second PIC
io_wait(); // Waiting for PIC to process
outb(PIC1_SPORT, 0x20); // Sending ICW2 to first PIC (Mapping IRQs)
io_wait(); // Waiting for PIC to process
outb(PIC2_SPORT, 0x28); // Sending ICW2 to second PIC
io_wait(); // Waiting for PIC to process
outb(PIC1_SPORT, 4); // Sending ICW3 to first PIC, "there is a second one - slave" (0000 0100)
io_wait(); // Waiting for PIC to process
outb(PIC2_SPORT, 2); // Sending ICW3 to second PIC "You are slave" (0000 0010)
io_wait(); // Waiting for PIC to process
outb(PIC1_SPORT, 1); // Sending ICW4 to first PIC putting it into 80x86 mode (0000 0001)
io_wait(); // Waiting for PIC to process
outb(PIC2_SPORT, 1); // Sending ICW4 to second PIC putting it into 80x86 mode (0000 0001)
io_wait(); // Waiting for PIC to process
debug::println("PIC initialized!");
}
uint16_t __getIrqReg(uint8_t ocw3) {
outb(PIC1_SPORT, ocw3);
outb(PIC2_SPORT, ocw3);
return (inb(PIC2_SPORT) << 8) | inb(PIC1_SPORT);
}
uint16_t getIRR() {
return __getIrqReg(OCW3_READ_IRR);
}
uint16_t getISR() {
return __getIrqReg(OCW3_READ_ISR);
}
void ack(uint8_t irq) {
/* write EOI */
if (irq >= 16) return; // It's not a valid irq
if (irq >= 8) outb(PIC2_SPORT, 0x20); // It's a PIC2
// PIC1 EOI must be called anyway
outb(PIC1_SPORT, 0x20);
}
void mask(uint8_t irq, bool enable) {
uint16_t port;
if (irq < 8) port = PIC1_SPORT;
else if (irq < 16) {
port = PIC2_SPORT;
irq -= 8;
} else return;
uint8_t value = inb(port);
wait(150);
if (enable) value = value & ~(1 << irq);
else value = value | (1 << irq);
outb(port, value);
wait(150);
}
}
header:
#ifndef PIC_H
#define PIC_H
#include <stdint.h>
namespace pic {
void init();
uint16_t getIRR();
uint16_t getISR();
void ack(uint8_t irq);
void mask(uint8_t irq, bool enabled);
}
#endif
IDT 的所有设置 idt.cpp
#include <stdint.h>
extern "C" {
// CPU Exceptions https://wiki.osdev.org/Exceptions
extern void isr_0(void); // Divide By Zero
extern void isr_1(void); // Debug
extern void isr_2(void); // Non-Maskable Interrupt
extern void isr_3(void); // Breakpoint
extern void isr_4(void); // Overflow
extern void isr_5(void); // Bound Range Exceeded
extern void isr_6(void); // Invalid Opcode
extern void isr_7(void); // Device Not Avaible
extern void isr_8(void); // Double Fault
extern void isr_9(void); // Coprocessor Segment Overrun (Old - out of use)
extern void isr_10(void); // Invalid TTS
extern void isr_11(void); // Segment Not Present
extern void isr_12(void); // Stack Segment Fault
extern void isr_13(void); // General Protection Fault
extern void isr_14(void); // Page Fault
extern void isr_16(void); // x87 Floating-Point Exception
extern void isr_17(void); // Aligment Check
extern void isr_18(void); // Machine Check
extern void isr_19(void); // SIMD Floating Point Exception
extern void isr_20(void); // Virtualization Exception
extern void isr_30(void); // Security Exception
// IRQs https://wiki.osdev.org/Interrupts#General_IBM-PC_Compatible_Interrupt_Information
extern void isr_32(void); // Programmable Interrupt Timer
extern void isr_33(void); // Keyboard
extern void isr_34(void); // Used Internally (Never Raised)
extern void isr_35(void); // COM2
extern void isr_36(void); // COM1
extern void isr_37(void); // LPT2
extern void isr_38(void); // Floppy Disk
extern void isr_39(void); // LPT1
extern void isr_40(void); // CMOS RTC
extern void isr_41(void); // Peripherals
extern void isr_42(void); // Peripherals
extern void isr_43(void); // Peripherals
extern void isr_44(void); // PS/2 Mouse
extern void isr_45(void); // FPU / Coprocessor / Inter-processor
extern void isr_46(void); // Primary ATA Hard Disk
extern void isr_47(void); // Seconadry ATA Hard Disk
extern void syscallHandler(void);
extern void isr_49(void);
extern void isr_50(void);
}
/* IDT - Interrupt Descriptor Table https://wiki.osdev.org/IDT
* offset - tells where Interrupt Service Routine Is Located
* selector - something like properties
* flags:
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* +---+---+---+---+---+---+---+---+
* | P | DPL | S | GateType |
* +---+---+---+---+---+---+---+---+
* P - Present (0 if unused)
* DPL - Sort of permission to call`
* Storage Segment - We want it 0
* GateType - Trap, Interrupt, Task
*/
struct idt_entry {
uint16_t offset_low;
uint16_t selector;
uint8_t unused;
uint8_t flags;
uint16_t offset_high;
};
#define IDT_ENTRY(offset, selector, flags) { \
(uint16_t)((uintptr_t)(offset) & 0xFFFF), \
(selector), \
0, \
(flags), \
(uint16_t)(((uintptr_t)(offset) >> 16) & 0xFFFF) \
}
#define IDT_INTERRUPT_GATE 0xE
#define IDT_TRAP_GATE 0xF
#define IDT_RING0 (0 << 5)
#define IDT_RING3 (3 << 5)
#define IDT_PRESENT (1 << 7)
extern "C" {
idt_entry idt[] = {
IDT_ENTRY(isr_0, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_1, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_2, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_3, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_4, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_5, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_6, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_7, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_8, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_9, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_10, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_11, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_12, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_13, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_14, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(isr_16, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_17, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_18, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_19, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_20, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(isr_32, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_33, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_34, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_35, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_36, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_37, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_38, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_39, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_40, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_41, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_42, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_43, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_44, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_45, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_46, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_47, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
//IDT_ENTRY(syscallHandler, 0x8, IDT_TRAP_GATE | IDT_RING3 | IDT_PRESENT),
IDT_ENTRY(isr_49, 0x8, IDT_INTERRUPT_GATE | IDT_RING3 | IDT_PRESENT),
IDT_ENTRY(isr_50, 0x8, IDT_INTERRUPT_GATE | IDT_RING3 | IDT_PRESENT),
};
uint16_t idt_size = sizeof(idt) - 1;
}
将 interrupt.cpp
和 interrupt.h
粘合在一起的文件(在那个文件中有一个 causes crashes
的函数,但我会在所有文件之后解释它。)
#include "interrupt.h"
#include "signals.h"
#include <stdint.h>
#include "../utils/debug.h"
#include "../drivers/IO.h"
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20
#define EX_DEVIDE_BY_ZERO 0
#define EX_DEBUG 1
#define EX_NON_MASKABLE_INTERRUPT 2
#define EX_BREAKPOINT 3
#define EX_OVERFLOW 4
#define EX_BOUND_RANGE_EXCEEDED 5
#define EX_INVALID_OPCODE 6
#define EX_DEVICE_NOT_AVAILABLE 7
#define EX_DOUBLE_FAULT 8
#define EX_COPROCESSOR_SEGMENT_OVERRUN 9
#define EX_INVAILD_TSS 10
#define EX_SEGMENT_NOT_PRESENT 11
#define EX_STACK_SEGMENT_FAULT 12
#define EX_GENERAL_PROTECTION_FAULT 13
#define EX_PAGE_FAULT 14
#define EX_X87_FLOATING_POINT_EXCEPTION 16
#define EX_ALIGNMENT_CHECK 17
#define EX_MACHINE_CHECK 18
#define EX_SIMD_FLOATING_POINT_EXCEPTION 19
#define EX_VIRTUALIZATION_EXCEPTION 20
const char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
void (*interrupt::irqHandlers[16])(int) = {0};
void interrupt::init(){
__asm__ (
"push $idt \r\n" \
"pushw idt_size \r\n" \
"lidt (%esp) \r\n"
);
}
void interrupt::disable() {
asm volatile ("cli");
}
void interrupt::enable() {
asm volatile ("sti");
}
extern "C" {
volatile unsigned long signalPending = 0;
}
static bool handleUserspaceException(const InterruptContext* context) {
siginfo_t siginfo = {};
switch (context->interrupt) {
case EX_DEVIDE_BY_ZERO:
siginfo.si_signo = SIGFPE;
siginfo.si_code = FPE_INTDIV;
siginfo.si_addr = (void*) context->eip;
break;
case EX_DEBUG:
case EX_BREAKPOINT:
siginfo.si_signo = SIGTRAP;
siginfo.si_code = TRAP_BRKPT;
siginfo.si_addr = (void*) context->eip;
break;
case EX_OVERFLOW:
case EX_BOUND_RANGE_EXCEEDED:
case EX_STACK_SEGMENT_FAULT:
case EX_GENERAL_PROTECTION_FAULT:
siginfo.si_signo = SIGSEGV;
siginfo.si_code = SI_KERNEL;
siginfo.si_addr = (void*) context->eip;
break;
case EX_INVALID_OPCODE:
siginfo.si_signo = SIGILL;
siginfo.si_code = ILL_ILLOPC;
siginfo.si_addr = (void*) context->eip;
break;
case EX_PAGE_FAULT:
siginfo.si_signo = SIGSEGV;
siginfo.si_code = SEGV_MAPERR;
asm ("mov %%cr2, %0" : "=r"(siginfo.si_addr));
break;
case EX_X87_FLOATING_POINT_EXCEPTION:
case EX_SIMD_FLOATING_POINT_EXCEPTION:
siginfo.si_signo = SIGFPE;
siginfo.si_code = FPE_FLTINV;
siginfo.si_addr = (void*) context->eip;
break;
default:
return false;
}
//Process::current->raiseSignal(siginfo);
return true;
}
extern "C" InterruptContext* handleInterrupt(InterruptContext* context) {
InterruptContext* newContext = context;
if (context->interrupt <= 31 && context->cs != 0x8) {
if (!handleUserspaceException(context)) goto handleKernelException;
} else if (context->interrupt <= 31) { // CPU Exception
handleKernelException:
debug::print("Exception ");
debug::print(context->interrupt);
debug::print(" (");
debug::print(exception_messages[context->interrupt]);
debug::println(") occurred!");
debug::print("eax: 0x");
debug::print(context->eax);
debug::print(", ebx: 0x");
debug::print(context->ebx);
debug::print(", ecx: 0x");
debug::print(context->ecx);
debug::print(", edx: 0x");
debug::println(context->edx);
debug::print("edi: 0x");
debug::print(context->edi);
debug::print(", esi: 0x");
debug::print(context->esi);
debug::print(", ebp: 0x");
debug::print(context->ebp);
debug::print(", error: 0x");
debug::println(context->error);
debug::print("eip: 0x");
debug::print(context->eip);
debug::print(", cs: 0x");
debug::print(context->cs);
debug::print(", eflags: 0x");
debug::println(context->eflags);
if (context->cs != 0x8) {
debug::print("ss: 0x");
debug::print(context->ss);
debug::print(", esp: 0x");
debug::println(context->esp);
}
// Halt the cpu
while (true) asm volatile ("cli; hlt");
} else if (context->interrupt <= 47) { // IRQ
int irq = context->interrupt - 32;
if (irq == 0) {
//newContext = Process::schedule(context);
}
if (interrupt::irqHandlers[irq]) {
interrupt::irqHandlers[irq](irq);
}
// Send End of Interrupt
if (irq >= 8) {
outb(PIC2_COMMAND, PIC_EOI);
}
outb(PIC1_COMMAND, PIC_EOI);
} else if (context->interrupt == 0x32) {
//newContext = Signal::sigreturn(context);
debug::println("Keyboard!!");
} else {
debug::print("Unknown interrupt ");
debug::print(context->interrupt);
debug::println("!");
}
return newContext;
}
header:
#ifndef INTERRUPS_H
#define INTERRUPS_H
#include <stdint.h>
extern "C" volatile unsigned long signalPending;
namespace Signal {
static inline bool isPending() { return signalPending; }
}
struct InterruptContext {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t interrupt;
uint32_t error;
// These are pushed by the cpu when an interrupt happens.
uint32_t eip;
uint32_t cs;
uint32_t eflags;
// These are only valid if the interrupt came from Ring 3
uint32_t esp;
uint32_t ss;
};
union sigval {
int sival_int;
void* sival_ptr;
};
typedef __UINT64_TYPE__ __uid_t;
typedef struct {
int si_signo;
int si_code;
int si_pid;
__uid_t si_uid;
void* si_addr;
int si_status;
union sigval si_value;
} siginfo_t;
namespace interrupt {
extern void (*irqHandlers[])(int);
void init();
void disable();
void enable();
}
#endif
最后是汇编代码intr.s
.section .text
.macro isr no
.global isr_\no
isr_\no:
push [=16=] # no error code
push $\no
jmp commonHandler
.endm
.macro isr_error_code no
.global isr_\no
isr_\no:
# an error code was already pushed
push $\no
jmp commonHandler
.endm
commonHandler:
cld
# Push registers
push %ebp
push %edi
push %esi
push %edx
push %ecx
push %ebx
push %eax
# Switch to kernel data segment
mov [=16=]x10, %ax
mov %ax, %ds
mov %ax, %es
mov %esp, %eax
and $(~0xFF), %esp # Align the stack
sub , %esp
push %eax
call handleInterrupt
mov %eax, %esp
# Check whether signals are pending.
mov signalPending, %ebx
test %ebx, %ebx
jz 1f
# Don't handle signals when returning to kernelspace.
mov 40(%esp), %ebx # cs
cmp [=16=]x8, %ebx
je 1f
and $(~0xFF), %esp # Align the stack
sub , %esp
push %eax
# call handleSignal
mov %eax, %esp
# Switch back to user data segment
1: mov [=16=]x23, %ax
mov %ax, %ds
mov %ax, %es
pop %eax
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
# Remove error code and interrupt number from stack
add , %esp
iret
# CPU Exceptions
isr 0 # Devide-by-zero Error
isr 1 # Debug
isr 2 # Non-maskable Interrupt
isr 3 # Breakpoint
isr 4 # Overflow
isr 5 # Bound Range Exceeded
isr 6 # Invalid Opcode
isr 7 # Device Not Available
isr_error_code 8 # Double Fault
isr 9 # Coprocessor Segment Overrun
isr_error_code 10 # Invalid TSS
isr_error_code 11 # Segment Not Present
isr_error_code 12 # Stack-Segement Fault
isr_error_code 13 # General Protection Fault
isr_error_code 14 # Page Fault
#isr 15 # Reserved
isr 16 # x87 Floating-Point Exception
isr_error_code 17 # Alignment Check
isr 18 # Machine Check
isr 19 # SIMD Floating-Point Exception
isr 20 # Virtualization Exception
# IRQs
isr 32
isr 33
isr 34
isr 35
isr 36
isr 37
isr 38
isr 39
isr 40
isr 41
isr 42
isr 43
isr 44
isr 45
isr 46
isr 47
#isr 48 # Syscall
isr 49 # Schedule
isr 50 # sigreturn
.global beginSigreturn
beginSigreturn:
# This section is mapped in all user address spaces. When a userspace
# program returns from a signal handler it will return to this address and
# and then perform a sigreturn.
int [=16=]x32
.global endSigreturn
endSigreturn:
现在 compile.sh
我正在使用宏编译(我知道我会尝试让它们参与的 makefile)
if [ $# -eq 0 ]; then
nasm -g -f elf32 -F dwarf -o boot.o bootloader/bootloader.asm
ld -melf_i386 -Ttext=0x7c00 -nostdlib --nmagic -o boot.elf boot.o
objcopy -O binary boot.elf boot.bin
g++ -std=c++14 -g -c -m32 -ffreestanding kernel.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/display.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/serial.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/keyboard.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/pic.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding interrupt/interrupt.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding interrupt/idt.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding utils/debug.cpp
g++ -m32 -c interrupt/intr.s -o intr.o
ld -r -m elf_i386 kernel.o display.o serial.o keyboard.o pic.o interrupt.o idt.o intr.o debug.o -o main.o
ld -melf_i386 -Tlinker.ld -nostdlib --nmagic -o main.elf main.o
objcopy -O binary main.elf main.bin
dd if=/dev/zero of=disk.img bs=512 count=2880
dd if=boot.bin of=disk.img bs=512 conv=notrunc
dd if=main.bin of=disk.img bs=512 seek=1 conv=notrunc
rm -rf boot.o
rm -rf kernel.o
rm -rf serial.o
rm -rf main.o
rm -rf keyboard.o
rm -rf debug.o
rm -rf pic.o
rm -rf display.o
rm -rf boot.bin
rm -rf kernel.bin
else
if [ = "clean" ]; then
rm -rf boot.o
echo successfully removed boot.o!
rm -rf kernel.o
echo successfully removed kernel.o!
rm -rf IO.o
echo successfully removed IO.o!
rm -rf main.o
echo successfully removed main.o!
rm -rf boot.bin
echo successfully removed boot.bin!
rm -rf kernel.bin
echo successfully removed kernel.bin!
rm -rf boot.elf
echo successfully removed boot.elf!
rm -rf kernel.elf
echo successfully removed kernel.elf!
rm -rf disk.img
echo successfully removed disk.img!
echo Cleanup done!
fi
fi
最后一个 run.sh
和 rund.sh
我用来宏 qemu 等
qemu-system-i386 -fda disk.img -d guest_errors & \
echo "Reading kernel log (Ctrl+C for exit)"
tail -f virtual.log
qemu-system-i386 -m 1024 -fda disk.img -S -s &
gdb main.elf \
-ex 'target remote localhost:1234' \
-ex 'layout src' \
-ex 'layout reg' \
-ex 'break main' \
-ex 'continue'
我也包括 qemu guest errors
输出
EAX=0000be44 EBX=0000be44 ECX=00090000 EDX=000003f8
ESI=00000000 EDI=00000000 EBP=bee00000 ESP=0008ffba
EIP=ffc80000 EFL=00000016 [----AP-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007d35 00000017
IDT= 0000bee0 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=0000268b CCD=0000be44 CCO=ADDL
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
就像我说的。导致关机的代码片段在 interrupt.cpp
void interrupt::init(){
__asm__ (
"push $idt \r\n" \
"pushw idt_size \r\n" \
"lidt (%esp) \r\n"
);
}
如果我评论这个,os 工作,但没有中断。
我不知道如何解决它。
有什么想法吗?
问题是您没有恢复 interrupt::init 中的堆栈指针,因此该函数 return 中的 return 变成了杂草。
最简单但效果不佳的解决方法是简单地添加
add , %esp
lidt 之后。
一个更好的解决方案是将其更改为不在内联汇编中修改 esp。
void interrupt::init()
{
struct __attribute__((packed)) { uint16_t size; uint32_t idt; }
descr = { idt_size, idt };
__asm__ __volatile__ ("lidt %0" : : "m"(descr));
}
虽然我很感激你把所有的代码都包括在内,但我没有仔细阅读所有的代码;我只是简单回答了我注意到的第一个问题,所以你可能还有问题。
我正在写自己的小 os。我已经完成了启动、进入保护模式、一些文本打印和与 qemu 的串行通信。
两天多来我一直在尝试添加中断。我到处都在寻找,包括其他系统资源。不,我有下面的代码,qemu(我不知道为什么)关闭了。我包括来自 qemu 的 geust errors
。
这是我的主文件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;
}
PIC driver 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 Register
* ISR - In-Service Register or Interrupt Service Routine
*
*/
namespace pic {
static const uint16_t PIC1_PORT = 0x20; // I/O offset address for master PIC
static const uint16_t PIC2_PORT = 0xA0; // I/O offset address for slave PIC
static const uint16_t PIC1_SPORT = 0x21; // I/O offset address for master PIC data
static const uint16_t PIC2_SPORT = 0xA1; // I/O offset address for slave PIC data
static const uint8_t OCW3_READ_IRR = 0x0A; // OCW3 irq ready next CMD read
static const uint8_t OCW3_READ_ISR = 0x0B; // OCW3 irq service next CMD read
void init(){
outb(PIC1_PORT, 0x11); // Sending ICW1 to first PIC (starting initialization)
io_wait(); // Waiting for PIC to process
outb(PIC2_PORT, 0x11); // Sending ICW1 to second PIC
io_wait(); // Waiting for PIC to process
outb(PIC1_SPORT, 0x20); // Sending ICW2 to first PIC (Mapping IRQs)
io_wait(); // Waiting for PIC to process
outb(PIC2_SPORT, 0x28); // Sending ICW2 to second PIC
io_wait(); // Waiting for PIC to process
outb(PIC1_SPORT, 4); // Sending ICW3 to first PIC, "there is a second one - slave" (0000 0100)
io_wait(); // Waiting for PIC to process
outb(PIC2_SPORT, 2); // Sending ICW3 to second PIC "You are slave" (0000 0010)
io_wait(); // Waiting for PIC to process
outb(PIC1_SPORT, 1); // Sending ICW4 to first PIC putting it into 80x86 mode (0000 0001)
io_wait(); // Waiting for PIC to process
outb(PIC2_SPORT, 1); // Sending ICW4 to second PIC putting it into 80x86 mode (0000 0001)
io_wait(); // Waiting for PIC to process
debug::println("PIC initialized!");
}
uint16_t __getIrqReg(uint8_t ocw3) {
outb(PIC1_SPORT, ocw3);
outb(PIC2_SPORT, ocw3);
return (inb(PIC2_SPORT) << 8) | inb(PIC1_SPORT);
}
uint16_t getIRR() {
return __getIrqReg(OCW3_READ_IRR);
}
uint16_t getISR() {
return __getIrqReg(OCW3_READ_ISR);
}
void ack(uint8_t irq) {
/* write EOI */
if (irq >= 16) return; // It's not a valid irq
if (irq >= 8) outb(PIC2_SPORT, 0x20); // It's a PIC2
// PIC1 EOI must be called anyway
outb(PIC1_SPORT, 0x20);
}
void mask(uint8_t irq, bool enable) {
uint16_t port;
if (irq < 8) port = PIC1_SPORT;
else if (irq < 16) {
port = PIC2_SPORT;
irq -= 8;
} else return;
uint8_t value = inb(port);
wait(150);
if (enable) value = value & ~(1 << irq);
else value = value | (1 << irq);
outb(port, value);
wait(150);
}
}
header:
#ifndef PIC_H
#define PIC_H
#include <stdint.h>
namespace pic {
void init();
uint16_t getIRR();
uint16_t getISR();
void ack(uint8_t irq);
void mask(uint8_t irq, bool enabled);
}
#endif
IDT 的所有设置 idt.cpp
#include <stdint.h>
extern "C" {
// CPU Exceptions https://wiki.osdev.org/Exceptions
extern void isr_0(void); // Divide By Zero
extern void isr_1(void); // Debug
extern void isr_2(void); // Non-Maskable Interrupt
extern void isr_3(void); // Breakpoint
extern void isr_4(void); // Overflow
extern void isr_5(void); // Bound Range Exceeded
extern void isr_6(void); // Invalid Opcode
extern void isr_7(void); // Device Not Avaible
extern void isr_8(void); // Double Fault
extern void isr_9(void); // Coprocessor Segment Overrun (Old - out of use)
extern void isr_10(void); // Invalid TTS
extern void isr_11(void); // Segment Not Present
extern void isr_12(void); // Stack Segment Fault
extern void isr_13(void); // General Protection Fault
extern void isr_14(void); // Page Fault
extern void isr_16(void); // x87 Floating-Point Exception
extern void isr_17(void); // Aligment Check
extern void isr_18(void); // Machine Check
extern void isr_19(void); // SIMD Floating Point Exception
extern void isr_20(void); // Virtualization Exception
extern void isr_30(void); // Security Exception
// IRQs https://wiki.osdev.org/Interrupts#General_IBM-PC_Compatible_Interrupt_Information
extern void isr_32(void); // Programmable Interrupt Timer
extern void isr_33(void); // Keyboard
extern void isr_34(void); // Used Internally (Never Raised)
extern void isr_35(void); // COM2
extern void isr_36(void); // COM1
extern void isr_37(void); // LPT2
extern void isr_38(void); // Floppy Disk
extern void isr_39(void); // LPT1
extern void isr_40(void); // CMOS RTC
extern void isr_41(void); // Peripherals
extern void isr_42(void); // Peripherals
extern void isr_43(void); // Peripherals
extern void isr_44(void); // PS/2 Mouse
extern void isr_45(void); // FPU / Coprocessor / Inter-processor
extern void isr_46(void); // Primary ATA Hard Disk
extern void isr_47(void); // Seconadry ATA Hard Disk
extern void syscallHandler(void);
extern void isr_49(void);
extern void isr_50(void);
}
/* IDT - Interrupt Descriptor Table https://wiki.osdev.org/IDT
* offset - tells where Interrupt Service Routine Is Located
* selector - something like properties
* flags:
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* +---+---+---+---+---+---+---+---+
* | P | DPL | S | GateType |
* +---+---+---+---+---+---+---+---+
* P - Present (0 if unused)
* DPL - Sort of permission to call`
* Storage Segment - We want it 0
* GateType - Trap, Interrupt, Task
*/
struct idt_entry {
uint16_t offset_low;
uint16_t selector;
uint8_t unused;
uint8_t flags;
uint16_t offset_high;
};
#define IDT_ENTRY(offset, selector, flags) { \
(uint16_t)((uintptr_t)(offset) & 0xFFFF), \
(selector), \
0, \
(flags), \
(uint16_t)(((uintptr_t)(offset) >> 16) & 0xFFFF) \
}
#define IDT_INTERRUPT_GATE 0xE
#define IDT_TRAP_GATE 0xF
#define IDT_RING0 (0 << 5)
#define IDT_RING3 (3 << 5)
#define IDT_PRESENT (1 << 7)
extern "C" {
idt_entry idt[] = {
IDT_ENTRY(isr_0, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_1, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_2, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_3, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_4, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_5, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_6, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_7, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_8, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_9, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_10, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_11, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_12, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_13, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_14, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(isr_16, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_17, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_18, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_19, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_20, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(0, 0, 0),
IDT_ENTRY(isr_32, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_33, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_34, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_35, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_36, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_37, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_38, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_39, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_40, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_41, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_42, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_43, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_44, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_45, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_46, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
IDT_ENTRY(isr_47, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
//IDT_ENTRY(syscallHandler, 0x8, IDT_TRAP_GATE | IDT_RING3 | IDT_PRESENT),
IDT_ENTRY(isr_49, 0x8, IDT_INTERRUPT_GATE | IDT_RING3 | IDT_PRESENT),
IDT_ENTRY(isr_50, 0x8, IDT_INTERRUPT_GATE | IDT_RING3 | IDT_PRESENT),
};
uint16_t idt_size = sizeof(idt) - 1;
}
将 interrupt.cpp
和 interrupt.h
粘合在一起的文件(在那个文件中有一个 causes crashes
的函数,但我会在所有文件之后解释它。)
#include "interrupt.h"
#include "signals.h"
#include <stdint.h>
#include "../utils/debug.h"
#include "../drivers/IO.h"
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20
#define EX_DEVIDE_BY_ZERO 0
#define EX_DEBUG 1
#define EX_NON_MASKABLE_INTERRUPT 2
#define EX_BREAKPOINT 3
#define EX_OVERFLOW 4
#define EX_BOUND_RANGE_EXCEEDED 5
#define EX_INVALID_OPCODE 6
#define EX_DEVICE_NOT_AVAILABLE 7
#define EX_DOUBLE_FAULT 8
#define EX_COPROCESSOR_SEGMENT_OVERRUN 9
#define EX_INVAILD_TSS 10
#define EX_SEGMENT_NOT_PRESENT 11
#define EX_STACK_SEGMENT_FAULT 12
#define EX_GENERAL_PROTECTION_FAULT 13
#define EX_PAGE_FAULT 14
#define EX_X87_FLOATING_POINT_EXCEPTION 16
#define EX_ALIGNMENT_CHECK 17
#define EX_MACHINE_CHECK 18
#define EX_SIMD_FLOATING_POINT_EXCEPTION 19
#define EX_VIRTUALIZATION_EXCEPTION 20
const char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
void (*interrupt::irqHandlers[16])(int) = {0};
void interrupt::init(){
__asm__ (
"push $idt \r\n" \
"pushw idt_size \r\n" \
"lidt (%esp) \r\n"
);
}
void interrupt::disable() {
asm volatile ("cli");
}
void interrupt::enable() {
asm volatile ("sti");
}
extern "C" {
volatile unsigned long signalPending = 0;
}
static bool handleUserspaceException(const InterruptContext* context) {
siginfo_t siginfo = {};
switch (context->interrupt) {
case EX_DEVIDE_BY_ZERO:
siginfo.si_signo = SIGFPE;
siginfo.si_code = FPE_INTDIV;
siginfo.si_addr = (void*) context->eip;
break;
case EX_DEBUG:
case EX_BREAKPOINT:
siginfo.si_signo = SIGTRAP;
siginfo.si_code = TRAP_BRKPT;
siginfo.si_addr = (void*) context->eip;
break;
case EX_OVERFLOW:
case EX_BOUND_RANGE_EXCEEDED:
case EX_STACK_SEGMENT_FAULT:
case EX_GENERAL_PROTECTION_FAULT:
siginfo.si_signo = SIGSEGV;
siginfo.si_code = SI_KERNEL;
siginfo.si_addr = (void*) context->eip;
break;
case EX_INVALID_OPCODE:
siginfo.si_signo = SIGILL;
siginfo.si_code = ILL_ILLOPC;
siginfo.si_addr = (void*) context->eip;
break;
case EX_PAGE_FAULT:
siginfo.si_signo = SIGSEGV;
siginfo.si_code = SEGV_MAPERR;
asm ("mov %%cr2, %0" : "=r"(siginfo.si_addr));
break;
case EX_X87_FLOATING_POINT_EXCEPTION:
case EX_SIMD_FLOATING_POINT_EXCEPTION:
siginfo.si_signo = SIGFPE;
siginfo.si_code = FPE_FLTINV;
siginfo.si_addr = (void*) context->eip;
break;
default:
return false;
}
//Process::current->raiseSignal(siginfo);
return true;
}
extern "C" InterruptContext* handleInterrupt(InterruptContext* context) {
InterruptContext* newContext = context;
if (context->interrupt <= 31 && context->cs != 0x8) {
if (!handleUserspaceException(context)) goto handleKernelException;
} else if (context->interrupt <= 31) { // CPU Exception
handleKernelException:
debug::print("Exception ");
debug::print(context->interrupt);
debug::print(" (");
debug::print(exception_messages[context->interrupt]);
debug::println(") occurred!");
debug::print("eax: 0x");
debug::print(context->eax);
debug::print(", ebx: 0x");
debug::print(context->ebx);
debug::print(", ecx: 0x");
debug::print(context->ecx);
debug::print(", edx: 0x");
debug::println(context->edx);
debug::print("edi: 0x");
debug::print(context->edi);
debug::print(", esi: 0x");
debug::print(context->esi);
debug::print(", ebp: 0x");
debug::print(context->ebp);
debug::print(", error: 0x");
debug::println(context->error);
debug::print("eip: 0x");
debug::print(context->eip);
debug::print(", cs: 0x");
debug::print(context->cs);
debug::print(", eflags: 0x");
debug::println(context->eflags);
if (context->cs != 0x8) {
debug::print("ss: 0x");
debug::print(context->ss);
debug::print(", esp: 0x");
debug::println(context->esp);
}
// Halt the cpu
while (true) asm volatile ("cli; hlt");
} else if (context->interrupt <= 47) { // IRQ
int irq = context->interrupt - 32;
if (irq == 0) {
//newContext = Process::schedule(context);
}
if (interrupt::irqHandlers[irq]) {
interrupt::irqHandlers[irq](irq);
}
// Send End of Interrupt
if (irq >= 8) {
outb(PIC2_COMMAND, PIC_EOI);
}
outb(PIC1_COMMAND, PIC_EOI);
} else if (context->interrupt == 0x32) {
//newContext = Signal::sigreturn(context);
debug::println("Keyboard!!");
} else {
debug::print("Unknown interrupt ");
debug::print(context->interrupt);
debug::println("!");
}
return newContext;
}
header:
#ifndef INTERRUPS_H
#define INTERRUPS_H
#include <stdint.h>
extern "C" volatile unsigned long signalPending;
namespace Signal {
static inline bool isPending() { return signalPending; }
}
struct InterruptContext {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t interrupt;
uint32_t error;
// These are pushed by the cpu when an interrupt happens.
uint32_t eip;
uint32_t cs;
uint32_t eflags;
// These are only valid if the interrupt came from Ring 3
uint32_t esp;
uint32_t ss;
};
union sigval {
int sival_int;
void* sival_ptr;
};
typedef __UINT64_TYPE__ __uid_t;
typedef struct {
int si_signo;
int si_code;
int si_pid;
__uid_t si_uid;
void* si_addr;
int si_status;
union sigval si_value;
} siginfo_t;
namespace interrupt {
extern void (*irqHandlers[])(int);
void init();
void disable();
void enable();
}
#endif
最后是汇编代码intr.s
.section .text
.macro isr no
.global isr_\no
isr_\no:
push [=16=] # no error code
push $\no
jmp commonHandler
.endm
.macro isr_error_code no
.global isr_\no
isr_\no:
# an error code was already pushed
push $\no
jmp commonHandler
.endm
commonHandler:
cld
# Push registers
push %ebp
push %edi
push %esi
push %edx
push %ecx
push %ebx
push %eax
# Switch to kernel data segment
mov [=16=]x10, %ax
mov %ax, %ds
mov %ax, %es
mov %esp, %eax
and $(~0xFF), %esp # Align the stack
sub , %esp
push %eax
call handleInterrupt
mov %eax, %esp
# Check whether signals are pending.
mov signalPending, %ebx
test %ebx, %ebx
jz 1f
# Don't handle signals when returning to kernelspace.
mov 40(%esp), %ebx # cs
cmp [=16=]x8, %ebx
je 1f
and $(~0xFF), %esp # Align the stack
sub , %esp
push %eax
# call handleSignal
mov %eax, %esp
# Switch back to user data segment
1: mov [=16=]x23, %ax
mov %ax, %ds
mov %ax, %es
pop %eax
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
# Remove error code and interrupt number from stack
add , %esp
iret
# CPU Exceptions
isr 0 # Devide-by-zero Error
isr 1 # Debug
isr 2 # Non-maskable Interrupt
isr 3 # Breakpoint
isr 4 # Overflow
isr 5 # Bound Range Exceeded
isr 6 # Invalid Opcode
isr 7 # Device Not Available
isr_error_code 8 # Double Fault
isr 9 # Coprocessor Segment Overrun
isr_error_code 10 # Invalid TSS
isr_error_code 11 # Segment Not Present
isr_error_code 12 # Stack-Segement Fault
isr_error_code 13 # General Protection Fault
isr_error_code 14 # Page Fault
#isr 15 # Reserved
isr 16 # x87 Floating-Point Exception
isr_error_code 17 # Alignment Check
isr 18 # Machine Check
isr 19 # SIMD Floating-Point Exception
isr 20 # Virtualization Exception
# IRQs
isr 32
isr 33
isr 34
isr 35
isr 36
isr 37
isr 38
isr 39
isr 40
isr 41
isr 42
isr 43
isr 44
isr 45
isr 46
isr 47
#isr 48 # Syscall
isr 49 # Schedule
isr 50 # sigreturn
.global beginSigreturn
beginSigreturn:
# This section is mapped in all user address spaces. When a userspace
# program returns from a signal handler it will return to this address and
# and then perform a sigreturn.
int [=16=]x32
.global endSigreturn
endSigreturn:
现在 compile.sh
我正在使用宏编译(我知道我会尝试让它们参与的 makefile)
if [ $# -eq 0 ]; then
nasm -g -f elf32 -F dwarf -o boot.o bootloader/bootloader.asm
ld -melf_i386 -Ttext=0x7c00 -nostdlib --nmagic -o boot.elf boot.o
objcopy -O binary boot.elf boot.bin
g++ -std=c++14 -g -c -m32 -ffreestanding kernel.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/display.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/serial.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/keyboard.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding drivers/pic.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding interrupt/interrupt.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding interrupt/idt.cpp
g++ -std=c++14 -g -c -m32 -ffreestanding utils/debug.cpp
g++ -m32 -c interrupt/intr.s -o intr.o
ld -r -m elf_i386 kernel.o display.o serial.o keyboard.o pic.o interrupt.o idt.o intr.o debug.o -o main.o
ld -melf_i386 -Tlinker.ld -nostdlib --nmagic -o main.elf main.o
objcopy -O binary main.elf main.bin
dd if=/dev/zero of=disk.img bs=512 count=2880
dd if=boot.bin of=disk.img bs=512 conv=notrunc
dd if=main.bin of=disk.img bs=512 seek=1 conv=notrunc
rm -rf boot.o
rm -rf kernel.o
rm -rf serial.o
rm -rf main.o
rm -rf keyboard.o
rm -rf debug.o
rm -rf pic.o
rm -rf display.o
rm -rf boot.bin
rm -rf kernel.bin
else
if [ = "clean" ]; then
rm -rf boot.o
echo successfully removed boot.o!
rm -rf kernel.o
echo successfully removed kernel.o!
rm -rf IO.o
echo successfully removed IO.o!
rm -rf main.o
echo successfully removed main.o!
rm -rf boot.bin
echo successfully removed boot.bin!
rm -rf kernel.bin
echo successfully removed kernel.bin!
rm -rf boot.elf
echo successfully removed boot.elf!
rm -rf kernel.elf
echo successfully removed kernel.elf!
rm -rf disk.img
echo successfully removed disk.img!
echo Cleanup done!
fi
fi
最后一个 run.sh
和 rund.sh
我用来宏 qemu 等
qemu-system-i386 -fda disk.img -d guest_errors & \
echo "Reading kernel log (Ctrl+C for exit)"
tail -f virtual.log
qemu-system-i386 -m 1024 -fda disk.img -S -s &
gdb main.elf \
-ex 'target remote localhost:1234' \
-ex 'layout src' \
-ex 'layout reg' \
-ex 'break main' \
-ex 'continue'
我也包括 qemu guest errors
输出
EAX=0000be44 EBX=0000be44 ECX=00090000 EDX=000003f8
ESI=00000000 EDI=00000000 EBP=bee00000 ESP=0008ffba
EIP=ffc80000 EFL=00000016 [----AP-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 00007d35 00000017
IDT= 0000bee0 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=0000268b CCD=0000be44 CCO=ADDL
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
就像我说的。导致关机的代码片段在 interrupt.cpp
void interrupt::init(){
__asm__ (
"push $idt \r\n" \
"pushw idt_size \r\n" \
"lidt (%esp) \r\n"
);
}
如果我评论这个,os 工作,但没有中断。 我不知道如何解决它。 有什么想法吗?
问题是您没有恢复 interrupt::init 中的堆栈指针,因此该函数 return 中的 return 变成了杂草。
最简单但效果不佳的解决方法是简单地添加
add , %esp
lidt 之后。
一个更好的解决方案是将其更改为不在内联汇编中修改 esp。
void interrupt::init()
{
struct __attribute__((packed)) { uint16_t size; uint32_t idt; }
descr = { idt_size, idt };
__asm__ __volatile__ ("lidt %0" : : "m"(descr));
}
虽然我很感激你把所有的代码都包括在内,但我没有仔细阅读所有的代码;我只是简单回答了我注意到的第一个问题,所以你可能还有问题。