diff --git a/bin/os b/bin/os index 6cec5cc..5f26b92 100755 Binary files a/bin/os and b/bin/os differ diff --git a/image.hdd b/image.hdd index f50cb29..80c6868 100644 Binary files a/image.hdd and b/image.hdd differ diff --git a/limine.sh b/limine.sh index 835232c..d77eb93 100644 --- a/limine.sh +++ b/limine.sh @@ -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/BOOTX64.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 diff --git a/obj/src/int.c.d b/obj/src/int.c.d index e4af4f5..84722c1 100644 --- a/obj/src/int.c.d +++ b/obj/src/int.c.d @@ -1,5 +1,7 @@ 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/common.h: src/print.h: @@ -9,3 +11,6 @@ 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: diff --git a/obj/src/int.c.o b/obj/src/int.c.o index 760d2c6..5674450 100644 Binary files a/obj/src/int.c.o and b/obj/src/int.c.o differ diff --git a/obj/src/main.c.d b/obj/src/main.c.d index 203febb..eb61cf0 100644 --- a/obj/src/main.c.d +++ b/obj/src/main.c.d @@ -1,12 +1,14 @@ 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/alloc.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/../print.h src/lib/elf/elf64.h + src/prompt/file.h src/acpi.h src/common.h src/ahci.h src/alloc.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/../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/prompt/lex.h: src/prompt/file.h: -src/prompt/file.h: src/acpi.h: src/common.h: src/ahci.h: @@ -17,6 +19,12 @@ src/lib/ctype.h: src/lib/string.h: src/lib/../lib/stdio.h: src/lib/../lib/malloc.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: diff --git a/obj/src/main.c.o b/obj/src/main.c.o index e6e83ff..b710c8a 100644 Binary files a/obj/src/main.c.o and b/obj/src/main.c.o differ diff --git a/src/int.c b/src/int.c index 2610703..d382237 100644 --- a/src/int.c +++ b/src/int.c @@ -61,27 +61,32 @@ void load_idt(void *addr) { extern void draw(u8 vect); struct cpu_ctx *interrupt_dispatch(struct cpu_ctx* ctx) { + if(ctx->vect == 0x21) { kbd_handler(); return ctx; } if(ctx->vect == 0x80) { - print("SYSCALL\n"); syscall_handler(ctx); return ctx; } - + print("COMING THROUGH"); print("\n[IRQ "); print8(ctx->vect); print("] with 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"); - if(ctx->vect == 0x0D || ctx->vect == 0x0E) { + if(ctx->vect < 0x10) while(1); - } return ctx; } diff --git a/src/kbd.c b/src/kbd.c index c3375fa..7ddc5a4 100644 --- a/src/kbd.c +++ b/src/kbd.c @@ -72,23 +72,23 @@ char kbd_buffer_getc() { return c; } -static u8 held_map[0x100/16]; +u8 kbd_held_map[0x100/16]; static void hold_key(u8 key) { 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) { 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) { key &= (0x100/2)-1; - return (held_map[key>>3] & (1 << (key & 7))); + return (kbd_held_map[key>>3] & (1 << (key & 7))); } void kbd_handler() { diff --git a/src/lib/elf/elf64.h b/src/lib/elf/elf64.h index 3a36982..92c5e9b 100644 --- a/src/lib/elf/elf64.h +++ b/src/lib/elf/elf64.h @@ -5,139 +5,276 @@ #include "../../lib/malloc.h" #pragma pack(push, 1) + typedef struct elf64_header { - u32 MAGIC; /* '\x7FELF' */ - 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 */ - u8 version; /* ELF version */ - u8 abi; /* ABI identification */ - u8 abi_version; /* ABI version */ - u8 padding[7]; /* Padding to align the structure */ - + u32 MAGIC; /* '\x7FELF' as LE u32 = 0x464C457F */ + + enum : u8 { + ELF32 = 1, + 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 padding[7]; /* Reserved, must be zero */ + enum : u16 { - ELF_RELOC = 1, - ELF_EXEC = 2, - ELF_SHARED = 3, - ELF_CORe = 4, - } type; /* 1 for relocatable, 2 for executable, 3 for shared, 4 for core */ - u16 instruction_set; /* Architecture: e.g., EM_X86_64 = 62 */ - u32 elf_version; /* Version of the ELF specification */ - u64 prog_entry_offset; /* Entry point address */ - u64 prog_header_table_offset; /* Program header table offset */ - u64 sect_header_table_offset; /* Section header table offset */ - u32 flags; /* Processor-specific flags */ - u16 header_size; /* Size of this header */ - u16 prog_entry_size; /* Size of program entry */ - u16 prog_entry_count; /* Number of program entries */ - u16 sect_entry_size; /* Size of section entry */ - u16 sect_entry_count; /* Number of section entries */ - u16 sect_index; /* Index of the section header string table */ + ELF_RELOC = 1, /* Relocatable object */ + ELF_EXEC = 2, /* Executable */ + ELF_SHARED = 3, /* Shared object */ + ELF_CORE = 4, /* Core dump */ + } type; + + u16 instruction_set; /* Architecture (EM_X86_64 = 62) */ + u32 elf_version; /* ELF version (always 1) */ + u64 prog_entry_offset; /* Virtual entry-point address */ + 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 */ + u16 header_size; /* Size of this header (64 bytes) */ + u16 prog_entry_size; /* Size of one program header entry */ + u16 prog_entry_count; /* Number of program header entries */ + u16 sect_entry_size; /* Size of one section header entry */ + u16 sect_entry_count; /* Number of section header entries */ + u16 sect_index; /* Section-name string table index */ } elf64_header_t; typedef struct elf64_prog_header { - enum : u32 { - ELF64_IGNORE, - ELF64_LOAD, - ELF64_DYNAMIC, - ELF64_INTERP, - ELF64_NOTE, - } type; - enum : u32 { ELF64_X = 1, ELF64_W = 2, ELF64_R = 4} flags; - u64 data_offset; - u64* vmem_start; - u64 seg_phys; - u64 seg_filesize; - u64 seg_memsize; - u64 req_alignment; + enum : u32 { + ELF64_PT_NULL = 0, + ELF64_PT_LOAD = 1, + ELF64_PT_DYNAMIC = 2, + ELF64_PT_INTERP = 3, + ELF64_PT_NOTE = 4, + } type; + enum : u32 { + ELF64_PF_X = 1, + ELF64_PF_W = 2, + ELF64_PF_R = 4, + } flags; + u64 data_offset; /* Offset of segment data in file */ + 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; typedef struct elf64_sect_header { - u32 name_offset; + u32 name_offset; /* Offset into .shstrtab */ enum : u32 { - SHT_NULL = 0, - SHT_PROGBITS = 1, - SHT_SYMTAB = 2, - SHT_STRTAB = 3, - SHT_RELA = 4, - SHT_NOBITS = 8, - SHT_REL = 9, + SHT_NULL = 0, /* Inactive section */ + SHT_PROGBITS = 1, /* Program-defined data (.text, .data, …) */ + SHT_SYMTAB = 2, /* Full symbol table */ + SHT_STRTAB = 3, /* String table */ + SHT_RELA = 4, /* Relocation with explicit addends */ + SHT_HASH = 5, /* Symbol hash table */ + 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; u64 flags; - u64 addr; - u64 offset; // offset in file - u64 size; - u32 link; // for RELA: index of associated symbol table section - u32 info; // for RELA: index of section the relocations apply to - u64 addralign; - u64 entsize; + u64 addr; /* Load address (0 for relocatable) */ + u64 offset; /* Offset of section data in file */ + u64 size; /* Size of section data in file */ + u32 link; /* Section link index (type-dependent) */ + u32 info; /* Extra info (type-dependent) */ + u64 addralign; /* Required alignment (power of 2) */ + u64 entsize; /* Size of fixed-size entries, if any */ } 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 { - u32 name_offset; - u8 info; // binding (high 4) + type (low 4) - u8 other; - u16 sect_index; - u64 value; // offset within its section for relocatable files - u64 size; + u32 name_offset; /* Offset into owning string table */ + u8 info; /* Binding (high 4 bits) | Type (low 4 bits) */ + u8 other; /* Visibility (low 2 bits) */ + u16 sect_index; /* Section index (SHN_* or section number) */ + u64 value; /* Symbol value / offset within section */ + u64 size; /* Size of the object / function */ } elf64_sym_t; typedef struct elf64_rela { - u64 offset; // offset within the target section to patch - u64 info; // symbol index (high 32) + relocation type (low 32) - i64 addend; + u64 offset; /* Offset within target section to patch */ + u64 info; /* Symbol index (high 32) | type (low 32) */ + i64 addend; /* Explicit addend */ } elf64_rela_t; #pragma pack(pop) -#define ELF_MAGIC 0x464C457F // '\x7FELF' as 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 ELF_MAGIC 0x464C457FU /* '\x7FELF' in little-endian u32 */ -#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_INFO(sym, type) (((u64)(sym) << 32) | (u32)(type)) +/* Validate an ELF64 LE x86-64 header. */ static bool elf64_validate(const elf64_header_t *hdr) { - return !((hdr->MAGIC != ELF_MAGIC) - || (hdr->size != ELF64) - || (hdr->endianness != ELF64_LE) - || (hdr->instruction_set != 62)); + if (!hdr) { + printf("elf64_validate: NULL header\n"); + return false; + } + 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) { 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) { return (elf64_sect_header_t *)((u8 *)hdr + hdr->sect_header_table_offset + i * hdr->sect_entry_size); } -static u64 (*elf64_resolve_entry(const elf64_header_t* hdr, void** sect_bases)) () { - u64 entry_offset = hdr->prog_entry_offset; - - 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(entry_offset >= sh->addr && entry_offset < sh->addr + sh->size) - return (u64 (*)())((u8*) sect_bases[i] + (entry_offset - sh->addr)); - } - - // 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 the string table pointer for section i (must be SHT_STRTAB). */ +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); } -static void elf64_alloc_section(const elf64_header_t *hdr, +/* 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 ""; + 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++) { + elf64_sect_header_t *sh = elf_sect(hdr, i); + const char *sname = shstrtab + sh->name_offset; + + /* Simple strcmp — replace with your lib's version if available. */ + const char *a = sname, *b = name; + while (*a && *a == *b) { a++; b++; } + if (*a == *b) return sh; + } + 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, const elf64_sect_header_t *sh, - void **out) { + void **out) { *out = NULL; if (sh->type != SHT_PROGBITS && sh->type != SHT_NOBITS) return; @@ -145,26 +282,34 @@ static void elf64_alloc_section(const elf64_header_t *hdr, void *mem = calloc(sh->size, 1); if (!mem) { - print("elf64: calloc failed\n"); + printf("elf64_alloc_section: calloc(%u) failed\n", (unsigned long long)sh->size); return; } if (sh->type == SHT_PROGBITS) { - u8 *src = (u8 *)elf_off(hdr, sh->offset); - u8 *dst = (u8 *)mem; + const u8 *src = (const u8 *)elf_off(hdr, sh->offset); + u8 *dst = (u8 *)mem; for (u64 b = 0; b < sh->size; b++) dst[b] = src[b]; } + /* SHT_NOBITS (.bss) stays zeroed from calloc. */ *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) { u64 n = hdr->sect_entry_count; - void **bases = calloc(n, sizeof(void *)); + void **bases = (void **)calloc(n, sizeof(void *)); 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; } @@ -174,6 +319,32 @@ static void **elf64_alloc_sections(const elf64_header_t *hdr) { 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, const elf64_sym_t *symtab, void **section_bases, @@ -181,41 +352,85 @@ static void elf64_apply_rela(const elf64_rela_t *rela, u64 sym_idx = RELA_SYM(rela->info); u32 rel_type = RELA_TYPE(rela->info); - 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])? - (u64)section_bases[sym->sect_index] + sym->value : 0; - - i64 offset = rela->addend; - u64 reference = (u64)target_base + rela->offset; + /* Compute S: the runtime address of the symbol. */ + 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). */ + } - switch(rel_type) { - case R_X86_64_64: - *(u64*)reference = (u64)(s+offset); - break; - case R_X86_64_32: - *(u32*)reference = (u32)(s+offset); - break; - case R_X86_64_32S: - *(i32*)reference = (i32)(s+offset); - break; - case R_X86_64_PC32: - case R_X86_64_PLT32: - *(i32*)reference = (i32)(s+offset - (i64)reference); - break; - default: - printf("elf64_apply_rela: unhandled relocation type\n"); - break; - } + /* P: the runtime address of the patch location. */ + u64 p = (u64)target_base + rela->offset; + i64 a = rela->addend; + + switch (rel_type) { + case R_X86_64_NONE: + break; + + case R_X86_64_64: + *(u64 *)p = (u64)(s + (u64)a); + break; + + case R_X86_64_32: + *(u32 *)p = (u32)((u64)(s + (u64)a)); + break; + + case R_X86_64_32S: + *(i32 *)p = (i32)((i64)s + a); + break; + + case R_X86_64_PC32: + case R_X86_64_PLT32: + /* PC-relative: result must fit in 32 bits after sign-extension. */ + *(i32 *)p = (i32)((i64)s + a - (i64)p); + break; + + case R_X86_64_PC64: + *(i64 *)p = (i64)s + a - (i64)p; + break; + + default: + printf("elf64_apply_rela: unhandled relocation type %u\n", rel_type); + break; + } } static void elf64_process_rela_section(const elf64_header_t *hdr, const elf64_sect_header_t *rela_sh, void **section_bases) { 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_rela_t *relas = (elf64_rela_t *)elf_off(hdr, rela_sh->offset); 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]); } +/* Walk all section headers and apply every SHT_RELA section. */ static void elf64_relocate(const elf64_header_t *hdr, void **section_bases) { for (u64 i = 0; i < hdr->sect_entry_count; 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) { - if(!hdr || !elf64_validate(hdr)) { - printf("elf64_load: Invalid ELF64 header\n"); - return -1; - } +static u64 (*elf64_resolve_entry(const elf64_header_t *hdr, + void **sect_bases))() { + u64 entry_va = hdr->prog_entry_offset; - void** sect_bases = elf64_alloc_sections(hdr); - if(!sect_bases) { - printf("elf64_load: Failed to allocate sections.\n"); - } + /* 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)); + } + } - elf64_relocate(hdr, sect_bases); + /* 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); + } + } - u64 (*entry)() = elf64_resolve_entry(hdr, sect_bases); + printf("elf64_resolve_entry: failed to resolve entry point (entry_va=0x%x)\n", + (unsigned long long)entry_va); + return NULL; +} - if(!entry) { - printf("elf64_load: failed to resolve entry point\n"); - return -1; - } +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; + } - for(size_t i = 0; i < 64; i++) { - char c = ((char*)entry)[i]; - print8(c); - put(((i & 7) == 7)? '\n' : ' '); - } - printf("elf64_load: jumping to entry\n"); - u64 ret = entry(); - printf("elf64_load: returning"); - return ret; + /* Allocate runtime memory for each section. */ + void **sect_bases = elf64_alloc_sections(hdr); + if (!sect_bases) { + printf("elf64_load: failed to allocate sections\n"); + return (u64)-1; + } + + /* Apply all RELA relocations. */ + elf64_relocate(hdr, sect_bases); + + /* Resolve entry point. */ + u64 (*entry)() = elf64_resolve_entry(hdr, sect_bases); + if (!entry) { + printf("elf64_load: failed to resolve entry point\n"); + elf64_free_sections(sect_bases, hdr->sect_entry_count); + return (u64)-1; + } + + /* Dump the first 64 bytes of entry for debugging. */ + printf("elf64_load: entry point at 0x%x — first 64 bytes:\n", + (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' : ' '); + } + + printf("elf64_load: jumping to entry\n"); + u64 ret = entry(); + printf("elf64_load: entry returned 0x%x\n", (unsigned long long)ret); + + elf64_free_sections(sect_bases, hdr->sect_entry_count); + return ret; } \ No newline at end of file diff --git a/src/lib/sys.h b/src/lib/sys.h index 8785bfd..14901f5 100644 --- a/src/lib/sys.h +++ b/src/lib/sys.h @@ -2,5 +2,14 @@ #define SYS_OPEN 0 #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; \ No newline at end of file diff --git a/src/main.c b/src/main.c index 4b6b25c..3e7136e 100644 --- a/src/main.c +++ b/src/main.c @@ -235,35 +235,13 @@ void kmain() { 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 * be for my machines ;^) */ /* APIC stuff */ apic_enable(); - print("APIC Enabled\n"); ioapic_init(); asm volatile("sti"); - - ahci_init(); read_active_port = -1; @@ -272,7 +250,6 @@ void kmain() { // assume we want the first port if(read_active_port < 0) read_active_port = i; - printf("Port %d is active!\n", i); } } @@ -287,7 +264,6 @@ void kmain() { i8 bootpart = -1; fat32_mbr_partition_t bpart; - printf("Fat32 Partitions:\n"); for(size_t i = 0; i < 4; i++) { fat32_mbr_partition_t* part = &mbr->partitions[i]; u32 lba_start = part->lba_start; @@ -297,11 +273,7 @@ void kmain() { bootpart = i; 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) { @@ -324,24 +296,14 @@ void kmain() { u8 *raw = alloc(4096); 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"); if(!execfile) { printf("Didn't find executable :("); } else { - printf("Found:\n"); + extern volatile u32* fb_scr; elf64_header_t* hdr = (elf64_header_t*) slurp(execfile); - char* ret = (char*)elf64_load(hdr); - printf("AFTER:\n"); - print64((u64)ret); + elf64_load(hdr); } while(1); diff --git a/src/print.c b/src/print.c index 4e47d51..6789389 100644 --- a/src/print.c +++ b/src/print.c @@ -1,26 +1,24 @@ +#define TAB_STOP 4 + #include "etc.h" #include "font.h" - #include "../include/limine.h" - u32 bg = 0x00000000; u32 fg = (0x007F1754 << 1); static size_t row; static size_t col; static size_t term_width, term_height; -static size_t fb_width, fb_height; -static volatile u32 *fb_scr; - +size_t fb_width, fb_height; +volatile u32 *fb_scr; #define TAB_STOP 4 - -// buffer at each edge for readability -#define GLYPH_WIDTH (FONT_WIDTH + 2) -#define GLYPH_HEIGHT (FONT_HEIGHT + 2) +#define SCALE 4 +#define GLYPH_WIDTH ((FONT_WIDTH + 2) * SCALE) +#define GLYPH_HEIGHT ((FONT_HEIGHT + 2) * SCALE) void print_init(struct limine_framebuffer *fb) { - term_width = fb->width / GLYPH_WIDTH; + term_width = fb->width / GLYPH_WIDTH; term_height = fb->height / GLYPH_HEIGHT; - fb_width = fb->width; + fb_width = fb->width; fb_height = fb->height; fb_scr = fb->address; } @@ -36,7 +34,6 @@ static void scrollback() { void put(int ch) { ch = (unsigned char)ch; - if (!isprint(ch)) { if (ch == '\n') { col = 0; @@ -53,12 +50,10 @@ void put(int ch) { } return; } - if (col >= term_width) { col = 0; row++; } - if (row >= term_height) { scrollback(); row = term_height - 1; @@ -66,23 +61,37 @@ void put(int ch) { size_t idx = ch - ' '; u32 glyph = font[idx]; - size_t px = col * GLYPH_WIDTH; size_t py = row * GLYPH_HEIGHT; - for (size_t y = 0; y < GLYPH_HEIGHT; y++) { - for (size_t x = 0; x < GLYPH_WIDTH; x++) { - size_t off = (py + y) * fb_width + (px + x); - bool padding = - (y == 0 || y == GLYPH_HEIGHT - 1 || x == 0 || x == GLYPH_WIDTH - 1); - fb_scr[off] = ((~glyph & 1) | padding) ? ((fb_scr[off] == fg) ? bg : fb_scr[off]) : fg; + // iterate over logical (unscaled) glyph pixels + size_t unscaled_w = FONT_WIDTH + 2; + size_t unscaled_h = FONT_HEIGHT + 2; + for (size_t y = 0; y < unscaled_h; y++) { + for (size_t x = 0; x < unscaled_w; x++) { + 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; } } - col++; } + + void print(const char *msg) { while (*msg) { put(*(msg++)); @@ -132,4 +141,4 @@ void unput(void) { for (size_t y = 0; y < GLYPH_HEIGHT; y++) for (size_t x = 0; x < GLYPH_WIDTH; x++) fb_scr[(py + y) * fb_width + (px + x)] = bg; -} +} \ No newline at end of file diff --git a/src/syscalls.c b/src/syscalls.c index 3284040..265efa3 100644 --- a/src/syscalls.c +++ b/src/syscalls.c @@ -38,12 +38,73 @@ static void sys_slurp_impl(struct cpu_ctx* ctx) { return; } + ctx->rdi = (u64) filetable[fd]->info.file_size; 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[] = { - [SYS_OPEN] sys_open_impl, - [SYS_SLURP] sys_slurp_impl, + [SYS_OPEN] = sys_open_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 @@ -137,10 +198,10 @@ void dump_cpu_ctx(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); - printf("SYSCALL COMPLETE\n"); + //printf("SYSCALL COMPLETE\n"); } \ No newline at end of file