summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-01-06 01:25:58 +1100
committer Vas Crabb <vas@vastheman.com>2021-01-06 02:18:04 +1100
commit4eca05fe67e6a61a30af9d168590f3f3aaf9f639 (patch)
tree8ca9d1878d84d54ffaa11d0bafe43ea28b638f33
parent7b22d972aea2dca442de9b8fb58687504e4444bc (diff)
cpu: Allow recompilers to work with W^X policy
-rw-r--r--scripts/resources/windows/mame/mame.man2
-rw-r--r--scripts/resources/windows/mess/mess.man2
-rw-r--r--src/devices/cpu/drcbeut.cpp2
-rw-r--r--src/devices/cpu/drccache.cpp155
-rw-r--r--src/devices/cpu/drccache.h50
-rw-r--r--src/devices/cpu/drcuml.cpp2
-rw-r--r--src/osd/modules/lib/osdlib.h88
-rw-r--r--src/osd/modules/lib/osdlib_macosx.cpp131
-rw-r--r--src/osd/modules/lib/osdlib_unix.cpp134
-rw-r--r--src/osd/modules/lib/osdlib_uwp.cpp85
-rw-r--r--src/osd/modules/lib/osdlib_win32.cpp117
-rw-r--r--src/osd/osdcore.h21
12 files changed, 476 insertions, 313 deletions
diff --git a/scripts/resources/windows/mame/mame.man b/scripts/resources/windows/mame/mame.man
index 85e0f31644e..cd2705c8886 100644
--- a/scripts/resources/windows/mame/mame.man
+++ b/scripts/resources/windows/mame/mame.man
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="MAME" type="win32" />
<description>MAME</description>
<dependency>
diff --git a/scripts/resources/windows/mess/mess.man b/scripts/resources/windows/mess/mess.man
index 4856b147be1..d03a874f8fb 100644
--- a/scripts/resources/windows/mess/mess.man
+++ b/scripts/resources/windows/mess/mess.man
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="MESS" type="win32" />
<description>MESS</description>
<dependency>
diff --git a/src/devices/cpu/drcbeut.cpp b/src/devices/cpu/drcbeut.cpp
index bf49969ca06..ce7cf527e3c 100644
--- a/src/devices/cpu/drcbeut.cpp
+++ b/src/devices/cpu/drcbeut.cpp
@@ -501,7 +501,7 @@ drccodeptr drc_label_list::get_codeptr(uml::code_label label, drc_label_fixup_de
label_fixup *fixup = reinterpret_cast<label_fixup *>(m_cache.alloc(sizeof(*fixup)));
new (fixup) label_fixup{ nullptr, curlabel, callback };
m_fixup_list.append(*fixup);
- m_cache.request_oob_codegen(m_oob_callback_delegate, fixup, param);
+ m_cache.request_oob_codegen(drc_oob_delegate(m_oob_callback_delegate), fixup, param);
}
return curlabel->m_codeptr;
diff --git a/src/devices/cpu/drccache.cpp b/src/devices/cpu/drccache.cpp
index fc86fd37cc6..4a41cdcddb0 100644
--- a/src/devices/cpu/drccache.cpp
+++ b/src/devices/cpu/drccache.cpp
@@ -11,15 +11,22 @@
#include "emu.h"
#include "drccache.h"
+#include <algorithm>
-//**************************************************************************
-// MACROS
-//**************************************************************************
+namespace {
-// ensure that all memory allocated is aligned to an 8-byte boundary
-#define ALIGN_PTR_UP(p) ((void *)(((uintptr_t)(p) + (CACHE_ALIGNMENT - 1)) & ~(CACHE_ALIGNMENT - 1)))
-#define ALIGN_PTR_DOWN(p) ((void *)((uintptr_t)(p) & ~(CACHE_ALIGNMENT - 1)))
+template <typename T, typename U> constexpr T *ALIGN_PTR_UP(T *p, U align)
+{
+ return reinterpret_cast<T *>((uintptr_t(p) + (align - 1)) & ~uintptr_t(align - 1));
+}
+
+template <typename T, typename U> constexpr T *ALIGN_PTR_DOWN(T *p, U align)
+{
+ return reinterpret_cast<T *>(uintptr_t(p) & ~uintptr_t(align - 1));
+}
+
+} // anonymous namespace
@@ -31,17 +38,27 @@
// drc_cache - constructor
//-------------------------------------------------
-drc_cache::drc_cache(size_t bytes)
- : m_near((drccodeptr)osd_alloc_executable(bytes)),
- m_neartop(m_near),
- m_base(m_near + NEAR_CACHE_SIZE),
- m_top(m_base),
- m_end(m_near + bytes),
- m_codegen(nullptr),
- m_size(bytes)
+drc_cache::drc_cache(size_t bytes) :
+ m_cache({ NEAR_CACHE_SIZE, bytes - NEAR_CACHE_SIZE }),
+ m_near(reinterpret_cast<drccodeptr>(m_cache.get())),
+ m_neartop(m_near),
+ m_base(ALIGN_PTR_UP(m_near + NEAR_CACHE_SIZE, m_cache.page_size())),
+ m_top(m_base),
+ m_limit(m_near + m_cache.size()),
+ m_end(m_limit),
+ m_codegen(nullptr),
+ m_size(m_cache.size())
{
- memset(m_free, 0, sizeof(m_free));
- memset(m_nearfree, 0, sizeof(m_nearfree));
+ // alignment and page size must be powers of two, cache must be page-aligned
+ assert(!(CACHE_ALIGNMENT & (CACHE_ALIGNMENT - 1)));
+ assert(!(m_cache.page_size() & (m_cache.page_size() - 1)));
+ assert(!(uintptr_t(m_near) & (m_cache.page_size() - 1)));
+ assert(m_cache.page_size() >= CACHE_ALIGNMENT);
+
+ std::fill(std::begin(m_free), std::end(m_free), nullptr);
+ std::fill(std::begin(m_nearfree), std::end(m_nearfree), nullptr);
+
+ m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
}
@@ -51,8 +68,6 @@ drc_cache::drc_cache(size_t bytes)
drc_cache::~drc_cache()
{
- // release the memory
- osd_free_executable(m_near, m_size);
}
@@ -64,10 +79,11 @@ drc_cache::~drc_cache()
void drc_cache::flush()
{
// can't flush in the middle of codegen
- assert(m_codegen == nullptr);
+ assert(!m_codegen);
// just reset the top back to the base and re-seed
m_top = m_base;
+ m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
}
@@ -83,9 +99,9 @@ void *drc_cache::alloc(size_t bytes)
// pick first from the free list
if (bytes < MAX_PERMANENT_ALLOC)
{
- free_link **linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
- free_link *link = *linkptr;
- if (link != nullptr)
+ free_link **const linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
+ free_link *const link = *linkptr;
+ if (link)
{
*linkptr = link->m_next;
return link;
@@ -93,11 +109,13 @@ void *drc_cache::alloc(size_t bytes)
}
// if no space, we just fail
- drccodeptr ptr = (drccodeptr)ALIGN_PTR_DOWN(m_end - bytes);
- if (m_top > ptr)
+ drccodeptr const ptr = ALIGN_PTR_DOWN(m_end - bytes, CACHE_ALIGNMENT);
+ drccodeptr const limit = ALIGN_PTR_DOWN(ptr, m_cache.page_size());
+ if (m_top > limit)
return nullptr;
// otherwise update the end of the cache
+ m_limit = limit;
m_end = ptr;
return ptr;
}
@@ -115,9 +133,9 @@ void *drc_cache::alloc_near(size_t bytes)
// pick first from the free list
if (bytes < MAX_PERMANENT_ALLOC)
{
- free_link **linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
- free_link *link = *linkptr;
- if (link != nullptr)
+ free_link **const linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
+ free_link *const link = *linkptr;
+ if (link)
{
*linkptr = link->m_next;
return link;
@@ -125,8 +143,8 @@ void *drc_cache::alloc_near(size_t bytes)
}
// if no space, we just fail
- drccodeptr ptr = (drccodeptr)ALIGN_PTR_UP(m_neartop);
- if (ptr + bytes > m_base)
+ drccodeptr const ptr = ALIGN_PTR_UP(m_neartop, CACHE_ALIGNMENT);
+ if ((ptr + bytes) > m_base)
return nullptr;
// otherwise update the top of the near part of the cache
@@ -143,15 +161,16 @@ void *drc_cache::alloc_near(size_t bytes)
void *drc_cache::alloc_temporary(size_t bytes)
{
// can't allocate in the middle of codegen
- assert(m_codegen == nullptr);
+ assert(!m_codegen);
// if no space, we just fail
- drccodeptr ptr = m_top;
- if (ptr + bytes >= m_end)
+ drccodeptr const ptr = m_top;
+ if ((ptr + bytes) > m_limit)
return nullptr;
// otherwise, update the cache top
- m_top = (drccodeptr)ALIGN_PTR_UP(ptr + bytes);
+ m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
+ m_top = ALIGN_PTR_UP(ptr + bytes, CACHE_ALIGNMENT);
return ptr;
}
@@ -163,23 +182,32 @@ void *drc_cache::alloc_temporary(size_t bytes)
void drc_cache::dealloc(void *memory, size_t bytes)
{
+ drccodeptr const mem = reinterpret_cast<drccodeptr>(memory);
assert(bytes < MAX_PERMANENT_ALLOC);
- assert(((drccodeptr)memory >= m_near && (drccodeptr)memory < m_base) || ((drccodeptr)memory >= m_end && (drccodeptr)memory < m_near + m_size));
+ assert(((mem >= m_near) && (mem < m_base)) || ((mem >= m_end) && (mem < (m_near + m_size))));
// determine which free list to add to
- free_link **linkptr;
- if ((drccodeptr)memory < m_base)
- linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
- else
- linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
+ free_link **const linkptr = &((mem < m_base) ? m_nearfree : m_free)[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT];
// link is into the free list for our size
- free_link *link = (free_link *)memory;
+ free_link *const link = reinterpret_cast<free_link *>(memory);
link->m_next = *linkptr;
*linkptr = link;
}
+void drc_cache::codegen_init()
+{
+ m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
+}
+
+
+void drc_cache::codegen_complete()
+{
+ m_cache.set_access(m_base - m_near, ALIGN_PTR_UP(m_top, m_cache.page_size()) - m_base, osd::virtual_memory_allocation::READ_EXECUTE);
+}
+
+
//-------------------------------------------------
// begin_codegen - begin code generation
//-------------------------------------------------
@@ -187,15 +215,15 @@ void drc_cache::dealloc(void *memory, size_t bytes)
drccodeptr *drc_cache::begin_codegen(uint32_t reserve_bytes)
{
// can't restart in the middle of codegen
- assert(m_codegen == nullptr);
- assert(m_ooblist.first() == nullptr);
+ assert(!m_codegen);
+ assert(m_oob_list.empty());
- // if still no space, we just fail
- drccodeptr ptr = m_top;
- if (ptr + reserve_bytes >= m_end)
+ // if no space, we just fail
+ if ((m_top + reserve_bytes) > m_limit)
return nullptr;
// otherwise, return a pointer to the cache top
+ m_cache.set_access(0, m_size, osd::virtual_memory_allocation::READ_WRITE);
m_codegen = m_top;
return &m_top;
}
@@ -207,23 +235,22 @@ drccodeptr *drc_cache::begin_codegen(uint32_t reserve_bytes)
drccodeptr drc_cache::end_codegen()
{
- drccodeptr result = m_codegen;
+ drccodeptr const result = m_codegen;
// run the OOB handlers
- oob_handler *oob;
- while ((oob = m_ooblist.detach_head()) != nullptr)
+ while (!m_oob_list.empty())
{
// call the callback
- oob->m_callback(&m_top, oob->m_param1, oob->m_param2);
- assert(m_top - m_codegen < CODEGEN_MAX_BYTES);
+ m_oob_list.front().m_callback(&m_top, m_oob_list.front().m_param1, m_oob_list.front().m_param2);
+ assert((m_top - m_codegen) < CODEGEN_MAX_BYTES);
- // release our memory
- oob->~oob_handler();
- dealloc(oob, sizeof(*oob));
+ // add it to the free list
+ m_oob_free.splice(m_oob_free.begin(), m_oob_list, m_oob_list.begin());
}
// update the cache top
- m_top = (drccodeptr)ALIGN_PTR_UP(m_top);
+ osd::invalidate_instruction_cache(m_codegen, m_top - m_codegen);
+ m_top = ALIGN_PTR_UP(m_top, CACHE_ALIGNMENT);
m_codegen = nullptr;
return result;
@@ -235,20 +262,24 @@ drccodeptr drc_cache::end_codegen()
// out-of-band codegen
//-------------------------------------------------
-void drc_cache::request_oob_codegen(drc_oob_delegate callback, void *param1, void *param2)
+void drc_cache::request_oob_codegen(drc_oob_delegate &&callback, void *param1, void *param2)
{
- assert(m_codegen != nullptr);
+ assert(m_codegen);
// pull an item from the free list
- oob_handler *oob = (oob_handler *)alloc(sizeof(*oob));
- assert(oob != nullptr);
- new (oob) oob_handler();
+ std::list<oob_handler>::iterator oob;
+ if (m_oob_free.empty())
+ {
+ oob = m_oob_list.emplace(m_oob_list.end());
+ }
+ else
+ {
+ oob = m_oob_free.begin();
+ m_oob_list.splice(m_oob_list.end(), m_oob_free, oob);
+ }
// fill it in
oob->m_callback = std::move(callback);
oob->m_param1 = param1;
oob->m_param2 = param2;
-
- // add to the tail
- m_ooblist.append(*oob);
}
diff --git a/src/devices/cpu/drccache.h b/src/devices/cpu/drccache.h
index bbbcf62af63..07b0f847b81 100644
--- a/src/devices/cpu/drccache.h
+++ b/src/devices/cpu/drccache.h
@@ -7,12 +7,12 @@
Universal dynamic recompiler cache management.
***************************************************************************/
+#ifndef MAME_CPU_DRCCACHE_H
+#define MAME_CPU_DRCCACHE_H
#pragma once
-#ifndef __DRCCACHE_H__
-#define __DRCCACHE_H__
-
+#include "modules/lib/osdlib.h"
//**************************************************************************
@@ -63,43 +63,46 @@ public:
void dealloc(void *memory, size_t bytes);
// codegen helpers
+ void codegen_init();
+ void codegen_complete();
drccodeptr *begin_codegen(uint32_t reserve_bytes);
drccodeptr end_codegen();
- void request_oob_codegen(drc_oob_delegate callback, void *param1 = nullptr, void *param2 = nullptr);
+ void request_oob_codegen(drc_oob_delegate &&callback, void *param1 = nullptr, void *param2 = nullptr);
private:
// largest block of code that can be generated at once
- static const size_t CODEGEN_MAX_BYTES = 131072;
+ static constexpr size_t CODEGEN_MAX_BYTES = 131072;
// minimum alignment, in bytes (must be power of 2)
- static const size_t CACHE_ALIGNMENT = alignof(std::max_align_t);
+ static constexpr size_t CACHE_ALIGNMENT = alignof(std::max_align_t);
// largest permanent allocation we allow
- static const size_t MAX_PERMANENT_ALLOC = 1024;
+ static constexpr size_t MAX_PERMANENT_ALLOC = 1024;
// size of "near" area at the base of the cache
- static const size_t NEAR_CACHE_SIZE = 131072;
+ static constexpr size_t NEAR_CACHE_SIZE = 131072;
+
+ osd::virtual_memory_allocation m_cache;
// core parameters
- drccodeptr m_near; // pointer to the near part of the cache
- drccodeptr m_neartop; // top of the near part of the cache
- drccodeptr m_base; // base pointer to the compiler cache
- drccodeptr m_top; // current top of cache
- drccodeptr m_end; // end of cache memory
- drccodeptr m_codegen; // start of generated code
- size_t m_size; // size of the cache in bytes
+ drccodeptr const m_near; // pointer to the near part of the cache
+ drccodeptr m_neartop; // unallocated area of near cache
+ drccodeptr const m_base; // end of near cache
+ drccodeptr m_top; // end of temporary allocations and code
+ drccodeptr m_limit; // limit for temporary allocations and code (page-aligned)
+ drccodeptr m_end; // first allocated byte in cache
+ drccodeptr m_codegen; // start of current generated code block
+ size_t const m_size; // size of the cache in bytes
// oob management
struct oob_handler
{
- oob_handler *next() const { return m_next; }
-
- oob_handler * m_next; // next handler
- drc_oob_delegate m_callback; // callback function
- void * m_param1; // 1st pointer parameter
- void * m_param2; // 2nd pointer parameter
+ drc_oob_delegate m_callback; // callback function
+ void * m_param1; // 1st pointer parameter
+ void * m_param2; // 2nd pointer parameter
};
- simple_list<oob_handler> m_ooblist; // list of oob handlers
+ std::list<oob_handler> m_oob_list; // list of active oob handlers
+ std::list<oob_handler> m_oob_free; // list of recyclable oob handlers
// free lists
struct free_link
@@ -110,5 +113,4 @@ private:
free_link * m_nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT];
};
-
-#endif /* __DRCCACHE_H__ */
+#endif // MAME_CPU_DRCCACHE_H
diff --git a/src/devices/cpu/drcuml.cpp b/src/devices/cpu/drcuml.cpp
index e935913aceb..af7e97cee4c 100644
--- a/src/devices/cpu/drcuml.cpp
+++ b/src/devices/cpu/drcuml.cpp
@@ -348,7 +348,9 @@ void drcuml_block::end()
disassemble();
// generate the code via the back-end
+ m_drcuml.cache().codegen_init();
m_drcuml.generate(*this, &m_inst[0], m_nextinst);
+ m_drcuml.cache().codegen_complete();
// block is no longer in use
m_inuse = false;
diff --git a/src/osd/modules/lib/osdlib.h b/src/osd/modules/lib/osdlib.h
index 0095244d6fe..59b5291b0a8 100644
--- a/src/osd/modules/lib/osdlib.h
+++ b/src/osd/modules/lib/osdlib.h
@@ -16,6 +16,7 @@
#ifndef __OSDLIB__
#define __OSDLIB__
+#include <initializer_list>
#include <string>
#include <type_traits>
#include <vector>
@@ -58,6 +59,90 @@ int osd_setenv(const char *name, const char *value, int overwrite);
-----------------------------------------------------------------------------*/
std::string osd_get_clipboard_text(void);
+namespace osd {
+
+bool invalidate_instruction_cache(void const *start, std::size_t size);
+
+
+class virtual_memory_allocation
+{
+public:
+ enum : unsigned
+ {
+ NONE = 0x00,
+ READ = 0x01,
+ WRITE = 0x02,
+ EXECUTE = 0x04,
+ READ_WRITE = READ | WRITE,
+ READ_EXECUTE = READ | EXECUTE
+ };
+
+ virtual_memory_allocation(virtual_memory_allocation const &) = delete;
+ virtual_memory_allocation &operator=(virtual_memory_allocation const &) = delete;
+
+ virtual_memory_allocation() { }
+ virtual_memory_allocation(std::initializer_list<std::size_t> blocks)
+ {
+ m_memory = do_alloc(blocks, m_size, m_page_size);
+ }
+ virtual_memory_allocation(virtual_memory_allocation &&that) : m_memory(that.m_memory), m_size(that.m_size), m_page_size(that.m_page_size)
+ {
+ that.m_memory = nullptr;
+ that.m_size = that.m_page_size = 0U;
+ }
+ ~virtual_memory_allocation()
+ {
+ if (m_memory)
+ do_free(m_memory, m_size);
+ }
+
+ explicit operator bool() const { return bool(m_memory); }
+ void *get() { return m_memory; }
+ std::size_t size() const { return m_size; }
+ std::size_t page_size() const { return m_page_size; }
+
+ bool set_access(std::size_t start, std::size_t size, unsigned access)
+ {
+ if ((start % m_page_size) || (size % m_page_size) || (start > m_size) || ((m_size - start) < size))
+ return false;
+ else
+ return do_set_access(reinterpret_cast<std::uint8_t *>(m_memory) + start, size, access);
+ }
+
+ virtual_memory_allocation &operator=(std::nullptr_t)
+ {
+ if (m_memory)
+ do_free(m_memory, m_size);
+ m_memory = nullptr;
+ m_size = m_page_size = 0U;
+ return *this;
+ }
+
+ virtual_memory_allocation &operator=(virtual_memory_allocation &&that)
+ {
+ if (&that != this)
+ {
+ if (m_memory)
+ do_free(m_memory, m_size);
+ m_memory = that.m_memory;
+ m_size = that.m_size;
+ m_page_size = that.m_page_size;
+ that.m_memory = nullptr;
+ that.m_size = that.m_page_size = 0U;
+ }
+ return *this;
+ }
+
+private:
+ static void *do_alloc(std::initializer_list<std::size_t> blocks, std::size_t &size, std::size_t &page_size);
+ static void do_free(void *start, std::size_t size);
+ static bool do_set_access(void *start, std::size_t size, unsigned access);
+
+ void *m_memory = nullptr;
+ std::size_t m_size = 0U, m_page_size = 0U;
+};
+
+
/*-----------------------------------------------------------------------------
dynamic_module: load functions from optional shared libraries
@@ -69,7 +154,6 @@ std::string osd_get_clipboard_text(void);
revisions of a same library)
-----------------------------------------------------------------------------*/
-namespace osd {
class dynamic_module
{
public:
@@ -80,7 +164,7 @@ public:
virtual ~dynamic_module() { };
template <typename T>
- typename std::enable_if<std::is_pointer<T>::value, T>::type bind(char const *symbol)
+ typename std::enable_if_t<std::is_pointer_v<T>, T> bind(char const *symbol)
{
return reinterpret_cast<T>(get_symbol_address(symbol));
}
diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp
index c1f0520fa9b..0b4c30bc14a 100644
--- a/src/osd/modules/lib/osdlib_macosx.cpp
+++ b/src/osd/modules/lib/osdlib_macosx.cpp
@@ -8,26 +8,26 @@
//
//============================================================
-#include <cstdlib>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <csignal>
-#include <dlfcn.h>
+// MAME headers
+#include "osdcore.h"
+#include "osdlib.h"
+#include <csignal>
#include <cstdio>
+#include <cstdlib>
#include <iomanip>
#include <memory>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <Carbon/Carbon.h>
-// MAME headers
-#include "osdcore.h"
-#include "osdlib.h"
//============================================================
// osd_getenv
@@ -57,42 +57,6 @@ void osd_process_kill()
}
//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
-#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX)
- #ifdef __aarch64__
- // $$$$HACK! This assumes no DRC on Apple Silicon; making that work will be much more involved.
- return (void *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
- #else
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
- #endif
-#elif defined(SDLMAME_UNIX)
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, 0, 0);
-#endif
-}
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
-#ifdef SDLMAME_SOLARIS
- munmap((char *)ptr, size);
-#else
- munmap(ptr, size);
-#endif
-}
-
-//============================================================
// osd_break_into_debugger
//============================================================
@@ -202,25 +166,23 @@ int osd_getpid(void)
return getpid();
}
-//============================================================
-// dynamic_module_posix_impl
-//============================================================
namespace osd {
+
+namespace {
+
class dynamic_module_posix_impl : public dynamic_module
{
public:
- dynamic_module_posix_impl(std::vector<std::string> &libraries)
- : m_module(nullptr)
+ dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
{
- m_libraries = libraries;
}
virtual ~dynamic_module_posix_impl() override
{
- if (m_module != nullptr)
+ if (m_module)
dlclose(m_module);
- };
+ }
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
@@ -230,19 +192,17 @@ protected:
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
- {
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
- }
for (auto const &library : m_libraries)
{
- void *module = dlopen(library.c_str(), RTLD_LAZY);
+ void *const module = dlopen(library.c_str(), RTLD_LAZY);
if (module != nullptr)
{
- generic_fptr_t function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
+ generic_fptr_t const function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
- if (function != nullptr)
+ if (function)
{
m_module = module;
return function;
@@ -259,12 +219,61 @@ protected:
private:
std::vector<std::string> m_libraries;
- void * m_module;
+ void * m_module = nullptr;
};
+} // anonymous namespace
+
+
+bool invalidate_instruction_cache(void const *start, std::size_t size)
+{
+ char const *const begin(reinterpret_cast<char const *>(start));
+ char const *const end(begin + size);
+ __builtin___clear_cache(const_cast<char *>(begin), const_cast<char *>(end));
+ return true;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, std::size_t &size, std::size_t &page_size)
+{
+ long const p(sysconf(_SC_PAGE_SIZE));
+ if (0 >= p)
+ return nullptr;
+ std::size_t s(0);
+ for (std::size_t b : blocks)
+ s += (b + p - 1) / p;
+ s *= p;
+ if (!s)
+ return nullptr;
+ void *const result(mmap(nullptr, s, PROT_NONE, MAP_ANON | MAP_SHARED, -1, 0));
+ if (result == (void *)-1)
+ return nullptr;
+ size = s;
+ page_size = p;
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size)
+{
+ munmap(start, size);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access)
+{
+ int prot((NONE == access) ? PROT_NONE : 0);
+ if (access & READ)
+ prot |= PROT_READ;
+ if (access & WRITE)
+ prot |= PROT_WRITE;
+ if (access & EXECUTE)
+ prot |= PROT_EXEC;
+ return mprotect(start, size, prot) == 0;
+}
+
+
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
- return std::make_unique<dynamic_module_posix_impl>(names);
+ return std::make_unique<dynamic_module_posix_impl>(std::move(names));
}
} // namespace osd
diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp
index c2a34be7c98..1c51a2666c7 100644
--- a/src/osd/modules/lib/osdlib_unix.cpp
+++ b/src/osd/modules/lib/osdlib_unix.cpp
@@ -8,23 +8,23 @@
//
//============================================================
-#include <cstdlib>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <csignal>
-#include <dlfcn.h>
+// MAME headers
+#include "osdcore.h"
+#include "osdlib.h"
+#include <SDL2/SDL.h>
+
+#include <csignal>
#include <cstdio>
+#include <cstdlib>
#include <iomanip>
#include <memory>
+#include <dlfcn.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
-// MAME headers
-#include "osdcore.h"
-#include "osdlib.h"
-
-#include <SDL2/SDL.h>
//============================================================
// osd_getenv
@@ -54,37 +54,6 @@ void osd_process_kill()
}
//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
-#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) || defined(SDLMAME_EMSCRIPTEN)
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
-#else
- return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, 0, 0);
-#endif
-}
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
-#ifdef SDLMAME_SOLARIS
- munmap((char *)ptr, size);
-#else
- munmap(ptr, size);
-#endif
-}
-
-//============================================================
// osd_break_into_debugger
//============================================================
@@ -133,25 +102,23 @@ int osd_getpid(void)
return getpid();
}
-//============================================================
-// dynamic_module_posix_impl
-//============================================================
namespace osd {
+
+namespace {
+
class dynamic_module_posix_impl : public dynamic_module
{
public:
- dynamic_module_posix_impl(std::vector<std::string> &libraries)
- : m_module(nullptr)
+ dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
{
- m_libraries = libraries;
}
virtual ~dynamic_module_posix_impl() override
{
- if (m_module != nullptr)
+ if (m_module)
dlclose(m_module);
- };
+ }
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
@@ -161,19 +128,17 @@ protected:
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
- {
return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol));
- }
for (auto const &library : m_libraries)
{
- void *module = dlopen(library.c_str(), RTLD_LAZY);
+ void *const module = dlopen(library.c_str(), RTLD_LAZY);
if (module != nullptr)
{
- generic_fptr_t function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
+ generic_fptr_t const function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol));
- if (function != nullptr)
+ if (function)
{
m_module = module;
return function;
@@ -190,12 +155,67 @@ protected:
private:
std::vector<std::string> m_libraries;
- void * m_module;
+ void * m_module = nullptr;
};
+} // anonymous namespace
+
+
+bool invalidate_instruction_cache(void const *start, std::size_t size)
+{
+ char const *const begin(reinterpret_cast<char const *>(start));
+ char const *const end(begin + size);
+ __builtin___clear_cache(const_cast<char *>(begin), const_cast<char *>(end));
+ return true;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, std::size_t &size, std::size_t &page_size)
+{
+ long const p(sysconf(_SC_PAGE_SIZE));
+ if (0 >= p)
+ return nullptr;
+ std::size_t s(0);
+ for (std::size_t b : blocks)
+ s += (b + p - 1) / p;
+ s *= p;
+ if (!s)
+ return nullptr;
+#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) || defined(SDLMAME_EMSCRIPTEN)
+ int const fd(-1);
+#else
+ // TODO: portable applications are supposed to use -1 for anonymous mappings - detect whatever requires 0 specifically
+ int const fd(0);
+#endif
+ void *const result(mmap(nullptr, s, PROT_NONE, MAP_ANON | MAP_SHARED, fd, 0));
+ if (result == (void *)-1)
+ return nullptr;
+ size = s;
+ page_size = p;
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size)
+{
+ munmap(reinterpret_cast<char *>(start), size);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access)
+{
+ int prot((NONE == access) ? PROT_NONE : 0);
+ if (access & READ)
+ prot |= PROT_READ;
+ if (access & WRITE)
+ prot |= PROT_WRITE;
+ if (access & EXECUTE)
+ prot |= PROT_EXEC;
+ return mprotect(reinterpret_cast<char *>(start), size, prot) == 0;
+}
+
+
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
- return std::make_unique<dynamic_module_posix_impl>(names);
+ return std::make_unique<dynamic_module_posix_impl>(std::move(names));
}
} // namespace osd
diff --git a/src/osd/modules/lib/osdlib_uwp.cpp b/src/osd/modules/lib/osdlib_uwp.cpp
index 680594d9cc8..f9a3e6a5cf9 100644
--- a/src/osd/modules/lib/osdlib_uwp.cpp
+++ b/src/osd/modules/lib/osdlib_uwp.cpp
@@ -8,30 +8,27 @@
//
//============================================================
-#include <windows.h>
-#include <mmsystem.h>
-
-#include <cstdlib>
-
-#include <cstdio>
-#include <memory>
-
// MAME headers
#include "osdlib.h"
#include "osdcomm.h"
#include "osdcore.h"
#include "strconv.h"
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <memory>
+
#include <windows.h>
+#include <memoryapi.h>
+
#include <wrl\client.h>
-#include "strconv.h"
using namespace Platform;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace Windows::Foundation;
-#include <map>
//============================================================
// GLOBAL VARIABLES
@@ -89,30 +86,6 @@ void osd_process_kill()
}
//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
- return nullptr;
-}
-
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
-}
-
-
-//============================================================
// osd_break_into_debugger
//============================================================
@@ -188,3 +161,47 @@ int osd_getpid(void)
return GetCurrentProcessId();
}
+
+namespace osd {
+
+bool invalidate_instruction_cache(void const *start, std::size_t size)
+{
+ return FlushInstructionCache(GetCurrentProcess(), start, size) != 0;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, std::size_t &size, std::size_t &page_size)
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ SIZE_T s(0);
+ for (std::size_t b : blocks)
+ s += (b + info.dwPageSize - 1) / info.dwPageSize;
+ s *= info.dwPageSize;
+ if (!s)
+ return nullptr;
+ LPVOID const result(VirtualAllocFromApp(nullptr, s, MEM_COMMIT, PAGE_NOACCESS));
+ if (result)
+ {
+ size = s;
+ page_size = info.dwPageSize;
+ }
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size)
+{
+ VirtualFree(start, 0, MEM_RELEASE);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access)
+{
+ ULONG p, o;
+ if (access & EXECUTE)
+ p = (access & WRITE) ? PAGE_EXECUTE_READWRITE : (access & READ) ? PAGE_EXECUTE_READ : PAGE_EXECUTE;
+ else
+ p = (access & WRITE) ? PAGE_READWRITE : (access & READ) ? PAGE_READONLY : PAGE_NOACCESS;
+ return VirtualProtectFromApp(start, size, p, &o) != 0;
+}
+
+} // namespace osd
diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp
index b1051dad7a6..768b71463d2 100644
--- a/src/osd/modules/lib/osdlib_win32.cpp
+++ b/src/osd/modules/lib/osdlib_win32.cpp
@@ -8,17 +8,6 @@
//
//============================================================
-#include <windows.h>
-#include <mmsystem.h>
-
-#include <cstdlib>
-#ifndef _MSC_VER
-#include <unistd.h>
-#endif
-
-#include <cstdio>
-#include <memory>
-
// MAME headers
#include "osdlib.h"
#include "osdcomm.h"
@@ -29,6 +18,17 @@
#include "winutf8.h"
#endif
+#include <cstdio>
+#include <cstdlib>
+
+#include <windows.h>
+#include <memoryapi.h>
+
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+
//============================================================
// GLOBAL VARIABLES
//============================================================
@@ -82,30 +82,6 @@ void osd_process_kill()
TerminateProcess(GetCurrentProcess(), -1);
}
-//============================================================
-// osd_alloc_executable
-//
-// allocates "size" bytes of executable memory. this must take
-// things like NX support into account.
-//============================================================
-
-void *osd_alloc_executable(size_t size)
-{
- return VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
-}
-
-
-//============================================================
-// osd_free_executable
-//
-// frees memory allocated with osd_alloc_executable
-//============================================================
-
-void osd_free_executable(void *ptr, size_t size)
-{
- VirtualFree(ptr, 0, MEM_RELEASE);
-}
-
//============================================================
// osd_break_into_debugger
@@ -228,20 +204,21 @@ int osd_getpid()
#endif
namespace osd {
+
+namespace {
+
class dynamic_module_win32_impl : public dynamic_module
{
public:
- dynamic_module_win32_impl(std::vector<std::string> &libraries)
- : m_module(nullptr)
+ dynamic_module_win32_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries))
{
- m_libraries = libraries;
}
virtual ~dynamic_module_win32_impl() override
{
- if (m_module != nullptr)
+ if (m_module)
FreeLibrary(m_module);
- };
+ }
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
@@ -251,20 +228,18 @@ protected:
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
- {
return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol));
- }
for (auto const &library : m_libraries)
{
- osd::text::tstring tempstr = osd::text::to_tstring(library);
- HMODULE module = load_library(tempstr.c_str());
+ osd::text::tstring const tempstr = osd::text::to_tstring(library);
+ HMODULE const module = load_library(tempstr.c_str());
- if (module != nullptr)
+ if (module)
{
- auto function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol));
+ auto const function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol));
- if (function != nullptr)
+ if (function)
{
m_module = module;
return function;
@@ -281,12 +256,56 @@ protected:
private:
std::vector<std::string> m_libraries;
- HMODULE m_module;
+ HMODULE m_module = nullptr;
};
+} // anonymous namespace
+
+
+bool invalidate_instruction_cache(void const *start, std::size_t size)
+{
+ return FlushInstructionCache(GetCurrentProcess(), start, size) != 0;
+}
+
+
+void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, std::size_t &size, std::size_t &page_size)
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ SIZE_T s(0);
+ for (std::size_t b : blocks)
+ s += (b + info.dwPageSize - 1) / info.dwPageSize;
+ s *= info.dwPageSize;
+ if (!s)
+ return nullptr;
+ LPVOID const result(VirtualAlloc(nullptr, s, MEM_COMMIT, PAGE_NOACCESS));
+ if (result)
+ {
+ size = s;
+ page_size = info.dwPageSize;
+ }
+ return result;
+}
+
+void virtual_memory_allocation::do_free(void *start, std::size_t size)
+{
+ VirtualFree(start, 0, MEM_RELEASE);
+}
+
+bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access)
+{
+ DWORD p, o;
+ if (access & EXECUTE)
+ p = (access & WRITE) ? PAGE_EXECUTE_READWRITE : (access & READ) ? PAGE_EXECUTE_READ : PAGE_EXECUTE;
+ else
+ p = (access & WRITE) ? PAGE_READWRITE : (access & READ) ? PAGE_READONLY : PAGE_NOACCESS;
+ return VirtualProtect(start, size, p, &o) != 0;
+}
+
+
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
- return std::make_unique<dynamic_module_win32_impl>(names);
+ return std::make_unique<dynamic_module_win32_impl>(std::move(names));
}
} // namespace osd
diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h
index dd6ab5837d5..a7f652470db 100644
--- a/src/osd/osdcore.h
+++ b/src/osd/osdcore.h
@@ -342,27 +342,6 @@ void osd_work_item_release(osd_work_item *item);
MISCELLANEOUS INTERFACES
***************************************************************************/
-/// \brief Allocate memory that can contain executable code
-///
-/// Allocated memory must be both writable and executable. Allocated
-/// memory must be freed by calling #osd_free_executable passing the
-/// same size.
-/// \param [in] size Number of bytes to allocate.
-/// \return Pointer to allocated memory, or nullptr if allocation
-/// failed.
-/// \sa osd_free_executable
-void *osd_alloc_executable(size_t size);
-
-
-/// \brief Free memory allocated by osd_alloc_executable
-///
-/// \param [in] ptr Pointer returned by #osd_alloc_executable.
-/// \param [in] size Number of bytes originally requested. Must match
-/// the value passed to #osd_alloc_executable.
-/// \sa osd_alloc_executable
-void osd_free_executable(void *ptr, size_t size);
-
-
/// \brief Break into host debugger if attached
///
/// This function is called when a fatal error occurs. If a debugger is