summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/obj.h9
-rw-r--r--api/process.h6
-rw-r--r--api/syscall.h51
-rw-r--r--arch/x86_64/hal/obj.h4
-rw-r--r--arch/x86_64/hal/paging.c112
-rw-r--r--arch/x86_64/hal/paging.h7
-rw-r--r--arch/x86_64/hal/smp.c3
-rw-r--r--arch/x86_64/hal/smp.h6
-rw-r--r--arch/x86_64/proc/init.c20
-rw-r--r--arch/x86_64/proc/process.c41
-rw-r--r--arch/x86_64/proc/process.h8
-rw-r--r--arch/x86_64/proc/scheduler.c30
-rw-r--r--arch/x86_64/proc/switch.s10
-rw-r--r--arch/x86_64/sys/link.c69
-rw-r--r--arch/x86_64/sys/link.h15
-rw-r--r--boot/initrd.c2
-rw-r--r--boot/limine/memorymap.c8
-rw-r--r--config.mk4
-rw-r--r--doc/syscall.md120
-rw-r--r--hal/memory.h21
-rw-r--r--hal/obj.h2
-rw-r--r--lib/rbtree.c2
-rw-r--r--proc/init.c2
-rw-r--r--proc/ipc.c116
-rw-r--r--proc/ipc.h35
-rw-r--r--proc/process.c124
-rw-r--r--proc/process.h27
-rw-r--r--proc/scheduler.c70
-rw-r--r--proc/scheduler.h2
-rw-r--r--sys/link.c58
-rw-r--r--sys/link.h24
-rw-r--r--sys/message.c96
-rw-r--r--sys/message.h13
-rw-r--r--sys/objdir.c13
-rw-r--r--sys/syscall.c8
-rw-r--r--sys/syscall_objdir.c95
-rw-r--r--sys/syscall_pcb.c172
-rw-r--r--sys/syscall_untyped.c5
38 files changed, 1113 insertions, 297 deletions
diff --git a/api/obj.h b/api/obj.h
index 29238c1..2ac0b51 100644
--- a/api/obj.h
+++ b/api/obj.h
@@ -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);
diff --git a/config.mk b/config.mk
index 7416c4e..c6e0312 100644
--- a/config.mk
+++ b/config.mk
@@ -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,
diff --git a/hal/obj.h b/hal/obj.h
index 61ba968..befbc24 100644
--- a/hal/obj.h
+++ b/hal/obj.h
@@ -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);
diff --git a/sys/link.c b/sys/link.c
index 04a15cf..cda10c6 100644
--- a/sys/link.c
+++ b/sys/link.c
@@ -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;
-}
diff --git a/sys/link.h b/sys/link.h
index d4bc8d8..5659101 100644
--- a/sys/link.h
+++ b/sys/link.h
@@ -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;