From 2015e0e0aa5577463705b0c30a4dcffa8c000cf9 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Mon, 1 Sep 2025 23:22:47 +0200 Subject: [PATCH] Hello user process --- .gitignore | 1 - Makefile | 11 +- base/bin/.gitignore | 3 + base/bin/.gitkeep | 0 kernel/Makefile | 2 +- kernel/elf.h | 355 ++++++++++++++++++++++++++++++++++++ kernel/errors.h | 2 +- kernel/fs/kvfs/kvfs.c | 18 +- kernel/fs/kvfs/kvfs.h | 2 + kernel/fs/portlfs/portlfs.c | 37 +++- kernel/fs/portlfs/portlfs.h | 2 + kernel/hal/x86_64/vmm.c | 19 +- kernel/hal/x86_64/vmm.h | 5 +- kernel/proc/proc.c | 208 +++++++++++++++++---- kernel/proc/proc.h | 4 + kernel/vfs/vfs.c | 16 ++ kernel/vfs/vfs.h | 12 +- kernel/vmm/vmm.c | 4 +- scripts/devel.sh | 2 +- scripts/mkbaseimg.sh | 5 +- user/.gitignore | 1 + user/Makefile | 14 ++ user/Makefile.inc | 9 + user/arch/x86_64/link.ld | 26 +++ user/arch/x86_64/x86_64.mk | 22 +++ user/hello/.gitignore | 2 + user/hello/Makefile | 21 +++ user/hello/hello.s | 6 + 28 files changed, 744 insertions(+), 65 deletions(-) create mode 100644 base/bin/.gitignore create mode 100644 base/bin/.gitkeep create mode 100644 kernel/elf.h create mode 100644 user/.gitignore create mode 100644 user/Makefile create mode 100644 user/Makefile.inc create mode 100644 user/arch/x86_64/link.ld create mode 100644 user/arch/x86_64/x86_64.mk create mode 100644 user/hello/.gitignore create mode 100644 user/hello/Makefile create mode 100644 user/hello/hello.s diff --git a/.gitignore b/.gitignore index a6a0246..244b48a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /limine /iso_root -/base_root *.iso *.img diff --git a/Makefile b/Makefile index 10f891f..3e026e6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,10 @@ -.PHONY: all clean prepare cleanall iso base +.PHONY: clean prepare cleanall iso base kernel user -all: - make -C kernel all +kernel: + make -C kernel ROOT=$(PWD) all + +user: + make -C user ROOT=$(PWD) all prepare: if [ ! -d limine ]; then \ @@ -13,10 +16,10 @@ prepare: cleanall: make clean rm -rf limine - rm -rf littlefs-fuse clean: make -C kernel clean + make -C user clean rm -f mop2.iso base.img base: diff --git a/base/bin/.gitignore b/base/bin/.gitignore new file mode 100644 index 0000000..bf27f31 --- /dev/null +++ b/base/bin/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!.gitkeep diff --git a/base/bin/.gitkeep b/base/bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/kernel/Makefile b/kernel/Makefile index b4b423e..955015a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -29,7 +29,7 @@ endif include arch/$(ARCH)/$(ARCH).mk include extconf/extra.mk -LDFLAGS := -nostdlib -static -T arch/$(ARCH)/link.ld $(shell $(CC) -print-libgcc-file-name) +LDFLAGS += -nostdlib -static -T arch/$(ARCH)/link.ld $(shell $(CC) -print-libgcc-file-name) SRCFILES := $(wildcard *.c) \ $(wildcard printf/*.c) \ diff --git a/kernel/elf.h b/kernel/elf.h new file mode 100644 index 0000000..90bc6fd --- /dev/null +++ b/kernel/elf.h @@ -0,0 +1,355 @@ +#ifndef ELF_H_ +#define ELF_H_ + +#include + +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFOSABI_SYSV 0 +#define EM_X86_64 62 + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOBITS 8 +#define SHT_DYNSYM 11 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Machine type */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point address */ + Elf32_Off e_phoff; /* Program header offset */ + Elf32_Off e_shoff; /* Section header offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* Size of program header entry */ + Elf32_Half e_phnum; /* Number of program header entries */ + Elf32_Half e_shentsize; /* Size of section header entry */ + Elf32_Half e_shnum; /* Number of section header entries */ + Elf32_Half e_shstrndx; /* Section name string table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Machine type */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point address */ + Elf64_Off e_phoff; /* Program header offset */ + Elf64_Off e_shoff; /* Section header offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* Size of program header entry */ + Elf64_Half e_phnum; /* Number of program header entries */ + Elf64_Half e_shentsize; /* Size of section header entry */ + Elf64_Half e_shnum; /* Number of section header entries */ + Elf64_Half e_shstrndx; /* Section name string table index */ +} Elf64_Ehdr; + +enum { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, +}; + +enum { SHN_UNDEF = 0, SHN_ABS = 0xFFF1 }; + +typedef struct { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +enum { STB_GLOBAL = 1, STB_WEAK = 2, STB_GNU_UNIQUE = 10 }; + +enum { STT_OBJECT = 1, STT_FUNC = 2, STT_TLS = 6 }; + +enum { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, +}; + +enum { + R_AARCH64_ABS64 = 257, + R_AARCH64_COPY = 1024, + R_AARCH64_GLOB_DAT = 1025, + R_AARCH64_JUMP_SLOT = 1026, + R_AARCH64_RELATIVE = 1027, + R_AARCH64_TLS_TPREL = 1030, + R_AARCH64_TLSDESC = 1031 +}; + +typedef struct { + Elf64_Addr r_offset; + uint64_t r_info; +} Elf64_Rel; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +static inline Elf64_Xword ELF64_R_SYM(Elf64_Xword info) { return info >> 32; } +static inline Elf64_Xword ELF64_R_TYPE(Elf64_Xword info) { + return info & 0xFFFFFFFF; +} + +enum { + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_PHDR = 6, + PT_TLS = 7, + PT_GNU_EH_FRAME = 0x6474E550, + PT_GNU_STACK = 0x6474E551, + PT_GNU_RELRO = 0x6474E552, + PT_GNU_PROPERTY = 0x6474E553, +}; + +enum { PF_X = 1, PF_W = 2, PF_R = 4 }; + +typedef struct { + Elf64_Word p_type; /* Type of segment */ + Elf64_Word p_flags; /* Segment attributes */ + Elf64_Off p_offset; /* Offset in file */ + Elf64_Addr p_vaddr; /* Virtual address in memory */ + Elf64_Addr p_paddr; /* Reserved */ + Elf64_Xword p_filesz; /* Size of segment in file */ + Elf64_Xword p_memsz; /* Size of segment in memory */ + Elf64_Xword p_align; /* Alignment of segment */ +} Elf64_Phdr; + +enum { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_BIND_NOW = 24, + DT_INIT_ARRAY = 25, + DT_FINI_ARRAY = 26, + DT_INIT_ARRAYSZ = 27, + DT_FINI_ARRAYSZ = 28, + DT_RUNPATH = 29, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_JMPREL = 23, + DT_FLAGS = 30, + DT_GNU_HASH = 0x6ffffef5, + DT_TLSDESC_PLT = 0x6ffffef6, + DT_TLSDESC_GOT = 0x6ffffef7, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff +}; + +enum { + // For DT_FLAGS. + DF_SYMBOLIC = 0x02, + DF_STATIC_TLS = 0x10, + + // For DT_FLAGS_1. + DF_1_NOW = 0x00000001 +}; + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +/* ST_TYPE (subfield of st_info) values (symbol type) */ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +/* ST_BIND (subfield of st_info) values (symbol binding) */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +/* sh_type (section type) values */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_SYMTAB_SHNDX 18 + +/* special section indices */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xff00 + +/* values for e_machine */ +#define EM_NONE 0 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_X86_64 62 + +/* e_indent constants */ +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define EI_CLASS 4 +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define EI_DATA 5 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 +#define ELFDATANUM 3 + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 + +typedef struct { + uint64_t entry; + uint64_t phdr; + uint64_t phent; + uint64_t phnum; +} ElfAuxval; + +#endif // ELF_H_ diff --git a/kernel/errors.h b/kernel/errors.h index c8882e4..e08f860 100644 --- a/kernel/errors.h +++ b/kernel/errors.h @@ -8,6 +8,6 @@ #define E_OUTOFBOUNDS -4 #define E_UNKNOWN_SDTYPE -5 #define E_TODO -6 -#define E_GENERIC_ERROR -7 +#define E_BADIO -7 #endif // ERRORS_H_ diff --git a/kernel/fs/kvfs/kvfs.c b/kernel/fs/kvfs/kvfs.c index d348abd..e51e5f5 100644 --- a/kernel/fs/kvfs/kvfs.c +++ b/kernel/fs/kvfs/kvfs.c @@ -27,6 +27,22 @@ int32_t kvfs_read(struct VfsMountPoint *vmp, const char *key, uint8_t *const buf return E_OK; } +int32_t kvfs_stat(struct VfsMountPoint *vmp, const char *key, struct VfsStat *stat) { + KvfsNode *node = NULL; + + spinlock_acquire(&vmp->spinlock); + HSHTB_GET(&vmp->fs.kvfs, nodes, (char *)key, key_, node); + spinlock_release(&vmp->spinlock); + + if (node == NULL) { + return E_NOENTRY; + } + + stat->type = VFS_TYPE_FILE; + stat->size = KVFS_BUFFER_SIZE; + return E_OK; +} + int32_t kvfs_write(struct VfsMountPoint *vmp, const char *key, const uint8_t *const buffer, size_t n, size_t off) { KvfsNode *node = NULL; @@ -85,7 +101,7 @@ int32_t kvfs_create(struct VfsMountPoint *vmp, const char *path, int32_t type) { bool kvfs_check(void) { int32_t ret; - ret = vfs_create("tmpvars", "hello", VFS_CREATE_FILE); + ret = vfs_create("tmpvars", "hello", VFS_TYPE_FILE); if (ret != E_OK) return false; char *hello = "WAWAWAWA!!!"; diff --git a/kernel/fs/kvfs/kvfs.h b/kernel/fs/kvfs/kvfs.h index fe7f081..4840507 100644 --- a/kernel/fs/kvfs/kvfs.h +++ b/kernel/fs/kvfs/kvfs.h @@ -5,6 +5,7 @@ #include struct VfsMountPoint; +struct VfsStat; #define KVFS_NODE_KEY_MAX 128 #define KVFS_NODES_MAX 256 @@ -21,6 +22,7 @@ typedef struct { } Kvfs; int32_t kvfs_read(struct VfsMountPoint *vmp, const char *key, uint8_t *const buffer, size_t n, size_t off); +int32_t kvfs_stat(struct VfsMountPoint *vmp, const char *key, struct VfsStat *stat); int32_t kvfs_write(struct VfsMountPoint *vmp, const char *key, const uint8_t *const buffer, size_t n, size_t off); int32_t kvfs_remove(struct VfsMountPoint *vmp, const char *key); int32_t kvfs_create(struct VfsMountPoint *vmp, const char *path, int32_t type); diff --git a/kernel/fs/portlfs/portlfs.c b/kernel/fs/portlfs/portlfs.c index b3a4ac4..6cf2e5c 100644 --- a/kernel/fs/portlfs/portlfs.c +++ b/kernel/fs/portlfs/portlfs.c @@ -9,7 +9,6 @@ #define CHECK(err) \ do { \ int ok = (err); \ - kprintf("ok = %d\n", ok); \ if (ok < 0) goto bad; \ } while(0) @@ -27,7 +26,29 @@ int32_t littlefs_read(struct VfsMountPoint *vmp, const char *path, uint8_t *cons return E_OK; bad: spinlock_release(&vmp->spinlock); - return E_GENERIC_ERROR; + return E_BADIO; +} + +int32_t littlefs_stat(struct VfsMountPoint *vmp, const char *path, struct VfsStat *stat) { + spinlock_acquire(&vmp->spinlock); + + LittleFs *fs = &vmp->fs.littlefs; + struct lfs_info stat1; + CHECK(lfs_stat(&fs->instance, path, &stat1)); + + if (stat1.type == LFS_TYPE_REG) { + stat->type = VFS_TYPE_FILE; + } else if (stat1.type == LFS_TYPE_DIR) { + stat->type = VFS_TYPE_DIR; + } + + stat->size = stat1.size; + + spinlock_release(&vmp->spinlock); + return E_OK; +bad: + spinlock_release(&vmp->spinlock); + return E_BADIO; } int32_t littlefs_write(struct VfsMountPoint *vmp, const char *path, const uint8_t *const buffer, size_t n, size_t off) { @@ -44,7 +65,7 @@ int32_t littlefs_write(struct VfsMountPoint *vmp, const char *path, const uint8_ return E_OK; bad: spinlock_release(&vmp->spinlock); - return E_GENERIC_ERROR; + return E_BADIO; } int32_t littlefs_remove(struct VfsMountPoint *vmp, const char *path) { @@ -57,7 +78,7 @@ int32_t littlefs_remove(struct VfsMountPoint *vmp, const char *path) { return E_OK; bad: spinlock_release(&vmp->spinlock); - return E_GENERIC_ERROR; + return E_BADIO; } int32_t littlefs_cleanup(struct VfsMountPoint *vmp) { @@ -67,7 +88,7 @@ int32_t littlefs_cleanup(struct VfsMountPoint *vmp) { return err; } err = lfs_unmount(&vmp->fs.littlefs.instance); - if (err < 0) { return E_GENERIC_ERROR; } + if (err < 0) { return E_BADIO; } return E_OK; } @@ -76,10 +97,10 @@ int32_t littlefs_create(struct VfsMountPoint *vmp, const char *path, int32_t typ LittleFs *fs = &vmp->fs.littlefs; switch (type) { - case VFS_CREATE_DIR: + case VFS_TYPE_DIR: CHECK(lfs_mkdir(&fs->instance, path)); break; - case VFS_CREATE_FILE: { + case VFS_TYPE_FILE: { lfs_file_t file; CHECK(lfs_file_open(&fs->instance, &file, path, LFS_O_CREAT | LFS_O_WRONLY)); CHECK(lfs_file_close(&fs->instance, &file)); @@ -90,7 +111,7 @@ int32_t littlefs_create(struct VfsMountPoint *vmp, const char *path, int32_t typ return E_OK; bad: spinlock_release(&vmp->spinlock); - return E_GENERIC_ERROR; + return E_BADIO; } bool littlefs_check(void) { diff --git a/kernel/fs/portlfs/portlfs.h b/kernel/fs/portlfs/portlfs.h index c4cf080..a75d1fe 100644 --- a/kernel/fs/portlfs/portlfs.h +++ b/kernel/fs/portlfs/portlfs.h @@ -8,12 +8,14 @@ #define LITTLEFS_BLOCK_SIZE 4096 struct VfsMountPoint; +struct VfsStat; typedef struct { lfs_t instance; } LittleFs; int32_t littlefs_read(struct VfsMountPoint *vmp, const char *path, uint8_t *const buffer, size_t n, size_t off); +int32_t littlefs_stat(struct VfsMountPoint *vmp, const char *path, struct VfsStat *stat); int32_t littlefs_write(struct VfsMountPoint *vmp, const char *path, const uint8_t *const buffer, size_t n, size_t off); int32_t littlefs_remove(struct VfsMountPoint *vmp, const char *path); int32_t littlefs_create(struct VfsMountPoint *vmp, const char *path, int32_t type); diff --git a/kernel/hal/x86_64/vmm.c b/kernel/hal/x86_64/vmm.c index 3b73f31..eff28a1 100644 --- a/kernel/hal/x86_64/vmm.c +++ b/kernel/hal/x86_64/vmm.c @@ -5,6 +5,8 @@ #include "bootinfo/bootinfo.h" #include "pmm/pmm.h" #include "paging.h" +#include "proc/proc.h" +#include "kprintf.h" PgTable *KERNEL_CR3 = NULL; @@ -73,7 +75,7 @@ void hal_vmm_map_range(PgTable *cr3, void *virtstart, void *physstart, size_t si } } -void hal_vmm_unmap_range(PgTable *cr3, void *virtstart, void *physstart, size_t size, uint32_t flags) { +void hal_vmm_unmap_range(PgTable *cr3, void *virtstart, void *physstart, size_t size) { if (size % HAL_PAGE_SIZE != 0 || (uint64_t)virtstart % HAL_PAGE_SIZE != 0 || (uint64_t)physstart % HAL_PG_PRESENT != 0) { return; } @@ -96,6 +98,21 @@ void hal_vmm_switch_pd(PgTable *cr3) { hal_loadpd(cr3); } +PgTable *hal_vmm_userproc_pml4(Proc *proc) { + uint8_t *cr3 = pmm_alloc(1); + PgTable *pml4 = (PgTable *)VIRT(cr3); + hal_memset(pml4, 0, HAL_PAGE_SIZE); + + PgTable *kcr3 = VIRT(KERNEL_CR3); + + for (size_t i = 256; i < 512; i++) { + pml4->ents[i] = kcr3->ents[i]; + } + + return (PgTable *)cr3; +} + void hal_vmm_init(void) { KERNEL_CR3 = hal_vmm_current_cr3(); + kprintf("KERNEL_CR3 = %p\n", KERNEL_CR3); } diff --git a/kernel/hal/x86_64/vmm.h b/kernel/hal/x86_64/vmm.h index 6a8622f..7fcc0c8 100644 --- a/kernel/hal/x86_64/vmm.h +++ b/kernel/hal/x86_64/vmm.h @@ -5,6 +5,8 @@ #include #include "compiler/attr.h" +struct Proc; + enum { HAL_PG_PRESENT = 1<<0, HAL_PG_RW = 1<<1, @@ -43,6 +45,7 @@ void hal_vmm_unmap_page(PgTable *pml4, uint64_t virtaddr, uint64_t physaddr); void hal_vmm_map_page(PgTable *pml4, uint64_t virtaddr, uint64_t physaddr, uint32_t flags); PgTable *hal_vmm_current_cr3(void); void hal_vmm_map_range(PgTable *cr3, void *virtstart, void *physstart, size_t size, uint32_t flags); -void hal_vmm_unmap_range(PgTable *cr3, void *virtstart, void *physstart, size_t size, uint32_t flags); +void hal_vmm_unmap_range(PgTable *cr3, void *virtstart, void *physstart, size_t size); +PgTable *hal_vmm_userproc_pml4(struct Proc *proc); #endif // HAL_VMM_H_ diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c index b6b3f99..8902341 100644 --- a/kernel/proc/proc.c +++ b/kernel/proc/proc.c @@ -1,5 +1,6 @@ #include #include +#include #include "hal/hal.h" #include "vmm/vmm.h" #include "spinlock/spinlock.h" @@ -8,6 +9,10 @@ #include "pmm/pmm.h" #include "util/util.h" #include "kprintf.h" +#include "elf.h" +#include "errors.h" +#include "vfs/vfs.h" +#include "bootinfo/bootinfo.h" #define PROC_REAPER_FREQ 30 @@ -22,7 +27,66 @@ uint64_t sched_ticks = 0; Procs PROCS; +bool proc_checkelf(uint8_t *elf) { + if (elf[0] != 0x7f || elf[1] != 'E' || elf[2] != 'L' || elf[3] != 'F') { + return false; + } + return true; +} + +ElfAuxval proc_load_elf_segs(Proc *proc, uint8_t *data) { + #if defined(__x86_64__) + PgTable *vas = proc->platformdata.cr3; + #endif + ElfAuxval aux = {0}; + + Elf64_Ehdr *elfhdr = (Elf64_Ehdr *)data; + aux.entry = elfhdr->e_entry; + aux.phnum = elfhdr->e_phnum; + aux.phent = elfhdr->e_phentsize; + + for (uint64_t seg = 0; seg < elfhdr->e_phnum; seg++) { + Elf64_Phdr *phdr = (Elf64_Phdr *)(data + elfhdr->e_phoff + (elfhdr->e_phentsize * seg)); + + switch (phdr->p_type) { + case PT_PHDR: { + aux.phdr = (uint64_t)phdr->p_vaddr; + } break; + case PT_LOAD: { + uint64_t off = phdr->p_vaddr & (HAL_PAGE_SIZE - 1); + uint64_t blocks = (phdr->p_memsz / HAL_PAGE_SIZE) + 1; + + uint8_t *physaddr = pmm_alloc(blocks); + uint8_t *virtaddr = (uint8_t *)(phdr->p_vaddr - off); + + hal_memset(VIRT(physaddr), 0, phdr->p_memsz); + hal_memcpy(VIRT(physaddr) + off, (data + phdr->p_offset), phdr->p_filesz); + + #if defined(__x86_64__) + uint32_t pgflags = HAL_PG_USER | HAL_PG_RW | HAL_PG_PRESENT; + hal_vmm_map_range(VIRT(vas), virtaddr, physaddr, blocks * HAL_PAGE_SIZE, pgflags); + #endif + + VasRange *range = dlmalloc(sizeof(*range)); + range->virtstart = virtaddr; + range->physstart = physaddr; + range->size = blocks * HAL_PAGE_SIZE; + #if defined(__x86_64__) + range->pgflags = pgflags; + #endif + + LL_APPEND(proc->vas, range); + } break; + } + } + return aux; +} + Proc *proc_spawnkern(void (*ent)(void), char *name) { + if (pids >= PROC_MAX) { + return NULL; + } + Proc *proc = dlmalloc(sizeof(*proc)); if (proc == NULL) { return NULL; @@ -51,6 +115,56 @@ Proc *proc_spawnkern(void (*ent)(void), char *name) { return proc; } +Proc *proc_spawnuser(char *mountpoint, char *path) { + VfsStat stat; + if (vfs_stat(mountpoint, path, &stat) != E_OK) { + return NULL; + } + if (stat.type != VFS_TYPE_FILE) { + return NULL; + } + + uint8_t *data = dlmalloc(stat.size); + if (vfs_read(mountpoint, path, data, stat.size, 0) != E_OK) { + return NULL; + } + + Proc *proc = dlmalloc(sizeof(*proc)); + hal_memset(proc, 0, sizeof(*proc)); + ksprintf(proc->name, "%s:%s", mountpoint, path); + + uint8_t *sp = (uint8_t *)pmm_alloc(PROC_STACKBLOCKS) + PROC_STACKSIZE; + uint8_t *spbase = sp - PROC_STACKSIZE; + + #if defined(__x86_64__) + proc->platformdata.kstack = sp; + hal_memset(&proc->platformdata.trapframe, 0, sizeof(proc->platformdata.trapframe)); + + proc->platformdata.cr3 = hal_vmm_userproc_pml4(proc); + uint32_t flags = HAL_PG_RW | HAL_PG_USER | HAL_PG_PRESENT; + hal_vmm_map_range(VIRT(proc->platformdata.cr3), spbase, spbase, PROC_STACKSIZE, flags); + VasRange *range = dlmalloc(sizeof(*range)); + range->virtstart = spbase; + range->physstart = spbase; + range->size = PROC_STACKSIZE; + range->pgflags = flags; + + LL_APPEND(proc->vas, range); + + ElfAuxval aux = proc_load_elf_segs(proc, data); + + proc->platformdata.trapframe.ss = 0x20 | 0x3; + proc->platformdata.trapframe.rsp = (uint64_t)VIRT(sp); + proc->platformdata.trapframe.rflags = 0x202; + proc->platformdata.trapframe.cs = 0x18 | 0x3; + proc->platformdata.trapframe.rip = aux.entry; + #endif + proc->state = PROC_READY; + proc->pid = pids++; + + return proc; +} + void proc_register(Proc *proc) { spinlock_acquire(&PROCS.spinlock); LL_APPEND(PROCS.procs, proc); @@ -63,24 +177,53 @@ Proc *proc_nextready(void) { return proc; } +void proc_reaper(void) { + Proc *head = PROCS.procs; + while (head) { + if (head->state == PROC_ZOMBIE) { + Proc *zombie = head; + head = head->next; + + LL_REMOVE(PROCS.procs, zombie); + + #if defined(__x86_64__) + pmm_free((uintptr_t)(zombie->platformdata.kstack - PROC_STACKSIZE), PROC_STACKBLOCKS); + #endif + + if (!zombie->kern) { + VasRange *vashead = zombie->vas; + size_t i = 0; + while (vashead) { + VasRange *tmp = vashead; + vashead = vashead->next; + #if defined(__x86_64__) + hal_vmm_unmap_range(zombie->platformdata.cr3, tmp->virtstart, tmp->physstart, tmp->size); + #endif + // first pmm mapping is for the elf itself + if (i == 0) { + pmm_free((uintptr_t)tmp->physstart, tmp->size / HAL_PAGE_SIZE); + } + dlfree(tmp); + i++; + } + + #if defined(__x86_64__) + pmm_free((uintptr_t)zombie->platformdata.cr3, 1); + #endif + } + dlfree(zombie); + } else { + head = head->next; + } + } +} + void proc_sched(void *cpustate) { hal_intr_disable(); sched_ticks++; if (sched_ticks % PROC_REAPER_FREQ == 0) { - Proc *head = PROCS.procs; - while (head) { - if (head->state == PROC_ZOMBIE) { - Proc *zombie = head; - head = head->next; - - LL_REMOVE(PROCS.procs, zombie); - pmm_free((uintptr_t)(zombie->platformdata.kstack - PROC_STACKSIZE), PROC_STACKBLOCKS); - dlfree(zombie); - } else { - head = head->next; - } - } + proc_reaper(); } #if defined(__x86_64__) @@ -116,31 +259,18 @@ void proc_idle(void) { } } -int a = 0; - -void proc_print(void) { +void proc_status(void) { for (;;) { - hal_wait(1 * 1000); - - /* if (a == 10) { */ - /* PROC_DIE(); */ - /* } */ - kprintf("A"); - a++; - } -} - -int b = 0; - -void proc_print2(void) { - for (;;) { - hal_wait(2 * 1000); - - /* if (b == 20) { */ - /* PROC_DIE(); */ - /* } */ - kprintf("B"); - b++; + spinlock_acquire(&PROCS.spinlock); + Proc *head = PROCS.procs; + while (head) { + kprintf("%s %s\n", head->kern ? "kern" : "user", head->name); + head = head->next; + } + kprintf("\n\n"); + spinlock_release(&PROCS.spinlock); + + hal_wait(3 * 1000); } } @@ -152,8 +282,8 @@ void proc_init(void) { proc_register(idle); PROCS.current = idle; - proc_register(proc_spawnkern(&proc_print, "print")); - proc_register(proc_spawnkern(&proc_print2, "print")); + proc_register(proc_spawnkern(&proc_status, "status")); + proc_register(proc_spawnuser("base", "/bin/hello")); #if defined(__x86_64__) hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3); diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index 61461a9..57337fd 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -12,6 +12,8 @@ #define PROC_STACKBLOCKS 32 #define PROC_STACKSIZE (PROC_STACKBLOCKS * BITMAP_BLOCK_SIZE) +#define PROC_MAX 0x100 // max amount of processes + enum { PROC_READY, PROC_RUNNING, @@ -38,7 +40,9 @@ typedef struct { extern Procs PROCS; void proc_init(void); +void proc_register(Proc *proc); Proc *proc_spawnkern(void (*ent)(void), char *name); +Proc *proc_spawnuser(char *mountpoint, char *path); void proc_sched(void *cpustate); #endif // PROC_PROC_H_ diff --git a/kernel/vfs/vfs.c b/kernel/vfs/vfs.c index 8c48489..38b0eb3 100644 --- a/kernel/vfs/vfs.c +++ b/kernel/vfs/vfs.c @@ -18,6 +18,7 @@ VfsTable VFS_TABLE; void vfs_init_kvfs(VfsMountPoint *mp) { mp->read = &kvfs_read; + mp->stat = &kvfs_stat; mp->write = &kvfs_write; mp->remove = &kvfs_remove; mp->check = &kvfs_check; @@ -52,6 +53,7 @@ void vfs_init_littlefs(VfsMountPoint *mp) { } mp->read = &littlefs_read; + mp->stat = &littlefs_stat; mp->write = &littlefs_write; mp->remove = &littlefs_remove; mp->check = &littlefs_check; @@ -123,6 +125,20 @@ int32_t vfs_read(char *mountpoint, const char *path, uint8_t *const buffer, size return mp->read(mp, path, buffer, n, off); } +int32_t vfs_stat(char *mountpoint, const char *path, VfsStat *stat) { + VfsMountPoint *mp = NULL; + + spinlock_acquire(&VFS_TABLE.spinlock); + HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); + spinlock_release(&VFS_TABLE.spinlock); + + if (mp == NULL) { + return E_NOENTRY; + } + + return mp->stat(mp, path, stat); +} + int32_t vfs_create(char *mountpoint, const char *path, int32_t type) { VfsMountPoint *mp = NULL; diff --git a/kernel/vfs/vfs.h b/kernel/vfs/vfs.h index cece048..e8859ea 100644 --- a/kernel/vfs/vfs.h +++ b/kernel/vfs/vfs.h @@ -23,10 +23,15 @@ static const char *vfs_strings[] = { }; enum { - VFS_CREATE_DIR, - VFS_CREATE_FILE, + VFS_TYPE_DIR, + VFS_TYPE_FILE, }; +typedef struct VfsStat { + size_t size; + int32_t type; +} VfsStat; + typedef struct VfsMountPoint { bool taken; uint8_t label[VFS_MOUNTPOINT_LABEL_MAX]; @@ -34,6 +39,7 @@ typedef struct VfsMountPoint { StoreDev *backingsd; int32_t (*read)(struct VfsMountPoint *vmp, const char *path, uint8_t *const buffer, size_t n, size_t off); + int32_t (*stat)(struct VfsMountPoint *vmp, const char *path, struct VfsStat *stat); int32_t (*write)(struct VfsMountPoint *vmp, const char *path, const uint8_t *const buffer, size_t n, size_t off); int32_t (*remove)(struct VfsMountPoint *vmp, const char *path); int32_t (*create)(struct VfsMountPoint *vmp, const char *path, int32_t type); @@ -56,9 +62,11 @@ extern VfsTable VFS_TABLE; void vfs_init(void); int32_t vfs_read(char *mountpoint, const char *path, uint8_t *const buffer, size_t n, size_t off); +int32_t vfs_stat(char *mountpoint, const char *path, VfsStat *stat); int32_t vfs_write(char *mountpoint, const char *path, const uint8_t *const buffer, size_t n, size_t off); int32_t vfs_remove(char *mountpoint, const char *path); int32_t vfs_create(char *mountpoint, const char *path, int32_t type); int32_t vfs_unmount(char *mountpoint); + #endif // VFS_VFS_H_ diff --git a/kernel/vmm/vmm.c b/kernel/vmm/vmm.c index e1a8856..a4ce52d 100644 --- a/kernel/vmm/vmm.c +++ b/kernel/vmm/vmm.c @@ -35,10 +35,10 @@ void vmm_map_kern_range(void *virtstart, void *physstart, size_t size, uint32_t spinlock_release(&VIRT_MEM.spinlock); } -void vmm_unmap_kern_range(void *virtstart, void *physstart, size_t size, uint32_t flags) { +void vmm_unmap_kern_range(void *virtstart, void *physstart, size_t size) { spinlock_acquire(&VIRT_MEM.spinlock); #if defined(__x86_64__) - hal_vmm_unmap_range(KERNEL_CR3, virtstart, physstart, size, flags); + hal_vmm_unmap_range(KERNEL_CR3, virtstart, physstart, size); #endif spinlock_release(&VIRT_MEM.spinlock); } diff --git a/scripts/devel.sh b/scripts/devel.sh index 45b9414..35a5138 100755 --- a/scripts/devel.sh +++ b/scripts/devel.sh @@ -1,3 +1,3 @@ #!/bin/sh -make -B && make base && make iso +make -B kernel && make -B user && make base && make iso diff --git a/scripts/mkbaseimg.sh b/scripts/mkbaseimg.sh index 687ee6a..08ec5d1 100755 --- a/scripts/mkbaseimg.sh +++ b/scripts/mkbaseimg.sh @@ -1,6 +1,5 @@ #!/bin/sh rm -f base.img -rm -rf base_root -mkdir -p base_root -mklittlefs -c base_root -b 4096 -s $((1<<20)) base.img +cat user/FILES.txt | while read line; do cp -v $line base/bin; done +mklittlefs -c base -b 4096 -s $((1<<20)) base.img diff --git a/user/.gitignore b/user/.gitignore new file mode 100644 index 0000000..b5a35ef --- /dev/null +++ b/user/.gitignore @@ -0,0 +1 @@ +FILES.txt diff --git a/user/Makefile b/user/Makefile new file mode 100644 index 0000000..d26e74d --- /dev/null +++ b/user/Makefile @@ -0,0 +1,14 @@ +CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + +.PHONY: all clean + +APP_DIR := $(shell find . -mindepth 1 -maxdepth 1 -type d -not -path "./arch") + +all: + rm -f FILES.txt + touch FILES.txt + for dir in $(APP_DIR); do make -C $$dir FILES=$(CURRENT_DIR)/FILES.txt all; done + +clean: + for dir in $(APP_DIR); do make -C $$dir clean; done + diff --git a/user/Makefile.inc b/user/Makefile.inc new file mode 100644 index 0000000..8d751cb --- /dev/null +++ b/user/Makefile.inc @@ -0,0 +1,9 @@ +ARCH ?= x86_64 + +CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc + +CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + +include $(CURRENT_DIR)/arch/$(ARCH)/$(ARCH).mk + +LDFLAGS += -nostdlib -static $(shell $(CC) -print-libgcc-file-name) -T $(CURRENT_DIR)/arch/$(ARCH)/link.ld diff --git a/user/arch/x86_64/link.ld b/user/arch/x86_64/link.ld new file mode 100644 index 0000000..e846459 --- /dev/null +++ b/user/arch/x86_64/link.ld @@ -0,0 +1,26 @@ +ENTRY(_start) + +SECTIONS { + /* . = 0xffff000000000000; */ + . = 0x0000000000000000; + + .rodata ALIGN(4K): + { + *(.rodata .rodata.*) + } + + .text ALIGN(4K): + { + *(.text .text.*) + } + + .data ALIGN(4K): + { + *(.data .data.*) + } + + .bss ALIGN(4K): + { + *(.bss .bss.*) + } +} diff --git a/user/arch/x86_64/x86_64.mk b/user/arch/x86_64/x86_64.mk new file mode 100644 index 0000000..bec49ac --- /dev/null +++ b/user/arch/x86_64/x86_64.mk @@ -0,0 +1,22 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld + +CFLAGS += -m64 \ + -fPIE \ + -mno-80387 \ + -mno-mmx \ + -mno-sse \ + -nostartfiles \ + -nostdlib \ + -mno-sse2 \ + -mno-red-zone \ + -fno-stack-protector \ + -fno-stack-check \ + -Os \ + +LDFLAGS += -m elf_x86_64 \ + -pie \ + --no-dynamic-linker \ + -z text \ + -z max-page-size=0x1000 + diff --git a/user/hello/.gitignore b/user/hello/.gitignore new file mode 100644 index 0000000..59b32b2 --- /dev/null +++ b/user/hello/.gitignore @@ -0,0 +1,2 @@ +*.o +hello diff --git a/user/hello/Makefile b/user/hello/Makefile new file mode 100644 index 0000000..64130a8 --- /dev/null +++ b/user/hello/Makefile @@ -0,0 +1,21 @@ +include ../Makefile.inc + +.PHONY: all clean + +TARGET := hello + +SRCFILES := $(wildcard *.s) +ASFILES := $(filter %.s,$(SRCFILES)) +OBJ := $(patsubst %.s,%.o,$(ASFILES)) + +%.o: %.s + $(CC) $(CFLAGS) -c $< -o $@ + +all: $(TARGET) + +hello: $(OBJ) + $(LD) $^ $(LDFLAGS) -o $@ + echo "$(realpath $@)" >> $(FILES) + +clean: + rm -f $(OBJ) $(TARGET) diff --git a/user/hello/hello.s b/user/hello/hello.s new file mode 100644 index 0000000..bf780c3 --- /dev/null +++ b/user/hello/hello.s @@ -0,0 +1,6 @@ + +.global _start +_start: +.spin: + jmp .spin +