mirror of
https://github.com/drasko/codezero.git
synced 2026-01-13 11:23:16 +01:00
337 lines
7.9 KiB
C
337 lines
7.9 KiB
C
/*
|
|
* 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 <l4lib/arch/syscalls.h>
|
|
#include <l4/macros.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);
|
|
}
|
|
|
|
/*
|
|
* If we're about to do another ipc, this saves the last ipc's
|
|
* parameters such as the sender and tag information.
|
|
* Any previously saved data in save slots are destroyed.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
static inline l4id_t self_tid(void)
|
|
{
|
|
struct task_ids ids;
|
|
|
|
l4_getid(&ids);
|
|
return ids.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;
|
|
void *virt = l4_new_virtual(npages);
|
|
|
|
l4_getid(&ids);
|
|
l4_map(phys, virt, npages, MAP_USR_RW_FLAGS, ids.tid);
|
|
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__ */
|