|
@@ -0,0 +1,53 @@
|
|
|
+/*
|
|
|
+ * Marshall sysvars into a buffer to be sent to the FPGA.
|
|
|
+ */
|
|
|
+
|
|
|
+#include "common.h"
|
|
|
+#include "sysvars.h"
|
|
|
+
|
|
|
+/*
|
|
|
+ * Marshall a set or subset of sysvar entries into a buffer
|
|
|
+ * for use by another CPU (for which the address to said buffer
|
|
|
+ * might differ from what this CPU uses.)
|
|
|
+ *
|
|
|
+ * Returns the number of entries successfully marshalled.
|
|
|
+ * extaddr refers to the external address of the buffer, for which
|
|
|
+ * internal pointers should be adjusted.
|
|
|
+ *
|
|
|
+ * On return, *buflen is adjusted to the number of bytes actually used.
|
|
|
+ */
|
|
|
+size_t sysvar_marshall(enum sysvars_enum first, size_t count,
|
|
|
+ void *buf, size_t *buflen, uintptr_t extaddr)
|
|
|
+{
|
|
|
+ static const size_t align_mask = 3;
|
|
|
+ size_t bytes = count * sizeof(sysvar_t);
|
|
|
+ if (*buflen < bytes) {
|
|
|
+ /* Only space for a partial result */
|
|
|
+ count = *buflen / sizeof(sysvar_t);
|
|
|
+ bytes = count * sizeof(sysvar_t);
|
|
|
+ }
|
|
|
+ sysvar_t *vp = (sysvar_t *)buf;
|
|
|
+ size_t bufsize = *buflen;
|
|
|
+ const sysvar_t *v = &sysvar_val[first];
|
|
|
+ const sysvar_type_t *t = &sysvar_types[first];
|
|
|
+ size_t ok = 0;
|
|
|
+ intptr_t adjust = extaddr - (uintptr_t)buf;
|
|
|
+
|
|
|
+ while (count--) {
|
|
|
+ sysvar_t vv = *vp++ = *v++;
|
|
|
+ sysvar_type_t type = *t++;
|
|
|
+ if (type->datasize) {
|
|
|
+ size_t dsize = type->datasize(vv);
|
|
|
+ size_t adj_bytes = (bytes + align_mask) & ~align_mask;
|
|
|
+ if (adj_bytes + dsize > bufsize)
|
|
|
+ break; /* Insufficient buffer space */
|
|
|
+ char *dp = (char *)buf + adj_bytes;
|
|
|
+ memcpy(dp, vv.v_ptr, dsize);
|
|
|
+ vv.v_ptr = (void *)((uintptr_t)vv.v_ptr + adjust);
|
|
|
+ bytes = adj_bytes + dsize;
|
|
|
+ }
|
|
|
+ ok++;
|
|
|
+ }
|
|
|
+ *buflen = bytes;
|
|
|
+ return ok;
|
|
|
+}
|