Espresso 0.0.2c

This commit is contained in:
2026-03-20 16:57:08 -05:00
parent 021fdbbcef
commit 5971218b56
77 changed files with 4538 additions and 518 deletions

46
drivers/audio/pcspeaker.c Normal file
View File

@ -0,0 +1,46 @@
#include <stdlib.h>
#include <port_io.h>
#include <drivers/audio/pcspeaker.h>
/*
this code is taken from the OSDev wiki: https://wiki.osdev.org/PC_Speaker
with slight modifications to the local variable and parameter names,
along with removing the 'static' keyword from play_sound and nosound (which is renamed to stop_sound)
*/
void play_sound(uint32_t nfrequence)
{
uint32_t div;
uint8_t tmp;
// Set the PIT to the desired frequency
div = 1193180 / nfrequence;
outb(0x43, 0xb6);
outb(0x42, (uint8_t) (div));
outb(0x42, (uint8_t) (div >> 8));
// And play the sound using the PC speaker
tmp = inb(0x61);
if (tmp != (tmp | 3))
{
outb(0x61, tmp | 3);
}
}
// make it shut up
void stop_sound(void)
{
uint8_t tmp = inb(0x61) & 0xFC;
outb(0x61, tmp);
}
// Make a beep
void beep(void)
{
play_sound(1000);
//timer_wait(10);
sleep(10);
stop_sound();
//set_PIT_2(old_frequency);
}

View File

@ -13,10 +13,10 @@
elf_executable_t* load_elf32(void* elf_data)
{
/*Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;*/
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
/* Check ELF magic */
/*if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
{
printf("Invalid ELF file\n");
return NULL;
@ -30,7 +30,8 @@ elf_executable_t* load_elf32(void* elf_data)
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
for (int i = 0; i < ehdr->e_phnum; i++) {
for (int i = 0; i < ehdr->e_phnum; i++)
{
Elf32_Phdr* phdr = &phdrs[i];
if (phdr->p_type != PT_LOAD)
{
@ -43,7 +44,7 @@ elf_executable_t* load_elf32(void* elf_data)
for (uint32_t page = 0; page < segment_pages; page++)
{
void* phys = alloc_page();
void* phys = pmm_alloc_page();
void* virt = (void*)(vaddr_start + page * PAGE_SIZE);
map_page(phys, virt);
memset(virt, 0, PAGE_SIZE);
@ -53,12 +54,15 @@ elf_executable_t* load_elf32(void* elf_data)
void* src = (uint8_t*)elf_data + phdr->p_offset;
memcpy(dest, src, phdr->p_filesz);
printf("Mapped segment %d: 0x%08x0x%08x (memsz: %u, filesz: %u)\n", i, phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz, phdr->p_filesz);
#ifdef _DEBUG
printf("Mapped segment %d: ", i);
printf("0x%x - 0x%x (memsz: %u, filesz: %u)\n", phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz, phdr->p_filesz);
#endif
}
elf_executable_t* result = malloc(sizeof(elf_executable_t));
result->entry_point = (void*)(uintptr_t)ehdr->e_entry;
return result;*/
result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry;
return result;
return NULL;
}

48
drivers/exec/secf.c Normal file
View File

@ -0,0 +1,48 @@
/*
Simple Executable Code Format
SECF is a executable format for any platform (though designed with x86(-32) in mind.)
that makes use of registers, syscalls/interrupts, and other tables/structures instead of libraries.
register map:
(unused means the program can use the register without any issue, no data used/passed by the SECF will be there)
EAX: unused
EBX: unused
ECX: arg string length
EDX: variable area size (bytes)
ESI: pointer to arg string
EDI: unused
ESP: unused, normal function
EBP: pointer to variable area
The variable area is a area of a specific size (size in EDX) that can be used for storing variables/temporary data.
Any additional memory space needed can be aquired via malloc.
The minimum size of the variable area is 16 bytes and a maximum size of 64KiB.
Use syscall/int (number TBT) to call functions
*/
#include <types.h>
#include <stdlib.h>
void* init_var_area(size_t size)
{
if (size == (size_t) 0)
{
return NULL; /* size 0 is invalid. */
}
else if (size >= 65536)
{
return NULL; /* size above 65,536 is invalid. */
}
else if (size < 16)
{
size = 16;
}
return malloc(size); /* No need to check for null because we'd return null in that case */
}

49
drivers/fs/ekfs.c Normal file
View File

@ -0,0 +1,49 @@
#include <types.h>
#include <string.h>
#include <drivers/ide.h>
#include <fs/ekfs.h>
/* work on this later */
#if 0
/* note: __l being 0 is allowed, because that way read() can be used to tell if a file exists (with return value 0) */
int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l)
{
int rv = 0;
if (!__f || !__b || (!__f->f_inode))
{
return -1;
}
/* we assume drive 0 is already mounted */
char buffer[512];
memset(buffer, 0, 512);
int num_sectors = __f->f_inode->i_len / 512;
if ((__l / 512) > num_sectors)
{
return EKFS_E_FILETOOSMALL;
}
int read_sectors = num_sectors;
for (int i = 0; i < read_sectors; i++);
{
rv = read_sector(__f->f_inode->i_start, buffer);
if (rv != 0)
{
break;
}
}
return rv;
}
#endif

374
drivers/fs/fat16.c Normal file
View File

@ -0,0 +1,374 @@
#include <string.h>
#include <drivers/ide.h>
#include <stdio.h>
#include <fs/fat16.h>
/*
READ BELOW!!!
Before any of you (or me,) use this code, please note that the functions below REQUIRE 8.3 formatted names.
in fat16.h there is a helper function for convertion between normal filenames and 8.3 ones. ('filename_to_83', see static implementation in fat16.h)
*/
static fat16_fs_t fs;
static uint8_t boot_sector[SECTOR_SIZE];
int fat16_mount(uint8_t drive)
{
if (read_sector(0, boot_sector) != 0)
{
return -1;
}
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
fs.sectors_per_cluster = boot_sector[13];
fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8);
fs.num_fats = boot_sector[16];
fs.root_entry_count = boot_sector[17] | (boot_sector[18] << 8);
fs.total_sectors_16 = boot_sector[19] | (boot_sector[20] << 8);
fs.sectors_per_fat = boot_sector[22] | (boot_sector[23] << 8);
fs.total_sectors = fs.total_sectors_16 != 0 ? fs.total_sectors_16 : boot_sector[32] | (boot_sector[33]<<8) | (boot_sector[34]<<16) | (boot_sector[35]<<24);
fs.fat_start_lba = fs.reserved_sector_count;
fs.root_dir_lba = fs.fat_start_lba + (fs.num_fats * fs.sectors_per_fat);
fs.data_start_lba = fs.root_dir_lba + ((fs.root_entry_count * 32 + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector);
return 0;
}
static uint32_t cluster_to_lba(uint16_t cluster)
{
return fs.data_start_lba + (cluster - 2) * fs.sectors_per_cluster;
}
/* ----------------------- FAT helpers ------------------------- */
static int read_fat_entry(uint16_t cluster, uint16_t* out_value)
{
uint32_t offset = (uint32_t)cluster * 2;
uint32_t sector_index = offset / fs.bytes_per_sector;
uint32_t idx = offset % fs.bytes_per_sector;
uint8_t sector[SECTOR_SIZE];
if (read_sector(fs.fat_start_lba + sector_index, sector) != 0)
{
return -1;
}
if (idx == fs.bytes_per_sector - 1)
{
/* entry spans boundary -> read next sector */
uint8_t next_sector[SECTOR_SIZE];
if (read_sector(fs.fat_start_lba + sector_index + 1, next_sector) != 0)
{
return -1;
}
*out_value = sector[idx] | (next_sector[0] << 8);
}
else
{
*out_value = sector[idx] | (sector[idx + 1] << 8);
}
return 0;
}
static int write_fat_entry(uint16_t cluster, uint16_t value)
{
uint32_t offset = cluster * 2;
uint32_t sector_lba = fs.fat_start_lba + (offset / fs.bytes_per_sector);
uint8_t sector[SECTOR_SIZE];
if (read_sector(sector_lba, sector) != 0)
{
return -1;
}
sector[offset % fs.bytes_per_sector] = value & 0xFF;
sector[(offset % fs.bytes_per_sector) + 1] = (value >> 8) & 0xFF;
/* write to all FAT copies */
for (uint8_t f = 0; f < fs.num_fats; f++)
{
if (write_sector(fs.fat_start_lba + f * fs.sectors_per_fat + (offset / fs.bytes_per_sector), sector) != 0)
{
return -1;
}
}
return 0;
}
static int find_free_cluster(uint16_t* out_cluster)
{
uint16_t total_clusters = (fs.total_sectors - fs.data_start_lba) / fs.sectors_per_cluster;
uint16_t value;
for (uint16_t c = 2; c < total_clusters; c++)
{
if (read_fat_entry(c, &value) != 0)
{
return -1;
}
if (value == 0x0000)
{
*out_cluster = c;
return 0;
}
}
return -1; /* no free cluster */
}
/* -------------------- Root directory ------------------------- */
static int find_free_root_entry(uint32_t* out_sector, uint32_t* out_offset)
{
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
uint8_t sector[SECTOR_SIZE];
for (uint32_t i = 0; i < root_dir_sectors; i++)
{
if (read_sector(fs.root_dir_lba + i, sector) != 0)
{
return -1;
}
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
{
if (sector[offset] == 0x00 || sector[offset] == 0xE5)
{
*out_sector = fs.root_dir_lba + i;
*out_offset = offset;
return 0;
}
}
}
return -1;
}
/* -------------------- File operations ----------------------- */
int fat16_find_file(const char* name, fat16_file_t* out_file)
{
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
uint8_t sector[SECTOR_SIZE];
for (uint32_t i = 0; i < root_dir_sectors; i++)
{
if (read_sector(fs.root_dir_lba + i, sector) != 0)
{
return -1;
}
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
{
if (sector[offset] == 0x00)
{
return -1; /* no more entries */
}
else if (sector[offset] == 0xE5)
{
continue; /* deleted entry */
}
if (memcmp(sector + offset, name, 11) == 0)
{
memcpy(out_file->name, sector + offset, 12);
out_file->attr = sector[offset + 11];
out_file->first_cluster = sector[offset + 26] | (sector[offset + 27] << 8);
out_file->size = sector[offset + 28] | (sector[offset + 29] << 8) | (sector[offset + 30] << 16) | (sector[offset + 31] << 24);
return 0;
}
}
}
return -1;
}
int fat16_create_file(const char* name, fat16_file_t* out_file)
{
uint16_t free_cluster;
if (find_free_cluster(&free_cluster) != 0)
{
return -1;
}
uint32_t sector_lba, offset;
if (find_free_root_entry(&sector_lba, &offset) != 0)
{
return -1;
}
uint8_t sector[SECTOR_SIZE];
if (read_sector(sector_lba, sector) != 0)
{
return -1;
}
/* Fill root entry */
memset(sector + offset, ' ', 11);
memcpy(sector + offset, name, 11);
sector[offset + 11] = 0x20; /* normal file */
sector[offset + 26] = free_cluster & 0xFF;
sector[offset + 27] = (free_cluster >> 8) & 0xFF;
sector[offset + 28] = 0; sector[offset + 29] = 0;
sector[offset + 30] = 0; sector[offset + 31] = 0;
if (write_sector(sector_lba, sector) != 0)
{
return -1;
}
/* mark cluster as end-of-chain */
if (write_fat_entry(free_cluster, 0xFFFF) != 0)
{
return -1;
}
if (out_file)
{
memset(out_file, 0, sizeof(fat16_file_t));
strncpy(out_file->name, name, 11);
out_file->first_cluster = free_cluster;
out_file->size = 0;
out_file->attr = 0x20;
}
return 0;
}
int fat16_write_file(fat16_file_t* file, const void* buffer, uint32_t size) {
const uint8_t* buf = (const uint8_t*)buffer;
uint32_t bytes_remaining = size;
uint16_t cluster = file->first_cluster;
if (cluster == 0) return -1; /* safety: file must have a cluster */
while (bytes_remaining > 0) {
uint32_t lba = cluster_to_lba(cluster);
for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++) {
uint8_t sector[SECTOR_SIZE];
memset(sector, 0, SECTOR_SIZE);
uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE;
memcpy(sector, buf, copy_bytes);
if (write_sector(lba + i, sector) != 0) return -1;
buf += copy_bytes;
bytes_remaining -= copy_bytes;
}
uint16_t next_cluster;
if (bytes_remaining > 0) {
if (find_free_cluster(&next_cluster) != 0) return -1;
if (write_fat_entry(cluster, next_cluster) != 0) return -1;
if (write_fat_entry(next_cluster, 0xFFFF) != 0) return -1;
cluster = next_cluster;
}
}
/* Update file size in root entry (your code already does this on disk) */
/* Now update the in-memory struct so subsequent reads use the new size */
file->size = size;
/* optionally: refresh metadata from disk:
fat16_find_file(file->name, file); */
return 0;
}
int fat16_read_file(fat16_file_t* file, void* buffer)
{
uint8_t sector[SECTOR_SIZE];
uint16_t cluster = file->first_cluster;
uint32_t bytes_remaining = file->size;
uint8_t* buf = (uint8_t*)buffer;
while (cluster >= 0x0002 && cluster < 0xFFF8)
{
uint32_t lba = cluster_to_lba(cluster);
for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++)
{
if (read_sector(lba + i, sector) != 0)
{
return -1;
}
uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE;
memcpy(buf, sector, copy_bytes);
buf += copy_bytes;
bytes_remaining -= copy_bytes;
}
/* read next cluster from FAT */
uint32_t fat_offset = cluster * 2; /* FAT16 */
uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector);
uint16_t fat_entry;
if (read_sector(fat_sector, sector) != 0)
{
return -1;
}
fat_entry = sector[fat_offset % fs.bytes_per_sector] | (sector[(fat_offset % fs.bytes_per_sector) + 1] << 8);
cluster = fat_entry;
}
return 0;
}
int fat16_delete_file(const char* filename)
{
uint8_t sector[512];
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
uint32_t root_dir_start = fs.root_dir_lba;
for (uint32_t s = 0; s < root_dir_sectors; s++)
{
if (read_sector(root_dir_start + s, sector) != 0)
return -1;
for (int i = 0; i < fs.bytes_per_sector; i += 32)
{
uint8_t* entry = &sector[i];
if (entry[0] == 0x00)
return -1; // end of directory
if (entry[0] == 0xE5)
continue; // already deleted
if (memcmp(entry, filename, 11) == 0)
{
// Found the file — mark as deleted
entry[0] = 0xE5;
if (write_sector(root_dir_start + s, sector) != 0)
return -1;
// Free FAT chain
uint16_t cluster = entry[26] | (entry[27] << 8);
while (cluster >= 0x0002 && cluster < 0xFFF8)
{
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector);
uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
if (read_sector(fat_sector, sector) != 0)
break;
uint16_t next_cluster = sector[ent_offset] | (sector[ent_offset + 1] << 8);
sector[ent_offset] = 0x00;
sector[ent_offset + 1] = 0x00;
if (write_sector(fat_sector, sector) != 0)
break;
cluster = next_cluster;
}
return 0; // success
}
}
}
return -1; // file not found
}

View File

@ -1,24 +1,76 @@
#include <stdlib.h>
#include <string.h>
#include <tty.h>
#include <fs/vfs.h>
/* we use something similar to the Linux kernel in terms of a VFS system */
typedef struct vfs_file_header {
char* filename; /* The filename, not the path. */
int32_t fd;
uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */
uint16_t* fs_header;
struct vfs_file_header* next; /* Linked list */
} vfs_file_header_t;
#define MAX_FDS 64
struct inode {
size_t size;
int permissions;
void *fs_data; /* FS-specific */
};
struct file_ops {
int (*read)(struct file*, char*, size_t);
int (*write)(struct file*, const char*, size_t);
};
struct file {
struct inode* f_inode;
size_t f_offset;
size_t f_refcount;
const struct file_ops f_ops;
};
vfs_file_header_t* root;
struct fdtable {
struct file* fds[MAX_FDS];
};
int vfs_handle_stdout(struct file* __f, const char* __s, size_t __l)
{
(void) __f;
terminal_write(__s, __l);
return 0;
}
struct fdtable* vfs_init_kernel_fdtable(void)
{
#if 0
struct fdtable* ft = malloc(sizeof(struct fdtable));
struct file* _stdout = malloc(sizeof(struct file));
struct file* _stdin = malloc(sizeof(struct file));
if (!ft || !_stdin || !_stdout)
{
return NULL;
}
_stdout->f_inode = NULL;
_stdout->f_offset = 0;
_stdout->f_refcount = 1;
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
#endif
return NULL;
}
int init_vfs(int argc, char** argv)
{
(void) argc;
(void) argv;
return 0;
}
/*
@ -28,5 +80,7 @@ vfs_file_header_t* root;
wow.
and now my CPU fan is going nuts.
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia drivers..
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia®©™ drivers..
--update: I wrote what months ago. now is 3/12/2026, I don't even remember what was going on well. wow.
*/

View File

@ -7,8 +7,8 @@
uint64_t gdt[GDT_ENTRIES];
struct {
uint16_t limit;
uint32_t base;
uint16_t limit;
uint32_t base;
} __attribute__((packed)) gp;

View File

@ -1,6 +1,11 @@
#include <stdio.h>
#include <port_io.h>
#include <scheduler.h>
#include <kernel/syscall.h>
#include <drivers/irq.h>
#include <drivers/idt.h>
@ -29,8 +34,7 @@ typedef struct {
} __attribute__((packed)) idtr_t;
__attribute__((aligned(0x10)))
static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
static idt_entry_t idt[256]; /* create an array of IDT entries; aligned for performance */
static idtr_t idtr;
@ -38,91 +42,6 @@ static bool vectors[IDT_MAX_DESCRIPTORS];
extern void* isr_stub_table[];
__attribute__((noreturn))
void exception_dispatcher(uint32_t int_no, uint32_t err_code)
{
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;
}
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));
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
asm volatile ("cli; hlt");
/* Will never be reached */
while (true)
{
asm volatile ("hlt" ::: "memory");
}
}
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)
{
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_init(void)
{
idtr.base = (uintptr_t)&idt[0];
@ -136,13 +55,141 @@ void idt_init(void)
extern void* irq_stub_table[];
for (uint8_t i = 0; i < 16; i++)
for (uint8_t i = 0; i < 20; 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 */
//asm volatile ("sti"); /* set the interrupt flag */
}
registers_t* interrupt_dispatcher(registers_t* regs)
{
if (regs->int_no < 32)
{
printf("external: %s, IDT/GDT: %s, ", ((regs->err_code & 0x0001) ? "true" : "false"), (regs->err_code & 0x0006) ? "IDT" : "GDT");
printf("LDT: %s, selector: %x (%i)\n", ((regs->err_code & 0x0006) == 0b10) ? "true" : "false", regs->err_code & 0xFFF8, regs->err_code & 0xFFF8);
printf("int: %i (%x), err: %i (%x)\n", regs->int_no, regs->int_no, regs->err_code, regs->err_code);
exception_handler(regs);
}
else if (regs->int_no < 52)
{
uint32_t irq = regs->int_no - 32;
regs = irq_handler(irq, regs);
if (irq >= 8)
{
outb(0xA0, 0x20); /* acknowledge the IRQ to slave PIC */
}
outb(0x20, 0x20); /* acknowledge the IRQ to master PIC */
}
return regs;
}
__noreturn
void exception_handler(registers_t* regs)
{
uint32_t int_no = regs->int_no;
uint32_t err_code = regs->err_code;
switch (int_no)
{
case 0:
printf("Divide by zero exception (or other division error)\n");
break;
case 2:
printf("NMI encountered\n");
break;
case 6: /* XXX: NOTE: this can be used to emulate instructions that do not exist on the current CPU :NOTE :XXX */
printf("Invalid opcode encountered at %p\n", regs->eip);
break;
case 7: /* XXX: NOTE: use this for FPU emulation and for saving/restoring FPU registers in a multiprocessing enviroment :NOTE :XXX */
printf("FPU instructions used, but FPU is nonexistant/disabled\n");
break;
case 8: /* double fault */
printf("Double fault at %p, err %i\n", regs->eip, regs->err_code);
break;
case 13:
printf("General Protection Fault: err=0x%x at %p\n", err_code, regs->eip);
break;
case 14:
{
uint32_t cr2;
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
printf("PF addr=%p eip=%p err=%x\n", cr2, regs->eip, err_code);
//printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
break;
}
default:
printf("Unhandled exception #%u, err=0x%x at %p\n", int_no, err_code, regs->eip);
break;
}
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));
if (((uint16_t) regs->cs != cs) || ((uint16_t) regs->ds != ds) || ((uint16_t) regs->es != es))
{
printf("segment register mismatch!\n");
}
printf("cs: 0x%x, ds: 0x%x, es: 0x%x,\nss: 0x%x, fs: 0x%x, gs: 0x%x\n", regs->cs, regs->ds, regs->es, ss, regs->fs, regs->gs);
asm volatile ("cli; hlt");
/* Will never be reached */
while (true)
{
asm volatile ("hlt" ::: "memory");
}
}
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)
{
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 the master PIC about Slave PIC at IRQ2 (0000 0100) */
outb(PIC1_DATA, 0x04);
/* tell the 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);
}

View File

@ -3,46 +3,74 @@
#include <drivers/pit.h>
#include <port_io.h>
/* TEMP DEBUG */
#include <tty.h>
#include <kernel/syscall.h>
#include <drivers/irq.h>
#define NUM_IRQS 0x90
irq_func_t func_list[NUM_IRQS];
#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */
typedef struct {
uint32_t irq_no;
irq_func_t func;
} irq_handler_t;
static volatile uint32_t num_irqs_missed = 0;
uint32_t num_irq_handlers = 0;
irq_handler_t handler_list[MAX_IRQ_HANDLERS];
volatile uint32_t num_irqs_missed = 0;
void irq_init(void)
{
for (int i = 0; i < NUM_IRQS; i++)
for (int i = 0; i < MAX_IRQ_HANDLERS; i++)
{
func_list[i] = 0x0;
handler_list[i].irq_no = 0;
handler_list[i].func = NULL;
}
set_irq_handler(0, (irq_func_t*) pit_handler);
set_irq_handler(1, (irq_func_t*) keyboard_handler);
set_irq_handler(0, (irq_func_t) pit_handler);
//set_irq_handler(1, (irq_func_t) ps2_keyboard_handler);
}
void irq_handler(uint8_t irq_number)
registers_t* irq_handler(uint32_t irq, registers_t* regs)
{
if (irq_number < NUM_IRQS)
{
if (func_list[irq_number])
uint8_t funcs_called = 0;
if (num_irq_handlers > 0)
{
for (unsigned int i = 0; i < MAX_IRQ_HANDLERS; i++)
{
func_list[irq_number]();
outb(0x20, 0x20); /* Acknowledge the IRQ to PIC */
}
else
{
num_irqs_missed++;
if (handler_list[i].irq_no == irq && handler_list[i].func != NULL)
{
regs = handler_list[i].func(regs);
funcs_called++;
/* PIC IRQ acknowledgement happens in idt.c */
}
}
}
if (funcs_called == 0)
{
num_irqs_missed++;
}
return regs;
}
void set_irq_handler(uint32_t num, irq_func_t* handler)
uint32_t get_interrupts_missed(void)
{
if (num < NUM_IRQS)
return num_irqs_missed;
}
void set_irq_handler(uint32_t num, irq_func_t handler)
{
if (num < MAX_IRQ_HANDLERS)
{
func_list[num] = (irq_func_t)handler;
handler_list[num].irq_no = num;
handler_list[num].func = handler;
num_irq_handlers++;
}
}

148
drivers/keyboard.c Normal file
View File

@ -0,0 +1,148 @@
#include <types.h>
#include <port_io.h>
#include <new_tty.h>
#include <stdio.h>
#include <drivers/irq.h>
#include <drivers/keyboard.h>
/*
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.
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 1
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 */
};
volatile uint32_t mods = 0;
volatile bool keyboard_initialied = false;
volatile bool extended = false;
int init_keyboard(void)
{
#ifdef _DEBUG
printf("Initializing the keyboard...\n");
#endif
keyboard_initialied = true;
set_irq_handler(1, (irq_func_t) keyboard_handler);
#ifdef _DEBUG
printf("Keyboard initialized\n");
#endif
return 0;
}
registers_t* keyboard_handler(registers_t* regs)
{
if (!(inb(PS2_STATUS_PORT) & 1))
{
return regs;
}
uint8_t scancode = inb(PS2_DATA_PORT);
if (scancode & 0x80)
{
return regs;
}
/* Handle shift press/release */
if (scancode == 0x2A || scancode == 0x36)
{
mods |= MODIFIER_SHIFT;
return regs;
}
else if (scancode == 0xAA || scancode == 0xB6)
{
mods &= MODIFIER_SHIFT_DESTROY;
return regs;
}
else if (scancode == 0x3A)
{
TOGGLE_BIT(mods, 0); /* TOGGLE_BIT defined in types.h, should move elsewhere. */
return regs;
}
/*else if (scancode == 0xE0)
{
extended = true;
return;
}*/
/* XXX: NOTE: we don't do extended codes yet. :NOTE :XXX */
/*if (extended)
{*/
/*switch (scancode)
{
case 0x48:
c = KEY_ARROW_UP;
break;
case 0x50:
c = KEY_ARROW_DOWN;
break;
case 0x4B:
c = KEY_ARROW_LEFT;
break;
case 0x4D:
c = KEY_ARROW_RIGHT;
break;
default:
c = KEY_NONE;
break;
}*/
/*tty_receive_char(c, mod);
extended = false;
return;
}*/
bool release = scancode & 0x80;
scancode &= 0x7F;
if (release)
{
return regs;
}
uint16_t c = (uint16_t) scancode_map[scancode];
if (c)
{
//tty_receive_char(c, mods);
char ch = tty_translate_char(c, mods);
tty_input_char(tty_get_active(), ch);
}
return regs;
}

382
drivers/new_tty.c Normal file
View File

@ -0,0 +1,382 @@
#include <stdio.h>
#include <stdlib.h>
#include <processes.h>
#include <sync.h>
#include <types.h>
#include <new_tty.h>
static tty_t ttys[MAX_TTYS];
static uint8_t num_ttys = 0;
static tty_t* active_tty = NULL;
static inline size_t next_index(size_t index)
{
return (index + 1) % TTY_BUFFER_SIZE;
}
static inline bool tty_empty(tty_t* tty)
{
return tty->head == tty->tail;
}
static inline bool tty_full(tty_t* tty)
{
return ((tty->head + 1) % TTY_BUFFER_SIZE) == tty->tail;
}
static inline bool is_canonical(tty_t* tty)
{
return (tty->flags & TTY_CANONICAL) != 0;
}
tty_t* tty_get_active(void)
{
return active_tty;
}
void tty_backspace(tty_t* tty)
{
if (tty->head == tty->tail)
{
return; /* buffer empty */
}
//tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE;
}
ssize_t tty_read_active(char* buf, size_t count)
{
return tty_read(active_tty, buf, count);
}
/*ssize_t tty_read(tty_t* tty, char* buf, size_t count)
{
size_t bytes_read = 0;
while (bytes_read < count)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
if (!tty_empty(tty))
{
char c = tty->input_buffer[tty->tail];
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
tty->tail = next_index(tty->tail);
spin_unlock(&tty->lock);
IRQ_ENABLE(); /* change? *//*
buf[bytes_read++] = c;
if (is_canonical(tty) && c == '\n')
{
break;
}
}
else
{
spin_unlock(&tty->lock);
IRQ_ENABLE();
}
}
return bytes_read;
}*/
ssize_t tty_read(tty_t* tty, char* buf, size_t count)
{
if (!tty || !buf)
return -1;
size_t bytes = 0;
while (1)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
if (!tty->line_ready)
{
spin_unlock(&tty->lock);
IRQ_ENABLE();
continue; /* spin until newline */
}
while (bytes < count && tty->tail != tty->head)
{
char c = tty->input_buffer[tty->tail];
tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE;
buf[bytes++] = c;
if (c == '\n')
{
tty->line_ready = false;
break;
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
break;
}
return bytes;
}
int input_buffer_put(tty_t* tty, char c)
{
IRQ_DISABLE();
spin_lock(&tty->lock);
size_t next = next_index(tty->head);
if (next == tty->tail)
{
spin_unlock(&tty->lock);
IRQ_ENABLE();
return -1;
}
tty->input_buffer[tty->head] = c;
tty->head = next;
spin_unlock(&tty->lock);
IRQ_ENABLE();
return 0;
}
int init_tty(void)
{
if (num_ttys >= MAX_TTYS)
{
return -1;
}
tty_t* t = &ttys[0];
memset(t, 0, sizeof(tty_t));
t->flags = TTY_NORMAL;
active_tty = t;
num_ttys = 1;
return 0;
}
tty_t* get_active_tty(void)
{
return active_tty;
}
tty_t* make_tty(uint32_t flags)
{
if (num_ttys >= MAX_TTYS)
{
return NULL;
}
tty_t* t = &ttys[num_ttys];
memset(t, 0, sizeof(tty_t));
t->flags = flags;
num_ttys++;
return t;
}
void tty_receive_char(char c, uint32_t kbd_mod)
{
if (!active_tty || c == 0)
{
return;
}
c = tty_translate_char(c, kbd_mod);
/* Handle backspace */
if (c == '\b')
{
tty_backspace(active_tty);
if (active_tty->head == active_tty->tail)
{
extern void terminal_putcharat(char c, uint16_t row, uint16_t column);
terminal_putcharat('Z', 20, 20);
}
if (active_tty->flags & TTY_ECHO)
{
/* erase character visually */
putc('\b');
}
return;
}
input_buffer_put(active_tty, c);
if (active_tty->flags & TTY_ECHO)
{
if ((active_tty->flags & TTY_PASSWORD) == 0)
{
putc(c);
}
else
{
putc('*');
}
}
}
void tty_input_char(tty_t* tty, char c)
{
if (!tty || c == 0)
return;
IRQ_DISABLE();
spin_lock(&tty->lock);
/* backspace */
if (c == '\b')
{
if (tty->head != tty->tail)
{
tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE;
if (tty->flags & TTY_ECHO)
{
putc('\b');/*
putc(' ');
putc('\b');*/
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
return;
}
size_t next = (tty->head + 1) % TTY_BUFFER_SIZE;
if (next != tty->tail)
{
tty->input_buffer[tty->head] = c;
tty->head = next;
if (c == '\n')
{
tty->line_ready = true;
}
}
spin_unlock(&tty->lock);
IRQ_ENABLE();
if (tty->flags & TTY_ECHO)
{
putc(c);
}
}
char tty_translate_char(char c, uint32_t modifiers)
{
bool caps = (modifiers & MODIFIER_CAPS) != 0;
bool shift = (modifiers & MODIFIER_SHIFT) != 0;
bool ctrl = (modifiers & (MODIFIER_LCTRL | MODIFIER_RCTRL)) != 0;
/* handle alphabetic characters */
if (c >= 'a' && c <= 'z')
{
if (caps ^ shift) /* XOR logic */
{
return c - 32; /* to uppercase */
}
return c;
}
if (c >= 'A' && c <= 'Z')
{
if (caps ^ shift)
{
return c;
}
return c + 32; /* to lowercase */
}
/* handle ctrl (should later include control mapping/sending messages to processes via these) */
if (ctrl)
{
if (c >= 'a' && c <= 'z')
{
return c - 'a' + 1; /* Ctrl+A → 1 */
}
if (c >= 'A' && c <= 'Z')
{
return c - 'A' + 1;
}
}
/* shifted symbols (US layout) */
if (shift)
{
switch (c)
{
case '1':
return '!';
case '2':
return '@';
case '3':
return '#';
case '4':
return '$';
case '5':
return '%';
case '6':
return '^';
case '7':
return '&';
case '8':
return '*';
case '9':
return '(';
case '0':
return ')';
case '-':
return '_';
case '=':
return '+';
case '[':
return '{';
case ']':
return '}';
case ';':
return ':';
case '\'':
return '"';
case ',':
return '<';
case '.':
return '>';
case '/':
return '?';
case '\\':
return '|';
case '`':
return '~';
}
}
return c;
}

View File

@ -2,6 +2,8 @@
#include <port_io.h>
#include <stdio.h>
#include <scheduler.h>
#include <drivers/pit.h>
@ -14,12 +16,14 @@ volatile uint64_t pit_ticks = 0;
bool pit_initialized = false;
void pit_init(void)
{
{
printf("pit_initialized addr = %x\n", &pit_initialized);
#ifdef _DEBUG
printf("[ PIT ] Initializing the PIT...\n");
#endif
uint16_t divisor = (uint16_t)1193;
uint16_t divisor = (uint16_t) 1193;
/* Send command byte */
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
@ -35,9 +39,10 @@ void pit_init(void)
#endif
}
void pit_handler(void)
registers_t* pit_handler(registers_t* regs)
{
pit_ticks++;
return regs;
}
void pit_sleep(uint64_t ms)
@ -48,3 +53,14 @@ void pit_sleep(uint64_t ms)
asm volatile ("hlt");
}
}
/*void pit_sleep(uint64_t ms)
{
extern task_t* current_task;
current_task->wakeup_tick = pit_ticks + ms;
current_task->state = TASK_SLEEPING;
asm volatile("int $32");*/ /* force reschedule immediately */
/*}
*/

View File

@ -3,6 +3,8 @@
#include <tty.h>
#include <stdlib.h>
#include <new_tty.h>
#include <drivers/ps2_keyboard.h>
@ -62,6 +64,8 @@ volatile int32_t current_length = 0;
volatile int32_t capacity = 0;
volatile uint16_t current_key;
volatile bool use_new_tty = false;
volatile ps2_hook_t* hooks = NULL;
volatile int hook_count = 0;
@ -84,6 +88,10 @@ static const char scancode_map[128] = {
/* The rest are function and control keys */
};
void set_use_new_tty(bool t)
{
use_new_tty = t;
}
void keyboard_init(void)
{
@ -94,6 +102,8 @@ void keyboard_init(void)
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
hooks = NULL;
set_use_new_tty(true);
ps2keyboard_initialized = true;
@ -199,6 +209,7 @@ void call_hooks(char c)
if (hook_count == 0)
{
_sti_asm();
return;
}
@ -396,32 +407,45 @@ void free_current_string(void)
}
}
void keyboard_handler(void)
registers_t* ps2_keyboard_handler(registers_t* regs)
{
#if 0
uint8_t scancode = inb(PS2_DATA_PORT);
/* Handle shift press/release */
if (scancode == 0x2A || scancode == 0x36)
{
shift_pressed = true;
return;
return regs;
}
else if (scancode == 0xAA || scancode == 0xB6)
{
shift_pressed = false;
return;
return regs;
}
else if (scancode == 0x3A)
{
capslock_pressed = !capslock_pressed;
return;
return regs;
}
else if (scancode == 0xE0)
{
extended = true;
return;
return regs;
}
uint32_t flags = 0;
if (capslock_pressed)
{
flags |= MODIFIER_CAPS;
}
if (shift_pressed)
{
flags |= MODIFIER_SHIFT;
}
if (scancode & 0x80)
{
@ -430,84 +454,94 @@ void keyboard_handler(void)
else
{
uint16_t c = (uint16_t) scancode_map[scancode];
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
if (!use_new_tty)
{
c -= 32; /* Convert to uppercase */
if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z'))
{
c -= 32; /* Convert to uppercase */
}
else if (shift_pressed)
{
c = (uint16_t) terminal_get_shifted((unsigned char) c);
}
if (extended)
{
switch (scancode)
{
case 0x48:
c = KEY_ARROW_UP;
break;
case 0x50:
c = KEY_ARROW_DOWN;
break;
case 0x4B:
c = KEY_ARROW_LEFT;
break;
case 0x4D:
c = KEY_ARROW_RIGHT;
break;
default:
c = KEY_NONE;
break;
}
if (gets_called)
{
gets_append_char(c);
return regs;
}
current_key = c;
is_new_key = true;
extended = false;
return regs;
}
if (gets_called)
{
gets_append_char(c);
return regs;
}
if (c)
{
if (c != '\n')
{
append_char(c);
}
current_char = c;
is_new_char = true;
if (c == '\n')
{
/*append_char(c);
current_char = c;
is_new_char = true;*/
free_current_string();
}
}
}
else if (shift_pressed)
else
{
c = (uint16_t) terminal_get_shifted((unsigned char) c);
tty_receive_char(c, flags);
}
if (hook_count > 0)
{
call_hooks(c);
}
if (extended)
{
switch (scancode)
{
case 0x48:
c = KEY_ARROW_UP;
break;
case 0x50:
c = KEY_ARROW_DOWN;
break;
case 0x4B:
c = KEY_ARROW_LEFT;
break;
case 0x4D:
c = KEY_ARROW_RIGHT;
break;
default:
c = KEY_NONE;
break;
}
if (gets_called)
{
gets_append_char(c);
return;
}
current_key = c;
is_new_key = true;
extended = false;
return;
}
if (gets_called)
{
gets_append_char(c);
return;
}
if (c)
{
if (c != '\n')
{
append_char(c);
}
current_char = c;
is_new_char = true;
if (c == '\n')
{
/*append_char(c);
current_char = c;
is_new_char = true;*/
free_current_string();
}
}
}
#endif
return regs;
}

View File

@ -306,3 +306,12 @@ void terminal_update_cursor(void)
outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
}
void terminal_putcharat(char c, uint16_t row, uint16_t column)
{
int _r;
int _c;
terminal_get_cursor(&_r, &_c);
terminal_set_cursor(row, column);
terminal_putchar(c);
terminal_set_cursor((uint16_t) _r, (uint16_t) _c);
}