From 352e211fb030f3662e261bf4609f73eeabe0fb1b Mon Sep 17 00:00:00 2001 From: Morten Delenk Date: Sun, 30 Apr 2017 14:46:49 +0000 Subject: [PATCH] added source code generation for interrupt handling --- .gitignore | 2 + config.py | 12 +++++ kernel/arch/arm/sourcegen.py | 87 +++++++++++++++++++++++++++++++ kernel/arch/x86/sourcegen.py | 73 ++++++++++++++++++++++++++ kernel/arch/x86_64/sourcegen.py | 73 ++++++++++++++++++++++++++ kernel/hw/3ds11/picafb/picafb.cpp | 3 +- kernel/hw/pc/8259/pic.cpp | 82 +++++++++++++++++++++++++++++ kernel/hw/pc/8259/pic.hpp | 15 ++++++ kernel/hw/pc/config.py | 2 + kernel/hw/pc/io.hpp | 21 ++++++++ 10 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 kernel/arch/arm/sourcegen.py create mode 100644 kernel/arch/x86/sourcegen.py create mode 100644 kernel/arch/x86_64/sourcegen.py create mode 100644 kernel/hw/pc/8259/pic.cpp create mode 100644 kernel/hw/pc/8259/pic.hpp create mode 100644 kernel/hw/pc/io.hpp diff --git a/.gitignore b/.gitignore index c270f97..fdae5ec 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ iso/kernel *.firm html/ latex/ +int.s +regs.h diff --git a/config.py b/config.py index 431185b..19c55c7 100755 --- a/config.py +++ b/config.py @@ -89,3 +89,15 @@ if "ENABLE_FRAMEBUFFER_UNICODE" in config: p.stdin.write(l.encode("UTF-8")) p.stdin.close() p.wait() + +print("Generating sourcecode…") +int_handler = open("kernel/arch/"+config["ARCH"]+"/int.s","w") +import os +try: + os.makedirs("kernel/arch/"+config["ARCH"]+"/include") +except: + pass +reg_struct = open("kernel/arch/"+config["ARCH"]+"/include/regs.h","w") +exec(open("kernel/arch/"+config["ARCH"]+"/sourcegen.py").read()) +int_handler.close() +reg_struct.close() diff --git a/kernel/arch/arm/sourcegen.py b/kernel/arch/arm/sourcegen.py new file mode 100644 index 0000000..e8abcbc --- /dev/null +++ b/kernel/arch/arm/sourcegen.py @@ -0,0 +1,87 @@ +int_handler.write( +"""\ +.arm +.fpu vfpv2 +.global branch_macro +branch_macro: + ldr pc, [pc, #-4] //Load the next word into PC +.global data_abort +data_abort: + sub lr, #4 + push {r0-r12,lr} + ldr r0, =0 + blx intr_common_handler + pop {r0-r12,pc} +.global fast_irq +fast_irq: + sub lr, #4 + push {r0-r12,lr} + ldr r0, =1 + blx intr_common_handler + pop {r0-r12,pc} +.global normal_irq +normal_irq: + sub lr, #4 + push {r0-r12,lr} + ldr r0, =2 + blx intr_common_handler + pop {r0-r12,pc} +.global prefetch_abort +prefetch_abort: + sub lr, #4 + push {r0-r12,lr} + ldr r0, =3 + blx intr_common_handler + pop {r0-r12,pc} +.global svc_call +svc_call: + push {r0-r12,lr} + ldr r0, =4 + blx intr_common_handler + pop {r0-r12,pc} +.global undefined_op +undefined_op: + push {r0-r12,lr} + ldr r0, =5 + blx intr_common_handler + pop {r0-r12,pc} + +.extern handleINT +intr_common_handler: +""") +push_regs=[] +pop_regs=[] +if ("ENABLE_HARD" in config) and config["ENABLE_HARD"]: + #Save the registers + for i,j in enumerate(["fpsid","fpscr","fpexc"]): + push_regs.append("fmrx r"+str(i+1)+", "+j) + pop_regs.append("fmxr "+j+", r"+str(i+1)) + push_regs.append("push {r1,r2,r3,r4,r5}") + pop_regs.append("pop {r1,r2,r3,r4,r5}") + push_regs.append("vpush {d0-d15}") + pop_regs.append("vpop {d0-d15}") +push_regs.append("mov r1, sp") +pop_regs.append("mov sp, r0") + +for opc in push_regs: + int_handler.write(" "+opc+"\n") +int_handler.write(" blx handleINT\n") +for opc in reversed(pop_regs): + int_handler.write(" "+opc+"\n") +int_handler.write(" bx lr\n") + +int_handler.write(".global panic\n.extern panic2\npanic:\n push {r0-r12,lr}\n") +for opc in push_regs: + int_handler.write(" "+opc+"\n") +int_handler.write(" b panic\n") + +reg_struct.write("#include \nstruct cpu_state {\n") +if ("ENABLE_HARD" in config) and config["ENABLE_HARD"]: + for reg in ["fpsid","fpscr","fpexc"]: + reg_struct.write(" uint32_t "+reg+";\n") + for reg in ("d"+str(i) for i in range(16)): + reg_struct.write(" double "+reg+";\n") +for i in range(13): + reg_struct.write(" uint32_t r"+str(i)+";\n") +reg_struct.write(" uint32_t pc;\n};") + diff --git a/kernel/arch/x86/sourcegen.py b/kernel/arch/x86/sourcegen.py new file mode 100644 index 0000000..951a49b --- /dev/null +++ b/kernel/arch/x86/sourcegen.py @@ -0,0 +1,73 @@ +print("Writing interrupt stubs") +int_handler.write(".macro intr_stub nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushl $0\n pushl $\\nr\n jmp intr_common_handler\n.endm\n.macro intr_stub_error_code nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushl $\\nr\n jmp intr_common_handler\n.endm\n") +for i in range(256): + if i in [8,10,11,12,13,14,17]: + int_handler.write("intr_stub_error_code "+str(i)+"\n") + else: + int_handler.write("intr_stub "+str(i)+"\n") + +int_handler.write(".extern handleINT\n") +int_handler.write("intr_common_handler:\n") +int_handler.write(" cli\n") +print("Generating register save/restore") +all_regs_push=[] +all_regs_pop=[] +data_section="" +for reg in ["ebp","edi","esi","edx","ecx","ebx","eax"]: + all_regs_push.append("push %"+reg) + all_regs_pop.append("pop %"+reg) +if config["ENABLE_FPU"] and not config["ENABLE_SSE"]: + data_section+="fsave_reg:\n .space 108\n" + all_regs_push.append("fsave fsave_reg") + all_regs_pop.append("frstor fsave_reg") + all_regs_push.append("pushl $fsave_reg") +if config["ENABLE_SSE"]: + data_section+=".align 16\nfxsave_reg:\n .space 512" + all_regs_push.append("fxsave fxsave_reg") + all_regs_pop.append("fxrstor fxsave_reg") + all_regs_push.append("pushl $fxsave_reg") + +print("Writing interrupt handler") +for ins in all_regs_push: + int_handler.write(" "+ins+"\n") +int_handler.write(" push %esp\n call handleINT\n mov %eax, %esp\n") +for ins in reversed(all_regs_pop): + int_handler.write(" "+ins+"\n") +int_handler.write(" add $8, %esp\n iret\n") + +print("Writing panic handler") +int_handler.write(".global panic\n.extern panic2\npanic:\n") +for ins in all_regs_push: + int_handler.write(" "+ins+"\n") +int_handler.write(" push %esp\n jmp panic2\n") + +int_handler.write(".section .data\n"+data_section) + +print("Generating cpu_state struct") +reg_struct.write("#include \n") +if config["ENABLE_FPU"] and not config["ENABLE_SSE"]: + reg_struct.write("struct fpu_state {\n") + for reg in ["cwd","swd","twd","fip","fcs","foo","fos"]: + reg_struct.write(" uint32_t "+reg+";\n") + for reg in ("st"+str(i) for i in range(8)): + reg_struct.write(" __float80 "+reg+";\n") + reg_struct.write("}__attribute__((packed,aligned(16)));\n") +if config["ENABLE_SSE"]: + reg_struct.write("struct fpu_state {\n") + for reg in ["cwd","swd","twd","fop"]: + reg_struct.write(" uint16_t "+reg+";\n") + for reg in ["fip","fcs","foo","fos","mxcsr","mxcsr_mask"]: + reg_struct.write(" uint32_t "+reg+";\n") + for reg in range(8): + reg_struct.write(" __float80 st"+str(reg)+";\n") + reg_struct.write(" char buf"+str(reg)+"[6];\n") + for reg in range(16): + reg_struct.write(" __float128 xmm"+str(reg)+";\n") + reg_struct.write("}__attribute__((packed,aligned(16)));\n") +reg_struct.write("struct cpu_state {\n") +if config["ENABLE_FPU"]: + reg_struct.write(" fpu_state *fpu;\n") +for reg in ["eax","ebx","ecx","edx","esi","edi","ebp","intr","error","eip","cs","eflags","esp","ss"]: + reg_struct.write(" uint32_t "+reg+";\n") +reg_struct.write("}__attribute__((packed));") + diff --git a/kernel/arch/x86_64/sourcegen.py b/kernel/arch/x86_64/sourcegen.py new file mode 100644 index 0000000..301fd60 --- /dev/null +++ b/kernel/arch/x86_64/sourcegen.py @@ -0,0 +1,73 @@ +print("Writing interrupt stubs") +int_handler.write(".macro intr_stub nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushq $0\n pushq $\\nr\n jmp intr_common_handler\n.endm\n.macro intr_stub_error_code nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushq $\\nr\n jmp intr_common_handler\n.endm\n") +for i in range(256): + if i in [8,10,11,12,13,14,17]: + int_handler.write("intr_stub_error_code "+str(i)+"\n") + else: + int_handler.write("intr_stub "+str(i)+"\n") + +int_handler.write(".extern handleINT\n") +int_handler.write("intr_common_handler:\n") +int_handler.write(" cli\n") +print("Generating register save/restore") +all_regs_push=[] +all_regs_pop=[] +data_section="" +for reg in ["r15","r14","r13","r12","r11","r10","r9","r8","rbp","rdi","rsi","rdx","rcx","rbx","rax"]: + all_regs_push.append("push %"+reg) + all_regs_pop.append("pop %"+reg) +if config["ENABLE_FPU"] and not config["ENABLE_SSE"]: + data_section+="fsave_reg:\n .space 108\n" + all_regs_push.append("fsave fsave_reg") + all_regs_pop.append("frstor fsave_reg") + all_regs_push.append("pushq $fsave_reg") +if config["ENABLE_SSE"]: + data_section+=".align 16\nfxsave_reg:\n .space 512" + all_regs_push.append("fxsave fxsave_reg") + all_regs_pop.append("fxrstor fxsave_reg") + all_regs_push.append("pushq $fxsave_reg") + +print("Writing interrupt handler") +for ins in all_regs_push: + int_handler.write(" "+ins+"\n") +int_handler.write(" mov %rsp, %rdi\n call handleINT\n mov %rax, %rsp\n") +for ins in reversed(all_regs_pop): + int_handler.write(" "+ins+"\n") +int_handler.write(" add $8, %esp\n iret\n") + +print("Writing panic handler") +int_handler.write(".global panic\n.extern panic2\npanic:\n") +for ins in all_regs_push: + int_handler.write(" "+ins+"\n") +int_handler.write(" mov %rsp, %rdi\n jmp panic2\n") + +int_handler.write(".section .data\n"+data_section) + +print("Generating cpu_state struct") +reg_struct.write("#include \n") +if config["ENABLE_FPU"] and not config["ENABLE_SSE"]: + reg_struct.write("struct fpu_state {\n") + for reg in ["cwd","swd","twd","fip","fcs","foo","fos"]: + reg_struct.write(" uint32_t "+reg+";\n") + for reg in ("st"+str(i) for i in range(8)): + reg_struct.write(" __float80 "+reg+";\n") + reg_struct.write("}__attribute__((packed,aligned(16)));\n") +if config["ENABLE_SSE"]: + reg_struct.write("struct fpu_state {\n") + for reg in ["cwd","swd","twd","fop"]: + reg_struct.write(" uint16_t "+reg+";\n") + for reg in ["fip","fcs","foo","fos","mxcsr","mxcsr_mask"]: + reg_struct.write(" uint32_t "+reg+";\n") + for reg in range(8): + reg_struct.write(" __float80 st"+str(reg)+";\n") + reg_struct.write(" char buf"+str(reg)+"[6];\n") + for reg in range(16): + reg_struct.write(" __float128 xmm"+str(reg)+";\n") + reg_struct.write("}__attribute__((packed,aligned(16)));\n") +reg_struct.write("struct cpu_state {\n") +if config["ENABLE_FPU"]: + reg_struct.write(" fpu_state *fpu;\n") +for reg in ["rax","rbx","rcx","rdx","rsi","rdi","rbp","r8","r9","r10","r11","r12","r13","r14","r15","intr","error","rip","cs","rflags","rsp","ss"]: + reg_struct.write(" uint64_t "+reg+";\n") +reg_struct.write("}__attribute__((packed));") + diff --git a/kernel/hw/3ds11/picafb/picafb.cpp b/kernel/hw/3ds11/picafb/picafb.cpp index e1d45da..94d702e 100644 --- a/kernel/hw/3ds11/picafb/picafb.cpp +++ b/kernel/hw/3ds11/picafb/picafb.cpp @@ -20,7 +20,8 @@ PICAfb::PICAfb() : Framebuffer(25, 30) { *((uint32_t *)0x10202A40) = 0x3F; // Bottom screen brightness *((uint32_t *)0x10202244) = 0x1023E; *((uint32_t *)0x10202A44) = 0x1023E; - + // TODO this code is ugly and copied right out of the arm9loaderhax git + // find out what 90% of this does // Top screen *(volatile uint32_t *)0x10400400 = 0x000001c2; *(volatile uint32_t *)0x10400404 = 0x000000d1; diff --git a/kernel/hw/pc/8259/pic.cpp b/kernel/hw/pc/8259/pic.cpp new file mode 100644 index 0000000..93e164a --- /dev/null +++ b/kernel/hw/pc/8259/pic.cpp @@ -0,0 +1,82 @@ +#include "pic.hpp" +#include "../io.hpp" +#define PIC1 0x20 +#define PIC2 0xA0 +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1 + 1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2 + 1) + +#define PIC_EOI 0x20 +#define ICW1_ICW4 0x01 +#define ICW1_SINGLE 0x02 +#define ICW1_INTERVAL4 0x04 +#define ICW1_LEVEL 0x08 +#define ICW1_INIT 0x10 + +#define ICW4_8086 0x01 +#define ICW4_AUTO 0x02 +#define ICW4_BUF_SLAVE 0x04 +#define ICW4_BUF_MASTER 0x0C +#define ICW4_SFNM 0x10 +namespace PIC { +auto sendEOI(bool slave) -> void { + if (slave) { out(PIC2_COMMAND, PIC_EOI); } + out(PIC1_COMMAND, PIC_EOI); +} +auto initPIC(int off1, int off2) -> void { + uint8_t a1 = in(PIC1_DATA); + uint8_t a2 = in(PIC2_DATA); + + out(PIC1_COMMAND, ICW1_INIT + ICW1_ICW4); + out(PIC2_COMMAND, ICW1_INIT + ICW1_ICW4); + out(PIC1_DATA, off1); + out(PIC2_DATA, off2); + out(PIC1_DATA, 4); // Slave at 2 + out(PIC2_DATA, 2); // Self at 2 + + out(PIC1_DATA, ICW4_8086); + out(PIC2_DATA, ICW4_8086); + + out(PIC1_DATA, a1); + out(PIC2_DATA, a2); +} +auto disable() -> void { + out(PIC1_DATA, 0xFF); + out(PIC2_DATA, 0xFF); +} +auto mask(int no) -> void { + if (no < 8) { + out(PIC1_DATA, in(PIC1_DATA) | (1 << no)); + } else { + no -= 8; + out(PIC2_DATA, in(PIC2_DATA) | (1 << no)); + } +} +auto unmask(int no) -> void { + if (no < 8) { + out(PIC1_DATA, in(PIC1_DATA) & ~(1 << no)); + } else { + no -= 8; + out(PIC2_DATA, in(PIC2_DATA) & ~(1 << no)); + } +} +auto disableSlave() -> void { mask(2); } +auto enableSlave() -> void { unmask(2); } +auto isSpurious(bool slave) -> bool { + if (slave) { + out(PIC2_COMMAND, 0x0B); + io_wait(); + if (!(in(PIC2_DATA) & 0x80)) { + sendEOI(false); + return true; + } else { + return false; + } + } else { + out(PIC1_COMMAND, 0x0B); + io_wait(); + return (in(PIC1_DATA) & 0x80) ? true : false; + } +} +} diff --git a/kernel/hw/pc/8259/pic.hpp b/kernel/hw/pc/8259/pic.hpp new file mode 100644 index 0000000..6803bf5 --- /dev/null +++ b/kernel/hw/pc/8259/pic.hpp @@ -0,0 +1,15 @@ +#pragma once +#include +/** + * Namespace contains function to control the Programmable Interrupt Controller + */ +namespace PIC { +auto sendEOI(bool slave) -> void; ///< Signals the PIC that the interrupt has ended +auto initPIC(int off1, int off2) -> void; ///< Initializes the pic/remaps it +auto disable() -> void; ///< disables PIC completely +auto maskIRQ(int no) -> void; ///< disables a single IRQ +auto unmaskIRQ(int no) -> void; ///< reenables a single IRQ +auto disableSlave() -> void; ///< disables IRQ2 and 8-15 +auto enableSlave() -> void; ///< reenables at least IRQ2 +auto isSpurious(bool slave) -> bool; ///< Return if this isn't an actual IRQ. +} diff --git a/kernel/hw/pc/config.py b/kernel/hw/pc/config.py index acdfe98..3529762 100644 --- a/kernel/hw/pc/config.py +++ b/kernel/hw/pc/config.py @@ -6,3 +6,5 @@ if config["ENABLE_FRAMEBUFFER"]: add_driver(False, "vesafb") else: add_driver(False, "cgaterm") +add_driver(False, "8259") +add_driver(False, "idt") diff --git a/kernel/hw/pc/io.hpp b/kernel/hw/pc/io.hpp new file mode 100644 index 0000000..b408215 --- /dev/null +++ b/kernel/hw/pc/io.hpp @@ -0,0 +1,21 @@ +template +static void out(uint16_t port, T val) { + if (sizeof(T) == 1) + asm volatile("outb %0, %1" : : "a"(val), "Nd"(port)); + else if (sizeof(T) == 2) + asm volatile("outw %0, %1" : : "a"(val), "Nd"(port)); + else if (sizeof(T) == 4) + asm volatile("outl %0, %1" : : "a"(val), "Nd"(port)); +} +template +static T in(uint16_t port) { + T val = 0; + if (sizeof(T) == 1) + asm volatile("inb %1, %0" : "=a"(val) : "Nd"(port)); + else if (sizeof(T) == 2) + asm volatile("inw %1, %0" : "=a"(val) : "Nd"(port)); + else if (sizeof(T) == 4) + asm volatile("inl %1, %0" : "=a"(val) : "Nd"(port)); + return val; +} +static void io_wait() { out(0x80, 0); }