Espresso 0.0.0e

This commit is contained in:
2025-06-13 18:03:39 -05:00
parent 6d366537dd
commit 1e5b4a765b
40 changed files with 742 additions and 718 deletions

View File

@ -5,6 +5,8 @@ CC := i686-elf-gcc
AS := i686-elf-as
NASM := nasm
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
WNOFLAGS := -Wno-discarded-qualifiers
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS)
@ -21,7 +23,7 @@ GRUB_CFG := grub.cfg
# === File collection ===
C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c'))
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
CRTBEGIN_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
@ -64,6 +66,8 @@ iso: $(TARGET)
# === Run in QEMU ===
run: iso
$(QEMU_MKE_IMG)
echo "\n"
$(MKFS_VFAT) $(MKFS_FLAGS) espresso.img
qemu-system-i386 $(QEMUFLAGS)
# === Clean all build artifacts ===

View File

@ -44,7 +44,6 @@ int32_t fat32_init(int32_t drive)
memcpy(&bpb, sector, sizeof(bpb));
fat_start_lba = bpb.reserved_sector_count;
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
current_directory_cluster = bpb.root_cluster;

View File

@ -1,34 +1,52 @@
#include <stdio.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);
void gdt_install()
void gdt_install(bool prnt_gdt)
{
gp.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1;
gp.base = (uint32_t)&gdt;
create_descriptor(0, 0, 0, 0, prnt_gdt); // Null
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 */
gdt_set_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
gdt_set_entry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
gp.limit = sizeof(gdt) - 1;
gp.base = (uint32_t)&gdt;
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);
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
uint64_t descriptor;
gdt[num].limit_low = (limit & 0xFFFF);
gdt[num].granularity = (limit >> 16) & 0x0F;
descriptor = limit & 0x000F0000; // limit bits 19:16
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);
gdt[num].access = access;
descriptor <<= 32;
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
View File

View File

@ -1,131 +1,141 @@
#include <string.h>
#include <stdio.h>
#include <port_io.h>
#include <idt.h>
#include <drivers/idt.h>
#define IDT_ENTRIES 256
struct idt_entry idt[IDT_ENTRIES];
struct idt_ptr idtp;
#define IDT_MAX_DESCRIPTORS 256
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;
idtp.base = (uint32_t)&idt;
switch (int_no)
{
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(...)` */
/* Example: idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E); */
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
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)
{
outb(0x20, 0x11); /* Start init for master PIC */
outb(0xA0, 0x11); /* Start init for slave PIC */
outb(0x21, 0x20); /* Master PIC vector offset */
outb(0xA1, 0x28); /* Slave PIC vector offset */
outb(0x21, 0x04); /* Tell Master PIC about Slave PIC at IRQ2 */
outb(0xA1, 0x02); /* Tell Slave PIC its cascade identity */
outb(0x21, 0x01); /* 8086/88 mode */
outb(0xA1, 0x01);
outb(0x21, 0x0); /* Unmask master */
outb(0xA1, 0x0); /* Unmask slave */
uint8_t a1, a2;
// Save masks
a1 = inb(PIC1_DATA);
a2 = inb(PIC2_DATA);
// Start initialization sequence (in cascade mode)
outb(PIC1_COMMAND, 0x11);
outb(PIC2_COMMAND, 0x11);
// Set vector offset
outb(PIC1_DATA, 0x20); // IRQs 0-7 mapped to IDT entries 0x20-0x27 (3239)
outb(PIC2_DATA, 0x28); // IRQs 8-15 mapped to IDT entries 0x28-0x2F (4047)
// 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;
idt[num].base_high = (base >> 16) & 0xFFFF;
idtr.base = (uintptr_t)&idt[0];
idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1;
idt[num].sel = sel;
idt[num].always0 = 0;
idt[num].flags = flags;
}
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);
for (uint8_t vector = 0; vector < 32; vector++)
{
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
vectors[vector] = true;
}
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
View File

@ -0,0 +1,9 @@
#include <drivers/irq.h>
void irq_handler(uint8_t irq_number)
{
}

View File

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

View File

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

View File

@ -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.
IO Port Access Type Purpose
0x60 Read/Write Data Port
0x64 Read Status Register
0x64 Write Command Register
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
0x60 Read/Write Data Port
0x64 Read Status 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)
{
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
View 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");
}
}
*/

View File

@ -151,7 +151,10 @@ void terminal_clearl(size_t 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;
}
}

View File

@ -3,13 +3,12 @@ global gdt_flush
gdt_flush:
mov eax, [esp + 4]
lgdt [eax]
; Reload segment registers
mov ax, 0x10 ; Kernel data segment
jmp 0x08:.flush_label ; long jump to reload CS with new segment
.flush_label:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; Kernel code segment
.flush:
ret

40
idt.asm
View File

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

@ -0,0 +1,8 @@
#ifndef _IRQ_H
#define _IRQ_H
#include <types.h>
void irq_handler(uint8_t irq_number);
#endif

View File

@ -3,5 +3,7 @@
#include <types.h>
void pit_init(uint32_t freq);
void sleep(uint32_t millis);
#endif

View File

@ -2,9 +2,7 @@
#define _PS2_KEYBOARD_H
#include <types.h>
#include <isr.h>
void keyboard_init(void);
void keyboard_handler(isr_stack_t* regs);
#endif

11
include/drivers/timer.h Normal file
View 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

View File

@ -1,6 +1,7 @@
#ifndef _FAT32_H
#define _FAT32_H
#include <stdint.h>
#include <types.h>
#define FAT32_MAX_FILENAME 11
#define FAT32_ATTR_DIRECTORY 0x10

View File

@ -3,21 +3,7 @@
#include <stdint.h>
struct gdt_entry {
uint16_t limit_low; /* Lower 16 bits of limit */
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);
void gdt_install(bool prnt_gdt);
void create_descriptor(int index, uint32_t base, uint32_t limit, uint16_t flag, bool prnt_gdt);
#endif

View File

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

View File

@ -4,7 +4,6 @@
#define ESPRESSO_IO_H
#include <stdint.h>
#include <text_display.h>
void print(const char* str);
@ -13,4 +12,4 @@ char* input(uint8_t dev=0);
void writefile(uint8_t mode, char* file, char* data);
char* readfile(char* file);
#endif
#endif

View File

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

View File

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

View File

@ -14,6 +14,7 @@ void printf(const char*, ...);
void print_int(int32_t value);
void print_uint(uint32_t value);
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);
#endif

167
isr.asm Normal file
View 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
View 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

View File

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

View File

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

View File

@ -3,7 +3,8 @@
#include <string.h>
#include <kernel/boot.h>
uint8_t parse_boot_data(const char* data)
{
if (strlen(data) == 0)

View File

@ -3,7 +3,7 @@
#include <stdio.h>
#include <port_io.h>
#include <kernel/intro_anim.h>
#include <kernel/intro.h>
void delay_us(uint32_t microseconds, uint32_t cpu_mhz) {
uint32_t count = cpu_mhz * microseconds;

View File

@ -18,14 +18,14 @@
#include <panic.h>
#include <gdt.h>
#include <idt.h>
#include <drivers/idt.h>
#include <multiboot.h>
#include <stdio.h>
#include <drivers/pci.h>
#include <drivers/ps2_keyboard.h>
//#include <drivers/ahci.h>
/*#include <drivers/ahci.h>*/
#include <drivers/ide.h>
#include <mm/mm.h>
#include <fs/ramfs.h>
@ -34,7 +34,7 @@
#include <vector_extentions/sse.h>
#include <kernel/intro_anim.h>
#include <kernel/intro.h>
#define DEBUG
@ -42,6 +42,7 @@
extern HBA_PORT *ahci_port;*/
extern void _hang_asm(void);
extern void _sti_asm(void);
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 --- */
const char* espresso_kernel_version = "0.0.0e";
/* We need to initialize the terminal so that any error/debuging messages show. */
terminal_initialize();
printf("Loading Espresso %s...\n", espresso_kernel_version);
terminal_setcolor(VGA_COLOR_RED);
/* 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();
}
gdt_install();
gdt_install(false);
pic_remap();
idt_install_isrs();
idt_install();
idt_init();
/*pit_init(1000); 1000 Hz = 1ms tick */
_sti_asm();
terminal_setcolor(VGA_COLOR_GREEN);
printd("Initializing physical memory manager...\n");
pmm_init(mbd);
printd("Physical memory manager initialized\n");
printd("Initializing paging...\n");
@ -115,23 +120,30 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
ide_initialize();
printd("IDE initialized\n");
printd("Initializing DuckFS...\n");
/*printd("Initializing DuckFS...\n");
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 --- */
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");
_hang_asm();
while (true)
{
}
}

View File

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

View File

@ -3,6 +3,7 @@
#include <mm/paging.h>
#include <mm/pmm.h>
#include <mm/heap.h>
#define PAGE_DIRECTORY_ENTRIES 1024
#define PAGE_TABLE_ENTRIES 1024
@ -11,7 +12,7 @@
typedef uint32_t page_directory_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];
extern void _enable_paging_asm(void);
@ -19,37 +20,37 @@ extern void _enable_paging_asm(void);
void paging_init(void)
{
/* Allocate and clear the page directory */
page_directory = (uint32_t*)alloc_page();
memset(page_directory, 0, 4096);
page_directory = (page_directory_entry_t*)alloc_page();
memset(page_directory, 0, PAGE_SIZE);
/* Allocate and set up the first identity-mapped page table (04MB) */
uint32_t* first_table = (uint32_t*)alloc_page();
memset(first_table, 0, 4096);
for (uint32_t i = 0; i < 1024; i++)
page_tables[0] = (page_table_entry_t*)alloc_page();
memset(page_tables[0], 0, PAGE_SIZE);
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 --- */
uint32_t* heap_table = (uint32_t*)alloc_page();
memset(heap_table, 0, 4096);
for (uint32_t i = 0; i < 1024; i++) /* 256 pages = 1MB */
/* Allocate and clear the heap page table */
uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */
page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page();
memset(page_tables[heap_pd_index], 0, PAGE_SIZE);
/* 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)
{
printf("Out of physical memory during heap mapping!\n");
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 */
page_directory[768] = ((uint32_t)heap_table) | 3;
// Load page directory
/* Load page directory */
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
/* Enable paging */
@ -67,16 +68,14 @@ void map_page(void* phys_addr, void* virt_addr)
void* pt_phys = alloc_page();
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++)
{
page_tables[pd_index][i] = 0x00000002; /* Not present */
}
memset(page_tables[pd_index], 0, PAGE_SIZE);
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 */
asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory");
}

View File

@ -34,7 +34,7 @@ void printf(const char* format, ...) {
if (format[i] == '%' && format[i + 1] != '\0') {
++i;
// Parse width (only supports zero-padding like %04x)
// Check for width (like %016llx)
int width = 0;
if (format[i] == '0') {
++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]) {
case 's': {
const char* str = va_arg(args, const char*);
@ -67,13 +74,23 @@ void printf(const char* format, ...) {
break;
}
case 'x': {
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width, false);
if (is_ll) {
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;
}
case 'X': {
uint32_t val = va_arg(args, uint32_t);
print_hex(val, width, true);
if (is_ll) {
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;
}
case 'p': {
@ -84,8 +101,8 @@ void printf(const char* format, ...) {
}
case 'f':
case 'F': {
double val = va_arg(args, double); // double is promoted from float
print_double(val, 2); // 2 decimal places
double val = va_arg(args, double);
print_double(val, 2);
break;
}
case '%': {
@ -106,41 +123,6 @@ void printf(const char* format, ...) {
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) {
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]);
}
}
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]);
}

View File

@ -19,6 +19,10 @@
.global _pop_regs
.global _hang_asm
.global _halt_asm
.global _sti_asm
_enable_paging_asm:
push %eax
@ -59,4 +63,12 @@ _hang_asm:
hlt
jmp _hang_asm
_halt_asm:
nop
ret
_sti_asm:
sti
ret
.section .data

127
pit.asm
View File

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