Espresso 0.0.0e
This commit is contained in:
6
Makefile
6
Makefile
@ -5,6 +5,8 @@ CC := i686-elf-gcc
|
|||||||
AS := i686-elf-as
|
AS := i686-elf-as
|
||||||
NASM := nasm
|
NASM := nasm
|
||||||
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M
|
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M
|
||||||
|
MKFS_VFAT := sudo mkfs.vfat
|
||||||
|
MKFS_FLAGS := -F 32 --mbr -S 512
|
||||||
NASMFLAGS := -f elf32
|
NASMFLAGS := -f elf32
|
||||||
WNOFLAGS := -Wno-discarded-qualifiers
|
WNOFLAGS := -Wno-discarded-qualifiers
|
||||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS)
|
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS)
|
||||||
@ -21,7 +23,7 @@ GRUB_CFG := grub.cfg
|
|||||||
# === File collection ===
|
# === File collection ===
|
||||||
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
|
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
|
||||||
S_SRCS := boot.s crti.s crtn.s misc_asm.s
|
S_SRCS := boot.s crti.s crtn.s misc_asm.s
|
||||||
NASM_SRCS := idt.asm isr128.asm gdt.asm isr_stub_table.asm pit.asm
|
NASM_SRCS := gdt.asm pit.asm isr.asm
|
||||||
CRTI_OBJ := crti.o
|
CRTI_OBJ := crti.o
|
||||||
CRTBEGIN_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
|
CRTBEGIN_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
|
||||||
CRTEND_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
|
CRTEND_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
|
||||||
@ -64,6 +66,8 @@ iso: $(TARGET)
|
|||||||
# === Run in QEMU ===
|
# === Run in QEMU ===
|
||||||
run: iso
|
run: iso
|
||||||
$(QEMU_MKE_IMG)
|
$(QEMU_MKE_IMG)
|
||||||
|
echo "\n"
|
||||||
|
$(MKFS_VFAT) $(MKFS_FLAGS) espresso.img
|
||||||
qemu-system-i386 $(QEMUFLAGS)
|
qemu-system-i386 $(QEMUFLAGS)
|
||||||
|
|
||||||
# === Clean all build artifacts ===
|
# === Clean all build artifacts ===
|
||||||
|
@ -44,7 +44,6 @@ int32_t fat32_init(int32_t drive)
|
|||||||
|
|
||||||
memcpy(&bpb, sector, sizeof(bpb));
|
memcpy(&bpb, sector, sizeof(bpb));
|
||||||
|
|
||||||
|
|
||||||
fat_start_lba = bpb.reserved_sector_count;
|
fat_start_lba = bpb.reserved_sector_count;
|
||||||
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
||||||
current_directory_cluster = bpb.root_cluster;
|
current_directory_cluster = bpb.root_cluster;
|
||||||
|
@ -1,34 +1,52 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <gdt.h>
|
#include <gdt.h>
|
||||||
|
#include <drivers/gdt_ec.h>
|
||||||
|
|
||||||
|
#define GDT_ENTRIES 5
|
||||||
|
uint64_t gdt[GDT_ENTRIES];
|
||||||
|
|
||||||
#define GDT_ENTRIES 3
|
struct {
|
||||||
|
uint16_t limit;
|
||||||
|
uint32_t base;
|
||||||
|
} __attribute__((packed)) gp;
|
||||||
|
|
||||||
struct gdt_entry gdt[GDT_ENTRIES];
|
|
||||||
struct gdt_ptr gp;
|
|
||||||
|
|
||||||
extern void gdt_flush(uint32_t);
|
extern void gdt_flush(uint32_t);
|
||||||
|
|
||||||
void gdt_install()
|
void gdt_install(bool prnt_gdt)
|
||||||
{
|
{
|
||||||
gp.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1;
|
create_descriptor(0, 0, 0, 0, prnt_gdt); // Null
|
||||||
gp.base = (uint32_t)&gdt;
|
create_descriptor(1, 0, 0x000FFFFF, GDT_CODE_PL0, prnt_gdt); // Kernel code
|
||||||
|
create_descriptor(2, 0, 0x000FFFFF, GDT_DATA_PL0, prnt_gdt); // Kernel data
|
||||||
|
create_descriptor(3, 0, 0x000FFFFF, GDT_CODE_PL3, prnt_gdt); // User code
|
||||||
|
create_descriptor(4, 0, 0x000FFFFF, GDT_DATA_PL3, prnt_gdt); // User data
|
||||||
|
|
||||||
gdt_set_entry(0, 0, 0, 0, 0); /* Null segment */
|
gp.limit = sizeof(gdt) - 1;
|
||||||
gdt_set_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
|
gp.base = (uint32_t)&gdt;
|
||||||
gdt_set_entry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
|
|
||||||
|
|
||||||
gdt_flush((uint32_t)&gp);
|
gdt_flush((uint32_t)&gp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdt_set_entry(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
|
void create_descriptor(int index, uint32_t base, uint32_t limit, uint16_t flag, bool prnt_gdt)
|
||||||
{
|
{
|
||||||
gdt[num].base_low = (base & 0xFFFF);
|
uint64_t descriptor;
|
||||||
gdt[num].base_middle = (base >> 16) & 0xFF;
|
|
||||||
gdt[num].base_high = (base >> 24) & 0xFF;
|
|
||||||
|
|
||||||
gdt[num].limit_low = (limit & 0xFFFF);
|
descriptor = limit & 0x000F0000; // limit bits 19:16
|
||||||
gdt[num].granularity = (limit >> 16) & 0x0F;
|
descriptor |= (flag << 8) & 0x00F0FF00; // flags and access
|
||||||
|
descriptor |= (base >> 16) & 0x000000FF; // base bits 23:16
|
||||||
|
descriptor |= base & 0xFF000000; // base bits 31:24
|
||||||
|
|
||||||
gdt[num].granularity |= (gran & 0xF0);
|
descriptor <<= 32;
|
||||||
gdt[num].access = access;
|
|
||||||
|
descriptor |= ((uint64_t)base << 16); // base bits 15:0
|
||||||
|
descriptor |= (limit & 0x0000FFFF); // limit bits 15:0
|
||||||
|
|
||||||
|
gdt[index] = descriptor;
|
||||||
|
|
||||||
|
if (prnt_gdt)
|
||||||
|
{
|
||||||
|
printf("GDT[%d] = 0x%llX\n", index, descriptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
drivers/gdt_ec.c
Normal file
0
drivers/gdt_ec.c
Normal file
228
drivers/idt.c
228
drivers/idt.c
@ -1,131 +1,141 @@
|
|||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
#include <port_io.h>
|
#include <port_io.h>
|
||||||
|
|
||||||
#include <idt.h>
|
#include <drivers/idt.h>
|
||||||
|
|
||||||
#define IDT_ENTRIES 256
|
|
||||||
|
|
||||||
struct idt_entry idt[IDT_ENTRIES];
|
#define IDT_MAX_DESCRIPTORS 256
|
||||||
struct idt_ptr idtp;
|
|
||||||
|
|
||||||
extern void idt_load(uint32_t);
|
#define PIC1_COMMAND 0x20
|
||||||
|
#define PIC1_DATA 0x21
|
||||||
|
#define PIC2_COMMAND 0xA0
|
||||||
|
#define PIC2_DATA 0xA1
|
||||||
|
|
||||||
void idt_install(void)
|
/*
|
||||||
|
Most of the code is this file (and idt.h) are taken from the osdev wiki: https://wiki.osdev.org/Interrupts_Tutorial, though not all of it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t isr_low; // The lower 16 bits of the ISR's address
|
||||||
|
uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR
|
||||||
|
uint8_t reserved; // Set to zero
|
||||||
|
uint8_t attributes; // Type and attributes; see the IDT page
|
||||||
|
uint16_t isr_high; // The higher 16 bits of the ISR's address
|
||||||
|
} __attribute__((packed)) idt_entry_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t limit;
|
||||||
|
uint32_t base;
|
||||||
|
} __attribute__((packed)) idtr_t;
|
||||||
|
|
||||||
|
__attribute__((aligned(0x10)))
|
||||||
|
|
||||||
|
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
|
||||||
|
|
||||||
|
static idtr_t idtr;
|
||||||
|
|
||||||
|
static bool vectors[IDT_MAX_DESCRIPTORS];
|
||||||
|
|
||||||
|
extern void* isr_stub_table[];
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
void exception_dispatcher(uint32_t int_no, uint32_t err_code)
|
||||||
{
|
{
|
||||||
idtp.limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1;
|
switch (int_no)
|
||||||
idtp.base = (uint32_t)&idt;
|
{
|
||||||
|
case 0:
|
||||||
|
printf("Divide by zero exception\n");
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
printf("General Protection Fault: err=0x%x\n", err_code);
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
{
|
||||||
|
uint32_t cr2;
|
||||||
|
__asm__ volatile ("mov %%cr2, %0" : "=r"(cr2));
|
||||||
|
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
printf("Unhandled exception #%u, err=0x%x\n", int_no, err_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&idt, 0, sizeof(struct idt_entry) * IDT_ENTRIES);
|
uint16_t cs, ds, es, ss;
|
||||||
|
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
||||||
|
asm volatile ("mov %%ds, %0" : "=r"(ds));
|
||||||
|
asm volatile ("mov %%es, %0" : "=r"(es));
|
||||||
|
asm volatile ("mov %%ss, %0" : "=r"(ss));
|
||||||
|
|
||||||
/* Set entries for IRQs/ISRs here using `idt_set_entry(...)` */
|
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
|
||||||
/* Example: idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E); */
|
|
||||||
|
|
||||||
idt_load((uint32_t)&idtp);
|
__asm__ volatile ("cli; hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) {
|
||||||
|
idt_entry_t* descriptor = &idt[vector];
|
||||||
|
|
||||||
|
descriptor->isr_low = (uint32_t)isr & 0xFFFF;
|
||||||
|
descriptor->kernel_cs = 0x08;
|
||||||
|
descriptor->attributes = flags;
|
||||||
|
descriptor->isr_high = (uint32_t)isr >> 16;
|
||||||
|
descriptor->reserved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pic_remap(void)
|
void pic_remap(void)
|
||||||
{
|
{
|
||||||
outb(0x20, 0x11); /* Start init for master PIC */
|
uint8_t a1, a2;
|
||||||
outb(0xA0, 0x11); /* Start init for slave PIC */
|
|
||||||
outb(0x21, 0x20); /* Master PIC vector offset */
|
// Save masks
|
||||||
outb(0xA1, 0x28); /* Slave PIC vector offset */
|
a1 = inb(PIC1_DATA);
|
||||||
outb(0x21, 0x04); /* Tell Master PIC about Slave PIC at IRQ2 */
|
a2 = inb(PIC2_DATA);
|
||||||
outb(0xA1, 0x02); /* Tell Slave PIC its cascade identity */
|
|
||||||
outb(0x21, 0x01); /* 8086/88 mode */
|
// Start initialization sequence (in cascade mode)
|
||||||
outb(0xA1, 0x01);
|
outb(PIC1_COMMAND, 0x11);
|
||||||
outb(0x21, 0x0); /* Unmask master */
|
outb(PIC2_COMMAND, 0x11);
|
||||||
outb(0xA1, 0x0); /* Unmask slave */
|
|
||||||
|
// Set vector offset
|
||||||
|
outb(PIC1_DATA, 0x20); // IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39)
|
||||||
|
outb(PIC2_DATA, 0x28); // IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47)
|
||||||
|
|
||||||
|
// Tell Master PIC about Slave PIC at IRQ2 (0000 0100)
|
||||||
|
outb(PIC1_DATA, 0x04);
|
||||||
|
|
||||||
|
// Tell Slave PIC its cascade identity (0000 0010)
|
||||||
|
outb(PIC2_DATA, 0x02);
|
||||||
|
|
||||||
|
// Set 8086/88 mode
|
||||||
|
outb(PIC1_DATA, 0x01);
|
||||||
|
outb(PIC2_DATA, 0x01);
|
||||||
|
|
||||||
|
// Restore saved masks
|
||||||
|
outb(PIC1_DATA, a1);
|
||||||
|
outb(PIC2_DATA, a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void idt_set_entry(int num, uint32_t base, uint16_t sel, uint8_t flags)
|
void idt_init(void)
|
||||||
{
|
{
|
||||||
idt[num].base_low = base & 0xFFFF;
|
idtr.base = (uintptr_t)&idt[0];
|
||||||
idt[num].base_high = (base >> 16) & 0xFFFF;
|
idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1;
|
||||||
|
|
||||||
idt[num].sel = sel;
|
for (uint8_t vector = 0; vector < 32; vector++)
|
||||||
idt[num].always0 = 0;
|
{
|
||||||
idt[num].flags = flags;
|
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
||||||
}
|
vectors[vector] = true;
|
||||||
|
}
|
||||||
extern void IRQ0_handler(void);
|
|
||||||
extern void isr0(void);
|
|
||||||
extern void isr1(void);
|
|
||||||
extern void isr2(void);
|
|
||||||
extern void isr3(void);
|
|
||||||
extern void isr4(void);
|
|
||||||
extern void isr5(void);
|
|
||||||
extern void isr6(void);
|
|
||||||
extern void isr7(void);
|
|
||||||
extern void isr8(void);
|
|
||||||
extern void isr9(void);
|
|
||||||
extern void isr10(void);
|
|
||||||
extern void isr11(void);
|
|
||||||
extern void isr12(void);
|
|
||||||
extern void isr13(void);
|
|
||||||
extern void isr14(void);
|
|
||||||
extern void isr15(void);
|
|
||||||
extern void isr16(void);
|
|
||||||
extern void isr17(void);
|
|
||||||
extern void isr18(void);
|
|
||||||
extern void isr19(void);
|
|
||||||
extern void isr20(void);
|
|
||||||
extern void isr21(void);
|
|
||||||
extern void isr22(void);
|
|
||||||
extern void isr23(void);
|
|
||||||
extern void isr24(void);
|
|
||||||
extern void isr25(void);
|
|
||||||
extern void isr26(void);
|
|
||||||
extern void isr27(void);
|
|
||||||
extern void isr28(void);
|
|
||||||
extern void isr29(void);
|
|
||||||
extern void isr30(void);
|
|
||||||
extern void isr31(void);
|
|
||||||
|
|
||||||
extern void isr33(void);
|
|
||||||
|
|
||||||
extern void isr128(void);
|
|
||||||
|
|
||||||
|
|
||||||
void idt_install_isrs(void)
|
|
||||||
{
|
|
||||||
idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E);
|
|
||||||
idt_set_entry(1, (uint32_t)isr1, 0x08, 0x8E);
|
|
||||||
idt_set_entry(2, (uint32_t)isr2, 0x08, 0x8E);
|
|
||||||
idt_set_entry(3, (uint32_t)isr3, 0x08, 0x8E);
|
|
||||||
idt_set_entry(4, (uint32_t)isr4, 0x08, 0x8E);
|
|
||||||
idt_set_entry(5, (uint32_t)isr5, 0x08, 0x8E);
|
|
||||||
idt_set_entry(6, (uint32_t)isr6, 0x08, 0x8E);
|
|
||||||
idt_set_entry(7, (uint32_t)isr7, 0x08, 0x8E);
|
|
||||||
idt_set_entry(8, (uint32_t)isr8, 0x08, 0x8E);
|
|
||||||
idt_set_entry(9, (uint32_t)isr9, 0x08, 0x8E);
|
|
||||||
idt_set_entry(10, (uint32_t)isr10, 0x08, 0x8E);
|
|
||||||
idt_set_entry(11, (uint32_t)isr11, 0x08, 0x8E);
|
|
||||||
idt_set_entry(12, (uint32_t)isr12, 0x08, 0x8E);
|
|
||||||
idt_set_entry(13, (uint32_t)isr13, 0x08, 0x8E);
|
|
||||||
idt_set_entry(14, (uint32_t)isr14, 0x08, 0x8E);
|
|
||||||
idt_set_entry(15, (uint32_t)isr15, 0x08, 0x8E);
|
|
||||||
idt_set_entry(16, (uint32_t)isr16, 0x08, 0x8E);
|
|
||||||
idt_set_entry(17, (uint32_t)isr17, 0x08, 0x8E);
|
|
||||||
idt_set_entry(18, (uint32_t)isr18, 0x08, 0x8E);
|
|
||||||
idt_set_entry(19, (uint32_t)isr19, 0x08, 0x8E);
|
|
||||||
idt_set_entry(20, (uint32_t)isr20, 0x08, 0x8E);
|
|
||||||
idt_set_entry(21, (uint32_t)isr21, 0x08, 0x8E);
|
|
||||||
idt_set_entry(22, (uint32_t)isr22, 0x08, 0x8E);
|
|
||||||
idt_set_entry(23, (uint32_t)isr23, 0x08, 0x8E);
|
|
||||||
idt_set_entry(24, (uint32_t)isr24, 0x08, 0x8E);
|
|
||||||
idt_set_entry(25, (uint32_t)isr25, 0x08, 0x8E);
|
|
||||||
idt_set_entry(26, (uint32_t)isr26, 0x08, 0x8E);
|
|
||||||
idt_set_entry(27, (uint32_t)isr27, 0x08, 0x8E);
|
|
||||||
idt_set_entry(28, (uint32_t)isr28, 0x08, 0x8E);
|
|
||||||
idt_set_entry(29, (uint32_t)isr29, 0x08, 0x8E);
|
|
||||||
idt_set_entry(30, (uint32_t)isr30, 0x08, 0x8E);
|
|
||||||
idt_set_entry(31, (uint32_t)isr31, 0x08, 0x8E);
|
|
||||||
|
|
||||||
idt_set_entry(33, (uint32_t)isr33, 0x08, 0x8E);
|
extern void* irq_stub_table[];
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__asm__ volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
||||||
|
__asm__ volatile ("sti"); /* set the interrupt flag */
|
||||||
}
|
}
|
||||||
|
|
||||||
void idt_install_syscall(void)
|
|
||||||
{
|
|
||||||
idt_set_entry(128, (uint32_t)isr128, 0x08, 0xEE);
|
|
||||||
}
|
|
||||||
|
9
drivers/irq.c
Normal file
9
drivers/irq.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <drivers/irq.h>
|
||||||
|
|
||||||
|
|
||||||
|
void irq_handler(uint8_t irq_number)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,42 +0,0 @@
|
|||||||
#include <port_io.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <isr.h>
|
|
||||||
|
|
||||||
|
|
||||||
void (*irq_handlers[256])(isr_stack_t *r) = { 0 };
|
|
||||||
|
|
||||||
void register_interrupt_handler(uint8_t n, void (*handler)(isr_stack_t *))
|
|
||||||
{
|
|
||||||
irq_handlers[n] = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void isr_handler(isr_stack_t *r)
|
|
||||||
{
|
|
||||||
if (irq_handlers[r->int_no]) {
|
|
||||||
irq_handlers[r->int_no](r);
|
|
||||||
} else {
|
|
||||||
printf("Unhandled interrupt: %d\n", r->int_no);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Send EOI to PIC */
|
|
||||||
if (r->int_no >= 40)
|
|
||||||
{
|
|
||||||
outb(0xA0, 0x20);
|
|
||||||
}
|
|
||||||
if (r->int_no >= 32)
|
|
||||||
{
|
|
||||||
outb(0x20, 0x20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void syscall_handler(regs_t *r)
|
|
||||||
{
|
|
||||||
switch (r->eax) {
|
|
||||||
case 0: printf("Syscall: Hello world\n"); break;
|
|
||||||
case 1: printf("Syscall: value = %d\n", r->ebx); break;
|
|
||||||
default: printf("Unknown syscall %d\n", r->eax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
/*#include <stdint.h>
|
||||||
|
#include <port_io.h>
|
||||||
|
#include <drivers/irq.h>
|
||||||
|
|
||||||
|
#define PIT_CHANNEL0 0x40
|
||||||
|
#define PIT_COMMAND 0x43
|
||||||
|
#define PIT_FREQUENCY 1193182
|
||||||
|
|
||||||
|
static uint32_t tick = 0;
|
||||||
|
|
||||||
|
void pit_callback(struct regs* r)
|
||||||
|
{
|
||||||
|
(void)r;
|
||||||
|
tick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pit_init(uint32_t frequency)
|
||||||
|
{
|
||||||
|
uint32_t divisor = PIT_FREQUENCY / frequency;
|
||||||
|
|
||||||
|
outb(PIT_COMMAND, 0x36);
|
||||||
|
outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF));
|
||||||
|
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF));
|
||||||
|
|
||||||
|
register_interrupt_handler(32, pit_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleep(uint32_t milliseconds)
|
||||||
|
{
|
||||||
|
uint32_t target = tick + milliseconds;
|
||||||
|
while (tick < target);
|
||||||
|
}*/
|
||||||
|
@ -5,94 +5,18 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PS/2 Controller IO Ports
|
PS/2 Controller IO Ports
|
||||||
|
|
||||||
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
|
The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers.
|
||||||
|
|
||||||
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
|
Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles.
|
||||||
IO Port Access Type Purpose
|
IO Port Access Type Purpose
|
||||||
0x60 Read/Write Data Port
|
0x60 Read/Write Data Port
|
||||||
0x64 Read Status Register
|
0x64 Read Status Register
|
||||||
0x64 Write Command Register
|
0x64 Write Command Register
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PS2_DATA_PORT 0x60
|
|
||||||
#define PS2_STATUS_PORT 0x64
|
|
||||||
|
|
||||||
#define KEYBOARD_IRQ 33
|
|
||||||
|
|
||||||
/*extern void register_interrupt_handler(int irq, void (*handler)(void));*/
|
|
||||||
|
|
||||||
static const char scancode_map[128] = {
|
|
||||||
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
|
|
||||||
'\t', /* Tab */
|
|
||||||
'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */
|
|
||||||
0, /* Control */
|
|
||||||
'a','s','d','f','g','h','j','k','l',';','\'','`',
|
|
||||||
0, /* Left shift */
|
|
||||||
'\\','z','x','c','v','b','n','m',',','.','/',
|
|
||||||
0, /* Right shift */
|
|
||||||
'*',
|
|
||||||
0, /* Alt */
|
|
||||||
' ', /* Spacebar */
|
|
||||||
0, /* Caps lock */
|
|
||||||
/* The rest are function and control keys */
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool shift_pressed = false;
|
|
||||||
|
|
||||||
void keyboard_handler(isr_stack_t* regs)
|
|
||||||
{
|
|
||||||
(void)regs; /* Only here to dismiss the "Unused parameter" warnings */
|
|
||||||
printd("PS/2 Keyboard handler fired!\n");
|
|
||||||
|
|
||||||
uint8_t scancode = inb(PS2_DATA_PORT);
|
|
||||||
|
|
||||||
/* Handle shift press/release */
|
|
||||||
if (scancode == 0x2A || scancode == 0x36)
|
|
||||||
{
|
|
||||||
shift_pressed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (scancode == 0xAA || scancode == 0xB6)
|
|
||||||
{
|
|
||||||
shift_pressed = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scancode & 0x80)
|
|
||||||
{
|
|
||||||
/* Key release event, ignore for now */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char c = scancode_map[scancode];
|
|
||||||
if (shift_pressed && c >= 'a' && c <= 'z')
|
|
||||||
{
|
|
||||||
c -= 32; /* Convert to uppercase */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
/* Do something with the keypress (e.g., print or buffer) */
|
|
||||||
printf("Char: %c", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
outb(0x20, 0x20); /* Acknowledge PIC */
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_handler(isr_stack_t* r) {
|
|
||||||
printf("IRQ1 fired!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void keyboard_init(void)
|
void keyboard_init(void)
|
||||||
{
|
{
|
||||||
outb(0x21, inb(0x21) & ~0x02);
|
|
||||||
|
|
||||||
register_interrupt_handler(KEYBOARD_IRQ, test_handler);
|
|
||||||
|
|
||||||
/* Enable keyboard (controller-specific, often optional if already working) */
|
|
||||||
//outb(0x64, 0xAE);
|
|
||||||
}
|
}
|
||||||
|
21
drivers/timer.c
Normal file
21
drivers/timer.c
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*#include <drivers/isr.h>
|
||||||
|
#include <drivers/irq.h>
|
||||||
|
|
||||||
|
#include <drivers/timer.h>
|
||||||
|
|
||||||
|
volatile uint32_t tick_count = 0;
|
||||||
|
|
||||||
|
void irq0_handler(regs_t* regs)
|
||||||
|
{
|
||||||
|
tick_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_sleep(uint32_t ms)
|
||||||
|
{
|
||||||
|
uint32_t target = tick_count + ms;
|
||||||
|
while (tick_count < target)
|
||||||
|
{
|
||||||
|
asm volatile("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -151,7 +151,10 @@ void terminal_clearl(size_t num_lines)
|
|||||||
|
|
||||||
while (terminal_row < num_lines)
|
while (terminal_row < num_lines)
|
||||||
{
|
{
|
||||||
terminal_writechar_r(' ');
|
for (int32_t k = 0; k < (int32_t)VGA_WIDTH; k++)
|
||||||
|
{
|
||||||
|
terminal_putentryat((unsigned char)' ', terminal_getcolor(), (size_t)terminal_row, (size_t)k);
|
||||||
|
}
|
||||||
terminal_row -= 1;
|
terminal_row -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
gdt.asm
7
gdt.asm
@ -3,13 +3,12 @@ global gdt_flush
|
|||||||
gdt_flush:
|
gdt_flush:
|
||||||
mov eax, [esp + 4]
|
mov eax, [esp + 4]
|
||||||
lgdt [eax]
|
lgdt [eax]
|
||||||
; Reload segment registers
|
jmp 0x08:.flush_label ; long jump to reload CS with new segment
|
||||||
mov ax, 0x10 ; Kernel data segment
|
.flush_label:
|
||||||
|
mov ax, 0x10
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
mov es, ax
|
mov es, ax
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
mov gs, ax
|
mov gs, ax
|
||||||
mov ss, ax
|
mov ss, ax
|
||||||
jmp 0x08:.flush ; Kernel code segment
|
|
||||||
.flush:
|
|
||||||
ret
|
ret
|
||||||
|
40
idt.asm
40
idt.asm
@ -1,40 +0,0 @@
|
|||||||
[bits 32]
|
|
||||||
global idt_load
|
|
||||||
global common_isr_stub
|
|
||||||
|
|
||||||
extern isr_handler
|
|
||||||
extern _push_regs
|
|
||||||
extern _pop_regs
|
|
||||||
|
|
||||||
idt_load:
|
|
||||||
mov eax, [esp + 4]
|
|
||||||
lidt [eax]
|
|
||||||
ret
|
|
||||||
|
|
||||||
common_isr_stub:
|
|
||||||
call _push_regs ; Push all general-purpose registers
|
|
||||||
push ds
|
|
||||||
push es
|
|
||||||
push fs
|
|
||||||
push gs
|
|
||||||
|
|
||||||
mov ax, 0x10 ; Load kernel data segment
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
push esp ; Pass pointer to the register state
|
|
||||||
call isr_handler ; Call your C ISR handler
|
|
||||||
|
|
||||||
add esp, 4 ; Clean up stack from push esp
|
|
||||||
pop gs
|
|
||||||
pop fs
|
|
||||||
pop es
|
|
||||||
pop ds
|
|
||||||
|
|
||||||
call _pop_regs ; restore all general-purpose registers
|
|
||||||
|
|
||||||
add esp, 8 ; Remove int_no and err_code
|
|
||||||
sti
|
|
||||||
iret
|
|
8
include/drivers/gdt_ec.c
Normal file
8
include/drivers/gdt_ec.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _GDT_EC_H
|
||||||
|
#define _GDT_EC_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
void create_descriptor(uint32_t base, uint32_t limit, uint16_t flag);
|
||||||
|
|
||||||
|
#endif
|
50
include/drivers/gdt_ec.h
Normal file
50
include/drivers/gdt_ec.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef _GDT_EC_H
|
||||||
|
#define _GDT_EC_H
|
||||||
|
|
||||||
|
#include <types.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
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
13
include/drivers/idt.h
Normal file
13
include/drivers/idt.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _IDT_H
|
||||||
|
#define _IDT_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
|
||||||
|
void idt_init(void);
|
||||||
|
void pic_remap(void);
|
||||||
|
void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
|
||||||
|
void exception_dispatcher(uint32_t int_no, uint32_t err_code);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
8
include/drivers/irq.h
Normal file
8
include/drivers/irq.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _IRQ_H
|
||||||
|
#define _IRQ_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
void irq_handler(uint8_t irq_number);
|
||||||
|
|
||||||
|
#endif
|
@ -3,5 +3,7 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
|
void pit_init(uint32_t freq);
|
||||||
|
void sleep(uint32_t millis);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
#define _PS2_KEYBOARD_H
|
#define _PS2_KEYBOARD_H
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <isr.h>
|
|
||||||
|
|
||||||
void keyboard_init(void);
|
void keyboard_init(void);
|
||||||
void keyboard_handler(isr_stack_t* regs);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
include/drivers/timer.h
Normal file
11
include/drivers/timer.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _TIMER_H
|
||||||
|
#define _TIMER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern volatile uint32_t tick_count;
|
||||||
|
|
||||||
|
void timer_sleep(uint32_t ms);
|
||||||
|
void pit_init(uint32_t frequency);
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef _FAT32_H
|
#ifndef _FAT32_H
|
||||||
#define _FAT32_H
|
#define _FAT32_H
|
||||||
#include <stdint.h>
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
#define FAT32_MAX_FILENAME 11
|
#define FAT32_MAX_FILENAME 11
|
||||||
#define FAT32_ATTR_DIRECTORY 0x10
|
#define FAT32_ATTR_DIRECTORY 0x10
|
||||||
|
@ -3,21 +3,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct gdt_entry {
|
void gdt_install(bool prnt_gdt);
|
||||||
uint16_t limit_low; /* Lower 16 bits of limit */
|
void create_descriptor(int index, uint32_t base, uint32_t limit, uint16_t flag, bool prnt_gdt);
|
||||||
uint16_t base_low; /* Lower 16 bits of base */
|
|
||||||
uint8_t base_middle; /* Next 8 bits of base */
|
|
||||||
uint8_t access; /* Access flags */
|
|
||||||
uint8_t granularity; /* Granularity + high 4 bits of limit */
|
|
||||||
uint8_t base_high; /* Last 8 bits of base */
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct gdt_ptr {
|
|
||||||
uint16_t limit; /* Size of GDT - 1 */
|
|
||||||
uint32_t base; /* Base address of GDT */
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
void gdt_install();
|
|
||||||
void gdt_set_entry(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
#ifndef _IDT_H
|
|
||||||
#define _IDT_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
struct idt_entry {
|
|
||||||
uint16_t base_low;
|
|
||||||
uint16_t sel; /* Kernel segment selector */
|
|
||||||
uint8_t always0; /* Always 0 */
|
|
||||||
uint8_t flags; /* Type and attributes */
|
|
||||||
uint16_t base_high;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct idt_ptr {
|
|
||||||
uint16_t limit;
|
|
||||||
uint32_t base;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
void idt_install(void);
|
|
||||||
void idt_install_isrs(void);
|
|
||||||
void idt_install_syscall(void);
|
|
||||||
void pic_remap(void);
|
|
||||||
void idt_set_entry(int num, uint32_t base, uint16_t sel, uint8_t flags);
|
|
||||||
|
|
||||||
#endif
|
|
@ -4,7 +4,6 @@
|
|||||||
#define ESPRESSO_IO_H
|
#define ESPRESSO_IO_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <text_display.h>
|
|
||||||
|
|
||||||
void print(const char* str);
|
void print(const char* str);
|
||||||
|
|
||||||
@ -13,4 +12,4 @@ char* input(uint8_t dev=0);
|
|||||||
void writefile(uint8_t mode, char* file, char* data);
|
void writefile(uint8_t mode, char* file, char* data);
|
||||||
char* readfile(char* file);
|
char* readfile(char* file);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef _ISR_H
|
|
||||||
#define _ISR_H
|
|
||||||
|
|
||||||
#include <types.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t ds, edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
|
||||||
uint32_t int_no, err_code;
|
|
||||||
uint32_t eip, cs, eflags, useresp, ss;
|
|
||||||
} regs_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t ds;
|
|
||||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
|
||||||
uint32_t int_no, err_code;
|
|
||||||
uint32_t eip, cs, eflags, useresp, ss;
|
|
||||||
} isr_stack_t;
|
|
||||||
|
|
||||||
void isr_handler(isr_stack_t *r);
|
|
||||||
void syscall_handler(regs_t *r);
|
|
||||||
void register_interrupt_handler(uint8_t n, void (*handler)(isr_stack_t *));
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||||||
#ifndef _SYSCALLS_H
|
|
||||||
#define _SYSCALLS_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
int16_t syscall_write(int32_t fd, const void* buffer, int32_t length);
|
|
||||||
|
|
||||||
#endif
|
|
@ -14,6 +14,7 @@ void printf(const char*, ...);
|
|||||||
void print_int(int32_t value);
|
void print_int(int32_t value);
|
||||||
void print_uint(uint32_t value);
|
void print_uint(uint32_t value);
|
||||||
void print_hex(uint32_t value, int width, bool uppercase);
|
void print_hex(uint32_t value, int width, bool uppercase);
|
||||||
|
void print_hex64(uint64_t value, int width, bool uppercase);
|
||||||
void print_double(double value, int precision);
|
void print_double(double value, int precision);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
167
isr.asm
Normal file
167
isr.asm
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
[BITS 32]
|
||||||
|
[GLOBAL isr_stub_table]
|
||||||
|
[GLOBAL irq_stub_table]
|
||||||
|
extern irq_handler ; C function
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
; --------------------------------------------
|
||||||
|
; ------------------- IRQs -------------------
|
||||||
|
; --------------------------------------------
|
||||||
|
|
||||||
|
%macro irq_stub 1
|
||||||
|
irq_stub_%+%1:
|
||||||
|
pusha
|
||||||
|
push ds
|
||||||
|
push es
|
||||||
|
push fs
|
||||||
|
push gs
|
||||||
|
|
||||||
|
mov ax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
|
||||||
|
push dword %1 ; Push IRQ number
|
||||||
|
call irq_handler
|
||||||
|
add esp, 4 ; Clean up stack
|
||||||
|
|
||||||
|
; Send EOI
|
||||||
|
mov al, 0x20
|
||||||
|
mov bl, %1
|
||||||
|
cmp bl, 8
|
||||||
|
jb .skip_slave_eoi
|
||||||
|
out 0xA0, al
|
||||||
|
.skip_slave_eoi:
|
||||||
|
out 0x20, al
|
||||||
|
|
||||||
|
pop gs
|
||||||
|
pop fs
|
||||||
|
pop es
|
||||||
|
pop ds
|
||||||
|
popa
|
||||||
|
iret
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
|
||||||
|
; Define 16 IRQ stubs
|
||||||
|
irq_stub 0
|
||||||
|
irq_stub 1
|
||||||
|
irq_stub 2
|
||||||
|
irq_stub 3
|
||||||
|
irq_stub 4
|
||||||
|
irq_stub 5
|
||||||
|
irq_stub 6
|
||||||
|
irq_stub 7
|
||||||
|
irq_stub 8
|
||||||
|
irq_stub 9
|
||||||
|
irq_stub 10
|
||||||
|
irq_stub 11
|
||||||
|
irq_stub 12
|
||||||
|
irq_stub 13
|
||||||
|
irq_stub 14
|
||||||
|
irq_stub 15
|
||||||
|
|
||||||
|
irq_stub_table:
|
||||||
|
%assign i 0
|
||||||
|
%rep 16
|
||||||
|
dd irq_stub_%+i
|
||||||
|
%assign i i+1
|
||||||
|
%endrep
|
||||||
|
|
||||||
|
; --------------------------------------------
|
||||||
|
; ------------------- ISRs -------------------
|
||||||
|
; --------------------------------------------
|
||||||
|
|
||||||
|
; Common exception handler entry point
|
||||||
|
isr_common_handler:
|
||||||
|
pusha ; Push general-purpose registers
|
||||||
|
push ds
|
||||||
|
push es
|
||||||
|
push fs
|
||||||
|
push gs
|
||||||
|
|
||||||
|
; Load known-good segment selectors
|
||||||
|
mov ax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
|
||||||
|
; Print exception number and error code
|
||||||
|
; You can insert direct port writes or call kernel logging function here
|
||||||
|
; For now, just hang
|
||||||
|
.halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt
|
||||||
|
|
||||||
|
; If you want to later restore:
|
||||||
|
pop gs
|
||||||
|
pop fs
|
||||||
|
pop es
|
||||||
|
pop ds
|
||||||
|
popa
|
||||||
|
add esp, 8 ; clean up int_no + err_code
|
||||||
|
iret
|
||||||
|
|
||||||
|
; Macro: for exceptions with error code
|
||||||
|
%macro isr_err_stub 1
|
||||||
|
isr_stub_%+%1:
|
||||||
|
cli
|
||||||
|
push dword %1 ; interrupt number
|
||||||
|
jmp isr_common_handler
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
; Macro: for exceptions without error code
|
||||||
|
%macro isr_no_err_stub 1
|
||||||
|
isr_stub_%+%1:
|
||||||
|
cli
|
||||||
|
push dword 0 ; fake error code
|
||||||
|
push dword %1 ; interrupt number
|
||||||
|
jmp isr_common_handler
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
; Define all 32 exception stubs
|
||||||
|
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
|
||||||
|
|
||||||
|
; Create jump table
|
||||||
|
isr_stub_table:
|
||||||
|
%assign i 0
|
||||||
|
%rep 32
|
||||||
|
dd isr_stub_%+i
|
||||||
|
%assign i i+1
|
||||||
|
%endrep
|
||||||
|
|
97
isr.old.asm
Normal file
97
isr.old.asm
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
[BITS 32]
|
||||||
|
[GLOBAL isr_stub_table]
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
; Common exception handler entry point
|
||||||
|
isr_common_handler:
|
||||||
|
pusha ; Push general-purpose registers
|
||||||
|
push ds
|
||||||
|
push es
|
||||||
|
push fs
|
||||||
|
push gs
|
||||||
|
|
||||||
|
; Load known-good segment selectors
|
||||||
|
mov ax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
|
||||||
|
; Print exception number and error code
|
||||||
|
; You can insert direct port writes or call kernel logging function here
|
||||||
|
; For now, just hang
|
||||||
|
.halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt
|
||||||
|
|
||||||
|
; If you want to later restore:
|
||||||
|
pop gs
|
||||||
|
pop fs
|
||||||
|
pop es
|
||||||
|
pop ds
|
||||||
|
popa
|
||||||
|
add esp, 8 ; clean up int_no + err_code
|
||||||
|
iret
|
||||||
|
|
||||||
|
; Macro: for exceptions with error code
|
||||||
|
%macro isr_err_stub 1
|
||||||
|
isr_stub_%+%1:
|
||||||
|
cli
|
||||||
|
push dword %1 ; interrupt number
|
||||||
|
jmp isr_common_handler
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
; Macro: for exceptions without error code
|
||||||
|
%macro isr_no_err_stub 1
|
||||||
|
isr_stub_%+%1:
|
||||||
|
cli
|
||||||
|
push dword 0 ; fake error code
|
||||||
|
push dword %1 ; interrupt number
|
||||||
|
jmp isr_common_handler
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
; Define all 32 exception stubs
|
||||||
|
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
|
||||||
|
|
||||||
|
; Create jump table
|
||||||
|
isr_stub_table:
|
||||||
|
%assign i 0
|
||||||
|
%rep 32
|
||||||
|
dd isr_stub_%+i
|
||||||
|
%assign i i+1
|
||||||
|
%endrep
|
||||||
|
|
34
isr128.asm
34
isr128.asm
@ -1,34 +0,0 @@
|
|||||||
[bits 32]
|
|
||||||
global isr128
|
|
||||||
extern isr_handler
|
|
||||||
extern _push_regs
|
|
||||||
extern _pop_regs
|
|
||||||
|
|
||||||
isr128:
|
|
||||||
cli
|
|
||||||
call _push_regs
|
|
||||||
|
|
||||||
push ds
|
|
||||||
push es
|
|
||||||
push fs
|
|
||||||
push gs
|
|
||||||
|
|
||||||
mov ax, 0x10
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
; Pass register state to C handler
|
|
||||||
push esp
|
|
||||||
call isr_handler
|
|
||||||
add esp, 4
|
|
||||||
|
|
||||||
pop gs
|
|
||||||
pop fs
|
|
||||||
pop es
|
|
||||||
pop ds
|
|
||||||
call _pop_regs
|
|
||||||
|
|
||||||
sti
|
|
||||||
iret
|
|
@ -1,87 +0,0 @@
|
|||||||
[bits 32]
|
|
||||||
global isr_stub_table
|
|
||||||
global isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7
|
|
||||||
global isr8, isr9, isr10, isr11, isr12, isr13, isr14, isr15
|
|
||||||
global isr16, isr17, isr18, isr19, isr20, isr21, isr22, isr23
|
|
||||||
global isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31
|
|
||||||
global isr33
|
|
||||||
|
|
||||||
extern isr_handler
|
|
||||||
extern _push_regs
|
|
||||||
extern _pop_regs
|
|
||||||
|
|
||||||
%macro ISR_NOERR 1
|
|
||||||
isr%1:
|
|
||||||
cli
|
|
||||||
push dword 0 ; Fake error code
|
|
||||||
push dword %1 ; Interrupt number
|
|
||||||
jmp isr_common_stub
|
|
||||||
%endmacro
|
|
||||||
|
|
||||||
%macro ISR_ERR 1
|
|
||||||
isr%1:
|
|
||||||
cli
|
|
||||||
push dword %1 ; Interrupt number
|
|
||||||
jmp isr_common_stub
|
|
||||||
%endmacro
|
|
||||||
|
|
||||||
; ISRs 0-31 (exceptions)
|
|
||||||
ISR_NOERR 0
|
|
||||||
ISR_NOERR 1
|
|
||||||
ISR_NOERR 2
|
|
||||||
ISR_NOERR 3
|
|
||||||
ISR_NOERR 4
|
|
||||||
ISR_NOERR 5
|
|
||||||
ISR_NOERR 6
|
|
||||||
ISR_NOERR 7
|
|
||||||
ISR_ERR 8 ; Double fault
|
|
||||||
ISR_NOERR 9
|
|
||||||
ISR_ERR 10 ; Invalid TSS
|
|
||||||
ISR_ERR 11 ; Segment not present
|
|
||||||
ISR_ERR 12 ; Stack segment fault
|
|
||||||
ISR_ERR 13 ; General protection fault
|
|
||||||
ISR_ERR 14 ; Page fault
|
|
||||||
ISR_NOERR 15
|
|
||||||
ISR_NOERR 16
|
|
||||||
ISR_NOERR 17
|
|
||||||
ISR_NOERR 18
|
|
||||||
ISR_NOERR 19
|
|
||||||
ISR_NOERR 20
|
|
||||||
ISR_NOERR 21
|
|
||||||
ISR_NOERR 22
|
|
||||||
ISR_NOERR 23
|
|
||||||
ISR_NOERR 24
|
|
||||||
ISR_NOERR 25
|
|
||||||
ISR_NOERR 26
|
|
||||||
ISR_NOERR 27
|
|
||||||
ISR_NOERR 28
|
|
||||||
ISR_NOERR 29
|
|
||||||
ISR_ERR 30 ; Security exception
|
|
||||||
ISR_NOERR 31
|
|
||||||
ISR_NOERR 33
|
|
||||||
|
|
||||||
isr_common_stub:
|
|
||||||
pusha
|
|
||||||
push ds
|
|
||||||
push es
|
|
||||||
push fs
|
|
||||||
push gs
|
|
||||||
|
|
||||||
mov ax, 0x10
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
push esp
|
|
||||||
call isr_handler
|
|
||||||
add esp, 4
|
|
||||||
|
|
||||||
pop gs
|
|
||||||
pop fs
|
|
||||||
pop es
|
|
||||||
pop ds
|
|
||||||
popa
|
|
||||||
add esp, 8
|
|
||||||
;sti
|
|
||||||
iret
|
|
@ -3,7 +3,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <kernel/boot.h>
|
#include <kernel/boot.h>
|
||||||
|
|
||||||
|
|
||||||
uint8_t parse_boot_data(const char* data)
|
uint8_t parse_boot_data(const char* data)
|
||||||
{
|
{
|
||||||
if (strlen(data) == 0)
|
if (strlen(data) == 0)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <port_io.h>
|
#include <port_io.h>
|
||||||
|
|
||||||
#include <kernel/intro_anim.h>
|
#include <kernel/intro.h>
|
||||||
|
|
||||||
void delay_us(uint32_t microseconds, uint32_t cpu_mhz) {
|
void delay_us(uint32_t microseconds, uint32_t cpu_mhz) {
|
||||||
uint32_t count = cpu_mhz * microseconds;
|
uint32_t count = cpu_mhz * microseconds;
|
@ -18,14 +18,14 @@
|
|||||||
#include <panic.h>
|
#include <panic.h>
|
||||||
|
|
||||||
#include <gdt.h>
|
#include <gdt.h>
|
||||||
#include <idt.h>
|
#include <drivers/idt.h>
|
||||||
|
|
||||||
#include <multiboot.h>
|
#include <multiboot.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <drivers/pci.h>
|
#include <drivers/pci.h>
|
||||||
#include <drivers/ps2_keyboard.h>
|
#include <drivers/ps2_keyboard.h>
|
||||||
//#include <drivers/ahci.h>
|
/*#include <drivers/ahci.h>*/
|
||||||
#include <drivers/ide.h>
|
#include <drivers/ide.h>
|
||||||
#include <mm/mm.h>
|
#include <mm/mm.h>
|
||||||
#include <fs/ramfs.h>
|
#include <fs/ramfs.h>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
#include <vector_extentions/sse.h>
|
#include <vector_extentions/sse.h>
|
||||||
|
|
||||||
#include <kernel/intro_anim.h>
|
#include <kernel/intro.h>
|
||||||
|
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
@ -42,6 +42,7 @@
|
|||||||
extern HBA_PORT *ahci_port;*/
|
extern HBA_PORT *ahci_port;*/
|
||||||
|
|
||||||
extern void _hang_asm(void);
|
extern void _hang_asm(void);
|
||||||
|
extern void _sti_asm(void);
|
||||||
|
|
||||||
|
|
||||||
void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
||||||
@ -49,9 +50,13 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
|
|
||||||
/* --- BEGIN INITIALIZATION SECTION --- */
|
/* --- BEGIN INITIALIZATION SECTION --- */
|
||||||
|
|
||||||
|
const char* espresso_kernel_version = "0.0.0e";
|
||||||
|
|
||||||
/* We need to initialize the terminal so that any error/debuging messages show. */
|
/* We need to initialize the terminal so that any error/debuging messages show. */
|
||||||
terminal_initialize();
|
terminal_initialize();
|
||||||
|
|
||||||
|
printf("Loading Espresso %s...\n", espresso_kernel_version);
|
||||||
|
|
||||||
terminal_setcolor(VGA_COLOR_RED);
|
terminal_setcolor(VGA_COLOR_RED);
|
||||||
|
|
||||||
/* Make sure the magic number matches for memory mapping*/
|
/* Make sure the magic number matches for memory mapping*/
|
||||||
@ -69,17 +74,17 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
_hang_asm();
|
_hang_asm();
|
||||||
}
|
}
|
||||||
|
|
||||||
gdt_install();
|
gdt_install(false);
|
||||||
|
|
||||||
pic_remap();
|
pic_remap();
|
||||||
idt_install_isrs();
|
idt_init();
|
||||||
idt_install();
|
/*pit_init(1000); 1000 Hz = 1ms tick */
|
||||||
|
_sti_asm();
|
||||||
|
|
||||||
terminal_setcolor(VGA_COLOR_GREEN);
|
terminal_setcolor(VGA_COLOR_GREEN);
|
||||||
|
|
||||||
printd("Initializing physical memory manager...\n");
|
printd("Initializing physical memory manager...\n");
|
||||||
|
|
||||||
pmm_init(mbd);
|
pmm_init(mbd);
|
||||||
|
|
||||||
printd("Physical memory manager initialized\n");
|
printd("Physical memory manager initialized\n");
|
||||||
|
|
||||||
printd("Initializing paging...\n");
|
printd("Initializing paging...\n");
|
||||||
@ -115,23 +120,30 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
ide_initialize();
|
ide_initialize();
|
||||||
printd("IDE initialized\n");
|
printd("IDE initialized\n");
|
||||||
|
|
||||||
printd("Initializing DuckFS...\n");
|
/*printd("Initializing DuckFS...\n");
|
||||||
int32_t duckfs_init_rv = duckfs_init(0);
|
int32_t duckfs_init_rv = duckfs_init(0);
|
||||||
printf("[ DEBUG ] DuckFS initialized with RV %d\n", duckfs_init_rv);
|
printf("[ DEBUG ] DuckFS initialized with RV %d\n", duckfs_init_rv);*/
|
||||||
|
|
||||||
|
/*printd("Initializing FAT32...\n");
|
||||||
|
fat32_init(0);
|
||||||
|
printd("FAT32 initialized\n");*/
|
||||||
|
|
||||||
|
/*printd("Initializing the PIT...\n");
|
||||||
|
pit_init(1000);
|
||||||
|
printd("PIT initialized\n");*/
|
||||||
|
|
||||||
/* --- END INITIALIZATION SECTION --- */
|
/* --- END INITIALIZATION SECTION --- */
|
||||||
|
|
||||||
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
|
terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
|
||||||
|
|
||||||
const char* espresso_kernel_version = "0.0.0b";
|
/*sleep(1000);*/
|
||||||
|
|
||||||
printf("Loading Espresso %s...\n", espresso_kernel_version);
|
begin_anim(espresso_kernel_version);
|
||||||
|
|
||||||
/*begin_anim(espresso_kernel_version);*/
|
printf("Guten tag and welcome to Espresso\n");
|
||||||
|
|
||||||
printf("Hello and welcome to Espresso\n");
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
_hang_asm();
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <kernel/syscalls.h>
|
|
||||||
|
|
||||||
|
|
||||||
int16_t syscall_write(int32_t fd, const void* buffer, int32_t length)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <mm/paging.h>
|
#include <mm/paging.h>
|
||||||
#include <mm/pmm.h>
|
#include <mm/pmm.h>
|
||||||
|
#include <mm/heap.h>
|
||||||
|
|
||||||
#define PAGE_DIRECTORY_ENTRIES 1024
|
#define PAGE_DIRECTORY_ENTRIES 1024
|
||||||
#define PAGE_TABLE_ENTRIES 1024
|
#define PAGE_TABLE_ENTRIES 1024
|
||||||
@ -11,7 +12,7 @@
|
|||||||
typedef uint32_t page_directory_entry_t;
|
typedef uint32_t page_directory_entry_t;
|
||||||
typedef uint32_t page_table_entry_t;
|
typedef uint32_t page_table_entry_t;
|
||||||
|
|
||||||
static page_directory_entry_t* page_directory = (page_directory_entry_t*)0x9C000; /* Must be page-aligned */
|
static page_directory_entry_t* page_directory = NULL; /* Will be allocated */
|
||||||
static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES];
|
static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES];
|
||||||
|
|
||||||
extern void _enable_paging_asm(void);
|
extern void _enable_paging_asm(void);
|
||||||
@ -19,37 +20,37 @@ extern void _enable_paging_asm(void);
|
|||||||
void paging_init(void)
|
void paging_init(void)
|
||||||
{
|
{
|
||||||
/* Allocate and clear the page directory */
|
/* Allocate and clear the page directory */
|
||||||
page_directory = (uint32_t*)alloc_page();
|
page_directory = (page_directory_entry_t*)alloc_page();
|
||||||
memset(page_directory, 0, 4096);
|
memset(page_directory, 0, PAGE_SIZE);
|
||||||
|
|
||||||
/* Allocate and set up the first identity-mapped page table (0–4MB) */
|
/* Allocate and set up the first identity-mapped page table (0–4MB) */
|
||||||
uint32_t* first_table = (uint32_t*)alloc_page();
|
page_tables[0] = (page_table_entry_t*)alloc_page();
|
||||||
memset(first_table, 0, 4096);
|
memset(page_tables[0], 0, PAGE_SIZE);
|
||||||
for (uint32_t i = 0; i < 1024; i++)
|
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++)
|
||||||
{
|
{
|
||||||
first_table[i] = (i * 0x1000) | 3; /* Present | RW */
|
page_tables[0][i] = (i * PAGE_SIZE) | 3; /* Present | RW */
|
||||||
}
|
}
|
||||||
page_directory[0] = ((uint32_t)first_table) | 3;
|
page_directory[0] = ((uint32_t)page_tables[0]) | 3;
|
||||||
|
|
||||||
/* --- Map 4MB heap at 0xC0000000 --- */
|
/* Allocate and clear the heap page table */
|
||||||
uint32_t* heap_table = (uint32_t*)alloc_page();
|
uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */
|
||||||
memset(heap_table, 0, 4096);
|
page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page();
|
||||||
|
memset(page_tables[heap_pd_index], 0, PAGE_SIZE);
|
||||||
for (uint32_t i = 0; i < 1024; i++) /* 256 pages = 1MB */
|
|
||||||
|
/* Map 4MB heap pages */
|
||||||
|
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) /* 1024 pages = 4MB */
|
||||||
{
|
{
|
||||||
uint32_t phys = (uint32_t)alloc_page();
|
void* phys = alloc_page();
|
||||||
if (phys == 0)
|
if (phys == 0)
|
||||||
{
|
{
|
||||||
printf("Out of physical memory during heap mapping!\n");
|
printf("Out of physical memory during heap mapping!\n");
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
heap_table[i] = phys | 3; /* Present | RW */
|
page_tables[heap_pd_index][i] = ((uint32_t)phys & 0xFFFFF000) | 3; /* Present | RW */
|
||||||
}
|
}
|
||||||
|
page_directory[heap_pd_index] = ((uint32_t)page_tables[heap_pd_index]) | 3;
|
||||||
|
|
||||||
/* 0xC0000000 >> 22 == 768 */
|
/* Load page directory */
|
||||||
page_directory[768] = ((uint32_t)heap_table) | 3;
|
|
||||||
|
|
||||||
// Load page directory
|
|
||||||
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
|
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
|
||||||
|
|
||||||
/* Enable paging */
|
/* Enable paging */
|
||||||
@ -67,16 +68,14 @@ void map_page(void* phys_addr, void* virt_addr)
|
|||||||
void* pt_phys = alloc_page();
|
void* pt_phys = alloc_page();
|
||||||
page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */
|
page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */
|
||||||
|
|
||||||
for (int i = 0; i < PAGE_TABLE_ENTRIES; i++)
|
memset(page_tables[pd_index], 0, PAGE_SIZE);
|
||||||
{
|
|
||||||
page_tables[pd_index][i] = 0x00000002; /* Not present */
|
|
||||||
}
|
|
||||||
|
|
||||||
page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */
|
page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */
|
||||||
}
|
}
|
||||||
|
|
||||||
page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) | 0xC0000000);
|
page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) + 0xC0000000);
|
||||||
page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */
|
page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */
|
||||||
|
|
||||||
asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory");
|
asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
120
lib/printf.c
120
lib/printf.c
@ -34,7 +34,7 @@ void printf(const char* format, ...) {
|
|||||||
if (format[i] == '%' && format[i + 1] != '\0') {
|
if (format[i] == '%' && format[i + 1] != '\0') {
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
// Parse width (only supports zero-padding like %04x)
|
// Check for width (like %016llx)
|
||||||
int width = 0;
|
int width = 0;
|
||||||
if (format[i] == '0') {
|
if (format[i] == '0') {
|
||||||
++i;
|
++i;
|
||||||
@ -44,6 +44,13 @@ void printf(const char* format, ...) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for 'll' prefix
|
||||||
|
bool is_ll = false;
|
||||||
|
if (format[i] == 'l' && format[i + 1] == 'l') {
|
||||||
|
is_ll = true;
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
|
||||||
switch (format[i]) {
|
switch (format[i]) {
|
||||||
case 's': {
|
case 's': {
|
||||||
const char* str = va_arg(args, const char*);
|
const char* str = va_arg(args, const char*);
|
||||||
@ -67,13 +74,23 @@ void printf(const char* format, ...) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'x': {
|
case 'x': {
|
||||||
uint32_t val = va_arg(args, uint32_t);
|
if (is_ll) {
|
||||||
print_hex(val, width, false);
|
uint64_t val = va_arg(args, uint64_t);
|
||||||
|
print_hex64(val, width ? width : 16, false);
|
||||||
|
} else {
|
||||||
|
uint32_t val = va_arg(args, uint32_t);
|
||||||
|
print_hex(val, width ? width : 8, false);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'X': {
|
case 'X': {
|
||||||
uint32_t val = va_arg(args, uint32_t);
|
if (is_ll) {
|
||||||
print_hex(val, width, true);
|
uint64_t val = va_arg(args, uint64_t);
|
||||||
|
print_hex64(val, width ? width : 16, true);
|
||||||
|
} else {
|
||||||
|
uint32_t val = va_arg(args, uint32_t);
|
||||||
|
print_hex(val, width ? width : 8, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p': {
|
case 'p': {
|
||||||
@ -84,8 +101,8 @@ void printf(const char* format, ...) {
|
|||||||
}
|
}
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F': {
|
case 'F': {
|
||||||
double val = va_arg(args, double); // double is promoted from float
|
double val = va_arg(args, double);
|
||||||
print_double(val, 2); // 2 decimal places
|
print_double(val, 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '%': {
|
case '%': {
|
||||||
@ -106,41 +123,6 @@ void printf(const char* format, ...) {
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_double(double value, int precision)
|
|
||||||
{
|
|
||||||
// Handle the integer part
|
|
||||||
int32_t integer_part = (int32_t)value;
|
|
||||||
double fractional_part = value - integer_part;
|
|
||||||
|
|
||||||
// Print the integer part
|
|
||||||
print_int(integer_part);
|
|
||||||
|
|
||||||
// Print the decimal point
|
|
||||||
terminal_putchar('.');
|
|
||||||
|
|
||||||
// Print the fractional part (scaled up)
|
|
||||||
fractional_part *= 1;
|
|
||||||
for (int i = 0; i < precision; i++) {
|
|
||||||
fractional_part *= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t frac_int = (int32_t)fractional_part;
|
|
||||||
print_int(frac_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_uint(uint32_t value) {
|
|
||||||
char buffer[11]; // Enough for 32-bit unsigned int
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
buffer[i++] = '0' + (value % 10);
|
|
||||||
value /= 10;
|
|
||||||
} while (value > 0);
|
|
||||||
|
|
||||||
while (i--) {
|
|
||||||
terminal_putchar(buffer[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_int(int32_t value) {
|
void print_int(int32_t value) {
|
||||||
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
|
char buffer[12]; // Enough for 32-bit signed int (-2147483648)
|
||||||
@ -181,3 +163,57 @@ void print_hex(uint32_t value, int width, bool uppercase)
|
|||||||
terminal_putchar(buffer[i]);
|
terminal_putchar(buffer[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_double(double value, int precision)
|
||||||
|
{
|
||||||
|
// Handle the integer part
|
||||||
|
int32_t integer_part = (int32_t)value;
|
||||||
|
double fractional_part = value - integer_part;
|
||||||
|
|
||||||
|
// Print the integer part
|
||||||
|
print_int(integer_part);
|
||||||
|
|
||||||
|
// Print the decimal point
|
||||||
|
terminal_putchar('.');
|
||||||
|
|
||||||
|
// Print the fractional part (scaled up)
|
||||||
|
fractional_part *= 1;
|
||||||
|
for (int i = 0; i < precision; i++) {
|
||||||
|
fractional_part *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t frac_int = (int32_t)fractional_part;
|
||||||
|
print_int(frac_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_uint(uint32_t value) {
|
||||||
|
char buffer[11]; // Enough for 32-bit unsigned int
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
buffer[i++] = '0' + (value % 10);
|
||||||
|
value /= 10;
|
||||||
|
} while (value > 0);
|
||||||
|
|
||||||
|
while (i--) {
|
||||||
|
terminal_putchar(buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_hex64(uint64_t value, int width, bool uppercase) {
|
||||||
|
char buffer[17] = {0};
|
||||||
|
const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
buffer[i++] = digits[value % 16];
|
||||||
|
value /= 16;
|
||||||
|
} while (value > 0);
|
||||||
|
|
||||||
|
while (i < width)
|
||||||
|
buffer[i++] = '0';
|
||||||
|
|
||||||
|
while (i--)
|
||||||
|
terminal_putchar(buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
12
misc_asm.s
12
misc_asm.s
@ -19,6 +19,10 @@
|
|||||||
.global _pop_regs
|
.global _pop_regs
|
||||||
|
|
||||||
.global _hang_asm
|
.global _hang_asm
|
||||||
|
.global _halt_asm
|
||||||
|
|
||||||
|
.global _sti_asm
|
||||||
|
|
||||||
|
|
||||||
_enable_paging_asm:
|
_enable_paging_asm:
|
||||||
push %eax
|
push %eax
|
||||||
@ -59,4 +63,12 @@ _hang_asm:
|
|||||||
hlt
|
hlt
|
||||||
jmp _hang_asm
|
jmp _hang_asm
|
||||||
|
|
||||||
|
_halt_asm:
|
||||||
|
nop
|
||||||
|
ret
|
||||||
|
|
||||||
|
_sti_asm:
|
||||||
|
sti
|
||||||
|
ret
|
||||||
|
|
||||||
.section .data
|
.section .data
|
||||||
|
127
pit.asm
127
pit.asm
@ -3,130 +3,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
section .bss
|
|
||||||
system_timer_fractions: resd 1 ; Fractions of 1 ms since timer initialized
|
|
||||||
system_timer_ms: resd 1 ; Number of whole ms since timer initialized
|
|
||||||
IRQ0_fractions: resd 1 ; Fractions of 1 ms between IRQs
|
|
||||||
IRQ0_ms: resd 1 ; Number of whole ms between IRQs
|
|
||||||
IRQ0_frequency: resd 1 ; Actual frequency of PIT
|
|
||||||
PIT_reload_value: resw 1 ; Current PIT reload value
|
|
||||||
|
|
||||||
section .text
|
|
||||||
|
|
||||||
global IRQ0_handler
|
|
||||||
global init_PIT
|
|
||||||
|
|
||||||
IRQ0_handler:
|
|
||||||
push eax
|
|
||||||
push ebx
|
|
||||||
|
|
||||||
mov eax, [IRQ0_fractions]
|
|
||||||
mov ebx, [IRQ0_ms] ; eax.ebx = amount of time between IRQs
|
|
||||||
add [system_timer_fractions], eax ; Update system timer tick fractions
|
|
||||||
adc [system_timer_ms], ebx ; Update system timer tick milli-seconds
|
|
||||||
|
|
||||||
mov al, 0x20
|
|
||||||
out 0x20, al ; Send the EOI to the PIC
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
pop eax
|
|
||||||
iretd
|
|
||||||
|
|
||||||
|
|
||||||
;Input
|
|
||||||
; ebx Desired PIT frequency in Hz
|
|
||||||
|
|
||||||
init_PIT:
|
|
||||||
pushad
|
|
||||||
|
|
||||||
; Do some checking
|
|
||||||
|
|
||||||
mov eax,0x10000 ;eax = reload value for slowest possible frequency (65536)
|
|
||||||
cmp ebx,18 ;Is the requested frequency too low?
|
|
||||||
jbe .gotReloadValue ; yes, use slowest possible frequency
|
|
||||||
|
|
||||||
mov eax,1 ;ax = reload value for fastest possible frequency (1)
|
|
||||||
cmp ebx,1193181 ;Is the requested frequency too high?
|
|
||||||
jae .gotReloadValue ; yes, use fastest possible frequency
|
|
||||||
|
|
||||||
; Calculate the reload value
|
|
||||||
|
|
||||||
mov eax,3579545
|
|
||||||
mov edx,0 ;edx:eax = 3579545
|
|
||||||
div ebx ;eax = 3579545 / frequency, edx = remainder
|
|
||||||
cmp edx,3579545 / 2 ;Is the remainder more than half?
|
|
||||||
jb .l1 ; no, round down
|
|
||||||
inc eax ; yes, round up
|
|
||||||
.l1:
|
|
||||||
mov ebx,3
|
|
||||||
mov edx,0 ;edx:eax = 3579545 * 256 / frequency
|
|
||||||
div ebx ;eax = (3579545 * 256 / 3 * 256) / frequency
|
|
||||||
cmp edx,3 / 2 ;Is the remainder more than half?
|
|
||||||
jb .l2 ; no, round down
|
|
||||||
inc eax ; yes, round up
|
|
||||||
.l2:
|
|
||||||
|
|
||||||
|
|
||||||
; Store the reload value and calculate the actual frequency
|
|
||||||
|
|
||||||
.gotReloadValue:
|
|
||||||
push eax ;Store reload_value for later
|
|
||||||
mov [PIT_reload_value],ax ;Store the reload value for later
|
|
||||||
mov ebx,eax ;ebx = reload value
|
|
||||||
|
|
||||||
mov eax,3579545
|
|
||||||
mov edx,0 ;edx:eax = 3579545
|
|
||||||
div ebx ;eax = 3579545 / reload_value, edx = remainder
|
|
||||||
cmp edx,3579545 / 2 ;Is the remainder more than half?
|
|
||||||
jb .l3 ; no, round down
|
|
||||||
inc eax ; yes, round up
|
|
||||||
.l3:
|
|
||||||
mov ebx,3
|
|
||||||
mov edx,0 ;edx:eax = 3579545 / reload_value
|
|
||||||
div ebx ;eax = (3579545 / 3) / frequency
|
|
||||||
cmp edx,3 / 2 ;Is the remainder more than half?
|
|
||||||
jb .l4 ; no, round down
|
|
||||||
inc eax ; yes, round up
|
|
||||||
.l4:
|
|
||||||
mov [IRQ0_frequency],eax ;Store the actual frequency for displaying later
|
|
||||||
|
|
||||||
|
|
||||||
; Calculate the amount of time between IRQs in 32.32 fixed point
|
|
||||||
;
|
|
||||||
; Note: The basic formula is:
|
|
||||||
; time in ms = reload_value / (3579545 / 3) * 1000
|
|
||||||
; This can be rearranged in the following way:
|
|
||||||
; time in ms = reload_value * 3000 / 3579545
|
|
||||||
; time in ms = reload_value * 3000 / 3579545 * (2^42)/(2^42)
|
|
||||||
; time in ms = reload_value * 3000 * (2^42) / 3579545 / (2^42)
|
|
||||||
; time in ms * 2^32 = reload_value * 3000 * (2^42) / 3579545 / (2^42) * (2^32)
|
|
||||||
; time in ms * 2^32 = reload_value * 3000 * (2^42) / 3579545 / (2^10)
|
|
||||||
|
|
||||||
pop ebx ;ebx = reload_value
|
|
||||||
mov eax,0xDBB3A062 ;eax = 3000 * (2^42) / 3579545
|
|
||||||
mul ebx ;edx:eax = reload_value * 3000 * (2^42) / 3579545
|
|
||||||
shrd eax,edx,10
|
|
||||||
shr edx,10 ;edx:eax = reload_value * 3000 * (2^42) / 3579545 / (2^10)
|
|
||||||
|
|
||||||
mov [IRQ0_ms],edx ;Set whole ms between IRQs
|
|
||||||
mov [IRQ0_fractions],eax ;Set fractions of 1 ms between IRQs
|
|
||||||
|
|
||||||
|
|
||||||
; Program the PIT channel
|
|
||||||
|
|
||||||
pushfd
|
|
||||||
cli ;Disabled interrupts (just in case)
|
|
||||||
|
|
||||||
mov al,00110100b ;channel 0, lobyte/hibyte, rate generator
|
|
||||||
out 0x43, al
|
|
||||||
|
|
||||||
mov ax,[PIT_reload_value] ;ax = 16 bit reload value
|
|
||||||
out 0x40,al ;Set low byte of PIT reload value
|
|
||||||
mov al,ah ;ax = high 8 bits of reload value
|
|
||||||
out 0x40,al ;Set high byte of PIT reload value
|
|
||||||
|
|
||||||
popfd
|
|
||||||
|
|
||||||
popad
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user