URL
https://opencores.org/ocsvn/c0or1k/c0or1k/trunk
Subversion Repositories c0or1k
[/] [c0or1k/] [trunk/] [conts/] [libl4/] [include/] [l4lib/] [arch/] [arm/] [syslib.h] - Rev 2
Compare with Previous | Blame | View Log
/* * Helper functions that wrap raw l4 syscalls. * * Copyright (C) 2007-2009 Bahadir Bilgehan Balban */ #ifndef __L4LIB_SYSLIB_H__ #define __L4LIB_SYSLIB_H__ #include <stdio.h> #include <l4/macros.h> #include L4LIB_INC_ARCH(syscalls.h) /* * NOTE: * Its best to use these wrappers because they generalise the way * common ipc data like sender id, error, ipc tag are passed * between ipc parties. * * The arguments to l4_ipc() are used by the microkernel to initiate * the ipc. Any data passed in message registers may or may not be * a duplicate of this data, but the distinction is that anything * that is passed via the mrs are meant to be used by the other party * participating in the ipc. */ /* For system call arguments */ #define L4SYS_ARG0 (MR_UNUSED_START) #define L4SYS_ARG1 (MR_UNUSED_START + 1) #define L4SYS_ARG2 (MR_UNUSED_START + 2) #define L4SYS_ARG3 (MR_UNUSED_START + 3) #define L4_IPC_TAG_MASK 0x00000FFF /* * Servers get sender. */ static inline l4id_t l4_get_sender(void) { return (l4id_t)read_mr(MR_SENDER); } /* * When doing an ipc the sender never has to be explicitly set in * the utcb via this function since this information is found out * by the microkernel by checking the system caller's id. This is * only used for restoring the sender on the utcb in order to * complete an earlier ipc. */ static inline void l4_set_sender(l4id_t sender) { write_mr(MR_SENDER, sender); } static inline unsigned int l4_set_ipc_size(unsigned int word, unsigned int size) { word &= ~L4_IPC_FLAGS_SIZE_MASK; word |= ((size << L4_IPC_FLAGS_SIZE_SHIFT) & L4_IPC_FLAGS_SIZE_MASK); return word; } static inline unsigned int l4_get_ipc_size(unsigned int word) { return (word & L4_IPC_FLAGS_SIZE_MASK) >> L4_IPC_FLAGS_SIZE_SHIFT; } static inline unsigned int l4_set_ipc_msg_index(unsigned int word, unsigned int index) { /* FIXME: Define MR_PRIMARY_TOTAL, MR_TOTAL etc. and use MR_TOTAL HERE! */ BUG_ON(index > UTCB_SIZE); word &= ~L4_IPC_FLAGS_MSG_INDEX_MASK; word |= (index << L4_IPC_FLAGS_MSG_INDEX_SHIFT) & L4_IPC_FLAGS_MSG_INDEX_MASK; return word; } static inline unsigned int l4_get_ipc_msg_index(unsigned int word) { return (word & L4_IPC_FLAGS_MSG_INDEX_MASK) >> L4_IPC_FLAGS_MSG_INDEX_SHIFT; } static inline unsigned int l4_set_ipc_flags(unsigned int word, unsigned int flags) { word &= ~L4_IPC_FLAGS_TYPE_MASK; word |= flags & L4_IPC_FLAGS_TYPE_MASK; return word; } static inline unsigned int l4_get_ipc_flags(unsigned int word) { return word & L4_IPC_FLAGS_TYPE_MASK; } static inline unsigned int l4_get_tag(void) { return read_mr(MR_TAG) & L4_IPC_TAG_MASK; } static inline void l4_set_tag(unsigned int tag) { unsigned int tag_flags = read_mr(MR_TAG); tag_flags &= ~L4_IPC_TAG_MASK; tag_flags |= tag & L4_IPC_TAG_MASK; write_mr(MR_TAG, tag_flags); } /* Servers: * Sets the message register for returning errors back to client task. * These are usually posix error codes. */ static inline void l4_set_retval(int retval) { write_mr(MR_RETURN, retval); } /* Clients: * Learn result of request. */ static inline int l4_get_retval(void) { return read_mr(MR_RETURN); } /* * This is useful for stacked IPC. A stacked IPC happens * when a new IPC is initiated before concluding the current * one. * * This saves the last ipc's parameters such as the sender * and tag information. Any previously saved data in save * slots are destroyed. This is fine as IPC stacking is only * useful if done once. */ static inline void l4_save_ipcregs(void) { l4_get_utcb()->saved_sender = l4_get_sender(); l4_get_utcb()->saved_tag = l4_get_tag(); } static inline void l4_restore_ipcregs(void) { l4_set_tag(l4_get_utcb()->saved_tag); l4_set_sender(l4_get_utcb()->saved_sender); } #define TASK_CID_MASK 0xFF000000 #define TASK_ID_MASK 0x00FFFFFF #define TASK_CID_SHIFT 24 static inline l4id_t __raw_tid(l4id_t tid) { return tid & TASK_ID_MASK; } static inline l4id_t __cid(l4id_t tid) { return (tid & TASK_CID_MASK) >> TASK_CID_SHIFT; } static inline l4id_t self_tid(void) { struct task_ids ids; l4_getid(&ids); return ids.tid; } static inline l4id_t __raw_self_tid(void) { return __raw_tid(self_tid()); } static inline int l4_send_full(l4id_t to, unsigned int tag) { l4_set_tag(tag); return l4_ipc(to, L4_NILTHREAD, L4_IPC_FLAGS_FULL); } static inline int l4_receive_full(l4id_t from) { return l4_ipc(L4_NILTHREAD, from, L4_IPC_FLAGS_FULL); } static inline int l4_sendrecv_full(l4id_t to, l4id_t from, unsigned int tag) { int err; BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD); l4_set_tag(tag); err = l4_ipc(to, from, L4_IPC_FLAGS_FULL); return err; } static inline int l4_send_extended(l4id_t to, unsigned int tag, unsigned int size, void *buf) { unsigned int flags = 0; l4_set_tag(tag); /* Set up flags word for extended ipc */ flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED); flags = l4_set_ipc_size(flags, size); flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0); /* Write buffer pointer to MR index that we specified */ write_mr(L4SYS_ARG0, (unsigned long)buf); return l4_ipc(to, L4_NILTHREAD, flags); } static inline int l4_receive_extended(l4id_t from, unsigned int size, void *buf) { unsigned int flags = 0; /* Indicate extended receive */ flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED); /* How much data is accepted */ flags = l4_set_ipc_size(flags, size); /* Indicate which MR index buffer pointer is stored */ flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0); /* Set MR with buffer to receive data */ write_mr(L4SYS_ARG0, (unsigned long)buf); return l4_ipc(L4_NILTHREAD, from, flags); } /* * Return result value as extended IPC. * * Extended IPC copies up to 2KB user address space buffers. * Along with such an ipc, a return value is sent using a primary * mr that is used as the return register. * * It may not be desirable to return a payload on certain conditions, * (such as an error return value) So a nopayload field is provided. */ static inline int l4_return_extended(int retval, unsigned int size, void *buf, int nopayload) { unsigned int flags = 0; l4id_t sender = l4_get_sender(); l4_set_retval(retval); /* Set up flags word for extended ipc */ flags = l4_set_ipc_flags(flags, L4_IPC_FLAGS_EXTENDED); flags = l4_set_ipc_msg_index(flags, L4SYS_ARG0); /* Write buffer pointer to MR index that we specified */ write_mr(L4SYS_ARG0, (unsigned long)buf); if (nopayload) flags = l4_set_ipc_size(flags, 0); else flags = l4_set_ipc_size(flags, size); return l4_ipc(sender, L4_NILTHREAD, flags); } static inline int l4_sendrecv_extended(l4id_t to, l4id_t from, unsigned int tag, void *buf) { /* Need to imitate sendrecv but with extended send/recv flags */ return 0; } static inline int l4_send(l4id_t to, unsigned int tag) { l4_set_tag(tag); return l4_ipc(to, L4_NILTHREAD, 0); } static inline int l4_sendrecv(l4id_t to, l4id_t from, unsigned int tag) { int err; BUG_ON(to == L4_NILTHREAD || from == L4_NILTHREAD); l4_set_tag(tag); err = l4_ipc(to, from, 0); return err; } static inline int l4_receive(l4id_t from) { return l4_ipc(L4_NILTHREAD, from, 0); } static inline void l4_print_mrs() { printf("Message registers: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", read_mr(0), read_mr(1), read_mr(2), read_mr(3), read_mr(4), read_mr(5)); } /* Servers: * Return the ipc result back to requesting task. */ static inline int l4_ipc_return(int retval) { l4id_t sender = l4_get_sender(); l4_set_retval(retval); /* Setting the tag would overwrite retval so we l4_send without tagging */ return l4_ipc(sender, L4_NILTHREAD, 0); } void *l4_new_virtual(int npages); void *l4_del_virtual(void *virt, int npages); /* A helper that translates and maps a physical address to virtual */ static inline void *l4_map_helper(void *phys, int npages) { struct task_ids ids; int err; void *virt = l4_new_virtual(npages); l4_getid(&ids); if ((err = l4_map(phys, virt, npages, MAP_USR_DEFAULT, ids.tid)) < 0) return PTR_ERR(err); return virt; } /* A helper that translates and maps a physical address to virtual */ static inline void *l4_unmap_helper(void *virt, int npages) { struct task_ids ids; l4_getid(&ids); l4_unmap(virt, npages, ids.tid); l4_del_virtual(virt, npages); return 0; } #define L4_EXIT_MASK 0xFFFF static inline void l4_exit(unsigned int exit_code) { struct task_ids ids; l4_getid(&ids); l4_thread_control(THREAD_DESTROY | (exit_code & L4_EXIT_MASK), &ids); } #endif /* __L4LIB_SYSLIB_H__ */