Espresso 0.0.2c
This commit is contained in:
46
drivers/audio/pcspeaker.c
Normal file
46
drivers/audio/pcspeaker.c
Normal 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);
|
||||
}
|
||||
@ -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%08x–0x%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
48
drivers/exec/secf.c
Normal 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
49
drivers/fs/ekfs.c
Normal 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
374
drivers/fs/fat16.c
Normal 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(§or_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 = §or[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
|
||||
}
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
|
||||
225
drivers/idt.c
225
drivers/idt.c
@ -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 (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_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 (32–39) */
|
||||
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -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
148
drivers/keyboard.c
Normal 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
382
drivers/new_tty.c
Normal 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;
|
||||
}
|
||||
@ -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 */
|
||||
/*}
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user