Kernel: add IDT (for interrupts) and fixed GDT - now can be loaded from grub

This commit is contained in:
g1n 2021-08-10 16:18:54 +03:00
parent f46798410a
commit 04b9ba01e8
5 changed files with 231 additions and 88 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}

116
kernel/kernel/interrupts.c Normal file
View File

@ -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");
}

View File

@ -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");
}