Interrupts mostly working, frame seems to be offset by one tho
This commit is contained in:
parent
5ba67be4c0
commit
c2f8ccdf2e
BIN
bin/shade.bin
BIN
bin/shade.bin
Binary file not shown.
BIN
bin/shade.iso
BIN
bin/shade.iso
Binary file not shown.
|
@ -0,0 +1,9 @@
|
|||
#ifndef GDT_H
|
||||
#define GDT_H
|
||||
|
||||
#define KERNEL_CODE 0x08
|
||||
#define KERNEL_DATA 0x10
|
||||
#define USERLAND_CODE 0x18
|
||||
#define USERLAND_DATA 0x20
|
||||
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <shade/platform/gdt.h>
|
||||
|
||||
#define IDT_DESCRIPTORS 256
|
||||
|
||||
extern void* isr_stub_table[];
|
||||
|
||||
typedef struct idt_entry_struct {
|
||||
uint16_t isr_low; // Low 16 bits of handler address
|
||||
uint16_t kernel_cs; // The selector in the GDT that the CPU will load into CS before calling the handler
|
||||
uint8_t ist; // The IST in the TSS that the CPU will load into RSP; set to zero for now
|
||||
uint8_t attributes; // Type and attributes
|
||||
uint16_t isr_mid; // Middle 16 bits of handler address
|
||||
uint32_t isr_high; // Upper 32 bits of handler address
|
||||
uint32_t reserved; // Reserved, set to 0
|
||||
} __attribute__((packed)) idt_descriptor_t;
|
||||
|
||||
typedef struct idt_ptr_struct {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} __attribute__((packed)) idt_ptr_t;
|
||||
|
||||
__attribute__((aligned(0x10)))
|
||||
static idt_descriptor_t idt[IDT_DESCRIPTORS];
|
||||
static idt_ptr_t idt_ptr;
|
||||
static bool vectors[IDT_DESCRIPTORS];
|
||||
|
||||
void idt_set_gate(uint8_t index, void* isr, uint8_t flags);
|
||||
void idt_assemble();
|
||||
|
||||
void idt_enable_interrupts();
|
||||
void idt_disable_interrupts();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ERR_MAX 5
|
||||
|
||||
static int err_count = 0;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint64_t cr4;
|
||||
uint64_t cr3;
|
||||
uint64_t cr2;
|
||||
uint64_t cr0;
|
||||
} control_registers;
|
||||
|
||||
struct {
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rbx;
|
||||
uint64_t rax;
|
||||
} general_registers;
|
||||
|
||||
struct {
|
||||
uint64_t rbp;
|
||||
uint64_t vector;
|
||||
uint64_t error_code;
|
||||
uint64_t rip;
|
||||
uint64_t cs;
|
||||
uint64_t rflags;
|
||||
uint64_t rsp;
|
||||
uint64_t dss;
|
||||
} base_frame;
|
||||
} isr_xframe_t;
|
||||
|
||||
__attribute__((noreturn))
|
||||
void exception_handler(isr_xframe_t frame);
|
||||
|
||||
__attribute__((noreturn))
|
||||
void interrupt_handler(isr_xframe_t frame);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef PIC_H
|
||||
#define PIC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PIC1 0x20 /* IO base address for master PIC */
|
||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
||||
#define PIC1_COMMAND PIC1
|
||||
#define PIC1_DATA (PIC1+1)
|
||||
#define PIC2_COMMAND PIC2
|
||||
#define PIC2_DATA (PIC2+1)
|
||||
|
||||
#define PIC_EOI 0x20 /* End-of-interrupt command code */
|
||||
|
||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
||||
|
||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||
|
||||
#define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */
|
||||
#define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */
|
||||
|
||||
|
||||
void pic_send_eoi(uint8_t irq);
|
||||
void pic_remap(int offset1, int offset2);
|
||||
void pic_mask_irq(uint8_t irq);
|
||||
void pic_unmask_irq(uint8_t irq);
|
||||
static uint16_t __pic_get_irq_reg(int ocw3);
|
||||
uint16_t pic_get_irr();
|
||||
uint16_t pic_get_isr();
|
||||
|
||||
|
||||
#endif
|
|
@ -1,4 +1,11 @@
|
|||
unsigned char port_byte_in(unsigned short port);
|
||||
void port_byte_out(unsigned short port, unsigned char data);
|
||||
unsigned short port_word_in(unsigned short port);
|
||||
void port_word_out(unsigned short port, unsigned short data);
|
||||
#ifndef PORTS_H
|
||||
#define PORTS_H
|
||||
|
||||
unsigned char inb(unsigned short port);
|
||||
void outb(unsigned short port, unsigned char data);
|
||||
unsigned short inw(unsigned short port);
|
||||
void outw(unsigned short port, unsigned short data);
|
||||
|
||||
void io_wait();
|
||||
|
||||
#endif
|
|
@ -3,6 +3,5 @@
|
|||
|
||||
void memcpy(char *source, char *dest, int nbytes);
|
||||
void memset(char *dest, char val, int len);
|
||||
void int_to_ascii(int n, char str[]);
|
||||
|
||||
#endif
|
|
@ -1,10 +1,17 @@
|
|||
#ifndef STRINGS_H
|
||||
#define STRINGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void itoa(int n, char str[]);
|
||||
void strrev(char s[]);
|
||||
int strlen(char s[]);
|
||||
char* strcpy(char* strDest, const char* strSrc);
|
||||
char* strcnc(char* str1, char* str2);
|
||||
|
||||
char* u8_hex(const uint8_t x);
|
||||
char* u16_hex(const uint16_t x);
|
||||
char* u32_hex(const uint32_t x);
|
||||
char* u64_hex(const uint64_t x);
|
||||
|
||||
#endif
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,7 @@
|
|||
#include <shade/platform/ports.h>
|
||||
#include <shade/print.h>
|
||||
#include <shade/platform/interrupts/idt.h>
|
||||
#include <shade/platform/interrupts/pic.h>
|
||||
|
||||
void kernel_welcome() {
|
||||
print_str("Welcome to ");
|
||||
|
@ -43,4 +45,10 @@ void kmain() {
|
|||
print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n");
|
||||
print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n");
|
||||
|
||||
pic_remap(0x20, 0x28);
|
||||
idt_assemble();
|
||||
kernel_msg_ok("Enabled interrupts");
|
||||
__asm__ __volatile__("int $2");
|
||||
|
||||
for (;;) {}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include <shade/platform/interrupts/idt.h>
|
||||
|
||||
void idt_set_gate(uint8_t index, void* isr, uint8_t flags) {
|
||||
idt_descriptor_t* descriptor = &idt[index];
|
||||
|
||||
descriptor->isr_low = (uint64_t)isr & 0xFFFF;
|
||||
descriptor->kernel_cs = KERNEL_CODE;
|
||||
descriptor->ist = 0;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->isr_mid = ((uint64_t)isr >> 16) & 0xFFFF;
|
||||
descriptor->isr_high = ((uint64_t)isr >> 32) & 0xFFFFFFFF;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
void idt_assemble() {
|
||||
idt_ptr.base = (uintptr_t)&idt[0];
|
||||
idt_ptr.limit = (uint16_t)sizeof(idt_descriptor_t) * IDT_DESCRIPTORS - 1;
|
||||
|
||||
for (uint8_t vector = 0; vector < 47; vector++) {
|
||||
idt_set_gate(vector, isr_stub_table[vector], 0x8E);
|
||||
vectors[vector] = true;
|
||||
}
|
||||
|
||||
__asm__ __volatile__ ("lidt %0" : : "m"(idt_ptr));
|
||||
idt_enable_interrupts();
|
||||
}
|
||||
|
||||
void idt_enable_interrupts() {
|
||||
__asm__ __volatile__("sti");
|
||||
}
|
||||
void idt_disable_interrupts() {
|
||||
__asm__ __volatile__("cli");
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
extern exception_handler
|
||||
|
||||
%macro isr_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
push %1
|
||||
jmp isr_xframe_assembler
|
||||
%endmacro
|
||||
|
||||
%macro isr_no_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
push 0
|
||||
push %1
|
||||
jmp isr_xframe_assembler
|
||||
%endmacro
|
||||
|
||||
%macro interrupt_stub 1
|
||||
isr_stub_%+%1:
|
||||
push 0
|
||||
push %1
|
||||
jmp isr_xframe_assembler
|
||||
%endmacro
|
||||
|
||||
%macro pushagrd 0
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
%endmacro
|
||||
|
||||
%macro popagrd 0
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
%endmacro
|
||||
|
||||
%macro pushacrd 0
|
||||
mov rax, cr0
|
||||
push rax
|
||||
mov rax, cr2
|
||||
push rax
|
||||
mov rax, cr3
|
||||
push rax
|
||||
mov rax, cr4
|
||||
push rax
|
||||
%endmacro
|
||||
|
||||
%macro popacrd 0
|
||||
pop rax
|
||||
mov cr4, rax
|
||||
pop rax
|
||||
mov cr3, rax
|
||||
pop rax
|
||||
mov cr2, rax
|
||||
pop rax
|
||||
mov cr0, rax
|
||||
%endmacro
|
||||
|
||||
isr_xframe_assembler:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
pushagrd
|
||||
pushacrd
|
||||
mov ax, ds
|
||||
push rax
|
||||
push qword 0
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
lea rdi, [rsp + 0x10]
|
||||
call exception_handler
|
||||
|
||||
pop rax
|
||||
pop rax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
popacrd
|
||||
popagrd
|
||||
pop rbp
|
||||
add rsp, 0x10
|
||||
iretq
|
||||
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
isr_no_err_stub 3
|
||||
isr_no_err_stub 4
|
||||
isr_no_err_stub 5
|
||||
isr_no_err_stub 6
|
||||
isr_no_err_stub 7
|
||||
isr_err_stub 8
|
||||
isr_no_err_stub 9
|
||||
isr_err_stub 10
|
||||
isr_err_stub 11
|
||||
isr_err_stub 12
|
||||
isr_err_stub 13
|
||||
isr_err_stub 14
|
||||
isr_no_err_stub 15
|
||||
isr_no_err_stub 16
|
||||
isr_err_stub 17
|
||||
isr_no_err_stub 18
|
||||
isr_no_err_stub 19
|
||||
isr_no_err_stub 20
|
||||
isr_no_err_stub 21
|
||||
isr_no_err_stub 22
|
||||
isr_no_err_stub 23
|
||||
isr_no_err_stub 24
|
||||
isr_no_err_stub 25
|
||||
isr_no_err_stub 26
|
||||
isr_no_err_stub 27
|
||||
isr_no_err_stub 28
|
||||
isr_no_err_stub 29
|
||||
isr_err_stub 30
|
||||
isr_no_err_stub 31
|
||||
|
||||
interrupt_stub 32
|
||||
interrupt_stub 33
|
||||
interrupt_stub 34
|
||||
interrupt_stub 35
|
||||
interrupt_stub 36
|
||||
interrupt_stub 37
|
||||
interrupt_stub 38
|
||||
interrupt_stub 39
|
||||
interrupt_stub 40
|
||||
interrupt_stub 41
|
||||
interrupt_stub 42
|
||||
interrupt_stub 43
|
||||
interrupt_stub 44
|
||||
interrupt_stub 45
|
||||
interrupt_stub 46
|
||||
interrupt_stub 47
|
||||
|
||||
global isr_stub_table
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 47
|
||||
dq isr_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
|
@ -0,0 +1,24 @@
|
|||
#include <shade/print.h>
|
||||
#include <shade/platform/interrupts/isr.h>
|
||||
|
||||
void exception_handler(isr_xframe_t frame) {
|
||||
err_count++;
|
||||
char s[256];
|
||||
itoa(err_count, s);
|
||||
print_str(" ");
|
||||
print_str(s);
|
||||
print_str(": cpu: check_exception ");
|
||||
itoa(frame.base_frame.vector, s);
|
||||
print_str(s);
|
||||
print_str(" @ ");
|
||||
itoa(frame.base_frame.rip, s);
|
||||
print_str(s);
|
||||
print_str(" err_code => ");
|
||||
itoa(frame.base_frame.error_code, s);
|
||||
print_str(s);
|
||||
print_str("\n");
|
||||
if (err_count > ERR_MAX) {
|
||||
print_str("cpu: ierr hit err_max, halt");
|
||||
__asm__ __volatile__("cli; hlt");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#include <shade/platform/interrupts/pic.h>
|
||||
#include <shade/platform/ports.h>
|
||||
|
||||
void pic_send_eoi(uint8_t irq) {
|
||||
if (irq >= 8) {
|
||||
outb(PIC2_COMMAND, PIC_EOI);
|
||||
}
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
void pic_remap(int offset1, int offset2) {
|
||||
uint8_t a1, a2;
|
||||
|
||||
a1 = inb(PIC1_DATA); // Save the current masks for later use
|
||||
a2 = inb(PIC2_DATA); // Save the current masks for later use
|
||||
|
||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode)
|
||||
io_wait();
|
||||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, offset1); // ICW2: Master PIC vector offset
|
||||
io_wait();
|
||||
outb(PIC2_DATA, offset2); // ICW2: Slave PIC vector offset
|
||||
io_wait();
|
||||
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
|
||||
outb(PIC1_DATA, a1); // restore saved masks.
|
||||
outb(PIC2_DATA, a2);
|
||||
}
|
||||
|
||||
void pic_mask_irq(uint8_t irq) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (irq < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
irq -= 8;
|
||||
}
|
||||
value = inb(port) | (1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
void pic_unmask_irq(uint8_t irq) {
|
||||
uint16_t port;
|
||||
uint8_t value;
|
||||
|
||||
if (irq < 8) {
|
||||
port = PIC1_DATA;
|
||||
} else {
|
||||
port = PIC2_DATA;
|
||||
irq -= 8;
|
||||
}
|
||||
value = inb(port) & ~(1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
|
||||
static uint16_t __pic_get_irq_reg(int ocw3) {
|
||||
outb(PIC1_COMMAND, ocw3);
|
||||
outb(PIC2_COMMAND, ocw3);
|
||||
return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||
}
|
||||
|
||||
uint16_t pic_get_irr() {
|
||||
return __pic_get_irq_reg(PIC_READ_IRR);
|
||||
}
|
||||
|
||||
uint16_t pic_get_isr() {
|
||||
return __pic_get_irq_reg(PIC_READ_ISR);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Read 1 byte from specified port
|
||||
*/
|
||||
unsigned char port_byte_in(unsigned short port) {
|
||||
unsigned char inb(unsigned short port) {
|
||||
unsigned char result;
|
||||
// source and dest are backwards.
|
||||
// "=a (result)" set the C variable to the value of register e'a'x
|
||||
|
@ -9,18 +9,22 @@ unsigned char port_byte_in(unsigned short port) {
|
|||
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
|
||||
}
|
||||
|
||||
void port_byte_out(unsigned short port, unsigned char data) {
|
||||
void outb(unsigned short port, unsigned char data) {
|
||||
// both regs are C vars, nothing is returned, so no '=' in asm syntax
|
||||
// comma because two vars in input area and none in return area
|
||||
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
unsigned short port_word_in(unsigned short port) {
|
||||
unsigned short inw(unsigned short port) {
|
||||
unsigned short result;
|
||||
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_word_out(unsigned short port, unsigned short data) {
|
||||
void outw(unsigned short port, unsigned short data) {
|
||||
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
void io_wait() {
|
||||
outb(0x80, 0);
|
||||
}
|
|
@ -87,10 +87,10 @@ void print_set_color(char foreground, char background) {
|
|||
|
||||
void set_cursor_pos(int col, int row) {
|
||||
int offset = col + NUM_COLS * row;
|
||||
port_byte_out(REG_SCREEN_CTRL, 14);
|
||||
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
|
||||
port_byte_out(REG_SCREEN_CTRL, 15);
|
||||
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
|
||||
outb(REG_SCREEN_CTRL, 14);
|
||||
outb(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
|
||||
outb(REG_SCREEN_CTRL, 15);
|
||||
outb(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
|
||||
}
|
||||
|
||||
void kernel_msg_ok(char* msg) {
|
||||
|
|
|
@ -11,15 +11,3 @@ void memset(char *dest, char val, int len) {
|
|||
char *temp = (char *)dest;
|
||||
for(; len !=0; len--) *temp++ = val;
|
||||
}
|
||||
|
||||
void int_to_ascii(int n, char str[]) {
|
||||
int i, sign;
|
||||
if ((sign = n) < 0) n = -n;
|
||||
i = 0;
|
||||
do {
|
||||
str[i++] = n % 10 + '0';
|
||||
} while ((n /= 10) > 0);
|
||||
|
||||
if (sign < 0) str[i++] = '-';
|
||||
str[i] = '\0';
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include <strings.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void itoa(int n, char str[]) {
|
||||
int i, sign;
|
||||
|
|
Loading…
Reference in New Issue