slight progress

This commit is contained in:
Conál Paxton 2026-03-06 20:37:10 -05:00
parent dd2f204ab5
commit 897dced938
14 changed files with 555 additions and 233 deletions

BIN
bin/os

Binary file not shown.

BIN
image.hdd

Binary file not shown.

View File

@ -28,5 +28,5 @@ mcopy -i image.hdd@@1M bin/os ::/boot
mcopy -i image.hdd@@1M limine.conf limine/limine-bios.sys ::/boot/limine mcopy -i image.hdd@@1M limine.conf limine/limine-bios.sys ::/boot/limine
mcopy -i image.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT mcopy -i image.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT
mcopy -i image.hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT mcopy -i image.hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT
mcopy -i image.hdd@@1M mnt/usr/bin/test ::/usr/bin/test mcopy -i image.hdd@@1M mnt/usr/bin/test.o ::/usr/bin/test
mcopy -i image.hdd@@1M fortune ::/fort/fortu.ne mcopy -i image.hdd@@1M fortune ::/fort/fortu.ne

View File

@ -1,5 +1,7 @@
obj/src/int.c.o: src/int.c src/apic.h src/common.h src/print.h src/kbd.h \ obj/src/int.c.o: src/int.c src/apic.h src/common.h src/print.h src/kbd.h \
src/syscalls.h src/lib/sys.h src/int.h src/lib/stdio.h src/lib/malloc.h src/syscalls.h src/lib/sys.h src/int.h src/lib/stdio.h \
src/lib/malloc.h src/lib/../common.h src/lib/../kbd.h \
src/lib/../print.h
src/apic.h: src/apic.h:
src/common.h: src/common.h:
src/print.h: src/print.h:
@ -9,3 +11,6 @@ src/lib/sys.h:
src/int.h: src/int.h:
src/lib/stdio.h: src/lib/stdio.h:
src/lib/malloc.h: src/lib/malloc.h:
src/lib/../common.h:
src/lib/../kbd.h:
src/lib/../print.h:

Binary file not shown.

View File

@ -1,12 +1,14 @@
obj/src/main.c.o: src/main.c src/../include/limine.h src/prompt/lex.h \ obj/src/main.c.o: src/main.c src/../include/limine.h src/prompt/lex.h \
src/prompt/file.h src/prompt/file.h src/acpi.h src/common.h src/ahci.h \ src/prompt/file.h src/acpi.h src/common.h src/ahci.h src/alloc.h \
src/alloc.h src/apic.h src/fat32.h src/lib/ctype.h src/lib/string.h \ src/apic.h src/fat32.h src/lib/ctype.h src/lib/string.h \
src/lib/../lib/stdio.h src/lib/../lib/malloc.h src/lib/../lib/../kbd.h \ src/lib/../lib/stdio.h src/lib/../lib/malloc.h \
src/lib/../lib/../print.h src/lib/elf/elf64.h src/lib/../lib/../common.h src/lib/../lib/../kbd.h \
src/lib/../lib/../print.h src/lib/stdio.h src/print.h \
src/lib/elf/elf64.h src/lib/elf/../../common.h \
src/lib/elf/../../lib/stdio.h src/lib/elf/../../lib/malloc.h
src/../include/limine.h: src/../include/limine.h:
src/prompt/lex.h: src/prompt/lex.h:
src/prompt/file.h: src/prompt/file.h:
src/prompt/file.h:
src/acpi.h: src/acpi.h:
src/common.h: src/common.h:
src/ahci.h: src/ahci.h:
@ -17,6 +19,12 @@ src/lib/ctype.h:
src/lib/string.h: src/lib/string.h:
src/lib/../lib/stdio.h: src/lib/../lib/stdio.h:
src/lib/../lib/malloc.h: src/lib/../lib/malloc.h:
src/lib/../lib/../common.h:
src/lib/../lib/../kbd.h: src/lib/../lib/../kbd.h:
src/lib/../lib/../print.h: src/lib/../lib/../print.h:
src/lib/stdio.h:
src/print.h:
src/lib/elf/elf64.h: src/lib/elf/elf64.h:
src/lib/elf/../../common.h:
src/lib/elf/../../lib/stdio.h:
src/lib/elf/../../lib/malloc.h:

Binary file not shown.

View File

@ -61,27 +61,32 @@ void load_idt(void *addr) {
extern void draw(u8 vect); extern void draw(u8 vect);
struct cpu_ctx *interrupt_dispatch(struct cpu_ctx* ctx) { struct cpu_ctx *interrupt_dispatch(struct cpu_ctx* ctx) {
if(ctx->vect == 0x21) { if(ctx->vect == 0x21) {
kbd_handler(); kbd_handler();
return ctx; return ctx;
} }
if(ctx->vect == 0x80) { if(ctx->vect == 0x80) {
print("SYSCALL\n");
syscall_handler(ctx); syscall_handler(ctx);
return ctx; return ctx;
} }
print("COMING THROUGH");
print("\n[IRQ "); print("\n[IRQ ");
print8(ctx->vect); print8(ctx->vect);
print("] with err: "); print("] with err: ");
print64(ctx->err); print64(ctx->err);
print(" and cr2: ");
u64 cr2;
asm volatile("mov %%cr2, %0" : "=r"(cr2));
print64(cr2);
printf(" rip: 0x");
print64(ctx->iret_rip);
print("\n"); print("\n");
if(ctx->vect == 0x0D || ctx->vect == 0x0E) { if(ctx->vect < 0x10)
while(1); while(1);
}
return ctx; return ctx;
} }

View File

@ -72,23 +72,23 @@ char kbd_buffer_getc() {
return c; return c;
} }
static u8 held_map[0x100/16]; u8 kbd_held_map[0x100/16];
static void hold_key(u8 key) { static void hold_key(u8 key) {
key &= (0x100/2)-1; key &= (0x100/2)-1;
held_map[key>>3] |= (1 << (key & 7)); kbd_held_map[key>>3] |= (1 << (key & 7));
} }
static void release_key(u8 key) { static void release_key(u8 key) {
key &= (0x100/2)-1; key &= (0x100/2)-1;
held_map[key>>3] &= ~(1 << (key & 7)); kbd_held_map[key>>3] &= ~(1 << (key & 7));
} }
static bool key_held(u8 key) { static bool key_held(u8 key) {
key &= (0x100/2)-1; key &= (0x100/2)-1;
return (held_map[key>>3] & (1 << (key & 7))); return (kbd_held_map[key>>3] & (1 << (key & 7)));
} }
void kbd_handler() { void kbd_handler() {

View File

@ -5,136 +5,273 @@
#include "../../lib/malloc.h" #include "../../lib/malloc.h"
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct elf64_header { typedef struct elf64_header {
u32 MAGIC; /* '\x7FELF' */ u32 MAGIC; /* '\x7FELF' as LE u32 = 0x464C457F */
enum : u8 { ELF32 = 1, ELF64 = 2} size; /* 1 for ELF32, 2 for ELF64 */
enum : u8 { ELF64_LE = 1, ELF64_BE = 2} endianness; /* 1 for little-endian, 2 for big-endian */ enum : u8 {
u8 version; /* ELF version */ ELF32 = 1,
u8 abi; /* ABI identification */ ELF64 = 2,
} size; /* 1 = ELF32, 2 = ELF64 */
enum : u8 {
ELF64_LE = 1,
ELF64_BE = 2,
} endianness; /* 1 = little-endian, 2 = big-endian */
u8 version; /* ELF spec version (always 1) */
u8 abi; /* OS/ABI identifier */
u8 abi_version; /* ABI version */ u8 abi_version; /* ABI version */
u8 padding[7]; /* Padding to align the structure */ u8 padding[7]; /* Reserved, must be zero */
enum : u16 { enum : u16 {
ELF_RELOC = 1, ELF_RELOC = 1, /* Relocatable object */
ELF_EXEC = 2, ELF_EXEC = 2, /* Executable */
ELF_SHARED = 3, ELF_SHARED = 3, /* Shared object */
ELF_CORe = 4, ELF_CORE = 4, /* Core dump */
} type; /* 1 for relocatable, 2 for executable, 3 for shared, 4 for core */ } type;
u16 instruction_set; /* Architecture: e.g., EM_X86_64 = 62 */
u32 elf_version; /* Version of the ELF specification */ u16 instruction_set; /* Architecture (EM_X86_64 = 62) */
u64 prog_entry_offset; /* Entry point address */ u32 elf_version; /* ELF version (always 1) */
u64 prog_header_table_offset; /* Program header table offset */ u64 prog_entry_offset; /* Virtual entry-point address */
u64 sect_header_table_offset; /* Section header table offset */ u64 prog_header_table_offset;/* Offset of program header table */
u64 sect_header_table_offset;/* Offset of section header table */
u32 flags; /* Processor-specific flags */ u32 flags; /* Processor-specific flags */
u16 header_size; /* Size of this header */ u16 header_size; /* Size of this header (64 bytes) */
u16 prog_entry_size; /* Size of program entry */ u16 prog_entry_size; /* Size of one program header entry */
u16 prog_entry_count; /* Number of program entries */ u16 prog_entry_count; /* Number of program header entries */
u16 sect_entry_size; /* Size of section entry */ u16 sect_entry_size; /* Size of one section header entry */
u16 sect_entry_count; /* Number of section entries */ u16 sect_entry_count; /* Number of section header entries */
u16 sect_index; /* Index of the section header string table */ u16 sect_index; /* Section-name string table index */
} elf64_header_t; } elf64_header_t;
typedef struct elf64_prog_header { typedef struct elf64_prog_header {
enum : u32 { enum : u32 {
ELF64_IGNORE, ELF64_PT_NULL = 0,
ELF64_LOAD, ELF64_PT_LOAD = 1,
ELF64_DYNAMIC, ELF64_PT_DYNAMIC = 2,
ELF64_INTERP, ELF64_PT_INTERP = 3,
ELF64_NOTE, ELF64_PT_NOTE = 4,
} type; } type;
enum : u32 { ELF64_X = 1, ELF64_W = 2, ELF64_R = 4} flags; enum : u32 {
u64 data_offset; ELF64_PF_X = 1,
u64* vmem_start; ELF64_PF_W = 2,
u64 seg_phys; ELF64_PF_R = 4,
u64 seg_filesize; } flags;
u64 seg_memsize; u64 data_offset; /* Offset of segment data in file */
u64 req_alignment; u64 *vmem_start; /* Desired virtual load address */
u64 seg_phys; /* Physical address (often ignored) */
u64 seg_filesize; /* Bytes in file image of segment */
u64 seg_memsize; /* Bytes in memory image (>= filesize) */
u64 req_alignment; /* Required alignment (power of 2) */
} elf64_prog_header_t; } elf64_prog_header_t;
typedef struct elf64_sect_header { typedef struct elf64_sect_header {
u32 name_offset; u32 name_offset; /* Offset into .shstrtab */
enum : u32 { enum : u32 {
SHT_NULL = 0, SHT_NULL = 0, /* Inactive section */
SHT_PROGBITS = 1, SHT_PROGBITS = 1, /* Program-defined data (.text, .data, …) */
SHT_SYMTAB = 2, SHT_SYMTAB = 2, /* Full symbol table */
SHT_STRTAB = 3, SHT_STRTAB = 3, /* String table */
SHT_RELA = 4, SHT_RELA = 4, /* Relocation with explicit addends */
SHT_NOBITS = 8, SHT_HASH = 5, /* Symbol hash table */
SHT_REL = 9, SHT_DYNAMIC = 6, /* Dynamic linking info */
SHT_NOTE = 7, /* Notes */
SHT_NOBITS = 8, /* Occupies no file space (.bss) */
SHT_REL = 9, /* Relocation without explicit addends */
SHT_DYNSYM = 11, /* Dynamic linker symbol table */
} type; } type;
u64 flags; u64 flags;
u64 addr; u64 addr; /* Load address (0 for relocatable) */
u64 offset; // offset in file u64 offset; /* Offset of section data in file */
u64 size; u64 size; /* Size of section data in file */
u32 link; // for RELA: index of associated symbol table section u32 link; /* Section link index (type-dependent) */
u32 info; // for RELA: index of section the relocations apply to u32 info; /* Extra info (type-dependent) */
u64 addralign; u64 addralign; /* Required alignment (power of 2) */
u64 entsize; u64 entsize; /* Size of fixed-size entries, if any */
} elf64_sect_header_t; } elf64_sect_header_t;
/* Section-header flags */
#define SHF_WRITE 0x1ULL /* Writable at runtime */
#define SHF_ALLOC 0x2ULL /* Occupies memory at runtime */
#define SHF_EXECINSTR 0x4ULL /* Contains executable instructions */
typedef struct elf64_sym { typedef struct elf64_sym {
u32 name_offset; u32 name_offset; /* Offset into owning string table */
u8 info; // binding (high 4) + type (low 4) u8 info; /* Binding (high 4 bits) | Type (low 4 bits) */
u8 other; u8 other; /* Visibility (low 2 bits) */
u16 sect_index; u16 sect_index; /* Section index (SHN_* or section number) */
u64 value; // offset within its section for relocatable files u64 value; /* Symbol value / offset within section */
u64 size; u64 size; /* Size of the object / function */
} elf64_sym_t; } elf64_sym_t;
typedef struct elf64_rela { typedef struct elf64_rela {
u64 offset; // offset within the target section to patch u64 offset; /* Offset within target section to patch */
u64 info; // symbol index (high 32) + relocation type (low 32) u64 info; /* Symbol index (high 32) | type (low 32) */
i64 addend; i64 addend; /* Explicit addend */
} elf64_rela_t; } elf64_rela_t;
#pragma pack(pop) #pragma pack(pop)
#define ELF_MAGIC 0x464C457F // '\x7FELF' as little-endian u32 #define ELF_MAGIC 0x464C457FU /* '\x7FELF' in little-endian u32 */
#define R_X86_64_64 1 // S + A
#define R_X86_64_PC32 2 // S + A - P
#define R_X86_64_PLT32 4 // S + A - P (treat same as PC32 for static)
#define R_X86_64_32 10 // S + A (zero-extend to 64)
#define R_X86_64_32S 11 // S + A (sign-extend to 64)
#define RELA_SYM(info) ((info) >> 32) /* x86-64 relocation types (System V ABI) */
#define R_X86_64_NONE 0 /* No relocation */
#define R_X86_64_64 1 /* S + A (64-bit) */
#define R_X86_64_PC32 2 /* S + A - P (32-bit PC-relative) */
#define R_X86_64_GOT32 3 /* G + A (32-bit GOT offset) */
#define R_X86_64_PLT32 4 /* L + A - P (treated as PC32 for static linking) */
#define R_X86_64_32 10 /* S + A, zero-extend to 64 bits */
#define R_X86_64_32S 11 /* S + A, sign-extend to 64 bits */
#define R_X86_64_PC64 24 /* S + A - P (64-bit PC-relative) */
/* Special section indices */
#define SHN_UNDEF 0 /* Undefined / external symbol */
#define SHN_ABS 0xFFF1U /* Absolute value, not relocated */
#define SHN_COMMON 0xFFF2U /* Common block */
/* Symbol binding (high 4 bits of info) */
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define ELF64_ST_BIND(info) ((info) >> 4)
/* Symbol type (low 4 bits of info) */
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define ELF64_ST_TYPE(info) ((info) & 0xFU)
/* Symbol visibility (low 2 bits of other) */
#define STV_DEFAULT 0
#define STV_INTERNAL 1
#define STV_HIDDEN 2
#define STV_PROTECTED 3
/* Pack/unpack rela.info */
#define RELA_SYM(info) ((u64)(info) >> 32)
#define RELA_TYPE(info) ((u32)(info)) #define RELA_TYPE(info) ((u32)(info))
#define RELA_INFO(sym, type) (((u64)(sym) << 32) | (u32)(type))
/* Validate an ELF64 LE x86-64 header. */
static bool elf64_validate(const elf64_header_t *hdr) { static bool elf64_validate(const elf64_header_t *hdr) {
return !((hdr->MAGIC != ELF_MAGIC) if (!hdr) {
|| (hdr->size != ELF64) printf("elf64_validate: NULL header\n");
|| (hdr->endianness != ELF64_LE) return false;
|| (hdr->instruction_set != 62)); }
if (hdr->MAGIC != ELF_MAGIC) {
printf("elf64_validate: bad magic 0x%08X\n", hdr->MAGIC);
return false;
}
if (hdr->size != ELF64) {
printf("elf64_validate: not a 64-bit ELF (class=%u)\n", (u32)hdr->size);
return false;
}
if (hdr->endianness != ELF64_LE) {
printf("elf64_validate: not little-endian (data=%u)\n", (u32)hdr->endianness);
return false;
}
if (hdr->instruction_set != 62) {
printf("elf64_validate: unexpected ISA %u (expected 62 = x86-64)\n",
(u32)hdr->instruction_set);
return false;
}
if (hdr->version != 1 || hdr->elf_version != 1) {
printf("elf64_validate: unexpected ELF version\n");
return false;
}
return true;
} }
/* Pointer arithmetic from the raw ELF image base. */
static inline void *elf_off(const elf64_header_t *hdr, u64 offset) { static inline void *elf_off(const elf64_header_t *hdr, u64 offset) {
return (void *)((u8 *)hdr + offset); return (void *)((u8 *)hdr + offset);
} }
/* Return a pointer to section header i. */
static inline elf64_sect_header_t *elf_sect(const elf64_header_t *hdr, u64 i) { static inline elf64_sect_header_t *elf_sect(const elf64_header_t *hdr, u64 i) {
return (elf64_sect_header_t *)((u8 *)hdr return (elf64_sect_header_t *)((u8 *)hdr
+ hdr->sect_header_table_offset + hdr->sect_header_table_offset
+ i * hdr->sect_entry_size); + i * hdr->sect_entry_size);
} }
static u64 (*elf64_resolve_entry(const elf64_header_t* hdr, void** sect_bases)) () { /* Return the string table pointer for section i (must be SHT_STRTAB). */
u64 entry_offset = hdr->prog_entry_offset; static inline const char *elf_strtab(const elf64_header_t *hdr, u64 i) {
if (i == 0 || i >= hdr->sect_entry_count) return NULL;
elf64_sect_header_t *sh = elf_sect(hdr, i);
if (sh->type != SHT_STRTAB) return NULL;
return (const char *)elf_off(hdr, sh->offset);
}
/* Return a section's name from .shstrtab (NULL if unavailable). */
static inline const char *elf_sect_name(const elf64_header_t *hdr,
const elf64_sect_header_t *sh) {
const char *shstrtab = elf_strtab(hdr, hdr->sect_index);
if (!shstrtab) return "<no-shstrtab>";
return shstrtab + sh->name_offset;
}
static elf64_sect_header_t *elf64_section_by_name(const elf64_header_t *hdr,
const char *name) {
const char *shstrtab = elf_strtab(hdr, hdr->sect_index);
if (!shstrtab) return NULL;
for (u64 i = 0; i < hdr->sect_entry_count; i++) { for (u64 i = 0; i < hdr->sect_entry_count; i++) {
elf64_sect_header_t *sh = elf_sect(hdr, i); elf64_sect_header_t *sh = elf_sect(hdr, i);
if(!sect_bases[i]) continue; const char *sname = shstrtab + sh->name_offset;
if(entry_offset >= sh->addr && entry_offset < sh->addr + sh->size) /* Simple strcmp — replace with your lib's version if available. */
return (u64 (*)())((u8*) sect_bases[i] + (entry_offset - sh->addr)); const char *a = sname, *b = name;
while (*a && *a == *b) { a++; b++; }
if (*a == *b) return sh;
} }
// fallback: offset into sect 1 (.text)
printf("elf64_resolve_entry: using fallback offset into section 1 (.text)\n");
if (hdr->sect_entry_count > 1 && sect_bases[1])
return (u64 (*)())((u8 *)sect_bases[1] + entry_offset);
return NULL; return NULL;
} }
static u64 elf64_find_symtab_index(const elf64_header_t *hdr) {
u64 dynsym_idx = 0;
for (u64 i = 1; i < hdr->sect_entry_count; i++) {
elf64_sect_header_t *sh = elf_sect(hdr, i);
if (sh->type == SHT_SYMTAB) return i;
if (sh->type == SHT_DYNSYM && !dynsym_idx) dynsym_idx = i;
}
return dynsym_idx;
}
static const elf64_sym_t *elf64_lookup_symbol(const elf64_header_t *hdr,
const char *name,
u64 *sect_idx_out) {
u64 symtab_idx = elf64_find_symtab_index(hdr);
if (!symtab_idx) return NULL;
elf64_sect_header_t *sym_sh = elf_sect(hdr, symtab_idx);
elf64_sect_header_t *str_sh = elf_sect(hdr, sym_sh->link);
const char *strtab = (const char *)elf_off(hdr, str_sh->offset);
const elf64_sym_t *syms = (const elf64_sym_t *)elf_off(hdr, sym_sh->offset);
u64 n_syms = sym_sh->size / sizeof(elf64_sym_t);
for (u64 i = 0; i < n_syms; i++) {
const char *sname = strtab + syms[i].name_offset;
const char *a = sname, *b = name;
while (*a && *a == *b) { a++; b++; }
if (*a == *b) {
if (sect_idx_out) *sect_idx_out = symtab_idx;
return &syms[i];
}
}
return NULL;
}
/*
* Allocate memory for a single section and copy its data.
*
* - SHT_PROGBITS: allocate and copy from file image.
* - SHT_NOBITS : allocate and zero (calloc already does this).
* - Everything else: *out = NULL (no runtime allocation needed).
*/
static void elf64_alloc_section(const elf64_header_t *hdr, static void elf64_alloc_section(const elf64_header_t *hdr,
const elf64_sect_header_t *sh, const elf64_sect_header_t *sh,
void **out) { void **out) {
@ -145,26 +282,34 @@ static void elf64_alloc_section(const elf64_header_t *hdr,
void *mem = calloc(sh->size, 1); void *mem = calloc(sh->size, 1);
if (!mem) { if (!mem) {
print("elf64: calloc failed\n"); printf("elf64_alloc_section: calloc(%u) failed\n", (unsigned long long)sh->size);
return; return;
} }
if (sh->type == SHT_PROGBITS) { if (sh->type == SHT_PROGBITS) {
u8 *src = (u8 *)elf_off(hdr, sh->offset); const u8 *src = (const u8 *)elf_off(hdr, sh->offset);
u8 *dst = (u8 *)mem; u8 *dst = (u8 *)mem;
for (u64 b = 0; b < sh->size; b++) for (u64 b = 0; b < sh->size; b++)
dst[b] = src[b]; dst[b] = src[b];
} }
/* SHT_NOBITS (.bss) stays zeroed from calloc. */
*out = mem; *out = mem;
} }
/*
* Allocate and initialise all allocatable sections.
* Returns a heap-allocated array of (sect_entry_count) void* pointers.
* Non-allocatable sections have their pointer set to NULL.
* The caller must free this array (and each non-NULL element) when done.
*/
static void **elf64_alloc_sections(const elf64_header_t *hdr) { static void **elf64_alloc_sections(const elf64_header_t *hdr) {
u64 n = hdr->sect_entry_count; u64 n = hdr->sect_entry_count;
void **bases = calloc(n, sizeof(void *)); void **bases = (void **)calloc(n, sizeof(void *));
if (!bases) { if (!bases) {
print("elf64: calloc failed for section table\n"); printf("elf64_alloc_sections: calloc failed for %u-entry table\n",
(unsigned long long)n);
return NULL; return NULL;
} }
@ -174,6 +319,32 @@ static void **elf64_alloc_sections(const elf64_header_t *hdr) {
return bases; return bases;
} }
/*
* Free all sections allocated by elf64_alloc_sections, then free the array.
*/
static void elf64_free_sections(void **section_bases, u64 count) {
if (!section_bases) return;
for (u64 i = 0; i < count; i++)
if (section_bases[i]) free(section_bases[i]);
free(section_bases);
}
/*
* Apply a single RELA relocation.
*
* Formulae (System V AMD64 ABI):
* R_X86_64_64 : *(u64*)P = S + A
* R_X86_64_32 : *(u32*)P = (u32)(S + A) [zero-extend]
* R_X86_64_32S : *(i32*)P = (i32)(S + A) [sign-extend]
* R_X86_64_PC32 : *(i32*)P = (i32)(S + A - P) [PC-relative]
* R_X86_64_PLT32: same as PC32 for static linking
* R_X86_64_PC64 : *(i64*)P = S + A - P [64-bit PC-relative]
*
* Where:
* S = runtime address of the referenced symbol
* A = explicit addend (rela->addend)
* P = runtime address of the location to be patched
*/
static void elf64_apply_rela(const elf64_rela_t *rela, static void elf64_apply_rela(const elf64_rela_t *rela,
const elf64_sym_t *symtab, const elf64_sym_t *symtab,
void **section_bases, void **section_bases,
@ -183,28 +354,56 @@ static void elf64_apply_rela(const elf64_rela_t *rela,
const elf64_sym_t *sym = &symtab[sym_idx]; const elf64_sym_t *sym = &symtab[sym_idx];
u64 s = (sym->sect_index != 0 && section_bases[sym->sect_index])? /* Compute S: the runtime address of the symbol. */
(u64)section_bases[sym->sect_index] + sym->value : 0; u64 s = 0;
if (sym->sect_index == SHN_ABS) {
/* Absolute symbol — value is the literal address. */
s = sym->value;
} else if (sym->sect_index != SHN_UNDEF
&& sym->sect_index != SHN_COMMON
&& section_bases[sym->sect_index]) {
s = (u64)section_bases[sym->sect_index] + sym->value;
} else if (sym->sect_index == SHN_UNDEF) {
/* Unresolved external — only fatal for non-weak symbols. */
if (ELF64_ST_BIND(sym->info) != STB_WEAK) {
printf("elf64_apply_rela: unresolved non-weak symbol (sym_idx=u, type=%u)\n",
(unsigned long long)sym_idx, rel_type);
}
/* For weak unresolved symbols, s remains 0 (ABI-defined behaviour). */
}
i64 offset = rela->addend; /* P: the runtime address of the patch location. */
u64 reference = (u64)target_base + rela->offset; u64 p = (u64)target_base + rela->offset;
i64 a = rela->addend;
switch (rel_type) { switch (rel_type) {
case R_X86_64_NONE:
break;
case R_X86_64_64: case R_X86_64_64:
*(u64*)reference = (u64)(s+offset); *(u64 *)p = (u64)(s + (u64)a);
break; break;
case R_X86_64_32: case R_X86_64_32:
*(u32*)reference = (u32)(s+offset); *(u32 *)p = (u32)((u64)(s + (u64)a));
break; break;
case R_X86_64_32S: case R_X86_64_32S:
*(i32*)reference = (i32)(s+offset); *(i32 *)p = (i32)((i64)s + a);
break; break;
case R_X86_64_PC32: case R_X86_64_PC32:
case R_X86_64_PLT32: case R_X86_64_PLT32:
*(i32*)reference = (i32)(s+offset - (i64)reference); /* PC-relative: result must fit in 32 bits after sign-extension. */
*(i32 *)p = (i32)((i64)s + a - (i64)p);
break; break;
case R_X86_64_PC64:
*(i64 *)p = (i64)s + a - (i64)p;
break;
default: default:
printf("elf64_apply_rela: unhandled relocation type\n"); printf("elf64_apply_rela: unhandled relocation type %u\n", rel_type);
break; break;
} }
} }
@ -213,9 +412,25 @@ static void elf64_process_rela_section(const elf64_header_t *hdr,
const elf64_sect_header_t *rela_sh, const elf64_sect_header_t *rela_sh,
void **section_bases) { void **section_bases) {
u64 target_idx = rela_sh->info; u64 target_idx = rela_sh->info;
if (!section_bases[target_idx]) return;
elf64_sect_header_t *sym_sh = elf_sect(hdr, rela_sh->link); if (target_idx >= hdr->sect_entry_count) {
printf("elf64_process_rela_section: target section index %u out of range\n",
(unsigned long long)target_idx);
return;
}
if (!section_bases[target_idx]) {
/* Target section was not allocated (e.g. non-allocatable debug section). */
return;
}
u64 link = rela_sh->link;
if (link == 0 || link >= hdr->sect_entry_count) {
printf("elf64_process_rela_section: invalid symtab link index %u\n",
(unsigned long long)link);
return;
}
elf64_sect_header_t *sym_sh = elf_sect(hdr, link);
elf64_sym_t *symtab = (elf64_sym_t *)elf_off(hdr, sym_sh->offset); elf64_sym_t *symtab = (elf64_sym_t *)elf_off(hdr, sym_sh->offset);
elf64_rela_t *relas = (elf64_rela_t *)elf_off(hdr, rela_sh->offset); elf64_rela_t *relas = (elf64_rela_t *)elf_off(hdr, rela_sh->offset);
u64 n_relas = rela_sh->size / sizeof(elf64_rela_t); u64 n_relas = rela_sh->size / sizeof(elf64_rela_t);
@ -224,6 +439,7 @@ static void elf64_process_rela_section(const elf64_header_t *hdr,
elf64_apply_rela(&relas[r], symtab, section_bases, section_bases[target_idx]); elf64_apply_rela(&relas[r], symtab, section_bases, section_bases[target_idx]);
} }
/* Walk all section headers and apply every SHT_RELA section. */
static void elf64_relocate(const elf64_header_t *hdr, void **section_bases) { static void elf64_relocate(const elf64_header_t *hdr, void **section_bases) {
for (u64 i = 0; i < hdr->sect_entry_count; i++) { for (u64 i = 0; i < hdr->sect_entry_count; i++) {
elf64_sect_header_t *sh = elf_sect(hdr, i); elf64_sect_header_t *sh = elf_sect(hdr, i);
@ -232,33 +448,80 @@ static void elf64_relocate(const elf64_header_t *hdr, void **section_bases) {
} }
} }
static u64 elf64_load(elf64_header_t* hdr) { static u64 (*elf64_resolve_entry(const elf64_header_t *hdr,
if(!hdr || !elf64_validate(hdr)) { void **sect_bases))() {
printf("elf64_load: Invalid ELF64 header\n"); u64 entry_va = hdr->prog_entry_offset;
return -1;
/* Pass 1: find the section whose VMA range contains entry_va. */
for (u64 i = 0; i < hdr->sect_entry_count; i++) {
elf64_sect_header_t *sh = elf_sect(hdr, i);
if (!sect_bases[i]) continue;
if (sh->addr == 0) continue; /* No VMA assigned */
if (entry_va >= sh->addr && entry_va < sh->addr + sh->size) {
return (u64 (*)())((u8 *)sect_bases[i] + (entry_va - sh->addr));
}
} }
/* Pass 2: entry_va is a file offset — search for an executable section. */
printf("elf64_resolve_entry: VMA match failed; "
"trying executable section + file offset\n");
for (u64 i = 0; i < hdr->sect_entry_count; i++) {
elf64_sect_header_t *sh = elf_sect(hdr, i);
if (!sect_bases[i]) continue;
if (sh->flags & SHF_EXECINSTR) {
printf("elf64_resolve_entry: using section %u (%s) as .text fallback\n",
(unsigned long long)i, elf_sect_name(hdr, sh));
return (u64 (*)())((u8 *)sect_bases[i] + entry_va);
}
}
printf("elf64_resolve_entry: failed to resolve entry point (entry_va=0x%x)\n",
(unsigned long long)entry_va);
return NULL;
}
static u64 elf64_load(elf64_header_t *hdr) {
if (!hdr) {
printf("elf64_load: NULL header\n");
return (u64)-1;
}
if (!elf64_validate(hdr)) {
printf("elf64_load: invalid ELF64 header\n");
return (u64)-1;
}
/* Allocate runtime memory for each section. */
void **sect_bases = elf64_alloc_sections(hdr); void **sect_bases = elf64_alloc_sections(hdr);
if (!sect_bases) { if (!sect_bases) {
printf("elf64_load: Failed to allocate sections.\n"); printf("elf64_load: failed to allocate sections\n");
return (u64)-1;
} }
/* Apply all RELA relocations. */
elf64_relocate(hdr, sect_bases); elf64_relocate(hdr, sect_bases);
/* Resolve entry point. */
u64 (*entry)() = elf64_resolve_entry(hdr, sect_bases); u64 (*entry)() = elf64_resolve_entry(hdr, sect_bases);
if (!entry) { if (!entry) {
printf("elf64_load: failed to resolve entry point\n"); printf("elf64_load: failed to resolve entry point\n");
return -1; elf64_free_sections(sect_bases, hdr->sect_entry_count);
return (u64)-1;
} }
for(size_t i = 0; i < 64; i++) { /* Dump the first 64 bytes of entry for debugging. */
char c = ((char*)entry)[i]; printf("elf64_load: entry point at 0x%x — first 64 bytes:\n",
print8(c); (unsigned long long)(u64)entry);
for (u64 i = 0; i < 64; i++) {
u8 byte = ((const u8 *)entry)[i];
/* Print as two hex nibbles */
print8(byte);
put(((i & 7) == 7) ? '\n' : ' '); put(((i & 7) == 7) ? '\n' : ' ');
} }
printf("elf64_load: jumping to entry\n"); printf("elf64_load: jumping to entry\n");
u64 ret = entry(); u64 ret = entry();
printf("elf64_load: returning"); printf("elf64_load: entry returned 0x%x\n", (unsigned long long)ret);
elf64_free_sections(sect_bases, hdr->sect_entry_count);
return ret; return ret;
} }

View File

@ -2,5 +2,14 @@
#define SYS_OPEN 0 #define SYS_OPEN 0
#define SYS_SLURP 1 #define SYS_SLURP 1
#define SYS_GETFB 2
#define SYS_PRINT 3
#define SYS_GETLINE 4
#define SYS_GETKEYS 5
#define SYS_FREE 6
typedef struct sys_framebuffer {
u32* fb;
u32 width;
u32 height;
} sys_framebuffer_t;

View File

@ -235,35 +235,13 @@ void kmain() {
rsdp = (struct acpi_rsdp_header *)(rsdp_req.response->address); rsdp = (struct acpi_rsdp_header *)(rsdp_req.response->address);
print("Found RSDP @ 0x");
print64((u64)rsdp);
put('\n');
print("With signature: ");
printn((char *)rsdp->signature, sizeof(rsdp->signature));
print(" v");
print8(rsdp->revision);
print("\nRSDT at 0x");
struct acpi_rsdt *rsdt =
(struct acpi_rsdt *)((rsdp->revision ? rsdp->ptr64 : rsdp->ptr32) +
hhdm_offset);
print64((u64)rsdt);
print("\nSDT Signature: ");
printn((const char *)rsdt->signature, sizeof(rsdt->signature));
print("\nAPIC Local Base: ");
/* I should check cpuid to ensure its supported but it will /* I should check cpuid to ensure its supported but it will
* be for my machines ;^) */ * be for my machines ;^) */
/* APIC stuff */ /* APIC stuff */
apic_enable(); apic_enable();
print("APIC Enabled\n");
ioapic_init(); ioapic_init();
asm volatile("sti"); asm volatile("sti");
ahci_init(); ahci_init();
read_active_port = -1; read_active_port = -1;
@ -272,7 +250,6 @@ void kmain() {
// assume we want the first port // assume we want the first port
if(read_active_port < 0) if(read_active_port < 0)
read_active_port = i; read_active_port = i;
printf("Port %d is active!\n", i);
} }
} }
@ -287,7 +264,6 @@ void kmain() {
i8 bootpart = -1; i8 bootpart = -1;
fat32_mbr_partition_t bpart; fat32_mbr_partition_t bpart;
printf("Fat32 Partitions:\n");
for(size_t i = 0; i < 4; i++) { for(size_t i = 0; i < 4; i++) {
fat32_mbr_partition_t* part = &mbr->partitions[i]; fat32_mbr_partition_t* part = &mbr->partitions[i];
u32 lba_start = part->lba_start; u32 lba_start = part->lba_start;
@ -298,10 +274,6 @@ void kmain() {
bpart = *part; bpart = *part;
} }
printf("\t%s, %d Sectors [0x%x-0x%x]\n",
(part->status == 0x80)? "[BOOTABLE]" : "[UNBOOTABLE]",
part->sector_count,
lba_start, lba_end);
} }
if(bootpart < 0) { if(bootpart < 0) {
@ -324,24 +296,14 @@ void kmain() {
u8 *raw = alloc(4096); u8 *raw = alloc(4096);
ahci_read(read_active_port, root_lba, active_vol.sectors_per_cluster, raw); ahci_read(read_active_port, root_lba, active_vol.sectors_per_cluster, raw);
struct FILE* fortune = fat32_find_path(read_active_port, &active_vol, "fort/fortu.ne");
u8* fort = slurp(fortune);
printn(fort, fortune->info.file_size);
free(fort);
FILE* execfile = fat32_find_path(read_active_port, &active_vol, "/usr/bin/test"); FILE* execfile = fat32_find_path(read_active_port, &active_vol, "/usr/bin/test");
if(!execfile) { if(!execfile) {
printf("Didn't find executable :("); printf("Didn't find executable :(");
} else { } else {
printf("Found:\n"); extern volatile u32* fb_scr;
elf64_header_t* hdr = (elf64_header_t*) slurp(execfile); elf64_header_t* hdr = (elf64_header_t*) slurp(execfile);
char* ret = (char*)elf64_load(hdr); elf64_load(hdr);
printf("AFTER:\n");
print64((u64)ret);
} }
while(1); while(1);

View File

@ -1,21 +1,19 @@
#define TAB_STOP 4
#include "etc.h" #include "etc.h"
#include "font.h" #include "font.h"
#include "../include/limine.h" #include "../include/limine.h"
u32 bg = 0x00000000; u32 bg = 0x00000000;
u32 fg = (0x007F1754 << 1); u32 fg = (0x007F1754 << 1);
static size_t row; static size_t row;
static size_t col; static size_t col;
static size_t term_width, term_height; static size_t term_width, term_height;
static size_t fb_width, fb_height; size_t fb_width, fb_height;
static volatile u32 *fb_scr; volatile u32 *fb_scr;
#define TAB_STOP 4 #define TAB_STOP 4
#define SCALE 4
// buffer at each edge for readability #define GLYPH_WIDTH ((FONT_WIDTH + 2) * SCALE)
#define GLYPH_WIDTH (FONT_WIDTH + 2) #define GLYPH_HEIGHT ((FONT_HEIGHT + 2) * SCALE)
#define GLYPH_HEIGHT (FONT_HEIGHT + 2)
void print_init(struct limine_framebuffer *fb) { void print_init(struct limine_framebuffer *fb) {
term_width = fb->width / GLYPH_WIDTH; term_width = fb->width / GLYPH_WIDTH;
@ -36,7 +34,6 @@ static void scrollback() {
void put(int ch) { void put(int ch) {
ch = (unsigned char)ch; ch = (unsigned char)ch;
if (!isprint(ch)) { if (!isprint(ch)) {
if (ch == '\n') { if (ch == '\n') {
col = 0; col = 0;
@ -53,12 +50,10 @@ void put(int ch) {
} }
return; return;
} }
if (col >= term_width) { if (col >= term_width) {
col = 0; col = 0;
row++; row++;
} }
if (row >= term_height) { if (row >= term_height) {
scrollback(); scrollback();
row = term_height - 1; row = term_height - 1;
@ -66,23 +61,37 @@ void put(int ch) {
size_t idx = ch - ' '; size_t idx = ch - ' ';
u32 glyph = font[idx]; u32 glyph = font[idx];
size_t px = col * GLYPH_WIDTH; size_t px = col * GLYPH_WIDTH;
size_t py = row * GLYPH_HEIGHT; size_t py = row * GLYPH_HEIGHT;
for (size_t y = 0; y < GLYPH_HEIGHT; y++) { // iterate over logical (unscaled) glyph pixels
for (size_t x = 0; x < GLYPH_WIDTH; x++) { size_t unscaled_w = FONT_WIDTH + 2;
size_t off = (py + y) * fb_width + (px + x); size_t unscaled_h = FONT_HEIGHT + 2;
bool padding = for (size_t y = 0; y < unscaled_h; y++) {
(y == 0 || y == GLYPH_HEIGHT - 1 || x == 0 || x == GLYPH_WIDTH - 1); for (size_t x = 0; x < unscaled_w; x++) {
fb_scr[off] = ((~glyph & 1) | padding) ? ((fb_scr[off] == fg) ? bg : fb_scr[off]) : fg; bool padding = (y == 0 || y == unscaled_h - 1 || x == 0 || x == unscaled_w - 1);
u32 color = ((~glyph & 1) | padding)
? ((/* will fill per scaled pixel */ 0), bg)
: fg;
// for padding, preserve existing unless it was fg
// expand each logical pixel into SCALE x SCALE block
for (size_t sy = 0; sy < SCALE; sy++) {
for (size_t sx = 0; sx < SCALE; sx++) {
size_t off = (py + y * SCALE + sy) * fb_width + (px + x * SCALE + sx);
if (padding)
fb_scr[off] = (fb_scr[off] == fg) ? bg : fb_scr[off];
else
fb_scr[off] = color;
}
}
glyph >>= !padding; glyph >>= !padding;
} }
} }
col++; col++;
} }
void print(const char *msg) { void print(const char *msg) {
while (*msg) { while (*msg) {
put(*(msg++)); put(*(msg++));

View File

@ -38,12 +38,73 @@ static void sys_slurp_impl(struct cpu_ctx* ctx) {
return; return;
} }
ctx->rdi = (u64) filetable[fd]->info.file_size;
ctx->rax = (u64) slurp(filetable[fd]); ctx->rax = (u64) slurp(filetable[fd]);
} }
extern volatile u32 *fb_scr;
static sys_framebuffer_t g_fb;
extern size_t fb_width, fb_height;
static void sys_getfb_impl(struct cpu_ctx* ctx) {
printf("SYS_GETFB\n");
g_fb.fb = fb_scr;
g_fb.width = fb_width;
g_fb.height = fb_height;
ctx->rax = (u64)&g_fb;
}
static void sys_print_impl(struct cpu_ctx* ctx) {
const char* fmt = (const char*)ctx->rdi;
if (!fmt) {
ctx->rax = -1;
return;
}
// Remaining GP registers hold the variadic args (System V AMD64 ABI)
ctx->rax = ctx->rsi;
printn((const char*)ctx->rdi, ctx->rsi);
}
static void sys_getline_impl(struct cpu_ctx* ctx) {
asm volatile("sti");
ctx->rax = (u64)getline_alloc(0);
}
extern u8 kbd_held_map[0x100/16];
static void sys_getkeys_impl(struct cpu_ctx* ctx) {
const char* fmt = (const char*)ctx->rdi;
if (!fmt) {
ctx->rax = -1;
return;
}
if(ctx->rdi == 0) {
ctx->rax = (u64)malloc(sizeof(kbd_held_map));
} else {
ctx->rax = ctx->rdi;
}
if(ctx->rax)
memcpy((void*)ctx->rax, &kbd_held_map[0], sizeof(kbd_held_map));
}
static void sys_free_impl(struct cpu_ctx* ctx) {
void* addr = (void*)ctx->rdi;
free(addr);
}
static syscall_t syscalls[] = { static syscall_t syscalls[] = {
[SYS_OPEN] sys_open_impl, [SYS_OPEN] = sys_open_impl,
[SYS_SLURP] sys_slurp_impl, [SYS_SLURP] = sys_slurp_impl,
[SYS_GETFB] = sys_getfb_impl,
[SYS_PRINT] = sys_print_impl,
[SYS_GETLINE] = sys_getline_impl,
[SYS_GETKEYS] = sys_getkeys_impl,
[SYS_FREE] = sys_free_impl,
}; };
// Function to dump the contents of cpu_ctx // Function to dump the contents of cpu_ctx
@ -137,10 +198,10 @@ void dump_cpu_ctx(struct cpu_ctx *ctx) {
void syscall_handler(struct cpu_ctx* ctx) { void syscall_handler(struct cpu_ctx* ctx) {
dump_cpu_ctx(ctx); //dump_cpu_ctx(ctx);
if(ctx->rax < 2) if(ctx->rax < sizeof(syscalls)/sizeof(syscalls[0]))
syscalls[ctx->rax](ctx); syscalls[ctx->rax](ctx);
printf("SYSCALL COMPLETE\n"); //printf("SYSCALL COMPLETE\n");
} }