sysvars_marshall.c 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. /*
  2. * Marshall sysvars into a buffer to be sent to the FPGA.
  3. */
  4. #include "common.h"
  5. #include "sysvars.h"
  6. /*
  7. * Marshall a set or subset of sysvar entries into a buffer
  8. * for use by another CPU (for which the address to said buffer
  9. * might differ from what this CPU uses.)
  10. *
  11. * Returns the number of entries successfully marshalled.
  12. * extaddr refers to the external address of the buffer, for which
  13. * internal pointers should be adjusted.
  14. *
  15. * On return, *buflen is adjusted to the number of bytes actually used.
  16. */
  17. size_t sysvar_marshall(enum sysvar_enum first, size_t count,
  18. void *buf, size_t *buflen, uintptr_t extaddr)
  19. {
  20. static const size_t align_mask = 3;
  21. size_t bytes = count * sizeof(sysvar_t);
  22. if (*buflen < bytes) {
  23. /* Only space for a partial result */
  24. count = *buflen / sizeof(sysvar_t);
  25. bytes = count * sizeof(sysvar_t);
  26. }
  27. sysvar_t *vp = (sysvar_t *)buf;
  28. size_t bufsize = *buflen;
  29. const sysvar_t *v = &sysvar_val[first];
  30. const sysvar_type_t *t = &sysvar_types[first];
  31. size_t ok = 0;
  32. intptr_t adjust = extaddr - (uintptr_t)buf;
  33. while (count--) {
  34. sysvar_t vv = *vp++ = *v++;
  35. sysvar_type_t type = *t++;
  36. if (type->datasize && vv.v_ptr) {
  37. size_t dsize = type->datasize(vv);
  38. size_t adj_bytes = (bytes + align_mask) & ~align_mask;
  39. if (adj_bytes + dsize > bufsize)
  40. break; /* Insufficient buffer space */
  41. char *dp = (char *)buf + adj_bytes;
  42. memcpy(dp, vv.v_ptr, dsize);
  43. vv.v_ptr = (void *)((uintptr_t)vv.v_ptr + adjust);
  44. bytes = adj_bytes + dsize;
  45. }
  46. ok++;
  47. }
  48. *buflen = bytes;
  49. return ok;
  50. }