1/**
2 * \file
3 * \brief Legacy IDC buffer format. PLEASE DO NOT USE FOR ANY NEW CODE!
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#ifndef BARRELFISH_LEGACY_IDC_BUFFER_H
16#define BARRELFISH_LEGACY_IDC_BUFFER_H
17
18/**
19 * \brief Maximum total length of IDC message (header + payload)
20 *
21 * Determined by number of registers available to transfer messages.
22 */
23// XXX Doesnt that sound ever so slightly machine dependent to you ???
24// XXX See also related magic in syscalls.c
25#define IDC_SEND_LENGTH         12
26
27/// Length of IDC message headers
28// XXX Is there a good reason that this isnt just done with sizeof() ???
29#if defined(__SIZEOF_POINTER__)
30#if __SIZEOF_POINTER__ == 4
31#define IDC_SEND_HEADER_LENGTH 3
32#elif __SIZEOF_POINTER__ == 8
33#define IDC_SEND_HEADER_LENGTH 2
34#else
35#error "Unknown pointer size"
36#endif
37#else
38#error "Unknown pointer size"
39#endif
40
41/// Length of IDC message payload
42#define IDC_MSG_LENGTH          (IDC_SEND_LENGTH - IDC_SEND_HEADER_LENGTH)
43
44#include <assert.h>
45#include <string.h>
46#include <stdlib.h> // for abort
47
48#if __x86_64__
49typedef unsigned int idc_flag_t;
50#elif __i386__
51typedef unsigned int idc_flag_t;
52#elif __arm__
53typedef uint8_t idc_flag_t;
54#else
55#error "Unknown architecture."
56#endif
57
58#ifdef IN_KERNEL
59#define idc_fatal_error(x, ...) panic(x, __VA_ARGS__)
60#else // IN_KERNEL
61#define idc_fatal_error(x, ...) abort();
62#endif // IN_KERNEL
63
64/**
65 * \brief IDC sender-side header.
66 */
67union idc_send_header {
68    uintptr_t raw[IDC_SEND_HEADER_LENGTH];
69    struct {
70        struct __attribute__ ((__packed__)) {
71            idc_flag_t sync   :1; ///< Synchronous call (yields caller's timeslice)
72            idc_flag_t yield  :1; ///< Yield to receiver if disabled/unable to transfer
73        } flags;
74        uint8_t     length;         ///< Length of payload in words
75        uint8_t     invoke_bits;    ///< Valid bits in invoke_cptr
76        uint8_t     send_bits;      ///< Valid bits in send_cptr
77        capaddr_t     invoke_cptr;    ///< Cap to invoke
78        capaddr_t     send_cptr;      ///< Cap to send or #CPTR_NULL
79    } x;
80};
81
82/**
83 * \brief IDC receiver-side header.
84 */
85union idc_recv_header {
86    uintptr_t raw;
87    struct {
88        struct __attribute__ ((__packed__)) {
89            idc_flag_t captransfer :1;    ///< A cap was transferred
90        } flags;
91        uint8_t     length;                 ///< Length of payload in words
92    } x;
93};
94
95/**
96 * \brief Message layout on sender side.
97 */
98union idc_send_msg_body {
99    uintptr_t       raw[IDC_SEND_LENGTH]; ///< Raw message contents
100
101    struct {
102        union idc_send_header header;
103        uintptr_t words[IDC_MSG_LENGTH];  ///< Message payload
104    } x;
105};
106
107/**
108 * \brief Message layout on receiver side.
109 */
110struct idc_recv_msg_body {
111    union idc_recv_header header;     ///< Header
112    uintptr_t words[IDC_MSG_LENGTH];  ///< Message payload
113};
114
115/// IDC send message, with position indicator for marshalling
116struct idc_send_msg {
117    int                         pos;    ///< Index in message
118    union idc_send_msg_body     u;      ///< Actual transferred message content
119};
120
121/// IDC receive message, with position indicator for demarshalling
122struct idc_recv_msg {
123    int                         pos;    ///< Index in message
124    struct idc_recv_msg_body    msg;    ///< Actual transferred message content
125};
126
127static inline uintptr_t *idc_get_raw(struct idc_send_msg *msg)
128{
129    return msg->u.raw;
130}
131
132static inline errval_t idc_msg_decode_word(struct idc_recv_msg *msg,
133                                           uintptr_t *ret)
134{
135    assert(ret != NULL);
136    if(msg->pos < msg->msg.header.x.length) {
137        *ret = msg->msg.words[msg->pos++];
138        return SYS_ERR_OK;
139    } else {
140        return SYS_ERR_IDC_MSG_BOUNDS;
141    }
142}
143
144/**
145 * \brief decode a word from the message
146 * \returns the word, or 0 if out of bounds
147 * \bug XXX: do not use this for new code!
148 */
149static inline uintptr_t idc_msg_decode_word_or_zero(struct idc_recv_msg *msg)
150{
151    uintptr_t w;
152    if (err_is_ok(idc_msg_decode_word(msg, &w))) {
153        return w;
154    } else {
155        return 0;
156    }
157}
158
159static inline void idc_msg_encode_word(struct idc_send_msg *msg, uintptr_t word)
160{
161    if(msg->pos < IDC_MSG_LENGTH) {
162        msg->u.x.words[msg->pos++] = word;
163        msg->u.x.header.x.length = msg->pos;
164    }
165    else {
166        idc_fatal_error("%s: msg %p pos %d",
167                        __FUNCTION__, msg, (int)msg->pos);
168    }
169}
170
171static inline void idc_msg_init(struct idc_send_msg *msg)
172{
173    int i;
174    msg->pos = 0;
175    for (i = 0; i < IDC_SEND_HEADER_LENGTH; i++) {
176        msg->u.raw[i] = 0;
177    }
178
179    // Sync, yielding IDC is the default
180    msg->u.x.header.x.flags.sync = 1;
181    msg->u.x.header.x.flags.yield = 1;
182}
183
184// Set the msg flag to be async
185static inline void idc_msg_set_async(struct idc_send_msg *msg)
186{
187    msg->u.x.header.x.flags.sync = 0;
188}
189
190// Macro cleanup
191#undef idc_fatal_error
192
193#endif // BARRELFISH_LEGACY_IDC_BUFFER_H
194