Parcourir la source

Kernel: Add support for interrupts on x86_64

Gunnar Beutner il y a 4 ans
Parent
commit
065c6c307d

+ 14 - 4
Kernel/Arch/x86/DescriptorTable.h

@@ -116,9 +116,15 @@ struct [[gnu::packed]] IDTEntry
     u16 offset_1; // offset bits 0..15
     u16 selector; // a code segment selector in GDT or LDT
 
-    u8 zero; // unused, set to 0 (maybe used on amd64)
+#if ARCH(I386)
+    u8 zero; // unused, set to 0
+#else
+    struct {
+        u8 interrupt_stack_table : 3;
+        u8 zero : 5; // unused, set to 0
+    };
+#endif
     struct {
-        // FIXME: Is the order correct?
         u8 gate_type : 4;
         u8 storage_segment : 1;
         u8 descriptor_privilege_level : 2;
@@ -126,7 +132,6 @@ struct [[gnu::packed]] IDTEntry
     } type_attr;  // type and attributes
     u16 offset_2; // offset bits 16..31
 #if !ARCH(I386)
-// we may need to switch those around?
     u32 offset_3;
     u32 zeros;
 #endif
@@ -135,6 +140,9 @@ struct [[gnu::packed]] IDTEntry
     IDTEntry(FlatPtr callback, u16 selector_, IDTEntryType type, u8 storage_segment, u8 privilege_level)
         : offset_1 { (u16)((FlatPtr)callback & 0xFFFF) }
         , selector { selector_ }
+#if !ARCH(I386)
+        , interrupt_stack_table { 0 }
+#endif
         , zero { 0 }
         , type_attr {
             .gate_type = (u8)type,
@@ -150,7 +158,7 @@ struct [[gnu::packed]] IDTEntry
     {
     }
 
-    u32 off()
+    FlatPtr off()
     {
 #if ARCH(I386)
         return (u32)offset_2 << 16 & (u32)offset_1;
@@ -165,4 +173,6 @@ struct [[gnu::packed]] IDTEntry
 };
 // clang-format on
 
+static_assert(sizeof(IDTEntry) == 2 * sizeof(void*));
+
 }

+ 1 - 1
Kernel/Arch/x86/TrapFrame.h

@@ -15,7 +15,7 @@
 namespace Kernel {
 
 struct TrapFrame {
-    u32 prev_irq_level;
+    FlatPtr prev_irq_level;
     TrapFrame* next_trap;
     RegisterState* regs; // must be last
 

+ 53 - 4
Kernel/Arch/x86/common/Interrupts.cpp

@@ -100,8 +100,32 @@ static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interr
     asm(                                            \
         ".globl " #title "_asm_entry\n"             \
         "" #title "_asm_entry: \n"                  \
-        "    cli;hlt;\n"                            \
-);
+        "    pushq %r15\n"                          \
+        "    pushq %r14\n"                          \
+        "    pushq %r13\n"                          \
+        "    pushq %r12\n"                          \
+        "    pushq %r11\n"                          \
+        "    pushq %r10\n"                          \
+        "    pushq %r9\n"                           \
+        "    pushq %r8\n"                           \
+        "    pushq %rax\n"                          \
+        "    pushq %rcx\n"                          \
+        "    pushq %rdx\n"                          \
+        "    pushq %rbx\n"                          \
+        "    pushq %rsp\n"                          \
+        "    pushq %rbp\n"                          \
+        "    pushq %rsi\n"                          \
+        "    pushq %rdi\n"                          \
+        "    pushq %rsp \n" /* set TrapFrame::regs */ \
+        "    subq $" __STRINGIFY(TRAP_FRAME_SIZE - 8) ", %rsp \n" \
+        "    subq $0x8, %rsp\n" /* align stack */   \
+        "    lea 0x8(%rsp), %rdi \n"                \
+        "    cld\n"                                 \
+        "    call enter_trap_no_irq \n"             \
+        "    lea 0x8(%rsp), %rdi \n"                \
+        "    call " #title "_handler\n"             \
+        "    addq $0x8, %rsp\n" /* undo alignment */\
+        "    jmp common_trap_exit \n");
 
 #define EH_ENTRY_NO_CODE(ec, title)                 \
     extern "C" void title##_handler(TrapFrame*);    \
@@ -109,8 +133,33 @@ static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interr
 asm(                                                \
         ".globl " #title "_asm_entry\n"             \
         "" #title "_asm_entry: \n"                  \
-        "    cli;hlt;\n"                            \
-);
+        "    pushq $0x0\n"                          \
+        "    pushq %r15\n"                          \
+        "    pushq %r14\n"                          \
+        "    pushq %r13\n"                          \
+        "    pushq %r12\n"                          \
+        "    pushq %r11\n"                          \
+        "    pushq %r10\n"                          \
+        "    pushq %r9\n"                           \
+        "    pushq %r8\n"                           \
+        "    pushq %rax\n"                          \
+        "    pushq %rcx\n"                          \
+        "    pushq %rdx\n"                          \
+        "    pushq %rbx\n"                          \
+        "    pushq %rsp\n"                          \
+        "    pushq %rbp\n"                          \
+        "    pushq %rsi\n"                          \
+        "    pushq %rdi\n"                          \
+        "    pushq %rsp \n" /* set TrapFrame::regs */ \
+        "    subq $" __STRINGIFY(TRAP_FRAME_SIZE - 8) ", %rsp \n" \
+        "    subq $0x8, %rsp\n" /* align stack */   \
+        "    lea 0x8(%rsp), %rdi \n"                \
+        "    cld\n"                                 \
+        "    call enter_trap_no_irq \n"             \
+        "    lea 0x8(%rsp), %rdi \n"                \
+        "    call " #title "_handler\n"             \
+        "    addq $0x8, %rsp\n" /* undo alignment */\
+        "    jmp common_trap_exit \n");
 #endif
 
 // clang-format on

+ 30 - 10
Kernel/Arch/x86/x86_64/InterruptEntry.cpp

@@ -10,15 +10,35 @@
 
 // clang-format off
 asm(
-".globl interrupt_common_asm_entry\n"
-"interrupt_common_asm_entry: \n"
-"    int3 \n" // FIXME
-".globl common_trap_exit \n"
-"common_trap_exit: \n"
-// another thread may have handled this trap at this point, so don't
-// make assumptions about the stack other than there's a TrapFrame
-// and a pointer to it.
-"    call exit_trap \n"
-"    int3 \n" // FIXME
+    ".globl interrupt_common_asm_entry\n"
+    "interrupt_common_asm_entry: \n"
+    "    hlt \n" // FIXME
+    ".globl common_trap_exit \n"
+    "common_trap_exit: \n"
+    // another thread may have handled this trap at this point, so don't
+    // make assumptions about the stack other than there's a TrapFrame.
+    "    movq %rsp, %rdi \n"
+    "    call exit_trap \n"
+    "    addq $" __STRINGIFY(TRAP_FRAME_SIZE) ", %rsp\n" // pop TrapFrame
+    ".globl interrupt_common_asm_exit \n"
+    "interrupt_common_asm_exit: \n"
+    "    popq %rdi\n"
+    "    popq %rsi\n"
+    "    popq %rbp\n"
+    "    addq $8, %rsp\n" // skip restoring rsp
+    "    popq %rbx\n"
+    "    popq %rdx\n"
+    "    popq %rcx\n"
+    "    popq %rax\n"
+    "    popq %r8\n"
+    "    popq %r9\n"
+    "    popq %r10\n"
+    "    popq %r11\n"
+    "    popq %r12\n"
+    "    popq %r13\n"
+    "    popq %r14\n"
+    "    popq %r15\n"
+    "    addq $0x8, %rsp\n" // skip exception_code, isr_number
+    "    iretq\n"
 );
 // clang-format on