io_semihosting.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <platform_def.h>
  8. #include <drivers/io/io_driver.h>
  9. #include <drivers/io/io_semihosting.h>
  10. #include <drivers/io/io_storage.h>
  11. #include <lib/semihosting.h>
  12. /* Identify the device type as semihosting */
  13. static io_type_t device_type_sh(void)
  14. {
  15. return IO_TYPE_SEMIHOSTING;
  16. }
  17. /* Semi-hosting functions, device info and handle */
  18. static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
  19. static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
  20. io_entity_t *entity);
  21. static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset);
  22. static int sh_file_len(io_entity_t *entity, size_t *length);
  23. static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
  24. size_t *length_read);
  25. static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
  26. size_t length, size_t *length_written);
  27. static int sh_file_close(io_entity_t *entity);
  28. static const io_dev_connector_t sh_dev_connector = {
  29. .dev_open = sh_dev_open
  30. };
  31. static const io_dev_funcs_t sh_dev_funcs = {
  32. .type = device_type_sh,
  33. .open = sh_file_open,
  34. .seek = sh_file_seek,
  35. .size = sh_file_len,
  36. .read = sh_file_read,
  37. .write = sh_file_write,
  38. .close = sh_file_close,
  39. .dev_init = NULL, /* NOP */
  40. .dev_close = NULL, /* NOP */
  41. };
  42. static io_dev_info_t sh_dev_info = {
  43. .funcs = &sh_dev_funcs,
  44. .info = (uintptr_t)NULL
  45. };
  46. /* Open a connection to the semi-hosting device */
  47. static int sh_dev_open(const uintptr_t dev_spec __unused,
  48. io_dev_info_t **dev_info)
  49. {
  50. assert(dev_info != NULL);
  51. *dev_info = &sh_dev_info;
  52. return 0;
  53. }
  54. /* Open a file on the semi-hosting device */
  55. static int sh_file_open(io_dev_info_t *dev_info __unused,
  56. const uintptr_t spec, io_entity_t *entity)
  57. {
  58. int result = -ENOENT;
  59. long sh_result;
  60. const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
  61. assert(file_spec != NULL);
  62. assert(entity != NULL);
  63. sh_result = semihosting_file_open(file_spec->path, file_spec->mode);
  64. if (sh_result > 0) {
  65. entity->info = (uintptr_t)sh_result;
  66. result = 0;
  67. }
  68. return result;
  69. }
  70. /* Seek to a particular file offset on the semi-hosting device */
  71. static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset)
  72. {
  73. long file_handle, sh_result;
  74. assert(entity != NULL);
  75. file_handle = (long)entity->info;
  76. sh_result = semihosting_file_seek(file_handle, (ssize_t)offset);
  77. return (sh_result == 0) ? 0 : -ENOENT;
  78. }
  79. /* Return the size of a file on the semi-hosting device */
  80. static int sh_file_len(io_entity_t *entity, size_t *length)
  81. {
  82. int result = -ENOENT;
  83. assert(entity != NULL);
  84. assert(length != NULL);
  85. long sh_handle = (long)entity->info;
  86. long sh_result = semihosting_file_length(sh_handle);
  87. if (sh_result >= 0) {
  88. result = 0;
  89. *length = (size_t)sh_result;
  90. }
  91. return result;
  92. }
  93. /* Read data from a file on the semi-hosting device */
  94. static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
  95. size_t *length_read)
  96. {
  97. int result = -ENOENT;
  98. long sh_result;
  99. size_t bytes = length;
  100. long file_handle;
  101. assert(entity != NULL);
  102. assert(length_read != NULL);
  103. file_handle = (long)entity->info;
  104. sh_result = semihosting_file_read(file_handle, &bytes, buffer);
  105. if (sh_result >= 0) {
  106. *length_read = (bytes != length) ? bytes : length;
  107. result = 0;
  108. }
  109. return result;
  110. }
  111. /* Write data to a file on the semi-hosting device */
  112. static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
  113. size_t length, size_t *length_written)
  114. {
  115. long sh_result;
  116. long file_handle;
  117. size_t bytes = length;
  118. assert(entity != NULL);
  119. assert(length_written != NULL);
  120. file_handle = (long)entity->info;
  121. sh_result = semihosting_file_write(file_handle, &bytes, buffer);
  122. *length_written = length - bytes;
  123. return (sh_result == 0) ? 0 : -ENOENT;
  124. }
  125. /* Close a file on the semi-hosting device */
  126. static int sh_file_close(io_entity_t *entity)
  127. {
  128. long sh_result;
  129. long file_handle;
  130. assert(entity != NULL);
  131. file_handle = (long)entity->info;
  132. sh_result = semihosting_file_close(file_handle);
  133. return (sh_result >= 0) ? 0 : -ENOENT;
  134. }
  135. /* Exported functions */
  136. /* Register the semi-hosting driver with the IO abstraction */
  137. int register_io_dev_sh(const io_dev_connector_t **dev_con)
  138. {
  139. int result;
  140. assert(dev_con != NULL);
  141. result = io_register_device(&sh_dev_info);
  142. if (result == 0)
  143. *dev_con = &sh_dev_connector;
  144. return result;
  145. }