Espresso 0.0.1b
This commit is contained in:
8
Makefile
8
Makefile
@ -1,17 +1,17 @@
|
|||||||
# === Config ===
|
# === Config ===
|
||||||
TARGET := boot/espresso.bin
|
TARGET := boot/espresso.elf
|
||||||
ISO := boot/espresso.iso
|
ISO := boot/espresso.iso
|
||||||
CC := i686-elf-gcc
|
CC := i686-elf-gcc
|
||||||
AS := i686-elf-as
|
AS := i686-elf-as
|
||||||
NASM := nasm
|
NASM := nasm
|
||||||
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M
|
QEMU_MKE_IMG := qemu-img create -f raw espresso.img 256M
|
||||||
MKFS_VFAT := sudo mkfs.vfat
|
MKFS_VFAT := sudo mkfs.vfat
|
||||||
MKFS_FLAGS := -F 32 --mbr -S 512
|
MKFS_FLAGS := -F 32 -S 512
|
||||||
NASMFLAGS := -f elf32
|
NASMFLAGS := -f elf32
|
||||||
WNOFLAGS := -Wno-discarded-qualifiers
|
WNOFLAGS := -Wno-discarded-qualifiers
|
||||||
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS)
|
CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS)
|
||||||
LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib
|
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
|
SRC_DIRS := kernel drivers lib
|
||||||
INCLUDE_DIRS := include
|
INCLUDE_DIRS := include
|
||||||
INCLUDES := $(addprefix -I, $(INCLUDE_DIRS))
|
INCLUDES := $(addprefix -I, $(INCLUDE_DIRS))
|
||||||
|
49
boot.s
49
boot.s
@ -74,6 +74,8 @@ enable_sse_asm:
|
|||||||
push %ebx
|
push %ebx
|
||||||
push %ecx
|
push %ecx
|
||||||
push %edx
|
push %edx
|
||||||
|
push %esi
|
||||||
|
push %edi
|
||||||
|
|
||||||
# Check CPUID support
|
# Check CPUID support
|
||||||
pushf
|
pushf
|
||||||
@ -87,13 +89,16 @@ enable_sse_asm:
|
|||||||
xor %ecx, %eax
|
xor %ecx, %eax
|
||||||
jz .no_cpuid
|
jz .no_cpuid
|
||||||
|
|
||||||
# Check for SSE
|
# CPUID function 1
|
||||||
mov $1, %eax
|
mov $1, %eax
|
||||||
cpuid
|
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
|
jz .no_sse
|
||||||
|
|
||||||
# Enable SSE
|
# Enable SSE (required for SSE1/2/3/SSSE3/4.1)
|
||||||
mov %cr0, %eax
|
mov %cr0, %eax
|
||||||
and $~0x4, %eax # Clear EM (bit 2)
|
and $~0x4, %eax # Clear EM (bit 2)
|
||||||
or $0x2, %eax # Set MP (bit 1)
|
or $0x2, %eax # Set MP (bit 1)
|
||||||
@ -103,17 +108,48 @@ enable_sse_asm:
|
|||||||
or $0x600, %eax # Set OSFXSR | OSXMMEXCPT
|
or $0x600, %eax # Set OSFXSR | OSXMMEXCPT
|
||||||
mov %eax, %cr4
|
mov %eax, %cr4
|
||||||
|
|
||||||
lea sse_initialized, %ebx
|
# Set version = 1 (SSE1)
|
||||||
movl $1, (%ebx)
|
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_sse:
|
||||||
.no_cpuid:
|
.no_cpuid:
|
||||||
|
lea sse_initialized, %edi
|
||||||
|
mov $0, (%edi)
|
||||||
|
|
||||||
|
.done:
|
||||||
|
pop %edi
|
||||||
|
pop %esi
|
||||||
pop %edx
|
pop %edx
|
||||||
pop %ecx
|
pop %ecx
|
||||||
pop %ebx
|
pop %ebx
|
||||||
pop %eax
|
pop %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
_kernel_early:
|
_kernel_early:
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
@ -205,8 +241,9 @@ This is useful when debugging or when you implement call tracing.
|
|||||||
*/
|
*/
|
||||||
.size _start, . - _start
|
.size _start, . - _start
|
||||||
|
|
||||||
|
|
||||||
.section .data
|
.section .data
|
||||||
|
|
||||||
.global sse_initialized
|
.global sse_initialized
|
||||||
|
|
||||||
sse_initialized: .word 0
|
sse_initialized: .int 0
|
||||||
|
63
drivers/elf.c
Normal file
63
drivers/elf.c
Normal 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%08x–0x%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
195
drivers/elf_load.c
Normal 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;
|
||||||
|
*/
|
||||||
|
/*}*/
|
@ -1,93 +1,806 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <drivers/ide.h>
|
#include <drivers/ide.h>
|
||||||
|
|
||||||
#include <fs/duckfs.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?"
|
int32_t duckfs_mount(void)
|
||||||
#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)
|
|
||||||
{
|
{
|
||||||
printf("\t%i\n", (sizeof(duckfs_file_header_t)));
|
if (disk_read(8, &super, 1) != 0)
|
||||||
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) */
|
return -1;
|
||||||
/* int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) */
|
|
||||||
|
|
||||||
/*uint8_t superblock_sector[512] = { 0 };
|
|
||||||
|
|
||||||
ide_read*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memcmp(super.magic, DUCKFS_MAGIC, 7) != 0)
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ¤t) != 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
50
drivers/fs/duckfs_disk_io.c
Normal file
50
drivers/fs/duckfs_disk_io.c
Normal 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
248
drivers/fs/fat16.c
Normal 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*)§or_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*)§or_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*)§or_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;
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,8 @@ int32_t fat32_init(int32_t drive)
|
|||||||
{
|
{
|
||||||
fat32_drive = drive;
|
fat32_drive = drive;
|
||||||
int err = ide_read48(drive, 0, 1, sector);
|
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);
|
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -47,52 +48,75 @@ int32_t fat32_init(int32_t drive)
|
|||||||
fat_start_lba = bpb.reserved_sector_count;
|
fat_start_lba = bpb.reserved_sector_count;
|
||||||
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
||||||
current_directory_cluster = bpb.root_cluster;
|
current_directory_cluster = bpb.root_cluster;
|
||||||
|
printf("========= Start FAT info =========\n");
|
||||||
printf("Bytes per sector: %u\n", bpb.bytes_per_sector);
|
printf("Bytes per sector: %u\n", bpb.bytes_per_sector);
|
||||||
printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster);
|
printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster);
|
||||||
printf("Reserved sectors: %u\n", bpb.reserved_sector_count);
|
printf("Reserved sectors: %u\n", bpb.reserved_sector_count);
|
||||||
printf("Number of FATs: %u\n", bpb.num_fats);
|
printf("Number of FATs: %u\n", bpb.num_fats);
|
||||||
printf("FAT size (32): %u\n", bpb.fat_size_32);
|
printf("FAT size (32): %u\n", bpb.fat_size_32);
|
||||||
printf("Root cluster: %u\n", bpb.root_cluster);
|
printf("Root cluster: %u\n", bpb.root_cluster);
|
||||||
|
printf("========= End FAT info =========\n");
|
||||||
|
|
||||||
return 0;
|
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)
|
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;
|
return cluster_heap_lba + (cluster - 2) * bpb.sectors_per_cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void format_83_name(const char *input, char out[11]) {
|
void format_83_name(const char* input, char* output)
|
||||||
memset(out, ' ', 11);
|
{
|
||||||
int i = 0, j = 0;
|
printf("Input name: %s, Input length: %i\n", input, strlen(input));
|
||||||
|
|
||||||
// Copy name part (up to 8 chars)
|
memset(output, ' ', 11);
|
||||||
while (input[i] && input[i] != '.' && j < 8) {
|
int32_t i = 0, j = 0;
|
||||||
out[j++] = toupper((unsigned char)input[i++]);
|
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
|
static uint32_t find_free_cluster(void)
|
||||||
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++) {
|
{
|
||||||
|
/* 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_sector = fat_start_lba + (cluster * 4) / 512;
|
||||||
uint32_t fat_offset = (cluster * 4) % 512;
|
uint32_t fat_offset = (cluster * 4) % 512;
|
||||||
|
|
||||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||||
if (entry == 0x00000000) {
|
if (entry == 0x00000000)
|
||||||
|
{
|
||||||
return cluster;
|
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)
|
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
|
||||||
{
|
{
|
||||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
char formatted[11];
|
||||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -161,35 +196,34 @@ int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((uint8_t)entry[0] == 0xE5)
|
|
||||||
|
if ((uint8_t)entry[0] == 0xE5 || (uint8_t)entry[11] == 0x0F)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char entry_name[12];
|
printf("here\n");
|
||||||
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)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File found */
|
||||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||||
uint32_t size = *(uint32_t *)(entry + 28);
|
uint32_t size = *(uint32_t *)(entry + 28);
|
||||||
uint32_t bytes_read = 0;
|
uint32_t bytes_read = 0;
|
||||||
|
|
||||||
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
||||||
{
|
{
|
||||||
uint32_t lba = cluster_to_lba(cluster);
|
uint32_t file_lba = cluster_to_lba(cluster);
|
||||||
if (ide_read48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
if (ide_read48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
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 bytes_read;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 *)§or[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 = §or[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 = §or[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;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
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);
|
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
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)
|
for (int32_t i = 0; i < 512; i += 32)
|
||||||
{
|
{
|
||||||
char *entry = (char *)§or[i];
|
char *entry = (char *)§or[i];
|
||||||
if ((uint8_t)entry[0] == 0x00) break;
|
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5)
|
||||||
if ((uint8_t)entry[0] == 0xE5) continue;
|
{
|
||||||
|
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 *)§or[i];
|
||||||
|
if ((uint8_t)entry[0] == 0x00)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uint8_t)entry[0] == 0xE5)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
char entry_name[12];
|
char entry_name[12];
|
||||||
memcpy(entry_name, entry, 11);
|
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;
|
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 = §or[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 *)§or[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 *)§or[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))
|
if (!(entry[11] & FAT32_ATTR_DIRECTORY))
|
||||||
|
{
|
||||||
return -2;
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||||
return 0;
|
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;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
206
drivers/fs/vfs.c
206
drivers/fs/vfs.c
@ -1,8 +1,8 @@
|
|||||||
#include <fs/ramfs.h>
|
/*#include <fs/fat16.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <fs/vfs.h>
|
#include <fs/vfs.h>*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -11,7 +11,7 @@
|
|||||||
-33 means stdout (which can be read)
|
-33 means stdout (which can be read)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool vfs_initialized = false;
|
/*bool vfs_initialized = false;
|
||||||
ramfs_file_header_t* vfs_current_dir = NULL;
|
ramfs_file_header_t* vfs_current_dir = NULL;
|
||||||
|
|
||||||
void vfs_init(void)
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
121
drivers/ide.c
121
drivers/ide.c
@ -17,7 +17,7 @@ static int32_t ide_wait(uint16_t io, int32_t check_drq)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pit_sleep(4);
|
pit_sleep(2);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -35,9 +35,8 @@ static int32_t ide_wait_ready(uint16_t io)
|
|||||||
return 1;
|
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;
|
uint16_t io = ATA_PRIMARY_IO;
|
||||||
uint8_t slave_bit = (drive & 1) << 4;
|
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_LBA0, 0);
|
||||||
outb(io + ATA_REG_LBA1, 0);
|
outb(io + ATA_REG_LBA1, 0);
|
||||||
outb(io + ATA_REG_LBA2, 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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ide_initialize(void) {
|
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];
|
uint16_t identify_buf[256];
|
||||||
if (ide_identify(0, identify_buf) == 0) {
|
if (ide_identify(0, identify_buf) == 0)
|
||||||
|
{
|
||||||
char model[41];
|
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 + 0] = identify_buf[27 + i] >> 8;
|
||||||
model[i * 2 + 1] = identify_buf[27 + i] & 0xFF;
|
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) {
|
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;
|
uint16_t io = ATA_PRIMARY_IO;
|
||||||
uint8_t slave_bit = (drive & 1) << 4;
|
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 + ATA_REG_SECCOUNT0, (sector_count >> 8) & 0xFF); /* high count */
|
||||||
outb(io + 2, sector_count & 0xFF); // Sector Count Low
|
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); /* LBA5 */
|
||||||
outb(io + 3, (lba >> 0) & 0xFF); // LBA[7:0]
|
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); /* LBA4 */
|
||||||
outb(io + 4, (lba >> 8) & 0xFF); // LBA[15:8]
|
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); /* LBA3 */
|
||||||
outb(io + 5, (lba >> 16) & 0xFF); // LBA[23:16]
|
|
||||||
|
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);
|
outb(io + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS_EXT);
|
||||||
|
|
||||||
|
|
||||||
uint16_t* ptr = (uint16_t*)buffer;
|
uint16_t* ptr = (uint16_t*)buffer;
|
||||||
for (int i = 0; i < sector_count; i++) {
|
for (int i = 0; i < sector_count; i++)
|
||||||
if (ide_wait(io, 1)) {
|
{
|
||||||
|
if (ide_wait(io, 1))
|
||||||
|
{
|
||||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||||
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
|
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
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);
|
insw(io + ATA_REG_DATA, ptr, 256);
|
||||||
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) {
|
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer)
|
||||||
if (sector_count == 0) return -1;
|
{
|
||||||
|
if (sector_count == 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t io = ATA_PRIMARY_IO;
|
uint16_t io = ATA_PRIMARY_IO;
|
||||||
uint8_t slave_bit = (drive & 1) << 4;
|
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_SECCOUNT0, 0); // Sector count high byte
|
||||||
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); // LBA[47:40]
|
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_LBA1, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||||
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); // LBA[31:24]
|
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_SECCOUNT0, sector_count); // Sector count low byte
|
||||||
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); // LBA[7:0]
|
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_LBA1, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||||
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
|
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||||
|
|
||||||
// Send write command
|
/* Send write command */
|
||||||
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); // 0x34
|
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); /* 0x34 */
|
||||||
|
|
||||||
const uint16_t* ptr = (const uint16_t*)buffer;
|
const uint16_t* ptr = (const uint16_t*)buffer;
|
||||||
for (int i = 0; i < sector_count; i++) {
|
for (int i = 0; i < sector_count; i++)
|
||||||
if (ide_wait(io, 1)) {
|
{
|
||||||
|
if (ide_wait(io, 1))
|
||||||
|
{
|
||||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||||
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
|
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for drive error
|
/* Check for drive error */
|
||||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
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 */
|
inb(io + ATA_REG_STATUS); /* Dummy read */
|
||||||
ptr += 256;
|
ptr += 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for BSY=0 before issuing FLUSH CACHE
|
/* Wait for BSY=0 before issuing FLUSH CACHE */
|
||||||
if (ide_wait_ready(io)) return -5;
|
if (ide_wait_ready(io))
|
||||||
outb(io + ATA_REG_COMMAND, 0xE7); // FLUSH CACHE
|
{
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
outb(io + ATA_REG_COMMAND, 0xE7);
|
||||||
|
|
||||||
if (ide_wait(io, 0)) {
|
if (ide_wait(io, 0)) {
|
||||||
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
|
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ void exception_dispatcher(uint32_t int_no, uint32_t err_code)
|
|||||||
case 14:
|
case 14:
|
||||||
{
|
{
|
||||||
uint32_t cr2;
|
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);
|
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
||||||
break;
|
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);
|
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;
|
uint8_t a1, a2;
|
||||||
|
|
||||||
// Save masks
|
/* Save masks */
|
||||||
a1 = inb(PIC1_DATA);
|
a1 = inb(PIC1_DATA);
|
||||||
a2 = inb(PIC2_DATA);
|
a2 = inb(PIC2_DATA);
|
||||||
|
|
||||||
// Start initialization sequence (in cascade mode)
|
/* Start initialization sequence (in cascade mode) */
|
||||||
outb(PIC1_COMMAND, 0x11);
|
outb(PIC1_COMMAND, 0x11);
|
||||||
outb(PIC2_COMMAND, 0x11);
|
outb(PIC2_COMMAND, 0x11);
|
||||||
|
|
||||||
// Set vector offset
|
/* Set vector offset */
|
||||||
outb(PIC1_DATA, 0x20); // IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39)
|
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)
|
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)
|
/* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */
|
||||||
outb(PIC1_DATA, 0x04);
|
outb(PIC1_DATA, 0x04);
|
||||||
|
|
||||||
// Tell Slave PIC its cascade identity (0000 0010)
|
/* Tell Slave PIC its cascade identity (0000 0010) */
|
||||||
outb(PIC2_DATA, 0x02);
|
outb(PIC2_DATA, 0x02);
|
||||||
|
|
||||||
// Set 8086/88 mode
|
/* Set 8086/88 mode */
|
||||||
outb(PIC1_DATA, 0x01);
|
outb(PIC1_DATA, 0x01);
|
||||||
outb(PIC2_DATA, 0x01);
|
outb(PIC2_DATA, 0x01);
|
||||||
|
|
||||||
// Restore saved masks
|
/* Restore saved masks */
|
||||||
outb(PIC1_DATA, a1);
|
outb(PIC1_DATA, a1);
|
||||||
outb(PIC2_DATA, a2);
|
outb(PIC2_DATA, a2);
|
||||||
}
|
}
|
||||||
@ -135,7 +141,7 @@ void idt_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__asm__ volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
||||||
__asm__ volatile ("sti"); /* set the interrupt flag */
|
asm volatile ("sti"); /* set the interrupt flag */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ static void append_char(char c)
|
|||||||
{
|
{
|
||||||
if (current_length + 1 >= capacity)
|
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;
|
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
|
||||||
|
|
||||||
char* new_str = (char*)malloc(new_capacity);
|
char* new_str = (char*)malloc(new_capacity);
|
||||||
@ -93,6 +93,11 @@ static void append_char(char c)
|
|||||||
free(current_string);
|
free(current_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_string)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
current_string = new_str;
|
current_string = new_str;
|
||||||
capacity = new_capacity;
|
capacity = new_capacity;
|
||||||
}
|
}
|
||||||
@ -148,6 +153,12 @@ void keyboard_handler(void) {
|
|||||||
c = (char) terminal_get_shifted((unsigned char) c);
|
c = (char) terminal_get_shifted((unsigned char) c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scancode == 0x1C) {
|
||||||
|
printf("\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (c)
|
if (c)
|
||||||
{
|
{
|
||||||
current_char = c;
|
current_char = c;
|
||||||
@ -164,3 +175,4 @@ void keyboard_handler(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ void terminal_putchar(const char c)
|
|||||||
{
|
{
|
||||||
terminal_row -= 1;
|
terminal_row -= 1;
|
||||||
|
|
||||||
if (terminal_row <= -1)
|
if (terminal_row == (size_t)-1)
|
||||||
{
|
{
|
||||||
terminal_row = 0;
|
terminal_row = 0;
|
||||||
}
|
}
|
||||||
@ -246,3 +246,4 @@ unsigned char terminal_get_shifted(unsigned char uc)
|
|||||||
|
|
||||||
return '\0';
|
return '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
grub.cfg
3
grub.cfg
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
menuentry "Espresso" {
|
menuentry "Espresso" {
|
||||||
multiboot /boot/espresso.bin
|
multiboot /boot/espresso.elf
|
||||||
}
|
}
|
||||||
|
45
include/drivers/elf.h
Normal file
45
include/drivers/elf.h
Normal 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
|
8
include/drivers/elf_load.h
Normal file
8
include/drivers/elf_load.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _ELF_LOADER_H
|
||||||
|
#define _ELF_LOADER_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -3,6 +3,52 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#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
|
#endif
|
||||||
|
38
include/fs/fat16.h
Normal file
38
include/fs/fat16.h
Normal 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
|
@ -8,10 +8,15 @@
|
|||||||
|
|
||||||
int32_t fat32_init(int32_t drive); /* 0 = primary master */
|
int32_t fat32_init(int32_t drive); /* 0 = primary master */
|
||||||
int32_t fat32_list_root(void);
|
int32_t fat32_list_root(void);
|
||||||
|
|
||||||
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len);
|
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_write_file(const char *name, const uint8_t *buffer, uint32_t len);
|
||||||
|
|
||||||
int32_t fat32_create_file(const char *name);
|
int32_t fat32_create_file(const char *name);
|
||||||
int32_t fat32_create_directory(const char *name);
|
int32_t fat32_create_directory(const char *name);
|
||||||
|
|
||||||
int32_t fat32_change_directory(const char *name);
|
int32_t fat32_change_directory(const char *name);
|
||||||
|
|
||||||
|
void format_83_name(const char* input, char* output);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,16 +5,6 @@
|
|||||||
|
|
||||||
typedef int32_t FILE;
|
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
|
#endif
|
||||||
|
44
include/kernel/kconfig.h
Normal file
44
include/kernel/kconfig.h
Normal 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
|
@ -9,10 +9,4 @@ typedef struct {
|
|||||||
uint32_t mantissa; /* 23 bits stored (MSB implicit for normalized numbers) */
|
uint32_t mantissa; /* 23 bits stored (MSB implicit for normalized numbers) */
|
||||||
} soft_float32_t;
|
} 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
|
#endif
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef _PMM_H
|
#ifndef _PMM_H
|
||||||
#define _PMM_H
|
#define _PMM_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <types.h>
|
||||||
#include <multiboot.h>
|
#include <multiboot.h>
|
||||||
|
|
||||||
void pmm_init(multiboot_info_t* mb_info);
|
void pmm_init(multiboot_info_t* mb_info);
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
#ifndef _PROCESSES_H
|
#ifndef _PROCESSES_H
|
||||||
#define _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
|
elf_executable_t* exe;
|
||||||
{
|
|
||||||
uint16_t id;
|
|
||||||
uint8_t policy;
|
|
||||||
uint16_t priority;
|
|
||||||
|
|
||||||
char name[16];
|
|
||||||
|
|
||||||
struct process* next;
|
struct process* next;
|
||||||
};
|
} process_t;
|
||||||
|
|
||||||
|
int32_t make_process(char* name, char* group, elf_executable_t* exe);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,14 +3,15 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#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 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);
|
int32_t strncmp(const char *s1, const char *s2, size_t n);
|
||||||
size_t strcpy(char *dst, 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* strncpy(char *dest, const char *src, uint32_t n);
|
||||||
void strcat(char *dest, const char *src);
|
char* strcat(char *dest, const char *src);
|
||||||
char* strdup(const char* s);
|
char* strdup(const char* s);
|
||||||
char* strtok(char* str, const char* delim);
|
char* strtok(char* str, const char* delim);
|
||||||
char* strchr(const char* s, int c);
|
char* strchr(const char* s, int c);
|
||||||
@ -19,12 +20,14 @@ int32_t ischar(int32_t c);
|
|||||||
int32_t isspace(char c);
|
int32_t isspace(char c);
|
||||||
int32_t isalpha(char c);
|
int32_t isalpha(char c);
|
||||||
char upper(char c);
|
char upper(char c);
|
||||||
|
char lower(char c);
|
||||||
char toupper(char c);
|
char toupper(char c);
|
||||||
char lower(char c);
|
char lower(char c);
|
||||||
|
|
||||||
void *memset(void *dst, char c, uint32_t n);
|
void *memset(void *dst, char c, uint32_t n);
|
||||||
void *memcpy(void *dst, const void *src, 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
|
#endif
|
||||||
|
8
include/time.h
Normal file
8
include/time.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _TIME_H
|
||||||
|
#define _TIME_H
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
void ksleep(uint64_t millis);
|
||||||
|
|
||||||
|
#endif
|
97
isr.old.asm
97
isr.old.asm
@ -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
6
kernel/E.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
________
|
||||||
|
|
|
||||||
|
|______
|
||||||
|
|
|
||||||
|
|
|
||||||
|
________
|
@ -53,7 +53,7 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
|
|
||||||
const char* espresso_kernel_version = "0.0.0f";
|
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();
|
terminal_initialize();
|
||||||
|
|
||||||
printf("Loading Espresso %s...\n", espresso_kernel_version);
|
printf("Loading Espresso %s...\n", espresso_kernel_version);
|
||||||
@ -63,7 +63,6 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
/* Make sure the magic number matches for memory mapping */
|
/* Make sure the magic number matches for memory mapping */
|
||||||
if(magic != MULTIBOOT_BOOTLOADER_MAGIC)
|
if(magic != MULTIBOOT_BOOTLOADER_MAGIC)
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("[ ERROR ] invalid magic number!\n");
|
printf("[ ERROR ] invalid magic number!\n");
|
||||||
_hang_asm();
|
_hang_asm();
|
||||||
}
|
}
|
||||||
@ -79,7 +78,6 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
|
|
||||||
pic_remap();
|
pic_remap();
|
||||||
idt_init();
|
idt_init();
|
||||||
/*pit_init(1000); 1000 Hz = 1ms tick */
|
|
||||||
_sti_asm();
|
_sti_asm();
|
||||||
|
|
||||||
terminal_setcolor(VGA_COLOR_GREEN);
|
terminal_setcolor(VGA_COLOR_GREEN);
|
||||||
@ -121,14 +119,14 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
printd("AHCI initialized\n");
|
printd("AHCI initialized\n");
|
||||||
*/
|
*/
|
||||||
|
|
||||||
printd("Initializing VFS...\n");
|
|
||||||
vfs_init();
|
|
||||||
printd("VFS initialized.\n");
|
|
||||||
|
|
||||||
printd("Initializing IDE system...\n");
|
printd("Initializing IDE system...\n");
|
||||||
ide_initialize();
|
ide_initialize();
|
||||||
printd("IDE initialized\n");
|
printd("IDE initialized\n");
|
||||||
|
|
||||||
|
/*printd("Initializing fat16...\n");
|
||||||
|
fat16_init(0);
|
||||||
|
printd("fat16 initialized.\n");*/
|
||||||
|
|
||||||
/*printd("Initializing DuckFS...\n");
|
/*printd("Initializing DuckFS...\n");
|
||||||
duckfs_init();
|
duckfs_init();
|
||||||
printd("DuckFS initialized\n");*/
|
printd("DuckFS initialized\n");*/
|
||||||
@ -147,43 +145,9 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
|
|||||||
/*pit_sleep(4000);
|
/*pit_sleep(4000);
|
||||||
begin_anim(espresso_kernel_version);*/
|
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");
|
printf("Guten tag and welcome to Espresso\n");
|
||||||
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -15,12 +15,3 @@ soft_float32_t decode_float(uint32_t raw)
|
|||||||
f.mantissa = raw & 0x7FFFFF;
|
f.mantissa = raw & 0x7FFFFF;
|
||||||
return f;
|
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;
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <processes.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;
|
||||||
|
}
|
||||||
|
@ -37,7 +37,7 @@ char* fgets(char* buf, int n, FILE file)
|
|||||||
|
|
||||||
while (total_read < n - 1)
|
while (total_read < n - 1)
|
||||||
{
|
{
|
||||||
int bytes = read_file(file, &c, 1);
|
int bytes = 0/*read_file(file, &c, 1)*/;
|
||||||
|
|
||||||
if (bytes <= 0)
|
if (bytes <= 0)
|
||||||
{
|
{
|
||||||
|
140
lib/string.c
140
lib/string.c
@ -1,31 +1,32 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <vector_extentions/sse.h>
|
#include <vector_extentions/sse.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
extern int16_t sse_initialized;
|
extern int32_t sse_initialized;
|
||||||
|
|
||||||
size_t strlen(const char* str)
|
size_t strlen(const char* str)
|
||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (str[len]) len++;
|
while (str[len])
|
||||||
|
{
|
||||||
|
len++;
|
||||||
|
}
|
||||||
return 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 && (*s1 == *s2))
|
||||||
|
{
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return (unsigned char)*s1 - (unsigned char)*s2;
|
||||||
|
}
|
||||||
|
|
||||||
while ((s1[i] == s2[i]))
|
|
||||||
{
|
|
||||||
if (s2[i++] == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t strncmp(const char *s1, const char *s2, size_t n)
|
int32_t strncmp(const char *s1, const char *s2, size_t n)
|
||||||
{
|
{
|
||||||
@ -45,15 +46,35 @@ int32_t strncmp(const char *s1, const char *s2, size_t n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t strcasecmp(const char* s1, const char* s2)
|
||||||
size_t strcpy(char *dst, const char *src)
|
|
||||||
{
|
{
|
||||||
int32_t i = 0;
|
unsigned char c1, c2;
|
||||||
while ((*dst++ = *src++) != 0)
|
|
||||||
i++;
|
while (*s1 && *s2)
|
||||||
return i;
|
{
|
||||||
|
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* 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)
|
char* strncpy(char *dest, const char *src, uint32_t n)
|
||||||
{
|
{
|
||||||
if (sse_initialized > 0)
|
if (sse_initialized > 0)
|
||||||
@ -63,22 +84,31 @@ char *strncpy(char *dest, const char *src, uint32_t n)
|
|||||||
|
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
for (; i < n && src[i]; ++i)
|
for (; i < n && src[i]; ++i)
|
||||||
|
{
|
||||||
dest[i] = src[i];
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
|
||||||
for (; i < n; ++i)
|
for (; i < n; ++i)
|
||||||
|
{
|
||||||
dest[i] = '\0';
|
dest[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strcat(char *dest, const char *src)
|
char* strcat(char *dest, const char *src)
|
||||||
{
|
{
|
||||||
char *end = (char *)dest + strlen(dest);
|
char *end = dest + strlen(dest);
|
||||||
memcpy((void *)end, (void *)src, strlen(src));
|
while (*src)
|
||||||
end = end + strlen(src);
|
{
|
||||||
*end = '\0';
|
*end++ = *src++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*end = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char* strdup(const char* s)
|
char* strdup(const char* s)
|
||||||
{
|
{
|
||||||
if (!s)
|
if (!s)
|
||||||
@ -158,40 +188,51 @@ 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;
|
char *temp = dst;
|
||||||
for (; n != 0; n--) *temp++ = c;
|
for (; n != 0; n--)
|
||||||
|
{
|
||||||
|
*temp++ = c;
|
||||||
|
}
|
||||||
return dst;
|
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);
|
return sse2_memcpy(dst, src, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *ret = dst;
|
char *d = dst;
|
||||||
char *p = dst;
|
const char *s = src;
|
||||||
const char *q = src;
|
|
||||||
while (n--)
|
while (n--)
|
||||||
*p++ = *q++;
|
{
|
||||||
return ret;
|
*d++ = *s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t memcmp(uint8_t *s1, uint8_t *s2, uint32_t n)
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t memcmp(const void *s1, const void *s2, size_t n)
|
||||||
{
|
{
|
||||||
while (n--)
|
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 (*s1 != *s2)
|
if (p1[i] != p2[i])
|
||||||
|
{
|
||||||
|
return (int32_t)p1[i] - (int32_t)p2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
s1++;
|
|
||||||
s2++;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memclr(const void * const m_start, const size_t m_count)
|
|
||||||
|
void* memclr(void* m_start, size_t m_count)
|
||||||
{
|
{
|
||||||
if (sse_initialized > 0)
|
if (sse_initialized > 1)
|
||||||
{
|
{
|
||||||
return memclr_sse2(m_start, m_count);
|
return memclr_sse2(m_start, m_count);
|
||||||
}
|
}
|
||||||
@ -215,13 +256,6 @@ int32_t ischar(int32_t c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char upper(char c)
|
char upper(char c)
|
||||||
{
|
|
||||||
if ((c >= 'a') && (c <= 'z'))
|
|
||||||
return (c - 32);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
char toupper(char c)
|
|
||||||
{
|
{
|
||||||
if ((c >= 'a') && (c <= 'z'))
|
if ((c >= 'a') && (c <= 'z'))
|
||||||
{
|
{
|
||||||
@ -233,6 +267,18 @@ char toupper(char c)
|
|||||||
char lower(char c)
|
char lower(char c)
|
||||||
{
|
{
|
||||||
if ((c >= 'A') && (c <= 'Z'))
|
if ((c >= 'A') && (c <= 'Z'))
|
||||||
|
{
|
||||||
return (c + 32);
|
return (c + 32);
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char toupper(char c)
|
||||||
|
{
|
||||||
|
return upper(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
char tolower(char c)
|
||||||
|
{
|
||||||
|
return lower(c);
|
||||||
|
}
|
||||||
|
10
lib/time.c
Normal file
10
lib/time.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <drivers/pit.h>
|
||||||
|
#include <port_io.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
void ksleep(uint64_t millis)
|
||||||
|
{
|
||||||
|
pit_sleep(millis);
|
||||||
|
}
|
@ -7,7 +7,8 @@
|
|||||||
#include <vector_extentions/sse.h>
|
#include <vector_extentions/sse.h>
|
||||||
|
|
||||||
|
|
||||||
void enable_sse(void) {
|
void enable_sse(void)
|
||||||
|
{
|
||||||
uint32_t cr0, cr4;
|
uint32_t cr0, cr4;
|
||||||
|
|
||||||
__asm__ volatile ("mov %%cr0, %0" : "=r"(cr0));
|
__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
|
// Basic SSE test: add two arrays of 4 floats using xmm registers
|
||||||
__attribute__((force_align_arg_pointer))
|
__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 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 b[4] __attribute__((aligned(16))) = {5.0f, 6.0f, 7.0f, 8.0f};
|
||||||
float result[4] __attribute__((aligned(16)));
|
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;
|
uint32_t i = 0;
|
||||||
|
|
||||||
/* Align initial copy */
|
/* 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];
|
dest[i] = src[i];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
5
scripts/.config
Normal file
5
scripts/.config
Normal 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
296
scripts/kconfig.c
Normal 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
BIN
scripts/menuconfig-lite
Executable file
Binary file not shown.
Reference in New Issue
Block a user