Compare commits
No commits in common. "f2cc79759989e2dd5024f9ed00989367366a7baa" and "ad0f6546d7c94c39037855db9b892110b33cd937" have entirely different histories.
f2cc797599
...
ad0f6546d7
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,5 +3,4 @@ toolchain/
|
|||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
initrd/boot/moon
|
initrd/boot/moon
|
||||||
env-local.sh
|
env-local.sh
|
||||||
initrd/bin/**
|
|
@ -14,8 +14,6 @@ set(CMAKE_CXX_COMPILER x86_64-luna-g++)
|
|||||||
|
|
||||||
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
|
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
|
||||||
|
|
||||||
set(CMAKE_ASM_NASM_LINK_EXECUTABLE "x86_64-luna-ld <FLAGS> <CMAKE_ASM_NASM_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
|
||||||
|
|
||||||
set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/x86-64-luna)
|
set(CMAKE_FIND_ROOT_PATH ${LUNA_ROOT}/toolchain/x86-64-luna)
|
||||||
|
|
||||||
set(ARCH $ENV{ARCH})
|
set(ARCH $ENV{ARCH})
|
||||||
@ -27,5 +25,4 @@ endif()
|
|||||||
message(STATUS "Configuring Luna for ${ARCH}")
|
message(STATUS "Configuring Luna for ${ARCH}")
|
||||||
|
|
||||||
add_subdirectory(luna)
|
add_subdirectory(luna)
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(kernel)
|
||||||
add_subdirectory(apps)
|
|
@ -1,6 +0,0 @@
|
|||||||
function(luna_app SOURCE_FILE APP_NAME)
|
|
||||||
add_executable(${APP_NAME} ${SOURCE_FILE})
|
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${APP_NAME}" DESTINATION ${LUNA_ROOT}/initrd/bin)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
luna_app(app.asm app)
|
|
18
apps/app.asm
18
apps/app.asm
@ -1,18 +0,0 @@
|
|||||||
section .text
|
|
||||||
global _start
|
|
||||||
_start:
|
|
||||||
mov eax, ecx
|
|
||||||
push rdx
|
|
||||||
mov eax, 1
|
|
||||||
mov edi, hello_world
|
|
||||||
mov esi, 14
|
|
||||||
int 42h
|
|
||||||
nop
|
|
||||||
|
|
||||||
section .rodata
|
|
||||||
hello_world:
|
|
||||||
db 'Hello, world!', 0xa, 0
|
|
||||||
|
|
||||||
section .bss
|
|
||||||
array:
|
|
||||||
resb 10
|
|
@ -16,7 +16,6 @@ set(SOURCES
|
|||||||
src/thread/Thread.cpp
|
src/thread/Thread.cpp
|
||||||
src/thread/Scheduler.cpp
|
src/thread/Scheduler.cpp
|
||||||
src/InitRD.cpp
|
src/InitRD.cpp
|
||||||
src/ELF.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if("${ARCH}" MATCHES "x86_64")
|
if("${ARCH}" MATCHES "x86_64")
|
||||||
|
@ -1,137 +0,0 @@
|
|||||||
#include "ELF.h"
|
|
||||||
#include "Log.h"
|
|
||||||
#include "arch/CPU.h"
|
|
||||||
#include "arch/MMU.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
|
||||||
#include <luna/Alignment.h>
|
|
||||||
#include <luna/Alloc.h>
|
|
||||||
#include <luna/CString.h>
|
|
||||||
#include <luna/ScopeGuard.h>
|
|
||||||
|
|
||||||
static bool can_execute_segment(u32 flags)
|
|
||||||
{
|
|
||||||
return flags & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool can_write_segment(u32 flags)
|
|
||||||
{
|
|
||||||
return flags & 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static bool can_write_and_execute_segment(u32 flags)
|
|
||||||
{
|
|
||||||
return can_write_segment(flags) && can_execute_segment(flags);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
ELFSegment::ELFSegment(u64 base, usize size) : m_base(base), m_size(size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ELFLoader
|
|
||||||
{
|
|
||||||
// FIXME: Check that all calls to read_contents() read the proper amount of bytes.
|
|
||||||
Result<ELFData> load(const TarStream::Entry& elf_entry, const TarStream& stream)
|
|
||||||
{
|
|
||||||
LinkedList<ELFSegment> segments;
|
|
||||||
|
|
||||||
auto guard = make_scope_guard([&] { segments.consume([](ELFSegment* segment) { delete segment; }); });
|
|
||||||
|
|
||||||
Elf64_Ehdr elf_header;
|
|
||||||
usize nread = stream.read_contents(elf_entry, &elf_header, 0, sizeof elf_header);
|
|
||||||
if (nread < sizeof elf_header)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF header does not fit in entry");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF header has no valid magic");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF object is not 64-bit");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_header.e_ident[EI_DATA] != ELFDATA2LSB)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF object is not 2's complement little-endian");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_header.e_type != ET_EXEC)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF object is not an executable");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_header.e_machine != EM_MACH)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF object's target architecture does not match the current one (%s)",
|
|
||||||
CPU::platform_string());
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_header.e_phnum == 0)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: ELF object has no program headers");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
kdbgln("ELF: Loading ELF with entry=%#.16lx", elf_header.e_entry);
|
|
||||||
|
|
||||||
usize i;
|
|
||||||
Elf64_Phdr program_header;
|
|
||||||
|
|
||||||
for (stream.read_contents(elf_entry, &program_header, elf_header.e_phoff, sizeof program_header), i = 0;
|
|
||||||
i < elf_header.e_phnum;
|
|
||||||
i++, stream.read_contents(elf_entry, &program_header, elf_header.e_phoff + (i * elf_header.e_phentsize),
|
|
||||||
sizeof program_header))
|
|
||||||
{
|
|
||||||
if (program_header.p_type == PT_LOAD)
|
|
||||||
{
|
|
||||||
kdbgln("ELF: Loading segment (offset=%zu, base=%#.16lx, filesize=%zu, memsize=%zu)",
|
|
||||||
program_header.p_offset, program_header.p_vaddr, program_header.p_filesz,
|
|
||||||
program_header.p_memsz);
|
|
||||||
|
|
||||||
check(is_aligned<ARCH_PAGE_SIZE>(program_header.p_vaddr));
|
|
||||||
/*expect(!can_write_and_execute_segment(program_header.p_flags),
|
|
||||||
"Segment is both writable and executable");*/
|
|
||||||
|
|
||||||
ELFSegment* segment = TRY(make<ELFSegment>(program_header.p_vaddr, program_header.p_memsz));
|
|
||||||
segments.append(segment);
|
|
||||||
|
|
||||||
int flags = MMU::User | MMU::NoExecute;
|
|
||||||
if (can_write_segment(program_header.p_flags)) flags |= MMU::ReadWrite;
|
|
||||||
else if (can_execute_segment(program_header.p_flags))
|
|
||||||
flags &= ~MMU::NoExecute;
|
|
||||||
|
|
||||||
// Allocate physical memory for the segment
|
|
||||||
TRY(MemoryManager::alloc_at(program_header.p_vaddr,
|
|
||||||
get_blocks_from_size(program_header.p_memsz, ARCH_PAGE_SIZE), flags));
|
|
||||||
|
|
||||||
// Load the file section of the segment
|
|
||||||
stream.read_contents(elf_entry, (void*)program_header.p_vaddr, program_header.p_offset,
|
|
||||||
program_header.p_filesz);
|
|
||||||
|
|
||||||
// Fill out the rest of the segment with 0s
|
|
||||||
memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0,
|
|
||||||
program_header.p_memsz - program_header.p_filesz);
|
|
||||||
}
|
|
||||||
else { kdbgln("ELF: Encountered non-loadable program header, skipping"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segments.count() == 0)
|
|
||||||
{
|
|
||||||
kdbgln("Error while loading ELF: No loadable segments");
|
|
||||||
return err(ENOEXEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
guard.deactivate();
|
|
||||||
|
|
||||||
return ELFData { segments, elf_header.e_entry };
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <luna/LinkedList.h>
|
|
||||||
#include <luna/TarStream.h>
|
|
||||||
#include <luna/Types.h>
|
|
||||||
|
|
||||||
#define ELFMAG "\177ELF"
|
|
||||||
#define SELFMAG 4
|
|
||||||
#define EI_CLASS 4 /* File class byte index */
|
|
||||||
#define ELFCLASS64 2 /* 64-bit objects */
|
|
||||||
#define EI_DATA 5 /* Data encoding byte index */
|
|
||||||
#define ELFDATA2LSB 1 /* 2's complement, little endian */
|
|
||||||
#define ET_EXEC 2 /* Executable file */
|
|
||||||
#define PT_LOAD 1 /* Loadable program segment */
|
|
||||||
#ifdef ARCH_X86_64
|
|
||||||
#define EM_MACH 62 /* AMD x86-64 architecture */
|
|
||||||
#else
|
|
||||||
#error "Unknown architecture."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
u8 e_ident[16]; /* Magic number and other info */
|
|
||||||
u16 e_type; /* Object file type */
|
|
||||||
u16 e_machine; /* Architecture */
|
|
||||||
u32 e_version; /* Object file version */
|
|
||||||
u64 e_entry; /* Entry point virtual address */
|
|
||||||
u64 e_phoff; /* Program header table file offset */
|
|
||||||
u64 e_shoff; /* Section header table file offset */
|
|
||||||
u32 e_flags; /* Processor-specific flags */
|
|
||||||
u16 e_ehsize; /* ELF header size in bytes */
|
|
||||||
u16 e_phentsize; /* Program header table entry size */
|
|
||||||
u16 e_phnum; /* Program header table entry count */
|
|
||||||
u16 e_shentsize; /* Section header table entry size */
|
|
||||||
u16 e_shnum; /* Section header table entry count */
|
|
||||||
u16 e_shstrndx; /* Section header string table index */
|
|
||||||
} Elf64_Ehdr;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
u32 p_type; /* Segment type */
|
|
||||||
u32 p_flags; /* Segment flags */
|
|
||||||
u64 p_offset; /* Segment file offset */
|
|
||||||
u64 p_vaddr; /* Segment virtual address */
|
|
||||||
u64 p_paddr; /* Segment physical address */
|
|
||||||
u64 p_filesz; /* Segment size in file */
|
|
||||||
u64 p_memsz; /* Segment size in memory */
|
|
||||||
u64 p_align; /* Segment alignment */
|
|
||||||
} Elf64_Phdr;
|
|
||||||
|
|
||||||
struct ELFSegment : public LinkedListNode<ELFSegment>
|
|
||||||
{
|
|
||||||
u64 base() const
|
|
||||||
{
|
|
||||||
return m_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
usize size() const
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ELFSegment(u64 base, usize size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
u64 m_base;
|
|
||||||
usize m_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ELFData
|
|
||||||
{
|
|
||||||
LinkedList<ELFSegment> segments;
|
|
||||||
u64 entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ELFLoader
|
|
||||||
{
|
|
||||||
Result<ELFData> load(const TarStream::Entry& elf_entry, const TarStream& stream);
|
|
||||||
};
|
|
@ -1,4 +1,3 @@
|
|||||||
#include "ELF.h"
|
|
||||||
#include "InitRD.h"
|
#include "InitRD.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
@ -68,8 +67,6 @@ Result<void> init()
|
|||||||
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
kinfoln("Used memory: %s", to_dynamic_unit(MemoryManager::used()).release_value().chars());
|
||||||
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
kinfoln("Reserved memory: %s", to_dynamic_unit(MemoryManager::reserved()).release_value().chars());
|
||||||
|
|
||||||
MMU::unmap(0x400000);
|
|
||||||
|
|
||||||
TarStream::Entry entry;
|
TarStream::Entry entry;
|
||||||
while (TRY(g_initrd.read_next_entry().try_set_value_with_specific_error(entry, 0)))
|
while (TRY(g_initrd.read_next_entry().try_set_value_with_specific_error(entry, 0)))
|
||||||
{
|
{
|
||||||
@ -78,11 +75,11 @@ Result<void> init()
|
|||||||
kinfoln("Found file %s in initial ramdisk, of size %s", entry.name,
|
kinfoln("Found file %s in initial ramdisk, of size %s", entry.name,
|
||||||
to_dynamic_unit(entry.size).release_value().chars());
|
to_dynamic_unit(entry.size).release_value().chars());
|
||||||
|
|
||||||
if (!strcmp(entry.name, "bin/app"))
|
if (!strcmp(entry.name, "sys/config"))
|
||||||
{
|
{
|
||||||
auto data = TRY(ELFLoader::load(entry, g_initrd));
|
auto contents = TRY(g_initrd.read_contents_as_string(entry, 0, entry.size));
|
||||||
data.segments.consume([](ELFSegment* segment) { delete segment; });
|
|
||||||
kinfoln("Loaded ELF with entry=%#.16lx", data.entry);
|
kinfoln("%s", contents.chars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ class TarStream
|
|||||||
|
|
||||||
void rewind();
|
void rewind();
|
||||||
|
|
||||||
usize read_contents(const Entry& entry, void* buf, usize offset, usize length) const;
|
usize read_contents(const Entry& entry, void* buf, usize offset, usize length);
|
||||||
|
|
||||||
Result<OwnedStringView> read_contents_as_string(const Entry& entry, usize offset, usize max) const;
|
Result<OwnedStringView> read_contents_as_string(const Entry& entry, usize offset, usize max);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct [[gnu::packed]] TarHeader
|
struct [[gnu::packed]] TarHeader
|
||||||
|
@ -87,7 +87,7 @@ Result<TarStream::Entry> TarStream::read_next_entry()
|
|||||||
return parse_header(&header);
|
return parse_header(&header);
|
||||||
}
|
}
|
||||||
|
|
||||||
usize TarStream::read_contents(const Entry& entry, void* buf, usize offset, usize length) const
|
usize TarStream::read_contents(const Entry& entry, void* buf, usize offset, usize length)
|
||||||
{
|
{
|
||||||
if (offset >= entry.size) return 0;
|
if (offset >= entry.size) return 0;
|
||||||
if ((length + offset) > entry.size) length = entry.size - offset;
|
if ((length + offset) > entry.size) length = entry.size - offset;
|
||||||
@ -97,7 +97,7 @@ usize TarStream::read_contents(const Entry& entry, void* buf, usize offset, usiz
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<OwnedStringView> TarStream::read_contents_as_string(const Entry& entry, usize offset, usize max) const
|
Result<OwnedStringView> TarStream::read_contents_as_string(const Entry& entry, usize offset, usize max)
|
||||||
{
|
{
|
||||||
char* buf = TRY(make_array<char>(max + 1));
|
char* buf = TRY(make_array<char>(max + 1));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user