diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-13 22:31:43 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-13 22:31:43 -0400 |
| commit | 548506392b789f58b1556a6ffca917441e1d89fd (patch) | |
| tree | 58e4b747446ea64e7951e523353f58510b3a8b2f | |
| parent | c5e3bb7917689bc9ed54fee23a143144fade802d (diff) | |
| download | jove-kernel-548506392b789f58b1556a6ffca917441e1d89fd.tar.gz jove-kernel-548506392b789f58b1556a6ffca917441e1d89fd.tar.bz2 jove-kernel-548506392b789f58b1556a6ffca917441e1d89fd.zip | |
ipc functions. work on process spawning
38 files changed, 1113 insertions, 297 deletions
@@ -1,9 +1,8 @@ #ifndef _JOVE_API_OBJ_H #define _JOVE_API_OBJ_H 1 -#include <stdint.h> - typedef unsigned char objtype_t; +typedef unsigned short objpath_part_t; enum { @@ -33,8 +32,10 @@ enum #define JOVE_PERM_ALL 7 -#define OBJDIR_NUM_ENTRIES (0x1000 / sizeof(uintmax_t)) +#define OBJDIR_SIZE 0x1000 +#define OBJDIR_ENTRIES (OBJDIR_SIZE / sizeof(uintmax_t)) -typedef uint16_t objpath_part_t; +#define MESSAGE_ALIGN 0x1000 +#define MESSAGE_SIZE 0x1000 #endif diff --git a/api/process.h b/api/process.h index 5ccf69d..05b7632 100644 --- a/api/process.h +++ b/api/process.h @@ -23,4 +23,10 @@ enum pcb_rootdir_entries PCB_ROOTDIR_PAGEDIR_I, }; +enum pcb_stack_type +{ + PCB_STACK_SYSTEM = 0, + PCB_STACK_INTERRUPT +}; + #endif diff --git a/api/syscall.h b/api/syscall.h index 54ff267..40fedd4 100644 --- a/api/syscall.h +++ b/api/syscall.h @@ -74,9 +74,31 @@ enum { _SYSCALL_OBJDIR_BADCALL = 0, SYSCALL_OBJDIR_OBJTYPE, + SYSCALL_OBJDIR_SWAP, + SYSCALL_OBJDIR_LINK, + SYSCALL_OBJDIR_ISLINK }; -#define SYSCALL_PERM_OBJDIR_OBJTYPE JOVE_PERM_READ +#define SYSCALL_PERM_OBJDIR_OBJTYPE (JOVE_PERM_READ) +#define SYSCALL_PERM_OBJDIR_SWAP (JOVE_PERM_WRITE) +#define SYSCALL_PERM_OBJDIR_LINK (JOVE_PERM_WRITE) + +#define SYSCALL_PERM_OBJDIR_SWAP_TGT (JOVE_PERM_WRITE) +#define SYSCALL_PERM_OBJDIR_LINK_TGT (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) + +struct syscall_objdir_swap +{ + objpath_part_t index; + objpath_part_t other_path_length; + objpath_part_t other_path[]; +}; + +struct syscall_objdir_link +{ + objpath_part_t index; + objpath_part_t other_path_length; + objpath_part_t other_path[]; +}; /* JOVE_OBJ_PAGEDIR syscalls * */ @@ -183,17 +205,23 @@ enum SYSCALL_PCB_YIELD, SYSCALL_PCB_SEND, SYSCALL_PCB_RECV, + SYSCALL_PCB_SWAP, + SYSCALL_PCB_STACK, SYSCALL_PCB_READY, }; #define SYSCALL_PERM_PCB_PID (JOVE_PERM_READ) #define SYSCALL_PERM_PCB_YIELD (JOVE_PERM_WRITE) #define SYSCALL_PERM_PCB_SEND (JOVE_PERM_WRITE) -#define SYSCALL_PERM_PCB_RECV (JOVE_PERM_WRITE) -#define SYSCALL_PERM_PCB_READY (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) +#define SYSCALL_PERM_PCB_RECV (JOVE_PERM_READ | JOVE_PERM_WRITE) +#define SYSCALL_PERM_PCB_SWAP (SYSCALL_PERM_PCB_SEND | SYSCALL_PERM_PCB_RECV) +#define SYSCALL_PERM_PCB_STACK (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) +#define SYSCALL_PERM_PCB_READY (JOVE_PERM_ALL) #define SYSCALL_PERM_PCB_SEND_OBJDIR (JOVE_PERM_WRITE) #define SYSCALL_PERM_PCB_RECV_DST (JOVE_PERM_MUTATE) +#define SYSCALL_PERM_PCB_SWAP_OBJ (JOVE_PERM_MUTATE) +#define SYSCALL_PERM_PCB_STACK_OBJ (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) struct syscall_pcb_yield { @@ -216,6 +244,23 @@ struct syscall_pcb_recv objpath_part_t recv_path[]; }; +struct syscall_pcb_swap +{ + pid_t swap_target; + uintmax_t send_timeout; + uintmax_t recv_timeout; + + objpath_part_t swap_path_length; + objpath_part_t swap_path[]; +}; + +struct syscall_pcb_stack +{ + char type; + objpath_part_t stack_path_length; + objpath_part_t stack_path[]; +}; + /**JOVE_OBJ_INITRD_FILE syscalls * */ diff --git a/arch/x86_64/hal/obj.h b/arch/x86_64/hal/obj.h index 4364348..b939406 100644 --- a/arch/x86_64/hal/obj.h +++ b/arch/x86_64/hal/obj.h @@ -15,8 +15,8 @@ enum typedef union jove_obj { struct { - uint8_t type; atomic_flag lock; + uint8_t type; /*Raw value or pointer to a data-structure located in identity memory.*/ uint64_t value : 48; }; @@ -33,7 +33,5 @@ typedef struct jove_locked_obj /*Object directories are always 1 page wide. Since an object inside the directory * in this arch is a pointer width, that is 512 entries per directory.*/ -#define JOVE_OBJDIR_SIZE 0x1000 -#define JOVE_OBJDIR_ENTRIES (JOVE_OBJDIR_SIZE / sizeof(jove_obj_t)) #endif diff --git a/arch/x86_64/hal/paging.c b/arch/x86_64/hal/paging.c index 535d5b2..d5bcee3 100644 --- a/arch/x86_64/hal/paging.c +++ b/arch/x86_64/hal/paging.c @@ -22,6 +22,14 @@ PAGEALIGN page_t _kernel_pml1[512]; PAGEALIGN static page_t ident_pml3[IDENT_MASSIVEPAGES][512]; PAGEALIGN static page_t ident_pml2[IDENT_GIANTPAGES][512]; +virtaddr_t __syscall_stack_guard; +virtaddr_t __syscall_stack; +virtaddr_t __interrupt_stack_guard; +virtaddr_t __interrupt_stack; + +virtaddr_t *__syscall_stack_mapping; +virtaddr_t *__interrupt_stack_mapping; + void* phys_tovirt(uintptr_t phys) { @@ -95,7 +103,7 @@ s_pagedir_get_pml1(page_t *pml4, uintptr_t vptr) return 0; } - #define PML_TBL(tbl, i) (page_t*)(((uintptr_t)tbl[i].paddr << 12) | IDENT_VIRT_BASE) + #define PML_TBL(tbl, i) (page_t*)(((uintptr_t)tbl[i].pfn << 12) | IDENT_VIRT_BASE) page_t *pml3 = PML_TBL(pml4, pml4i); size_t pml3i = PML3I(vptr); @@ -137,18 +145,48 @@ uintptr_t *pagedir_get_mapping(jove_owned_obj_t *pagedir, uintptr_t vptr) return (uintptr_t*)mapping; } -uintptr_t +size_t +pagedir_mapping_get_pfn(virtaddr_t *mapping) +{ + return ((page_t*)mapping)->pfn; +} + +virtaddr_t pagedir_ident_from_mapping(uintptr_t *mapping) { - return (((page_t*)mapping)->paddr << 12) | IDENT_VIRT_BASE; + return (((page_t*)mapping)->pfn << 12) | IDENT_VIRT_BASE; +} + +inline bool pagedir_mapping_is_present(virtaddr_t *mapping) +{ + return ((page_t*)mapping)->p; +} + +inline void pagedir_mapping_set_pfn(virtaddr_t *mapping, size_t pfn) +{ + ((page_t*)mapping)->pfn = pfn; } -void -pagedir_mapping_set_present(uintptr_t *mapping, bool present) +inline void pagedir_mapping_set_present(virtaddr_t *mapping, bool present) { ((page_t*)mapping)->p = present; } +inline void pagedir_mapping_set_writeable(virtaddr_t *mapping, bool rw) +{ + ((page_t*)mapping)->rw = rw; +} + +inline void pagedir_mapping_set_user(virtaddr_t *mapping, bool user) +{ + ((page_t*)mapping)->u = user; +} + +inline void pagedir_mapping_set_type(virtaddr_t *mapping, int type) +{ + ((page_t*)mapping)->mapping_type = type; +} + int pagedir_map_frame(page_t *pml4, uintptr_t pptr, uintptr_t vptr, uintmax_t flg) @@ -165,11 +203,11 @@ int pagedir_map_frame(page_t *pml4, return 0; } -int pagedir_map_shmem(page_t *pml4, +int pagedir_map_frame_type(page_t *pml4, uintptr_t pptr, uintptr_t vptr, - struct syscall_pagedir_flags flg) + struct syscall_pagedir_flags flg, int type) { - uintmax_t real_flg = PAGE_USER | PAGE_SHMEM; + uintmax_t real_flg = PAGE_USER | (type << PAGE_SHL_TYPE); if(flg.writeable) { real_flg |= PAGE_WRITEABLE; } @@ -191,9 +229,7 @@ int pagedir_map_untyped_frame( } uintptr_t frame = obj_getvalue(untyped->obj); - return pagedir_map_frame(pml4, frame, vptr, PAGE_USER | - (flg.writeable ? PAGE_WRITEABLE : 0) | - (flg.executable ? 0 : PAGE_XD)); + return pagedir_map_frame_type(pml4, frame, vptr, flg, JOVE_MAPPING_TYPE_UNTYPED); } int pagedir_map_table(page_t *pml4, @@ -209,7 +245,7 @@ int pagedir_map_table(page_t *pml4, goto map_table; } - page_t *pml3 = (page_t*)(((uintptr_t)pml4[pml4i].paddr << 12) + page_t *pml3 = (page_t*)(((uintptr_t)pml4[pml4i].pfn << 12) | IDENT_VIRT_BASE); size_t pml3i = PML3I(vptr); if(!pml3[pml3i].p) { @@ -217,7 +253,7 @@ int pagedir_map_table(page_t *pml4, goto map_table; } - page_t *pml2 = (page_t*)(((uintptr_t)pml3[pml3i].paddr << 12) + page_t *pml2 = (page_t*)(((uintptr_t)pml3[pml3i].pfn << 12) | IDENT_VIRT_BASE); size_t pml2i = PML2I(vptr); if(!pml2[pml2i].p) { @@ -265,9 +301,7 @@ int pagedir_map_shmem_frame( uintptr_t frame = value & ~0xFF; frame += (uintmax_t)page_offset << 12; - return pagedir_map_frame(pml4, frame, vptr, PAGE_USER | - (flg.writeable ? PAGE_WRITEABLE : 0) | - (flg.executable ? 0 : PAGE_XD)); + return pagedir_map_frame_type(pml4, frame, vptr, flg, JOVE_MAPPING_TYPE_SHMEM); } int pagedir_unmap_untyped_frame( @@ -276,13 +310,14 @@ int pagedir_unmap_untyped_frame( page_t *pml4 = obj_deref(tgt); size_t pml4i = PML4I(vptr); - if(!pml4[pml4i].p) return ENOMAP; + if(!pml4[pml4i].p) return -ENOMAP; page_t *pml1 = s_pagedir_get_pml1(pml4, vptr); size_t pml1i = PML1I(vptr); - if(!pml1[pml1i].p) return ENOMAP; + if(!pml1[pml1i].p) return -ENOMAP; - uintptr_t untyped_pptr = (pml1[pml1i].paddr << 12); + if(pml1[pml1i].mapping_type != JOVE_MAPPING_TYPE_UNTYPED) return -ENOMAP; + uintptr_t untyped_pptr = (pml1[pml1i].pfn << 12); obj_settype(dst, JOVE_OBJ_UNTYPED); obj_setvalue(dst, untyped_pptr); @@ -294,6 +329,26 @@ int pagedir_unmap_untyped_frame( return 0; } +int pagedir_unmap_shmem_frame( + jove_owned_obj_t *tgt, uintptr_t vptr) +{ + page_t *pml4 = obj_deref(tgt); + + size_t pml4i = PML4I(vptr); + if(!pml4[pml4i].p) return -ENOMAP; + + page_t *pml1 = s_pagedir_get_pml1(pml4, vptr); + size_t pml1i = PML1I(vptr); + if(!pml1[pml1i].p) return -ENOMAP; + + if(pml1[pml1i].mapping_type != JOVE_MAPPING_TYPE_UNTYPED) return -ENOMAP; + + pml1[pml1i].p = 0; + pagedir_invlpg(vptr); + + return 0; +} + int pagedir_unmap_untyped_table( jove_owned_obj_t *tgt, jove_owned_obj_t *dst, uintptr_t vptr) { @@ -304,12 +359,12 @@ int pagedir_unmap_untyped_table( //trying to unmap the entire address space. We don't support this. size_t pml4i = PML4I(vptr); if(!pml4[pml4i].p) { - return ENOMAP; + return -ENOMAP; } target_table = &pml4[pml4i]; //Try to unmap the pml4 entry if the pml3 entry does not exist. - page_t *pml3 = (page_t*)(((uintptr_t)pml4[pml4i].paddr << 12) | IDENT_VIRT_BASE); + page_t *pml3 = (page_t*)(((uintptr_t)pml4[pml4i].pfn << 12) | IDENT_VIRT_BASE); size_t pml3i = PML3I(vptr); if(!pml3[pml3i].p) { goto unmap_table; @@ -317,7 +372,7 @@ int pagedir_unmap_untyped_table( target_table = &pml3[pml3i]; //Try to unmap the pml3 entry if the pml2 entry does not exist. - page_t *pml2 = (page_t*)(((uintptr_t)pml3[pml3i].paddr << 12) | IDENT_VIRT_BASE); + page_t *pml2 = (page_t*)(((uintptr_t)pml3[pml3i].pfn << 12) | IDENT_VIRT_BASE); size_t pml2i = PML2I(vptr); if(!pml2[pml2i].p) { goto unmap_table; @@ -327,13 +382,13 @@ int pagedir_unmap_untyped_table( unmap_table: { - uintptr_t frame = target_table->paddr << 12; + uintptr_t frame = target_table->pfn << 12; page_t *target_vals = (page_t*)(frame | IDENT_VIRT_BASE); //Check that the page table at our target entry is empty. //If it's not, we return an error saying that the entry contains a map. for(size_t i = 0; i < 512; i++) { - if(target_vals[i].p) return EHASMAP; + if(target_vals[i].p) return -EHASMAP; } //Populate the none object with an untyped object at the free'd page frame. @@ -421,6 +476,15 @@ paging_pml4_init(void) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL | PAGE_XD; } + size_t kernel_stack_off = kernel_data_off + kernel_data_pages; + __syscall_stack_guard = ((kernel_stack_off) << 12) + KERNEL_VIRT_BASE; + __syscall_stack = __syscall_stack_guard + 0x1000; + __interrupt_stack_guard = __syscall_stack + 0x1000; + __interrupt_stack = __interrupt_stack_guard + 0x1000; + + __syscall_stack_mapping = (virtaddr_t*)&_kernel_pml1[kernel_stack_off + 1]; + __interrupt_stack_mapping = (virtaddr_t*)&_kernel_pml1[kernel_stack_off + 3]; + /*Identity pages are mapped as huge pages starting at the 256'th PML3 entry. *We want to support any range of physical memory up to several TiB, so *the mapper has to consider multiple heirarchies of huge pages.*/ diff --git a/arch/x86_64/hal/paging.h b/arch/x86_64/hal/paging.h index becf353..6edac0c 100644 --- a/arch/x86_64/hal/paging.h +++ b/arch/x86_64/hal/paging.h @@ -17,10 +17,9 @@ typedef union page_table_entry uint8_t d : 1; uint8_t ps : 1; uint8_t g : 1; - uint8_t shm : 1; - uint8_t ign_0 : 1; + uint8_t mapping_type : 2; uint8_t r : 1; - uint64_t paddr : 35; + uint64_t pfn : 35; uint8_t ign_1 : 4; uint8_t pkey : 4; uint8_t xd : 1; @@ -37,7 +36,7 @@ typedef union page_table_entry #define PAGE_DIRTY 0b1000000 #define PAGE_PS 0b10000000 #define PAGE_GLOBAL 0b100000000 -#define PAGE_SHMEM 0b1000000000 +#define PAGE_SHL_TYPE 9 #define PAGE_XD (1ULL << 63) extern void *_kernel_physptr; diff --git a/arch/x86_64/hal/smp.c b/arch/x86_64/hal/smp.c index 392e68f..7d94340 100644 --- a/arch/x86_64/hal/smp.c +++ b/arch/x86_64/hal/smp.c @@ -1,4 +1,5 @@ #include "smp.h" +#include "hal/memory.h" #include "proc/init.h" #include "config.h" #include "jove.h" @@ -57,6 +58,8 @@ smp_init_bsp(void) idt_init(); paging_pml4_init(); + + bsp->tss.rsp[0] = __interrupt_stack; } inline processor_t *processor_current(void) diff --git a/arch/x86_64/hal/smp.h b/arch/x86_64/hal/smp.h index b26d4ac..0f0fc40 100644 --- a/arch/x86_64/hal/smp.h +++ b/arch/x86_64/hal/smp.h @@ -1,6 +1,7 @@ #ifndef _JOVE_x86_64_HAL_SMP_H #define _JOVE_x86_64_HAL_SMP_H 1 +#include "arch/x86_64/hal/paging.h" #include "arch/x86_64/proc/process.h" #include "gdt.h" #include "hal/obj.h" @@ -11,7 +12,10 @@ typedef struct processor struct gdt_entry gdt[GDT_TSS_HI+1]; struct tss tss; uint8_t iopb[0x2000]; - + + page_t syscall_page; + page_t interrupt_page; + jove_owned_obj_t *pcb_obj; pcb_t *pcb; } processor_t; diff --git a/arch/x86_64/proc/init.c b/arch/x86_64/proc/init.c index 155cff6..8003a6d 100644 --- a/arch/x86_64/proc/init.c +++ b/arch/x86_64/proc/init.c @@ -5,6 +5,7 @@ #include "jove.h" #include "hal/obj.h" #include "lib/string.h" +#include "sys/message.h" #include "sys/objdir.h" #include "panic/panic.h" #include "lib/printf.h" @@ -126,20 +127,19 @@ init_setup(void) //Map the syscall message. last_base = (last_base + 0xFFF) & ~0xFFF; jove_owned_obj_t message_frame = init_pop_alloc(); - pagedir_map_frame(pml4, obj_getvalue(&message_frame), last_base, - PAGE_WRITEABLE | PAGE_USER | PAGE_XD); + jove_owned_obj_t *message_obj = objdir_getlocal(_rootdir_obj, INIT_ROOTDIR_MESSAGE_I); + + message_new(&message_frame); + objdir_swapobj(message_obj, &message_frame); + message_map(message_obj, init_pagedir, last_base); + + obj_release(init_pagedir); - extern struct init_payload _init_payload; _init_payload.brk = last_base + 0x1000; + //Copy init payload into syscall message. + extern struct init_payload _init_payload; memcpy((void*)last_base, &_init_payload, sizeof(struct init_payload)); - - jove_owned_obj_t *message_obj = objdir_getlocal(_rootdir_obj, INIT_ROOTDIR_MESSAGE_I); - obj_settype(message_obj, JOVE_OBJ_MESSAGE); - obj_setvalue(message_obj, last_base | 1); - obj_release(message_obj); - - obj_release(init_pagedir); //Enable syscalls extern void _syscall_entry(void); diff --git a/arch/x86_64/proc/process.c b/arch/x86_64/proc/process.c index 5935303..b10d538 100644 --- a/arch/x86_64/proc/process.c +++ b/arch/x86_64/proc/process.c @@ -40,3 +40,44 @@ processing_setup(void (*process_main)) scheduler_init(init_pcb_obj, process_main); } + +inline physaddr_t +pcb_get_syscall_stack(pcb_t *pcb) +{ + return pcb->syscall_page.pfn << 12; +} + +inline physaddr_t +pcb_get_interrupt_stack(pcb_t *pcb) +{ + return pcb->interrupt_page.pfn << 12; +} + +physaddr_t +pcb_set_syscall_stack(pcb_t *pcb, physaddr_t page) +{ + physaddr_t old_page = pcb_get_syscall_stack(pcb); + pcb->syscall_page.pfn = page >> 12; + pcb->syscall_page.p = 1; + pcb->syscall_page.rw = 1; + return old_page; +} +physaddr_t +pcb_set_interrupt_stack(pcb_t *pcb, physaddr_t page) +{ + physaddr_t old_page = pcb_get_interrupt_stack(pcb); + pcb->interrupt_page.pfn = page >> 12; + pcb->interrupt_page.p = 1; + pcb->interrupt_page.rw = 1; + return old_page; +} + +inline void pcb_map_syscall_stack(pcb_t *pcb) +{ + *__syscall_stack_mapping = pcb->syscall_page.value; +} + +inline void pcb_map_interrupt_stack(pcb_t *pcb) +{ + *__interrupt_stack_mapping = pcb->interrupt_page.value; +} diff --git a/arch/x86_64/proc/process.h b/arch/x86_64/proc/process.h index 5004b49..866184b 100644 --- a/arch/x86_64/proc/process.h +++ b/arch/x86_64/proc/process.h @@ -3,16 +3,16 @@ #include "proc/process.h" #include "lib/rbtree.h" +#include "arch/x86_64/hal/paging.h" typedef struct process_control_block { struct pcb_header header; jove_obj_t *iopb; - - char kstack[]; -} pcb_t; -#define PCB_KSTACK_SIZE (0x1000 - sizeof(pcb_t)) + page_t syscall_page; + page_t interrupt_page; +} pcb_t; #endif diff --git a/arch/x86_64/proc/scheduler.c b/arch/x86_64/proc/scheduler.c index 23e54af..49a0c4d 100644 --- a/arch/x86_64/proc/scheduler.c +++ b/arch/x86_64/proc/scheduler.c @@ -1,14 +1,16 @@ #include "proc/scheduler.h" #include "arch/x86_64/hal/gdt.h" +#include "lib/string.h" #include "process.h" #include "../hal/smp.h" -#include <string.h> +#include "../proc/process.h" void _scheduler_switch_pcb_arch(pcb_t *target) { processor_t *proc = processor_current(); - proc->tss.rsp[0] = (uintptr_t)target->header.ksp; + proc->syscall_page = target->interrupt_page; + proc->interrupt_page = target->interrupt_page; if(target->iopb) { proc->tss.iopb = sizeof(struct tss); @@ -18,3 +20,27 @@ _scheduler_switch_pcb_arch(pcb_t *target) proc->tss.iopb = 0xff; } } + +__attribute__((naked)) +void scheduler_switch(void *this_sp, void *other_sp, void *new_cr3) +{ + __asm__ volatile("\ + movq %%rsp, (%%rdi); \ + movq %%rsi, %%rsp; \ + movq %%cr3, %%rax; \ + cmp %%rax, %%rdx; \ + je .nocr3swap; \ + movq %%rdx, %%cr3; \ + .nocr3swap: \ + movq %%gs:%c[syscall_page], %%rax; \ + movq %%rax, __syscall_stack_mapping; \ + movq (__syscall_stack), %%rax; \ + invlpg (%%rax); \ + movq %%gs:%c[interrupt_page], %%rax; \ + movq %%rax, __interrupt_stack_mapping; \ + movq (__interrupt_stack), %%rax; \ + invlpg (%%rax); \ + retq":: + [syscall_page] "i"(offsetof(processor_t, syscall_page)), + [interrupt_page] "i"(offsetof(processor_t, interrupt_page))); +} diff --git a/arch/x86_64/proc/switch.s b/arch/x86_64/proc/switch.s index 16b2198..028a949 100644 --- a/arch/x86_64/proc/switch.s +++ b/arch/x86_64/proc/switch.s @@ -1,13 +1,3 @@ -.global scheduler_switch -.type scheduler_switch @function - -scheduler_switch: - movq %rsp, (%rdi) - movq %rsi, %rsp - retq - -.size scheduler_switch, . - scheduler_switch - .global scheduler_savestate .type scheduler_savestate @function diff --git a/arch/x86_64/sys/link.c b/arch/x86_64/sys/link.c index 96f8eeb..c8b08ec 100644 --- a/arch/x86_64/sys/link.c +++ b/arch/x86_64/sys/link.c @@ -1,19 +1,58 @@ #include "sys/link.h" +#include "api/obj.h" +#include "arch/x86_64/hal/paging.h" +#include "hal/memory.h" +#include "hal/obj.h" +#include "jove.h" +#include "sys/lock.h" -jove_obj_t -link_unlink(jove_owned_obj_t *link) +int link_new(jove_owned_obj_t *target_obj, jove_owned_obj_t *untyped_obj, uint8_t permissions) { - struct obj_link *linkval = obj_deref(link); - if(--linkval->refcount == 1) { - jove_obj_t held_obj = linkval->obj; - link->locked = held_obj; - return (jove_obj_t) { - .lock = 0, - .type = JOVE_OBJ_UNTYPED, - .value = (uintptr_t)linkval - }; - }else{ - obj_settype(link, JOVE_OBJ_NONE); - } - return (jove_obj_t) { 0 }; + jove_untyped_t *untyped = obj_deref(untyped_obj); + if(untyped->limit != sizeof(jove_link_obj_t)) return -EBADSIZE; + + jove_link_obj_t *link = (jove_link_obj_t*)untyped; + release_mutex(&link->lock); + link->permissions = permissions; + link->refcount = 2; + link->obj = target_obj->locked; + + obj_setvalue(target_obj, (uintptr_t)link); + obj_setvalue(untyped_obj, (uintptr_t)link); + + obj_settype(target_obj, JOVE_OBJ_LINK); + obj_settype(untyped_obj, JOVE_OBJ_LINK); + + return 0; +} + +int link_dup(jove_owned_obj_t *link_obj, jove_owned_obj_t *dest_obj) +{ + jove_link_obj_t *link = obj_deref(link_obj); + obj_settype(dest_obj, JOVE_OBJ_LINK); + obj_setvalue(dest_obj, obj_getvalue(link_obj)); + link->refcount++; + return 0; +} + +inline jove_owned_obj_t* +link_deref(jove_link_obj_t *link) +{ + return obj_take(&link->obj); } + +inline jove_owned_obj_t* +link_try_deref(jove_link_obj_t *link) +{ + return obj_trytake(&link->obj); +} + +inline void link_lock(jove_link_obj_t *link) +{ take_mutex(&link->lock); } +inline void link_unlock(jove_link_obj_t *link) +{ release_mutex(&link->lock); } + +inline uint8_t link_getperm(jove_link_obj_t *link) +{ return link->permissions; } +inline void link_setperm(jove_link_obj_t *link, uint8_t perm) +{ link->permissions = perm; } diff --git a/arch/x86_64/sys/link.h b/arch/x86_64/sys/link.h new file mode 100644 index 0000000..e826dc3 --- /dev/null +++ b/arch/x86_64/sys/link.h @@ -0,0 +1,15 @@ +#ifndef _JOVE_ARCH_SYS_LINK_H +#define _JOVE_ARCH_SYS_LINK_H 1 + +#include <stdatomic.h> +#include "hal/obj.h" + +typedef struct link_obj +{ + jove_obj_t obj; + uint32_t refcount; + uint8_t permissions; + atomic_flag lock; +} jove_link_obj_t; + +#endif diff --git a/boot/initrd.c b/boot/initrd.c index 84636c3..e998c08 100644 --- a/boot/initrd.c +++ b/boot/initrd.c @@ -48,7 +48,7 @@ initrd_seek(jove_owned_obj_t *objdir, const char *path) if(obj_gettype(objdir) != JOVE_OBJ_OBJDIR) { reterr(EBADOBJ); } - for(size_t i = 0; i < JOVE_OBJDIR_ENTRIES; i++) { + for(size_t i = 0; i < OBJDIR_ENTRIES; i++) { jove_owned_obj_t *file_obj = objdir_getlocal(objdir, i); if(obj_gettype(file_obj) != JOVE_OBJ_INITRD_FILE) { goto loop_continue; diff --git a/boot/limine/memorymap.c b/boot/limine/memorymap.c index 48f3f33..c558e75 100644 --- a/boot/limine/memorymap.c +++ b/boot/limine/memorymap.c @@ -53,12 +53,12 @@ mem_setup_regions(void) entry->type == LIMINE_MEMMAP_ACPI_RECLAIMABLE || entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) { - if(region_i > JOVE_OBJDIR_ENTRIES){ + if(region_i > OBJDIR_ENTRIES){ kprintf("%s: Provided memory map exceeds kernel limits. Some memory may not be accessable.", __func__); break; } - klogf("%p : %p %s\n", entry->base, entry->length, limine_mmap_entry_type_str[entry->type]); + klogf("Free %p : %p %s\n", entry->base, entry->length, limine_mmap_entry_type_str[entry->type]); if(entry->base == 0) continue; { @@ -73,14 +73,14 @@ mem_setup_regions(void) { intmax_t hw_pages = entry->length >> 12; uintptr_t base = entry->base; + klogf("HWmem %p : %p %s\n", entry->base, entry->length, limine_mmap_entry_type_str[entry->type]); while(hw_pages > 0) { - if(hwmem_i >= JOVE_OBJDIR_ENTRIES) { + if(hwmem_i >= OBJDIR_ENTRIES) { kprintf("%s: Reserved memory region exceeds indexing limits!\n", __func__); break; } size_t pages = hw_pages > 4095 ? 4095 : hw_pages; - //klogf("%p : %p RESERVED\n", base, ((pages + 1) << 12)); jove_owned_obj_t *hwmem_obj = obj_take(&s_hwmemory_objdir.entries[hwmem_i++]); obj_settype(hwmem_obj, JOVE_OBJ_SHMEMORY); @@ -1,3 +1,5 @@ +DBGFLAGS := IPC + CFLAGS = \ -ffreestanding \ -nostdlib \ @@ -11,6 +13,8 @@ CFLAGS = \ -Iinclude \ -I. +CFLAGS += $(foreach flg,$(DBGFLAGS),-DDEBUG_$(flg)) + LDFLAGS = -nostdlib \ -T link/$(TARGET_TRIPLET).ld diff --git a/doc/syscall.md b/doc/syscall.md index 70f0570..10f8eb5 100644 --- a/doc/syscall.md +++ b/doc/syscall.md @@ -157,11 +157,11 @@ Successful retypes return 0. ### JOVE_OBJ_OBJDIR -| Syscall | Target Permissions | -|------------------------|--------------------------------------| -| SYSCALL_OBJDIR_OBJTYPE | JOVE_PERM_READ | -| SYSCALL_OBJDIR_UNTYPE | JOVE_PERM_WRITE <br>JOVE_PERM_MUTATE | -| SYSCALL_OBJDIR_SEND | JOVE_PERM_MUTATE | +| Syscall | Target Permissions | Subject Permissions | +|------------------------|--------------------|-----------------------------------| +| SYSCALL_OBJDIR_OBJTYPE | JOVE_PERM_READ | | +| SYSCALL_OBJDIR_SWAP | JOVE_PERM_WRITE | JOVE_PERM_WRITE | +| SYSCALL_OBJDIR_LINK | | JOVE_PERM_WRITE, JOVE_PERM_MUTATE | #### SYSCALL_OBJDIR_OBJTYPE @@ -175,17 +175,45 @@ If the message is too small to hold the payload, the kernel will return `-ETOOSM If the entry index exceeds `JOVE_OBJDIR_ENTRIES`, the kernel returns `-EOOB`. -#### SYSCALL_OBJDIR_UNTYPE -Converts the target object to an untyped object if possible. +#### SYSCALL_OBJDIR_SWAP -| Data | Entry Index | -|--------------|-------------| -| Size (bytes) | 2 | +Exchanges an object at the given entry index with the object at a given path. + +| Data | Entry Index | Other Path Length | Other Path | +|--------------|------------------------|------------------------|-----------------------------------------| +| Size (bytes) | sizeof(objpath_part_t) | sizeof(objpath_part_t) | other_path_len * sizeof(objpath_part_t) | + +If the entry index exceeds `JOVE_OBJDIR_ENTRIES`, the kernel will return `-EOOB`. + +If the other object does not point to an object, the kernel will return `-EBADPATH`. + +If the other object's parent directory does not have `JOVE_PERM_WRITE` permissions, the kernel will return `-EPERM`. + +Successful swaps will return 0. + + +#### SYSCALL_OBJDIR_LINK + +Copies an existing `JOVE_OBJ_LINK` object at a given entry into the passed object path. -If the target object does not have underlying memory, the kernel will replace the object with `JOVE_OBJ_NONE`. +Each copy increments the refcount. -If the target object has underlying memory, the kernel will replace the object with `JOVE_OBJ_UNTYPED`. +Permissions are inherited from the existing link. + +| Data | Entry Index | Other Path Length | Other Path | +|--------------|------------------------|------------------------|-----------------------------------------| +| Size (bytes) | sizeof(objpath_part_t) | sizeof(objpath_part_t) | other_path_len * sizeof(objpath_part_t) | + +If the entry index exceeds `JOVE_OBJDIR_ENTRIES`, the kernel will return `-EOOB`. + +If the other object does not point to an object, the kernel will return `-EBADPATH`. + +If the other object is not `JOVE_OBJ_NONE`, the kernel will return `-EFULL`. + +If the other object does not have `JOVE_PERM_WRITE | JOVE_PERM_MUTATE`, the kernel will return `-EPERM`. + +Successful links return 0. ### JOVE_OBJ_PAGEDIR @@ -341,12 +369,14 @@ Successful unmapping returns `0`. ### JOVE_OBJ_PCB -| Syscall | Target Permissions | Subject Permissions | -|-------------------|--------------------|---------------------| -| SYSCALL_PCB_PID | JOVE_PERM_READ | | -| SYSCALL_PCB_YIELD | JOVE_PERM_WRITE | | -| SYSCALL_PCB_SEND | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | -| SYSCALL_PCB_RECV | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | +| Syscall | Target Permissions | Subject Permissions | +|-------------------|-----------------------------------|-----------------------------------| +| SYSCALL_PCB_PID | JOVE_PERM_READ | | +| SYSCALL_PCB_YIELD | JOVE_PERM_WRITE | | +| SYSCALL_PCB_SEND | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | +| SYSCALL_PCB_RECV | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | +| SYSCALL_PCB_SWAP | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | +| SYSCALL_PCB_STACK | JOVE_PERM_WRITE, JOVE_PERM_MUTATE | JOVE_PERM_WRITE, JOVE_PERM_MUTATE | #### SYSCALL_PCB_YIELD @@ -358,7 +388,7 @@ Yields control to the specified process. If the yield target = `0`, the scheduler will determine the next process. -If the yield target does not exist, the kernel will return `-ENOPROC`. +If the yield target does not exist, the kernel will return `-EBADPROC`. #### SYSCALL_PCB_SEND @@ -400,16 +430,66 @@ Destination object is locked until the timeout expires or an object is placed in |--------------|-----------------|-------------------|------------------|-------------------| | Size (bytes) | sizeof(pid_t) | sizeof(uintmax_t) | 2 | 2 * dest_path_len | -If the specified pid does not correspond to a process, the kernel will return `-ENOPROC`. +If the specified pid does not correspond to a process, the kernel will return `-EBADPROC`. If the destination path does not correspond to a `JOVE_OBJ_NONE` object, the kernel will return `-EFULL`. If the destination path does not have the `JOVE_PERM_MUTATE` permission, the kernel will return `-EPERM`. +If the blocking timeout expires and an object was not received, the kernel will return `-ETIMEOUT`. + Recieved messages will be sent to the specified destination path. Successful retrieval returns `0`. +#### SYSCALL_PCB_SWAP + +Tries to send an object through the PCB mailbox, then tries to recieve an object back. + +Blocks on send until send timeout expires or returns early if mailbox is full and send timeout == 0. + +Blocks on recieve until recieve timeout expires or returns early if mailbox is empty and recieve timeout == 0. + +Destination object is locked until the timeout expires or an object is placed in the destination path. + +| Data | Target Process | Send Timeout | Recieve Timeout | Subject Path Length | Subject Path | +|--------------|----------------|-------------------|--------------------|---------------------|-------------------| +| Size (bytes) | sizeof(pid_t) | sizeof(uintmax_t) | sizeof(uintmax_t) | 2 | 2 * dest_path_len | + +If the specified pid does not correspond to a process, the kernel will return `-EBADPROC`. + +If the subject path does not have the `JOVE_PERM_MUTATE` permission, the kernel will return `-EPERM`. + +If the send timeout expires and the object was not sent, the kernel will retun `-ETIMEOUT`. + +If the receive timeout expires and an object was not recieved, the kernel will return `-ETIMEOUT`. + +Successful swap returns `0`. + + +#### SYSCALL_PCB_STACK + +Marks a page-aligned untyped object as either the interrupt stack or the system stack. + +Only one page is allowed per stack per process. Both stacks are required for a PCB to be placed in the READY queue. + +| Data | Stack Type | Stack Path Length | Stack Path | +|--------------|------------|------------------------|-------------------------------------------| +| Size (bytes) | 1 | sizeof(objpath_part_t) | stack_path_length * sizeof(objpath_part_t | + +If the stack type is not present in the pcb_stack_type enum, the kernel will return `-EBADARG`. + +If the subject object is not a `JOVE_OBJ_UNTYPED` object, the kernel will return `-EBADOBJ`. + +If the untyped is not the size of a page, the kernel will return `-EBADSIZE`. + +If the untyped is not aligned to a page boundary, the kernel will return `-EALIGN`. + +If the PCB already has a stack of the specified type, the kernel will return `-EFULL`. + +Successful operation returns `0`. + + ### JOVE_OBJ_INITRD_FILE | Syscall | Target Permissions | diff --git a/hal/memory.h b/hal/memory.h index 1aec7e9..9e799c0 100644 --- a/hal/memory.h +++ b/hal/memory.h @@ -34,6 +34,20 @@ typedef struct jove_obj_untyped #define JOVE_UNTYPED_MINSIZE 0x10 #define JOVE_SMHEM_MAXPAGES 0xFFF +enum { + JOVE_MAPPING_TYPE_UNTYPED = 0, + JOVE_MAPPING_TYPE_SHMEM, + JOVE_MAPPING_TYPE_MESSAGE +}; + +extern virtaddr_t __syscall_stack_guard; +extern virtaddr_t __syscall_stack; +extern virtaddr_t __interrupt_stack_guard; +extern virtaddr_t __interrupt_stack; + +extern virtaddr_t *__syscall_stack_mapping; +extern virtaddr_t *__interrupt_stack_mapping; + void mem_setup_regions(void); physaddr_t phys_fromvirt(virtaddr_t virt); @@ -65,8 +79,15 @@ void pagedir_invlpg(virtaddr_t vptr); virtaddr_t *pagedir_get_mapping( jove_owned_obj_t *pagedir, virtaddr_t vptr); +size_t pagedir_mapping_get_pfn(virtaddr_t *mapping); virtaddr_t pagedir_ident_from_mapping(virtaddr_t *mapping); +bool pagedir_mapping_is_present(virtaddr_t *mapping); + +void pagedir_mapping_set_pfn(virtaddr_t *mapping, size_t pfn); void pagedir_mapping_set_present(virtaddr_t *mapping, bool present); +void pagedir_mapping_set_writeable(virtaddr_t *mapping, bool rw); +void pagedir_mapping_set_user(virtaddr_t *mapping, bool user); +void pagedir_mapping_set_type(virtaddr_t *mapping, int type); int pagedir_map_untyped_frame( jove_owned_obj_t *tgt, jove_perm_obj_t *untyped_obj, @@ -12,7 +12,7 @@ typedef struct jove_objdir { - jove_obj_t entries[JOVE_OBJDIR_ENTRIES]; + jove_obj_t entries[OBJDIR_ENTRIES]; } jove_objdir_t; /*Locks the mutex of the kernel object provided. Returns the locked version. */ diff --git a/lib/rbtree.c b/lib/rbtree.c index a63df4d..f08e2dc 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c @@ -1,6 +1,6 @@ #include "rbtree.h" #include "api/error.h" -#include "errno.h" +#include "jove.h" static inline int s_direction(const struct rbtree_node *node) diff --git a/proc/init.c b/proc/init.c index 10f8a01..130b10e 100644 --- a/proc/init.c +++ b/proc/init.c @@ -3,7 +3,7 @@ #include "hal/memory.h" #include "panic/panic.h" -objpath_part_t s_last_region = JOVE_OBJDIR_ENTRIES-1; +objpath_part_t s_last_region = OBJDIR_ENTRIES-1; jove_owned_obj_t init_pop_alloc(void) diff --git a/proc/ipc.c b/proc/ipc.c new file mode 100644 index 0000000..db1233d --- /dev/null +++ b/proc/ipc.c @@ -0,0 +1,116 @@ +#include "ipc.h" +#include "api/error.h" +#include "proc/process.h" +#include "sys/objdir.h" +#include "jove.h" + +inline pid_t port_get_owner(struct port *port) +{ + return port->owner; +} + +inline struct port *port_get_send_target(struct port *port) +{ + return port->send_target; +} + +inline struct port *port_get_recv_target(struct port *port) +{ + return port->recv_target; +} + +inline void port_set_recv_target(struct port *port, struct port *target) +{ + port->recv_target = target; +} + +inline bool port_poll_send(struct port *port) { return port_get_send_target(port) != 0; } +inline bool port_poll_recv(struct port *port) { return obj_peektype(port->recv) != JOVE_OBJ_NONE; } + +int port_take_send(struct port *port, jove_owned_obj_t *dest_obj) +{ + jove_owned_obj_t *send_obj = obj_take(&port->send); + + if(!port_get_send_target(port)) { + ipc_klogf("Port %p does not have mail to send\n", port); + obj_release(send_obj); + return -EEMPTY; + } + + ipc_klogf("Taking obj from %i into obj %p\n", port->send_target, dest_obj); + + objdir_swapobj(send_obj, dest_obj); + port->send_target = 0; + obj_release(send_obj); + return 0; +} + +struct port *port_take_recv(struct port *port, jove_owned_obj_t *dest_obj) +{ + errno = 0; + jove_owned_obj_t *recv_obj = obj_take(&port->recv); + + //Validate that the port has an object in the recv object. + if(obj_gettype(recv_obj) == JOVE_OBJ_NONE) { + ipc_klogf("Port %p does not have mail\n", port); + obj_release(recv_obj); + errno = EEMPTY; + return NULL; + } + + ipc_klogf("Taking obj from %i into obj %p\n", port->recv_target, dest_obj); + + objdir_swapobj(recv_obj, dest_obj); + struct port *recv_port = port_get_recv_target(port); + port_set_recv_target(port, (void*)-1); + obj_release(recv_obj); + + return recv_port; +} + +int port_send(struct port *source, struct port *target, jove_owned_obj_t *sent_obj) +{ + jove_owned_obj_t *target_recv_obj = obj_take(&target->recv); + + //Validate that the target is full or is not accepting from this port. + if((port_get_recv_target(target) != 0 && port_get_recv_target(target) != source) + || port_poll_recv(target)) { + + obj_release(target_recv_obj); + ipc_klogf("Target %p is full. Sending to send buffer. \n", target); + + jove_owned_obj_t *source_send_obj = obj_take(&source->send); + + //Validate that the send buffer has space. + if(port_get_send_target(source)) { + ipc_klogf("Source %p is full\n", source); + obj_release(source_send_obj); + return -EFULL; + } + objdir_swapobj(source_send_obj, sent_obj); + source->send_target = target; + + obj_release(source_send_obj); + return 1; + } + + objdir_swapobj(target_recv_obj, sent_obj); + target->recv_target = source; + + obj_release(target_recv_obj); + return 0; +} + +int port_recv(struct port *source, struct port *target) +{ + jove_owned_obj_t *source_send_obj = obj_take(&source->send); + jove_owned_obj_t *target_recv_obj = obj_take(&target->recv); + + objdir_swapobj(source_send_obj, target_recv_obj); + target->recv_target = source; + source->send_target = NULL; + + obj_release(target_recv_obj); + obj_release(source_send_obj); + return 0; +} diff --git a/proc/ipc.h b/proc/ipc.h new file mode 100644 index 0000000..4a3dce3 --- /dev/null +++ b/proc/ipc.h @@ -0,0 +1,35 @@ +#ifndef _JOVE_PROC_IPC_H +#define _JOVE_PROC_IPC_H 1 + +#include "hal/obj.h" +#include "api/process.h" +#include <stdatomic.h> +#include <stdbool.h> + +struct port +{ + pid_t owner; + + struct port *send_target; + jove_obj_t send; + + struct port *recv_target; + jove_obj_t recv; +}; + +pid_t port_get_owner(struct port *port); + +struct port *port_get_send_target(struct port *port); +struct port *port_get_recv_target(struct port *port); +void port_set_recv_target(struct port *port, struct port *target); + +bool port_poll_send(struct port *port); +bool port_poll_recv(struct port *port); + +int port_take_send(struct port *port, jove_owned_obj_t *dest_obj); +struct port *port_take_recv(struct port *port, jove_owned_obj_t *dest_obj); + +int port_send(struct port *source, struct port *target, jove_owned_obj_t *sent_obj); +int port_recv(struct port *source, struct port *target); + +#endif diff --git a/proc/process.c b/proc/process.c index f0b83c6..f659c24 100644 --- a/proc/process.c +++ b/proc/process.c @@ -2,9 +2,10 @@ #include "api/error.h" #include "api/process.h" #include "hal/smp.h" +#include "proc/ipc.h" #include "proc/scheduler.h" #include "sys/objdir.h" -#include <string.h> +#include "lib/string.h" struct rbtree_node *pcb_tree; pid_t __next_pid = 1; @@ -23,74 +24,81 @@ pcb_new(jove_owned_obj_t *pcb_obj, size_t size, jove_owned_obj_t *rootdir_obj) pcb_header->tree_node.get_key = (void*)pcb_getpid; pcb_tree = rbtree_insert(pcb_tree, &pcb_header->tree_node); + pcb_header->mailbox.owner = pcb_header->pid; + pcb_header->state = PCB_STATE_EMBRYO; - pcb_header->ksp = (void*)pcb_obj + size - sizeof(uintmax_t); + pcb_header->ksp = (void*)(__syscall_stack + 0x1000 - sizeof(void*)); return _pcb_new_arch((pcb_t*)pcb_header); } int pcb_send(pcb_t *pcb, pid_t target, jove_owned_obj_t *subject, size_t timeout) { - struct pcb_header *pcb_header = (struct pcb_header*)pcb; - struct pcb_header *target_pcb = (struct pcb_header*)rbtree_search(pcb_tree, target); + //Validate that the target PCB has a valid port. + pcb_t *target_pcb = (pcb_t*)rbtree_search(pcb_tree, target); if(target_pcb == 0) { return -EBADPROC; } - if(target_pcb->recv.obj == NULL && - (target_pcb->recv.pid == pcb_getpid(pcb) || target_pcb->recv.pid == 0)) - { - target_pcb->recv.obj = subject; - target_pcb->recv.pid = pcb_getpid(pcb); - return scheduler_yield(target); - } - - if(timeout == 0) { - return -EFULL; - } + struct port *pcb_port = pcb_getport(pcb); + struct port *target_port = pcb_getport(target_pcb); - pcb_header->send.obj = subject; - pcb_header->send.pid = target; - - scheduler_block_for_mail(pcb_header, timeout, target); + //Try to send to either the send buffer or the target recv buffer. + int port_send_result = port_send(pcb_port, target_port, subject); - if(pcb_header->send.obj) return -ETIMEOUT; + if(port_send_result < 0) { + //Port send buffer was full. Wait for it to clear, or timeout. + if(timeout == 0) return -EFULL; + scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target); + if((port_send_result = port_send(pcb_port, target_port, subject)) < 0) { + //If the send buffer is still full, then we timed out. + return -ETIMEOUT; + } + } + if(port_send_result == 1) { + //We sent to the port, but it's stuck in the send buffer. + scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target); + if(port_poll_send(pcb_port)) { + //If the send buffer is still full, then we timed out. + port_take_send(pcb_port, subject); + return -ETIMEOUT; + } + } return 0; } int pcb_recv(pcb_t *pcb, pid_t target, jove_owned_obj_t *dest_obj, size_t timeout) { - struct pcb_header *pcb_header = (struct pcb_header*)pcb; - struct pcb_header *target_pcb = (struct pcb_header*)rbtree_search(pcb_tree, target); - if(target_pcb == 0) { - return -EBADPROC; - } - - if(pcb_header->recv.obj) { - goto recv_success; - return 0; + struct port *target_port = NULL; + if(target == 0) { + //If the target is zero, we're accepting from all send targets. + pcb_t *target_pcb = (pcb_t*)rbtree_search(pcb_tree, target); + if(target_pcb == 0) { + return -EBADPROC; + } + target_port = pcb_getport(target_pcb); } - if(timeout == 0) { - return -EEMPTY; + struct port *pcb_port = pcb_getport(pcb); + + //Block PCB port from recieving from anything other than the target. + port_set_recv_target(pcb_port, target_port); + struct port *recv_from = port_take_recv(pcb_port, dest_obj); + + if(recv_from == 0) { + if(timeout == 0) { + //If non-blocking, leave immediately. + return -EEMPTY; + } + scheduler_block_for_mail((struct pcb_header*)pcb, timeout, target); + recv_from = port_take_recv(pcb_port, dest_obj); + if(recv_from == 0) { + //If blocking, and timeout expired, then we timed out. + return -ETIMEOUT; + } } - - pcb_header->recv.pid = target; - scheduler_block_for_mail(pcb_header, timeout, target); - - if(!pcb_header->recv.obj) { - pcb_header->recv.pid = -1; - return -ETIMEOUT; - } - -recv_success: - objdir_swapobj(pcb_header->recv.obj, dest_obj); - obj_release(pcb_header->recv.obj); - pcb_header->recv.obj = 0; - pcb_header->recv.pid = -1; - - return 0; + return port_get_owner(recv_from); } pcb_t *pcb_frompid(pid_t pid) @@ -104,49 +112,55 @@ process_current(void) return processor_getpcb(((processor_t*)processor_current())); } -pid_t +inline pid_t pcb_getpid(pcb_t *pcb) { return ((struct pcb_header*)pcb)->pid; } -jove_obj_t* +inline jove_obj_t* pcb_getrootdir(pcb_t *pcb) { return ((struct pcb_header*)pcb)->rootdir; } -jove_owned_obj_t* +inline jove_owned_obj_t* pcb_getpagedir(jove_owned_obj_t *rootdir_obj) { return objdir_getlocal(rootdir_obj, PCB_ROOTDIR_PAGEDIR_I); } -jove_owned_obj_t* +inline jove_owned_obj_t* pcb_getself(jove_owned_obj_t *rootdir_obj) { return objdir_getlocal(rootdir_obj, PCB_ROOTDIR_SELF_I); } -enum pcb_state +inline struct port* +pcb_getport(pcb_t *pcb) +{ + return &((struct pcb_header*)pcb)->mailbox; +} + +inline enum pcb_state pcb_getstate(pcb_t *pcb) { return ((struct pcb_header*)pcb)->state; } -intmax_t +inline intmax_t pcb_getstatecode(pcb_t *pcb) { return ((struct pcb_header*)pcb)->state_code; } -void* +inline void* pcb_getksp(pcb_t *pcb) { return ((struct pcb_header*)pcb)->ksp; } -void** +inline void** pcb_getksp_ref(pcb_t *pcb) { return &((struct pcb_header*)pcb)->ksp; diff --git a/proc/process.h b/proc/process.h index 21dbf8d..f566ba4 100644 --- a/proc/process.h +++ b/proc/process.h @@ -1,15 +1,18 @@ #ifndef _JOVE_HAL_PROCESS_H #define _JOVE_HAL_PROCESS_H 1 +#include "hal/memory.h" #include "hal/obj.h" #include "lib/rbtree.h" #include "api/process.h" +#include "proc/ipc.h" -struct pcb_mailbox -{ - jove_owned_obj_t *obj; - pid_t pid; -}; +#ifdef DEBUG_IPC +#include "lib/printf.h" +#define ipc_klogf(fmt, ...) kprintf("%s: " fmt, __func__, __VA_ARGS__) +#else +#define ipc_klogf(fmt, ...) +#endif struct pcb_header { @@ -24,7 +27,7 @@ struct pcb_header intmax_t state_code; size_t block_until; - struct pcb_mailbox send, recv; + struct port mailbox; void *ksp; }; @@ -43,8 +46,7 @@ jove_obj_t *pcb_getrootdir(pcb_t *pcb); jove_owned_obj_t *pcb_getpagedir(jove_owned_obj_t *rootdir_obj); jove_owned_obj_t *pcb_getself(jove_owned_obj_t *rootdir_obj); -struct pcb_mailbox *pcb_getmail_send(pcb_t *pcb); -struct pcb_mailbox *pcb_getmail_recv(pcb_t *pcb); +struct port *pcb_getport(pcb_t *pcb); enum pcb_state pcb_getstate(pcb_t *pcb); intmax_t pcb_getstatecode(pcb_t *pcb); @@ -57,6 +59,15 @@ pcb_t *pcb_frompid(pid_t pid); int pcb_send(pcb_t *pcb, pid_t target, jove_owned_obj_t *subject, size_t timeout); int pcb_recv(pcb_t *pcb, pid_t target, jove_owned_obj_t *dest_obj, size_t timeout); +physaddr_t pcb_get_syscall_stack(pcb_t *pcb); +physaddr_t pcb_get_interrupt_stack(pcb_t *pcb); + +physaddr_t pcb_set_syscall_stack(pcb_t *pcb, physaddr_t page); +physaddr_t pcb_set_interrupt_stack(pcb_t *pcb, physaddr_t page); + +void pcb_map_syscall_stack(pcb_t *pcb); +void pcb_map_interrupt_stack(pcb_t *pcb); + extern struct rbtree_node *pcb_tree; #endif diff --git a/proc/scheduler.c b/proc/scheduler.c index 29f45b5..ba00abc 100644 --- a/proc/scheduler.c +++ b/proc/scheduler.c @@ -1,9 +1,11 @@ #include "scheduler.h" #include "api/error.h" #include "hal/smp.h" +#include "lib/printf.h" #include "sys/objdir.h" #include "proc/init.h" #include "proc/process.h" +#include "proc/ipc.h" //TODO: Better scheduling algorithm than round robin. static struct pcb_header *s_running_list; @@ -18,12 +20,18 @@ s_scheduler_swap_pcb(processor_t *proc, pcb_t *current_pcb, pcb_t *target_pcb) { jove_owned_obj_t *target_rootdir = obj_take(pcb_getrootdir(target_pcb)); jove_owned_obj_t *target_pcb_obj = pcb_getself(target_rootdir); + jove_obj_t target_pagedir = objdir_peeklocal(target_rootdir, PCB_ROOTDIR_PAGEDIR_I); + obj_release(target_rootdir); processor_setpcb(proc, target_pcb_obj); _scheduler_switch_pcb_arch(target_pcb); - scheduler_switch(pcb_getksp_ref(current_pcb), pcb_getksp(target_pcb)); + + scheduler_switch( + pcb_getksp_ref(current_pcb), + pcb_getksp(target_pcb), + (void*)obj_getvalue((jove_owned_obj_t*)&target_pagedir)); } int scheduler_yield(pid_t target_pid) @@ -59,6 +67,8 @@ s_enqueue_pcb(struct pcb_header *pcb, struct pcb_header *list) void scheduler_block_for_mail(struct pcb_header *pcb, uintmax_t timeout, pid_t yield_target) { + ipc_klogf("Blocking PID %i for %i ticks for %i\n", + pcb_getpid((pcb_t*)pcb), timeout, yield_target); pcb->state = PCB_STATE_BLOCKED_MAIL; s_enqueue_pcb(pcb, s_mail_queue); @@ -88,24 +98,31 @@ s_schedule_mail_queue(void) while(pcb) { struct pcb_header *next_pcb = pcb->sched_next; - if(pcb->send.obj) { - struct pcb_header *send_target = (struct pcb_header*)pcb_frompid(pcb->send.pid); - if(send_target->recv.pid == 0 || send_target->recv.pid == pcb->pid) { - objdir_swapobj(send_target->recv.obj, pcb->send.obj); - send_target->recv.pid = pcb->pid; - - s_enqueue_pcb(pcb, s_running_list); - s_running_list = pcb; - goto loop_end; - } + struct port *pcb_port = pcb_getport((pcb_t*)pcb); + if(port_poll_send(pcb_port)) { + //Send buffer is full. Try to transfer to target recv buffer. + //First check if the target recv buffer has space. + struct port *recv_port = port_get_send_target(pcb_port); + if(port_poll_recv(recv_port)) continue; + + //Now check if the recv buffer is accepting from this port. + struct port *recv_target = port_get_recv_target(recv_port); + if(recv_target != 0 && pcb_port != recv_target) continue; + + //This never hits, but if things change in impl we may have to abort here. + if(port_recv(recv_port, pcb_port) < 0) continue; + s_enqueue_pcb(pcb, s_running_list); + s_running_list = pcb; } - if(pcb->recv.obj) { + if(port_poll_recv(pcb_port)) { + //Recv buffer is full, so unblock. s_enqueue_pcb(pcb, s_running_list); s_running_list = pcb; - goto loop_end; } if(s_this_tick >= pcb->block_until) { + ipc_klogf("Unblocking %i due to timeout\n", pcb_getpid((pcb_t*)pcb)); + s_enqueue_pcb(pcb, s_running_list); s_running_list = pcb; } @@ -147,10 +164,27 @@ void scheduler_init(jove_owned_obj_t *pcb_obj, void *process_main) processor_t *proc = processor_current(); processor_setpcb(proc, pcb_obj); - s_running_list = pcb_header; + jove_owned_obj_t syscall_stack = init_pop_alloc(); + jove_owned_obj_t interrupt_stack = init_pop_alloc(); - __asm__("movq %0, %%rsp; \ - xorq %%rbp, %%rbp; \ - jmp %1":: - "m"(pcb_header->ksp), "r"(process_main)); + pcb_set_syscall_stack((pcb_t*)pcb_header, obj_getvalue(&syscall_stack)); + pcb_set_interrupt_stack((pcb_t*)pcb_header, obj_getvalue(&interrupt_stack)); + + kprintf("Syscall stack %p %p\n", *__syscall_stack_mapping, pcb_get_syscall_stack((pcb_t*)pcb_header)); + kprintf("Interrupt stack %p %p\n", *__interrupt_stack_mapping, pcb_get_interrupt_stack((pcb_t*)pcb_header)); + + _scheduler_switch_pcb_arch((pcb_t*)pcb_header); + + jove_owned_obj_t *pagedir_obj = pcb_getpagedir(_rootdir_obj); + void *pagedir = (void*)obj_getvalue(pagedir_obj); + obj_release(pagedir_obj); + + pcb_map_syscall_stack((pcb_t*)pcb_header); + pcb_map_interrupt_stack((pcb_t*)pcb_header); + + s_running_list = pcb_header; + __asm__ volatile("\ + movq %0, %%rsp; \ + xorq %%rbp, %%rbp; \ + jmpq %1":: "r"(pcb_header->ksp), "r"(process_main)); } diff --git a/proc/scheduler.h b/proc/scheduler.h index 2fc0c44..964f2c0 100644 --- a/proc/scheduler.h +++ b/proc/scheduler.h @@ -8,7 +8,7 @@ void scheduler_init(jove_owned_obj_t *pcb_obj, void *process_main); void scheduler_savestate(void); void scheduler_restorestate(void); -void scheduler_switch(void *this_sp, void *other_sp); +void scheduler_switch(void *this_sp, void *other_sp, void *other_cr3); void _scheduler_switch_pcb_arch(pcb_t *target); int scheduler_yield(pid_t target); @@ -5,46 +5,15 @@ #include "lib/printf.h" #include "jove.h" -uint8_t -link_gettype(jove_owned_obj_t *obj) -{ - return obj_gettype(link_deref(obj)); -} - -uint8_t -link_getperm(jove_owned_obj_t *link) -{ - struct obj_link *linkval = obj_deref(link); - return linkval->permissions; -} - -uint64_t -link_getvalue(jove_owned_obj_t *obj) -{ - return obj_getvalue(link_deref(obj)); -} - -jove_owned_obj_t* -link_deref(jove_owned_obj_t *link) -{ - struct obj_link *linkval = obj_deref(link); - return obj_take(&linkval->obj); -} - -jove_owned_obj_t* -link_try_deref(jove_owned_obj_t *link) -{ - struct obj_link *linkval = obj_deref(link); - return obj_trytake(&linkval->obj); -} jove_perm_obj_t link_traverse(jove_owned_obj_t *link, lockstack_t *lockstack) { jove_perm_obj_t perm_obj = { .obj = link, .permissions = JOVE_PERM_ALL }; while(obj_gettype(perm_obj.obj) == JOVE_OBJ_LINK) { - perm_obj.permissions &= link_getperm(perm_obj.obj); - perm_obj.obj = lockstack_push(lockstack, link_deref(perm_obj.obj)); + jove_link_obj_t *link = obj_deref(perm_obj.obj); + perm_obj.permissions &= link_getperm(link); + perm_obj.obj = lockstack_push(lockstack, link_deref(link)); } return perm_obj; } @@ -54,8 +23,9 @@ link_try_traverse(jove_owned_obj_t *link, lockstack_t *lockstack) { jove_perm_obj_t perm_obj = { .obj = link, .permissions = JOVE_PERM_ALL }; while(perm_obj.obj != NULL && obj_gettype(perm_obj.obj) == JOVE_OBJ_LINK) { - perm_obj.permissions &= link_getperm(perm_obj.obj); - perm_obj.obj = lockstack_push(lockstack, link_deref(perm_obj.obj)); + jove_link_obj_t *link = obj_deref(perm_obj.obj); + perm_obj.permissions &= link_getperm(link); + perm_obj.obj = lockstack_push(lockstack, link_deref(link)); } return perm_obj; } @@ -80,19 +50,3 @@ link_try_traverse_objdir(jove_owned_obj_t *objdir, lockstack_t *lockstack, traverse_obj.permissions &= perm_obj.permissions; return traverse_obj; } - -jove_owned_obj_t *link_new(jove_obj_t *tgt, jove_owned_obj_t *dst, uint16_t permissions) -{ - struct obj_link *linkval = obj_deref(dst); - linkval->obj = *tgt; - linkval->refcount = 2; - linkval->permissions = permissions; - - { - jove_owned_obj_t *tgt_owned = obj_take(tgt); - obj_settype(tgt_owned, JOVE_OBJ_LINK); - obj_setvalue(tgt_owned, (uintptr_t)linkval); - obj_release(tgt_owned); - } - return dst; -} @@ -4,12 +4,9 @@ #include "hal/obj.h" -struct obj_link -{ - jove_obj_t obj; - uint16_t refcount; - uint8_t permissions; -}; +#ifdef __x86_64__ +#include "arch/x86_64/sys/link.h" +#endif typedef struct obj_perm_group { @@ -17,12 +14,14 @@ typedef struct obj_perm_group uint8_t permissions; } jove_perm_obj_t; -uint8_t link_gettype(jove_owned_obj_t *obj); -uint8_t link_getperm(jove_owned_obj_t *link); -uint64_t link_getvalue(jove_owned_obj_t *obj); +uint8_t link_getperm(jove_link_obj_t *link); +void link_setperm(jove_link_obj_t *link, uint8_t perm); + +void link_lock(jove_link_obj_t *link); +void link_unlock(jove_link_obj_t *link); -jove_owned_obj_t *link_deref(jove_owned_obj_t *link); -jove_owned_obj_t *link_try_deref(jove_owned_obj_t *link); +jove_owned_obj_t *link_deref(jove_link_obj_t *link); +jove_owned_obj_t *link_try_deref(jove_link_obj_t *link); jove_perm_obj_t link_traverse(jove_owned_obj_t *link, lockstack_t *lockstack); jove_perm_obj_t link_try_traverse(jove_owned_obj_t *link, lockstack_t *lockstack); @@ -34,6 +33,7 @@ jove_perm_obj_t link_try_traverse_objdir(jove_owned_obj_t *objdir, lockstack_t *lockstack, size_t pathlen, objpath_part_t *path); jove_obj_t link_unlink(jove_owned_obj_t *link); -jove_owned_obj_t *link_new(jove_obj_t *tgt, jove_owned_obj_t *dst, uint16_t permissions); +int link_new(jove_owned_obj_t *target_obj, jove_owned_obj_t *untyped_obj, uint8_t permissions); +int link_dup(jove_owned_obj_t *link_obj, jove_owned_obj_t *dest_obj); #endif diff --git a/sys/message.c b/sys/message.c index c87487b..c4414e0 100644 --- a/sys/message.c +++ b/sys/message.c @@ -1,54 +1,94 @@ #include "message.h" #include "api/error.h" -#include "errno.h" +#include "jove.h" #include "hal/memory.h" #include "hal/obj.h" #include "lib/printf.h" -int -message_hasmap(jove_owned_obj_t *obj) +static inline uintptr_t +s_message_addr(jove_owned_obj_t *message_obj) +{ + return (obj_getvalue(message_obj) >> 1) << 12; +} + +int message_new(jove_owned_obj_t *untyped_obj) +{ + uintmax_t untyped_value = obj_getvalue(untyped_obj); + jove_untyped_t *untyped = obj_deref(untyped_obj); + if(untyped->limit != 0x1000) { + klogf("Passed untyped has bad size : %x vs %x\n", untyped->limit, MESSAGE_SIZE); + return -EBADSIZE; + } + if(untyped_value & (MESSAGE_ALIGN - 1)) { + klogf("Passed untyped has bad alignment : %x\n", untyped_value & (MESSAGE_ALIGN - 1)); + return -EALIGN; + } + + obj_settype(untyped_obj, JOVE_OBJ_MESSAGE); + obj_setvalue(untyped_obj, obj_getvalue(untyped_obj) >> 11); + return 0; +} + +inline int +message_hasmap(jove_owned_obj_t *message_obj) { - return obj_getvalue(obj) & 1; + return obj_getvalue(message_obj) & 1; } -uintptr_t -message_unmap(jove_owned_obj_t *obj, jove_owned_obj_t *pagedir) +virtaddr_t +message_unmap(jove_owned_obj_t *message_obj, jove_owned_obj_t *pagedir_obj) { - if(message_hasmap(obj) == 0) { - kprintf("Message %p doesn't have a map\n", obj_getvalue(obj)); - return -ENOMAP; + errno = 0; + if(message_hasmap(message_obj) == 0) { + klogf("Message %p doesn't have a map\n", obj_getvalue(message_obj)); + errno = -ENOMAP; + return 0; } - uintptr_t vptr = obj->locked.value & ~0xFFFULL; - uintptr_t *mapping = pagedir_get_mapping(pagedir, vptr); + + virtaddr_t message_vaddr = s_message_addr(message_obj); + virtaddr_t *mapping = pagedir_get_mapping(pagedir_obj, message_vaddr); + physaddr_t message_pfn = pagedir_mapping_get_pfn(mapping); pagedir_mapping_set_present(mapping, false); - pagedir_invlpg(vptr); + obj_setvalue(message_obj, message_pfn << 1); + pagedir_invlpg(message_vaddr); + message_klogf("Unmapped message %p from %p\n", message_pfn << 12, message_vaddr); - obj_setvalue(obj, *mapping); - return vptr; + return message_vaddr; } -void -message_remap(jove_owned_obj_t *message, jove_owned_obj_t *pagedir, uintptr_t vptr) +int +message_map(jove_owned_obj_t *message, jove_owned_obj_t *pagedir, virtaddr_t vaddr) { if(message_hasmap(message)) { - errno = -EHASMAP; - return; + return -EHASMAP; } - uintmax_t *mapping = pagedir_get_mapping(pagedir, vptr); + virtaddr_t message_paddr = s_message_addr(message); + virtaddr_t *mapping = pagedir_get_mapping(pagedir, vaddr); - *mapping = obj_getvalue(message) | 1; - pagedir_invlpg(vptr); + if(pagedir_mapping_is_present(mapping)) { + klogf("Mapping %p is occupied\n", + mapping, message); + return -EHASMAP; + } + + pagedir_mapping_set_pfn(mapping, message_paddr >> 12); + pagedir_mapping_set_present(mapping, true); + pagedir_mapping_set_writeable(mapping, true); + pagedir_mapping_set_user(mapping, true); + pagedir_mapping_set_type(mapping, JOVE_MAPPING_TYPE_MESSAGE); - obj_setvalue(message, vptr | 1); + pagedir_invlpg(vaddr); + + message_klogf("Mapped message %p to %p\n", message_paddr, vaddr); + obj_setvalue(message, (vaddr >> 11) | 1); + return 0; } -uintptr_t message_getdata(jove_owned_obj_t *message) +virtaddr_t message_getdata(jove_owned_obj_t *message) { - if(message_hasmap(message)) - return obj_getvalue(message) & ~0xFFFULL; - - uintptr_t message_val = obj_getvalue(message); - return pagedir_ident_from_mapping(&message_val); + uintptr_t message_addr = s_message_addr(message); + if(message_hasmap(message)) return message_addr; + return (virtaddr_t)phys_tovirt(message_addr); } diff --git a/sys/message.h b/sys/message.h index 97d0f71..1a3b43e 100644 --- a/sys/message.h +++ b/sys/message.h @@ -2,13 +2,20 @@ #define _JOVE_SYS_MESSAGE_H 1 #include "hal/obj.h" +#include "hal/memory.h" +#ifdef DEBUG_MESSAGE +#include "lib/printf.h" +#define message_klogf(fmt, ...) kprintf("%s: " fmt, __func__, __VA_ARGS__) +#else +#define message_klogf(fmt, ...) +#endif -#define MESSAGE_ALIGN 0x1000 +int message_new(jove_owned_obj_t *untyped_obj); int message_hasmap(jove_owned_obj_t *message); -uintptr_t message_unmap(jove_owned_obj_t *message, jove_owned_obj_t *pagedir); -void message_remap(jove_owned_obj_t *message, jove_owned_obj_t *pagedir, uintptr_t vptr); +virtaddr_t message_unmap(jove_owned_obj_t *message, jove_owned_obj_t *pagedir); +int message_map(jove_owned_obj_t *message, jove_owned_obj_t *pagedir, virtaddr_t vaddr); uintptr_t message_getdata(jove_owned_obj_t *message); diff --git a/sys/objdir.c b/sys/objdir.c index f956309..5b59ddc 100644 --- a/sys/objdir.c +++ b/sys/objdir.c @@ -4,16 +4,15 @@ #include "hal/obj.h" #include "lib/string.h" #include "jove.h" -#include <errno.h> int objdir_new(jove_owned_obj_t *untyped_obj) { jove_untyped_t *untyped = obj_deref(untyped_obj); - if((uintptr_t)untyped & (JOVE_OBJDIR_SIZE - 1)) return -EALIGN; - if(untyped->limit != JOVE_OBJDIR_SIZE) return -EBADSIZE; + if((uintptr_t)untyped & (OBJDIR_SIZE - 1)) return -EALIGN; + if(untyped->limit != OBJDIR_SIZE) return -EBADSIZE; - memset(untyped, 0, JOVE_OBJDIR_SIZE); + memset(untyped, 0, OBJDIR_SIZE); obj_settype(untyped_obj, JOVE_OBJ_OBJDIR); return 0; } @@ -27,7 +26,7 @@ objdir_peeklocal( errno = EBADOBJ; return (jove_obj_t) { 0 }; } - if(entry >= JOVE_OBJDIR_ENTRIES) { + if(entry >= OBJDIR_ENTRIES) { errno = EBADPATH; return (jove_obj_t) { 0 }; } @@ -44,7 +43,7 @@ objdir_getlocal( if(obj_gettype(objdir_obj) != JOVE_OBJ_OBJDIR) { reterr(EBADOBJ); } - if(entry >= JOVE_OBJDIR_ENTRIES) { + if(entry >= OBJDIR_ENTRIES) { reterr(EBADPATH); } @@ -60,7 +59,7 @@ objdir_trygetlocal( if(obj_gettype(objdir_obj) != JOVE_OBJ_OBJDIR) { reterr(EBADOBJ); } - if(entry >= JOVE_OBJDIR_ENTRIES) { + if(entry >= OBJDIR_ENTRIES) { reterr(EBADPATH); } diff --git a/sys/syscall.c b/sys/syscall.c index 0c40418..7d43d66 100644 --- a/sys/syscall.c +++ b/sys/syscall.c @@ -116,6 +116,12 @@ syscall_handler(uintmax_t message_path_raw, uint16_t message_pathlen) jove_owned_obj_t *pagedir = lockstack_push(&ctx.lockstack, pcb_getpagedir(ctx.objdir)); uintptr_t message_vptr = message_unmap(ctx.message.obj, pagedir); + if(message_vptr == 0) { + klogf("Process %i tried to call syscall with unmapped message %P\n", + pcb_getpid(pcb), message_path, message_pathlen); + sysret = -EBADOBJ; + goto release_return; + } size_t messagelen = 0x1000; void *messagedata = (void*)message_getdata(ctx.message.obj); @@ -160,7 +166,7 @@ fail_target_busy: sysret = _syscall_handle_switch(&ctx); remap_return: - message_remap(ctx.message.obj, pagedir, message_vptr); + message_map(ctx.message.obj, pagedir, message_vptr); release_return: lockstack_popall(&ctx.lockstack); diff --git a/sys/syscall_objdir.c b/sys/syscall_objdir.c index 9243af1..199cbab 100644 --- a/sys/syscall_objdir.c +++ b/sys/syscall_objdir.c @@ -2,6 +2,7 @@ #include "proc/process.h" #include "jove.h" #include "lib/printf.h" +#include "sys/objdir.h" #include "syscall.h" int @@ -16,7 +17,7 @@ s_syscall_objdir_objtype( uint16_t local_idx = *((uint16_t*)payload_data); - if(local_idx > JOVE_OBJDIR_ENTRIES) { + if(local_idx > OBJDIR_ENTRIES) { kprintf("%s: Object index is out of bounds (>= 512)\n", __func__); return EOOB; } @@ -25,6 +26,85 @@ s_syscall_objdir_objtype( return obj_peektype(local_obj); } +static int +s_syscall_objdir_swap(jove_owned_obj_t *target_obj, + lockstack_t *lockstack, + jove_owned_obj_t *rootdir, + size_t bytes_left, + void *payload_data) +{ + size_t bytes_needed = sizeof(struct syscall_objdir_swap); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload."); + + struct syscall_objdir_swap *payload = payload_data; + bytes_needed += payload->other_path_length * sizeof(objpath_part_t); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for other path."); + + jove_owned_obj_t *obj_a = lockstack_push(lockstack, objdir_trygetlocal(target_obj, payload->index)); + if(obj_a == NULL) { + klogf("Getting local object %i failed : %s\n", + payload->index, errstr(errno)); + return -errno; + } + jove_perm_obj_t objdir_b = link_try_traverse_objdir(rootdir, lockstack, + payload->other_path_length - 1, payload->other_path); + if(objdir_b.obj == NULL) { + klogf("Getting object %P failed : %s\n", + payload->other_path, payload->other_path_length, errstr(errno)); + return -errno; + } + + CHECK_OBJPERM(objdir_b, SYSCALL_PERM_OBJDIR_SWAP_TGT, "Other object is missing permission"); + jove_owned_obj_t *obj_b = lockstack_push(lockstack, + objdir_trygetlocal(objdir_b.obj, payload->other_path[payload->other_path_length-1])); + if(obj_b == NULL) { + klogf("Getting object %P failed : %s\n", + payload->other_path, payload->other_path_length, errstr(errno)); + return -errno; + } + + objdir_swapobj(obj_a, obj_b); + return 0; +} + +static int +s_syscall_objdir_link(jove_owned_obj_t *target_obj, + lockstack_t *lockstack, + jove_owned_obj_t *rootdir_obj, + size_t bytes_left, + void *payload_data) +{ + size_t bytes_needed = sizeof(struct syscall_objdir_link); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); + + struct syscall_objdir_link *payload = payload_data; + bytes_needed += payload->other_path_length * sizeof(objpath_part_t); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for other object"); + + jove_owned_obj_t *link_obj = lockstack_push(lockstack, objdir_trygetlocal(target_obj, payload->index)); + if(link_obj == NULL) { + klogf("Getting local object %i failed : %s\n", payload->index, errstr(errno)); + return -errno; + } + CHECK_OBJTYPE(link_obj, JOVE_OBJ_LINK, "Local object is not a link object"); + + jove_perm_obj_t dest_obj = link_try_traverse_objdir(rootdir_obj, lockstack, + payload->other_path_length, payload->other_path); + if(dest_obj.obj == NULL) { + klogf("Getting destination object %P failed : %s\n", + payload->other_path, payload->other_path_length, errstr(errno)); + return -errno; + } + + if(obj_gettype(dest_obj.obj) != JOVE_OBJ_NONE) { + klogf("Destination object %P is not empty\n", + payload->other_path, payload->other_path_length); + return -EFULL; + } + CHECK_OBJPERM(dest_obj, SYSCALL_PERM_OBJDIR_LINK_TGT, "Destination object is missing permissions"); + return link_dup(link_obj, dest_obj.obj); +} + int _syscall_handle_objdir(syscall_context_t *ctx) { @@ -34,6 +114,19 @@ _syscall_handle_objdir(syscall_context_t *ctx) return s_syscall_objdir_objtype( ctx->objdir, ctx->target.obj, ctx->bytes_left, ctx->payload); return -EPERM; + + case SYSCALL_OBJDIR_SWAP: + if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_SWAP) + return s_syscall_objdir_swap(ctx->target.obj, + &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); + return -EPERM; + + case SYSCALL_OBJDIR_LINK: + if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_LINK) + return s_syscall_objdir_link(ctx->target.obj, + &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); + return -EPERM; + default: return -EBADCALL; } diff --git a/sys/syscall_pcb.c b/sys/syscall_pcb.c index 4fe557b..3aeb22b 100644 --- a/sys/syscall_pcb.c +++ b/sys/syscall_pcb.c @@ -6,17 +6,20 @@ #include "proc/process.h" #include "proc/scheduler.h" #include "syscall.h" -#include "errno.h" int s_syscall_pcb_yield(jove_owned_obj_t *pcb_obj, size_t bytes_left, void *payload_data) { + //Validate that message is big enough for payload size_t bytes_needed = sizeof(pid_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); + //Get subject PID from payload. pid_t subject_pid = *((pid_t*)payload_data); + + //Yield to target. return scheduler_yield(subject_pid); } @@ -27,13 +30,22 @@ s_syscall_pcb_send(jove_owned_obj_t *pcb_obj, size_t bytes_left, void *payload_data) { + //Validate that message is big enough for payload. size_t bytes_needed = sizeof(struct syscall_pcb_send); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); - struct syscall_pcb_send *payload = payload_data; + + //Validate that message is big enough for payload object path. bytes_needed += payload->send_path_length; CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for subject path"); + //Validate that subject object path is not the root directory. + if(payload->send_path_length == 0) { + kprintf("%s: Unable to send root directory\n", __func__); + return -EBADPATH; + } + + //Validate that the subject objdir path is valid. jove_perm_obj_t subject_objdir = link_try_traverse_objdir( objdir_obj, lockstack, payload->send_path_length - 1, payload->send_path); if(errno) { @@ -41,8 +53,11 @@ s_syscall_pcb_send(jove_owned_obj_t *pcb_obj, payload->send_path, payload->send_path_length, errstr(errno)); return -errno; } + + //Validate that the currently running PCB has mutate permissions for this objdir. CHECK_OBJPERM(subject_objdir, SYSCALL_PERM_PCB_SEND_OBJDIR, "Subject objdir does not permit send"); + //Validate that the subject exists in the subject objdir. jove_owned_obj_t *subject = objdir_trygetlocal(subject_objdir.obj, payload->send_path[payload->send_path_length-1]); if(subject == 0) { @@ -51,6 +66,7 @@ s_syscall_pcb_send(jove_owned_obj_t *pcb_obj, return -errno; } + //Send subject to target. return pcb_send(obj_deref(pcb_obj), payload->send_target, subject, payload->send_timeout); } @@ -61,13 +77,16 @@ s_syscall_pcb_recv(jove_owned_obj_t *pcb_obj, size_t bytes_left, void *payload_data) { + //Validate that the message is big enough for the payload. size_t bytes_needed = sizeof(struct syscall_pcb_recv); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); - struct syscall_pcb_recv *payload = payload_data; + + //Validate that the message is big enough for the payload object. bytes_needed += payload->recv_path_length * sizeof(objpath_part_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for destination path"); + //Validate that the destination object exists. jove_perm_obj_t destination = link_try_traverse_objdir( objdir_obj, lockstack, payload->recv_path_length, payload->recv_path); if(errno) { @@ -75,12 +94,147 @@ s_syscall_pcb_recv(jove_owned_obj_t *pcb_obj, payload->recv_path, payload->recv_path_length, errstr(errno)); return -errno; } + + //Validate that the destination path is JOVE_OBJ_NONE and that the object has recieve permissions. + CHECK_OBJTYPE(destination.obj, JOVE_OBJ_NONE, "Destination object is occupied"); CHECK_OBJPERM(destination, SYSCALL_PERM_PCB_RECV_DST, "Destination object does not permit recv."); + //Recieve from some PID into destination. return pcb_recv(obj_deref(pcb_obj), payload->recv_target, destination.obj, payload->recv_timeout); } int +s_syscall_pcb_swap(jove_owned_obj_t *pcb_obj, + lockstack_t *lockstack, + jove_owned_obj_t *objdir_obj, + size_t bytes_left, + void *payload_data) +{ + //Validate that the message is big enough for payload. + size_t bytes_needed = sizeof(struct syscall_pcb_recv); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); + struct syscall_pcb_swap *payload = payload_data; + + //Validate that the message is big enough for the subject path. + bytes_needed += payload->swap_path_length * sizeof(objpath_part_t); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for swap path"); + + //Validate that the subject is not the rootdir. + if(payload->swap_path_length == 0) { + kprintf("%s: Unable to swap the root directory\n", __func__); + return -EBADPATH; + } + + //Validate that the subject objdir exists. + jove_perm_obj_t subject_objdir = link_try_traverse_objdir( + objdir_obj, lockstack, payload->swap_path_length - 1, payload->swap_path); + if(errno) { + klogf("Unable to get subject %P objdir : %s\n", + payload->swap_path, payload->swap_path_length, errstr(errno)); + return -errno; + } + //Validate that the subject objdir has send permissions. + CHECK_OBJPERM(subject_objdir, SYSCALL_PERM_PCB_SEND_OBJDIR, "Subject objdir does not permit send"); + + //Validate that the subject object exists. + jove_owned_obj_t *subject = objdir_trygetlocal(subject_objdir.obj, + payload->swap_path[payload->swap_path_length-1]); + if(subject == 0) { + klogf("Unable to get subject %P object : %s\n", + payload->swap_path, payload->swap_path_length, errstr(errno)); + return -errno; + } + + //Validate that the target PCB exists. + if(pcb_frompid(payload->swap_target) == 0) { + klogf("Swap PCB target %i does not exist\n", payload->swap_target); + return -EBADPROC; + } + + //Validate that the message was sent before timeout. + int send_result = pcb_send( + obj_deref(pcb_obj), payload->swap_target, subject, payload->send_timeout); + if(send_result < 0) { + klogf("Send to %i failed with code %s\n", payload->swap_target, errstr(-send_result)); + return send_result; + } + + //Validate that a message was recieved before timeout. + int recv_result = pcb_recv( + obj_deref(pcb_obj), payload->swap_target, subject, payload->recv_timeout); + return recv_result; +} + +int +s_syscall_pcb_stack(jove_owned_obj_t *pcb_obj, + lockstack_t *lockstack, + jove_owned_obj_t *rootdir, + size_t bytes_left, + void *payload_data) +{ + //Verify the message is big enough for the payload struct. + size_t bytes_needed = sizeof(struct syscall_pcb_stack); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); + + //Verify the message is big enough for the untyped object path. + struct syscall_pcb_stack *payload = payload_data; + bytes_needed += sizeof(objpath_part_t) * payload->stack_path_length; + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for untyped path"); + + jove_perm_obj_t untyped = link_try_traverse_objdir(rootdir, lockstack, + payload->stack_path_length, payload->stack_path); + //Verify the untyped object exists. + if(untyped.obj == NULL) { + klogf("Unable to get untyped %P : %s\n", + payload->stack_path, payload->stack_path_length, errstr(errno)); + return -errno; + } + + //Verify the correct type and permissions. + CHECK_OBJTYPE(untyped.obj, JOVE_OBJ_UNTYPED, "Subject untyped is not an untyped."); + CHECK_OBJPERM(untyped, SYSCALL_PERM_PCB_STACK_OBJ, "Untyped is missing permissions"); + + jove_untyped_t *untyped_data = obj_deref(untyped.obj); + if((uintptr_t)untyped_data & 0xFFF) { + klogf("Untyped object %P is not aligned to page boundary.\n", + payload->stack_path, payload->stack_path_length); + return -EALIGN; + } + if(untyped_data->limit != 0x1000) { + klogf("Untyped object %P is not page sized.\n", + payload->stack_path, payload->stack_path_length); + return -EBADSIZE; + } + + //Set the stack. Error if bad type or stack already exists. + pcb_t *pcb = obj_deref(pcb_obj); + switch(payload->type) { + case PCB_STACK_SYSTEM: + if(pcb_get_syscall_stack(pcb) != 0) { + klogf("PCB %p Already has a system stack!\n", pcb); + return -EFULL; + } + pcb_set_syscall_stack(pcb, obj_getvalue(untyped.obj)); + break; + case PCB_STACK_INTERRUPT: + if(pcb_get_interrupt_stack(pcb) != 0) { + klogf("PCB %p Already has a interrupt stack!\n", pcb); + return -EFULL; + } + pcb_set_interrupt_stack(pcb, obj_getvalue(untyped.obj)); + break; + default: + klogf("Unknown stack type %i\n", payload->type); + return -EBADARG; + } + + //Destroy untyped object. + obj_settype(untyped.obj, JOVE_OBJ_NONE); + obj_setvalue(untyped.obj, 0); + return 0; +} + +int _syscall_handle_pcb(syscall_context_t *ctx) { switch(ctx->header->callid) { @@ -101,6 +255,18 @@ _syscall_handle_pcb(syscall_context_t *ctx) ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; + case SYSCALL_PCB_SWAP: + if(ctx->target.permissions & SYSCALL_PERM_PCB_SWAP) + return s_syscall_pcb_swap( + ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); + return -EPERM; + + case SYSCALL_PCB_STACK: + if(ctx->target.permissions & SYSCALL_PERM_PCB_STACK) + return s_syscall_pcb_stack( + ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); + return -EPERM; + default: return -EBADCALL; } diff --git a/sys/syscall_untyped.c b/sys/syscall_untyped.c index c4378ea..c64dea1 100644 --- a/sys/syscall_untyped.c +++ b/sys/syscall_untyped.c @@ -5,6 +5,7 @@ #include "jove.h" #include "lib/printf.h" #include "proc/process.h" +#include "sys/message.h" #include "sys/objdir.h" #include "syscall.h" @@ -148,6 +149,10 @@ int _syscall_handle_untyped(syscall_context_t *ctx) return s_syscall_untyped_retype_pcb( ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->header); return -EPERM; + case SYSCALL_UNTYPED_RETYPE_MESSAGE: + if(ctx->target.permissions & SYSCALL_PERM_UNTYPED_RETYPE) + return message_new(ctx->target.obj); + return -EPERM; default: return -EBADCALL; |
