Kernel: add IDT (for interrupts) and fixed GDT - now can be loaded from grub
This commit is contained in:
parent
f46798410a
commit
04b9ba01e8
|
@ -43,16 +43,98 @@ _start:
|
|||
|
||||
.global gdt_flush
|
||||
gdt_flush:
|
||||
cli
|
||||
mov 0x4(%esp),%eax
|
||||
sgdtl (%eax)
|
||||
lgdt (%eax)
|
||||
mov $0x10,%ax
|
||||
mov %ax,%ds
|
||||
mov %ax,%es
|
||||
mov %ax,%fs
|
||||
mov %ax,%gs
|
||||
mov %ax,%ss
|
||||
jmp $0x8,$.flush
|
||||
.flush:
|
||||
ret
|
||||
|
||||
// IDT
|
||||
|
||||
.global idt_flush
|
||||
idt_flush:
|
||||
mov 0x4(%esp),%eax
|
||||
lidt (%eax)
|
||||
ret
|
||||
|
||||
// Interrupt Service Routine
|
||||
|
||||
.macro ISR_NOERRCODE num
|
||||
.global isr\num
|
||||
isr\num:
|
||||
cli
|
||||
push $0x0
|
||||
push $0x\num
|
||||
jmp isr_common_stub
|
||||
.endm
|
||||
|
||||
.macro ISR_ERRCODE num
|
||||
.global isr\num
|
||||
isr\num:
|
||||
cli
|
||||
push $0x\num
|
||||
jmp isr_common_stub
|
||||
.endm
|
||||
|
||||
ISR_NOERRCODE 0 // Divide by sero
|
||||
ISR_NOERRCODE 1 // Debug
|
||||
ISR_NOERRCODE 2 // Non-maskable Interrupt
|
||||
ISR_NOERRCODE 3 // Breakpoint
|
||||
ISR_NOERRCODE 4 // Overflow
|
||||
ISR_NOERRCODE 5 // Bound Range Exceeded
|
||||
ISR_NOERRCODE 6 // Invalid Opcode
|
||||
ISR_NOERRCODE 7 // Device Not Avalible
|
||||
ISR_ERRCODE 8 // Double Fault
|
||||
ISR_NOERRCODE 9 // Coprocessor Segment Overrun
|
||||
ISR_ERRCODE 10 // Invalid TSS
|
||||
ISR_ERRCODE 11
|
||||
ISR_ERRCODE 12
|
||||
ISR_ERRCODE 13
|
||||
ISR_ERRCODE 14
|
||||
ISR_NOERRCODE 15
|
||||
ISR_NOERRCODE 16
|
||||
ISR_ERRCODE 17
|
||||
ISR_NOERRCODE 18
|
||||
ISR_NOERRCODE 19
|
||||
ISR_NOERRCODE 20
|
||||
ISR_NOERRCODE 21
|
||||
ISR_NOERRCODE 22
|
||||
ISR_NOERRCODE 23
|
||||
ISR_NOERRCODE 24
|
||||
ISR_NOERRCODE 25
|
||||
ISR_NOERRCODE 26
|
||||
ISR_NOERRCODE 27
|
||||
ISR_NOERRCODE 28
|
||||
ISR_NOERRCODE 29
|
||||
ISR_ERRCODE 30
|
||||
ISR_NOERRCODE 31
|
||||
|
||||
isr_common_stub:
|
||||
pusha
|
||||
mov %ds,%ax
|
||||
push %eax
|
||||
mov $0x10,%ax
|
||||
mov %eax,%ds
|
||||
mov %eax,%es
|
||||
mov %eax,%fs
|
||||
mov %eax,%gs
|
||||
mov %eax,%ss
|
||||
ljmp $0x8,$.flush
|
||||
.flush:
|
||||
ret
|
||||
|
||||
call isr_handler
|
||||
|
||||
pop %eax
|
||||
mov %eax,%ds
|
||||
mov %eax,%es
|
||||
mov %eax,%fs
|
||||
mov %eax,%gs
|
||||
popa
|
||||
add $0x8,%esp
|
||||
sti
|
||||
iret
|
||||
|
||||
|
||||
|
|
|
@ -3,10 +3,15 @@
|
|||
#include <kernel/tty.h>
|
||||
#include "serial.h"
|
||||
#include "gdt.c"
|
||||
#include "interrupts.c"
|
||||
|
||||
void kernel_early_main(void) {
|
||||
gdt_init();
|
||||
terminal_initialize();
|
||||
init_serial();
|
||||
serial_printf("gdt initialized!\n");
|
||||
idt_init();
|
||||
serial_printf("idt initialized!\n");
|
||||
//asm volatile("int $0x3");
|
||||
//asm volatile("int $0x4");
|
||||
terminal_initialize();
|
||||
}
|
||||
|
|
|
@ -1,54 +1,7 @@
|
|||
|
||||
// Used for creating GDT segment descriptors in 64-bit integer form.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Each define here is for a specific flag in the descriptor.
|
||||
// Refer to the intel documentation for a description of what each one does.
|
||||
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
|
||||
#define SEG_PRES(x) ((x) << 0x07) // Present
|
||||
#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
|
||||
#define SEG_LONG(x) ((x) << 0x0D) // Long mode
|
||||
#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
|
||||
#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)
|
||||
#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3)
|
||||
|
||||
#define SEG_DATA_RD 0x00 // Read-Only
|
||||
#define SEG_DATA_RDA 0x01 // Read-Only, accessed
|
||||
#define SEG_DATA_RDWR 0x02 // Read/Write
|
||||
#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed
|
||||
#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down
|
||||
#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed
|
||||
#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down
|
||||
#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
|
||||
#define SEG_CODE_EX 0x08 // Execute-Only
|
||||
#define SEG_CODE_EXA 0x09 // Execute-Only, accessed
|
||||
#define SEG_CODE_EXRD 0x0A // Execute/Read
|
||||
#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed
|
||||
#define SEG_CODE_EXC 0x0C // Execute-Only, conforming
|
||||
#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed
|
||||
#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming
|
||||
#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed
|
||||
|
||||
#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(0) | SEG_DATA_RDWR
|
||||
|
||||
#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(3) | SEG_CODE_EXRD
|
||||
|
||||
#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
|
||||
SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
|
||||
SEG_PRIV(3) | SEG_DATA_RDWR
|
||||
#define GDT_MAX_DESCRIPTORS 3
|
||||
|
||||
struct gdt_entry {
|
||||
struct gdt_entry_struct {
|
||||
uint16_t limit_low;
|
||||
uint16_t base_low;
|
||||
uint8_t base_middle;
|
||||
|
@ -56,53 +9,40 @@ struct gdt_entry {
|
|||
uint8_t granularity;
|
||||
uint8_t base_high;
|
||||
}__attribute__((packed));
|
||||
typedef struct gdt_entry_struct gdt_entry_t;
|
||||
|
||||
struct gdt_ptr {
|
||||
struct gdt_ptr_struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
}__attribute__((packed));
|
||||
typedef struct gdt_ptr_struct gdt_ptr_t;
|
||||
|
||||
struct gdt_entry gdt[GDT_MAX_DESCRIPTORS];
|
||||
struct gdt_ptr gp;
|
||||
gdt_entry_t gdt_entries[5];
|
||||
gdt_ptr_t gdt_ptr;
|
||||
|
||||
extern void gdt_flush(struct gdt_ptr* gdt_ptr_addr);
|
||||
|
||||
void
|
||||
create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
|
||||
static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
||||
{
|
||||
uint64_t descriptor;
|
||||
gdt_entries[num].base_low = (base & 0xFFFF);
|
||||
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
|
||||
gdt_entries[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
gdt_entries[num].limit_low = (limit & 0xFFFF);
|
||||
gdt_entries[num].granularity = (limit >> 16) & 0x0F;
|
||||
|
||||
// Create the high 32 bit segment
|
||||
descriptor = limit & 0x000F0000; // set limit bits 19:16
|
||||
descriptor |= (flag << 8) & 0x00F0FF00; // set type, p, dpl, s, g, d/b, l and avl fields
|
||||
descriptor |= (base >> 16) & 0x000000FF; // set base bits 23:16
|
||||
descriptor |= base & 0xFF000000; // set base bits 31:24
|
||||
|
||||
// Shift by 32 to allow for low part of segment
|
||||
descriptor <<= 32;
|
||||
|
||||
// Create the low 32 bit segment
|
||||
descriptor |= base << 16; // set base bits 15:0
|
||||
descriptor |= limit & 0x0000FFFF; // set limit bits 15:0
|
||||
|
||||
printf("0x%.16llX\n", descriptor);
|
||||
gdt_entries[num].granularity |= gran & 0xF0;
|
||||
gdt_entries[num].access = access;
|
||||
}
|
||||
|
||||
void gdt_init() {
|
||||
gp.limit = (sizeof(struct gdt_entry) * GDT_MAX_DESCRIPTORS) - 1;
|
||||
gp.base = (uint32_t) &gdt;
|
||||
|
||||
create_descriptor(0, 0, 0);
|
||||
create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL0));
|
||||
create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL0));
|
||||
create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3));
|
||||
create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3));
|
||||
|
||||
/*
|
||||
gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1;
|
||||
gdt_ptr.base = (uint32_t)&gdt_entries;
|
||||
|
||||
gdt_set_gate(0, 0, 0, 0, 0);
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
|
||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
|
||||
*/
|
||||
|
||||
gdt_flush(&gp);
|
||||
|
||||
gdt_flush((uint32_t)&gdt_ptr);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
struct idt_entry_struct
|
||||
{
|
||||
uint16_t base_lo; // The lower 16 bits of the ISR's address
|
||||
uint16_t sel; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||
uint8_t always0; // Always set to zero
|
||||
uint8_t flags; // Type and attributes
|
||||
uint16_t base_hi; // The higher 16 bits of the ISR's address
|
||||
} __attribute__((packed));
|
||||
typedef struct idt_entry_struct idt_entry_t;
|
||||
|
||||
struct idt_ptr_struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed));
|
||||
typedef struct idt_ptr_struct idt_ptr_t;
|
||||
|
||||
idt_entry_t idt_entries[256];
|
||||
idt_ptr_t idt_ptr;
|
||||
|
||||
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
|
||||
idt_entries[num].base_lo = base & 0xFFFF;
|
||||
idt_entries[num].base_hi = (base >> 16) & 0xFFFF;
|
||||
|
||||
idt_entries[num].sel = sel;
|
||||
idt_entries[num].always0 = 0;
|
||||
|
||||
idt_entries[num].flags = flags;
|
||||
}
|
||||
|
||||
void idt_init(void);
|
||||
void idt_init() {
|
||||
idt_ptr.base = (uintptr_t)&idt_entries;
|
||||
idt_ptr.limit = (uint16_t)sizeof(idt_entry_t) * 256 - 1;
|
||||
|
||||
memset(&idt_entries, 0, sizeof(idt_entry_t)*256);
|
||||
|
||||
extern isr0;
|
||||
extern isr1;
|
||||
extern isr2;
|
||||
extern isr3;
|
||||
extern isr4;
|
||||
extern isr5;
|
||||
extern isr6;
|
||||
extern isr7;
|
||||
extern isr8;
|
||||
extern isr9;
|
||||
extern isr10;
|
||||
extern isr11;
|
||||
extern isr12;
|
||||
extern isr13;
|
||||
extern isr14;
|
||||
extern isr15;
|
||||
extern isr16;
|
||||
extern isr17;
|
||||
extern isr18;
|
||||
extern isr19;
|
||||
extern isr20;
|
||||
extern isr21;
|
||||
extern isr22;
|
||||
extern isr23;
|
||||
extern isr24;
|
||||
extern isr25;
|
||||
extern isr26;
|
||||
extern isr27;
|
||||
extern isr28;
|
||||
extern isr29;
|
||||
extern isr30;
|
||||
extern isr31;
|
||||
|
||||
idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr1, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr2, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr3, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr4, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr5, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr6, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr7, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr8, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr9, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr10, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr11, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr12, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr13, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr14, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr15, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr16, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr17, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr18, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr19, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr20, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr21, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr22, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr23, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr24, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr25, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr26, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr27, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr28, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr29, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr30, 0x08, 0x8E);
|
||||
idt_set_gate(0, (uint32_t)isr31, 0x08, 0x8E);
|
||||
|
||||
|
||||
//__asm__ volatile ("lidt %0" : : "memory"(idt_ptr)); // load the new IDT
|
||||
//__asm__ volatile ("sti"); // set the interrupt flag
|
||||
|
||||
extern void idt_flush(uint32);
|
||||
idt_flush((uint32_t)&idt_ptr);
|
||||
|
||||
}
|
||||
|
||||
void isr_handler()
|
||||
{
|
||||
serial_printf("Received interrupt\n");
|
||||
}
|
||||
|
|
@ -6,6 +6,6 @@ void kernel_main(void) {
|
|||
serial_printf("Test is success!\n");
|
||||
serial_printf("Newline test\n");
|
||||
char * test_string = "test";
|
||||
serial_printf("This is string from variable: %s", test_string);
|
||||
serial_printf("This is string from variable: %s\n", test_string);
|
||||
printf("Test finished success!\n");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue