13 Commits

Author SHA1 Message Date
bbb91f4afa Create fat16.c
Add implementation for fat16 filesystem
2026-01-18 18:11:25 -08:00
06c49171cf Create fat16.h
Add fat16 filesystem support.
2026-01-18 18:07:55 -08:00
b6c158957e Merge pull request #95 from shoshta73/qol
[misc] add editorconfig, clangd config and clang-format config
2026-01-18 16:46:05 -08:00
Borna Šoštarić
a7b0d1152f add rules for formatting consecutives 2026-01-18 10:54:18 +01:00
Borna Šoštarić
e38f1aa2ee add .clang-format 2026-01-18 10:40:34 +01:00
Borna Šoštarić
78d5e9a7ab added editorconfig file 2026-01-18 10:18:23 +01:00
Borna Šoštarić
daead5ee57 add clangd config file 2026-01-18 10:15:38 +01:00
Borna Šoštarić
4fb81d2e57 add compile_commands.json genereation 2026-01-18 10:10:39 +01:00
19f7c7b213 Merge pull request #93 from vmttmv/fix/91-header-cleanup
Remove types.c/.h, use klibc headers, amend stdbool.h, reimplement cpuid()
2026-01-13 07:40:03 -08:00
bc9d84a93e Merge branch 'main' into fix/91-header-cleanup 2026-01-13 07:39:46 -08:00
9066ceaddb Merge pull request #94 from vmttmv/fix/92-paging
Fix PDE/PTE definitions, header cleanup
2026-01-13 07:29:27 -08:00
vmttmv
3b67e81ed0 Fix PDE/PTE definitions, header cleanup
- Fixes PDE/PTE definitions in kernel/paging.h
- removes memset declaration from kernel/utils.h, uses klibc string.h as
needed
2026-01-12 04:02:15 +02:00
vmttmv
841892398a Remove types.c/.h, use klibc headers, amend stdbool.h, reimplement cpuid() 2026-01-12 02:43:37 +02:00
17 changed files with 266 additions and 126 deletions

24
.clang-format Normal file
View File

@@ -0,0 +1,24 @@
BasedOnStyle: Google
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 80
DerivePointerAlignment: false
PointerAlignment: Right
ReferenceAlignment: Right
AlignConsecutiveMacros: Consecutive
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
IncludeBlocks: Regroup
IncludeCategories:
# Std headers
- Regex: '<[[:alnum:]_.]+>'
Priority: 2
# Other headers
- Regex: '.*'
Priority: 1

6
.clangd Normal file
View File

@@ -0,0 +1,6 @@
CompileFlags:
CompilationDatabase: build
Diagnostics:
UnusedIncludes: Strict
MissingIncludes: Strict

12
.editorconfig Normal file
View File

@@ -0,0 +1,12 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[Makefile]
indent_style = tab
indent_size = 8
tab_width = 8

View File

@@ -18,9 +18,9 @@ KERNEL_OBJ += $(patsubst kernel/%.asm, $(BUILD_DIR)/asm_%.o, $(KERNEL_ASM_SRC))
KLIBC_SRC = $(wildcard klibc/src/*.c)
KLIBC_OBJ = $(patsubst klibc/src/%.c, $(BUILD_DIR)/klibc/%.o, $(KLIBC_SRC))
.PHONY: all stage1 stage2 kernel compile-commands $(BUILD_DIR)/compile_commands.json run gdb clean clean-cross clean-all
all: $(DISK_IMG)
.PHONY: stage1 stage2 kernel run gdb clean
stage1: $(BUILD_DIR)
$(AS) $(ASFLAGS) -o $(BUILD_DIR)/$@.o bootloader/$@.asm
$(LD) -Ttext=0x7c00 -melf_i386 -o $(BUILD_DIR)/$@.elf $(BUILD_DIR)/$@.o
@@ -57,6 +57,10 @@ $(BUILD_DIR):
mkdir -p $@
mkdir -p $(BUILD_DIR)/klibc
compile-commands: $(BUILD_DIR)/compile_commands.json
$(BUILD_DIR)/compile_commands.json: $(BUILD_DIR)
bear --output $@ -- make -B
run:
qemu-system-i386 -s -S $(DISK_IMG)

View File

@@ -3,6 +3,14 @@
#include "terminal.h"
#include "utils.h"
void cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
__asm__(
"cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(leaf)
);
}
// Helper to print a labeled decimal value
void print_val(const char* label, uint32_t val) {
char buf[12];

107
kernel/fat16.c Normal file
View File

@@ -0,0 +1,107 @@
#include "fat16.h"
#include "ata.h" // Use ata_read_sector and ata_write_sector
#include "print.h" // For debugging
#include <string.h> // For string manipulation
// Global variables
static fat16_boot_sector_t boot_sector;
static uint32_t root_dir_sector = FAT16_ROOT_DIR_SECTOR;
// Read a sector from the disk using ATA
bool read_sector(uint32_t lba, uint8_t* buffer) {
return ata_read_sector(lba, buffer);
}
// Write a sector to the disk using ATA
bool write_sector(uint32_t lba, const uint8_t* buffer) {
return ata_write_sector(lba, buffer);
}
// Parse the boot sector to retrieve basic file system info
bool parse_fat16_boot_sector(void) {
uint8_t sector_buffer[FAT16_SECTOR_SIZE];
// Read the boot sector
if (!read_sector(FAT16_BOOT_SECTOR, sector_buffer)) {
print_string("[FAT16] Failed to read boot sector\n");
return false;
}
// Cast to boot sector structure
memcpy(&boot_sector, sector_buffer, sizeof(fat16_boot_sector_t));
// Check for FAT16 signature
if (boot_sector.oem_name[0] != 'F' || boot_sector.oem_name[1] != 'A' || boot_sector.oem_name[2] != 'T') {
print_string("[FAT16] Invalid FAT16 boot sector signature\n");
return false;
}
print_string("[FAT16] FAT16 boot sector parsed successfully\n");
return true;
}
// Parse the root directory
bool parse_fat16_root_dir(void) {
uint8_t sector_buffer[FAT16_SECTOR_SIZE];
for (int i = 0; i < (boot_sector.max_root_entries / (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t))); i++) {
// Read root directory sector
if (!read_sector(root_dir_sector + i, sector_buffer)) {
print_string("[FAT16] Failed to read root directory sector\n");
return false;
}
// Parse the root directory entries
for (int j = 0; j < (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t)); j++) {
fat16_dir_entry_t* entry = (fat16_dir_entry_t*)&sector_buffer[j * sizeof(fat16_dir_entry_t)];
if (entry->name[0] == 0x00) {
// End of directory entries
return true;
}
if (entry->name[0] != 0xE5) {
// Print file name (8.3 format)
char filename[12];
strncpy(filename, (char*)entry->name, 8);
filename[8] = '.';
strncpy(&filename[9], (char*)entry->ext, 3);
filename[11] = '\0';
print_string(filename);
print_string("\n");
}
}
}
return true;
}
// Read a specific directory entry from the FAT16 root directory
bool read_fat16_entry(uint16_t entry_index, fat16_dir_entry_t* entry) {
uint8_t sector_buffer[FAT16_SECTOR_SIZE];
uint32_t sector_num = FAT16_ROOT_DIR_SECTOR + (entry_index / (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t)));
uint16_t entry_offset = entry_index % (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t));
// Read the sector
if (!read_sector(sector_num, sector_buffer)) {
print_string("[FAT16] Failed to read root directory sector\n");
return false;
}
// Get the entry
memcpy(entry, &sector_buffer[entry_offset * sizeof(fat16_dir_entry_t)], sizeof(fat16_dir_entry_t));
return true;
}
// Mount the FAT16 filesystem
bool mount_fat16(void) {
// Parse the boot sector
if (!parse_fat16_boot_sector()) {
return false;
}
// Parse the root directory
if (!parse_fat16_root_dir()) {
return false;
}
print_string("[FAT16] Filesystem mounted successfully\n");
return true;
}

60
kernel/fat16.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef FAT16_H
#define FAT16_H
#include <stdint.h>
#include <stdbool.h>
/* FAT16 Constants */
#define FAT16_SECTOR_SIZE 512
#define FAT16_CLUSTER_SIZE 1
#define FAT16_MAX_FILENAME_LEN 11 // 8.3 format
#define FAT16_ROOT_DIR_ENTRIES 224 // Fat16 root directory entries (typically 512 bytes per entry)
#define FAT16_BOOT_SECTOR 0
#define FAT16_FAT1_SECTOR 1
#define FAT16_FAT2_SECTOR 2
#define FAT16_ROOT_DIR_SECTOR 19 // First sector of root directory
/* Boot Sector */
typedef struct {
uint8_t jmp[3]; // Jump instruction to code
uint8_t oem_name[8]; // OEM Name
uint16_t bytes_per_sector; // Bytes per sector (512)
uint8_t sectors_per_cluster; // Sectors per cluster
uint16_t reserved_sectors; // Reserved sectors
uint8_t num_fats; // Number of FAT tables
uint16_t max_root_entries; // Max number of root directory entries
uint16_t total_sectors_16; // Total sectors in FAT16
uint8_t media_type; // Media type (0xF8 = fixed drive)
uint16_t sectors_per_fat; // Sectors per FAT table
uint16_t sectors_per_track; // Sectors per track (for CHS addressing)
uint16_t num_heads; // Number of heads (for CHS addressing)
uint32_t hidden_sectors; // Hidden sectors (before the partition)
uint32_t total_sectors_32; // Total sectors in FAT16 (extended)
} __attribute__((packed)) fat16_boot_sector_t;
/* FAT16 Directory Entry */
typedef struct {
uint8_t name[8]; // File name (8 chars)
uint8_t ext[3]; // File extension (3 chars)
uint8_t attributes; // File attributes (e.g., directory, read-only)
uint8_t reserved; // Reserved
uint8_t creation_time[2]; // Creation time
uint8_t creation_date[2]; // Creation date
uint8_t last_access_date[2]; // Last access date
uint8_t first_cluster_high[2]; // High part of first cluster number
uint8_t last_mod_time[2]; // Last modification time
uint8_t last_mod_date[2]; // Last modification date
uint8_t first_cluster_low[2]; // Low part of first cluster number
uint32_t file_size; // File size in bytes
} __attribute__((packed)) fat16_dir_entry_t;
/* Function Prototypes */
bool mount_fat16(void);
bool read_sector(uint32_t lba, uint8_t* buffer);
bool write_sector(uint32_t lba, const uint8_t* buffer);
bool parse_fat16_boot_sector(void);
bool parse_fat16_root_dir(void);
bool read_fat16_entry(uint16_t entry_index, fat16_dir_entry_t* entry);
#endif // FAT16_H

View File

@@ -1,7 +1,7 @@
#ifndef IRQ_H
#define IRQ_H
#include "types.h"
#include <stdint.h>
void irq_remap(void);
void irq_install(void);

View File

@@ -1,3 +1,4 @@
#include <stdbool.h>
#include "terminal.h"
#include "serial.h"
#include "isr.h"

View File

@@ -1,21 +1,17 @@
#include "paging.h"
#include "io.h"
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "io.h"
#include "paging.h"
page_directory_entry_t *page_directory = (page_directory_entry_t *)0x200000;
page_table_entry_t *page_table = (page_table_entry_t *)0x201000;
page_table_entry_t *heap_page_table = (page_table_entry_t *)0x202000;
// Helper function to set up the page directory entry
void set_page_directory(page_directory_entry_t *dir) {
for (int i = 0; i < PAGE_DIRECTORY_SIZE; i++) {
dir[i].present = 0;
}
// Set first PDE
dir[0].present = 1;
dir[0].rw = 1;
dir[0].user = 0;
dir[0].frame = (uint32_t)page_table >> 12;
dir[0].addr = (uint32_t)page_table >> 12;
}
// Helper function to set up the page table entry
@@ -23,12 +19,8 @@ void set_page_table(page_table_entry_t *table) {
for (int i = 0; i < PAGE_TABLE_SIZE; i++) {
// Set up page table entries with identity mapping
table[i].present = 1;
table[i].rw = 1; // Read/Write
table[i].user = 0; // Kernel mode
table[i].write_through = 0;
table[i].cache_disabled = 0;
table[i].accessed = 0;
table[i].frame = i; // Identity mapping
table[i].rw = 1; // Read/Write
table[i].addr = i; // Identity mapping
}
}
@@ -47,26 +39,13 @@ void enable_paging() {
// Initialize paging: set up the page directory and enable paging
void paging_init() {
// Zero out the tables
memset(page_directory, 0x00, PAGE_DIRECTORY_SIZE * sizeof *page_directory);
memset(page_table, 0x00, PAGE_TABLE_SIZE * sizeof *page_table);
// Set up identity-mapped page directory + table
set_page_directory(page_directory);
set_page_table(page_table);
// === Set up heap mapping at 0xC0100000 ===
for (int i = 0; i < PAGE_TABLE_SIZE; i++) {
heap_page_table[i].present = 1;
heap_page_table[i].rw = 1;
heap_page_table[i].user = 0;
heap_page_table[i].write_through = 0;
heap_page_table[i].cache_disabled = 0;
heap_page_table[i].accessed = 0;
heap_page_table[i].frame = (256 + i); // Start physical heap at 1MB (256*4KB = 1MB)
}
// Index 772 = 0xC0100000 / 4MB
page_directory[772].present = 1;
page_directory[772].rw = 1;
page_directory[772].user = 0;
page_directory[772].frame = (uint32_t)heap_page_table >> 12;
enable_paging();
}

View File

@@ -10,31 +10,31 @@
// Page Directory and Page Table structure
typedef struct {
uint32_t present : 1; // Present bit (1: page is present in memory)
uint32_t rw : 1; // Read-Write bit (1: page is read-write)
uint32_t user : 1; // User-supervisor bit (1: user mode access)
uint32_t write_through : 1; // Write-through cache
uint32_t cache_disabled : 1; // Cache disabled
uint32_t accessed : 1; // Accessed bit
uint32_t reserved : 1; // Reserved bit
uint32_t page_size : 1; // Page size (0: 4KB, 1: 4MB)
uint32_t global : 1; // Global page (can be used across different processes)
uint32_t available : 3; // Available bits for the system
uint32_t frame : 20; // Frame address (physical address)
uint32_t present : 1; // Present bit (1: page is present in memory)
uint32_t rw : 1; // Read-Write bit (1: page is read-write)
uint32_t user : 1; // User-supervisor bit (1: user mode access)
uint32_t write_through : 1; // Write-through cache
uint32_t cache_disabled : 1; // Cache disabled
uint32_t accessed : 1; // Accessed bit
uint32_t dirty : 1; // Dirty bit
uint32_t attribute : 1; // Page size (0: 4KB, 1: 4MB)
uint32_t global : 1; // Global page (can be used across different processes)
uint32_t reserved : 3; // Unused
uint32_t addr : 20; // Page frame address (physical address)
} __attribute__((packed)) page_table_entry_t;
// Define page directory entry
typedef struct {
uint32_t present : 1;
uint32_t rw : 1;
uint32_t user : 1;
uint32_t write_through : 1;
uint32_t cache_disabled : 1;
uint32_t accessed : 1;
uint32_t reserved : 1;
uint32_t zero : 5; // Must be zero for page directory
uint32_t reserved_2 : 7; // Reserved bits
uint32_t frame : 20; // Frame address of the page table
uint32_t present : 1; // Present bit (1: PTE is present in memory)
uint32_t rw : 1; // Read-Write bit (1: pages are read-write)
uint32_t user : 1; // User-supervisor bit (1: user mode access)
uint32_t write_through : 1; // Write-through cache
uint32_t cache_disabled : 1; // Cache disabled
uint32_t accessed : 1; // Accessed bit
uint32_t available : 1; // Unused
uint32_t page_size : 1; // Page size (0: 4KB, 1: 4MB)
uint32_t available_2 : 4; // Unused
uint32_t addr : 20; // Page table address
} __attribute__((packed)) page_directory_entry_t;
extern page_directory_entry_t *page_directory;

View File

@@ -1,7 +1,7 @@
#ifndef PRINT_H
#define PRINT_H
#include "types.h"
#include <stdint.h>
void print_string(const char *str);
void my_printf(const char *format, ...);

View File

@@ -1,9 +1,8 @@
#include <stdbool.h>
#include <string.h>
#include "malloc.h"
#include "print.h"
#include "threading.h"
#include "types.h"
#include "utils.h"
#include <stdint.h>
#define MAX_THREADS 16 // Maximum number of threads
#define THREAD_STACK_SIZE 8192 // Stack size for each thread

View File

@@ -1 +0,0 @@
#include "types.h"

View File

@@ -1,61 +0,0 @@
#ifndef TYPES_H
#define TYPES_H
// ----------------------------
// Fixed-width integer types
// ----------------------------
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef unsigned long long uint64_t;
typedef signed long long int64_t;
// ----------------------------
// Boolean & NULL definitions
// ----------------------------
#ifndef __cplusplus
typedef enum { false = 0, true = 1 } bool;
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
// ----------------------------
// OS subsystem types
// ----------------------------
typedef int32_t ssize_t;
typedef uint32_t phys_addr_t; // Physical address
typedef uint32_t virt_addr_t; // Virtual address
typedef uint32_t pid_t; // Process ID
typedef uint32_t tid_t; // Thread ID
// ----------------------------
// Bitfield & utility macros
// ----------------------------
#define BIT(n) (1U << (n))
#define BITS(m, n) (((1U << ((n) - (m) + 1)) - 1) << (m))
// Align value to next multiple of alignment
#define ALIGN_UP(val, align) (((val) + ((align)-1)) & ~((align)-1))
#define ALIGN_DOWN(val, align) ((val) & ~((align)-1))
// ----------------------------
// Attributes for structures
// ----------------------------
#define PACKED __attribute__((packed))
#define ALIGN(x) __attribute__((aligned(x)))
// ----------------------------
// Likely/unlikely branch hints
// (for future optimization use)
// ----------------------------
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif // TYPES_H

View File

@@ -3,14 +3,10 @@
#include <stddef.h>
#include "types.h"
// Convert integer to string (base is typically 10, 16, etc.)
char* itoa(int value, char* str, int base);
// Convert unsigned integer to string (base is typically 10, 16, etc.)
char* utoa(unsigned int value, char* str, int base);
void *memset(void *dest, int value, size_t len);
#endif // UTILS_H

View File

@@ -1,6 +1,12 @@
#ifndef CLASSICOS_KLIBC_STDBOOL_H
#define CLASSICOS_KLIBC_STDBOOL_H
typedef enum { false = 0, true = 1 } bool;
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#endif
#define __bool_true_false_are_defined 1
#endif // CLASSICOS_KLIBC_STDBOOL_H