Changes for 4.5.0 snapshot
[newlib-cygwin.git] / libgloss / arc / hl / hl_api.c
blobcb24fb9970e2a1be091bdf7547c75227374a2a80
1 /*
2 * hl_api.c -- high-level Hostlink IO API.
4 * Copyright (c) 2024 Synopsys Inc.
6 * The authors hereby grant permission to use, copy, modify, distribute,
7 * and license this software and its documentation for any purpose, provided
8 * that existing copyright notices are retained in all copies and that this
9 * notice is included verbatim in any distributions. No written agreement,
10 * license, or royalty fee is required for any of the authorized uses.
11 * Modifications to this software may be copyrighted by their authors
12 * and need not follow the licensing terms described here, provided that
13 * the new terms are clearly indicated on the first page of each file where
14 * they apply.
18 #include <string.h>
19 #include <stdarg.h>
21 #include "hl_gw.h"
22 #include "hl_api.h"
24 /* Parameter types. */
25 #define PAT_CHAR 1
26 #define PAT_SHORT 2
27 #define PAT_INT 3
28 #define PAT_STRING 4
29 /* For future use. */
30 #define PAT_INT64 5
32 /* Used internally to pass user hostlink parameters to _hl_message(). */
33 struct _hl_user_info {
34 uint32_t vendor_id;
35 uint32_t opcode;
36 uint32_t result;
40 * Main function to send a message using hostlink.
42 * syscall - one of HL_SYSCALL_* defines from hl_api.h.
44 * user - parameters and return value for _user_hostlink implementation.
45 * Packing structure:
46 * uint32 vendor_id - user-defined vendor ID. ID 1025 is reserved for
47 * GNU IO extensions.
48 * uint32 opcode - operation code for user-defined hostlink.
49 * char format[] - argument string in the same format as for
50 * _hl_message() function, see below.
52 * format - argument and return values format string [(i4sp)*:?(i4sp)*], where
53 * characters before ':' is arguments and after is return values.
54 * Supported format characters:
55 * i or 4 - uint32 value, pack_int will be used;
56 * s - char * data, pack_str will be used;
57 * p - void * data, pack_ptr will be used.
59 * ap - argument values and pointers to the output values. Must be in sync
60 * with format string.
61 * For hostlink message argument:
62 * i or 4 - uint32 value;
63 * s - char * pointer to the NUL-teminated string;
64 * p - void * pointer to the buffer and uint32 buffer length.
65 * For output values:
66 * i or 4 - uint32 * pointer to uint32 to return;
67 * s - char * pointer to buffer to return, it must have enough
68 * space to store returned data.
69 * You can get packed buffer length with _hl_get_ptr_len();
70 * p - void * pointer and uint32 * length pointer to store
71 * returned data along with length. Buffer must be enough
72 * to store returned data.
73 * You can get packed buffer length with _hl_get_ptr_len();
75 * return - pointer to the hostlink buffer after output values.
77 static volatile __uncached char *
78 _hl_message_va (uint32_t syscall, struct _hl_user_info *user,
79 const char *format, va_list ap)
81 const char *f = format;
82 volatile __uncached char *p = _hl_payload ();
83 int get_answer = 0;
85 p = _hl_pack_int (p, syscall);
87 if (syscall == HL_SYSCALL_USER)
89 p = _hl_pack_int (p, user->vendor_id);
90 p = _hl_pack_int (p, user->opcode);
91 p = _hl_pack_str (p, format);
94 for (; *f; f++)
96 void *ptr;
97 uint32_t len;
99 if (*f == ':')
101 f++;
102 get_answer = 1;
103 break;
106 switch (*f)
108 case 'i':
109 case '4':
110 p = _hl_pack_int (p, va_arg (ap, uint32_t));
111 break;
112 case 's':
113 p = _hl_pack_str (p, va_arg (ap, char *));
114 break;
115 case 'p':
116 ptr = va_arg (ap, void *);
117 len = va_arg (ap, uint32_t);
118 p = _hl_pack_ptr (p, ptr, len);
119 break;
120 default:
121 return NULL;
124 if (p == NULL)
125 return NULL;
128 _hl_send (p);
130 p = _hl_recv ();
132 if (syscall == HL_SYSCALL_USER && p)
133 p = _hl_unpack_int (p, &user->result);
135 if (p && get_answer)
137 for (; *f; f++)
139 void *ptr;
140 uint32_t *plen;
142 switch (*f)
144 case 'i':
145 case '4':
146 p = _hl_unpack_int (p, va_arg (ap, uint32_t *));
147 break;
148 case 's':
149 p = _hl_unpack_str (p, va_arg (ap, char *));
150 break;
151 case 'p':
152 ptr = va_arg (ap, void *);
153 plen = va_arg (ap, uint32_t *);
154 p = _hl_unpack_ptr (p, ptr, plen);
155 break;
156 default:
157 return NULL;
160 if (p == NULL)
161 return NULL;
165 return p;
169 * Pack integer value (uint32) to provided buffer.
170 * Packing structure:
171 * uint16 type (PAT_INT = 3)
172 * uint16 size (4)
173 * uint32 value
175 volatile __uncached char *
176 _hl_pack_int (volatile __uncached char *p, uint32_t x)
178 volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p;
179 volatile __uncached uint16_t *size = (volatile __uncached uint16_t *)
180 (p + 2);
181 volatile __uncached uint32_t *val = (volatile __uncached uint32_t *)
182 (p + 4);
183 const uint32_t payload_used = 8;
185 if (_hl_payload_left (p) < payload_used)
186 return NULL;
188 *type = PAT_INT;
189 *size = 4;
190 *val = x;
192 return p + payload_used;
196 * Pack data (pointer and legth) to provided buffer.
197 * Packing structure:
198 * uint16 type (PAT_STRING = 4)
199 * uint16 size (length)
200 * char buf[length]
202 volatile __uncached char *
203 _hl_pack_ptr (volatile __uncached char *p, const void *s, uint16_t len)
205 volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p;
206 volatile __uncached uint16_t *size = (volatile __uncached uint16_t *)
207 (p + 2);
208 volatile __uncached char *buf = p + 4;
209 const uint32_t payload_used = 4 + ALIGN (len, 4);
211 if (_hl_payload_left (p) < payload_used)
212 return NULL;
214 *type = PAT_STRING;
215 *size = len;
217 /* _vdmemcpy(buf, s, len); */
218 for (uint16_t i = 0; i < len; i++)
219 buf[i] = ((const char *) s)[i];
221 return p + payload_used;
225 * Pack NUL-terminated string to provided buffer.
226 * Packing structure:
227 * uint16 type (PAT_STRING = 4)
228 * uint16 size (length)
229 * char buf[length]
231 volatile __uncached char *
232 _hl_pack_str (volatile __uncached char *p, const char *s)
234 return _hl_pack_ptr (p, s, strlen (s) + 1);
237 /* Unpack integer value (uint32_t) from a buffer. */
238 volatile __uncached char *
239 _hl_unpack_int (volatile __uncached char *p, uint32_t *x)
241 volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p;
242 volatile __uncached uint16_t *size = (volatile __uncached uint16_t *)
243 (p + 2);
244 volatile __uncached uint32_t *val = (volatile __uncached uint32_t *)
245 (p + 4);
246 const uint32_t payload_used = 8;
248 if (_hl_payload_left (p) < payload_used || *type != PAT_INT || *size != 4)
249 return NULL;
251 if (x)
252 *x = *val;
254 return p + payload_used;
257 /* Unpack data from a buffer. */
258 volatile __uncached char *
259 _hl_unpack_ptr (volatile __uncached char *p, void *s, uint32_t *plen)
261 volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p;
262 volatile __uncached uint16_t *size = (volatile __uncached uint16_t *)
263 (p + 2);
264 volatile __uncached char *buf = p + 4;
265 uint32_t payload_used;
266 uint32_t len;
268 if (_hl_payload_left (p) < 4 || *type != PAT_STRING)
269 return NULL;
271 len = *size;
272 payload_used = 4 + ALIGN (len, 4);
274 if (_hl_payload_left (p) < payload_used)
275 return NULL;
277 if (plen)
278 *plen = len;
280 /* _vsmemcpy(s, buf, len); */
281 if (s)
283 for (uint32_t i = 0; i < len; i++)
284 ((char *) s)[i] = buf[i];
287 return p + payload_used;
291 * Unpack data from a buffer.
293 * No difference compared to _hl_unpack_ptr, except that this function
294 * does not return a length.
296 volatile __uncached char *
297 _hl_unpack_str (volatile __uncached char *p, char *s)
299 return _hl_unpack_ptr (p, s, NULL);
302 /* Return length of packed data (PAT_STRING) if it is on top of the buffer. */
303 uint32_t
304 _hl_get_ptr_len (volatile __uncached char *p)
306 volatile __uncached uint16_t *type = (volatile __uncached uint16_t *) p;
307 volatile __uncached uint16_t *size = (volatile __uncached uint16_t *)
308 (p + 2);
310 if (_hl_payload_left (p) < 4 || *type != PAT_STRING)
311 return 0;
313 return *size;
316 /* Public version of _hl_message_va(). */
317 volatile __uncached char *
318 _hl_message (uint32_t syscall, const char *format, ...)
320 va_list ap;
321 volatile __uncached char *p;
323 va_start (ap, format);
325 p = _hl_message_va (syscall, 0, format, ap);
327 va_end (ap);
329 return p;
333 * API to call user-defined hostlink. See description of user argument in
334 * _hl_message_va().
336 uint32_t
337 _user_hostlink (uint32_t vendor, uint32_t opcode, const char *format, ...)
339 va_list ap;
340 struct _hl_user_info ui = { .vendor_id = vendor,
341 .opcode = opcode };
343 va_start (ap, format);
345 _hl_message_va (HL_SYSCALL_USER, &ui, format, ap);
347 va_end (ap);
349 return ui.result;