General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
4.2 KiB

  1. #pragma once
  2. #include <cstdint>
  3. #include <cstddef>
  4. #include <gp/containers/buffer.hpp>
  5. #if defined(__x86_64__)
  6. #if defined(__linux__)
  7. constexpr bool is_x86_64_linux = true;
  8. #else
  9. constexpr bool is_x86_64_linux = false;
  10. #endif
  11. #else
  12. constexpr bool is_x86_64_linux = false;
  13. #endif
  14. template<int64_t syscall_id, int arg_count>
  15. struct syscall;
  16. template<int64_t syscall_id>
  17. requires is_x86_64_linux
  18. struct syscall<syscall_id, 1> {
  19. int64_t operator()(int64_t p1) const {
  20. int64_t ret;
  21. asm volatile
  22. (
  23. "syscall"
  24. : "=a" (ret)
  25. : "0"(syscall_id), "D"(p1)
  26. : "rcx", "r11", "memory"
  27. );
  28. return ret;
  29. }
  30. };
  31. template<int64_t syscall_id>
  32. requires is_x86_64_linux
  33. struct syscall<syscall_id, 2> {
  34. int64_t operator()(int64_t p1,int64_t p2) const {
  35. int64_t ret;
  36. asm volatile
  37. (
  38. "syscall"
  39. : "=a" (ret)
  40. : "0"(syscall_id), "D"(p1), "S"(p2)
  41. : "rcx", "r11", "memory"
  42. );
  43. return ret;
  44. }
  45. };
  46. template<int64_t syscall_id>
  47. requires is_x86_64_linux
  48. struct syscall<syscall_id, 3> {
  49. int64_t operator()(int64_t p1,int64_t p2,int64_t p3) const {
  50. int64_t ret;
  51. asm volatile
  52. (
  53. "syscall"
  54. : "=a" (ret)
  55. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3)
  56. : "rcx", "r11", "memory"
  57. );
  58. return ret;
  59. }
  60. };
  61. template<int64_t syscall_id>
  62. requires is_x86_64_linux
  63. struct syscall<syscall_id, 4> {
  64. int64_t operator()(int64_t p1,int64_t p2,int64_t p3,int64_t p4) const {
  65. int64_t ret;
  66. register long r10 asm("r10") = p4;
  67. asm volatile
  68. (
  69. "syscall"
  70. : "=a" (ret)
  71. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10)
  72. : "rcx", "r11", "memory"
  73. );
  74. return ret;
  75. }
  76. };
  77. template<int64_t syscall_id>
  78. requires is_x86_64_linux
  79. struct syscall<syscall_id, 5> {
  80. int64_t operator()(int64_t p1,int64_t p2,int64_t p3,int64_t p4,int64_t p5) const {
  81. int64_t ret;
  82. register long r10 asm("r10") = p4;
  83. register long r8 asm("r8") = p5;
  84. asm volatile
  85. (
  86. "syscall"
  87. : "=a" (ret)
  88. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10), "r"(r8)
  89. : "rcx", "r11", "memory"
  90. );
  91. return ret;
  92. }
  93. };
  94. template<int64_t syscall_id>
  95. requires is_x86_64_linux
  96. struct syscall<syscall_id, 6> {
  97. int64_t operator()(int64_t p1,int64_t p2,int64_t p3,int64_t p4,int64_t p5,int64_t p6) const {
  98. int64_t ret;
  99. register long r10 asm("r10") = p4;
  100. register long r8 asm("r8") = p5;
  101. register long r9 asm("r9") = p6;
  102. asm volatile
  103. (
  104. "syscall"
  105. : "=a" (ret)
  106. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10), "r"(r8), "r"(r9)
  107. : "rcx", "r11", "memory"
  108. );
  109. return ret;
  110. }
  111. };
  112. constexpr auto _read = syscall<0, 3>{};
  113. constexpr auto _write = syscall<1, 3>{};
  114. constexpr auto _mmap = syscall<9, 6>{};
  115. constexpr auto _munmap = syscall<11, 2>{};
  116. constexpr auto _exit = syscall<60, 1>{};
  117. inline int read(int fd, char* buffer, size_t sz) {
  118. return _read((int64_t)fd, (int64_t)buffer, (int64_t)sz);
  119. }
  120. inline int write(int fd, char* buffer, size_t sz) {
  121. return _write((int64_t)fd, (int64_t)buffer, (int64_t)sz);
  122. }
  123. inline void* mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
  124. return (void*)_mmap((int64_t)addr, (int64_t)length, (int64_t)prot, (int64_t)flags, (int64_t)fd, (int64_t)offset);
  125. }
  126. inline int munmap(void *addr, size_t length) {
  127. return _munmap((int64_t)addr, (int64_t)length);
  128. }
  129. extern "C" {
  130. /// Yes, __attribute__((__noreturn__)), not [[noreturn]], because some God forsaken potato decided that those attributes are not the attributes I am looking for
  131. inline __attribute__ ((__noreturn__)) void exit(int status) {
  132. _exit((int64_t)status);
  133. while(true);
  134. }
  135. }
  136. inline int read(int fd, gp::buffer<char> buffer) {
  137. return _read((int64_t)fd, (int64_t)buffer.begin().data, (int64_t)buffer.size());
  138. }
  139. inline int write(int fd, gp::buffer<char> buffer) {
  140. return _write((int64_t)fd, (int64_t)buffer.begin().data, (int64_t)buffer.size());
  141. }