summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/proc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/proc')
-rw-r--r--arch/x86_64/proc/init.c173
-rw-r--r--arch/x86_64/proc/process.c64
-rw-r--r--arch/x86_64/proc/process.h29
3 files changed, 266 insertions, 0 deletions
diff --git a/arch/x86_64/proc/init.c b/arch/x86_64/proc/init.c
new file mode 100644
index 0000000..4c86038
--- /dev/null
+++ b/arch/x86_64/proc/init.c
@@ -0,0 +1,173 @@
+#include "init.h"
+#include "arch/x86_64/hal/msr.h"
+#include "config.h"
+#include "proc/process.h"
+#include "jove.h"
+#include "hal/obj.h"
+#include "lib/string.h"
+#include "panic/panic.h"
+#include "lib/printf.h"
+#include "arch/x86_64/lib/elf.h"
+#include "arch/x86_64/hal/paging.h"
+#include "boot/cmdline.h"
+#include "boot/initrd.h"
+
+PAGEALIGN static uint8_t s_init_program_pages[INIT_PROGRAM_PAGES_MAX][0x1000];
+PAGEALIGN static uint8_t s_init_stack_pages[INIT_STACK_PAGES + 3][0x1000];
+PAGEALIGN static uint8_t s_init_message_page[0x1000];
+
+static int
+elf_is_valid(struct elf_header *ehdr)
+{
+ if(ehdr->e_ident[0] != EI_MAG0 ||
+ ehdr->e_ident[1] != EI_MAG1 ||
+ ehdr->e_ident[2] != EI_MAG2 ||
+ ehdr->e_ident[3] != EI_MAG3) {
+ kprintf("ELF: Magic does not match!\n");
+ return 0;
+ }
+ if(ehdr->e_ident[4] != EI_CLASS_64) {
+ kprintf("ELF: Class is not 64-bit!\n");
+ return 0;
+ }
+ if(ehdr->e_ident[5] != EI_DATA_LE) {
+ kprintf("ELF: Data is not little-endian!\n");
+ return 0;
+ }
+ if(ehdr->e_type != ET_EXEC) {
+ kprintf("ELF: Program is not standard executable type!\n");
+ return 0;
+ }
+ if(ehdr->e_machine != EM_x86_64) {
+ kprintf("ELF: Executable is not x86_64!\n");
+ return 0;
+ }
+ return 1;
+}
+
+void
+init_setup(void)
+{
+ //Get the init file data from the initrd.
+ const char *init_path = cmdline_getarg("init");
+ if(init_path == NULL) {
+ kpanic("Kernel commandline is missing 'init' arg.\n");
+ }
+
+ jove_owned_obj_t *initrd_obj = objdir_getlocal(_rootdir_obj, ROOTDIR_INITRD_I);
+ jove_owned_obj_t *init_obj = initrd_seek(initrd_obj, init_path);
+ if(init_obj == NULL) {
+ kpanic("init: Cannot find file '%s' in initrd.\n", init_path);
+ }
+ obj_release(initrd_obj);
+
+ void *init_data = initrd_file_data(init_obj);
+ obj_release(init_obj);
+
+ struct elf_header *init_ehdr = init_data;
+ if(init_ehdr == NULL) {
+ kpanic("init: Cannot get file data for file '%s': %i\n", init_path, errno);
+ }
+
+ if(!elf_is_valid(init_ehdr)) {
+ kpanic("init: Either passed file '%s' is not an ELF file or is not loadable.\n", init_path);
+ }
+
+ jove_owned_obj_t *init_pagedir = objdir_getlocal(_rootdir_obj, ROOTDIR_PAGEDIR_I);
+ page_t *pml4 = obj_deref(init_pagedir);
+ size_t last_base = 0;
+
+ //Load the init ELF
+ size_t last_page = 0;
+ for(size_t i = 0; i < init_ehdr->e_phnum; i++) {
+ struct elf_phdr *phdr = init_data + init_ehdr->e_phoff + i * init_ehdr->e_phentsize;
+ if(phdr->p_type != PT_LOAD) continue;
+ kprintf("init: phdr %i flags %b\n", i, phdr->p_flags);
+
+ uintptr_t base = phdr->p_vaddr;
+ size_t limit = phdr->p_memsz;
+ if(last_base < base + limit) last_base = base + limit;
+
+ uintptr_t page_base = base & ~0xFFFULL;
+ size_t pages = (limit + 4095) / 4096;
+
+ for(size_t i = 0; i < pages; i++) {
+ uintptr_t page_virt = page_base + (i << 12);
+ if(last_page >= INIT_PROGRAM_PAGES_MAX) {
+ kpanic("Program exceeds size limit! (%i > %i)\n", last_page, INIT_PROGRAM_PAGES_MAX);
+ }
+
+ int tblres = 0;
+ do {
+ uintptr_t tbl_frame = KPTR_TOPHYS(&s_init_program_pages[last_page++]);
+ tblres = pagedir_map_table(pml4, tbl_frame, page_virt);
+ if(tblres == EHASMAP) last_page--;
+ }while(!tblres);
+
+ pagedir_map_frame(pml4, KPTR_TOPHYS(&s_init_program_pages[last_page++]), page_virt,
+ PAGE_WRITEABLE | PAGE_USER);
+ }
+
+ //Copy data from section if SHT_PROGBITS
+ memcpy((void*)phdr->p_vaddr, init_data + phdr->p_offset, phdr->p_memsz);
+ }
+
+ //Map the stack
+ size_t stack_base = 0x00007FFFFFFFF000;
+ int stack_mapres = 0;
+
+ last_page = 0;
+ for(size_t i = 0; i < INIT_STACK_PAGES; i++) {
+ uintptr_t page_virt = stack_base - (i << 12);
+ int tblres = 0;
+
+ do {
+ uintptr_t tbl_frame = KPTR_TOPHYS(&s_init_stack_pages[last_page++]);
+ tblres = pagedir_map_table(pml4, tbl_frame, page_virt);
+ if(tblres == EHASMAP) last_page--;
+ }while(!tblres);
+
+ pagedir_map_frame(pml4, KPTR_TOPHYS(&s_init_stack_pages[last_page++]), page_virt,
+ PAGE_WRITEABLE | PAGE_USER | PAGE_XD);
+ }
+
+ //Map the syscall message.
+ last_base = (last_base + 0xFFF) & ~0xFFF;
+ uintptr_t message_pptr = KPTR_TOPHYS(s_init_message_page);
+ pagedir_map_frame(pml4, message_pptr, last_base,
+ PAGE_WRITEABLE | PAGE_USER | PAGE_XD);
+
+ extern struct init_payload _init_payload;
+ _init_payload.brk = last_base + 0x1000;
+
+ memcpy((void*)last_base, &_init_payload, sizeof(struct init_payload));
+
+ jove_owned_obj_t *message_obj = objdir_getlocal(_rootdir_obj, ROOTDIR_MESSAGE_I);
+ obj_settype(message_obj, JOVE_OBJ_MESSAGE);
+ obj_setvalue(message_obj, (message_pptr & ~0xFFF) | 1);
+ obj_release(message_obj);
+
+ obj_release(init_pagedir);
+
+ //Enable syscalls
+ extern void _syscall_entry(void);
+ msr_set_lstar(_syscall_entry);
+
+ //Setup KSP for syscalls
+ jove_owned_obj_t *pcb_obj = process_current();
+ pcb_t *pcb = obj_deref(pcb_obj);
+
+ obj_release(pcb_obj);
+ obj_release(_rootdir_obj);
+
+ uintptr_t usp = 0x00007FFFFFFFFFF8;
+ uintptr_t uip = init_ehdr->e_entry;
+
+ __asm__ volatile("movq %0, %%rsp; \
+ movq %1, %%rcx; \
+ movq %2, %%rdi; \
+ movq $0x202, %%r11; \
+ swapgs; \
+ sysretq"::
+ "r"(usp), "r"(uip), "m"(last_base): "memory");
+}
diff --git a/arch/x86_64/proc/process.c b/arch/x86_64/proc/process.c
new file mode 100644
index 0000000..55af85a
--- /dev/null
+++ b/arch/x86_64/proc/process.c
@@ -0,0 +1,64 @@
+#include "process.h"
+#include "proc/process.h"
+#include "arch/x86_64/hal/obj.h"
+#include "arch/x86_64/hal/smp.h"
+#include "arch/x86_64/hal/paging.h"
+#include "hal/obj.h"
+#include "hal/smp.h"
+#include "lib/string.h"
+#include "init.h"
+#include "jove.h"
+
+PAGEALIGN uint8_t s_init_iopb[0x2000];
+PAGEALIGN char _init_pcb_bytes[0x1000] = { 0 };
+pcb_t *_init_pcb = (pcb_t*)&_init_pcb_bytes;
+
+pid_t
+pcb_pid(pcb_t *pcb)
+{
+ return pcb->pid;
+}
+
+jove_obj_t*
+pcb_rootdir(pcb_t *pcb)
+{
+ return pcb->rootdir;
+}
+
+void
+processing_setup(void (*process_main))
+{
+ memset(s_init_iopb, 0xFF, 0x2000);
+ uintptr_t ksp = ((uintptr_t)&_init_pcb_bytes) + 0xFF8;
+
+ _init_pcb->tree_node.get_key = (void*)pcb_pid;
+
+ _init_pcb->pid = 1;
+ _init_pcb->ksp = (void*)ksp;
+ _init_pcb->pml4 = paging_get_pml4();
+ _init_pcb->rootdir = _rootdir_obj;
+
+ jove_owned_obj_t *iopb_obj = objdir_getlocal(_rootdir_obj, ROOTDIR_IOPB_I);
+ obj_settype(iopb_obj, JOVE_OBJ_IOPB);
+ obj_setvalue(iopb_obj, (uintptr_t)s_init_iopb);
+ _init_pcb->iopb = iopb_obj;
+
+ processor_t *proc = processor_current();
+ proc->tss.rsp[0] = (uintptr_t)_init_pcb->ksp;
+ memcpy(proc->iopb, s_init_iopb, 0x2000);
+
+ {
+ jove_owned_obj_t *process_obj = objdir_getlocal(_rootdir_obj, ROOTDIR_PCB_I);
+ obj_settype(process_obj, JOVE_OBJ_PCB);
+ obj_setvalue(process_obj, (uintptr_t)_init_pcb);
+
+ proc->pcb_obj = process_obj;
+ proc->pcb = _init_pcb;
+ }
+
+ __asm__ volatile("\
+ movq %0, %%rsp; \
+ xorq %%rbp, %%rbp; \
+ jmpq %1"::
+ "r"(_init_pcb->ksp), "r"(process_main));
+}
diff --git a/arch/x86_64/proc/process.h b/arch/x86_64/proc/process.h
new file mode 100644
index 0000000..cf4d8a8
--- /dev/null
+++ b/arch/x86_64/proc/process.h
@@ -0,0 +1,29 @@
+#ifndef _JOVE_x86_64_HAL_PROCESS_H
+#define _JOVE_x86_64_HAL_PROCESS_H 1
+
+#include "proc/process.h"
+#include "arch/x86_64/x86_64.h"
+#include "lib/rbtree.h"
+
+typedef struct process_control_block
+{
+ struct rbtree_node tree_node;
+ struct process_control_block *sched_next;
+
+ pid_t pid;
+ jove_obj_t *rootdir;
+ jove_owned_obj_t *iopb;
+ uintptr_t pml4;
+
+ enum pcb_state state;
+ int killed;
+ struct pcb_mailbox send, recv;
+
+ struct cpu_context context;
+ void *ksp;
+ char kstack[];
+} pcb_t;
+
+#define PCB_KSTACK_SIZE (0x1000 - sizeof(pcb_t))
+
+#endif