added source code generation for interrupt handling

This commit is contained in:
Morten Delenk 2017-04-30 14:46:49 +00:00
parent e41b942c38
commit 352e211fb0
10 changed files with 369 additions and 1 deletions

2
.gitignore vendored
View file

@ -13,3 +13,5 @@ iso/kernel
*.firm *.firm
html/ html/
latex/ latex/
int.s
regs.h

View file

@ -89,3 +89,15 @@ if "ENABLE_FRAMEBUFFER_UNICODE" in config:
p.stdin.write(l.encode("UTF-8")) p.stdin.write(l.encode("UTF-8"))
p.stdin.close() p.stdin.close()
p.wait() 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()

View file

@ -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 <stdint.h>\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};")

View file

@ -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 <stdint.h>\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));")

View file

@ -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 <stdint.h>\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));")

View file

@ -20,7 +20,8 @@ PICAfb::PICAfb() : Framebuffer(25, 30) {
*((uint32_t *)0x10202A40) = 0x3F; // Bottom screen brightness *((uint32_t *)0x10202A40) = 0x3F; // Bottom screen brightness
*((uint32_t *)0x10202244) = 0x1023E; *((uint32_t *)0x10202244) = 0x1023E;
*((uint32_t *)0x10202A44) = 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 // Top screen
*(volatile uint32_t *)0x10400400 = 0x000001c2; *(volatile uint32_t *)0x10400400 = 0x000001c2;
*(volatile uint32_t *)0x10400404 = 0x000000d1; *(volatile uint32_t *)0x10400404 = 0x000000d1;

82
kernel/hw/pc/8259/pic.cpp Normal file
View file

@ -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<unsigned char>(PIC2_COMMAND, PIC_EOI); }
out<unsigned char>(PIC1_COMMAND, PIC_EOI);
}
auto initPIC(int off1, int off2) -> void {
uint8_t a1 = in<uint8_t>(PIC1_DATA);
uint8_t a2 = in<uint8_t>(PIC2_DATA);
out<uint8_t>(PIC1_COMMAND, ICW1_INIT + ICW1_ICW4);
out<uint8_t>(PIC2_COMMAND, ICW1_INIT + ICW1_ICW4);
out<uint8_t>(PIC1_DATA, off1);
out<uint8_t>(PIC2_DATA, off2);
out<uint8_t>(PIC1_DATA, 4); // Slave at 2
out<uint8_t>(PIC2_DATA, 2); // Self at 2
out<uint8_t>(PIC1_DATA, ICW4_8086);
out<uint8_t>(PIC2_DATA, ICW4_8086);
out(PIC1_DATA, a1);
out(PIC2_DATA, a2);
}
auto disable() -> void {
out<uint8_t>(PIC1_DATA, 0xFF);
out<uint8_t>(PIC2_DATA, 0xFF);
}
auto mask(int no) -> void {
if (no < 8) {
out<uint8_t>(PIC1_DATA, in<uint8_t>(PIC1_DATA) | (1 << no));
} else {
no -= 8;
out<uint8_t>(PIC2_DATA, in<uint8_t>(PIC2_DATA) | (1 << no));
}
}
auto unmask(int no) -> void {
if (no < 8) {
out<uint8_t>(PIC1_DATA, in<uint8_t>(PIC1_DATA) & ~(1 << no));
} else {
no -= 8;
out<uint8_t>(PIC2_DATA, in<uint8_t>(PIC2_DATA) & ~(1 << no));
}
}
auto disableSlave() -> void { mask(2); }
auto enableSlave() -> void { unmask(2); }
auto isSpurious(bool slave) -> bool {
if (slave) {
out<uint8_t>(PIC2_COMMAND, 0x0B);
io_wait();
if (!(in<uint8_t>(PIC2_DATA) & 0x80)) {
sendEOI(false);
return true;
} else {
return false;
}
} else {
out<uint8_t>(PIC1_COMMAND, 0x0B);
io_wait();
return (in<uint8_t>(PIC1_DATA) & 0x80) ? true : false;
}
}
}

15
kernel/hw/pc/8259/pic.hpp Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
/**
* 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.
}

View file

@ -6,3 +6,5 @@ if config["ENABLE_FRAMEBUFFER"]:
add_driver(False, "vesafb") add_driver(False, "vesafb")
else: else:
add_driver(False, "cgaterm") add_driver(False, "cgaterm")
add_driver(False, "8259")
add_driver(False, "idt")

21
kernel/hw/pc/io.hpp Normal file
View file

@ -0,0 +1,21 @@
template <typename T>
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 <typename T>
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<unsigned char>(0x80, 0); }