mirror of
https://github.com/drasko/codezero.git
synced 2026-01-15 12:23:15 +01:00
- Added a full ipc send/recv test - Removed non-zero value checking in r2 for ipc that was there to catch inadvertent full ipc calls. - Added correct hanlding for read/write mrs for current status of utcb. TODO: - Add mapping of every utcb to every task for privileged access so that the kernel can access every utcb without switching spaces. - Removal of same mappings - Upon thread creation need to copy page tables accordingly i.e. each task will have its own utcb mapped with USER access, but every other utcb as kernel access only. Need to handle this case upon page table copying.
290 lines
6.7 KiB
C
290 lines
6.7 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_MASK;
|
|
word |= flags & L4_IPC_FLAGS_MASK;
|
|
return word;
|
|
}
|
|
|
|
static inline unsigned int l4_get_ipc_flags(unsigned int word)
|
|
{
|
|
return word & L4_IPC_FLAGS_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);
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
|
|
printf("%s: to %d from %d tag %u\n", __FUNCTION__, to, from, 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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
// unsigned int tag = l4_get_tag();
|
|
l4id_t sender = l4_get_sender();
|
|
|
|
l4_set_retval(retval);
|
|
|
|
/* Setting the tag may overwrite retval so we l4_send without tagging */
|
|
return l4_ipc(sender, L4_NILTHREAD, 0);
|
|
}
|
|
|
|
/* 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;
|
|
|
|
l4_getid(&ids);
|
|
l4_map(phys, phys_to_virt(phys), npages, MAP_USR_RW_FLAGS, ids.tid);
|
|
return phys_to_virt(phys);
|
|
}
|
|
|
|
|
|
/* 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);
|
|
return virt_to_phys(virt);
|
|
}
|
|
|
|
#endif /* __L4LIB_SYSLIB_H__ */
|