Espresso 0.0.1b
This commit is contained in:
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 <stdlib.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/duckfs.h>
|
||||
|
||||
|
||||
#define DFS_MAGIC 0xDF1984CC
|
||||
static duckfs_superblock_t super;
|
||||
|
||||
#define DFS_BLOCK_SIZE 512
|
||||
extern int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count);
|
||||
extern int32_t disk_read(uint64_t lba, void* buffer, uint32_t count);
|
||||
|
||||
#define DFS_VERSION_0 "DuckFS, wheresDax?"
|
||||
#define DFS_VERSION_1 "DuckFS, Terminator"
|
||||
#define DFS_VERSION_2 "DuckFS-Terminator2"
|
||||
#define DFS_VERSION_3 "DuckFS,StarWarsEIV"
|
||||
#define DFS_VERSION_4 "DuckFS QUACK,QUACK"
|
||||
|
||||
|
||||
#define DFS_FILE_ERROR -8
|
||||
#define DFS_FILE_UNUSED -1
|
||||
#define DFS_FILE_USED 0
|
||||
#define DFS_FILE_TEXT 0
|
||||
#define DFS_FILE_BINARY 1
|
||||
#define DFS_FILE_DIRECTORY 2
|
||||
|
||||
/* encryption algorithms */
|
||||
#define DFS_CAESAR_5 88
|
||||
#define DFS_CAESAR_8 84
|
||||
#define DFS_CAESAR_2 09
|
||||
#define DFS_QUACK_32 99
|
||||
|
||||
#define DFS_MAX_FILENAME_LEN 64
|
||||
#define DFS_MAX_FILES 256
|
||||
|
||||
|
||||
typedef struct duckfs_file_header {
|
||||
char filename[DFS_MAX_FILENAME_LEN + 1]; /* + 1 for the \0 */
|
||||
char permissions[3]; /* Same thing here */
|
||||
|
||||
/*
|
||||
512 Bytes per sector, meaning a 2 sector file is 1024 bytes, or 1 KiB.
|
||||
Only valid if this file is not a directory.
|
||||
*/
|
||||
int32_t num_sectors;
|
||||
|
||||
int16_t type; /* Indicates the file type. -1 for null file, 0 for a text file, 1 for a binary file, and 2 for a directory. */
|
||||
|
||||
uint16_t _reserved0; /* (align to 4) */
|
||||
|
||||
struct duckfs_file_header* next; /* Next file in the directory this file is in. */
|
||||
struct duckfs_file_header* contents; /* contains the first file in the directory. only valid if this file is a directory. */
|
||||
struct duckfs_file_header* parent; /* The directory this file is in. */
|
||||
|
||||
uint64_t next_lba; /* The LBA of the next file's file header on the disk. */
|
||||
uint64_t contents_lba;
|
||||
uint64_t parent_lba;
|
||||
|
||||
uint64_t lba_start; /* only is valid if this file is not a directory. */
|
||||
uint64_t lba_end; /* only is valid if this file is not a directory. */
|
||||
|
||||
uint8_t _reserved1[126]; /* padding to 256 bytes total */
|
||||
} duckfs_file_header_t;
|
||||
|
||||
typedef struct duckfs_superblock {
|
||||
int32_t duckfs_magic; /* must be DFS_MAGIC. */
|
||||
char duckfs_version_string[19];
|
||||
char volume_label[19]; /* 18 characters and a null zero. */
|
||||
|
||||
int16_t encryption;
|
||||
|
||||
uint64_t duckfs_root; /* LBA of the root directory's file header */
|
||||
|
||||
uint32_t _padding[115]; /* padding to 512 bytes total */
|
||||
} duckfs_superblock_t;
|
||||
|
||||
|
||||
static uint16_t duckfs_initialized = 0;
|
||||
|
||||
static duckfs_file_header_t duckfs_root;
|
||||
|
||||
const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 };
|
||||
|
||||
void duckfs_init(void)
|
||||
int32_t duckfs_mount(void)
|
||||
{
|
||||
printf("\t%i\n", (sizeof(duckfs_file_header_t)));
|
||||
printf("\t\t%i\n", (sizeof(duckfs_superblock_t)));
|
||||
/* int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) */
|
||||
/* int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) */
|
||||
|
||||
/*uint8_t superblock_sector[512] = { 0 };
|
||||
|
||||
ide_read*/
|
||||
if (disk_read(8, &super, 1) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -5,24 +5,24 @@
|
||||
#include <fs/fat32.h>
|
||||
|
||||
struct __attribute__((packed)) fat32_bpb {
|
||||
uint8_t jmp[3];
|
||||
uint8_t oem[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sector_count;
|
||||
uint8_t num_fats;
|
||||
uint16_t root_entry_count;
|
||||
uint16_t total_sectors_16;
|
||||
uint8_t media;
|
||||
uint16_t fat_size_16;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_32;
|
||||
uint32_t fat_size_32;
|
||||
uint16_t ext_flags;
|
||||
uint16_t fs_version;
|
||||
uint32_t root_cluster;
|
||||
uint8_t jmp[3];
|
||||
uint8_t oem[8];
|
||||
uint16_t bytes_per_sector;
|
||||
uint8_t sectors_per_cluster;
|
||||
uint16_t reserved_sector_count;
|
||||
uint8_t num_fats;
|
||||
uint16_t root_entry_count;
|
||||
uint16_t total_sectors_16;
|
||||
uint8_t media;
|
||||
uint16_t fat_size_16;
|
||||
uint16_t sectors_per_track;
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t total_sectors_32;
|
||||
uint32_t fat_size_32;
|
||||
uint16_t ext_flags;
|
||||
uint16_t fs_version;
|
||||
uint32_t root_cluster;
|
||||
};
|
||||
|
||||
static int32_t fat32_drive = 0;
|
||||
@ -37,9 +37,10 @@ int32_t fat32_init(int32_t drive)
|
||||
{
|
||||
fat32_drive = drive;
|
||||
int err = ide_read48(drive, 0, 1, sector);
|
||||
if (err != 0) {
|
||||
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
|
||||
return -1;
|
||||
if (err != 0)
|
||||
{
|
||||
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&bpb, sector, sizeof(bpb));
|
||||
@ -47,56 +48,79 @@ int32_t fat32_init(int32_t drive)
|
||||
fat_start_lba = bpb.reserved_sector_count;
|
||||
cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32;
|
||||
current_directory_cluster = bpb.root_cluster;
|
||||
printf("========= Start FAT info =========\n");
|
||||
printf("Bytes per sector: %u\n", bpb.bytes_per_sector);
|
||||
printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster);
|
||||
printf("Reserved sectors: %u\n", bpb.reserved_sector_count);
|
||||
printf("Number of FATs: %u\n", bpb.num_fats);
|
||||
printf("FAT size (32): %u\n", bpb.fat_size_32);
|
||||
printf("Root cluster: %u\n", bpb.root_cluster);
|
||||
printf("========= End FAT info =========\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_83(const char *s) {
|
||||
for (int i = 0; i < 11; i++) {
|
||||
char c = s[i];
|
||||
if (c >= 32 && c <= 126) {
|
||||
printf("%c", c); // or your kernel's character output function
|
||||
} else {
|
||||
printf("\\x%02X", (unsigned char)c); // hex-escape non-printables
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
static uint32_t cluster_to_lba(uint32_t cluster)
|
||||
{
|
||||
printf("cluster_heap_lba: %u\n", cluster_heap_lba);
|
||||
return cluster_heap_lba + (cluster - 2) * bpb.sectors_per_cluster;
|
||||
}
|
||||
|
||||
static void format_83_name(const char *input, char out[11]) {
|
||||
memset(out, ' ', 11);
|
||||
int i = 0, j = 0;
|
||||
void format_83_name(const char* input, char* output)
|
||||
{
|
||||
printf("Input name: %s, Input length: %i\n", input, strlen(input));
|
||||
|
||||
// Copy name part (up to 8 chars)
|
||||
while (input[i] && input[i] != '.' && j < 8) {
|
||||
out[j++] = toupper((unsigned char)input[i++]);
|
||||
memset(output, ' ', 11);
|
||||
int32_t i = 0, j = 0;
|
||||
while (input[i] && j < 11)
|
||||
{
|
||||
if (input[i] == '.')
|
||||
{
|
||||
j = 8;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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++;
|
||||
if (j < 11)
|
||||
{
|
||||
output[j++] = toupper((unsigned char)input[i++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t find_free_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_offset = (cluster * 4) % 512;
|
||||
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
return 0;
|
||||
static uint32_t find_free_cluster(void)
|
||||
{
|
||||
/* Read FAT sectors one by one */
|
||||
for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++)
|
||||
{
|
||||
uint32_t fat_sector = fat_start_lba + (cluster * 4) / 512;
|
||||
uint32_t fat_offset = (cluster * 4) % 512;
|
||||
|
||||
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
if (entry == 0x00000000) {
|
||||
return cluster;
|
||||
}
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0; // No free cluster found
|
||||
|
||||
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
if (entry == 0x00000000)
|
||||
{
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return 0; // No free cluster found
|
||||
}
|
||||
|
||||
|
||||
@ -148,70 +172,336 @@ int32_t fat32_list_root(void)
|
||||
|
||||
int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
char formatted[11];
|
||||
memset(formatted, 0xAB, sizeof(formatted));
|
||||
format_83_name(name, formatted);
|
||||
|
||||
uint32_t dir_cluster = current_directory_cluster;
|
||||
|
||||
while (dir_cluster < 0x0FFFFFF8)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(dir_cluster);
|
||||
|
||||
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
|
||||
{
|
||||
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
printf("here\n");
|
||||
|
||||
char entry_name[12] = { '\0' };
|
||||
memcpy((void*)entry_name, (void*)entry, 11);
|
||||
|
||||
int32_t err = memcmp(entry_name, formatted, (size_t)11);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
printf("memcmp: %i\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* File found */
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t size = *(uint32_t *)(entry + 28);
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
||||
{
|
||||
uint32_t file_lba = cluster_to_lba(cluster);
|
||||
if (ide_read48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_read += bpb.sectors_per_cluster * 512;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char *entry = (char *)§or[i];
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
uint8_t *entry = &dir_sector[i];
|
||||
if (entry[0] == 0x00 || entry[0] == 0xE5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ((uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
printf("Writing entry at offset %d\n", i);
|
||||
memset(entry, 0, 32);
|
||||
memcpy(entry, formatted_name, 11);
|
||||
entry[11] = 0x20;
|
||||
|
||||
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] == ' ')
|
||||
uint32_t free_cluster = find_free_cluster();
|
||||
if (free_cluster == 0)
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
|
||||
uint32_t fat_offset = (free_cluster * 4) % 512;
|
||||
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t size = *(uint32_t *)(entry + 28);
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
if (ide_read48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0)
|
||||
if (ide_read48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes_read += bpb.sectors_per_cluster * 512;
|
||||
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
|
||||
|
||||
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)
|
||||
if (ide_write48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
|
||||
/* 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 bytes_read;
|
||||
}
|
||||
return -2;
|
||||
|
||||
return -8;
|
||||
}
|
||||
|
||||
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
||||
int32_t fat32_create_directory(const char *name)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(current_directory_cluster);
|
||||
if (ide_read48(fat32_drive, lba, 1, sector) != 0)
|
||||
@ -222,206 +512,90 @@ int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
|
||||
for (int32_t i = 0; i < 512; i += 32)
|
||||
{
|
||||
char *entry = (char *)§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 (int j = 0; j < 11; j++)
|
||||
if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
memset(entry, 0, 32);
|
||||
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
|
||||
entry[11] = FAT32_ATTR_DIRECTORY;
|
||||
|
||||
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
uint32_t bytes_written = 0;
|
||||
uint32_t cluster = 6;
|
||||
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
|
||||
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
|
||||
*(uint32_t *)(entry + 28) = 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)
|
||||
if (ide_write48(fat32_drive, lba, 1, sector) != 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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(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);
|
||||
int32_t fat32_change_directory(const char *name)
|
||||
{
|
||||
uint32_t dir_cluster = current_directory_cluster;
|
||||
|
||||
// Read root directory cluster sector (assuming 1 sector here for simplicity)
|
||||
if (ide_read48(fat32_drive, root_lba, 1, sector) != 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
if ((uint8_t)entry[0] == 0x00)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint8_t)entry[0] == 0xE5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
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;
|
||||
for (int j = 0; j < 11; j++)
|
||||
{
|
||||
if (entry_name[j] == ' ')
|
||||
{
|
||||
entry_name[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(entry_name, name, 11) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(entry[11] & FAT32_ATTR_DIRECTORY))
|
||||
return -2;
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -3;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
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 <string.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
#include <fs/vfs.h>*/
|
||||
|
||||
|
||||
/*
|
||||
@ -11,7 +11,7 @@
|
||||
-33 means stdout (which can be read)
|
||||
*/
|
||||
|
||||
bool vfs_initialized = false;
|
||||
/*bool vfs_initialized = false;
|
||||
ramfs_file_header_t* vfs_current_dir = NULL;
|
||||
|
||||
void vfs_init(void)
|
||||
@ -27,204 +27,4 @@ void vfs_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent); */
|
||||
|
||||
FILE create_file(char* filename, char type, char encryption, FILE parent)
|
||||
{
|
||||
if (!filename)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parent == -128)
|
||||
{
|
||||
parent = vfs_current_dir->fd;
|
||||
}
|
||||
|
||||
ramfs_file_header_t* file = ramfs_create_file(filename, type, encryption, ramfs_resolve_fd(parent));
|
||||
if (!file)
|
||||
{
|
||||
return -4; /* error code for failed creation */
|
||||
}
|
||||
|
||||
return file->fd;
|
||||
}
|
||||
|
||||
int32_t delete_file(FILE file)
|
||||
{
|
||||
/*
|
||||
XXX WARNING: ANY AND ALL PROCESSES CAN DELETE A FILE VIA THIS INTERFACE!!! XXX
|
||||
XXX THIS MUST BE PACHED SOON!!! OR AT LEAST ADD PERMISSION CHECKING IN THE SYSCALL INTERFACE XXX
|
||||
XXX OR IN THE C LIBRARIES!!! XXX
|
||||
*/
|
||||
|
||||
if (file < 1)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
return ramfs_delete_file(_file);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open a file based on a string.
|
||||
Return a file descriptor on success, a negative value on failure.
|
||||
|
||||
return values:
|
||||
(positive non-zero value) - File descriptor
|
||||
-1 - Insufficient permissions to open file
|
||||
-2 - File does not exist ( or at least, File not found. )
|
||||
-3 - No filesystem is initialized
|
||||
-4 - Internal error, perhaps try again
|
||||
*/
|
||||
FILE open_file(char* filename)
|
||||
{
|
||||
if (ramfs_get_initialized() && vfs_initialized)
|
||||
{
|
||||
ramfs_file_header_t* _file = ramfs_resolve_path(filename);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
return (FILE)-2;
|
||||
}
|
||||
|
||||
return (FILE)_file->fd;
|
||||
}
|
||||
|
||||
return (FILE)-3;
|
||||
}
|
||||
|
||||
|
||||
FILE write_file(FILE file, void* data, size_t len)
|
||||
{
|
||||
|
||||
if (file < 1 || !data || len == 0)
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
if (ramfs_get_initialized() && vfs_initialized)
|
||||
{
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (_file->type == RAMFS_FILE_DIR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_file->data_begin)
|
||||
{
|
||||
free(_file->data_begin);
|
||||
_file->data_begin = NULL;
|
||||
_file->data_end = NULL;
|
||||
}
|
||||
|
||||
void* new_buf = malloc(len);
|
||||
if (!new_buf)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
memcpy(new_buf, data, len);
|
||||
|
||||
_file->data_begin = new_buf;
|
||||
_file->data_end = (void*)((uint8_t*)new_buf + len);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
int32_t read_file(FILE file, void* buf, size_t buflen)
|
||||
{
|
||||
if (file < 1 || !buf || buflen == 0)
|
||||
{
|
||||
return -1; /* Invalid arguments */
|
||||
}
|
||||
|
||||
if (ramfs_get_initialized() && vfs_initialized)
|
||||
{
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file || _file->type == RAMFS_FILE_DIR)
|
||||
{
|
||||
return -2; /* Not a file or trying to read a directory */
|
||||
}
|
||||
|
||||
if (!_file->data_begin || !_file->data_end)
|
||||
{
|
||||
return 0; /* Empty file */
|
||||
}
|
||||
|
||||
size_t total_len = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
|
||||
|
||||
if (_file->read_offset >= (int32_t)total_len)
|
||||
{
|
||||
return 0; /* End of file */
|
||||
}
|
||||
|
||||
size_t available = total_len - _file->read_offset;
|
||||
size_t to_copy = (buflen < available) ? buflen : available;
|
||||
|
||||
memcpy(buf, (uint8_t*)_file->data_begin + _file->read_offset, to_copy);
|
||||
|
||||
_file->read_offset += to_copy;
|
||||
|
||||
return (int32_t)to_copy;
|
||||
}
|
||||
|
||||
return -3; /* FS not initialized */
|
||||
}
|
||||
|
||||
int32_t reset_read_offset(FILE file)
|
||||
{
|
||||
if (file < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
_file->read_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t seek_file(FILE file, int32_t offset)
|
||||
{
|
||||
if (file < 0 && file != -32 && file != -33)
|
||||
{
|
||||
return -1; /* Invalid file descriptor */
|
||||
}
|
||||
|
||||
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
|
||||
|
||||
if (!_file || _file->type == RAMFS_FILE_DIR)
|
||||
return -2; // Invalid file or directory
|
||||
|
||||
if (!_file->data_begin || !_file->data_end)
|
||||
return -3; // Empty file
|
||||
|
||||
size_t file_size = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
|
||||
|
||||
if (offset < 0 || (size_t)offset > file_size)
|
||||
return -4; // Offset out of bounds
|
||||
|
||||
_file->read_offset = offset;
|
||||
return 0; // Success
|
||||
}
|
||||
|
||||
|
227
drivers/ide.c
227
drivers/ide.c
@ -17,7 +17,7 @@ static int32_t ide_wait(uint16_t io, int32_t check_drq)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pit_sleep(4);
|
||||
pit_sleep(2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -35,142 +35,167 @@ static int32_t ide_wait_ready(uint16_t io)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer)
|
||||
{
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0);
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xA0 | slave_bit);
|
||||
outb(io + ATA_REG_SECCOUNT0, 0);
|
||||
outb(io + ATA_REG_LBA0, 0);
|
||||
outb(io + ATA_REG_LBA1, 0);
|
||||
outb(io + ATA_REG_LBA2, 0);
|
||||
outb(io + ATA_REG_COMMAND, 0xEC); /* IDENTIFY DEVICE command */
|
||||
|
||||
int32_t ide_identify(uint8_t drive, uint16_t* buffer) {
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status == 0)
|
||||
{
|
||||
return -1; /* No device */
|
||||
}
|
||||
|
||||
ide_wait(io, 0);
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xA0 | slave_bit);
|
||||
outb(io + ATA_REG_SECCOUNT0, 0);
|
||||
outb(io + ATA_REG_LBA0, 0);
|
||||
outb(io + ATA_REG_LBA1, 0);
|
||||
outb(io + ATA_REG_LBA2, 0);
|
||||
outb(io + ATA_REG_COMMAND, 0xEC); // IDENTIFY DEVICE
|
||||
if (ide_wait(io, 1))
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status == 0) return -1; // No device
|
||||
|
||||
if (ide_wait(io, 1)) return -2;
|
||||
|
||||
insw(io + ATA_REG_DATA, buffer, 256); // Read 512 bytes
|
||||
return 0;
|
||||
insw(io + ATA_REG_DATA, buffer, 256); /* Read 512 bytes */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ide_initialize(void) {
|
||||
outb(ATA_PRIMARY_CTRL, 0x02); // Disable IRQs
|
||||
|
||||
uint16_t identify_buf[256];
|
||||
if (ide_identify(0, identify_buf) == 0) {
|
||||
char model[41];
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
model[i * 2 + 0] = identify_buf[27 + i] >> 8;
|
||||
model[i * 2 + 1] = identify_buf[27 + i] & 0xFF;
|
||||
}
|
||||
model[40] = 0;
|
||||
printf("Disk model: %s\n", model);
|
||||
outb(ATA_PRIMARY_CTRL, 0x02); /* Disable IRQs from IDE disk controllers TODO: should probably use IRQs soon */
|
||||
|
||||
uint16_t identify_buf[256];
|
||||
if (ide_identify(0, identify_buf) == 0)
|
||||
{
|
||||
char model[41];
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
model[i * 2 + 0] = identify_buf[27 + i] >> 8;
|
||||
model[i * 2 + 1] = identify_buf[27 + i] & 0xFF;
|
||||
}
|
||||
model[40] = 0;
|
||||
printf("Disk model: %s\n", model);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) {
|
||||
if (sector_count == 0) return -1;
|
||||
if (sector_count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0); // Wait for BSY to clear
|
||||
ide_wait(io, 0); /* Wait for BSY to clear */
|
||||
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); /* Select drive */
|
||||
|
||||
// High bytes (use 0xC2 - 0xC6 offsets if you define them separately)
|
||||
outb(io + 6, (sector_count >> 8) & 0xFF); // Sector Count High
|
||||
outb(io + 7, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + 8, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + 9, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
|
||||
outb(io + ATA_REG_SECCOUNT0, (sector_count >> 8) & 0xFF); /* high count */
|
||||
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); /* LBA5 */
|
||||
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); /* LBA4 */
|
||||
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); /* LBA3 */
|
||||
|
||||
// Low bytes
|
||||
outb(io + 2, sector_count & 0xFF); // Sector Count Low
|
||||
outb(io + 3, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + 4, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + 5, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
outb(io + ATA_REG_SECCOUNT0, sector_count & 0xFF); /* low count */
|
||||
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); /* LBA0 */
|
||||
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); /* LBA1 */
|
||||
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); /* LBA2 */
|
||||
|
||||
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS_EXT);
|
||||
|
||||
uint16_t* ptr = (uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
if (ide_wait(io, 1)) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_READ_SECTORS_EXT);
|
||||
|
||||
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR) return -3;
|
||||
|
||||
insw(io + ATA_REG_DATA, ptr, 256);
|
||||
ptr += 256;
|
||||
uint16_t* ptr = (uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++)
|
||||
{
|
||||
if (ide_wait(io, 1))
|
||||
{
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (read), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
insw(io + ATA_REG_DATA, ptr, 256);
|
||||
ptr += 256;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) {
|
||||
if (sector_count == 0) return -1;
|
||||
int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer)
|
||||
{
|
||||
if (sector_count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
uint16_t io = ATA_PRIMARY_IO;
|
||||
uint8_t slave_bit = (drive & 1) << 4;
|
||||
|
||||
ide_wait(io, 0); // Wait for BSY to clear
|
||||
ide_wait(io, 0); /* Wait for BSY to clear */
|
||||
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); // Select drive
|
||||
outb(io + ATA_REG_HDDEVSEL, 0xE0 | slave_bit); /* Select drive */
|
||||
|
||||
// Send high bytes of sector count and LBA first
|
||||
outb(io + ATA_REG_SECCOUNT0, 0); // Sector count high byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
/* Send high bytes of sector count and LBA first */
|
||||
outb(io + ATA_REG_SECCOUNT0, 0); // Sector count high byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 40) & 0xFF); // LBA[47:40]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 32) & 0xFF); // LBA[39:32]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 24) & 0xFF); // LBA[31:24]
|
||||
|
||||
// Send low bytes
|
||||
outb(io + ATA_REG_SECCOUNT0, sector_count); // Sector count low byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
/* Send low bytes */
|
||||
outb(io + ATA_REG_SECCOUNT0, sector_count); // Sector count low byte
|
||||
outb(io + ATA_REG_LBA0, (lba >> 0) & 0xFF); // LBA[7:0]
|
||||
outb(io + ATA_REG_LBA1, (lba >> 8) & 0xFF); // LBA[15:8]
|
||||
outb(io + ATA_REG_LBA2, (lba >> 16) & 0xFF); // LBA[23:16]
|
||||
|
||||
// Send write command
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); // 0x34
|
||||
/* Send write command */
|
||||
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS_EXT); /* 0x34 */
|
||||
|
||||
const uint16_t* ptr = (const uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++) {
|
||||
if (ide_wait(io, 1)) {
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Check for drive error
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR) return -3;
|
||||
|
||||
outsw(io + ATA_REG_DATA, ptr, 256); // 256 words = 512 bytes
|
||||
inb(io + ATA_REG_STATUS); /* Dummy read */
|
||||
ptr += 256;
|
||||
const uint16_t* ptr = (const uint16_t*)buffer;
|
||||
for (int i = 0; i < sector_count; i++)
|
||||
{
|
||||
if (ide_wait(io, 1))
|
||||
{
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
printf("IDE DRQ wait failed (write), status = 0x%02X\n", status);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Wait for BSY=0 before issuing FLUSH CACHE
|
||||
if (ide_wait_ready(io)) return -5;
|
||||
outb(io + ATA_REG_COMMAND, 0xE7); // FLUSH CACHE
|
||||
if (ide_wait(io, 0)) {
|
||||
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
|
||||
return -4;
|
||||
/* Check for drive error */
|
||||
uint8_t status = inb(io + ATA_REG_STATUS);
|
||||
if (status & ATA_SR_ERR)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
outsw(io + ATA_REG_DATA, ptr, 256); /* 256 words = 512 bytes */
|
||||
inb(io + ATA_REG_STATUS); /* Dummy read */
|
||||
ptr += 256;
|
||||
}
|
||||
|
||||
/* Wait for BSY=0 before issuing FLUSH CACHE */
|
||||
if (ide_wait_ready(io))
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
outb(io + ATA_REG_COMMAND, 0xE7);
|
||||
|
||||
if (ide_wait(io, 0)) {
|
||||
printf("FLUSH CACHE timeout, status=0x%02X\n", inb(io + ATA_REG_STATUS));
|
||||
return -4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -53,7 +53,7 @@ void exception_dispatcher(uint32_t int_no, uint32_t err_code)
|
||||
case 14:
|
||||
{
|
||||
uint32_t cr2;
|
||||
__asm__ volatile ("mov %%cr2, %0" : "=r"(cr2));
|
||||
asm volatile ("mov %%cr2, %0" : "=r"(cr2));
|
||||
printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code);
|
||||
break;
|
||||
}
|
||||
@ -70,7 +70,13 @@ void exception_dispatcher(uint32_t int_no, uint32_t err_code)
|
||||
|
||||
printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss);
|
||||
|
||||
__asm__ volatile ("cli; hlt");
|
||||
asm volatile ("cli; hlt");
|
||||
|
||||
/* Will never be reached */
|
||||
while (true)
|
||||
{
|
||||
asm volatile ("hlt" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -89,29 +95,29 @@ void pic_remap(void)
|
||||
{
|
||||
uint8_t a1, a2;
|
||||
|
||||
// Save masks
|
||||
/* Save masks */
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
// Start initialization sequence (in cascade mode)
|
||||
/* Start initialization sequence (in cascade mode) */
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
// Set vector offset
|
||||
outb(PIC1_DATA, 0x20); // IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39)
|
||||
outb(PIC2_DATA, 0x28); // IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47)
|
||||
/* Set vector offset */
|
||||
outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */
|
||||
outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */
|
||||
|
||||
// Tell Master PIC about Slave PIC at IRQ2 (0000 0100)
|
||||
/* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */
|
||||
outb(PIC1_DATA, 0x04);
|
||||
|
||||
// Tell Slave PIC its cascade identity (0000 0010)
|
||||
/* Tell Slave PIC its cascade identity (0000 0010) */
|
||||
outb(PIC2_DATA, 0x02);
|
||||
|
||||
// Set 8086/88 mode
|
||||
/* Set 8086/88 mode */
|
||||
outb(PIC1_DATA, 0x01);
|
||||
outb(PIC2_DATA, 0x01);
|
||||
|
||||
// Restore saved masks
|
||||
/* Restore saved masks */
|
||||
outb(PIC1_DATA, a1);
|
||||
outb(PIC2_DATA, a2);
|
||||
}
|
||||
@ -123,19 +129,19 @@ void idt_init(void)
|
||||
|
||||
for (uint8_t vector = 0; vector < 32; vector++)
|
||||
{
|
||||
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
||||
vectors[vector] = true;
|
||||
idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
|
||||
vectors[vector] = true;
|
||||
}
|
||||
|
||||
extern void* irq_stub_table[];
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
|
||||
idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E);
|
||||
}
|
||||
|
||||
|
||||
__asm__ volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
||||
__asm__ volatile ("sti"); /* set the interrupt flag */
|
||||
asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */
|
||||
asm volatile ("sti"); /* set the interrupt flag */
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ static void append_char(char c)
|
||||
{
|
||||
if (current_length + 1 >= capacity)
|
||||
{
|
||||
/* Need more space (+1 for '\0') */
|
||||
/* Need more space (+1 for the null zero) */
|
||||
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
|
||||
|
||||
char* new_str = (char*)malloc(new_capacity);
|
||||
@ -92,6 +92,11 @@ static void append_char(char c)
|
||||
memcpy(new_str, current_string, current_length);
|
||||
free(current_string);
|
||||
}
|
||||
|
||||
if (!current_string)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current_string = new_str;
|
||||
capacity = new_capacity;
|
||||
@ -147,6 +152,12 @@ void keyboard_handler(void) {
|
||||
{
|
||||
c = (char) terminal_get_shifted((unsigned char) c);
|
||||
}
|
||||
|
||||
if (scancode == 0x1C) {
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (c)
|
||||
{
|
||||
@ -164,3 +175,4 @@ void keyboard_handler(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ void terminal_putchar(const char c)
|
||||
{
|
||||
terminal_row -= 1;
|
||||
|
||||
if (terminal_row <= -1)
|
||||
if (terminal_row == (size_t)-1)
|
||||
{
|
||||
terminal_row = 0;
|
||||
}
|
||||
@ -246,3 +246,4 @@ unsigned char terminal_get_shifted(unsigned char uc)
|
||||
|
||||
return '\0';
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user