From a39e30d17e4c1366f431d00879800d271fda0564 Mon Sep 17 00:00:00 2001 From: Jozef Nagy Date: Fri, 31 Jan 2025 21:12:29 +0100 Subject: [PATCH] Added x86_64 paging and ELF loader --- boot/arch/x86_64/common/mm/paging.c | 68 +++++++++++++++++++++++ boot/common/init.c | 19 +++++-- boot/common/loader/elf.c | 85 +++++++++++++++++++++++++++++ boot/include/lib/align.h | 29 ++++++++++ boot/include/loader/elf.h | 77 ++++++++++++++++++++++++++ boot/include/mm/vmm.h | 35 ++++++++++++ 6 files changed, 309 insertions(+), 4 deletions(-) create mode 100644 boot/arch/x86_64/common/mm/paging.c create mode 100644 boot/common/loader/elf.c create mode 100644 boot/include/lib/align.h create mode 100644 boot/include/loader/elf.h create mode 100644 boot/include/mm/vmm.h diff --git a/boot/arch/x86_64/common/mm/paging.c b/boot/arch/x86_64/common/mm/paging.c new file mode 100644 index 0000000..259623f --- /dev/null +++ b/boot/arch/x86_64/common/mm/paging.c @@ -0,0 +1,68 @@ +/*********************************************************************************/ +/* Module Name: paging.c */ +/* Project: AurixOS */ +/* */ +/* Copyright (c) 2024-2025 Jozef Nagy */ +/* */ +/* This source is subject to the MIT License. */ +/* See License.txt in the root of this repository. */ +/* All other rights reserved. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/*********************************************************************************/ + +#include +#include +#include +#include +#include + +/* Trimmed down version of */ +/* https://github.com/KevinAlavik/nekonix/blob/main/kernel/src/mm/vmm.c */ +/* Thanks, Kevin <3 */ + +void map_page(uintptr_t *pm, uintptr_t virt, uintptr_t phys, uint64_t flags) +{ + uint64_t pml1_idx = (virt & (uint64_t)0x1ff << 12) >> 12; + uint64_t pml2_idx = (virt & (uint64_t)0x1ff << 21) >> 21; + uint64_t pml3_idx = (virt & (uint64_t)0x1ff << 30) >> 30; + uint64_t pml4_idx = (virt & (uint64_t)0x1ff << 39) >> 39; + + if (!(pm[pml4_idx] & 1)) { + pm[pml4_idx] = (uint64_t)mem_alloc(PAGE_SIZE) | flags; + } + + uint64_t *pml3_table = (uint64_t *)(pm[pml4_idx] & 0x000FFFFFFFFFF000); + if (!(pml3_table[pml3_idx] & 1)) { + pml3_table[pml3_idx] = (uint64_t)mem_alloc(PAGE_SIZE) | flags; + } + + uint64_t *pml2_table = (uint64_t *)(pml3_table[pml3_idx] & 0x000FFFFFFFFFF000); + if (!(pml2_table[pml2_idx] & 1)) { + pml2_table[pml2_idx] = (uint64_t)mem_alloc(PAGE_SIZE) | flags; + } + + uint64_t *pml1_table = (uint64_t *)(pml2_table[pml2_idx] & 0x000FFFFFFFFFF000); + pml1_table[pml1_idx] = phys | flags; + + debug("map_page(): Mapped 0x%lx -> 0x%lx\n", phys, virt); +} + +uintptr_t *create_pagemap() +{ + uint64_t *pm = (uint64_t *)mem_alloc(PAGE_SIZE); + if (!pm) { + debug("create_pagemap(): Failed to allocate memory for a new pm.\n"); + return NULL; + } + memset(pm, 0, PAGE_SIZE); + + debug("create_pagemap(): Created new pm at 0x%lx\n", (uint64_t)pm); + return pm; +} diff --git a/boot/common/init.c b/boot/common/init.c index 453d1e0..53c368d 100644 --- a/boot/common/init.c +++ b/boot/common/init.c @@ -19,23 +19,34 @@ #include #include +#include +#include #include void axboot_init() { if (!vfs_init("\\")) { - debug("axboot_init(): Failed to mount boot drive! Halting..."); + debug("axboot_init(): Failed to mount boot drive! Halting...\n"); // TODO: Halt while (1); } // read kernel -> test read - char *buffer = NULL; - vfs_read("\\System\\axkrnl", &buffer); + char *kbuf = NULL; + vfs_read("\\System\\axkrnl", &kbuf); // TODO: Do something with the kernel :p + uintptr_t *pm = create_pagemap(); + if (!pm) { + debug("axboot_init(): Failed to create kernel pagemap! Halting...\n"); + // TODO: Halt + while (1); + } - mem_free(buffer); + void *kernel_entry = (void *)elf_load(kbuf, pm); + (void)kernel_entry; + + mem_free(kbuf); while (1); } \ No newline at end of file diff --git a/boot/common/loader/elf.c b/boot/common/loader/elf.c new file mode 100644 index 0000000..537f9ab --- /dev/null +++ b/boot/common/loader/elf.c @@ -0,0 +1,85 @@ +/*********************************************************************************/ +/* Module Name: elf.c */ +/* Project: AurixOS */ +/* */ +/* Copyright (c) 2024-2025 Jozef Nagy */ +/* */ +/* This source is subject to the MIT License. */ +/* See License.txt in the root of this repository. */ +/* All other rights reserved. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/*********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +/* https://github.com/KevinAlavik/nekonix/blob/main/kernel/src/proc/elf.c */ +/* Thanks, Kevin <3 */ + +uint64_t elf_load(char *data, uintptr_t *pagemap) +{ + struct elf_header *header = (struct elf_header *)data; + + if (header->e_magic != ELF_MAGIC) { + debug("Invalid ELF magic: 0x%x", header->e_magic); + return 0; + } + + if (header->e_class != 2) { + debug("Unsupported ELF class: %u", header->e_class); + return 0; + } + + struct elf_program_header *ph = (struct elf_program_header *)(data + header->e_phoff); + + for (uint16_t i = 0; i < header->e_phnum; i++) { + if (ph[i].p_type != PT_LOAD) + continue; + + uint64_t vaddr_start = ALIGN_DOWN(ph[i].p_vaddr, PAGE_SIZE); + uint64_t vaddr_end = ALIGN_UP(ph[i].p_vaddr + ph[i].p_memsz, PAGE_SIZE); + uint64_t offset = ph[i].p_offset; + + uint64_t flags = VMM_PRESENT; + if (ph[i].p_flags & PF_W) + flags |= VMM_WRITABLE; + if (!(ph[i].p_flags & PF_X)) + flags |= VMM_NX; + + for (uint64_t addr = vaddr_start; addr < vaddr_end; addr += PAGE_SIZE) { + uint64_t phys = (uint64_t)mem_alloc(PAGE_SIZE); + if (!phys) { + debug("Out of physical memory"); + return 0; + } + + map_page(pagemap, addr, phys, flags); + + uint64_t file_offset = offset + (addr - vaddr_start); + if (file_offset < offset + ph[i].p_filesz) { + uint64_t to_copy = PAGE_SIZE; + if (file_offset + PAGE_SIZE > offset + ph[i].p_filesz) + to_copy = offset + ph[i].p_filesz - file_offset; + + memcpy((void *)phys, data + file_offset, to_copy); + } else { + memset((void *)phys, 0, PAGE_SIZE); + } + } + } + + debug("ELF loaded successfully, entry: 0x%lx", header->e_entry); + return header->e_entry; +} diff --git a/boot/include/lib/align.h b/boot/include/lib/align.h new file mode 100644 index 0000000..8cfbd08 --- /dev/null +++ b/boot/include/lib/align.h @@ -0,0 +1,29 @@ +/*********************************************************************************/ +/* Module Name: align.h */ +/* Project: AurixOS */ +/* */ +/* Copyright (c) 2024-2025 Jozef Nagy */ +/* */ +/* This source is subject to the MIT License. */ +/* See License.txt in the root of this repository. */ +/* All other rights reserved. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/*********************************************************************************/ + +#ifndef _LIB_ALIGN_H +#define _LIB_ALIGN_H + +#include + +#define DIV_ROUND_UP(x,y) (((uint64_t)(x) + ((uint64_t)(y) - 1)) / (uint64_t)(y)) +#define ALIGN_UP(x,y) (DIV_ROUND_UP(x, y) * (uint64_t)(y)) +#define ALIGN_DOWN(x,y) (((uint64_t)(x) / (uint64_t)(y)) * (uint64_t)(y)) + +#endif /* _LIB_ALIGN_H */ \ No newline at end of file diff --git a/boot/include/loader/elf.h b/boot/include/loader/elf.h new file mode 100644 index 0000000..c1b8931 --- /dev/null +++ b/boot/include/loader/elf.h @@ -0,0 +1,77 @@ +/*********************************************************************************/ +/* Module Name: elf.h */ +/* Project: AurixOS */ +/* */ +/* Copyright (c) 2024-2025 Jozef Nagy */ +/* */ +/* This source is subject to the MIT License. */ +/* See License.txt in the root of this repository. */ +/* All other rights reserved. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/*********************************************************************************/ + +#ifndef _LOADER_ELF_H +#define _LOADER_ELF_H + +#include +//#include + +#define ELF_MAGIC 0x464C457F + +struct elf_header { + uint32_t e_magic; + uint8_t e_class; + uint8_t e_data; + uint8_t e_version; + uint8_t e_osabi; + uint8_t e_abiversion; + uint8_t e_pad[7]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version2; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} __attribute__((packed)); + +struct elf_program_header { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} __attribute__((packed)); + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 + +uint64_t elf_load(char *kernel, uintptr_t *pagemap); + +#endif /* _LOADER_ELF_H */ diff --git a/boot/include/mm/vmm.h b/boot/include/mm/vmm.h new file mode 100644 index 0000000..6ea50c0 --- /dev/null +++ b/boot/include/mm/vmm.h @@ -0,0 +1,35 @@ +/*********************************************************************************/ +/* Module Name: vmm.h */ +/* Project: AurixOS */ +/* */ +/* Copyright (c) 2024-2025 Jozef Nagy */ +/* */ +/* This source is subject to the MIT License. */ +/* See License.txt in the root of this repository. */ +/* All other rights reserved. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/*********************************************************************************/ + +#ifndef _MM_VMM_H +#define _MM_VMM_H + +#include +#include + +#define VMM_PRESENT 1 +#define VMM_WRITABLE 2 +#define VMM_NX (1ull << 63) +#define VMM_USER 4 + +uintptr_t *create_pagemap(void); + +void map_page(uintptr_t *pm, uintptr_t virt, uintptr_t phys, uint64_t flags); + +#endif /* _MM_VMM_H */ \ No newline at end of file