/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * pal_host.h * * This file contains definition of PAL host ABI. */ #ifndef PAL_HOST_H #define PAL_HOST_H #ifndef IN_PAL # error "cannot be included outside PAL" #endif #include /* Simpler mutex design: a single variable that tracks whether the * mutex is locked (just waste a 64 bit word for now). State is 1 (locked) or * 0 (unlocked). * Keep a count of how many threads are waiting on the mutex. * If DEBUG_MUTEX is defined, * mutex_handle will record the owner of mutex locking. */ typedef struct mutex_handle { volatile int64_t locked; struct atomic_int nwaiters; #ifdef DEBUG_MUTEX int owner; #endif } PAL_LOCK; /* Initializer of Mutexes */ #define MUTEX_HANDLE_INIT { .locked = 0, .nwaiters.counter = 0 } #define INIT_MUTEX_HANDLE(m) do { m->locked = 0; atomic_set(&m->nwaiters, 0); } while (0) #define LOCK_INIT MUTEX_HANDLE_INIT #define INIT_LOCK(lock) INIT_MUTEX_HANDLE(lock); #define _DkInternalLock _DkMutexLock #define _DkInternalUnlock _DkMutexUnlock /* Locking and unlocking of Mutexes */ int _DkMutexLock (struct mutex_handle * mut); int _DkMutexLockTimeout (struct mutex_handle * mut, uint64_t timeout); int _DkMutexUnlock (struct mutex_handle * mut); typedef struct { PAL_HDR hdr; #if TRACE_HEAP_LEAK == 1 struct heap_trace_info { /* maintaining a list of handles */ struct pal_handle ** pprev, * next; /* trace the PC where the handle is created */ PAL_PTR caller; } heap_trace; #endif } PAL_RESERVED_HDR; typedef struct pal_handle { /* TSAI: Here we define the internal types of PAL_HANDLE * in PAL design, user has not to access the content inside the * handle, also there is no need to allocate the internal * handles, so we hide the type name of these handles on purpose. */ PAL_HDR hdr; union { struct { PAL_IDX fds[2]; } generic; struct { PAL_IDX fd; PAL_NUM offset; PAL_BOL append; PAL_BOL pass; PAL_STR realpath; } file; struct { PAL_IDX fd; PAL_NUM pipeid; PAL_BOL nonblocking; } pipe; struct { PAL_IDX fds[2]; PAL_BOL nonblocking; } pipeprv; struct { PAL_IDX fd_in, fd_out; PAL_IDX dev_type; PAL_BOL destroy; PAL_STR realpath; } dev; struct { PAL_IDX fd; PAL_STR realpath; PAL_PTR buf; PAL_PTR ptr; PAL_PTR end; PAL_BOL endofstream; } dir; struct { PAL_IDX fd; PAL_NUM token; } gipc; struct { PAL_IDX fd; PAL_PTR bind; PAL_PTR conn; PAL_BOL nonblocking; PAL_BOL reuseaddr; PAL_NUM linger; PAL_NUM receivebuf; PAL_NUM sendbuf; PAL_NUM receivetimeout; PAL_NUM sendtimeout; PAL_BOL tcp_cork; PAL_BOL tcp_keepalive; PAL_BOL tcp_nodelay; } sock; struct { PAL_IDX stream_in, stream_out; PAL_IDX cargo; PAL_IDX pid; PAL_BOL nonblocking; } process; struct { PAL_IDX cli; PAL_IDX srv; PAL_IDX port; PAL_BOL nonblocking; PAL_PTR addr; } mcast; struct { PAL_IDX tid; } thread; struct { struct mutex_handle mut; } mutex; struct { struct atomic_int signaled; struct atomic_int nwaiters; PAL_BOL isnotification; } event; }; } * PAL_HANDLE; #define RFD(n) (00001 << (n)) #define WFD(n) (00010 << (n)) #define WRITEABLE(n) (00100 << (n)) #define ERROR(n) (01000 << (n)) #define MAX_FDS (3) #define HAS_FDS (00077) #define HANDLE_TYPE(handle) ((handle)->hdr.type) struct arch_frame { #ifdef __x86_64__ unsigned long rsp, rbp, rbx, rsi, rdi, r12, r13, r14, r15; #else # error "unsupported architecture" #endif }; #ifdef __x86_64__ # define store_register(reg, var) \ asm volatile ("movq %%" #reg ", %0" : "=a" (var) :: "memory"); # define store_register_in_frame(reg, f) store_register(reg, (f)->reg) # define arch_store_frame(f) \ store_register_in_frame(rsp, f) \ store_register_in_frame(rbp, f) \ store_register_in_frame(rbx, f) \ store_register_in_frame(rsi, f) \ store_register_in_frame(rdi, f) \ store_register_in_frame(r12, f) \ store_register_in_frame(r13, f) \ store_register_in_frame(r14, f) \ store_register_in_frame(r15, f) # define restore_register(reg, var, clobber...) \ asm volatile ("movq %0, %%" #reg :: "g" (var) : "memory", ##clobber); # define restore_register_in_frame(reg, f) \ restore_register(reg, (f)->reg, \ "r15", "r14", "r13", "r12", "rdi", "rsi", "rbx") # define arch_restore_frame(f) \ restore_register_in_frame(r15, f) \ restore_register_in_frame(r14, f) \ restore_register_in_frame(r13, f) \ restore_register_in_frame(r12, f) \ restore_register_in_frame(rdi, f) \ restore_register_in_frame(rsi, f) \ restore_register_in_frame(rbx, f) \ restore_register_in_frame(rbp, f) \ restore_register_in_frame(rsp, f) #else /* __x86_64__ */ # error "unsupported architecture" #endif #define PAL_FRAME_IDENTIFIER (0xdeaddeadbeefbeef) struct pal_frame { volatile uint64_t identifier; void * func; const char * funcname; struct arch_frame arch; }; static inline void __store_frame (struct pal_frame * frame, void * func, const char * funcname) { arch_store_frame(&frame->arch) frame->func = func; frame->funcname = funcname; asm volatile ("nop" ::: "memory"); frame->identifier = PAL_FRAME_IDENTIFIER; } #define ENTER_PAL_CALL(name) \ struct pal_frame frame; \ __store_frame(&frame, &(name), #name) static inline void __clear_frame (struct pal_frame * frame) { if (frame->identifier == PAL_FRAME_IDENTIFIER) { asm volatile ("nop" ::: "memory"); frame->identifier = 0; } } #define LEAVE_PAL_CALL() \ do { \ __clear_frame(&frame); \ } while (0) #define LEAVE_PAL_CALL_RETURN(retval) \ do { \ __clear_frame(&frame); \ return (retval); \ } while (0) #if TRACE_HEAP_LEAK == 1 /* The following code adds a piece of information in each handle to trace heap leakage. */ extern PAL_HANDLE heap_alloc_head; extern PAL_LOCK heap_alloc_trace_lock; /* call the following function in GDB */ typedef struct { PAL_PTR caller; PAL_NUM count; } HEAP_ALLOC_RECORD; extern HEAP_ALLOC_RECORD * collect_heap_alloc_records (PAL_NUM max_records); static inline void __trace_heap (PAL_HANDLE handle, struct pal_frame * frame) { _DkInternalLock(&heap_alloc_trace_lock); handle->hdr.heap_trace.caller = ((PAL_PTR *)frame->arch.rbp)[1]; /* Add the handle to the list */ if (heap_alloc_head) heap_alloc_head->hdr.heap_trace.pprev = &handle->hdr.heap_trace.next; handle->hdr.heap_trace.next = heap_alloc_head; handle->hdr.heap_trace.pprev = &heap_alloc_head; heap_alloc_head = handle; _DkInternalUnlock(&heap_alloc_trace_lock); } #define TRACE_HEAP(handle) \ do { if (handle) __trace_heap(handle, &frame); } while (0) static inline void __untrace_heap (PAL_HANDLE handle) { _DkInternalLock(&heap_alloc_trace_lock); /* remove the handle from the list */ *handle->hdr.heap_trace.pprev = handle->hdr.heap_trace.next; if (handle->hdr.heap_trace.next) handle->hdr.heap_trace.next->hdr.heap_trace.pprev = handle->hdr.heap_trace.pprev; handle->hdr.heap_trace.pprev = NULL; handle->hdr.heap_trace.next = NULL; _DkInternalUnlock(&heap_alloc_trace_lock); } #define UNTRACE_HEAP(handle) \ do { if (handle) __untrace_heap(handle); } while (0) #endif /* TRACE_HEAP_LEAK == 1 */ #endif /* PAL_HOST_H */