summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-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
12 files changed, 252 insertions, 73 deletions
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