Skip to content

Commit

Permalink
misc: Start porting mlibc
Browse files Browse the repository at this point in the history
  • Loading branch information
Qwinci committed Nov 5, 2023
1 parent d9a2173 commit 47a674e
Show file tree
Hide file tree
Showing 21 changed files with 489 additions and 50 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.21)
project(crescent)

add_subdirectory(kernel)
add_subdirectory(libs)
add_subdirectory(apps)

include(image.cmake)
3 changes: 3 additions & 0 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
set(APPS
user_tty
libc_test_app
)
set(APP_FILES
user_tty/user_tty
libc_test_app/libc_test_app
)

add_subdirectory(user_tty)
add_subdirectory(libc_test_app)

add_custom_target(copy_apps
DEPENDS ${APPS}
Expand Down
9 changes: 9 additions & 0 deletions apps/libc_test_app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
project(libc_test_app)

set(CMAKE_C_STANDARD 17)

add_executable(libc_test_app libc_test_app.c)

target_compile_options(libc_test_app PRIVATE --sysroot=${CMAKE_BINARY_DIR}/sysroot)
target_link_options(libc_test_app PRIVATE --sysroot=${CMAKE_BINARY_DIR}/sysroot -Wl,-dynamic-linker,/lib/ld.so)
add_dependencies(libc_test_app mlibc)
5 changes: 5 additions & 0 deletions apps/libc_test_app/libc_test_app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <stdio.h>

int main() {
puts("Hello from libc!");
}
3 changes: 2 additions & 1 deletion kernel/limine.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ TIMEOUT=0

PROTOCOL=limine
KERNEL_PATH=boot:///crescent
KERNEL_CMDLINE=init=ext2_p0/user_tty
#KERNEL_CMDLINE=init=ext2_p0/user_tty
KERNEL_CMDLINE=init=ext2_p0/libc_test_app posix_root=ext2_p0

MODULE_PATH=boot:///Tamsyn8x16r.psf
MODULE_CMDLINE=Tamsyn8x16r.psf
Expand Down
115 changes: 109 additions & 6 deletions kernel/src/exe/elf_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void elf_protect(ElfInfo info, void* load_base, void* map, bool user) {
}
}

int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {
int elf_load_from_file(Process* process, VNode* node, LoadedElf* res, bool relocate, usize* interp_base) {
Elf64EHdr ehdr;
int ret = 0;
if ((ret = node->ops.read(node, &ehdr, 0, sizeof(Elf64EHdr))) != 0) {
Expand Down Expand Up @@ -208,6 +208,11 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {
}

usize base = relocatable ? 0x400000 : 0;
if (interp_base) {
base = 0x10000000;
*interp_base = base;
}

for (u16 i = 0; i < ehdr.e_phnum; ++i) {
const Elf64PHdr* phdr = offset(phdrs, Elf64PHdr*, i * ehdr.e_phentsize);
if (phdr->p_type == PT_LOAD) {
Expand Down Expand Up @@ -238,8 +243,8 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {
}

void* mapping;
bool high = aligned_addr >= (usize) task->process->high_vmem.base;
void* mem = vm_user_alloc_backed(task->process, (void*) aligned_addr, size / PAGE_SIZE, flags, high, &mapping);
bool high = aligned_addr >= (usize) process->high_vmem.base;
void* mem = vm_user_alloc_backed(process, (void*) aligned_addr, size / PAGE_SIZE, flags, high, &mapping);
if (!mem) {
for (u16 j = 0; j < i; ++j) {
const Elf64PHdr* phdr2 = offset(phdrs, Elf64PHdr*, j * ehdr.e_phentsize);
Expand All @@ -250,7 +255,7 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {
usize align2 = phdr2->p_vaddr & (PAGE_SIZE - 1);
usize aligned_addr2 = base + phdr2->p_vaddr - align2;
usize size2 = ALIGNUP(phdr2->p_memsz + align2, PAGE_SIZE);
vm_user_dealloc_backed(task->process, (void*) aligned_addr2, size2 / PAGE_SIZE, high, NULL);
vm_user_dealloc_backed(process, (void*) aligned_addr2, size2 / PAGE_SIZE, high, NULL);
}
}

Expand All @@ -269,7 +274,7 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {
usize align2 = phdr2->p_vaddr & (PAGE_SIZE - 1);
usize aligned_addr2 = base + phdr2->p_vaddr - align2;
usize size2 = ALIGNUP(phdr2->p_memsz + align2, PAGE_SIZE);
vm_user_dealloc_backed(task->process, (void*) aligned_addr2, size2 / PAGE_SIZE, high, NULL);
vm_user_dealloc_backed(process, (void*) aligned_addr2, size2 / PAGE_SIZE, high, NULL);
}
}

Expand Down Expand Up @@ -326,7 +331,7 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {

usize rela_size = dyn[DT_RELASZ];
usize rela_off = dyn[DT_RELA];
if (rela_size) {
if (relocate && rela_size) {
Elf64Rela* rela = kmalloc(rela_size);
if (!rela) {
for (usize j = 0; j < ehdr.e_phnum; ++j) {
Expand Down Expand Up @@ -394,6 +399,8 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {
panic("unsupported elf relocation type %u\n", type);
}
}

kfree(rela, rela_size);
}
}
}
Expand All @@ -408,8 +415,104 @@ int elf_load_from_file(Task* task, VNode* node, LoadedElf* res) {

kfree(phdrs, ehdr.e_phnum * ehdr.e_phentsize);
kfree(mappings, ehdr.e_phnum * sizeof(ElfMapping));
kfree(dyn_ptr, dyn_size);

res->entry = relocatable ? (void*) (base + ehdr.e_entry) : (void*) ehdr.e_entry;

return 0;
}

int elf_get_interp(VNode* node, char** interp, usize* interp_len) {
Elf64EHdr ehdr;
if (node->ops.read(node, &ehdr, 0, sizeof(Elf64EHdr)) != 0) {
return ERR_INVALID_ARG;
}

CrescentStat s;
if (node->ops.stat(node, &s) != 0) {
return ERR_INVALID_ARG;
}

if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
ehdr.e_ident[EI_DATA] != ELFDATA2LSB ||
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
ehdr.e_machine != EM_X86_64 ||
(ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) ||
ehdr.e_phentsize != sizeof(Elf64PHdr) ||
ehdr.e_shentsize != sizeof(Elf64SHdr) ||
ehdr.e_phoff >= s.size ||
ehdr.e_shoff >= s.size ||
ehdr.e_phnum * sizeof(Elf64PHdr) >= s.size) {
return ERR_INVALID_ARG;
}

for (u16 i = 0; i < ehdr.e_phnum; ++i) {
Elf64PHdr phdr;
if (node->ops.read(node, &phdr, ehdr.e_phoff + i * ehdr.e_phentsize, sizeof(Elf64PHdr)) != 0) {
return ERR_INVALID_ARG;
}
if (phdr.p_type == PT_INTERP) {
char* mem = (char*) kmalloc(phdr.p_filesz);
if (!mem) {
return ERR_NO_MEM;
}
if (node->ops.read(node, mem, phdr.p_offset, phdr.p_filesz) != 0) {
kfree(mem, phdr.p_filesz);
return ERR_INVALID_ARG;
}
*interp = mem;
*interp_len = phdr.p_filesz;
return 0;
}
}

return ERR_NOT_EXISTS;
}

int elf_load_user_phdrs(Process* process, VNode* node, void** user_mem, usize* user_phdr_count, usize* user_entry) {
Elf64EHdr ehdr;
int ret = 0;
if ((ret = node->ops.read(node, &ehdr, 0, sizeof(Elf64EHdr))) != 0) {
return ERR_INVALID_ARG;
}

CrescentStat s;
if ((ret = node->ops.stat(node, &s)) != 0) {
return ret;
}

if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
ehdr.e_ident[EI_DATA] != ELFDATA2LSB ||
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
ehdr.e_machine != EM_X86_64 ||
(ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) ||
ehdr.e_phentsize != sizeof(Elf64PHdr) ||
ehdr.e_shentsize != sizeof(Elf64SHdr) ||
ehdr.e_phoff >= s.size ||
ehdr.e_shoff >= s.size ||
ehdr.e_phnum * sizeof(Elf64PHdr) >= s.size) {
return ERR_INVALID_ARG;
}

void* mapping;
void* phdrs = vm_user_alloc_backed(process, NULL, ALIGNUP(ehdr.e_phnum * ehdr.e_phentsize, PAGE_SIZE) / PAGE_SIZE, PF_USER | PF_READ | PF_WRITE, true, &mapping);
if (!phdrs) {
return ERR_NO_MEM;
}
if ((ret = node->ops.read(node, mapping, ehdr.e_phoff, ehdr.e_phnum * ehdr.e_phentsize)) != 0) {
vm_user_dealloc_backed(process, phdrs, ALIGNUP(ehdr.e_phnum * ehdr.e_phentsize, PAGE_SIZE) / PAGE_SIZE, true, mapping);
return ERR_INVALID_ARG;
}
*user_mem = phdrs;
*user_phdr_count = ehdr.e_phnum;
*user_entry = ehdr.e_entry;
return 0;
}
6 changes: 4 additions & 2 deletions kernel/src/exe/elf_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ LoadedElf elf_load(ElfInfo info, void* load_base, void* run_base);

void elf_protect(ElfInfo info, void* load_base, void* map, bool user);

typedef struct Task Task;
typedef struct Process Process;
typedef struct VNode VNode;

int elf_load_from_file(Task* task, VNode* node, LoadedElf* res);
int elf_load_from_file(Process* process, VNode* node, LoadedElf* res, bool relocate, usize* interp_base);
int elf_get_interp(VNode* node, char** interp, usize* interp_len);
int elf_load_user_phdrs(Process* process, VNode* node, void** user_mem, usize* user_phdr_count, usize* user_entry);
2 changes: 1 addition & 1 deletion kernel/src/fs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
target_sources(crescent PRIVATE vfs.c tar.c ext2.c fat.c)
target_sources(crescent PRIVATE vfs.c tar.c ext2.c fat.c posix_rootfs.c)
80 changes: 70 additions & 10 deletions kernel/src/fs/ext2.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ typedef struct {
u8 unused3[760];
} Ext2SuperBlock;

#define FEATURE_64BIT 0x80

typedef struct {
u32 bg_block_bitmap;
u32 bg_inode_bitmap;
Expand All @@ -79,6 +81,35 @@ typedef struct {
u16 bg_used_dirs_count;
u8 unused[14];
} BlockGroupDesc;
static_assert(sizeof(BlockGroupDesc) == 32);

typedef struct {
u32 bg_block_bitmap_lo;
u32 bg_inode_bitmap_lo;
u32 bg_inode_table_lo;
u16 bg_free_blocks_count_lo;
u16 bg_free_inodes_count_lo;
u16 bg_used_dirs_count_lo;
u16 bg_flags;
u32 bg_exclude_bitmap_lo;
u16 bg_block_bitmap_csum_lo;
u16 bg_inode_bitmap_csum_lo;
u16 bg_itable_unused_lo;
u16 bg_checksum;

u32 bg_block_bitmap_hi;
u32 bg_inode_bitmap_hi;
u32 bg_inode_table_hi;
u16 bg_free_blocks_count_hi;
u16 bg_free_inodes_count_hi;
u16 bg_used_dirs_count_hi;
u16 bg_itable_unused_hi;
u32 bg_exclude_bitmap_hi;
u16 bg_block_bitmap_csum_hi;
u16 bg_inode_bitmap_csum_hi;
u32 bg_reserved;
} BlockGroupDesc64;
static_assert(sizeof(BlockGroupDesc64) == 64);

typedef struct {
u16 i_mode;
Expand Down Expand Up @@ -121,7 +152,10 @@ typedef struct {
usize start_blk;
usize device_blks_in_ext_blk;

BlockGroupDesc* block_groups;
union {
BlockGroupDesc* block_groups;
BlockGroupDesc64* block_groups64;
};

u32 block_size;

Expand All @@ -134,6 +168,8 @@ typedef struct {

u32 inode_size;
u32 groups_size;

u32 features;
} Ext2Partition;

void* ext2_block_read(Ext2Partition* self, usize block) {
Expand All @@ -144,16 +180,33 @@ void* ext2_block_read(Ext2Partition* self, usize block) {
}

InodeDesc ext2_inode_read(Ext2Partition* self, u32 num) {
BlockGroupDesc* block_group = &self->block_groups[(num - 1) / self->inodes_in_group];
u32 inode_idx = (num - 1) % self->inodes_in_group;
if (self->features & FEATURE_64BIT) {
BlockGroupDesc64* block_group = &self->block_groups64[(num - 1) / self->inodes_in_group];
u32 inode_idx = (num - 1) % self->inodes_in_group;

u32 inode_byte_off = inode_idx * self->inode_size;

u64 bg_inode_table_block = block_group->bg_inode_table_lo | (u64) block_group->bg_inode_table_hi << 32;

u32 inode_byte_off = inode_idx * self->inode_size;
u32 inode_block = block_group->bg_inode_table + (inode_byte_off / self->block_size);
u32 inode_block_off = inode_byte_off % self->block_size;
u64 inode_block = bg_inode_table_block + (inode_byte_off / self->block_size);
u32 inode_block_off = inode_byte_off % self->block_size;

void* block = ext2_block_read(self, inode_block);
assert(block);
return *offset(block, InodeDesc*, inode_block_off);
void* block = ext2_block_read(self, inode_block);
assert(block);
return *offset(block, InodeDesc*, inode_block_off);
}
else {
BlockGroupDesc* block_group = &self->block_groups[(num - 1) / self->inodes_in_group];
u32 inode_idx = (num - 1) % self->inodes_in_group;

u32 inode_byte_off = inode_idx * self->inode_size;
u32 inode_block = block_group->bg_inode_table + (inode_byte_off / self->block_size);
u32 inode_block_off = inode_byte_off % self->block_size;

void* block = ext2_block_read(self, inode_block);
assert(block);
return *offset(block, InodeDesc*, inode_block_off);
}
}

typedef struct {
Expand Down Expand Up @@ -476,7 +529,14 @@ bool ext2_enum_partition(Storage* storage, usize start_blk, usize end_blk) {
}

self->inode_size = super_block->s_rev_level == 1 ? super_block->s_inode_size : 128;
self->groups_size = self->total_groups * sizeof(BlockGroupDesc);
u8 block_group_size = sizeof(BlockGroupDesc);
if (super_block->s_rev_level == 1) {
if (super_block->s_feature_incompat & FEATURE_64BIT) {
self->features |= FEATURE_64BIT;
block_group_size = sizeof(BlockGroupDesc64);
}
}
self->groups_size = self->total_groups * block_group_size;

kfree(super_block, MAX(sizeof(Ext2SuperBlock), storage->blk_size));

Expand Down
Loading

0 comments on commit 47a674e

Please sign in to comment.