Espresso 0.0.1b

This commit is contained in:
2025-06-27 14:48:06 -05:00
parent fca025a9bf
commit c336584114
39 changed files with 2676 additions and 936 deletions

BIN
E.xcf Normal file

Binary file not shown.

View File

@ -1,17 +1,17 @@
# === Config ===
TARGET := boot/espresso.bin
TARGET := boot/espresso.elf
ISO := boot/espresso.iso
CC := i686-elf-gcc
AS := i686-elf-as
NASM := nasm
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 256M
MKFS_VFAT := sudo mkfs.vfat
MKFS_FLAGS := -F 32 --mbr -S 512
MKFS_FLAGS := -F 32 -S 512
NASMFLAGS := -f elf32
WNOFLAGS := -Wno-discarded-qualifiers
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS)
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib
QEMUFLAGS := -device isa-debug-exit -serial stdio -kernel $(TARGET) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse2 #-singlestep
QEMUFLAGS := -boot d -cdrom $(ISO) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1 -singlestep
SRC_DIRS := kernel drivers lib
INCLUDE_DIRS := include
INCLUDES := $(addprefix -I, $(INCLUDE_DIRS))

49
boot.s
View File

@ -74,6 +74,8 @@ enable_sse_asm:
push %ebx
push %ecx
push %edx
push %esi
push %edi
# Check CPUID support
pushf
@ -87,13 +89,16 @@ enable_sse_asm:
xor %ecx, %eax
jz .no_cpuid
# Check for SSE
# CPUID function 1
mov $1, %eax
cpuid
test $0x02000000, %edx
mov %edx, %ebx # EDX = SSE1/SSE2 bits
mov %ecx, %esi # ECX = SSE3/SSSE3/SSE4.1 bits
test $0x02000000, %ebx # SSE
jz .no_sse
# Enable SSE
# Enable SSE (required for SSE1/2/3/SSSE3/4.1)
mov %cr0, %eax
and $~0x4, %eax # Clear EM (bit 2)
or $0x2, %eax # Set MP (bit 1)
@ -103,17 +108,48 @@ enable_sse_asm:
or $0x600, %eax # Set OSFXSR | OSXMMEXCPT
mov %eax, %cr4
lea sse_initialized, %ebx
movl $1, (%ebx)
# Set version = 1 (SSE1)
mov $1, %eax
test $0x04000000, %ebx # SSE2 (bit 26)
jz .check_sse3
mov $2, %eax
.check_sse3:
test $0x00000001, %esi # SSE3 (bit 0)
jz .check_ssse3
mov $3, %eax
.check_ssse3:
test $0x00000200, %esi # SSSE3 (bit 9)
jz .check_sse41
mov $4, %eax
.check_sse41:
test $0x00080000, %esi # SSE4.1 (bit 19)
jz .set_result
mov $5, %eax
.set_result:
lea sse_initialized, %edi
mov %eax, (%edi)
jmp .done
.no_sse:
.no_cpuid:
lea sse_initialized, %edi
mov $0, (%edi)
.done:
pop %edi
pop %esi
pop %edx
pop %ecx
pop %ebx
pop %eax
ret
_kernel_early:
call _init
@ -205,8 +241,9 @@ This is useful when debugging or when you implement call tracing.
*/
.size _start, . - _start
.section .data
.global sse_initialized
sse_initialized: .word 0
sse_initialized: .int 0

63
drivers/elf.c Normal file
View File

@ -0,0 +1,63 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <mm/pmm.h>
#include <mm/paging.h>
#include <drivers/elf.h>
#define PAGE_SIZE 4096
#define ALIGN_DOWN(x) ((x) & ~(PAGE_SIZE - 1))
#define ALIGN_UP(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
elf_executable_t* load_elf32(void* elf_data)
{
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;
/* Check ELF magic */
if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0)
{
printf("Invalid ELF file\n");
return NULL;
}
if (ehdr->e_machine != 3 || ehdr->e_type != 2)
{
printf("Unsupported ELF type or architecture\n");
return NULL;
}
Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff);
for (int i = 0; i < ehdr->e_phnum; i++) {
Elf32_Phdr* phdr = &phdrs[i];
if (phdr->p_type != PT_LOAD)
{
continue;
}
uint32_t vaddr_start = ALIGN_DOWN(phdr->p_vaddr);
uint32_t vaddr_end = ALIGN_UP(phdr->p_vaddr + phdr->p_memsz);
uint32_t segment_pages = (vaddr_end - vaddr_start) / PAGE_SIZE;
for (uint32_t page = 0; page < segment_pages; page++)
{
void* phys = alloc_page();
void* virt = (void*)(vaddr_start + page * PAGE_SIZE);
map_page(phys, virt);
memset(virt, 0, PAGE_SIZE);
}
void* dest = (void*)(uintptr_t)phdr->p_vaddr;
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);
}
elf_executable_t* result = malloc(sizeof(elf_executable_t));
result->entry_point = (void*)(uintptr_t)ehdr->e_entry;
return result;
}

195
drivers/elf_load.c Normal file
View File

@ -0,0 +1,195 @@
/*#include <stdlib.h>
#include <drivers/elf_load.h>*/
/*
ELF Header
The ELF header is always found at the start of the file.
Position (32 bit) Position (64 bit) Value
0-3 0-3 Magic number - 0x7F, then 'ELF' in ASCII
4 4 1 = 32 bit, 2 = 64 bit
5 5 1 = little endian, 2 = big endian
6 6 ELF header version
7 7 OS ABI - usually 0 for System V
8-15 8-15 Unused/padding
16-17 16-17 Type (1 = relocatable, 2 = executable, 3 = shared, 4 = core)
18-19 18-19 Instruction set - see table below
20-23 20-23 ELF Version (currently 1)
24-27 24-31 Program entry offset
28-31 32-39 Program header table offset
32-35 40-47 Section header table offset
36-39 48-51 Flags - architecture dependent; see note below
40-41 52-53 ELF Header size
42-43 54-55 Size of an entry in the program header table
44-45 56-57 Number of entries in the program header table
46-47 58-59 Size of an entry in the section header table
48-49 60-61 Number of entries in the section header table
50-51 62-63 Section index to the section header string table
The flags entry can probably be ignored for x86 ELFs, as no flags are actually defined.
Instruction Set Architectures:
Architecture Value
No Specific 0x00
Sparc 0x02
x86 0x03
MIPS 0x08
PowerPC 0x14
ARM 0x28
SuperH 0x2A
IA-64 0x32
x86-64 0x3E
AArch64 0xB7
RISC-V 0xF3
Program header
This is an array of N (given in the main header) entries in the following format. Make sure to use the correct version depending on whether the file is 32 bit or 64 bit as the tables are quite different.
32 bit version:
Position Value
0-3 Type of segment (see below)
4-7 The offset in the file that the data for this segment can be found (p_offset)
8-11 Where you should start to put this segment in virtual memory (p_vaddr)
12-15 Reserved for segment's physical address (p_paddr)
16-19 Size of the segment in the file (p_filesz)
20-23 Size of the segment in memory (p_memsz, at least as big as p_filesz)
24-27 Flags (see below)
28-31 The required alignment for this section (usually a power of 2)
64 bit version:
Position Value
0-3 Type of segment (see below)
4-7 Flags (see below)
8-15 The offset in the file that the data for this segment can be found (p_offset)
16-23 Where you should start to put this segment in virtual memory (p_vaddr)
24-31 Reserved for segment's physical address (p_paddr)
32-39 Size of the segment in the file (p_filesz)
40-47 Size of the segment in memory (p_memsz, at least as big as p_filesz)
48-55 The required alignment for this section (usually a power of 2)
Segment types: 0 = null - ignore the entry; 1 = load - clear p_memsz bytes at p_vaddr to 0, then copy p_filesz bytes from p_offset to p_vaddr; 2 = dynamic - requires dynamic linking; 3 = interp - contains a file path to an executable to use as an interpreter for the following segment; 4 = note section. There are more values, but mostly contain architecture/environment specific information, which is probably not required for the majority of ELF files.
Flags: 1 = executable, 2 = writable, 4 = readable.
*/
/*typedef struct elf_header {
uint32_t elf_magic;
uint8_t bitness;*/ /* 1 = 32 bit, 2 = 64 bit */
/*uint8_t endianess;*/ /* 1 = little endian, 2 = big endian */
/*uint8_t elf_header_version;
uint8_t os_abi;*/ /* usually 0 for System V */
/*uint8_t unused_padding[8];
uint16_t type;
uint16_t isa;
uint32_t elf_version;
uint32_t program_entry_offset;
uint32_t program_header_offset;
uint32_t section_header_offset;
uint32_t flags;
uint16_t elf_header_size;
uint16_t program_header_entry_size;
uint16_t program_header_num_entries;
uint16_t section_header_entry_size;
uint16_t section_header_num_entries;
uint16_t section_header_string_table_index;
} elf_header_t;
typedef struct program_header_entry {
uint32_t type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t flags;
uint32_t alignment_required;
} program_header_entry_t;*/
/*int32_t elf_check(void* executable)
{
elf_header_t* e_header = (elf_header_t*)executable;
char* elf_magic = (char*)e_header->elf_magic;
if (elf_magic[0] != 0x7F || elf_magic[1] != 'E' || elf_magic[2] != 'L' || elf_magic[3] != 'F')
{
return -1;
}
if (e_header->bitness != 1 || e_header->endianess != 1)
{
return -2;
}
uint32_t* cph_addr = (uint32_t*)e_header + e_header->program_header_offset
program_header_entry_t* p_header = (program_header_entry_t*)cph_addr;
uint8_t load = 0;
uin16_t num_phs = 1;
while (p_header)
{
if (num_phs == program_header_num_entries)
{
break;
}
if (p_header->type == 1)
{
load = 1;
break;
}
cph_addr += e_header->program_header_entry_size;
p_header = (program_header_entry_t*)cph_addr;
num_phs++;
}
uint32_t memsz = p_header->p_vaddr + p_header->p_memsz;
void* new_mem = malloc(memsz);
void* memloc = memclr(new_mem, (size_t)memsz);
void *memcpy(void *dst, const void *src, uint32_t n);
void* program_header_table_end = (e_header->program_header_entry_size + e_header->program_header_num_entries);
void* data_begin = (p_header->p_offset + p_header->p_filesz);
memcpy(memloc, p_header->p_offset*/
/*
typedef struct program_header_entry {
uint32_t type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t flags;
uint32_t alignment_required;
} program_header_entry_t;
*/
/*}*/

View File

@ -1,93 +1,806 @@
#include <string.h>
#include <stdlib.h>
#include <drivers/ide.h>
#include <fs/duckfs.h>
#define DFS_MAGIC 0xDF1984CC
static duckfs_superblock_t super;
#define DFS_BLOCK_SIZE 512
extern int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count);
extern int32_t disk_read(uint64_t lba, void* buffer, uint32_t count);
#define DFS_VERSION_0 "DuckFS, wheresDax?"
#define DFS_VERSION_1 "DuckFS, Terminator"
#define DFS_VERSION_2 "DuckFS-Terminator2"
#define DFS_VERSION_3 "DuckFS,StarWarsEIV"
#define DFS_VERSION_4 "DuckFS QUACK,QUACK"
#define DFS_FILE_ERROR -8
#define DFS_FILE_UNUSED -1
#define DFS_FILE_USED 0
#define DFS_FILE_TEXT 0
#define DFS_FILE_BINARY 1
#define DFS_FILE_DIRECTORY 2
/* encryption algorithms */
#define DFS_CAESAR_5 88
#define DFS_CAESAR_8 84
#define DFS_CAESAR_2 09
#define DFS_QUACK_32 99
#define DFS_MAX_FILENAME_LEN 64
#define DFS_MAX_FILES 256
typedef struct duckfs_file_header {
char filename[DFS_MAX_FILENAME_LEN + 1]; /* + 1 for the \0 */
char permissions[3]; /* Same thing here */
/*
512 Bytes per sector, meaning a 2 sector file is 1024 bytes, or 1 KiB.
Only valid if this file is not a directory.
*/
int32_t num_sectors;
int16_t type; /* Indicates the file type. -1 for null file, 0 for a text file, 1 for a binary file, and 2 for a directory. */
uint16_t _reserved0; /* (align to 4) */
struct duckfs_file_header* next; /* Next file in the directory this file is in. */
struct duckfs_file_header* contents; /* contains the first file in the directory. only valid if this file is a directory. */
struct duckfs_file_header* parent; /* The directory this file is in. */
uint64_t next_lba; /* The LBA of the next file's file header on the disk. */
uint64_t contents_lba;
uint64_t parent_lba;
uint64_t lba_start; /* only is valid if this file is not a directory. */
uint64_t lba_end; /* only is valid if this file is not a directory. */
uint8_t _reserved1[126]; /* padding to 256 bytes total */
} duckfs_file_header_t;
typedef struct duckfs_superblock {
int32_t duckfs_magic; /* must be DFS_MAGIC. */
char duckfs_version_string[19];
char volume_label[19]; /* 18 characters and a null zero. */
int16_t encryption;
uint64_t duckfs_root; /* LBA of the root directory's file header */
uint32_t _padding[115]; /* padding to 512 bytes total */
} duckfs_superblock_t;
static uint16_t duckfs_initialized = 0;
static duckfs_file_header_t duckfs_root;
const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 };
void duckfs_init(void)
int32_t duckfs_mount(void)
{
printf("\t%i\n", (sizeof(duckfs_file_header_t)));
printf("\t\t%i\n", (sizeof(duckfs_superblock_t)));
/* int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) */
/* int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) */
if (disk_read(8, &super, 1) != 0)
{
return -1;
}
/*uint8_t superblock_sector[512] = { 0 };
if (memcmp(super.magic, DUCKFS_MAGIC, 7) != 0)
{
return -2;
}
ide_read*/
return 0;
}
static int32_t read_header(uint64_t lba, duckfs_file_header_t* hdr)
{
uint8_t sector[512];
if (disk_read(lba, sector, 1) != 0)
{
return -1;
}
memcpy(hdr, sector, sizeof(duckfs_file_header_t));
return 0;
}
static const char* next_token(const char* path, char* token)
{
while (*path == '/')
{
path++;
}
if (*path == 0)
{
return NULL;
}
size_t len = 0;
while (*path && *path != '/')
{
token[len++] = *path++;
}
token[len] = 0;
return path;
}
static int32_t duckfs_alloc_block(uint64_t* out_lba)
{
if (super.free_list_lba == 0)
{
return -1;
}
*out_lba = super.free_list_lba;
uint64_t next;
if (disk_read(*out_lba, &next, 1) != 0)
{
return -2;
}
super.free_list_lba = next;
/* Persist the updated superblock */
if (disk_write(8, &super, 1) != 0)
{
return -3;
}
return 0;
}
static int32_t duckfs_alloc_file_data(const void* content, size_t size, uint64_t* first_lba)
{
const uint8_t* src = (const uint8_t*)content;
size_t remaining = size;
uint64_t prev_lba = 0;
uint64_t head_lba = 0;
while (remaining > 0)
{
uint64_t block_lba;
if (duckfs_alloc_block(&block_lba) != 0)
{
return -1;
}
/* Write next block LBA at start (for linking) */
uint64_t next = 0;
if (remaining > super.block_size - sizeof(uint64_t))
{
if (duckfs_alloc_block(&next) != 0)
{
return -2;
}
}
uint8_t buffer[512] = {0};
memcpy(buffer, &next, sizeof(uint64_t));
size_t copy_len = super.block_size - sizeof(uint64_t);
if (copy_len > remaining)
{
copy_len = remaining;
}
memcpy(buffer + sizeof(uint64_t), src, copy_len);
if (disk_write(block_lba, buffer, 1) != 0)
{
return -3;
}
if (prev_lba != 0) {
if (disk_write(prev_lba, &block_lba, 1) != 0)
{
return -4;
}
}
else
{
head_lba = block_lba;
}
prev_lba = block_lba;
src += copy_len;
remaining -= copy_len;
}
*first_lba = head_lba;
return 0;
}
int32_t duckfs_find(const char* path, duckfs_file_header_t* out)
{
char token[DUCKFS_NAME_LEN];
duckfs_file_header_t current;
if (read_header(super.root_header_lba, &current) != 0)
{
return -1;
}
const char* p = path;
while ((p = next_token(p, token)))
{
if (current.type != DUCKFS_TYPE_DIR)
{
return -2;
}
uint64_t child = current.child_lba;
int32_t found = 0;
while (child != 0)
{
duckfs_file_header_t entry;
if (read_header(child, &entry) != 0)
{
return -3;
}
if (strncmp(entry.name, token, DUCKFS_NAME_LEN) == 0)
{
current = entry;
found = 1;
break;
}
child = entry.next_file_lba;
}
if (!found)
{
return -4;
}
}
*out = current;
return 0;
}
int32_t duckfs_create_file(const char* name, const void* content, size_t size, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
/* Check for existing file */
duckfs_file_header_t child;
uint64_t current = parent_dir->child_lba;
uint64_t prev_lba = 0;
while (current != 0)
{
if (disk_read(current, &child, 1) != 0)
{
return -2;
}
if (strncmp(child.name, name, DUCKFS_NAME_LEN) == 0)
{
/* Overwrite content */
uint64_t data_lba;
if (duckfs_alloc_file_data(content, size, &data_lba) != 0)
{
return -3;
}
child.first_block_lba = data_lba;
child.size = size;
child.modified = 0; /* TODO: timestamp */
return disk_write(current, &child, 1);
}
prev_lba = current;
current = child.next_file_lba;
}
/* Allocate header */
uint64_t file_hdr_lba;
if (duckfs_alloc_block(&file_hdr_lba) != 0)
{
return -4;
}
/* Write content */
uint64_t data_lba;
if (duckfs_alloc_file_data(content, size, &data_lba) != 0)
{
return -5;
}
duckfs_file_header_t new_file = {0};
strncpy(new_file.name, name, DUCKFS_NAME_LEN);
new_file.type = DUCKFS_TYPE_FILE;
new_file.permissions = perms;
new_file.uid = uid;
new_file.gid = gid;
new_file.size = size;
new_file.first_block_lba = data_lba;
new_file.modified = 0;
/* Add to dir */
if (prev_lba == 0)
{
parent_dir->child_lba = file_hdr_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -6;
}
}
else
{
child.next_file_lba = file_hdr_lba;
if (disk_write(prev_lba, &child, 1) != 0)
{
return -7;
}
}
return disk_write(file_hdr_lba, &new_file, 1);
}
int32_t duckfs_create_dir(const char* name, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
/* Allocate header */
uint64_t hdr_lba;
if (duckfs_alloc_block(&hdr_lba) != 0)
{
return -2;
}
duckfs_file_header_t new_dir = {0};
strncpy(new_dir.name, name, DUCKFS_NAME_LEN);
new_dir.type = DUCKFS_TYPE_DIR;
new_dir.permissions = perms;
new_dir.uid = uid;
new_dir.gid = gid;
new_dir.modified = 0;
new_dir.size = 0;
/* Write header */
if (disk_write(hdr_lba, &new_dir, 1) != 0)
{
return -3;
}
/* Add to parent */
duckfs_file_header_t sibling;
uint64_t current = parent_dir->child_lba;
uint64_t prev = 0;
while (current != 0)
{
if (disk_read(current, &sibling, 1) != 0)
{
return -4;
}
prev = current;
current = sibling.next_file_lba;
}
if (prev == 0)
{
parent_dir->child_lba = hdr_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -5;
}
}
else
{
sibling.next_file_lba = hdr_lba;
if (disk_write(prev, &sibling, 1) != 0)
{
return -6;
}
}
return 0;
}
int32_t duckfs_read_file(const duckfs_file_header_t* file, void* buffer, size_t size)
{
if (file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t to_read = size;
if (to_read > file->size)
{
to_read = file->size;
}
uint64_t blocks = (to_read + super.block_size - 1) / super.block_size;
return disk_read(file->first_block_lba, buffer, blocks);
}
int32_t duckfs_write_data(duckfs_file_header_t* file, const void* data, size_t offset, size_t length)
{
if (!file || file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t final_size = offset + length;
if (final_size > file->size)
{
/* Grow */
if (duckfs_append_data(file, ((const uint8_t*)data) + (file->size - offset), final_size - file->size) != 0)
{
return -2;
}
}
size_t block_size = super.block_size;
size_t remaining = length;
const uint8_t* src = (const uint8_t*)data;
uint64_t current_lba = file->first_block_lba;
uint64_t block_offset = 0;
/* Traverse to block containing `offset` */
size_t logical = 0;
while (logical + (block_size - 8) <= offset)
{
uint64_t next;
if (disk_read(current_lba, &next, 1) != 0)
{
return -3;
}
current_lba = next;
if (current_lba == 0)
{
return -4; /* ran out */
}
logical += block_size - 8;
}
/* Start writing */
while (remaining > 0)
{
uint8_t buffer[512];
if (disk_read(current_lba, buffer, 1) != 0)
{
return -5;
}
uint64_t next_lba;
memcpy(&next_lba, buffer, sizeof(uint64_t));
size_t block_start = (offset > logical) ? (offset - logical) : 0;
size_t to_copy = block_size - 8 - block_start;
if (to_copy > remaining) to_copy = remaining;
memcpy(buffer + 8 + block_start, src, to_copy);
if (disk_write(current_lba, buffer, 1) != 0)
{
return -6;
}
src += to_copy;
remaining -= to_copy;
offset += to_copy;
logical += block_size - 8;
current_lba = next_lba;
}
return 0;
}
int32_t duckfs_append_data(duckfs_file_header_t* file, const void* data, size_t length)
{
if (!file || file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t block_size = super.block_size;
size_t data_per_block = block_size - sizeof(uint64_t);
uint64_t last_lba = file->first_block_lba;
if (last_lba == 0)
{
/* Allocate first block */
if (duckfs_alloc_block(&last_lba) != 0)
{
return -2;
}
file->first_block_lba = last_lba;
}
else
{
/* Traverse to last block */
uint64_t next;
while (1)
{
if (disk_read(last_lba, &next, 1) != 0)
{
return -3;
}
memcpy(&next, &next, sizeof(uint64_t));
if (next == 0)
{
break;
}
last_lba = next;
}
}
size_t offset_in_block = file->size % data_per_block;
size_t remaining = length;
const uint8_t* src = (const uint8_t*)data;
/* Write to the partially filled last block */
if (offset_in_block != 0)
{
uint8_t buffer[512];
if (disk_read(last_lba, buffer, 1) != 0)
{
return -4;
}
size_t to_copy = data_per_block - offset_in_block;
if (to_copy > remaining)
{
to_copy = remaining;
}
memcpy(buffer + sizeof(uint64_t) + offset_in_block, src, to_copy);
if (disk_write(last_lba, buffer, 1) != 0)
{
return -5;
}
file->size += to_copy;
remaining -= to_copy;
src += to_copy;
}
/* Write remaining data to new blocks */
while (remaining > 0)
{
uint64_t new_lba;
if (duckfs_alloc_block(&new_lba) != 0)
{
return -6;
}
/* Link previous block to this one */
if (disk_write(last_lba, &new_lba, 1) != 0)
{
return -7;
}
uint8_t buffer[512] = {0};
uint64_t next = 0;
memcpy(buffer, &next, sizeof(uint64_t));
size_t to_copy = (remaining > data_per_block) ? data_per_block : remaining;
memcpy(buffer + sizeof(uint64_t), src, to_copy);
if (disk_write(new_lba, buffer, 1) != 0)
{
return -8;
}
last_lba = new_lba;
src += to_copy;
remaining -= to_copy;
file->size += to_copy;
}
return 0;
}
int32_t duckfs_truncate(duckfs_file_header_t* file, size_t new_size)
{
if (!file || file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t block_size = super.block_size;
size_t data_per_block = block_size - sizeof(uint64_t);
size_t needed_blocks = (new_size + data_per_block - 1) / data_per_block;
uint64_t current = file->first_block_lba;
uint64_t prev = 0;
for (size_t i = 0; i < needed_blocks; i++)
{
if (current == 0)
{
break;
}
uint64_t next;
if (disk_read(current, &next, 1) != 0)
{
return -2;
}
memcpy(&next, &next, sizeof(uint64_t));
prev = current;
current = next;
}
/* `current` is now first block to free */
while (current != 0)
{
uint64_t next;
if (disk_read(current, &next, 1) != 0)
{
return -3;
}
memcpy(&next, &next, sizeof(uint64_t));
/* Write freelist entry */
if (disk_write(current, &super.free_list_lba, 1) != 0)
{
return -4;
}
super.free_list_lba = current;
current = next;
}
/* Finalize */
if (disk_write(8, &super, 1) != 0)
{
return -5;
}
/* Cut block chain */
if (prev != 0)
{
uint64_t zero = 0;
if (disk_write(prev, &zero, 1) != 0)
{
return -6;
}
}
file->size = new_size;
return 0;
}
int32_t duckfs_delete_file(const char* name, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
duckfs_file_header_t child;
uint64_t prev_lba = 0;
uint64_t current_lba = parent_dir->child_lba;
/* Search for file by name */
while (current_lba != 0)
{
if (disk_read(current_lba, &child, 1) != 0)
{
return -2;
}
if (strncmp(child.name, name, DUCKFS_NAME_LEN) == 0)
{
break;
}
prev_lba = current_lba;
current_lba = child.next_file_lba;
}
if (current_lba == 0)
{
return -3; /* not found */
}
/* Remove from parent's linked list */
if (prev_lba == 0)
{
/* It's the first child */
parent_dir->child_lba = child.next_file_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -4;
}
}
else
{
duckfs_file_header_t prev;
if (disk_read(prev_lba, &prev, 1) != 0)
{
return -5;
}
prev.next_file_lba = child.next_file_lba;
if (disk_write(prev_lba, &prev, 1) != 0)
{
return -6;
}
}
/* Free file data blocks */
uint64_t current = child.first_block_lba;
while (current != 0)
{
uint64_t next;
if (disk_read(current, &next, 1) != 0)
{
return -7;
}
/* Insert this block into the freelist */
if (disk_write(current, &super.free_list_lba, 1) != 0)
{
return -8;
}
super.free_list_lba = current;
current = next;
}
/* Free file header block */
if (disk_write(current_lba, &super.free_list_lba, 1) != 0)
{
return -9;
}
super.free_list_lba = current_lba;
/* Save updated superblock */
if (disk_write(8, &super, 1) != 0)
{
return -10;
}
return 0;
}
int32_t duckfs_delete_dir(const char* name, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
duckfs_file_header_t dir;
uint64_t prev_lba = 0;
uint64_t current_lba = parent_dir->child_lba;
/* Find directory */
while (current_lba != 0)
{
if (disk_read(current_lba, &dir, 1) != 0)
{
return -2;
}
if (strncmp(dir.name, name, DUCKFS_NAME_LEN) == 0 && dir.type == DUCKFS_TYPE_DIR)
{
break;
}
prev_lba = current_lba;
current_lba = dir.next_file_lba;
}
if (current_lba == 0)
{
return -3; /* not found */
}
/* Delete contents recursively */
uint64_t child_lba = dir.child_lba;
while (child_lba != 0)
{
duckfs_file_header_t child;
if (disk_read(child_lba, &child, 1) != 0)
{
return -4;
}
uint64_t next_lba = child.next_file_lba;
if (child.type == DUCKFS_TYPE_FILE)
{
if (duckfs_delete_file(child.name, &dir) != 0)
{
return -5;
}
}
else if (child.type == DUCKFS_TYPE_DIR)
{
if (duckfs_delete_dir(child.name, &dir) != 0)
{
return -6;
}
}
child_lba = next_lba;
}
/* Remove dir from parent */
if (prev_lba == 0)
{
parent_dir->child_lba = dir.next_file_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -7;
}
}
else
{
duckfs_file_header_t prev;
if (disk_read(prev_lba, &prev, 1) != 0)
{
return -8;
}
prev.next_file_lba = dir.next_file_lba;
if (disk_write(prev_lba, &prev, 1) != 0)
{
return -9;
}
}
/* Free directory header block */
if (disk_write(current_lba, &super.free_list_lba, 1) != 0)
{
return -10;
}
super.free_list_lba = current_lba;
/* Save updated superblock */
return disk_write(8, &super, 1);
}

View File

@ -0,0 +1,50 @@
#include <fs/duckfs.h>
#include <string.h>
#include <stdio.h>
extern int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer);
extern int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer);
static uint8_t duckfs_drive = 0;
void duckfs_set_drive(uint8_t drive)
{
duckfs_drive = drive;
}
int32_t disk_read(uint64_t lba, void* buffer, uint32_t count)
{
/* IDE spec only allows up to 256 sectors in one call */
while (count > 0)
{
uint8_t sectors = (count > 256) ? 256 : count;
int32_t result = ide_read48(duckfs_drive, lba, sectors, buffer);
if (result < 0)
{
return -1;
}
lba += sectors;
count -= sectors;
buffer = (void*)((uintptr_t)buffer + 512 * sectors);
}
return 0;
}
int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count)
{
while (count > 0)
{
uint8_t sectors = (count > 256) ? 256 : count;
int32_t result = ide_write48(duckfs_drive, lba, sectors, buffer);
if (result < 0)
{
return -1;
}
lba += sectors;
count -= sectors;
buffer = (const void*)((uintptr_t)buffer + 512 * sectors);
}
return 0;
}

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

@ -0,0 +1,248 @@
#include <drivers/ide.h>
#include <string.h>
#include <stdio.h>
#include <fs/fat16.h>
static fat16_t fat;
#pragma pack(push, 1)
typedef struct {
uint8_t jmp[3];
char oem[8];
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t fat_count;
uint16_t root_entries;
uint16_t total_sectors_short;
uint8_t media_desc;
uint16_t fat_size_sectors;
uint16_t sectors_per_track;
uint16_t heads;
uint32_t hidden_sectors;
uint32_t total_sectors_long;
// Extended Boot Record...
} fat16_bpb_t;
typedef struct {
char name[8];
char ext[3];
uint8_t attr;
uint8_t reserved;
uint8_t create_time_tenth;
uint16_t create_time;
uint16_t create_date;
uint16_t access_date;
uint16_t first_cluster_hi;
uint16_t write_time;
uint16_t write_date;
uint16_t first_cluster_lo;
uint32_t size;
} fat16_direntry_raw_t;
#pragma pack(pop)
static uint8_t sector_buffer[512];
uint32_t cluster_to_lba(uint16_t cluster)
{
return fat.data_start + ((cluster - 2) * fat.sectors_per_cluster);
}
int32_t fat16_init(uint8_t drive)
{
if (ide_read48(drive, 0, 1, sector_buffer) < 0)
{
return -1;
}
fat16_bpb_t* bpb = (fat16_bpb_t*)sector_buffer;
fat.drive = drive;
fat.bytes_per_sector = bpb->bytes_per_sector;
fat.sectors_per_cluster = bpb->sectors_per_cluster;
fat.root_entry_count = bpb->root_entries;
fat.fat_start = bpb->reserved_sectors;
fat.root_dir_start = fat.fat_start + bpb->fat_count * bpb->fat_size_sectors;
fat.data_start = fat.root_dir_start + ((bpb->root_entries * 32 + fat.bytes_per_sector - 1) / fat.bytes_per_sector);
fat.current_dir_cluster = 0;
return 0;
}
uint16_t fat16_get_fat_entry(uint16_t cluster)
{
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0)
{
return 0xFFFF;
}
return *(uint16_t*)&sector_buffer[ent_offset];
}
uint16_t fat16_alloc_cluster(void)
{
for (uint16_t cluster = 2; cluster < 0xFFF0; ++cluster) {
uint16_t entry = fat16_get_fat_entry(cluster);
if (entry == 0x0000) {
// Mark as end of chain
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0) return 0;
*(uint16_t*)&sector_buffer[ent_offset] = 0xFFFF;
if (ide_write48(fat.drive, fat_sector, 1, sector_buffer) < 0) return 0;
return cluster;
}
}
return 0;
}
int32_t fat16_list_dir(fat16_dir_entry_t* entries, size_t max_entries)
{
size_t count = 0;
if (fat.current_dir_cluster == 0)
{
uint16_t root_sectors = ((fat.root_entry_count * 32) + (fat.bytes_per_sector - 1)) / fat.bytes_per_sector;
for (uint32_t i = 0; i < root_sectors && count < max_entries; ++i)
{
if (ide_read48(fat.drive, fat.root_dir_start + i, 1, sector_buffer) < 0)
{
return -1;
}
fat16_direntry_raw_t* de = (fat16_direntry_raw_t*)sector_buffer;
for (int32_t j = 0; j < 512 / 32 && count < max_entries; ++j, ++de)
{
if (de->name[0] == 0x00 || de->name[0] == 0xE5)
{
continue;
}
memcpy(entries[count].name, de->name, 8);
entries[count].name[8] = '\0';
entries[count].attr = de->attr;
entries[count].cluster = de->first_cluster_lo;
entries[count].size = de->size;
count++;
}
}
}
/* TODO: Add support for listing subdirectories if current_dir_cluster != 0 */
return count;
}
int32_t fat16_read_file(const char* filename, void* buffer, size_t max_size) {
fat16_dir_entry_t entries[64];
int32_t n = fat16_list_dir(entries, 64);
for (int32_t i = 0; i < n; ++i) {
if (!(entries[i].attr & FAT16_ATTR_DIRECTORY) &&
strncmp(entries[i].name, filename, FAT16_MAX_FILENAME) == 0) {
uint16_t cluster = entries[i].cluster;
uint8_t* out = (uint8_t*)buffer;
size_t remaining = entries[i].size < max_size ? entries[i].size : max_size;
while (cluster >= 0x0002 && cluster < 0xFFF8 && remaining > 0) {
uint32_t lba = cluster_to_lba(cluster);
size_t to_read = fat.bytes_per_sector * fat.sectors_per_cluster;
if (ide_read48(fat.drive, lba, fat.sectors_per_cluster, sector_buffer) < 0)
return -1;
size_t copy_size = (remaining < to_read) ? remaining : to_read;
memcpy(out, sector_buffer, copy_size);
out += copy_size;
remaining -= copy_size;
cluster = fat16_get_fat_entry(cluster);
}
return (int32_t)(out - (uint8_t*)buffer);
}
}
return -1;
}
int32_t fat16_write_file(const char* filename, const void* data, size_t size) {
fat16_dir_entry_t entries[64];
int32_t n = fat16_list_dir(entries, 64);
for (int32_t i = 0; i < n; ++i) {
if (strncmp(entries[i].name, filename, FAT16_MAX_FILENAME) == 0) {
uint16_t cluster = entries[i].cluster;
const uint8_t* src = (const uint8_t*)data;
size_t remaining = size;
while (remaining > 0) {
uint32_t lba = cluster_to_lba(cluster);
size_t cluster_bytes = fat.sectors_per_cluster * fat.bytes_per_sector;
size_t to_write = remaining < cluster_bytes ? remaining : cluster_bytes;
memset(sector_buffer, 0, cluster_bytes); // Clear old data
memcpy(sector_buffer, src, to_write);
if (ide_write48(fat.drive, lba, fat.sectors_per_cluster, sector_buffer) < 0)
return -1;
src += to_write;
remaining -= to_write;
// Last chunk?
if (remaining == 0)
break;
// Check next cluster
uint16_t next = fat16_get_fat_entry(cluster);
if (next >= 0xFFF8 || next == 0x0000) {
// Need to allocate a new cluster
uint16_t new_cluster = fat16_alloc_cluster();
if (new_cluster == 0) return -1;
// Update FAT to point to new cluster
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0) return -1;
*(uint16_t*)&sector_buffer[ent_offset] = new_cluster;
if (ide_write48(fat.drive, fat_sector, 1, sector_buffer) < 0) return -1;
next = new_cluster;
}
cluster = next;
}
return (int32_t)size;
}
}
return -1;
}
int32_t fat16_change_dir(const char* dirname)
{
fat16_dir_entry_t entries[64];
int32_t n = fat16_list_dir(entries, 64);
for (int32_t i = 0; i < n; ++i)
{
if ((entries[i].attr & FAT16_ATTR_DIRECTORY) && strncmp(entries[i].name, dirname, FAT16_MAX_FILENAME) == 0)
{
fat.current_dir_cluster = entries[i].cluster;
return 0;
}
}
return -1;
}

View File

@ -37,7 +37,8 @@ int32_t fat32_init(int32_t drive)
{
fat32_drive = drive;
int err = ide_read48(drive, 0, 1, sector);
if (err != 0) {
if (err != 0)
{
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
return -1;
}
@ -47,52 +48,75 @@ int32_t fat32_init(int32_t drive)
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;
printf("========= Start FAT info =========\n");
printf("Bytes per sector: %u\n", bpb.bytes_per_sector);
printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster);
printf("Reserved sectors: %u\n", bpb.reserved_sector_count);
printf("Number of FATs: %u\n", bpb.num_fats);
printf("FAT size (32): %u\n", bpb.fat_size_32);
printf("Root cluster: %u\n", bpb.root_cluster);
printf("========= End FAT info =========\n");
return 0;
}
void print_83(const char *s) {
for (int i = 0; i < 11; i++) {
char c = s[i];
if (c >= 32 && c <= 126) {
printf("%c", c); // or your kernel's character output function
} else {
printf("\\x%02X", (unsigned char)c); // hex-escape non-printables
}
}
printf("\n");
}
static uint32_t cluster_to_lba(uint32_t cluster)
{
printf("cluster_heap_lba: %u\n", cluster_heap_lba);
return cluster_heap_lba + (cluster - 2) * bpb.sectors_per_cluster;
}
static void format_83_name(const char *input, char out[11]) {
memset(out, ' ', 11);
int i = 0, j = 0;
void format_83_name(const char* input, char* output)
{
printf("Input name: %s, Input length: %i\n", input, strlen(input));
// Copy name part (up to 8 chars)
while (input[i] && input[i] != '.' && j < 8) {
out[j++] = toupper((unsigned char)input[i++]);
memset(output, ' ', 11);
int32_t i = 0, j = 0;
while (input[i] && j < 11)
{
if (input[i] == '.')
{
j = 8;
i++;
continue;
}
if (j < 11)
{
output[j++] = toupper((unsigned char)input[i++]);
}
// Skip dot
if (input[i] == '.') i++;
// Copy extension (up to 3 chars)
int k = 8;
while (input[i] && j < 11) {
out[k++] = toupper((unsigned char)input[i++]);
j++;
}
}
static uint32_t find_free_cluster() {
// Read FAT sectors one by one
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++) {
static uint32_t find_free_cluster(void)
{
/* Read FAT sectors one by one */
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++)
{
uint32_t fat_sector = fat_start_lba + (cluster * 4) / 512;
uint32_t fat_offset = (cluster * 4) % 512;
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
{
return 0;
}
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
if (entry == 0x00000000) {
if (entry == 0x00000000)
{
return cluster;
}
}
@ -148,8 +172,19 @@ int32_t fat32_list_root(void)
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
{
uint32_t lba = cluster_to_lba(current_directory_cluster);
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
char formatted[11];
memset(formatted, 0xAB, sizeof(formatted));
format_83_name(name, formatted);
uint32_t dir_cluster = current_directory_cluster;
while (dir_cluster < 0x0FFFFFF8)
{
uint32_t lba = cluster_to_lba(dir_cluster);
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
{
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
@ -161,35 +196,34 @@ int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
{
break;
}
if ((uint8_t)entry[0] == 0xE5)
if ((uint8_t)entry[0] == 0xE5 || (uint8_t)entry[11] == 0x0F)
{
continue;
}
char entry_name[12];
memcpy(entry_name, entry, 11);
entry_name[11] = 0;
for (int32_t j = 0; j < 11; j++)
{
if (entry_name[j] == ' ')
{
entry_name[j] = 0;
}
}
printf("here\n");
if (strncmp(entry_name, name, 11) != 0)
char entry_name[12] = { '\0' };
memcpy((void*)entry_name, (void*)entry, 11);
int32_t err = memcmp(entry_name, formatted, (size_t)11);
if (err != 0)
{
printf("memcmp: %i\n", err);
continue;
}
/* File found */
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
uint32_t size = *(uint32_t *)(entry + 28);
uint32_t bytes_read = 0;
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
{
uint32_t lba = cluster_to_lba(cluster);
if (ide_read48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
uint32_t file_lba = cluster_to_lba(cluster);
if (ide_read48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
{
return -1;
}
@ -208,10 +242,266 @@ int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
return bytes_read;
}
return -2;
}
/* Next directory cluster */
uint32_t fat_sector = dir_cluster * 4 / 512;
uint32_t fat_offset = dir_cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
}
return -2; /* File not found */
}
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
{
uint8_t fat_sector_buf[512];
char formatted[11];
memset(formatted, 0xAB, sizeof(formatted));
format_83_name(name, formatted);
uint32_t dir_cluster = current_directory_cluster;
while (dir_cluster < 0x0FFFFFF8)
{
uint32_t lba = cluster_to_lba(dir_cluster);
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
{
// Read directory sector
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
// Find matching entry offset inside this sector
int32_t entry_offset = -1;
for (int32_t i = 0; i < 512; i += 32)
{
char *entry = (char *)&sector[i];
if ((uint8_t)entry[0] == 0x00)
{
break;
}
if ((uint8_t)entry[0] == 0xE5 || (uint8_t)entry[11] == 0x0F)
{
continue;
}
char entry_name[12] = {0};
memcpy(entry_name, entry, 11);
if (memcmp(entry_name, formatted, 11) == 0)
{
entry_offset = i;
break;
}
}
if (entry_offset == -1)
{
// Not found in this sector, continue to next
continue;
}
// Entry found, write file data clusters
uint8_t *entry = &sector[entry_offset];
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
uint32_t bytes_written = 0;
while (cluster < 0x0FFFFFF8 && bytes_written < len)
{
uint32_t file_lba = cluster_to_lba(cluster);
if (ide_write48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0)
{
return -1;
}
bytes_written += bpb.sectors_per_cluster * 512;
if (bytes_written < len)
{
// Read FAT sector for current cluster
uint32_t fat_sector = cluster * 4 / 512;
uint32_t fat_offset = cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
uint32_t next_cluster = find_free_cluster();
if (next_cluster == 0)
{
return -3; // No free cluster
}
*(uint32_t *)(fat_sector_buf + fat_offset) = next_cluster & 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
cluster = next_cluster;
}
else
{
// Mark end of cluster chain
uint32_t fat_sector = cluster * 4 / 512;
uint32_t fat_offset = cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
break;
}
}
// **Re-read the directory sector before updating file size**
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
// Update file size in directory entry again after re-read
entry = &sector[entry_offset];
*(uint32_t *)(entry + 28) = len;
// Write back updated directory sector
if (ide_write48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
// Debug print updated directory entry
printf("Directory entry after write (offset %d):\n", entry_offset);
for (int j = 0; j < 32; j++) {
uint8_t b = (uint8_t)entry[j];
printf("%02X ", b);
if ((j + 1) % 16 == 0) printf(" ");
}
printf("\n");
for (int j = 0; j < 32; j++) {
char c = entry[j];
printf("%c", (c >= 32 && c <= 126) ? c : '.');
}
printf("\n");
return bytes_written;
}
// Move to next cluster of the directory
uint32_t fat_sector = dir_cluster * 4 / 512;
uint32_t fat_offset = dir_cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
}
return -2; // File not found
}
int32_t fat32_create_file(const char *name)
{
uint8_t dir_sector[512];
uint8_t fat_sector_buf[512];
uint32_t root_lba = cluster_to_lba(current_directory_cluster);
if (ide_read48(fat32_drive, root_lba, 1, dir_sector) != 0)
{
return -1;
}
char formatted_name[11];
format_83_name(name, formatted_name);
for (int32_t i = 0; i < 512; i += 32)
{
uint8_t *entry = &dir_sector[i];
if (entry[0] == 0x00 || entry[0] == 0xE5)
{
printf("Writing entry at offset %d\n", i);
memset(entry, 0, 32);
memcpy(entry, formatted_name, 11);
entry[11] = 0x20;
uint32_t free_cluster = find_free_cluster();
if (free_cluster == 0)
{
return -2;
}
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
uint32_t fat_offset = (free_cluster * 4) % 512;
if (ide_read48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
/* Set first cluster */
entry[20] = (free_cluster >> 16) & 0xFF;
entry[21] = (free_cluster >> 24) & 0xFF;
entry[26] = free_cluster & 0xFF;
entry[27] = (free_cluster >> 8) & 0xFF;
/* File size = 0 */
memset(entry + 28, 0, 4);
if (ide_write48(fat32_drive, root_lba, 1, dir_sector) != 0)
{
return -1;
}
uint8_t temp[512];
ide_read48(fat32_drive, cluster_to_lba(bpb.root_cluster), 1, temp);
printf("Root directory cluster 2 dump (first 64 bytes):\n");
for (int i = 0; i < 64; i++) {
printf("%02X ", temp[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
return 0;
}
}
return -8;
}
int32_t fat32_create_directory(const char *name)
{
uint32_t lba = cluster_to_lba(current_directory_cluster);
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
@ -222,8 +512,55 @@ int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
for (int32_t i = 0; i < 512; i += 32)
{
char *entry = (char *)&sector[i];
if ((uint8_t)entry[0] == 0x00) break;
if ((uint8_t)entry[0] == 0xE5) continue;
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5)
{
memset(entry, 0, 32);
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
entry[11] = FAT32_ATTR_DIRECTORY;
uint32_t cluster = 6;
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
*(uint32_t *)(entry + 28) = 0;
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
{
return -1;
}
return 0;
}
}
return -2;
}
int32_t fat32_change_directory(const char *name)
{
uint32_t dir_cluster = current_directory_cluster;
while (dir_cluster < 0x0FFFFFF8)
{
uint32_t lba = cluster_to_lba(dir_cluster);
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
{
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
for (int32_t i = 0; i < 512; i += 32)
{
char *entry = (char *)&sector[i];
if ((uint8_t)entry[0] == 0x00)
{
break;
}
if ((uint8_t)entry[0] == 0xE5)
{
continue;
}
char entry_name[12];
memcpy(entry_name, entry, 11);
@ -241,187 +578,24 @@ int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
continue;
}
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
uint32_t bytes_written = 0;
while (cluster < 0x0FFFFFF8 && bytes_written < len)
{
uint32_t lba = cluster_to_lba(cluster);
if (ide_write48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0)
{
return -1;
}
bytes_written += bpb.sectors_per_cluster * 512;
if (bytes_written < len)
{
uint32_t fat_sector = cluster * 4 / 512;
uint32_t fat_offset = cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
uint32_t next_cluster = find_free_cluster();
if (next_cluster == 0)
{
return -3;
}
*(uint32_t *)(sector + fat_offset) = next_cluster & 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
cluster = next_cluster;
}
else
{
uint32_t fat_sector = cluster * 4 / 512;
uint32_t fat_offset = cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
*(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
break;
}
}
*(uint32_t *)(entry + 28) = len;
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
{
return -1;
}
return bytes_written;
}
return -2;
}
int32_t fat32_create_file(const char *name) {
uint32_t root_lba = cluster_to_lba(bpb.root_cluster);
// Read root directory cluster sector (assuming 1 sector here for simplicity)
if (ide_read48(fat32_drive, root_lba, 1, sector) != 0)
return -1;
char formatted_name[11];
format_83_name(name, formatted_name);
for (int32_t i = 0; i < 512; i += 32) {
uint8_t *entry = &sector[i];
if (entry[0] == 0x00 || entry[0] == 0xE5) {
// Found free directory entry, clear it
memset(entry, 0, 32);
// Copy formatted filename
memcpy(entry, formatted_name, 11);
// Set attributes to Archive (normal file)
entry[11] = 0x20;
// Allocate first cluster for the file
uint32_t free_cluster = find_free_cluster();
if (free_cluster == 0) {
return -2; // No free cluster
}
// Mark cluster as end-of-chain in FAT
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
uint32_t fat_offset = (free_cluster * 4) % 512;
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
return -1;
*(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF; // end of cluster chain
if (ide_write48(fat32_drive, fat_sector, 1, sector) != 0)
return -1;
// Set first cluster in directory entry (split high and low 16 bits)
entry[20] = (free_cluster >> 16) & 0xFF;
entry[21] = (free_cluster >> 24) & 0xFF;
entry[26] = free_cluster & 0xFF;
entry[27] = (free_cluster >> 8) & 0xFF;
// Set file size = 0
entry[28] = 0;
entry[29] = 0;
entry[30] = 0;
entry[31] = 0;
// Write back directory sector
if (ide_write48(fat32_drive, root_lba, 1, sector) != 0)
return -1;
return 0; // Success
}
}
return -3; // No free directory entry found
}
int32_t fat32_create_directory(const char *name) {
uint32_t lba = cluster_to_lba(current_directory_cluster);
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
return -1;
for (int32_t i = 0; i < 512; i += 32) {
char *entry = (char *)&sector[i];
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5) {
memset(entry, 0, 32);
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
entry[11] = FAT32_ATTR_DIRECTORY;
uint32_t cluster = 6;
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
*(uint32_t *)(entry + 28) = 0;
if (ide_write48(fat32_drive, lba, 1, sector) != 0)
return -1;
return 0;
}
}
return -2;
}
int32_t fat32_change_directory(const char *name) {
uint32_t lba = cluster_to_lba(current_directory_cluster);
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
return -1;
for (int32_t i = 0; i < 512; i += 32) {
char *entry = (char *)&sector[i];
if ((uint8_t)entry[0] == 0x00) break;
if ((uint8_t)entry[0] == 0xE5) continue;
char entry_name[12];
memcpy(entry_name, entry, 11);
entry_name[11] = 0;
for (int32_t j = 0; j < 11; j++)
if (entry_name[j] == ' ') entry_name[j] = 0;
if (strncmp(entry_name, name, 11) != 0) continue;
if (!(entry[11] & FAT32_ATTR_DIRECTORY))
{
return -2;
}
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
return 0;
}
}
uint32_t fat_sector = dir_cluster * 4 / 512;
uint32_t fat_offset = dir_cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
return -1;
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
}
return -3;
}

View File

@ -1,8 +1,8 @@
#include <fs/ramfs.h>
/*#include <fs/fat16.h>
#include <stdlib.h>
#include <string.h>
#include <fs/vfs.h>
#include <fs/vfs.h>*/
/*
@ -11,7 +11,7 @@
-33 means stdout (which can be read)
*/
bool vfs_initialized = false;
/*bool vfs_initialized = false;
ramfs_file_header_t* vfs_current_dir = NULL;
void vfs_init(void)
@ -27,204 +27,4 @@ void vfs_init(void)
}
}
/* ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent); */
FILE create_file(char* filename, char type, char encryption, FILE parent)
{
if (!filename)
{
return -1;
}
if (parent == -128)
{
parent = vfs_current_dir->fd;
}
ramfs_file_header_t* file = ramfs_create_file(filename, type, encryption, ramfs_resolve_fd(parent));
if (!file)
{
return -4; /* error code for failed creation */
}
return file->fd;
}
int32_t delete_file(FILE file)
{
/*
XXX WARNING: ANY AND ALL PROCESSES CAN DELETE A FILE VIA THIS INTERFACE!!! XXX
XXX THIS MUST BE PACHED SOON!!! OR AT LEAST ADD PERMISSION CHECKING IN THE SYSCALL INTERFACE XXX
XXX OR IN THE C LIBRARIES!!! XXX
*/
if (file < 1)
{
return -4;
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
return ramfs_delete_file(_file);
}
/*
Open a file based on a string.
Return a file descriptor on success, a negative value on failure.
return values:
(positive non-zero value) - File descriptor
-1 - Insufficient permissions to open file
-2 - File does not exist ( or at least, File not found. )
-3 - No filesystem is initialized
-4 - Internal error, perhaps try again
*/
FILE open_file(char* filename)
{
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_path(filename);
if (!_file)
{
return (FILE)-2;
}
return (FILE)_file->fd;
}
return (FILE)-3;
}
FILE write_file(FILE file, void* data, size_t len)
{
if (file < 1 || !data || len == 0)
{
return file;
}
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file)
{
return -4;
}
if (_file->type == RAMFS_FILE_DIR)
{
return -1;
}
if (_file->data_begin)
{
free(_file->data_begin);
_file->data_begin = NULL;
_file->data_end = NULL;
}
void* new_buf = malloc(len);
if (!new_buf)
{
return -2;
}
memcpy(new_buf, data, len);
_file->data_begin = new_buf;
_file->data_end = (void*)((uint8_t*)new_buf + len);
return file;
}
return -3;
}
int32_t read_file(FILE file, void* buf, size_t buflen)
{
if (file < 1 || !buf || buflen == 0)
{
return -1; /* Invalid arguments */
}
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file || _file->type == RAMFS_FILE_DIR)
{
return -2; /* Not a file or trying to read a directory */
}
if (!_file->data_begin || !_file->data_end)
{
return 0; /* Empty file */
}
size_t total_len = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
if (_file->read_offset >= (int32_t)total_len)
{
return 0; /* End of file */
}
size_t available = total_len - _file->read_offset;
size_t to_copy = (buflen < available) ? buflen : available;
memcpy(buf, (uint8_t*)_file->data_begin + _file->read_offset, to_copy);
_file->read_offset += to_copy;
return (int32_t)to_copy;
}
return -3; /* FS not initialized */
}
int32_t reset_read_offset(FILE file)
{
if (file < 1)
{
return -1;
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file)
{
return -2;
}
_file->read_offset = 0;
return 0;
}
int32_t seek_file(FILE file, int32_t offset)
{
if (file < 0 && file != -32 && file != -33)
{
return -1; /* Invalid file descriptor */
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file || _file->type == RAMFS_FILE_DIR)
return -2; // Invalid file or directory
if (!_file->data_begin || !_file->data_end)
return -3; // Empty file
size_t file_size = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
if (offset < 0 || (size_t)offset > file_size)
return -4; // Offset out of bounds
_file->read_offset = offset;
return 0; // Success
}

View File

@ -17,7 +17,7 @@ static int32_t ide_wait(uint16_t io, int32_t check_drq)
return 0;
}
}
pit_sleep(4);
pit_sleep(2);
}
return 1;
}
@ -35,9 +35,8 @@ static int32_t ide_wait_ready(uint16_t io)
return 1;
}
int32_t ide_identify(uint8_t drive, uint16_t* buffer) {
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
{
uint16_t io = ATA_PRIMARY_IO;
uint8_t slave_bit = (drive & 1) << 4;
@ -47,24 +46,32 @@ int32_t ide_identify(uint8_t drive, uint16_t* buffer) {
outb(io + ATA_REG_LBA0, 0);
outb(io + ATA_REG_LBA1, 0);
outb(io + ATA_REG_LBA2, 0);
outb(io + ATA_REG_COMMAND, 0xEC); // IDENTIFY DEVICE
outb(io + ATA_REG_COMMAND, 0xEC); /* IDENTIFY DEVICE command */
uint8_t status = inb(io + ATA_REG_STATUS);
if (status == 0) return -1; // No device
if (status == 0)
{
return -1; /* No device */
}
if (ide_wait(io, 1)) return -2;
if (ide_wait(io, 1))
{
return -2;
}
insw(io + ATA_REG_DATA, buffer, 256); // Read 512 bytes
insw(io + ATA_REG_DATA, buffer, 256); /* Read 512 bytes */
return 0;
}
void ide_initialize(void) {
outb(ATA_PRIMARY_CTRL, 0x02); // Disable IRQs
outb(ATA_PRIMARY_CTRL, 0x02); /* Disable IRQs from IDE disk controllers TODO: should probably use IRQs soon */
uint16_t identify_buf[256];
if (ide_identify(0, identify_buf) == 0) {
if (ide_identify(0, identify_buf) == 0)
{
char model[41];
for (int i = 0; i < 20; ++i) {
for (int i = 0; i < 20; ++i)
{
model[i * 2 + 0] = identify_buf[27 + i] >> 8;
model[i * 2 + 1] = identify_buf[27 + i] & 0xFF;
}
@ -74,40 +81,49 @@ void ide_initialize(void) {
}
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
if (sector_count == 0) return -1;
if (sector_count == 0)
{
return -1;
}
uint16_t io = ATA_PRIMARY_IO;
uint8_t slave_bit = (drive & 1) << 4;
ide_wait(io, 0); // Wait for BSY to clear
ide_wait(io, 0); /* Wait for BSY to clear */
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); /* Select drive */
// High bytes (use 0xC2 - 0xC6 offsets if you define them separately)
outb(io + 6, (sector_count >> 8) & 0xFF); // Sector Count High
outb(io + 7, (lba >> 40) & 0xFF); // LBA[47:40]
outb(io + 8, (lba >> 32) & 0xFF); // LBA[39:32]
outb(io + 9, (lba >> 24) & 0xFF); // LBA[31:24]
// Low bytes
outb(io + 2, sector_count & 0xFF); // Sector Count Low
outb(io + 3, (lba >> 0) & 0xFF); // LBA[7:0]
outb(io + 4, (lba >> 8) & 0xFF); // LBA[15:8]
outb(io + 5, (lba >> 16) & 0xFF); // LBA[23:16]
outb(io + ATA_REG_SECCOUNT0, (sector_count >> 8) & 0xFF); /* high count */
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); /* LBA5 */
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); /* LBA4 */
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); /* LBA3 */
outb(io + ATA_REG_SECCOUNT0, sector_count & 0xFF); /* low count */
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); /* LBA0 */
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); /* LBA1 */
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); /* LBA2 */
outb(io + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS_EXT);
uint16_t* ptr = (uint16_t*)buffer;
for (int i = 0; i < sector_count; i++) {
if (ide_wait(io, 1)) {
for (int i = 0; i < sector_count; i++)
{
if (ide_wait(io, 1))
{
uint8_t status = inb(io + ATA_REG_STATUS);
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
return -2;
}
uint8_t status = inb(io + ATA_REG_STATUS);
if (status & ATA_SR_ERR) return -3;
if (status & ATA_SR_ERR)
{
return -3;
}
insw(io + ATA_REG_DATA, ptr, 256);
ptr += 256;
@ -117,60 +133,69 @@ int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buff
}
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) {
if (sector_count == 0) return -1;
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer)
{
if (sector_count == 0)
{
return -1;
}
uint16_t io = ATA_PRIMARY_IO;
uint8_t slave_bit = (drive & 1) << 4;
ide_wait(io, 0); // Wait for BSY to clear
ide_wait(io, 0); /* Wait for BSY to clear */
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); /* Select drive */
// Send high bytes of sector count and LBA first
/* Send high bytes of sector count and LBA first */
outb(io + ATA_REG_SECCOUNT0, 0); // Sector count high byte
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); // LBA[47:40]
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); // LBA[39:32]
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); // LBA[31:24]
// Send low bytes
/* Send low bytes */
outb(io + ATA_REG_SECCOUNT0, sector_count); // Sector count low byte
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); // LBA[7:0]
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); // LBA[15:8]
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
// Send write command
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); // 0x34
/* Send write command */
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); /* 0x34 */
const uint16_t* ptr = (const uint16_t*)buffer;
for (int i = 0; i < sector_count; i++) {
if (ide_wait(io, 1)) {
for (int i = 0; i < sector_count; i++)
{
if (ide_wait(io, 1))
{
uint8_t status = inb(io + ATA_REG_STATUS);
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
return -2;
}
// Check for drive error
/* Check for drive error */
uint8_t status = inb(io + ATA_REG_STATUS);
if (status & ATA_SR_ERR) return -3;
if (status & ATA_SR_ERR)
{
return -3;
}
outsw(io + ATA_REG_DATA, ptr, 256); // 256 words = 512 bytes
outsw(io + ATA_REG_DATA, ptr, 256); /* 256 words = 512 bytes */
inb(io + ATA_REG_STATUS); /* Dummy read */
ptr += 256;
}
// Wait for BSY=0 before issuing FLUSH CACHE
if (ide_wait_ready(io)) return -5;
outb(io + ATA_REG_COMMAND, 0xE7); // FLUSH CACHE
/* Wait for BSY=0 before issuing FLUSH CACHE */
if (ide_wait_ready(io))
{
return -5;
}
outb(io + ATA_REG_COMMAND, 0xE7);
if (ide_wait(io, 0)) {
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
return -4;
}
return 0;
}

View File

@ -53,7 +53,7 @@ void exception_dispatcher(uint32_t int_no, uint32_t err_code)
case 14:
{
uint32_t cr2;
__asm__ volatile ("mov %%cr2, %0" : "=r"(cr2));
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
break;
}
@ -70,7 +70,13 @@ void exception_dispatcher(uint32_t int_no, uint32_t err_code)
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
__asm__ volatile ("cli; hlt");
asm volatile ("cli; hlt");
/* Will never be reached */
while (true)
{
asm volatile ("hlt" ::: "memory");
}
}
@ -89,29 +95,29 @@ void pic_remap(void)
{
uint8_t a1, a2;
// Save masks
/* Save masks */
a1 = inb(PIC1_DATA);
a2 = inb(PIC2_DATA);
// Start initialization sequence (in cascade mode)
/* 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)
/* 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)
/* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */
outb(PIC1_DATA, 0x04);
// Tell Slave PIC its cascade identity (0000 0010)
/* Tell Slave PIC its cascade identity (0000 0010) */
outb(PIC2_DATA, 0x02);
// Set 8086/88 mode
/* Set 8086/88 mode */
outb(PIC1_DATA, 0x01);
outb(PIC2_DATA, 0x01);
// Restore saved masks
/* Restore saved masks */
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
}
@ -135,7 +141,7 @@ void idt_init(void)
}
__asm__ volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
__asm__ volatile ("sti"); /* set the interrupt flag */
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
asm volatile ("sti"); /* set the interrupt flag */
}

View File

@ -79,7 +79,7 @@ static void append_char(char c)
{
if (current_length + 1 >= capacity)
{
/* Need more space (+1 for '\0') */
/* Need more space (+1 for the null zero) */
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
char* new_str = (char*)malloc(new_capacity);
@ -93,6 +93,11 @@ static void append_char(char c)
free(current_string);
}
if (!current_string)
{
return;
}
current_string = new_str;
capacity = new_capacity;
}
@ -148,6 +153,12 @@ void keyboard_handler(void) {
c = (char) terminal_get_shifted((unsigned char) c);
}
if (scancode == 0x1C) {
printf("\n");
return;
}
if (c)
{
current_char = c;
@ -164,3 +175,4 @@ void keyboard_handler(void) {
}
}
}

View File

@ -84,7 +84,7 @@ void terminal_putchar(const char c)
{
terminal_row -= 1;
if (terminal_row <= -1)
if (terminal_row == (size_t)-1)
{
terminal_row = 0;
}
@ -246,3 +246,4 @@ unsigned char terminal_get_shifted(unsigned char uc)
return '\0';
}

View File

@ -1,3 +1,4 @@
menuentry "Espresso" {
multiboot /boot/espresso.bin
multiboot /boot/espresso.elf
}

45
include/drivers/elf.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef _ELF_H
#define _ELF_H
#include <types.h>
#define EI_NIDENT 16
#define PT_NULL 0
#define PT_LOAD 1
typedef struct {
unsigned char e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry;
uint32_t e_phoff;
uint32_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} Elf32_Ehdr;
typedef struct {
uint32_t p_type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
} Elf32_Phdr;
typedef struct {
void* entry_point;
} elf_executable_t;
elf_executable_t* load_elf32(void* elf_data);
#endif

View File

@ -0,0 +1,8 @@
#ifndef _ELF_LOADER_H
#define _ELF_LOADER_H
#include <types.h>
#endif

View File

@ -3,6 +3,52 @@
#include <types.h>
void duckfs_init(void);
#define DUCKFS_MAGIC "DUCKFS1"
#define DUCKFS_NAME_LEN 32
typedef enum { DUCKFS_TYPE_FILE = 0, DUCKFS_TYPE_DIR = 1, DUCKFS_TYPE_SYMLINK = 2 } duckfs_type_t;
typedef struct {
char name[DUCKFS_NAME_LEN];
duckfs_type_t type;
uint8_t permissions; /* rwxrwxrwx packed into 9 bits */
uint16_t uid;
uint16_t gid;
uint64_t size;
uint64_t created;
uint64_t modified;
uint64_t first_block_lba;
uint64_t next_file_lba;
uint64_t child_lba; /* only for directories */
} __attribute__((packed)) duckfs_file_header_t;
typedef struct {
char magic[8]; /* "DUCKFS1\0" */
uint32_t block_size;
uint64_t total_blocks;
uint64_t root_header_lba;
uint64_t free_list_lba;
uint32_t fs_version;
} __attribute__((packed)) duckfs_superblock_t;
struct free_block {
uint64_t next;
};
/* DuckFS API */
int32_t duckfs_mount(void);
int32_t duckfs_find(const char* path, duckfs_file_header_t* out);
int32_t duckfs_create_file(const char* name, const void* content, size_t size, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir);
int32_t duckfs_create_dir(const char* name, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir);
int32_t duckfs_delete_file(const char* name, duckfs_file_header_t* parent_dir);
int32_t duckfs_delete_dir(const char* name, duckfs_file_header_t* parent_dir);
int32_t duckfs_read_file(const duckfs_file_header_t* file, void* buffer, size_t size);
int32_t duckfs_write_data(duckfs_file_header_t* file, const void* data, size_t offset, size_t length);
int32_t duckfs_append_data(duckfs_file_header_t* file, const void* data, size_t length);
int32_t duckfs_truncate(duckfs_file_header_t* file, size_t new_size);
#endif

38
include/fs/fat16.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef _FAT16_H
#define _FAT16_H
#include <types.h>
#define FAT16_MAX_FILENAME 256
#define FAT16_ATTR_DIRECTORY 0x10
typedef struct {
uint8_t drive;
uint32_t fat_start;
uint32_t root_dir_start;
uint32_t data_start;
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t root_entry_count;
uint32_t current_dir_cluster;
} fat16_t;
typedef struct {
char name[FAT16_MAX_FILENAME];
uint8_t attr;
uint32_t cluster;
uint32_t size;
} fat16_dir_entry_t;
int32_t fat16_init(uint8_t drive);
uint32_t cluster_to_lba(uint16_t cluster);
uint16_t fat16_get_fat_entry(uint16_t cluster);
uint16_t fat16_alloc_cluster(void);
int32_t fat16_list_dir(fat16_dir_entry_t* entries, size_t max_entries);
int32_t fat16_change_dir(const char* dirname);
int32_t fat16_read_file(const char* filename, void* buffer, size_t max_size);
int32_t fat16_write_file(const char* filename, const void* data, size_t size);
#endif

View File

@ -8,10 +8,15 @@
int32_t fat32_init(int32_t drive); /* 0 = primary master */
int32_t fat32_list_root(void);
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len);
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len);
int32_t fat32_create_file(const char *name);
int32_t fat32_create_directory(const char *name);
int32_t fat32_change_directory(const char *name);
void format_83_name(const char* input, char* output);
#endif

View File

@ -5,16 +5,6 @@
typedef int32_t FILE;
void vfs_init(void);
FILE create_file(char* filename, char type, char encryption, FILE parent);
int32_t delete_file(FILE file);
FILE open_file(char* filename);
FILE write_file(FILE file, void* data, size_t len);
int32_t read_file(FILE file, void* buf, size_t buflen);
int32_t reset_read_offset(FILE file);
#endif

44
include/kernel/kconfig.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef _KCONFIG_H
#define _KCONFIG_H
#include <types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ENABLE_DEBUGGING_MESSAGES
//#define ENABLE_FILESYSTEMS
#define ENABLE_IDE
//#define ENABLE_USB
//#define ENABLE_NETWORK
static inline kconf_t get_kconfig(void)
{
kconf_t kc = { false, false, false, false, false };
#ifdef ENABLE_DEBUGGING_MESSAGES
kc.enable_debug = true;
#endif
#ifdef ENABLE_FILESYSTEMS
kc.enable_fs = true;
#endif
#ifdef ENABLE_IDE
kc.enable_ide = true;
#endif
#ifdef ENABLE_USB
kc.enable_usb = true;
#endif
#ifdef ENABLE_NETWORK
kc.enable_networking = true;
#endif
return kc;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -9,10 +9,4 @@ typedef struct {
uint32_t mantissa; /* 23 bits stored (MSB implicit for normalized numbers) */
} soft_float32_t;
typedef struct {
uint8_t sign; /* 0 = positive, 1 = negative */
uint16_t exponent; /* 11-bit biased exponent (bias = 1023) */
uint64_t mantissa; /* 52 bits stored (MSB implicit for normalized numbers) */
} soft_float64_t;
#endif

View File

@ -1,7 +1,7 @@
#ifndef _PMM_H
#define _PMM_H
#include <stdint.h>
#include <types.h>
#include <multiboot.h>
void pmm_init(multiboot_info_t* mb_info);

View File

@ -1,19 +1,19 @@
#ifndef _PROCESSES_H
#define _PROCESSES_H
#include <stdint.h>
#include <types.h>
#include <drivers/elf.h>
typedef struct process {
int32_t id;
int32_t group;
struct process
{
uint16_t id;
uint8_t policy;
uint16_t priority;
char name[16];
elf_executable_t* exe;
struct process* next;
};
} process_t;
int32_t make_process(char* name, char* group, elf_executable_t* exe);
#endif

View File

@ -3,14 +3,15 @@
#include <types.h>
/* TODO: change all applicable 'int32_t's with 'size_t's. */
/* TODO: change all applicable `int32_t`s with `size_t`s. */
size_t strlen(const char* str);
size_t strcmp(const char *s1, const char *s2);
int32_t strcmp(const char *s1, const char *s2);
int32_t strncmp(const char *s1, const char *s2, size_t n);
size_t strcpy(char *dst, const char *src);
char *strncpy(char *dest, const char *src, uint32_t n);
void strcat(char *dest, const char *src);
int32_t strcasecmp(const char* s1, const char* s2);
char* strcpy(char *dst, const char *src);
char* strncpy(char *dest, const char *src, uint32_t n);
char* strcat(char *dest, const char *src);
char* strdup(const char* s);
char* strtok(char* str, const char* delim);
char* strchr(const char* s, int c);
@ -19,12 +20,14 @@ int32_t ischar(int32_t c);
int32_t isspace(char c);
int32_t isalpha(char c);
char upper(char c);
char lower(char c);
char toupper(char c);
char lower(char c);
void *memset(void *dst, char c, uint32_t n);
void *memcpy(void *dst, const void *src, uint32_t n);
int32_t memcmp(uint8_t *s1, uint8_t *s2, uint32_t n);
int32_t memcmp(const void *s1, const void *s2, size_t n);
void* memclr(void* m_start, size_t m_count);
#endif

8
include/time.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _TIME_H
#define _TIME_H
#include <types.h>
void ksleep(uint64_t millis);
#endif

View File

@ -1,97 +0,0 @@
[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

6
kernel/E.txt Normal file
View File

@ -0,0 +1,6 @@
________
|
|______
|
|
________

View File

@ -53,17 +53,16 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
const char* espresso_kernel_version = "0.0.0f";
/* We need to initialize the terminal so that any error/debuging messages show. */
/* We need to initialize the terminal so that any error/debugging 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*/
/* Make sure the magic number matches for memory mapping */
if(magic != MULTIBOOT_BOOTLOADER_MAGIC)
{
printf("[ ERROR ] invalid magic number!\n");
_hang_asm();
}
@ -79,7 +78,6 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
pic_remap();
idt_init();
/*pit_init(1000); 1000 Hz = 1ms tick */
_sti_asm();
terminal_setcolor(VGA_COLOR_GREEN);
@ -121,14 +119,14 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
printd("AHCI initialized\n");
*/
printd("Initializing VFS...\n");
vfs_init();
printd("VFS initialized.\n");
printd("Initializing IDE system...\n");
ide_initialize();
printd("IDE initialized\n");
/*printd("Initializing fat16...\n");
fat16_init(0);
printd("fat16 initialized.\n");*/
/*printd("Initializing DuckFS...\n");
duckfs_init();
printd("DuckFS initialized\n");*/
@ -147,43 +145,9 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
/*pit_sleep(4000);
begin_anim(espresso_kernel_version);*/
printf("Creating file via VFS...\n");
FILE file = create_file("test.txt", 't', 'n', -128);
printf("file = %d\n", file);
char buf[32] = "Hello from VFS";
char bufr[32] = { 0 };
write_file(file, buf, strlen(buf));
read_file(file, bufr, sizeof(bufr));
printf("Read data: %s\n", bufr);
/*printf("Creating file...\n");
ramfs_file_header_t* fil = ramfs_create_file("text", "txt", 't', 'n', ramfs_get_root());
if (!fil)
{
printf("File creation failed!\n");
return;
}
printf("File created\n");
char buf[32] = "hello from RAMFS";
char bufr[32] = { 0 };
ramfs_write_file(fil, buf, strlen(buf));
ramfs_read_file(fil, bufr, sizeof(bufr));
printf("Read data: %s\n", bufr);*/
printf("Guten tag and welcome to Espresso\n");
while (true)
{

View File

@ -15,12 +15,3 @@ soft_float32_t decode_float(uint32_t raw)
f.mantissa = raw & 0x7FFFFF;
return f;
}
soft_float64_t decode_double(uint64_t raw)
{
soft_float64_t d;
d.sign = (raw >> 63) & 1;
d.exponent = (raw >> 52) & 0x7FF;
d.mantissa = raw & 0xFFFFFFFFFFFFF;
return d;
}

View File

@ -1,5 +1,15 @@
#include <stdint.h>
#include <processes.h>
int32_t next_id = 9; /* 0 through 8 are reserved for kernel operations */
int32_t make_process(char* name, char* group, elf_executable_t* exe)
{
if (!name || !group || !exe)
{
return -1;
}
return 0;
}

View File

@ -37,7 +37,7 @@ char* fgets(char* buf, int n, FILE file)
while (total_read < n - 1)
{
int bytes = read_file(file, &c, 1);
int bytes = 0/*read_file(file, &c, 1)*/;
if (bytes <= 0)
{

View File

@ -1,32 +1,33 @@
#include <stdlib.h>
#include <stdio.h>
#include <vector_extentions/sse.h>
#include <string.h>
extern int16_t sse_initialized;
extern int32_t sse_initialized;
size_t strlen(const char* str)
{
size_t len = 0;
while (str[len]) len++;
while (str[len])
{
len++;
}
return len;
}
size_t strcmp(const char *s1, const char *s2)
int32_t strcmp(const char *s1, const char *s2)
{
int32_t i = 0;
while ((s1[i] == s2[i]))
while (*s1 && (*s1 == *s2))
{
if (s2[i++] == 0)
{
return 0;
s1++;
s2++;
}
}
return 1;
return (unsigned char)*s1 - (unsigned char)*s2;
}
int32_t strncmp(const char *s1, const char *s2, size_t n)
{
while (n--)
@ -45,16 +46,36 @@ int32_t strncmp(const char *s1, const char *s2, size_t n)
return 0;
}
size_t strcpy(char *dst, const char *src)
int32_t strcasecmp(const char* s1, const char* s2)
{
int32_t i = 0;
while ((*dst++ = *src++) != 0)
i++;
return i;
unsigned char c1, c2;
while (*s1 && *s2)
{
c1 = lower((unsigned char)*s1);
c2 = lower((unsigned char)*s2);
if (c1 != c2)
{
return c1 - c2;
}
s1++;
s2++;
}
return lower((unsigned char)*s1) - lower((unsigned char)*s2);
}
char *strncpy(char *dest, const char *src, uint32_t n)
char* strcpy(char *dst, const char *src)
{
char *ret = dst;
while ((*dst++ = *src++) != 0);
return ret;
}
char* strncpy(char *dest, const char *src, uint32_t n)
{
if (sse_initialized > 0)
{
@ -63,22 +84,31 @@ char *strncpy(char *dest, const char *src, uint32_t n)
uint32_t i = 0;
for (; i < n && src[i]; ++i)
{
dest[i] = src[i];
}
for (; i < n; ++i)
{
dest[i] = '\0';
}
return dest;
}
void strcat(char *dest, const char *src)
char* strcat(char *dest, const char *src)
{
char *end = (char *)dest + strlen(dest);
memcpy((void *)end, (void *)src, strlen(src));
end = end + strlen(src);
char *end = dest + strlen(dest);
while (*src)
{
*end++ = *src++;
}
*end = '\0';
return dest;
}
char* strdup(const char* s)
{
if (!s)
@ -155,43 +185,54 @@ char* strchr(const char* s, int c)
void *memset(void *dst, char c, uint32_t n)
void* memset(void *dst, char c, uint32_t n)
{
char *temp = dst;
for (; n != 0; n--) *temp++ = c;
for (; n != 0; n--)
{
*temp++ = c;
}
return dst;
}
void *memcpy(void *dst, const void *src, uint32_t n)
void* memcpy(void *dst, const void *src, uint32_t n)
{
if (sse_initialized > 0)
if (sse_initialized > 1)
{
return sse2_memcpy(dst, src, n);
}
char *ret = dst;
char *p = dst;
const char *q = src;
while (n--)
*p++ = *q++;
return ret;
}
int32_t memcmp(uint8_t *s1, uint8_t *s2, uint32_t n)
{
char *d = dst;
const char *s = src;
while (n--)
{
if (*s1 != *s2)
return 0;
s1++;
s2++;
*d++ = *s++;
}
return 1;
return dst;
}
void* memclr(const void * const m_start, const size_t m_count)
int32_t memcmp(const void *s1, const void *s2, size_t n)
{
if (sse_initialized > 0)
const uint8_t *p1 = (const uint8_t *)s1;
const uint8_t *p2 = (const uint8_t *)s2;
printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);
for (size_t i = 0; i < n; i++)
{
if (p1[i] != p2[i])
{
return (int32_t)p1[i] - (int32_t)p2[i];
}
}
return 0;
}
void* memclr(void* m_start, size_t m_count)
{
if (sse_initialized > 1)
{
return memclr_sse2(m_start, m_count);
}
@ -215,13 +256,6 @@ int32_t ischar(int32_t c)
}
char upper(char c)
{
if ((c >= 'a') && (c <= 'z'))
return (c - 32);
return c;
}
char toupper(char c)
{
if ((c >= 'a') && (c <= 'z'))
{
@ -233,6 +267,18 @@ char toupper(char c)
char lower(char c)
{
if ((c >= 'A') && (c <= 'Z'))
{
return (c + 32);
}
return c;
}
char toupper(char c)
{
return upper(c);
}
char tolower(char c)
{
return lower(c);
}

10
lib/time.c Normal file
View File

@ -0,0 +1,10 @@
#include <drivers/pit.h>
#include <port_io.h>
#include <time.h>
void ksleep(uint64_t millis)
{
pit_sleep(millis);
}

View File

@ -7,7 +7,8 @@
#include <vector_extentions/sse.h>
void enable_sse(void) {
void enable_sse(void)
{
uint32_t cr0, cr4;
__asm__ volatile ("mov %%cr0, %0" : "=r"(cr0));
@ -23,7 +24,8 @@ void enable_sse(void) {
// Basic SSE test: add two arrays of 4 floats using xmm registers
__attribute__((force_align_arg_pointer))
int32_t test_sse(void) {
int32_t test_sse(void)
{
float a[4] __attribute__((aligned(16))) = {1.0f, 2.0f, 3.0f, 4.0f};
float b[4] __attribute__((aligned(16))) = {5.0f, 6.0f, 7.0f, 8.0f};
float result[4] __attribute__((aligned(16)));
@ -141,7 +143,8 @@ char *sse2_strncpy(char *dest, const char *src, uint32_t n)
uint32_t i = 0;
/* Align initial copy */
while (((uintptr_t)(dest + i) & 15) && i < n && src[i]) {
while (((uintptr_t)(dest + i) & 15) && i < n && src[i])
{
dest[i] = src[i];
i++;
}

5
scripts/.config Normal file
View File

@ -0,0 +1,5 @@
Enable Debug=n
Enable Filesystem=y
Enable AHCI=y
Enable USB=n
Enable Network=n

296
scripts/kconfig.c Normal file
View File

@ -0,0 +1,296 @@
#include <ncurses.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
typedef struct {
const char* name;
int enabled;
} option_t;
typedef struct {
const char* title;
option_t* options;
size_t num_options;
} menu_t;
void show_menu(menu_t* menu);
void load_config(menu_t* menus, size_t menu_count);
void save_config(menu_t* menus, size_t menu_count);
#define SIZE(x) (sizeof(x) / sizeof(option_t))
#define NUM_MENUS (sizeof(all_menus) / sizeof(menu_t))
#define KEY_ESCAPE 27
option_t general_opts[] = {
{ "Enable Debugging Messages", 1 },
{ "Enable Filesystems", 0 },
};
option_t drivers_opts[] = {
{ "Enable IDE", 1 },
{ "Enable USB", 0 },
{ "Enable Network", 0 },
};
menu_t all_menus[] = {
{ "General Settings", general_opts, SIZE(general_opts) },
{ "Device Drivers", drivers_opts, SIZE(drivers_opts) },
};
bool current_config_saved = false;
void strfix(char *str)
{
for (size_t i = 0; str[i] != '\0'; ++i)
{
if (isspace((unsigned char)str[i]))
{
str[i] = '_';
}
else
{
str[i] = toupper((unsigned char)str[i]);
}
}
}
void load_config(menu_t* menus, size_t menu_count)
{
FILE* f = fopen(".config", "r");
if (!f)
{
return;
}
char line[128];
while (fgets(line, sizeof(line), f))
{
char* newline = strchr(line, '\n');
if (newline)
{
*newline = 0;
}
for (size_t m = 0; m < menu_count; m++)
{
for (size_t i = 0; i < menus[m].num_options; i++)
{
if (strncmp(line, menus[m].options[i].name, strlen(menus[m].options[i].name)) == 0)
{
if (strstr(line, "=y"))
{
menus[m].options[i].enabled = 1;
}
else
{
menus[m].options[i].enabled = 0;
}
}
}
}
}
fclose(f);
}
const char* cc = "\n\nstatic inline kconf_t get_kconfig(void)\n"
"{\n"
"\tkconf_t kc = { false, false, false, false, false };\n\n"
"#ifdef ENABLE_DEBUGGING_MESSAGES\n"
"\tkc.enable_debug = true;\n"
"#endif\n"
"#ifdef ENABLE_FILESYSTEMS\n"
"\tkc.enable_fs = true;\n"
"#endif\n"
"#ifdef ENABLE_IDE\n"
"\tkc.enable_ide = true;\n"
"#endif\n"
"#ifdef ENABLE_USB\n"
"\tkc.enable_usb = true;\n"
"#endif\n"
"#ifdef ENABLE_NETWORK\n"
"\tkc.enable_networking = true;\n"
"#endif\n\n"
"\treturn kc;\n"
"}\n\n"
"#ifdef __cplusplus\n"
"}\n"
"#endif\n";
/* Save current configuration options to Makefile and/or kconfig.h */
void save_config(menu_t* menus, size_t menu_count)
{
FILE* kconff = fopen("../include/kernel/kconfig.h", "w");
if (!kconff)
{
return;
}
const char* hg = "#ifndef _KCONFIG_H\n#define _KCONFIG_H\n\n#include <types.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
fprintf(kconff, hg);
for (size_t m = 0; m < menu_count; m++)
{
for (size_t i = 0; i < menus[m].num_options; i++)
{
char buffer[128];
strncpy(buffer, menus[m].options[i].name, sizeof(buffer));
buffer[sizeof(buffer)-1] = '\0';
strfix(buffer);
if (menus[m].options[i].enabled == 0)
{
fprintf(kconff, "//");
}
fprintf(kconff, "#define %s\n", buffer, menus[m].options[i].enabled);
}
}
fprintf(kconff, cc);
fprintf(kconff, "\n#endif\n");
fclose(kconff);
current_config_saved = true;
}
menu_t* create_menu(const char* title)
{
menu_t* menu = malloc(sizeof(menu_t));
menu->title = strdup(title);
menu->options = NULL;
menu->num_options = 0;
return menu;
}
void add_option(menu_t* menu, const char* name, int default_value)
{
menu->options = realloc(menu->options, sizeof(option_t) * (menu->num_options + 1));
menu->options[menu->num_options].name = strdup(name);
menu->options[menu->num_options].enabled = default_value;
menu->num_options++;
}
/* Display a single submenu */
void show_menu(menu_t* menu)
{
int selected = 0;
while (1)
{
clear();
mvprintw(0, 0, "%s (SPACE=toggle, (left arrow key or esc)=back, S=save)", menu->title);
for (size_t i = 0; i < menu->num_options; i++)
{
if ((int)i == selected)
{
attron(A_REVERSE);
}
mvprintw(i + 2, 2, "[%c] %s", menu->options[i].enabled ? 'X' : ' ', menu->options[i].name);
if ((int)i == selected)
{
attroff(A_REVERSE);
}
}
int ch = getch();
if (ch == KEY_UP && selected > 0)
{
selected--;
}
else if (ch == KEY_DOWN && selected < (int)menu->num_options - 1)
{
selected++;
}
else if (ch == ' ')
{
menu->options[selected].enabled = !menu->options[selected].enabled;
current_config_saved = false;
}
else if (ch == 's' || ch == 'S')
{
save_config(all_menus, NUM_MENUS);
mvprintw(menu->num_options + 3, 2, "Saved.");
refresh();
getch();
}
else if (ch == KEY_LEFT || ch == KEY_ESCAPE || ch == 'q' || ch == 'Q')
{
break;
}
}
}
/* Main menu with submenu navigation */
int main(void)
{
initscr();
noecho();
cbreak();
keypad(stdscr, TRUE);
set_escdelay(25); /* wait only 25ms for escape sequences */
/*load_config(all_menus, NUM_MENUS);*/
int selected = 0;
while (1)
{
clear();
mvprintw(0, 0, "Kernel Configuration (ENTER=submenu, S=save, Q=quit)");
for (size_t i = 0; i < NUM_MENUS; i++)
{
if ((int)i == selected)
{
attron(A_REVERSE);
}
mvprintw(i + 2, 2, "> %s", all_menus[i].title);
if ((int)i == selected)
{
attroff(A_REVERSE);
}
}
int ch = getch();
if (ch == KEY_UP && selected > 0)
{
selected--;
}
else if (ch == KEY_DOWN && selected < (int)NUM_MENUS - 1)
{
selected++;
}
else if (ch == '\n')
{
show_menu(&all_menus[selected]);
}
else if (ch == 's' || ch == 'S')
{
save_config(all_menus, NUM_MENUS);
mvprintw(NUM_MENUS + 3, 2, "Saved.");
refresh();
getch();
}
else if (ch == 'q' || ch == 'Q')
{
break;
}
}
endwin();
return 0;
}

BIN
scripts/menuconfig-lite Executable file

Binary file not shown.