diff --git a/.gdbinit b/.gdbinit index 568ed61..2431280 100644 --- a/.gdbinit +++ b/.gdbinit @@ -1,3 +1,4 @@ -target remote localhost:1234 +source ~/.gdbinit-gef.py +gef-remote --qemu-user --qemu-binary=builddbg/zion/zion localhost 1234 file builddbg/zion/zion break zion diff --git a/CMakeLists.txt b/CMakeLists.txt index 36d3e3e..599cffb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_EXPORT_COMPILE_COMMANDS True) add_subdirectory(zion) +add_subdirectory(sys) add_custom_command( OUTPUT disk.img diff --git a/scripts/build_image.sh b/scripts/build_image.sh index 8cc970c..150022c 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -18,6 +18,7 @@ echo "Loopback device: ${dev}" cleanup() { umount efi rm -rf efi + losetup -d $dev } trap cleanup EXIT @@ -35,5 +36,7 @@ cp /usr/share/limine/BOOTX64.EFI efi/EFI/BOOT cp /usr/share/limine/limine.sys efi/ cp ../zion/boot/limine.cfg efi/ cp zion/zion efi/ +mkdir -p efi/sys +cp sys/test efi/sys/test chown drew:drew $1 diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt new file mode 100644 index 0000000..6884a8e --- /dev/null +++ b/sys/CMakeLists.txt @@ -0,0 +1,17 @@ + +set(_COMPILE_FLAGS "-ffreestanding -mgeneral-regs-only") +set(_LINK_FLAGS "-nostdlib") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +add_executable(test + test.cpp + ) + +target_link_libraries(test + zion_lib) + +set_target_properties(test + PROPERTIES + COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${_COMPILE_FLAGS}" + LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${_LINK_FLAGS}" + ) diff --git a/sys/test.cpp b/sys/test.cpp new file mode 100644 index 0000000..1485e1f --- /dev/null +++ b/sys/test.cpp @@ -0,0 +1,7 @@ + +#include "zcall.h" + +int main() { + ZDebug("Testing"); + return 0; +} diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index a76529a..4cf3ba1 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -5,6 +5,8 @@ add_executable(zion debug/debug.cpp interrupt/interrupt.cpp interrupt/interrupt_enter.s + loader/elf_loader.cpp + loader/init_loader.cpp memory/kernel_heap.cpp memory/paging_util.cpp memory/physical_memory.cpp @@ -50,3 +52,17 @@ set_target_properties(zion COMPILE_FLAGS "${_Z_COMPILE_FLAGS}" LINK_FLAGS "${_Z_LINK_FLAGS}" ) + + + +add_library(zion_lib STATIC + usr/crt0.s + usr/zcall.cpp) + +target_include_directories(zion_lib + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +set_target_properties(zion_lib + PROPERTIES + COMPILE_FLAGS "${_Z_COMPILE_FLAGS}") diff --git a/zion/boot/boot_info.cpp b/zion/boot/boot_info.cpp index 6cbe2d5..2ed0e58 100644 --- a/zion/boot/boot_info.cpp +++ b/zion/boot/boot_info.cpp @@ -25,4 +25,15 @@ uint64_t GetHigherHalfDirectMap() { return gHhdmRequest.response->offset; } +static volatile struct limine_module_request gModuleRequest { + .id = LIMINE_MODULE_REQUEST, .revision = 0, .response = 0, +}; + +const limine_module_response& GetModules() { + if (!gModuleRequest.response) { + panic("No module response from limine"); + } + return *gModuleRequest.response; +} + } // namespace boot diff --git a/zion/boot/boot_info.h b/zion/boot/boot_info.h index 4506713..15e6e40 100644 --- a/zion/boot/boot_info.h +++ b/zion/boot/boot_info.h @@ -7,4 +7,6 @@ namespace boot { const limine_memmap_response& GetMemoryMap(); uint64_t GetHigherHalfDirectMap(); +const limine_module_response& GetModules(); + } // namespace boot diff --git a/zion/boot/limine.cfg b/zion/boot/limine.cfg index 62ef188..3470793 100644 --- a/zion/boot/limine.cfg +++ b/zion/boot/limine.cfg @@ -3,7 +3,7 @@ TIMEOUT=0 :AcadiaOS + PROTOCOL=limine -PROTOCOL=limine - -KERNEL_PATH=boot:///zion + KERNEL_PATH=boot:///zion + MODULE_PATH=boot:///sys/test diff --git a/zion/include/zcall.h b/zion/include/zcall.h new file mode 100644 index 0000000..67bca77 --- /dev/null +++ b/zion/include/zcall.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#define Z_DEBUG_PRINT 100 + +uint64_t ZDebug(const char* message); + diff --git a/zion/loader/elf_loader.cpp b/zion/loader/elf_loader.cpp new file mode 100644 index 0000000..44474fe --- /dev/null +++ b/zion/loader/elf_loader.cpp @@ -0,0 +1,74 @@ +#include "loader/elf_loader.h" + +#include "debug/debug.h" +#include "memory/paging_util.h" + +namespace { + +typedef struct { + char ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry; + uint64_t phoff; + uint64_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +} Elf64Header; + +typedef struct { + uint32_t name; + uint32_t type; + uint64_t flags; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint32_t link; + uint32_t info; + uint64_t addralign; + uint64_t entsize; +} Elf64SectionHeader; + +typedef struct { + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t vaddr; + uint64_t paddr; + uint64_t filesz; + uint64_t memsz; + uint64_t align; +} Elf64ProgramHeader; + +void badmemcpy(uint64_t base, uint64_t offset, uint64_t dest) { + uint8_t* ptr = reinterpret_cast(base); + uint8_t* dest_ptr = reinterpret_cast(dest); + for (uint64_t i = 0; i < offset; i++) { + dest_ptr[i] = ptr[i]; + } +} + +} // namespace + +void LoadElfProgram(uint64_t base, uint64_t offset) { + Elf64Header* header = reinterpret_cast(base); + dbgln("phoff: %u phnum: %u", header->phoff, header->phnum); + Elf64ProgramHeader* programs = + reinterpret_cast(base + header->phoff); + for (uint64_t i = 0; i < header->phnum; i++) { + Elf64ProgramHeader& program = programs[i]; + dbgln( + "prog: type: %u, flags: %u, offset: %u\n vaddr: %m, paddr: %m\n " + "filesz: %u, memsz: %u, align: %u", + program.type, program.flags, program.offset, program.vaddr, + program.paddr, program.filesz, program.memsz, program.align); + EnsureResident(program.vaddr, program.memsz); + badmemcpy(base + program.offset, program.filesz, program.vaddr); + } +} diff --git a/zion/loader/elf_loader.h b/zion/loader/elf_loader.h new file mode 100644 index 0000000..4feac5e --- /dev/null +++ b/zion/loader/elf_loader.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void LoadElfProgram(uint64_t base, uint64_t length); diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp new file mode 100644 index 0000000..d183bd6 --- /dev/null +++ b/zion/loader/init_loader.cpp @@ -0,0 +1,30 @@ +#include "loader/init_loader.h" + +#include "boot/boot_info.h" +#include "debug/debug.h" +#include "loader/elf_loader.h" +#include "scheduler/process.h" +#include "scheduler/scheduler.h" + +namespace { + +const limine_file& GetInitProgram() { + const limine_module_response& resp = boot::GetModules(); + dbgln("Dumping modules"); + for (uint64_t i = 0; i < resp.module_count; i++) { + const limine_file& file = *resp.modules[i]; + dbgln("%s,%m,%x", file.path, file.address, file.size); + // TODO eventually compare this file path. + return file; + } + panic("No init program found"); +} + +} // namespace + +void LoadInitProgram() { + const limine_file& init_prog = GetInitProgram(); + + sched::InsertProcess( + new Process(reinterpret_cast(init_prog.address))); +} diff --git a/zion/loader/init_loader.h b/zion/loader/init_loader.h new file mode 100644 index 0000000..d6903e0 --- /dev/null +++ b/zion/loader/init_loader.h @@ -0,0 +1,3 @@ +#pragma once + +void LoadInitProgram(); diff --git a/zion/scheduler/process.cpp b/zion/scheduler/process.cpp index 94b8e72..8557715 100644 --- a/zion/scheduler/process.cpp +++ b/zion/scheduler/process.cpp @@ -25,14 +25,14 @@ Process* Process::RootProcess() { return proc; } -Process::Process() : id_(gNextId++) { +Process::Process(uint64_t elf_ptr) : id_(gNextId++) { cr3_ = phys_mem::AllocatePage(); InitializePml4(cr3_); - CreateThread(); + CreateThread(elf_ptr); } -void Process::CreateThread() { - Thread* thread = new Thread(this, next_thread_id_++); +void Process::CreateThread(uint64_t elf_ptr) { + Thread* thread = new Thread(this, next_thread_id_++, elf_ptr); ThreadEntry* tentry = new ThreadEntry{ .thread = thread, .next = nullptr, diff --git a/zion/scheduler/process.h b/zion/scheduler/process.h index 503aecc..3ede000 100644 --- a/zion/scheduler/process.h +++ b/zion/scheduler/process.h @@ -9,12 +9,12 @@ class Process { public: // Caller takes ownership of returned process. static Process* RootProcess(); - Process(); + Process(uint64_t elf_ptr); uint64_t id() { return id_; } uint64_t cr3() { return cr3_; } - void CreateThread(); + void CreateThread(uint64_t elf_ptr); Thread* GetThread(uint64_t tid); private: diff --git a/zion/scheduler/scheduler.cpp b/zion/scheduler/scheduler.cpp index 8d8164b..2930d2d 100644 --- a/zion/scheduler/scheduler.cpp +++ b/zion/scheduler/scheduler.cpp @@ -55,6 +55,7 @@ class Scheduler { Process& CurrentProcess() { return current_thread_->process(); } Thread& CurrentThread() { return *current_thread_; } + void InsertProcess(Process* process) { proc_list_.InsertProcess(process); } void Enqueue(Thread* thread) { Thread* back = current_thread_; while (back->next_thread_ != nullptr) { @@ -108,6 +109,7 @@ void EnableScheduler() { GetScheduler().Enable(); } void Yield() { GetScheduler().Yield(); } +void InsertProcess(Process* process) { GetScheduler().InsertProcess(process); } void EnqueueThread(Thread* thread) { GetScheduler().Enqueue(thread); } Process& CurrentProcess() { return GetScheduler().CurrentProcess(); } diff --git a/zion/scheduler/thread.cpp b/zion/scheduler/thread.cpp index 011a707..75753a5 100644 --- a/zion/scheduler/thread.cpp +++ b/zion/scheduler/thread.cpp @@ -1,6 +1,7 @@ #include "scheduler/thread.h" #include "debug/debug.h" +#include "loader/elf_loader.h" #include "scheduler/process.h" #include "scheduler/scheduler.h" @@ -16,7 +17,8 @@ extern "C" void thread_init() { Thread* Thread::RootThread(Process* root_proc) { return new Thread(root_proc); } -Thread::Thread(Process* proc, uint64_t tid) : process_(proc), id_(tid) { +Thread::Thread(Process* proc, uint64_t tid, uint64_t elf_ptr) + : process_(proc), id_(tid), elf_ptr_(elf_ptr) { uint64_t* stack = new uint64_t[512]; uint64_t* stack_ptr = stack + 511; // 0: rip @@ -34,6 +36,7 @@ Thread::Thread(Process* proc, uint64_t tid) : process_(proc), id_(tid) { uint64_t Thread::pid() { return process_->id(); } void Thread::Init() { + LoadElfProgram(elf_ptr_, 0); while (true) { dbgln("[%u.%u]", pid(), id_); sched::Yield(); diff --git a/zion/scheduler/thread.h b/zion/scheduler/thread.h index 89239bf..b442dc5 100644 --- a/zion/scheduler/thread.h +++ b/zion/scheduler/thread.h @@ -9,7 +9,7 @@ class Thread { public: static Thread* RootThread(Process* root_proc); - explicit Thread(Process* proc, uint64_t tid); + explicit Thread(Process* proc, uint64_t tid, uint64_t elf_ptr); uint64_t tid() { return id_; }; uint64_t pid(); @@ -31,6 +31,8 @@ class Thread { Process* process_; uint64_t id_; + uint64_t elf_ptr_; + // Stack pointer to take on resume. // Stack will contain the full thread context. uint64_t rsp0_; diff --git a/zion/usr/crt0.s b/zion/usr/crt0.s new file mode 100644 index 0000000..530badd --- /dev/null +++ b/zion/usr/crt0.s @@ -0,0 +1,10 @@ +.text + +.global _start +_start: + call main + call _exit + +_exit: + mov $1, %rdi + syscall diff --git a/zion/usr/zcall.cpp b/zion/usr/zcall.cpp new file mode 100644 index 0000000..8b2f285 --- /dev/null +++ b/zion/usr/zcall.cpp @@ -0,0 +1,13 @@ +#include "include/zcall.h" + +#include + +uint64_t SysCall1(uint64_t number, const void* first) { + uint64_t return_code; + asm("syscall" : "=a"(return_code) : "D"(number), "S"(first) : "rcx", "r11"); + return return_code; +} + +uint64_t ZDebug(const char* message) { + return SysCall1(Z_DEBUG_PRINT, message); +} diff --git a/zion/zion.cpp b/zion/zion.cpp index 31e89e7..dfc270d 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -3,6 +3,7 @@ #include "common/gdt.h" #include "debug/debug.h" #include "interrupt/interrupt.h" +#include "loader/init_loader.h" #include "memory/kernel_heap.h" #include "memory/paging_util.h" #include "memory/physical_memory.h" @@ -21,11 +22,9 @@ extern "C" void zion() { InitSyscall(); sched::InitScheduler(); - Process p1; - p1.CreateThread(); - Process p2; - p2.CreateThread(); sched::EnableScheduler(); + + LoadInitProgram(); sched::Yield(); dbgln("Sleeping!");