BVB Source Codes

xenia Show shim_utils.h Source code

Return Download xenia: download shim_utils.h Source code - Download xenia Source code - Type:.h
  1. /**
  2.  ******************************************************************************
  3.  * Xenia : Xbox 360 Emulator Research Project                                 *
  4.  ******************************************************************************
  5.  * Copyright 2013 Ben Vanik. All rights reserved.                             *
  6.  * Released under the BSD license - see LICENSE in the root for more details. *
  7.  ******************************************************************************
  8.  */
  9.  
  10. #ifndef XENIA_KERNEL_UTIL_SHIM_UTILS_H_
  11. #define XENIA_KERNEL_UTIL_SHIM_UTILS_H_
  12.  
  13. #include <gflags/gflags.h>
  14.  
  15. #include <cstring>
  16. #include <string>
  17.  
  18. #include "xenia/base/byte_order.h"
  19. #include "xenia/base/logging.h"
  20. #include "xenia/base/memory.h"
  21. #include "xenia/base/string_buffer.h"
  22. #include "xenia/cpu/export_resolver.h"
  23. #include "xenia/cpu/ppc/ppc_context.h"
  24. #include "xenia/kernel/kernel_state.h"
  25.  
  26. DECLARE_bool(log_high_frequency_kernel_calls);
  27.  
  28. namespace xe {
  29. namespace kernel {
  30.  
  31. using PPCContext = xe::cpu::ppc::PPCContext;
  32.  
  33. #define SHIM_CALL void __cdecl
  34. #define SHIM_SET_MAPPING(library_name, export_name, shim_data) \
  35.   export_resolver->SetFunctionMapping(                         \
  36.       library_name, ordinals::export_name,                     \
  37.       (xe::cpu::xe_kernel_export_shim_fn)export_name##_shim);
  38.  
  39. #define SHIM_MEM_BASE ppc_context->virtual_membase
  40. #define SHIM_MEM_ADDR(a) (a ? (ppc_context->virtual_membase + a) : nullptr)
  41.  
  42. #define SHIM_MEM_8(a) xe::load_and_swap<uint8_t>(SHIM_MEM_ADDR(a))
  43. #define SHIM_MEM_16(a) xe::load_and_swap<uint16_t>(SHIM_MEM_ADDR(a))
  44. #define SHIM_MEM_32(a) xe::load_and_swap<uint32_t>(SHIM_MEM_ADDR(a))
  45. #define SHIM_MEM_64(a) xe::load_and_swap<uint64_t>(SHIM_MEM_ADDR(a))
  46. #define SHIM_SET_MEM_8(a, v) xe::store_and_swap<uint8_t>(SHIM_MEM_ADDR(a), v)
  47. #define SHIM_SET_MEM_16(a, v) xe::store_and_swap<uint16_t>(SHIM_MEM_ADDR(a), v)
  48. #define SHIM_SET_MEM_32(a, v) xe::store_and_swap<uint32_t>(SHIM_MEM_ADDR(a), v)
  49. #define SHIM_SET_MEM_64(a, v) xe::store_and_swap<uint64_t>(SHIM_MEM_ADDR(a), v)
  50.  
  51. namespace util {
  52. inline uint32_t get_arg_stack_ptr(PPCContext* ppc_context, uint8_t index) {
  53.   return ((uint32_t)ppc_context->r[1]) + 0x54 + index * 8;
  54. }
  55.  
  56. inline uint8_t get_arg_8(PPCContext* ppc_context, uint8_t index) {
  57.   if (index <= 7) {
  58.     return (uint8_t)ppc_context->r[3 + index];
  59.   }
  60.   uint32_t stack_address = get_arg_stack_ptr(ppc_context, index - 8);
  61.   return SHIM_MEM_8(stack_address);
  62. }
  63.  
  64. inline uint16_t get_arg_16(PPCContext* ppc_context, uint8_t index) {
  65.   if (index <= 7) {
  66.     return (uint16_t)ppc_context->r[3 + index];
  67.   }
  68.   uint32_t stack_address = get_arg_stack_ptr(ppc_context, index - 8);
  69.   return SHIM_MEM_16(stack_address);
  70. }
  71.  
  72. inline uint32_t get_arg_32(PPCContext* ppc_context, uint8_t index) {
  73.   if (index <= 7) {
  74.     return (uint32_t)ppc_context->r[3 + index];
  75.   }
  76.   uint32_t stack_address = get_arg_stack_ptr(ppc_context, index - 8);
  77.   return SHIM_MEM_32(stack_address);
  78. }
  79.  
  80. inline uint64_t get_arg_64(PPCContext* ppc_context, uint8_t index) {
  81.   if (index <= 7) {
  82.     return ppc_context->r[3 + index];
  83.   }
  84.   uint32_t stack_address = get_arg_stack_ptr(ppc_context, index - 8);
  85.   return SHIM_MEM_64(stack_address);
  86. }
  87. }  // namespace util
  88.  
  89. #define SHIM_GET_ARG_8(n) util::get_arg_8(ppc_context, n)
  90. #define SHIM_GET_ARG_16(n) util::get_arg_16(ppc_context, n)
  91. #define SHIM_GET_ARG_32(n) util::get_arg_32(ppc_context, n)
  92. #define SHIM_GET_ARG_64(n) util::get_arg_64(ppc_context, n)
  93. #define SHIM_SET_RETURN_32(v) ppc_context->r[3] = (uint64_t)((int32_t)v)
  94.  
  95. #define SHIM_STRUCT(type, address) \
  96.   reinterpret_cast<type*>(SHIM_MEM_ADDR(address))
  97.  
  98. namespace shim {
  99.  
  100. class Param {
  101.  public:
  102.   struct Init {
  103.     PPCContext* ppc_context;
  104.     int ordinal;
  105.     int float_ordinal;
  106.   };
  107.  
  108.   Param& operator=(const Param&) = delete;
  109.  
  110.   int ordinal() const { return ordinal_; }
  111.  
  112.  protected:
  113.   Param() : ordinal_(-1) {}
  114.   explicit Param(Init& init) : ordinal_(--init.ordinal) {}
  115.  
  116.   template <typename V>
  117.   void LoadValue(Init& init, V* out_value) {
  118.     if (ordinal_ <= 7) {
  119.       *out_value = V(init.ppc_context->r[3 + ordinal_]);
  120.     } else {
  121.       uint32_t stack_ptr =
  122.           uint32_t(init.ppc_context->r[1]) + 0x54 + (ordinal_ - 8) * 8;
  123.       *out_value =
  124.           xe::load_and_swap<V>(init.ppc_context->virtual_membase + stack_ptr);
  125.     }
  126.   }
  127.  
  128.   int ordinal_;
  129. };
  130. template <>
  131. inline void Param::LoadValue<float>(Param::Init& init, float* out_value) {
  132.   *out_value =
  133.       static_cast<float>(init.ppc_context->f[1 + ++init.float_ordinal]);
  134. }
  135. template <>
  136. inline void Param::LoadValue<double>(Param::Init& init, double* out_value) {
  137.   *out_value = init.ppc_context->f[1 + ++init.float_ordinal];
  138. }
  139. template <typename T>
  140. class ParamBase : public Param {
  141.  public:
  142.   ParamBase() : Param(), value_(0) {}
  143.   ParamBase(T value) : Param(), value_(value) {}
  144.   ParamBase(Init& init) : Param(init) { LoadValue<T>(init, &value_); }
  145.   ParamBase& operator=(const T& other) {
  146.     value_ = other;
  147.     return *this;
  148.   }
  149.   operator T() const { return value_; }
  150.   T value() const { return value_; }
  151.  
  152.  protected:
  153.   T value_;
  154. };
  155.  
  156. class PointerParam : public ParamBase<uint32_t> {
  157.  public:
  158.   PointerParam(Init& init) : ParamBase(init) {
  159.     host_ptr_ = value_ ? init.ppc_context->virtual_membase + value_ : nullptr;
  160.   }
  161.   PointerParam(void* host_ptr) : ParamBase(), host_ptr_(host_ptr) {}
  162.   PointerParam& operator=(void*& other) {
  163.     host_ptr_ = other;
  164.     return *this;
  165.   }
  166.   uint32_t guest_address() const { return value_; }
  167.   uintptr_t host_address() const {
  168.     return reinterpret_cast<uintptr_t>(host_ptr_);
  169.   }
  170.   template <typename T>
  171.   T as() const {
  172.     return reinterpret_cast<T>(host_ptr_);
  173.   }
  174.   template <typename T>
  175.   xe::be<T>* as_array() const {
  176.     return reinterpret_cast<xe::be<T>*>(host_ptr_);
  177.   }
  178.   operator void*() const { return host_ptr_; }
  179.   operator uint8_t*() const { return reinterpret_cast<uint8_t*>(host_ptr_); }
  180.   operator bool() const { return host_ptr_ != nullptr; }
  181.   void* operator+(int offset) const {
  182.     return reinterpret_cast<uint8_t*>(host_ptr_) + offset;
  183.   }
  184.   void Zero(size_t size) const {
  185.     assert_not_null(host_ptr_);
  186.     std::memset(host_ptr_, 0, size);
  187.   }
  188.  
  189.  protected:
  190.   void* host_ptr_;
  191. };
  192.  
  193. template <typename T>
  194. class PrimitivePointerParam : public ParamBase<uint32_t> {
  195.  public:
  196.   PrimitivePointerParam(Init& init) : ParamBase(init) {
  197.     host_ptr_ = value_ ? reinterpret_cast<xe::be<T>*>(
  198.                              init.ppc_context->virtual_membase + value_)
  199.                        : nullptr;
  200.   }
  201.   PrimitivePointerParam(T* host_ptr) : ParamBase() {
  202.     host_ptr_ = reinterpret_cast<xe::be<T>*>(host_ptr);
  203.   }
  204.   PrimitivePointerParam& operator=(const T*& other) {
  205.     host_ptr_ = other;
  206.     return *this;
  207.   }
  208.   uint32_t guest_address() const { return value_; }
  209.   uintptr_t host_address() const {
  210.     return reinterpret_cast<uintptr_t>(host_ptr_);
  211.   }
  212.   T value() const { return *host_ptr_; }
  213.   operator T() const { return *host_ptr_; }
  214.   operator xe::be<T>*() const { return host_ptr_; }
  215.   operator bool() const { return host_ptr_ != nullptr; }
  216.   void Zero() const {
  217.     assert_not_null(host_ptr_);
  218.     *host_ptr_ = 0;
  219.   }
  220.  
  221.  protected:
  222.   xe::be<T>* host_ptr_;
  223. };
  224.  
  225. template <typename CHAR, typename STR>
  226. class StringPointerParam : public ParamBase<uint32_t> {
  227.  public:
  228.   StringPointerParam(Init& init) : ParamBase(init) {
  229.     host_ptr_ = value_ ? reinterpret_cast<CHAR*>(
  230.                              init.ppc_context->virtual_membase + value_)
  231.                        : nullptr;
  232.   }
  233.   StringPointerParam(CHAR* host_ptr) : ParamBase(), host_ptr_(host_ptr) {}
  234.   StringPointerParam& operator=(const CHAR*& other) {
  235.     host_ptr_ = other;
  236.     return *this;
  237.   }
  238.   uint32_t guest_address() const { return value_; }
  239.   uintptr_t host_address() const {
  240.     return reinterpret_cast<uintptr_t>(host_ptr_);
  241.   }
  242.   STR value() const { return xe::load_and_swap<STR>(host_ptr_); }
  243.   operator CHAR*() const { return host_ptr_; }
  244.   operator bool() const { return host_ptr_ != nullptr; }
  245.  
  246.  protected:
  247.   CHAR* host_ptr_;
  248. };
  249.  
  250. template <typename T>
  251. class TypedPointerParam : public ParamBase<uint32_t> {
  252.  public:
  253.   TypedPointerParam(Init& init) : ParamBase(init) {
  254.     host_ptr_ =
  255.         value_
  256.             ? reinterpret_cast<T*>(init.ppc_context->virtual_membase + value_)
  257.             : nullptr;
  258.   }
  259.   TypedPointerParam(T* host_ptr) : ParamBase(), host_ptr_(host_ptr) {}
  260.   TypedPointerParam& operator=(const T*& other) {
  261.     host_ptr_ = other;
  262.     return *this;
  263.   }
  264.   uint32_t guest_address() const { return value_; }
  265.   uintptr_t host_address() const {
  266.     return reinterpret_cast<uintptr_t>(host_ptr_);
  267.   }
  268.   operator T*() const { return host_ptr_; }
  269.   operator bool() const { return host_ptr_ != nullptr; }
  270.   T* operator->() const {
  271.     assert_not_null(host_ptr_);
  272.     return host_ptr_;
  273.   }
  274.   void Zero() const {
  275.     assert_not_null(host_ptr_);
  276.     std::memset(host_ptr_, 0, sizeof(T));
  277.   }
  278.  
  279.  protected:
  280.   T* host_ptr_;
  281. };
  282.  
  283. template <typename T>
  284. class Result {
  285.  public:
  286.   Result(T value) : value_(value) {}
  287.   void Store(PPCContext* ppc_context) {
  288.     ppc_context->r[3] = uint64_t(int32_t(value_));
  289.   }
  290.   Result() = delete;
  291.   Result& operator=(const Result&) = delete;
  292.   operator T() const { return value_; }
  293.  
  294.  private:
  295.   T value_;
  296. };
  297.  
  298. }  // namespace shim
  299.  
  300. using int_t = const shim::ParamBase<int32_t>&;
  301. using word_t = const shim::ParamBase<uint16_t>&;
  302. using dword_t = const shim::ParamBase<uint32_t>&;
  303. using qword_t = const shim::ParamBase<uint64_t>&;
  304. using float_t = const shim::ParamBase<float>&;
  305. using double_t = const shim::ParamBase<double>&;
  306. using lpvoid_t = const shim::PointerParam&;
  307. using lpword_t = const shim::PrimitivePointerParam<uint16_t>&;
  308. using lpdword_t = const shim::PrimitivePointerParam<uint32_t>&;
  309. using lpqword_t = const shim::PrimitivePointerParam<uint64_t>&;
  310. using lpfloat_t = const shim::PrimitivePointerParam<float>&;
  311. using lpdouble_t = const shim::PrimitivePointerParam<double>&;
  312. using lpstring_t = const shim::StringPointerParam<char, std::string>&;
  313. using lpwstring_t = const shim::StringPointerParam<wchar_t, std::wstring>&;
  314. using function_t = const shim::ParamBase<uint32_t>&;
  315. using unknown_t = const shim::ParamBase<uint32_t>&;
  316. using lpunknown_t = const shim::PointerParam&;
  317. template <typename T>
  318. using pointer_t = const shim::TypedPointerParam<T>&;
  319.  
  320. using int_result_t = shim::Result<int32_t>;
  321. using dword_result_t = shim::Result<uint32_t>;
  322. using pointer_result_t = shim::Result<uint32_t>;
  323.  
  324. // Exported from kernel_state.cc.
  325. KernelState* kernel_state();
  326. inline Memory* kernel_memory() { return kernel_state()->memory(); }
  327.  
  328. namespace shim {
  329.  
  330. inline void AppendParam(StringBuffer* string_buffer, int_t param) {
  331.   string_buffer->AppendFormat("%d", int32_t(param));
  332. }
  333. inline void AppendParam(StringBuffer* string_buffer, word_t param) {
  334.   string_buffer->AppendFormat("%.4X", uint16_t(param));
  335. }
  336. inline void AppendParam(StringBuffer* string_buffer, dword_t param) {
  337.   string_buffer->AppendFormat("%.8X", uint32_t(param));
  338. }
  339. inline void AppendParam(StringBuffer* string_buffer, qword_t param) {
  340.   string_buffer->AppendFormat("%.16llX", uint64_t(param));
  341. }
  342. inline void AppendParam(StringBuffer* string_buffer, float_t param) {
  343.   string_buffer->AppendFormat("%G", static_cast<float>(param));
  344. }
  345. inline void AppendParam(StringBuffer* string_buffer, double_t param) {
  346.   string_buffer->AppendFormat("%G", static_cast<double>(param));
  347. }
  348. inline void AppendParam(StringBuffer* string_buffer, lpvoid_t param) {
  349.   string_buffer->AppendFormat("%.8X", uint32_t(param));
  350. }
  351. inline void AppendParam(StringBuffer* string_buffer, lpdword_t param) {
  352.   string_buffer->AppendFormat("%.8X", param.guest_address());
  353.   if (param) {
  354.     string_buffer->AppendFormat("(%.8X)", param.value());
  355.   }
  356. }
  357. inline void AppendParam(StringBuffer* string_buffer, lpqword_t param) {
  358.   string_buffer->AppendFormat("%.8X", param.guest_address());
  359.   if (param) {
  360.     string_buffer->AppendFormat("(%.16llX)", param.value());
  361.   }
  362. }
  363. inline void AppendParam(StringBuffer* string_buffer, lpfloat_t param) {
  364.   string_buffer->AppendFormat("%.8X", param.guest_address());
  365.   if (param) {
  366.     string_buffer->AppendFormat("(%G)", param.value());
  367.   }
  368. }
  369. inline void AppendParam(StringBuffer* string_buffer, lpdouble_t param) {
  370.   string_buffer->AppendFormat("%.8X", param.guest_address());
  371.   if (param) {
  372.     string_buffer->AppendFormat("(%G)", param.value());
  373.   }
  374. }
  375. inline void AppendParam(StringBuffer* string_buffer, lpstring_t param) {
  376.   string_buffer->AppendFormat("%.8X", param.guest_address());
  377.   if (param) {
  378.     string_buffer->AppendFormat("(%s)", param.value().c_str());
  379.   }
  380. }
  381. inline void AppendParam(StringBuffer* string_buffer, lpwstring_t param) {
  382.   string_buffer->AppendFormat("%.8X", param.guest_address());
  383.   if (param) {
  384.     string_buffer->AppendFormat("(%S)", param.value().c_str());
  385.   }
  386. }
  387. inline void AppendParam(StringBuffer* string_buffer,
  388.                         pointer_t<X_OBJECT_ATTRIBUTES> record) {
  389.   string_buffer->AppendFormat("%.8X", record.guest_address());
  390.   if (record) {
  391.     auto name_string =
  392.         kernel_memory()->TranslateVirtual<X_ANSI_STRING*>(record->name_ptr);
  393.     std::string name =
  394.         name_string == nullptr
  395.             ? "(null)"
  396.             : name_string->to_string(kernel_memory()->virtual_membase());
  397.     string_buffer->AppendFormat("(%.8X,%s,%.8X)",
  398.                                 uint32_t(record->root_directory), name.c_str(),
  399.                                 uint32_t(record->attributes));
  400.   }
  401. }
  402. inline void AppendParam(StringBuffer* string_buffer,
  403.                         pointer_t<X_EX_TITLE_TERMINATE_REGISTRATION> reg) {
  404.   string_buffer->AppendFormat("%.8X(%.8X, %.8X)", reg.guest_address(),
  405.                               static_cast<uint32_t>(reg->notification_routine),
  406.                               static_cast<uint32_t>(reg->priority));
  407. }
  408. inline void AppendParam(StringBuffer* string_buffer,
  409.                         pointer_t<X_EXCEPTION_RECORD> record) {
  410.   string_buffer->AppendFormat("%.8X(%.8X)", record.guest_address(),
  411.                               uint32_t(record->exception_code));
  412. }
  413. template <typename T>
  414. void AppendParam(StringBuffer* string_buffer, pointer_t<T> param) {
  415.   string_buffer->AppendFormat("%.8X", param.guest_address());
  416. }
  417.  
  418. enum class KernelModuleId {
  419.   xboxkrnl,
  420.   xam,
  421.   xbdm,
  422. };
  423.  
  424. template <size_t I = 0, typename... Ps>
  425. typename std::enable_if<I == sizeof...(Ps)>::type AppendKernelCallParams(
  426.     StringBuffer& string_buffer, xe::cpu::Export* export_entry,
  427.     const std::tuple<Ps...>&) {}
  428.  
  429. template <size_t I = 0, typename... Ps>
  430.     typename std::enable_if <
  431.     I<sizeof...(Ps)>::type AppendKernelCallParams(
  432.         StringBuffer& string_buffer, xe::cpu::Export* export_entry,
  433.         const std::tuple<Ps...>& params) {
  434.   if (I) {
  435.     string_buffer.Append(", ");
  436.   }
  437.   auto param = std::get<I>(params);
  438.   AppendParam(&string_buffer, param);
  439.   AppendKernelCallParams<I + 1>(string_buffer, export_entry, params);
  440. }
  441.  
  442. StringBuffer* thread_local_string_buffer();
  443.  
  444. template <typename Tuple>
  445. void PrintKernelCall(cpu::Export* export_entry, const Tuple& params) {
  446.   auto& string_buffer = *thread_local_string_buffer();
  447.   string_buffer.Reset();
  448.   string_buffer.Append(export_entry->name);
  449.   string_buffer.Append('(');
  450.   AppendKernelCallParams(string_buffer, export_entry, params);
  451.   string_buffer.Append(')');
  452.   if (export_entry->tags & xe::cpu::ExportTag::kImportant) {
  453.     xe::LogLine('i', string_buffer.GetString(), string_buffer.length());
  454.   } else {
  455.     xe::LogLine('d', string_buffer.GetString(), string_buffer.length());
  456.   }
  457. }
  458.  
  459. template <typename F, typename Tuple, std::size_t... I>
  460. auto KernelTrampoline(F&& f, Tuple&& t, std::index_sequence<I...>) {
  461.   return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
  462. }
  463.  
  464. template <KernelModuleId MODULE, uint16_t ORDINAL, typename R, typename... Ps>
  465. xe::cpu::Export* RegisterExport(R (*fn)(Ps&...), const char* name,
  466.                                 xe::cpu::ExportTag::type tags) {
  467.   static const auto export_entry = new cpu::Export(
  468.       ORDINAL, xe::cpu::Export::Type::kFunction, name,
  469.       tags | xe::cpu::ExportTag::kImplemented | xe::cpu::ExportTag::kLog);
  470.   static R (*FN)(Ps & ...) = fn;
  471.   struct X {
  472.     static void Trampoline(PPCContext* ppc_context) {
  473.       ++export_entry->function_data.call_count;
  474.       Param::Init init = {
  475.           ppc_context, sizeof...(Ps), 0,
  476.       };
  477.       auto params = std::make_tuple<Ps...>(Ps(init)...);
  478.       if (export_entry->tags & xe::cpu::ExportTag::kLog &&
  479.           (!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) ||
  480.            FLAGS_log_high_frequency_kernel_calls)) {
  481.         PrintKernelCall(export_entry, params);
  482.       }
  483.       auto result =
  484.           KernelTrampoline(FN, std::forward<std::tuple<Ps...>>(params),
  485.                            std::make_index_sequence<sizeof...(Ps)>());
  486.       result.Store(ppc_context);
  487.       if (export_entry->tags &
  488.           (xe::cpu::ExportTag::kLog | xe::cpu::ExportTag::kLogResult)) {
  489.         // TODO(benvanik): log result.
  490.       }
  491.     }
  492.   };
  493.   export_entry->function_data.trampoline = &X::Trampoline;
  494.   return export_entry;
  495. }
  496.  
  497. template <KernelModuleId MODULE, uint16_t ORDINAL, typename... Ps>
  498. xe::cpu::Export* RegisterExport(void (*fn)(Ps&...), const char* name,
  499.                                 xe::cpu::ExportTag::type tags) {
  500.   static const auto export_entry = new cpu::Export(
  501.       ORDINAL, xe::cpu::Export::Type::kFunction, name,
  502.       tags | xe::cpu::ExportTag::kImplemented | xe::cpu::ExportTag::kLog);
  503.   static void (*FN)(Ps & ...) = fn;
  504.   struct X {
  505.     static void Trampoline(PPCContext* ppc_context) {
  506.       ++export_entry->function_data.call_count;
  507.       Param::Init init = {
  508.           ppc_context, sizeof...(Ps),
  509.       };
  510.       auto params = std::make_tuple<Ps...>(Ps(init)...);
  511.       if (export_entry->tags & xe::cpu::ExportTag::kLog &&
  512.           (!(export_entry->tags & xe::cpu::ExportTag::kHighFrequency) ||
  513.            FLAGS_log_high_frequency_kernel_calls)) {
  514.         PrintKernelCall(export_entry, params);
  515.       }
  516.       KernelTrampoline(FN, std::forward<std::tuple<Ps...>>(params),
  517.                        std::make_index_sequence<sizeof...(Ps)>());
  518.     }
  519.   };
  520.   export_entry->function_data.trampoline = &X::Trampoline;
  521.   return export_entry;
  522. }
  523.  
  524. }  // namespace shim
  525.  
  526. using xe::cpu::ExportTag;
  527.  
  528. #define DECLARE_EXPORT(module_name, name, tags)                            \
  529.   const auto EXPORT_##module_name##_##name = RegisterExport_##module_name( \
  530.       xe::kernel::shim::RegisterExport<                                    \
  531.           xe::kernel::shim::KernelModuleId::module_name, ordinals::name>(  \
  532.           &name, #name, tags));
  533.  
  534. #define DECLARE_XAM_EXPORT(name, tags) DECLARE_EXPORT(xam, name, tags)
  535. #define DECLARE_XBDM_EXPORT(name, tags) DECLARE_EXPORT(xbdm, name, tags)
  536. #define DECLARE_XBOXKRNL_EXPORT(name, tags) DECLARE_EXPORT(xboxkrnl, name, tags)
  537.  
  538. }  // namespace kernel
  539. }  // namespace xe
  540.  
  541. #endif  // XENIA_KERNEL_UTIL_SHIM_UTILS_H_
  542.  
downloadshim_utils.h Source code - Download xenia Source code
Related Source Codes/Software:
flux-comparison - 2017-02-18
luvit - Lua + libUV + jIT = pure awesomesauce ... 2017-02-18
orleans - Orleans - Distributed Virtual Actor Model ... 2017-02-18
gemoji - Emoji images and names. 2017-02-18
gruvbox - Retro groove color scheme for Vim 2017-02-18
pydata-book - Materials and IPython notebooks for "Python for Da... 2017-02-19
angular-http-auth - 2017-02-19
BGARefreshLayout-Android - On a variety of drop-down refresh effect, loading ... 2017-02-19
MRProgress - Collection of iOS drop-in components to visualize ... 2017-02-19
OptiKey - OptiKey - Full computer control and speech with yo... 2017-02-19
dirtycow.github.io - Dirty COW https://dirtycow.... 2017-04-11
server-configs-apache - Apache HTTP server boilerplate config 2017-04-11
hubot-slack - Slack Developer Kit for Hubot ... 2017-04-11
tyk - Tyk Open Source API Gateway written in Go 2017-04-11
edward - A library for probabilistic modeling, inference, a... 2017-04-11
extract-text-webpack-plugin - Extract text from the bundle into a file. 2017-04-11
webdis - A Redis HTTP interface with JSON output ... 2017-04-11
password_compat - Compatibility with the password_* functions that s... 2017-04-11
gitflow-avh - AVH Edition of the git extensions to dojo.provide ... 2017-04-11
Core-Data-Editor - Core Data Editor lets you easily view, edit and an... 2017-04-11

 Back to top