kmem.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <strings.h>
  4. #include <stdlib.h>
  5. #include <stdint.h>
  6. #include <stdarg.h>
  7. #include <fcntl.h>
  8. #include <unistd.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/mman.h>
  11. #include <arpa/inet.h>
  12. #include <errno.h>
  13. #include <assert.h>
  14. #include "pcilib.h"
  15. #include "pci.h"
  16. #include "kmem.h"
  17. #include "error.h"
  18. pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) {
  19. int ret;
  20. int i;
  21. void *addr;
  22. kmem_handle_t kh = {0};
  23. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)malloc(sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t));
  24. if (!kbuf) {
  25. pcilib_error("Memory allocation has failed");
  26. return NULL;
  27. }
  28. memset(kbuf, 0, sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t));
  29. ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_KMEM );
  30. if (ret) {
  31. pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed");
  32. return NULL;
  33. }
  34. kh.type = type;
  35. kh.size = size;
  36. kh.align = alignment;
  37. kh.use = use;
  38. if (type != PCILIB_KMEM_TYPE_PAGE) {
  39. kh.size += alignment;
  40. }
  41. for ( i = 0; i < nmemb; i++) {
  42. ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);
  43. if (ret) {
  44. kbuf->buf.n_blocks = i;
  45. pcilib_free_kernel_memory(ctx, kbuf);
  46. pcilib_error("PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed");
  47. return NULL;
  48. }
  49. kbuf->buf.blocks[i].handle_id = kh.handle_id;
  50. kbuf->buf.blocks[i].pa = kh.pa;
  51. kbuf->buf.blocks[i].size = kh.size;
  52. if ((alignment)&&(type != PCILIB_KMEM_TYPE_PAGE)) {
  53. if (kh.pa % alignment) kbuf->buf.blocks[i].alignment_offset = alignment - kh.pa % alignment;
  54. kbuf->buf.blocks[i].size -= alignment;
  55. }
  56. addr = mmap( 0, kh.size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
  57. if ((!addr)||(addr == MAP_FAILED)) {
  58. kbuf->buf.n_blocks = i + 1;
  59. pcilib_free_kernel_memory(ctx, kbuf);
  60. pcilib_error("Failed to mmap allocated kernel memory");
  61. return NULL;
  62. }
  63. kbuf->buf.blocks[i].ua = addr;
  64. kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask;
  65. }
  66. if (nmemb == 1) {
  67. memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t));
  68. }
  69. kbuf->buf.n_blocks = nmemb;
  70. kbuf->prev = NULL;
  71. kbuf->next = ctx->kmem_list;
  72. if (ctx->kmem_list) ctx->kmem_list->prev = kbuf;
  73. ctx->kmem_list = kbuf;
  74. return (pcilib_kmem_handle_t*)kbuf;
  75. }
  76. void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
  77. int ret, err = 0;
  78. int i;
  79. kmem_handle_t kh = {0};
  80. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  81. // if linked in to the list
  82. if (kbuf->next) kbuf->next->prev = kbuf->prev;
  83. if (kbuf->prev) kbuf->prev->next = kbuf->next;
  84. else if (ctx->kmem_list == kbuf) ctx->kmem_list = kbuf->next;
  85. for (i = 0; i < kbuf->buf.n_blocks; i++) {
  86. if (kbuf->buf.blocks[i].ua) munmap(kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset);
  87. kh.handle_id = kbuf->buf.blocks[i].handle_id;
  88. kh.pa = kbuf->buf.blocks[i].pa;
  89. ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh);
  90. if ((ret)&&(!err)) err = ret;
  91. }
  92. free(kbuf);
  93. if (err) {
  94. pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed");
  95. }
  96. }
  97. int pcilib_sync_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir) {
  98. int i;
  99. int ret;
  100. kmem_sync_t ks;
  101. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  102. ks.dir = dir;
  103. for (i = 0; i < kbuf->buf.n_blocks; i++) {
  104. ks.handle.handle_id = kbuf->buf.blocks[i].handle_id;
  105. ks.handle.pa = kbuf->buf.blocks[i].pa;
  106. ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_SYNC, &ks);
  107. if (ret) {
  108. pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed");
  109. return PCILIB_ERROR_FAILED;
  110. }
  111. if (!kbuf->buf.blocks[i].pa) {
  112. kbuf->buf.blocks[i].pa = ks.handle.pa;
  113. }
  114. }
  115. return 0;
  116. }
  117. void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
  118. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  119. return kbuf->buf.addr.ua + kbuf->buf.addr.alignment_offset + kbuf->buf.addr.mmap_offset;
  120. }
  121. uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
  122. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  123. return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset;
  124. }
  125. void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
  126. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  127. return kbuf->buf.blocks[block].ua + kbuf->buf.blocks[block].alignment_offset + kbuf->buf.blocks[block].mmap_offset;
  128. }
  129. uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
  130. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  131. return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset;
  132. }
  133. size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
  134. pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
  135. return kbuf->buf.blocks[block].size;
  136. }